diff options
Diffstat (limited to 'src/libnm-systemd-shared/src/basic/path-util.c')
-rw-r--r-- | src/libnm-systemd-shared/src/basic/path-util.c | 94 |
1 files changed, 64 insertions, 30 deletions
diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c index a2af9e0ce2..638e4860a6 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.c +++ b/src/libnm-systemd-shared/src/basic/path-util.c @@ -43,7 +43,7 @@ int path_split_and_make_absolute(const char *p, char ***ret) { return r; } -char *path_make_absolute(const char *p, const char *prefix) { +char* path_make_absolute(const char *p, const char *prefix) { assert(p); /* Makes every item in the list an absolute path by prepending @@ -135,11 +135,9 @@ int path_make_relative(const char *from, const char *to, char **ret) { return -ENOMEM; } else { /* 'to' is inside of 'from'. */ - result = strdup(t); - if (!result) - return -ENOMEM; - - path_simplify(result); + r = path_simplify_alloc(t, &result); + if (r < 0) + return r; if (!path_is_valid(result)) return -EINVAL; @@ -255,7 +253,7 @@ int path_strv_make_absolute_cwd(char **l) { return 0; } -char **path_strv_resolve(char **l, const char *root) { +char** path_strv_resolve(char **l, const char *root) { unsigned k = 0; bool enomem = false; int r; @@ -336,7 +334,7 @@ char **path_strv_resolve(char **l, const char *root) { return l; } -char **path_strv_resolve_uniq(char **l, const char *root) { +char** path_strv_resolve_uniq(char **l, const char *root) { if (strv_isempty(l)) return l; @@ -348,9 +346,9 @@ char **path_strv_resolve_uniq(char **l, const char *root) { } #endif /* NM_IGNORED */ -char *path_simplify(char *path) { - bool add_slash = false; - char *f = ASSERT_PTR(path); +char* path_simplify_full(char *path, PathSimplifyFlags flags) { + bool add_slash = false, keep_trailing_slash, absolute, beginning = true; + char *f = path; int r; /* Removes redundant inner and trailing slashes. Also removes unnecessary dots. @@ -358,13 +356,17 @@ char *path_simplify(char *path) { * * ///foo//./bar/. becomes /foo/bar * .//./foo//./bar/. becomes foo/bar + * /../foo/bar becomes /foo/bar + * /../foo/bar/.. becomes /foo/bar/.. */ if (isempty(path)) return path; - if (path_is_absolute(path)) - f++; + keep_trailing_slash = FLAGS_SET(flags, PATH_SIMPLIFY_KEEP_TRAILING_SLASH) && endswith(path, "/"); + + absolute = path_is_absolute(path); + f += absolute; /* Keep leading /, if present. */ for (const char *p = f;;) { const char *e; @@ -373,11 +375,17 @@ char *path_simplify(char *path) { if (r == 0) break; + if (r > 0 && absolute && beginning && path_startswith(e, "..")) + /* If we're at the beginning of an absolute path, we can safely skip ".." */ + continue; + + beginning = false; + if (add_slash) *f++ = '/'; if (r < 0) { - /* if path is invalid, then refuse to simplify remaining part. */ + /* if path is invalid, then refuse to simplify the remaining part. */ memmove(f, p, strlen(p) + 1); return path; } @@ -392,11 +400,14 @@ char *path_simplify(char *path) { if (f == path) *f++ = '.'; + if (*(f-1) != '/' && keep_trailing_slash) + *f++ = '/'; + *f = '\0'; return path; } -char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) { +char* path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) { assert(path); assert(prefix); @@ -489,10 +500,6 @@ int path_compare(const char *a, const char *b) { } } -bool path_equal_or_inode_same(const char *a, const char *b, int flags) { - return path_equal(a, b) || inode_same(a, b, flags) > 0; -} - int path_compare_filename(const char *a, const char *b) { _cleanup_free_ char *fa = NULL, *fb = NULL; int r, j, k; @@ -661,7 +668,14 @@ static int find_executable_impl(const char *name, const char *root, char **ret_f return 0; } -int find_executable_full(const char *name, const char *root, char **exec_search_path, bool use_path_envvar, char **ret_filename, int *ret_fd) { +int find_executable_full( + const char *name, + const char *root, + char **exec_search_path, + bool use_path_envvar, + char **ret_filename, + int *ret_fd) { + int last_error = -ENOENT, r = 0; const char *p = NULL; @@ -812,7 +826,7 @@ int fsck_exists_for_fstype(const char *fstype) { } #endif /* NM_IGNORED */ -static const char *skip_slash_or_dot(const char *p) { +static const char* skip_slash_or_dot(const char *p) { for (; !isempty(p); p++) { if (*p == '/') continue; @@ -896,7 +910,7 @@ int path_find_first_component(const char **p, bool accept_dot_dot, const char ** return len; } -static const char *skip_slash_or_dot_backward(const char *path, const char *q) { +static const char* skip_slash_or_dot_backward(const char *path, const char *q) { assert(path); assert(!q || q >= path); @@ -1005,7 +1019,7 @@ int path_find_last_component(const char *path, bool accept_dot_dot, const char * return len; } -const char *last_path_component(const char *path) { +const char* last_path_component(const char *path) { /* Finds the last component of the path, preserving the optional trailing slash that signifies a directory. * @@ -1126,17 +1140,19 @@ int path_extract_directory(const char *path, char **ret) { if (!path_is_valid(a)) return -EINVAL; - *ret = TAKE_PTR(a); + if (ret) + *ret = TAKE_PTR(a); + return 0; } -bool filename_is_valid(const char *p) { +bool filename_part_is_valid(const char *p) { const char *e; - if (isempty(p)) - return false; + /* Checks f the specified string is OK to be *part* of a filename. This is different from + * filename_is_valid() as "." and ".." and "" are OK by this call, but not by filename_is_valid(). */ - if (dot_or_dot_dot(p)) /* Yes, in this context we consider "." and ".." invalid */ + if (!p) return false; e = strchrnul(p, '/'); @@ -1149,6 +1165,17 @@ bool filename_is_valid(const char *p) { return true; } +bool filename_is_valid(const char *p) { + + if (isempty(p)) + return false; + + if (dot_or_dot_dot(p)) /* Yes, in this context we consider "." and ".." invalid */ + return false; + + return filename_part_is_valid(p); +} + bool path_is_valid_full(const char *p, bool accept_dot_dot) { if (isempty(p)) return false; @@ -1265,9 +1292,16 @@ bool hidden_or_backup_file(const char *filename) { bool is_device_path(const char *path) { /* Returns true for paths that likely refer to a device, either by path in sysfs or to something in - * /dev. */ + * /dev. This accepts any path that starts with /dev/ or /sys/ and has something after that prefix. + * It does not actually resolve the path. + * + * Examples: + * /dev/sda, /dev/sda/foo, /sys/class, /dev/.., /sys/.., /./dev/foo → yes. + * /../dev/sda, /dev, /sys, /usr/path, /usr/../dev/sda → no. + */ - return PATH_STARTSWITH_SET(path, "/dev/", "/sys/"); + const char *p = PATH_STARTSWITH_SET(ASSERT_PTR(path), "/dev/", "/sys/"); + return !isempty(p); } bool valid_device_node_path(const char *path) { |