/* Links blobs being exported. */
struct list_head export_blob_list;
-
- /* Links original list of blobs in the read-write mounted image. */
- struct list_head orig_blob_list;
};
};
#include "wimlib/types.h"
#include "wimlib/wim.h"
-/* Metadata for a WIM image */
+/*
+ * This structure holds the directory tree that comprises a WIM image, along
+ * with other information maintained at the image level. It is populated either
+ * by reading and parsing a metadata resource or by scanning new files.
+ *
+ * An image that hasn't been modified from its on-disk copy is considered
+ * "clean" and is loaded from its metadata resource on demand by
+ * select_wim_image(). Such an image may be unloaded later to save memory when
+ * a different image is selected. An image that has been modified or has been
+ * created from scratch, on the other hand, is considered "dirty" and is never
+ * automatically unloaded.
+ *
+ * To implement exports, it's allowed that multiple WIMStructs reference the
+ * same wim_image_metadata.
+ */
struct wim_image_metadata {
- /* Number of WIMStruct's that are sharing this image metadata (from
- * calls to wimlib_export_image().) */
- unsigned long refcnt;
+ /* Number of WIMStructs that reference this image. This will always be
+ * >= 1. It may be > 1 if this image has been exported. */
+ u32 refcnt;
- /* Pointer to the root dentry of the image. */
+ /* Number of WIMStructs that have this image selected as their
+ * current_image. This will always be <= 'refcnt' and may be 0. */
+ u32 selected_refcnt;
+
+ /* Pointer to the root dentry of this image, or NULL if this image is
+ * completely empty or is not currently loaded. */
struct wim_dentry *root_dentry;
- /* Pointer to the security data of the image. */
+ /* Pointer to the security data of this image, or NULL if this image is
+ * not currently loaded. */
struct wim_security_data *security_data;
/* Pointer to the blob descriptor for this image's metadata resource.
* with blob_location==BLOB_NONEXISTENT. */
struct blob_descriptor *metadata_blob;
- /* Linked list of 'struct wim_inode's for this image. */
+ /* Linked list of 'struct wim_inode's for this image, or an empty list
+ * if this image is completely empty or is not currently loaded. */
struct hlist_head inode_list;
/* Linked list of 'struct blob_descriptor's for blobs that are
imd->stats_outdated = true;
}
+/* Return true iff the specified image is currently loaded into memory. */
+static inline bool
+is_image_loaded(const struct wim_image_metadata *imd)
+{
+ /* Check security_data rather than root_dentry, since root_dentry will
+ * be NULL for a completely empty image whereas security_data will still
+ * be non-NULL in that case. */
+ return imd->security_data != NULL;
+}
+
+/* Return true iff it is okay to unload the specified image. The image can be
+ * unloaded if no WIMStructs have it selected and it is not dirty. */
+static inline bool
+can_unload_image(const struct wim_image_metadata *imd)
+{
+ return imd->selected_refcnt == 0 && !is_image_dirty(imd);
+}
+
/* Iterate over each inode in a WIM image */
#define image_for_each_inode(inode, imd) \
hlist_for_each_entry(inode, &(imd)->inode_list, i_hlist_node)
list_for_each_entry_safe(blob, tmp, &(imd)->unhashed_blobs, unhashed_list)
extern void
-put_image_metadata(struct wim_image_metadata *imd, struct blob_table *table);
+put_image_metadata(struct wim_image_metadata *imd);
extern int
append_image_metadata(WIMStruct *wim, struct wim_image_metadata *imd);
extern struct wim_image_metadata *
-new_image_metadata(void) _malloc_attribute;
+new_empty_image_metadata(void);
+
+extern struct wim_image_metadata *
+new_unloaded_image_metadata(struct blob_descriptor *metadata_blob);
#endif /* _WIMLIB_METADATA_H */
/*
- * add_image.c - Add an image to a WIM file.
+ * add_image.c - Add an image to a WIMStruct.
*/
/*
- * Copyright (C) 2012, 2013, 2014 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
*
* This file is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
#include "wimlib/security.h"
#include "wimlib/xml.h"
-/* Creates and appends a 'struct wim_image_metadata' for an empty image.
- *
- * The resulting image will be the last in the WIM, so its index will be
- * the new value of wim->hdr.image_count. */
-static int
-add_empty_image_metadata(WIMStruct *wim)
-{
- int ret;
- struct blob_descriptor *metadata_blob;
- struct wim_security_data *sd;
- struct wim_image_metadata *imd;
-
- /* Create a blob descriptor for the new metadata resource. */
- ret = WIMLIB_ERR_NOMEM;
- metadata_blob = new_blob_descriptor();
- if (!metadata_blob)
- goto out;
-
- metadata_blob->refcnt = 1;
- metadata_blob->is_metadata = 1;
-
- /* Create empty security data (no security descriptors). */
- sd = new_wim_security_data();
- if (!sd)
- goto out_free_metadata_blob;
-
- imd = new_image_metadata();
- if (!imd)
- goto out_free_security_data;
-
- /* A NULL root_dentry indicates a completely empty image, without even a
- * root directory. */
- imd->root_dentry = NULL;
- imd->metadata_blob = metadata_blob;
- imd->security_data = sd;
-
- /* Append as next image index. */
- ret = append_image_metadata(wim, imd);
- if (ret)
- put_image_metadata(imd, NULL);
- goto out;
-
-out_free_security_data:
- free_wim_security_data(sd);
-out_free_metadata_blob:
- free_blob_descriptor(metadata_blob);
-out:
- return ret;
-}
-
/* API function documented in wimlib.h */
WIMLIBAPI int
wimlib_add_empty_image(WIMStruct *wim, const tchar *name, int *new_idx_ret)
{
+ struct wim_image_metadata *imd;
int ret;
if (wimlib_image_name_in_use(wim, name)) {
return WIMLIB_ERR_IMAGE_NAME_COLLISION;
}
- ret = add_empty_image_metadata(wim);
+ imd = new_empty_image_metadata();
+ if (!imd)
+ return WIMLIB_ERR_NOMEM;
+
+ ret = append_image_metadata(wim, imd);
if (ret)
- return ret;
+ goto err_put_imd;
ret = xml_add_image(wim->xml_info, name);
- if (ret) {
- put_image_metadata(wim->image_metadata[--wim->hdr.image_count],
- NULL);
- return ret;
- }
+ if (ret)
+ goto err_undo_append;
if (new_idx_ret)
*new_idx_ret = wim->hdr.image_count;
return 0;
+
+err_undo_append:
+ wim->hdr.image_count--;
+err_put_imd:
+ put_image_metadata(imd);
+ return ret;
}
/* Translate the 'struct wimlib_capture_source's passed to
*/
/*
- * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
*
* This file is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
}
if (reshdr.flags & WIM_RESHDR_FLAG_METADATA) {
-
- cur_blob->is_metadata = 1;
-
/* Blob table entry for a metadata resource. */
/* Metadata entries with no references must be ignored.
* this overrides the actual locations of the metadata
* resources themselves in the WIM file as well as any
* information written in the XML data. */
- wim->image_metadata[image_index++]->metadata_blob = cur_blob;
+ wim->image_metadata[image_index] = new_unloaded_image_metadata(cur_blob);
+ if (!wim->image_metadata[image_index])
+ goto oom;
+ image_index++;
} else {
/* Blob table entry for a non-metadata blob. */
if (wim->hdr.part_number == 1 && image_index != wim->hdr.image_count) {
WARNING("Could not find metadata resources for all images");
- for (u32 i = image_index; i < wim->hdr.image_count; i++)
- put_image_metadata(wim->image_metadata[i], NULL);
wim->hdr.image_count = image_index;
}
*/
/*
- * Copyright (C) 2012, 2013, 2014 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
*
* This file is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
#include <string.h>
#include "wimlib.h"
+#include "wimlib/dentry.h"
#include "wimlib/metadata.h"
#include "wimlib/wim.h"
#include "wimlib/xml.h"
delete_wim_image(WIMStruct *wim, int image)
{
int ret;
+ struct wim_image_metadata *imd;
/* Load the metadata for the image to be deleted. This is necessary
* because blobs referenced by files in the image need to have their
if (ret)
return ret;
- /* Release the reference to the image metadata and decrement reference
- * counts on the blobs referenced by files in the image. */
- put_image_metadata(wim->image_metadata[image - 1], wim->blob_table);
+ /* Release the files and decrement the reference counts of the blobs
+ * they reference. */
+ imd = wim->image_metadata[image - 1];
+ free_dentry_tree(imd->root_dentry, wim->blob_table);
+ imd->root_dentry = NULL;
+
+ /* Deselect the image and release its metadata. */
+ deselect_current_wim_image(wim);
+ put_image_metadata(imd);
/* Remove the empty slot from the image metadata array. */
memmove(&wim->image_metadata[image - 1], &wim->image_metadata[image],
sizeof(wim->image_metadata[0]));
/* Decrement the image count. */
- --wim->hdr.image_count;
+ wim->hdr.image_count--;
/* Remove the image from the XML information. */
xml_delete_image(wim->xml_info, image);
else if (wim->hdr.boot_idx > image)
wim->hdr.boot_idx--;
- /* The image is no longer valid. */
- wim->current_image = WIMLIB_NO_IMAGE;
return 0;
}
*/
/*
- * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
*
* This file is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
while (dest_wim->hdr.image_count > orig_dest_image_count)
{
put_image_metadata(dest_wim->image_metadata[
- --dest_wim->hdr.image_count], NULL);
+ --dest_wim->hdr.image_count]);
}
for_blob_in_table(dest_wim->blob_table, blob_rollback_export,
dest_wim->blob_table);
*/
/*
- * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
*
* This file is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
return 0;
}
+static int
+handle_pwm_metadata_resource(WIMStruct *pwm, int image, bool is_needed)
+{
+ struct blob_descriptor *blob;
+ struct wim_reshdr reshdr;
+ struct wim_resource_descriptor *rdesc;
+ int ret;
+
+ ret = WIMLIB_ERR_NOMEM;
+ blob = new_blob_descriptor();
+ if (!blob)
+ goto out;
+
+ ret = read_pwm_blob_header(pwm, blob->hash, &reshdr, NULL);
+ if (ret)
+ goto out;
+
+ ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
+ if (!(reshdr.flags & WIM_RESHDR_FLAG_METADATA)) {
+ ERROR("Expected metadata resource, but found non-metadata "
+ "resource");
+ goto out;
+ }
+
+ ret = WIMLIB_ERR_NOMEM;
+ rdesc = MALLOC(sizeof(*rdesc));
+ if (!rdesc)
+ goto out;
+
+ wim_reshdr_to_desc_and_blob(&reshdr, pwm, rdesc, blob);
+ pwm->refcnt++;
+
+ ret = WIMLIB_ERR_NOMEM;
+ pwm->image_metadata[image - 1] = new_unloaded_image_metadata(blob);
+ if (!pwm->image_metadata[image - 1])
+ goto out;
+ blob = NULL;
+
+ /* If the metadata resource is for the image being extracted, then parse
+ * it and save the metadata in memory. Otherwise, skip over it. */
+ if (is_needed)
+ ret = select_wim_image(pwm, image);
+ else
+ ret = skip_wim_resource(rdesc);
+out:
+ free_blob_descriptor(blob);
+ return ret;
+}
+
/* Creates a temporary file opened for writing. The open file descriptor is
* returned in @fd_ret and its name is returned in @name_ret (dynamically
* allocated). */
/* Load the needed metadata resource. */
for (i = 1; i <= pwm->hdr.image_count; i++) {
- struct wim_image_metadata *imd;
- struct wim_reshdr reshdr;
- struct wim_resource_descriptor *metadata_rdesc;
-
- imd = pwm->image_metadata[i - 1];
-
- ret = WIMLIB_ERR_NOMEM;
- imd->metadata_blob = new_blob_descriptor();
- if (!imd->metadata_blob)
- goto out_wimlib_free;
-
- imd->metadata_blob->is_metadata = 1;
-
- ret = read_pwm_blob_header(pwm, imd->metadata_blob->hash,
- &reshdr, NULL);
+ ret = handle_pwm_metadata_resource(pwm, i, i == image);
if (ret)
goto out_wimlib_free;
-
- if (!(reshdr.flags & WIM_RESHDR_FLAG_METADATA)) {
- ERROR("Expected metadata resource, but found "
- "non-metadata resource");
- ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
- goto out_wimlib_free;
- }
-
- ret = WIMLIB_ERR_NOMEM;
- metadata_rdesc = MALLOC(sizeof(struct wim_resource_descriptor));
- if (!metadata_rdesc)
- goto out_wimlib_free;
- wim_reshdr_to_desc_and_blob(&reshdr, pwm, metadata_rdesc,
- imd->metadata_blob);
- pwm->refcnt++;
-
- if (i == image) {
- /* Metadata resource is for the image being extracted.
- * Parse it and save the metadata in memory. */
- ret = read_metadata_resource(imd);
- if (ret)
- goto out_wimlib_free;
- } else {
- /* Metadata resource is not for the image being
- * extracted. Skip over it. */
- ret = skip_wim_resource(metadata_rdesc);
- if (ret)
- goto out_wimlib_free;
- }
}
/* Extract the image. */
extract_flags |= WIMLIB_EXTRACT_FLAG_FROM_PIPE;
*/
/*
- * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
*
* This file is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
/* Number of file descriptors open to the mounted WIM image. */
unsigned long num_open_fds;
- /* Original list of blobs in the mounted image, linked by
- * 'struct blob_descriptor'.orig_blob_list. */
- struct list_head orig_blob_list;
+ /* For read-write mounts, the original metadata resource of the mounted
+ * image. */
+ struct blob_descriptor *metadata_resource;
/* Parameters for unmounting the image (can be set via extended
* attribute "wimfs.unmount_info"). */
}
}
-static void
-release_extra_refcnts(struct wimfs_context *ctx)
-{
- struct list_head *list = &ctx->orig_blob_list;
- struct blob_table *blob_table = ctx->wim->blob_table;
- struct blob_descriptor *blob, *tmp;
-
- list_for_each_entry_safe(blob, tmp, list, orig_blob_list)
- blob_subtract_refcnt(blob, blob_table, blob->out_refcnt);
-}
-
/* Delete the 'struct blob_descriptor' for any stream that was modified
* or created in the read-write mounted image and had a final size of 0. */
static void
renew_current_image(struct wimfs_context *ctx)
{
WIMStruct *wim = ctx->wim;
- int idx = wim->current_image - 1;
- struct wim_image_metadata *imd = wim->image_metadata[idx];
- struct wim_image_metadata *replace_imd;
- struct blob_descriptor *new_blob;
+ int image = wim->current_image;
+ struct wim_image_metadata *imd;
+ struct wim_inode *inode;
int ret;
- /* Create 'replace_imd' structure to use for the reset original,
- * unmodified image. */
ret = WIMLIB_ERR_NOMEM;
- replace_imd = new_image_metadata();
- if (!replace_imd)
+ imd = new_unloaded_image_metadata(ctx->metadata_resource);
+ if (!imd)
goto err;
- /* Create new blob descriptor for the modified image's metadata
- * resource, which doesn't exist yet. */
- ret = WIMLIB_ERR_NOMEM;
- new_blob = new_blob_descriptor();
- if (!new_blob)
- goto err_put_replace_imd;
-
- new_blob->refcnt = 1;
- new_blob->is_metadata = 1;
-
- /* Make the image being moved available at a new index. Increments the
- * WIM's image count, but does not increment the reference count of the
- * 'struct image_metadata'. */
- ret = append_image_metadata(wim, imd);
+ ret = append_image_metadata(wim, wim->image_metadata[image - 1]);
if (ret)
- goto err_free_new_blob;
+ goto err_put_imd;
- ret = xml_add_image(wim->xml_info, NULL);
+ ret = xml_export_image(wim->xml_info, image,
+ wim->xml_info, NULL, NULL, false);
if (ret)
goto err_undo_append;
- replace_imd->metadata_blob = imd->metadata_blob;
- imd->metadata_blob = new_blob;
- wim->image_metadata[idx] = replace_imd;
+ wim->image_metadata[image - 1] = imd;
wim->current_image = wim->hdr.image_count;
+
+ ret = select_wim_image(wim, image);
+ if (ret)
+ goto err_undo_export;
+
+ image_for_each_inode(inode, imd) {
+ for (unsigned i = 0; i < inode->i_num_streams; i++) {
+ struct blob_descriptor *blob;
+
+ blob = stream_blob(&inode->i_streams[i],
+ wim->blob_table);
+ if (blob)
+ blob->refcnt += inode->i_nlink;
+ }
+ }
+
+ select_wim_image(wim, wim->hdr.image_count);
+ ctx->metadata_resource = NULL;
return 0;
+err_undo_export:
+ xml_delete_image(wim->xml_info, wim->hdr.image_count);
+ wim->image_metadata[image - 1] = wim->image_metadata[wim->hdr.image_count - 1];
+ wim->current_image = image;
err_undo_append:
wim->hdr.image_count--;
-err_free_new_blob:
- free_blob_descriptor(new_blob);
-err_put_replace_imd:
- put_image_metadata(replace_imd, NULL);
+err_put_imd:
+ imd->metadata_blob = NULL;
+ put_image_metadata(imd);
err:
return ret;
}
int ret = renew_current_image(ctx);
if (ret)
return ret;
- } else {
- release_extra_refcnts(ctx);
}
- INIT_LIST_HEAD(&ctx->orig_blob_list);
delete_empty_blobs(ctx);
- mark_image_dirty(wim_get_current_image_metadata(ctx->wim));
write_flags = 0;
ctx.mount_flags = mount_flags;
if (mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS)
ctx.default_lookup_flags = LOOKUP_FLAG_ADS_OK;
- /* For read-write mount, create the staging directory. */
+
+ /* For read-write mounts, create the staging directory, save a reference
+ * to the image's metadata resource, and mark the image dirty. */
if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
ret = make_staging_dir(&ctx, staging_dir);
if (ret)
- goto out_unlock;
+ goto out;
+ ret = WIMLIB_ERR_NOMEM;
+ ctx.metadata_resource = clone_blob_descriptor(
+ imd->metadata_blob);
+ if (!ctx.metadata_resource)
+ goto out;
+ mark_image_dirty(imd);
}
ctx.owner_uid = getuid();
ctx.owner_gid = getgid();
- /* Add each blob referenced by files in the image to a list and
- * preemptively double the number of references to each. This is done
- * to allow implementing the WIMLIB_UNMOUNT_FLAG_NEW_IMAGE semantics.
- */
- INIT_LIST_HEAD(&ctx.orig_blob_list);
- if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) {
- unsigned i;
- struct wim_inode *inode;
- struct blob_descriptor *blob;
-
- image_for_each_inode(inode, imd) {
- for (i = 0; i < inode->i_num_streams; i++) {
- blob = stream_blob(&inode->i_streams[i],
- wim->blob_table);
- if (blob)
- blob->out_refcnt = 0;
- }
- }
-
- image_for_each_inode(inode, imd) {
- for (i = 0; i < inode->i_num_streams; i++) {
- blob = stream_blob(&inode->i_streams[i],
- wim->blob_table);
- if (blob) {
- if (blob->out_refcnt == 0)
- list_add(&blob->orig_blob_list,
- &ctx.orig_blob_list);
- blob->out_refcnt += inode->i_nlink;
- blob->refcnt += inode->i_nlink;
- }
- }
- }
- }
-
/* Number the inodes in the mounted image sequentially and initialize
* the file descriptor arrays */
prepare_inodes(&ctx);
/* Cleanup and return. */
if (ret)
ret = WIMLIB_ERR_FUSE;
+out:
FREE(ctx.mountpoint_abspath);
- release_extra_refcnts(&ctx);
- if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
+ free_blob_descriptor(ctx.metadata_resource);
+ if (ctx.staging_dir_name)
delete_staging_dir(&ctx);
-out_unlock:
unlock_wim_for_append(wim);
return ret;
}
*/
/*
- * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers
+ * Copyright (C) 2012-2016 Eric Biggers
*
* This file is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
}
static void
-destroy_image_metadata(struct wim_image_metadata *imd,
- struct blob_table *table,
- bool free_metadata_blob_descriptor)
+unload_image_metadata(struct wim_image_metadata *imd)
{
- free_dentry_tree(imd->root_dentry, table);
+ free_dentry_tree(imd->root_dentry, NULL);
imd->root_dentry = NULL;
free_wim_security_data(imd->security_data);
imd->security_data = NULL;
-
- if (free_metadata_blob_descriptor) {
- free_blob_descriptor(imd->metadata_blob);
- imd->metadata_blob = NULL;
- }
- if (!table) {
- struct blob_descriptor *blob, *tmp;
- list_for_each_entry_safe(blob, tmp, &imd->unhashed_blobs, unhashed_list)
- free_blob_descriptor(blob);
- }
- INIT_LIST_HEAD(&imd->unhashed_blobs);
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_table *table)
+put_image_metadata(struct wim_image_metadata *imd)
{
- if (imd && --imd->refcnt == 0) {
- destroy_image_metadata(imd, table, true);
- FREE(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
{
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));
return 0;
}
-struct wim_image_metadata *
-new_image_metadata(void)
+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) {
- imd->refcnt = 1;
- INIT_HLIST_HEAD(&imd->inode_list);
- INIT_LIST_HEAD(&imd->unhashed_blobs);
- }
+ 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;
}
-static struct wim_image_metadata **
-new_image_metadata_array(unsigned num_images)
+/* Create an image metadata structure for a new empty image. */
+struct wim_image_metadata *
+new_empty_image_metadata(void)
{
- struct wim_image_metadata **imd_array;
-
- imd_array = CALLOC(num_images, sizeof(imd_array[0]));
+ struct blob_descriptor *metadata_blob;
+ struct wim_security_data *security_data;
+ struct wim_image_metadata *imd;
- if (!imd_array)
- return NULL;
- for (unsigned i = 0; i < num_images; i++) {
- imd_array[i] = new_image_metadata();
- if (unlikely(!imd_array[i])) {
- for (unsigned j = 0; j < i; j++)
- put_image_metadata(imd_array[j], NULL);
- FREE(imd_array);
- return NULL;
- }
+ 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;
}
- return imd_array;
+ 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
if (!wim_has_metadata(wim))
return WIMLIB_ERR_METADATA_NOT_FOUND;
- /* If a valid image is currently selected, its metadata can be freed if
- * it is not dirty and no other WIMStructs may have it selected. */
deselect_current_wim_image(wim);
- wim->current_image = image;
- imd = wim_get_current_image_metadata(wim);
- if (imd->root_dentry || is_image_dirty(imd)) {
- ret = 0;
- } else {
+
+ imd = wim->image_metadata[image - 1];
+ if (!is_image_loaded(imd)) {
ret = read_metadata_resource(imd);
if (ret)
- wim->current_image = WIMLIB_NO_IMAGE;
+ return ret;
}
- return ret;
+ wim->current_image = image;
+ imd->selected_refcnt++;
+ return 0;
}
+/*
+ * Deselect the WIMStruct's currently selected image, if any. To reduce memory
+ * usage, possibly unload the newly deselected image's metadata from memory.
+ */
void
deselect_current_wim_image(WIMStruct *wim)
{
struct wim_image_metadata *imd;
+
if (wim->current_image == WIMLIB_NO_IMAGE)
return;
imd = wim_get_current_image_metadata(wim);
- if (!is_image_dirty(imd) && imd->refcnt == 1) {
+ wimlib_assert(imd->selected_refcnt > 0);
+ imd->selected_refcnt--;
+ wim->current_image = WIMLIB_NO_IMAGE;
+
+ if (can_unload_image(imd)) {
wimlib_assert(list_empty(&imd->unhashed_blobs));
- destroy_image_metadata(imd, NULL, false);
+ unload_image_metadata(imd);
}
- wim->current_image = WIMLIB_NO_IMAGE;
}
/*
}
if (wim->hdr.image_count != 0 && wim->hdr.part_number == 1) {
- wim->image_metadata = new_image_metadata_array(wim->hdr.image_count);
+ wim->image_metadata = CALLOC(wim->hdr.image_count,
+ sizeof(wim->image_metadata[0]));
if (!wim->image_metadata)
return WIMLIB_ERR_NOMEM;
}
free_blob_table(wim->blob_table);
wim->blob_table = NULL;
if (wim->image_metadata != NULL) {
+ deselect_current_wim_image(wim);
for (int i = 0; i < wim->hdr.image_count; i++)
- put_image_metadata(wim->image_metadata[i], NULL);
+ put_image_metadata(wim->image_metadata[i]);
FREE(wim->image_metadata);
wim->image_metadata = NULL;
}