summaryrefslogtreecommitdiff
path: root/src/libnm-systemd-shared/src/basic/path-util.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-systemd-shared/src/basic/path-util.c')
-rw-r--r--src/libnm-systemd-shared/src/basic/path-util.c94
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) {