diff options
-rw-r--r-- | src/shared/dissect-image.c | 42 | ||||
-rw-r--r-- | src/shared/dissect-image.h | 4 | ||||
-rw-r--r-- | src/test/test-loop-block.c | 28 |
3 files changed, 59 insertions, 15 deletions
diff --git a/src/shared/dissect-image.c b/src/shared/dissect-image.c index cf7fae76d1..ddd6c5430a 100644 --- a/src/shared/dissect-image.c +++ b/src/shared/dissect-image.c @@ -74,9 +74,15 @@ /* how many times to wait for the device nodes to appear */ #define N_DEVICE_NODE_LIST_ATTEMPTS 10 -int probe_filesystem_full(int fd, const char *path, char **ret_fstype) { +int probe_filesystem_full( + int fd, + const char *path, + uint64_t offset, + uint64_t size, + char **ret_fstype) { + /* Try to find device content type and return it in *ret_fstype. If nothing is found, - * 0/NULL will be returned. -EUCLEAN will be returned for ambiguous results, and an + * 0/NULL will be returned. -EUCLEAN will be returned for ambiguous results, and a * different error otherwise. */ #if HAVE_BLKID @@ -105,12 +111,19 @@ int probe_filesystem_full(int fd, const char *path, char **ret_fstype) { path = path_by_fd; } + if (size == 0) /* empty size? nothing found! */ + goto not_found; + b = blkid_new_probe(); if (!b) return -ENOMEM; errno = 0; - r = blkid_probe_set_device(b, fd, 0, 0); + r = blkid_probe_set_device( + b, + fd, + offset, + size == UINT64_MAX ? 0 : size); /* when blkid sees size=0 it understands "everything". We prefer using UINT64_MAX for that */ if (r != 0) return errno_or_else(ENOMEM); @@ -154,7 +167,7 @@ not_found: } #if HAVE_BLKID -static int dissected_image_probe_filesystem(DissectedImage *m) { +static int dissected_image_probe_filesystems(DissectedImage *m, int fd) { int r; assert(m); @@ -167,9 +180,14 @@ static int dissected_image_probe_filesystem(DissectedImage *m) { if (!p->found) continue; - if (!p->fstype && p->mount_node_fd >= 0 && !p->decrypted_node) { - r = probe_filesystem_full(p->mount_node_fd, p->node, &p->fstype); - if (r < 0 && r != -EUCLEAN) + if (!p->fstype) { + /* If we have an fd referring to the partition block device, use that. Otherwise go + * via the whole block device or backing regular file, and read via offset. */ + if (p->mount_node_fd >= 0) + r = probe_filesystem_full(p->mount_node_fd, p->node, 0, UINT64_MAX, &p->fstype); + else + r = probe_filesystem_full(fd, p->node, p->offset, p->size, &p->fstype); + if (r < 0) return r; } @@ -1117,6 +1135,10 @@ static int dissect_image( } } + r = dissected_image_probe_filesystems(m, fd); + if (r < 0) + return r; + return 0; } #endif @@ -2240,7 +2262,7 @@ int dissected_image_decrypt( } if (!p->decrypted_fstype && p->mount_node_fd >= 0 && p->decrypted_node) { - r = probe_filesystem_full(p->mount_node_fd, p->decrypted_node, &p->decrypted_fstype); + r = probe_filesystem_full(p->mount_node_fd, p->decrypted_node, 0, UINT64_MAX, &p->decrypted_fstype); if (r < 0 && r != -EUCLEAN) return r; } @@ -2952,10 +2974,6 @@ int dissect_loop_device( if (r < 0) return r; - r = dissected_image_probe_filesystem(m); - if (r < 0) - return r; - *ret = TAKE_PTR(m); return 0; #else diff --git a/src/shared/dissect-image.h b/src/shared/dissect-image.h index 52d8a2e569..2f77228a1d 100644 --- a/src/shared/dissect-image.h +++ b/src/shared/dissect-image.h @@ -133,9 +133,9 @@ MountOptions* mount_options_free_all(MountOptions *options); DEFINE_TRIVIAL_CLEANUP_FUNC(MountOptions*, mount_options_free_all); const char* mount_options_from_designator(const MountOptions *options, PartitionDesignator designator); -int probe_filesystem_full(int fd, const char *path, char **ret_fstype); +int probe_filesystem_full(int fd, const char *path, uint64_t offset, uint64_t size, char **ret_fstype); static inline int probe_filesystem(const char *path, char **ret_fstype) { - return probe_filesystem_full(-1, path, ret_fstype); + return probe_filesystem_full(-1, path, 0, UINT64_MAX, ret_fstype); } int dissect_image_file( const char *path, diff --git a/src/test/test-loop-block.c b/src/test/test-loop-block.c index af2a9683a4..b06ab0d172 100644 --- a/src/test/test-loop-block.c +++ b/src/test/test-loop-block.c @@ -4,6 +4,8 @@ #include <linux/loop.h> #include <pthread.h> #include <sys/file.h> +#include <sys/ioctl.h> +#include <sys/mount.h> #include "alloc-util.h" #include "capability-util.h" @@ -44,6 +46,15 @@ static void verify_dissected_image(DissectedImage *dissected) { assert_se(dissected->partitions[PARTITION_HOME].node); } +static void verify_dissected_image_harder(DissectedImage *dissected) { + verify_dissected_image(dissected); + + assert_se(streq(dissected->partitions[PARTITION_ESP].fstype, "vfat")); + assert_se(streq(dissected->partitions[PARTITION_XBOOTLDR].fstype, "vfat")); + assert_se(streq(dissected->partitions[PARTITION_ROOT].fstype, "ext4")); + assert_se(streq(dissected->partitions[PARTITION_HOME].fstype, "ext4")); +} + static void* thread_func(void *ptr) { int fd = PTR_TO_FD(ptr); int r; @@ -246,8 +257,23 @@ static int run(int argc, char *argv[]) { assert_se(make_filesystem(dissected->partitions[PARTITION_HOME].node, "ext4", "home", NULL, id, true) >= 0); dissected = dissected_image_unref(dissected); + + /* We created the file systems now via the per-partition block devices. But the dissection code might + * probe them via the whole block device. These block devices have separate buffer caches though, + * hence what was written via the partition device might not appear on the whole block device + * yet. Let's hence explicitly flush the whole block device, so that the read-back definitely + * works. */ + assert_se(ioctl(loop->fd, BLKFLSBUF, 0) >= 0); + + /* Try to read once, without pinning or adding partitions, i.e. by only accessing the whole block + * device. */ + assert_se(dissect_loop_device(loop, NULL, NULL, 0, &dissected) >= 0); + verify_dissected_image_harder(dissected); + dissected = dissected_image_unref(dissected); + + /* Now go via the loopback device after all, but this time add/pin, because now we want to mount it. */ assert_se(dissect_loop_device(loop, NULL, NULL, DISSECT_IMAGE_ADD_PARTITION_DEVICES|DISSECT_IMAGE_PIN_PARTITION_DEVICES, &dissected) >= 0); - verify_dissected_image(dissected); + verify_dissected_image_harder(dissected); assert_se(mkdtemp_malloc(NULL, &mounted) >= 0); |