the WIM image, like those output by the \fB@IMAGEX_PROGNAME@ dir\fR (1) command.
However, path separators may be either forward or backward slashes, and the
leading slash is optional; also, on Windows, the paths are treated
-case-insensitively, while on UNIX, paths are treated case-sensitively.
+case-insensitively, while on UNIX, paths are treated case-sensitively, except
+when overwritten through the \fBWIMLIB_IMAGEX_IGNORE_CASE\fR environmental
+variable, as documented in \fB@IMAGEX_PROGNAME@\fR (1).
.PP
If no \fIPATH\fRs are provided, the default behavior is to extract the full
image, as if the path "/" had been provided.
\fB--strict-wildcards\fR
Fail if any wildcards or paths in \fILISTFILE\fR do not match any files in the
WIM image. The default behavior is to warn only.
-.TP
-\fB--case-insensitive-wildcards\fR
-Treat the wildcards or paths in \fILISTFILE\fR as case-insensitive. On Windows
-this is already the default behavior, but on UNIX-like systems it is not.
.SH NOTES
See the documentation \fB@IMAGEX_PROGNAME@ apply\fR (1) for documentation about
what data and metadata are extracted on UNIX-like systems versus on Windows.
this functionality is not available in Windows builds of wimlib and
\fB@IMAGEX_PROGNAME@\fR.)
.SH LOCALES AND CHARACTER ENCODINGS
-On Windows, wimlib works in UTF-16LE, and there should be no problems with
-character encodings.
+WIM files themselves store file and stream names using the UTF16-LE. On
+Windows, wimlib works in UTF-16LE, so conversions are usually necessary and
+there should be no problems with character encodings, except possibly in the XML
+data.
.PP
-On UNIX, wimlib works primarily in the locale-dependent multibyte encoding,
-which you are strongly recommended to set to UTF-8 to avoid any problems.
+On UNIX-like systems, wimlib works primarily in the locale-dependent multibyte
+encoding, which you are strongly recommended to set to UTF-8 to avoid any
+problems. You can alternatively set the environmental variable
+\fBWIMLIB_IMAGEX_USE_UTF8\fR to force \fB@IMAGEX_PROGNAME@\fR to use UTF-8
+character encoding internally, even if the current locale is not UTF-8
+compatible.
.SH CASE SENSITIVITY
-The case sensitivity of \fB@IMAGEX_PROGNAME@\fR differs somewhat between
-UNIX-like systems and Windows. Filenames are internally treated as
-case-sensitive, but on Windows paths actually provided by the user will be
-treated as case-insensitive in order to get the "expected" behavior. Otherwise,
-options and non-path arguments should be specified in lower case.
+By default, the case sensitivity of \fB@IMAGEX_PROGNAME@\fR differs somewhat
+between UNIX-like systems and Windows. WIM images may (but usually do not) have
+multiple files with the same case-insensitive name. Internally, wimlib
+stores filenames as case-sensitive, but on Windows paths
+actually provided by the user for use in a WIM image (e.g. for extracting,
+adding, renaming, or deleting files) will be treated as case-insensitive in
+order to get the "expected" behavior. This differs from the default behavior on
+UNIX-like systems, where such paths will be treated as case-sensitive. Note
+that with case insensitively, a path component may in general be ambiguous due
+to multiple files or directories having the same case-insensitive name. In such
+cases, if there is a file or directory with an exactly matching name, it is
+chosen; otherwise, one of the case-insensitively matching file or directories is
+chosen arbitrarily.
+.PP
+The default behavior can be overwritten by explicitly setting the environmental
+variable \fBWIMLIB_IMAGEX_IGNORE_CASE\fR to 1, in which case such paths will be
+treated case insensitively, or 0, in which such paths will be treated case
+sensitsively.
+.PP
+Regardless of these settings, options and non-path arguments must be specified
+in lower case.
.SH LICENSE
wimlib and \fB@IMAGEX_PROGNAME@\fR are distributed under the GNU General Public
License version 3 or later. Be aware this means this software is provided as-is
* one of the provided globs did not match a file. */
#define WIMLIB_EXTRACT_FLAG_STRICT_GLOB 0x00080000
-/** In combination with ::WIMLIB_EXTRACT_FLAG_GLOB_PATHS, causes the globbing to
- * be performed case insensitively. On Windows this is already the default
- * behavior but on UNIX-like systems it is not. */
-#define WIMLIB_EXTRACT_FLAG_CASE_INSENSITIVE_GLOB 0x00100000
-
/** @} */
/** @ingroup G_mounting_wim_images
* @{ */
*/
#define WIMLIB_INIT_FLAG_STRICT_APPLY_PRIVILEGES 0x00000008
+/** Default to interpreting WIM paths case sensitively (default on UNIX-like
+ * systems). */
+#define WIMLIB_INIT_FLAG_DEFAULT_CASE_SENSITIVE 0x00000010
+
+/** Default to interpreting WIM paths case insensitively (default on Windows).
+ * This does not apply to mounted images. */
+#define WIMLIB_INIT_FLAG_DEFAULT_CASE_INSENSITIVE 0x00000020
+
/** @} */
/** @ingroup G_nonstandalone_wims
* @{ */
* case sensitive long name. */
struct rb_node rb_node;
-#ifdef __WIN32__
/* Node for the parent's red-black tree of child dentries, sorted by
* case insensitive long name. */
struct rb_node rb_node_case_insensitive;
/* List of dentries in a directory that have different case sensitive
* long names but share the same case insensitive long name */
struct list_head case_insensitive_conflict_list;
-#endif
/* Length of UTF-16LE encoded short filename, in bytes, not including
* the terminating zero wide-character. */
* any. Keyed by wim_dentry->file_name, case sensitively. */
struct rb_root i_children;
-#ifdef __WIN32__
/* Root of a red-black tree storing the children of this inode, if any.
* Keyed by wim_dentry->file_name, case insensitively. */
struct rb_root i_children_case_insensitive;
-#endif
/* List of dentries that are aliases for this inode. There will be
* i_nlink dentries in this list. */
extern int
set_dentry_name(struct wim_dentry *dentry, const tchar *new_name);
-extern struct wim_dentry *
-get_dentry(struct WIMStruct *wim, const tchar *path);
-extern struct wim_inode *
-wim_pathname_to_inode(struct WIMStruct *wim, const tchar *path);
+typedef enum {
+ /* NTFS-3g headers define CASE_SENSITIVE... */
+ WIMLIB_CASE_PLATFORM_DEFAULT = 0,
+ WIMLIB_CASE_SENSITIVE = 1,
+ WIMLIB_CASE_INSENSITIVE = 2,
+} CASE_SENSITIVITY_TYPE;
+
+extern bool default_ignore_case;
+
+extern struct wim_dentry *
+get_dentry(struct WIMStruct *wim, const tchar *path,
+ CASE_SENSITIVITY_TYPE case_type);
extern struct wim_dentry *
get_dentry_child_with_name(const struct wim_dentry *dentry,
- const tchar *name);
+ const tchar *name,
+ CASE_SENSITIVITY_TYPE case_type);
extern struct wim_dentry *
get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry,
const utf16lechar *name,
- size_t name_nbytes);
+ size_t name_nbytes,
+ CASE_SENSITIVITY_TYPE case_type);
extern struct wim_dentry *
-get_parent_dentry(struct WIMStruct *wim, const tchar *path);
+get_parent_dentry(struct WIMStruct *wim, const tchar *path,
+ CASE_SENSITIVITY_TYPE case_type);
extern int
print_dentry(struct wim_dentry *dentry, void *lookup_table);
dentry_add_child(struct wim_dentry * restrict parent,
struct wim_dentry * restrict child);
+extern int
+rename_wim_path(WIMStruct *wim, const tchar *from, const tchar *to,
+ CASE_SENSITIVITY_TYPE case_type);
+
extern struct wim_ads_entry *
inode_get_ads_entry(struct wim_inode *inode, const tchar *stream_name,
u16 *idx_ret);
extern void
iconv_global_cleanup(void);
+extern void
+init_upcase(void);
+
extern bool wimlib_mbs_is_utf8;
#define DECLARE_CHAR_CONVERSION_FUNCTIONS(varname1, varname2, \
extern int
tstr_to_utf8_simple(const tchar *tstr, char **out);
+extern int
+cmp_utf16le_strings(const utf16lechar *s1, size_t n1,
+ const utf16lechar *s2, size_t n2,
+ bool ignore_case);
+
#endif /* _WIMLIB_ENCODING_H */
extern int
expand_wildcard_wim_paths(WIMStruct *wim,
- const char * const *wildcards,
+ const tchar * const *wildcards,
size_t num_wildcards,
tchar ***expanded_paths_ret,
size_t *num_expanded_paths_ret,
#ifdef __WIN32__
extern int
fnmatch(const tchar *pattern, const tchar *string, int flags);
-# define FNM_CASEFOLD 0
+# define FNM_CASEFOLD 0x1
+# define FNM_PATHNAME 0x2
+# define FNM_NOESCAPE 0x4
+# define FNM_NOMATCH 1
#else
# include <fnmatch.h>
# ifndef FNM_CASEFOLD
extern int
write_wim_header_flags(u32 hdr_flags, struct filedes *out_fd);
-extern int
-rename_wim_path(WIMStruct *wim, const tchar *from, const tchar *to);
-
extern int
select_wim_image(WIMStruct *wim, int image);
extern void
win32_global_cleanup(void);
-#define FNM_PATHNAME 0x1
-#define FNM_NOESCAPE 0x2
-#define FNM_NOMATCH 1
-extern int
-fnmatch(const tchar *pattern, const tchar *string, int flags);
-
extern int
fsync(int fd);
# define taccess _waccess
# define tstrdup wcsdup
# define ttempnam _wtempnam
+# define tgetenv _wgetenv
/* 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 tmkdir mkdir
# define tstrdup strdup
# define ttempnam tempnam
+# define tgetenv getenv
# define TSTRDUP STRDUP
# define tstrerror_r strerror_r
# define trename rename
enum {
IMAGEX_ALLOW_OTHER_OPTION,
IMAGEX_BOOT_OPTION,
- IMAGEX_CASE_INSENSITIVE_WILDCARDS_OPTION,
IMAGEX_CHECK_OPTION,
IMAGEX_CHUNK_SIZE_OPTION,
IMAGEX_COMMAND_OPTION,
{T("include-invalid-names"), no_argument, NULL, IMAGEX_INCLUDE_INVALID_NAMES_OPTION},
{T("strict-wildcards"), no_argument, NULL, IMAGEX_STRICT_WILDCARDS_OPTION},
{T("no-wildcards"), no_argument, NULL, IMAGEX_NO_WILDCARDS_OPTION},
- {T("case-insensitive-wildcards"), no_argument, NULL, IMAGEX_CASE_INSENSITIVE_WILDCARDS_OPTION},
{NULL, 0, NULL, 0},
};
case IMAGEX_NO_WILDCARDS_OPTION:
listfile_extract_flags &= ~WIMLIB_EXTRACT_FLAG_GLOB_PATHS;
break;
- case IMAGEX_CASE_INSENSITIVE_WILDCARDS_OPTION:
- listfile_extract_flags |= WIMLIB_EXTRACT_FLAG_CASE_INSENSITIVE_GLOB;
- break;
case IMAGEX_STRICT_WILDCARDS_OPTION:
listfile_extract_flags |= WIMLIB_EXTRACT_FLAG_STRICT_GLOB;
break;
}
}
+
#endif /* !__WIN32__ */
+ {
+ tchar *igcase = tgetenv(T("WIMLIB_IMAGEX_IGNORE_CASE"));
+ if (igcase != NULL) {
+ if (!tstrcmp(igcase, T("no")) ||
+ !tstrcmp(igcase, T("0")))
+ init_flags |= WIMLIB_INIT_FLAG_DEFAULT_CASE_SENSITIVE;
+ else if (!tstrcmp(igcase, T("yes")) ||
+ !tstrcmp(igcase, T("1")))
+ init_flags |= WIMLIB_INIT_FLAG_DEFAULT_CASE_INSENSITIVE;
+ else {
+ fprintf(stderr,
+ "WARNING: Ignoring unknown setting of "
+ "WIMLIB_IMAGEX_IGNORE_CASE\n");
+ }
+ }
+ }
+
/* Allow being invoked as wimCOMMAND (e.g. wimapply). */
cmd = CMD_NONE;
if (!tstrncmp(invocation_name, T("wim"), 3) &&
#include "wimlib/error.h"
#include "wimlib/lookup_table.h"
#include "wimlib/metadata.h"
+#include "wimlib/paths.h"
#include "wimlib/resource.h"
#include "wimlib/security.h"
#include "wimlib/sha1.h"
}
}
-/* Case-sensitive UTF-16LE dentry or stream name comparison. Used on both UNIX
- * (always) and Windows (sometimes) */
-static int
-compare_utf16le_names_case_sensitive(const utf16lechar *name1, size_t nbytes1,
- const utf16lechar *name2, size_t nbytes2)
-{
- /* Return the result if the strings differ up to their minimum length.
- * Note that we cannot use strcmp() or strncmp() here, as the strings
- * are in UTF-16LE format. */
- int result = memcmp(name1, name2, min(nbytes1, nbytes2));
- if (result)
- return result;
-
- /* The strings are the same up to their minimum length, so return a
- * result based on their lengths. */
- if (nbytes1 < nbytes2)
- return -1;
- else if (nbytes1 > nbytes2)
- return 1;
- else
- return 0;
-}
-
-#ifdef __WIN32__
-/* Windoze: Case-insensitive UTF-16LE dentry or stream name comparison */
-static int
-compare_utf16le_names_case_insensitive(const utf16lechar *name1, size_t nbytes1,
- const utf16lechar *name2, size_t nbytes2)
-{
- /* Return the result if the strings differ up to their minimum length.
- * */
- int result = _wcsnicmp((const wchar_t*)name1, (const wchar_t*)name2,
- min(nbytes1 / 2, nbytes2 / 2));
- if (result)
- return result;
-
- /* The strings are the same up to their minimum length, so return a
- * result based on their lengths. */
- if (nbytes1 < nbytes2)
- return -1;
- else if (nbytes1 > nbytes2)
- return 1;
- else
- return 0;
-}
-#endif /* __WIN32__ */
-
-#ifdef __WIN32__
-# define compare_utf16le_names compare_utf16le_names_case_insensitive
-#else
-# define compare_utf16le_names compare_utf16le_names_case_sensitive
-#endif
-
-
-#ifdef __WIN32__
static int
dentry_compare_names_case_insensitive(const struct wim_dentry *d1,
const struct wim_dentry *d2)
{
- return compare_utf16le_names_case_insensitive(d1->file_name,
- d1->file_name_nbytes,
- d2->file_name,
- d2->file_name_nbytes);
+ return cmp_utf16le_strings(d1->file_name,
+ d1->file_name_nbytes / 2,
+ d2->file_name,
+ d2->file_name_nbytes / 2,
+ true);
}
-#endif /* __WIN32__ */
static int
dentry_compare_names_case_sensitive(const struct wim_dentry *d1,
const struct wim_dentry *d2)
{
- return compare_utf16le_names_case_sensitive(d1->file_name,
- d1->file_name_nbytes,
- d2->file_name,
- d2->file_name_nbytes);
+ return cmp_utf16le_strings(d1->file_name,
+ d1->file_name_nbytes / 2,
+ d2->file_name,
+ d2->file_name_nbytes / 2,
+ false);
}
-#ifdef __WIN32__
-# define dentry_compare_names dentry_compare_names_case_insensitive
-#else
-# define dentry_compare_names dentry_compare_names_case_sensitive
-#endif
-
/* Return %true iff the alternate data stream entry @entry has the UTF-16LE
* stream name @name that has length @name_nbytes bytes. */
static inline bool
ads_entry_has_name(const struct wim_ads_entry *entry,
- const utf16lechar *name, size_t name_nbytes)
+ const utf16lechar *name, size_t name_nbytes,
+ bool ignore_case)
{
- return !compare_utf16le_names(name, name_nbytes,
- entry->stream_name,
- entry->stream_name_nbytes);
+ return 0 == cmp_utf16le_strings(name,
+ name_nbytes / 2,
+ entry->stream_name,
+ entry->stream_name_nbytes / 2,
+ ignore_case);
}
+bool default_ignore_case =
+#ifdef __WIN32__
+ true
+#else
+ false
+#endif
+;
+
+static bool
+will_ignore_case(CASE_SENSITIVITY_TYPE case_type)
+{
+ if (case_type == WIMLIB_CASE_SENSITIVE)
+ return false;
+ if (case_type == WIMLIB_CASE_INSENSITIVE)
+ return true;
+
+ return default_ignore_case;
+}
+
+
/* Given a UTF-16LE filename and a directory, look up the dentry for the file.
* Return it if found, otherwise NULL. This is case-sensitive on UNIX and
* case-insensitive on Windows. */
struct wim_dentry *
get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry,
const utf16lechar *name,
- size_t name_nbytes)
+ size_t name_nbytes,
+ CASE_SENSITIVITY_TYPE case_ctype)
{
struct rb_node *node;
-#ifdef __WIN32__
- node = dentry->d_inode->i_children_case_insensitive.rb_node;
-#else
- node = dentry->d_inode->i_children.rb_node;
-#endif
+ bool ignore_case = will_ignore_case(case_ctype);
+
+ if (ignore_case)
+ node = dentry->d_inode->i_children_case_insensitive.rb_node;
+ else
+ node = dentry->d_inode->i_children.rb_node;
struct wim_dentry *child;
while (node) {
- #ifdef __WIN32__
- child = rb_entry(node, struct wim_dentry, rb_node_case_insensitive);
- #else
- child = rbnode_dentry(node);
- #endif
- int result = compare_utf16le_names(name, name_nbytes,
- child->file_name,
- child->file_name_nbytes);
- if (result < 0)
+ if (ignore_case)
+ child = rb_entry(node, struct wim_dentry, rb_node_case_insensitive);
+ else
+ child = rb_entry(node, struct wim_dentry, rb_node);
+
+ int result = cmp_utf16le_strings(name,
+ name_nbytes / 2,
+ child->file_name,
+ child->file_name_nbytes / 2,
+ ignore_case);
+ if (result < 0) {
node = node->rb_left;
- else if (result > 0)
+ } else if (result > 0) {
node = node->rb_right;
- else {
- #ifdef __WIN32__
- if (!list_empty(&child->case_insensitive_conflict_list))
- {
- WARNING("Result of case-insensitive lookup is ambiguous "
- "(returning \"%ls\" instead of \"%ls\")",
- child->file_name,
- container_of(child->case_insensitive_conflict_list.next,
- struct wim_dentry,
- case_insensitive_conflict_list)->file_name);
- }
- #endif
+ } else if (!ignore_case ||
+ list_empty(&child->case_insensitive_conflict_list)) {
+ return child;
+ } else {
+ /* Multiple dentries have the same case-insensitive
+ * name, and a case-insensitive lookup is being
+ * performed. Choose the dentry with the same
+ * case-sensitive name, if one exists; otherwise print a
+ * warning and choose one arbitrarily. */
+ struct wim_dentry *alt = child;
+ size_t num_alts = 0;
+
+ do {
+ num_alts++;
+ if (0 == cmp_utf16le_strings(name,
+ name_nbytes / 2,
+ alt->file_name,
+ alt->file_name_nbytes / 2,
+ false))
+ return alt;
+ alt = list_entry(alt->case_insensitive_conflict_list.next,
+ struct wim_dentry,
+ case_insensitive_conflict_list);
+ } while (alt != child);
+
+ WARNING("Result of case-insensitive lookup is ambiguous\n"
+ " (returning \"%"TS"\" of %zu "
+ "possible files, including \"%"TS"\")",
+ dentry_full_path(child),
+ num_alts,
+ dentry_full_path(list_entry(child->case_insensitive_conflict_list.next,
+ struct wim_dentry,
+ case_insensitive_conflict_list)));
return child;
}
}
/* Returns the child of @dentry that has the file name @name. Returns NULL if
* no child has the name. */
struct wim_dentry *
-get_dentry_child_with_name(const struct wim_dentry *dentry, const tchar *name)
+get_dentry_child_with_name(const struct wim_dentry *dentry, const tchar *name,
+ CASE_SENSITIVITY_TYPE case_type)
{
#if TCHAR_IS_UTF16LE
return get_dentry_child_with_utf16le_name(dentry, name,
- tstrlen(name) * sizeof(tchar));
+ tstrlen(name) * sizeof(tchar),
+ case_type);
#else
utf16lechar *utf16le_name;
size_t utf16le_name_nbytes;
} else {
child = get_dentry_child_with_utf16le_name(dentry,
utf16le_name,
- utf16le_name_nbytes);
+ utf16le_name_nbytes,
+ case_type);
FREE(utf16le_name);
}
return child;
}
static struct wim_dentry *
-get_dentry_utf16le(WIMStruct *wim, const utf16lechar *path)
+get_dentry_utf16le(WIMStruct *wim, const utf16lechar *path,
+ CASE_SENSITIVITY_TYPE case_type)
{
struct wim_dentry *cur_dentry, *parent_dentry;
const utf16lechar *p, *pp;
pp++;
cur_dentry = get_dentry_child_with_utf16le_name(parent_dentry, p,
- (void*)pp - (void*)p);
+ (u8*)pp - (u8*)p,
+ case_type);
if (cur_dentry == NULL)
break;
p = pp;
/*
* Returns the dentry in the currently selected WIM image named by @path
* starting from the root of the WIM image, or NULL if there is no such dentry.
- *
- * On Windows, the search is done case-insensitively.
*/
struct wim_dentry *
-get_dentry(WIMStruct *wim, const tchar *path)
+get_dentry(WIMStruct *wim, const tchar *path, CASE_SENSITIVITY_TYPE case_type)
{
#if TCHAR_IS_UTF16LE
- return get_dentry_utf16le(wim, path);
+ return get_dentry_utf16le(wim, path, case_type);
#else
utf16lechar *path_utf16le;
size_t path_utf16le_nbytes;
&path_utf16le, &path_utf16le_nbytes);
if (ret)
return NULL;
- dentry = get_dentry_utf16le(wim, path_utf16le);
+ dentry = get_dentry_utf16le(wim, path_utf16le, case_type);
FREE(path_utf16le);
return dentry;
#endif
}
-struct wim_inode *
-wim_pathname_to_inode(WIMStruct *wim, const tchar *path)
-{
- struct wim_dentry *dentry;
- dentry = get_dentry(wim, path);
- if (dentry)
- return dentry->d_inode;
- else
- 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
/* Returns the dentry that corresponds to the parent directory of @path, or NULL
* if the dentry is not found. */
struct wim_dentry *
-get_parent_dentry(WIMStruct *wim, const tchar *path)
+get_parent_dentry(WIMStruct *wim, const tchar *path,
+ CASE_SENSITIVITY_TYPE case_type)
{
size_t path_len = tstrlen(path);
tchar buf[path_len + 1];
tmemcpy(buf, path, path_len + 1);
to_parent_name(buf, path_len);
- return get_dentry(wim, buf);
+ return get_dentry(wim, buf, case_type);
}
/* Prints the full path of a dentry. */
for_dentry_in_tree_depth(root, do_free_dentry, lookup_table);
}
-#ifdef __WIN32__
-
/* Insert a dentry into the case insensitive index for a directory.
*
* This is a red-black tree, but when multiple dentries share the same
rb_insert_color(&child->rb_node_case_insensitive, root);
return NULL;
}
-#endif
/*
* Links a dentry into the directory tree.
rb_link_node(&child->rb_node, rb_parent, new);
rb_insert_color(&child->rb_node, root);
-#ifdef __WIN32__
+ /* Case insensitive child dentry index */
{
struct wim_dentry *existing;
existing = dentry_add_child_case_insensitive(parent, child);
INIT_LIST_HEAD(&child->case_insensitive_conflict_list);
}
}
-#endif
return NULL;
}
if (parent == dentry)
return;
rb_erase(&dentry->rb_node, &parent->d_inode->i_children);
-#ifdef __WIN32__
+
if (dentry->rb_node_case_insensitive.__rb_parent_color) {
/* This dentry was in the case-insensitive red-black tree. */
rb_erase(&dentry->rb_node_case_insensitive,
}
}
list_del(&dentry->case_insensitive_conflict_list);
-#endif
+}
+
+static int
+free_dentry_full_path(struct wim_dentry *dentry, void *_ignore)
+{
+ FREE(dentry->_full_path);
+ dentry->_full_path = NULL;
+ return 0;
+}
+
+/* Rename a file or directory in the WIM. */
+int
+rename_wim_path(WIMStruct *wim, const tchar *from, const tchar *to,
+ CASE_SENSITIVITY_TYPE case_type)
+{
+ struct wim_dentry *src;
+ struct wim_dentry *dst;
+ struct wim_dentry *parent_of_dst;
+ int ret;
+
+ /* This rename() implementation currently only supports actual files
+ * (not alternate data streams) */
+
+ src = get_dentry(wim, from, case_type);
+ if (!src)
+ return -errno;
+
+ dst = get_dentry(wim, to, case_type);
+
+ if (dst) {
+ /* Destination file exists */
+
+ if (src == dst) /* Same file */
+ return 0;
+
+ if (!dentry_is_directory(src)) {
+ /* Cannot rename non-directory to directory. */
+ if (dentry_is_directory(dst))
+ return -EISDIR;
+ } else {
+ /* Cannot rename directory to a non-directory or a non-empty
+ * directory */
+ if (!dentry_is_directory(dst))
+ return -ENOTDIR;
+ if (dentry_has_children(dst))
+ return -ENOTEMPTY;
+ }
+ parent_of_dst = dst->parent;
+ } else {
+ /* Destination does not exist */
+ parent_of_dst = get_parent_dentry(wim, to, case_type);
+ if (!parent_of_dst)
+ return -errno;
+
+ if (!dentry_is_directory(parent_of_dst))
+ return -ENOTDIR;
+ }
+
+ ret = set_dentry_name(src, path_basename(to));
+ if (ret)
+ return -ENOMEM;
+ if (dst) {
+ unlink_dentry(dst);
+ free_dentry_tree(dst, wim->lookup_table);
+ }
+ unlink_dentry(src);
+ dentry_add_child(parent_of_dst, src);
+ if (src->_full_path)
+ for_dentry_in_tree(src, free_dentry_full_path, NULL);
+ return 0;
}
/*
do {
if (ads_entry_has_name(&inode->i_ads_entries[i],
stream_name_utf16le,
- stream_name_utf16le_nbytes))
+ stream_name_utf16le_nbytes,
+ false))
{
if (idx_ret)
*idx_ret = i;
struct image_iterate_dir_tree_ctx *ctx = wim->private;
struct wim_dentry *dentry;
- dentry = get_dentry(wim, ctx->path);
+ dentry = get_dentry(wim, ctx->path, WIMLIB_CASE_PLATFORM_DEFAULT);
if (dentry == NULL)
return WIMLIB_ERR_PATH_DOES_NOT_EXIST;
return do_iterate_dir_tree(wim, dentry, ctx->flags, ctx->cb, ctx->user_ctx);
if (ret)
return ret;
- template_dentry = get_dentry(template_wim, dentry->_full_path);
+ template_dentry = get_dentry(template_wim, dentry->_full_path,
+ WIMLIB_CASE_SENSITIVE);
if (template_dentry == NULL) {
DEBUG("\"%"TS"\": newly added file", dentry->_full_path);
return 0;
#include "wimlib.h"
#include "wimlib/encoding.h"
+#include "wimlib/endianness.h"
#include "wimlib/error.h"
#include "wimlib/list.h"
#include "wimlib/util.h"
iconv_cleanup(&iconv_utf8_to_utf16le);
#endif
}
+
+/* Upper case table --- Borrowed from NTFS-3g
+ *
+ * Copyright (c) 2000-2004 Anton Altaparmakov
+ * Copyright (c) 2002-2009 Szabolcs Szakacsits
+ * Copyright (c) 2008-2011 Jean-Pierre Andre
+ * Copyright (c) 2008 Bernhard Kaindl
+ *
+ * License is GPLv2 or later.
+ */
+
+/**
+ * ntfs_upcase_table_build - build the default upcase table for NTFS
+ * @uc: destination buffer where to store the built table
+ * @uc_len: size of destination buffer in bytes
+ *
+ * ntfs_upcase_table_build() builds the default upcase table for NTFS and
+ * stores it in the caller supplied buffer @uc of size @uc_len.
+ *
+ * Note, @uc_len must be at least 128kiB in size or bad things will happen!
+ */
+static void
+ntfs_upcase_table_build(utf16lechar *uc, u32 uc_len)
+{
+ /*
+ * This is the table as defined by Vista
+ */
+ /*
+ * "Start" is inclusive and "End" is exclusive, every value has the
+ * value of "Add" added to it.
+ */
+ static int uc_run_table[][3] = { /* Start, End, Add */
+ {0x0061, 0x007b, -32}, {0x00e0, 0x00f7, -32}, {0x00f8, 0x00ff, -32},
+ {0x0256, 0x0258, -205}, {0x028a, 0x028c, -217}, {0x037b, 0x037e, 130},
+ {0x03ac, 0x03ad, -38}, {0x03ad, 0x03b0, -37}, {0x03b1, 0x03c2, -32},
+ {0x03c2, 0x03c3, -31}, {0x03c3, 0x03cc, -32}, {0x03cc, 0x03cd, -64},
+ {0x03cd, 0x03cf, -63}, {0x0430, 0x0450, -32}, {0x0450, 0x0460, -80},
+ {0x0561, 0x0587, -48}, {0x1f00, 0x1f08, 8}, {0x1f10, 0x1f16, 8},
+ {0x1f20, 0x1f28, 8}, {0x1f30, 0x1f38, 8}, {0x1f40, 0x1f46, 8},
+ {0x1f51, 0x1f52, 8}, {0x1f53, 0x1f54, 8}, {0x1f55, 0x1f56, 8},
+ {0x1f57, 0x1f58, 8}, {0x1f60, 0x1f68, 8}, {0x1f70, 0x1f72, 74},
+ {0x1f72, 0x1f76, 86}, {0x1f76, 0x1f78, 100}, {0x1f78, 0x1f7a, 128},
+ {0x1f7a, 0x1f7c, 112}, {0x1f7c, 0x1f7e, 126}, {0x1f80, 0x1f88, 8},
+ {0x1f90, 0x1f98, 8}, {0x1fa0, 0x1fa8, 8}, {0x1fb0, 0x1fb2, 8},
+ {0x1fb3, 0x1fb4, 9}, {0x1fcc, 0x1fcd, -9}, {0x1fd0, 0x1fd2, 8},
+ {0x1fe0, 0x1fe2, 8}, {0x1fe5, 0x1fe6, 7}, {0x1ffc, 0x1ffd, -9},
+ {0x2170, 0x2180, -16}, {0x24d0, 0x24ea, -26}, {0x2c30, 0x2c5f, -48},
+ {0x2d00, 0x2d26, -7264}, {0xff41, 0xff5b, -32}, {0}
+ };
+ /*
+ * "Start" is exclusive and "End" is inclusive, every second value is
+ * decremented by one.
+ */
+ static int uc_dup_table[][2] = { /* Start, End */
+ {0x0100, 0x012f}, {0x0132, 0x0137}, {0x0139, 0x0149}, {0x014a, 0x0178},
+ {0x0179, 0x017e}, {0x01a0, 0x01a6}, {0x01b3, 0x01b7}, {0x01cd, 0x01dd},
+ {0x01de, 0x01ef}, {0x01f4, 0x01f5}, {0x01f8, 0x01f9}, {0x01fa, 0x0220},
+ {0x0222, 0x0234}, {0x023b, 0x023c}, {0x0241, 0x0242}, {0x0246, 0x024f},
+ {0x03d8, 0x03ef}, {0x03f7, 0x03f8}, {0x03fa, 0x03fb}, {0x0460, 0x0481},
+ {0x048a, 0x04bf}, {0x04c1, 0x04c4}, {0x04c5, 0x04c8}, {0x04c9, 0x04ce},
+ {0x04ec, 0x04ed}, {0x04d0, 0x04eb}, {0x04ee, 0x04f5}, {0x04f6, 0x0513},
+ {0x1e00, 0x1e95}, {0x1ea0, 0x1ef9}, {0x2183, 0x2184}, {0x2c60, 0x2c61},
+ {0x2c67, 0x2c6c}, {0x2c75, 0x2c76}, {0x2c80, 0x2ce3}, {0}
+ };
+ /*
+ * Set the Unicode character at offset "Offset" to "Value". Note,
+ * "Value" is host endian.
+ */
+ static int uc_byte_table[][2] = { /* Offset, Value */
+ {0x00ff, 0x0178}, {0x0180, 0x0243}, {0x0183, 0x0182}, {0x0185, 0x0184},
+ {0x0188, 0x0187}, {0x018c, 0x018b}, {0x0192, 0x0191}, {0x0195, 0x01f6},
+ {0x0199, 0x0198}, {0x019a, 0x023d}, {0x019e, 0x0220}, {0x01a8, 0x01a7},
+ {0x01ad, 0x01ac}, {0x01b0, 0x01af}, {0x01b9, 0x01b8}, {0x01bd, 0x01bc},
+ {0x01bf, 0x01f7}, {0x01c6, 0x01c4}, {0x01c9, 0x01c7}, {0x01cc, 0x01ca},
+ {0x01dd, 0x018e}, {0x01f3, 0x01f1}, {0x023a, 0x2c65}, {0x023e, 0x2c66},
+ {0x0253, 0x0181}, {0x0254, 0x0186}, {0x0259, 0x018f}, {0x025b, 0x0190},
+ {0x0260, 0x0193}, {0x0263, 0x0194}, {0x0268, 0x0197}, {0x0269, 0x0196},
+ {0x026b, 0x2c62}, {0x026f, 0x019c}, {0x0272, 0x019d}, {0x0275, 0x019f},
+ {0x027d, 0x2c64}, {0x0280, 0x01a6}, {0x0283, 0x01a9}, {0x0288, 0x01ae},
+ {0x0289, 0x0244}, {0x028c, 0x0245}, {0x0292, 0x01b7}, {0x03f2, 0x03f9},
+ {0x04cf, 0x04c0}, {0x1d7d, 0x2c63}, {0x214e, 0x2132}, {0}
+ };
+ int i, r;
+ int k, off;
+
+ memset((char*)uc, 0, uc_len);
+ uc_len >>= 1;
+ if (uc_len > 65536)
+ uc_len = 65536;
+ for (i = 0; (u32)i < uc_len; i++)
+ uc[i] = cpu_to_le16(i);
+ for (r = 0; uc_run_table[r][0]; r++) {
+ off = uc_run_table[r][2];
+ for (i = uc_run_table[r][0]; i < uc_run_table[r][1]; i++)
+ uc[i] = cpu_to_le16(i + off);
+ }
+ for (r = 0; uc_dup_table[r][0]; r++)
+ for (i = uc_dup_table[r][0]; i < uc_dup_table[r][1]; i += 2)
+ uc[i + 1] = cpu_to_le16(i);
+ for (r = 0; uc_byte_table[r][0]; r++) {
+ k = uc_byte_table[r][1];
+ uc[uc_byte_table[r][0]] = cpu_to_le16(k);
+ }
+}
+
+static utf16lechar upcase[65536];
+
+void
+init_upcase(void)
+{
+ ntfs_upcase_table_build(upcase, ARRAY_LEN(upcase));
+}
+
+/* Compare UTF-16LE strings case-sensitively (%ignore_case == false) or
+ * case-insensitively (%ignore_case == true).
+ *
+ * This is implemented using the default upper-case table used by NTFS. It does
+ * not handle all possible cases allowed by UTF-16LE. For example, different
+ * normalizations of the same sequence of "characters" are not considered equal.
+ * It hopefully does the right thing most of the time though. */
+int
+cmp_utf16le_strings(const utf16lechar *s1, size_t n1,
+ const utf16lechar *s2, size_t n2,
+ bool ignore_case)
+{
+ size_t n = min(n1, n2);
+
+ if (ignore_case) {
+ for (size_t i = 0; i < n; i++) {
+ u16 c1 = le16_to_cpu(upcase[le16_to_cpu(s1[i])]);
+ u16 c2 = le16_to_cpu(upcase[le16_to_cpu(s2[i])]);
+ if (c1 != c2)
+ return (c1 < c2) ? -1 : 1;
+ }
+ } else {
+ for (size_t i = 0; i < n; i++) {
+ u16 c1 = le16_to_cpu(s1[i]);
+ u16 c2 = le16_to_cpu(s2[i]);
+ if (c1 != c2)
+ return (c1 < c2) ? -1 : 1;
+ }
+ }
+ if (n1 == n2)
+ return 0;
+ return (n1 < n2) ? -1 : 1;
+}
/* Translate the path to extract into the corresponding
* `struct wim_dentry', which will be the root of the
* "dentry tree" to extract. */
- root = get_dentry(wim, wim_source_path);
+ root = get_dentry(wim, wim_source_path, WIMLIB_CASE_PLATFORM_DEFAULT);
if (!root) {
ERROR("Path \"%"TS"\" does not exist in WIM image %d",
wim_source_path, wim->current_image);
else
wildcard_flags |= WILDCARD_FLAG_WARN_IF_NO_MATCH;
- if (extract_flags & WIMLIB_EXTRACT_FLAG_CASE_INSENSITIVE_GLOB)
+ if (default_ignore_case)
wildcard_flags |= WILDCARD_FLAG_CASE_INSENSITIVE;
ret = expand_wildcard_wim_paths(wim, paths, num_paths,
}
}
- dentry = get_dentry(wim, path);
+ dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
if (p)
*p = T(':');
if (!dentry)
lzms_end_encode_item(ctx, length);
}
-static struct lzms_match
-lzms_get_best_match(struct lzms_compressor *ctx)
-{
- struct lzms_match match;
-
- /* TODO */
-
- match.length = 0;
-
- return match;
-}
-
static void
lzms_record_literal(u8 literal, void *_ctx)
{
}
#if 0
+
+static struct lzms_match
+lzms_get_best_match(struct lzms_compressor *ctx)
+{
+ struct lzms_match match;
+
+ /* TODO */
+
+ match.length = 0;
+
+ return match;
+}
+
static void
lzms_slow_encode(struct lzms_compressor *ctx)
{
static void
lzms_rebuild_adaptive_huffman_code(struct lzms_huffman_decoder *dec)
{
- int ret;
/* XXX: This implementation makes use of code already implemented for
* the XPRESS and LZX compression formats. However, since for the
dec->num_syms);
make_canonical_huffman_code(dec->num_syms, LZMS_MAX_CODEWORD_LEN,
dec->sym_freqs, dec->lens, dec->codewords);
- ret = make_huffman_decode_table(dec->decode_table, dec->num_syms,
- LZMS_DECODE_TABLE_BITS, dec->lens,
- LZMS_MAX_CODEWORD_LEN);
+#if defined(ENABLE_LZMS_DEBUG)
+ int ret =
+#endif
+ make_huffman_decode_table(dec->decode_table, dec->num_syms,
+ LZMS_DECODE_TABLE_BITS, dec->lens,
+ LZMS_MAX_CODEWORD_LEN);
LZMS_ASSERT(ret == 0);
}
struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx);
int ret;
- parent = get_parent_dentry(wimfs_ctx->wim, path);
+ parent = get_parent_dentry(wimfs_ctx->wim, path, WIMLIB_CASE_SENSITIVE);
if (!parent)
return -errno;
return -ENOTDIR;
basename = path_basename(path);
- if (get_dentry_child_with_name(parent, basename))
+ if (get_dentry_child_with_name(parent, basename, WIMLIB_CASE_SENSITIVE))
return -EEXIST;
ret = new_dentry_with_inode(basename, &new);
return 0;
}
+static struct wim_inode *
+wim_pathname_to_inode(WIMStruct *wim, const tchar *path)
+{
+ struct wim_dentry *dentry;
+ dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
+ if (dentry)
+ return dentry->d_inode;
+ else
+ return NULL;
+}
+
/* Remove a dentry from a mounted WIM image; i.e. remove an alias for the
* corresponding inode.
*
FILE_ATTRIBUTE_REPARSE_POINT))
return -EPERM;
- from_dentry_parent = get_parent_dentry(wim, from);
+ from_dentry_parent = get_parent_dentry(wim, from, WIMLIB_CASE_SENSITIVE);
if (!from_dentry_parent)
return -errno;
if (!dentry_is_directory(from_dentry_parent))
return -ENOTDIR;
link_name = path_basename(from);
- if (get_dentry_child_with_name(from_dentry_parent, link_name))
+ if (get_dentry_child_with_name(from_dentry_parent, link_name,
+ WIMLIB_CASE_SENSITIVE))
return -EEXIST;
ret = new_dentry(link_name, &from_dentry);
static int
wimfs_rename(const char *from, const char *to)
{
- return rename_wim_path(wimfs_get_WIMStruct(), from, to);
+ return rename_wim_path(wimfs_get_WIMStruct(), from, to,
+ WIMLIB_CASE_SENSITIVE);
}
/* Remove a directory */
struct wim_dentry *dentry;
WIMStruct *wim = wimfs_get_WIMStruct();
- dentry = get_dentry(wim, path);
+ dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
if (!dentry)
return -errno;
struct wim_inode *inode;
WIMStruct *wim = wimfs_get_WIMStruct();
- dentry = get_dentry(wim, path);
+ dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
if (!dentry)
return -errno;
inode = dentry->d_inode;
struct wim_inode *inode;
WIMStruct *wim = wimfs_get_WIMStruct();
- dentry = get_dentry(wim, path);
+ dentry = get_dentry(wim, path, WIMLIB_CASE_SENSITIVE);
if (!dentry)
return -errno;
inode = dentry->d_inode;
/* Capture each data stream or reparse data stream. */
while (!ntfs_attr_lookup(type, NULL, 0,
- CASE_SENSITIVE, 0, NULL, 0, actx))
+ WIMLIB_CASE_SENSITIVE, 0, NULL, 0, actx))
{
u64 data_size = ntfs_get_attribute_value_length(actx->attr);
u64 name_length = actx->attr->name_length;
le32 attributes;
int ret;
struct wim_dentry *root = NULL;
- struct wim_inode *inode;
+ struct wim_inode *inode = NULL;
ATTR_TYPES stream_type;
if (exclude_path(path, path_len, params->config, false)) {
/* Get the maximum size of uncompressed chunks in this resource, which
* we require be a power of 2. */
- u32 chunk_size;
+ u32 chunk_size = 0;
u64 cur_read_offset = rspec->offset_in_wim;
- int ctype;
+ int ctype = WIMLIB_COMPRESSION_TYPE_NONE;
if (alt_chunk_table) {
/* Alternate chunk table format. Its header specifies the chunk
* size and compression format. */
{
struct wim_dentry *root = NULL;
int ret;
- struct wim_inode *inode;
+ struct wim_inode *inode = NULL;
struct stat stbuf;
if (exclude_path(path, path_len, params->config, true)) {
*/
static int
attach_branch(struct wim_dentry **root_p, struct wim_dentry *branch,
- tchar *target_path)
+ tchar *target_path, CASE_SENSITIVITY_TYPE case_type)
{
tchar *slash;
struct wim_dentry *dentry, *parent, *target;
parent = *root_p;
while ((slash = tstrchr(target_path, WIM_PATH_SEPARATOR))) {
*slash = T('\0');
- dentry = get_dentry_child_with_name(parent, target_path);
+ dentry = get_dentry_child_with_name(parent, target_path,
+ case_type);
if (!dentry) {
ret = new_filler_directory(target_path, &dentry);
if (ret)
/* If the target path already existed, overlay the branch onto it.
* Otherwise, set the branch as the target path. */
target = get_dentry_child_with_utf16le_name(parent, branch->file_name,
- branch->file_name_nbytes);
+ branch->file_name_nbytes,
+ case_type);
if (target) {
return do_overlay(target, branch);
} else {
if (ret)
goto out_ntfs_umount;
- ret = attach_branch(&imd->root_dentry, branch, wim_target_path);
+ ret = attach_branch(&imd->root_dentry, branch, wim_target_path,
+ WIMLIB_CASE_PLATFORM_DEFAULT);
if (ret)
goto out_ntfs_umount;
}
DEBUG("Deleting WIM path \"%"TS"\" (flags=%#x)", wim_path, flags);
- tree = get_dentry(wim, wim_path);
+ tree = get_dentry(wim, wim_path, WIMLIB_CASE_PLATFORM_DEFAULT);
if (!tree) {
/* Path to delete does not exist in the WIM. */
if (flags & WIMLIB_DELETE_FLAG_FORCE) {
return 0;
}
-static int
-free_dentry_full_path(struct wim_dentry *dentry, void *_ignore)
-{
- FREE(dentry->_full_path);
- dentry->_full_path = NULL;
- return 0;
-}
-
-/*
- * Rename a file or directory in the WIM.
- *
- * This is also called from wimfs_rename() in the FUSE mount code.
- */
-int
-rename_wim_path(WIMStruct *wim, const tchar *from, const tchar *to)
-{
- struct wim_dentry *src;
- struct wim_dentry *dst;
- struct wim_dentry *parent_of_dst;
- int ret;
-
- /* This rename() implementation currently only supports actual files
- * (not alternate data streams) */
-
- src = get_dentry(wim, from);
- if (!src)
- return -errno;
-
- dst = get_dentry(wim, to);
-
- if (dst) {
- /* Destination file exists */
-
- if (src == dst) /* Same file */
- return 0;
-
- if (!dentry_is_directory(src)) {
- /* Cannot rename non-directory to directory. */
- if (dentry_is_directory(dst))
- return -EISDIR;
- } else {
- /* Cannot rename directory to a non-directory or a non-empty
- * directory */
- if (!dentry_is_directory(dst))
- return -ENOTDIR;
- if (dentry_has_children(dst))
- return -ENOTEMPTY;
- }
- parent_of_dst = dst->parent;
- } else {
- /* Destination does not exist */
- parent_of_dst = get_parent_dentry(wim, to);
- if (!parent_of_dst)
- return -errno;
-
- if (!dentry_is_directory(parent_of_dst))
- return -ENOTDIR;
- }
-
- ret = set_dentry_name(src, path_basename(to));
- if (ret)
- return -ENOMEM;
- if (dst) {
- unlink_dentry(dst);
- free_dentry_tree(dst, wim->lookup_table);
- }
- unlink_dentry(src);
- dentry_add_child(parent_of_dst, src);
- if (src->_full_path)
- for_dentry_in_tree(src, free_dentry_full_path, NULL);
- return 0;
-}
-
-
static int
execute_rename_command(WIMStruct *wim,
const struct wimlib_update_command *rename_cmd)
wimlib_assert(rename_cmd->op == WIMLIB_UPDATE_OP_RENAME);
ret = rename_wim_path(wim, rename_cmd->rename.wim_source_path,
- rename_cmd->rename.wim_target_path);
+ rename_cmd->rename.wim_target_path,
+ WIMLIB_CASE_PLATFORM_DEFAULT);
if (ret) {
ret = -ret;
errno = ret;
bool case_insensitive;
};
+#ifdef __WIN32__
+static bool
+match_wildcard_case_sensitive(const tchar *string, size_t string_len,
+ const tchar *wildcard, size_t wildcard_len)
+{
+ for (;;) {
+ if (string_len == 0) {
+ while (wildcard_len != 0 && *wildcard == T('*')) {
+ wildcard++;
+ wildcard_len--;
+ }
+ return (wildcard_len == 0);
+ } else if (wildcard_len == 0) {
+ return false;
+ } else if (*string == *wildcard || *wildcard == '?') {
+ string++;
+ string_len--;
+ wildcard_len--;
+ wildcard++;
+ continue;
+ } else if (*wildcard == '*') {
+ return match_wildcard_case_sensitive(
+ string, string_len,
+ wildcard + 1, wildcard_len - 1) ||
+ match_wildcard_case_sensitive(
+ string + 1, string_len - 1,
+ wildcard, wildcard_len);
+ } else {
+ return false;
+ }
+ }
+}
+#endif
+
static bool
match_wildcard(const tchar *string, tchar *wildcard,
size_t wildcard_len, bool case_insensitive)
{
- char orig;
- int flags;
- int ret;
+ /* Note: in Windows builds fnmatch() calls a replacement function.
+ * It does support case-sensitive globbing. */
+#ifdef __WIN32__
+ if (case_insensitive)
+#endif
+ {
+ char orig;
+ int ret;
+ int flags = FNM_NOESCAPE;
+ if (case_insensitive)
+ flags |= FNM_CASEFOLD;
- orig = wildcard[wildcard_len];
- wildcard[wildcard_len] = T('\0');
+ orig = wildcard[wildcard_len];
+ wildcard[wildcard_len] = T('\0');
- /* Warning: in Windows builds fnmatch() calls a replacement function.
- * Also, FNM_CASEFOLD is a GNU extension and it is defined to 0 if not
- * available. */
- flags = FNM_NOESCAPE;
- if (case_insensitive)
- flags |= FNM_CASEFOLD;
- ret = fnmatch(wildcard, string, flags);
+ ret = fnmatch(wildcard, string, flags);
- wildcard[wildcard_len] = orig;
- return (ret == 0);
+ wildcard[wildcard_len] = orig;
+ return (ret == 0);
+ }
+#ifdef __WIN32__
+ else
+ {
+ return match_wildcard_case_sensitive(string,
+ tstrlen(string),
+ wildcard,
+ wildcard_len);
+ }
+#endif
}
static int
int
expand_wildcard_wim_paths(WIMStruct *wim,
- const char * const *wildcards,
+ const tchar * const *wildcards,
size_t num_wildcards,
tchar ***expanded_paths_ret,
size_t *num_expanded_paths_ret,
wimlib_global_init(int init_flags)
{
static bool already_inited = false;
- int ret;
if (already_inited)
return 0;
#endif
}
#ifdef __WIN32__
- ret = win32_global_init(init_flags);
- if (ret)
- return ret;
-#else
- ret = 0;
+ {
+ int ret = win32_global_init(init_flags);
+ if (ret)
+ return ret;
+ }
#endif
+ init_upcase();
+ if (init_flags & WIMLIB_INIT_FLAG_DEFAULT_CASE_SENSITIVE)
+ default_ignore_case = false;
+ else if (init_flags & WIMLIB_INIT_FLAG_DEFAULT_CASE_INSENSITIVE)
+ default_ignore_case = true;
already_inited = true;
- return ret;
+ return 0;
}
/* API function documented in wimlib.h */
unsigned vol_flags)
{
struct wim_dentry *root = NULL;
- struct wim_inode *inode;
+ struct wim_inode *inode = NULL;
DWORD err;
u64 file_size;
int ret;
#include "wimlib/file_io.h"
#include "wimlib/glob.h"
#include "wimlib/error.h"
+#include "wimlib/wildcard.h"
#include "wimlib/util.h"
/* Replacement for POSIX fsync() */