目录
概述
m_inode节点介绍
fs/sys_utime设置文件访问和修改时间
fs/sys_access检查访问权限
fs/sys_chdir改变当前工作目录
fs/sys_chroot改变根目录
fs/sys_chmod修改文件属性
fs/sys_chown修改文件宿主
lib/open用户层文件打开函数,调用sys_open
fs/sys_open内核层打开、创建文件
fs/sys_create创建文件
fs/sys_close关闭文件
fs/open.c实现文件的创建、打开、关闭,文件宿主和属性的修改、文件访问权限的修改、文件操作时间的修改等等。
lib/open.c是up用户空间文件打开函数,lib/open.c->open()调用fs/open.c->sys_open()
代码里都做了详细的解释
这是一个用于表示UNIX操作系统中的i节点(inode)结构体。以下是每个变量的含义:
- `i_mode`:i节点的访问模式(如文件、目录、设备等)。
- `i_uid`:拥有该i节点的用户ID。
- `i_size`:文件的大小(以字节为单位)。
- `i_mtime`:文件的修改时间(上次修改的时间戳)。
- `i_gid`:拥有该i节点的组ID。
- `i_nlinks`:指向该i节点的硬链接数。
- `i_zone`:存储文件数据的逻辑块号数组(指向数据块在磁盘中的位置)。
- `i_wait`:等待该i节点的任务(进程)队列。
- `i_atime`:文件的访问时间(上次访问的时间戳)。
- `i_ctime`:文件的创建时间(时间戳)。
- `i_dev`:文件所在的设备号。
- `i_num`:用于在文件系统中唯一标识该i节点的编号。
- `i_count`:引用当前i节点的计数器。
- `i_lock`:用于对该i节点进行加锁操作的标识。
- `i_dirt`:表示该i节点是否被修改过的标识。
- `i_pipe`:用于指示该i节点是否与管道相关的标识。
- `i_mount`:用于指示该i节点是否挂载的标识。
- `i_seek`:用于指示该i节点是否处于查找(搜索)状态的标识。
- `i_update`:用于指示该i节点是否需要进行更新的标识。
struct m_inode {
unsigned short i_mode;
unsigned short i_uid;
unsigned long i_size;
unsigned long i_mtime;
unsigned char i_gid;
unsigned char i_nlinks;
unsigned short i_zone[9];
/* these are in memory also */
struct task_struct * i_wait;
unsigned long i_atime;
unsigned long i_ctime;
unsigned short i_dev;
unsigned short i_num;
unsigned short i_count;
unsigned char i_lock;
unsigned char i_dirt;
unsigned char i_pipe;
unsigned char i_mount;
unsigned char i_seek;
unsigned char i_update;
};
int sys_utime(char * filename, struct utimbuf * times)
{
struct m_inode * inode;
long actime,modtime;
//根据文件名字找到对应的inode节点
if (!(inode=namei(filename)))
return -ENOENT;
//如果定义times,就设置用户设置的时间值,否则设置当前时间
if (times) {
actime = get_fs_long((unsigned long *) ×->actime);
modtime = get_fs_long((unsigned long *) ×->modtime);
} else
actime = modtime = CURRENT_TIME;
inode->i_atime = actime;
inode->i_mtime = modtime;
//设置修改标志位,释放inode节点
inode->i_dirt = 1;
iput(inode);
return 0;
}
/*
* XXX should we use the real or effective uid? BSD uses the real uid,
* so as to make this call useful to setuid programs.
*/
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;
//如果文件属性具有查询的属性位,则访问许可,返回0
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.
*/
//如果当前用户id为0(超级用户)并且屏蔽码执行位为0或者文件可以被任何人访问,返回0
if ((!current->uid) &&
(!(mode & 1) || (i_mode & 0111)))
return 0;
return -EACCES;
}
int sys_chdir(const char * filename)
{
struct m_inode * inode;
if (!(inode = namei(filename)))
return -ENOENT;
//判断节点是否为目录
if (!S_ISDIR(inode->i_mode)) {
iput(inode);
return -ENOTDIR;
}
//释放当前进程原工作目录
iput(current->pwd);
//设置当前进程工作目录
current->pwd = inode;
return (0);
}
int sys_chroot(const char * filename)
{
struct m_inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
if (!S_ISDIR(inode->i_mode)) {
iput(inode);
return -ENOTDIR;
}
//同上
iput(current->root);
current->root = inode;
return (0);
}
int sys_chmod(const char * filename,int mode)
{
struct m_inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
//如果当前进程的有效用户ID不等于文件节点i的用户id,并且不是当前进程的超级用户,返回错误码
if ((current->euid != inode->i_uid) && !suser()) {
iput(inode);
return -EACCES;
}
//重新设置i节点文件属性
inode->i_mode = (mode & 07777) | (inode->i_mode & ~07777);
inode->i_dirt = 1;
iput(inode);
return 0;
}
int sys_chown(const char * filename,int uid,int gid)
{
struct m_inode * inode;
if (!(inode=namei(filename)))
return -ENOENT;
//不是超级用户就返回
if (!suser()) {
iput(inode);
return -EACCES;
}
//设置用户和组id
inode->i_uid=uid;
inode->i_gid=gid;
inode->i_dirt=1;
iput(inode);
return 0;
}
#define __NR_open 5
//第五个是sys_open函数
fn_ptr sys_call_table[] = { sys_setup, sys_exit, sys_fork, sys_read,
sys_write, sys_open, sys_close, sys_waitpid, sys_creat, sys_link,
sys_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
sys_uname, sys_umask, sys_chroot, sys_ustat, sys_dup2, sys_getppid,
sys_getpgrp, sys_setsid, sys_sigaction, sys_sgetmask, sys_ssetmask,
sys_setreuid,sys_setregid };
int open(const char * filename, int flag, ...)
{
register int res;
va_list arg;
va_start(arg,flag);
__asm__("int $0x80"
//eax存放返回值
:"=a" (res)
//__NR_open系统调用号5
:"0" (__NR_open),"b" (filename),"c" (flag),
"d" (va_arg(arg,int)));
if (res>=0)
return res;
errno = -res;
return -1;
}
int sys_open(const char * filename,int flag,int mode)
{
struct m_inode * inode;
struct file * f;
int i,fd;
mode &= 0777 & ~current->umask;
//在文件结构描述符查找一个空闲的
for(fd=0 ; fdfilp[fd])
break;
if (fd>=NR_OPEN)
return -EINVAL;
//关闭文件句柄位图
current->close_on_exec &= ~(1<f_count) break;
if (i>=NR_FILE)
return -EINVAL;
//文件句柄引用+1
(current->filp[fd]=f)->f_count++;
if ((i=open_namei(filename,flag,mode,&inode))<0) {
current->filp[fd]=NULL;
f->f_count=0;
return i;
}
//特殊设备ttyxx主设备4,tty主设备5
/* ttys are somewhat special (ttyxx major==4, tty major==5) */
//如果是字符设备文件并且设备号为4,则设置当前进程的tty号为该i节点的子设备号
if (S_ISCHR(inode->i_mode)) {
if (MAJOR(inode->i_zone[0])==4) {
//检查当前进程是否是会话的leader,tty<0表示当前进程没有关联任何终端设备
if (current->leader && current->tty<0) {
//设置tty为当前进程的子设备号
current->tty = MINOR(inode->i_zone[0]);
//将终端设备的进程组ID设置为当前进程的组ID
tty_table[current->tty].pgrp = current->pgrp;
}
} else if (MAJOR(inode->i_zone[0])==5)
if (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);
}
int sys_creat(const char * pathname, int mode)
{
return sys_open(pathname, O_CREAT | O_TRUNC, mode);
}
int sys_creat(const char * pathname, int mode)
{
return sys_open(pathname, O_CREAT | O_TRUNC, mode);
}