+ ret = begin_write(w, path, write_flags);
+ if (ret)
+ goto out_close_wim;
+
+ ret = write_wim_streams(w, image, write_flags, num_threads,
+ progress_func);
+ if (ret)
+ goto out_close_wim;
+
+ if (progress_func)
+ progress_func(WIMLIB_PROGRESS_MSG_WRITE_METADATA_BEGIN, NULL);
+
+ ret = for_image(w, image, write_metadata_resource);
+ if (ret)
+ goto out_close_wim;
+
+ if (progress_func)
+ progress_func(WIMLIB_PROGRESS_MSG_WRITE_METADATA_END, NULL);
+
+ ret = finish_write(w, image, write_flags, progress_func);
+ /* finish_write() closed the WIM for us */
+ goto out;
+out_close_wim:
+ close_wim_writable(w);
+out:
+ DEBUG("wimlib_write(path=%"TS") = %d", path, ret);
+ return ret;
+}
+
+static bool
+any_images_modified(WIMStruct *w)
+{
+ for (int i = 0; i < w->hdr.image_count; i++)
+ if (w->image_metadata[i]->modified)
+ return true;
+ return false;
+}
+
+/*
+ * 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,
+ wimlib_progress_func_t progress_func)
+{
+ int ret;
+ struct list_head stream_list;
+ off_t old_wim_end;
+
+ DEBUG("Overwriting `%"TS"' 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;
+ }
+
+
+ if (w->hdr.integrity.offset)
+ old_wim_end = w->hdr.integrity.offset + w->hdr.integrity.size;