stat-util: unify code that checks whether something is a regular file
authorLennart Poettering <lennart@poettering.net>
Mon, 19 Feb 2018 17:01:05 +0000 (18:01 +0100)
committerLennart Poettering <lennart@poettering.net>
Tue, 20 Feb 2018 14:39:31 +0000 (15:39 +0100)
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
src/basic/stat-util.c
src/basic/stat-util.h
src/import/export-raw.c
src/journal/journal-file.c
src/journal/sd-journal.c
src/shared/install.c
src/shared/loop-util.c

index 19d385a..3d30497 100644 (file)
@@ -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. */
-
-        if (fstat(outfd, &st) < 0)
-                return -errno;
+        /* Make sure we invoke the ioctl on a regular file, so that no device driver accidentally gets it. */
 
-        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;
index 0fb6750..3689f6e 100644 (file)
@@ -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);
+}
index da33e68..4b941f6 100644 (file)
@@ -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);
index 8485027..eaa6d10 100644 (file)
@@ -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);
index 1640a8b..96e45e9 100644 (file)
@@ -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)
index 7e1fda8..11dbd83 100644 (file)
@@ -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;
-                        goto fail;
-                }
-                if (!S_ISREG(st.st_mode)) {
-                        r = -EBADFD;
+                r = stat_verify_regular(&st);
+                if (r < 0)
                         goto fail;
-                }
 
                 r = add_any_file(j, fds[i], NULL);
                 if (r < 0)
index fdce447..01e2ebf 100644 (file)
@@ -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)
index 37b8479..0f3defd 100644 (file)
@@ -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)