+static void
+unload_image_metadata(struct wim_image_metadata *imd)
+{
+ free_dentry_tree(imd->root_dentry, NULL);
+ imd->root_dentry = NULL;
+ free_wim_security_data(imd->security_data);
+ imd->security_data = NULL;
+ INIT_HLIST_HEAD(&imd->inode_list);
+}
+
+/* Release a reference to the specified image metadata. This assumes that no
+ * WIMStruct has the image selected. */
+void
+put_image_metadata(struct wim_image_metadata *imd)
+{
+ struct blob_descriptor *blob, *tmp;
+
+ if (!imd)
+ return;
+ wimlib_assert(imd->refcnt > 0);
+ if (--imd->refcnt != 0)
+ return;
+ wimlib_assert(imd->selected_refcnt == 0);
+ unload_image_metadata(imd);
+ list_for_each_entry_safe(blob, tmp, &imd->unhashed_blobs, unhashed_list)
+ free_blob_descriptor(blob);
+ free_blob_descriptor(imd->metadata_blob);
+ FREE(imd);
+}
+
+/* Appends the specified image metadata structure to the array of image metadata
+ * for a WIM, and increments the image count. */
+int
+append_image_metadata(WIMStruct *wim, struct wim_image_metadata *imd)
+{
+ struct wim_image_metadata **imd_array;
+
+ if (!wim_has_metadata(wim))
+ return WIMLIB_ERR_METADATA_NOT_FOUND;
+
+ if (wim->hdr.image_count >= MAX_IMAGES)
+ return WIMLIB_ERR_IMAGE_COUNT;
+
+ imd_array = REALLOC(wim->image_metadata,
+ sizeof(wim->image_metadata[0]) * (wim->hdr.image_count + 1));
+
+ if (!imd_array)
+ return WIMLIB_ERR_NOMEM;
+ wim->image_metadata = imd_array;
+ imd_array[wim->hdr.image_count++] = imd;
+ return 0;
+}
+
+static struct wim_image_metadata *
+new_image_metadata(struct blob_descriptor *metadata_blob,
+ struct wim_security_data *security_data)
+{
+ struct wim_image_metadata *imd;
+
+ imd = CALLOC(1, sizeof(*imd));
+ if (!imd)
+ return NULL;
+
+ metadata_blob->is_metadata = 1;
+ imd->refcnt = 1;
+ imd->selected_refcnt = 0;
+ imd->root_dentry = NULL;
+ imd->security_data = security_data;
+ imd->metadata_blob = metadata_blob;
+ INIT_HLIST_HEAD(&imd->inode_list);
+ INIT_LIST_HEAD(&imd->unhashed_blobs);
+ imd->stats_outdated = false;
+ return imd;
+}
+
+/* Create an image metadata structure for a new empty image. */
+struct wim_image_metadata *
+new_empty_image_metadata(void)
+{
+ struct blob_descriptor *metadata_blob;
+ struct wim_security_data *security_data;
+ struct wim_image_metadata *imd;
+
+ metadata_blob = new_blob_descriptor();
+ security_data = new_wim_security_data();
+ if (metadata_blob && security_data) {
+ metadata_blob->refcnt = 1;
+ imd = new_image_metadata(metadata_blob, security_data);
+ if (imd)
+ return imd;
+ }
+ free_blob_descriptor(metadata_blob);
+ FREE(security_data);
+ return NULL;
+}
+
+/* Create an image metadata structure that refers to the specified metadata
+ * resource and is initially not loaded. */
+struct wim_image_metadata *
+new_unloaded_image_metadata(struct blob_descriptor *metadata_blob)
+{
+ wimlib_assert(metadata_blob->blob_location == BLOB_IN_WIM);
+ return new_image_metadata(metadata_blob, NULL);
+}
+
+/*
+ * Load the metadata for the specified WIM image into memory and set it
+ * as the WIMStruct's currently selected image.
+ *
+ * @wim
+ * The WIMStruct for the WIM.
+ * @image
+ * The 1-based index of the image in the WIM to select.
+ *
+ * On success, 0 will be returned, wim->current_image will be set to
+ * @image, and wim_get_current_image_metadata() can be used to retrieve
+ * metadata information for the image.
+ *
+ * On failure, WIMLIB_ERR_INVALID_IMAGE, WIMLIB_ERR_METADATA_NOT_FOUND,
+ * or another error code will be returned.
+ */