Linux-0.11 文件系统open.c详解
模块简介
对于一个文件系统,需要提供一些封装好的系统调用提供给应用层调用。例如打开一个文件,对于应用层而言,其并不关心底层的inode和buffer_cache的操作。 open.c便是提供这样的一个功能。
同样是文件系统high-level的API的有:
- open.c
- exec.c
- stat.c
- fcntl.c
- ioctl.c
函数详解
sys_ustat
int sys_ustat(int dev, struct ustat * ubuf)
该函数的作用是获取文件系统信息。不过Linux-0.11版本尚未实现。
在代码实现中,仅仅是返回了一个错误码ENOSYS。
return -ENOSYS;
sys_utime
int sys_utime(char * filename, struct utimbuf * times)
该函数的作用是设置文件的修改和访问时间。入参中,filename代表文件名, times是一个访问和修改时间结构的指针。
首先调用namei函数(fs/namei.c)获取文件的i节点, 因为一个文件与时间相关的信息存储在inode节点中。 接着从入参中提取出访问时间和修改时间。
struct m_inode * inode;long actime,modtime;if (!(inode=namei(filename)))//获取文件的i节点return -ENOENT;if (times) {//如果times指针不为空,则从times中获取。actime = get_fs_long((unsigned long *) ×->actime);modtime = get_fs_long((unsigned long *) ×->modtime);} else//如果times指针为空,则直接从系统时间获取actime = modtime = CURRENT_TIME;
接着将i节点的访问时间和修改时间进行修改, 并设置该i节点有脏数据。
inode->i_atime = actime; //设置访问时间inode->i_mtime = modtime; //设置修改时间inode->i_dirt = 1; //设置i节点有脏数据iput(inode); //放回i节点return 0;
sys_access
int sys_access(const char * filename,int mode)
该函数的作用是检查文件的访问权限。
struct m_inode * inode;int res, i_mode;mode &= 0007;if (!(inode=namei(filename)))return -EACCES;i_mode = res = inode->i_mode & 0777;iput(inode);if (current->uid == inode->i_uid)res >>= 6;else if (current->gid == inode->i_gid)res >>= 6; //这里似乎是一个bug, 应该是>>3, namei中的permission函数没有这个问题if ((res & 0007 & mode) == mode)return 0;/** XXX we are doing this test last because we really should be* swapping the effective with the real user id (temporarily),* and then calling suser() routine. If we do call the* suser() routine, it needs to be called last. */if ((!current->uid) &&(!(mode & 1) || (i_mode & 0111)))return 0;return -EACCES;
sys_chdir
int sys_chdir(const char * filename)
该函数的作用是改变当前进程的工作目录。
首先通过namei找到路径filename对应的i节点。节点将该i节点设置给PCB中的pwd字段。
struct m_inode * inode;if (!(inode = namei(filename)))return -ENOENT;if (!S_ISDIR(inode->i_mode)) { //如果给定的filename对应的不是一个目录i节点,则返回错误iput(inode);return -ENOTDIR;}iput(current->pwd);current->pwd = inode; //将当前进程的工作路径设置为filename对应的i节点return (0);
sys_chroot
int sys_chroot(const char * filename)
该函数的作用是修改进程的根目录。
首先通过namei找到路径filename对应的i节点。节点将该i节点设置给PCB中的root字段。
struct m_inode * inode;if (!(inode=namei(filename)))return -ENOENT;if (!S_ISDIR(inode->i_mode)) {//如果给定的filename对应的不是一个目录i节点,则返回错误iput(inode);return -ENOTDIR;}iput(current->root);current->root = inode;//将当前进程的根路径设置为filename对应的i节点return (0);
sys_chmod
int sys_chmod(const char * filename,int mode)
该函数的作用是用于修改文件的权限。
struct m_inode * inode;if (!(inode=namei(filename))) //先查找出filename对应的i节点return -ENOENT;if ((current->euid != inode->i_uid) && !suser()) { //如果当前进程的有效用户不等于i节点用户,并且也不是超级用户,则没有操作该i节点的权限iput(inode);return -EACCES;}inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);//否则重新设置该i节点的文件属性,并设置该i节点含有脏数据inode->i_dirt = 1;iput(inode);return 0;
sys_chown
int sys_chown(const char * filename,int uid,int gid)
该函数的作用是修改文件的拥有用户和拥有组。
struct m_inode * inode;if (!(inode=namei(filename)))//获取filename对应的i节点return -ENOENT;if (!suser()) {//如果不是超级用户则不能操作iput(inode);return -EACCES;}inode->i_uid=uid;//设置uidinode->i_gid=gid;//设置gidinode->i_dirt=1;//设置有脏数据iput(inode);return 0;
sys_open
int sys_open(const char * filename,int flag,int mode)
该函数的作用是用于打开一个文件。该函数是打开文件的系统调用。
struct m_inode * inode;struct file * f;int i,fd;mode &= 0777 & ~current->umask; //mode和进程的屏蔽码相与for(fd=0 ; fd<NR_OPEN ; fd++) //从进程的fd数组中找到一个空闲项if (!current->filp[fd]) break;if (fd>=NR_OPEN) //如果超过了进程最大可以打开的文件数则返回错误return -EINVAL;current->close_on_exec &= ~(1<<fd);f=0+file_table;for (i=0 ; i<NR_FILE ; i++,f++)if (!f->f_count) break;if (i>=NR_FILE)return -EINVAL;(current->filp[fd]=f)->f_count++;if ((i=open_namei(filename,flag,mode,&inode))<0) {//调用open_namei打开filename对应的i节点current->filp[fd]=NULL;f->f_count=0;return i;}
/* ttys are somewhat special (ttyxx major==4, tty major==5) */if (S_ISCHR(inode->i_mode)) {if (MAJOR(inode->i_zone[0])==4) {//ttyxx major = 4if (current->leader && current->tty<0) {current->tty = MINOR(inode->i_zone[0]);tty_table[current->tty].pgrp = current->pgrp;}} else if (MAJOR(inode->i_zone[0])==5)//tty major=5if (current->tty<0) {iput(inode);current->filp[fd]=NULL;f->f_count=0;return -EPERM;}}
/* Likewise with block-devices: check for floppy_change */if (S_ISBLK(inode->i_mode))check_disk_change(inode->i_zone[0]);f->f_mode = inode->i_mode;f->f_flags = flag;f->f_count = 1;f->f_inode = inode;f->f_pos = 0;return (fd);
sys_creat
int sys_creat(const char * pathname, int mode)
该函数是创建文件的系统调用。
其内部调用了sys_open函数,传递参数时,设置flag = O_CREAT | O_TRUNC。
return sys_open(pathname, O_CREAT | O_TRUNC, mode);
sys_close
int sys_close(unsigned int fd)
该函数是关闭文件的系统调用。
struct file * filp;if (fd >= NR_OPEN)//如果fd大于了程序可以打开的最大的文件数,则返回错误。return -EINVAL;current->close_on_exec &= ~(1<<fd);//将执行时关闭的句柄位图复位为0if (!(filp = current->filp[fd]))//fd对应的进程文件描述符并没有对应的文件结构体,则返回错误。return -EINVAL;current->filp[fd] = NULL;//将fd对应的文件结构体置为NULLif (filp->f_count == 0)panic("Close: file count is 0");if (--filp->f_count)//减少引用计数,如果f_count不为0, 代表还有其他进程在使用该文件结构体,则直接返回return (0);iput(filp->f_inode);//否则代表没有进程在使用该文件结构体,则可以进行放回操作return (0);