X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fwrite.c;h=6ae5599337b9552f556134effd691838feaa3318;hb=1f2091f5bb860769e20105af2d9eff3a0872c57b;hp=43e81b677ea57848759cbd2a86b11127f69e98dd;hpb=34a91e36924e10b924117d91acd116ade58df0b4;p=wimlib diff --git a/src/write.c b/src/write.c index 43e81b67..6ae55993 100644 --- a/src/write.c +++ b/src/write.c @@ -339,12 +339,6 @@ write_wim_resource(struct wim_lookup_table_entry *lte, flags &= ~WIMLIB_RESOURCE_FLAG_RECOMPRESS; - if (wim_resource_size(lte) == 0) { - /* Empty resource; nothing needs to be done, so just return - * success. */ - return 0; - } - /* Get current position in output WIM */ offset = ftello(out_fp); if (offset == -1) { @@ -621,11 +615,11 @@ do_write_stream_list(struct list_head *stream_list, struct wim_lookup_table *lookup_table, FILE *out_fp, int out_ctype, + int write_resource_flags, wimlib_progress_func_t progress_func, - union wimlib_progress_info *progress, - int write_resource_flags) + union wimlib_progress_info *progress) { - int ret; + int ret = 0; struct wim_lookup_table_entry *lte; /* For each stream in @stream_list ... */ @@ -645,7 +639,7 @@ do_write_stream_list(struct list_head *stream_list, lookup_table, &tmp); if (ret) - return ret; + break; if (tmp != lte) { lte = tmp; /* We found a duplicate stream. */ @@ -674,7 +668,7 @@ do_write_stream_list(struct list_head *stream_list, <e->output_resource_entry, write_resource_flags); if (ret) - return ret; + break; if (lte->unhashed) { list_del(<e->unhashed_list); lookup_table_insert(lookup_table, lte); @@ -685,7 +679,7 @@ do_write_stream_list(struct list_head *stream_list, progress_func, wim_resource_size(lte)); } - return 0; + return ret; } static int @@ -707,8 +701,10 @@ write_stream_list_serial(struct list_head *stream_list, return do_write_stream_list(stream_list, lookup_table, out_fp, - out_ctype, progress_func, - progress, write_resource_flags); + out_ctype, + write_resource_flags, + progress_func, + progress); } #ifdef ENABLE_MULTITHREADED_COMPRESSION @@ -1268,6 +1264,10 @@ write_stream_list(struct list_head *stream_list, if (list_empty(stream_list)) return 0; + /* Calculate the total size of the streams to be written. Note: this + * will be the uncompressed size, as we may not know the compressed size + * yet, and also this will assume that every unhashed stream will be + * written (which will not necessarily be the case). */ list_for_each_entry(lte, stream_list, write_streams_list) { num_streams++; total_bytes += wim_resource_size(lte); @@ -1336,15 +1336,15 @@ stream_size_table_insert(struct wim_lookup_table_entry *lte, void *_tab) { struct stream_size_table *tab = _tab; size_t pos; - struct wim_lookup_table_entry *hashed_lte; + struct wim_lookup_table_entry *same_size_lte; struct hlist_node *tmp; pos = hash_u64(wim_resource_size(lte)) % tab->capacity; lte->unique_size = 1; - hlist_for_each_entry(hashed_lte, tmp, &tab->array[pos], hash_list_2) { - if (wim_resource_size(hashed_lte) == wim_resource_size(lte)) { + hlist_for_each_entry(same_size_lte, tmp, &tab->array[pos], hash_list_2) { + if (wim_resource_size(same_size_lte) == wim_resource_size(lte)) { lte->unique_size = 0; - hashed_lte->unique_size = 0; + same_size_lte->unique_size = 0; break; } } @@ -1362,14 +1362,34 @@ struct lte_overwrite_prepare_args { struct stream_size_table stream_size_tab; }; +/* First phase of preparing streams for an in-place overwrite. This is called + * on all streams, both hashed and unhashed, except the metadata resources. */ static int -lte_overwrite_prepare(struct wim_lookup_table_entry *lte, void *arg) +lte_overwrite_prepare(struct wim_lookup_table_entry *lte, void *_args) { - struct lte_overwrite_prepare_args *args = arg; + struct lte_overwrite_prepare_args *args = _args; - if (lte->resource_location == RESOURCE_IN_WIM && - lte->wim == args->wim) - { + wimlib_assert(!(lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)); + if (lte->resource_location != RESOURCE_IN_WIM || lte->wim != args->wim) + list_add_tail(<e->write_streams_list, &args->stream_list); + lte->out_refcnt = lte->refcnt; + stream_size_table_insert(lte, &args->stream_size_tab); + return 0; +} + +/* Second phase of preparing streams for an in-place overwrite. This is called + * on existing metadata resources and hashed streams, but not unhashed streams. + * + * NOTE: lte->output_resource_entry is in union with lte->hash_list_2, so + * lte_overwrite_prepare_2() must be called after lte_overwrite_prepare(), as + * the latter uses lte->hash_list_2, while the former expects to set + * lte->output_resource_entry. */ +static int +lte_overwrite_prepare_2(struct wim_lookup_table_entry *lte, void *_args) +{ + struct lte_overwrite_prepare_args *args = _args; + + if (lte->resource_location == RESOURCE_IN_WIM && lte->wim == args->wim) { /* We can't do an in place overwrite on the WIM if there are * streams after the XML data. */ if (lte->resource_entry.offset + @@ -1381,19 +1401,6 @@ lte_overwrite_prepare(struct wim_lookup_table_entry *lte, void *arg) #endif return WIMLIB_ERR_RESOURCE_ORDER; } - } else { - wimlib_assert(!(lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA)); - list_add_tail(<e->write_streams_list, &args->stream_list); - } - lte->out_refcnt = lte->refcnt; - stream_size_table_insert(lte, &args->stream_size_tab); - return 0; -} - -static int -lte_set_output_res_entry(struct wim_lookup_table_entry *lte, void *_wim) -{ - if (lte->resource_location == RESOURCE_IN_WIM && lte->wim == _wim) { copy_resource_entry(<e->output_resource_entry, <e->resource_entry); } @@ -1419,6 +1426,7 @@ prepare_streams_for_overwrite(WIMStruct *wim, off_t end_offset, { int ret; struct lte_overwrite_prepare_args args; + unsigned i; args.wim = wim; args.end_offset = end_offset; @@ -1428,28 +1436,25 @@ prepare_streams_for_overwrite(WIMStruct *wim, off_t end_offset, return ret; INIT_LIST_HEAD(&args.stream_list); - for (int i = 0; i < wim->hdr.image_count; i++) { + for (i = 0; i < wim->hdr.image_count; i++) { struct wim_image_metadata *imd; struct wim_lookup_table_entry *lte; imd = wim->image_metadata[i]; - image_for_each_unhashed_stream(lte, imd) { - ret = lte_overwrite_prepare(lte, &args); - if (ret) - goto out_destroy_stream_size_table; - } + image_for_each_unhashed_stream(lte, imd) + lte_overwrite_prepare(lte, &args); + } + for_lookup_table_entry(wim->lookup_table, lte_overwrite_prepare, &args); + list_transfer(&args.stream_list, stream_list); + + for (i = 0; i < wim->hdr.image_count; i++) { + ret = lte_overwrite_prepare_2(wim->image_metadata[i]->metadata_lte, + &args); + if (ret) + goto out_destroy_stream_size_table; } ret = for_lookup_table_entry(wim->lookup_table, - lte_overwrite_prepare, &args); - if (ret) - goto out_destroy_stream_size_table; - - for (int i = 0; i < wim->hdr.image_count; i++) - lte_set_output_res_entry(wim->image_metadata[i]->metadata_lte, - wim); - for_lookup_table_entry(wim->lookup_table, lte_set_output_res_entry, wim); - INIT_LIST_HEAD(stream_list); - list_splice(&args.stream_list, stream_list); + lte_overwrite_prepare_2, &args); out_destroy_stream_size_table: destroy_stream_size_table(&args.stream_size_tab); return ret; @@ -1484,8 +1489,8 @@ inode_find_streams_to_write(struct wim_inode *inode, static int image_find_streams_to_write(WIMStruct *w) { - struct wim_image_metadata *imd; struct find_streams_ctx *ctx; + struct wim_image_metadata *imd; struct wim_inode *inode; struct wim_lookup_table_entry *lte; @@ -1535,10 +1540,8 @@ prepare_stream_list(WIMStruct *wim, int image, struct list_head *stream_list) wim->private = &ctx; ret = for_image(wim, image, image_find_streams_to_write); destroy_stream_size_table(&ctx.stream_size_tab); - if (ret == 0) { - INIT_LIST_HEAD(stream_list); - list_splice(&ctx.stream_list, stream_list); - } + if (ret == 0) + list_transfer(&ctx.stream_list, stream_list); return ret; } @@ -1622,13 +1625,11 @@ finish_write(WIMStruct *w, int image, int write_flags, * it should be a copy of the resource entry for the image that is * marked as bootable. This is not well documented... */ if (hdr.boot_idx == 0) { - memset(&hdr.boot_metadata_res_entry, 0, - sizeof(struct resource_entry)); + zero_resource_entry(&hdr.boot_metadata_res_entry); } else { - memcpy(&hdr.boot_metadata_res_entry, - &w->image_metadata[ - hdr.boot_idx - 1]->metadata_lte->output_resource_entry, - sizeof(struct resource_entry)); + copy_resource_entry(&hdr.boot_metadata_res_entry, + &w->image_metadata[ hdr.boot_idx- 1 + ]->metadata_lte->output_resource_entry); } if (!(write_flags & WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE)) { @@ -1648,7 +1649,7 @@ finish_write(WIMStruct *w, int image, int write_flags, if (write_flags & WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML) { struct wim_header checkpoint_hdr; memcpy(&checkpoint_hdr, &hdr, sizeof(struct wim_header)); - memset(&checkpoint_hdr.integrity, 0, sizeof(struct resource_entry)); + zero_resource_entry(&checkpoint_hdr.integrity); if (fseeko(out, 0, SEEK_SET)) { ERROR_WITH_ERRNO("Failed to seek to beginning " "of WIM being written"); @@ -1692,7 +1693,7 @@ finish_write(WIMStruct *w, int image, int write_flags, if (ret) goto out_close_wim; } else { - memset(&hdr.integrity, 0, sizeof(struct resource_entry)); + zero_resource_entry(&hdr.integrity); } if (fseeko(out, 0, SEEK_SET) != 0) { @@ -1923,6 +1924,7 @@ overwrite_wim_inplace(WIMStruct *w, int write_flags, int ret; struct list_head stream_list; off_t old_wim_end; + u64 old_lookup_table_end, old_xml_begin, old_xml_end; DEBUG("Overwriting `%"TS"' in-place", w->filename); @@ -1930,33 +1932,45 @@ overwrite_wim_inplace(WIMStruct *w, int write_flags, * data, and that there are no stream resources, metadata resources, or * lookup tables after the XML data. Otherwise, these data would be * overwritten. */ - if (w->hdr.integrity.offset != 0 && - w->hdr.integrity.offset < w->hdr.xml_res_entry.offset) { + old_xml_begin = w->hdr.xml_res_entry.offset; + old_xml_end = old_xml_begin + w->hdr.xml_res_entry.size; + old_lookup_table_end = w->hdr.lookup_table_res_entry.offset + + w->hdr.lookup_table_res_entry.size; + if (w->hdr.integrity.offset != 0 && w->hdr.integrity.offset < old_xml_end) { ERROR("Didn't expect the integrity table to be before the XML data"); return WIMLIB_ERR_RESOURCE_ORDER; } - if (w->hdr.lookup_table_res_entry.offset > w->hdr.xml_res_entry.offset) { + if (old_lookup_table_end > old_xml_begin) { ERROR("Didn't expect the lookup table to be after the XML data"); return WIMLIB_ERR_RESOURCE_ORDER; } - - if (w->hdr.integrity.offset) - old_wim_end = w->hdr.integrity.offset + w->hdr.integrity.size; - else - old_wim_end = w->hdr.xml_res_entry.offset + w->hdr.xml_res_entry.size; - + /* Set @old_wim_end, which indicates the point beyond which we don't + * allow any file and metadata resources to appear without returning + * WIMLIB_ERR_RESOURCE_ORDER (due to the fact that we would otherwise + * overwrite these resources). */ if (!w->deletion_occurred && !any_images_modified(w)) { /* If no images have been modified and no images have been - * deleted, a new lookup table does not need to be written. */ + * deleted, a new lookup table does not need to be written. We + * shall write the new XML data and optional integrity table + * immediately after the lookup table. Note that this may + * overwrite an existing integrity table. */ DEBUG("Skipping writing lookup table " "(no images modified or deleted)"); - old_wim_end = w->hdr.lookup_table_res_entry.offset + - w->hdr.lookup_table_res_entry.size; + old_wim_end = old_lookup_table_end; write_flags |= WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE | WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML; + } else if (w->hdr.integrity.offset) { + /* Old WIM has an integrity table; begin writing new streams + * after it. */ + old_wim_end = w->hdr.integrity.offset + w->hdr.integrity.size; + } else { + /* No existing integrity table; begin writing new streams after + * the old XML data. */ + old_wim_end = old_xml_end; } + ret = prepare_streams_for_overwrite(w, old_wim_end, &stream_list); if (ret) return ret; @@ -1968,15 +1982,13 @@ overwrite_wim_inplace(WIMStruct *w, int write_flags, ret = lock_wim(w, w->out_fp); if (ret) { - fclose(w->out_fp); - w->out_fp = NULL; + close_wim_writable(w); return ret; } if (fseeko(w->out_fp, old_wim_end, SEEK_SET) != 0) { ERROR_WITH_ERRNO("Can't seek to end of WIM"); - fclose(w->out_fp); - w->out_fp = NULL; + close_wim_writable(w); w->wim_locked = 0; return WIMLIB_ERR_WRITE; } @@ -1991,20 +2003,20 @@ overwrite_wim_inplace(WIMStruct *w, int write_flags, num_threads, progress_func); if (ret) - goto out_ftruncate; + goto out_truncate; for (int i = 0; i < w->hdr.image_count; i++) { if (w->image_metadata[i]->modified) { select_wim_image(w, i + 1); ret = write_metadata_resource(w); if (ret) - goto out_ftruncate; + goto out_truncate; } } write_flags |= WIMLIB_WRITE_FLAG_REUSE_INTEGRITY_TABLE; ret = finish_write(w, WIMLIB_ALL_IMAGES, write_flags, progress_func); -out_ftruncate: +out_truncate: close_wim_writable(w); if (ret != 0 && !(write_flags & WIMLIB_WRITE_FLAG_NO_LOOKUP_TABLE)) { WARNING("Truncating `%"TS"' to its original size (%"PRIu64" bytes)", @@ -2038,9 +2050,9 @@ overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags, ret = wimlib_write(w, tmpfile, WIMLIB_ALL_IMAGES, write_flags | WIMLIB_WRITE_FLAG_FSYNC, num_threads, progress_func); - if (ret != 0) { + if (ret) { ERROR("Failed to write the WIM file `%"TS"'", tmpfile); - goto err; + goto out_unlink; } DEBUG("Renaming `%"TS"' to `%"TS"'", tmpfile, w->filename); @@ -2061,7 +2073,7 @@ overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags, ERROR_WITH_ERRNO("Failed to rename `%"TS"' to `%"TS"'", tmpfile, w->filename); ret = WIMLIB_ERR_RENAME; - goto err; + goto out_unlink; } if (progress_func) { @@ -2086,11 +2098,12 @@ overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags, FREE(w->filename); w->filename = NULL; } - return ret; -err: + goto out; +out_unlink: /* Remove temporary file. */ if (tunlink(tmpfile) != 0) WARNING_WITH_ERRNO("Failed to remove `%"TS"'", tmpfile); +out: return ret; }