From: Lennart Poettering Date: Fri, 29 Sep 2023 13:37:58 +0000 (+0200) Subject: fileio: revamp search_and_fopen() X-Git-Tag: v255-rc1~319^2~14 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=2c07d314b2d9309c4d91a966a01a8d1b76898c1d;p=thirdparty%2Fsystemd.git fileio: revamp search_and_fopen() 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() --- diff --git a/src/basic/fileio.c b/src/basic/fileio.c index c41db65eb19..527f53daee8 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -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) { diff --git a/src/basic/fileio.h b/src/basic/fileio.h index 769bf394fdf..cd18bcc1177 100644 --- a/src/basic/fileio.h +++ b/src/basic/fileio.h @@ -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); diff --git a/src/test/test-fileio.c b/src/test/test-fileio.c index 0eb7b073313..6efa8f2939a 100644 --- a/src/test/test-fileio.c +++ b/src/test/test-fileio.c @@ -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) {