X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fwim.c;h=1b66aaf7271ef2fb1bfb2988a1ad4af0f498cf7a;hp=e7025daf03e0badcf094cdcc1f33e48df1e85231;hb=065b2b3513da8692efab0cd5344c054f246fa635;hpb=3071e89c11d1be71cf45b694432e5908e0c4ded9 diff --git a/src/wim.c b/src/wim.c index e7025daf..1b66aaf7 100644 --- a/src/wim.c +++ b/src/wim.c @@ -3,7 +3,7 @@ */ /* - * Copyright (C) 2012, 2013, 2014 Eric Biggers + * Copyright (C) 2012, 2013, 2014, 2015 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 @@ -23,231 +23,213 @@ # include "config.h" #endif +#include +#include +#ifndef __WIN32__ +# include +#endif +#include +#include +#include + #include "wimlib.h" +#include "wimlib/assert.h" +#include "wimlib/blob_table.h" #include "wimlib/dentry.h" #include "wimlib/encoding.h" #include "wimlib/file_io.h" #include "wimlib/integrity.h" -#include "wimlib/lookup_table.h" #include "wimlib/metadata.h" -#ifdef WITH_NTFS_3G -# include "wimlib/ntfs_3g.h" /* for do_ntfs_umount() */ -#endif +#include "wimlib/ntfs_3g.h" /* for libntfs3g_global_init() */ #include "wimlib/security.h" #include "wimlib/wim.h" #include "wimlib/xml.h" -#include "wimlib/version.h" +#include "wimlib/win32.h" + +/* Information about the available compression types for the WIM format. */ +static const struct { + const tchar *name; + u32 min_chunk_size; + u32 max_chunk_size; + u32 default_nonsolid_chunk_size; + u32 default_solid_chunk_size; +} wim_ctype_info[] = { + [WIMLIB_COMPRESSION_TYPE_NONE] = { + .name = T("None"), + .min_chunk_size = 0, + .max_chunk_size = 0, + .default_nonsolid_chunk_size = 0, + .default_solid_chunk_size = 0, + }, + [WIMLIB_COMPRESSION_TYPE_XPRESS] = { + .name = T("XPRESS"), + .min_chunk_size = 4096, + .max_chunk_size = 65536, + .default_nonsolid_chunk_size = 32768, + .default_solid_chunk_size = 32768, + }, + [WIMLIB_COMPRESSION_TYPE_LZX] = { + .name = T("LZX"), + .min_chunk_size = 32768, + .max_chunk_size = 2097152, + .default_nonsolid_chunk_size = 32768, + .default_solid_chunk_size = 32768, + }, + [WIMLIB_COMPRESSION_TYPE_LZMS] = { + .name = T("LZMS"), + .min_chunk_size = 32768, + .max_chunk_size = 1073741824, + .default_nonsolid_chunk_size = 131072, + .default_solid_chunk_size = 67108864, + }, +}; + +/* Is the specified compression type valid? */ +static bool +wim_compression_type_valid(enum wimlib_compression_type ctype) +{ + return (unsigned)ctype < ARRAY_LEN(wim_ctype_info) && + wim_ctype_info[(unsigned)ctype].name != NULL; +} -#ifdef __WIN32__ -# include "wimlib/win32.h" /* for realpath() replacement */ -#endif +/* Is the specified chunk size valid for the compression type? */ +static bool +wim_chunk_size_valid(u32 chunk_size, enum wimlib_compression_type ctype) +{ + if (!(chunk_size == 0 || is_power_of_2(chunk_size))) + return false; -#include -#include -#ifndef __WIN32__ -# include -#endif -#include -#include + return chunk_size >= wim_ctype_info[(unsigned)ctype].min_chunk_size && + chunk_size <= wim_ctype_info[(unsigned)ctype].max_chunk_size; +} -static int -wim_default_pack_compression_type(void) +/* Return the default chunk size to use for the specified compression type in + * non-solid resources. */ +static u32 +wim_default_nonsolid_chunk_size(enum wimlib_compression_type ctype) { - return WIMLIB_COMPRESSION_TYPE_LZMS; + return wim_ctype_info[(unsigned)ctype].default_nonsolid_chunk_size; } +/* Return the default chunk size to use for the specified compression type in + * solid resources. */ static u32 -wim_default_pack_chunk_size(int ctype) { - switch (ctype) { - case WIMLIB_COMPRESSION_TYPE_LZMS: - return 1U << 25; /* 33554432 */ - default: - return 1U << 15; /* 32768 */ - } +wim_default_solid_chunk_size(enum wimlib_compression_type ctype) +{ + return wim_ctype_info[(unsigned)ctype].default_solid_chunk_size; } -static WIMStruct * -new_wim_struct(void) +/* Return the default compression type to use in solid resources. */ +static enum wimlib_compression_type +wim_default_solid_compression_type(void) { - WIMStruct *wim = CALLOC(1, sizeof(WIMStruct)); - if (!wim) - return NULL; - - filedes_invalidate(&wim->in_fd); - filedes_invalidate(&wim->out_fd); - wim->out_pack_compression_type = wim_default_pack_compression_type(); - wim->out_pack_chunk_size = wim_default_pack_chunk_size( - wim->out_pack_compression_type); - INIT_LIST_HEAD(&wim->subwims); - return wim; + return WIMLIB_COMPRESSION_TYPE_LZMS; } -/* Determine if the chunk size is valid for the specified compression type. */ -static bool -wim_chunk_size_valid(u32 chunk_size, int ctype) +static int +is_blob_in_solid_resource(struct blob_descriptor *blob, void *_ignore) { - u32 order; - - /* Chunk size is meaningless for uncompressed WIMs --- any value is - * okay. */ - if (ctype == WIMLIB_COMPRESSION_TYPE_NONE) - return true; - - /* Chunk size must be power of 2. */ - if (chunk_size == 0) - return false; - order = bsr32(chunk_size); - if (chunk_size != 1U << order) - return false; - - /* Order Size - * ===== ==== - * 15 32768 - * 16 65536 - * 17 131072 - * 18 262144 - * 19 524288 - * 20 1048576 - * 21 2097152 - * 22 4194304 - * 23 8388608 - * 24 16777216 - * 25 33554432 - * 26 67108864 - */ - - /* See the documentation for the --chunk-size option of `wimlib-imagex - * capture' for information about allowed chunk sizes. */ - switch (ctype) { - case WIMLIB_COMPRESSION_TYPE_LZX: - return order >= 15 && order <= 21; - case WIMLIB_COMPRESSION_TYPE_XPRESS: - return order >= 12 && order <= 16; - case WIMLIB_COMPRESSION_TYPE_LZMS: - return order >= 15 && order <= 30; - } - return false; + return blob->blob_location == BLOB_IN_WIM && + (blob->rdesc->flags & WIM_RESHDR_FLAG_SOLID); } -/* Return the default chunk size to use for the specified compression type. - * - * See notes above in wim_chunk_size_valid(). */ -static u32 -wim_default_chunk_size(int ctype) +bool +wim_has_solid_resources(const WIMStruct *wim) { - switch (ctype) { - case WIMLIB_COMPRESSION_TYPE_LZMS: - return 1U << 17; /* 131072 */ - default: - return 1U << 15; /* 32768 */ - } + return for_blob_in_table(wim->blob_table, is_blob_in_solid_resource, NULL); } -/* - * Calls a function on images in the WIM. If @image is WIMLIB_ALL_IMAGES, - * @visitor is called on the WIM once for each image, with each image selected - * as the current image in turn. If @image is a certain image, @visitor is - * called on the WIM only once, with that image selected. - */ -int -for_image(WIMStruct *wim, int image, int (*visitor)(WIMStruct *)) +static WIMStruct * +new_wim_struct(void) { - int ret; - int start; - int end; - int i; + WIMStruct *wim = CALLOC(1, sizeof(WIMStruct)); + if (!wim) + return NULL; - if (image == WIMLIB_ALL_IMAGES) { - start = 1; - end = wim->hdr.image_count; - } else if (image >= 1 && image <= wim->hdr.image_count) { - start = image; - end = image; - } else { - return WIMLIB_ERR_INVALID_IMAGE; - } - for (i = start; i <= end; i++) { - ret = select_wim_image(wim, i); - if (ret != 0) - return ret; - ret = visitor(wim); - if (ret != 0) - return ret; - } - return 0; + 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; } /* API function documented in wimlib.h */ WIMLIBAPI int -wimlib_create_new_wim(int ctype, WIMStruct **wim_ret) +wimlib_create_new_wim(enum wimlib_compression_type ctype, WIMStruct **wim_ret) { - WIMStruct *wim; - struct wim_lookup_table *table; int ret; + WIMStruct *wim; ret = wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8); if (ret) return ret; + if (!wim_ret) + return WIMLIB_ERR_INVALID_PARAM; + + if (!wim_compression_type_valid(ctype)) + return WIMLIB_ERR_INVALID_COMPRESSION_TYPE; + wim = new_wim_struct(); if (!wim) return WIMLIB_ERR_NOMEM; - ret = init_wim_header(&wim->hdr, ctype, wim_default_chunk_size(ctype)); - if (ret) - goto out_free_wim; - - table = new_lookup_table(9001); - if (!table) { - ret = WIMLIB_ERR_NOMEM; - goto out_free_wim; + wim->xml_info = xml_new_info_struct(); + wim->blob_table = new_blob_table(9001); + if (!wim->xml_info || !wim->blob_table) { + wimlib_free(wim); + return WIMLIB_ERR_NOMEM; } - wim->lookup_table = table; - wim->refcnts_ok = 1; - wim->compression_type = ctype; - wim->out_compression_type = ctype; + + /* Fill in wim->hdr with default values */ + wim->hdr.magic = WIM_MAGIC; + wim->hdr.wim_version = WIM_VERSION_DEFAULT; + wim->hdr.flags = 0; + wim->hdr.chunk_size = 0; + generate_guid(wim->hdr.guid); + wim->hdr.part_number = 1; + wim->hdr.total_parts = 1; + wim->hdr.image_count = 0; + wim->hdr.boot_idx = 0; + + wim->compression_type = WIMLIB_COMPRESSION_TYPE_NONE; wim->chunk_size = wim->hdr.chunk_size; - wim->out_chunk_size = wim->hdr.chunk_size; + + /* Set the output compression type */ + wim->out_compression_type = ctype; + wim->out_chunk_size = wim_default_nonsolid_chunk_size(ctype); + *wim_ret = wim; return 0; - -out_free_wim: - FREE(wim); - return ret; } static void destroy_image_metadata(struct wim_image_metadata *imd, - struct wim_lookup_table *table, - bool free_metadata_lte) + struct blob_table *table, + bool free_metadata_blob_descriptor) { free_dentry_tree(imd->root_dentry, table); imd->root_dentry = NULL; free_wim_security_data(imd->security_data); imd->security_data = NULL; - if (free_metadata_lte) { - free_lookup_table_entry(imd->metadata_lte); - imd->metadata_lte = NULL; + if (free_metadata_blob_descriptor) { + free_blob_descriptor(imd->metadata_blob); + imd->metadata_blob = NULL; } if (!table) { - struct wim_lookup_table_entry *lte, *tmp; - list_for_each_entry_safe(lte, tmp, &imd->unhashed_streams, unhashed_list) - free_lookup_table_entry(lte); + 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_streams); - INIT_LIST_HEAD(&imd->inode_list); -#ifdef WITH_NTFS_3G - if (imd->ntfs_vol) { - do_ntfs_umount(imd->ntfs_vol); - imd->ntfs_vol = NULL; - } -#endif + INIT_LIST_HEAD(&imd->unhashed_blobs); + INIT_HLIST_HEAD(&imd->inode_list); } void -put_image_metadata(struct wim_image_metadata *imd, - struct wim_lookup_table *table) +put_image_metadata(struct wim_image_metadata *imd, struct blob_table *table) { if (imd && --imd->refcnt == 0) { destroy_image_metadata(imd, table, true); @@ -280,8 +262,8 @@ new_image_metadata(void) imd = CALLOC(1, sizeof(*imd)); if (imd) { imd->refcnt = 1; - INIT_LIST_HEAD(&imd->inode_list); - INIT_LIST_HEAD(&imd->unhashed_streams); + INIT_HLIST_HEAD(&imd->inode_list); + INIT_LIST_HEAD(&imd->unhashed_blobs); } return imd; } @@ -344,42 +326,65 @@ select_wim_image(WIMStruct *wim, int image) /* If a valid image is currently selected, its metadata can be freed if * it has not been modified. */ - if (wim->current_image != WIMLIB_NO_IMAGE) { - imd = wim_get_current_image_metadata(wim); - if (!imd->modified) { - wimlib_assert(list_empty(&imd->unhashed_streams)); - destroy_image_metadata(imd, NULL, false); - } - } + 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 { - ret = read_metadata_resource(wim, imd); + ret = read_metadata_resource(imd); if (ret) wim->current_image = WIMLIB_NO_IMAGE; } return ret; } +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(list_empty(&imd->unhashed_blobs)); + destroy_image_metadata(imd, NULL, false); + } + wim->current_image = WIMLIB_NO_IMAGE; +} -/* API function documented in wimlib.h */ -WIMLIBAPI const tchar * -wimlib_get_compression_type_string(int ctype) -{ - switch (ctype) { - case WIMLIB_COMPRESSION_TYPE_NONE: - return T("None"); - case WIMLIB_COMPRESSION_TYPE_XPRESS: - return T("XPRESS"); - case WIMLIB_COMPRESSION_TYPE_LZX: - return T("LZX"); - case WIMLIB_COMPRESSION_TYPE_LZMS: - return T("LZMS"); - default: - return T("Invalid"); +/* + * Calls a function on images in the WIM. If @image is WIMLIB_ALL_IMAGES, + * @visitor is called on the WIM once for each image, with each image selected + * as the current image in turn. If @image is a certain image, @visitor is + * called on the WIM only once, with that image selected. + */ +int +for_image(WIMStruct *wim, int image, int (*visitor)(WIMStruct *)) +{ + int ret; + int start; + int end; + int i; + + if (image == WIMLIB_ALL_IMAGES) { + start = 1; + end = wim->hdr.image_count; + } else if (image >= 1 && image <= wim->hdr.image_count) { + start = image; + end = image; + } else { + return WIMLIB_ERR_INVALID_IMAGE; } + for (i = start; i <= end; i++) { + ret = select_wim_image(wim, i); + if (ret != 0) + return ret; + ret = visitor(wim); + if (ret != 0) + return ret; + } + return 0; } /* API function documented in wimlib.h */ @@ -436,7 +441,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 */ @@ -444,7 +449,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; @@ -452,7 +457,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) || @@ -472,14 +477,16 @@ wimlib_get_wim_info(WIMStruct *wim, struct wimlib_wim_info *info) WIMLIBAPI int wimlib_set_wim_info(WIMStruct *wim, const struct wimlib_wim_info *info, int which) { - int ret; - if (which & ~(WIMLIB_CHANGE_READONLY_FLAG | WIMLIB_CHANGE_GUID | WIMLIB_CHANGE_BOOT_INDEX | WIMLIB_CHANGE_RPFIX_FLAG)) return WIMLIB_ERR_INVALID_PARAM; + if ((which & WIMLIB_CHANGE_BOOT_INDEX) && + info->boot_index > wim->hdr.image_count) + return WIMLIB_ERR_INVALID_IMAGE; + if (which & WIMLIB_CHANGE_READONLY_FLAG) { if (info->is_marked_readonly) wim->hdr.flags |= WIM_HDR_FLAG_READONLY; @@ -487,21 +494,11 @@ wimlib_set_wim_info(WIMStruct *wim, const struct wimlib_wim_info *info, int whic wim->hdr.flags &= ~WIM_HDR_FLAG_READONLY; } - if ((which & ~WIMLIB_CHANGE_READONLY_FLAG) == 0) - return 0; - - ret = can_modify_wim(wim); - if (ret) - return ret; - 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) { - if (info->boot_index > wim->hdr.image_count) - return WIMLIB_ERR_INVALID_IMAGE; + if (which & WIMLIB_CHANGE_BOOT_INDEX) wim->hdr.boot_idx = info->boot_index; - } if (which & WIMLIB_CHANGE_RPFIX_FLAG) { if (info->has_rpfix) @@ -512,86 +509,84 @@ wimlib_set_wim_info(WIMStruct *wim, const struct wimlib_wim_info *info, int whic return 0; } -static int -set_out_ctype(int ctype, u8 *out_ctype_p) -{ - switch (ctype) { - case WIMLIB_COMPRESSION_TYPE_NONE: - case WIMLIB_COMPRESSION_TYPE_LZX: - case WIMLIB_COMPRESSION_TYPE_XPRESS: - case WIMLIB_COMPRESSION_TYPE_LZMS: - *out_ctype_p = ctype; - return 0; - } - return WIMLIB_ERR_INVALID_COMPRESSION_TYPE; -} - /* API function documented in wimlib.h */ WIMLIBAPI int -wimlib_set_output_compression_type(WIMStruct *wim, int ctype) +wimlib_set_output_compression_type(WIMStruct *wim, + enum wimlib_compression_type ctype) { - int ret = set_out_ctype(ctype, &wim->out_compression_type); - if (ret) - return ret; + if (!wim_compression_type_valid(ctype)) + return WIMLIB_ERR_INVALID_COMPRESSION_TYPE; + + wim->out_compression_type = ctype; /* Reset the chunk size if it's no longer valid. */ if (!wim_chunk_size_valid(wim->out_chunk_size, ctype)) - wim->out_chunk_size = wim_default_chunk_size(ctype); + wim->out_chunk_size = wim_default_nonsolid_chunk_size(ctype); return 0; } /* API function documented in wimlib.h */ WIMLIBAPI int -wimlib_set_output_pack_compression_type(WIMStruct *wim, int ctype) +wimlib_set_output_pack_compression_type(WIMStruct *wim, + enum wimlib_compression_type ctype) { - int ret = set_out_ctype(ctype, &wim->out_pack_compression_type); - if (ret) - return ret; + if (!wim_compression_type_valid(ctype)) + return WIMLIB_ERR_INVALID_COMPRESSION_TYPE; - /* Reset the chunk size if it's no longer valid. */ - if (!wim_chunk_size_valid(wim->out_pack_chunk_size, ctype)) - wim->out_pack_chunk_size = wim_default_pack_chunk_size(ctype); - return 0; -} + /* Solid resources can't be uncompressed. */ + if (ctype == WIMLIB_COMPRESSION_TYPE_NONE) + return WIMLIB_ERR_INVALID_COMPRESSION_TYPE; -static int -set_out_chunk_size(u32 chunk_size, int ctype, u32 *out_chunk_size_p) -{ - if (!wim_chunk_size_valid(chunk_size, ctype)) - return WIMLIB_ERR_INVALID_CHUNK_SIZE; + wim->out_solid_compression_type = ctype; - *out_chunk_size_p = chunk_size; + /* Reset the chunk size if it's no longer valid. */ + if (!wim_chunk_size_valid(wim->out_solid_chunk_size, ctype)) + wim->out_solid_chunk_size = wim_default_solid_chunk_size(ctype); return 0; } /* API function documented in wimlib.h */ WIMLIBAPI int -wimlib_set_output_chunk_size(WIMStruct *wim, uint32_t chunk_size) +wimlib_set_output_chunk_size(WIMStruct *wim, u32 chunk_size) { if (chunk_size == 0) { wim->out_chunk_size = - wim_default_chunk_size(wim->out_compression_type); + wim_default_nonsolid_chunk_size(wim->out_compression_type); return 0; } - return set_out_chunk_size(chunk_size, - wim->out_compression_type, - &wim->out_chunk_size); + if (!wim_chunk_size_valid(chunk_size, wim->out_compression_type)) + return WIMLIB_ERR_INVALID_CHUNK_SIZE; + + wim->out_chunk_size = chunk_size; + return 0; } /* API function documented in wimlib.h */ WIMLIBAPI int -wimlib_set_output_pack_chunk_size(WIMStruct *wim, uint32_t chunk_size) +wimlib_set_output_pack_chunk_size(WIMStruct *wim, u32 chunk_size) { if (chunk_size == 0) { - wim->out_pack_chunk_size = - wim_default_pack_chunk_size(wim->out_pack_compression_type); + wim->out_solid_chunk_size = + wim_default_solid_chunk_size(wim->out_solid_compression_type); return 0; } - return set_out_chunk_size(chunk_size, - wim->out_pack_compression_type, - &wim->out_pack_chunk_size); + if (!wim_chunk_size_valid(chunk_size, wim->out_solid_compression_type)) + return WIMLIB_ERR_INVALID_CHUNK_SIZE; + + wim->out_solid_chunk_size = chunk_size; + return 0; +} + +/* API function documented in wimlib.h */ +WIMLIBAPI const tchar * +wimlib_get_compression_type_string(enum wimlib_compression_type ctype) +{ + if (!wim_compression_type_valid(ctype)) + return T("Invalid"); + + return wim_ctype_info[(unsigned)ctype].name; } WIMLIBAPI void @@ -619,13 +614,12 @@ open_wim_file(const tchar *filename, struct filedes *fd_ret) /* * Begins the reading of a WIM file; opens the file and reads its header and - * lookup table, and optionally checks the integrity. + * blob table, and optionally checks the integrity. */ 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) { @@ -735,24 +729,26 @@ begin_read(WIMStruct *wim, const void *wim_filename_or_fd, int open_flags) } if (open_flags & WIMLIB_OPEN_FLAG_FROM_PIPE) { - wim->lookup_table = new_lookup_table(9001); - if (!wim->lookup_table) + wim->blob_table = new_blob_table(9001); + 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."); return WIMLIB_ERR_IMAGE_COUNT; } - ret = read_wim_lookup_table(wim); + ret = read_blob_table(wim); if (ret) return ret; } @@ -814,27 +810,26 @@ wimlib_open_wim(const tchar *wimfile, int open_flags, WIMStruct **wim_ret) NULL, NULL); } -/* Checksum all streams that are unhashed (other than the metadata streams), - * merging them into the lookup table as needed. This is a no-op unless the - * library has previously used to add or mount an image using the same - * WIMStruct. */ +/* Checksum all blobs that are unhashed (other than the metadata blobs), merging + * them into the blob table as needed. This is a no-op unless files have been + * added to an image in the same WIMStruct. */ int -wim_checksum_unhashed_streams(WIMStruct *wim) +wim_checksum_unhashed_blobs(WIMStruct *wim) { int ret; if (!wim_has_metadata(wim)) return 0; for (int i = 0; i < wim->hdr.image_count; i++) { - struct wim_lookup_table_entry *lte, *tmp; + struct blob_descriptor *blob, *tmp; struct wim_image_metadata *imd = wim->image_metadata[i]; - image_for_each_unhashed_stream_safe(lte, tmp, imd) { - struct wim_lookup_table_entry *new_lte; - ret = hash_unhashed_stream(lte, wim->lookup_table, &new_lte); + image_for_each_unhashed_blob_safe(blob, tmp, imd) { + struct blob_descriptor *new_blob; + ret = hash_unhashed_blob(blob, wim->blob_table, &new_blob); if (ret) return ret; - if (new_lte != lte) - free_lookup_table_entry(lte); + if (new_blob != blob) + free_blob_descriptor(blob); } } return 0; @@ -872,33 +867,6 @@ can_modify_wim(WIMStruct *wim) return 0; } -/* - * can_delete_from_wim - Check if files or images can be deleted from a given - * WIM file. - * - * This theoretically should be exactly the same as can_modify_wim(), but - * unfortunately, due to bugs in Microsoft's software that generate incorrect - * reference counts for some WIM resources, we need to run expensive - * verifications to make sure the reference counts are correct on all WIM - * resources. Otherwise we might delete a WIM resource whose reference count - * has fallen to 0, but is actually still referenced somewhere. - */ -int -can_delete_from_wim(WIMStruct *wim) -{ - int ret; - - ret = can_modify_wim(wim); - if (ret) - return ret; - if (!wim->refcnts_ok) { - ret = wim_recalculate_refcnts(wim); - if (ret) - return ret; - } - return 0; -} - /* API function documented in wimlib.h */ WIMLIBAPI void wimlib_free(WIMStruct *wim) @@ -919,12 +887,12 @@ wimlib_free(WIMStruct *wim) if (filedes_valid(&wim->out_fd)) filedes_close(&wim->out_fd); - free_lookup_table(wim->lookup_table); + free_blob_table(wim->blob_table); wimlib_free_decompressor(wim->decompressor); FREE(wim->filename); - free_wim_info(wim->wim_info); + xml_free_info_struct(wim->xml_info); if (wim->image_metadata) { for (unsigned i = 0; i < wim->hdr.image_count; i++) put_image_metadata(wim->image_metadata[i], NULL); @@ -952,32 +920,50 @@ test_locale_ctype_utf8(void) WIMLIBAPI u32 wimlib_get_version(void) { - return WIMLIB_VERSION_CODE; + return (WIMLIB_MAJOR_VERSION << 20) | + (WIMLIB_MINOR_VERSION << 10) | + WIMLIB_PATCH_VERSION; } static bool lib_initialized = false; +static pthread_mutex_t lib_initialization_mutex = PTHREAD_MUTEX_INITIALIZER; /* API function documented in wimlib.h */ WIMLIBAPI int wimlib_global_init(int init_flags) { + int ret = 0; + if (lib_initialized) - return 0; + goto out; + + pthread_mutex_lock(&lib_initialization_mutex); + + if (lib_initialized) + goto out_unlock; #ifdef ENABLE_ERROR_MESSAGES if (!wimlib_error_file) wimlib_error_file = stderr; #endif + ret = WIMLIB_ERR_INVALID_PARAM; if (init_flags & ~(WIMLIB_INIT_FLAG_ASSUME_UTF8 | WIMLIB_INIT_FLAG_DONT_ACQUIRE_PRIVILEGES | WIMLIB_INIT_FLAG_STRICT_CAPTURE_PRIVILEGES | WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES | WIMLIB_INIT_FLAG_DEFAULT_CASE_SENSITIVE | WIMLIB_INIT_FLAG_DEFAULT_CASE_INSENSITIVE)) - return WIMLIB_ERR_INVALID_PARAM; + goto out_unlock; + + ret = WIMLIB_ERR_INVALID_PARAM; + if ((init_flags & (WIMLIB_INIT_FLAG_DEFAULT_CASE_SENSITIVE | + WIMLIB_INIT_FLAG_DEFAULT_CASE_INSENSITIVE)) + == (WIMLIB_INIT_FLAG_DEFAULT_CASE_SENSITIVE | + WIMLIB_INIT_FLAG_DEFAULT_CASE_INSENSITIVE)) + goto out_unlock; - libxml_global_init(); + xml_global_init(); if (!(init_flags & WIMLIB_INIT_FLAG_ASSUME_UTF8)) { wimlib_mbs_is_utf8 = test_locale_ctype_utf8(); #ifdef WITH_NTFS_3G @@ -986,11 +972,9 @@ wimlib_global_init(int init_flags) #endif } #ifdef __WIN32__ - { - int ret = win32_global_init(init_flags); - if (ret) - return ret; - } + ret = win32_global_init(init_flags); + if (ret) + goto out_unlock; #endif iconv_global_init(); init_upcase(); @@ -999,7 +983,11 @@ wimlib_global_init(int init_flags) else if (init_flags & WIMLIB_INIT_FLAG_DEFAULT_CASE_INSENSITIVE) default_ignore_case = true; lib_initialized = true; - return 0; + ret = 0; +out_unlock: + pthread_mutex_unlock(&lib_initialization_mutex); +out: + return ret; } /* API function documented in wimlib.h */ @@ -1008,7 +996,13 @@ wimlib_global_cleanup(void) { if (!lib_initialized) return; - libxml_global_cleanup(); + + pthread_mutex_lock(&lib_initialization_mutex); + + if (!lib_initialized) + goto out_unlock; + + xml_global_cleanup(); iconv_global_cleanup(); #ifdef __WIN32__ win32_global_cleanup(); @@ -1016,4 +1010,7 @@ wimlib_global_cleanup(void) wimlib_set_error_file(NULL); lib_initialized = false; + +out_unlock: + pthread_mutex_unlock(&lib_initialization_mutex); }