X-Git-Url: https://wimlib.net/git/?a=blobdiff_plain;f=src%2Fwim.c;h=ff43ba59e5deda4921dec2d728fb800224d9e13d;hb=377d436d5f3d5e626b2bbe446bdcd871ee53c5b5;hp=9b776023dd326d16f6f617bb3dcd61430a4d97b2;hpb=8908ce4c8e6ef4d7620863aedb06b9500e02707d;p=wimlib diff --git a/src/wim.c b/src/wim.c index 9b776023..ff43ba59 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 @@ -35,113 +35,95 @@ #include "wimlib.h" #include "wimlib/assert.h" #include "wimlib/blob_table.h" -#include "wimlib/bitops.h" #include "wimlib/dentry.h" #include "wimlib/encoding.h" #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/ntfs_3g.h" /* for libntfs3g_global_init() */ #include "wimlib/security.h" #include "wimlib/wim.h" #include "wimlib/xml.h" -#ifdef __WIN32__ -# include "wimlib/win32.h" /* for realpath() replacement */ -#endif - -static int -wim_default_solid_compression_type(void) +#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 WIMLIB_COMPRESSION_TYPE_LZMS; -} - -static u32 -wim_default_solid_chunk_size(int ctype) { - switch (ctype) { - case WIMLIB_COMPRESSION_TYPE_LZMS: - return (u32)1 << 26; /* 67108864 */ - default: - return (u32)1 << 15; /* 32768 */ - } + return (unsigned)ctype < ARRAY_LEN(wim_ctype_info) && + wim_ctype_info[(unsigned)ctype].name != NULL; } -static WIMStruct * -new_wim_struct(void) +/* Is the specified chunk size valid for the compression type? */ +static bool +wim_chunk_size_valid(u32 chunk_size, enum wimlib_compression_type ctype) { - WIMStruct *wim = CALLOC(1, sizeof(WIMStruct)); - if (!wim) - return NULL; + if (!(chunk_size == 0 || is_power_of_2(chunk_size))) + return false; - 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; + return chunk_size >= wim_ctype_info[(unsigned)ctype].min_chunk_size && + chunk_size <= wim_ctype_info[(unsigned)ctype].max_chunk_size; } -/* Determine if the chunk size is valid for the specified compression type. */ -static bool -wim_chunk_size_valid(u32 chunk_size, int ctype) +/* 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) { - 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 = fls32(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 wim_ctype_info[(unsigned)ctype].default_nonsolid_chunk_size; } -/* Return the default chunk size to use for the specified compression type. - * - * See notes above in wim_chunk_size_valid(). */ +/* Return the default chunk size to use for the specified compression type in + * solid resources. */ static u32 -wim_default_chunk_size(int ctype) +wim_default_solid_chunk_size(enum wimlib_compression_type ctype) { - switch (ctype) { - case WIMLIB_COMPRESSION_TYPE_LZMS: - return 1U << 17; /* 131072 */ - default: - return 1U << 15; /* 32768 */ - } + return wim_ctype_info[(unsigned)ctype].default_solid_chunk_size; +} + +/* Return the default compression type to use in solid resources. */ +static enum wimlib_compression_type +wim_default_solid_compression_type(void) +{ + return WIMLIB_COMPRESSION_TYPE_LZMS; } static int @@ -157,46 +139,28 @@ wim_has_solid_resources(const WIMStruct *wim) 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; int ret; + WIMStruct *wim; ret = wimlib_global_init(WIMLIB_INIT_FLAG_ASSUME_UTF8); if (ret) @@ -205,29 +169,39 @@ wimlib_create_new_wim(int ctype, WIMStruct **wim_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; - wim->blob_table = new_blob_table(9001); if (!wim->blob_table) { - ret = WIMLIB_ERR_NOMEM; - goto out_free_wim; + wimlib_free(wim); + return WIMLIB_ERR_NOMEM; } - 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; + randomize_byte_array(wim->hdr.guid, WIMLIB_GUID_LEN); + 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 @@ -250,13 +224,7 @@ destroy_image_metadata(struct wim_image_metadata *imd, free_blob_descriptor(blob); } INIT_LIST_HEAD(&imd->unhashed_blobs); - 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_HLIST_HEAD(&imd->inode_list); } void @@ -293,7 +261,7 @@ new_image_metadata(void) imd = CALLOC(1, sizeof(*imd)); if (imd) { imd->refcnt = 1; - INIT_LIST_HEAD(&imd->inode_list); + INIT_HLIST_HEAD(&imd->inode_list); INIT_LIST_HEAD(&imd->unhashed_blobs); } return imd; @@ -384,22 +352,38 @@ deselect_current_wim_image(WIMStruct *wim) wim->current_image = WIMLIB_NO_IMAGE; } -/* API function documented in wimlib.h */ -WIMLIBAPI const tchar * -wimlib_get_compression_type_string(int ctype) +/* + * 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 *)) { - 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"); + 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 */ @@ -524,41 +508,35 @@ 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_solid_compression_type); - if (ret) - return ret; + if (!wim_compression_type_valid(ctype)) + return WIMLIB_ERR_INVALID_COMPRESSION_TYPE; + + /* Solid resources can't be uncompressed. */ + if (ctype == WIMLIB_COMPRESSION_TYPE_NONE) + return WIMLIB_ERR_INVALID_COMPRESSION_TYPE; + + wim->out_solid_compression_type = ctype; /* Reset the chunk size if it's no longer valid. */ if (!wim_chunk_size_valid(wim->out_solid_chunk_size, ctype)) @@ -566,34 +544,26 @@ wimlib_set_output_pack_compression_type(WIMStruct *wim, int ctype) return 0; } -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; - - *out_chunk_size_p = chunk_size; - 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_solid_chunk_size = @@ -601,9 +571,21 @@ wimlib_set_output_pack_chunk_size(WIMStruct *wim, uint32_t chunk_size) return 0; } - return set_out_chunk_size(chunk_size, - wim->out_solid_compression_type, - &wim->out_solid_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 @@ -948,16 +930,15 @@ static pthread_mutex_t lib_initialization_mutex = PTHREAD_MUTEX_INITIALIZER; WIMLIBAPI int wimlib_global_init(int init_flags) { - int ret; + int ret = 0; if (lib_initialized) - return 0; + goto out; pthread_mutex_lock(&lib_initialization_mutex); - ret = 0; if (lib_initialized) - goto out; + goto out_unlock; #ifdef ENABLE_ERROR_MESSAGES if (!wimlib_error_file) @@ -971,7 +952,14 @@ wimlib_global_init(int init_flags) WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES | WIMLIB_INIT_FLAG_DEFAULT_CASE_SENSITIVE | WIMLIB_INIT_FLAG_DEFAULT_CASE_INSENSITIVE)) - goto out; + 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(); if (!(init_flags & WIMLIB_INIT_FLAG_ASSUME_UTF8)) { @@ -984,7 +972,7 @@ wimlib_global_init(int init_flags) #ifdef __WIN32__ ret = win32_global_init(init_flags); if (ret) - goto out; + goto out_unlock; #endif iconv_global_init(); init_upcase(); @@ -994,8 +982,9 @@ wimlib_global_init(int init_flags) default_ignore_case = true; lib_initialized = true; ret = 0; -out: +out_unlock: pthread_mutex_unlock(&lib_initialization_mutex); +out: return ret; } @@ -1009,7 +998,7 @@ wimlib_global_cleanup(void) pthread_mutex_lock(&lib_initialization_mutex); if (!lib_initialized) - goto out; + goto out_unlock; libxml_global_cleanup(); iconv_global_cleanup(); @@ -1020,6 +1009,6 @@ wimlib_global_cleanup(void) wimlib_set_error_file(NULL); lib_initialized = false; -out: +out_unlock: pthread_mutex_unlock(&lib_initialization_mutex); }