commit f837169ab53dc915e10bdb480eaeb5bbb52c0c09 Author: Paul Evans Date: Wed Mar 6 12:28:16 2024 +0000 gfs2_edit: truncate to filesystem size at end of restoremeta() Truncate to metadata header's filesystem size at the end of restore if a header is present. Resolves: RHEL-26661 Signed-off-by: Paul Evans diff --git a/gfs2/edit/savemeta.c b/gfs2/edit/savemeta.c index 4ee76be0..f5448974 100644 --- a/gfs2/edit/savemeta.c +++ b/gfs2/edit/savemeta.c @@ -1327,9 +1327,8 @@ static void restoremeta_usage(void) fprintf(stderr, "gfs2_edit restoremeta \n"); } -static int restore_init(const char *path, struct metafd *mfd, int printonly) +static int restore_init(const char *path, struct metafd *mfd, struct savemeta *sm, int printonly) { - struct savemeta sm = {0}; struct gfs2_sb rsb; uint16_t sb_siglen; char *end; @@ -1357,7 +1356,7 @@ static int restore_init(const char *path, struct metafd *mfd, int printonly) return -1; } bp = restore_buf; - ret = parse_header(bp, &sm); + ret = parse_header(bp, sm); if (ret == 0) { bp = restore_buf + sizeof(struct savemeta_header); restore_off = sizeof(struct savemeta_header); @@ -1383,10 +1382,10 @@ static int restore_init(const char *path, struct metafd *mfd, int printonly) if (ret != 0) return ret; - if (sm.sm_fs_bytes > 0) { - sbd.fssize = sm.sm_fs_bytes / sbd.sd_bsize; + if (sm->sm_fs_bytes > 0) { + sbd.fssize = sm->sm_fs_bytes / sbd.sd_bsize; printf("Saved file system size is %"PRIu64" blocks, %.2fGB\n", - sbd.fssize, sm.sm_fs_bytes / ((float)(1 << 30))); + sbd.fssize, sm->sm_fs_bytes / ((float)(1 << 30))); } printf("Block size is %uB\n", sbd.sd_bsize); printf("This is gfs%c metadata.\n", sbd.gfs1 ? '1': '2'); @@ -1406,6 +1405,8 @@ static int restore_init(const char *path, struct metafd *mfd, int printonly) void restoremeta(const char *in_fn, const char *out_device, uint64_t printonly) { struct metafd mfd = {0}; + struct savemeta sm = {0}; + struct stat st; int error; termlines = 0; @@ -1430,7 +1431,7 @@ void restoremeta(const char *in_fn, const char *out_device, uint64_t printonly) optional block no */ printonly = check_keywords(out_device); - error = restore_init(in_fn, &mfd, printonly); + error = restore_init(in_fn, &mfd, &sm, printonly); if (error != 0) exit(error); @@ -1440,6 +1441,23 @@ void restoremeta(const char *in_fn, const char *out_device, uint64_t printonly) } error = restore_data(sbd.device_fd, &mfd, printonly); + + /* When there is a metadata header available, truncate to filesystem + size if our device_fd is a regular file */ + if (!printonly) { + if (fstat(sbd.device_fd, &st) == -1) { + fprintf(stderr, "Failed to stat %s: %s\n", out_device, strerror(errno)); + error = errno; + } + + if (sm.sm_fs_bytes > 0 && S_ISREG(st.st_mode)) { + if (ftruncate(sbd.device_fd, sm.sm_fs_bytes) != 0) { + fprintf(stderr, "Failed to truncate: %s, %s\n", out_device, strerror(errno)); + error = errno; + } + } + } + printf("File %s %s %s.\n", in_fn, (printonly ? "print" : "restore"), (error ? "error" : "successful")); diff --git a/tests/edit.at b/tests/edit.at index d6795218..29835df0 100644 --- a/tests/edit.at +++ b/tests/edit.at @@ -61,3 +61,13 @@ AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT], 0, [ignore], [ignore]) AT_CHECK([gfs2_edit savemeta -z0 $GFS_TGT /dev/null], 0, [ignore], [ignore]) AT_CHECK([gfs2_edit savemeta $GFS_TGT /dev/null], 0, [ignore], [ignore]) AT_CLEANUP + +AT_SETUP([Truncate on restoremeta]) +AT_KEYWORDS(gfs2_edit edit) +GFS_TGT_REGEN +AT_CHECK([$GFS_MKFS -p lock_nolock $GFS_TGT], 0, [ignore], [ignore]) +AT_CHECK([gfs2_edit savemeta $GFS_TGT test.meta], 0, [ignore], [ignore]) +AT_CHECK([truncate -s 10K test.file], 0, [ignore], [ignore]) +AT_CHECK([gfs2_edit restoremeta test.meta test.file], 0, [ignore], [ignore]) +AT_CHECK([fsck.gfs2 -n test.file], 0, [ignore], [ignore]) +AT_CLEANUP