aboutsummaryrefslogtreecommitdiff
path: root/linux/fs/fcntl.c
diff options
context:
space:
mode:
Diffstat (limited to 'linux/fs/fcntl.c')
-rw-r--r--linux/fs/fcntl.c69
1 files changed, 69 insertions, 0 deletions
diff --git a/linux/fs/fcntl.c b/linux/fs/fcntl.c
new file mode 100644
index 0000000..169f376
--- /dev/null
+++ b/linux/fs/fcntl.c
@@ -0,0 +1,69 @@
+#include <string.h>
+#include <errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+
+#include <fcntl.h>
+#include <sys/stat.h>
+
+extern int sys_close(int fd);
+
+static int dupfd(unsigned int fd, unsigned int arg)
+{
+ if (fd >= NR_OPEN || !current->filp[fd])
+ return -EBADF;
+ if (arg >= NR_OPEN)
+ return -EINVAL;
+ while (arg < NR_OPEN)
+ if (current->filp[arg])
+ arg++;
+ else
+ break;
+ if (arg >= NR_OPEN)
+ return -EMFILE;
+ current->close_on_exec &= ~(1<<arg);
+ (current->filp[arg] = current->filp[fd])->f_count++;
+ return arg;
+}
+
+int sys_dup2(unsigned int oldfd, unsigned int newfd)
+{
+ sys_close(newfd);
+ return dupfd(oldfd,newfd);
+}
+
+int sys_dup(unsigned int fildes)
+{
+ return dupfd(fildes,0);
+}
+
+int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
+{
+ struct file * filp;
+
+ if (fd >= NR_OPEN || !(filp = current->filp[fd]))
+ return -EBADF;
+ switch (cmd) {
+ case F_DUPFD:
+ return dupfd(fd,arg);
+ case F_GETFD:
+ return (current->close_on_exec>>fd)&1;
+ case F_SETFD:
+ if (arg&1)
+ current->close_on_exec |= (1<<fd);
+ else
+ current->close_on_exec &= ~(1<<fd);
+ return 0;
+ case F_GETFL:
+ return filp->f_flags;
+ case F_SETFL:
+ filp->f_flags &= ~(O_APPEND | O_NONBLOCK);
+ filp->f_flags |= arg & (O_APPEND | O_NONBLOCK);
+ return 0;
+ case F_GETLK: case F_SETLK: case F_SETLKW:
+ return -1;
+ default:
+ return -1;
+ }
+}