diff options
Diffstat (limited to 'fs/fcntl.c')
-rw-r--r-- | fs/fcntl.c | 46 |
1 files changed, 19 insertions, 27 deletions
diff --git a/fs/fcntl.c b/fs/fcntl.c index 12f7cf489..99a1638e1 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -4,8 +4,6 @@ * Copyright (C) 1991, 1992 Linus Torvalds */ -#include <asm/segment.h> - #include <linux/sched.h> #include <linux/kernel.h> #include <linux/errno.h> @@ -13,25 +11,25 @@ #include <linux/fcntl.h> #include <linux/string.h> -extern int fcntl_getlk(unsigned int, struct flock *); -extern int fcntl_setlk(unsigned int, unsigned int, struct flock *); +#include <asm/bitops.h> +#include <asm/uaccess.h> + extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); -static int dupfd(unsigned int fd, unsigned int arg) +static inline int dupfd(unsigned int fd, unsigned int arg) { - if (fd >= NR_OPEN || !current->files->fd[fd]) + struct files_struct * files = current->files; + + if (fd >= NR_OPEN || !files->fd[fd]) return -EBADF; if (arg >= NR_OPEN) return -EINVAL; - while (arg < NR_OPEN) - if (current->files->fd[arg]) - arg++; - else - break; - if (arg >= NR_OPEN) + arg = find_next_zero_bit(&files->open_fds, NR_OPEN, arg); + if (arg >= current->rlim[RLIMIT_NOFILE].rlim_cur) return -EMFILE; - FD_CLR(arg, ¤t->files->close_on_exec); - (current->files->fd[arg] = current->files->fd[fd])->f_count++; + FD_SET(arg, &files->open_fds); + FD_CLR(arg, &files->close_on_exec); + (files->fd[arg] = files->fd[fd])->f_count++; return arg; } @@ -41,19 +39,9 @@ asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd) return -EBADF; if (newfd == oldfd) return newfd; - /* - * errno's for dup2() are slightly different than for fcntl(F_DUPFD) - * for historical reasons. - */ - if (newfd > NR_OPEN) /* historical botch - should have been >= */ - return -EBADF; /* dupfd() would return -EINVAL */ -#if 1 - if (newfd == NR_OPEN) - return -EBADF; /* dupfd() does return -EINVAL and that may - * even be the standard! But that is too - * weird for now. - */ -#endif + if (newfd >= NR_OPEN) + return -EBADF; /* following POSIX.1 6.2.1 */ + sys_close(newfd); return dupfd(oldfd,newfd); } @@ -97,6 +85,10 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) if (!(arg & FASYNC) && (filp->f_flags & FASYNC) && filp->f_op->fasync) filp->f_op->fasync(filp->f_inode, filp, 0); + /* required for SunOS emulation */ + if (O_NONBLOCK != O_NDELAY) + if (arg & O_NDELAY) + arg |= O_NONBLOCK; filp->f_flags &= ~(O_APPEND | O_NONBLOCK | FASYNC); filp->f_flags |= arg & (O_APPEND | O_NONBLOCK | FASYNC); |