X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwim.c;h=ec345a9322e0d51e5fb9af5e10eee1579e050033;hp=a82bd479117831b217af8c5400a0163c8fff1cb2;hb=831eeaad4513475ce947efaef16fc79ab3997444;hpb=2fc33f535a398ea85964c0e483c5692821d775f3 diff --git a/src/wim.c b/src/wim.c index a82bd479..ec345a93 100644 --- a/src/wim.c +++ b/src/wim.c @@ -3,7 +3,7 @@ */ /* - * 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 @@ -25,9 +25,6 @@ #include #include -#ifndef __WIN32__ -# include -#endif #include #include #include @@ -40,15 +37,10 @@ #include "wimlib/file_io.h" #include "wimlib/integrity.h" #include "wimlib/metadata.h" -#ifdef WITH_NTFS_3G -# include "wimlib/ntfs_3g.h" /* for do_ntfs_umount() */ -#endif #include "wimlib/security.h" #include "wimlib/wim.h" #include "wimlib/xml.h" -#ifdef __WIN32__ -# include "wimlib/win32.h" /* for realpath() replacement */ -#endif +#include "wimlib/win32.h" /* Information about the available compression types for the WIM format. */ static const struct { @@ -92,8 +84,8 @@ static const struct { static bool wim_compression_type_valid(enum wimlib_compression_type ctype) { - return ctype >= 0 && ctype < ARRAY_LEN(wim_ctype_info) && - wim_ctype_info[ctype].name != NULL; + return (unsigned)ctype < ARRAY_LEN(wim_ctype_info) && + wim_ctype_info[(unsigned)ctype].name != NULL; } /* Is the specified chunk size valid for the compression type? */ @@ -103,8 +95,8 @@ wim_chunk_size_valid(u32 chunk_size, enum wimlib_compression_type ctype) if (!(chunk_size == 0 || is_power_of_2(chunk_size))) return false; - return chunk_size >= wim_ctype_info[ctype].min_chunk_size && - chunk_size <= wim_ctype_info[ctype].max_chunk_size; + return chunk_size >= wim_ctype_info[(unsigned)ctype].min_chunk_size && + chunk_size <= wim_ctype_info[(unsigned)ctype].max_chunk_size; } /* Return the default chunk size to use for the specified compression type in @@ -112,7 +104,7 @@ wim_chunk_size_valid(u32 chunk_size, enum wimlib_compression_type ctype) static u32 wim_default_nonsolid_chunk_size(enum wimlib_compression_type ctype) { - return wim_ctype_info[ctype].default_nonsolid_chunk_size; + return wim_ctype_info[(unsigned)ctype].default_nonsolid_chunk_size; } /* Return the default chunk size to use for the specified compression type in @@ -120,7 +112,7 @@ wim_default_nonsolid_chunk_size(enum wimlib_compression_type ctype) static u32 wim_default_solid_chunk_size(enum wimlib_compression_type ctype) { - return wim_ctype_info[ctype].default_solid_chunk_size; + return wim_ctype_info[(unsigned)ctype].default_solid_chunk_size; } /* Return the default compression type to use in solid resources. */ @@ -150,12 +142,12 @@ new_wim_struct(void) if (!wim) return NULL; + wim->refcnt = 1; filedes_invalidate(&wim->in_fd); filedes_invalidate(&wim->out_fd); wim->out_solid_compression_type = wim_default_solid_compression_type(); wim->out_solid_chunk_size = wim_default_solid_chunk_size( wim->out_solid_compression_type); - INIT_LIST_HEAD(&wim->subwims); return wim; } @@ -166,7 +158,7 @@ wimlib_create_new_wim(enum wimlib_compression_type ctype, WIMStruct **wim_ret) int ret; WIMStruct *wim; - ret = wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8); + ret = wimlib_global_init(0); if (ret) return ret; @@ -180,59 +172,57 @@ wimlib_create_new_wim(enum wimlib_compression_type ctype, WIMStruct **wim_ret) if (!wim) return WIMLIB_ERR_NOMEM; - wim->blob_table = new_blob_table(9001); - if (!wim->blob_table) { + /* Fill in wim->hdr with default values */ + wim->hdr.magic = WIM_MAGIC; + wim->hdr.wim_version = WIM_VERSION_DEFAULT; + wim->hdr.part_number = 1; + wim->hdr.total_parts = 1; + wim->compression_type = WIMLIB_COMPRESSION_TYPE_NONE; + + /* Set the output compression type */ + wim->out_compression_type = ctype; + wim->out_chunk_size = wim_default_nonsolid_chunk_size(ctype); + + /* Allocate an empty XML info and blob table */ + wim->xml_info = xml_new_info_struct(); + wim->blob_table = new_blob_table(64); + if (!wim->xml_info || !wim->blob_table) { wimlib_free(wim); return WIMLIB_ERR_NOMEM; } - init_wim_header(&wim->hdr, ctype, - wim_default_nonsolid_chunk_size(ctype)); - wim->compression_type = ctype; - wim->out_compression_type = ctype; - wim->chunk_size = wim->hdr.chunk_size; - wim->out_chunk_size = wim->hdr.chunk_size; - *wim_ret = wim; return 0; } 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); -#ifdef WITH_NTFS_3G - if (imd->ntfs_vol) { - do_ntfs_umount(imd->ntfs_vol); - imd->ntfs_vol = NULL; - } -#endif } +/* 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 @@ -242,6 +232,12 @@ 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)); @@ -252,41 +248,57 @@ append_image_metadata(WIMStruct *wim, struct wim_image_metadata *imd) 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 @@ -322,33 +334,39 @@ select_wim_image(WIMStruct *wim, int image) 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 has not been modified. */ deselect_current_wim_image(wim); - wim->current_image = image; - imd = wim_get_current_image_metadata(wim); - if (imd->root_dentry || imd->modified) { - 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 (!imd->modified) { + 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; } /* @@ -439,7 +457,7 @@ wimlib_print_available_images(const WIMStruct *wim, int image) tputchar(T('-')); tputchar(T('\n')); for (i = first; i <= last; i++) - print_image_info(wim->wim_info, i); + xml_print_image_info(wim->xml_info, i); } /* API function documented in wimlib.h */ @@ -447,7 +465,7 @@ WIMLIBAPI int wimlib_get_wim_info(WIMStruct *wim, struct wimlib_wim_info *info) { memset(info, 0, sizeof(struct wimlib_wim_info)); - memcpy(info->guid, wim->hdr.guid, WIMLIB_GUID_LEN); + copy_guid(info->guid, wim->hdr.guid); info->image_count = wim->hdr.image_count; info->boot_index = wim->hdr.boot_idx; info->wim_version = wim->hdr.wim_version; @@ -455,7 +473,7 @@ wimlib_get_wim_info(WIMStruct *wim, struct wimlib_wim_info *info) info->part_number = wim->hdr.part_number; info->total_parts = wim->hdr.total_parts; info->compression_type = wim->compression_type; - info->total_bytes = wim_info_get_total_bytes(wim->wim_info); + info->total_bytes = xml_get_total_bytes(wim->xml_info); info->has_integrity_table = wim_has_integrity_table(wim); info->opened_from_file = (wim->filename != NULL); info->is_readonly = (wim->hdr.flags & WIM_HDR_FLAG_READONLY) || @@ -493,7 +511,7 @@ wimlib_set_wim_info(WIMStruct *wim, const struct wimlib_wim_info *info, int whic } if (which & WIMLIB_CHANGE_GUID) - memcpy(wim->hdr.guid, info->guid, WIM_GUID_LEN); + copy_guid(wim->hdr.guid, info->guid); if (which & WIMLIB_CHANGE_BOOT_INDEX) wim->hdr.boot_idx = info->boot_index; @@ -584,7 +602,7 @@ wimlib_get_compression_type_string(enum wimlib_compression_type ctype) if (!wim_compression_type_valid(ctype)) return T("Invalid"); - return wim_ctype_info[ctype].name; + return wim_ctype_info[(unsigned)ctype].name; } WIMLIBAPI void @@ -618,7 +636,6 @@ static int begin_read(WIMStruct *wim, const void *wim_filename_or_fd, int open_flags) { int ret; - int xml_num_images; const tchar *wimfile; if (open_flags & WIMLIB_OPEN_FLAG_FROM_PIPE) { @@ -722,23 +739,26 @@ begin_read(WIMStruct *wim, const void *wim_filename_or_fd, int open_flags) } 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; } if (open_flags & WIMLIB_OPEN_FLAG_FROM_PIPE) { - wim->blob_table = new_blob_table(9001); + wim->blob_table = new_blob_table(64); if (!wim->blob_table) return WIMLIB_ERR_NOMEM; } else { + if (wim->hdr.blob_table_reshdr.uncompressed_size == 0 && + wim->hdr.xml_data_reshdr.uncompressed_size == 0) + return WIMLIB_ERR_WIM_IS_INCOMPLETE; ret = read_wim_xml_data(wim); if (ret) return ret; - xml_num_images = wim_info_get_num_images(wim->wim_info); - if (xml_num_images != wim->hdr.image_count) { + if (xml_get_image_count(wim->xml_info) != wim->hdr.image_count) { ERROR("The WIM's header is inconsistent with its XML data.\n" " Please submit a bug report if you believe this " "WIM file should be considered valid."); @@ -760,7 +780,7 @@ open_wim_as_WIMStruct(const void *wim_filename_or_fd, int open_flags, WIMStruct *wim; int ret; - ret = wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8); + ret = wimlib_global_init(0); if (ret) return ret; @@ -864,53 +884,46 @@ can_modify_wim(WIMStruct *wim) return 0; } -/* API function documented in wimlib.h */ -WIMLIBAPI void -wimlib_free(WIMStruct *wim) +/* Release a reference to a WIMStruct. If the reference count reaches 0, the + * WIMStruct is freed. */ +void +wim_decrement_refcnt(WIMStruct *wim) { - if (!wim) + wimlib_assert(wim->refcnt > 0); + if (--wim->refcnt != 0) return; - - while (!list_empty(&wim->subwims)) { - WIMStruct *subwim; - - subwim = list_entry(wim->subwims.next, WIMStruct, subwim_node); - list_del(&subwim->subwim_node); - wimlib_free(subwim); - } - if (filedes_valid(&wim->in_fd)) filedes_close(&wim->in_fd); if (filedes_valid(&wim->out_fd)) filedes_close(&wim->out_fd); - - free_blob_table(wim->blob_table); - wimlib_free_decompressor(wim->decompressor); - + xml_free_info_struct(wim->xml_info); FREE(wim->filename); - free_wim_info(wim->wim_info); - if (wim->image_metadata) { - for (unsigned i = 0; i < wim->hdr.image_count; i++) - put_image_metadata(wim->image_metadata[i], NULL); - FREE(wim->image_metadata); - } FREE(wim); } -static bool -test_locale_ctype_utf8(void) +/* API function documented in wimlib.h */ +WIMLIBAPI void +wimlib_free(WIMStruct *wim) { -#ifdef __WIN32__ - return false; -#else - char *ctype = nl_langinfo(CODESET); - - return (!strstr(ctype, "UTF-8") || - !strstr(ctype, "UTF8") || - !strstr(ctype, "utf8") || - !strstr(ctype, "utf-8")); -#endif + if (!wim) + return; + + /* The blob table and image metadata are freed immediately, but other + * members of the WIMStruct such as the input file descriptor are + * retained until no more exported resources reference the WIMStruct. */ + + 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]); + FREE(wim->image_metadata); + wim->image_metadata = NULL; + } + + wim_decrement_refcnt(wim); } /* API function documented in wimlib.h */ @@ -960,20 +973,12 @@ wimlib_global_init(int init_flags) WIMLIB_INIT_FLAG_DEFAULT_CASE_INSENSITIVE)) goto out_unlock; - libxml_global_init(); - if (!(init_flags & WIMLIB_INIT_FLAG_ASSUME_UTF8)) { - wimlib_mbs_is_utf8 = test_locale_ctype_utf8(); - #ifdef WITH_NTFS_3G - if (!wimlib_mbs_is_utf8) - libntfs3g_global_init(); - #endif - } + xml_global_init(); #ifdef __WIN32__ ret = win32_global_init(init_flags); if (ret) goto out_unlock; #endif - iconv_global_init(); init_upcase(); if (init_flags & WIMLIB_INIT_FLAG_DEFAULT_CASE_SENSITIVE) default_ignore_case = false; @@ -999,8 +1004,7 @@ wimlib_global_cleanup(void) if (!lib_initialized) goto out_unlock; - libxml_global_cleanup(); - iconv_global_cleanup(); + xml_global_cleanup(); #ifdef __WIN32__ win32_global_cleanup(); #endif