|
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的数据结构来描述文件相关的操作数据。
struct nameidata {
struct dentry *dentry; // 目录数据
struct vfsmount *mnt; // 虚拟文件挂载点数据
struct qstr last; // hash值
unsigned int flags; // 文件操作标识
int last_type; // 类型
unsigned depth;
char *saved_names[MAX_NESTED_LINKS + 1];
union {
struct open_intent open;
} intent; // 专用数据
};
struct file *filp_open(const char * filename, int flags, int mode){
int namei_flags, error;
struct nameidata nd;
namei_flags = flags;
if ((namei_flags+1) & O_ACCMODE)
namei_flags++; // 如果flags有O_WRONLY,则增加O_RDONLY
if (namei_flags & O_TRUNC)
namei_flags |= 2; // 如果有O_TRUNC,则增加O_RDWR
error = open_namei(filename, namei_flags, mode, &nd); // 如3.2.3.1 描述
if (!error)
return dentry_open(nd.dentry, nd.mnt, flags); // 如3.2.3.2描述
return ERR_PTR(error); // 返回错误代码
}
|
4.2.4.1.filp_open子函数open_namei
open_namei函数主要执行文件操作的inode部分的打开等操作。
int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd){
int acc_mode, error = 0;
struct dentry *dentry;
struct dentry *dir;
int count = 0;
acc_mode = ACC_MODE(flag); // 取出低2位操作标识
if (flag & O_APPEND) // 取出O_APPEND操作标识
acc_mode |= MAY_APPEND;
//赋值open函数的专用数据
nd->;intent.open.flags = flag;
nd->;intent.open.create_mode = mode;
// 如果不需要创建文件,则在进程目录文件表搜索已有文件,并把结果拷贝到nd中
if (!(flag & O_CREAT)) {
error = path_lookup(pathname, lookup_flags(flag)|LOOKUP_OPEN, nd);
if (error) // 错误代码有ENOENT,ENOTDIR,EAGAIN,ESTALE,
return error;
goto ok; // 否则执行打开函数,更新inode数据
}
// 在进程文件表中搜索该文件,如果不存在,则创建,结果由nd保存
error = path_lookup(pathname, LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, nd);
if (error)
return error;
// 检测nd的结果是否是一个目录文件,是则返回
error = -EISDIR;
if (nd->;last_type != LAST_NORM || nd->;last.name[nd->;last.len])
goto exit;
// 获取文件的相关目录数据,结果返回到dentry中。
dir = nd->;dentry;
nd->;flags &= ~LOOKUP_PARENT;
down(&dir->;d_inode->;i_sem);
dentry = __lookup_hash(&nd->;last, nd->;dentry, nd);
do_last:
// 如果dentry是一个错误值,则返回
error = PTR_ERR(dentry);
if (IS_ERR(dentry)) {
up(&dir->;d_inode->;i_sem);
goto exit;
}
// 如果dentry不存在,则创建他
if (!dentry->;d_inode) {
if (!IS_POSIXACL(dir->;d_inode))
mode &= ~current->;fs->;umask;
error = vfs_create(dir->;d_inode, dentry, mode, nd); // 创建inode
up(&dir->;d_inode->;i_sem);
dput(nd->;dentry);
nd->;dentry = dentry;
if (error)
goto exit;
acc_mode = 0;
flag &= ~O_TRUNC;
goto ok;
}
up(&dir->;d_inode->;i_sem);
error = -EEXIST; // 如果指定了O_EXCL和O_CREAT,文件存在时,出错
if (flag & O_EXCL)
goto exit_dput;
if (d_mountpoint(dentry)) { // 检测文件是否是连接文件
error = -ELOOP;
if (flag & O_NOFOLLOW) // 如果指定不遍历连接文件,则返回
goto exit_dput;
// 检测dentry挂载点
while (__follow_down(&nd->;mnt,&dentry) && d_mountpoint(dentry));
}
error = -ENOENT;
if (!dentry->;d_inode) // inode 不存在,则返回
goto exit_dput;
if (dentry->;d_inode->;i_op && dentry->;d_inode->;i_op->;follow_link)
goto do_link; // 允许遍历连接文件,则手工找到连接文件对应的文件
// 把处理后的dentry复制到nd结构中,并判断其是否是目录,是则返回错误
dput(nd->;dentry);
nd->;dentry = dentry;
error = -EISDIR;
if (dentry->;d_inode && S_ISDIR(dentry->;d_inode->;i_mode))
goto exit;
ok:
error = may_open(nd, acc_mode, flag); // 打开文件,返回处理结果代码。如3.2.3.1.1描述
if (error)
goto exit;
return 0;
exit_dput:
dput(dentry); // 释放dentry
exit:
path_release(nd); // 释放nd结构
return error; // 返回错误代码
do_link:
error = -ELOOP;
if (flag & O_NOFOLLOW)
goto exit_dput; // 不允许遍历连接文件,则返回错误
// 以下代码是手工找到连接文件对应的文件dentry数据
nd->;flags |= LOOKUP_PARENT;
error = security_inode_follow_link(dentry, nd);
if (error)
goto exit_dput;
error = __do_follow_link(dentry, nd);
dput(dentry);
if (error)
return error;
nd->;flags &= ~LOOKUP_PARENT;
if (nd->;last_type == LAST_BIND) {
dentry = nd->;dentry;
goto ok;
}
error = -EISDIR;
if (nd->;last_type != LAST_NORM)
goto exit;
if (nd->;last.name[nd->;last.len]) {
putname(nd->;last.name);
goto exit;
}
error = -ELOOP;
if (count++==32) {
putname(nd->;last.name);
goto exit;
}
dir = nd->;dentry;
down(&dir->;d_inode->;i_sem);
dentry = __lookup_hash(&nd->;last, nd->;dentry, nd);
putname(nd->;last.name);
goto do_last;
}
|
共6页: 上一页 [1] [2] 3 [4] [5] [6] 下一页
|