X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=programs%2Fimagex.c;h=eeb7093cb806e4e2a5927ddf28eabc044bb36cfa;hp=e524135870343292797ac5ea1a185a929c40ed06;hb=c78bad31163cdefdf3f97e199c4f19bd8a9ad0a2;hpb=01c6f902b2a48a33af3f94e29791f85c68df91d0 diff --git a/programs/imagex.c b/programs/imagex.c index e5241358..eeb7093c 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 */ @@ -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( @@ -217,6 +221,7 @@ enum { IMAGEX_METADATA_OPTION, IMAGEX_NORPFIX_OPTION, IMAGEX_NO_ACLS_OPTION, + IMAGEX_PATH_OPTION, IMAGEX_REBUILD_OPTION, IMAGEX_RECOMPRESS_OPTION, IMAGEX_RECURSIVE_OPTION, @@ -275,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}, @@ -976,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))) @@ -1065,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")); @@ -1119,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, @@ -1192,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; } @@ -1631,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; @@ -1659,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) { @@ -1730,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; @@ -1815,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 @@ -1846,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); @@ -1876,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; @@ -1912,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) @@ -1934,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); @@ -1945,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 @@ -2087,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; @@ -2107,11 +2156,11 @@ imagex_export(int argc, tchar **argv) goto out; } } else { - wim_is_new = true; /* dest_wimfile is not an existing file, so create a new WIM. */ - if (!compression_type_specified) - compression_type = wimlib_get_compression_type(src_w); if (errno == ENOENT) { + wim_is_new = true; + if (!compression_type_specified) + compression_type = wimlib_get_compression_type(src_w); ret = wimlib_create_new_wim(compression_type, &dest_w); if (ret != 0) goto out; @@ -2151,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) { @@ -2215,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; @@ -2352,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 @@ -2375,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) { @@ -2438,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"))) { @@ -2453,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")); @@ -2464,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 " @@ -2495,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) { @@ -2548,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; @@ -2571,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) { @@ -2610,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); @@ -2693,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) { @@ -2773,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) { @@ -2806,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; @@ -2844,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) @@ -2981,9 +3076,9 @@ 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; @@ -3072,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; @@ -3145,11 +3236,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; @@ -3160,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 */ @@ -3174,7 +3268,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: