]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
loop-util: allow creating loopback block devices with offset/length
authorLennart Poettering <lennart@poettering.net>
Thu, 4 Jul 2019 15:57:29 +0000 (17:57 +0200)
committerLennart Poettering <lennart@poettering.net>
Mon, 2 Dec 2019 09:05:49 +0000 (10:05 +0100)
src/shared/loop-util.c
src/shared/loop-util.h

index 150029400db614f1ebe84527d0723cdaa966a7c6..4bd89d37cbbaed85e3e7177373905756232b8f7c 100644 (file)
 #include "loop-util.h"
 #include "stat-util.h"
 
-int loop_device_make(int fd, int open_flags, uint32_t loop_flags, LoopDevice **ret) {
-        const struct loop_info64 info = {
-                /* Use the specified flags, but configure the read-only flag from the open flags, and force autoclear */
-                .lo_flags = (loop_flags & ~LO_FLAGS_READ_ONLY) | ((loop_flags & O_ACCMODE) == O_RDONLY ? LO_FLAGS_READ_ONLY : 0) | LO_FLAGS_AUTOCLEAR,
-        };
+int loop_device_make_full(
+                int fd,
+                int open_flags,
+                uint64_t offset,
+                uint64_t size,
+                uint32_t loop_flags,
+                LoopDevice **ret) {
 
         _cleanup_close_ int control = -1, loop = -1;
         _cleanup_free_ char *loopdev = NULL;
         unsigned n_attempts = 0;
+        struct loop_info64 info;
         struct stat st;
         LoopDevice *d;
         int nr, r;
@@ -31,32 +34,34 @@ int loop_device_make(int fd, int open_flags, uint32_t loop_flags, LoopDevice **r
                 return -errno;
 
         if (S_ISBLK(st.st_mode)) {
-                int copy;
+                if (offset == 0 && IN_SET(size, 0, UINT64_MAX)) {
+                        int copy;
 
-                /* If this is already a block device, store a copy of the fd as it is */
+                        /* If this is already a block device, store a copy of the fd as it is */
 
-                copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
-                if (copy < 0)
-                        return -errno;
+                        copy = fcntl(fd, F_DUPFD_CLOEXEC, 3);
+                        if (copy < 0)
+                                return -errno;
 
-                d = new0(LoopDevice, 1);
-                if (!d)
-                        return -ENOMEM;
+                        d = new(LoopDevice, 1);
+                        if (!d)
+                                return -ENOMEM;
 
-                *d = (LoopDevice) {
-                        .fd = copy,
-                        .nr = -1,
-                        .relinquished = true, /* It's not allocated by us, don't destroy it when this object is freed */
-                };
+                        *d = (LoopDevice) {
+                                .fd = copy,
+                                .nr = -1,
+                                .relinquished = true, /* It's not allocated by us, don't destroy it when this object is freed */
+                        };
 
-                *ret = d;
-                return d->fd;
+                        *ret = d;
+                        return d->fd;
+                }
+        } else {
+                r = stat_verify_regular(&st);
+                if (r < 0)
+                        return r;
         }
 
-        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)
                 return -errno;
@@ -87,6 +92,13 @@ int loop_device_make(int fd, int open_flags, uint32_t loop_flags, LoopDevice **r
                 loop = safe_close(loop);
         }
 
+        info = (struct loop_info64) {
+                /* Use the specified flags, but configure the read-only flag from the open flags, and force autoclear */
+                .lo_flags = (loop_flags & ~LO_FLAGS_READ_ONLY) | ((loop_flags & O_ACCMODE) == O_RDONLY ? LO_FLAGS_READ_ONLY : 0) | LO_FLAGS_AUTOCLEAR,
+                .lo_offset = offset,
+                .lo_sizelimit = size == UINT64_MAX ? 0 : size,
+        };
+
         if (ioctl(loop, LOOP_SET_STATUS64, &info) < 0)
                 return -errno;
 
index 80a114f9d996ade50023c222814a4eb43f13fe90..50b959fe2514777dee3fa4d73d7532050af0f6f6 100644 (file)
@@ -14,7 +14,11 @@ struct LoopDevice {
         bool relinquished;
 };
 
-int loop_device_make(int fd, int open_flags, uint32_t loop_flags, LoopDevice **ret);
+int loop_device_make_full(int fd, int open_flags, uint64_t offset, uint64_t size, uint32_t loop_flags, LoopDevice **ret);
+static inline int loop_device_make(int fd, int open_flags, uint32_t loop_flags, LoopDevice **ret) {
+        return loop_device_make_full(fd, open_flags, 0, 0, loop_flags, ret);
+}
+
 int loop_device_make_by_path(const char *path, int open_flags, uint32_t loop_flags, LoopDevice **ret);
 int loop_device_open(const char *loop_path, int open_flags, LoopDevice **ret);