X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=programs%2Fimagex.c;h=8f0f4b87ffce4e68cb65fedb829a83fb46fa7d87;hp=9ee6df34ed630e99198f13584456f2f2c823d74a;hb=bb11c4650a416d1eaf6c8f8385c3c6e4d5e0eff3;hpb=d55cda59032e0abe5f71cd6f16ade943d2713fee diff --git a/programs/imagex.c b/programs/imagex.c index 9ee6df34..8f0f4b87 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -50,12 +50,16 @@ # include "imagex-win32.h" # define tbasename win32_wbasename # define tglob win32_wglob +# define OS_PREFERRED_PATH_SEPARATOR L'\\' +# define OS_PREFERRED_PATH_SEPARATOR_STRING L"\\" #else /* __WIN32__ */ # include # include # include # define tbasename basename # define tglob glob +# define OS_PREFERRED_PATH_SEPARATOR '/' +# define OS_PREFERRED_PATH_SEPARATOR_STRING "/" #endif /* !__WIN32 */ @@ -104,7 +108,7 @@ IMAGEX_PROGNAME" apply WIMFILE [IMAGE_NUM | IMAGE_NAME | all]\n" " (DIRECTORY | NTFS_VOLUME) [--check] [--hardlink]\n" " [--symlink] [--verbose] [--ref=\"GLOB\"] [--unix-data]\n" " [--no-acls] [--strict-acls] [--rpfix] [--norpfix]\n" -" [--force-all-files]\n" +" [--include-invalid-names]\n" ), [CAPTURE] = T( @@ -121,7 +125,7 @@ IMAGEX_PROGNAME" delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check] [--soft ), [DIR] = T( -IMAGEX_PROGNAME" dir WIMFILE (IMAGE_NUM | IMAGE_NAME | all)\n" +IMAGEX_PROGNAME" dir WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--path=PATH]\n" ), [EXPORT] = T( @@ -135,7 +139,7 @@ T( IMAGEX_PROGNAME" extract WIMFILE (IMAGE_NUM | IMAGE_NAME) [PATH...]\n" " [--check] [--ref=\"GLOB\"] [--verbose] [--unix-data]\n" " [--no-acls] [--strict-acls] [--to-stdout] [--dest-dir=DIR]\n" -" [--force-all-files]\n" +" [--include-invalid-names]\n" ), [INFO] = T( @@ -176,7 +180,7 @@ IMAGEX_PROGNAME" unmount DIRECTORY [--commit] [--check] [--rebuild] [--lazy]\n" T( IMAGEX_PROGNAME" update WIMFILE [IMAGE_NUM | IMAGE_NAME] [--check] [--rebuild]\n" " [--threads=NUM_THREADS] [DEFAULT_ADD_OPTIONS]\n" -" [DEFAULT_DELETE_OPTIONS] < CMDFILE\n" +" [DEFAULT_DELETE_OPTIONS] [--command=STRING] [< CMDFILE]\n" ), }; @@ -199,6 +203,7 @@ enum { IMAGEX_ALLOW_OTHER_OPTION, IMAGEX_BOOT_OPTION, IMAGEX_CHECK_OPTION, + IMAGEX_COMMAND_OPTION, IMAGEX_COMMIT_OPTION, IMAGEX_COMPRESS_OPTION, IMAGEX_CONFIG_OPTION, @@ -208,14 +213,15 @@ enum { IMAGEX_EXTRACT_XML_OPTION, IMAGEX_FLAGS_OPTION, IMAGEX_FORCE_OPTION, - IMAGEX_FORCE_ALL_FILES_OPTION, IMAGEX_HARDLINK_OPTION, IMAGEX_HEADER_OPTION, + IMAGEX_INCLUDE_INVALID_NAMES_OPTION, IMAGEX_LAZY_OPTION, IMAGEX_LOOKUP_TABLE_OPTION, IMAGEX_METADATA_OPTION, IMAGEX_NORPFIX_OPTION, IMAGEX_NO_ACLS_OPTION, + IMAGEX_PATH_OPTION, IMAGEX_REBUILD_OPTION, IMAGEX_RECOMPRESS_OPTION, IMAGEX_RECURSIVE_OPTION, @@ -246,7 +252,7 @@ static const struct option apply_options[] = { {T("strict-acls"), no_argument, NULL, IMAGEX_STRICT_ACLS_OPTION}, {T("rpfix"), no_argument, NULL, IMAGEX_RPFIX_OPTION}, {T("norpfix"), no_argument, NULL, IMAGEX_NORPFIX_OPTION}, - {T("force-all-files"), no_argument, NULL, IMAGEX_FORCE_ALL_FILES_OPTION}, + {T("include-invalid-names"), no_argument, NULL, IMAGEX_INCLUDE_INVALID_NAMES_OPTION}, {NULL, 0, NULL, 0}, }; static const struct option capture_or_append_options[] = { @@ -274,6 +280,11 @@ static const struct option delete_options[] = { {NULL, 0, NULL, 0}, }; +static const struct option dir_options[] = { + {T("path"), required_argument, NULL, IMAGEX_PATH_OPTION}, + {NULL, 0, NULL, 0}, +}; + static const struct option export_options[] = { {T("boot"), no_argument, NULL, IMAGEX_BOOT_OPTION}, {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, @@ -294,7 +305,7 @@ static const struct option extract_options[] = { {T("strict-acls"), no_argument, NULL, IMAGEX_STRICT_ACLS_OPTION}, {T("dest-dir"), required_argument, NULL, IMAGEX_DEST_DIR_OPTION}, {T("to-stdout"), no_argument, NULL, IMAGEX_TO_STDOUT_OPTION}, - {T("force-all-files"), no_argument, NULL, IMAGEX_FORCE_ALL_FILES_OPTION}, + {T("include-invalid-names"), no_argument, NULL, IMAGEX_INCLUDE_INVALID_NAMES_OPTION}, {NULL, 0, NULL, 0}, }; @@ -353,6 +364,7 @@ static const struct option update_options[] = { {T("threads"), required_argument, NULL, IMAGEX_THREADS_OPTION}, {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION}, {T("rebuild"), no_argument, NULL, IMAGEX_REBUILD_OPTION}, + {T("command"), required_argument, NULL, IMAGEX_COMMAND_OPTION}, /* Default delete options */ {T("force"), no_argument, NULL, IMAGEX_FORCE_OPTION}, @@ -368,6 +380,7 @@ static const struct option update_options[] = { {T("noacls"), no_argument, NULL, IMAGEX_NO_ACLS_OPTION}, {T("no-acls"), no_argument, NULL, IMAGEX_NO_ACLS_OPTION}, {T("strict-acls"), no_argument, NULL, IMAGEX_STRICT_ACLS_OPTION}, + {NULL, 0, NULL, 0}, }; @@ -973,18 +986,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))) @@ -1062,7 +1063,8 @@ imagex_progress_func(enum wimlib_progress_msg msg, case WIMLIB_PROGRESS_MSG_SCAN_BEGIN: tprintf(T("Scanning \"%"TS"\""), info->scan.source); if (*info->scan.wim_target_path) { - tprintf(T(" (loading as WIM path: \"/%"TS"\")...\n"), + tprintf(T(" (loading as WIM path: " + "\""WIMLIB_WIM_PATH_SEPARATOR_STRING"%"TS"\")...\n"), info->scan.wim_target_path); } else { tprintf(T(" (loading as root of WIM image)...\n")); @@ -1080,8 +1082,8 @@ imagex_progress_func(enum wimlib_progress_msg msg, unit_shift = get_unit(info->integrity.total_bytes, &unit_name); percent_done = TO_PERCENT(info->integrity.completed_bytes, info->integrity.total_bytes); - tprintf(T("\rVerifying integrity of \"%"TS"\": %"PRIu64" "TS" " - "of %"PRIu64" "TS" (%u%%) done"), + tprintf(T("\rVerifying integrity of \"%"TS"\": %"PRIu64" %"TS" " + "of %"PRIu64" %"TS" (%u%%) done"), info->integrity.filename, info->integrity.completed_bytes >> unit_shift, unit_name, @@ -1116,7 +1118,8 @@ imagex_progress_func(enum wimlib_progress_msg msg, info->extract.target); break; case WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN: - tprintf(T("Extracting \"%"TS"\" from image %d (\"%"TS"\") " + tprintf(T("Extracting " + "\""WIMLIB_WIM_PATH_SEPARATOR_STRING"%"TS"\" from image %d (\"%"TS"\") " "in \"%"TS"\" to \"%"TS"\"\n"), info->extract.extract_root_wim_source_path, info->extract.image, @@ -1189,6 +1192,25 @@ imagex_progress_func(enum wimlib_progress_msg msg, info->split.cur_part_number); } break; + case WIMLIB_PROGRESS_MSG_UPDATE_END_COMMAND: + switch (info->update.command->op) { + case WIMLIB_UPDATE_OP_DELETE: + tprintf(T("Deleted WIM path " + "\""WIMLIB_WIM_PATH_SEPARATOR_STRING "%"TS"\"\n"), + info->update.command->delete.wim_path); + break; + case WIMLIB_UPDATE_OP_RENAME: + tprintf(T("Renamed WIM path " + "\""WIMLIB_WIM_PATH_SEPARATOR_STRING "%"TS"\" => " + "\""WIMLIB_WIM_PATH_SEPARATOR_STRING "%"TS"\"\n"), + info->update.command->rename.wim_source_path, + info->update.command->rename.wim_target_path); + break; + case WIMLIB_UPDATE_OP_ADD: + default: + break; + } + break; default: break; } @@ -1533,7 +1555,7 @@ imagex_apply(int argc, tchar **argv) case IMAGEX_RPFIX_OPTION: extract_flags |= WIMLIB_EXTRACT_FLAG_RPFIX; break; - case IMAGEX_FORCE_ALL_FILES_OPTION: + case IMAGEX_INCLUDE_INVALID_NAMES_OPTION: extract_flags |= WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES; extract_flags |= WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS; break; @@ -1628,7 +1650,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; @@ -1656,6 +1678,7 @@ imagex_capture_or_append(int argc, tchar **argv) bool capture_sources_malloced; struct wimlib_capture_source *capture_sources; size_t num_sources; + bool name_defaulted; for_opt(c, capture_or_append_options) { switch (c) { @@ -1727,13 +1750,16 @@ imagex_capture_or_append(int argc, tchar **argv) if (argc >= 3) { name = argv[2]; + name_defaulted = false; } else { /* Set default name to SOURCE argument, omitting any directory * prefixes and trailing slashes. This requires making a copy - * of @source. */ + * of @source. Leave some free characters at the end in case we + * append a number to keep the name unique. */ source_name_len = tstrlen(source); - source_copy = alloca((source_name_len + 1) * sizeof(tchar)); + source_copy = alloca((source_name_len + 1 + 25) * sizeof(tchar)); name = tbasename(tstrcpy(source_copy, source)); + name_defaulted = true; } /* Image description defaults to NULL if not given. */ desc = (argc >= 4) ? argv[3] : NULL; @@ -1812,6 +1838,20 @@ imagex_capture_or_append(int argc, tchar **argv) } } } + + if (cmd == APPEND && name_defaulted) { + /* If the user did not specify an image name, and the basename + * of the source already exists as an image name in the WIM + * file, append a suffix to make it unique. */ + unsigned long conflict_idx; + tchar *name_end = tstrchr(name, T('\0')); + for (conflict_idx = 1; + wimlib_image_name_in_use(w, name); + conflict_idx++) + { + tsprintf(name_end, T(" (%lu)"), conflict_idx); + } + } #ifdef __WIN32__ win32_acquire_capture_privileges(); #endif @@ -1843,8 +1883,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); @@ -1873,7 +1911,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; @@ -1909,10 +1947,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) @@ -1931,8 +1965,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); @@ -1942,56 +1974,80 @@ out: return ret; } +static int +print_full_path(const struct wimlib_dir_entry *wdentry, void *_ignore) +{ + int ret = tprintf(T("%"TS"\n"), wdentry->full_path); + return (ret >= 0) ? 0 : -1; +} + /* Print the files contained in an image(s) in a WIM file. */ static int imagex_dir(int argc, tchar **argv) { const tchar *wimfile; - WIMStruct *w; + WIMStruct *wim = NULL; int image; int ret; - int num_images; + const tchar *path = T(""); + int c; - if (argc < 2) { + for_opt(c, dir_options) { + switch (c) { + case IMAGEX_PATH_OPTION: + path = optarg; + break; + default: + goto out_usage; + } + } + argc -= optind; + argv += optind; + + if (argc < 1) { imagex_error(T("Must specify a WIM file")); - usage(DIR); - return -1; + goto out_usage; } - if (argc > 3) { + if (argc > 2) { imagex_error(T("Too many arguments")); - usage(DIR); - return -1; + goto out_usage; } - wimfile = argv[1]; - ret = wimlib_open_wim(wimfile, WIMLIB_OPEN_FLAG_SPLIT_OK, &w, + wimfile = argv[0]; + ret = wimlib_open_wim(wimfile, WIMLIB_OPEN_FLAG_SPLIT_OK, &wim, imagex_progress_func); - if (ret != 0) - return ret; + if (ret) + goto out; - if (argc == 3) { - image = wimlib_resolve_image(w, argv[2]); - ret = verify_image_exists(image, argv[2], wimfile); - if (ret != 0) - goto out; + if (argc == 2) { + image = wimlib_resolve_image(wim, argv[1]); + ret = verify_image_exists(image, argv[1], wimfile); + if (ret) + goto out_wimlib_free; } else { /* Image was not specified. If the WIM only contains one image, * choose that one; otherwise, print an error. */ - num_images = wimlib_get_num_images(w); + int num_images = wimlib_get_num_images(wim); if (num_images != 1) { imagex_error(T("\"%"TS"\" contains %d images; Please " "select one."), wimfile, num_images); - usage(DIR); - ret = -1; - goto out; + wimlib_free(wim); + goto out_usage; } image = 1; } - ret = wimlib_print_files(w, image); + ret = wimlib_iterate_dir_tree(wim, image, path, + WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE, + print_full_path, NULL); +out_wimlib_free: + wimlib_free(wim); out: - wimlib_free(w); return ret; +out_usage: + usage(DIR); + ret = -1; + goto out; } /* Exports one, or all, images from a WIM file to a new WIM file or an existing @@ -2084,12 +2140,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; @@ -2148,8 +2200,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) { @@ -2212,8 +2262,8 @@ prepare_extract_commands(tchar **paths, unsigned num_paths, free_extract_commands(cmds, num_cmds, dest_dir); return NULL; } - tsprintf(cmds[i].fs_dest_path, T("%"TS"/%"TS), dest_dir, - tbasename(paths[i])); + tsprintf(cmds[i].fs_dest_path, T("%"TS""OS_PREFERRED_PATH_SEPARATOR_STRING"%"TS), + dest_dir, tbasename(paths[i])); } } *num_cmds_ret = num_cmds; @@ -2268,7 +2318,7 @@ imagex_extract(int argc, tchar **argv) extract_flags |= WIMLIB_EXTRACT_FLAG_TO_STDOUT; imagex_be_quiet = true; break; - case IMAGEX_FORCE_ALL_FILES_OPTION: + case IMAGEX_INCLUDE_INVALID_NAMES_OPTION: extract_flags |= WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES; extract_flags |= WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS; break; @@ -2349,6 +2399,76 @@ out_usage: goto out; } +static void print_byte_field(const uint8_t field[], size_t len) +{ + while (len--) + tprintf(T("%02hhx"), *field++); +} + +static void +print_wim_information(const tchar *wimfile, const struct wimlib_wim_info *info) +{ + tputs(T("WIM Information:")); + tputs(T("----------------")); + tprintf(T("Path: %"TS"\n"), wimfile); + tprintf(T("GUID: 0x")); + print_byte_field(info->guid, sizeof(info->guid)); + tputchar(T('\n')); + tprintf(T("Image Count: %d\n"), info->image_count); + tprintf(T("Compression: %"TS"\n"), + wimlib_get_compression_type_string(info->compression_type)); + tprintf(T("Part Number: %d/%d\n"), info->part_number, info->total_parts); + tprintf(T("Boot Index: %d\n"), info->boot_index); + tprintf(T("Size: %"PRIu64" bytes\n"), info->total_bytes); + tprintf(T("Integrity Info: %"TS"\n"), + info->has_integrity_table ? T("yes") : T("no")); + tprintf(T("Relative path junction: %"TS"\n"), + info->has_rpfix ? T("yes") : T("no")); + tputchar(T('\n')); +} + +static int +print_resource(const struct wimlib_resource_entry *resource, + void *_ignore) +{ + + tprintf(T("Uncompressed size = %"PRIu64" bytes\n"), + resource->uncompressed_size); + + tprintf(T("Compressed size = %"PRIu64" bytes\n"), + resource->compressed_size); + + tprintf(T("Offset = %"PRIu64" bytes\n"), + resource->offset); + + + tprintf(T("Part Number = %u\n"), resource->part_number); + tprintf(T("Reference Count = %u\n"), resource->reference_count); + + tprintf(T("Hash = 0x")); + print_byte_field(resource->sha1_hash, sizeof(resource->sha1_hash)); + tputchar(T('\n')); + + tprintf(T("Flags = ")); + if (resource->is_compressed) + tprintf(T("WIM_RESHDR_FLAG_COMPRESSED ")); + if (resource->is_metadata) + tprintf(T("WIM_RESHDR_FLAG_METADATA ")); + if (resource->is_free) + tprintf(T("WIM_RESHDR_FLAG_FREE ")); + if (resource->is_spanned) + tprintf(T("WIM_RESHDR_FLAG_SPANNED ")); + tputchar(T('\n')); + tputchar(T('\n')); + return 0; +} + +static void +print_lookup_table(WIMStruct *wim) +{ + wimlib_iterate_lookup_table(wim, 0, print_resource, NULL); +} + /* Prints information about a WIM file; also can mark an image as bootable, * change the name of an image, or change the description of an image. */ static int @@ -2372,9 +2492,7 @@ imagex_info(int argc, tchar **argv) int image; int ret; int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK; - int part_number; - int total_parts; - int num_images; + struct wimlib_wim_info info; for_opt(c, info_options) { switch (c) { @@ -2435,7 +2553,7 @@ imagex_info(int argc, tchar **argv) if (ret != 0) return ret; - part_number = wimlib_get_part_number(w, &total_parts); + wimlib_get_wim_info(w, &info); image = wimlib_resolve_image(w, image_num_or_name); if (image == WIMLIB_NO_IMAGE && tstrcmp(image_num_or_name, T("0"))) { @@ -2450,9 +2568,7 @@ imagex_info(int argc, tchar **argv) goto out; } - num_images = wimlib_get_num_images(w); - - if (num_images == 0) { + if (info.image_count == 0) { if (boot) { imagex_error(T("--boot is meaningless on a WIM with no " "images")); @@ -2461,7 +2577,7 @@ imagex_info(int argc, tchar **argv) } } - if (image == WIMLIB_ALL_IMAGES && num_images > 1) { + if (image == WIMLIB_ALL_IMAGES && info.image_count > 1) { if (boot) { imagex_error(T("Cannot specify the --boot flag " "without specifying a specific " @@ -2492,18 +2608,18 @@ imagex_info(int argc, tchar **argv) } if (image == WIMLIB_ALL_IMAGES && short_header) - wimlib_print_wim_information(w); + print_wim_information(wimfile, &info); if (header) wimlib_print_header(w); if (lookup_table) { - if (total_parts != 1) { - tprintf(T("Warning: Only showing the lookup table " - "for part %d of a %d-part WIM.\n"), - part_number, total_parts); + if (info.total_parts != 1) { + tfprintf(stderr, T("Warning: Only showing the lookup table " + "for part %d of a %d-part WIM.\n"), + info.part_number, info.total_parts); } - wimlib_print_lookup_table(w); + print_lookup_table(w); } if (xml) { @@ -2545,11 +2661,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; @@ -2568,7 +2680,10 @@ imagex_info(int argc, tchar **argv) } else { tprintf(T("Marking image %d as bootable.\n"), image); - wimlib_set_boot_idx(w, image); + info.boot_index = image; + ret = wimlib_set_wim_info(w, &info, WIMLIB_CHANGE_BOOT_INDEX); + if (ret) + goto out; } } if (new_name) { @@ -2607,21 +2722,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); @@ -2690,8 +2796,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) { @@ -2770,12 +2878,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) { @@ -2803,7 +2905,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; @@ -2841,10 +2943,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) @@ -2978,18 +3076,19 @@ 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 = 0; + int update_flags = WIMLIB_UPDATE_FLAG_SEND_PROGRESS; int default_add_flags = WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE; int default_delete_flags = 0; unsigned num_threads = 0; int c; - tchar *cmd_file_contents; + tchar *cmd_file_contents = NULL; size_t cmd_file_nchars; struct wimlib_update_command *cmds; size_t num_cmds; int num_images; + tchar *command_str = NULL; const tchar *config_file = NULL; tchar *config_str; @@ -3012,7 +3111,22 @@ imagex_update(int argc, tchar **argv) case IMAGEX_REBUILD_OPTION: write_flags |= WIMLIB_WRITE_FLAG_REBUILD; break; - + case IMAGEX_COMMAND_OPTION: + if (command_str) { + imagex_error(T("--command may only be specified " + "one time. Please provide\n" + " the update commands " + "on standard input instead.")); + ret = -1; + goto out; + } + command_str = tstrdup(optarg); + if (!command_str) { + imagex_error(T("Out of memory!")); + ret = -1; + goto out; + } + break; /* Default delete options */ case IMAGEX_FORCE_OPTION: default_delete_flags |= WIMLIB_DELETE_FLAG_FORCE; @@ -3053,10 +3167,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; @@ -3100,31 +3210,39 @@ imagex_update(int argc, tchar **argv) config = &default_capture_config; } - /* Read update commands from standard input */ - if (isatty(STDIN_FILENO)) { - tputs(T("Reading update commands from standard input...")); - recommend_man_page(T("update")); - } - cmd_file_contents = stdin_get_text_contents(&cmd_file_nchars); - if (!cmd_file_contents) { - ret = -1; - goto out_free_config; - } + /* Read update commands from standard input, or the command string if + * specified. */ + if (command_str) { + cmds = parse_update_command_file(&command_str, tstrlen(command_str), + &num_cmds); + } else { + if (isatty(STDIN_FILENO)) { + tputs(T("Reading update commands from standard input...")); + recommend_man_page(T("update")); + } + cmd_file_contents = stdin_get_text_contents(&cmd_file_nchars); + if (!cmd_file_contents) { + ret = -1; + goto out_free_config; + } - /* Parse the update commands */ - cmds = parse_update_command_file(&cmd_file_contents, cmd_file_nchars, - &num_cmds); + /* Parse the update commands */ + cmds = parse_update_command_file(&cmd_file_contents, cmd_file_nchars, + &num_cmds); + } if (!cmds) { ret = -1; goto out_free_cmd_file_contents; } /* 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; @@ -3135,7 +3253,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 */ @@ -3149,9 +3268,9 @@ 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 -out_free_cmds: free(cmds); out_free_cmd_file_contents: free(cmd_file_contents); @@ -3164,6 +3283,7 @@ out_free_config: out_wimlib_free: wimlib_free(wim); out: + free(command_str); return ret; out_usage: usage(UPDATE);