58217f5900
WOO HOO!
103 lines
2.4 KiB
C
103 lines
2.4 KiB
C
/*
|
|
* linux/fs/fcntl.c
|
|
*
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
*/
|
|
|
|
#include <asm/segment.h>
|
|
|
|
#include <linux/sched.h>
|
|
#include <linux/kernel.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/stat.h>
|
|
#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 *);
|
|
extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg);
|
|
|
|
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;
|
|
FD_CLR(arg, ¤t->close_on_exec);
|
|
(current->filp[arg] = current->filp[fd])->f_count++;
|
|
return arg;
|
|
}
|
|
|
|
asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd)
|
|
{
|
|
if (oldfd >= NR_OPEN || !current->filp[oldfd])
|
|
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
|
|
sys_close(newfd);
|
|
return dupfd(oldfd,newfd);
|
|
}
|
|
|
|
asmlinkage int sys_dup(unsigned int fildes)
|
|
{
|
|
return dupfd(fildes,0);
|
|
}
|
|
|
|
asmlinkage 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 FD_ISSET(fd, ¤t->close_on_exec);
|
|
case F_SETFD:
|
|
if (arg&1)
|
|
FD_SET(fd, ¤t->close_on_exec);
|
|
else
|
|
FD_CLR(fd, ¤t->close_on_exec);
|
|
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:
|
|
return fcntl_getlk(fd, (struct flock *) arg);
|
|
case F_SETLK:
|
|
return fcntl_setlk(fd, cmd, (struct flock *) arg);
|
|
case F_SETLKW:
|
|
return fcntl_setlk(fd, cmd, (struct flock *) arg);
|
|
default:
|
|
/* sockets need a few special fcntls. */
|
|
if (S_ISSOCK (filp->f_inode->i_mode))
|
|
{
|
|
return (sock_fcntl (filp, cmd, arg));
|
|
}
|
|
return -EINVAL;
|
|
}
|
|
}
|