From b98b25b85877d1bccdc8673a23576b1fac0ab1c6 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Sat, 14 Jun 2014 01:10:45 -0500 Subject: [PATCH] finish_write(): Read old integrity table into memory if needed This is a better fix for the problem, since it doesn't prevent the old table from being used when it can be. --- include/wimlib/integrity.h | 11 ++++++- include/wimlib/write.h | 11 +++---- src/integrity.c | 40 +++++------------------ src/write.c | 66 +++++++++++++++++++++++--------------- 4 files changed, 63 insertions(+), 65 deletions(-) diff --git a/include/wimlib/integrity.h b/include/wimlib/integrity.h index 1d115ff8..fa4e6a34 100644 --- a/include/wimlib/integrity.h +++ b/include/wimlib/integrity.h @@ -8,10 +8,19 @@ #define WIM_INTEGRITY_NOT_OK -1 #define WIM_INTEGRITY_NONEXISTENT -2 +struct integrity_table; + +extern int +read_integrity_table(WIMStruct *wim, u64 num_checked_bytes, + struct integrity_table **table_ret); + +#define free_integrity_table(table) FREE(table) + extern int write_integrity_table(WIMStruct *wim, off_t new_lookup_table_end, - off_t old_lookup_table_end); + off_t old_lookup_table_end, + struct integrity_table *old_table); extern int check_wim_integrity(WIMStruct *wim); diff --git a/include/wimlib/write.h b/include/wimlib/write.h index 273a6a71..d6957ace 100644 --- a/include/wimlib/write.h +++ b/include/wimlib/write.h @@ -7,12 +7,11 @@ /* Internal use only */ #define WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE 0x80000000 #define WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML 0x40000000 -#define WIMLIB_WRITE_FLAG_REUSE_INTEGRITY_TABLE 0x20000000 -#define WIMLIB_WRITE_FLAG_HEADER_AT_END 0x10000000 -#define WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR 0x08000000 -#define WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES 0x04000000 -#define WIMLIB_WRITE_FLAG_NO_METADATA 0x02000000 -#define WIMLIB_WRITE_FLAG_OVERWRITE 0x01000000 +#define WIMLIB_WRITE_FLAG_HEADER_AT_END 0x20000000 +#define WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR 0x10000000 +#define WIMLIB_WRITE_FLAG_USE_EXISTING_TOTALBYTES 0x08000000 +#define WIMLIB_WRITE_FLAG_NO_METADATA 0x04000000 +#define WIMLIB_WRITE_FLAG_OVERWRITE 0x02000000 /* Keep in sync with wimlib.h */ #define WIMLIB_WRITE_MASK_PUBLIC ( \ diff --git a/src/integrity.c b/src/integrity.c index ebde9306..30817cda 100644 --- a/src/integrity.c +++ b/src/integrity.c @@ -107,7 +107,7 @@ calculate_chunk_sha1(struct filedes *in_fd, size_t this_chunk_size, * WIMLIB_ERR_READ * WIMLIB_ERR_UNEXPECTED_END_OF_FILE */ -static int +int read_integrity_table(WIMStruct *wim, u64 num_checked_bytes, struct integrity_table **table_ret) { @@ -146,7 +146,6 @@ read_integrity_table(WIMStruct *wim, u64 num_checked_bytes, return 0; invalid: - ERROR("Integrity table is invalid"); return WIMLIB_ERR_INVALID_INTEGRITY_TABLE; } @@ -282,12 +281,7 @@ out_free_new_table: * chunks of the file). * * This function can optionally re-use entries from an older integrity table. - * To do this, ensure that @wim->hdr.integrity_table_reshdr is the resource - * header for the older table (note: this is an input-output parameter), and set - * @old_lookup_table_end to the offset of the byte directly following the last - * byte checked by the old table. If the old integrity table is invalid or - * cannot be read, a warning is printed and the integrity information is - * re-calculated. + * To do this, specify old_lookup_table_end and old_table. * * @wim: * WIMStruct for the WIM file. @wim->out_fd must be a seekable descriptor @@ -307,18 +301,16 @@ out_free_new_table: * If nonzero, the offset of the byte directly following the old lookup * table in the WIM. * - * Return values: - * WIMLIB_ERR_SUCCESS (0) - * WIMLIB_ERR_NOMEM - * WIMLIB_ERR_UNEXPECTED_END_OF_FILE - * WIMLIB_ERR_WRITE + * @old_table + * Pointer to the old integrity table read into memory, or NULL if not + * specified. */ int write_integrity_table(WIMStruct *wim, off_t new_lookup_table_end, - off_t old_lookup_table_end) + off_t old_lookup_table_end, + struct integrity_table *old_table) { - struct integrity_table *old_table; struct integrity_table *new_table; int ret; u32 new_table_size; @@ -329,25 +321,11 @@ write_integrity_table(WIMStruct *wim, wimlib_assert(old_lookup_table_end <= new_lookup_table_end); - old_table = NULL; - if (wim_has_integrity_table(wim) && old_lookup_table_end != 0) { - ret = read_integrity_table(wim, - old_lookup_table_end - WIM_HEADER_DISK_SIZE, - &old_table); - if (ret == WIMLIB_ERR_INVALID_INTEGRITY_TABLE) { - WARNING("Old integrity table is invalid! " - "Ignoring it"); - } else if (ret != 0) { - WARNING("Can't read old integrity table! " - "Ignoring it"); - } - } - ret = calculate_integrity_table(&wim->out_fd, new_lookup_table_end, old_table, old_lookup_table_end, &new_table, wim->progfunc, wim->progctx); if (ret) - goto out_free_old_table; + return ret; new_table_size = new_table->size; @@ -365,8 +343,6 @@ write_integrity_table(WIMStruct *wim, NULL, 0); FREE(new_table); -out_free_old_table: - FREE(old_table); DEBUG("ret=%d", ret); return ret; } diff --git a/src/write.c b/src/write.c index 9acdffac..2baba967 100644 --- a/src/write.c +++ b/src/write.c @@ -6,7 +6,7 @@ */ /* - * Copyright (C) 2012, 2013 Eric Biggers + * Copyright (C) 2012, 2013, 2014 Eric Biggers * * This file is part of wimlib, a library for working with WIM files. * @@ -2264,10 +2264,6 @@ write_wim_lookup_table(WIMStruct *wim, int image, int write_flags, * (private) WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE: * Don't write the lookup table. * - * (private) WIMLIB_WRITE_FLAG_REUSE_INTEGRITY_TABLE: - * When (if) writing the integrity table, re-use entries from the - * existing integrity table, if possible. - * * (private) WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML: * After writing the XML data but before writing the integrity * table, write a temporary WIM header and flush the stream so that @@ -2284,6 +2280,9 @@ write_wim_lookup_table(WIMStruct *wim, int image, int write_flags, * Use the existing stored in the in-memory XML * information, rather than setting it to the offset of the XML * data being written. + * (private) WIMLIB_WRITE_FLAG_OVERWRITE + * The existing WIM file is being updated in-place. The entries + * from its integrity table may be re-used. */ static int finish_write(WIMStruct *wim, int image, int write_flags, @@ -2292,9 +2291,10 @@ finish_write(WIMStruct *wim, int image, int write_flags, int ret; off_t hdr_offset; int write_resource_flags; - off_t old_lookup_table_end; + off_t old_lookup_table_end = 0; off_t new_lookup_table_end; u64 xml_totalbytes; + struct integrity_table *old_integrity_table = NULL; DEBUG("image=%d, write_flags=%08x", image, write_flags); @@ -2313,15 +2313,36 @@ finish_write(WIMStruct *wim, int image, int write_flags, wim->hdr.boot_idx - 1]->metadata_lte->out_reshdr); } - /* Write lookup table. (Save old position first.) */ - old_lookup_table_end = wim->hdr.lookup_table_reshdr.offset_in_wim + - wim->hdr.lookup_table_reshdr.size_in_wim; + /* If overwriting the WIM file containing an integrity table in-place, + * we'd like to re-use the information in the old integrity table + * instead of recalculating it. But we might overwrite the old + * integrity table when we expand the XML data. Read it into memory + * just in case. */ + if ((write_flags & (WIMLIB_WRITE_FLAG_OVERWRITE | + WIMLIB_WRITE_FLAG_CHECK_INTEGRITY)) == + (WIMLIB_WRITE_FLAG_OVERWRITE | + WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) + && wim_has_integrity_table(wim)) + { + old_lookup_table_end = wim->hdr.lookup_table_reshdr.offset_in_wim + + wim->hdr.lookup_table_reshdr.size_in_wim; + (void)read_integrity_table(wim, + old_lookup_table_end - WIM_HEADER_DISK_SIZE, + &old_integrity_table); + /* If we couldn't read the old integrity table, we can still + * re-calculate the full integrity table ourselves. Hence the + * ignoring of the return value. */ + } + + /* Write lookup table. */ if (!(write_flags & WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE)) { ret = write_wim_lookup_table(wim, image, write_flags, &wim->hdr.lookup_table_reshdr, lookup_table_list); - if (ret) + if (ret) { + free_integrity_table(old_integrity_table); return ret; + } } /* Write XML data. */ @@ -2331,8 +2352,10 @@ finish_write(WIMStruct *wim, int image, int write_flags, ret = write_wim_xml_data(wim, image, xml_totalbytes, &wim->hdr.xml_data_reshdr, write_resource_flags); - if (ret) + if (ret) { + free_integrity_table(old_integrity_table); return ret; + } /* Write integrity table (optional). */ if (write_flags & WIMLIB_WRITE_FLAG_CHECK_INTEGRITY) { @@ -2343,20 +2366,10 @@ finish_write(WIMStruct *wim, int image, int write_flags, checkpoint_hdr.flags |= WIM_HDR_FLAG_WRITE_IN_PROGRESS; ret = write_wim_header_at_offset(&checkpoint_hdr, &wim->out_fd, 0); - if (ret) + if (ret) { + free_integrity_table(old_integrity_table); return ret; - } - - if (!(write_flags & WIMLIB_WRITE_FLAG_REUSE_INTEGRITY_TABLE)) - old_lookup_table_end = 0; - - if (wim->hdr.integrity_table_reshdr.offset_in_wim < - wim->hdr.xml_data_reshdr.offset_in_wim + - wim->hdr.xml_data_reshdr.size_in_wim) - { - /* Old integrity table was partially overwritten by the - * XML data. */ - old_lookup_table_end = 0; + } } new_lookup_table_end = wim->hdr.lookup_table_reshdr.offset_in_wim + @@ -2364,7 +2377,9 @@ finish_write(WIMStruct *wim, int image, int write_flags, ret = write_integrity_table(wim, new_lookup_table_end, - old_lookup_table_end); + old_lookup_table_end, + old_integrity_table); + free_integrity_table(old_integrity_table); if (ret) return ret; } else { @@ -3102,7 +3117,6 @@ overwrite_wim_inplace(WIMStruct *wim, int write_flags, unsigned num_threads) if (ret) goto out_truncate; - write_flags |= WIMLIB_WRITE_FLAG_REUSE_INTEGRITY_TABLE; ret = finish_write(wim, WIMLIB_ALL_IMAGES, write_flags, &lookup_table_list); if (ret) -- 2.43.0