/*
* linux/fs/fcntl.c
*
* (C) 1991 Linus Torvalds
*/
#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);
/* 复制文件句柄,参数fd是指与复制的文件句柄,arg是指定新文件的句柄的最小值 */
static int dupfd(unsigned int fd, unsigned int arg)
{
// 如果文件句柄值大于一个程序最多打开文件数NR_OPEN,或者该句柄的文件结构不存在,则出错,
// 返回出错码并退出
if (fd >= NR_OPEN || !current->filp[fd])
return -EBADF;
// 如果指定的新句柄值arg 大于最多打开文件数,则出错
if (arg >= NR_OPEN)
return -EINVAL;
// 在当前进程的文件结构指针数组中寻找索引号大于等于arg 但还没有使用的项
while (arg < NR_OPEN)
if (current->filp[arg])
arg++;
else
break;
// 如果找到的新句柄值arg 大于最多打开文件数,则出错
if (arg >= NR_OPEN)
return -EMFILE;
// 在运行exec()类函数时不关闭该句柄
current->close_on_exec &= ~(1<<arg);
// 令该文件结构指针等于原句柄fd 的指针,并将文件引用计数增1
(current->filp[arg] = current->filp[fd])->f_count++;
return arg;
}
/* 复制文件句柄系统调用函数 */
int sys_dup2(unsigned int oldfd, unsigned int newfd)
{
// 若句柄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;
// 如果文件句柄值大于一个进程最多打开文件数NR_OPEN,或者该句柄的文件结构指针为空,则出错,
// 返回出错码并退出
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;
}
}