#ifdef __WIN32__
# include "imagex-win32.h"
-# define tbasename win32_wbasename
# define OS_PREFERRED_PATH_SEPARATOR L'\\'
# define OS_PREFERRED_PATH_SEPARATOR_STRING L"\\"
+# define print_security_descriptor win32_print_security_descriptor
#else /* __WIN32__ */
-# include <glob.h>
# include <getopt.h>
# include <langinfo.h>
-# define tbasename basename
# define OS_PREFERRED_PATH_SEPARATOR '/'
# define OS_PREFERRED_PATH_SEPARATOR_STRING "/"
+# define print_security_descriptor default_print_security_descriptor
static inline void set_fd_to_binary_mode(int fd)
{
}
#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
+static inline bool
+is_any_path_separator(tchar c)
+{
+ return c == T('/') || c == T('\\');
+}
+
+/* Like basename(), but handles both forward and backwards slashes. */
+static tchar *
+tbasename(tchar *path)
+{
+ tchar *p = tstrchr(path, T('\0'));
+
+ for (;;) {
+ if (p == path)
+ return path;
+ if (!is_any_path_separator(*--p))
+ break;
+ *p = T('\0');
+ }
+
+ for (;;) {
+ if (p == path)
+ return path;
+ if (is_any_path_separator(*--p))
+ return ++p;
+ }
+}
+
#define for_opt(c, opts) while ((c = getopt_long_only(argc, (tchar**)argv, T(""), \
opts, NULL)) != -1)
IMAGEX_ALLOW_OTHER_OPTION,
IMAGEX_BOOT_OPTION,
IMAGEX_CHECK_OPTION,
+ IMAGEX_CHUNK_SIZE_OPTION,
IMAGEX_COMMAND_OPTION,
IMAGEX_COMMIT_OPTION,
IMAGEX_COMPRESS_OPTION,
+ IMAGEX_COMPRESS_SLOW_OPTION,
IMAGEX_CONFIG_OPTION,
IMAGEX_DEBUG_OPTION,
IMAGEX_DELTA_FROM_OPTION,
IMAGEX_DEREFERENCE_OPTION,
IMAGEX_DEST_DIR_OPTION,
+ IMAGEX_DETAILED_OPTION,
IMAGEX_EXTRACT_XML_OPTION,
IMAGEX_FLAGS_OPTION,
IMAGEX_FORCE_OPTION,
IMAGEX_NORPFIX_OPTION,
IMAGEX_NOCHECK_OPTION,
IMAGEX_NO_ACLS_OPTION,
+ IMAGEX_NO_ATTRIBUTES_OPTION,
+ IMAGEX_NO_WILDCARDS_OPTION,
+ IMAGEX_NULLGLOB_OPTION,
+ IMAGEX_ONE_FILE_ONLY_OPTION,
IMAGEX_NOT_PIPABLE_OPTION,
+ IMAGEX_PACK_CHUNK_SIZE_OPTION,
+ IMAGEX_PACK_STREAMS_OPTION,
IMAGEX_PATH_OPTION,
IMAGEX_PIPABLE_OPTION,
+ IMAGEX_PRESERVE_DIR_STRUCTURE_OPTION,
IMAGEX_REBUILD_OPTION,
IMAGEX_RECOMPRESS_OPTION,
IMAGEX_RECURSIVE_OPTION,
{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},
+ {T("no-attributes"), no_argument, NULL, IMAGEX_NO_ATTRIBUTES_OPTION},
{T("rpfix"), no_argument, NULL, IMAGEX_RPFIX_OPTION},
{T("norpfix"), no_argument, NULL, IMAGEX_NORPFIX_OPTION},
{T("include-invalid-names"), no_argument, NULL, IMAGEX_INCLUDE_INVALID_NAMES_OPTION},
{T("no-check"), no_argument, NULL, IMAGEX_NOCHECK_OPTION},
{T("nocheck"), no_argument, NULL, IMAGEX_NOCHECK_OPTION},
{T("compress"), required_argument, NULL, IMAGEX_COMPRESS_OPTION},
+ {T("compress-slow"), no_argument, NULL, IMAGEX_COMPRESS_SLOW_OPTION},
+ {T("chunk-size"), required_argument, NULL, IMAGEX_CHUNK_SIZE_OPTION},
+ {T("pack-chunk-size"), required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
+ {T("solid-chunk-size"),required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
+ {T("pack-streams"), no_argument, NULL, IMAGEX_PACK_STREAMS_OPTION},
+ {T("solid"), no_argument, NULL, IMAGEX_PACK_STREAMS_OPTION},
{T("config"), required_argument, NULL, IMAGEX_CONFIG_OPTION},
{T("dereference"), no_argument, NULL, IMAGEX_DEREFERENCE_OPTION},
{T("flags"), required_argument, NULL, IMAGEX_FLAGS_OPTION},
};
static const struct option dir_options[] = {
- {T("path"), required_argument, NULL, IMAGEX_PATH_OPTION},
+ {T("path"), required_argument, NULL, IMAGEX_PATH_OPTION},
+ {T("detailed"), no_argument, NULL, IMAGEX_DETAILED_OPTION},
+ {T("one-file-only"), no_argument, NULL, IMAGEX_ONE_FILE_ONLY_OPTION},
{NULL, 0, NULL, 0},
};
{T("nocheck"), no_argument, NULL, IMAGEX_NOCHECK_OPTION},
{T("no-check"), no_argument, NULL, IMAGEX_NOCHECK_OPTION},
{T("compress"), required_argument, NULL, IMAGEX_COMPRESS_OPTION},
+ {T("pack-streams"),no_argument, NULL, IMAGEX_PACK_STREAMS_OPTION},
+ {T("solid"), no_argument, NULL, IMAGEX_PACK_STREAMS_OPTION},
+ {T("chunk-size"), required_argument, NULL, IMAGEX_CHUNK_SIZE_OPTION},
+ {T("pack-chunk-size"), required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
+ {T("solid-chunk-size"),required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
{T("ref"), required_argument, NULL, IMAGEX_REF_OPTION},
{T("threads"), required_argument, NULL, IMAGEX_THREADS_OPTION},
{T("rebuild"), no_argument, NULL, IMAGEX_REBUILD_OPTION},
{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},
+ {T("no-attributes"), no_argument, NULL, IMAGEX_NO_ATTRIBUTES_OPTION},
{T("dest-dir"), required_argument, NULL, IMAGEX_DEST_DIR_OPTION},
{T("to-stdout"), no_argument, NULL, IMAGEX_TO_STDOUT_OPTION},
{T("include-invalid-names"), no_argument, NULL, IMAGEX_INCLUDE_INVALID_NAMES_OPTION},
+ {T("no-wildcards"), no_argument, NULL, IMAGEX_NO_WILDCARDS_OPTION},
+ {T("nullglob"), no_argument, NULL, IMAGEX_NULLGLOB_OPTION},
+ {T("preserve-dir-structure"), no_argument, NULL, IMAGEX_PRESERVE_DIR_STRUCTURE_OPTION},
{NULL, 0, NULL, 0},
};
{T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
{T("nocheck"), no_argument, NULL, IMAGEX_NOCHECK_OPTION},
{T("no-check"), no_argument, NULL, IMAGEX_NOCHECK_OPTION},
+ {T("compress"), required_argument, NULL, IMAGEX_COMPRESS_OPTION},
{T("recompress"), no_argument, NULL, IMAGEX_RECOMPRESS_OPTION},
+ {T("compress-slow"), no_argument, NULL, IMAGEX_COMPRESS_SLOW_OPTION},
+ {T("recompress-slow"), no_argument, NULL, IMAGEX_COMPRESS_SLOW_OPTION},
+ {T("chunk-size"), required_argument, NULL, IMAGEX_CHUNK_SIZE_OPTION},
+ {T("pack-chunk-size"), required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
+ {T("solid-chunk-size"),required_argument, NULL, IMAGEX_PACK_CHUNK_SIZE_OPTION},
+ {T("pack-streams"),no_argument, NULL, IMAGEX_PACK_STREAMS_OPTION},
+ {T("solid"), no_argument, NULL, IMAGEX_PACK_STREAMS_OPTION},
{T("threads"), required_argument, NULL, IMAGEX_THREADS_OPTION},
{T("pipable"), no_argument, NULL, IMAGEX_PIPABLE_OPTION},
{T("not-pipable"), no_argument, NULL, IMAGEX_NOT_PIPABLE_OPTION},
return WIMLIB_COMPRESSION_TYPE_LZX;
else if (!tstrcasecmp(optarg, T("fast")) || !tstrcasecmp(optarg, T("xpress")))
return WIMLIB_COMPRESSION_TYPE_XPRESS;
+ else if (!tstrcasecmp(optarg, T("recovery")) || !tstrcasecmp(optarg, T("lzms")))
+ return WIMLIB_COMPRESSION_TYPE_LZMS;
else if (!tstrcasecmp(optarg, T("none")))
return WIMLIB_COMPRESSION_TYPE_NONE;
else {
}
}
-struct refglob_set {
- const tchar **globs;
- unsigned num_globs;
- unsigned num_alloc_globs;
+static void
+set_compress_slow(void)
+{
+ static const struct wimlib_lzx_compressor_params lzx_slow_params = {
+ .hdr = {
+ .size = sizeof(struct wimlib_lzx_compressor_params),
+ },
+ .algorithm = WIMLIB_LZX_ALGORITHM_SLOW,
+ .alg_params = {
+ .slow = {
+ .use_len2_matches = 1,
+ .nice_match_length = 96,
+ .num_optim_passes = 4,
+ .max_search_depth = 100,
+ .max_matches_per_pos = 10,
+ .main_nostat_cost = 15,
+ .len_nostat_cost = 15,
+ .aligned_nostat_cost = 7,
+ },
+ },
+ };
+
+ static const struct wimlib_lzms_compressor_params lzms_slow_params = {
+ .hdr = {
+ .size = sizeof(struct wimlib_lzms_compressor_params),
+ },
+ .min_match_length = 2,
+ .max_match_length = UINT32_MAX,
+ .nice_match_length = 96,
+ .max_search_depth = 100,
+ .max_matches_per_pos = 10,
+ .optim_array_length = 1024,
+ };
+
+ wimlib_set_default_compressor_params(WIMLIB_COMPRESSION_TYPE_LZX,
+ &lzx_slow_params.hdr);
+
+ wimlib_set_default_compressor_params(WIMLIB_COMPRESSION_TYPE_LZMS,
+ &lzms_slow_params.hdr);
+}
+
+struct string_set {
+ const tchar **strings;
+ unsigned num_strings;
+ unsigned num_alloc_strings;
};
-#define REFGLOB_SET_INITIALIZER \
- { .globs = NULL, .num_globs = 0, .num_alloc_globs = 0, }
+#define STRING_SET_INITIALIZER \
+ { .strings = NULL, .num_strings = 0, .num_alloc_strings = 0, }
-#define REFGLOB_SET(_refglobs) \
- struct refglob_set _refglobs = REFGLOB_SET_INITIALIZER
+#define STRING_SET(_strings) \
+ struct string_set _strings = STRING_SET_INITIALIZER
static int
-refglob_set_append(struct refglob_set *set, const tchar *glob)
+string_set_append(struct string_set *set, const tchar *glob)
{
- unsigned num_alloc_globs = set->num_alloc_globs;
+ unsigned num_alloc_strings = set->num_alloc_strings;
- if (set->num_globs == num_alloc_globs) {
- const tchar **new_globs;
+ if (set->num_strings == num_alloc_strings) {
+ const tchar **new_strings;
- num_alloc_globs += 4;
- new_globs = realloc(set->globs, sizeof(set->globs[0]) * num_alloc_globs);
- if (!new_globs) {
+ num_alloc_strings += 4;
+ new_strings = realloc(set->strings,
+ sizeof(set->strings[0]) * num_alloc_strings);
+ if (!new_strings) {
imagex_error(T("Out of memory!"));
return -1;
}
- set->globs = new_globs;
- set->num_alloc_globs = num_alloc_globs;
+ set->strings = new_strings;
+ set->num_alloc_strings = num_alloc_strings;
}
- set->globs[set->num_globs++] = glob;
+ set->strings[set->num_strings++] = glob;
return 0;
}
+static void
+string_set_destroy(struct string_set *set)
+{
+ free(set->strings);
+}
+
static int
-wim_reference_globs(WIMStruct *wim, struct refglob_set *set, int open_flags)
+wim_reference_globs(WIMStruct *wim, struct string_set *set, int open_flags)
{
- return wimlib_reference_resource_files(wim, set->globs, set->num_globs,
+ return wimlib_reference_resource_files(wim, set->strings,
+ set->num_strings,
WIMLIB_REF_FLAG_GLOB_ENABLE,
open_flags,
imagex_progress_func);
}
-static void
-refglob_set_destroy(struct refglob_set *set)
-{
- free(set->globs);
-}
-
static void
do_resource_not_found_warning(const tchar *wimfile,
const struct wimlib_wim_info *info,
- const struct refglob_set *refglobs)
+ const struct string_set *refglobs)
{
if (info->total_parts > 1) {
- if (refglobs->num_globs == 0) {
+ if (refglobs->num_strings == 0) {
imagex_error(T("\"%"TS"\" is part of a split WIM. "
"Use --ref to specify the other parts."),
wimfile);
}
} else {
imagex_error(T("If this is a delta WIM, use the --ref argument "
- "to specify the WIM on which it is based."));
+ "to specify the WIM(s) on which it is based."));
}
}
#define TO_PERCENT(numerator, denominator) \
(((denominator) == 0) ? 0 : ((numerator) * 100 / (denominator)))
-/* Given an enumerated value for WIM compression type, return a descriptive
- * string. */
-static const tchar *
-get_data_type(int ctype)
-{
- switch (ctype) {
- case WIMLIB_COMPRESSION_TYPE_NONE:
- return T("uncompressed");
- case WIMLIB_COMPRESSION_TYPE_LZX:
- return T("LZX-compressed");
- case WIMLIB_COMPRESSION_TYPE_XPRESS:
- return T("XPRESS-compressed");
- }
- return NULL;
-}
-
#define GIBIBYTE_MIN_NBYTES 10000000000ULL
#define MEBIBYTE_MIN_NBYTES 10000000ULL
#define KIBIBYTE_MIN_NBYTES 10000ULL
}
}
+static struct wimlib_progress_info_scan last_scan_progress;
+
+static void
+report_scan_progress(const struct wimlib_progress_info_scan *scan, bool done)
+{
+ uint64_t prev_count, cur_count;
+
+ prev_count = last_scan_progress.num_nondirs_scanned +
+ last_scan_progress.num_dirs_scanned;
+ cur_count = scan->num_nondirs_scanned + scan->num_dirs_scanned;
+
+ if (done || prev_count == 0 || cur_count >= prev_count + 100 ||
+ cur_count % 128 == 0)
+ {
+ unsigned unit_shift;
+ const tchar *unit_name;
+
+ unit_shift = get_unit(scan->num_bytes_scanned, &unit_name);
+ imagex_printf(T("\r%"PRIu64" %"TS" scanned (%"PRIu64" files, "
+ "%"PRIu64" directories) "),
+ scan->num_bytes_scanned >> unit_shift,
+ unit_name,
+ scan->num_nondirs_scanned,
+ scan->num_dirs_scanned);
+ last_scan_progress = *scan;
+ }
+}
+
/* Progress callback function passed to various wimlib functions. */
static int
imagex_progress_func(enum wimlib_progress_msg msg,
unsigned percent_done;
unsigned unit_shift;
const tchar *unit_name;
+
if (imagex_be_quiet)
return 0;
switch (msg) {
case WIMLIB_PROGRESS_MSG_WRITE_STREAMS:
+ {
+ static bool first = true;
+ if (first) {
+ imagex_printf(T("Writing %"TS"-compressed data "
+ "using %u thread%"TS"\n"),
+ wimlib_get_compression_type_string(
+ info->write_streams.compression_type),
+ info->write_streams.num_threads,
+ (info->write_streams.num_threads == 1) ? T("") : T("s"));
+ first = false;
+ }
+ }
unit_shift = get_unit(info->write_streams.total_bytes, &unit_name);
percent_done = TO_PERCENT(info->write_streams.completed_bytes,
info->write_streams.total_bytes);
- if (info->write_streams.completed_streams == 0) {
- const tchar *data_type;
-
- data_type = get_data_type(info->write_streams.compression_type);
- imagex_printf(T("Writing %"TS" data using %u thread%"TS"\n"),
- data_type, info->write_streams.num_threads,
- (info->write_streams.num_threads == 1) ? T("") : T("s"));
- }
if (info->write_streams.total_parts <= 1) {
imagex_printf(T("\r%"PRIu64" %"TS" of %"PRIu64" %"TS" (uncompressed) "
"written (%u%% done)"),
"\""WIMLIB_WIM_PATH_SEPARATOR_STRING"%"TS"\")...\n"),
info->scan.wim_target_path);
} else {
- imagex_printf(T(" (loading as root of WIM image)...\n"));
+ imagex_printf(T("\n"));
}
+ memset(&last_scan_progress, 0, sizeof(last_scan_progress));
break;
case WIMLIB_PROGRESS_MSG_SCAN_DENTRY:
switch (info->scan.status) {
case WIMLIB_SCAN_DENTRY_OK:
- imagex_printf(T("Scanning \"%"TS"\"\n"), info->scan.cur_path);
+ report_scan_progress(&info->scan, false);
break;
case WIMLIB_SCAN_DENTRY_EXCLUDED:
- imagex_printf(T("Excluding \"%"TS"\" from capture\n"), info->scan.cur_path);
+ imagex_printf(T("\nExcluding \"%"TS"\" from capture\n"), info->scan.cur_path);
break;
case WIMLIB_SCAN_DENTRY_UNSUPPORTED:
- imagex_printf(T("WARNING: Excluding unsupported file or directory\n"
+ imagex_printf(T("\nWARNING: Excluding unsupported file or directory\n"
" \"%"TS"\" from capture\n"), info->scan.cur_path);
break;
+ case WIMLIB_SCAN_DENTRY_EXCLUDED_SYMLINK:
+ imagex_printf(T("\nWARNING: Ignoring absolute symbolic link "
+ "with out-of-tree target:\n"
+ " \"%"TS"\" => \"%"TS"\"\n"
+ " (Use --norpfix to capture "
+ "absolute symbolic links as-is)\n"),
+ info->scan.cur_path, info->scan.symlink_target);
+ break;
}
break;
+ case WIMLIB_PROGRESS_MSG_SCAN_END:
+ report_scan_progress(&info->scan, true);
+ imagex_printf(T("\n"));
+ break;
case WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY:
unit_shift = get_unit(info->integrity.total_bytes, &unit_name);
percent_done = TO_PERCENT(info->integrity.completed_bytes,
info->extract.target);
break;
case WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN:
- imagex_printf(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,
- info->extract.image_name,
- info->extract.wimfile_name,
- info->extract.target);
+ if (info->extract.extract_root_wim_source_path[0]) {
+ imagex_printf(T("Extracting \"%"TS"\" from image %d "
+ "(\"%"TS"\") in \"%"TS"\" to \"%"TS"\"\n"),
+ info->extract.extract_root_wim_source_path,
+ info->extract.image,
+ info->extract.image_name,
+ info->extract.wimfile_name,
+ info->extract.target);
+ }
break;
case WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS:
percent_done = TO_PERCENT(info->extract.completed_bytes,
}
}
+static uint32_t parse_chunk_size(const tchar *optarg)
+{
+ tchar *tmp;
+ unsigned long chunk_size = tstrtoul(optarg, &tmp, 10);
+ if (chunk_size >= UINT32_MAX || *tmp || tmp == optarg) {
+ imagex_error(T("Chunk size must be a non-negative integer!"));
+ return UINT32_MAX;
+ } else {
+ return chunk_size;
+ }
+}
+
+
/*
* Parse an option passed to an update command.
*
imagex_apply(int argc, tchar **argv, int cmd)
{
int c;
- int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
+ int open_flags = 0;
int image = WIMLIB_NO_IMAGE;
WIMStruct *wim;
struct wimlib_wim_info info;
const tchar *wimfile;
const tchar *target;
const tchar *image_num_or_name = NULL;
- int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
+ int extract_flags = 0;
- REFGLOB_SET(refglobs);
+ STRING_SET(refglobs);
for_opt(c, apply_options) {
switch (c) {
extract_flags |= WIMLIB_EXTRACT_FLAG_SYMLINK;
break;
case IMAGEX_VERBOSE_OPTION:
- extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE;
+ /* No longer does anything. */
break;
case IMAGEX_REF_OPTION:
- ret = refglob_set_append(&refglobs, optarg);
+ ret = string_set_append(&refglobs, optarg);
if (ret)
goto out_free_refglobs;
break;
case IMAGEX_STRICT_ACLS_OPTION:
extract_flags |= WIMLIB_EXTRACT_FLAG_STRICT_ACLS;
break;
+ case IMAGEX_NO_ATTRIBUTES_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES;
+ break;
case IMAGEX_NORPFIX_OPTION:
extract_flags |= WIMLIB_EXTRACT_FLAG_NORPFIX;
break;
}
}
- if (refglobs.num_globs) {
+ if (refglobs.num_strings) {
if (wim == NULL) {
imagex_error(T("Can't specify --ref when applying from stdin!"));
ret = -1;
out_wimlib_free:
wimlib_free(wim);
out_free_refglobs:
- refglob_set_destroy(&refglobs);
+ string_set_destroy(&refglobs);
return ret;
out_usage:
int c;
int open_flags = WIMLIB_OPEN_FLAG_WRITE_ACCESS;
int add_image_flags = WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE |
- WIMLIB_ADD_IMAGE_FLAG_WINCONFIG;
+ WIMLIB_ADD_IMAGE_FLAG_WINCONFIG |
+ WIMLIB_ADD_IMAGE_FLAG_VERBOSE;
int write_flags = 0;
- int compression_type = WIMLIB_COMPRESSION_TYPE_LZX;
+ int compression_type = WIMLIB_COMPRESSION_TYPE_INVALID;
+ uint32_t chunk_size = UINT32_MAX;
+ uint32_t pack_chunk_size = UINT32_MAX;
const tchar *wimfile;
int wim_fd;
const tchar *name;
const tchar *flags_element = NULL;
WIMStruct *wim;
- WIMStruct *base_wim;
- const tchar *base_wimfile = NULL;
+ STRING_SET(base_wimfiles);
+ WIMStruct **base_wims;
+
WIMStruct *template_wim;
const tchar *template_wimfile = NULL;
const tchar *template_image_name_or_num = NULL;
struct wimlib_capture_source *capture_sources;
size_t num_sources;
bool name_defaulted;
+ bool compress_slow = false;
for_opt(c, capture_or_append_options) {
switch (c) {
if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
goto out_err;
break;
+ case IMAGEX_COMPRESS_SLOW_OPTION:
+ compress_slow = true;
+ break;
+ case IMAGEX_CHUNK_SIZE_OPTION:
+ chunk_size = parse_chunk_size(optarg);
+ if (chunk_size == UINT32_MAX)
+ goto out_err;
+ break;
+ case IMAGEX_PACK_CHUNK_SIZE_OPTION:
+ pack_chunk_size = parse_chunk_size(optarg);
+ if (pack_chunk_size == UINT32_MAX)
+ goto out_err;
+ break;
+ case IMAGEX_PACK_STREAMS_OPTION:
+ write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
+ break;
case IMAGEX_FLAGS_OPTION:
flags_element = optarg;
break;
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE;
break;
case IMAGEX_VERBOSE_OPTION:
- add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_VERBOSE;
+ /* No longer does anything. */
break;
case IMAGEX_THREADS_OPTION:
num_threads = parse_num_threads(optarg);
"valid for capture!"));
goto out_usage;
}
- if (base_wimfile) {
- imagex_error(T("'--delta-from' can only be "
- "specified one time!"));
- goto out_err;
- }
- base_wimfile = optarg;
+ ret = string_set_append(&base_wimfiles, optarg);
+ if (ret)
+ goto out_free_base_wimfiles;
write_flags |= WIMLIB_WRITE_FLAG_SKIP_EXTERNAL_WIMS;
break;
default:
source = argv[0];
wimfile = argv[1];
+ /* Set default compression type and parameters. */
+
+
+ if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID) {
+ compression_type = WIMLIB_COMPRESSION_TYPE_LZX;
+
+ if (!compress_slow) {
+ struct wimlib_lzx_compressor_params params = {
+ .hdr.size = sizeof(params),
+ .algorithm = WIMLIB_LZX_ALGORITHM_FAST,
+ .use_defaults = 1,
+ };
+ wimlib_set_default_compressor_params(WIMLIB_COMPRESSION_TYPE_LZX,
+ ¶ms.hdr);
+ }
+ }
+
+ if (compress_slow)
+ set_compress_slow();
+
if (!tstrcmp(wimfile, T("-"))) {
/* Writing captured WIM to standard output. */
#if 0
/* If template image was specified using --update-of=IMAGE rather
* than --update-of=WIMFILE:IMAGE, set the default WIMFILE. */
if (template_image_name_or_num && !template_wimfile) {
- if (base_wimfile) {
- /* Capturing delta WIM: default to base WIM. */
- template_wimfile = base_wimfile;
+ if (base_wimfiles.num_strings == 1) {
+ /* Capturing delta WIM based on single WIM: default to
+ * base WIM. */
+ template_wimfile = base_wimfiles.strings[0];
} else if (cmd == CMD_APPEND) {
/* Appending to WIM: default to WIM being appended to.
*/
} else {
/* Capturing a normal (non-delta) WIM, so the WIM file
* *must* be explicitly specified. */
- imagex_error(T("For capture of non-delta WIM, "
- "'--update-of' must specify "
- "WIMFILE:IMAGE!"));
+ if (base_wimfiles.num_strings > 1) {
+ imagex_error(T("For capture of delta WIM "
+ "based on multiple existing "
+ "WIMs,\n"
+ " '--update-of' must "
+ "specify WIMFILE:IMAGE!"));
+ } else {
+ imagex_error(T("For capture of non-delta WIM, "
+ "'--update-of' must specify "
+ "WIMFILE:IMAGE!"));
+ }
goto out_usage;
}
}
if (ret)
goto out_free_config;
+ /* Set chunk size if non-default. */
+ if (chunk_size != UINT32_MAX) {
+ ret = wimlib_set_output_chunk_size(wim, chunk_size);
+ if (ret)
+ goto out_free_wim;
+ }
+ if (pack_chunk_size != UINT32_MAX) {
+ ret = wimlib_set_output_pack_chunk_size(wim, pack_chunk_size);
+ if (ret)
+ goto out_free_wim;
+ }
+
#ifndef __WIN32__
/* Detect if source is regular file or block device and set NTFS volume
* capture mode. */
}
}
- /* If capturing a delta WIM, reference resources from the base WIM
+ /* If capturing a delta WIM, reference resources from the base WIMs
* before adding the new image. */
- if (base_wimfile) {
- ret = wimlib_open_wim(base_wimfile, open_flags,
- &base_wim, imagex_progress_func);
- if (ret)
+ if (base_wimfiles.num_strings) {
+ base_wims = calloc(base_wimfiles.num_strings,
+ sizeof(base_wims[0]));
+ if (base_wims == NULL) {
+ imagex_error(T("Out of memory!"));
+ ret = -1;
goto out_free_wim;
+ }
+
+ for (size_t i = 0; i < base_wimfiles.num_strings; i++) {
+ ret = wimlib_open_wim(base_wimfiles.strings[i],
+ open_flags, &base_wims[i],
+ imagex_progress_func);
+ if (ret)
+ goto out_free_base_wims;
- imagex_printf(T("Capturing delta WIM based on \"%"TS"\"\n"),
- base_wimfile);
+ }
- ret = wimlib_reference_resources(wim, &base_wim, 1, 0);
+ ret = wimlib_reference_resources(wim, base_wims,
+ base_wimfiles.num_strings, 0);
if (ret)
- goto out_free_base_wim;
+ goto out_free_base_wims;
+
+ if (base_wimfiles.num_strings == 1) {
+ imagex_printf(T("Capturing delta WIM based on \"%"TS"\"\n"),
+ base_wimfiles.strings[0]);
+ } else {
+ imagex_printf(T("Capturing delta WIM based on %u WIMs\n"),
+ base_wimfiles.num_strings);
+ }
+
} else {
- base_wim = NULL;
+ base_wims = NULL;
}
/* If capturing or appending as an update of an existing (template) image,
if (template_image_name_or_num) {
- if (template_wimfile == base_wimfile) {
- template_wim = base_wim;
+ if (base_wimfiles.num_strings == 1 &&
+ template_wimfile == base_wimfiles.strings[0]) {
+ template_wim = base_wims[0];
} else if (template_wimfile == wimfile) {
template_wim = wim;
} else {
ret = wimlib_open_wim(template_wimfile, open_flags,
&template_wim, imagex_progress_func);
if (ret)
- goto out_free_base_wim;
+ goto out_free_base_wims;
}
template_image = wimlib_resolve_image(template_wim,
unsigned long n;
struct wimlib_wim_info info;
- wimlib_get_wim_info(wim, &info);
+ wimlib_get_wim_info(template_wim, &info);
n = tstrtoul(template_image_name_or_num + 1, &tmp, 10);
if (n >= 1 && n <= info.image_count &&
*tmp == T('\0') &&
imagex_progress_func);
}
out_free_template_wim:
- /* template_wim may alias base_wim or wim. */
- if (template_wim != base_wim && template_wim != wim)
+ /* template_wim may alias base_wims[0] or wim. */
+ if ((base_wimfiles.num_strings != 1 || template_wim != base_wims[0]) &&
+ template_wim != wim)
wimlib_free(template_wim);
-out_free_base_wim:
- wimlib_free(base_wim);
+out_free_base_wims:
+ for (size_t i = 0; i < base_wimfiles.num_strings; i++)
+ wimlib_free(base_wims[i]);
+ free(base_wims);
out_free_wim:
wimlib_free(wim);
out_free_config:
free(capture_sources);
out_free_source_list_contents:
free(source_list_contents);
-out:
+out_free_base_wimfiles:
+ string_set_destroy(&base_wimfiles);
return ret;
out_usage:
usage(cmd, stderr);
out_err:
ret = -1;
- goto out;
+ goto out_free_base_wimfiles;
}
/* Remove image(s) from a WIM. */
goto out;
}
+struct print_dentry_options {
+ bool detailed;
+};
+
+static void
+print_dentry_full_path(const struct wimlib_dir_entry *dentry)
+{
+ tprintf(T("%"TS"\n"), dentry->full_path);
+}
+
+static const struct {
+ uint32_t flag;
+ const tchar *name;
+} file_attr_flags[] = {
+ {WIMLIB_FILE_ATTRIBUTE_READONLY, T("READONLY")},
+ {WIMLIB_FILE_ATTRIBUTE_HIDDEN, T("HIDDEN")},
+ {WIMLIB_FILE_ATTRIBUTE_SYSTEM, T("SYSTEM")},
+ {WIMLIB_FILE_ATTRIBUTE_DIRECTORY, T("DIRECTORY")},
+ {WIMLIB_FILE_ATTRIBUTE_ARCHIVE, T("ARCHIVE")},
+ {WIMLIB_FILE_ATTRIBUTE_DEVICE, T("DEVICE")},
+ {WIMLIB_FILE_ATTRIBUTE_NORMAL, T("NORMAL")},
+ {WIMLIB_FILE_ATTRIBUTE_TEMPORARY, T("TEMPORARY")},
+ {WIMLIB_FILE_ATTRIBUTE_SPARSE_FILE, T("SPARSE_FILE")},
+ {WIMLIB_FILE_ATTRIBUTE_REPARSE_POINT, T("REPARSE_POINT")},
+ {WIMLIB_FILE_ATTRIBUTE_COMPRESSED, T("COMPRESSED")},
+ {WIMLIB_FILE_ATTRIBUTE_OFFLINE, T("OFFLINE")},
+ {WIMLIB_FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, T("NOT_CONTENT_INDEXED")},
+ {WIMLIB_FILE_ATTRIBUTE_ENCRYPTED, T("ENCRYPTED")},
+ {WIMLIB_FILE_ATTRIBUTE_VIRTUAL, T("VIRTUAL")},
+};
+
+#define TIMESTR_MAX 100
+
+static void
+timespec_to_string(const struct timespec *spec, tchar *buf)
+{
+ time_t t = spec->tv_sec;
+ struct tm tm;
+ gmtime_r(&t, &tm);
+ tstrftime(buf, TIMESTR_MAX, T("%a %b %d %H:%M:%S %Y UTC"), &tm);
+ buf[TIMESTR_MAX - 1] = '\0';
+}
+
+static void
+print_time(const tchar *type, const struct timespec *spec)
+{
+ tchar timestr[TIMESTR_MAX];
+
+ timespec_to_string(spec, timestr);
+
+ tprintf(T("%-20"TS"= %"TS"\n"), type, timestr);
+}
+
+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("Version: %u\n"), info->wim_version);
+ tprintf(T("Image Count: %d\n"), info->image_count);
+ tprintf(T("Compression: %"TS"\n"),
+ wimlib_get_compression_type_string(info->compression_type));
+ tprintf(T("Chunk Size: %"PRIu32" bytes\n"),
+ info->chunk_size);
+ 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"));
+ tprintf(T("Pipable: %"TS"\n"),
+ info->pipable ? T("yes") : T("no"));
+ tputchar(T('\n'));
+}
+
static int
-print_full_path(const struct wimlib_dir_entry *wdentry, void *_ignore)
+print_resource(const struct wimlib_resource_entry *resource,
+ void *_ignore)
{
- int ret = tprintf(T("%"TS"\n"), wdentry->full_path);
- return (ret >= 0) ? 0 : -1;
+ tprintf(T("Hash = 0x"));
+ print_byte_field(resource->sha1_hash, sizeof(resource->sha1_hash));
+ tputchar(T('\n'));
+
+ if (!resource->is_missing) {
+ tprintf(T("Uncompressed size = %"PRIu64" bytes\n"),
+ resource->uncompressed_size);
+ if (resource->packed) {
+ tprintf(T("Raw compressed size = %"PRIu64" bytes\n"),
+ resource->raw_resource_compressed_size);
+
+ tprintf(T("Raw offset in WIM = %"PRIu64" bytes\n"),
+ resource->raw_resource_offset_in_wim);
+
+ tprintf(T("Offset in raw = %"PRIu64" bytes\n"),
+ resource->offset);
+ } else {
+ tprintf(T("Compressed size = %"PRIu64" bytes\n"),
+ resource->compressed_size);
+
+ tprintf(T("Offset in WIM = %"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("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 "));
+ if (resource->packed)
+ tprintf(T("WIM_RESHDR_FLAG_PACKED_STREAMS "));
+ tputchar(T('\n'));
+ }
+ tputchar(T('\n'));
+ return 0;
+}
+
+static void
+print_lookup_table(WIMStruct *wim)
+{
+ wimlib_iterate_lookup_table(wim, 0, print_resource, NULL);
+}
+
+static void
+default_print_security_descriptor(const uint8_t *sd, size_t size)
+{
+ tprintf(T("Security Descriptor = "));
+ print_byte_field(sd, size);
+ tputchar(T('\n'));
+}
+
+static void
+print_dentry_detailed(const struct wimlib_dir_entry *dentry)
+{
+
+ tprintf(T(
+"----------------------------------------------------------------------------\n"));
+ tprintf(T("Full Path = \"%"TS"\"\n"), dentry->full_path);
+ if (dentry->dos_name)
+ tprintf(T("Short Name = \"%"TS"\"\n"), dentry->dos_name);
+ tprintf(T("Attributes = 0x%08x\n"), dentry->attributes);
+ for (size_t i = 0; i < ARRAY_LEN(file_attr_flags); i++)
+ if (file_attr_flags[i].flag & dentry->attributes)
+ tprintf(T(" FILE_ATTRIBUTE_%"TS" is set\n"),
+ file_attr_flags[i].name);
+
+ if (dentry->security_descriptor) {
+ print_security_descriptor(dentry->security_descriptor,
+ dentry->security_descriptor_size);
+ }
+
+ print_time(T("Creation Time"), &dentry->creation_time);
+ print_time(T("Last Write Time"), &dentry->last_write_time);
+ print_time(T("Last Access Time"), &dentry->last_access_time);
+
+
+ if (dentry->attributes & WIMLIB_FILE_ATTRIBUTE_REPARSE_POINT)
+ tprintf(T("Reparse Tag = 0x%"PRIx32"\n"), dentry->reparse_tag);
+
+ tprintf(T("Link Group ID = 0x%016"PRIx64"\n"), dentry->hard_link_group_id);
+ tprintf(T("Link Count = %"PRIu32"\n"), dentry->num_links);
+
+ for (uint32_t i = 0; i <= dentry->num_named_streams; i++) {
+ if (dentry->streams[i].stream_name) {
+ tprintf(T("\tData stream \"%"TS"\":\n"),
+ dentry->streams[i].stream_name);
+ } else {
+ tprintf(T("\tUnnamed data stream:\n"));
+ }
+ print_resource(&dentry->streams[i].resource, NULL);
+ }
+}
+
+static int
+print_dentry(const struct wimlib_dir_entry *dentry, void *_options)
+{
+ const struct print_dentry_options *options = _options;
+ if (!options->detailed)
+ print_dentry_full_path(dentry);
+ else
+ print_dentry_detailed(dentry);
+ return 0;
}
/* Print the files contained in an image(s) in a WIM file. */
int ret;
const tchar *path = T("");
int c;
+ struct print_dentry_options options = {
+ .detailed = false,
+ };
+ int iterate_flags = WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE;
for_opt(c, dir_options) {
switch (c) {
case IMAGEX_PATH_OPTION:
path = optarg;
break;
+ case IMAGEX_DETAILED_OPTION:
+ options.detailed = true;
+ break;
+ case IMAGEX_ONE_FILE_ONLY_OPTION:
+ iterate_flags &= ~WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE;
+ break;
default:
goto out_usage;
}
}
wimfile = argv[0];
- ret = wimlib_open_wim(wimfile, WIMLIB_OPEN_FLAG_SPLIT_OK, &wim,
- imagex_progress_func);
+ ret = wimlib_open_wim(wimfile, 0, &wim, imagex_progress_func);
if (ret)
goto out;
image = 1;
}
- ret = wimlib_iterate_dir_tree(wim, image, path,
- WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE,
- print_full_path, NULL);
+ ret = wimlib_iterate_dir_tree(wim, image, path, iterate_flags,
+ print_dentry, &options);
out_wimlib_free:
wimlib_free(wim);
out:
int image;
struct stat stbuf;
bool wim_is_new;
- REFGLOB_SET(refglobs);
+ STRING_SET(refglobs);
unsigned num_threads = 0;
+ uint32_t chunk_size = UINT32_MAX;
+ uint32_t pack_chunk_size = UINT32_MAX;
for_opt(c, export_options) {
switch (c) {
if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
goto out_err;
break;
+ case IMAGEX_PACK_STREAMS_OPTION:
+ write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
+ break;
+ case IMAGEX_CHUNK_SIZE_OPTION:
+ chunk_size = parse_chunk_size(optarg);
+ if (chunk_size == UINT32_MAX)
+ goto out_err;
+ break;
+ case IMAGEX_PACK_CHUNK_SIZE_OPTION:
+ pack_chunk_size = parse_chunk_size(optarg);
+ if (pack_chunk_size == UINT32_MAX)
+ goto out_err;
+ break;
case IMAGEX_REF_OPTION:
- ret = refglob_set_append(&refglobs, optarg);
+ ret = string_set_append(&refglobs, optarg);
if (ret)
goto out_free_refglobs;
break;
dest_wimfile = argv[2];
dest_name = (argc >= 4) ? argv[3] : NULL;
dest_desc = (argc >= 5) ? argv[4] : NULL;
- ret = wimlib_open_wim(src_wimfile,
- open_flags | WIMLIB_OPEN_FLAG_SPLIT_OK, &src_wim,
+ ret = wimlib_open_wim(src_wimfile, open_flags, &src_wim,
imagex_progress_func);
if (ret)
goto out_free_refglobs;
ret = -1;
goto out_free_src_wim;
}
- ret = wimlib_open_wim(dest_wimfile, open_flags | WIMLIB_OPEN_FLAG_WRITE_ACCESS,
+ ret = wimlib_open_wim(dest_wimfile,
+ open_flags | WIMLIB_OPEN_FLAG_WRITE_ACCESS,
&dest_wim, imagex_progress_func);
if (ret)
goto out_free_src_wim;
ret = wimlib_create_new_wim(compression_type, &dest_wim);
if (ret)
goto out_free_src_wim;
+
+ /* Use same chunk size if compression type is the same. */
+ if (compression_type == src_info.compression_type &&
+ chunk_size == UINT32_MAX)
+ wimlib_set_output_chunk_size(dest_wim, src_info.chunk_size);
+ }
+
+ if (chunk_size != UINT32_MAX) {
+ /* Set destination chunk size. */
+ ret = wimlib_set_output_chunk_size(dest_wim, chunk_size);
+ if (ret)
+ goto out_free_dest_wim;
+ }
+ if (pack_chunk_size != UINT32_MAX) {
+ ret = wimlib_set_output_pack_chunk_size(dest_wim, pack_chunk_size);
+ if (ret)
+ goto out_free_dest_wim;
}
image = wimlib_resolve_image(src_wim, src_image_num_or_name);
if (ret)
goto out_free_dest_wim;
- if (refglobs.num_globs) {
+ if (refglobs.num_strings) {
ret = wim_reference_globs(src_wim, &refglobs, open_flags);
if (ret)
goto out_free_dest_wim;
out_free_src_wim:
wimlib_free(src_wim);
out_free_refglobs:
- refglob_set_destroy(&refglobs);
+ string_set_destroy(&refglobs);
return ret;
out_usage:
goto out_free_refglobs;
}
-static bool
-is_root_wim_path(const tchar *path)
-{
- const tchar *p;
- for (p = path; *p; p++)
- if (*p != T('\\') && *p != T('/'))
- return false;
- return true;
-}
-
-static void
-free_extract_commands(struct wimlib_extract_command *cmds, size_t num_cmds,
- const tchar *dest_dir)
-{
- for (size_t i = 0; i < num_cmds; i++)
- if (cmds[i].fs_dest_path != dest_dir)
- free(cmds[i].fs_dest_path);
- free(cmds);
-}
-
-static struct wimlib_extract_command *
-prepare_extract_commands(tchar **paths, unsigned num_paths,
- int extract_flags, tchar *dest_dir,
- size_t *num_cmds_ret)
-{
- struct wimlib_extract_command *cmds;
- size_t num_cmds;
- tchar *emptystr = T("");
-
- if (num_paths == 0) {
- num_paths = 1;
- paths = &emptystr;
- }
- num_cmds = num_paths;
- cmds = calloc(num_cmds, sizeof(cmds[0]));
- if (!cmds) {
- imagex_error(T("Out of memory!"));
- return NULL;
- }
-
- for (size_t i = 0; i < num_cmds; i++) {
- cmds[i].extract_flags = extract_flags;
- cmds[i].wim_source_path = paths[i];
- if (is_root_wim_path(paths[i])) {
- cmds[i].fs_dest_path = dest_dir;
- } else {
- size_t len = tstrlen(dest_dir) + 1 + tstrlen(paths[i]);
- cmds[i].fs_dest_path = malloc((len + 1) * sizeof(tchar));
- if (!cmds[i].fs_dest_path) {
- free_extract_commands(cmds, num_cmds, dest_dir);
- return NULL;
- }
- tsprintf(cmds[i].fs_dest_path,
- T("%"TS""OS_PREFERRED_PATH_SEPARATOR_STRING"%"TS),
- dest_dir, tbasename(paths[i]));
- }
- }
- *num_cmds_ret = num_cmds;
- return cmds;
-}
-
/* Extract files or directories from a WIM image */
static int
imagex_extract(int argc, tchar **argv, int cmd)
{
int c;
- int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
+ int open_flags = 0;
int image;
WIMStruct *wim;
int ret;
const tchar *wimfile;
const tchar *image_num_or_name;
+ const tchar *pathlist;
tchar *dest_dir = T(".");
- int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL | WIMLIB_EXTRACT_FLAG_NORPFIX;
+ int extract_flags = WIMLIB_EXTRACT_FLAG_NORPFIX |
+ WIMLIB_EXTRACT_FLAG_GLOB_PATHS |
+ WIMLIB_EXTRACT_FLAG_STRICT_GLOB;
+ int notlist_extract_flags = WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE;
- REFGLOB_SET(refglobs);
+ STRING_SET(refglobs);
struct wimlib_extract_command *cmds;
size_t num_cmds;
+ tchar *root_path = T("");
for_opt(c, extract_options) {
switch (c) {
open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
break;
case IMAGEX_VERBOSE_OPTION:
- extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE;
+ /* No longer does anything. */
break;
case IMAGEX_REF_OPTION:
- ret = refglob_set_append(&refglobs, optarg);
+ ret = string_set_append(&refglobs, optarg);
if (ret)
goto out_free_refglobs;
break;
case IMAGEX_STRICT_ACLS_OPTION:
extract_flags |= WIMLIB_EXTRACT_FLAG_STRICT_ACLS;
break;
+ case IMAGEX_NO_ATTRIBUTES_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES;
+ break;
case IMAGEX_DEST_DIR_OPTION:
dest_dir = optarg;
break;
extract_flags |= WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES;
extract_flags |= WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS;
break;
+ case IMAGEX_NO_WILDCARDS_OPTION:
+ extract_flags &= ~WIMLIB_EXTRACT_FLAG_GLOB_PATHS;
+ break;
+ case IMAGEX_NULLGLOB_OPTION:
+ extract_flags &= ~WIMLIB_EXTRACT_FLAG_STRICT_GLOB;
+ break;
+ case IMAGEX_PRESERVE_DIR_STRUCTURE_OPTION:
+ notlist_extract_flags &= ~WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE;
+ break;
default:
goto out_usage;
}
argc -= 2;
argv += 2;
- cmds = prepare_extract_commands(argv, argc, extract_flags, dest_dir,
- &num_cmds);
- if (!cmds)
- goto out_err;
-
ret = wimlib_open_wim(wimfile, open_flags, &wim, imagex_progress_func);
if (ret)
- goto out_free_cmds;
+ goto out_free_refglobs;
image = wimlib_resolve_image(wim, image_num_or_name);
ret = verify_image_exists_and_is_single(image,
if (ret)
goto out_wimlib_free;
- if (refglobs.num_globs) {
+ if (refglobs.num_strings) {
ret = wim_reference_globs(wim, &refglobs, open_flags);
if (ret)
goto out_wimlib_free;
}
- ret = wimlib_extract_files(wim, image, cmds, num_cmds, 0,
- imagex_progress_func);
+ if (argc == 0) {
+ argv = &root_path;
+ argc = 1;
+ extract_flags &= ~WIMLIB_EXTRACT_FLAG_GLOB_PATHS;
+ }
+
+ while (argc != 0 && ret == 0) {
+ int num_paths;
+
+ for (num_paths = 0;
+ num_paths < argc && argv[num_paths][0] != T('@');
+ num_paths++)
+ ;
+
+ if (num_paths) {
+ ret = wimlib_extract_paths(wim, image, dest_dir,
+ (const tchar **)argv,
+ num_paths,
+ extract_flags | notlist_extract_flags,
+ imagex_progress_func);
+ argc -= num_paths;
+ argv += num_paths;
+ } else {
+ ret = wimlib_extract_pathlist(wim, image, dest_dir,
+ argv[0] + 1,
+ extract_flags,
+ imagex_progress_func);
+ argc--;
+ argv++;
+ }
+ }
+
if (ret == 0) {
if (!imagex_be_quiet)
imagex_printf(T("Done extracting files.\n"));
tfprintf(stderr, T("Note: You can use `%"TS"' to see what "
"files and directories\n"
" are in the WIM image.\n"),
- get_cmd_string(CMD_INFO, false));
+ get_cmd_string(CMD_DIR, false));
} else if (ret == WIMLIB_ERR_RESOURCE_NOT_FOUND) {
struct wimlib_wim_info info;
}
out_wimlib_free:
wimlib_free(wim);
-out_free_cmds:
- free_extract_commands(cmds, num_cmds, dest_dir);
out_free_refglobs:
- refglob_set_destroy(&refglobs);
+ string_set_destroy(&refglobs);
return ret;
out_usage:
goto out_free_refglobs;
}
-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"));
- tprintf(T("Pipable: %"TS"\n"),
- info->pipable ? 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
bool header = false;
bool lookup_table = false;
bool xml = false;
- bool metadata = false;
bool short_header = true;
const tchar *xml_out_file = NULL;
const tchar *wimfile;
WIMStruct *wim;
int image;
int ret;
- int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
+ int open_flags = 0;
struct wimlib_wim_info info;
for_opt(c, info_options) {
short_header = false;
break;
case IMAGEX_METADATA_OPTION:
- metadata = true;
- short_header = false;
- break;
+ imagex_error(T("The --metadata option has been removed. "
+ "Use 'wimdir --detail' instead."));
+ goto out_err;
default:
goto out_usage;
}
if (short_header)
wimlib_print_available_images(wim, image);
- if (metadata) {
- ret = wimlib_print_metadata(wim, image);
- if (ret)
- goto out_wimlib_free;
- }
ret = 0;
} else {
imagex_join(int argc, tchar **argv, int cmd)
{
int c;
- int swm_open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
+ int swm_open_flags = 0;
int wim_write_flags = 0;
const tchar *output_path;
int ret;
{
int c;
int mount_flags = 0;
- int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
+ int open_flags = 0;
const tchar *staging_dir = NULL;
const tchar *wimfile;
const tchar *dir;
int image;
int ret;
- REFGLOB_SET(refglobs);
+ STRING_SET(refglobs);
if (cmd == CMD_MOUNTRW) {
mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE;
}
break;
case IMAGEX_REF_OPTION:
- ret = refglob_set_append(&refglobs, optarg);
+ ret = string_set_append(&refglobs, optarg);
if (ret)
goto out_free_refglobs;
break;
dir = argv[1];
}
- if (refglobs.num_globs) {
+ if (refglobs.num_strings) {
ret = wim_reference_globs(wim, &refglobs, open_flags);
if (ret)
goto out_free_wim;
out_free_wim:
wimlib_free(wim);
out_free_refglobs:
- refglob_set_destroy(&refglobs);
+ string_set_destroy(&refglobs);
return ret;
out_usage:
int c;
int open_flags = WIMLIB_OPEN_FLAG_WRITE_ACCESS;
int write_flags = WIMLIB_WRITE_FLAG_REBUILD;
+ int compression_type = WIMLIB_COMPRESSION_TYPE_INVALID;
+ uint32_t chunk_size = UINT32_MAX;
+ uint32_t pack_chunk_size = UINT32_MAX;
int ret;
WIMStruct *wim;
const tchar *wimfile;
case IMAGEX_NOCHECK_OPTION:
write_flags |= WIMLIB_WRITE_FLAG_NO_CHECK_INTEGRITY;
break;
+ case IMAGEX_COMPRESS_OPTION:
+ write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
+ compression_type = get_compression_type(optarg);
+ if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
+ goto out_err;
+ break;
case IMAGEX_RECOMPRESS_OPTION:
write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
break;
+ case IMAGEX_COMPRESS_SLOW_OPTION:
+ write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
+ set_compress_slow();
+ break;
+ case IMAGEX_CHUNK_SIZE_OPTION:
+ chunk_size = parse_chunk_size(optarg);
+ if (chunk_size == UINT32_MAX)
+ goto out_err;
+ break;
+ case IMAGEX_PACK_CHUNK_SIZE_OPTION:
+ pack_chunk_size = parse_chunk_size(optarg);
+ if (pack_chunk_size == UINT32_MAX)
+ goto out_err;
+ break;
+ case IMAGEX_PACK_STREAMS_OPTION:
+ write_flags |= WIMLIB_WRITE_FLAG_PACK_STREAMS;
+ write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
+ break;
case IMAGEX_THREADS_OPTION:
num_threads = parse_num_threads(optarg);
if (num_threads == UINT_MAX)
if (ret)
goto out;
+ if (compression_type != WIMLIB_COMPRESSION_TYPE_INVALID) {
+ /* Change compression type. */
+ ret = wimlib_set_output_compression_type(wim, compression_type);
+ if (ret)
+ goto out_wimlib_free;
+ }
+
+ if (chunk_size != UINT32_MAX) {
+ /* Change chunk size. */
+ ret = wimlib_set_output_chunk_size(wim, chunk_size);
+ if (ret)
+ goto out_wimlib_free;
+ }
+ if (pack_chunk_size != UINT32_MAX) {
+ ret = wimlib_set_output_pack_chunk_size(wim, pack_chunk_size);
+ if (ret)
+ goto out_wimlib_free;
+ }
+
old_size = file_get_size(wimfile);
tprintf(T("\"%"TS"\" original size: "), wimfile);
if (old_size == -1)
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_FLAG_EXCLUDE_VERBOSE;
+ int default_add_flags = WIMLIB_ADD_FLAG_EXCLUDE_VERBOSE |
+ WIMLIB_ADD_FLAG_VERBOSE;
int default_delete_flags = 0;
unsigned num_threads = 0;
int c;
/* Default add options */
case IMAGEX_VERBOSE_OPTION:
- default_add_flags |= WIMLIB_ADD_FLAG_VERBOSE;
+ /* No longer does anything. */
break;
case IMAGEX_DEREFERENCE_OPTION:
default_add_flags |= WIMLIB_ADD_FLAG_DEREFERENCE;
T(
" %"TS" (DIRECTORY | NTFS_VOLUME) WIMFILE\n"
" [IMAGE_NAME [IMAGE_DESCRIPTION]] [--boot] [--check]\n"
-" [--nocheck] [--flags EDITION_ID] [--verbose]\n"
-" [--dereference] [--config=FILE] [--threads=NUM_THREADS]\n"
-" [--rebuild] [--unix-data] [--source-list] [--no-acls]\n"
-" [--strict-acls] [--rpfix] [--norpfix] [--pipable]\n"
-" [--not-pipable] [--update-of=[WIMFILE:]IMAGE]\n"
+" [--nocheck] [--flags EDITION_ID] [--dereference]\n"
+" [--config=FILE] [--threads=NUM_THREADS] [--source-list]\n"
+" [--no-acls] [--strict-acls] [--rpfix] [--norpfix]\n"
+" [--update-of=[WIMFILE:]IMAGE]\n"
),
[CMD_APPLY] =
T(
" %"TS" 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"
+" (DIRECTORY | NTFS_VOLUME) [--check] [--ref=\"GLOB\"]\n"
+" [--no-acls] [--strict-acls] [--no-attributes]\n"
+" [--rpfix] [--norpfix] [--hardlink] [--symlink]\n"
" [--include-invalid-names]\n"
),
[CMD_CAPTURE] =
" %"TS" (DIRECTORY | NTFS_VOLUME) WIMFILE\n"
" [IMAGE_NAME [IMAGE_DESCRIPTION]] [--boot] [--check]\n"
" [--nocheck] [--compress=TYPE] [--flags EDITION_ID]\n"
-" [--verbose] [--dereference] [--config=FILE]\n"
-" [--threads=NUM_THREADS] [--unix-data] [--source-list]\n"
-" [--no-acls] [--strict-acls] [--norpfix] [--pipable]\n"
-" [--update-of=[WIMFILE:]IMAGE] [--delta-from=WIMFILE]\n"
+" [--dereference] [--config=FILE] [--threads=NUM_THREADS]\n"
+" [--source-list] [--no-acls] [--strict-acls] [--rpfix]\n"
+" [--norpfix] [--update-of=[WIMFILE:]IMAGE]\n"
+" [--delta-from=WIMFILE]\n"
),
[CMD_DELETE] =
T(
-" %"TS" WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check]\n"
-" [--soft]\n"
+" %"TS" WIMFILE (IMAGE_NUM | IMAGE_NAME | all)\n"
+" [--check] [--soft]\n"
),
[CMD_DIR] =
T(
-" %"TS" WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--path=PATH]\n"
+" %"TS" WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--path=PATH] [--detailed]\n"
),
[CMD_EXPORT] =
T(
" DEST_WIMFILE [DEST_IMAGE_NAME [DEST_IMAGE_DESCRIPTION]]\n"
" [--boot] [--check] [--nocheck] [--compress=TYPE]\n"
" [--ref=\"GLOB\"] [--threads=NUM_THREADS] [--rebuild]\n"
-" [--pipable] [--not-pipable]\n"
),
[CMD_EXTRACT] =
T(
-" %"TS" WIMFILE (IMAGE_NUM | IMAGE_NAME) [PATH...]\n"
-" [--check] [--ref=\"GLOB\"] [--verbose] [--unix-data]\n"
-" [--no-acls] [--strict-acls] [--to-stdout]\n"
-" [--dest-dir=CMD_DIR] [--include-invalid-names]\n"
+" %"TS" WIMFILE (IMAGE_NUM | IMAGE_NAME) [(PATH | @LISTFILE)...]\n"
+" [--check] [--ref=\"GLOB\"] [--dest-dir=CMD_DIR]\n"
+" [--to-stdout] [--no-acls] [--strict-acls]\n"
+" [--no-attributes] [--include-invalid-names]\n"
+" [--no-wildcards] [--nullglob]\n"
),
[CMD_INFO] =
T(
" %"TS" WIMFILE [(IMAGE_NUM | IMAGE_NAME) [NEW_NAME\n"
-" [NEW_DESC]]] [--boot] [--check] [--nocheck] [--header]\n"
-" [--lookup-table] [--xml] [--extract-xml FILE]\n"
-" [--metadata]\n"
+" [NEW_DESC]]] [--boot] [--check] [--nocheck] [--xml]\n"
+" [--extract-xml FILE] [--header] [--lookup-table]\n"
),
[CMD_JOIN] =
T(
[CMD_MOUNT] =
T(
" %"TS" WIMFILE [(IMAGE_NUM | IMAGE_NAME)] DIRECTORY\n"
-" [--check] [--debug] [--streams-interface=INTERFACE]\n"
-" [--ref=\"GLOB\"] [--unix-data] [--allow-other]\n"
+" [--check] [--streams-interface=INTERFACE]\n"
+" [--ref=\"GLOB\"] [--allow-other]\n"
),
[CMD_MOUNTRW] =
T(
" %"TS" WIMFILE [(IMAGE_NUM | IMAGE_NAME)] DIRECTORY\n"
-" [--check] [--debug] [--streams-interface=INTERFACE]\n"
-" [--staging-dir=CMD_DIR] [--unix-data] [--allow-other]\n"
+" [--check] [--streams-interface=INTERFACE]\n"
+" [--staging-dir=CMD_DIR] [--allow-other]\n"
),
#endif
[CMD_OPTIMIZE] =
T(
" %"TS" WIMFILE [--check] [--nocheck] [--recompress]\n"
-" [--threads=NUM_THREADS] [--pipable] [--not-pipable]\n"
+" [--recompress-slow] [--compress=TYPE]\n"
+" [--threads=NUM_THREADS]\n"
),
[CMD_SPLIT] =
T(
{
const tchar *format_str;
#ifdef __WIN32__
- format_str = T("See %"TS".pdf in the doc directory for more details.\n");
+ format_str = T("Uncommon options are not listed;\n"
+ "See %"TS".pdf in the doc directory for more details.\n");
#else
- format_str = T("Try `man %"TS"' for more details.\n");
+ format_str = T("Uncommon options are not listed;\n"
+ "Try `man %"TS"' for more details.\n");
#endif
tfprintf(fp, format_str, get_cmd_string(cmd, true));
}
}
}
+
#endif /* !__WIN32__ */
+ {
+ tchar *igcase = tgetenv(T("WIMLIB_IMAGEX_IGNORE_CASE"));
+ if (igcase != NULL) {
+ if (!tstrcmp(igcase, T("no")) ||
+ !tstrcmp(igcase, T("0")))
+ init_flags |= WIMLIB_INIT_FLAG_DEFAULT_CASE_SENSITIVE;
+ else if (!tstrcmp(igcase, T("yes")) ||
+ !tstrcmp(igcase, T("1")))
+ init_flags |= WIMLIB_INIT_FLAG_DEFAULT_CASE_INSENSITIVE;
+ else {
+ fprintf(stderr,
+ "WARNING: Ignoring unknown setting of "
+ "WIMLIB_IMAGEX_IGNORE_CASE\n");
+ }
+ }
+ }
+
/* Allow being invoked as wimCOMMAND (e.g. wimapply). */
cmd = CMD_NONE;
if (!tstrncmp(invocation_name, T("wim"), 3) &&