Linux0.11内核源码解析-open.c

目录

概述

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()

代码里都做了详细的解释

m_inode节点介绍

这是一个用于表示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;
};

fs/sys_utime设置文件访问和修改时间

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 *) &times->actime);
		modtime = get_fs_long((unsigned long *) &times->modtime);
	} else
		actime = modtime = CURRENT_TIME;
	inode->i_atime = actime;
	inode->i_mtime = modtime;
    //设置修改标志位,释放inode节点
	inode->i_dirt = 1;
	iput(inode);
	return 0;
}

fs/sys_access检查访问权限

/*
 * 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;
}

fs/sys_chdir改变当前工作目录

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);
}

fs/sys_chroot改变根目录

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);
}

fs/sys_chmod修改文件属性

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;
}

fs/sys_chown修改文件宿主

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;
}

lib/open用户层文件打开函数,调用sys_open

#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;
}

fs/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;
    //在文件结构描述符查找一个空闲的
	for(fd=0 ; fd<NR_OPEN ; 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;
    //文件句柄引用+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);
}

fs/sys_create创建文件

int sys_creat(const char * pathname, int mode)
{
	return sys_open(pathname, O_CREAT | O_TRUNC, mode);
}

fs/sys_close关闭文件

int sys_creat(const char * pathname, int mode)
{
	return sys_open(pathname, O_CREAT | O_TRUNC, mode);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值