fcntl.c实现了文件控制系统调用fcntl和两个文件句柄描述符的复制系统调用dup()和dup2()。
dup返回当前值最小的未用句柄,dup2返回指定新句柄的数值,句柄的复制操作主要用在文件的标准输入、输出重定向和管道方面。
复制文件句柄,参数fd是要复制的文件句柄,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;
//清除进程的 close_on_exec 位图中的特定位。close_on_exec 是一个位图,用于记录在执行 exec 系统调用时是否关闭相应的文件描述符。
current->close_on_exec &= ~(1<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);
}
sys_fcntl
的函数实现了 fcntl
系统调用的功能。fcntl
系统调用用于对打开文件描述符进行操作和控制,通过传递不同的命令(cmd
)来实现不同的操作。
下面是该函数的作用和代码实现的解释:
首先,它检查给定的文件描述符(fd
)是否有效,即必须小于已打开文件描述符的最大数目(NR_OPEN
),并且与当前进程的文件描述符表中的相应条目(current->filp[fd]
)关联。
如果文件描述符无效,函数返回错误码 -EBADF
(-9:无效的文件描述符)。
根据传递的命令(cmd
)参数,执行不同的操作:
F_DUPFD
:如果命令是 F_DUPFD
,则调用 dupfd
函数来复制给定的文件描述符(fd
)到最小的可用文件描述符号(arg
)。F_GETFD
:如果命令是 F_GETFD
,则返回当前进程的 close_on_exec
位图中对应文件描述符的状态(即该文件描述符在 exec
执行时是否会被关闭)。F_SETFD
:如果命令是 F_SETFD
,则根据参数 arg
将当前进程的 close_on_exec
位图中对应文件描述符的状态进行设置,即设置或清除该文件描述符在 exec
执行时是否会被关闭的标志位。F_GETFL
:如果命令是 F_GETFL
,则返回与给定文件描述符关联的文件状态标志。F_SETFL
:如果命令是 F_SETFL
,则根据参数 arg
对给定文件描述符关联的文件状态标志进行设置,例如设置或清除非阻塞(O_NONBLOCK)和追加(O_APPEND)等标志位。F_GETLK
、F_SETLK
、F_SETLKW
):该函数返回 -1,表示不支持给定的命令。
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<close_on_exec &= ~(1<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;
}
}
ioctl.c文件实现了输入、输出控制系统调用ioctl,主要调用tty_ioctl函数,对终端IO进行控制
extern int tty_ioctl(int dev, int cmd, int arg);
typedef int (*ioctl_ptr)(int dev,int cmd,int arg);
#define NRDEVS ((sizeof (ioctl_table))/(sizeof (ioctl_ptr)))
static ioctl_ptr ioctl_table[]={
NULL, /* nodev */
NULL, /* /dev/mem */
NULL, /* /dev/fd */
NULL, /* /dev/hd */
tty_ioctl, /* /dev/ttyx */
tty_ioctl, /* /dev/tty */
NULL, /* /dev/lp */
NULL}; /* named pipes */
int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct file * filp;
int dev,mode;
if (fd >= NR_OPEN || !(filp = current->filp[fd]))
return -EBADF;
//判断文件类型
mode=filp->f_inode->i_mode;
if (!S_ISCHR(mode) && !S_ISBLK(mode))
return -EINVAL;
//获取设备号
dev = filp->f_inode->i_zone[0];
if (MAJOR(dev) >= NRDEVS)
return -ENODEV;
if (!ioctl_table[MAJOR(dev)])
return -ENOTTY;
//对应ioctl_table函数指针表中没有对应函数,则返回出错码
return ioctl_table[MAJOR(dev)](dev,cmd,arg);
}
实现了取文件信息状态系统调用stat和fstat,并将信息存放用户的文件状态结果缓冲区中
static void cp_stat(struct m_inode * inode, struct stat * statbuf)
{
struct stat tmp;
int i;
//验证存放数据的内存空间
verify_area(statbuf,sizeof (* statbuf));
tmp.st_dev = inode->i_dev;
tmp.st_ino = inode->i_num;
tmp.st_mode = inode->i_mode;
tmp.st_nlink = inode->i_nlinks;
tmp.st_uid = inode->i_uid;
tmp.st_gid = inode->i_gid;
tmp.st_rdev = inode->i_zone[0];
tmp.st_size = inode->i_size;
tmp.st_atime = inode->i_atime;
tmp.st_mtime = inode->i_mtime;
tmp.st_ctime = inode->i_ctime;
//复制状态信息到用户缓冲区
for (i=0 ; i
int sys_stat(char * filename, struct stat * statbuf)
{
struct m_inode * inode;
//根据文件名找出对应的i节点
if (!(inode=namei(filename)))
return -ENOENT;
cp_stat(inode,statbuf);
iput(inode);
return 0;
}
int sys_fstat(unsigned int fd, struct stat * statbuf)
{
struct file * f;
struct m_inode * inode;
if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode))
return -EBADF;
cp_stat(inode,statbuf);
return 0;
}