]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
fileio: revamp search_and_fopen()
authorLennart Poettering <lennart@poettering.net>
Fri, 29 Sep 2023 13:37:58 +0000 (15:37 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 5 Oct 2023 17:01:28 +0000 (19:01 +0200)
Let's modernize and clean up search_and_fopen a bit: let's add support
for regular open() (instead of fopen()), as well as access() (if caller
just wants to check if a file exists without opening it.

This unifies much of the code involved, which previously was duplicated
in search_and_fopen() and search_and_fopen_nulstr()

src/basic/fileio.c
src/basic/fileio.h
src/test/test-fileio.c

index c41db65eb199addbd5adedea2b64e1cc50acf46b..527f53daee8726c1405aef5c4fa78a7d6def6b46 100644 (file)
@@ -1076,117 +1076,171 @@ int fdopen_independent(int fd, const char *mode, FILE **ret) {
         return 0;
 }
 
-static int search_and_fopen_internal(
+static int search_and_open_internal(
                 const char *path,
-                const char *mode,
+                int mode,            /* if ret_fd is NULL this is an [FRWX]_OK mode for access(), otherwise an open mode for open() */
                 const char *root,
                 char **search,
-                FILE **ret,
+                int *ret_fd,
                 char **ret_path) {
 
+        int r;
+
+        assert(!ret_fd || !FLAGS_SET(mode, O_CREAT)); /* We don't support O_CREAT for this */
         assert(path);
-        assert(mode);
-        assert(ret);
+
+        if (path_is_absolute(path)) {
+                _cleanup_close_ int fd = -EBADF;
+
+                if (ret_fd)
+                        /* We only specify 0777 here to appease static analyzers, it's never used since we
+                         * don't support O_CREAT here */
+                        r = fd = RET_NERRNO(open(path, mode, 0777));
+                else
+                        r = RET_NERRNO(access(path, mode));
+                if (r < 0)
+                        return r;
+
+                if (ret_path) {
+                        r = path_simplify_alloc(path, ret_path);
+                        if (r < 0)
+                                return r;
+                }
+
+                if (ret_fd)
+                        *ret_fd = TAKE_FD(fd);
+
+                return 0;
+        }
 
         if (!path_strv_resolve_uniq(search, root))
                 return -ENOMEM;
 
         STRV_FOREACH(i, search) {
+                _cleanup_close_ int fd = -EBADF;
                 _cleanup_free_ char *p = NULL;
-                FILE *f;
 
                 p = path_join(root, *i, path);
                 if (!p)
                         return -ENOMEM;
 
-                f = fopen(p, mode);
-                if (f) {
+                if (ret_fd)
+                        /* as above, 0777 is static analyzer appeasement */
+                        r = fd = RET_NERRNO(open(p, mode, 0777));
+                else
+                        r = RET_NERRNO(access(p, F_OK));
+                if (r >= 0) {
                         if (ret_path)
                                 *ret_path = path_simplify(TAKE_PTR(p));
 
-                        *ret = f;
+                        if (ret_fd)
+                                *ret_fd = TAKE_FD(fd);
+
                         return 0;
                 }
-
-                if (errno != ENOENT)
-                        return -errno;
+                if (r != -ENOENT)
+                        return r;
         }
 
         return -ENOENT;
 }
 
-int search_and_fopen(
-                const char *filename,
-                const char *mode,
+int search_and_open(
+                const char *path,
+                int mode,
                 const char *root,
-                const char **search,
-                FILE **ret,
+                char **search,
+                int *ret_fd,
                 char **ret_path) {
 
         _cleanup_strv_free_ char **copy = NULL;
-        int r;
 
-        assert(filename);
-        assert(mode);
-        assert(ret);
+        assert(path);
 
-        if (path_is_absolute(filename)) {
-                _cleanup_fclose_ FILE *f = NULL;
+        copy = strv_copy((char**) search);
+        if (!copy)
+                return -ENOMEM;
 
-                f = fopen(filename, mode);
+        return search_and_open_internal(path, mode, root, copy, ret_fd, ret_path);
+}
+
+static int search_and_fopen_internal(
+                const char *path,
+                const char *mode,
+                const char *root,
+                char **search,
+                FILE **ret_file,
+                char **ret_path) {
+
+        _cleanup_free_ char *found_path = NULL;
+        _cleanup_close_ int fd = -EBADF;
+        int r;
+
+        assert(path);
+        assert(mode || !ret_file);
+
+        r = search_and_open(
+                        path,
+                        mode ? fopen_mode_to_flags(mode) : 0,
+                        root,
+                        search,
+                        ret_file ? &fd : NULL,
+                        ret_path ? &found_path : NULL);
+        if (r < 0)
+                return r;
+
+        if (ret_file) {
+                FILE *f = take_fdopen(&fd, mode);
                 if (!f)
                         return -errno;
 
-                if (ret_path) {
-                        r = path_simplify_alloc(filename, ret_path);
-                        if (r < 0)
-                                return r;
-                }
-
-                *ret = TAKE_PTR(f);
-                return 0;
+                *ret_file = f;
         }
 
+        if (ret_path)
+                *ret_path = TAKE_PTR(found_path);
+
+        return 0;
+}
+
+int search_and_fopen(
+                const char *path,
+                const char *mode,
+                const char *root,
+                const char **search,
+                FILE **ret_file,
+                char **ret_path) {
+
+        _cleanup_strv_free_ char **copy = NULL;
+
+        assert(path);
+        assert(mode || !ret_file);
+
         copy = strv_copy((char**) search);
         if (!copy)
                 return -ENOMEM;
 
-        return search_and_fopen_internal(filename, mode, root, copy, ret, ret_path);
+        return search_and_fopen_internal(path, mode, root, copy, ret_file, ret_path);
 }
 
 int search_and_fopen_nulstr(
-                const char *filename,
+                const char *path,
                 const char *mode,
                 const char *root,
                 const char *search,
-                FILE **ret,
+                FILE **ret_file,
                 char **ret_path) {
 
-        _cleanup_strv_free_ char **s = NULL;
-        int r;
-
-        if (path_is_absolute(filename)) {
-                _cleanup_fclose_ FILE *f = NULL;
+        _cleanup_strv_free_ char **l = NULL;
 
-                f = fopen(filename, mode);
-                if (!f)
-                        return -errno;
-
-                if (ret_path) {
-                        r = path_simplify_alloc(filename, ret_path);
-                        if (r < 0)
-                                return r;
-                }
-
-                *ret = TAKE_PTR(f);
-                return 0;
-        }
+        assert(path);
+        assert(mode || !ret_file);
 
-        s = strv_split_nulstr(search);
-        if (!s)
+        l = strv_split_nulstr(search);
+        if (!l)
                 return -ENOMEM;
 
-        return search_and_fopen_internal(filename, mode, root, s, ret, ret_path);
+        return search_and_fopen_internal(path, mode, root, l, ret_file, ret_path);
 }
 
 int fflush_and_check(FILE *f) {
index 769bf394fdfe66f2ce2c1de727d38bda1f740fc1..cd18bcc1177bbf56d257c90b79d3ac8a0b26acd4 100644 (file)
@@ -129,8 +129,12 @@ static inline int fopen_unlocked(const char *path, const char *mode, FILE **ret)
 
 int fdopen_independent(int fd, const char *mode, FILE **ret);
 
-int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **ret, char **ret_path);
-int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **ret, char **ret_path);
+int search_and_open(const char *path, int mode, const char *root, char **search, int *ret_fd, char **ret_path);
+static inline int search_and_access(const char *path, int mode, const char *root, char**search, char **ret_path) {
+        return search_and_open(path, mode, root, search, NULL, ret_path);
+}
+int search_and_fopen(const char *path, const char *mode, const char *root, const char **search, FILE **ret_file, char **ret_path);
+int search_and_fopen_nulstr(const char *path, const char *mode, const char *root, const char *search, FILE **ret_file, char **ret_path);
 
 int fflush_and_check(FILE *f);
 int fflush_sync_and_check(FILE *f);
index 0eb7b0733131237cece4c5afd30af13101504dcc..6efa8f2939a596afdbd3422d69397023e0bfc633 100644 (file)
@@ -582,12 +582,23 @@ TEST(search_and_fopen) {
         f = safe_fclose(f);
         p = mfree(p);
 
+        r = search_and_fopen(basename(name), NULL, NULL, (const char**) dirs, NULL, &p);
+        assert_se(r >= 0);
+        assert_se(e = path_startswith(p, "/tmp/"));
+        assert_se(streq(basename(name), e));
+        p = mfree(p);
+
         r = search_and_fopen(name, "re", NULL, (const char**) dirs, &f, &p);
         assert_se(r >= 0);
         assert_se(path_equal(name, p));
         f = safe_fclose(f);
         p = mfree(p);
 
+        r = search_and_fopen(name, NULL, NULL, (const char**) dirs, NULL, &p);
+        assert_se(r >= 0);
+        assert_se(path_equal(name, p));
+        p = mfree(p);
+
         r = search_and_fopen(basename(name), "re", "/", (const char**) dirs, &f, &p);
         assert_se(r >= 0);
         assert_se(e = path_startswith(p, "/tmp/"));
@@ -595,16 +606,28 @@ TEST(search_and_fopen) {
         f = safe_fclose(f);
         p = mfree(p);
 
+        r = search_and_fopen(basename(name), NULL, "/", (const char**) dirs, NULL, &p);
+        assert_se(r >= 0);
+        assert_se(e = path_startswith(p, "/tmp/"));
+        assert_se(streq(basename(name), e));
+        p = mfree(p);
+
         r = search_and_fopen("/a/file/which/does/not/exist/i/guess", "re", NULL, (const char**) dirs, &f, &p);
         assert_se(r == -ENOENT);
+        r = search_and_fopen("/a/file/which/does/not/exist/i/guess", NULL, NULL, (const char**) dirs, NULL, &p);
+        assert_se(r == -ENOENT);
         r = search_and_fopen("afilewhichdoesnotexistiguess", "re", NULL, (const char**) dirs, &f, &p);
         assert_se(r == -ENOENT);
+        r = search_and_fopen("afilewhichdoesnotexistiguess", NULL, NULL, (const char**) dirs, NULL, &p);
+        assert_se(r == -ENOENT);
 
         r = unlink(name);
         assert_se(r == 0);
 
         r = search_and_fopen(basename(name), "re", NULL, (const char**) dirs, &f, &p);
         assert_se(r == -ENOENT);
+        r = search_and_fopen(basename(name), NULL, NULL, (const char**) dirs, NULL, &p);
+        assert_se(r == -ENOENT);
 }
 
 TEST(search_and_fopen_nulstr) {