+ ret = finish_write(w, image, write_flags);
+ if (ret == 0 && (write_flags & WIMLIB_WRITE_FLAG_SHOW_PROGRESS))
+ printf("Successfully wrote `%s'\n", path);
+out:
+ close_wim_writable(w);
+ return ret;
+}
+
+static int lte_overwrite_prepare(struct lookup_table_entry *lte,
+ void *ignore)
+{
+ memcpy(<e->output_resource_entry, <e->resource_entry,
+ sizeof(struct resource_entry));
+ lte->out_refcnt = 0;
+ return 0;
+}
+
+static int check_resource_offset(struct lookup_table_entry *lte, void *arg)
+{
+ off_t end_offset = *(u64*)arg;
+
+ wimlib_assert(lte->out_refcnt <= lte->refcnt);
+ if (lte->out_refcnt < lte->refcnt) {
+ if (lte->resource_entry.offset + lte->resource_entry.size > end_offset) {
+ ERROR("The following resource is after the XML data:");
+ print_lookup_table_entry(lte);
+ return WIMLIB_ERR_RESOURCE_ORDER;
+ }
+ }
+ return 0;
+}
+
+static int find_new_streams(struct lookup_table_entry *lte, void *arg)
+{
+ if (lte->out_refcnt == lte->refcnt)
+ list_add(<e->staging_list, (struct list_head*)arg);
+ else
+ lte->out_refcnt = lte->refcnt;
+ return 0;
+}
+
+/*
+ * Overwrite a WIM, possibly appending streams to it.
+ *
+ * A WIM looks like (or is supposed to look like) the following:
+ *
+ * Header (212 bytes)
+ * Streams and metadata resources (variable size)
+ * Lookup table (variable size)
+ * XML data (variable size)
+ * Integrity table (optional) (variable size)
+ *
+ * If we are not adding any streams or metadata resources, the lookup table is
+ * unchanged--- so we only need to overwrite the XML data, integrity table, and
+ * header. This operation is potentially unsafe if the program is abruptly
+ * terminated while the XML data or integrity table are being overwritten, but
+ * before the new header has been written. To partially alleviate this problem,
+ * a special flag (WIMLIB_WRITE_FLAG_CHECKPOINT_AFTER_XML) is passed to
+ * finish_write() to cause a temporary WIM header to be written after the XML
+ * data has been written. This may prevent the WIM from becoming corrupted if
+ * the program is terminated while the integrity table is being calculated (but
+ * no guarantees, due to write re-ordering...).
+ *
+ * If we are adding new streams or images (metadata resources), the lookup table
+ * needs to be changed, and those streams need to be written. In this case, we
+ * try to perform a safe update of the WIM file by writing the streams *after*
+ * the end of the previous WIM, then writing the new lookup table, XML data, and
+ * (optionally) integrity table following the new streams. This will produce a
+ * layout like the following:
+ *
+ * Header (212 bytes)
+ * (OLD) Streams and metadata resources (variable size)
+ * (OLD) Lookup table (variable size)
+ * (OLD) XML data (variable size)
+ * (OLD) Integrity table (optional) (variable size)
+ * (NEW) Streams and metadata resources (variable size)
+ * (NEW) Lookup table (variable size)
+ * (NEW) XML data (variable size)
+ * (NEW) Integrity table (optional) (variable size)
+ *
+ * At all points, the WIM is valid as nothing points to the new data yet. Then,
+ * the header is overwritten to point to the new lookup table, XML data, and
+ * integrity table, to produce the following layout:
+ *
+ * Header (212 bytes)
+ * Streams and metadata resources (variable size)
+ * Nothing (variable size)
+ * More Streams and metadata resources (variable size)
+ * Lookup table (variable size)
+ * XML data (variable size)
+ * Integrity table (optional) (variable size)
+ *
+ * This method allows an image to be appended to a large WIM very quickly, and
+ * is is crash-safe except in the case of write re-ordering, but the
+ * disadvantage is that a small hole is left in the WIM where the old lookup
+ * table, xml data, and integrity table were. (These usually only take up a
+ * small amount of space compared to the streams, however.
+ */
+static int overwrite_wim_inplace(WIMStruct *w, int write_flags,
+ unsigned num_threads,
+ int modified_image_idx)
+{
+ int ret;
+ struct list_head stream_list;
+ off_t old_wim_end;
+
+ DEBUG("Overwriting `%s' in-place", w->filename);
+
+ /* Make sure that the integrity table (if present) is after the XML
+ * 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) {
+ 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) {
+ ERROR("Didn't expect the lookup table to be after the XML data");
+ return WIMLIB_ERR_RESOURCE_ORDER;
+ }
+
+ DEBUG("Identifying newly added streams");
+ for_lookup_table_entry(w->lookup_table, lte_overwrite_prepare, NULL);
+ INIT_LIST_HEAD(&stream_list);
+ for (int i = modified_image_idx; i < w->hdr.image_count; i++) {
+ DEBUG("Identifiying streams in image %d", i + 1);
+ wimlib_assert(w->image_metadata[i].modified);
+ wimlib_assert(!w->image_metadata[i].has_been_mounted_rw);
+ wimlib_assert(w->image_metadata[i].root_dentry != NULL);
+ wimlib_assert(w->image_metadata[i].metadata_lte != NULL);
+ w->private = &stream_list;
+ for_dentry_in_tree(w->image_metadata[i].root_dentry,
+ dentry_find_streams_to_write, w);
+ }
+
+ 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;
+
+ ret = for_lookup_table_entry(w->lookup_table, check_resource_offset,
+ &old_wim_end);
+ if (ret != 0)