diff options
author | Michael Olbrich <m.olbrich@pengutronix.de> | 2019-09-22 14:33:45 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-09-22 14:33:45 +0000 |
commit | dc09d79f7329826bb652ef73f1c7ef71e39fc5af (patch) | |
tree | 007529e5ed970a560d3ad9945e4af8f03579ea3f | |
parent | 3300b46aeb61d8eb0a723b7a3947ae4d95ba3666 (diff) | |
parent | f69e15de765e48869fa26f9a9920557b6a9d2732 (diff) | |
download | genimage-dc09d79f7329826bb652ef73f1c7ef71e39fc5af.tar.gz genimage-dc09d79f7329826bb652ef73f1c7ef71e39fc5af.tar.xz |
Merge pull request #50 from ssorensen/sparse
hdimage: Implement sparse support
-rwxr-xr-x | test/basic-images.test | 20 | ||||
-rw-r--r-- | util.c | 158 |
2 files changed, 148 insertions, 30 deletions
diff --git a/test/basic-images.test b/test/basic-images.test index 52e2f22..d35898f 100755 --- a/test/basic-images.test +++ b/test/basic-images.test @@ -97,6 +97,25 @@ sfdisk_validate() { fi } +get_disk_usage() { + local file="${1}" + if [ ! -f "${file}" ]; then + echo "Failed to check file disk usage: '${file}' does not exist!" + return 1 + fi + set -- $(du -B 1 "${file}") + usage="${1}" +} + +check_disk_usage_range() { + local usage + get_disk_usage "${1}" || return + if [ "${usage}" -lt "${2}" -o "${usage}" -gt "${3}" ]; then + echo "Incorrect file disk usage for '${1}': expected min: ${2} max: ${3} found: ${usage}" + return 1 + fi +} + exec_test_set_prereq() { command -v "${1}" > /dev/null && test_set_prereq "${1/./_}" } @@ -208,6 +227,7 @@ test_expect_success fdisk,sfdisk "hdimage" " run_genimage hdimage.config test.hdimage && check_size images/test.hdimage 10485760 && sfdisk_validate images/test.hdimage && + check_disk_usage_range images/test.hdimage 40960 57344 && # check the this identifier fdisk -l images/test.hdimage | grep identifier: > hdimage.fdisk && # check partitions; filter output to handle different sfdisk versions @@ -25,6 +25,7 @@ #include <sys/stat.h> #include <sys/wait.h> #include <linux/fs.h> +#include <linux/fiemap.h> #include <unistd.h> #include <fcntl.h> #include <ctype.h> @@ -323,13 +324,83 @@ static int open_file(struct image *image, const char *filename, int extra_flags) return fd; } +struct extent { + unsigned long long start, end; +}; + +/* Build a file extent covering the whole file */ +static int whole_file_exent(size_t size, struct extent **extents, + size_t *extent_count) +{ + *extents = xzalloc(sizeof(struct extent)); + (*extents)[0].start = 0; + (*extents)[0].end = size; + *extent_count = 1; + return 0; +} + +/* Build an file extent array for the file */ +static int map_file_extents(struct image *image, const char *filename, int f, + size_t size, struct extent **extents, + size_t *extent_count) +{ + struct fiemap *fiemap; + unsigned i; + int ret; + + /* Get extent count */ + fiemap = xzalloc(sizeof(struct fiemap)); + fiemap->fm_length = size; + ret = ioctl(f, FS_IOC_FIEMAP, fiemap); + if (ret == -1) + goto err_out; + + /* Get extents */ + fiemap = realloc(fiemap, sizeof(struct fiemap) + fiemap->fm_mapped_extents * sizeof(struct fiemap_extent)); + fiemap->fm_extent_count = fiemap->fm_mapped_extents; + ret = ioctl(f, FS_IOC_FIEMAP, fiemap); + if (ret == -1) + goto err_out; + + /* Build extent array */ + *extent_count = fiemap->fm_mapped_extents; + *extents = xzalloc(fiemap->fm_mapped_extents * sizeof(struct extent)); + for (i = 0; i < fiemap->fm_mapped_extents; i++) { + (*extents)[i].start = fiemap->fm_extents[i].fe_logical; + (*extents)[i].end = fiemap->fm_extents[i].fe_logical + fiemap->fm_extents[i].fe_length; + } + free(fiemap); + + /* The last extent may extend beyond the end of file, limit it to the actual end */ + if ((*extents)[i-1].end > size) + (*extents)[i-1].end = size; + + return 0; + +err_out: + ret = -errno; + + free(fiemap); + + /* If failure is due to no filesystem support, return a single extent */ + if (ret == -EOPNOTSUPP) + return whole_file_exent(size, extents, extent_count); + + image_error(image, "fiemap %s: %d %s\n", filename, errno, strerror(errno)); + return ret; +} + int pad_file(struct image *image, const char *infile, size_t size, unsigned char fillpattern, enum pad_mode mode) { const char *outfile = imageoutfile(image); int f = -1, outf = -1, flags = 0; + unsigned long f_offset = 0; + struct extent *extents; + size_t extent_count; void *buf = NULL; int now, r, w; + unsigned e; struct stat s; int ret = 0; @@ -397,44 +468,71 @@ int pad_file(struct image *image, const char *infile, goto fill; } - while (size) { - now = min(size, 4096); - - r = read(f, buf, now); - w = write(outf, buf, r); - if (w < r) { - ret = -errno; - image_error(image, "write %s: %s\n", outfile, strerror(errno)); + if ((s.st_mode & S_IFMT) == S_IFREG) { + ret = map_file_extents(image, infile, f, size, &extents, &extent_count); + if (ret != 0) goto err_out; - } - size -= r; - - if (r < now) - goto fill; } - - now = read(f, buf, 1); - if (now == 1) { - image_error(image, "input file '%s' too large\n", infile); - ret = -EINVAL; - goto err_out; + else { + whole_file_exent(size, &extents, &extent_count); } -fill: - memset(buf, fillpattern, 4096); + for (e = 0; e < extent_count && size > 0; e++) { + /* Ship over any holes in the input file */ + if (f_offset != extents[e].start) { + unsigned long skip = extents[e].start - f_offset; + lseek(f, skip, SEEK_CUR); + lseek(outf, skip, SEEK_CUR); + size -= skip; + f_offset += skip; + } - while (size) { - now = min(size, 4096); + /* Copy the data in the extent */ + while (f_offset < extents[e].end) { + now = min(extents[e].end - f_offset, 4096); + + r = read(f, buf, now); + w = write(outf, buf, r); + if (w < r) { + ret = -errno; + image_error(image, "write %s: %s\n", outfile, strerror(errno)); + goto err_out; + } + size -= r; + f_offset += r; + + if (r < now) + goto fill; + } + } - r = write(outf, buf, now); - if (r < now) { - ret = -errno; - image_error(image, "write %s: %s\n", outfile, strerror(errno)); - goto err_out; +fill: + if (fillpattern == 0 && (s.st_mode & S_IFMT) == S_IFREG) { + /* Truncate output to desired size */ + image_info(image, "f_offset=%lu filesize=%llu\n", f_offset, (unsigned long long)lseek(outf, 0, SEEK_CUR)); + image->last_offset = lseek(outf, 0, SEEK_CUR) + size; + ret = ftruncate(outf, image->last_offset); + if (ret == -1) { + image_error(image, "ftruncate %s: %s\n", outfile, strerror(errno)); + goto err_out; + } + } + else { + memset(buf, fillpattern, 4096); + + while (size) { + now = min(size, 4096); + + r = write(outf, buf, now); + if (r < now) { + ret = -errno; + image_error(image, "write %s: %s\n", outfile, strerror(errno)); + goto err_out; + } + size -= now; } - size -= now; + image->last_offset = lseek(outf, 0, SEEK_CUR); } - image->last_offset = lseek(outf, 0, SEEK_CUR); err_out: free(buf); if (f >= 0) |