*/
#include "config.h"
-#include "wimlib_tchar.h"
#include "wimlib.h"
+#include "wimlib_tchar.h"
#include <ctype.h>
#include <errno.h>
" [--verbose] [--dereference] [--config=FILE]\n"
" [--threads=NUM_THREADS] [--rebuild] [--unix-data]\n"
" [--source-list] [--no-acls] [--strict-acls]\n"
+" [--rpfix] [--norpfix]\n"
),
[APPLY] =
T(
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]\n"
+" [--no-acls] [--strict-acls] [--rpfix] [--norpfix]\n"
),
[CAPTURE] =
T(
" [--flags EDITION_ID] [--verbose] [--dereference]\n"
" [--config=FILE] [--threads=NUM_THREADS] [--unix-data]\n"
" [--source-list] [--no-acls] [--strict-acls]\n"
+" [--rpfix] [--norpfix]\n"
),
[DELETE] =
T(
[OPTIMIZE] =
T(
IMAGEX_PROGNAME" optimize WIMFILE [--check] [--recompress]\n"
+" [--threads=NUM_THREADS]\n"
),
[SPLIT] =
T(
),
};
+enum {
+ IMAGEX_ALLOW_OTHER_OPTION,
+ IMAGEX_BOOT_OPTION,
+ IMAGEX_CHECK_OPTION,
+ IMAGEX_COMMIT_OPTION,
+ IMAGEX_COMPRESS_OPTION,
+ IMAGEX_CONFIG_OPTION,
+ IMAGEX_DEBUG_OPTION,
+ IMAGEX_DEREFERENCE_OPTION,
+ IMAGEX_EXTRACT_XML_OPTION,
+ IMAGEX_FLAGS_OPTION,
+ IMAGEX_HARDLINK_OPTION,
+ IMAGEX_HEADER_OPTION,
+ IMAGEX_LOOKUP_TABLE_OPTION,
+ IMAGEX_METADATA_OPTION,
+ IMAGEX_NO_ACLS_OPTION,
+ IMAGEX_NORPFIX_OPTION,
+ IMAGEX_REBULID_OPTION,
+ IMAGEX_RECOMPRESS_OPTION,
+ IMAGEX_REF_OPTION,
+ IMAGEX_RPFIX_OPTION,
+ IMAGEX_SOFT_OPTION,
+ IMAGEX_SOURCE_LIST_OPTION,
+ IMAGEX_STAGING_DIR_OPTION,
+ IMAGEX_STREAMS_INTERFACE_OPTION,
+ IMAGEX_STRICT_ACLS_OPTION,
+ IMAGEX_SYMLINK_OPTION,
+ IMAGEX_THREADS_OPTION,
+ IMAGEX_UNIX_DATA_OPTION,
+ IMAGEX_VERBOSE_OPTION,
+ IMAGEX_XML_OPTION,
+};
+
static const struct option apply_options[] = {
- {T("check"), no_argument, NULL, 'c'},
- {T("hardlink"), no_argument, NULL, 'h'},
- {T("symlink"), no_argument, NULL, 's'},
- {T("verbose"), no_argument, NULL, 'v'},
- {T("ref"), required_argument, NULL, 'r'},
- {T("unix-data"), no_argument, NULL, 'U'},
- {T("noacls"), no_argument, NULL, 'N'},
- {T("no-acls"), no_argument, NULL, 'N'},
- {T("strict-acls"), no_argument, NULL, 'A'},
+ {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
+ {T("hardlink"), no_argument, NULL, IMAGEX_HARDLINK_OPTION},
+ {T("symlink"), no_argument, NULL, IMAGEX_SYMLINK_OPTION},
+ {T("verbose"), no_argument, NULL, IMAGEX_VERBOSE_OPTION},
+ {T("ref"), required_argument, NULL, IMAGEX_REF_OPTION},
+ {T("unix-data"), no_argument, NULL, IMAGEX_UNIX_DATA_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("rpfix"), no_argument, NULL, IMAGEX_RPFIX_OPTION},
+ {T("norpfix"), no_argument, NULL, IMAGEX_NORPFIX_OPTION},
{NULL, 0, NULL, 0},
};
static const struct option capture_or_append_options[] = {
- {T("boot"), no_argument, NULL, 'b'},
- {T("check"), no_argument, NULL, 'c'},
- {T("compress"), required_argument, NULL, 'x'},
- {T("config"), required_argument, NULL, 'C'},
- {T("dereference"), no_argument, NULL, 'L'},
- {T("flags"), required_argument, NULL, 'f'},
- {T("verbose"), no_argument, NULL, 'v'},
- {T("threads"), required_argument, NULL, 't'},
- {T("rebuild"), no_argument, NULL, 'R'},
- {T("unix-data"), no_argument, NULL, 'U'},
- {T("source-list"), no_argument, NULL, 'S'},
- {T("noacls"), no_argument, NULL, 'N'},
- {T("no-acls"), no_argument, NULL, 'N'},
- {T("strict-acls"), no_argument, NULL, 'A'},
+ {T("boot"), no_argument, NULL, IMAGEX_BOOT_OPTION},
+ {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
+ {T("compress"), required_argument, NULL, IMAGEX_COMPRESS_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},
+ {T("verbose"), no_argument, NULL, IMAGEX_VERBOSE_OPTION},
+ {T("threads"), required_argument, NULL, IMAGEX_THREADS_OPTION},
+ {T("rebuild"), no_argument, NULL, IMAGEX_REBULID_OPTION},
+ {T("unix-data"), no_argument, NULL, IMAGEX_UNIX_DATA_OPTION},
+ {T("source-list"), no_argument, NULL, IMAGEX_SOURCE_LIST_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("rpfix"), no_argument, NULL, IMAGEX_RPFIX_OPTION},
+ {T("norpfix"), no_argument, NULL, IMAGEX_NORPFIX_OPTION},
{NULL, 0, NULL, 0},
};
static const struct option delete_options[] = {
- {T("check"), no_argument, NULL, 'c'},
- {T("soft"), no_argument, NULL, 's'},
+ {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
+ {T("soft"), no_argument, NULL, IMAGEX_SOFT_OPTION},
{NULL, 0, NULL, 0},
};
static const struct option export_options[] = {
- {T("boot"), no_argument, NULL, 'b'},
- {T("check"), no_argument, NULL, 'c'},
- {T("compress"), required_argument, NULL, 'x'},
- {T("ref"), required_argument, NULL, 'r'},
- {T("threads"), required_argument, NULL, 't'},
- {T("rebuild"), no_argument, NULL, 'R'},
+ {T("boot"), no_argument, NULL, IMAGEX_BOOT_OPTION},
+ {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
+ {T("compress"), required_argument, NULL, IMAGEX_COMPRESS_OPTION},
+ {T("ref"), required_argument, NULL, IMAGEX_REF_OPTION},
+ {T("threads"), required_argument, NULL, IMAGEX_THREADS_OPTION},
+ {T("rebuild"), no_argument, NULL, IMAGEX_REBULID_OPTION},
{NULL, 0, NULL, 0},
};
static const struct option info_options[] = {
- {T("boot"), no_argument, NULL, 'b'},
- {T("check"), no_argument, NULL, 'c'},
- {T("extract-xml"), required_argument, NULL, 'X'},
- {T("header"), no_argument, NULL, 'h'},
- {T("lookup-table"), no_argument, NULL, 'l'},
- {T("metadata"), no_argument, NULL, 'm'},
- {T("xml"), no_argument, NULL, 'x'},
+ {T("boot"), no_argument, NULL, IMAGEX_BOOT_OPTION},
+ {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
+ {T("extract-xml"), required_argument, NULL, IMAGEX_EXTRACT_XML_OPTION},
+ {T("header"), no_argument, NULL, IMAGEX_HEADER_OPTION},
+ {T("lookup-table"), no_argument, NULL, IMAGEX_LOOKUP_TABLE_OPTION},
+ {T("metadata"), no_argument, NULL, IMAGEX_METADATA_OPTION},
+ {T("xml"), no_argument, NULL, IMAGEX_XML_OPTION},
{NULL, 0, NULL, 0},
};
static const struct option join_options[] = {
- {T("check"), no_argument, NULL, 'c'},
+ {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
{NULL, 0, NULL, 0},
};
static const struct option mount_options[] = {
- {T("check"), no_argument, NULL, 'c'},
- {T("debug"), no_argument, NULL, 'd'},
- {T("streams-interface"), required_argument, NULL, 's'},
- {T("ref"), required_argument, NULL, 'r'},
- {T("staging-dir"), required_argument, NULL, 'D'},
- {T("unix-data"), no_argument, NULL, 'U'},
- {T("allow-other"), no_argument, NULL, 'A'},
+ {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
+ {T("debug"), no_argument, NULL, IMAGEX_DEBUG_OPTION},
+ {T("streams-interface"), required_argument, NULL, IMAGEX_STREAMS_INTERFACE_OPTION},
+ {T("ref"), required_argument, NULL, IMAGEX_REF_OPTION},
+ {T("staging-dir"), required_argument, NULL, IMAGEX_STAGING_DIR_OPTION},
+ {T("unix-data"), no_argument, NULL, IMAGEX_UNIX_DATA_OPTION},
+ {T("allow-other"), no_argument, NULL, IMAGEX_ALLOW_OTHER_OPTION},
{NULL, 0, NULL, 0},
};
static const struct option optimize_options[] = {
- {T("check"), no_argument, NULL, 'c'},
- {T("recompress"), no_argument, NULL, 'r'},
+ {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
+ {T("recompress"), no_argument, NULL, IMAGEX_RECOMPRESS_OPTION},
+ {T("threads"), required_argument, NULL, IMAGEX_THREADS_OPTION},
{NULL, 0, NULL, 0},
};
static const struct option split_options[] = {
- {T("check"), no_argument, NULL, 'c'},
+ {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
{NULL, 0, NULL, 0},
};
static const struct option unmount_options[] = {
- {T("commit"), no_argument, NULL, 'c'},
- {T("check"), no_argument, NULL, 'C'},
- {T("rebuild"), no_argument, NULL, 'R'},
+ {T("commit"), no_argument, NULL, IMAGEX_COMMIT_OPTION},
+ {T("check"), no_argument, NULL, IMAGEX_CHECK_OPTION},
+ {T("rebuild"), no_argument, NULL, IMAGEX_REBULID_OPTION},
{NULL, 0, NULL, 0},
};
static int
get_compression_type(const tchar *optarg)
{
- if (tstrcasecmp(optarg, T("maximum")) == 0 || tstrcasecmp(optarg, T("lzx")) == 0)
+ if (!tstrcasecmp(optarg, T("maximum")) || !tstrcasecmp(optarg, T("lzx")))
return WIMLIB_COMPRESSION_TYPE_LZX;
- else if (tstrcasecmp(optarg, T("fast")) == 0 || tstrcasecmp(optarg, T("xpress")) == 0)
+ else if (!tstrcasecmp(optarg, T("fast")) || !tstrcasecmp(optarg, T("xpress")))
return WIMLIB_COMPRESSION_TYPE_XPRESS;
- else if (tstrcasecmp(optarg, T("none")) == 0)
+ else if (!tstrcasecmp(optarg, T("none")))
return WIMLIB_COMPRESSION_TYPE_NONE;
else {
imagex_error(T("Invalid compression type \"%"TS"\"! Must be "
return (off_t)-1;
}
-static const tchar *default_capture_config =
-T(
-"[ExclusionList]\n"
-"\\$ntfs.log\n"
-"\\hiberfil.sys\n"
-"\\pagefile.sys\n"
-"\\System Volume Information\n"
-"\\RECYCLER\n"
-"\\Windows\\CSC\n"
-"\n"
-"[CompressionExclusionList]\n"
-"*.mp3\n"
-"*.zip\n"
-"*.cab\n"
-"\\WINDOWS\\inf\\*.pnf\n"
-);
+tchar pat_ntfs_log[] = T("/$ntfs.log");
+tchar pat_hiberfil_sys[] = T("/hiberfil.sys");
+tchar pat_pagefile_sys[] = T("/pagefile.sys");
+tchar pat_system_volume_information[] = T("/System Volume Information");
+tchar pat_recycler[] = T("/RECYCLER");
+tchar pat_windows_csc[] = T("/Windows/CSC");
+
+tchar *default_pats[] = {
+ pat_ntfs_log,
+ pat_hiberfil_sys,
+ pat_pagefile_sys,
+ pat_system_volume_information,
+ pat_recycler,
+ pat_windows_csc,
+};
+
+static struct wimlib_capture_config default_capture_config = {
+ .exclusion_pats = {
+ .num_pats = sizeof(default_pats) / sizeof(*default_pats),
+ .pats = default_pats,
+ },
+};
enum {
PARSE_FILENAME_SUCCESS = 0,
}
}
+static ssize_t
+text_file_count_lines(tchar **contents_p, size_t *nchars_p)
+{
+ ssize_t nlines = 0;
+ tchar *contents = *contents_p;
+ size_t nchars = *nchars_p;
+ size_t i;
+
+ for (i = 0; i < nchars; i++)
+ if (contents[i] == T('\n'))
+ nlines++;
+
+ /* Handle last line not terminated by a newline */
+ if (nchars != 0 && contents[nchars - 1] != T('\n')) {
+ contents = realloc(contents, (nchars + 1) * sizeof(tchar));
+ if (!contents) {
+ imagex_error(T("Out of memory!"));
+ return -1;
+ }
+ contents[nchars] = T('\n');
+ *contents_p = contents;
+ nchars++;
+ nlines++;
+ }
+ *nchars_p = nchars;
+ return nlines;
+}
+
/* Parses a file in the source list format. (See the man page for
* 'wimlib-imagex capture' for details on this format and the meaning.)
*
parse_source_list(tchar **source_list_contents_p, size_t source_list_nchars,
size_t *nsources_ret)
{
- size_t nlines;
+ ssize_t nlines;
tchar *p;
struct wimlib_capture_source *sources;
size_t i, j;
- tchar *source_list_contents = *source_list_contents_p;
- nlines = 0;
- for (i = 0; i < source_list_nchars; i++)
- if (source_list_contents[i] == T('\n'))
- nlines++;
+ nlines = text_file_count_lines(source_list_contents_p,
+ &source_list_nchars);
+ if (nlines < 0)
+ return NULL;
- /* Handle last line not terminated by a newline */
- if (source_list_nchars != 0 &&
- source_list_contents[source_list_nchars - 1] != T('\n'))
- {
- source_list_contents = realloc(source_list_contents,
- (source_list_nchars + 1) * sizeof(tchar));
- if (!source_list_contents)
- goto oom;
- source_list_contents[source_list_nchars] = T('\n');
- *source_list_contents_p = source_list_contents;
- source_list_nchars++;
- nlines++;
+ /* Always allocate at least 1 slot, just in case the implementation of
+ * calloc() returns NULL if 0 bytes are requested. */
+ sources = calloc(nlines ?: 1, sizeof(*sources));
+ if (!sources) {
+ imagex_error(T("out of memory"));
+ return NULL;
}
-
- sources = calloc(nlines, sizeof(*sources));
- if (!sources)
- goto oom;
- p = source_list_contents;
+ p = *source_list_contents_p;
j = 0;
for (i = 0; i < nlines; i++) {
/* XXX: Could use rawmemchr() here instead, but it may not be
}
*nsources_ret = j;
return sources;
-oom:
- imagex_error(T("out of memory"));
- return NULL;
+}
+
+
+enum capture_config_section {
+ CAPTURE_CONFIG_NO_SECTION,
+ CAPTURE_CONFIG_EXCLUSION_SECTION,
+ CAPTURE_CONFIG_EXCLUSION_EXCEPTION_SECTION,
+ CAPTURE_CONFIG_IGNORE_SECTION,
+};
+
+enum {
+ CAPTURE_CONFIG_INVALID_SECTION,
+ CAPTURE_CONFIG_CHANGED_SECTION,
+ CAPTURE_CONFIG_SAME_SECTION,
+};
+
+static int
+check_config_section(tchar *line, size_t len,
+ enum capture_config_section *cur_section)
+{
+ while (istspace(*line))
+ line++;
+
+ if (*line != T('['))
+ return CAPTURE_CONFIG_SAME_SECTION;
+
+ line++;
+ tchar *endbrace = tstrrchr(line, T(']'));
+ if (!endbrace)
+ return CAPTURE_CONFIG_SAME_SECTION;
+
+ if (!tmemcmp(line, T("ExclusionList"), endbrace - line)) {
+ *cur_section = CAPTURE_CONFIG_EXCLUSION_SECTION;
+ } else if (!tmemcmp(line, T("ExclusionException"), endbrace - line)) {
+ *cur_section = CAPTURE_CONFIG_EXCLUSION_EXCEPTION_SECTION;
+ } else if (!tmemcmp(line, T("CompressionExclusionList"), endbrace - line)) {
+ *cur_section = CAPTURE_CONFIG_IGNORE_SECTION;
+ tfputs(T("WARNING: Ignoring [CompressionExclusionList] section "
+ "of capture config file\n"),
+ stderr);
+ } else if (!tmemcmp(line, T("AlignmentList"), endbrace - line)) {
+ *cur_section = CAPTURE_CONFIG_IGNORE_SECTION;
+ tfputs(T("WARNING: Ignoring [AlignmentList] section "
+ "of capture config file\n"),
+ stderr);
+ } else {
+ imagex_error(T("Invalid capture config file section \"%"TS"\""),
+ line - 1);
+ return CAPTURE_CONFIG_INVALID_SECTION;
+ }
+ return CAPTURE_CONFIG_CHANGED_SECTION;
+}
+
+
+static bool
+pattern_list_add_pattern(struct wimlib_pattern_list *pat_list,
+ tchar *pat)
+{
+ if (pat_list->num_pats == pat_list->num_allocated_pats) {
+ tchar **pats;
+ size_t num_allocated_pats = pat_list->num_pats + 8;
+
+ pats = realloc(pat_list->pats,
+ num_allocated_pats * sizeof(pat_list->pats[0]));
+ if (!pats) {
+ imagex_error(T("Out of memory!"));
+ return false;
+ }
+ pat_list->pats = pats;
+ pat_list->num_allocated_pats = num_allocated_pats;
+ }
+ pat_list->pats[pat_list->num_pats++] = pat;
+ return true;
+}
+
+static bool
+parse_capture_config_line(tchar *line, size_t len,
+ enum capture_config_section *cur_section,
+ struct wimlib_capture_config *config)
+{
+ tchar *filename;
+ int ret;
+
+ ret = check_config_section(line, len, cur_section);
+ if (ret == CAPTURE_CONFIG_INVALID_SECTION)
+ return false;
+ if (ret == CAPTURE_CONFIG_CHANGED_SECTION)
+ return true;
+
+ switch (*cur_section) {
+ case CAPTURE_CONFIG_NO_SECTION:
+ imagex_error(T("Line \"%"TS"\" is not in a section "
+ "(such as [ExclusionList]"), line);
+ return false;
+ case CAPTURE_CONFIG_EXCLUSION_SECTION:
+ if (parse_filename(&line, &len, &filename) != PARSE_FILENAME_SUCCESS)
+ return false;
+ return pattern_list_add_pattern(&config->exclusion_pats,
+ filename);
+ case CAPTURE_CONFIG_EXCLUSION_EXCEPTION_SECTION:
+ if (parse_filename(&line, &len, &filename) != PARSE_FILENAME_SUCCESS)
+ return false;
+ return pattern_list_add_pattern(&config->exclusion_exception_pats,
+ filename);
+ case CAPTURE_CONFIG_IGNORE_SECTION:
+ return true;
+ }
+ return false;
+}
+
+static int
+parse_capture_config(tchar **contents_p, size_t nchars,
+ struct wimlib_capture_config *config)
+{
+ ssize_t nlines;
+ tchar *p;
+ size_t i;
+ enum capture_config_section cur_section;
+
+ memset(config, 0, sizeof(*config));
+
+ nlines = text_file_count_lines(contents_p, &nchars);
+ if (nlines < 0)
+ return -1;
+
+ cur_section = CAPTURE_CONFIG_NO_SECTION;
+ p = *contents_p;
+ for (i = 0; i < nlines; i++) {
+ tchar *endp = tmemchr(p, T('\n'), nchars);
+ size_t len = endp - p + 1;
+ *endp = T('\0');
+ if (!is_comment_line(p, len))
+ if (!parse_capture_config_line(p, len, &cur_section, config))
+ return -1;
+ p = endp + 1;
+
+ }
+ return 0;
}
/* Reads the contents of a file into memory. */
static tchar *
-translate_text_to_tstr(char **text_p, size_t num_bytes,
+translate_text_to_tstr(char *text, size_t num_bytes,
size_t *num_tchars_ret)
{
#ifndef __WIN32__
/* On non-Windows, assume an ASCII-compatible encoding, such as UTF-8.
* */
*num_tchars_ret = num_bytes;
- return *text_p;
+ return text;
#else /* !__WIN32__ */
/* On Windows, translate the text to UTF-16LE */
- const char *text_bytestr = *text_p;
wchar_t *text_wstr;
size_t num_wchars;
if (num_bytes >= 2 &&
- ((text_bytestr[0] == 0xff && text_bytestr[1] == 0xfe) ||
- (text_bytestr[0] <= 0x7f && text_bytestr[1] == 0x00)))
+ ((text[0] == 0xff && text[1] == 0xfe) ||
+ (text[0] <= 0x7f && text[1] == 0x00)))
{
/* File begins with 0xfeff, the BOM for UTF-16LE, or it begins
* with something that looks like an ASCII character encoded as
* a UTF-16LE code unit. Assume the file is encoded as
* UTF-16LE. This is not a 100% reliable check. */
num_wchars = num_bytes / 2;
- text_wstr = (wchar_t*)text_bytestr;
+ text_wstr = (wchar_t*)text;
} else {
/* File does not look like UTF-16LE. Assume it is encoded in
* the current Windows code page. I think these are always
* ASCII-compatible, so any so-called "plain-text" (ASCII) files
* should work as expected. */
- text_wstr = win32_mbs_to_wcs(text_bytestr,
+ text_wstr = win32_mbs_to_wcs(text,
num_bytes,
&num_wchars);
+ free(text);
}
*num_tchars_ret = num_wchars;
return text_wstr;
contents = file_get_contents(filename, &num_bytes);
if (!contents)
return NULL;
- return translate_text_to_tstr(&contents, num_bytes, num_tchars_ret);
+ return translate_text_to_tstr(contents, num_bytes, num_tchars_ret);
}
static tchar *
contents = stdin_get_contents(&num_bytes);
if (!contents)
return NULL;
- return translate_text_to_tstr(&contents, num_bytes, 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;
info->extract.target);
break;
/*case WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN:*/
- /*printf("Applying directory structure to %s\n",*/
- /*info->extract.target);*/
+ /*tprintf(T("Applying directory structure to %"TS"\n"),*/
+ /*info->extract.target);*/
/*break;*/
case WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS:
percent_done = TO_PERCENT(info->extract.completed_bytes,
info->extract.total_bytes >> 20,
percent_done);
if (info->extract.completed_bytes >= info->extract.total_bytes)
- putchar('\n');
+ tputchar(T('\n'));
break;
case WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY:
tprintf(T("%"TS"\n"), info->extract.cur_path);
case WIMLIB_PROGRESS_MSG_JOIN_STREAMS:
percent_done = TO_PERCENT(info->join.completed_bytes,
info->join.total_bytes);
- printf("Writing resources from part %u of %u: "
- "%"PRIu64 " MiB of %"PRIu64" MiB (%u%%) written\n",
- (info->join.completed_parts == info->join.total_parts) ?
- info->join.completed_parts : info->join.completed_parts + 1,
- info->join.total_parts,
- info->join.completed_bytes >> 20,
- info->join.total_bytes >> 20,
- percent_done);
+ tprintf(T("Writing resources from part %u of %u: "
+ "%"PRIu64 " MiB of %"PRIu64" MiB (%u%%) written\n"),
+ (info->join.completed_parts == info->join.total_parts) ?
+ info->join.completed_parts : info->join.completed_parts + 1,
+ info->join.total_parts,
+ info->join.completed_bytes >> 20,
+ info->join.total_bytes >> 20,
+ percent_done);
break;
case WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART:
percent_done = TO_PERCENT(info->split.completed_bytes,
parse_num_threads(const tchar *optarg)
{
tchar *tmp;
- unsigned nthreads = tstrtoul(optarg, &tmp, 10);
- if (nthreads == UINT_MAX || *tmp || tmp == optarg) {
+ unsigned long ul_nthreads = tstrtoul(optarg, &tmp, 10);
+ if (ul_nthreads >= UINT_MAX || *tmp || tmp == optarg) {
imagex_error(T("Number of threads must be a non-negative integer!"));
return UINT_MAX;
} else {
- return nthreads;
+ return ul_nthreads;
}
}
for_opt(c, apply_options) {
switch (c) {
- case 'c':
+ case IMAGEX_CHECK_OPTION:
open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
break;
- case 'h':
+ case IMAGEX_HARDLINK_OPTION:
extract_flags |= WIMLIB_EXTRACT_FLAG_HARDLINK;
break;
- case 's':
+ case IMAGEX_SYMLINK_OPTION:
extract_flags |= WIMLIB_EXTRACT_FLAG_SYMLINK;
break;
- case 'v':
+ case IMAGEX_VERBOSE_OPTION:
extract_flags |= WIMLIB_EXTRACT_FLAG_VERBOSE;
break;
- case 'r':
+ case IMAGEX_REF_OPTION:
swm_glob = optarg;
break;
- case 'U':
+ case IMAGEX_UNIX_DATA_OPTION:
extract_flags |= WIMLIB_EXTRACT_FLAG_UNIX_DATA;
break;
- case 'N':
+ case IMAGEX_NO_ACLS_OPTION:
extract_flags |= WIMLIB_EXTRACT_FLAG_NO_ACLS;
break;
- case 'A':
+ case IMAGEX_STRICT_ACLS_OPTION:
extract_flags |= WIMLIB_EXTRACT_FLAG_STRICT_ACLS;
break;
+ case IMAGEX_NORPFIX_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_NORPFIX;
+ break;
+ case IMAGEX_RPFIX_OPTION:
+ extract_flags |= WIMLIB_EXTRACT_FLAG_RPFIX;
+ break;
default:
usage(APPLY);
return -1;
{
int c;
int open_flags = 0;
- int add_image_flags = 0;
+ int add_image_flags = WIMLIB_ADD_IMAGE_FLAG_EXCLUDE_VERBOSE;
int write_flags = 0;
int compression_type = WIMLIB_COMPRESSION_TYPE_XPRESS;
const tchar *wimfile;
const tchar *name;
const tchar *desc;
const tchar *flags_element = NULL;
- WIMStruct *w = NULL;
+ WIMStruct *w;
int ret;
int cur_image;
int cmd = tstrcmp(argv[0], T("append")) ? CAPTURE : APPEND;
tchar *source_copy;
const tchar *config_file = NULL;
- tchar *config_str = NULL;
- size_t config_len;
+ tchar *config_str;
+ struct wimlib_capture_config *config = NULL;
bool source_list = false;
size_t source_list_nchars;
- tchar *source_list_contents = NULL;
- bool capture_sources_malloced = false;
+ tchar *source_list_contents;
+ bool capture_sources_malloced;
struct wimlib_capture_source *capture_sources;
size_t num_sources;
for_opt(c, capture_or_append_options) {
switch (c) {
- case 'b':
+ case IMAGEX_BOOT_OPTION:
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_BOOT;
break;
- case 'c':
+ case IMAGEX_CHECK_OPTION:
open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
break;
- case 'C':
+ case IMAGEX_CONFIG_OPTION:
config_file = optarg;
break;
- case 'x':
+ case IMAGEX_COMPRESS_OPTION:
compression_type = get_compression_type(optarg);
if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
return -1;
break;
- case 'f':
+ case IMAGEX_FLAGS_OPTION:
flags_element = optarg;
break;
- case 'L':
+ case IMAGEX_DEREFERENCE_OPTION:
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_DEREFERENCE;
break;
- case 'v':
+ case IMAGEX_VERBOSE_OPTION:
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_VERBOSE;
break;
- case 't':
+ case IMAGEX_THREADS_OPTION:
num_threads = parse_num_threads(optarg);
if (num_threads == UINT_MAX)
return -1;
break;
- case 'R':
+ case IMAGEX_REBULID_OPTION:
write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
break;
- case 'U':
+ case IMAGEX_UNIX_DATA_OPTION:
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA;
break;
- case 'S':
+ case IMAGEX_SOURCE_LIST_OPTION:
source_list = true;
break;
- case 'N':
+ case IMAGEX_NO_ACLS_OPTION:
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NO_ACLS;
break;
- case 'A':
+ case IMAGEX_STRICT_ACLS_OPTION:
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_STRICT_ACLS;
break;
+ case IMAGEX_RPFIX_OPTION:
+ add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_RPFIX;
+ break;
+ case IMAGEX_NORPFIX_OPTION:
+ add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NORPFIX;
+ break;
default:
usage(cmd);
return -1;
&num_sources);
if (!capture_sources) {
ret = -1;
- goto out;
+ goto out_free_source_list_contents;
}
capture_sources_malloced = true;
} else {
capture_sources[0].wim_target_path = NULL;
capture_sources[0].reserved = 0;
num_sources = 1;
+ capture_sources_malloced = false;
+ source_list_contents = NULL;
}
if (config_file) {
+ size_t config_len;
+
config_str = file_get_text_contents(config_file, &config_len);
if (!config_str) {
ret = -1;
- goto out;
+ goto out_free_capture_sources;
}
+
+ config = alloca(sizeof(*config));
+ ret = parse_capture_config(&config_str, config_len, config);
+ if (ret)
+ goto out_free_config;
+ } else {
+ config = &default_capture_config;
}
if (cmd == APPEND)
imagex_progress_func);
else
ret = wimlib_create_new_wim(compression_type, &w);
- if (ret != 0)
- goto out;
+ if (ret)
+ goto out_free_config;
if (!source_list) {
struct stat stbuf;
imagex_error_with_errno(T("Failed to stat "
"\"%"TS"\""), source);
ret = -1;
- goto out;
+ goto out_wimlib_free;
}
}
}
win32_acquire_capture_privileges();
#endif
- ret = wimlib_add_image_multisource(w, capture_sources,
- num_sources, name,
- (config_str ? config_str :
- default_capture_config),
- (config_str ? config_len :
- tstrlen(default_capture_config)),
+ ret = wimlib_add_image_multisource(w,
+ capture_sources,
+ num_sources,
+ name,
+ config,
add_image_flags,
imagex_progress_func);
if (ret != 0)
#ifdef __WIN32__
win32_release_capture_privileges();
#endif
-out:
+out_wimlib_free:
wimlib_free(w);
- free(config_str);
- free(source_list_contents);
+out_free_config:
+ if (config != NULL && config != &default_capture_config) {
+ free(config->exclusion_pats.pats);
+ free(config->exclusion_exception_pats.pats);
+ free(config_str);
+ }
+out_free_capture_sources:
if (capture_sources_malloced)
free(capture_sources);
+out_free_source_list_contents:
+ free(source_list_contents);
return ret;
}
for_opt(c, delete_options) {
switch (c) {
- case 'c':
+ case IMAGEX_CHECK_OPTION:
open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
break;
- case 's':
+ case IMAGEX_SOFT_OPTION:
write_flags |= WIMLIB_WRITE_FLAG_SOFT_DELETE;
break;
default:
for_opt(c, export_options) {
switch (c) {
- case 'b':
+ case IMAGEX_BOOT_OPTION:
export_flags |= WIMLIB_EXPORT_FLAG_BOOT;
break;
- case 'c':
+ case IMAGEX_CHECK_OPTION:
open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
break;
- case 'x':
+ case IMAGEX_COMPRESS_OPTION:
compression_type = get_compression_type(optarg);
if (compression_type == WIMLIB_COMPRESSION_TYPE_INVALID)
return -1;
compression_type_specified = true;
break;
- case 'r':
+ case IMAGEX_REF_OPTION:
swm_glob = optarg;
break;
- case 't':
+ case IMAGEX_THREADS_OPTION:
num_threads = parse_num_threads(optarg);
if (num_threads == UINT_MAX)
return -1;
break;
- case 'R':
+ case IMAGEX_REBULID_OPTION:
write_flags |= WIMLIB_WRITE_FLAG_REBUILD;
break;
default:
for_opt(c, info_options) {
switch (c) {
- case 'b':
+ case IMAGEX_BOOT_OPTION:
boot = true;
break;
- case 'c':
+ case IMAGEX_CHECK_OPTION:
check = true;
break;
- case 'h':
+ case IMAGEX_HEADER_OPTION:
header = true;
short_header = false;
break;
- case 'l':
+ case IMAGEX_LOOKUP_TABLE_OPTION:
lookup_table = true;
short_header = false;
break;
- case 'x':
+ case IMAGEX_XML_OPTION:
xml = true;
short_header = false;
break;
- case 'X':
+ case IMAGEX_EXTRACT_XML_OPTION:
xml_out_file = optarg;
short_header = false;
break;
- case 'm':
+ case IMAGEX_METADATA_OPTION:
metadata = true;
short_header = false;
break;
ret = file_writable(wimfile);
if (ret != 0)
- return ret;
+ goto out;
if (check)
write_flags = WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
for_opt(c, join_options) {
switch (c) {
- case 'c':
+ case IMAGEX_CHECK_OPTION:
swm_open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
wim_write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
break;
unsigned num_additional_swms = 0;
const tchar *staging_dir = NULL;
- if (tstrcmp(argv[0], T("mountrw")) == 0)
+ if (!tstrcmp(argv[0], T("mountrw")))
mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE;
for_opt(c, mount_options) {
switch (c) {
- case 'A':
+ case IMAGEX_ALLOW_OTHER_OPTION:
mount_flags |= WIMLIB_MOUNT_FLAG_ALLOW_OTHER;
break;
- case 'c':
+ case IMAGEX_CHECK_OPTION:
open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
break;
- case 'd':
+ case IMAGEX_DEBUG_OPTION:
mount_flags |= WIMLIB_MOUNT_FLAG_DEBUG;
break;
- case 's':
- if (tstrcasecmp(optarg, T("none")) == 0)
+ case IMAGEX_STREAMS_INTERFACE_OPTION:
+ if (!tstrcasecmp(optarg, T("none")))
mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE;
- else if (tstrcasecmp(optarg, T("xattr")) == 0)
+ else if (!tstrcasecmp(optarg, T("xattr")))
mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
- else if (tstrcasecmp(optarg, T("windows")) == 0)
+ else if (!tstrcasecmp(optarg, T("windows")))
mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS;
else {
imagex_error(T("Unknown stream interface \"%"TS"\""),
goto mount_usage;
}
break;
- case 'r':
+ case IMAGEX_REF_OPTION:
swm_glob = optarg;
break;
- case 'D':
+ case IMAGEX_STAGING_DIR_OPTION:
staging_dir = optarg;
break;
- case 'U':
+ case IMAGEX_UNIX_DATA_OPTION:
mount_flags |= WIMLIB_MOUNT_FLAG_UNIX_DATA;
break;
default:
const tchar *wimfile;
off_t old_size;
off_t new_size;
+ unsigned num_threads = 0;
for_opt(c, optimize_options) {
switch (c) {
- case 'c':
+ case IMAGEX_CHECK_OPTION:
open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
break;
- case 'r':
+ case IMAGEX_RECOMPRESS_OPTION:
write_flags |= WIMLIB_WRITE_FLAG_RECOMPRESS;
break;
+ case IMAGEX_THREADS_OPTION:
+ num_threads = parse_num_threads(optarg);
+ if (num_threads == UINT_MAX)
+ return -1;
+ break;
default:
usage(OPTIMIZE);
return -1;
else
tprintf(T("%"PRIu64" KiB\n"), old_size >> 10);
- ret = wimlib_overwrite(w, write_flags, 0, imagex_progress_func);
+ ret = wimlib_overwrite(w, write_flags, num_threads,
+ imagex_progress_func);
if (ret == 0) {
new_size = file_get_size(argv[0]);
for_opt(c, split_options) {
switch (c) {
- case 'c':
+ case IMAGEX_CHECK_OPTION:
open_flags |= WIMLIB_OPEN_FLAG_CHECK_INTEGRITY;
write_flags |= WIMLIB_WRITE_FLAG_CHECK_INTEGRITY;
break;
for_opt(c, unmount_options) {
switch (c) {
- case 'c':
+ case IMAGEX_COMMIT_OPTION:
unmount_flags |= WIMLIB_UNMOUNT_FLAG_COMMIT;
break;
- case 'C':
+ case IMAGEX_CHECK_OPTION:
unmount_flags |= WIMLIB_UNMOUNT_FLAG_CHECK_INTEGRITY;
break;
- case 'R':
+ case IMAGEX_REBULID_OPTION:
unmount_flags |= WIMLIB_UNMOUNT_FLAG_REBUILD;
break;
default:
for (i = 1; i < argc; i++) {
p = argv[i];
- if (*p == '-')
+ if (*p == T('-'))
p++;
else
continue;
- if (*p == '-')
+ if (*p == T('-'))
p++;
if (!tstrcmp(p, T("help"))) {
for_imagex_command(cmd) {
{
const struct imagex_command *cmd;
int ret;
+ int init_flags = 0;
#ifndef __WIN32__
- setlocale(LC_ALL, "");
- {
- char *codeset = nl_langinfo(CODESET);
+ if (getenv("WIMLIB_IMAGEX_USE_UTF8")) {
+ init_flags |= WIMLIB_INIT_FLAG_ASSUME_UTF8;
+ } else {
+ char *codeset;
+
+ setlocale(LC_ALL, "");
+ codeset = nl_langinfo(CODESET);
if (!strstr(codeset, "UTF-8") &&
!strstr(codeset, "UTF8") &&
!strstr(codeset, "utf-8") &&
{
fputs(
"WARNING: Running "IMAGEX_PROGNAME" in a UTF-8 locale is recommended!\n"
-" (Maybe try: `export LANG=en_US.UTF-8'?\n", stderr);
+" Maybe try: `export LANG=en_US.UTF-8'?\n"
+" Alternatively, set the environmental variable WIMLIB_IMAGEX_USE_UTF8\n"
+" to any value to force wimlib to use UTF-8.\n",
+ stderr);
}
}
if (argc < 2) {
imagex_error(T("No command specified"));
usage_all();
- return 1;
+ ret = 2;
+ goto out;
}
/* Handle --help and --version for all commands. Note that this will
wimlib_set_print_errors(true);
/* Do any initializations that the library needs */
- ret = wimlib_global_init();
+ ret = wimlib_global_init(init_flags);
if (ret)
- goto out;
+ goto out_check_status;
/* Search for the function to handle the ImageX subcommand. */
for_imagex_command(cmd) {
imagex_error(T("Unrecognized command: `%"TS"'"), argv[0]);
usage_all();
- return 1;
+ ret = 2;
+ goto out_cleanup;
out_check_write_error:
/* For 'wimlib-imagex info' and 'wimlib-imagex dir', data printed to
* standard output is part of the program's actual behavior and not just
* there was a write error. */
if (cmd == &imagex_commands[INFO] || cmd == &imagex_commands[DIR]) {
if (ferror(stdout) || fclose(stdout)) {
- imagex_error_with_errno(T("output error"));
+ imagex_error_with_errno(T("error writing to standard output"));
if (ret == 0)
ret = -1;
}
}
-out:
+out_check_status:
/* Exit status (ret): -1 indicates an error found by 'wimlib-imagex'
* outside of the wimlib library code. 0 indicates success. > 0
* indicates a wimlib error code from which an error message can be
if (ret == WIMLIB_ERR_NTFS_3G && errno != 0)
imagex_error_with_errno(T("errno"));
}
-
+out_cleanup:
/* Make the library free any resources it's holding (not strictly
* necessary because the process is ending anyway). */
wimlib_global_cleanup();
+out:
return ret;
}