| 个空闲的文件表指针,如果出错,则返回
fd = get_unused_fd();
if (fd >;= 0) {
// 执行打开操作。见3.2.3说明
struct file *f = filp_open(tmp, flags, mode);
// 获取返回结果,如果出错,则跳转至out_error,否则执行fd_install
error = PTR_ERR(f);
if (IS_ERR(f))
goto out_error;
// 添加打开的文件表 f 到当前进程的文件表队列中。见3.2.4说明
fd_install(fd, f);
}
out:
// 释放getname分配的内存空间
putname(tmp);
}
return fd;
out_error:
// 将文件表指针返回到进程的文件表中,并返回错误代码。
put_unused_fd(fd);
fd = error;
goto out;
}
上一页 [1] [2] [3] [4] [5] [6] [7] 下一页
4.2.3.sys_open子函数getname
getname函数主要功能是在使用文件名之前将其拷贝到内核数据区,正常结束时返回内核分配的空间首地址,出错时返回错误代码。其调用了函数do_getname来实现。
static inline int do_getname(const char __user *filename, char *page){
int retval;
unsigned long len = PATH_MAX; // 内核允许的最大路径长度
// 如果进程的地址限制是否和KERNEL_DS相等,则检查文件名是否小于用户进程空间
if (!segment_eq(get_fs(), KERNEL_DS)) {
// 文件名地址大于用户进程空间,则返回错误-EFAULT
if ((unsigned long) filename >;= TASK_SIZE)
return -EFAULT;
// 获取较小的地址长度
if (TASK_SIZE - (unsigned long) filename < PATH_MAX)
len = TASK_SIZE - (unsigned long) filename;
}
// 将filename拷贝len长度到page中,返回实际拷贝长度
retval = strncpy_from_user(page, filename, len);
if (retval >; 0) {
// 如果retval大于等于len,则返回-ENAMETOOLONG
if (retval < len)
return 0;
return -ENAMETOOLONG;
} else if (!retval)
// filename 为空,则返回-ENOENT
retval = -ENOENT;
return retval;
}
char * getname(const char __user * filename){
char *tmp, *result;
result = ERR_PTR(-ENOMEM);
// 从内核缓存中分配空间,如果成功,则执行do_getname
tmp = __getname();
if (tmp) {
// 执行文件名拷贝操作
int retval = do_getname(filename, tmp);
result = tmp;
if (retval < 0) {
// do_getname出错,则释放空间,并返回错误代码
__putname(tmp);
result = ERR_PTR(retval);
}
}
// 如果前面操作成功,且audit_context不为空,则将当前文件名添加到audit列表中
if (unlikely(current->;audit_context) && !IS_ERR(result) && result)
audit_getname(result);
// 返回处理结果
return result;
}
4.2.4.sys_open子函数filp_open
这后面的函数使用了一个nameidata的数据结构来描述文件相关 上一页 [1] [2] [3] [4] [5] [6] [7] [8] [9] 下一页
|