- Removed deprecated functions: some (de)compression functions,
wimlib_extract_files(), and wimlib_print_metadata().
+ - WIM paths passed to progress functions now have a leading
+ slash.
+
Version 1.6.2:
Case-insensitive comparisons of strings (e.g. filenames) containing
UTF-16 codepoints above 32767 are now done correctly.
# define WIMLIB_WIM_PATH_SEPARATOR_STRING "/"
#endif
+/** Use this to specify the root directory of the WIM image. */
+#define WIMLIB_WIM_ROOT_PATH WIMLIB_WIM_PATH_SEPARATOR_STRING
+
+/** Use this to test if the specified path refers to the root directory of the
+ * WIM image. */
+#define WIMLIB_IS_WIM_ROOT_PATH(path) \
+ ((path)[0] == WIMLIB_WIM_PATH_SEPARATOR && \
+ (path)[1] == 0)
+
#ifdef __GNUC__
# define _wimlib_deprecated __attribute__((deprecated))
#else
union {
/** Target path in the WIM image. Only valid on
* messages ::WIMLIB_PROGRESS_MSG_SCAN_BEGIN and
- * ::WIMLIB_PROGRESS_MSG_SCAN_END. If capturing a full
- * image, this will be the empty string; otherwise it
- * will name the place in the WIM image at which the
- * directory tree is being added. */
+ * ::WIMLIB_PROGRESS_MSG_SCAN_END. */
const wimlib_tchar *wim_target_path;
/** For ::WIMLIB_PROGRESS_MSG_SCAN_DENTRY and a status
* data stream, or a reparse data buffer. */
uint64_t num_streams;
- /** This will be the empty string. */
- const wimlib_tchar *extract_root_wim_source_path;
+ /** Reserved. */
+ const wimlib_tchar *reserved_2;
/** Currently only used for
* ::WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN. */
* filesystem to be included in the WIM image. */
wimlib_tchar *fs_source_path;
- /** Destination path in the WIM image. Leading and trailing slashes are
- * ignored. The empty string or @c NULL means the root directory of the
- * WIM image. */
+ /** Destination path in the WIM image. Use WIMLIB_WIM_ROOT_PATH to
+ * specify the root directory of the WIM image. */
wimlib_tchar *wim_target_path;
/** Reserved; set to 0. */
/** Data for a ::WIMLIB_UPDATE_OP_ADD operation. */
struct wimlib_add_command {
- /** Filesystem path to the file or directory tree to
- * add. */
+ /** Filesystem path to the file or directory tree to add. */
wimlib_tchar *fs_source_path;
- /** Path, specified from the root of the WIM image, at
- * which to add the file or directory tree within the
- * WIM image. */
+
+ /** Destination path in the WIM image. Use WIMLIB_WIM_ROOT_PATH to
+ * specify the root directory of the WIM image. */
wimlib_tchar *wim_target_path;
/** Path to capture configuration file to use, or @c NULL for default.
/** Data for a ::WIMLIB_UPDATE_OP_DELETE operation. */
struct wimlib_delete_command {
- /** Path, specified from the root of the WIM image, for
- * the file or directory tree within the WIM image to be
- * deleted. */
+
+ /** Path, specified from the root of the WIM image, for the file or
+ * directory tree within the WIM image to be deleted. */
wimlib_tchar *wim_path;
- /** Bitwise OR of WIMLIB_DELETE_FLAG_* flags. */
+
+ /** Bitwise OR of WIMLIB_DELETE_FLAG_* flags. */
int delete_flags;
};
/** Data for a ::WIMLIB_UPDATE_OP_RENAME operation. */
struct wimlib_rename_command {
- /** Path, specified from the root of the WIM image, for
- * the source file or directory tree within the WIM
- * image. */
+
+ /** Path, specified from the root of the WIM image, for the source file
+ * or directory tree within the WIM image. */
wimlib_tchar *wim_source_path;
- /** Path, specified from the root of the WIM image, for
- * the destination file or directory tree within the WIM
- * image. */
+
+ /** Path, specified from the root of the WIM image, for the destination
+ * file or directory tree within the WIM image. */
wimlib_tchar *wim_target_path;
- /** Reserved; set to 0. */
+
+ /** Reserved; set to 0. */
int rename_flags;
};
#ifdef __WIN32__
# include "imagex-win32.h"
-# define OS_PREFERRED_PATH_SEPARATOR L'\\'
-# define OS_PREFERRED_PATH_SEPARATOR_STRING L"\\"
# define print_security_descriptor win32_print_security_descriptor
#else /* __WIN32__ */
# include <getopt.h>
# include <langinfo.h>
-# define OS_PREFERRED_PATH_SEPARATOR '/'
-# define OS_PREFERRED_PATH_SEPARATOR_STRING "/"
# define print_security_descriptor default_print_security_descriptor
static inline void set_fd_to_binary_mode(int fd)
{
break;
case WIMLIB_PROGRESS_MSG_SCAN_BEGIN:
imagex_printf(T("Scanning \"%"TS"\""), info->scan.source);
- if (*info->scan.wim_target_path) {
- imagex_printf(T(" (loading as WIM path: "
- "\""WIMLIB_WIM_PATH_SEPARATOR_STRING"%"TS"\")...\n"),
- info->scan.wim_target_path);
- } else {
+ if (WIMLIB_IS_WIM_ROOT_PATH(info->scan.wim_target_path)) {
imagex_printf(T("\n"));
+ } else {
+ imagex_printf(T(" (loading as WIM path: \"%"TS"\")...\n"),
+ info->scan.wim_target_path);
}
memset(&last_scan_progress, 0, sizeof(last_scan_progress));
break;
T("NTFS volume") : T("directory")),
info->extract.target);
break;
- case WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN:
- if (info->extract.extract_root_wim_source_path[0]) {
- imagex_printf(T("Extracting \"%"TS"\" from image %d "
- "(\"%"TS"\") in \"%"TS"\" to \"%"TS"\"\n"),
- info->extract.extract_root_wim_source_path,
- info->extract.image,
- info->extract.image_name,
- info->extract.wimfile_name,
- info->extract.target);
- }
- break;
case WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS:
percent_done = TO_PERCENT(info->extract.completed_bytes,
info->extract.total_bytes);
}
break;
case WIMLIB_PROGRESS_MSG_APPLY_TIMESTAMPS:
- if (info->extract.extract_root_wim_source_path[0] == T('\0'))
- imagex_printf(T("Setting timestamps on all extracted files...\n"));
+ imagex_printf(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) {
case WIMLIB_PROGRESS_MSG_UPDATE_END_COMMAND:
switch (info->update.command->op) {
case WIMLIB_UPDATE_OP_DELETE:
- imagex_printf(T("Deleted WIM path "
- "\""WIMLIB_WIM_PATH_SEPARATOR_STRING "%"TS"\"\n"),
+ imagex_printf(T("Deleted WIM path \"%"TS"\"\n"),
info->update.command->delete_.wim_path);
break;
case WIMLIB_UPDATE_OP_RENAME:
- imagex_printf(T("Renamed WIM path "
- "\""WIMLIB_WIM_PATH_SEPARATOR_STRING "%"TS"\" => "
- "\""WIMLIB_WIM_PATH_SEPARATOR_STRING "%"TS"\"\n"),
+ imagex_printf(T("Renamed WIM path \"%"TS"\" => \"%"TS"\"\n"),
info->update.command->rename.wim_source_path,
info->update.command->rename.wim_target_path);
break;
/* Set up capture source in non-source-list mode. */
capture_sources = alloca(sizeof(struct wimlib_capture_source));
capture_sources[0].fs_source_path = source;
- capture_sources[0].wim_target_path = NULL;
+ capture_sources[0].wim_target_path = WIMLIB_WIM_ROOT_PATH;
capture_sources[0].reserved = 0;
num_sources = 1;
capture_sources_malloced = false;
WIMStruct *wim = NULL;
int image;
int ret;
- const tchar *path = T("");
+ const tchar *path = WIMLIB_WIM_ROOT_PATH;
int c;
struct print_dentry_options options = {
.detailed = false,
STRING_SET(refglobs);
- tchar *root_path = T("");
+ tchar *root_path = WIMLIB_WIM_ROOT_PATH;
for_opt(c, extract_options) {
switch (c) {
* */
const struct wimlib_capture_source capture_src = {
.fs_source_path = (tchar*)source,
- .wim_target_path = T(""),
+ .wim_target_path = WIMLIB_WIM_ROOT_PATH,
.reserved = 0,
};
return wimlib_add_image_multisource(wim, &capture_src, 1, name,
ctx.progress.extract.target = target;
}
- ctx.progress.extract.extract_root_wim_source_path = T("");
ctx.target_dentry = wim_root_dentry(wim);
/* Note: ctx.target_dentry represents the dentry that gets extracted to
* @target. There may be none, in which case it gets set to the image
const tchar *target, int extract_flags,
wimlib_progress_func_t progress_func)
{
- const tchar *path = T("");
+ const tchar *path = WIMLIB_WIM_ROOT_PATH;
extract_flags |= WIMLIB_EXTRACT_FLAG_IMAGEMODE;
return do_wimlib_extract_paths(wim, image, target, &path, 1,
extract_flags, progress_func);
* canonicalize_wim_path() - Given a user-provided path to a file within a WIM
* image, translate it into a "canonical" path.
*
- * To do this, translate all supported path separators (is_any_path_separator())
- * into the WIM_PATH_SEPARATOR, and strip any leading and trailing slashes. The
- * returned string is allocated. Note that there still may be consecutive path
- * separators within the string. Furthermore, the string may be empty, which
- * indicates the root dentry of the WIM image.
+ * - Translate both types of slash into a consistent type (WIM_PATH_SEPARATOR).
+ * - Collapse path separators.
+ * - Add leading slash if missing.
+ * - Strip trailing slashes.
+ *
+ * Examples (with WIM_PATH_SEPARATOR == '/'):
+ *
+ * => / [ either NULL or empty string ]
+ * / => /
+ * \ => /
+ * hello => /hello
+ * \hello => /hello
+ * \hello => /hello
+ * /hello/ => /hello
+ * \hello/ => /hello
+ * /hello//1 => /hello/1
+ * \\hello\\1\\ => /hello/1
*/
tchar *
canonicalize_wim_path(const tchar *wim_path)
{
- tchar *canonical_path;
- tchar *p;
-
- if (wim_path == NULL) {
- wim_path = T("");
- } else {
- /* Strip leading path separators. */
- while (is_any_path_separator(*wim_path))
- wim_path++;
- }
+ const tchar *in;
+ tchar *out;
+ tchar *result;
- canonical_path = TSTRDUP(wim_path);
- if (canonical_path == NULL)
+ in = wim_path;
+ if (!in)
+ in = T("");
+
+ result = MALLOC((1 + tstrlen(in) + 1) * sizeof(result[0]));
+ if (!result)
return NULL;
- /* Translate all path separators to WIM_PATH_SEPARATOR. */
- for (p = canonical_path; *p; p++)
- if (is_any_path_separator(*p))
- *p = WIM_PATH_SEPARATOR;
+ out = result;
+
+ /* Add leading slash if missing */
+ if (!is_any_path_separator(*in))
+ *out++ = WIM_PATH_SEPARATOR;
+
+ while (*in) {
+ if (is_any_path_separator(*in)) {
+ /* Collapse multiple path separators into one */
+ *out++ = WIM_PATH_SEPARATOR;
+ do {
+ in++;
+ } while (is_any_path_separator(*in));
+ } else {
+ /* Copy non-path-separator character */
+ *out++ = *in++;
+ }
+ }
+
+ /* Remove trailing slash if existent */
+ if (*(out - 1) == WIM_PATH_SEPARATOR && (out - 1) != result)
+ --out;
- /* Strip trailing path separators. */
- while (p > canonical_path && *--p == WIM_PATH_SEPARATOR)
- *p = T('\0');
+ *out = T('\0');
- return canonical_path;
+ return result;
}
free_update_command_journal(j);
}
+/*
+ * Set the name of @branch for placing it at @target in the WIM image. This
+ * assumes that @target is in "canonical form", as produced by
+ * canonicalize_wim_path().
+ *
+ * Note: for the root target this produces the empty name.
+ */
static int
set_branch_name(struct wim_dentry *branch, const utf16lechar *target)
{
const utf16lechar *p;
+ /* Find end of string. (We can assume it contains at least one
+ * character, the leading slash.) */
+ wimlib_assert(target[0] == cpu_to_le16(WIM_PATH_SEPARATOR));
p = target;
- while (*p)
+ do {
p++;
+ } while (*p);
- /* No trailing slashes allowed */
- wimlib_assert(p == target || *(p - 1) != cpu_to_le16(WIM_PATH_SEPARATOR));
-
- while (p > target && *(p - 1) != cpu_to_le16(WIM_PATH_SEPARATOR))
+ while (*(p - 1) != cpu_to_le16(WIM_PATH_SEPARATOR))
p--;
+
+ /* We're assuming no trailing slashes. */
+ wimlib_assert(*p || p == &target[1]);
+
return dentry_set_name_utf16le(branch, p);
}
config.prefix = fs_source_path;
config.prefix_num_tchars = tstrlen(fs_source_path);
- if (wim_target_path[0] == T('\0'))
+ if (WIMLIB_IS_WIM_ROOT_PATH(wim_target_path))
params.add_flags |= WIMLIB_ADD_FLAG_ROOT;
ret = (*capture_tree)(&branch, fs_source_path, ¶ms);
if (ret)
if (progress_func)
progress_func(WIMLIB_PROGRESS_MSG_SCAN_END, ¶ms.progress);
- if (wim_target_path[0] == T('\0') &&
+ if (WIMLIB_IS_WIM_ROOT_PATH(wim_target_path) &&
branch && !dentry_is_directory(branch))
{
ERROR("\"%"TS"\" is not a directory!", fs_source_path);
goto out_cleanup_after_capture;
if (config_file && (add_flags & WIMLIB_ADD_FLAG_WIMBOOT) &&
- wim_target_path[0] == T('\0'))
+ WIMLIB_IS_WIM_ROOT_PATH(wim_target_path))
{
params.add_flags = 0;
params.progress_func = NULL;
WIMLIB_ADD_FLAG_NO_REPLACE))
return WIMLIB_ERR_INVALID_PARAM;
- /* Are we adding the entire image or not? An empty wim_target_path
- * indicates that the tree we're adding is to be placed in the root of
- * the image. We consider this to be capturing the entire image,
- * although it could potentially be an overlay on an existing root as
- * well. */
- bool is_entire_image = cmd->add.wim_target_path[0] == T('\0');
+ bool is_entire_image = WIMLIB_IS_WIM_ROOT_PATH(cmd->add.wim_target_path);
#ifdef __WIN32__
/* Check for flags not supported on Windows */