From 30cfd915ede8a2b24b693525ff835b2f03220cc9 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 21 May 2013 20:42:33 -0500 Subject: [PATCH] Add WIMLIB_OPEN_FLAG_WRITE_ACCESS flag --- NEWS | 16 ++++++++ include/wimlib.h | 94 +++++++++++++++++++++++++++----------------- include/wimlib/wim.h | 3 +- programs/imagex.c | 83 +++++++++----------------------------- src/header.c | 10 +---- src/split.c | 4 -- src/util.c | 4 +- src/wim.c | 76 ++++++++++++++++++++++++++++------- src/write.c | 9 +++-- 9 files changed, 162 insertions(+), 137 deletions(-) diff --git a/NEWS b/NEWS index bc18a41c..75b2b7d5 100644 --- a/NEWS +++ b/NEWS @@ -24,6 +24,22 @@ Version 1.4.1: wimlib-imagex will now choose different units for progress messages, depending on the amount of data that needs to be processed. + `wimlib-imagex append' will now generate a unique WIM image name if no + name is specified and the defaulted name already exists in the WIM. + + wimlib now allows you to create unnamed WIM images, which can then only + be referred to by index. + + wimlib now allows you to explicitly declare you want write access to a + WIM by providing the WIMLIB_OPEN_FLAG_WRITE_ACCESS flag to + wimlib_open_wim(). + + Progress callbacks have been added to wimlib's wimlib_update_image() + function. + + NTFS-3g capture now only warns about two conditions previously treated + as errors. + Fixed a couple issues with using wimlib-imagex on UDF filesystems. Version 1.4.0: diff --git a/include/wimlib.h b/include/wimlib.h index b7a21cf4..9951e502 100644 --- a/include/wimlib.h +++ b/include/wimlib.h @@ -805,12 +805,24 @@ struct wimlib_capture_config { * WIMLIB_OPEN_FLAG_* ******************************/ -/** Verify the WIM contents against the WIM's integrity table, if present. */ +/** Verify the WIM contents against the WIM's integrity table, if present. This + * causes the raw data of the WIM file, divided into 10 MB chunks, to be + * checksummed and checked against the SHA1 message digests specified in the + * integrity table. WIMLIB_ERR_INTEGRITY is returned if there are any + * mismatches. */ #define WIMLIB_OPEN_FLAG_CHECK_INTEGRITY 0x00000001 -/** Do not issue an error if the WIM is part of a split WIM. */ +/** Do not issue an error if the WIM is part of a split WIM. */ #define WIMLIB_OPEN_FLAG_SPLIT_OK 0x00000002 +/** Check if the WIM is writable and return ::WIMLIB_ERR_WIM_IS_READONLY if it + * is not. A WIM is considered writable only if it is writable at the + * filesystem level, does not have the WIM_HDR_FLAG_READONLY flag set in its + * header (note: wimlib currently never sets this flag), and is not part of a + * spanned set. It is not required to provide this flag to make changes to the + * WIM, but with this flag you get the error sooner rather than later. */ +#define WIMLIB_OPEN_FLAG_WRITE_ACCESS 0x00000004 + /****************************** * WIMLIB_UNMOUNT_FLAG_* ******************************/ @@ -1022,7 +1034,7 @@ enum wimlib_error_code { WIMLIB_ERR_VOLUME_LACKS_FEATURES, WIMLIB_ERR_WRITE, WIMLIB_ERR_XML, - WIMLIB_ERR_WIM_IS_MARKED_READONLY, + WIMLIB_ERR_WIM_IS_READONLY, }; @@ -1050,12 +1062,14 @@ enum wimlib_error_code { * * @return 0 on success; nonzero on failure. The possible error codes are: * - * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED - * @a wim is part of a split WIM. * @retval ::WIMLIB_ERR_IMAGE_NAME_COLLISION * There is already an image in @a wim named @a name. * @retval ::WIMLIB_ERR_NOMEM * Failed to allocate the memory needed to add the new image. + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * The WIM file is considered read-only because of any of the reasons + * mentioned in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS + * flag. */ extern int wimlib_add_empty_image(WIMStruct *wim, @@ -1203,9 +1217,10 @@ wimlib_create_new_wim(int ctype, WIMStruct **wim_ret); * Failed to allocate needed memory. * @retval ::WIMLIB_ERR_READ * Could not read the metadata resource for @a image from the WIM. - * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED - * @a wim is part of a split WIM. Deleting an image from a split WIM is - * unsupported. + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * The WIM file is considered read-only because of any of the reasons + * mentioned in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS + * flag. */ extern int wimlib_delete_image(WIMStruct *wim, int image); @@ -1306,9 +1321,10 @@ wimlib_delete_image(WIMStruct *wim, int image); * complete split WIM because they do not include all the parts of the * original WIM, there are duplicate parts, or not all the parts have the * same GUID and compression type. - * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED - * @a dest_wim is part of a split WIM. Exporting an image to a split WIM - * is unsupported. + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * @a dest_wim is considered read-only because of any of the reasons + * mentioned in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS + * flag. */ extern int wimlib_export_image(WIMStruct *src_wim, int src_image, @@ -1758,7 +1774,7 @@ wimlib_image_name_in_use(const WIMStruct *wim, const wimlib_tchar *name); * * @return 0 on success; nonzero on error. This function may return any value * returned by wimlib_open_wim() and wimlib_write() except - * ::WIMLIB_ERR_SPLIT_UNSUPPORTED, as well as the following error code: + * ::WIMLIB_ERR_WIM_IS_READONLY, as well as the following error code: * * @retval ::WIMLIB_ERR_SPLIT_INVALID * The split WIMs do not form a valid WIM because they do not include all @@ -1926,9 +1942,10 @@ wimlib_lzx_decompress(const void *compressed_data, unsigned compressed_len, * split WIM because they do not include all the parts of the original WIM, * there are duplicate parts, or not all the parts have the same GUID and * compression type. - * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED - * The WIM is a split WIM and a read-write mount was requested. We only - * support mounting a split WIM read-only. + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * ::WIMLIB_MOUNT_FLAG_READWRITE was specified in @a mount_flags, but @a + * wim is considered read-only because of any of the reasons mentioned in + * the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS flag. * @retval ::WIMLIB_ERR_UNSUPPORTED * Mounting is not supported, either because the platform is Windows, or * because the platform is UNIX and wimlib was compiled with @c @@ -1950,18 +1967,7 @@ wimlib_mount_image(WIMStruct *wim, * The path to the WIM file to open. * @param open_flags * Bitwise OR of flags ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY and/or - * ::WIMLIB_OPEN_FLAG_SPLIT_OK. - *

- * If ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY is given, the integrity table of - * the WIM, if it exists, is checked, and this function will fail with an - * ::WIMLIB_ERR_INTEGRITY status if any of the computed SHA1 message - * digests of the WIM do not exactly match the corresponding message - * digests given in the integrity table. - *

- * If ::WIMLIB_OPEN_FLAG_SPLIT_OK is given, no error will be issued if the - * WIM is part of a split WIM; otherwise ::WIMLIB_ERR_SPLIT_UNSUPPORTED is - * returned. (This flag may be removed in the future, in which case no - * error will be issued when opening a split WIM.) + * ::WIMLIB_OPEN_FLAG_SPLIT_OK and/or ::WIMLIB_OPEN_FLAG_WRITE_ACCESS. * * @param progress_func * If non-NULL, a function that will be called periodically with the @@ -2018,6 +2024,10 @@ wimlib_mount_image(WIMStruct *wim, * @retval ::WIMLIB_ERR_UNKNOWN_VERSION * A number other than 0x10d00 is written in the version field of the WIM * header of @a wim_file. (Probably a pre-Vista WIM). + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * ::WIMLIB_OPEN_FLAG_WRITE_ACCESS was specified and but the WIM file was + * considered read-only because of any of the reasons mentioned in the + * documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS flag. * @retval ::WIMLIB_ERR_XML * The XML data for @a wim_file is invalid. */ @@ -2086,7 +2096,7 @@ wimlib_open_wim(const wimlib_tchar *wim_file, * @return 0 on success; nonzero on error. This function may return any value * returned by wimlib_write() as well as the following error codes: * @retval ::WIMLIB_ERR_ALREADY_LOCKED - * The WIM was going to be modifien in-place (with no temporary file), but + * The WIM was going to be modified in-place (with no temporary file), but * an exclusive advisory lock on the on-disk WIM file could not be acquired * because another thread or process has mounted an image from the WIM * read-write or is currently modifying the WIM in-place. @@ -2096,6 +2106,10 @@ wimlib_open_wim(const wimlib_tchar *wim_file, * @retval ::WIMLIB_ERR_RENAME * The temporary file that the WIM was written to could not be renamed to * the original filename of @a wim. + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * The WIM file is considered read-only because of any of the reasons + * mentioned in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS + * flag. */ extern int wimlib_overwrite(WIMStruct *wim, int write_flags, unsigned num_threads, @@ -2275,8 +2289,9 @@ wimlib_resolve_image(WIMStruct *wim, * @retval ::WIMLIB_ERR_INVALID_IMAGE * @a boot_idx does not specify an existing image in @a wim, and it was not * 0. - * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED - * @a wim is part of a split WIM. + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * @a wim is considered read-only because of any of the reasons mentioned + * in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS flag. */ extern int wimlib_set_boot_idx(WIMStruct *wim, int boot_idx); @@ -2300,8 +2315,9 @@ wimlib_set_boot_idx(WIMStruct *wim, int boot_idx); * @retval ::WIMLIB_ERR_NOMEM * Failed to allocate the memory needed to duplicate the @a description * string. - * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED - * @a wim is part of a split WIM. + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * @a wim is considered read-only because of any of the reasons mentioned + * in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS flag. */ extern int wimlib_set_image_descripton(WIMStruct *wim, int image, @@ -2326,8 +2342,9 @@ wimlib_set_image_descripton(WIMStruct *wim, int image, * @a image does not specify a single existing image in @a wim. * @retval ::WIMLIB_ERR_NOMEM * Failed to allocate the memory needed to duplicate the @a flags string. - * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED - * @a wim is part of a split WIM. + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * @a wim is considered read-only because of any of the reasons mentioned + * in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS flag. */ extern int wimlib_set_image_flags(WIMStruct *wim, int image, const wimlib_tchar *flags); @@ -2353,8 +2370,9 @@ extern int wimlib_set_image_flags(WIMStruct *wim, int image, * @a image does not specify a single existing image in @a wim. * @retval ::WIMLIB_ERR_NOMEM * Failed to allocate the memory needed to duplicate the @a name string. - * @retval ::WIMLIB_ERR_SPLIT_UNSUPPORTED - * @a wim is part of a split WIM. + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * @a wim is considered read-only because of any of the reasons mentioned + * in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS flag. */ extern int wimlib_set_image_name(WIMStruct *wim, int image, const wimlib_tchar *name); @@ -2623,6 +2641,10 @@ wimlib_unmount_image(const wimlib_tchar *dir, * or, the platform is Windows and either the ::WIMLIB_ADD_FLAG_UNIX_DATA * or the ::WIMLIB_ADD_FLAG_DEREFERENCE flags were specified in the @a * add_flags for an update command. + * @retval ::WIMLIB_ERR_WIM_IS_READONLY + * The WIM file is considered read-only because of any of the reasons + * mentioned in the documentation for the ::WIMLIB_OPEN_FLAG_WRITE_ACCESS + * flag. */ extern int wimlib_update_image(WIMStruct *wim, diff --git a/include/wimlib/wim.h b/include/wimlib/wim.h index c1e669f9..9d01522a 100644 --- a/include/wimlib/wim.h +++ b/include/wimlib/wim.h @@ -55,8 +55,7 @@ extern int wim_run_full_verifications(WIMStruct *w); extern int -read_header(const tchar *filename, int in_fd, struct wim_header *hdr, - int split_ok); +read_header(const tchar *filename, int in_fd, struct wim_header *hdr); extern int write_header(const struct wim_header *hdr, int out_fd); diff --git a/programs/imagex.c b/programs/imagex.c index 5d7aa233..ebbb650e 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -980,18 +980,6 @@ stdin_get_text_contents(size_t *num_tchars_ret) return translate_text_to_tstr(contents, num_bytes, num_tchars_ret); } -/* Return 0 if a path names a file to which the current user has write access; - * -1 otherwise (and print an error message). */ -static int -file_writable(const tchar *path) -{ - int ret; - ret = taccess(path, W_OK); - if (ret != 0) - imagex_error_with_errno(T("Can't modify \"%"TS"\""), path); - return ret; -} - #define TO_PERCENT(numerator, denominator) \ (((denominator) == 0) ? 0 : ((numerator) * 100 / (denominator))) @@ -1656,7 +1644,7 @@ static int imagex_capture_or_append(int argc, tchar **argv) { int c; - int open_flags = 0; + int open_flags = WIMLIB_OPEN_FLAG_WRITE_ACCESS; int add_image_flags = WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE; int write_flags = 0; int compression_type = WIMLIB_COMPRESSION_TYPE_XPRESS; @@ -1889,8 +1877,6 @@ imagex_capture_or_append(int argc, tchar **argv) ret = wimlib_write(w, wimfile, WIMLIB_ALL_IMAGES, write_flags, num_threads, imagex_progress_func); } - if (ret == WIMLIB_ERR_REOPEN) - ret = 0; if (ret != 0) imagex_error(T("Failed to write the WIM file \"%"TS"\""), wimfile); @@ -1919,7 +1905,7 @@ static int imagex_delete(int argc, tchar **argv) { int c; - int open_flags = 0; + int open_flags = WIMLIB_OPEN_FLAG_WRITE_ACCESS; int write_flags = 0; const tchar *wimfile; const tchar *image_num_or_name; @@ -1955,10 +1941,6 @@ imagex_delete(int argc, tchar **argv) wimfile = argv[0]; image_num_or_name = argv[1]; - ret = file_writable(wimfile); - if (ret != 0) - return ret; - ret = wimlib_open_wim(wimfile, open_flags, &w, imagex_progress_func); if (ret != 0) @@ -1977,8 +1959,6 @@ imagex_delete(int argc, tchar **argv) } ret = wimlib_overwrite(w, write_flags, 0, imagex_progress_func); - if (ret == WIMLIB_ERR_REOPEN) - ret = 0; if (ret != 0) { imagex_error(T("Failed to write the file \"%"TS"\" with image " "deleted"), wimfile); @@ -2130,12 +2110,8 @@ imagex_export(int argc, tchar **argv) ret = -1; goto out; } - ret = wimlib_open_wim(dest_wimfile, open_flags, &dest_w, - imagex_progress_func); - if (ret != 0) - goto out; - - ret = file_writable(dest_wimfile); + ret = wimlib_open_wim(dest_wimfile, open_flags | WIMLIB_OPEN_FLAG_WRITE_ACCESS, + &dest_w, imagex_progress_func); if (ret != 0) goto out; @@ -2194,8 +2170,6 @@ imagex_export(int argc, tchar **argv) ret = wimlib_overwrite(dest_w, write_flags, num_threads, imagex_progress_func); out: - if (ret == WIMLIB_ERR_REOPEN) - ret = 0; wimlib_free(src_w); wimlib_free(dest_w); if (additional_swms) { @@ -2591,11 +2565,7 @@ imagex_info(int argc, tchar **argv) } else { /* Modification operations */ - if (total_parts != 1) { - imagex_error(T("Modifying a split WIM is not supported.")); - ret = -1; - goto out; - } + if (image == WIMLIB_ALL_IMAGES) image = 1; @@ -2653,21 +2623,12 @@ imagex_info(int argc, tchar **argv) if (boot || new_name || new_desc || (check && !wimlib_has_integrity_table(w))) { - int write_flags; - - ret = file_writable(wimfile); - if (ret != 0) - goto out; + int write_flags = 0; if (check) - write_flags = WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; - else - write_flags = 0; - + write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY; ret = wimlib_overwrite(w, write_flags, 1, imagex_progress_func); - if (ret == WIMLIB_ERR_REOPEN) - ret = 0; } else { tprintf(T("The file \"%"TS"\" was not modified because nothing " "needed to be done.\n"), wimfile); @@ -2736,8 +2697,10 @@ imagex_mount_rw_or_ro(int argc, tchar **argv) unsigned num_additional_swms = 0; const tchar *staging_dir = NULL; - if (!tstrcmp(argv[0], T("mountrw"))) + if (!tstrcmp(argv[0], T("mountrw"))) { mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE; + open_flags |= WIMLIB_OPEN_FLAG_WRITE_ACCESS; + } for_opt(c, mount_options) { switch (c) { @@ -2816,12 +2779,6 @@ imagex_mount_rw_or_ro(int argc, tchar **argv) goto out; } - if (mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) { - ret = file_writable(wimfile); - if (ret != 0) - goto out; - } - ret = wimlib_mount_image(w, image, dir, mount_flags, additional_swms, num_additional_swms, staging_dir); if (ret != 0) { @@ -2849,7 +2806,7 @@ static int imagex_optimize(int argc, tchar **argv) { int c; - int open_flags = 0; + int open_flags = WIMLIB_OPEN_FLAG_WRITE_ACCESS; int write_flags = WIMLIB_WRITE_FLAG_REBUILD; int ret; WIMStruct *w; @@ -2887,10 +2844,6 @@ imagex_optimize(int argc, tchar **argv) wimfile = argv[0]; - ret = file_writable(wimfile); - if (ret) - return ret; - ret = wimlib_open_wim(wimfile, open_flags, &w, imagex_progress_func); if (ret) @@ -3024,7 +2977,7 @@ imagex_update(int argc, tchar **argv) int image; WIMStruct *wim; int ret; - int open_flags = 0; + int open_flags = WIMLIB_OPEN_FLAG_WRITE_ACCESS; int write_flags = 0; int update_flags = WIMLIB_UPDATE_FLAG_SEND_PROGRESS; int default_add_flags = WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE; @@ -3115,10 +3068,6 @@ imagex_update(int argc, tchar **argv) goto out_usage; wimfile = argv[0]; - ret = file_writable(wimfile); - if (ret) - goto out; - ret = wimlib_open_wim(wimfile, open_flags, &wim, imagex_progress_func); if (ret) goto out; @@ -3188,11 +3137,13 @@ imagex_update(int argc, tchar **argv) } /* Set default flags and capture config on the update commands */ + bool have_add_command = false; for (size_t i = 0; i < num_cmds; i++) { switch (cmds[i].op) { case WIMLIB_UPDATE_OP_ADD: cmds[i].add.add_flags |= default_add_flags; cmds[i].add.config = config; + have_add_command = true; break; case WIMLIB_UPDATE_OP_DELETE: cmds[i].delete.delete_flags |= default_delete_flags; @@ -3203,7 +3154,8 @@ imagex_update(int argc, tchar **argv) } #ifdef __WIN32__ - win32_acquire_capture_privileges(); + if (have_add_command) + win32_acquire_capture_privileges(); #endif /* Execute the update commands */ @@ -3217,7 +3169,8 @@ imagex_update(int argc, tchar **argv) imagex_progress_func); out_release_privs: #ifdef __WIN32__ - win32_release_capture_privileges(); + if (have_add_command) + win32_release_capture_privileges(); #endif free(cmds); out_free_cmd_file_contents: diff --git a/src/header.c b/src/header.c index 5b164161..332d350f 100644 --- a/src/header.c +++ b/src/header.c @@ -115,8 +115,7 @@ struct wim_header_disk { /* Reads the header from a WIM file. */ int -read_header(const tchar *filename, int in_fd, - struct wim_header *hdr, int open_flags) +read_header(const tchar *filename, int in_fd, struct wim_header *hdr) { struct wim_header_disk disk_hdr _aligned_attribute(8); @@ -170,13 +169,6 @@ read_header(const tchar *filename, int in_fd, return WIMLIB_ERR_INVALID_PART_NUMBER; } - if (!(open_flags & WIMLIB_OPEN_FLAG_SPLIT_OK) && hdr->total_parts != 1) - { - ERROR("\"%"TS"\": This WIM is part %u of a %u-part WIM", - filename, hdr->part_number, hdr->total_parts); - return WIMLIB_ERR_SPLIT_UNSUPPORTED; - } - hdr->image_count = le32_to_cpu(disk_hdr.image_count); DEBUG("part_number = %u, total_parts = %u, image_count = %u", diff --git a/src/split.c b/src/split.c index 78dc8ab7..2636164b 100644 --- a/src/split.c +++ b/src/split.c @@ -143,10 +143,6 @@ wimlib_split(WIMStruct *w, const tchar *swm_name, write_flags &= WIMLIB_WRITE_MASK_PUBLIC; - ret = wim_checksum_unhashed_streams(w); - if (ret) - return ret; - swm_name_len = tstrlen(swm_name); tchar swm_base_name[swm_name_len + 20]; diff --git a/src/util.c b/src/util.c index 87dd3c50..2aca3da7 100644 --- a/src/util.c +++ b/src/util.c @@ -389,8 +389,8 @@ static const tchar *error_strings[] = { = T("The requested operation is unsupported"), [WIMLIB_ERR_VOLUME_LACKS_FEATURES] = T("The volume did not support a feature necessary to complete the operation"), - [WIMLIB_ERR_WIM_IS_MARKED_READONLY] - = T("The WIM is marked as read-only"), + [WIMLIB_ERR_WIM_IS_READONLY] + = T("The WIM is read-only (file permissions, header flag, or split WIM)"), [WIMLIB_ERR_WRITE] = T("Failed to write data to a file"), [WIMLIB_ERR_XML] diff --git a/src/wim.c b/src/wim.c index 4a8e6a8b..7927af3c 100644 --- a/src/wim.c +++ b/src/wim.c @@ -463,10 +463,22 @@ begin_read(WIMStruct *w, const tchar *in_wim_path, int open_flags, return WIMLIB_ERR_OPEN; } - ret = read_header(w->filename, w->in_fd, &w->hdr, open_flags); + ret = read_header(w->filename, w->in_fd, &w->hdr); if (ret) return ret; + if (open_flags & WIMLIB_OPEN_FLAG_WRITE_ACCESS) { + ret = can_modify_wim(w); + if (ret) + return ret; + } + + if (w->hdr.total_parts != 1 && !(open_flags & WIMLIB_OPEN_FLAG_SPLIT_OK)) { + ERROR("\"%"TS"\": This WIM is part %u of a %u-part WIM", + w->filename, w->hdr.part_number, w->hdr.total_parts); + return WIMLIB_ERR_SPLIT_UNSUPPORTED; + } + DEBUG("According to header, WIM contains %u images", w->hdr.image_count); /* If the boot index is invalid, print a warning and set it to 0 */ @@ -528,24 +540,31 @@ begin_read(WIMStruct *w, const tchar *in_wim_path, int open_flags, */ WIMLIBAPI int wimlib_open_wim(const tchar *wim_file, int open_flags, - WIMStruct **w_ret, + WIMStruct **wim_ret, wimlib_progress_func_t progress_func) { - WIMStruct *w; + WIMStruct *wim; int ret; - if (!wim_file || !w_ret) - return WIMLIB_ERR_INVALID_PARAM; + ret = WIMLIB_ERR_INVALID_PARAM; + if (!wim_file || !wim_ret) + goto out; - w = new_wim_struct(); - if (!w) - return WIMLIB_ERR_NOMEM; + ret = WIMLIB_ERR_NOMEM; + wim = new_wim_struct(); + if (!wim) + goto out; - ret = begin_read(w, wim_file, open_flags, progress_func); - if (ret == 0) - *w_ret = w; - else - wimlib_free(w); + ret = begin_read(wim, wim_file, open_flags, progress_func); + if (ret) + goto out_wimlib_free; + + ret = 0; + *wim_ret = wim; + goto out; +out_wimlib_free: + wimlib_free(wim); +out: return ret; } @@ -672,22 +691,49 @@ wim_checksum_unhashed_streams(WIMStruct *w) return 0; } +/* + * can_modify_wim - Check if a given WIM is writeable. This is only the case if + * it meets the following three conditions: + * + * 1. Write access is allowed to the underlying file (if any) at the filesystem level. + * 2. The WIM is not part of a spanned set. + * 3. The WIM_HDR_FLAG_READONLY flag is not set in the WIM header. + * + * Return value is 0 if writable; WIMLIB_ERR_WIM_IS_READONLY otherwise. + */ int can_modify_wim(WIMStruct *wim) { + if (wim->filename) { + if (taccess(wim->filename, W_OK)) { + ERROR_WITH_ERRNO("Can't modify \"%"TS"\"", wim->filename); + return WIMLIB_ERR_WIM_IS_READONLY; + } + } if (wim->hdr.total_parts != 1) { ERROR("Cannot modify \"%"TS"\": is part of a spanned set", wim->filename); - return WIMLIB_ERR_SPLIT_UNSUPPORTED; + return WIMLIB_ERR_WIM_IS_READONLY; } if (wim->hdr.flags & WIM_HDR_FLAG_READONLY) { ERROR("Cannot modify \"%"TS"\": is marked read-only", wim->filename); - return WIMLIB_ERR_WIM_IS_MARKED_READONLY; + return WIMLIB_ERR_WIM_IS_READONLY; } 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) { diff --git a/src/write.c b/src/write.c index 90dcaed4..2effd7db 100644 --- a/src/write.c +++ b/src/write.c @@ -2212,15 +2212,16 @@ wimlib_overwrite(WIMStruct *w, int write_flags, unsigned num_threads, wimlib_progress_func_t progress_func) { + int ret; + write_flags &= WIMLIB_WRITE_MASK_PUBLIC; if (!w->filename) return WIMLIB_ERR_NO_FILENAME; - if (w->hdr.total_parts != 1) { - ERROR("Cannot modify a split WIM"); - return WIMLIB_ERR_SPLIT_UNSUPPORTED; - } + ret = can_modify_wim(w); + if (ret) + return ret; if ((!w->deletion_occurred || (write_flags & WIMLIB_WRITE_FLAG_SOFT_DELETE)) && !(write_flags & WIMLIB_WRITE_FLAG_REBUILD)) -- 2.43.0