diff options
author | Lennart Poettering <lennart@poettering.net> | 2018-03-26 14:15:43 +0200 |
---|---|---|
committer | Sven Eden <yamakuzure@gmx.net> | 2018-08-24 16:47:08 +0200 |
commit | 087bd1d8dd8f3a8b54dfd523873ba85009217d7e (patch) | |
tree | bf24363f80fe9779449b3b4cac3768d77b6eabdb /src/basic/fs-util.c | |
parent | df15bd49b7c870a13f48f78ae7958380ad01f565 (diff) |
fs-util: add calls that combine chase_symlinks() and open()/opendir() in one
This is useful when opening files within disk images, as we'll then take
the relative root directory properly into account.
Diffstat (limited to 'src/basic/fs-util.c')
-rw-r--r-- | src/basic/fs-util.c | 121 |
1 files changed, 96 insertions, 25 deletions
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 8617968c1..d43aca249 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -469,10 +469,8 @@ int get_files_in_directory(const char *path, char ***list) { n++; } - if (list) { - *list = l; - l = NULL; /* avoid freeing */ - } + if (list) + *list = TAKE_PTR(l); return n; } @@ -594,6 +592,10 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) { } #endif // 0 +static bool noop_root(const char *root) { + return isempty(root) || path_equal(root, "/"); +} + static bool safe_transition(const struct stat *a, const struct stat *b) { /* Returns true if the transition from a to b is safe, i.e. that we never transition from unprivileged to * privileged files or directories. Why bother? So that unprivileged code can't symlink to privileged files @@ -644,7 +646,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, * specified path. */ /* A root directory of "/" or "" is identical to none */ - if (isempty(original_root) || path_equal(original_root, "/")) + if (noop_root(original_root)) original_root = NULL; if (original_root) { @@ -749,8 +751,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, } safe_close(fd); - fd = fd_parent; - fd_parent = -1; + fd = TAKE_FD(fd_parent); continue; } @@ -855,10 +856,9 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, } /* If this is not a symlink, then let's just add the name we read to what we already verified. */ - if (!done) { - done = first; - first = NULL; - } else { + if (!done) + done = TAKE_PTR(first); + else { /* If done is "/", as first also contains slash at the head, then remove this redundant slash. */ if (streq(done, "/")) *done = '\0'; @@ -869,8 +869,7 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, /* And iterate again, but go one directory further down. */ safe_close(fd); - fd = child; - child = -1; + fd = TAKE_FD(child); } if (!done) { @@ -880,27 +879,100 @@ int chase_symlinks(const char *path, const char *original_root, unsigned flags, return -ENOMEM; } - if (ret) { - *ret = done; - done = NULL; - } + if (ret) + *ret = TAKE_PTR(done); if (flags & CHASE_OPEN) { - int q; - /* Return the O_PATH fd we currently are looking to the caller. It can translate it to a proper fd by * opening /proc/self/fd/xyz. */ assert(fd >= 0); - q = fd; - fd = -1; - - return q; + return TAKE_FD(fd); } return exists; } +int chase_symlinks_and_open( + const char *path, + const char *root, + unsigned chase_flags, + int open_flags, + char **ret_path) { + + _cleanup_close_ int path_fd = -1; + _cleanup_free_ char *p = NULL; + int r; + + if (chase_flags & CHASE_NONEXISTENT) + return -EINVAL; + + if (noop_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) { + /* Shortcut this call if none of the special features of this call are requested */ + r = open(path, open_flags); + if (r < 0) + return -errno; + + return r; + } + + path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); + if (path_fd < 0) + return path_fd; + + r = fd_reopen(path_fd, open_flags); + if (r < 0) + return r; + + if (ret_path) + *ret_path = TAKE_PTR(p); + + return r; +} + +int chase_symlinks_and_opendir( + const char *path, + const char *root, + unsigned chase_flags, + char **ret_path, + DIR **ret_dir) { + + char procfs_path[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(int)]; + _cleanup_close_ int path_fd = -1; + _cleanup_free_ char *p = NULL; + DIR *d; + + if (!ret_dir) + return -EINVAL; + if (chase_flags & CHASE_NONEXISTENT) + return -EINVAL; + + if (noop_root(root) && !ret_path && (chase_flags & (CHASE_NO_AUTOFS|CHASE_SAFE)) == 0) { + /* Shortcut this call if none of the special features of this call are requested */ + d = opendir(path); + if (!d) + return -errno; + + *ret_dir = d; + return 0; + } + + path_fd = chase_symlinks(path, root, chase_flags|CHASE_OPEN, ret_path ? &p : NULL); + if (path_fd < 0) + return path_fd; + + xsprintf(procfs_path, "/proc/self/fd/%i", path_fd); + d = opendir(procfs_path); + if (!d) + return -errno; + + if (ret_path) + *ret_path = TAKE_PTR(p); + + *ret_dir = d; + return 0; +} + int access_fd(int fd, int mode) { char p[STRLEN("/proc/self/fd/") + DECIMAL_STR_MAX(fd) + 1]; int r; @@ -908,10 +980,9 @@ int access_fd(int fd, int mode) { /* Like access() but operates on an already open fd */ xsprintf(p, "/proc/self/fd/%i", fd); - r = access(p, mode); if (r < 0) - r = -errno; + return -errno; return r; } |