【场景二】open(pathname, O_PATH)
这个 O_PATH 似乎是不常用的,咱们先看看它的使用说明:
【open(2)】
- O_PATH (since Linux 2.6.39)
- Obtain a file descriptor that can be used for two purposes: to indicate a location in the filesystem tree and to perform operations that act purely at the file descriptor level. The file itself is not opened, and other file operations (e.g., read(2), write(2), fchmod(2), fchown(2), fgetxattr(2), mmap(2)) fail with the error EBADF.
-
- The following operations can be performed on the resulting file descriptor:
-
- * close(2); fchdir(2) (since Linux 3.5); fstat(2) (since Linux 3.6).
-
- * Duplicating the file descriptor (dup(2), fcntl(2) F_DUPFD, etc.).
-
- * Getting and setting file descriptor flags (fcntl(2) F_GETFD and F_SETFD).
-
- * Retrieving open file status flags using the fcntl(2) F_GETFL operation: the returned flags will include the bit O_PATH.
-
- * Passing the file descriptor as the dirfd argument of openat(2) and the other "*at()" system calls. This includes linkat(2) with AT_EMPTY_PATH (or via procfs using AT_SYMLINK_FOLLOW) even if the file is not a directory.
-
- * Passing the file descriptor to another process via a UNIX domain socket (see SCM_RIGHTS in unix(7)).
-
- When O_PATH is specified in flags, flag bits other than O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored.
-
- If pathname is a symbolic link and the O_NOFOLLOW flag is also specified, then the call returns a file descriptor referring to the symbolic link. This file descriptor can be used as the dirfd argument in calls to fchownat(2), fstatat(2), linkat(2), and readlinkat(2) with an empty pathname to have the calls operate on the symbolic link.
咱们还是先看看 build_open_flags 针对 O_PATH 做了什么手脚:
【fs/open.c】sys_open > do_sys_open > build_open_flags
点击(此处)折叠或打开
-
static inline int build_open_flags(int flags, umode_t mode, struct open_flags *op)
- {
...
-
} else if (flags & O_PATH) {
-
/*
-
* If we have O_PATH in the open flag. Then we
-
* cannot have anything other than the below set of flags
-
*/
-
flags &= O_DIRECTORY | O_NOFOLLOW | O_PATH;
-
acc_mode = 0;
- } else {
...
-
op->intent = flags & O_PATH ? 0 : LOOKUP_OPEN;
...
-
if (flags & O_DIRECTORY)
-
lookup_flags |= LOOKUP_DIRECTORY;
-
if (!(flags & O_NOFOLLOW))
-
lookup_flags |= LOOKUP_FOLLOW;
-
op->lookup_flags = lookup_flags;
-
return 0;
- }
【fs/namei.c】sys_open > do_sys_open > do_filp_open > path_openat > do_last
点击(此处)折叠或打开
-
static int do_last(struct nameidata *nd, struct path *path,
-
struct file *file, const struct open_flags *op,
-
int *opened, struct filename *name)
- {
...
-
if (!(open_flag & O_CREAT)) {
-
if (nd->last.name[nd->last.len])
-
nd->flags |= LOOKUP_FOLLOW | LOOKUP_DIRECTORY;
-
if (open_flag & O_PATH && !(nd->flags & LOOKUP_FOLLOW))
- symlink_ok = true;
...
-
}
...
- error = lookup_open(nd, path, file, op, got_write, opened);
...
- if (should_follow_link(path->dentry, !symlink_ok)) {
...
-
return 1;
- }
...
- error = finish_open(file, nd->path.dentry, NULL, opened);
...
- }
接下来 lookup_open 就不用说了吧,当它返回的时候 path 会站上最终目标,nd 则原地不动,它在等待在观望:如果 path 站上的不是符号链接或者即使是符号链接但是“即使是符号链接也 OK 啦”(3003)就会跟着 path 站上最终目标,然后在 finish_open 中完成打开。
finish_open 主要是调用 do_dentry_open,我们进去看看:
【fs/open.c】sys_open > do_sys_open > do_filp_open > path_openat > do_last
点击(此处)折叠或打开
-
static int do_dentry_open(struct file *f,
-
int (*open)(struct inode *, struct file *),
-
const struct cred *cred)
- {
...
-
if (unlikely(f->f_flags & O_PATH)) {
-
f->f_mode = FMODE_PATH;
-
f->f_op = &empty_fops;
-
return 0;
-
}
...
- }
好像这个 O_PATH 情景比上一个 O_RDONLY 还要简单,那我们就再假设一个情景。