From: Lennart Poettering Date: Fri, 25 Nov 2016 17:59:39 +0000 (+0100) Subject: fs-util: add chase_symlinks_prefix() and extend comments X-Git-Tag: v233.3~146 X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=commitdiff_plain;h=5de3db0016e2a97b779abe27be5e7326ec1b78aa fs-util: add chase_symlinks_prefix() and extend comments 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. --- diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 0d96302be..39f840581 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -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); +} diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index de4bb861e..d58b14801 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -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);