]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
path-util: add helper for extracting last filename from path
authorLennart Poettering <lennart@poettering.net>
Fri, 26 Oct 2018 14:07:35 +0000 (16:07 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 26 Nov 2018 17:09:01 +0000 (18:09 +0100)
src/basic/path-util.c
src/basic/path-util.h
src/test/test-path-util.c

index 243771d9e45f0676443679443ecb03c008b0d929..b7f91ee3ae60c63beaf225bce0e39c4fa555aa39 100644 (file)
@@ -769,6 +769,37 @@ const char *last_path_component(const char *path) {
         return path + k;
 }
 
+int path_extract_filename(const char *p, char **ret) {
+        _cleanup_free_ char *a = NULL;
+        const char *c, *e = NULL, *q;
+
+        /* 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. */
+
+        if (!p)
+                return -EINVAL;
+
+        c = last_path_component(p);
+
+        for (q = c; *q != 0; q++)
+                if (*q != '/')
+                        e = q + 1;
+
+        if (!e) /* no valid character? */
+                return -EINVAL;
+
+        a = strndup(c, e - c);
+        if (!a)
+                return -ENOMEM;
+
+        if (!filename_is_valid(a))
+                return -EINVAL;
+
+        *ret = TAKE_PTR(a);
+
+        return 0;
+}
+
 bool filename_is_valid(const char *p) {
         const char *e;
 
index e2a51ff33a29757f3c98a3078b8c8c3e5cf280b9..53b980d3c166625bbecc0aceaedb8ab5452ad5a6 100644 (file)
@@ -133,6 +133,7 @@ int parse_path_argument_and_warn(const char *path, bool suppress_root, char **ar
 
 char* dirname_malloc(const char *path);
 const char *last_path_component(const char *path);
+int path_extract_filename(const char *p, char **ret);
 
 bool filename_is_valid(const char *p) _pure_;
 bool path_is_valid(const char *p) _pure_;
index dd00f13905f432d5ceda1b24069b2669c3fcc1f6..7feae54068fce39b1207514157450c9dd9a85a21 100644 (file)
@@ -425,6 +425,45 @@ static void test_last_path_component(void) {
         assert_se(streq(last_path_component("/a/"), "a/"));
 }
 
+static void test_path_extract_filename_one(const char *input, const char *output, int ret) {
+        _cleanup_free_ char *k = NULL;
+        int r;
+
+        r = path_extract_filename(input, &k);
+        log_info("%s → %s/%s [expected: %s/%s]", strnull(input), strnull(k), strerror(-r), strnull(output), strerror(-ret));
+        assert_se(streq_ptr(k, output));
+        assert_se(r == ret);
+}
+
+static void test_path_extract_filename(void) {
+        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, -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("/foo/a", "a", 0);
+        test_path_extract_filename_one("/foo/a/", "a", 0);
+        test_path_extract_filename_one("", NULL, -EINVAL);
+        test_path_extract_filename_one("a", "a", 0);
+        test_path_extract_filename_one("a/", "a", 0);
+        test_path_extract_filename_one("/a", "a", 0);
+        test_path_extract_filename_one("/a/", "a", 0);
+        test_path_extract_filename_one("/////////////a/////////////", "a", 0);
+        test_path_extract_filename_one("xx/.", NULL, -EINVAL);
+        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, -EINVAL);
+        test_path_extract_filename_one("./", NULL, -EINVAL);
+}
+
 static void test_filename_is_valid(void) {
         char foo[FILENAME_MAX+2];
         int i;
@@ -543,6 +582,7 @@ int main(int argc, char **argv) {
         test_prefix_root();
         test_file_in_same_dir();
         test_last_path_component();
+        test_path_extract_filename();
         test_filename_is_valid();
         test_hidden_or_backup_file();
         test_skip_dev_prefix();