From 3cc44114038621237a9d8ee4be3ff836138a55c1 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Mon, 19 Feb 2018 18:01:05 +0100 Subject: [PATCH] stat-util: unify code that checks whether something is a regular file Let's add a common implementation for regular file checks, that are careful to return the right error code (EISDIR/EISLNK/EBADFD) when we are encountering a wrong file node. --- src/basic/btrfs-util.c | 37 +++++++++++++------------------------ src/basic/stat-util.c | 29 +++++++++++++++++++++++++++++ src/basic/stat-util.h | 3 +++ src/import/export-raw.c | 6 ++++-- src/journal/journal-file.c | 10 ++++++---- src/journal/sd-journal.c | 21 ++++++--------------- src/shared/install.c | 17 +++++++---------- src/shared/loop-util.c | 8 +++++--- 8 files changed, 73 insertions(+), 58 deletions(-) diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index 19d385ab7c..3d30497f74 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -232,23 +232,18 @@ int btrfs_subvol_get_read_only_fd(int fd) { } int btrfs_reflink(int infd, int outfd) { - struct stat st; int r; assert(infd >= 0); assert(outfd >= 0); - /* Make sure we invoke the ioctl on a regular file, so that no - * device driver accidentally gets it. */ + /* Make sure we invoke the ioctl on a regular file, so that no device driver accidentally gets it. */ - if (fstat(outfd, &st) < 0) - return -errno; - - if (!S_ISREG(st.st_mode)) - return -EINVAL; - - r = ioctl(outfd, BTRFS_IOC_CLONE, infd); + r = fd_verify_regular(outfd); if (r < 0) + return r; + + if (ioctl(outfd, BTRFS_IOC_CLONE, infd) < 0) return -errno; return 0; @@ -261,21 +256,17 @@ int btrfs_clone_range(int infd, uint64_t in_offset, int outfd, uint64_t out_offs .src_length = sz, .dest_offset = out_offset, }; - struct stat st; int r; assert(infd >= 0); assert(outfd >= 0); assert(sz > 0); - if (fstat(outfd, &st) < 0) - return -errno; - - if (!S_ISREG(st.st_mode)) - return -EINVAL; - - r = ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args); + r = fd_verify_regular(outfd); if (r < 0) + return r; + + if (ioctl(outfd, BTRFS_IOC_CLONE_RANGE, &args) < 0) return -errno; return 0; @@ -760,15 +751,13 @@ int btrfs_subvol_get_subtree_quota(const char *path, uint64_t subvol_id, BtrfsQu } int btrfs_defrag_fd(int fd) { - struct stat st; + int r; assert(fd >= 0); - if (fstat(fd, &st) < 0) - return -errno; - - if (!S_ISREG(st.st_mode)) - return -EINVAL; + r = fd_verify_regular(fd); + if (r < 0) + return r; if (ioctl(fd, BTRFS_IOC_DEFRAG, NULL) < 0) return -errno; diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 0fb6750a07..3689f6e983 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -269,3 +269,32 @@ int path_is_temporary_fs(const char *path) { return fd_is_temporary_fs(fd); } + +int stat_verify_regular(const struct stat *st) { + assert(st); + + /* Checks whether the specified stat() structure refers to a regular file. If not returns an appropriate error + * code. */ + + if (S_ISDIR(st->st_mode)) + return -EISDIR; + + if (S_ISLNK(st->st_mode)) + return -ELOOP; + + if (!S_ISREG(st->st_mode)) + return -EBADFD; + + return 0; +} + +int fd_verify_regular(int fd) { + struct stat st; + + assert(fd >= 0); + + if (fstat(fd, &st) < 0) + return -errno; + + return stat_verify_regular(&st); +} diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index da33e68db2..4b941f6104 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -75,3 +75,6 @@ int path_is_temporary_fs(const char *path); * signed/unsigned comparison, because the magic can be 32 bit unsigned. */ #define F_TYPE_EQUAL(a, b) (a == (typeof(a)) b) + +int stat_verify_regular(const struct stat *st); +int fd_verify_regular(int fd); diff --git a/src/import/export-raw.c b/src/import/export-raw.c index 8485027b2b..eaa6d10915 100644 --- a/src/import/export-raw.c +++ b/src/import/export-raw.c @@ -37,6 +37,7 @@ #include "import-common.h" #include "missing.h" #include "ratelimit.h" +#include "stat-util.h" #include "string-util.h" #include "util.h" @@ -319,8 +320,9 @@ int raw_export_start(RawExport *e, const char *path, int fd, ImportCompressType if (fstat(sfd, &e->st) < 0) return -errno; - if (!S_ISREG(e->st.st_mode)) - return -ENOTTY; + r = stat_verify_regular(&e->st); + if (r < 0) + return r; /* Try to take a reflink snapshot of the file, if we can t make the export atomic */ tfd = reflink_snapshot(sfd, path); diff --git a/src/journal/journal-file.c b/src/journal/journal-file.c index 1640a8baf0..96e45e92f5 100644 --- a/src/journal/journal-file.c +++ b/src/journal/journal-file.c @@ -42,6 +42,7 @@ #include "random-util.h" #include "sd-event.h" #include "set.h" +#include "stat-util.h" #include "string-util.h" #include "strv.h" #include "xattr-util.h" @@ -643,6 +644,8 @@ static int journal_file_verify_header(JournalFile *f) { } static int journal_file_fstat(JournalFile *f) { + int r; + assert(f); assert(f->fd >= 0); @@ -652,10 +655,9 @@ static int journal_file_fstat(JournalFile *f) { f->last_stat_usec = now(CLOCK_MONOTONIC); /* Refuse dealing with with files that aren't regular */ - if (S_ISDIR(f->last_stat.st_mode)) - return -EISDIR; - if (!S_ISREG(f->last_stat.st_mode)) - return -EBADFD; + r = stat_verify_regular(&f->last_stat); + if (r < 0) + return r; /* Refuse appending to files that are already deleted */ if (f->last_stat.st_nlink <= 0) diff --git a/src/journal/sd-journal.c b/src/journal/sd-journal.c index 7e1fda8596..11dbd83f2d 100644 --- a/src/journal/sd-journal.c +++ b/src/journal/sd-journal.c @@ -1303,14 +1303,10 @@ static int add_any_file( r = log_debug_errno(errno, "Failed to fstat file '%s': %m", path); goto finish; } - if (S_ISDIR(st.st_mode)) { - log_debug("Uh, file '%s' is a directory? Refusing.", path); - r = -EISDIR; - goto finish; - } - if (!S_ISREG(st.st_mode)) { - log_debug("Uh, file '%s' is not a regular file? Refusing.", path); - r = -EBADFD; + + r = stat_verify_regular(&st); + if (r < 0) { + log_debug_errno(r, "Refusing to open '%s', as it is not a regular file.", path); goto finish; } @@ -2074,14 +2070,9 @@ _public_ int sd_journal_open_files_fd(sd_journal **ret, int fds[], unsigned n_fd goto fail; } - if (S_ISDIR(st.st_mode)) { - r = -EISDIR; + r = stat_verify_regular(&st); + if (r < 0) goto fail; - } - if (!S_ISREG(st.st_mode)) { - r = -EBADFD; - goto fail; - } r = add_any_file(j, fds[i], NULL); if (r < 0) diff --git a/src/shared/install.c b/src/shared/install.c index fdce447c89..01e2ebf672 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -1284,10 +1284,10 @@ static int unit_file_load( info->type = UNIT_FILE_TYPE_MASKED; return 0; } - if (S_ISDIR(st.st_mode)) - return -EISDIR; - if (!S_ISREG(st.st_mode)) - return -ENOTTY; + + r = stat_verify_regular(&st); + if (r < 0) + return r; f = fdopen(fd, "re"); if (!f) @@ -2163,12 +2163,9 @@ int unit_file_link( if (lstat(full, &st) < 0) return -errno; - if (S_ISLNK(st.st_mode)) - return -ELOOP; - if (S_ISDIR(st.st_mode)) - return -EISDIR; - if (!S_ISREG(st.st_mode)) - return -ENOTTY; + r = stat_verify_regular(&st); + if (r < 0) + return r; q = in_search_path(&paths, *i); if (q < 0) diff --git a/src/shared/loop-util.c b/src/shared/loop-util.c index 37b8479f88..0f3defd581 100644 --- a/src/shared/loop-util.c +++ b/src/shared/loop-util.c @@ -27,6 +27,7 @@ #include "alloc-util.h" #include "fd-util.h" #include "loop-util.h" +#include "stat-util.h" int loop_device_make(int fd, int open_flags, LoopDevice **ret) { const struct loop_info64 info = { @@ -37,7 +38,7 @@ int loop_device_make(int fd, int open_flags, LoopDevice **ret) { _cleanup_free_ char *loopdev = NULL; struct stat st; LoopDevice *d; - int nr; + int nr, r; assert(fd >= 0); assert(ret); @@ -69,8 +70,9 @@ int loop_device_make(int fd, int open_flags, LoopDevice **ret) { return 0; } - if (!S_ISREG(st.st_mode)) - return -EINVAL; + r = stat_verify_regular(&st); + if (r < 0) + return r; control = open("/dev/loop-control", O_RDWR|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); if (control < 0)