diff --git a/vhd/lib/libvhd.c b/vhd/lib/libvhd.c index ae786196..58e9f04e 100644 --- a/vhd/lib/libvhd.c +++ b/vhd/lib/libvhd.c @@ -232,8 +232,8 @@ vhd_checksum_footer(vhd_footer_t *footer) return ~checksum; } -int -vhd_validate_footer(vhd_footer_t *footer) +static int +vhd_validate_footer_impl(vhd_footer_t *footer, bool suppress_invalid_footer_warning) { int csize; uint32_t checksum; @@ -244,7 +244,8 @@ vhd_validate_footer(vhd_footer_t *footer) char buf[9]; memcpy(buf, footer->cookie, 8); buf[8]= '\0'; - VHDLOG("invalid footer cookie: %s\n", buf); + if (!suppress_invalid_footer_warning) + VHDLOG("invalid footer cookie: %s\n", buf); return -EINVAL; } @@ -267,15 +268,24 @@ vhd_validate_footer(vhd_footer_t *footer) return 0; } - VHDLOG("invalid footer checksum: " - "footer = 0x%08x, calculated = 0x%08x\n", - footer->checksum, checksum); + if (!suppress_invalid_footer_warning) + { + VHDLOG("invalid footer checksum: " + "footer = 0x%08x, calculated = 0x%08x\n", + footer->checksum, checksum); + } return -EINVAL; } return 0; } +int +vhd_validate_footer(vhd_footer_t *footer) +{ + return vhd_validate_footer_impl(footer, false); +} + uint32_t vhd_checksum_header(vhd_header_t *header) { @@ -841,8 +851,8 @@ vhd_put_batmap(vhd_context_t *ctx) /* * look for 511 byte footer at end of file */ -int -vhd_read_short_footer(vhd_context_t *ctx, vhd_footer_t *footer) +static int +vhd_read_short_footer_impl(vhd_context_t *ctx, vhd_footer_t *footer, bool suppress_invalid_footer_warning) { off64_t eof; void *buf; @@ -860,6 +870,19 @@ vhd_read_short_footer(vhd_context_t *ctx, vhd_footer_t *footer) goto out; } + if (((eof - 511) % VHD_SECTOR_SIZE) != 0) { + /* + * The VHD file with short footer should have the size in the form 512 * n + 511, + * also vhd_read on block VHDs won't succeed if trying to read from a position + * that is not a multiple of 512. + */ + if (!suppress_invalid_footer_warning) + VHDLOG("%s: failed reading short footer: file size does not meet requirement", + ctx->file); + err = -EINVAL; + goto out; + } + err = vhd_seek(ctx, eof - 511, SEEK_SET); if (err) goto out; @@ -881,10 +904,10 @@ vhd_read_short_footer(vhd_context_t *ctx, vhd_footer_t *footer) memcpy(footer, buf, sizeof(vhd_footer_t)); vhd_footer_in(footer); - err = vhd_validate_footer(footer); + err = vhd_validate_footer_impl(footer, suppress_invalid_footer_warning); out: - if (err) + if (err && !suppress_invalid_footer_warning) VHDLOG("%s: failed reading short footer: %d\n", ctx->file, err); free(buf); @@ -892,7 +915,13 @@ vhd_read_short_footer(vhd_context_t *ctx, vhd_footer_t *footer) } int -vhd_read_footer_at(vhd_context_t *ctx, vhd_footer_t *footer, off64_t off) +vhd_read_short_footer(vhd_context_t *ctx, vhd_footer_t *footer) +{ + return vhd_read_short_footer_impl(ctx, footer, false); +} + +static int +vhd_read_footer_at_impl(vhd_context_t *ctx, vhd_footer_t *footer, off64_t off, bool suppress_invalid_footer_warning) { void *buf; int err; @@ -917,16 +946,22 @@ vhd_read_footer_at(vhd_context_t *ctx, vhd_footer_t *footer, off64_t off) memcpy(footer, buf, sizeof(vhd_footer_t)); vhd_footer_in(footer); - err = vhd_validate_footer(footer); + err = vhd_validate_footer_impl(footer, suppress_invalid_footer_warning); out: - if (err) + if (err && !suppress_invalid_footer_warning) VHDLOG("%s: reading footer at 0x%08"PRIx64" failed: %d\n", ctx->file, off, err); free(buf); return err; } +int +vhd_read_footer_at(vhd_context_t *ctx, vhd_footer_t *footer, off64_t off) +{ + return vhd_read_footer_at_impl(ctx, footer, off, false); +} + int vhd_read_footer(vhd_context_t *ctx, vhd_footer_t *footer, bool use_bkp_footer) { @@ -942,11 +977,16 @@ vhd_read_footer(vhd_context_t *ctx, vhd_footer_t *footer, bool use_bkp_footer) return -errno; if (!use_bkp_footer) { - err = vhd_read_footer_at(ctx, footer, off - 512); + /* + * As we will read the backup footer if the primary one is invalid, + * stop complaining the primary one is invalid + */ + + err = vhd_read_footer_at_impl(ctx, footer, off - 512, true); if (err != -EINVAL) return err; - err = vhd_read_short_footer(ctx, footer); + err = vhd_read_short_footer_impl(ctx, footer, true); if (err != -EINVAL) return err; }