return path + k;
}
-int path_extract_filename(const char *p, char **ret) {
+int path_extract_filename(const char *path, char **ret) {
_cleanup_free_ char *a = NULL;
- const char *c;
- size_t n;
+ const char *c, *next = NULL;
+ int r;
/* Extracts the filename part (i.e. right-most component) from a path, i.e. string that passes
* filename_is_valid(). A wrapper around last_path_component(), but eats up trailing
* slashes. Returns:
*
- * -EINVAL → if the passed in path is not a valid path
- * -EADDRNOTAVAIL → if only a directory was specified, but no filename, i.e. the root dir itself is specified
+ * -EINVAL → if the path is not valid
+ * -EADDRNOTAVAIL → if only a directory was specified, but no filename, i.e. the root dir
+ * itself or "." is specified
* -ENOMEM → no memory
*
- * Returns >= 0 on success. If the input path has a trailing slash, returns O_DIRECTORY, to indicate
- * the referenced file must be a directory.
+ * Returns >= 0 on success. If the input path has a trailing slash, returns O_DIRECTORY, to
+ * indicate the referenced file must be a directory.
*
* This function guarantees to return a fully valid filename, i.e. one that passes
* filename_is_valid() – this means "." and ".." are not accepted. */
- if (!path_is_valid(p))
+ if (!path_is_valid(path))
return -EINVAL;
- /* Special case the root dir, because in that case we simply have no filename, but
- * last_path_component() won't complain */
- if (path_equal(p, "/"))
+ r = path_find_last_component(path, false, &next, &c);
+ if (r < 0)
+ return r;
+ if (r == 0) /* root directory */
return -EADDRNOTAVAIL;
- c = last_path_component(p);
- n = strcspn(c, "/");
-
- a = strndup(c, n);
+ a = strndup(c, r);
if (!a)
return -ENOMEM;
- if (!filename_is_valid(a))
- return -EINVAL;
-
*ret = TAKE_PTR(a);
- return c[n] == '/' ? O_DIRECTORY : 0;
+ return strlen(c) > (size_t)r ? O_DIRECTORY : 0;
}
-int path_extract_directory(const char *p, char **ret) {
+int path_extract_directory(const char *path, char **ret) {
_cleanup_free_ char *a = NULL;
- const char *c;
+ const char *c, *next = NULL;
+ int r;
/* The inverse of path_extract_filename(), i.e. returns the directory path prefix. Returns:
*
- * -EINVAL → if the passed in path is not a valid path
+ * -EINVAL → if the path is not valid
* -EDESTADDRREQ → if no directory was specified in the passed in path, i.e. only a filename was passed
- * -EADDRNOTAVAIL → if the passed in parameter had no filename but did have a directory, i.e. the root dir itself was specified
+ * -EADDRNOTAVAIL → if the passed in parameter had no filename but did have a directory, i.e.
+ * the root dir itself or "." was specified
* -ENOMEM → no memory (surprise!)
*
* This function guarantees to return a fully valid path, i.e. one that passes path_is_valid().
*/
- if (!path_is_valid(p))
- return -EINVAL;
-
- /* Special case the root dir, because otherwise for an input of "///" last_path_component() returns
- * the pointer to the last slash only, which might be seen as a valid path below. */
- if (path_equal(p, "/"))
- return -EADDRNOTAVAIL;
-
- c = last_path_component(p);
-
- /* Delete trailing slashes, but keep one */
- while (c > p+1 && c[-1] == '/')
- c--;
-
- if (p == c) /* No path whatsoever? Then return a recognizable error */
- return -EDESTADDRREQ;
+ r = path_find_last_component(path, false, &next, &c);
+ if (r < 0)
+ return r;
+ if (r == 0) /* empty or root */
+ return isempty(path) ? -EINVAL : -EADDRNOTAVAIL;
+ if (next == path) {
+ if (*path != '/') /* filename only */
+ return -EDESTADDRREQ;
+
+ a = strdup("/");
+ if (!a)
+ return -ENOMEM;
+ *ret = TAKE_PTR(a);
+ return 0;
+ }
- a = strndup(p, c - p);
+ a = strndup(path, next - path);
if (!a)
return -ENOMEM;
+ path_simplify(a, true);
+
if (!path_is_valid(a))
return -EINVAL;
test_path_extract_filename_one("/", NULL, -EADDRNOTAVAIL);
test_path_extract_filename_one("//", NULL, -EADDRNOTAVAIL);
test_path_extract_filename_one("///", NULL, -EADDRNOTAVAIL);
- test_path_extract_filename_one(".", NULL, -EINVAL);
- test_path_extract_filename_one("./.", NULL, -EINVAL);
- test_path_extract_filename_one("././", NULL, -EINVAL);
- test_path_extract_filename_one("././/", NULL, -EINVAL);
+ test_path_extract_filename_one("/.", NULL, -EADDRNOTAVAIL);
+ test_path_extract_filename_one(".", NULL, -EADDRNOTAVAIL);
+ test_path_extract_filename_one("./", NULL, -EADDRNOTAVAIL);
+ test_path_extract_filename_one("./.", NULL, -EADDRNOTAVAIL);
+ test_path_extract_filename_one("././", NULL, -EADDRNOTAVAIL);
+ test_path_extract_filename_one("././/", NULL, -EADDRNOTAVAIL);
test_path_extract_filename_one("/foo/a", "a", 0);
test_path_extract_filename_one("/foo/a/", "a", O_DIRECTORY);
test_path_extract_filename_one("", NULL, -EINVAL);
test_path_extract_filename_one("a", "a", 0);
test_path_extract_filename_one("a/", "a", O_DIRECTORY);
+ test_path_extract_filename_one("a/././//.", "a", O_DIRECTORY);
test_path_extract_filename_one("/a", "a", 0);
test_path_extract_filename_one("/a/", "a", O_DIRECTORY);
+ test_path_extract_filename_one("/a//./.", "a", O_DIRECTORY);
test_path_extract_filename_one("/////////////a/////////////", "a", O_DIRECTORY);
- test_path_extract_filename_one("xx/.", NULL, -EINVAL);
+ test_path_extract_filename_one("//./a/.///b./././.c//./d//.", "d", O_DIRECTORY);
+ test_path_extract_filename_one("xx/.", "xx", O_DIRECTORY);
test_path_extract_filename_one("xx/..", NULL, -EINVAL);
test_path_extract_filename_one("..", NULL, -EINVAL);
test_path_extract_filename_one("/..", NULL, -EINVAL);
test_path_extract_filename_one("../", NULL, -EINVAL);
- test_path_extract_filename_one(".", NULL, -EINVAL);
- test_path_extract_filename_one("/.", NULL, -EADDRNOTAVAIL);
- test_path_extract_filename_one("./", NULL, -EINVAL);
}
static void test_path_extract_directory_one(const char *input, const char *output, int ret) {
test_path_extract_directory_one("/", NULL, -EADDRNOTAVAIL);
test_path_extract_directory_one("//", NULL, -EADDRNOTAVAIL);
test_path_extract_directory_one("///", NULL, -EADDRNOTAVAIL);
- test_path_extract_directory_one(".", NULL, -EDESTADDRREQ);
- test_path_extract_directory_one("./.", ".", 0);
- test_path_extract_directory_one("././", ".", 0);
- test_path_extract_directory_one("././/", ".", 0);
+ test_path_extract_directory_one("/.", NULL, -EADDRNOTAVAIL);
+ test_path_extract_directory_one(".", NULL, -EADDRNOTAVAIL);
+ test_path_extract_directory_one("./", NULL, -EADDRNOTAVAIL);
+ test_path_extract_directory_one("./.", NULL, -EADDRNOTAVAIL);
+ test_path_extract_directory_one("././", NULL, -EADDRNOTAVAIL);
+ test_path_extract_directory_one("././/", NULL, -EADDRNOTAVAIL);
test_path_extract_directory_one("/foo/a", "/foo", 0);
test_path_extract_directory_one("/foo/a/", "/foo", 0);
test_path_extract_directory_one("", NULL, -EINVAL);
test_path_extract_directory_one("a", NULL, -EDESTADDRREQ);
test_path_extract_directory_one("a/", NULL, -EDESTADDRREQ);
+ test_path_extract_directory_one("a/././//.", NULL, -EDESTADDRREQ);
test_path_extract_directory_one("/a", "/", 0);
test_path_extract_directory_one("/a/", "/", 0);
+ test_path_extract_directory_one("/a//./.", "/", 0);
test_path_extract_directory_one("/////////////a/////////////", "/", 0);
- test_path_extract_directory_one("xx/.", "xx", 0);
- test_path_extract_directory_one("xx/..", "xx", 0);
- test_path_extract_directory_one("..", NULL, -EDESTADDRREQ);
- test_path_extract_directory_one("/..", "/", 0);
- test_path_extract_directory_one("../", NULL, -EDESTADDRREQ);
- test_path_extract_directory_one(".", NULL, -EDESTADDRREQ);
- test_path_extract_directory_one("/.", NULL, -EADDRNOTAVAIL);
- test_path_extract_directory_one("./", NULL, -EDESTADDRREQ);
+ test_path_extract_directory_one("//./a/.///b./././.c//./d//.", "/a/b./.c", 0);
+ test_path_extract_directory_one("xx/.", NULL, -EDESTADDRREQ);
+ test_path_extract_directory_one("xx/..", NULL, -EINVAL);
+ test_path_extract_directory_one("..", NULL, -EINVAL);
+ test_path_extract_directory_one("/..", NULL, -EINVAL);
+ test_path_extract_directory_one("../", NULL, -EINVAL);
}
static void test_filename_is_valid(void) {
}
static void test_tempfn_random(void) {
+ log_info("/* %s */", __func__);
+
test_tempfn_random_one("", NULL, NULL, -EINVAL);
- test_tempfn_random_one(".", NULL, NULL, -EINVAL);
+ test_tempfn_random_one(".", NULL, NULL, -EADDRNOTAVAIL);
test_tempfn_random_one("..", NULL, NULL, -EINVAL);
test_tempfn_random_one("/", NULL, NULL, -EADDRNOTAVAIL);
}
static void test_tempfn_xxxxxx(void) {
+ log_info("/* %s */", __func__);
+
test_tempfn_xxxxxx_one("", NULL, NULL, -EINVAL);
- test_tempfn_xxxxxx_one(".", NULL, NULL, -EINVAL);
+ test_tempfn_xxxxxx_one(".", NULL, NULL, -EADDRNOTAVAIL);
test_tempfn_xxxxxx_one("..", NULL, NULL, -EINVAL);
test_tempfn_xxxxxx_one("/", NULL, NULL, -EADDRNOTAVAIL);