|
4.2.4.1.1.filp_open子函数may_open
may_open执行权限检测和文件打开,和truncate的操作。
int may_open(struct nameidata *nd, int acc_mode, int flag){
struct dentry *dentry = nd->;dentry;
struct inode *inode = dentry->;d_inode;
int error;
if (!inode) return -ENOENT; // inode为空,则返回错误
if (S_ISLNK(inode->;i_mode)) // 连接文件,返回错误
return -ELOOP;
if (S_ISDIR(inode->;i_mode) && (flag & FMODE_WRITE))
return -EISDIR; // 是目录且仅有写权限,返回错误
error = permission(inode, acc_mode, nd); // 见擦inode的accmode
if (error)
return error;
if (S_ISFIFO(inode->;i_mode) || S_ISSOCK(inode->;i_mode)) {
flag &= ~O_TRUNC; // 如果是FIFO文件,则不允许truncate
} else if (S_ISBLK(inode->;i_mode) || S_ISCHR(inode->;i_mode)) {
if (nd->;mnt->;mnt_flags & MNT_NODEV)
return -EACCES; // 如果是设备,则不允许truncate,否则返回错误
flag &= ~O_TRUNC;
} else if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
return -EROFS; 如果flag标识和inode权限冲突,则返回错误
// 如果inode只允许append方式写入,则不允许truncate和非append写入方式。
if (IS_APPEND(inode)) {
if ((flag & FMODE_WRITE) && !(flag & O_APPEND))
return -EPERM;
if (flag & O_TRUNC)
return -EPERM;
}
// O_NOATIME方式仅在inode用户是文件拥有者或者超级用户情况下才被允许
if (flag & O_NOATIME)
if (current->;fsuid != inode->;i_uid && !capable(CAP_FOWNER))
return -EPERM;
// 检查是否有其他进程在使用该文件
error = break_lease(inode, flag);
if (error)
return error;
if (flag & O_TRUNC) {
error = get_write_access(inode); // 获取一次inode写操作权限
if (error)
return error;
// 锁定inode
error = locks_verify_locked(inode);
if (!error) {
DQUOT_INIT(inode); // 对inode执行配额初始化
error = do_truncate(dentry, 0); // truncate dentry
}
put_write_access(inode); // 释放当前写操作权限
if (error)
return error;
} else
if (flag & FMODE_WRITE) // 如果有写标识,则对inode执行配额初始化
DQUOT_INIT(inode);
return 0;
}
|
4.2.4.2.open_namei子函数dentry_open
dentry_open函数主要实现文件表的对应打开等操作,返回文件指针。
struct file *dentry_open(struct dentry *dentry, struct vfsmount *mnt, int flags){
struct file * f;
struct inode *inode;
int error;
error = -ENFILE;
f = get_empty_filp(); // 从进程文件表中获取一个未使用的文件结构指针,空则出错返回
if (!f)
goto cleanup_dentry;
// 设置文件的flags和mode标识
f->;f_flags = flags;
f->;f_mode = ((flags+1) & O_ACCMODE) | FMODE_LSEEK | FMODE_PREAD | FMODE_PWRITE;
inode = dentry->;d_inode;
if (f->;f_mode & FMODE_WRITE) {
error = get_write_access(inode); // 获取一次inode写操作权限
if (error)
goto cleanup_file;
}
// 初始化文件结构
f->;f_mapping = inode->;i_mapping;
f->;f_dentry = dentry;
f->;f_vfsmnt = mnt;
f->;f_pos = 0;
f->;f_op = fops_get(inode->;i_fop);
file_move(f, &inode->;i_sb->;s_files);
// 调用文件驱动模块初始化物理磁盘
if (f->;f_op && f->;f_op->;open) {
error = f->;f_op->;open(inode,f);
if (error)
goto cleanup_all;
}
f->;f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC);
// 初始化上次读取状态
file_ra_state_init(&f->;f_ra, f->;f_mapping->;host->;i_mapping);
// 如果设置了O_DIRECT,则检测文件结构中是否有驱动的操作函数指针
if (f->;f_flags & O_DIRECT) {
if (!f->;f_mapping->;a_ops || !f->;f_mapping->;a_ops->;direct_IO) {
fput(f);
f = ERR_PTR(-EINVAL);
}
}
return f; // 返回文件结构
cleanup_all: // 出错,则释放资源并返回
fops_put(f->;f_op);
if (f->;f_mode & FMODE_WRITE)
put_write_access(inode);
file_kill(f);
f->;f_dentry = NULL;
f->;f_vfsmnt = NULL;
cleanup_file:
put_filp(f);
cleanup_dentry:
dput(dentry);
mntput(mnt);
return ERR_PTR(error);
}
|
共6页: 上一页 [1] [2] [3] 4 [5] [6] 下一页
|