ACLOCAL_AMFLAGS = -I m4
-AM_CPPFLAGS = -I$(top_srcdir)/src $(WINDOWS_CPPFLAGS)
-
-AM_CFLAGS = -std=gnu99 -D_LARGEFILE_SOURCE \
- -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+AM_CPPFLAGS = -I$(top_srcdir)/src $(WINDOWS_CPPFLAGS) \
+ -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE
+AM_CFLAGS = -std=gnu99
lib_LTLIBRARIES = libwim.la
src/verify.c \
src/wim.c \
src/wimlib.h \
+ wimlib_tchar.h \
src/wimlib_internal.h \
src/write.c \
src/xml.c \
bin_PROGRAMS = imagex
-imagex_SOURCES = programs/imagex.c
+imagex_SOURCES = programs/imagex.c wimlib_tchar.h
imagex_LDADD = $(top_builddir)/libwim.la
+imagex_CFLAGS = $(AM_CFLAGS) $(WINDOWS_CFLAGS)
if WINDOWS_NATIVE_BUILD
-imagex_SOURCES += programs/imagex-win32.c programs/imagex-win32.h
+imagex_SOURCES += programs/imagex-win32.c \
+ programs/imagex-win32.h \
+ programs/wgetopt.c \
+ programs/wgetopt.h
+
libwim_la_SOURCES += src/win32.c
endif
WITH_FUSE_DEFAULT="yes"
WINDOWS_NATIVE_BUILD="no"
VISIBILITY_CFLAGS="-fvisibility=hidden"
+WINDOWS_CFLAGS=""
WINDOWS_CPPFLAGS=""
WINDOWS_LDFLAGS=""
WINDOWS_LDADD=""
WITH_FUSE_DEFAULT="no"
WINDOWS_NATIVE_BUILD="yes"
VISIBILITY_CFLAGS=""
+ WINDOWS_CFLAGS="-municode"
WINDOWS_CPPFLAGS="-D_POSIX"
WINDOWS_LDFLAGS="-no-undefined"
WINDOWS_LDADD="-lshlwapi"
;;
*-*-cygwin*)
# Cygwin (WARNING: not well supported)
+ AC_MSG_WARN([wimlib has not been tested with Cygwin! Please do
+ a Windows-native build with MinGW-w64 instead])
WITH_NTFS_3G_DEFAULT="no"
WITH_FUSE_DEFAULT="no"
VISIBILITY_CFLAGS=""
AC_SUBST([WINDOWS_LDFLAGS], [$WINDOWS_LDFLAGS])
AC_SUBST([WINDOWS_LDADD], [$WINDOWS_LDADD])
AC_SUBST([WINDOWS_CPPFLAGS], [$WINDOWS_CPPFLAGS])
+AC_SUBST([WINDOWS_CFLAGS], [$WINDOWS_CFLAGS])
AM_CONDITIONAL([WINDOWS_NATIVE_BUILD], [test "x$WINDOWS_NATIVE_BUILD" = "xyes"])
AC_MSG_CHECKING([whether to include support for ntfs-3g])
#include <stdio.h>
/* Replacement for glob() in Windows native builds. */
-int glob(const char *pattern, int flags,
- int (*errfunc)(const char *epath, int eerrno),
- glob_t *pglob)
+int
+win32_wglob(const wchar_t *pattern, int flags,
+ int (*errfunc)(const wchar_t *epath, int eerrno),
+ glob_t *pglob)
{
- WIN32_FIND_DATA dat;
+ WIN32_FIND_DATAW dat;
DWORD err;
HANDLE hFind;
int ret;
size_t nspaces;
- const char *backslash, *forward_slash, *end_slash;
+ const wchar_t *backslash, *end_slash;
size_t prefix_len;
- backslash = strrchr(pattern, '\\');
- end_slash = strrchr(pattern, '/');
+ backslash = wcsrchr(pattern, L'\\');
+ end_slash = wcsrchr(pattern, L'/');
if (backslash > end_slash)
end_slash = backslash;
assert((flags & GLOB_ERR) == GLOB_ERR);
assert((flags & ~(GLOB_NOSORT | GLOB_ERR)) == 0);
- hFind = FindFirstFileA(pattern, &dat);
+ hFind = FindFirstFileW(pattern, &dat);
if (hFind == INVALID_HANDLE_VALUE) {
err = GetLastError();
if (err == ERROR_FILE_NOT_FOUND) {
pglob->gl_pathv = NULL;
nspaces = 0;
do {
- char *path;
+ wchar_t *path;
if (pglob->gl_pathc == nspaces) {
size_t new_nspaces;
- char **pathv;
+ wchar_t **pathv;
new_nspaces = nspaces * 2 + 1;
pathv = realloc(pglob->gl_pathv,
pglob->gl_pathv = pathv;
nspaces = new_nspaces;
}
- size_t filename_len = strlen(dat.cFileName);
+ size_t filename_len = wcslen(dat.cFileName);
size_t len_needed = prefix_len + filename_len;
- path = malloc(len_needed + 1);
+ path = malloc(len_needed + sizeof(wchar_t));
if (!path)
goto oom;
- memcpy(path, pattern, prefix_len);
- memcpy(path + prefix_len, dat.cFileName, filename_len + 1);
+ wmemcpy(path, pattern, prefix_len);
+ wmemcpy(path + prefix_len, dat.cFileName, filename_len + 1);
pglob->gl_pathv[pglob->gl_pathc++] = path;
- } while (FindNextFileA(hFind, &dat));
+ } while (FindNextFileW(hFind, &dat));
err = GetLastError();
CloseHandle(hFind);
if (err == ERROR_NO_MORE_FILES) {
return ret;
}
-void globfree(glob_t *pglob)
+void
+globfree(glob_t *pglob)
{
size_t i;
for (i = 0; i < pglob->gl_pathc; i++)
CloseHandle(hToken);
out:
if (!ret) {
- fprintf(stderr, "WARNING: Failed to %s privilege %s\n",
- enable ? "enable" : "disable", privilege);
- fprintf(stderr,
- "WARNING: The program will continue, "
- "but if permission issues are\n"
- "encountered, you may need to run "
- "this program as the administrator\n");
+ fwprintf(stderr, L"WARNING: Failed to %ls privilege %s\n",
+ enable ? L"enable" : L"disable", privilege);
+ fwprintf(stderr,
+ L"WARNING: The program will continue, "
+ L"but if permission issues are\n"
+ L"encountered, you may need to run "
+ L"this program as the administrator\n");
}
return ret;
}
{
win32_modify_restore_privileges(false);
}
+
+wchar_t *
+win32_mbs_to_wcs(const char *mbs, size_t mbs_nbytes, size_t *num_wchars_ret)
+{
+ if (mbs_nbytes > INT_MAX) {
+ fwprintf(stderr, L"ERROR: too much data (%zu bytes)!\n",
+ mbs_nbytes);
+ return NULL;
+ }
+ if (mbs_nbytes == 0) {
+ *num_wchars_ret = 0;
+ return (wchar_t*)mbs;
+ }
+ int len = MultiByteToWideChar(CP_ACP,
+ MB_ERR_INVALID_CHARS,
+ mbs,
+ mbs_nbytes,
+ NULL,
+ 0);
+ if (len <= 0)
+ goto out_invalid;
+ wchar_t *wcs = malloc(len * sizeof(wchar_t));
+ if (!wcs) {
+ fwprintf(stderr, L"ERROR: out of memory!\n");
+ return NULL;
+ }
+ int len2 = MultiByteToWideChar(CP_ACP,
+ MB_ERR_INVALID_CHARS,
+ mbs,
+ mbs_nbytes,
+ wcs,
+ len);
+ if (len2 != len) {
+ free(wcs);
+ goto out_invalid;
+ }
+ *num_wchars_ret = len;
+ return wcs;
+out_invalid:
+ fwprintf(stderr,
+L"ERROR: Invalid multi-byte string in the text file you provided as input!\n"
+L" Maybe try converting your text file to UTF-16LE?\n"
+ );
+ return NULL;
+}
+
+static inline bool
+is_path_separator(wchar_t c)
+{
+ return c == L'/' || c == L'\\';
+}
+
+wchar_t *
+win32_wbasename(wchar_t *path)
+{
+ wchar_t *p = wcschr(path, L'\0');
+
+ p--;
+ while (p >= path && is_path_separator(*p))
+ *p-- = '\0';
+ while (p >= path && !is_path_separator(*p))
+ p--;
+ p++;
+ return p;
+}
+
#include <stddef.h>
#include <stdbool.h>
+#include <wchar.h>
typedef struct {
- size_t gl_pathc;
- char **gl_pathv;
- size_t gl_offs;
+ size_t gl_pathc;
+ wchar_t **gl_pathv;
+ size_t gl_offs;
} glob_t;
/* WARNING: this is a reduced functionality replacement */
-extern int glob(const char *pattern, int flags,
- int (*errfunc)(const char *epath, int eerrno),
- glob_t *pglob);
+extern int
+win32_wglob(const wchar_t *pattern, int flags,
+ int (*errfunc)(const wchar_t *epath, int eerrno),
+ glob_t *pglob);
extern void globfree(glob_t *pglob);
extern void
win32_release_restore_privileges();
+extern wchar_t *
+win32_mbs_to_wcs(const char *mbs, size_t mbs_nbytes, size_t *num_wchars_ret);
+
+extern wchar_t *
+win32_wbasename(wchar_t *path);
+
+#include "wgetopt.h"
+
+#define optarg woptarg
+#define optind woptind
+#define opterr wopterr
+#define optopt woptopt
+#define option woption
+
+#define getopt_long_only wgetopt_long_only
+#define getopt_long wgetopt_long
+#define getopt wgetopt
+
#endif
*/
#include "config.h"
-
+#include "wimlib_tchar.h"
#include "wimlib.h"
#include <ctype.h>
#include <errno.h>
-#include <getopt.h>
#include <inttypes.h>
#include <libgen.h>
#ifdef __WIN32__
# include "imagex-win32.h"
-#else
+# define tbasename win32_wbasename
+# define tglob win32_wglob
+#else /* __WIN32__ */
# include <glob.h>
-#endif
+# include <getopt.h>
+# include <langinfo.h>
+# define tbasename basename
+# define tglob glob
+#endif /* !__WIN32 */
+
#define ARRAY_LEN(array) (sizeof(array) / sizeof(array[0]))
-#define for_opt(c, opts) while ((c = getopt_long_only(argc, (char**)argv, "", \
+#define for_opt(c, opts) while ((c = getopt_long_only(argc, (tchar**)argv, T(""), \
opts, NULL)) != -1)
enum imagex_op_type {
static void usage_all();
-static const char *usage_strings[] = {
+static const tchar *usage_strings[] = {
[APPEND] =
+T(
IMAGEX_PROGNAME" append (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n"
" [DESCRIPTION] [--boot] [--check] [--flags EDITION_ID]\n"
" [--verbose] [--dereference] [--config=FILE]\n"
" [--threads=NUM_THREADS] [--rebuild] [--unix-data]\n"
-" [--source-list] [--noacls]\n",
+" [--source-list] [--noacls]\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"
-" [--noacls]\n",
+" [--noacls]\n"
+),
[CAPTURE] =
+T(
IMAGEX_PROGNAME" capture (DIRECTORY | NTFS_VOLUME) WIMFILE [IMAGE_NAME]\n"
" [DESCRIPTION] [--boot] [--check] [--compress=TYPE]\n"
" [--flags EDITION_ID] [--verbose] [--dereference]\n"
" [--config=FILE] [--threads=NUM_THREADS] [--unix-data]\n"
-" [--source-list] [--noacls]\n",
+" [--source-list] [--noacls]\n"
+),
[DELETE] =
-IMAGEX_PROGNAME" delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check] [--soft]\n",
+T(
+IMAGEX_PROGNAME" delete WIMFILE (IMAGE_NUM | IMAGE_NAME | all) [--check] [--soft]\n"
+),
[DIR] =
-IMAGEX_PROGNAME" dir WIMFILE (IMAGE_NUM | IMAGE_NAME | all)\n",
+T(
+IMAGEX_PROGNAME" dir WIMFILE (IMAGE_NUM | IMAGE_NAME | all)\n"
+),
[EXPORT] =
+T(
IMAGEX_PROGNAME" export SRC_WIMFILE (SRC_IMAGE_NUM | SRC_IMAGE_NAME | all ) \n"
" DEST_WIMFILE [DEST_IMAGE_NAME] [DEST_IMAGE_DESCRIPTION]\n"
" [--boot] [--check] [--compress=TYPE] [--ref=\"GLOB\"]\n"
-" [--threads=NUM_THREADS] [--rebuild]\n",
+" [--threads=NUM_THREADS] [--rebuild]\n"
+),
[INFO] =
+T(
IMAGEX_PROGNAME" info WIMFILE [IMAGE_NUM | IMAGE_NAME] [NEW_NAME]\n"
" [NEW_DESC] [--boot] [--check] [--header] [--lookup-table]\n"
-" [--xml] [--extract-xml FILE] [--metadata]\n",
+" [--xml] [--extract-xml FILE] [--metadata]\n"
+),
[JOIN] =
-IMAGEX_PROGNAME" join [--check] WIMFILE SPLIT_WIM...\n",
+T(
+IMAGEX_PROGNAME" join [--check] WIMFILE SPLIT_WIM...\n"
+),
[MOUNT] =
+T(
IMAGEX_PROGNAME" mount WIMFILE (IMAGE_NUM | IMAGE_NAME) DIRECTORY\n"
" [--check] [--debug] [--streams-interface=INTERFACE]\n"
-" [--ref=\"GLOB\"] [--unix-data] [--allow-other]\n",
+" [--ref=\"GLOB\"] [--unix-data] [--allow-other]\n"
+),
[MOUNTRW] =
+T(
IMAGEX_PROGNAME" mountrw WIMFILE [IMAGE_NUM | IMAGE_NAME] DIRECTORY\n"
" [--check] [--debug] [--streams-interface=INTERFACE]\n"
-" [--staging-dir=DIR] [--unix-data] [--allow-other]\n",
+" [--staging-dir=DIR] [--unix-data] [--allow-other]\n"
+),
[OPTIMIZE] =
-IMAGEX_PROGNAME" optimize WIMFILE [--check] [--recompress] [--compress=TYPE]\n",
+T(
+IMAGEX_PROGNAME" optimize WIMFILE [--check] [--recompress]\n"
+),
[SPLIT] =
-IMAGEX_PROGNAME" split WIMFILE SPLIT_WIMFILE PART_SIZE_MB [--check]\n",
+T(
+IMAGEX_PROGNAME" split WIMFILE SPLIT_WIMFILE PART_SIZE_MB [--check]\n"
+),
[UNMOUNT] =
-IMAGEX_PROGNAME" unmount DIRECTORY [--commit] [--check] [--rebuild]\n",
+T(
+IMAGEX_PROGNAME" unmount DIRECTORY [--commit] [--check] [--rebuild]\n"
+),
};
static const struct option apply_options[] = {
- {"check", no_argument, NULL, 'c'},
- {"hardlink", no_argument, NULL, 'h'},
- {"symlink", no_argument, NULL, 's'},
- {"verbose", no_argument, NULL, 'v'},
- {"ref", required_argument, NULL, 'r'},
- {"unix-data", no_argument, NULL, 'U'},
- {"noacls", no_argument, NULL, 'N'},
+ {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'},
{NULL, 0, NULL, 0},
};
static const struct option capture_or_append_options[] = {
- {"boot", no_argument, NULL, 'b'},
- {"check", no_argument, NULL, 'c'},
- {"compress", required_argument, NULL, 'x'},
- {"config", required_argument, NULL, 'C'},
- {"dereference", no_argument, NULL, 'L'},
- {"flags", required_argument, NULL, 'f'},
- {"verbose", no_argument, NULL, 'v'},
- {"threads", required_argument, NULL, 't'},
- {"rebuild", no_argument, NULL, 'R'},
- {"unix-data", no_argument, NULL, 'U'},
- {"source-list", no_argument, NULL, 'S'},
- {"noacls", no_argument, NULL, 'N'},
+ {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'},
{NULL, 0, NULL, 0},
};
static const struct option delete_options[] = {
- {"check", no_argument, NULL, 'c'},
- {"soft", no_argument, NULL, 's'},
+ {T("check"), no_argument, NULL, 'c'},
+ {T("soft"), no_argument, NULL, 's'},
{NULL, 0, NULL, 0},
};
static const struct option export_options[] = {
- {"boot", no_argument, NULL, 'b'},
- {"check", no_argument, NULL, 'c'},
- {"compress", required_argument, NULL, 'x'},
- {"ref", required_argument, NULL, 'r'},
- {"threads", required_argument, NULL, 't'},
- {"rebuild", no_argument, NULL, 'R'},
+ {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'},
{NULL, 0, NULL, 0},
};
static const struct option info_options[] = {
- {"boot", no_argument, NULL, 'b'},
- {"check", no_argument, NULL, 'c'},
- {"extract-xml", required_argument, NULL, 'X'},
- {"header", no_argument, NULL, 'h'},
- {"lookup-table", no_argument, NULL, 'l'},
- {"metadata", no_argument, NULL, 'm'},
- {"xml", no_argument, NULL, 'x'},
+ {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'},
{NULL, 0, NULL, 0},
};
static const struct option join_options[] = {
- {"check", no_argument, NULL, 'c'},
+ {T("check"), no_argument, NULL, 'c'},
{NULL, 0, NULL, 0},
};
static const struct option mount_options[] = {
- {"check", no_argument, NULL, 'c'},
- {"debug", no_argument, NULL, 'd'},
- {"streams-interface", required_argument, NULL, 's'},
- {"ref", required_argument, NULL, 'r'},
- {"staging-dir", required_argument, NULL, 'D'},
- {"unix-data", no_argument, NULL, 'U'},
- {"allow-other", no_argument, NULL, 'A'},
+ {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'},
{NULL, 0, NULL, 0},
};
static const struct option optimize_options[] = {
- {"check", no_argument, NULL, 'c'},
- {"recompress", no_argument, NULL, 'r'},
+ {T("check"), no_argument, NULL, 'c'},
+ {T("recompress"), no_argument, NULL, 'r'},
{NULL, 0, NULL, 0},
};
static const struct option split_options[] = {
- {"check", no_argument, NULL, 'c'},
+ {T("check"), no_argument, NULL, 'c'},
{NULL, 0, NULL, 0},
};
static const struct option unmount_options[] = {
- {"commit", no_argument, NULL, 'c'},
- {"check", no_argument, NULL, 'C'},
- {"rebuild", no_argument, NULL, 'R'},
+ {T("commit"), no_argument, NULL, 'c'},
+ {T("check"), no_argument, NULL, 'C'},
+ {T("rebuild"), no_argument, NULL, 'R'},
{NULL, 0, NULL, 0},
};
/* Print formatted error message to stderr. */
-static void imagex_error(const char *format, ...)
+static void
+imagex_error(const tchar *format, ...)
{
va_list va;
va_start(va, format);
- fputs("ERROR: ", stderr);
- vfprintf(stderr, format, va);
- putc('\n', stderr);
+ tfputs(T("ERROR: "), stderr);
+ tvfprintf(stderr, format, va);
+ tputc(T('\n'), stderr);
va_end(va);
}
/* Print formatted error message to stderr. */
-static void imagex_error_with_errno(const char *format, ...)
+static void
+imagex_error_with_errno(const tchar *format, ...)
{
int errno_save = errno;
va_list va;
va_start(va, format);
- fputs("ERROR: ", stderr);
- vfprintf(stderr, format, va);
- fprintf(stderr, ": %s\n", strerror(errno_save));
+ tfputs(T("ERROR: "), stderr);
+ tvfprintf(stderr, format, va);
+ tfprintf(stderr, T(": %"TS"\n"), tstrerror(errno_save));
va_end(va);
}
-static int verify_image_exists(int image, const char *image_name,
- const char *wim_name)
+static int
+verify_image_exists(int image, const tchar *image_name, const tchar *wim_name)
{
if (image == WIMLIB_NO_IMAGE) {
- imagex_error("\"%s\" is not a valid image in `%s'!\n"
+ imagex_error(T("\"%"TS"\" is not a valid image in \"%"TS"\"!\n"
" Please specify a 1-based image index or "
"image name.\n"
" You may use `"IMAGEX_PROGNAME" info' to list the images "
- "contained in a WIM.",
+ "contained in a WIM."),
image_name, wim_name);
return -1;
}
return 0;
}
-static int verify_image_is_single(int image)
+static int
+verify_image_is_single(int image)
{
if (image == WIMLIB_ALL_IMAGES) {
- imagex_error("Cannot specify all images for this action!");
+ imagex_error(T("Cannot specify all images for this action!"));
return -1;
}
return 0;
}
-static int verify_image_exists_and_is_single(int image, const char *image_name,
- const char *wim_name)
+static int
+verify_image_exists_and_is_single(int image, const tchar *image_name,
+ const tchar *wim_name)
{
int ret;
ret = verify_image_exists(image, image_name, wim_name);
}
/* Parse the argument to --compress */
-static int get_compression_type(const char *optarg)
+static int
+get_compression_type(const tchar *optarg)
{
- if (strcasecmp(optarg, "maximum") == 0 || strcasecmp(optarg, "lzx") == 0)
+ if (tstrcasecmp(optarg, T("maximum")) == 0 || tstrcasecmp(optarg, T("lzx")) == 0)
return WIMLIB_COMPRESSION_TYPE_LZX;
- else if (strcasecmp(optarg, "fast") == 0 || strcasecmp(optarg, "xpress") == 0)
+ else if (tstrcasecmp(optarg, T("fast")) == 0 || tstrcasecmp(optarg, T("xpress")) == 0)
return WIMLIB_COMPRESSION_TYPE_XPRESS;
- else if (strcasecmp(optarg, "none") == 0)
+ else if (tstrcasecmp(optarg, T("none")) == 0)
return WIMLIB_COMPRESSION_TYPE_NONE;
else {
- imagex_error("Invalid compression type `%s'! Must be "
- "\"maximum\", \"fast\", or \"none\".", optarg);
+ imagex_error(T("Invalid compression type \"%"TS"\"! Must be "
+ "\"maximum\", \"fast\", or \"none\"."), optarg);
return WIMLIB_COMPRESSION_TYPE_INVALID;
}
}
/* Returns the size of a file given its name, or -1 if the file does not exist
* or its size cannot be determined. */
-static off_t file_get_size(const char *filename)
+static off_t
+file_get_size(const tchar *filename)
{
struct stat st;
- if (stat(filename, &st) == 0)
+ if (tstat(filename, &st) == 0)
return st.st_size;
else
return (off_t)-1;
}
-static const char *default_capture_config =
+static const tchar *default_capture_config =
+T(
"[ExclusionList]\n"
"\\$ntfs.log\n"
"\\hiberfil.sys\n"
"*.mp3\n"
"*.zip\n"
"*.cab\n"
-"\\WINDOWS\\inf\\*.pnf\n";
-
-/* Read standard input until EOF and return the full contents in a malloc()ed
- * buffer and the number of bytes of data in @len_ret. Returns NULL on read
- * error. */
-static char *stdin_get_contents(size_t *len_ret)
-{
- /* stdin can, of course, be a pipe or other non-seekable file, so the
- * total length of the data cannot be pre-determined */
- char *buf = NULL;
- size_t newlen = 1024;
- size_t pos = 0;
- size_t inc = 1024;
- for (;;) {
- char *p = realloc(buf, newlen);
- size_t bytes_read, bytes_to_read;
- if (!p) {
- imagex_error("out of memory while reading stdin");
- break;
- }
- buf = p;
- bytes_to_read = newlen - pos;
- bytes_read = fread(&buf[pos], 1, bytes_to_read, stdin);
- pos += bytes_read;
- if (bytes_read != bytes_to_read) {
- if (feof(stdin)) {
- *len_ret = pos;
- return buf;
- } else {
- imagex_error_with_errno("error reading stdin");
- break;
- }
- }
- newlen += inc;
- inc *= 3;
- inc /= 2;
- }
- free(buf);
- return NULL;
-}
+"\\WINDOWS\\inf\\*.pnf\n"
+);
enum {
PARSE_FILENAME_SUCCESS = 0,
* closing quote; or PARSE_FILENAME_NONE if the line ended before the
* beginning of a filename was found.
*/
-static int parse_filename(char **line_p, size_t *len_p, char **fn_ret)
+static int
+parse_filename(tchar **line_p, size_t *len_p, tchar **fn_ret)
{
size_t len = *len_p;
- char *line = *line_p;
- char *fn;
- char quote_char;
+ tchar *line = *line_p;
+ tchar *fn;
+ tchar quote_char;
/* Skip leading whitespace */
for (;;) {
if (len == 0)
return PARSE_FILENAME_NONE;
- if (!isspace(*line) && *line != '\0')
+ if (!istspace(*line) && *line != T('\0'))
break;
line++;
len--;
}
quote_char = *line;
- if (quote_char == '"' || quote_char == '\'') {
+ if (quote_char == T('"') || quote_char == T('\'')) {
/* Quoted filename */
line++;
len--;
fn = line;
- line = memchr(line, quote_char, len);
+ line = tmemchr(line, quote_char, len);
if (!line) {
- imagex_error("Missing closing quote: %s", fn - 1);
+ imagex_error(T("Missing closing quote: %"TS), fn - 1);
return PARSE_FILENAME_FAILURE;
}
} else {
fn = line;
do {
line++;
- } while (!isspace(*line) && *line != '\0');
+ } while (!istspace(*line) && *line != T('\0'));
}
- *line = '\0';
+ *line = T('\0');
len -= line - fn;
*len_p = len;
*line_p = line;
*
* Returns true if the line was valid; false otherwise. */
static bool
-parse_source_list_line(char *line, size_t len,
+parse_source_list_line(tchar *line, size_t len,
struct wimlib_capture_source *source)
{
/* SOURCE [DEST] */
/* Returns %true if the given line of length @len > 0 is a comment or empty line
* in the source list file format. */
-static bool is_comment_line(const char *line, size_t len)
+static bool
+is_comment_line(const tchar *line, size_t len)
{
for (;;) {
- if (*line == '#')
+ if (*line == T('#'))
return true;
- if (!isspace(*line) && *line != '\0')
+ if (!istspace(*line) && *line != T('\0'))
return false;
++line;
--len;
* the wimlib_add_image_multisource() function to specify how a WIM image is to
* be created. */
static struct wimlib_capture_source *
-parse_source_list(char *source_list_contents, size_t source_list_nbytes,
+parse_source_list(tchar **source_list_contents_p, size_t source_list_nchars,
size_t *nsources_ret)
{
size_t nlines;
- char *p;
+ 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_nbytes; i++)
- if (source_list_contents[i] == '\n')
+ for (i = 0; i < source_list_nchars; i++)
+ if (source_list_contents[i] == T('\n'))
nlines++;
- sources = calloc(nlines, sizeof(*sources));
- if (!sources) {
- imagex_error("out of memory");
- 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++;
}
+
+ sources = calloc(nlines, sizeof(*sources));
+ if (!sources)
+ goto oom;
p = source_list_contents;
j = 0;
for (i = 0; i < nlines; i++) {
/* XXX: Could use rawmemchr() here instead, but it may not be
* available on all platforms. */
- char *endp = memchr(p, '\n', source_list_nbytes);
+ tchar *endp = tmemchr(p, T('\n'), source_list_nchars);
size_t len = endp - p + 1;
- *endp = '\0';
+ *endp = T('\0');
if (!is_comment_line(p, len)) {
if (!parse_source_list_line(p, len, &sources[j++])) {
free(sources);
}
*nsources_ret = j;
return sources;
+oom:
+ imagex_error(T("out of memory"));
+ return NULL;
}
/* Reads the contents of a file into memory. */
-static char *file_get_contents(const char *filename, size_t *len_ret)
+static char *
+file_get_contents(const tchar *filename, size_t *len_ret)
{
struct stat stbuf;
- char *buf = NULL;
+ void *buf = NULL;
size_t len;
FILE *fp;
- if (stat(filename, &stbuf) != 0) {
- imagex_error_with_errno("Failed to stat the file `%s'", filename);
+ if (tstat(filename, &stbuf) != 0) {
+ imagex_error_with_errno(T("Failed to stat the file \"%"TS"\""), filename);
goto out;
}
len = stbuf.st_size;
- fp = fopen(filename, "rb");
+ fp = tfopen(filename, T("rb"));
if (!fp) {
- imagex_error_with_errno("Failed to open the file `%s'", filename);
+ imagex_error_with_errno(T("Failed to open the file \"%"TS"\""), filename);
goto out;
}
buf = malloc(len);
if (!buf) {
- imagex_error("Failed to allocate buffer of %zu bytes to hold "
- "contents of file `%s'", len, filename);
+ imagex_error(T("Failed to allocate buffer of %zu bytes to hold "
+ "contents of file \"%"TS"\""), len, filename);
goto out_fclose;
}
if (fread(buf, 1, len, fp) != len) {
- imagex_error_with_errno("Failed to read %lu bytes from the "
- "file `%s'", len, filename);
+ imagex_error_with_errno(T("Failed to read %zu bytes from the "
+ "file \"%"TS"\""), len, filename);
goto out_free_buf;
}
*len_ret = len;
return buf;
}
+/* Read standard input until EOF and return the full contents in a malloc()ed
+ * buffer and the number of bytes of data in @len_ret. Returns NULL on read
+ * error. */
+static char *
+stdin_get_contents(size_t *len_ret)
+{
+ /* stdin can, of course, be a pipe or other non-seekable file, so the
+ * total length of the data cannot be pre-determined */
+ char *buf = NULL;
+ size_t newlen = 1024;
+ size_t pos = 0;
+ size_t inc = 1024;
+ for (;;) {
+ char *p = realloc(buf, newlen);
+ size_t bytes_read, bytes_to_read;
+ if (!p) {
+ imagex_error(T("out of memory while reading stdin"));
+ break;
+ }
+ buf = p;
+ bytes_to_read = newlen - pos;
+ bytes_read = fread(&buf[pos], 1, bytes_to_read, stdin);
+ pos += bytes_read;
+ if (bytes_read != bytes_to_read) {
+ if (feof(stdin)) {
+ *len_ret = pos;
+ return buf;
+ } else {
+ imagex_error_with_errno(T("error reading stdin"));
+ break;
+ }
+ }
+ newlen += inc;
+ inc *= 3;
+ inc /= 2;
+ }
+ free(buf);
+ return NULL;
+}
+
+
+static tchar *
+translate_text_to_tstr(char **text_p, 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;
+#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)))
+ {
+ /* 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;
+ } 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,
+ num_bytes,
+ &num_wchars);
+ }
+ *num_tchars_ret = num_wchars;
+ return text_wstr;
+#endif /* __WIN32__ */
+}
+
+static tchar *
+file_get_text_contents(const tchar *filename, size_t *num_tchars_ret)
+{
+ char *contents;
+ size_t num_bytes;
+
+ contents = file_get_contents(filename, &num_bytes);
+ if (!contents)
+ return NULL;
+ return translate_text_to_tstr(&contents, num_bytes, num_tchars_ret);
+}
+
+static tchar *
+stdin_get_text_contents(size_t *num_tchars_ret)
+{
+ char *contents;
+ size_t num_bytes;
+
+ contents = stdin_get_contents(&num_bytes);
+ if (!contents)
+ return NULL;
+ 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 char *path)
+static int
+file_writable(const tchar *path)
{
int ret;
- ret = access(path, W_OK);
+ ret = taccess(path, W_OK);
if (ret != 0)
- imagex_error_with_errno("Can't modify `%s'", path);
+ imagex_error_with_errno(T("Can't modify \"%"TS"\""), path);
return ret;
}
/* Given an enumerated value for WIM compression type, return a descriptive
* string. */
-static const char *get_data_type(int ctype)
+static const tchar *
+get_data_type(int ctype)
{
switch (ctype) {
case WIMLIB_COMPRESSION_TYPE_NONE:
- return "uncompressed";
+ return T("uncompressed");
case WIMLIB_COMPRESSION_TYPE_LZX:
- return "LZX-compressed";
+ return T("LZX-compressed");
case WIMLIB_COMPRESSION_TYPE_XPRESS:
- return "XPRESS-compressed";
+ return T("XPRESS-compressed");
}
return NULL;
}
/* Progress callback function passed to various wimlib functions. */
-static int imagex_progress_func(enum wimlib_progress_msg msg,
- const union wimlib_progress_info *info)
+static int
+imagex_progress_func(enum wimlib_progress_msg msg,
+ const union wimlib_progress_info *info)
{
unsigned percent_done;
switch (msg) {
percent_done = TO_PERCENT(info->write_streams.completed_bytes,
info->write_streams.total_bytes);
if (info->write_streams.completed_streams == 0) {
- const char *data_type;
+ const tchar *data_type;
data_type = get_data_type(info->write_streams.compression_type);
- printf("Writing %s data using %u thread%s\n",
- data_type, info->write_streams.num_threads,
- (info->write_streams.num_threads == 1) ? "" : "s");
+ tprintf(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"));
}
- printf("\r%"PRIu64" MiB of %"PRIu64" MiB (uncompressed) "
- "written (%u%% done)",
- info->write_streams.completed_bytes >> 20,
- info->write_streams.total_bytes >> 20,
- percent_done);
+ tprintf(T("\r%"PRIu64" MiB of %"PRIu64" MiB (uncompressed) "
+ "written (%u%% done)"),
+ info->write_streams.completed_bytes >> 20,
+ info->write_streams.total_bytes >> 20,
+ percent_done);
if (info->write_streams.completed_bytes >= info->write_streams.total_bytes)
- putchar('\n');
+ tputchar(T('\n'));
break;
case WIMLIB_PROGRESS_MSG_SCAN_BEGIN:
- printf("Scanning `%s'", info->scan.source);
+ tprintf(T("Scanning \"%"TS"\""), info->scan.source);
if (*info->scan.wim_target_path) {
- printf(" (loading as WIM path: `/%s')...\n",
+ tprintf(T(" (loading as WIM path: \"/%"TS"\")...\n"),
info->scan.wim_target_path);
} else {
- printf(" (loading as root of WIM image)...\n");
+ tprintf(T(" (loading as root of WIM image)...\n"));
}
break;
case WIMLIB_PROGRESS_MSG_SCAN_DENTRY:
if (info->scan.excluded)
- printf("Excluding `%s' from capture\n", info->scan.cur_path);
+ tprintf(T("Excluding \"%"TS"\" from capture\n"), info->scan.cur_path);
else
- printf("Scanning `%s'\n", info->scan.cur_path);
+ tprintf(T("Scanning \"%"TS"\"\n"), info->scan.cur_path);
break;
/*case WIMLIB_PROGRESS_MSG_SCAN_END:*/
/*break;*/
case WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY:
percent_done = TO_PERCENT(info->integrity.completed_bytes,
info->integrity.total_bytes);
- printf("\rVerifying integrity of `%s': %"PRIu64" MiB "
- "of %"PRIu64" MiB (%u%%) done",
- info->integrity.filename,
- info->integrity.completed_bytes >> 20,
- info->integrity.total_bytes >> 20,
- percent_done);
+ tprintf(T("\rVerifying integrity of \"%"TS"\": %"PRIu64" MiB "
+ "of %"PRIu64" MiB (%u%%) done"),
+ info->integrity.filename,
+ info->integrity.completed_bytes >> 20,
+ info->integrity.total_bytes >> 20,
+ percent_done);
if (info->integrity.completed_bytes == info->integrity.total_bytes)
- putchar('\n');
+ tputchar(T('\n'));
break;
case WIMLIB_PROGRESS_MSG_CALC_INTEGRITY:
percent_done = TO_PERCENT(info->integrity.completed_bytes,
info->integrity.total_bytes);
- printf("\rCalculating integrity table for WIM: %"PRIu64" MiB "
- "of %"PRIu64" MiB (%u%%) done",
- info->integrity.completed_bytes >> 20,
- info->integrity.total_bytes >> 20,
- percent_done);
+ tprintf(T("\rCalculating integrity table for WIM: %"PRIu64" MiB "
+ "of %"PRIu64" MiB (%u%%) done"),
+ info->integrity.completed_bytes >> 20,
+ info->integrity.total_bytes >> 20,
+ percent_done);
if (info->integrity.completed_bytes == info->integrity.total_bytes)
- putchar('\n');
+ tputchar(T('\n'));
break;
case WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN:
- printf("Applying image %d (%s) from `%s' to %s `%s'\n",
- info->extract.image,
- info->extract.image_name,
- info->extract.wimfile_name,
- ((info->extract.extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) ?
- "NTFS volume" : "directory"),
- info->extract.target);
+ tprintf(T("Applying image %d (%"TS") from \"%"TS"\" "
+ "to %"TS" \"%"TS"\"\n"),
+ info->extract.image,
+ info->extract.image_name,
+ info->extract.wimfile_name,
+ ((info->extract.extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) ?
+ T("NTFS volume") : T("directory")),
+ info->extract.target);
break;
/*case WIMLIB_PROGRESS_MSG_EXTRACT_DIR_STRUCTURE_BEGIN:*/
/*printf("Applying directory structure to %s\n",*/
case WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS:
percent_done = TO_PERCENT(info->extract.completed_bytes,
info->extract.total_bytes);
- printf("\rExtracting files: "
- "%"PRIu64" MiB of %"PRIu64" MiB (%u%%) done",
- info->extract.completed_bytes >> 20,
- info->extract.total_bytes >> 20,
- percent_done);
+ tprintf(T("\rExtracting files: "
+ "%"PRIu64" MiB of %"PRIu64" MiB (%u%%) done"),
+ info->extract.completed_bytes >> 20,
+ info->extract.total_bytes >> 20,
+ percent_done);
if (info->extract.completed_bytes >= info->extract.total_bytes)
putchar('\n');
break;
case WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY:
- puts(info->extract.cur_path);
+ tprintf(T("%"TS"\n"), info->extract.cur_path);
break;
case WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS:
- printf("Setting timestamps on all extracted files...\n");
+ tprintf(T("Setting timestamps on all extracted files...\n"));
break;
case WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END:
if (info->extract.extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
- printf("Unmounting NTFS volume `%s'...\n",
- info->extract.target);
+ tprintf(T("Unmounting NTFS volume \"%"TS"\"...\n"),
+ info->extract.target);
}
break;
case WIMLIB_PROGRESS_MSG_JOIN_STREAMS:
case WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART:
percent_done = TO_PERCENT(info->split.completed_bytes,
info->split.total_bytes);
- printf("Writing `%s': %"PRIu64" MiB of %"PRIu64" MiB (%u%%) written\n",
- info->split.part_name,
- info->split.completed_bytes >> 20,
- info->split.total_bytes >> 20,
- percent_done);
+ tprintf(T("Writing \"%"TS"\": %"PRIu64" MiB of "
+ "%"PRIu64" MiB (%u%%) written\n"),
+ info->split.part_name,
+ info->split.completed_bytes >> 20,
+ info->split.total_bytes >> 20,
+ percent_done);
break;
case WIMLIB_PROGRESS_MSG_SPLIT_END_PART:
if (info->split.completed_bytes == info->split.total_bytes) {
- printf("Finished writing %u split WIM parts\n",
- info->split.cur_part_number);
+ tprintf(T("Finished writing %u split WIM parts\n"),
+ info->split.cur_part_number);
}
break;
default:
*
* @first_part specifies the first part of the split WIM and it may be either
* included or omitted from the glob. */
-static int open_swms_from_glob(const char *swm_glob,
- const char *first_part,
- int open_flags,
- WIMStruct ***additional_swms_ret,
- unsigned *num_additional_swms_ret)
+static int
+open_swms_from_glob(const tchar *swm_glob,
+ const tchar *first_part,
+ int open_flags,
+ WIMStruct ***additional_swms_ret,
+ unsigned *num_additional_swms_ret)
{
unsigned num_additional_swms = 0;
WIMStruct **additional_swms = NULL;
int ret;
/* Warning: glob() is replaced in Windows native builds */
- ret = glob(swm_glob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf);
+ ret = tglob(swm_glob, GLOB_ERR | GLOB_NOSORT, NULL, &globbuf);
if (ret != 0) {
if (ret == GLOB_NOMATCH) {
- imagex_error("Found no files for glob \"%s\"",
+ imagex_error(T("Found no files for glob \"%"TS"\""),
swm_glob);
} else {
- imagex_error_with_errno("Failed to process glob "
- "\"%s\"", swm_glob);
+ imagex_error_with_errno(T("Failed to process glob \"%"TS"\""),
+ swm_glob);
}
ret = -1;
goto out;
num_additional_swms = globbuf.gl_pathc;
additional_swms = calloc(num_additional_swms, sizeof(additional_swms[0]));
if (!additional_swms) {
- imagex_error("Out of memory");
+ imagex_error(T("Out of memory"));
ret = -1;
goto out_globfree;
}
unsigned offset = 0;
for (unsigned i = 0; i < num_additional_swms; i++) {
- if (strcmp(globbuf.gl_pathv[i], first_part) == 0) {
+ if (tstrcmp(globbuf.gl_pathv[i], first_part) == 0) {
offset++;
continue;
}
}
-static unsigned parse_num_threads(const char *optarg)
+static unsigned
+parse_num_threads(const tchar *optarg)
{
- char *tmp;
- unsigned nthreads = strtoul(optarg, &tmp, 10);
+ tchar *tmp;
+ unsigned nthreads = tstrtoul(optarg, &tmp, 10);
if (nthreads == UINT_MAX || *tmp || tmp == optarg) {
- imagex_error("Number of threads must be a non-negative integer!");
+ imagex_error(T("Number of threads must be a non-negative integer!"));
return UINT_MAX;
} else {
return nthreads;
/* Apply one image, or all images, from a WIM file into a directory, OR apply
* one image from a WIM file to a NTFS volume. */
-static int imagex_apply(int argc, char **argv)
+static int
+imagex_apply(int argc, tchar **argv)
{
int c;
int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
int num_images;
WIMStruct *w;
int ret;
- const char *wimfile;
- const char *target;
- const char *image_num_or_name;
+ const tchar *wimfile;
+ const tchar *target;
+ const tchar *image_num_or_name;
int extract_flags = WIMLIB_EXTRACT_FLAG_SEQUENTIAL;
- const char *swm_glob = NULL;
+ const tchar *swm_glob = NULL;
WIMStruct **additional_swms = NULL;
unsigned num_additional_swms = 0;
wimfile = argv[0];
if (argc == 2) {
- image_num_or_name = "1";
+ image_num_or_name = T("1");
target = argv[1];
} else {
image_num_or_name = argv[1];
num_images = wimlib_get_num_images(w);
if (argc == 2 && num_images != 1) {
- imagex_error("`%s' contains %d images; Please select one "
- "(or all)", wimfile, num_images);
+ imagex_error(T("\"%"TS"\" contains %d images; Please select one "
+ "(or all)"), wimfile, num_images);
usage(APPLY);
ret = -1;
goto out;
struct stat stbuf;
- ret = stat(target, &stbuf);
+ ret = tstat(target, &stbuf);
if (ret == 0) {
if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode))
extract_flags |= WIMLIB_EXTRACT_FLAG_NTFS;
} else {
if (errno != ENOENT) {
- imagex_error_with_errno("Failed to stat `%s'", target);
+ imagex_error_with_errno(T("Failed to stat \"%"TS"\""),
+ target);
ret = -1;
goto out;
}
additional_swms, num_additional_swms,
imagex_progress_func);
if (ret == 0)
- printf("Done applying WIM image.\n");
+ tprintf(T("Done applying WIM image.\n"));
#ifdef __WIN32__
win32_release_restore_privileges();
#endif
* directory trees. 'wimlib-imagex capture': create a new WIM file containing
* the desired image. 'wimlib-imagex append': add a new image to an existing
* WIM file. */
-static int imagex_capture_or_append(int argc, char **argv)
+static int
+imagex_capture_or_append(int argc, tchar **argv)
{
int c;
int open_flags = 0;
int add_image_flags = 0;
int write_flags = 0;
int compression_type = WIMLIB_COMPRESSION_TYPE_XPRESS;
- const char *wimfile;
- const char *name;
- const char *desc;
- const char *flags_element = NULL;
+ const tchar *wimfile;
+ const tchar *name;
+ const tchar *desc;
+ const tchar *flags_element = NULL;
WIMStruct *w = NULL;
int ret;
int cur_image;
- int cmd = strcmp(argv[0], "append") ? CAPTURE : APPEND;
+ int cmd = tstrcmp(argv[0], T("append")) ? CAPTURE : APPEND;
unsigned num_threads = 0;
- char *source;
+ tchar *source;
size_t source_name_len;
- char *source_copy;
+ tchar *source_copy;
- const char *config_file = NULL;
- char *config_str = NULL;
+ const tchar *config_file = NULL;
+ tchar *config_str = NULL;
size_t config_len;
bool source_list = false;
- size_t source_list_nbytes;
- char *source_list_contents = NULL;
+ size_t source_list_nchars;
+ tchar *source_list_contents = NULL;
bool capture_sources_malloced = false;
struct wimlib_capture_source *capture_sources;
size_t num_sources;
/* Set default name to SOURCE argument, omitting any directory
* prefixes and trailing slashes. This requires making a copy
* of @source. */
- source_name_len = strlen(source);
- source_copy = alloca(source_name_len + 1);
- name = basename(strcpy(source_copy, source));
+ source_name_len = tstrlen(source);
+ source_copy = alloca((source_name_len + 1) * sizeof(tchar));
+ name = tbasename(tstrcpy(source_copy, source));
}
/* Image description defaults to NULL if not given. */
desc = (argc >= 4) ? argv[3] : NULL;
if (source_list) {
/* Set up capture sources in source list mode */
- if (source[0] == '-' && source[1] == '\0') {
- source_list_contents = stdin_get_contents(&source_list_nbytes);
+ if (source[0] == T('-') && source[1] == T('\0')) {
+ source_list_contents = stdin_get_text_contents(&source_list_nchars);
} else {
- source_list_contents = file_get_contents(source,
- &source_list_nbytes);
+ source_list_contents = file_get_text_contents(source,
+ &source_list_nchars);
}
if (!source_list_contents)
return -1;
- capture_sources = parse_source_list(source_list_contents,
- source_list_nbytes,
+ capture_sources = parse_source_list(&source_list_contents,
+ source_list_nchars,
&num_sources);
if (!capture_sources) {
ret = -1;
}
if (config_file) {
- config_str = file_get_contents(config_file, &config_len);
+ config_str = file_get_text_contents(config_file, &config_len);
if (!config_str) {
ret = -1;
goto out;
if (!source_list) {
struct stat stbuf;
- ret = stat(source, &stbuf);
+ ret = tstat(source, &stbuf);
if (ret == 0) {
if (S_ISBLK(stbuf.st_mode) || S_ISREG(stbuf.st_mode)) {
- printf("Capturing WIM image from NTFS filesystem on `%s'\n",
- source);
+ tprintf(T("Capturing WIM image from NTFS "
+ "filesystem on \"%"TS"\"\n"), source);
add_image_flags |= WIMLIB_ADD_IMAGE_FLAG_NTFS;
}
} else {
if (errno != ENOENT) {
- imagex_error_with_errno("Failed to stat `%s'", source);
+ imagex_error_with_errno(T("Failed to stat "
+ "\"%"TS"\""), source);
ret = -1;
goto out;
}
(config_str ? config_str :
default_capture_config),
(config_str ? config_len :
- strlen(default_capture_config)),
+ tstrlen(default_capture_config)),
add_image_flags,
imagex_progress_func);
if (ret != 0)
if (ret == WIMLIB_ERR_REOPEN)
ret = 0;
if (ret != 0)
- imagex_error("Failed to write the WIM file `%s'", wimfile);
+ imagex_error(T("Failed to write the WIM file \"%"TS"\""),
+ wimfile);
out_release_privs:
#ifdef __WIN32__
win32_release_capture_privileges();
}
/* Remove image(s) from a WIM. */
-static int imagex_delete(int argc, char **argv)
+static int
+imagex_delete(int argc, tchar **argv)
{
int c;
int open_flags = 0;
int write_flags = 0;
- const char *wimfile;
- const char *image_num_or_name;
+ const tchar *wimfile;
+ const tchar *image_num_or_name;
WIMStruct *w;
int image;
int ret;
if (argc != 2) {
if (argc < 1)
- imagex_error("Must specify a WIM file");
+ imagex_error(T("Must specify a WIM file"));
if (argc < 2)
- imagex_error("Must specify an image");
+ imagex_error(T("Must specify an image"));
usage(DELETE);
return -1;
}
ret = wimlib_delete_image(w, image);
if (ret != 0) {
- imagex_error("Failed to delete image from `%s'", wimfile);
+ imagex_error(T("Failed to delete image from \"%"TS"\""), wimfile);
goto out;
}
if (ret == WIMLIB_ERR_REOPEN)
ret = 0;
if (ret != 0) {
- imagex_error("Failed to write the file `%s' with image "
- "deleted", wimfile);
+ imagex_error(T("Failed to write the file \"%"TS"\" with image "
+ "deleted"), wimfile);
}
out:
wimlib_free(w);
}
/* Print the files contained in an image(s) in a WIM file. */
-static int imagex_dir(int argc, char **argv)
+static int
+imagex_dir(int argc, tchar **argv)
{
- const char *wimfile;
+ const tchar *wimfile;
WIMStruct *w;
int image;
int ret;
int num_images;
if (argc < 2) {
- imagex_error("Must specify a WIM file");
+ imagex_error(T("Must specify a WIM file"));
usage(DIR);
return -1;
}
if (argc > 3) {
- imagex_error("Too many arguments");
+ imagex_error(T("Too many arguments"));
usage(DIR);
return -1;
}
* choose that one; otherwise, print an error. */
num_images = wimlib_get_num_images(w);
if (num_images != 1) {
- imagex_error("The file `%s' contains %d images; Please "
- "select one.", wimfile, num_images);
+ imagex_error(T("The file \"%"TS"\" contains %d images; Please "
+ "select one."), wimfile, num_images);
usage(DIR);
ret = -1;
goto out;
/* Exports one, or all, images from a WIM file to a new WIM file or an existing
* WIM file. */
-static int imagex_export(int argc, char **argv)
+static int
+imagex_export(int argc, tchar **argv)
{
int c;
int open_flags = 0;
int write_flags = 0;
int compression_type = WIMLIB_COMPRESSION_TYPE_NONE;
bool compression_type_specified = false;
- const char *src_wimfile;
- const char *src_image_num_or_name;
- const char *dest_wimfile;
- const char *dest_name;
- const char *dest_desc;
+ const tchar *src_wimfile;
+ const tchar *src_image_num_or_name;
+ const tchar *dest_wimfile;
+ const tchar *dest_name;
+ const tchar *dest_desc;
WIMStruct *src_w = NULL;
WIMStruct *dest_w = NULL;
int ret;
int image;
struct stat stbuf;
bool wim_is_new;
- const char *swm_glob = NULL;
+ const tchar *swm_glob = NULL;
WIMStruct **additional_swms = NULL;
unsigned num_additional_swms = 0;
unsigned num_threads = 0;
/* Determine if the destination is an existing file or not.
* If so, we try to append the exported image(s) to it; otherwise, we
* create a new WIM containing the exported image(s). */
- if (stat(dest_wimfile, &stbuf) == 0) {
+ if (tstat(dest_wimfile, &stbuf) == 0) {
int dest_ctype;
wim_is_new = false;
/* Destination file exists. */
if (!S_ISREG(stbuf.st_mode)) {
- imagex_error("`%s' is not a regular file",
+ imagex_error(T("\"%"TS"\" is not a regular file"),
dest_wimfile);
ret = -1;
goto out;
if (compression_type_specified
&& compression_type != dest_ctype)
{
- imagex_error("Cannot specify a compression type that is "
- "not the same as that used in the "
- "destination WIM");
+ imagex_error(T("Cannot specify a compression type that is "
+ "not the same as that used in the "
+ "destination WIM"));
ret = -1;
goto out;
}
if (ret != 0)
goto out;
} else {
- imagex_error_with_errno("Cannot stat file `%s'",
+ imagex_error_with_errno(T("Cannot stat file \"%"TS"\""),
dest_wimfile);
ret = -1;
goto out;
/* 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 imagex_info(int argc, char **argv)
+static int
+imagex_info(int argc, tchar **argv)
{
int c;
bool boot = false;
bool xml = false;
bool metadata = false;
bool short_header = true;
- const char *xml_out_file = NULL;
- const char *wimfile;
- const char *image_num_or_name = "all";
- const char *new_name = NULL;
- const char *new_desc = NULL;
+ const tchar *xml_out_file = NULL;
+ const tchar *wimfile;
+ const tchar *image_num_or_name = T("all");
+ const tchar *new_name = NULL;
+ const tchar *new_desc = NULL;
WIMStruct *w;
FILE *fp;
int image;
part_number = wimlib_get_part_number(w, &total_parts);
image = wimlib_resolve_image(w, image_num_or_name);
- if (image == WIMLIB_NO_IMAGE && strcmp(image_num_or_name, "0") != 0) {
- imagex_error("The image `%s' does not exist",
+ if (image == WIMLIB_NO_IMAGE && tstrcmp(image_num_or_name, T("0"))) {
+ imagex_error(T("The image \"%"TS"\" does not exist"),
image_num_or_name);
- if (boot)
- imagex_error("If you would like to set the boot "
- "index to 0, specify image \"0\" with "
- "the --boot flag.");
+ if (boot) {
+ imagex_error(T("If you would like to set the boot "
+ "index to 0, specify image \"0\" with "
+ "the --boot flag."));
+ }
ret = WIMLIB_ERR_INVALID_IMAGE;
goto out;
}
if (num_images == 0) {
if (boot) {
- imagex_error("--boot is meaningless on a WIM with no "
- "images");
+ imagex_error(T("--boot is meaningless on a WIM with no "
+ "images"));
ret = WIMLIB_ERR_INVALID_IMAGE;
goto out;
}
if (image == WIMLIB_ALL_IMAGES && num_images > 1) {
if (boot) {
- imagex_error("Cannot specify the --boot flag "
- "without specifying a specific "
- "image in a multi-image WIM");
+ imagex_error(T("Cannot specify the --boot flag "
+ "without specifying a specific "
+ "image in a multi-image WIM"));
ret = WIMLIB_ERR_INVALID_IMAGE;
goto out;
}
if (new_name) {
- imagex_error("Cannot specify the NEW_NAME "
- "without specifying a specific "
- "image in a multi-image WIM");
+ imagex_error(T("Cannot specify the NEW_NAME "
+ "without specifying a specific "
+ "image in a multi-image WIM"));
ret = WIMLIB_ERR_INVALID_IMAGE;
goto out;
}
/* Read-only operations */
if (image == WIMLIB_NO_IMAGE) {
- imagex_error("`%s' is not a valid image",
+ imagex_error(T("\"%"TS"\" is not a valid image"),
image_num_or_name);
ret = WIMLIB_ERR_INVALID_IMAGE;
goto out;
if (lookup_table) {
if (total_parts != 1) {
- printf("Warning: Only showing the lookup table "
- "for part %d of a %d-part WIM.\n",
- part_number, total_parts);
+ tprintf(T("Warning: Only showing the lookup table "
+ "for part %d of a %d-part WIM.\n"),
+ part_number, total_parts);
}
wimlib_print_lookup_table(w);
}
}
if (xml_out_file) {
- fp = fopen(xml_out_file, "wb");
+ fp = tfopen(xml_out_file, T("wb"));
if (!fp) {
- imagex_error_with_errno("Failed to open the "
- "file `%s' for "
- "writing ",
+ imagex_error_with_errno(T("Failed to open the "
+ "file \"%"TS"\" for "
+ "writing "),
xml_out_file);
ret = -1;
goto out;
}
ret = wimlib_extract_xml_data(w, fp);
if (fclose(fp) != 0) {
- imagex_error("Failed to close the file `%s'",
+ imagex_error(T("Failed to close the file "
+ "\"%"TS"\""),
xml_out_file);
ret = -1;
}
/* Modification operations */
if (total_parts != 1) {
- imagex_error("Modifying a split WIM is not supported.");
+ imagex_error(T("Modifying a split WIM is not supported."));
ret = -1;
goto out;
}
image = 1;
if (image == WIMLIB_NO_IMAGE && new_name) {
- imagex_error("Cannot specify new_name (`%s') when "
- "using image 0", new_name);
+ imagex_error(T("Cannot specify new_name (\"%"TS"\") "
+ "when using image 0"), new_name);
ret = -1;
goto out;
}
if (boot) {
if (image == wimlib_get_boot_idx(w)) {
- printf("Image %d is already marked as "
- "bootable.\n", image);
+ tprintf(T("Image %d is already marked as "
+ "bootable.\n"), image);
boot = false;
} else {
- printf("Marking image %d as bootable.\n",
- image);
+ tprintf(T("Marking image %d as bootable.\n"),
+ image);
wimlib_set_boot_idx(w, image);
}
}
if (new_name) {
- if (strcmp(wimlib_get_image_name(w, image),
- new_name) == 0) {
- printf("Image %d is already named \"%s\".\n",
- image, new_name);
+ if (!tstrcmp(wimlib_get_image_name(w, image), new_name))
+ {
+ tprintf(T("Image %d is already named \"%"TS"\".\n"),
+ image, new_name);
new_name = NULL;
} else {
- printf("Changing the name of image %d to "
- "\"%s\".\n", image, new_name);
+ tprintf(T("Changing the name of image %d to "
+ "\"%"TS"\".\n"), image, new_name);
ret = wimlib_set_image_name(w, image, new_name);
if (ret != 0)
goto out;
}
}
if (new_desc) {
- const char *old_desc;
+ const tchar *old_desc;
old_desc = wimlib_get_image_description(w, image);
- if (old_desc && strcmp(old_desc, new_desc) == 0) {
- printf("The description of image %d is already "
- "\"%s\".\n", image, new_desc);
+ if (old_desc && !tstrcmp(old_desc, new_desc)) {
+ tprintf(T("The description of image %d is already "
+ "\"%"TS"\".\n"), image, new_desc);
new_desc = NULL;
} else {
- printf("Changing the description of image %d "
- "to \"%s\".\n", image, new_desc);
+ tprintf(T("Changing the description of image %d "
+ "to \"%"TS"\".\n"), image, new_desc);
ret = wimlib_set_image_descripton(w, image,
new_desc);
if (ret != 0)
if (ret == WIMLIB_ERR_REOPEN)
ret = 0;
} else {
- printf("The file `%s' was not modified because nothing "
- "needed to be done.\n", wimfile);
+ tprintf(T("The file \"%"TS"\" was not modified because nothing "
+ "needed to be done.\n"), wimfile);
ret = 0;
}
}
}
/* Join split WIMs into one part WIM */
-static int imagex_join(int argc, char **argv)
+static int
+imagex_join(int argc, tchar **argv)
{
int c;
int swm_open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
int wim_write_flags = 0;
- const char *output_path;
+ const tchar *output_path;
for_opt(c, join_options) {
switch (c) {
argv += optind;
if (argc < 2) {
- imagex_error("Must specify one or more split WIM (.swm) parts "
- "to join");
+ imagex_error(T("Must specify one or more split WIM (.swm) "
+ "parts to join"));
goto err;
}
output_path = argv[0];
- return wimlib_join((const char **)++argv, --argc, output_path,
- swm_open_flags, wim_write_flags,
+ return wimlib_join((const tchar * const *)++argv,
+ --argc,
+ output_path,
+ swm_open_flags,
+ wim_write_flags,
imagex_progress_func);
err:
usage(JOIN);
}
/* Mounts an image using a FUSE mount. */
-static int imagex_mount_rw_or_ro(int argc, char **argv)
+static int
+imagex_mount_rw_or_ro(int argc, tchar **argv)
{
int c;
int mount_flags = 0;
int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
- const char *wimfile;
- const char *dir;
+ const tchar *wimfile;
+ const tchar *dir;
WIMStruct *w;
int image;
int num_images;
int ret;
- const char *swm_glob = NULL;
+ const tchar *swm_glob = NULL;
WIMStruct **additional_swms = NULL;
unsigned num_additional_swms = 0;
- const char *staging_dir = NULL;
+ const tchar *staging_dir = NULL;
- if (strcmp(argv[0], "mountrw") == 0)
+ if (tstrcmp(argv[0], T("mountrw")) == 0)
mount_flags |= WIMLIB_MOUNT_FLAG_READWRITE;
for_opt(c, mount_options) {
mount_flags |= WIMLIB_MOUNT_FLAG_DEBUG;
break;
case 's':
- if (strcasecmp(optarg, "none") == 0)
+ if (tstrcasecmp(optarg, T("none")) == 0)
mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_NONE;
- else if (strcasecmp(optarg, "xattr") == 0)
+ else if (tstrcasecmp(optarg, T("xattr")) == 0)
mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR;
- else if (strcasecmp(optarg, "windows") == 0)
+ else if (tstrcasecmp(optarg, T("windows")) == 0)
mount_flags |= WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_WINDOWS;
else {
- imagex_error("Unknown stream interface \"%s\"", optarg);
+ imagex_error(T("Unknown stream interface \"%"TS"\""),
+ optarg);
goto mount_usage;
}
break;
image = 1;
num_images = wimlib_get_num_images(w);
if (num_images != 1) {
- imagex_error("The file `%s' contains %d images; Please "
- "select one.", wimfile, num_images);
+ imagex_error(T("The file \"%"TS"\" contains %d images; Please "
+ "select one."), wimfile, num_images);
usage((mount_flags & WIMLIB_MOUNT_FLAG_READWRITE)
? MOUNTRW : MOUNT);
ret = -1;
ret = wimlib_mount_image(w, image, dir, mount_flags, additional_swms,
num_additional_swms, staging_dir);
if (ret != 0) {
- imagex_error("Failed to mount image %d from `%s' on `%s'",
+ imagex_error(T("Failed to mount image %d from \"%"TS"\" "
+ "on \"%"TS"\""),
image, wimfile, dir);
}
}
/* Rebuild a WIM file */
-static int imagex_optimize(int argc, char **argv)
+static int
+imagex_optimize(int argc, tchar **argv)
{
int c;
int open_flags = 0;
int write_flags = WIMLIB_WRITE_FLAG_REBUILD;
int ret;
WIMStruct *w;
- const char *wimfile;
+ const tchar *wimfile;
off_t old_size;
off_t new_size;
return ret;
old_size = file_get_size(argv[0]);
- printf("`%s' original size: ", wimfile);
+ tprintf(T("\"%"TS"\" original size: "), wimfile);
if (old_size == -1)
- puts("Unknown");
+ tfputs(T("Unknown\n"), stdout);
else
- printf("%"PRIu64" KiB\n", old_size >> 10);
+ tprintf(T("%"PRIu64" KiB\n"), old_size >> 10);
ret = wimlib_overwrite(w, write_flags, 0, imagex_progress_func);
if (ret == 0) {
new_size = file_get_size(argv[0]);
- printf("`%s' optimized size: ", wimfile);
+ tprintf(T("\"%"TS"\" optimized size: "), wimfile);
if (new_size == -1)
- puts("Unknown");
+ tfputs(T("Unknown\n"), stdout);
else
- printf("%"PRIu64" KiB\n", new_size >> 10);
+ tprintf(T("%"PRIu64" KiB\n"), new_size >> 10);
- fputs("Space saved: ", stdout);
+ tfputs(T("Space saved: "), stdout);
if (new_size != -1 && old_size != -1) {
- printf("%lld KiB\n",
+ tprintf(T("%lld KiB\n"),
((long long)old_size - (long long)new_size) >> 10);
} else {
- puts("Unknown");
+ tfputs(T("Unknown\n"), stdout);
}
}
}
/* Split a WIM into a spanned set */
-static int imagex_split(int argc, char **argv)
+static int
+imagex_split(int argc, tchar **argv)
{
int c;
int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK;
int write_flags = 0;
unsigned long part_size;
- char *tmp;
+ tchar *tmp;
int ret;
WIMStruct *w;
usage(SPLIT);
return -1;
}
- part_size = strtod(argv[2], &tmp) * (1 << 20);
+ part_size = tstrtod(argv[2], &tmp) * (1 << 20);
if (tmp == argv[2] || *tmp) {
- imagex_error("Invalid part size \"%s\"", argv[2]);
- imagex_error("The part size must be an integer or floating-point number of megabytes.");
+ imagex_error(T("Invalid part size \"%"TS"\""), argv[2]);
+ imagex_error(T("The part size must be an integer or "
+ "floating-point number of megabytes."));
return -1;
}
ret = wimlib_open_wim(argv[0], open_flags, &w, imagex_progress_func);
}
/* Unmounts a mounted WIM image. */
-static int imagex_unmount(int argc, char **argv)
+static int
+imagex_unmount(int argc, tchar **argv)
{
int c;
int unmount_flags = 0;
ret = wimlib_unmount_image(argv[0], unmount_flags,
imagex_progress_func);
if (ret != 0)
- imagex_error("Failed to unmount `%s'", argv[0]);
+ imagex_error(T("Failed to unmount \"%"TS"\""), argv[0]);
return ret;
}
struct imagex_command {
- const char *name;
- int (*func)(int , char **);
+ const tchar *name;
+ int (*func)(int , tchar **);
int cmd;
};
p != &imagex_commands[ARRAY_LEN(imagex_commands)]; p++)
static const struct imagex_command imagex_commands[] = {
- {"append", imagex_capture_or_append, APPEND},
- {"apply", imagex_apply, APPLY},
- {"capture", imagex_capture_or_append, CAPTURE},
- {"delete", imagex_delete, DELETE},
- {"dir", imagex_dir, DIR},
- {"export", imagex_export, EXPORT},
- {"info", imagex_info, INFO},
- {"join", imagex_join, JOIN},
- {"mount", imagex_mount_rw_or_ro, MOUNT},
- {"mountrw", imagex_mount_rw_or_ro, MOUNTRW},
- {"optimize",imagex_optimize, OPTIMIZE},
- {"split", imagex_split, SPLIT},
- {"unmount", imagex_unmount, UNMOUNT},
+ {T("append"), imagex_capture_or_append, APPEND},
+ {T("apply"), imagex_apply, APPLY},
+ {T("capture"), imagex_capture_or_append, CAPTURE},
+ {T("delete"), imagex_delete, DELETE},
+ {T("dir"), imagex_dir, DIR},
+ {T("export"), imagex_export, EXPORT},
+ {T("info"), imagex_info, INFO},
+ {T("join"), imagex_join, JOIN},
+ {T("mount"), imagex_mount_rw_or_ro, MOUNT},
+ {T("mountrw"), imagex_mount_rw_or_ro, MOUNTRW},
+ {T("optimize"),imagex_optimize, OPTIMIZE},
+ {T("split"), imagex_split, SPLIT},
+ {T("unmount"), imagex_unmount, UNMOUNT},
};
-static void version()
+static void
+version()
{
- static const char *s =
- IMAGEX_PROGNAME " (" PACKAGE ") " PACKAGE_VERSION "\n"
- "Copyright (C) 2012, 2013 Eric Biggers\n"
- "License GPLv3+; GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
- "This is free software: you are free to change and redistribute it.\n"
- "There is NO WARRANTY, to the extent permitted by law.\n"
- "\n"
- "Report bugs to "PACKAGE_BUGREPORT".\n";
- fputs(s, stdout);
+ static const tchar *s =
+ T(
+IMAGEX_PROGNAME " (" PACKAGE ") " PACKAGE_VERSION "\n"
+"Copyright (C) 2012, 2013 Eric Biggers\n"
+"License GPLv3+; GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.\n"
+"This is free software: you are free to change and redistribute it.\n"
+"There is NO WARRANTY, to the extent permitted by law.\n"
+"\n"
+"Report bugs to "PACKAGE_BUGREPORT".\n"
+ );
+ tfputs(s, stdout);
}
-static void help_or_version(int argc, char **argv)
+static void
+help_or_version(int argc, tchar **argv)
{
int i;
- const char *p;
+ const tchar *p;
const struct imagex_command *cmd;
for (i = 1; i < argc; i++) {
continue;
if (*p == '-')
p++;
- if (strcmp(p, "help") == 0) {
+ if (!tstrcmp(p, T("help"))) {
for_imagex_command(cmd) {
- if (strcmp(cmd->name, argv[1]) == 0) {
+ if (!tstrcmp(cmd->name, argv[1])) {
usage(cmd->cmd);
exit(0);
}
usage_all();
exit(0);
}
- if (strcmp(p, "version") == 0) {
+ if (!tstrcmp(p, T("version"))) {
version();
exit(0);
}
}
-static void usage(int cmd_type)
+static void
+usage(int cmd_type)
{
const struct imagex_command *cmd;
- printf("Usage: %s", usage_strings[cmd_type]);
+ tprintf(T("Usage:\n%"TS), usage_strings[cmd_type]);
for_imagex_command(cmd) {
- if (cmd->cmd == cmd_type)
- printf("\nTry `man "IMAGEX_PROGNAME"-%s' for more details.\n",
- cmd->name);
+ if (cmd->cmd == cmd_type) {
+ tprintf(T("\nTry `man "IMAGEX_PROGNAME"-%"TS"' "
+ "for more details.\n"), cmd->name);
+ }
}
}
-static void usage_all()
+static void
+usage_all()
{
- puts("IMAGEX: Usage:");
+ tfputs(T("Usage:\n"), stdout);
for (int i = 0; i < ARRAY_LEN(usage_strings); i++)
- printf(" %s", usage_strings[i]);
- static const char *extra =
+ tprintf(T(" %"TS), usage_strings[i]);
+ static const tchar *extra =
+ T(
" "IMAGEX_PROGNAME" --help\n"
" "IMAGEX_PROGNAME" --version\n"
"\n"
" The compression TYPE may be \"maximum\", \"fast\", or \"none\".\n"
"\n"
" Try `man "IMAGEX_PROGNAME"' for more information.\n"
- ;
- fputs(extra, stdout);
+ );
+ tfputs(extra, stdout);
}
-/* Entry point for wimlib's ImageX implementation */
-int main(int argc, char **argv)
+/* Entry point for wimlib's ImageX implementation. On UNIX the command
+ * arguments will just be 'char' strings (ideally UTF-8 encoded, but could be
+ * something else), while an Windows the command arguments will be UTF-16LE
+ * encoded 'wchar_t' strings. */
+int
+#ifdef __WIN32__
+wmain(int argc, wchar_t **argv, wchar_t **envp)
+#else
+main(int argc, char **argv)
+#endif
{
const struct imagex_command *cmd;
int ret;
+#ifndef __WIN32__
setlocale(LC_ALL, "");
+ {
+ char *codeset = nl_langinfo(CODESET);
+ if (!strstr(codeset, "UTF-8") &&
+ !strstr(codeset, "UTF8") &&
+ !strstr(codeset, "utf-8") &&
+ !strstr(codeset, "utf8"))
+ {
+ fputs(
+"WARNING: Running "IMAGEX_PROGNAME" in a UTF-8 locale is recommended!\n"
+" (Maybe try: `export LANG=en_US.UTF-8'?\n", stderr);
+
+ }
+ }
+#endif /* !__WIN32__ */
if (argc < 2) {
- imagex_error("No command specified");
+ imagex_error(T("No command specified"));
usage_all();
return 1;
}
/* Search for the function to handle the ImageX subcommand. */
for_imagex_command(cmd) {
- if (strcmp(cmd->name, *argv) == 0) {
+ if (!tstrcmp(cmd->name, *argv)) {
ret = cmd->func(argc, argv);
goto out_check_write_error;
}
}
- imagex_error("Unrecognized command: `%s'", argv[0]);
+ imagex_error(T("Unrecognized command: `%"TS"'"), argv[0]);
usage_all();
return 1;
out_check_write_error:
* there was a write error. */
if (cmd == &imagex_commands[INFO] || cmd == &imagex_commands[DIR]) {
if (ferror(stdout) || fclose(stdout)) {
- imagex_error_with_errno("output error");
+ imagex_error_with_errno(T("output error"));
if (ret == 0)
ret = -1;
}
* indicates a wimlib error code from which an error message can be
* printed. */
if (ret > 0) {
- imagex_error("Exiting with error code %d:\n"
- " %s.", ret,
+ imagex_error(T("Exiting with error code %d:\n"
+ " %"TS"."), ret,
wimlib_get_error_string(ret));
if (ret == WIMLIB_ERR_NTFS_3G && errno != 0)
- imagex_error_with_errno("errno");
+ imagex_error_with_errno(T("errno"));
}
/* Make the library free any resources it's holding (not strictly
--- /dev/null
+/*
+ * wgetopt.c: Wide-character versions of getopt, getopt_long, and
+ * getopt_long_only.
+ *
+ * This has been modified from the original, which is
+ * Copyright (C) 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995, 1996,
+ * 1997, 1998, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
+ * 2010 Free Software Foundation, Inc.
+ *
+ * This file is part of wimlib, a library for working with WIM files.
+ *
+ * wimlib is free software; you can redistribute it and/or modify it under the
+ * terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at your option)
+ * any later version.
+ *
+ * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
+ * A PARTICULAR PURPOSE. See the GNU General Public License for more
+ * details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with wimlib; if not, see http://www.gnu.org/licenses/.
+ */
+
+#include "wgetopt.h"
+#include <stdlib.h>
+#include <stdio.h>
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+wchar_t *woptarg = NULL;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns -1, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `woptind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* 1003.2 says this must be 1 before any call. */
+int woptind = 1;
+
+/* Formerly, initialization of getopt depended on woptind==0, which
+ causes problems with re-calling getopt as programs generally don't
+ know that. */
+
+int __getopt_initialized = 0;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static wchar_t *nextchar;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int wopterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int woptopt = '?';
+
+/* Describe how to deal with options that follow non-option ARGV-elements.
+
+ If the caller did not specify anything,
+ the default is REQUIRE_ORDER if the environment variable
+ POSIXLY_CORRECT is defined, PERMUTE otherwise.
+
+ REQUIRE_ORDER means don't recognize them as options;
+ stop option processing when the first non-option is seen.
+ This is what Unix does.
+ This mode of operation is selected by either setting the environment
+ variable POSIXLY_CORRECT, or using `+' as the first character
+ of the list of option characters.
+
+ PERMUTE is the default. We permute the contents of ARGV as we scan,
+ so that eventually all the non-options are at the end. This allows options
+ to be given in any order, even with programs that were not written to
+ expect this.
+
+ RETURN_IN_ORDER is an option available to programs that were written
+ to expect options and other ARGV-elements in any order and that care about
+ the ordering of the two. We describe each non-option ARGV-element
+ as if it were the argument of an option with character code 1.
+ Using `-' as the first character of the list of option characters
+ selects this mode of operation.
+
+ The special argument `--' forces an end of option-scanning regardless
+ of the value of `ordering'. In the case of RETURN_IN_ORDER, only
+ `--' can cause `getopt' to return -1 with `woptind' != ARGC. */
+
+static enum
+{
+ REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
+} ordering;
+
+/* Value of POSIXLY_CORRECT environment variable. */
+static char *posixly_correct;
+
+
+/* Handle permutation of arguments. */
+
+/* Describe the part of ARGV that contains non-options that have
+ been skipped. `first_nonopt' is the index in ARGV of the first of them;
+ `last_nonopt' is the index after the last of them. */
+
+static int first_nonopt;
+static int last_nonopt;
+
+/* Exchange two adjacent subsequences of ARGV.
+ One subsequence is elements [first_nonopt,last_nonopt)
+ which contains all the non-options that have been skipped so far.
+ The other is elements [last_nonopt,woptind), which contains all
+ the options processed since those non-options were skipped.
+
+ `first_nonopt' and `last_nonopt' are relocated so that they describe
+ the new indices of the non-options in ARGV after they are moved. */
+
+static void
+exchange (wchar_t **argv)
+{
+ int bottom = first_nonopt;
+ int middle = last_nonopt;
+ int top = woptind;
+ wchar_t *tem;
+
+ /* Exchange the shorter segment with the far end of the longer segment.
+ That puts the shorter segment into the right place.
+ It leaves the longer segment in the right place overall,
+ but it consists of two parts that need to be swapped next. */
+
+ while (top > middle && middle > bottom)
+ {
+ if (top - middle > middle - bottom)
+ {
+ /* Bottom segment is the short one. */
+ int len = middle - bottom;
+ register int i;
+
+ /* Swap it with the top part of the top segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[top - (middle - bottom) + i];
+ argv[top - (middle - bottom) + i] = tem;
+ }
+ /* Exclude the moved bottom segment from further swapping. */
+ top -= len;
+ }
+ else
+ {
+ /* Top segment is the short one. */
+ int len = top - middle;
+ register int i;
+
+ /* Swap it with the bottom part of the bottom segment. */
+ for (i = 0; i < len; i++)
+ {
+ tem = argv[bottom + i];
+ argv[bottom + i] = argv[middle + i];
+ argv[middle + i] = tem;
+ }
+ /* Exclude the moved top segment from further swapping. */
+ bottom += len;
+ }
+ }
+
+ /* Update records for the slots the non-options now occupy. */
+
+ first_nonopt += (woptind - last_nonopt);
+ last_nonopt = woptind;
+}
+
+/* Initialize the internal data when the first call is made. */
+
+static const wchar_t *
+_getopt_initialize (int argc, wchar_t *const *argv, const wchar_t *optstring)
+{
+ /* Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ first_nonopt = last_nonopt = woptind;
+
+ nextchar = NULL;
+
+ posixly_correct = getenv ("POSIXLY_CORRECT");
+
+ /* Determine how to handle the ordering of options and nonoptions. */
+
+ if (optstring[0] == L'-')
+ {
+ ordering = RETURN_IN_ORDER;
+ ++optstring;
+ }
+ else if (optstring[0] == L'+')
+ {
+ ordering = REQUIRE_ORDER;
+ ++optstring;
+ }
+ else if (posixly_correct != NULL)
+ ordering = REQUIRE_ORDER;
+ else
+ ordering = PERMUTE;
+
+ return optstring;
+}
+\f
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `getopt' finds another option character, it returns that character,
+ updating `woptind' and `nextchar' so that the next call to `getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `getopt' returns -1.
+ Then `woptind' is the index in ARGV of the first ARGV-element
+ that is not an option. (The ARGV-elements have been permuted
+ so that those that are not options now come last.)
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `wopterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `woptarg'. Two colons mean an option that
+ wants an optional arg; if there is text in the current ARGV-element,
+ it is returned in `woptarg', otherwise `woptarg' is set to zero.
+
+ If OPTSTRING starts with `-' or `+', it requests different methods of
+ handling the non-option ARGV-elements.
+ See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
+
+ Long-named options begin with `--' instead of `-'.
+ Their names may be abbreviated as long as the abbreviation is unique
+ or is an exact match for some defined option. If they have an
+ argument, it follows the option name in the same ARGV-element, separated
+ from the option name by a `=', or else the in next ARGV-element.
+ When `getopt' finds a long-named option, it returns 0 if that option's
+ `flag' field is nonzero, the value of the option's `val' field
+ if the `flag' field is zero.
+
+ The elements of ARGV aren't really const, because we permute them.
+ But we pretend they're const in the prototype to be compatible
+ with other systems.
+
+ LONGOPTS is a vector of `struct woption' terminated by an
+ element containing a name which is zero.
+
+ LONGIND returns the index in LONGOPT of the long-named option found.
+ It is only valid when a long-named option has been found by the most
+ recent call.
+
+ If LONG_ONLY is nonzero, '-' as well as '--' can introduce
+ long-named options. */
+
+int
+_wgetopt_internal (int argc, wchar_t *const *argv, const wchar_t *optstring,
+ const struct woption *longopts, int *longind, int long_only)
+{
+ woptarg = NULL;
+
+ if (woptind == 0 || !__getopt_initialized)
+ {
+ if (woptind == 0)
+ woptind = 1; /* Don't scan ARGV[0], the program name. */
+ optstring = _getopt_initialize (argc, argv, optstring);
+ __getopt_initialized = 1;
+ }
+
+ /* Test whether ARGV[woptind] points to a non-option argument.
+ Either it does not have option syntax, or there is an environment flag
+ from the shell indicating it is not an option. The later information
+ is only used when the used in the GNU libc. */
+# define NONOPTION_P (argv[woptind][0] != L'-' || argv[woptind][1] == L'\0')
+
+ if (nextchar == NULL || *nextchar == '\0')
+ {
+ /* Advance to the next ARGV-element. */
+
+ /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
+ moved back by the user (who may also have changed the arguments). */
+ if (last_nonopt > woptind)
+ last_nonopt = woptind;
+ if (first_nonopt > woptind)
+ first_nonopt = woptind;
+
+ if (ordering == PERMUTE)
+ {
+ /* If we have just processed some options following some non-options,
+ exchange them so that the options come first. */
+
+ if (first_nonopt != last_nonopt && last_nonopt != woptind)
+ exchange ((wchar_t **) argv);
+ else if (last_nonopt != woptind)
+ first_nonopt = woptind;
+
+ /* Skip any additional non-options
+ and extend the range of non-options previously skipped. */
+
+ while (woptind < argc && NONOPTION_P)
+ woptind++;
+ last_nonopt = woptind;
+ }
+
+ /* The special ARGV-element `--' means premature end of options.
+ Skip it like a null option,
+ then exchange with previous non-options as if it were an option,
+ then skip everything else like a non-option. */
+
+ if (woptind != argc && !wcscmp (argv[woptind], L"--"))
+ {
+ woptind++;
+
+ if (first_nonopt != last_nonopt && last_nonopt != woptind)
+ exchange ((wchar_t **) argv);
+ else if (first_nonopt == last_nonopt)
+ first_nonopt = woptind;
+ last_nonopt = argc;
+
+ woptind = argc;
+ }
+
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+
+ if (woptind == argc)
+ {
+ /* Set the next-arg-index to point at the non-options
+ that we previously skipped, so the caller will digest them. */
+ if (first_nonopt != last_nonopt)
+ woptind = first_nonopt;
+ return -1;
+ }
+
+ /* If we have come to a non-option and did not permute it,
+ either stop the scan or describe it to the caller and pass it by. */
+
+ if (NONOPTION_P)
+ {
+ if (ordering == REQUIRE_ORDER)
+ return -1;
+ woptarg = argv[woptind++];
+ return 1;
+ }
+
+ /* We have found another option-ARGV-element.
+ Skip the initial punctuation. */
+
+ nextchar = (argv[woptind] + 1
+ + (longopts != NULL && argv[woptind][1] == L'-'));
+ }
+
+ /* Decode the current option-ARGV-element. */
+
+ /* Check whether the ARGV-element is a long option.
+
+ If long_only and the ARGV-element has the form "-f", where f is
+ a valid short option, don't consider it an abbreviated form of
+ a long option that starts with f. Otherwise there would be no
+ way to give the -f short option.
+
+ On the other hand, if there's a long option "fubar" and
+ the ARGV-element is "-fu", do consider that an abbreviation of
+ the long option, just like "--fu", and not "-f" with arg "u".
+
+ This distinction seems to be the most useful approach. */
+
+ if (longopts != NULL
+ && (argv[woptind][1] == L'-'
+ || (long_only && (argv[woptind][2] || !wcschr (optstring, argv[woptind][1])))))
+ {
+ wchar_t *nameend;
+ const struct woption *p;
+ const struct woption *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = -1;
+ int option_index;
+
+ for (nameend = nextchar; *nameend && *nameend != L'='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!wcsncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar)
+ == (unsigned int) wcslen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+
+ if (ambig && !exact)
+ {
+ if (wopterr)
+ fwprintf (stderr, L"%ls: option `%ls' is ambiguous\n",
+ argv[0], argv[woptind]);
+ nextchar += wcslen (nextchar);
+ woptind++;
+ woptopt = 0;
+ return L'?';
+ }
+
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ woptind++;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ woptarg = nameend + 1;
+ else
+ {
+ if (wopterr) {
+ if (argv[woptind - 1][1] == L'-')
+ /* --option */
+ fwprintf (stderr,
+ L"%ls: option `--%ls' doesn't allow an argument\n",
+ argv[0], pfound->name);
+ else
+ /* +option or -option */
+ fwprintf (stderr,
+ L"%ls: option `%lc%ls' doesn't allow an argument\n",
+ argv[0], argv[woptind - 1][0], pfound->name);
+ }
+
+ nextchar += wcslen (nextchar);
+
+ woptopt = pfound->val;
+ return L'?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (woptind < argc)
+ woptarg = argv[woptind++];
+ else
+ {
+ if (wopterr)
+ fwprintf (stderr,
+ L"%ls: option `%ls' requires an argument\n",
+ argv[0], argv[woptind - 1]);
+ nextchar += wcslen (nextchar);
+ woptopt = pfound->val;
+ return optstring[0] == L':' ? L':' : L'?';
+ }
+ }
+ nextchar += wcslen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+
+ /* Can't find it as a long option. If this is not getopt_long_only,
+ or the option starts with '--' or is not a valid short
+ option, then it's an error.
+ Otherwise interpret it as a short option. */
+ if (!long_only || argv[woptind][1] == L'-'
+ || wcschr (optstring, *nextchar) == NULL)
+ {
+ if (wopterr)
+ {
+ if (argv[woptind][1] == '-')
+ /* --option */
+ fwprintf (stderr, L"%ls: unrecognized option `--%ls'\n",
+ argv[0], nextchar);
+ else
+ /* +option or -option */
+ fwprintf (stderr, L"%ls: unrecognized option `%lc%ls'\n",
+ argv[0], argv[woptind][0], nextchar);
+ }
+ nextchar = (wchar_t *) L"";
+ woptind++;
+ woptopt = 0;
+ return L'?';
+ }
+ }
+
+ /* Look at and handle the next short option-character. */
+
+ {
+ wchar_t c = *nextchar++;
+ wchar_t *temp = wcschr (optstring, c);
+
+ /* Increment `woptind' when we start to process its last character. */
+ if (*nextchar == L'\0')
+ ++woptind;
+
+ if (temp == NULL || c == L':')
+ {
+ if (wopterr)
+ {
+ if (posixly_correct)
+ /* 1003.2 specifies the format of this message. */
+ fwprintf (stderr, L"%ls: illegal option -- %lc\n",
+ argv[0], c);
+ else
+ fwprintf (stderr, L"%ls: invalid option -- %lc\n",
+ argv[0], c);
+ }
+ woptopt = c;
+ return L'?';
+ }
+ /* Convenience. Treat POSIX -W foo same as long option --foo */
+ if (temp[0] == L'W' && temp[1] == L';')
+ {
+ wchar_t *nameend;
+ const struct woption *p;
+ const struct woption *pfound = NULL;
+ int exact = 0;
+ int ambig = 0;
+ int indfound = 0;
+ int option_index;
+
+ /* This is an option that requires an argument. */
+ if (*nextchar != L'\0')
+ {
+ woptarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ woptind++;
+ }
+ else if (woptind == argc)
+ {
+ if (wopterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fwprintf (stderr, L"%ls: option requires an argument -- %lc\n",
+ argv[0], c);
+ }
+ woptopt = c;
+ if (optstring[0] == L':')
+ c = L':';
+ else
+ c = L'?';
+ return c;
+ }
+ else
+ /* We already incremented `woptind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ woptarg = argv[woptind++];
+
+ /* woptarg is now the argument, see if it's in the
+ table of longopts. */
+
+ for (nextchar = nameend = woptarg; *nameend && *nameend != L'='; nameend++)
+ /* Do nothing. */ ;
+
+ /* Test all long options for either exact match
+ or abbreviated matches. */
+ for (p = longopts, option_index = 0; p->name; p++, option_index++)
+ if (!wcsncmp (p->name, nextchar, nameend - nextchar))
+ {
+ if ((unsigned int) (nameend - nextchar) == wcslen (p->name))
+ {
+ /* Exact match found. */
+ pfound = p;
+ indfound = option_index;
+ exact = 1;
+ break;
+ }
+ else if (pfound == NULL)
+ {
+ /* First nonexact match found. */
+ pfound = p;
+ indfound = option_index;
+ }
+ else
+ /* Second or later nonexact match found. */
+ ambig = 1;
+ }
+ if (ambig && !exact)
+ {
+ if (wopterr)
+ fwprintf (stderr, L"%ls: option `-W %ls' is ambiguous\n",
+ argv[0], argv[woptind]);
+ nextchar += wcslen (nextchar);
+ woptind++;
+ return L'?';
+ }
+ if (pfound != NULL)
+ {
+ option_index = indfound;
+ if (*nameend)
+ {
+ /* Don't test has_arg with >, because some C compilers don't
+ allow it to be used on enums. */
+ if (pfound->has_arg)
+ woptarg = nameend + 1;
+ else
+ {
+ if (wopterr)
+ fwprintf (stderr, L"\
+%ls: option `-W %ls' doesn't allow an argument\n",
+ argv[0], pfound->name);
+
+ nextchar += wcslen (nextchar);
+ return L'?';
+ }
+ }
+ else if (pfound->has_arg == 1)
+ {
+ if (woptind < argc)
+ woptarg = argv[woptind++];
+ else
+ {
+ if (wopterr)
+ fwprintf (stderr,
+ L"%ls: option `%ls' requires an argument\n",
+ argv[0], argv[woptind - 1]);
+ nextchar += wcslen (nextchar);
+ return optstring[0] == L':' ? L':' : L'?';
+ }
+ }
+ nextchar += wcslen (nextchar);
+ if (longind != NULL)
+ *longind = option_index;
+ if (pfound->flag)
+ {
+ *(pfound->flag) = pfound->val;
+ return 0;
+ }
+ return pfound->val;
+ }
+ nextchar = NULL;
+ return L'W'; /* Let the application handle it. */
+ }
+ if (temp[1] == L':')
+ {
+ if (temp[2] == L':')
+ {
+ /* This is an option that accepts an argument optionally. */
+ if (*nextchar != L'\0')
+ {
+ woptarg = nextchar;
+ woptind++;
+ }
+ else
+ woptarg = NULL;
+ nextchar = NULL;
+ }
+ else
+ {
+ /* This is an option that requires an argument. */
+ if (*nextchar != L'\0')
+ {
+ woptarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ woptind++;
+ }
+ else if (woptind == argc)
+ {
+ if (wopterr)
+ {
+ /* 1003.2 specifies the format of this message. */
+ fwprintf (stderr,
+ L"%ls: option requires an argument -- %lc\n",
+ argv[0], c);
+ }
+ woptopt = c;
+ if (optstring[0] == L':')
+ c = L':';
+ else
+ c = L'?';
+ }
+ else
+ /* We already incremented `woptind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ woptarg = argv[woptind++];
+ nextchar = NULL;
+ }
+ }
+ return c;
+ }
+}
+
+int
+wgetopt (int argc, wchar_t *const *argv, const wchar_t *optstring)
+{
+ return _wgetopt_internal (argc, argv, optstring,
+ (const struct woption *) 0,
+ (int *) 0,
+ 0);
+}
+
+int
+wgetopt_long (int argc, wchar_t * const *argv, const wchar_t *options,
+ const struct woption *long_options, int *opt_index)
+{
+ return _wgetopt_internal (argc, argv, options, long_options, opt_index, 0);
+}
+
+/* Like getopt_long, but '-' as well as '--' can indicate a long option.
+ If an option that starts with '-' (not '--') doesn't match a long option,
+ but does match a short option, it is parsed as a short option
+ instead. */
+int
+wgetopt_long_only (int argc, wchar_t * const *argv, const wchar_t *options,
+ const struct woption *long_options, int *opt_index)
+{
+ return _wgetopt_internal (argc, argv, options, long_options, opt_index, 1);
+}
--- /dev/null
+#ifndef _WGETOPT_H
+#define _WGETOPT_H
+
+#include <wchar.h>
+
+extern wchar_t *woptarg;
+extern int woptind, wopterr, woptopt;
+
+struct woption {
+ const wchar_t *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+#define no_argument 0
+#define required_argument 1
+#define optional_argument 2
+
+extern int
+wgetopt (int argc, wchar_t *const *argv, const wchar_t *optstring);
+
+extern int
+wgetopt_long(int argc, wchar_t * const *argv, const wchar_t *options,
+ const struct woption *long_options, int *opt_index);
+
+extern int
+wgetopt_long_only(int argc, wchar_t *const *argv, const wchar_t *options,
+ const struct woption *long_options, int *opt_index);
+
+#endif
#include <ctype.h>
#include <errno.h>
#include <stdlib.h>
-
-#if TCHAR_IS_UTF16LE
-# include <wchar.h>
-#else
-# include <string.h>
-#endif
+#include <string.h>
#include <unistd.h>
unix_build_dentry_tree(struct wim_dentry **root_ret,
const char *root_disk_path,
struct wim_lookup_table *lookup_table,
- struct sd_set *sd,
+ struct sd_set *sd_set,
const struct capture_config *config,
int add_image_flags,
wimlib_progress_func_t progress_func,
if (*pp == T('\\'))
*pp = T('/');
- /* Remove drive letter
- * XXX maybe keep drive letter on Windows */
+ /* Remove drive letter (UNIX only) */
+ #ifndef __WIN32__
if (eol - p > 2 && istalpha(*p) && *(p + 1) == T(':'))
p += 2;
+ #endif
ret = 0;
- if (tstrcmp(p, T("[ExclusionList]")) == 0)
+ if (!tstrcmp(p, T("[ExclusionList]")))
type = EXCLUSION_LIST;
- else if (tstrcmp(p, T("[ExclusionException]")) == 0)
+ else if (!tstrcmp(p, T("[ExclusionException]")))
type = EXCLUSION_EXCEPTION;
- else if (tstrcmp(p, T("[CompressionExclusionList]")) == 0)
+ else if (!tstrcmp(p, T("[CompressionExclusionList]")))
type = COMPRESSION_EXCLUSION_LIST;
- else if (tstrcmp(p, T("[AlignmentList]")) == 0)
+ else if (!tstrcmp(p, T("[AlignmentList]")))
type = ALIGNMENT_LIST;
else if (p[0] == T('[') && tstrrchr(p, T(']'))) {
ERROR("Unknown capture configuration section \"%"TS"\"", p);
const tchar *basename = path_basename(path);
if (exclude_prefix) {
wimlib_assert(tstrlen(path) >= config->prefix_num_tchars);
- if (tmemcmp(config->prefix, path, config->prefix_num_tchars) == 0
- && path[config->prefix_num_tchars] == T('/'))
+ if (!tmemcmp(config->prefix, path, config->prefix_num_tchars) &&
+ path[config->prefix_num_tchars] == T('/'))
+ {
path += config->prefix_num_tchars;
+ }
}
return match_pattern(path, basename, &config->exclusion_list) &&
!match_pattern(path, basename, &config->exclusion_exception);
break;
}
- p = target_path + tstrlen(target_path) - 1;
+ p = tstrchr(target_path, T('\0')) - 1;
while (*p == T('/'))
*p-- = T('\0');
return target_path;
}
-static void
-zap_backslashes(tchar *s)
-{
- while (*s) {
- if (*s == T('\\'))
- *s = T('/');
- s++;
- }
-}
-
/* Strip leading and trailing slashes from the target paths */
static void
canonicalize_targets(struct wimlib_capture_source *sources, size_t num_sources)
"(the NTFS volume) in NTFS mode!");
return WIMLIB_ERR_INVALID_PARAM;
}
- if (sources[0].wim_target_path[0] != '\0') {
+ if (sources[0].wim_target_path[0] != T('\0')) {
ERROR("In NTFS capture mode the target path inside "
"the image must be the root directory!");
return WIMLIB_ERR_INVALID_PARAM;
* */
parent = *root_p;
while ((slash = tstrchr(target_path, T('/')))) {
- *slash = '\0';
+ *slash = T('\0');
dentry = get_dentry_child_with_name(parent, target_path);
if (!dentry) {
ret = new_filler_directory(target_path, &dentry);
destroy_image_metadata(&w->image_metadata[w->hdr.image_count - 1],
w->lookup_table);
w->hdr.image_count--;
- goto out;
+ goto out_destroy_sd_set;
out_free_branch:
free_dentry_tree(branch, w->lookup_table);
out_free_dentry_tree:
#include "wimlib_internal.h"
#include <errno.h>
-#ifdef TCHAR_IS_UTF16LE
-# include <wchar.h>
-#endif
-
/* Calculates the unaligned length, in bytes, of an on-disk WIM dentry that has
* a file name and short name that take the specified numbers of bytes. This
* excludes any alternate data stream entries that may follow the dentry. */
size_t name_utf16le_nbytes;
int ret;
#if TCHAR_IS_UTF16LE
- name_utf16le_nbytes = tstrlen(name) * 2;
- name_utf16le = MALLOC(name_utf16le_nbytes + 2);
+ name_utf16le_nbytes = tstrlen(name) * sizeof(utf16lechar);
+ name_utf16le = MALLOC(name_utf16le_nbytes + sizeof(utf16lechar));
if (!name_utf16le)
return WIMLIB_ERR_NOMEM;
- memcpy(name_utf16le, name, name_utf16le_nbytes + 2);
+ memcpy(name_utf16le, name, name_utf16le_nbytes + sizeof(utf16lechar));
ret = 0;
#else
- ret = tstr_to_utf16le(name, strlen(name), &name_utf16le,
+ ret = tstr_to_utf16le(name, tstrlen(name), &name_utf16le,
&name_utf16le_nbytes);
if (ret == 0) {
if (name_utf16le_nbytes > 0xffff) {
FREE(name_utf16le);
- ERROR("Multibyte string \"%s\" is too long!", name);
+ ERROR("Multibyte string \"%"TS"\" is too long!", name);
ret = WIMLIB_ERR_INVALID_UTF8_STRING;
}
}
}
/* Calculate the full path of @dentry. The full path of its parent must have
- * already been calculated. */
+ * already been calculated, or it must be the root dentry. */
int
calculate_dentry_full_path(struct wim_dentry *dentry, void *ignore)
{
dentry->parent->full_path != NULL);
if (dentry_is_root(dentry)) {
- full_path = TMALLOC(2);
+ full_path = TSTRDUP(T("/"));
if (!full_path)
return WIMLIB_ERR_NOMEM;
- full_path[0] = T('/');
- full_path[1] = T('\0');
full_path_nbytes = 1 * sizeof(tchar);
} else {
+ const struct wim_dentry *parent;
tchar *parent_full_path;
u32 parent_full_path_nbytes;
- const struct wim_dentry *parent;
size_t filename_nbytes;
- int ret;
parent = dentry->parent;
if (dentry_is_root(parent)) {
parent_full_path = parent->full_path;
parent_full_path_nbytes = parent->full_path_nbytes;
}
+
+ /* Append this dentry's name as a tchar string to the full path
+ * of the parent followed by the path separator */
#if TCHAR_IS_UTF16LE
filename_nbytes = dentry->file_name_nbytes;
#else
- ret = utf16le_to_mbs_nbytes(dentry->file_name,
- dentry->file_name_nbytes,
- &filename_nbytes);
- if (ret)
- return ret;
+ {
+ int ret = utf16le_to_tstr_nbytes(dentry->file_name,
+ dentry->file_name_nbytes,
+ &filename_nbytes);
+ if (ret)
+ return ret;
+ }
#endif
full_path_nbytes = parent_full_path_nbytes + sizeof(tchar) +
- dentry->file_name_nbytes;
+ filename_nbytes;
full_path = MALLOC(full_path_nbytes + sizeof(tchar));
if (!full_path)
return WIMLIB_ERR_NOMEM;
memcpy(full_path, parent_full_path, parent_full_path_nbytes);
- full_path[parent_full_path_nbytes] = T('/');
+ full_path[parent_full_path_nbytes / sizeof(tchar)] = T('/');
#if TCHAR_IS_UTF16LE
- memcpy(&full_path[parent_full_path_nbytes + 1],
+ memcpy(&full_path[parent_full_path_nbytes / sizeof(tchar) + 1],
dentry->file_name,
- dentry->file_name_nbytes + sizeof(tchar));
+ filename_nbytes + sizeof(tchar));
#else
- utf16le_to_mbs_buf(dentry->file_name,
- dentry->file_name_nbytes,
- &full_path[parent_full_path_nbytes + 1]);
+ utf16le_to_tstr_buf(dentry->file_name,
+ dentry->file_name_nbytes,
+ &full_path[parent_full_path_nbytes /
+ sizeof(tchar) + 1]);
#endif
}
FREE(dentry->full_path);
int ret;
struct wim_dentry *child;
- ret = tstr_to_utf16le(name, strlen(name),
+ ret = tstr_to_utf16le(name, tstrlen(name) * sizeof(tchar),
&utf16le_name, &utf16le_name_nbytes);
if (ret) {
child = NULL;
struct wim_dentry *cur_dentry, *parent_dentry;
const utf16lechar *p, *pp;
- parent_dentry = wim_root_dentry(w);
+ cur_dentry = parent_dentry = wim_root_dentry(w);
p = path;
while (1) {
while (*p == cpu_to_le16('/'))
p++;
- cur_dentry = parent_dentry;
if (*p == '\0')
break;
pp = p;
return NULL;
dentry = get_dentry_utf16le(w, path_utf16le, path_utf16le_nbytes);
FREE(path_utf16le);
- return cur_dentry;
+ return dentry;
#endif
}
return NULL;
}
+/* Takes in a path of length @len in @buf, and transforms it into a string for
+ * the path of its parent directory. */
+static void
+to_parent_name(tchar *buf, size_t len)
+{
+ ssize_t i = (ssize_t)len - 1;
+ while (i >= 0 && buf[i] == T('/'))
+ i--;
+ while (i >= 0 && buf[i] != T('/'))
+ i--;
+ while (i >= 0 && buf[i] == T('/'))
+ i--;
+ buf[i + 1] = T('\0');
+}
+
/* Returns the dentry that corresponds to the parent directory of @path, or NULL
* if the dentry is not found. */
struct wim_dentry *
print_dentry_full_path(struct wim_dentry *dentry, void *ignore)
{
if (dentry->full_path)
- printf("%"TS"\n", dentry->full_path);
+ tprintf(T("%"TS"\n"), dentry->full_path);
return 0;
}
if (dentry_has_short_name(dentry))
wimlib_printf(T("Short Name \"%"WS"\"\n"), dentry->short_name);
if (dentry->full_path)
- tprintf(T("Full Path = \"%"WS"\"\n"), dentry->full_path);
+ tprintf(T("Full Path = \"%"TS"\"\n"), dentry->full_path);
lte = inode_stream_lte(dentry->d_inode, 0, lookup_table);
if (lte) {
}
/* Creates an unlinked directory entry. */
-int new_dentry(const tchar *name, struct wim_dentry **dentry_ret)
+int
+new_dentry(const tchar *name, struct wim_dentry **dentry_ret)
{
struct wim_dentry *dentry;
int ret;
if (inode->i_num_ads == 0) {
return NULL;
} else {
- int ret;
size_t stream_name_utf16le_nbytes;
u16 i;
struct wim_ads_entry *result;
#else
utf16lechar *stream_name_utf16le;
- ret = tstr_to_utf16le(stream_name, tstrlen(stream_name) * sizeof(tchar),
- &stream_name_utf16le,
- &stream_name_utf16le_nbytes);
- if (ret)
- return NULL;
+ {
+ int ret = tstr_to_utf16le(stream_name,
+ tstrlen(stream_name) *
+ sizeof(tchar),
+ &stream_name_utf16le,
+ &stream_name_utf16le_nbytes);
+ if (ret)
+ return NULL;
+ }
#endif
i = 0;
result = NULL;
* u64 reserved1; (always 0)
* u64 reserved2; (always 0)
* };*/
- /*DEBUG("Dentry for file or directory `%s' has %"PRIu64" extra "*/
- /*"bytes of data",*/
- /*file_name_utf8, dentry->length - calculated_size);*/
+ /*DEBUG("Dentry for file or directory `%"WS"' has %"PRIu64" "*/
+ /*"extra bytes of data", file_name,*/
+ /*dentry->length - calculated_size);*/
}
/* Read the short filename if present. Note: if there is no short
u16 file_name_nbytes;
/* Length of full path name encoded using "tchars", in bytes, not
- * including the terminating null terminator. */
+ * including the terminating null character. */
u32 full_path_nbytes;
+ /* Has this dentry been extracted yet? */
u8 is_extracted : 1;
/* Only used during NTFS capture */
/*
- * encoding.c: Convert "multibyte" strings (the locale-default encoding---
- * generally, UTF-8 or something like ISO-8859-1) to UTF-16LE strings, and vice
- * versa. Also, convert UTF-8 strings to multibyte strings.
+ * encoding.c
*/
/*
earlyreturn, \
worst_case_len_expr, \
err_return, \
- err_msg) \
+ err_msg, \
+ modifier) \
static ICONV_LIST(iconv_##varname1##_to_##varname2, \
longname1, longname2); \
\
-int \
+modifier int \
varname1##_to_##varname2##_nbytes(const chartype1 *in, size_t in_nbytes,\
size_t *out_nbytes_ret) \
{ \
return ret; \
} \
\
-int \
+modifier int \
varname1##_to_##varname2##_buf(const chartype1 *in, size_t in_nbytes, \
chartype2 *out) \
{ \
return ret; \
} \
\
-int \
+modifier int \
varname1##_to_##varname2(const chartype1 *in, size_t in_nbytes, \
chartype2 **out_ret, \
size_t *out_nbytes_ret) \
return ret; \
}
-#if 0
-DEFINE_CHAR_CONVERSION_FUNCTIONS(utf16le, "UTF-16LE", utf16lechar,
- mbs, "", mbchar,
- false,
- in_nbytes / 2 * MB_CUR_MAX,
- WIMLIB_ERR_UNICODE_STRING_NOT_REPRESENTABLE,
- ERROR("Failed to convert UTF-16LE string "
- "to multibyte string!");
- ERROR("This may be because the UTF-16LE data "
- "could not be represented in your "
- "locale's character encoding."))
-#endif
-
#if !TCHAR_IS_UTF16LE
DEFINE_CHAR_CONVERSION_FUNCTIONS(tstr, "", tchar,
utf16le, "UTF-16LE", utf16lechar,
false,
- in_nbytes * 2,
+ in_nbytes * 4,
WIMLIB_ERR_INVALID_MULTIBYTE_STRING,
ERROR_WITH_ERRNO("Failed to convert multibyte "
"string \"%"TS"\" to UTF-16LE string!", in);
ERROR("If the data you provided was UTF-8, please make sure "
- "the character encoding of your current locale is UTF-8."))
+ "the character encoding of your current locale is UTF-8."),
+ )
+
+DEFINE_CHAR_CONVERSION_FUNCTIONS(utf16le, "UTF-16LE", utf16lechar,
+ tstr, "", tchar,
+ false,
+ in_nbytes * 2,
+ WIMLIB_ERR_UNICODE_STRING_NOT_REPRESENTABLE,
+ ERROR("Failed to convert UTF-16LE string to "
+ "multibyte string!");
+ ERROR("This may be because the UTF-16LE string "
+ "could not be represented in your "
+ "locale's character encoding."),
+ )
#endif
/* tchar to UTF-8 and back */
#if TCHAR_IS_UTF16LE
DEFINE_CHAR_CONVERSION_FUNCTIONS(tstr, "UTF16-LE", tchar,
- utf8, "UTF-8", utf8char,
+ utf8, "UTF-8", char,
false,
in_nbytes * 2,
- WIMLIB_ERR_INVALID_MULTIBYTE_STRING,
+ WIMLIB_ERR_INVALID_UTF16_STRING,
ERROR_WITH_ERRNO("Failed to convert UTF-16LE "
- "string \"%"TS"\" to UTF-8 string!", in);
- )
+ "string \"%"TS"\" to UTF-8 string!", in),
+ static)
-DEFINE_CHAR_CONVERSION_FUNCTIONS(utf8, "UTF-8", utf8char,
+DEFINE_CHAR_CONVERSION_FUNCTIONS(utf8, "UTF-8", char,
tstr, "UTF16-LE", tchar,
false,
in_nbytes * 2,
- WIMLIB_ERR_INVALID_MULTIBYTE_STRING,
+ WIMLIB_ERR_INVALID_UTF8_STRING,
ERROR_WITH_ERRNO("Failed to convert UTF-8 string "
- "to UTF-16LE string!");
- )
+ "to UTF-16LE string!"),
+ static)
#else
DEFINE_CHAR_CONVERSION_FUNCTIONS(tstr, "", tchar,
- utf8, "UTF-8", utf8char,
+ utf8, "UTF-8", char,
wimlib_mbs_is_utf8,
in_nbytes * 4,
WIMLIB_ERR_INVALID_MULTIBYTE_STRING,
ERROR_WITH_ERRNO("Failed to convert multibyte "
"string \"%"TS"\" to UTF-8 string!", in);
ERROR("If the data you provided was UTF-8, please make sure "
- "the character encoding of your current locale is UTF-8.");)
+ "the character encoding of your current locale is UTF-8."),
+ static)
-DEFINE_CHAR_CONVERSION_FUNCTIONS(utf8, "UTF-8", utf8char,
+DEFINE_CHAR_CONVERSION_FUNCTIONS(utf8, "UTF-8", char,
tstr, "", tchar,
wimlib_mbs_is_utf8,
in_nbytes * 4,
"multibyte string!");
ERROR("This may be because the UTF-8 data "
"could not be represented in your "
- "locale's character encoding.");)
+ "locale's character encoding."),
+ static)
#endif
int
-tstr_to_utf8_simple(const tchar *tstr, utf8char **out)
+tstr_to_utf8_simple(const tchar *tstr, char **out)
{
size_t out_nbytes;
return tstr_to_utf8(tstr, tstrlen(tstr), out, &out_nbytes);
}
int
-utf8_to_tstr_simple(const utf8char *utf8str, tchar **out)
+utf8_to_tstr_simple(const char *utf8str, tchar **out)
{
size_t out_nbytes;
return utf8_to_tstr(utf8str, strlen(utf8str), out, &out_nbytes);
void
iconv_global_cleanup()
{
- /*iconv_cleanup(&iconv_utf16le_to_mbs);*/
+ iconv_cleanup(&iconv_utf8_to_tstr);
+ iconv_cleanup(&iconv_tstr_to_utf8);
#if !TCHAR_IS_UTF16LE
- iconv_cleanup(&iconv_mbs_to_utf16le);
+ iconv_cleanup(&iconv_utf16le_to_tstr);
+ iconv_cleanup(&iconv_tstr_to_utf16le);
#endif
- /*iconv_cleanup(&iconv_utf8_to_mbs);*/
}
-
-#if 0
-bool
-utf8_str_contains_nonascii_chars(const utf8char *utf8_str)
-{
- do {
- if ((unsigned char)*utf8_str > 127)
- return true;
- } while (*++utf8_str);
- return false;
-}
-#endif
#include "lookup_table.h"
#include "xml.h"
-static int inode_allocate_needed_ltes(struct wim_inode *inode,
- struct wim_lookup_table *src_lookup_table,
- struct wim_lookup_table *dest_lookup_table,
- struct list_head *lte_list_head)
+static int
+inode_allocate_needed_ltes(struct wim_inode *inode,
+ struct wim_lookup_table *src_lookup_table,
+ struct wim_lookup_table *dest_lookup_table,
+ struct list_head *lte_list_head)
{
struct wim_lookup_table_entry *src_lte, *dest_lte;
unsigned i;
return 0;
}
-static void inode_move_ltes_to_table(struct wim_inode *inode,
- struct wim_lookup_table *src_lookup_table,
- struct wim_lookup_table *dest_lookup_table,
- struct list_head *lte_list_head)
+static void
+inode_move_ltes_to_table(struct wim_inode *inode,
+ struct wim_lookup_table *src_lookup_table,
+ struct wim_lookup_table *dest_lookup_table,
+ struct list_head *lte_list_head)
{
struct wim_lookup_table_entry *src_lte, *dest_lte;
unsigned i;
/*
* Copies an image, or all the images, from a WIM file, into another WIM file.
*/
-WIMLIBAPI int wimlib_export_image(WIMStruct *src_wim,
- int src_image,
- WIMStruct *dest_wim,
- const tchar *dest_name,
- const tchar *dest_description,
- int export_flags,
- WIMStruct **additional_swms,
- unsigned num_additional_swms,
- wimlib_progress_func_t progress_func)
+WIMLIBAPI int
+wimlib_export_image(WIMStruct *src_wim,
+ int src_image,
+ WIMStruct *dest_wim,
+ const tchar *dest_name,
+ const tchar *dest_description,
+ int export_flags,
+ WIMStruct **additional_swms,
+ unsigned num_additional_swms,
+ wimlib_progress_func_t progress_func)
{
int ret;
struct wim_security_data *sd;
/* Pre-allocate the new lookup table entries that will be needed. This
* way, it's not possible to run out of memory part-way through
* modifying the lookup table of the destination WIM. */
- INIT_LIST_HEAD(<e_list_head);
for_lookup_table_entry(src_wim->lookup_table, lte_zero_out_refcnt, NULL);
src_imd = wim_get_current_image_metadata(src_wim);
-
+ INIT_LIST_HEAD(<e_list_head);
hlist_for_each_entry(inode, cur_node, &src_imd->inode_list, i_hlist) {
ret = inode_allocate_needed_ltes(inode,
src_wim->lookup_table,
goto out;
out_xml_delete_image:
- xml_delete_image(&dest_wim->wim_info, dest_wim->hdr.image_count);
+ xml_delete_image(&dest_wim->wim_info, dest_wim->hdr.image_count + 1);
out_free_ltes:
{
struct wim_lookup_table_entry *lte, *tmp;
# include <alloca.h>
#endif
-#if TCHAR_IS_UTF16LE
-# include <wchar.h>
-#endif
-
#ifndef __WIN32__
+
+/* Returns the number of components of @path. */
+static unsigned
+get_num_path_components(const char *path)
+{
+ unsigned num_components = 0;
+ while (*path) {
+ while (*path == '/')
+ path++;
+ if (*path)
+ num_components++;
+ while (*path && *path != '/')
+ path++;
+ }
+ return num_components;
+}
+
+static const char *
+path_next_part(const char *path)
+{
+ while (*path && *path != '/')
+ path++;
+ while (*path && *path == '/')
+ path++;
+ return path;
+}
+
static int
extract_regular_file_linked(struct wim_dentry *dentry,
const char *output_path,
p2 = lte->extracted_file;
while (*p2 == '/')
p2++;
- while (num_output_dir_path_components--)
- p2 = path_next_part(p2, NULL);
+ while (num_output_dir_path_components > 0) {
+ p2 = path_next_part(p2);
+ num_output_dir_path_components--;
+ }
strcpy(p, p2);
if (symlink(buf, output_path) != 0) {
ERROR_WITH_ERRNO("Failed to symlink `%s' to `%s'",
}
static int
-symlink_apply_unix_data(const mbchar *link,
+symlink_apply_unix_data(const char *link,
const struct wimlib_unix_data *unix_data)
{
if (lchown(link, unix_data->uid, unix_data->gid)) {
return ret;
}
+static const tchar *filename_forbidden_chars =
+T(
+#ifdef __WIN32__
+"<>:\"/\\|?*"
+#else
+"/"
+#endif
+);
+/* This function checks if it is okay to use a WIM image's name as a directory
+ * name. */
static bool
image_name_ok_as_dir(const tchar *image_name)
{
- if (image_name == NULL)
- return false;
- if (image_name[0] == T('\0'))
- return false;
- if (tstrchr(image_name, T('/')))
- return false;
- if (tstrchr(image_name, T('\\')))
- return false;
- return true;
+ return image_name && *image_name &&
+ !tstrpbrk(image_name, filename_forbidden_chars);
}
/* Extracts all images from the WIM to the directory @target, with the images
if (ret)
return ret;
- wmemcpy(buf, target, output_path_len);
+ tmemcpy(buf, target, output_path_len);
buf[output_path_len] = T('/');
for (image = 1; image <= w->hdr.image_count; image++) {
image_name = wimlib_get_image_name(w, image);
if (image_name_ok_as_dir(image_name)) {
tstrcpy(buf + output_path_len + 1, image_name);
} else {
- /* Image name is empty, or may not be representable in
- * the current locale, or contains path separators. Use
- * the image number instead. */
+ /* Image name is empty, or contains forbidden
+ * characters. */
tsprintf(buf + output_path_len + 1, T("%d"), image);
}
ret = extract_single_image(w, image, buf, extract_flags,
{
struct wim_dentry *dentry;
inode_for_each_dentry(dentry, inode)
- printf("`%s'\n", dentry->full_path);
+ tprintf(T("`%"TS"'\n"), dentry->full_path);
}
#endif
if (num_true_inodes != 1) {
inode = container_of(true_inodes.first, struct wim_inode, i_hlist);
- printf("Split nominal inode 0x%"PRIx64" into %zu "
- "inodes:\n",
- inode->i_ino, num_true_inodes);
- puts("------------------------------------------------------------------------------");
+ tprintf(T("Split nominal inode 0x%"PRIx64" into %zu "
+ "inodes:\n"), inode->i_ino, num_true_inodes);
+ tputs(T("----------------------------------------------------"
+ "--------------------------"));
size_t i = 1;
hlist_for_each_entry(inode, cur, &true_inodes, i_hlist) {
- printf("[Split inode %zu]\n", i++);
+ tprintf(T("[Split inode %zu]\n"), i++);
print_inode_dentries(inode);
- putchar('\n');
+ tputchar(T('\n'));
}
- puts("------------------------------------------------------------------------------");
+ tputs(T("----------------------------------------------------"
+ "--------------------------"));
}
#endif
{
const struct wim_header *hdr = &w->hdr;
- printf("Magic Characters = MSWIM\\000\\000\\000\n");
- printf("Header Size = %u\n", WIM_HEADER_DISK_SIZE);
- printf("Version = 0x%x\n", WIM_VERSION);
+ tprintf(T("Magic Characters = MSWIM\\000\\000\\000\n"));
+ tprintf(T("Header Size = %u\n"), WIM_HEADER_DISK_SIZE);
+ tprintf(T("Version = 0x%x\n"), WIM_VERSION);
- printf("Flags = 0x%x\n", hdr->flags);
+ tprintf(T("Flags = 0x%x\n"), hdr->flags);
for (size_t i = 0; i < ARRAY_LEN(hdr_flags); i++)
if (hdr_flags[i].flag & hdr->flags)
- printf(" WIM_HDR_FLAG_%s is set\n", hdr_flags[i].name);
+ tprintf(T(" WIM_HDR_FLAG_%s is set\n"), hdr_flags[i].name);
- printf("Chunk Size = %u\n", WIM_CHUNK_SIZE);
- fputs ("GUID = ", stdout);
+ tprintf(T("Chunk Size = %u\n"), WIM_CHUNK_SIZE);
+ tfputs (T("GUID = "), stdout);
print_byte_field(hdr->guid, WIM_GID_LEN);
- putchar('\n');
- printf("Part Number = %hu\n", w->hdr.part_number);
- printf("Total Parts = %hu\n", w->hdr.total_parts);
- printf("Image Count = %u\n", hdr->image_count);
- printf("Lookup Table Size = %"PRIu64"\n",
+ tputchar(T('\n'));
+ tprintf(T("Part Number = %hu\n"), w->hdr.part_number);
+ tprintf(T("Total Parts = %hu\n"), w->hdr.total_parts);
+ tprintf(T("Image Count = %u\n"), hdr->image_count);
+ tprintf(T("Lookup Table Size = %"PRIu64"\n"),
(u64)hdr->lookup_table_res_entry.size);
- printf("Lookup Table Flags = 0x%hhx\n",
+ tprintf(T("Lookup Table Flags = 0x%hhx\n"),
(u8)hdr->lookup_table_res_entry.flags);
- printf("Lookup Table Offset = %"PRIu64"\n",
+ tprintf(T("Lookup Table Offset = %"PRIu64"\n"),
hdr->lookup_table_res_entry.offset);
- printf("Lookup Table Original_size = %"PRIu64"\n",
+ tprintf(T("Lookup Table Original_size = %"PRIu64"\n"),
hdr->lookup_table_res_entry.original_size);
- printf("XML Data Size = %"PRIu64"\n",
+ tprintf(T("XML Data Size = %"PRIu64"\n"),
(u64)hdr->xml_res_entry.size);
- printf("XML Data Flags = 0x%hhx\n",
+ tprintf(T("XML Data Flags = 0x%hhx\n"),
(u8)hdr->xml_res_entry.flags);
- printf("XML Data Offset = %"PRIu64"\n",
+ tprintf(T("XML Data Offset = %"PRIu64"\n"),
hdr->xml_res_entry.offset);
- printf("XML Data Original Size = %"PRIu64"\n",
+ tprintf(T("XML Data Original Size = %"PRIu64"\n"),
hdr->xml_res_entry.original_size);
- printf("Boot Metadata Size = %"PRIu64"\n",
+ tprintf(T("Boot Metadata Size = %"PRIu64"\n"),
(u64)hdr->boot_metadata_res_entry.size);
- printf("Boot Metadata Flags = 0x%hhx\n",
+ tprintf(T("Boot Metadata Flags = 0x%hhx\n"),
(u8)hdr->boot_metadata_res_entry.flags);
- printf("Boot Metadata Offset = %"PRIu64"\n",
+ tprintf(T("Boot Metadata Offset = %"PRIu64"\n"),
hdr->boot_metadata_res_entry.offset);
- printf("Boot Metadata Original Size = %"PRIu64"\n",
+ tprintf(T("Boot Metadata Original Size = %"PRIu64"\n"),
hdr->boot_metadata_res_entry.original_size);
- printf("Boot Index = %u\n", hdr->boot_idx);
- printf("Integrity Size = %"PRIu64"\n",
+ tprintf(T("Boot Index = %u\n"), hdr->boot_idx);
+ tprintf(T("Integrity Size = %"PRIu64"\n"),
(u64)hdr->integrity.size);
- printf("Integrity Flags = 0x%hhx\n",
+ tprintf(T("Integrity Flags = 0x%hhx\n"),
(u8)hdr->integrity.flags);
- printf("Integrity Offset = %"PRIu64"\n",
+ tprintf(T("Integrity Offset = %"PRIu64"\n"),
hdr->integrity.offset);
- printf("Integrity Original_size = %"PRIu64"\n",
+ tprintf(T("Integrity Original_size = %"PRIu64"\n"),
hdr->integrity.original_size);
}
u8 sha1sums[0][20];
};
-static int calculate_chunk_sha1(FILE *fp, size_t this_chunk_size,
- off_t offset, u8 sha1_md[])
+static int
+calculate_chunk_sha1(FILE *fp, size_t this_chunk_size,
+ off_t offset, u8 sha1_md[])
{
int ret;
u8 buf[BUFFER_SIZE];
* data.
* * WIMLIB_ERR_READ: Could not read the integrity data from the WIM file.
*/
-static int read_integrity_table(const struct resource_entry *res_entry,
- FILE *fp,
- u64 num_checked_bytes,
- struct integrity_table **table_ret)
+static int
+read_integrity_table(const struct resource_entry *res_entry,
+ FILE *fp,
+ u64 num_checked_bytes,
+ struct integrity_table **table_ret)
{
struct integrity_table *table = NULL;
int ret = 0;
*
* Returns 0 on success; nonzero on failure.
*/
-static int calculate_integrity_table(FILE *fp,
- off_t new_check_end,
- const struct integrity_table *old_table,
- off_t old_check_end,
- wimlib_progress_func_t progress_func,
- struct integrity_table **integrity_table_ret)
+static int
+calculate_integrity_table(FILE *fp,
+ off_t new_check_end,
+ const struct integrity_table *old_table,
+ off_t old_check_end,
+ wimlib_progress_func_t progress_func,
+ struct integrity_table **integrity_table_ret)
{
int ret = 0;
size_t chunk_size = INTEGRITY_CHUNK_SIZE;
* * WIMLIB_ERR_READ: Could not read a chunk of data that needed
* to be checked.
*/
-int write_integrity_table(FILE *fp,
- struct resource_entry *integrity_res_entry,
- off_t new_lookup_table_end,
- off_t old_lookup_table_end,
- wimlib_progress_func_t progress_func)
+int
+write_integrity_table(FILE *fp,
+ struct resource_entry *integrity_res_entry,
+ off_t new_lookup_table_end,
+ off_t old_lookup_table_end,
+ wimlib_progress_func_t progress_func)
{
struct integrity_table *old_table;
struct integrity_table *new_table;
* were no inconsistencies.
* -1 (WIM_INTEGRITY_NOT_OK) if the WIM failed the integrity check.
*/
-static int verify_integrity(FILE *fp, const tchar *filename,
- const struct integrity_table *table,
- u64 bytes_to_check,
- wimlib_progress_func_t progress_func)
+static int
+verify_integrity(FILE *fp, const tchar *filename,
+ const struct integrity_table *table,
+ u64 bytes_to_check,
+ wimlib_progress_func_t progress_func)
{
int ret;
u64 offset = WIM_HEADER_DISK_SIZE;
* -2 (WIM_INTEGRITY_NONEXISTENT) if the WIM contains no integrity
* information.
*/
-int check_wim_integrity(WIMStruct *w, wimlib_progress_func_t progress_func)
+int
+check_wim_integrity(WIMStruct *w, wimlib_progress_func_t progress_func)
{
int ret;
u64 bytes_to_check;
#include <unistd.h>
#endif
-struct wim_lookup_table *new_lookup_table(size_t capacity)
+struct wim_lookup_table *
+new_lookup_table(size_t capacity)
{
struct wim_lookup_table *table;
struct hlist_head *array;
memcpy(new, old, sizeof(*old));
new->extracted_file = NULL;
switch (new->resource_location) {
+#ifdef __WIN32__
case RESOURCE_WIN32:
+#endif
case RESOURCE_IN_STAGING_FILE:
case RESOURCE_IN_FILE_ON_DISK:
BUILD_BUG_ON((void*)&old->file_on_disk !=
return NULL;
}
-void free_lookup_table_entry(struct wim_lookup_table_entry *lte)
+void
+free_lookup_table_entry(struct wim_lookup_table_entry *lte)
{
if (lte) {
switch (lte->resource_location) {
}
}
-static int do_free_lookup_table_entry(struct wim_lookup_table_entry *entry,
- void *ignore)
+static int
+do_free_lookup_table_entry(struct wim_lookup_table_entry *entry, void *ignore)
{
free_lookup_table_entry(entry);
return 0;
}
-void free_lookup_table(struct wim_lookup_table *table)
+void
+free_lookup_table(struct wim_lookup_table *table)
{
DEBUG2("Freeing lookup table");
if (table) {
* @table: A pointer to the lookup table.
* @lte: A pointer to the entry to insert.
*/
-void lookup_table_insert(struct wim_lookup_table *table,
- struct wim_lookup_table_entry *lte)
+void
+lookup_table_insert(struct wim_lookup_table *table,
+ struct wim_lookup_table_entry *lte)
{
size_t i = lte->hash_short % table->capacity;
hlist_add_head(<e->hash_list, &table->array[i]);
table->num_entries++;
}
-static void finalize_lte(struct wim_lookup_table_entry *lte)
+static void
+finalize_lte(struct wim_lookup_table_entry *lte)
{
#ifdef WITH_FUSE
if (lte->resource_location == RESOURCE_IN_STAGING_FILE) {
* reference count reaches 0, it is unlinked from the lookup table. If,
* furthermore, the entry has no opened file descriptors associated with it, the
* entry is freed. */
-void lte_decrement_refcnt(struct wim_lookup_table_entry *lte,
- struct wim_lookup_table *table)
+void
+lte_decrement_refcnt(struct wim_lookup_table_entry *lte,
+ struct wim_lookup_table *table)
{
wimlib_assert(lte != NULL);
wimlib_assert(lte->refcnt != 0);
}
#ifdef WITH_FUSE
-void lte_decrement_num_opened_fds(struct wim_lookup_table_entry *lte)
+void
+lte_decrement_num_opened_fds(struct wim_lookup_table_entry *lte)
{
if (lte->num_opened_fds != 0)
if (--lte->num_opened_fds == 0 && lte->refcnt == 0)
/* Calls a function on all the entries in the WIM lookup table. Stop early and
* return nonzero if any call to the function returns nonzero. */
-int for_lookup_table_entry(struct wim_lookup_table *table,
- int (*visitor)(struct wim_lookup_table_entry *, void *),
- void *arg)
+int
+for_lookup_table_entry(struct wim_lookup_table *table,
+ int (*visitor)(struct wim_lookup_table_entry *, void *),
+ void *arg)
{
struct wim_lookup_table_entry *lte;
struct hlist_node *pos, *tmp;
/*
* Reads the lookup table from a WIM file.
*/
-int read_lookup_table(WIMStruct *w)
+int
+read_lookup_table(WIMStruct *w)
{
u64 num_entries;
u8 buf[WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE];
/*
* Writes a lookup table entry to the output file.
*/
-int write_lookup_table_entry(struct wim_lookup_table_entry *lte, void *__out)
+int
+write_lookup_table_entry(struct wim_lookup_table_entry *lte, void *__out)
{
FILE *out;
u8 buf[WIM_LOOKUP_TABLE_ENTRY_DISK_SIZE];
}
/* Writes the lookup table to the output file. */
-int write_lookup_table(struct wim_lookup_table *table, FILE *out,
- struct resource_entry *out_res_entry)
+int
+write_lookup_table(struct wim_lookup_table *table, FILE *out,
+ struct resource_entry *out_res_entry)
{
off_t start_offset, end_offset;
int ret;
}
-int lte_zero_real_refcnt(struct wim_lookup_table_entry *lte, void *ignore)
+int
+lte_zero_real_refcnt(struct wim_lookup_table_entry *lte, void *ignore)
{
lte->real_refcnt = 0;
return 0;
}
-int lte_zero_out_refcnt(struct wim_lookup_table_entry *lte, void *ignore)
+int
+lte_zero_out_refcnt(struct wim_lookup_table_entry *lte, void *ignore)
{
lte->out_refcnt = 0;
return 0;
}
-int lte_free_extracted_file(struct wim_lookup_table_entry *lte, void *ignore)
+int
+lte_free_extracted_file(struct wim_lookup_table_entry *lte, void *ignore)
{
if (lte->extracted_file != NULL) {
FREE(lte->extracted_file);
return 0;
}
-void print_lookup_table_entry(const struct wim_lookup_table_entry *lte,
- FILE *out)
+void
+print_lookup_table_entry(const struct wim_lookup_table_entry *lte, FILE *out)
{
if (!lte) {
tputc(T('\n'), out);
lte->wim->filename);
}
break;
+#ifdef __WIN32__
+ case RESOURCE_WIN32:
+#endif
case RESOURCE_IN_FILE_ON_DISK:
tfprintf(out, T("File on Disk = `%"TS"'\n"),
lte->file_on_disk);
tputc(T('\n'), out);
}
-static int do_print_lookup_table_entry(struct wim_lookup_table_entry *lte,
- void *fp)
+static int
+do_print_lookup_table_entry(struct wim_lookup_table_entry *lte, void *fp)
{
print_lookup_table_entry(lte, (FILE*)fp);
return 0;
/*
* Prints the lookup table of a WIM file.
*/
-WIMLIBAPI void wimlib_print_lookup_table(WIMStruct *w)
+WIMLIBAPI void
+wimlib_print_lookup_table(WIMStruct *w)
{
for_lookup_table_entry(w->lookup_table,
do_print_lookup_table_entry,
* This function always succeeds; unresolved lookup table entries are given a
* NULL pointer.
*/
-void inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table)
+void
+inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table)
{
if (!inode->i_resolved) {
}
}
-void inode_unresolve_ltes(struct wim_inode *inode)
+void
+inode_unresolve_ltes(struct wim_inode *inode)
{
if (inode->i_resolved) {
if (inode->i_lte)
* stream_idx = 0 means the default un-named file stream, and stream_idx >= 1
* corresponds to an alternate data stream.
*
- * This works for both resolved and un-resolved dentries.
+ * This works for both resolved and un-resolved inodes.
*/
struct wim_lookup_table_entry *
inode_stream_lte(const struct wim_inode *inode, unsigned stream_idx,
return inode_unnamed_lte_unresolved(inode, table);
}
-static int lte_add_stream_size(struct wim_lookup_table_entry *lte,
- void *total_bytes_p)
+static int
+lte_add_stream_size(struct wim_lookup_table_entry *lte, void *total_bytes_p)
{
*(u64*)total_bytes_p += lte->resource_entry.size;
return 0;
}
-u64 lookup_table_total_stream_size(struct wim_lookup_table *table)
+u64
+lookup_table_total_stream_size(struct wim_lookup_table *table)
{
u64 total_size = 0;
for_lookup_table_entry(table, lte_add_stream_size, &total_size);
WIMStruct *wim;
tchar *file_on_disk;
tchar *staging_file_name;
- u8 *attached_buffer;
+ void *attached_buffer;
#ifdef WITH_NTFS_3G
struct ntfs_location *ntfs_loc;
#endif
*
* @return: Zero on success, nonzero on failure.
*/
-int read_metadata_resource(WIMStruct *w, struct wim_image_metadata *imd)
+int
+read_metadata_resource(WIMStruct *w, struct wim_image_metadata *imd)
{
u8 *buf;
u32 dentry_offset;
return ret;
}
-static void recalculate_security_data_length(struct wim_security_data *sd)
+static void
+recalculate_security_data_length(struct wim_security_data *sd)
{
u32 total_length = sizeof(u64) * sd->num_entries + 2 * sizeof(u32);
for (u32 i = 0; i < sd->num_entries; i++)
/* Like write_wim_resource(), but the resource is specified by a buffer of
* uncompressed data rather a lookup table entry; also writes the SHA1 hash of
* the buffer to @hash. */
-static int write_wim_resource_from_buffer(const u8 *buf, u64 buf_size,
- FILE *out_fp, int out_ctype,
- struct resource_entry *out_res_entry,
- u8 hash[SHA1_HASH_SIZE])
+static int
+write_wim_resource_from_buffer(const u8 *buf, u64 buf_size,
+ FILE *out_fp, int out_ctype,
+ struct resource_entry *out_res_entry,
+ u8 hash[SHA1_HASH_SIZE])
{
/* Set up a temporary lookup table entry to provide to
* write_wim_resource(). */
lte.resource_entry.size = buf_size;
lte.resource_entry.offset = 0;
lte.resource_location = RESOURCE_IN_ATTACHED_BUFFER;
- lte.attached_buffer = (u8*)buf;
+ lte.attached_buffer = buf;
zero_out_hash(lte.hash);
ret = write_wim_resource(<e, out_fp, out_ctype, out_res_entry, 0);
}
/* Write the metadata resource for the current WIM image. */
-int write_metadata_resource(WIMStruct *w)
+int
+write_metadata_resource(WIMStruct *w)
{
u8 *buf;
u8 *p;
size_t stream_name_mbs_nbytes;
int ret;
- ret = utf16le_to_mbs(inode->i_ads_entries[i].stream_name,
- inode->i_ads_entries[i].stream_name_nbytes,
- &stream_name_mbs,
- &stream_name_mbs_nbytes);
+ ret = utf16le_to_tstr(inode->i_ads_entries[i].stream_name,
+ inode->i_ads_entries[i].stream_name_nbytes,
+ &stream_name_mbs,
+ &stream_name_mbs_nbytes);
if (ret)
return -errno;
size_t file_name_mbs_nbytes;
int ret;
- ret = utf16le_to_mbs(dentry->file_name,
- dentry->file_name_nbytes,
- &file_name_mbs,
- &file_name_mbs_nbytes);
+ ret = utf16le_to_tstr(dentry->file_name,
+ dentry->file_name_nbytes,
+ &file_name_mbs,
+ &file_name_mbs_nbytes);
if (ret)
return -errno;
static ntfs_inode *
dentry_open_parent_ni(const struct wim_dentry *dentry, ntfs_volume *vol)
{
- mbchar *p;
- const mbchar *dir_name;
+ char *p;
+ const char *dir_name;
ntfs_inode *dir_ni;
- mbchar orig;
+ char orig;
p = dentry->full_path + dentry->full_path_nbytes;
do {
/* Set DOS (short) name if given */
if (dentry_has_short_name(dentry)) {
- mbchar *short_name_mbs;
+ char *short_name_mbs;
size_t short_name_mbs_nbytes;
- ret = utf16le_to_mbs(dentry->short_name,
- dentry->short_name_nbytes,
- &short_name_mbs,
- &short_name_mbs_nbytes);
+ ret = utf16le_to_tstr(dentry->short_name,
+ dentry->short_name_nbytes,
+ &short_name_mbs,
+ &short_name_mbs_nbytes);
if (ret != 0)
goto out_close_dir_ni;
* file. So, this implies that the correct ordering of function calls
* to extract a NTFS file are:
*
- if (file has a DOS name) {
+ * if (file has a DOS name) {
* - Call ntfs_create() to create long name associated with
* the DOS name (this initially creates a POSIX name)
* - Call ntfs_set_ntfs_dos_name() to associate a DOS name
if (ret != 0 || name_type == FILE_NAME_DOS)
goto out;
}
- ret = utf16le_to_mbs(name, name_nbytes,
- &mbs_name, &mbs_name_nbytes);
+ ret = utf16le_to_tstr(name, name_nbytes,
+ &mbs_name, &mbs_name_nbytes);
if (ret)
goto out;
resource_compressed_size,
resource_uncompressed_size,
resource_offset);
- DEBUG2("resource_ctype = %s, len = %"PRIu64", offset = %"PRIu64"",
+ DEBUG2("resource_ctype = %"TS", len = %"PRIu64", offset = %"PRIu64"",
wimlib_get_compression_type_string(resource_ctype), len, offset);
/* Trivial case */
if (len == 0)
#include "buffer_io.h"
#include "security.h"
-
-#define SECURITY_DESCRIPTOR_REVISION 1
-#define SECURITY_DESCRIPTOR_REVISION1 1
-
-/* inherit AceFlags */
-#define OBJECT_INHERIT_ACE 0x01
-#define CONTAINER_INHERIT_ACE 0x02
-#define NO_PROPAGATE_INHERIT_ACE 0x04
-#define INHERIT_ONLY_ACE 0x08
-#define INHERITED_ACE 0x10
-#define VALID_INHERIT_FLAGS 0x1F
-
-#define SE_OWNER_DEFAULTED 0x00000001
-#define SE_GROUP_DEFAULTED 0x00000002
-#define SE_DACL_PRESENT 0x00000004
-#define SE_DACL_DEFAULTED 0x00000008
-#define SE_SACL_PRESENT 0x00000010
-#define SE_SACL_DEFAULTED 0x00000020
-#define SE_DACL_AUTO_INHERIT_REQ 0x00000100
-#define SE_SACL_AUTO_INHERIT_REQ 0x00000200
-#define SE_DACL_AUTO_INHERITED 0x00000400
-#define SE_SACL_AUTO_INHERITED 0x00000800
-#define SE_DACL_PROTECTED 0x00001000
-#define SE_SACL_PROTECTED 0x00002000
-#define SE_RM_CONTROL_VALID 0x00004000
-#define SE_SELF_RELATIVE 0x00008000
-
-/* Flags in access control entries */
-#define DELETE 0x00010000
-#define READ_CONTROL 0x00020000
-#define WRITE_DAC 0x00040000
-#define WRITE_OWNER 0x00080000
-#define SYNCHRONIZE 0x00100000
-#define STANDARD_RIGHTS_REQUIRED 0x000f0000
-
-#define STANDARD_RIGHTS_READ READ_CONTROL
-#define STANDARD_RIGHTS_WRITE READ_CONTROL
-#define STANDARD_RIGHTS_EXECUTE READ_CONTROL
-
-#define STANDARD_RIGHTS_ALL 0x001f0000
-
-#define SPECIFIC_RIGHTS_ALL 0x0000ffff
-
-#define GENERIC_READ 0x80000000
-#define GENERIC_WRITE 0x40000000
-#define GENERIC_EXECUTE 0x20000000
-#define GENERIC_ALL 0x10000000
-
-#define MAXIMUM_ALLOWED 0x02000000
-#define ACCESS_SYSTEM_SECURITY 0x01000000
-
-#define EVENT_QUERY_STATE 0x0001
-#define EVENT_MODIFY_STATE 0x0002
-#define EVENT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
-
-#define SEMAPHORE_MODIFY_STATE 0x0002
-#define SEMAPHORE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
-
-#define MUTEX_MODIFY_STATE 0x0001
-#define MUTEX_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1)
-
-#define JOB_OBJECT_ASSIGN_PROCESS 0x0001
-#define JOB_OBJECT_SET_ATTRIBUTES 0x0002
-#define JOB_OBJECT_QUERY 0x0004
-#define JOB_OBJECT_TERMINATE 0x0008
-#define JOB_OBJECT_SET_SECURITY_ATTRIBUTES 0x0010
-#define JOB_OBJECT_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x1f)
-
-#define TIMER_QUERY_STATE 0x0001
-#define TIMER_MODIFY_STATE 0x0002
-#define TIMER_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3)
-
-#define PROCESS_TERMINATE 0x0001
-#define PROCESS_CREATE_THREAD 0x0002
-#define PROCESS_VM_OPERATION 0x0008
-#define PROCESS_VM_READ 0x0010
-#define PROCESS_VM_WRITE 0x0020
-#define PROCESS_DUP_HANDLE 0x0040
-#define PROCESS_CREATE_PROCESS 0x0080
-#define PROCESS_SET_QUOTA 0x0100
-#define PROCESS_SET_INFORMATION 0x0200
-#define PROCESS_QUERY_INFORMATION 0x0400
-#define PROCESS_SUSPEND_RESUME 0x0800
-#define PROCESS_QUERY_LIMITED_INFORMATION 0x1000
-#define PROCESS_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0xfff)
-
-#define THREAD_TERMINATE 0x0001
-#define THREAD_SUSPEND_RESUME 0x0002
-#define THREAD_GET_CONTEXT 0x0008
-#define THREAD_SET_CONTEXT 0x0010
-#define THREAD_SET_INFORMATION 0x0020
-#define THREAD_QUERY_INFORMATION 0x0040
-#define THREAD_SET_THREAD_TOKEN 0x0080
-#define THREAD_IMPERSONATE 0x0100
-#define THREAD_DIRECT_IMPERSONATION 0x0200
-#define THREAD_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x3ff)
-
-#define THREAD_BASE_PRIORITY_LOWRT 15
-#define THREAD_BASE_PRIORITY_MAX 2
-#define THREAD_BASE_PRIORITY_MIN -2
-#define THREAD_BASE_PRIORITY_IDLE -15
-
-/* predefined authority values for SID's (security identifiers) */
-enum sid_authority_value {
- SECURITY_NULL_SID_AUTHORITY = 0,
- SECURITY_WORLD_SID_AUTHORITY = 1,
- SECURITY_LOCAL_SID_AUTHORITY = 2,
- SECURITY_CREATOR_SID_AUTHORITY = 3,
- SECURITY_NON_UNIQUE_AUTHORITY = 4,
- SECURITY_NT_AUTHORITY = 5,
-};
-
-/* local administrators group */
-#define SECURITY_BUILTIN_DOMAIN_RID 32
-#define DOMAIN_ALIAS_RID_ADMINS 544
-
-/* See ACEHeader. */
-enum ace_type {
- ACCESS_ALLOWED_ACE_TYPE = 0,
- ACCESS_DENIED_ACE_TYPE = 1,
- SYSTEM_AUDIT_ACE_TYPE = 2,
-};
-
/* At the start of each type of access control entry. */
typedef struct {
/* enum ace_type, specifies what type of ACE this is. */
}
static void
-print_acl(const u8 *p, const char *type)
+print_acl(const void *p, const tchar *type)
{
- const ACL *acl = (const ACL*)p;
+ const ACL *acl = p;
u8 revision = acl->revision;
u16 acl_size = le16_to_cpu(acl->acl_size);
u16 ace_count = le16_to_cpu(acl->ace_count);
- printf(" [%s ACL]\n", type);
- printf(" Revision = %u\n", revision);
- printf(" ACL Size = %u\n", acl_size);
- printf(" ACE Count = %u\n", ace_count);
+ tprintf(T(" [%"TS" ACL]\n"), type);
+ tprintf(T(" Revision = %u\n"), revision);
+ tprintf(T(" ACL Size = %u\n"), acl_size);
+ tprintf(T(" ACE Count = %u\n"), ace_count);
p += sizeof(ACL);
for (u16 i = 0; i < ace_count; i++) {
- const ACEHeader *hdr = (const ACEHeader*)p;
- printf(" [ACE]\n");
- printf(" ACE type = %d\n", hdr->type);
- printf(" ACE flags = 0x%x\n", hdr->flags);
- printf(" ACE size = %u\n", hdr->size);
+ const ACEHeader *hdr = p;
+ tprintf(T(" [ACE]\n"));
+ tprintf(T(" ACE type = %d\n"), hdr->type);
+ tprintf(T(" ACE flags = 0x%x\n"), hdr->flags);
+ tprintf(T(" ACE size = %u\n"), hdr->size);
const AccessAllowedACE *aaa = (const AccessAllowedACE*)hdr;
- printf(" ACE mask = %x\n", le32_to_cpu(aaa->mask));
- printf(" SID start = %u\n", le32_to_cpu(aaa->sid_start));
+ tprintf(T(" ACE mask = %x\n"), le32_to_cpu(aaa->mask));
+ tprintf(T(" SID start = %u\n"), le32_to_cpu(aaa->sid_start));
p += hdr->size;
}
- putchar('\n');
+ tputchar(T('\n'));
}
static void
-print_sid(const u8 *p, const char *type)
+print_sid(const void *p, const tchar *type)
{
- const SID *sid = (const SID*)p;
- printf(" [%s SID]\n", type);
- printf(" Revision = %u\n", sid->revision);
- printf(" Subauthority count = %u\n", sid->sub_authority_count);
- printf(" Identifier authority = ");
+ const SID *sid = p;
+ tprintf(T(" [%"TS" SID]\n"), type);
+ tprintf(T(" Revision = %u\n"), sid->revision);
+ tprintf(T(" Subauthority count = %u\n"), sid->sub_authority_count);
+ tprintf(T(" Identifier authority = "));
print_byte_field(sid->identifier_authority,
sizeof(sid->identifier_authority));
- putchar('\n');
- for (u8 i = 0; i < sid->sub_authority_count; i++)
- printf(" Subauthority %u = %u\n",
- i, le32_to_cpu(sid->sub_authority[i]));
- putchar('\n');
+ tputchar(T('\n'));
+ for (u8 i = 0; i < sid->sub_authority_count; i++) {
+ tprintf(T(" Subauthority %u = %u\n"),
+ i, le32_to_cpu(sid->sub_authority[i]));
+ }
+ tputchar(T('\n'));
}
static void
-print_security_descriptor(const u8 *p, u64 size)
+print_security_descriptor(const void *p, u64 size)
{
- const SecurityDescriptor *sd = (const SecurityDescriptor*)p;
+ const SecurityDescriptor *sd = p;
+
u8 revision = sd->revision;
u16 control = le16_to_cpu(sd->security_descriptor_control);
u32 owner_offset = le32_to_cpu(sd->owner_offset);
u32 group_offset = le32_to_cpu(sd->group_offset);
u32 sacl_offset = le32_to_cpu(sd->sacl_offset);
u32 dacl_offset = le32_to_cpu(sd->dacl_offset);
- printf("Revision = %u\n", revision);
- printf("Security Descriptor Control = %#x\n", control);
- printf("Owner offset = %u\n", owner_offset);
- printf("Group offset = %u\n", group_offset);
- printf("System ACL offset = %u\n", sacl_offset);
- printf("Discretionary ACL offset = %u\n", dacl_offset);
+ tprintf(T("Revision = %u\n"), revision);
+ tprintf(T("Security Descriptor Control = %#x\n"), control);
+ tprintf(T("Owner offset = %u\n"), owner_offset);
+ tprintf(T("Group offset = %u\n"), group_offset);
+ tprintf(T("System ACL offset = %u\n"), sacl_offset);
+ tprintf(T("Discretionary ACL offset = %u\n"), dacl_offset);
if (sd->owner_offset != 0)
- print_sid(p + owner_offset, "Owner");
+ print_sid(p + owner_offset, T("Owner"));
if (sd->group_offset != 0)
- print_sid(p + group_offset, "Group");
+ print_sid(p + group_offset, T("Group"));
if (sd->sacl_offset != 0)
- print_acl(p + sacl_offset, "System");
+ print_acl(p + sacl_offset, T("System"));
if (sd->dacl_offset != 0)
- print_acl(p + dacl_offset, "Discretionary");
+ print_acl(p + dacl_offset, T("Discretionary"));
}
/*
{
wimlib_assert(sd != NULL);
- puts("[SECURITY DATA]");
- printf("Length = %"PRIu32" bytes\n", sd->total_length);
- printf("Number of Entries = %"PRIu32"\n", sd->num_entries);
+ tputs(T("[SECURITY DATA]"));
+ tprintf(T("Length = %"PRIu32" bytes\n"), sd->total_length);
+ tprintf(T("Number of Entries = %"PRIu32"\n"), sd->num_entries);
for (u32 i = 0; i < sd->num_entries; i++) {
- printf("[SecurityDescriptor %"PRIu32", length = %"PRIu64"]\n",
- i, sd->sizes[i]);
+ tprintf(T("[SecurityDescriptor %"PRIu32", length = %"PRIu64"]\n"),
+ i, sd->sizes[i]);
print_security_descriptor(sd->descriptors[i], sd->sizes[i]);
- putchar('\n');
+ tputchar(T('\n'));
}
- putchar('\n');
+ tputchar(T('\n'));
}
void
{
sha1_update_intel((int*)&context->state, data, len / 64);
size_t j = (context->count[0] >> 3) & 63;
- if ((context->count[0] += len << 3) < (len << 3)) context->count[1]++;
+ if ((context->count[0] += len << 3) < (len << 3))
+ context->count[1]++;
context->count[1] += (len >> 29);
}
#include <stdlib.h>
#include "xml.h"
#include "buffer_io.h"
-#if TCHAR_IS_UTF16LE
-# include <wchar.h>
-#endif
-
struct split_args {
WIMStruct *w;
tchar *swm_base_name;
get_symlink_name(const void *resource, size_t resource_len, char *buf,
size_t buf_len, u32 reparse_tag)
{
- const u8 *p = resource;
+ const void *p = resource;
u16 substitute_name_offset;
u16 substitute_name_len;
u16 print_name_offset;
if (header_size + substitute_name_offset + substitute_name_len > resource_len)
return -EIO;
- ret = utf16le_to_mbs((const utf16lechar*)(p + substitute_name_offset),
- substitute_name_len,
- &link_target, &link_target_len);
+ ret = utf16le_to_tstr((const utf16lechar*)(p + substitute_name_offset),
+ substitute_name_len,
+ &link_target, &link_target_len);
if (ret)
return -errno;
- wimlib_assert(ret == 0);
-
- if (!link_target)
- return -EIO;
-
if (link_target_len + 1 > buf_len) {
ret = -ENAMETOOLONG;
goto out;
size_t len = 12 + name_utf16le_nbytes * 2;
void *buf = MALLOC(len);
if (buf) {
- u8 *p = buf;
+ void *p = buf;
p = put_u16(p, name_utf16le_nbytes); /* Substitute name offset */
p = put_u16(p, name_utf16le_nbytes); /* Substitute name length */
p = put_u16(p, 0); /* Print name offset */
return ret;
}
-#endif /* !defined(__WIN32__) && !defined(WITH_FUSE) */
+#endif /* !defined(__WIN32__) */
#include <unistd.h> /* for getpid() */
-size_t
+static size_t
utf16le_strlen(const utf16lechar *s)
{
const utf16lechar *p = s;
return (p - s) * sizeof(utf16lechar);
}
-/* Handle %W for UTF16-LE printing and %U for UTF-8 printing.
+#ifdef __WIN32__
+# define wimlib_vfprintf vfwprintf
+#else
+/* Handle %W for UTF16-LE printing.
*
* TODO: this is not yet done properly--- it's assumed that if the format string
- * contains %W and/or %U, then it contains no other format specifiers.
+ * contains %W, then it contains no other format specifiers.
*/
static int
wimlib_vfprintf(FILE *fp, const tchar *format, va_list va)
{
const tchar *p;
+ int n;
for (p = format; *p; p++)
- if (*p == '%' && (*(p + 1) == T('W') || *(p + 1) == T('U')))
+ if (*p == T('%') && *(p + 1) == T('W'))
goto special;
return tvfprintf(fp, format, va);
special:
- /* XXX */
- wimlib_assert(0);
-#if 0
- ;
- int n = 0;
+ n = 0;
for (p = format; *p; p++) {
- if (*p == T('%') && (*(p + 1) == T('W') || *(p + 1) == T('U'))) {
+ if (*p == T('%') && (*(p + 1) == T('W'))) {
int ret;
- tchar *mbs;
- size_t mbs_nbytes;
-
- if (*(p + 1) == T('W')) {
- utf16lechar *ucs = va_arg(va, utf16lechar*);
- size_t ucs_nbytes = utf16le_strlen(ucs);
- ret = utf16le_to_mbs(ucs, ucs_nbytes,
- &mbs, &mbs_nbytes);
- } else {
- utf8char *ucs = va_arg(va, utf8char*);
- size_t ucs_nbytes = strlen(ucs);
- ret = utf8_to_mbs(ucs, ucs_nbytes,
- &mbs, &mbs_nbytes);
- }
+ tchar *tstr;
+ size_t tstr_nbytes;
+ utf16lechar *ucs = va_arg(va, utf16lechar*);
+ size_t ucs_nbytes = utf16le_strlen(ucs);
+
+ ret = utf16le_to_tstr(ucs, ucs_nbytes,
+ &tstr, &tstr_nbytes);
if (ret) {
ret = tfprintf(fp, T("??????"));
} else {
- ret = tfprintf(fp, T("%s"), mbs);
- FREE(mbs);
+ ret = tfprintf(fp, T("%"TS), tstr);
+ FREE(tstr);
}
if (ret < 0)
return -1;
n += ret;
p++;
} else {
- if (putc(*p, fp) == EOF)
+ if (tputc(*p, fp) == EOF)
return -1;
n++;
}
}
return n;
-#endif
}
int
va_end(va);
return ret;
}
+#endif
#if defined(ENABLE_ERROR_MESSAGES) || defined(ENABLE_DEBUG)
static void
*p++ = rand();
}
-/* Takes in a path of length @len in @buf, and transforms it into a string for
- * the path of its parent directory. */
-void
-to_parent_name(tchar *buf, size_t len)
-{
- ssize_t i = (ssize_t)len - 1;
- while (i >= 0 && buf[i] == T('/'))
- i--;
- while (i >= 0 && buf[i] != T('/'))
- i--;
- while (i >= 0 && buf[i] == T('/'))
- i--;
- buf[i + 1] = T('\0');
-}
-
const tchar *
path_basename_with_len(const tchar *path, size_t len)
{
return stream_name + 1;
}
-/*
- * Splits a file path into the part before the first '/', or the entire name if
- * there is no '/', and the part after the first sequence of '/' characters.
- *
- * @path: The file path to split.
- * @first_part_len_ret: A pointer to a `size_t' into which the length of the
- * first part of the path will be returned.
- * @return: A pointer to the next part of the path, after the first
- * sequence of '/', or a pointer to the terminating
- * null byte in the case of a path without any '/'.
- */
-const tchar *
-path_next_part(const tchar *path, size_t *first_part_len_ret)
-{
- size_t i;
- const tchar *next_part;
-
- i = 0;
- while (path[i] != T('/') && path[i] != T('\0'))
- i++;
- if (first_part_len_ret)
- *first_part_len_ret = i;
- next_part = &path[i];
- while (*next_part == T('/'))
- next_part++;
- return next_part;
-}
-
-/* Returns the number of components of @path. */
-int
-get_num_path_components(const char *path)
-{
- int num_components = 0;
- while (*path) {
- while (*path == '/')
- path++;
- if (*path)
- num_components++;
- while (*path && *path != '/')
- path++;
- }
- return num_components;
-}
-
-
-/*
- * Prints a string. Printable characters are printed as-is, while unprintable
- * characters are printed as their octal escape codes.
- */
-void
-print_string(const void *string, size_t len)
-{
- const u8 *p = string;
-
- while (len--) {
- if (isprint(*p))
- putchar(*p);
- else
- printf("\\%03hho", *p);
- p++;
- }
-}
-
u64
get_wim_timestamp()
{
gmtime_r(&t, &tm);
tstrftime(buf, len, T("%a %b %d %H:%M:%S %Y UTC"), &tm);
}
+
+void
+zap_backslashes(tchar *s)
+{
+ if (s) {
+ while (*s != T('\0')) {
+ if (*s == T('\\'))
+ *s = T('/');
+ s++;
+ }
+ }
+}
#ifndef _WIMLIB_UTIL_H
#define _WIMLIB_UTIL_H
+#include "config.h"
+#include "wimlib_tchar.h"
+
#include <stdio.h>
#include <stdbool.h>
#include <stddef.h>
#include <inttypes.h>
#include <sys/types.h>
-#include "config.h"
#ifdef __GNUC__
# if defined(__CYGWIN__) || defined(__WIN32__)
# endif
# define ALWAYS_INLINE inline __attribute__((always_inline))
# define PACKED __attribute__((packed))
-//# define FORMAT(type, format_str, args_start) \
- //__attribute__((format(type, format_str, args_start)))
-# define FORMAT(type, format_str, args_start)
+# define FORMAT(type, format_str, args_start) \
+ /*__attribute__((format(type, format_str, args_start))) */
# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
# define COLD __attribute__((cold))
# else
/* A pointer to 'utf16lechar' indicates a UTF-16LE encoded string */
typedef u16 utf16lechar;
-typedef u8 utf8char;
-
-#ifdef __WIN32__
-/* For Windows builds, the "tchar" type will be 2 bytes and will be equivalent
- * to "wchar_t" and "utf16lechar". All indicate one code unit of a UTF16-LE
- * string. */
-typedef wchar_t tchar;
-# define TCHAR_IS_UTF16LE 1
-# define T(text) L##text /* Make a string literal into a wide string */
-# define TS "ls" /* Format a string of "tchar" */
-# define WS "ls" /* Format a UTF-16LE string (same as above) */
-
-/* For Windows builds, the following definitions replace the "tchar" functions
- * with the "wide-character" functions. */
-# define tmemchr wmemchr
-# define tmemcpy wmemcpy
-# define tstrcpy wcscpy
-# define tprintf wprintf
-# define tsprintf swprintf
-# define tfprintf fwprintf
-# define tvfprintf vfwprintf
-# define istalpha iswalpha
-# define tstrcmp wcscmp
-# define tstrchr wcschr
-# define tstrrchr wcsrchr
-# define tstrlen wcslen
-# define tmemcmp wmemcmp
-# define tstrftime wcsftime
-# define tputchar putwchar
-# define tputc putwc
-# define tputs _putws
-# define tfputs fputws
-# define tfopen _wfopen
-# define tstat _wstati64
-# define tstrtol wcstol
-# define tunlink _wunlink
-/* The following "tchar" functions do not have exact wide-character equivalents
- * on Windows so require parameter rearrangement or redirection to a replacement
- * function defined ourselves. */
-# define TSTRDUP WSTRDUP
-# define tmkdir(path, mode) _wmkdir(path)
-# define tstrerror_r(errnum, buf, bufsize) _wcserror_s(buf, bufsize, errnum)
-# define trename win32_rename_replacement
-# define ttruncate win32_truncate_replacement
-#else
-/* For non-Windows builds, the "tchar" type will be one byte and will specify a
- * string in the locale-dependent multibyte encoding. However, only UTF-8 is
- * well supported in this library. */
-typedef char tchar;
-# define TCHAR_IS_UTF16LE 0
-# define T(text) text /* In this case, strings of "tchar" are simply strings of
- char */
-# define TS "s" /* Similarly, a string of "tchar" is printed just as a
- normal string. */
-# define WS "W" /* UTF-16LE strings must be printed using a special
- extension implemented by wimlib itself. Note that
- "ls" will not work here because a string of wide
- characters on non-Windows systems is typically not
- UTF-16LE. */
-/* For non-Windows builds, replace the "tchar" functions with the regular old
- * string functions. */
-# define tmemchr memchr
-# define tmemcpy memcpy
-# define tstrcpy strcpy
-# define tprintf printf
-# define tsprintf sprintf
-# define tfprintf fprintf
-# define tvfprintf vfprintf
-# define istalpha isalpha
-# define tstrcmp strcmp
-# define tstrchr strchr
-# define tstrrchr strrchr
-# define tstrlen strlen
-# define tmemcmp memcmp
-# define tstrftime strftime
-# define tputchar putchar
-# define tputc putc
-# define tputs puts
-# define tfputs fputs
-# define tfopen fopen
-# define tstat stat
-# define tunlink unlink
-# define tstrtol strtol
-# define tmkdir mkdir
-# define TSTRDUP STRDUP
-# define tstrerror_r strerror_r
-# define trename rename
-# define ttruncate truncate
-#endif
-
#define TMALLOC(n) MALLOC((n) * sizeof(tchar))
-extern size_t
-utf16le_strlen(const utf16lechar *s);
-
/* encoding.c */
extern void
iconv_global_cleanup();
chartype1, chartype2) \
\
extern int \
+varname1##_to_##varname2(const chartype1 *in, size_t in_nbytes, \
+ chartype2 **out_ret, \
+ size_t *out_nbytes_ret); \
+ \
+extern int \
varname1##_to_##varname2##_nbytes(const chartype1 *in, size_t in_nbytes,\
size_t *out_nbytes_ret); \
\
extern int \
varname1##_to_##varname2##_buf(const chartype1 *in, size_t in_nbytes, \
- chartype2 *out); \
- \
-extern int \
-varname1##_to_##varname2(const chartype1 *in, size_t in_nbytes, \
- chartype2 **out_ret, \
- size_t *out_nbytes_ret); \
+ chartype2 *out);
+
#if !TCHAR_IS_UTF16LE
DECLARE_CHAR_CONVERSION_FUNCTIONS(utf16le, tstr, utf16lechar, tchar);
+DECLARE_CHAR_CONVERSION_FUNCTIONS(tstr, utf16le, tchar, utf16lechar);
#endif
extern int
-utf8_to_tstr_simple(const utf8char *utf8str, tchar **out);
+utf8_to_tstr_simple(const char *utf8str, tchar **out);
extern int
-tstr_to_utf8_simple(const tchar *tstr, utf8char **out);
+tstr_to_utf8_simple(const tchar *tstr, char **out);
#ifndef min
#define min(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); \
#define BUFFER_SIZE 4096
static inline void FORMAT(printf, 1, 2)
-dummy_printf(const char *format, ...)
+dummy_tprintf(const tchar *format, ...)
{
}
# define WARNING(format, ...) wimlib_warning(T(format), ## __VA_ARGS__)
# define WARNING_WITH_ERRNO(format, ...) wimlib_warning(T(format), ## __VA_ARGS__)
#else /* ENABLE_ERROR_MESSAGES */
-# define ERROR(format, ...) dummy_printf(format, ## __VA_ARGS__)
-# define ERROR_WITH_ERRNO(format, ...) dummy_printf(format, ## __VA_ARGS__)
-# define WARNING(format, ...) dummy_printf(format, ## __VA_ARGS__)
-# define WARNING_WITH_ERRNO(format, ...) dummy_printf(format, ## __VA_ARGS__)
+# define ERROR(format, ...) dummy_tprintf(T(format), ## __VA_ARGS__)
+# define ERROR_WITH_ERRNO(format, ...) dummy_tprintf(T(format), ## __VA_ARGS__)
+# define WARNING(format, ...) dummy_tprintf(T(format), ## __VA_ARGS__)
+# define WARNING_WITH_ERRNO(format, ...) dummy_tprintf(T(format), ## __VA_ARGS__)
#endif /* !ENABLE_ERROR_MESSAGES */
#if defined(ENABLE_MORE_DEBUG) && !defined(ENABLE_DEBUG)
wimlib_debug(T(__FILE__), __LINE__, __func__, T(format), ## __VA_ARGS__);
#else
-# define DEBUG(format, ...) dummy_printf(format, ## __VA_ARGS__)
+# define DEBUG(format, ...) dummy_tprintf(T(format), ## __VA_ARGS__)
#endif /* !ENABLE_DEBUG */
#ifdef ENABLE_MORE_DEBUG
# define DEBUG2(format, ...) DEBUG(format, ## __VA_ARGS__)
#else
-# define DEBUG2(format, ...) dummy_printf(format, ## __VA_ARGS__)
+# define DEBUG2(format, ...) dummy_tprintf(T(format), ## __VA_ARGS__)
#endif /* !ENABLE_MORE_DEBUG */
#ifdef ENABLE_ASSERTIONS
extern void
randomize_char_array_with_alnum(tchar p[], size_t n);
-extern const tchar *
-path_next_part(const tchar *path, size_t *first_part_len_ret);
-
const tchar *
path_basename_with_len(const tchar *path, size_t len);
extern const tchar *
path_stream_name(const tchar *path);
-extern void
-to_parent_name(tchar *buf, size_t len);
-
-extern void
-print_string(const void *string, size_t len);
-
-extern int
-get_num_path_components(const char *path);
-
static inline void
print_byte_field(const u8 field[], size_t len)
{
#endif
}
+#ifdef __WIN32__
+# define wimlib_fprintf fwprintf
+# define wimlib_printf wprintf
+#else /* __WIN32__ */
extern int
-wimlib_fprintf(FILE *fp, const tchar *format, ...)
- //FORMAT(printf, 2, 3)
- ;
+wimlib_fprintf(FILE *fp, const tchar *format, ...) FORMAT(printf, 2, 3);
extern int
-wimlib_printf(const tchar *format, ...)
- //FORMAT(printf, 1, 2)
- ;
+wimlib_printf(const tchar *format, ...) FORMAT(printf, 1, 2);
+#endif /* !__WIN32__ */
+
+extern void
+zap_backslashes(tchar *s);
#endif /* _WIMLIB_UTIL_H */
#include "dentry.h"
#include "lookup_table.h"
-static int verify_inode(struct wim_inode *inode, const WIMStruct *w)
+static int
+verify_inode(struct wim_inode *inode, const WIMStruct *w)
{
const struct wim_lookup_table *table = w->lookup_table;
const struct wim_security_data *sd = wim_const_security_data(w);
* descriptor". Anything else has to be a valid index into the WIM
* image's security descriptors table. */
if (inode->i_security_id < -1) {
- ERROR("Dentry `%s' has an invalid security ID (%d)",
- first_dentry->full_path, inode->i_security_id);
+ ERROR("Dentry `%"TS"' has an invalid security ID (%d)",
+ first_dentry->full_path, inode->i_security_id);
goto out;
}
if (inode->i_security_id >= sd->num_entries) {
- ERROR("Dentry `%s' has an invalid security ID (%d) "
+ ERROR("Dentry `%"TS"' has an invalid security ID (%d) "
"(there are only %u entries in the security table)",
first_dentry->full_path, inode->i_security_id,
sd->num_entries);
lte = __lookup_resource(table, hash);
if (!lte && !is_zero_hash(hash)) {
ERROR("Could not find lookup table entry for stream "
- "%u of dentry `%s'", i, first_dentry->full_path);
+ "%u of dentry `%"TS"'",
+ i, first_dentry->full_path);
goto out;
}
if (lte)
lte->real_refcnt += inode->i_nlink;
-
- /* The following is now done when required by
- * wim_run_full_verifications(). */
-
- #if 0
- if (lte && !w->full_verification_in_progress &&
- lte->real_refcnt > lte->refcnt)
- {
- #ifdef ENABLE_ERROR_MESSAGES
- WARNING("The following lookup table entry "
- "has a reference count of %u, but",
- lte->refcnt);
- WARNING("We found %u references to it",
- lte->real_refcnt);
- WARNING("(One dentry referencing it is at `%s')",
- first_dentry->full_path_utf8);
-
- print_lookup_table_entry(lte);
- #endif
- /* Guess what! install.wim for Windows 8
- * contains many streams referenced by more
- * dentries than the refcnt stated in the lookup
- * table entry. So we will need to handle this
- * case and not just make it be an error... I'm
- * just setting the reference count to the
- * number of references we found.
- * (Unfortunately, even after doing this, the
- * reference count could be too low if it's also
- * referenced in other WIM images) */
-
- #if 1
- lte->refcnt = lte->real_refcnt;
- WARNING("Fixing reference count");
- #else
- goto out;
- #endif
- }
- #endif
}
}
num_unnamed_streams++;
}
if (num_unnamed_streams > 1) {
- ERROR("Dentry `%s' has multiple (%u) un-named streams",
+ ERROR("Dentry `%"TS"' has multiple (%u) un-named streams",
first_dentry->full_path, num_unnamed_streams);
goto out;
}
if (dentry_has_short_name(dentry)) {
if (dentry_with_dos_name) {
ERROR("Hard-linked file has a DOS name at "
- "both `%s' and `%s'",
+ "both `%"TS"' and `%"TS"'",
dentry_with_dos_name->full_path,
dentry->full_path);
goto out;
/* Directories with multiple links have not been tested. XXX */
if (inode->i_nlink > 1 && inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) {
- ERROR("Hard-linked directory `%s' is unsupported",
+ ERROR("Hard-linked directory `%"TS"' is unsupported",
first_dentry->full_path);
goto out;
}
}
/* Run some miscellaneous verifications on a WIM dentry */
-int verify_dentry(struct wim_dentry *dentry, void *wim)
+int
+verify_dentry(struct wim_dentry *dentry, void *wim)
{
int ret;
+ WIMStruct *w = wim;
/* Verify the associated inode, but only one time no matter how many
- * dentries it has. */
- if (!dentry->d_inode->i_verified) {
- ret = verify_inode(dentry->d_inode, wim);
+ * dentries it has (unless we are doing a full verification of the WIM,
+ * in which case we need to force the inode to be verified again.) */
+ if (!dentry->d_inode->i_verified || w->full_verification_in_progress) {
+ ret = verify_inode(dentry->d_inode, w);
if (ret != 0)
return ret;
}
}
} else {
if (!dentry_has_long_name(dentry)) {
- ERROR("Dentry `%s' has no long name!",
+ ERROR("Dentry `%"TS"' has no long name!",
dentry->full_path);
return WIMLIB_ERR_INVALID_DENTRY;
}
/* Check timestamps */
if (inode->i_last_access_time < inode->i_creation_time ||
inode->i_last_write_time < inode->i_creation_time) {
- WARNING("Dentry `%s' was created after it was last accessed or "
- "written to", dentry->full_path_utf8);
+ WARNING("Dentry `%"TS"' was created after it was last accessed or "
+ "written to", dentry->full_path);
}
#endif
return 0;
}
-static int image_run_full_verifications(WIMStruct *w)
+static int
+image_run_full_verifications(WIMStruct *w)
{
return for_dentry_in_tree(wim_root_dentry(w), verify_dentry, w);
}
-static int lte_fix_refcnt(struct wim_lookup_table_entry *lte, void *ctr)
+static int
+lte_fix_refcnt(struct wim_lookup_table_entry *lte, void *ctr)
{
if (lte->refcnt != lte->real_refcnt) {
#ifdef ENABLE_ERROR_MESSAGES
* problem by looking at ALL the images to re-calculate the reference count of
* EVERY lookup table entry. This only absolutely has to be done before an image
* is deleted or before an image is mounted read-write. */
-int wim_run_full_verifications(WIMStruct *w)
+int
+wim_run_full_verifications(WIMStruct *w)
{
int ret;
* @return:
* 0 on success; WIMLIB_ERR_SPLIT_INVALID if the set is not valid.
*/
-int verify_swm_set(WIMStruct *w, WIMStruct **additional_swms,
- unsigned num_additional_swms)
+int
+verify_swm_set(WIMStruct *w, WIMStruct **additional_swms,
+ unsigned num_additional_swms)
{
unsigned total_parts = w->hdr.total_parts;
int ctype;
const u8 *guid;
if (total_parts != num_additional_swms + 1) {
- ERROR("`%s' says there are %u parts in the spanned set, "
- "but %s%u part%s provided",
+ ERROR("`%"TS"' says there are %u parts in the spanned set, "
+ "but %"TS"%u part%"TS" provided",
w->filename, total_parts,
- (num_additional_swms + 1 < total_parts) ? "only " : "",
+ (num_additional_swms + 1 < total_parts) ? T("only ") : T(""),
num_additional_swms + 1,
- (num_additional_swms) ? "s were" : " was");
+ (num_additional_swms) ? T("s were") : T(" was"));
return WIMLIB_ERR_SPLIT_INVALID;
}
if (w->hdr.part_number != 1) {
- ERROR("WIM `%s' is not the first part of the split WIM.",
- w->filename);
+ ERROR("WIM `%"TS"' is not the first part of the split WIM.",
+ T(w->filename));
return WIMLIB_ERR_SPLIT_INVALID;
}
for (unsigned i = 0; i < num_additional_swms; i++) {
if (additional_swms[i]->hdr.total_parts != total_parts) {
- ERROR("WIM `%s' says there are %u parts in the spanned set, "
- "but %u parts were provided",
+ ERROR("WIM `%"TS"' says there are %u parts in the "
+ "spanned set, but %u parts were provided",
additional_swms[i]->filename,
additional_swms[i]->hdr.total_parts,
total_parts);
return WIMLIB_ERR_SPLIT_INVALID;
}
if (swm->hdr.part_number == 1) {
- ERROR("WIMs `%s' and `%s' both are marked as the "
- "first WIM in the spanned set",
+ ERROR("WIMs `%"TS"' and `%"TS"' both are marked "
+ "as the first WIM in the spanned set",
w->filename, swm->filename);
return WIMLIB_ERR_SPLIT_INVALID;
}
if (swm->hdr.part_number == 0 ||
swm->hdr.part_number > total_parts)
{
- ERROR("WIM `%s' says it is part %u in the spanned set, "
- "but the part number must be in the range "
- "[1, %u]",
+ ERROR("WIM `%"TS"' says it is part %u in the "
+ "spanned set, but the part number must "
+ "be in the range [1, %u]",
swm->filename, swm->hdr.part_number, total_parts);
return WIMLIB_ERR_SPLIT_INVALID;
}
if (parts_to_swms[swm->hdr.part_number - 2])
{
- ERROR("`%s' and `%s' are both marked as part %u of %u "
- "in the spanned set",
+ ERROR("`%"TS"' and `%"TS"' are both marked as "
+ "part %u of %u in the spanned set",
parts_to_swms[swm->hdr.part_number - 2]->filename,
swm->filename,
swm->hdr.part_number,
}
return 0;
}
-
struct wim_lookup_table *table;
int ret;
- DEBUG("Creating new WIM with %s compression.",
+ DEBUG("Creating new WIM with %"TS" compression.",
wimlib_get_compression_type_string(ctype));
/* Allocate the WIMStruct. */
if (!image_name_or_num || !*image_name_or_num)
return WIMLIB_NO_IMAGE;
- if (tstrcmp(image_name_or_num, T("all")) == 0
- || tstrcmp(image_name_or_num, T("*")) == 0)
+ if (!tstrcasecmp(image_name_or_num, T("all"))
+ || !tstrcasecmp(image_name_or_num, T("*")))
return WIMLIB_ALL_IMAGES;
image = tstrtol(image_name_or_num, &p, 10);
if (p != image_name_or_num && *p == T('\0') && image > 0) {
{
char *ctype = nl_langinfo(CODESET);
- return (strstr(ctype, "UTF-8") == 0 ||
- strstr(ctype, "UTF8") == 0 ||
- strstr(ctype, "utf8") == 0 ||
- strstr(ctype, "utf-8") == 0);
+ return (!strstr(ctype, "UTF-8") ||
+ !strstr(ctype, "UTF8") ||
+ !strstr(ctype, "utf8") ||
+ !strstr(ctype, "utf-8"));
}
-/* Get global memory allocations out of the way. Not strictly necessary in
+/* Get global memory allocations out of the way,
* single-threaded programs like 'imagex'. */
WIMLIBAPI int
wimlib_global_init()
/**
* Since wimlib 1.2.6: Initialization function for wimlib. This is not
* re-entrant. If you are calling wimlib functions concurrently in different
- * threads, then you must call this function serially first. Also, since wimlib
- * 1.3.0, you must call this function if the character encoding of the current
- * locale is not UTF-8. Otherwise, calling this function this function is not
- * required.
+ * threads, then you must call this function serially first.
*
- * This function always returns 0.
+ * Since wimlib 1.3.0, you must call this function if the character encoding of
+ * the current locale is not UTF-8.
+ *
+ * Since wimlib 1.3.2, you must call this function if using the Windows-native
+ * build of the library so that certain functions can be dynamically loaded from
+ * system DLLs.
+ *
+ * This function currently always returns 0, but it may return other error codes
+ * in future releases.
*/
extern int
wimlib_global_init();
#include <windows.h>
#include <ntdef.h>
#include <wchar.h>
-#include <shlwapi.h> /* shlwapi.h for PathMatchSpecA() */
+#include <shlwapi.h> /* shlwapi.h for PathMatchSpecW() */
#ifdef ERROR /* windows.h defines this */
# undef ERROR
#endif
if (hKernel32 == NULL) {
DEBUG("Loading Kernel32.dll");
- hKernel32 = LoadLibraryA("Kernel32.dll");
+ hKernel32 = LoadLibraryW(L"Kernel32.dll");
if (hKernel32 == NULL) {
err = GetLastError();
WARNING("Can't load Kernel32.dll");
} while (FindNextFileW(hFind, &dat));
err = GetLastError();
if (err != ERROR_NO_MORE_FILES) {
- ERROR("Failed to read directory \"%s\"", dir_path);
+ ERROR("Failed to read directory \"%ls\"", dir_path);
win32_error(err);
if (ret == 0)
ret = WIMLIB_ERR_READ;
size_t path_nchars;
wchar_t *path;
int ret;
-
+
path_nchars = wcslen(root_disk_path);
if (path_nchars > 32767)
return WIMLIB_ERR_INVALID_PARAM;
if (!path)
return WIMLIB_ERR_NOMEM;
+ wmemcpy(path, root_disk_path, path_nchars + 1);
+
ret = win32_build_dentry_tree_recursive(root_ret,
path,
path_nchars,
{
DWORD err;
HANDLE h;
- int ret;
const struct wim_inode *inode = dentry->d_inode;
DEBUG("Opening \"%ls\" to set timestamps", path);
# define INVALID_HANDLE_VALUE ((HANDLE)(-1))
#endif
-#if TCHAR_IS_UTF16LE
-# include <wchar.h>
-#endif
-
static int
fflush_and_ftruncate(FILE *fp, off_t size)
{
} else if (!hashes_equal(md, lte->hash)) {
ERROR("WIM resource has incorrect hash!");
if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK) {
- ERROR("We were reading it from `%s'; maybe it changed "
- "while we were reading it.",
+ ERROR("We were reading it from `%"TS"'; maybe "
+ "it changed while we were reading it.",
lte->file_on_disk);
}
ret = WIMLIB_ERR_INVALID_RESOURCE_HASH;
static int
open_wim_writable(WIMStruct *w, const tchar *path,
- bool trunc, bool readable)
+ bool trunc, bool also_readable)
{
const tchar *mode;
if (trunc)
- if (readable)
+ if (also_readable)
mode = T("w+b");
else
mode = T("wb");
};
struct xml_string_spec {
- const utf8char *name;
+ const char *name;
size_t offset;
};
return T("x86_64");
/* XXX Are there other arch values? */
default:
- return NULL;
+ return T("unknown");
}
}
}
static inline bool
-node_name_is(xmlNode *node, const utf8char *name)
+node_name_is(xmlNode *node, const char *name)
{
/* For now, both upper case and lower case element names are accepted. */
return strcasecmp((const char *)node->name, name) == 0;
}
-/* Finds the text node that is a child of an element node and returns its
- * content converted to a 64-bit unsigned integer. Returns 0 if no text node is
- * found. */
static u64
-node_get_u64(const xmlNode *u64_node)
+node_get_number(const xmlNode *u64_node, int base)
{
xmlNode *child;
for_node_child(u64_node, child)
if (node_is_text(child))
- return strtoull((const char *)child->content, NULL, 10);
+ return strtoull(child->content, NULL, base);
return 0;
}
+/* Finds the text node that is a child of an element node and returns its
+ * content converted to a 64-bit unsigned integer. Returns 0 if no text node is
+ * found. */
+static u64
+node_get_u64(const xmlNode *u64_node)
+{
+ return node_get_number(u64_node, 10);
+}
+
/* Like node_get_u64(), but expects a number in base 16. */
static u64
node_get_hex_u64(const xmlNode *u64_node)
{
- xmlNode *child;
- for_node_child(u64_node, child)
- if (node_is_text(child))
- return strtoull(child->content, NULL, 16);
- return 0;
+ return node_get_number(u64_node, 16);
}
static int
const struct windows_version *windows_version;
tprintf(T("Architecture: %"TS"\n"),
- get_arch(windows_info->arch) ?: T("unknown"));
+ get_arch(windows_info->arch));
if (windows_info->product_name) {
tprintf(T("Product Name: %"TS"\n"),
const tchar *tstr)
{
if (tstr) {
- utf8char *utf8_str;
+ char *utf8_str;
int rc = tstr_to_utf8_simple(tstr, &utf8_str);
if (rc)
return rc;
/* Writes a time element to the XML document being constructed in memory. */
static int
-xml_write_time(xmlTextWriter *writer, const utf8char *element_name, u64 time)
+xml_write_time(xmlTextWriter *writer, const char *element_name, u64 time)
{
int rc;
rc = xmlTextWriterStartElement(writer, element_name);
if (image_info->windows_info_exists) {
rc = xml_write_windows_info(writer, &image_info->windows_info);
- if (rc < 0)
+ if (rc)
return rc;
}
ret = dup_strings_from_specs(old, new, windows_info_xml_string_specs,
ARRAY_LEN(windows_info_xml_string_specs));
+ if (ret)
+ return ret;
if (old->languages) {
new->languages = CALLOC(old->num_languages, sizeof(new->languages[0]));
{
struct wim_info *wim_info;
- DEBUG("Deleting image %d from the XML data.", image);
-
wim_info = *wim_info_p;
+ wimlib_assert(image >= 1 && image <= wim_info->num_images);
+ DEBUG("Deleting image %d from the XML data.", image);
destroy_image_info(&wim_info->images[image - 1]);
image_info->dir_count = 0;
image_info->total_bytes = 0;
image_info->hard_link_bytes = 0;
-
image_info->lookup_table = w->lookup_table;
+
for_dentry_in_tree(w->image_metadata[image - 1].root_dentry,
calculate_dentry_statistics,
image_info);
}
if (!node_is_element(root) || !node_name_is(root, "WIM")) {
- ERROR("Expected <WIM> for the root XML element (found <%s>)",
- root->name);
+ ERROR("Expected <WIM> for the root XML element");
ret = WIMLIB_ERR_XML;
goto out_free_doc;
}
if (!name || !*name)
return false;
for (int i = 1; i <= w->hdr.image_count; i++)
- if (tstrcmp(w->wim_info->images[i - 1].name, name) == 0)
+ if (!tstrcmp(w->wim_info->images[i - 1].name, name))
return true;
return false;
}
--- /dev/null
+#ifndef _WIMLIB_TCHAR_H
+#define _WIMLIB_TCHAR_H
+
+/* Functions to act on "tchar" strings, which have a platform-dependent encoding
+ * and character size. */
+
+#ifdef __WIN32__
+#include <wchar.h>
+/* For Windows builds, the "tchar" type will be 2 bytes and will be equivalent
+ * to "wchar_t" and "utf16lechar". All indicate one code unit of a UTF16-LE
+ * string. */
+typedef wchar_t tchar;
+# define TCHAR_IS_UTF16LE 1
+# define _T(text) L##text
+# define T(text) _T(text) /* Make a string literal into a wide string */
+# define TS "ls" /* Format a string of "tchar" */
+# define WS "ls" /* Format a UTF-16LE string (same as above) */
+
+/* For Windows builds, the following definitions replace the "tchar" functions
+ * with the "wide-character" functions. */
+# define tmemchr wmemchr
+# define tmemcpy wmemcpy
+# define tstrcpy wcscpy
+# define tprintf wprintf
+# define tsprintf swprintf
+# define tfprintf fwprintf
+# define tvfprintf vfwprintf
+# define istalpha iswalpha
+# define istspace iswspace
+# define tstrcmp wcscmp
+# define tstrchr wcschr
+# define tstrpbrk wcspbrk
+# define tstrrchr wcsrchr
+# define tstrlen wcslen
+# define tmemcmp wmemcmp
+# define tstrcasecmp _wcsicmp
+# define tstrftime wcsftime
+# define tputchar putwchar
+# define tputc putwc
+# define tputs _putws
+# define tfputs fputws
+# define tfopen _wfopen
+# define tstat _wstati64
+# define tstrtol wcstol
+# define tstrtod wcstod
+# define tstrtoul wcstoul
+# define tunlink _wunlink
+# define tstrerror _wcserror
+# define taccess _waccess
+/* The following "tchar" functions do not have exact wide-character equivalents
+ * on Windows so require parameter rearrangement or redirection to a replacement
+ * function defined ourselves. */
+# define TSTRDUP WSTRDUP
+# define tmkdir(path, mode) _wmkdir(path)
+# define tstrerror_r(errnum, buf, bufsize) _wcserror_s(buf, bufsize, errnum)
+# define trename win32_rename_replacement
+# define ttruncate win32_truncate_replacement
+#else /* __WIN32__ */
+/* For non-Windows builds, the "tchar" type will be one byte and will specify a
+ * string in the locale-dependent multibyte encoding. However, only UTF-8 is
+ * well supported in this library. */
+typedef char tchar;
+# define TCHAR_IS_UTF16LE 0
+# define T(text) text /* In this case, strings of "tchar" are simply strings of
+ char */
+# define TS "s" /* Similarly, a string of "tchar" is printed just as a
+ normal string. */
+# define WS "W" /* UTF-16LE strings must be printed using a special
+ extension implemented by wimlib itself. Note that
+ "ls" will not work here because a string of wide
+ characters on non-Windows systems is typically not
+ UTF-16LE. */
+/* For non-Windows builds, replace the "tchar" functions with the regular old
+ * string functions. */
+# define tmemchr memchr
+# define tmemcpy memcpy
+# define tstrcpy strcpy
+# define tprintf printf
+# define tsprintf sprintf
+# define tfprintf fprintf
+# define tvfprintf vfprintf
+# define istalpha isalpha
+# define istspace isspace
+# define tstrcmp strcmp
+# define tstrchr strchr
+# define tstrpbrk strpbrk
+# define tstrrchr strrchr
+# define tstrlen strlen
+# define tmemcmp memcmp
+# define tstrcasecmp strcasecmp
+# define tstrftime strftime
+# define tputchar putchar
+# define tputc putc
+# define tputs puts
+# define tfputs fputs
+# define tfopen fopen
+# define tstat stat
+# define tunlink unlink
+# define tstrerror strerror
+# define tstrtol strtol
+# define tstrtod strtod
+# define tstrtoul strtoul
+# define tmkdir mkdir
+# define TSTRDUP STRDUP
+# define tstrerror_r strerror_r
+# define trename rename
+# define ttruncate truncate
+# define taccess access
+#endif /* !__WIN32__ */
+
+#endif /* _WIMLIB_TCHAR_H */