* Also, the empty string is mapped to itself.
*
* This is different than basename(), which returns "" when a trailing slash is present.
+ *
+ * This always succeeds (except if you pass NULL in which case it returns NULL, too).
*/
unsigned l, k;
int path_extract_filename(const char *p, char **ret) {
_cleanup_free_ char *a = NULL;
- const char *c, *e = NULL, *q;
+ const char *c;
/* 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. */
+ * filename_is_valid(). A wrapper around last_path_component(), but eats up trailing slashes. Returns
+ * -EADDRNOTAVAIL if specified parameter includes no filename (i.e. is "/" or so). Returns -EINVAL if
+ * not a valid path in the first place. */
- if (!p)
+ if (!path_is_valid(p))
return -EINVAL;
- c = last_path_component(p);
-
- for (q = c; *q != 0; q++)
- if (*q != '/')
- e = q + 1;
+ /* 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, "/"))
+ return -EADDRNOTAVAIL;
- if (!e) /* no valid character? */
- return -EINVAL;
+ c = last_path_component(p);
- a = strndup(c, e - c);
+ a = strndup(c, strcspn(c, "/"));
if (!a)
return -ENOMEM;
return -EINVAL;
*ret = TAKE_PTR(a);
-
return 0;
}
test_path_extract_filename_one(NULL, NULL, -EINVAL);
test_path_extract_filename_one("a/b/c", "c", 0);
test_path_extract_filename_one("a/b/c/", "c", 0);
- 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, -EINVAL);
test_path_extract_filename_one("./.", NULL, -EINVAL);
test_path_extract_filename_one("././", NULL, -EINVAL);