chiark / gitweb /
fs-util: add chase_symlinks_prefix() and extend comments
authorLennart Poettering <lennart@poettering.net>
Fri, 25 Nov 2016 17:59:39 +0000 (18:59 +0100)
committerSven Eden <yamakuzure@gmx.net>
Mon, 17 Jul 2017 15:58:35 +0000 (17:58 +0200)
chase_symlinks() currently expects a fully qualified, absolute path, relative
to the host's root as first argument. Which is useful in many ways, and similar
to the paths unlink(), rename(), open(), … expect. Sometimes it's however
useful to first prefix the specified path with the specified root directory.
Add a new call chase_symlinks_prefix() for this, that is a simple wrapper.

src/basic/fs-util.c
src/basic/fs-util.h

index 0d96302bef5c5d9979da838b6a038718d104d664..39f840581aae92459aa22c3d505c69a53a5f21b3 100644 (file)
@@ -615,15 +615,24 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
         /* This is a lot like canonicalize_file_name(), but takes an additional "root" parameter, that allows following
          * symlinks relative to a root directory, instead of the root of the host.
          *
-         * Note that "root" matters only if we encounter an absolute symlink, it's unused otherwise. Most importantly
-         * this means the path parameter passed in is not prefixed by it.
+         * Note that "root" primarily matters if we encounter an absolute symlink. It is also used when following
+         * relative symlinks to ensure they cannot be used to "escape" the root directory. (For cases where this is
+         * attempted -EINVAL is returned.). The path parameter passed shall *not* be prefixed by it.
          *
          * Algorithmically this operates on two path buffers: "done" are the components of the path we already
          * processed and resolved symlinks, "." and ".." of. "todo" are the components of the path we still need to
          * process. On each iteration, we move one component from "todo" to "done", processing it's special meaning
          * each time. The "todo" path always starts with at least one slash, the "done" path always ends in no
          * slash. We always keep an O_PATH fd to the component we are currently processing, thus keeping lookup races
-         * at a minimum. */
+         * at a minimum.
+         *
+         * Suggested usage: whenever you want to canonicalize a path, use this function. Pass the absolute path you got
+         * as-is: fully qualified and relative to your host's root. Optionally, specify the root parameter to tell this
+         * function what to do when encountering a symlink with an absolute path as directory: prefix it by the
+         * specified path.
+         *
+         * Note: there's also chase_symlinks_prefix() (see below), which as first step prefixes the passed path by the
+         * passed root. */
 
         r = path_make_absolute_cwd(path, &buffer);
         if (r < 0)
@@ -786,3 +795,13 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
         return 0;
 }
 #endif // 0
+
+int chase_symlinks_prefix(const char *path, const char *root, char **ret) {
+        const char *t;
+
+        /* Same as chase_symlinks(), but prefixes 'path' by 'root' first. */
+
+        t = prefix_roota(root, path);
+
+        return chase_symlinks(t, root, ret);
+}
index de4bb861eab7ea574ba5713b6003f6b37473e2e7..d58b14801ba23c5f8520d2287536724167f0ea90 100644 (file)
@@ -90,5 +90,6 @@ union inotify_event_buffer {
 
 int inotify_add_watch_fd(int fd, int what, uint32_t mask);
 
-int chase_symlinks(const char *path, const char *_root, char **ret);
 #endif // 0
+int chase_symlinks(const char *path_with_prefix, const char *root, char **ret);
+int chase_symlinks_prefix(const char *path_without_prefix, const char *root, char **ret);