X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=elogind.git;a=blobdiff_plain;f=src%2Fbasic%2Ffs-util.c;h=eefdbb52d84243c9f6c3d4a091d4a88df2e621c2;hp=b97edb552c067c7b10b0c805e3aa7ccd8e2efad1;hb=a485a218fb4fc1baa0b279314b737ea0e36aa397;hpb=7b987da65ad4eacb30034519653a61457b688352
diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c
index b97edb552..eefdbb52d 100644
--- a/src/basic/fs-util.c
+++ b/src/basic/fs-util.c
@@ -17,7 +17,6 @@
along with systemd; If not, see .
***/
-#include
#include
#include
#include
@@ -38,6 +37,7 @@
#include "mkdir.h"
#include "parse-util.h"
#include "path-util.h"
+#include "stat-util.h"
#include "string-util.h"
#include "strv.h"
//#include "time-util.h"
@@ -236,7 +236,7 @@ int readlink_and_canonicalize(const char *p, const char *root, char **ret) {
if (r < 0)
return r;
- r = chase_symlinks(t, root, &s);
+ r = chase_symlinks(t, root, 0, &s);
if (r < 0)
/* If we can't follow up, then let's return the original string, slightly cleaned up. */
*ret = path_kill_slashes(t);
@@ -450,6 +450,7 @@ int mkfifo_atomic(const char *path, mode_t mode) {
int get_files_in_directory(const char *path, char ***list) {
_cleanup_closedir_ DIR *d = NULL;
+ struct dirent *de;
size_t bufsize = 0, n = 0;
_cleanup_strv_free_ char **l = NULL;
@@ -463,16 +464,7 @@ int get_files_in_directory(const char *path, char ***list) {
if (!d)
return -errno;
- for (;;) {
- struct dirent *de;
-
- errno = 0;
- de = readdir(d);
- if (!de && errno > 0)
- return -errno;
- if (!de)
- break;
-
+ FOREACH_DIRENT_ALL(de, d, return -errno) {
dirent_ensure_type(d, de);
if (!dirent_is_file(de))
@@ -500,7 +492,6 @@ int get_files_in_directory(const char *path, char ***list) {
return n;
}
-#if 0 /// UNNEEDED by elogind
static int getenv_tmp_dir(const char **ret_path) {
const char *n;
int r, ret = 0;
@@ -571,6 +562,7 @@ static int tmp_dir_internal(const char *def, const char **ret) {
return 0;
}
+#if 0 /// UNNEEDED by elogind
int var_tmp_dir(const char **ret) {
/* Returns the location for "larger" temporary files, that is backed by physical storage if available, and thus
@@ -580,6 +572,7 @@ int var_tmp_dir(const char **ret) {
return tmp_dir_internal("/var/tmp", ret);
}
+#endif // 0
int tmp_dir(const char **ret) {
@@ -589,6 +582,7 @@ int tmp_dir(const char **ret) {
return tmp_dir_internal("/tmp", ret);
}
+#if 0 /// UNNEEDED by elogind
int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
char path[strlen("/proc/self/fd/") + DECIMAL_STR_MAX(int) + 1];
int r;
@@ -602,11 +596,13 @@ int inotify_add_watch_fd(int fd, int what, uint32_t mask) {
return r;
}
+#endif // 0
-int chase_symlinks(const char *path, const char *_root, char **ret) {
+int chase_symlinks(const char *path, const char *original_root, unsigned flags, char **ret) {
_cleanup_free_ char *buffer = NULL, *done = NULL, *root = NULL;
_cleanup_close_ int fd = -1;
unsigned max_follow = 32; /* how many symlinks to follow before giving up and returning ELOOP */
+ bool exists = true;
char *todo;
int r;
@@ -616,8 +612,9 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
* symlinks relative to a root directory, instead of the root of the host.
*
* 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. The path parameter passed
- * shall *not* be prefixed by it.
+ * relative symlinks to ensure they cannot be used to "escape" the root directory. The path parameter passed is
+ * assumed to be already prefixed by it, except if the CHASE_PREFIX_ROOT flag is set, in which case it is first
+ * prefixed accordingly.
*
* 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
@@ -634,16 +631,19 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
* 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)
- return r;
-
- if (_root) {
- r = path_make_absolute_cwd(_root, &root);
+ if (original_root) {
+ r = path_make_absolute_cwd(original_root, &root);
if (r < 0)
return r;
+
+ if (flags & CHASE_PREFIX_ROOT)
+ path = prefix_roota(root, path);
}
+ r = path_make_absolute_cwd(path, &buffer);
+ if (r < 0)
+ return r;
+
fd = open("/", O_CLOEXEC|O_NOFOLLOW|O_PATH);
if (fd < 0)
return -errno;
@@ -708,13 +708,32 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
/* Otherwise let's see what this is. */
child = openat(fd, first + n, O_CLOEXEC|O_NOFOLLOW|O_PATH);
- if (child < 0)
+ if (child < 0) {
+
+ if (errno == ENOENT &&
+ (flags & CHASE_NONEXISTENT) &&
+ (isempty(todo) || path_is_safe(todo))) {
+
+ /* If CHASE_NONEXISTENT is set, and the path does not exist, then that's OK, return
+ * what we got so far. But don't allow this if the remaining path contains "../ or "./"
+ * or something else weird. */
+
+ if (!strextend(&done, first, todo, NULL))
+ return -ENOMEM;
+
+ exists = false;
+ break;
+ }
+
return -errno;
+ }
if (fstat(child, &st) < 0)
return -errno;
if (S_ISLNK(st.st_mode)) {
+ char *joined;
+
_cleanup_free_ char *destination = NULL;
/* This is a symlink, in this case read the destination. But let's make sure we don't follow
@@ -738,9 +757,6 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
if (fd < 0)
return -errno;
- free_and_replace(buffer, destination);
-
- todo = buffer;
free(done);
/* Note that we do not revalidate the root, we take it as is. */
@@ -752,19 +768,17 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
return -ENOMEM;
}
- } else {
- char *joined;
+ }
- /* A relative destination. If so, this is what we'll prefix what's left to do with what
- * we just read, and start the loop again, but remain in the current directory. */
+ /* Prefix what's left to do with what we just read, and start the loop again,
+ * but remain in the current directory. */
- joined = strjoin("/", destination, todo);
- if (!joined)
- return -ENOMEM;
+ joined = strjoin("/", destination, todo);
+ if (!joined)
+ return -ENOMEM;
- free(buffer);
- todo = buffer = joined;
- }
+ free(buffer);
+ todo = buffer = joined;
continue;
}
@@ -791,19 +805,10 @@ int chase_symlinks(const char *path, const char *_root, char **ret) {
return -ENOMEM;
}
- *ret = done;
- done = NULL;
-
- 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);
+ if (ret) {
+ *ret = done;
+ done = NULL;
+ }
- return chase_symlinks(t, root, ret);
+ return exists;
}