+ filter_ctx_ret->write_flags = write_flags;
+ filter_ctx_ret->wim = wim;
+
+ ret = prepare_unfiltered_list_of_blobs_in_output_wim(
+ wim,
+ image,
+ write_flags & WIMLIB_WRITE_FLAG_STREAMS_OK,
+ blob_list_ret);
+ if (ret)
+ return ret;
+
+ INIT_LIST_HEAD(blob_table_list_ret);
+ list_for_each_entry(blob, blob_list_ret, write_blobs_list)
+ list_add_tail(&blob->blob_table_list, blob_table_list_ret);
+
+ ret = determine_blob_size_uniquity(blob_list_ret, wim->blob_table,
+ filter_ctx_ret);
+ if (ret)
+ return ret;
+
+ if (may_filter_blobs(filter_ctx_ret))
+ filter_blob_list_for_write(blob_list_ret, filter_ctx_ret);
+
+ return 0;
+}
+
+static int
+write_file_data(WIMStruct *wim, int image, int write_flags,
+ unsigned num_threads,
+ struct list_head *blob_list_override,
+ struct list_head *blob_table_list_ret)
+{
+ int ret;
+ struct list_head _blob_list;
+ struct list_head *blob_list;
+ struct blob_descriptor *blob;
+ struct filter_context _filter_ctx;
+ struct filter_context *filter_ctx;
+
+ if (blob_list_override == NULL) {
+ /* Normal case: prepare blob list from image(s) being written.
+ */
+ blob_list = &_blob_list;
+ filter_ctx = &_filter_ctx;
+ ret = prepare_blob_list_for_write(wim, image, write_flags,
+ blob_list,
+ blob_table_list_ret,
+ filter_ctx);
+ if (ret)
+ return ret;
+ } else {
+ /* Currently only as a result of wimlib_split() being called:
+ * use blob list already explicitly provided. Use existing
+ * reference counts. */
+ blob_list = blob_list_override;
+ filter_ctx = NULL;
+ INIT_LIST_HEAD(blob_table_list_ret);
+ list_for_each_entry(blob, blob_list, write_blobs_list) {
+ blob->out_refcnt = blob->refcnt;
+ blob->will_be_in_output_wim = 1;
+ blob->unique_size = 0;
+ list_add_tail(&blob->blob_table_list, blob_table_list_ret);
+ }
+ }
+
+ return write_file_data_blobs(wim,
+ blob_list,
+ write_flags,
+ num_threads,
+ filter_ctx);
+}
+
+static int
+write_metadata_resources(WIMStruct *wim, int image, int write_flags)
+{
+ int ret;
+ int start_image;
+ int end_image;
+ int write_resource_flags;
+
+ if (write_flags & WIMLIB_WRITE_FLAG_NO_METADATA)
+ return 0;
+
+ write_resource_flags = write_flags_to_resource_flags(write_flags);
+
+ write_resource_flags &= ~WRITE_RESOURCE_FLAG_SOLID;
+
+ ret = call_progress(wim->progfunc,
+ WIMLIB_PROGRESS_MSG_WRITE_METADATA_BEGIN,
+ NULL, wim->progctx);
+ if (ret)
+ return ret;
+
+ if (image == WIMLIB_ALL_IMAGES) {
+ start_image = 1;
+ end_image = wim->hdr.image_count;
+ } else {
+ start_image = image;
+ end_image = image;
+ }
+
+ for (int i = start_image; i <= end_image; i++) {
+ struct wim_image_metadata *imd;
+
+ imd = wim->image_metadata[i - 1];
+ /* Build a new metadata resource only if image was modified from
+ * the original (or was newly added). Otherwise just copy the
+ * existing one. */
+ if (imd->modified) {
+ ret = write_metadata_resource(wim, i,
+ write_resource_flags);
+ } else if (write_flags & WIMLIB_WRITE_FLAG_APPEND) {
+ blob_set_out_reshdr_for_reuse(imd->metadata_blob);
+ ret = 0;
+ } else {
+ ret = write_wim_resource(imd->metadata_blob,
+ &wim->out_fd,
+ wim->out_compression_type,
+ wim->out_chunk_size,
+ write_resource_flags);
+ }
+ if (ret)
+ return ret;
+ }
+
+ return call_progress(wim->progfunc,
+ WIMLIB_PROGRESS_MSG_WRITE_METADATA_END,
+ NULL, wim->progctx);
+}
+
+static int
+open_wim_writable(WIMStruct *wim, const tchar *path, int open_flags)
+{
+ int raw_fd = topen(path, open_flags | O_BINARY, 0644);
+ if (raw_fd < 0) {
+ ERROR_WITH_ERRNO("Failed to open \"%"TS"\" for writing", path);
+ return WIMLIB_ERR_OPEN;
+ }
+ filedes_init(&wim->out_fd, raw_fd);
+ return 0;
+}
+
+static int
+close_wim_writable(WIMStruct *wim, int write_flags)
+{
+ int ret = 0;
+
+ if (!(write_flags & WIMLIB_WRITE_FLAG_FILE_DESCRIPTOR))
+ if (filedes_valid(&wim->out_fd))
+ if (filedes_close(&wim->out_fd))
+ ret = WIMLIB_ERR_WRITE;
+ filedes_invalidate(&wim->out_fd);
+ return ret;
+}
+
+static int
+cmp_blobs_by_out_rdesc(const void *p1, const void *p2)
+{
+ const struct blob_descriptor *blob1, *blob2;
+
+ blob1 = *(const struct blob_descriptor**)p1;
+ blob2 = *(const struct blob_descriptor**)p2;
+
+ if (blob1->out_reshdr.flags & WIM_RESHDR_FLAG_SOLID) {
+ if (blob2->out_reshdr.flags & WIM_RESHDR_FLAG_SOLID) {
+ if (blob1->out_res_offset_in_wim != blob2->out_res_offset_in_wim)
+ return cmp_u64(blob1->out_res_offset_in_wim,
+ blob2->out_res_offset_in_wim);
+ } else {
+ return 1;
+ }
+ } else {
+ if (blob2->out_reshdr.flags & WIM_RESHDR_FLAG_SOLID)
+ return -1;
+ }
+ return cmp_u64(blob1->out_reshdr.offset_in_wim,
+ blob2->out_reshdr.offset_in_wim);
+}
+
+static int
+write_blob_table(WIMStruct *wim, int image, int write_flags,
+ struct list_head *blob_table_list)
+{
+ int ret;
+
+ /* Set output resource metadata for blobs already present in WIM. */
+ if (write_flags & WIMLIB_WRITE_FLAG_APPEND) {
+ struct blob_descriptor *blob;
+ list_for_each_entry(blob, blob_table_list, blob_table_list) {
+ if (blob->blob_location == BLOB_IN_WIM &&
+ blob->rdesc->wim == wim)
+ {
+ blob_set_out_reshdr_for_reuse(blob);
+ }
+ }
+ }
+
+ ret = sort_blob_list(blob_table_list,
+ offsetof(struct blob_descriptor, blob_table_list),
+ cmp_blobs_by_out_rdesc);
+ if (ret)
+ return ret;
+
+ /* Add entries for metadata resources. */
+ if (!(write_flags & WIMLIB_WRITE_FLAG_NO_METADATA)) {
+ int start_image;
+ int end_image;
+
+ if (image == WIMLIB_ALL_IMAGES) {
+ start_image = 1;
+ end_image = wim->hdr.image_count;
+ } else {
+ start_image = image;
+ end_image = image;
+ }
+
+ /* Push metadata blob table entries onto the front of the list
+ * in reverse order, so that they're written in order.
+ */
+ for (int i = end_image; i >= start_image; i--) {
+ struct blob_descriptor *metadata_blob;
+
+ metadata_blob = wim->image_metadata[i - 1]->metadata_blob;
+ wimlib_assert(metadata_blob->out_reshdr.flags & WIM_RESHDR_FLAG_METADATA);
+ metadata_blob->out_refcnt = 1;
+ list_add(&metadata_blob->blob_table_list, blob_table_list);