From 14baa6ae892debbaa18dba8119931580efd0e517 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 19 Mar 2013 21:24:33 -0500 Subject: [PATCH] Improve char encoding support (IN PROGRESS) --- src/add_image.c | 166 +++++----- src/buffer_io.h | 2 +- src/delete_image.c | 3 +- src/dentry.c | 714 ++++++++++++++++++++++-------------------- src/dentry.h | 262 +++++++++------- src/encoding.c | 545 +++++++++++++------------------- src/extract_image.c | 191 ++++++----- src/hardlink.c | 61 ++-- src/lookup_table.c | 16 +- src/lookup_table.h | 20 +- src/mount_image.c | 427 +++++++++++++++---------- src/resource.c | 59 ++-- src/security.c | 42 ++- src/sha1.c | 3 +- src/sha1.h | 49 +-- src/symlink.c | 25 +- src/util.c | 170 ++++++++-- src/util.h | 96 +++--- src/wim.c | 6 + src/wimlib.h | 231 ++++++++------ src/wimlib_internal.h | 279 +++++++++++------ src/win32.c | 5 +- src/win32.h | 14 +- src/xml.c | 304 ++++++++++-------- src/xml.h | 51 +-- 25 files changed, 2109 insertions(+), 1632 deletions(-) diff --git a/src/add_image.c b/src/add_image.c index 67a354e4..4dce5bbb 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -51,8 +51,9 @@ * Adds the dentry tree and security data for a new image to the image metadata * array of the WIMStruct. */ -int add_new_dentry_tree(WIMStruct *w, struct wim_dentry *root_dentry, - struct wim_security_data *sd) +int +add_new_dentry_tree(WIMStruct *w, struct wim_dentry *root_dentry, + struct wim_security_data *sd) { struct wim_lookup_table_entry *metadata_lte; struct wim_image_metadata *imd; @@ -133,14 +134,15 @@ err: * the on-disk files during a call to wimlib_write() or * wimlib_overwrite(). */ -static int unix_build_dentry_tree(struct wim_dentry **root_ret, - const char *root_disk_path, - struct wim_lookup_table *lookup_table, - struct wim_security_data *sd, - const struct capture_config *config, - int add_image_flags, - wimlib_progress_func_t progress_func, - void *extra_arg) +static int +unix_build_dentry_tree(struct wim_dentry **root_ret, + const mbchar *root_disk_path, + struct wim_lookup_table *lookup_table, + struct wim_security_data *sd, + const struct capture_config *config, + int add_image_flags, + wimlib_progress_func_t progress_func, + void *extra_arg) { struct wim_dentry *root = NULL; int ret = 0; @@ -280,7 +282,7 @@ static int unix_build_dentry_tree(struct wim_dentry **root_ret, DEBUG("Add lte reference %u for `%s'", lte->refcnt, root_disk_path); } else { - char *file_on_disk = STRDUP(root_disk_path); + mbchar *file_on_disk = STRDUP(root_disk_path); if (!file_on_disk) { ERROR("Failed to allocate memory for file path"); ret = WIMLIB_ERR_NOMEM; @@ -318,7 +320,7 @@ static int unix_build_dentry_tree(struct wim_dentry **root_ret, /* Buffer for names of files in directory. */ size_t len = strlen(root_disk_path); - char name[len + 1 + FILENAME_MAX + 1]; + mbchar name[len + 1 + FILENAME_MAX + 1]; memcpy(name, root_disk_path, len); name[len] = '/'; @@ -362,7 +364,7 @@ static int unix_build_dentry_tree(struct wim_dentry **root_ret, * drive letter). */ - char deref_name_buf[4096]; + mbchar deref_name_buf[4096]; ssize_t deref_name_len; deref_name_len = readlink(root_disk_path, deref_name_buf, @@ -414,7 +416,7 @@ enum pattern_type { #define COMPAT_DEFAULT_CONFIG /* Default capture configuration file when none is specified. */ -static const char *default_config = +static const mbchar *default_config = #ifdef COMPAT_DEFAULT_CONFIG /* XXX: This policy is being moved to library users. The next ABI-incompatible library version will default to the empty string here. */ @@ -435,12 +437,14 @@ static const char *default_config = ""; #endif -static void destroy_pattern_list(struct pattern_list *list) +static void +destroy_pattern_list(struct pattern_list *list) { FREE(list->pats); } -static void destroy_capture_config(struct capture_config *config) +static void +destroy_capture_config(struct capture_config *config) { destroy_pattern_list(&config->exclusion_list); destroy_pattern_list(&config->exclusion_exception); @@ -451,8 +455,8 @@ static void destroy_capture_config(struct capture_config *config) memset(config, 0, sizeof(*config)); } -static int pattern_list_add_pattern(struct pattern_list *list, - const char *pattern) +static int +pattern_list_add_pattern(struct pattern_list *list, const mbchar *pattern) { const char **pats; if (list->num_pats >= list->num_allocated_pats) { @@ -469,13 +473,14 @@ static int pattern_list_add_pattern(struct pattern_list *list, /* Parses the contents of the image capture configuration file and fills in a * `struct capture_config'. */ -static int init_capture_config(struct capture_config *config, - const char *_config_str, size_t config_len) +static int +init_capture_config(struct capture_config *config, + const mbchar *_config_str, size_t config_len) { - char *config_str; - char *p; - char *eol; - char *next_p; + mbchar *config_str; + mbchar *p; + mbchar *eol; + mbchar *next_p; size_t bytes_remaining; enum pattern_type type = NONE; int ret; @@ -514,7 +519,7 @@ static int init_capture_config(struct capture_config *config, *eol = '\0'; /* Translate backslash to forward slash */ - for (char *pp = p; pp != eol; pp++) + for (mbchar *pp = p; pp != eol; pp++) if (*pp == '\\') *pp = '/'; @@ -568,9 +573,9 @@ out_destroy: } static int capture_config_set_prefix(struct capture_config *config, - const char *_prefix) + const mbchar *_prefix) { - char *prefix = STRDUP(_prefix); + mbchar *prefix = STRDUP(_prefix); if (!prefix) return WIMLIB_ERR_NOMEM; @@ -580,7 +585,8 @@ static int capture_config_set_prefix(struct capture_config *config, return 0; } -static bool match_pattern(const char *path, const char *path_basename, +static bool match_pattern(const mbchar *path, + const mbchar *path_basename, const struct pattern_list *list) { for (size_t i = 0; i < list->num_pats; i++) { @@ -623,10 +629,11 @@ static bool match_pattern(const char *path, const char *path_basename, * file /mnt/windows7/hiberfil.sys if we are capturing the /mnt/windows7 * directory. */ -bool exclude_path(const char *path, const struct capture_config *config, - bool exclude_prefix) +bool +exclude_path(const mbchar *path, const struct capture_config *config, + bool exclude_prefix) { - const char *basename = path_basename(path); + const mbchar *basename = path_basename(path); if (exclude_prefix) { wimlib_assert(strlen(path) >= config->prefix_len); if (memcmp(config->prefix, path, config->prefix_len) == 0 @@ -640,7 +647,8 @@ bool exclude_path(const char *path, const struct capture_config *config, /* Strip leading and trailing forward slashes from a string. Modifies it in * place and returns the stripped string. */ -static const char *canonicalize_target_path(char *target_path) +static const char * +canonicalize_target_path(char *target_path) { char *p; if (target_path == NULL) @@ -661,7 +669,8 @@ static const char *canonicalize_target_path(char *target_path) } #ifdef __WIN32__ -static void zap_backslashes(char *s) +static void +zap_backslashes(char *s) { while (*s) { if (*s == '\\') @@ -672,8 +681,8 @@ static void zap_backslashes(char *s) #endif /* Strip leading and trailing slashes from the target paths */ -static void canonicalize_targets(struct wimlib_capture_source *sources, - size_t num_sources) +static void +canonicalize_targets(struct wimlib_capture_source *sources, size_t num_sources) { while (num_sources--) { DEBUG("Canonicalizing { source: \"%s\", target=\"%s\"}", @@ -694,7 +703,8 @@ static void canonicalize_targets(struct wimlib_capture_source *sources, } } -static int capture_source_cmp(const void *p1, const void *p2) +static int +capture_source_cmp(const void *p1, const void *p2) { const struct wimlib_capture_source *s1 = p1, *s2 = p2; return strcmp(s1->wim_target_path, s2->wim_target_path); @@ -705,14 +715,15 @@ static int capture_source_cmp(const void *p1, const void *p2) * * One purpose of this is to make sure that target paths that are inside other * target paths are added after the containing target paths. */ -static void sort_sources(struct wimlib_capture_source *sources, - size_t num_sources) +static void +sort_sources(struct wimlib_capture_source *sources, size_t num_sources) { qsort(sources, num_sources, sizeof(sources[0]), capture_source_cmp); } -static int check_sorted_sources(struct wimlib_capture_source *sources, - size_t num_sources, int add_image_flags) +static int +check_sorted_sources(struct wimlib_capture_source *sources, size_t num_sources, + int add_image_flags) { if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_NTFS) { if (num_sources != 1) { @@ -767,7 +778,7 @@ static int check_sorted_sources(struct wimlib_capture_source *sources, /* Creates a new directory to place in the WIM image. This is to create parent * directories that are not part of any target as needed. */ static struct wim_dentry * -new_filler_directory(const char *name) +new_filler_directory(const mbchar *name) { struct wim_dentry *dentry; DEBUG("Creating filler directory \"%s\"", name); @@ -784,16 +795,17 @@ new_filler_directory(const char *name) /* Transfers the children of @branch to @target. It is an error if @target is * not a directory or if both @branch and @target contain a child dentry with * the same name. */ -static int do_overlay(struct wim_dentry *target, struct wim_dentry *branch) +static int +do_overlay(struct wim_dentry *target, struct wim_dentry *branch) { struct rb_root *rb_root; - DEBUG("Doing overlay %s => %s", - branch->file_name_utf8, target->file_name_utf8); + DEBUG("Doing overlay \"%W\" => \"%W\"", + branch->file_name, target->file_name); if (!dentry_is_directory(target)) { - ERROR("Cannot overlay directory `%s' over non-directory", - branch->file_name_utf8); + ERROR("Cannot overlay directory \"%W\" over non-directory", + branch->file_name); return WIMLIB_ERR_INVALID_OVERLAY; } @@ -806,9 +818,9 @@ static int do_overlay(struct wim_dentry *target, struct wim_dentry *branch) /* Revert the change to avoid leaking the directory tree * rooted at @child */ dentry_add_child(branch, child); - ERROR("Overlay error: file `%s' already exists " - "as a child of `%s'", - child->file_name_utf8, target->file_name_utf8); + ERROR("Overlay error: file \"%W\" already exists " + "as a child of \"%W\"", + child->file_name, target->file_name); return WIMLIB_ERR_INVALID_OVERLAY; } } @@ -828,15 +840,15 @@ static int do_overlay(struct wim_dentry *target, struct wim_dentry *branch) * Path in the WIM image to add the branch, with leading and trailing * slashes stripped. */ -static int attach_branch(struct wim_dentry **root_p, - struct wim_dentry *branch, - char *target_path) +static int +attach_branch(struct wim_dentry **root_p, struct wim_dentry *branch, + mbchar *target_path) { char *slash; struct wim_dentry *dentry, *parent, *target; - DEBUG("Attaching branch \"%s\" => \"%s\"", - branch->file_name_utf8, target_path); + DEBUG("Attaching branch \"%W\" => \"%s\"", + branch->file_name, target_path); if (*target_path == '\0') { /* Target: root directory */ @@ -882,7 +894,7 @@ static int attach_branch(struct wim_dentry **root_p, /* If the target path already existed, overlay the branch onto it. * Otherwise, set the branch as the target path. */ - target = get_dentry_child_with_name(parent, branch->file_name_utf8); + target = get_dentry_child_with_utf16le_name(parent, branch->file_name); if (target) { return do_overlay(target, branch); } else { @@ -891,20 +903,24 @@ static int attach_branch(struct wim_dentry **root_p, } } -WIMLIBAPI int wimlib_add_image_multisource(WIMStruct *w, - struct wimlib_capture_source *sources, - size_t num_sources, - const char *name, - const char *config_str, - size_t config_len, - int add_image_flags, - wimlib_progress_func_t progress_func) +WIMLIBAPI int +wimlib_add_image_multisource(WIMStruct *w, + struct wimlib_capture_source *sources, + size_t num_sources, + const utf8char *name, + const mbchar *config_str, + size_t config_len, + int add_image_flags, + wimlib_progress_func_t progress_func) { - int (*capture_tree)(struct wim_dentry **, const char *, + int (*capture_tree)(struct wim_dentry **, + const mbchar *, struct wim_lookup_table *, struct wim_security_data *, const struct capture_config *, - int, wimlib_progress_func_t, void *); + int, + wimlib_progress_func_t, + void *); void *extra_arg; struct wim_dentry *root_dentry; struct wim_dentry *branch; @@ -1063,24 +1079,24 @@ WIMLIBAPI int wimlib_add_image_multisource(WIMStruct *w, DEBUG("Calculating full paths of dentries."); ret = for_dentry_in_tree(root_dentry, calculate_dentry_full_path, NULL); - if (ret != 0) + if (ret) goto out_free_dentry_tree; ret = add_new_dentry_tree(w, root_dentry, sd); - if (ret != 0) + if (ret) goto out_free_dentry_tree; imd = &w->image_metadata[w->hdr.image_count - 1]; ret = dentry_tree_fix_inodes(root_dentry, &imd->inode_list); - if (ret != 0) + if (ret) goto out_destroy_imd; DEBUG("Assigning hard link group IDs"); assign_inode_numbers(&imd->inode_list); ret = xml_add_image(w, name); - if (ret != 0) + if (ret) goto out_destroy_imd; if (add_image_flags & WIMLIB_ADD_IMAGE_FLAG_BOOT) @@ -1107,10 +1123,14 @@ out: return ret; } -WIMLIBAPI int wimlib_add_image(WIMStruct *w, const char *source, - const char *name, const char *config_str, - size_t config_len, int add_image_flags, - wimlib_progress_func_t progress_func) +WIMLIBAPI int +wimlib_add_image(WIMStruct *w, + const mbchar *source, + const utf8char *name, + const mbchar *config_str, + size_t config_len, + int add_image_flags, + wimlib_progress_func_t progress_func) { if (!source || !*source) return WIMLIB_ERR_INVALID_PARAM; diff --git a/src/buffer_io.h b/src/buffer_io.h index 9dd88a01..685ffa8a 100644 --- a/src/buffer_io.h +++ b/src/buffer_io.h @@ -113,7 +113,7 @@ static inline u8 *put_zeroes(u8 *p, size_t num_bytes) return (u8*)memset(p, 0, num_bytes) + num_bytes; } -static inline u8 *put_bytes(u8 *p, size_t num_bytes, const u8 *input) +static inline u8 *put_bytes(u8 *p, size_t num_bytes, const void *input) { return (u8*)memcpy(p, input, num_bytes) + num_bytes; } diff --git a/src/delete_image.c b/src/delete_image.c index 3a337514..389d2309 100644 --- a/src/delete_image.c +++ b/src/delete_image.c @@ -28,7 +28,8 @@ /* * Deletes an image from the WIM. */ -WIMLIBAPI int wimlib_delete_image(WIMStruct *w, int image) +WIMLIBAPI int +wimlib_delete_image(WIMStruct *w, int image) { int i; int ret; diff --git a/src/dentry.c b/src/dentry.c index 15a44cee..ea2cdb1b 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -36,14 +36,14 @@ /* 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. */ -static u64 __dentry_correct_length_unaligned(u16 file_name_len, - u16 short_name_len) +static u64 +__dentry_correct_length_unaligned(u16 file_name_nbytes, u16 short_name_nbytes) { u64 length = WIM_DENTRY_DISK_SIZE; - if (file_name_len) - length += file_name_len + 2; - if (short_name_len) - length += short_name_len + 2; + if (file_name_nbytes) + length += file_name_nbytes + 2; + if (short_name_nbytes) + length += short_name_nbytes + 2; return length; } @@ -51,102 +51,91 @@ static u64 __dentry_correct_length_unaligned(u16 file_name_len, * the file name length and short name length. Note that dentry->length is * ignored; also, this excludes any alternate data stream entries that may * follow the dentry. */ -static u64 dentry_correct_length_unaligned(const struct wim_dentry *dentry) +static u64 +dentry_correct_length_unaligned(const struct wim_dentry *dentry) { - return __dentry_correct_length_unaligned(dentry->file_name_len, - dentry->short_name_len); + return __dentry_correct_length_unaligned(dentry->file_name_nbytes, + dentry->short_name_nbytes); } /* Return the "correct" value to write in the length field of a WIM dentry, * based on the file name length and short name length. */ -static u64 dentry_correct_length(const struct wim_dentry *dentry) +static u64 +dentry_correct_length(const struct wim_dentry *dentry) { return (dentry_correct_length_unaligned(dentry) + 7) & ~7; } -/* Return %true iff the alternate data stream entry @entry has the UTF-8 stream - * name @name that has length @name_len bytes. */ -static inline bool ads_entry_has_name(const struct wim_ads_entry *entry, - const char *name, size_t name_len) +/* 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) { - if (entry->stream_name_utf8_len != name_len) - return false; - return memcmp(entry->stream_name_utf8, name, name_len) == 0; + return entry->stream_name_nbytes == name_nbytes && + memcmp(entry->stream_name, name, name_nbytes) == 0; } -/* Duplicates a UTF-8 string into UTF-8 and UTF-16 strings and returns the - * strings and their lengths in the pointer arguments. (Frees existing strings - * first.) */ -static int get_names(char **name_utf16_ret, char **name_utf8_ret, - u16 *name_utf16_len_ret, u16 *name_utf8_len_ret, - const char *name) +/* Duplicates a multibyte string into a UTF-16LE string and returns the string + * and its length, in bytes, in the pointer arguments. Frees any existing + * string at the return location before overwriting it. */ +static int +get_utf16le_name(const mbchar *name, utf16lechar **name_utf16le_ret, + u16 *name_utf16le_nbytes_ret) { - size_t utf8_len; - size_t utf16_len; - char *name_utf16, *name_utf8; + utf16lechar *name_utf16le; + size_t name_utf16le_nbytes; int ret; - utf8_len = strlen(name); - ret = utf8_to_utf16(name, utf8_len, &name_utf16, &utf16_len); - if (ret != 0) - return ret; - - name_utf8 = MALLOC(utf8_len + 1); - if (!name_utf8) { - FREE(name_utf16); - return WIMLIB_ERR_NOMEM; + ret = mbs_to_utf16le(name, strlen(name), &name_utf16le, + &name_utf16le_nbytes); + if (name_utf16le_nbytes > 0xffff) { + FREE(name_utf16le); + ERROR("Multibyte string \"%s\" is too long!", name); + ret = WIMLIB_ERR_INVALID_UTF8_STRING; } - memcpy(name_utf8, name, utf8_len + 1); - FREE(*name_utf8_ret); - FREE(*name_utf16_ret); - *name_utf8_ret = name_utf8; - *name_utf16_ret = name_utf16; - *name_utf8_len_ret = utf8_len; - *name_utf16_len_ret = utf16_len; - return 0; + if (ret == 0) { + FREE(*name_utf16le_ret); + *name_utf16le_ret = name_utf16le; + *name_utf16le_nbytes_ret = name_utf16le_nbytes; + } + return ret; } -/* Sets the name of a WIM dentry. */ -int set_dentry_name(struct wim_dentry *dentry, const char *new_name) +/* Sets the name of a WIM dentry from a multibyte string. */ +int +set_dentry_name(struct wim_dentry *dentry, const mbchar *new_name) { int ret; - - ret = get_names(&dentry->file_name, &dentry->file_name_utf8, - &dentry->file_name_len, &dentry->file_name_utf8_len, - new_name); + ret = get_utf16le_name(new_name, &dentry->file_name, + &dentry->file_name_nbytes); if (ret == 0) { - if (dentry->short_name_len) { + /* Clear the short name and recalculate the dentry length */ + if (dentry->short_name_nbytes) { FREE(dentry->short_name); - dentry->short_name_len = 0; + dentry->short_name = NULL; + dentry->short_name_nbytes = 0; } dentry->length = dentry_correct_length(dentry); } return ret; } -/* - * Changes the name of an alternate data stream */ -static int change_ads_name(struct wim_ads_entry *entry, const char *new_name) -{ - return get_names(&entry->stream_name, &entry->stream_name_utf8, - &entry->stream_name_len, - &entry->stream_name_utf8_len, - new_name); -} - /* Returns the total length of a WIM alternate data stream entry on-disk, * including the stream name, the null terminator, AND the padding after the * entry to align the next ADS entry or dentry on an 8-byte boundary. */ -static u64 ads_entry_total_length(const struct wim_ads_entry *entry) +static u64 +ads_entry_total_length(const struct wim_ads_entry *entry) { u64 len = WIM_ADS_ENTRY_DISK_SIZE; - if (entry->stream_name_len) - len += entry->stream_name_len + 2; + if (entry->stream_name_nbytes) + len += entry->stream_name_nbytes + 2; return (len + 7) & ~7; } -static u64 __dentry_total_length(const struct wim_dentry *dentry, u64 length) +static u64 +__dentry_total_length(const struct wim_dentry *dentry, u64 length) { const struct wim_inode *inode = dentry->d_inode; for (u16 i = 0; i < inode->i_num_ads; i++) @@ -156,7 +145,8 @@ static u64 __dentry_total_length(const struct wim_dentry *dentry, u64 length) /* Calculate the aligned *total* length of an on-disk WIM dentry. This includes * all alternate data streams. */ -u64 dentry_correct_total_length(const struct wim_dentry *dentry) +u64 +dentry_correct_total_length(const struct wim_dentry *dentry) { return __dentry_total_length(dentry, dentry_correct_length_unaligned(dentry)); @@ -164,14 +154,16 @@ u64 dentry_correct_total_length(const struct wim_dentry *dentry) /* Like dentry_correct_total_length(), but use the existing dentry->length field * instead of calculating its "correct" value. */ -static u64 dentry_total_length(const struct wim_dentry *dentry) +static u64 +dentry_total_length(const struct wim_dentry *dentry) { return __dentry_total_length(dentry, dentry->length); } -int for_dentry_in_rbtree(struct rb_node *root, - int (*visitor)(struct wim_dentry *, void *), - void *arg) +int +for_dentry_in_rbtree(struct rb_node *root, + int (*visitor)(struct wim_dentry *, void *), + void *arg) { int ret; struct rb_node *node = root; @@ -197,9 +189,10 @@ int for_dentry_in_rbtree(struct rb_node *root, } } -static int for_dentry_tree_in_rbtree_depth(struct rb_node *node, - int (*visitor)(struct wim_dentry*, void*), - void *arg) +static int +for_dentry_tree_in_rbtree_depth(struct rb_node *node, + int (*visitor)(struct wim_dentry*, void*), + void *arg) { int ret; if (node) { @@ -218,9 +211,10 @@ static int for_dentry_tree_in_rbtree_depth(struct rb_node *node, return 0; } -static int for_dentry_tree_in_rbtree(struct rb_node *node, - int (*visitor)(struct wim_dentry*, void*), - void *arg) +static int +for_dentry_tree_in_rbtree(struct rb_node *node, + int (*visitor)(struct wim_dentry*, void*), + void *arg) { int ret; if (node) { @@ -237,97 +231,103 @@ static int for_dentry_tree_in_rbtree(struct rb_node *node, return 0; } -/* - * Calls a function on all directory entries in a WIM dentry tree. Logically, +/* Calls a function on all directory entries in a WIM dentry tree. Logically, * this is a pre-order traversal (the function is called on a parent dentry * before its children), but sibling dentries will be visited in order as well. - * - * In reality, the data structures are more complicated than the above might - * suggest because there is a separate red-black tree for each dentry that - * contains its direct children. - */ -int for_dentry_in_tree(struct wim_dentry *root, - int (*visitor)(struct wim_dentry*, void*), void *arg) + * */ +int +for_dentry_in_tree(struct wim_dentry *root, + int (*visitor)(struct wim_dentry*, void*), void *arg) { int ret = visitor(root, arg); - if (ret != 0) - return ret; - return for_dentry_tree_in_rbtree(root->d_inode->i_children.rb_node, visitor, arg); + if (ret == 0) { + ret = for_dentry_tree_in_rbtree(root->d_inode->i_children.rb_node, + visitor, + arg); + } + return ret; } -/* - * Like for_dentry_in_tree(), but the visitor function is always called on a - * dentry's children before on itself. - */ -int for_dentry_in_tree_depth(struct wim_dentry *root, - int (*visitor)(struct wim_dentry*, void*), void *arg) +/* Like for_dentry_in_tree(), but the visitor function is always called on a + * dentry's children before on itself. */ +int +for_dentry_in_tree_depth(struct wim_dentry *root, + int (*visitor)(struct wim_dentry*, void*), void *arg) { int ret; ret = for_dentry_tree_in_rbtree_depth(root->d_inode->i_children.rb_node, visitor, arg); - if (ret != 0) - return ret; - return visitor(root, arg); + if (ret == 0) + ret = visitor(root, arg); + return ret; } -/* - * Calculate the full path of @dentry, based on its parent's full path and on - * its UTF-8 file name. - */ -int calculate_dentry_full_path(struct wim_dentry *dentry, void *ignore) +/* Calculate the full path of @dentry. The full path of its parent must have + * already been calculated. */ +int +calculate_dentry_full_path(struct wim_dentry *dentry, void *ignore) { char *full_path; - u32 full_path_len; + u32 full_path_nbytes; + + wimlib_assert(dentry_is_root(dentry) || + dentry->parent->full_path != NULL); + if (dentry_is_root(dentry)) { full_path = MALLOC(2); if (!full_path) - goto oom; + return WIMLIB_ERR_NOMEM; full_path[0] = '/'; full_path[1] = '\0'; - full_path_len = 1; + full_path_nbytes = 1; } else { char *parent_full_path; - u32 parent_full_path_len; - const struct wim_dentry *parent = dentry->parent; - + u32 parent_full_path_nbytes; + const struct wim_dentry *parent; + char *name_mbs; + size_t name_mbs_nbytes; + int ret; + + ret = utf16le_to_mbs_nbytes(dentry->file_name, + dentry->file_name_nbytes, + &name_mbs_nbytes); + if (ret) + return ret; + parent = dentry->parent; if (dentry_is_root(parent)) { parent_full_path = ""; - parent_full_path_len = 0; + parent_full_path_nbytes = 0; } else { - parent_full_path = parent->full_path_utf8; - parent_full_path_len = parent->full_path_utf8_len; + parent_full_path = parent->full_path; + parent_full_path_nbytes = parent->full_path_nbytes; } - - full_path_len = parent_full_path_len + 1 + - dentry->file_name_utf8_len; - full_path = MALLOC(full_path_len + 1); + full_path_nbytes = parent_full_path_nbytes + 1 + + name_mbs_nbytes; + full_path = MALLOC(full_path_nbytes + 1); if (!full_path) - goto oom; - - memcpy(full_path, parent_full_path, parent_full_path_len); - full_path[parent_full_path_len] = '/'; - memcpy(full_path + parent_full_path_len + 1, - dentry->file_name_utf8, - dentry->file_name_utf8_len); - full_path[full_path_len] = '\0'; + return WIMLIB_ERR_NOMEM; + memcpy(full_path, parent_full_path, parent_full_path_nbytes); + full_path[parent_full_path_nbytes] = '/'; + + utf16le_to_mbs_buf(dentry->file_name, + dentry->file_name_nbytes, + &full_path[parent_full_path_nbytes + 1]); } - FREE(dentry->full_path_utf8); - dentry->full_path_utf8 = full_path; - dentry->full_path_utf8_len = full_path_len; + FREE(dentry->full_path); + dentry->full_path = full_path; + dentry->full_path_nbytes= full_path_nbytes; return 0; -oom: - ERROR("Out of memory while calculating dentry full path"); - return WIMLIB_ERR_NOMEM; } -static int increment_subdir_offset(struct wim_dentry *dentry, void *subdir_offset_p) +static int +increment_subdir_offset(struct wim_dentry *dentry, void *subdir_offset_p) { *(u64*)subdir_offset_p += dentry_correct_total_length(dentry); return 0; } -static int call_calculate_subdir_offsets(struct wim_dentry *dentry, - void *subdir_offset_p) +static int +call_calculate_subdir_offsets(struct wim_dentry *dentry, void *subdir_offset_p) { calculate_subdir_offsets(dentry, subdir_offset_p); return 0; @@ -340,7 +340,8 @@ static int call_calculate_subdir_offsets(struct wim_dentry *dentry, * @subdir_offset_p: The current subdirectory offset; i.e., the subdirectory * offset for @dentry. */ -void calculate_subdir_offsets(struct wim_dentry *dentry, u64 *subdir_offset_p) +void +calculate_subdir_offsets(struct wim_dentry *dentry, u64 *subdir_offset_p) { struct rb_node *node; @@ -368,96 +369,110 @@ void calculate_subdir_offsets(struct wim_dentry *dentry, u64 *subdir_offset_p) } } -static int compare_names(const char *name_1, u16 len_1, - const char *name_2, u16 len_2) +static int +dentry_compare_names(const struct wim_dentry *d1, const struct wim_dentry *d2) { - int result = strncmp(name_1, name_2, min(len_1, len_2)); - if (result) { + int result = memcmp(d1->file_name, d2->file_name, + min(d1->file_name_nbytes, d2->file_name_nbytes)); + if (result) return result; - } else { - return (int)len_1 - (int)len_2; - } -} - -static int dentry_compare_names(const struct wim_dentry *d1, const struct wim_dentry *d2) -{ - return compare_names(d1->file_name_utf8, d1->file_name_utf8_len, - d2->file_name_utf8, d2->file_name_utf8_len); + else + return d1->file_name_nbytes - d2->file_name_nbytes; } -static struct wim_dentry * -get_rbtree_child_with_name(const struct rb_node *node, - const char *name, size_t name_len) +struct wim_dentry * +get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry, + const utf16lechar *name) { - do { + struct rb_node *node = dentry->d_inode->i_children.rb_node; + while (node) { struct wim_dentry *child = rbnode_dentry(node); - int result = compare_names(name, name_len, - child->file_name_utf8, - child->file_name_utf8_len); + int result = dentry_compare_names(dentry, child); if (result < 0) node = node->rb_left; else if (result > 0) node = node->rb_right; else return child; - } while (node); + } return NULL; } -/* 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 char *name) +/* 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 mbchar *name) { - struct rb_node *node = dentry->d_inode->i_children.rb_node; - if (node) - return get_rbtree_child_with_name(node, name, strlen(name)); - else - return NULL; + utf16lechar *utf16le_name; + size_t utf16le_name_nbytes; + int ret; + struct wim_dentry *child; + + ret = mbs_to_utf16le(name, strlen(name), + &utf16le_name, &utf16le_name_nbytes); + if (ret) { + child = NULL; + } else { + child = get_dentry_child_with_utf16le_name(dentry, + utf16le_name); + FREE(utf16le_name); + } + return child; } -/* Retrieves the dentry that has the UTF-8 @path relative to the dentry - * @cur_dentry. Returns NULL if no dentry having the path is found. */ -static struct wim_dentry *get_dentry_relative_path(struct wim_dentry *cur_dentry, - const char *path) +/* Returns the dentry corresponding to the @path, or NULL if there is no such + * dentry. */ +struct wim_dentry * +get_dentry(WIMStruct *w, const mbchar *path) { - if (*path == '\0') - return cur_dentry; - - struct rb_node *node = cur_dentry->d_inode->i_children.rb_node; - if (node) { - struct wim_dentry *child; - size_t base_len; - const char *new_path; + utf16lechar *path_utf16le; + size_t path_utf16le_nbytes; + int ret; + struct wim_dentry *cur_dentry, *parent_dentry; + utf16lechar *p, *pp; + utf16lechar save; + + ret = mbs_to_utf16le(path, strlen(path), &path_utf16le, + &path_utf16le_nbytes); + if (ret) { + errno = ENOMEM; + return NULL; + } - new_path = path_next_part(path, &base_len); + parent_dentry = wim_root_dentry(w); + p = path_utf16le; - child = get_rbtree_child_with_name(node, path, base_len); - if (child) - return get_dentry_relative_path(child, new_path); + while (1) { + while (*p == '/') + p++; + cur_dentry = parent_dentry; + if (*p == '\0') + break; + pp = p; + while (*pp != '/' && *pp != '\0') + pp++; + + save = *pp; + *pp = '\0'; + cur_dentry = get_dentry_child_with_utf16le_name(parent_dentry, p); + if (cur_dentry == NULL) + break; + *pp = save; + p = pp; } - /* errno is set to ENOTDIR if the lookup failed due to reaching a - * non-directory, or ENOENT if the lookup failed otherwise. This maybe - * should be factored out somehow. */ - if (dentry_is_directory(cur_dentry)) - errno = ENOENT; - else - errno = ENOTDIR; - return NULL; -} - -/* Returns the dentry corresponding to the UTF-8 @path, or NULL if there is no - * such dentry. */ -struct wim_dentry *get_dentry(WIMStruct *w, const char *path) -{ - struct wim_dentry *root = wim_root_dentry(w); - while (*path == '/') - path++; - return get_dentry_relative_path(root, path); + FREE(path_utf16le); + if (cur_dentry == NULL) { + if (dentry_is_directory(parent_dentry)) + errno = ENOENT; + else + errno = ENOTDIR; + } + return cur_dentry; } -struct wim_inode *wim_pathname_to_inode(WIMStruct *w, const char *path) +struct wim_inode * +wim_pathname_to_inode(WIMStruct *w, const mbchar *path) { struct wim_dentry *dentry; dentry = get_dentry(w, path); @@ -469,23 +484,21 @@ struct wim_inode *wim_pathname_to_inode(WIMStruct *w, const char *path) /* 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 *w, const char *path) +struct wim_dentry *get_parent_dentry(WIMStruct *w, const mbchar *path) { size_t path_len = strlen(path); - char buf[path_len + 1]; + mbchar buf[path_len + 1]; memcpy(buf, path, path_len + 1); - to_parent_name(buf, path_len); - return get_dentry(w, buf); } /* Prints the full path of a dentry. */ int print_dentry_full_path(struct wim_dentry *dentry, void *ignore) { - if (dentry->full_path_utf8) - puts(dentry->full_path_utf8); + if (dentry->full_path) + puts(dentry->full_path); return 0; } @@ -546,13 +559,10 @@ int print_dentry(struct wim_dentry *dentry, void *lookup_table) printf("Hard Link Group = 0x%"PRIx64"\n", inode->i_ino); printf("Hard Link Group Size = %"PRIu32"\n", inode->i_nlink); printf("Number of Alternate Data Streams = %hu\n", inode->i_num_ads); - printf("Filename (UTF-8) = \"%s\"\n", dentry->file_name_utf8); - /*printf("Filename (UTF-8) Length = %hu\n", dentry->file_name_utf8_len);*/ - printf("Short Name (UTF-16LE) = \""); - print_string(dentry->short_name, dentry->short_name_len); - puts("\""); - /*printf("Short Name Length = %hu\n", dentry->short_name_len);*/ - printf("Full Path (UTF-8) = \"%s\"\n", dentry->full_path_utf8); + wimlib_printf("Filename = \"%W\"\n", dentry->file_name); + wimlib_printf("Short Name \"%W\"\n", dentry->short_name); + printf("Full Path = \"%s\"\n", dentry->full_path); + lte = inode_stream_lte(dentry->d_inode, 0, lookup_table); if (lte) { print_lookup_table_entry(lte, stdout); @@ -567,9 +577,9 @@ int print_dentry(struct wim_dentry *dentry, void *lookup_table) } for (u16 i = 0; i < inode->i_num_ads; i++) { printf("[Alternate Stream Entry %u]\n", i); - printf("Name = \"%s\"\n", inode->i_ads_entries[i].stream_name_utf8); - printf("Name Length (UTF-16) = %u\n", - inode->i_ads_entries[i].stream_name_len); + wimlib_printf("Name = \"%W\"\n", inode->i_ads_entries[i].stream_name); + printf("Name Length (UTF16) = %u\n", + inode->i_ads_entries[i].stream_name_nbytes); hash = inode_stream_hash(inode, i + 1); if (hash) { printf("Hash = 0x"); @@ -627,7 +637,7 @@ static struct wim_inode *new_inode() * * Returns a pointer to the new dentry, or NULL if out of memory. */ -struct wim_dentry *new_dentry(const char *name) +struct wim_dentry *new_dentry(const mbchar *name) { struct wim_dentry *dentry; @@ -650,7 +660,7 @@ err: static struct wim_dentry * -__new_dentry_with_inode(const char *name, bool timeless) +__new_dentry_with_inode(const mbchar *name, bool timeless) { struct wim_dentry *dentry; dentry = new_dentry(name); @@ -669,33 +679,37 @@ __new_dentry_with_inode(const char *name, bool timeless) return dentry; } -struct wim_dentry *new_dentry_with_timeless_inode(const char *name) +struct wim_dentry * +new_dentry_with_timeless_inode(const mbchar *name) { return __new_dentry_with_inode(name, true); } -struct wim_dentry *new_dentry_with_inode(const char *name) +struct wim_dentry * +new_dentry_with_inode(const mbchar *name) { return __new_dentry_with_inode(name, false); } -static int init_ads_entry(struct wim_ads_entry *ads_entry, const char *name) +static int +init_ads_entry(struct wim_ads_entry *ads_entry, const mbchar *name) { int ret = 0; memset(ads_entry, 0, sizeof(*ads_entry)); - if (name && *name) - ret = change_ads_name(ads_entry, name); + if (name && *name) { + ret = get_utf16le_name(name, &ads_entry->stream_name, + &ads_entry->stream_name_nbytes); + } return ret; } -static void destroy_ads_entry(struct wim_ads_entry *ads_entry) +static void +destroy_ads_entry(struct wim_ads_entry *ads_entry) { FREE(ads_entry->stream_name); - FREE(ads_entry->stream_name_utf8); } - /* Frees an inode. */ void free_inode(struct wim_inode *inode) { @@ -740,9 +754,8 @@ static void put_inode(struct wim_inode *inode) void free_dentry(struct wim_dentry *dentry) { FREE(dentry->file_name); - FREE(dentry->file_name_utf8); FREE(dentry->short_name); - FREE(dentry->full_path_utf8); + FREE(dentry->full_path); if (dentry->d_inode) put_inode(dentry->d_inode); FREE(dentry); @@ -804,8 +817,9 @@ int increment_dentry_refcnt(struct wim_dentry *dentry, void *ignore) * @parent: The dentry that will be the parent of @dentry. * @dentry: The dentry to link. */ -bool dentry_add_child(struct wim_dentry * restrict parent, - struct wim_dentry * restrict child) +bool +dentry_add_child(struct wim_dentry * restrict parent, + struct wim_dentry * restrict child) { wimlib_assert(dentry_is_directory(parent)); @@ -833,7 +847,8 @@ bool dentry_add_child(struct wim_dentry * restrict parent, } /* Unlink a WIM dentry from the directory entry tree. */ -void unlink_dentry(struct wim_dentry *dentry) +void +unlink_dentry(struct wim_dentry *dentry) { struct wim_dentry *parent = dentry->parent; if (parent == dentry) @@ -845,31 +860,49 @@ void unlink_dentry(struct wim_dentry *dentry) * Returns the alternate data stream entry belonging to @inode that has the * stream name @stream_name. */ -struct wim_ads_entry *inode_get_ads_entry(struct wim_inode *inode, - const char *stream_name, - u16 *idx_ret) +struct wim_ads_entry * +inode_get_ads_entry(struct wim_inode *inode, const mbchar *stream_name, + u16 *idx_ret) { - if (inode->i_num_ads != 0) { - u16 i = 0; - size_t stream_name_len = strlen(stream_name); + if (inode->i_num_ads == 0) { + return NULL; + } else { + int ret; + utf16lechar *stream_name_utf16le; + size_t stream_name_utf16le_nbytes; + u16 i; + struct wim_ads_entry *result; + + ret = mbs_to_utf16le(stream_name, strlen(stream_name), + &stream_name_utf16le, + &stream_name_utf16le_nbytes); + if (ret) + return NULL; + + i = 0; + result = NULL; do { if (ads_entry_has_name(&inode->i_ads_entries[i], - stream_name, stream_name_len)) + stream_name_utf16le, + stream_name_utf16le_nbytes)) { if (idx_ret) *idx_ret = i; - return &inode->i_ads_entries[i]; + result = &inode->i_ads_entries[i]; + break; } } while (++i != inode->i_num_ads); + FREE(stream_name_utf16le); + return result; } - return NULL; } /* * Add an alternate stream entry to a WIM inode and return a pointer to it, or * NULL if memory could not be allocated. */ -struct wim_ads_entry *inode_add_ads(struct wim_inode *inode, const char *stream_name) +struct wim_ads_entry * +inode_add_ads(struct wim_inode *inode, const char *stream_name) { u16 num_ads; struct wim_ads_entry *ads_entries; @@ -900,9 +933,10 @@ struct wim_ads_entry *inode_add_ads(struct wim_inode *inode, const char *stream_ return new_entry; } -int inode_add_ads_with_data(struct wim_inode *inode, const char *name, - const u8 *value, size_t size, - struct wim_lookup_table *lookup_table) +int +inode_add_ads_with_data(struct wim_inode *inode, const mbchar *name, + const void *value, size_t size, + struct wim_lookup_table *lookup_table) { int ret = WIMLIB_ERR_NOMEM; struct wim_ads_entry *new_ads_entry; @@ -949,8 +983,9 @@ out: } /* Remove an alternate data stream from a WIM inode */ -void inode_remove_ads(struct wim_inode *inode, u16 idx, - struct wim_lookup_table *lookup_table) +void +inode_remove_ads(struct wim_inode *inode, u16 idx, + struct wim_lookup_table *lookup_table) { struct wim_ads_entry *ads_entry; struct wim_lookup_table_entry *lte; @@ -960,7 +995,7 @@ void inode_remove_ads(struct wim_inode *inode, u16 idx, ads_entry = &inode->i_ads_entries[idx]; - DEBUG("Remove alternate data stream \"%s\"", ads_entry->stream_name_utf8); + DEBUG("Remove alternate data stream \"%W\"", ads_entry->stream_name); lte = ads_entry->lte; if (lte) @@ -975,9 +1010,10 @@ void inode_remove_ads(struct wim_inode *inode, u16 idx, } #ifndef __WIN32__ -int inode_get_unix_data(const struct wim_inode *inode, - struct wimlib_unix_data *unix_data, - u16 *stream_idx_ret) +int +inode_get_unix_data(const struct wim_inode *inode, + struct wimlib_unix_data *unix_data, + u16 *stream_idx_ret) { const struct wim_ads_entry *ads_entry; const struct wim_lookup_table_entry *lte; @@ -1011,10 +1047,9 @@ int inode_get_unix_data(const struct wim_inode *inode, return 0; } -int inode_set_unix_data(struct wim_inode *inode, - uid_t uid, gid_t gid, mode_t mode, - struct wim_lookup_table *lookup_table, - int which) +int +inode_set_unix_data(struct wim_inode *inode, uid_t uid, gid_t gid, mode_t mode, + struct wim_lookup_table *lookup_table, int which) { struct wimlib_unix_data unix_data; int ret; @@ -1086,8 +1121,8 @@ int inode_set_unix_data(struct wim_inode *inode, * is set to an array of `struct wim_ads_entry's of length inode->i_num_ads. On * failure, @inode is not modified. */ -static int read_ads_entries(const u8 *p, struct wim_inode *inode, - u64 remaining_size) +static int +read_ads_entries(const u8 *p, struct wim_inode *inode, u64 remaining_size) { u16 num_ads; struct wim_ads_entry *ads_entries; @@ -1126,15 +1161,14 @@ static int read_ads_entries(const u8 *p, struct wim_inode *inode, p = get_u64(p, &length); p += 8; /* Skip the reserved field */ p = get_bytes(p, SHA1_HASH_SIZE, (u8*)cur_entry->hash); - p = get_u16(p, &cur_entry->stream_name_len); + p = get_u16(p, &cur_entry->stream_name_nbytes); cur_entry->stream_name = NULL; - cur_entry->stream_name_utf8 = NULL; /* Length including neither the null terminator nor the padding * */ length_no_padding = WIM_ADS_ENTRY_DISK_SIZE + - cur_entry->stream_name_len; + cur_entry->stream_name_nbytes; /* Length including the null terminator and the padding */ total_length = ((length_no_padding + 2) + 7) & ~7; @@ -1166,22 +1200,16 @@ static int read_ads_entries(const u8 *p, struct wim_inode *inode, goto out_free_ads_entries; } - if (cur_entry->stream_name_len) { - cur_entry->stream_name = MALLOC(cur_entry->stream_name_len); + if (cur_entry->stream_name_nbytes) { + cur_entry->stream_name = MALLOC((size_t) + cur_entry->stream_name_nbytes + 2); if (!cur_entry->stream_name) { ret = WIMLIB_ERR_NOMEM; goto out_free_ads_entries; } - get_bytes(p, cur_entry->stream_name_len, - (u8*)cur_entry->stream_name); - - ret = utf16_to_utf8(cur_entry->stream_name, - cur_entry->stream_name_len, - &cur_entry->stream_name_utf8, - &utf8_len); - if (ret != 0) - goto out_free_ads_entries; - cur_entry->stream_name_utf8_len = utf8_len; + get_bytes(p, cur_entry->stream_name_nbytes, + cur_entry->stream_name); + cur_entry->stream_name[cur_entry->stream_name_nbytes / 2] = 0; } /* It's expected that the size of every ADS entry is a multiple * of 8. However, to be safe, I'm allowing the possibility of @@ -1224,17 +1252,16 @@ out_free_ads_entries: * this was a special "end of directory" dentry and not a real dentry. If * nonzero, this was a real dentry. */ -int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, - u64 offset, struct wim_dentry *dentry) +int +read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, + u64 offset, struct wim_dentry *dentry) { const u8 *p; u64 calculated_size; - char *file_name = NULL; - char *file_name_utf8 = NULL; - char *short_name = NULL; - u16 short_name_len; - u16 file_name_len; - size_t file_name_utf8_len = 0; + utf16lechar *file_name = NULL; + utf16lechar *short_name = NULL; + u16 short_name_nbytes; + u16 file_name_nbytes; int ret; struct wim_inode *inode = NULL; @@ -1321,8 +1348,8 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, p = get_u16(p, &inode->i_num_ads); - p = get_u16(p, &short_name_len); - p = get_u16(p, &file_name_len); + p = get_u16(p, &short_name_nbytes); + p = get_u16(p, &file_name_nbytes); /* We now know the length of the file name and short name. Make sure * the length of the dentry is large enough to actually hold them. @@ -1330,40 +1357,35 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, * The calculated length here is unaligned to allow for the possibility * that the dentry->length names an unaligned length, although this * would be unexpected. */ - calculated_size = __dentry_correct_length_unaligned(file_name_len, - short_name_len); + calculated_size = __dentry_correct_length_unaligned(file_name_nbytes, + short_name_nbytes); if (dentry->length < calculated_size) { ERROR("Unexpected end of directory entry! (Expected " "at least %"PRIu64" bytes, got %"PRIu64" bytes. " - "short_name_len = %hu, file_name_len = %hu)", + "short_name_nbytes = %hu, file_name_nbytes = %hu)", calculated_size, dentry->length, - short_name_len, file_name_len); + short_name_nbytes, file_name_nbytes); ret = WIMLIB_ERR_INVALID_DENTRY; goto out_free_inode; } /* Read the filename if present. Note: if the filename is empty, there * is no null terminator following it. */ - if (file_name_len) { - file_name = MALLOC(file_name_len); + if (file_name_nbytes) { + file_name = MALLOC((size_t)file_name_nbytes + 2); if (!file_name) { - ERROR("Failed to allocate %hu bytes for dentry file name", - file_name_len); + ERROR("Failed to allocate %zu bytes for dentry file name", + (size_t)file_name_nbytes + 2); ret = WIMLIB_ERR_NOMEM; goto out_free_inode; } - p = get_bytes(p, file_name_len, file_name); - - /* Convert filename to UTF-8. */ - ret = utf16_to_utf8(file_name, file_name_len, &file_name_utf8, - &file_name_utf8_len); - if (ret != 0) - goto out_free_file_name; - if (*(u16*)p) - WARNING("Expected two zero bytes following the file name " - "`%s', but found non-zero bytes", file_name_utf8); - p += 2; + p = get_bytes(p, (size_t)file_name_nbytes + 2, file_name); + if (file_name[file_name_nbytes / 2] != 0) { + file_name[file_name_nbytes / 2] = 0; + WARNING("File name in WIM dentry \"%W\" is not " + "null-terminated!", file_name); + } } /* Align the calculated size */ @@ -1393,27 +1415,27 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, * 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 `%s' has %"PRIu64" extra "*/ + /*"bytes of data",*/ + /*file_name_utf8, dentry->length - calculated_size);*/ } /* Read the short filename if present. Note: if there is no short * filename, there is no null terminator following it. */ - if (short_name_len) { - short_name = MALLOC(short_name_len); + if (short_name_nbytes) { + short_name = MALLOC((size_t)short_name_nbytes + 2); if (!short_name) { - ERROR("Failed to allocate %hu bytes for short filename", - short_name_len); + ERROR("Failed to allocate %zu bytes for dentry short name", + (size_t)short_name_nbytes + 2); ret = WIMLIB_ERR_NOMEM; - goto out_free_file_name_utf8; + goto out_free_file_name; + } + p = get_bytes(p, (size_t)short_name_nbytes + 2, short_name); + if (short_name[short_name_nbytes / 2] != 0) { + short_name[short_name_nbytes / 2] = 0; + WARNING("Short name in WIM dentry \"%W\" is not " + "null-terminated!", file_name); } - - p = get_bytes(p, short_name_len, short_name); - if (*(u16*)p) - WARNING("Expected two zero bytes following the short name of " - "`%s', but found non-zero bytes", file_name_utf8); - p += 2; } /* @@ -1451,25 +1473,20 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, goto out; } ERROR("Failed to read alternate data stream " - "entries of `%s'", dentry->file_name_utf8); + "entries of WIM dentry \"%W\"", file_name); goto out_free_short_name; } out: - /* We've read all the data for this dentry. Set the names and their * lengths, and we've done. */ - dentry->d_inode = inode; - dentry->file_name = file_name; - dentry->file_name_utf8 = file_name_utf8; - dentry->short_name = short_name; - dentry->file_name_len = file_name_len; - dentry->file_name_utf8_len = file_name_utf8_len; - dentry->short_name_len = short_name_len; + dentry->d_inode = inode; + dentry->file_name = file_name; + dentry->short_name = short_name; + dentry->file_name_nbytes = file_name_nbytes; + dentry->short_name_nbytes = short_name_nbytes; return 0; out_free_short_name: FREE(short_name); -out_free_file_name_utf8: - FREE(file_name_utf8); out_free_file_name: FREE(file_name); out_free_inode: @@ -1491,10 +1508,11 @@ out_free_inode: * does not need to be the real root because this procedure is * called recursively. * - * @return: Zero on success, nonzero on failure. + * Returns zero on success; nonzero on failure. */ -int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len, - struct wim_dentry *dentry) +int +read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len, + struct wim_dentry *dentry) { u64 cur_offset = dentry->subdir_offset; struct wim_dentry *child; @@ -1563,7 +1581,8 @@ int read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len, * @return: Pointer to the byte after the last byte we wrote as part of the * dentry. */ -static u8 *write_dentry(const struct wim_dentry *dentry, u8 *p) +static u8 * +write_dentry(const struct wim_dentry *dentry, u8 *p) { u8 *orig_p = p; const u8 *hash; @@ -1600,15 +1619,15 @@ static u8 *write_dentry(const struct wim_dentry *dentry, u8 *p) p = put_u64(p, link_group_id); } p = put_u16(p, inode->i_num_ads); - p = put_u16(p, dentry->short_name_len); - p = put_u16(p, dentry->file_name_len); - if (dentry->file_name_len) { - p = put_bytes(p, dentry->file_name_len, (u8*)dentry->file_name); - p = put_u16(p, 0); /* filename padding, 2 bytes. */ + p = put_u16(p, dentry->short_name_nbytes); + p = put_u16(p, dentry->file_name_nbytes); + if (dentry->file_name_nbytes) { + p = put_bytes(p, dentry->file_name_nbytes + 2, + dentry->file_name); } - if (dentry->short_name) { - p = put_bytes(p, dentry->short_name_len, (u8*)dentry->short_name); - p = put_u16(p, 0); /* short name padding, 2 bytes */ + if (dentry->short_name_nbytes) { + p = put_bytes(p, dentry->short_name_nbytes + 2, + dentry->short_name); } /* Align to 8-byte boundary */ @@ -1623,11 +1642,11 @@ static u8 *write_dentry(const struct wim_dentry *dentry, u8 *p) p = put_u64(p, 0); /* Unused */ hash = inode_stream_hash(inode, i + 1); p = put_bytes(p, SHA1_HASH_SIZE, hash); - p = put_u16(p, inode->i_ads_entries[i].stream_name_len); - if (inode->i_ads_entries[i].stream_name_len) { - p = put_bytes(p, inode->i_ads_entries[i].stream_name_len, - (u8*)inode->i_ads_entries[i].stream_name); - p = put_u16(p, 0); + p = put_u16(p, inode->i_ads_entries[i].stream_name_nbytes); + if (inode->i_ads_entries[i].stream_name_nbytes) { + p = put_bytes(p, + inode->i_ads_entries[i].stream_name_nbytes + 2, + inode->i_ads_entries[i].stream_name); } p = put_zeroes(p, (8 - (p - orig_p) % 8) % 8); } @@ -1635,16 +1654,19 @@ static u8 *write_dentry(const struct wim_dentry *dentry, u8 *p) return p; } -static int write_dentry_cb(struct wim_dentry *dentry, void *_p) +static int +write_dentry_cb(struct wim_dentry *dentry, void *_p) { u8 **p = _p; *p = write_dentry(dentry, *p); return 0; } -static u8 *write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p); +static u8 * +write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p); -static int write_dentry_tree_recursive_cb(struct wim_dentry *dentry, void *_p) +static int +write_dentry_tree_recursive_cb(struct wim_dentry *dentry, void *_p) { u8 **p = _p; *p = write_dentry_tree_recursive(dentry, *p); @@ -1653,7 +1675,8 @@ static int write_dentry_tree_recursive_cb(struct wim_dentry *dentry, void *_p) /* Recursive function that writes a dentry tree rooted at @parent, not including * @parent itself, which has already been written. */ -static u8 *write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p) +static u8 * +write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p) { /* Nothing to do if this dentry has no children. */ if (parent->subdir_offset == 0) @@ -1682,7 +1705,8 @@ static u8 *write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p) * * Returns pointer to the byte after the last byte we wrote. */ -u8 *write_dentry_tree(const struct wim_dentry *root, u8 *p) +u8 * +write_dentry_tree(const struct wim_dentry *root, u8 *p) { DEBUG("Writing dentry tree."); wimlib_assert(dentry_is_root(root)); diff --git a/src/dentry.h b/src/dentry.h index 76087320..dfbcafca 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -74,18 +74,12 @@ struct wim_ads_entry { struct wim_lookup_table_entry *lte; }; - /* Length of stream name (UTF-16). This is in bytes, not characters, - * and does not include the terminating null character */ - u16 stream_name_len; + /* Length of UTF16-encoded stream name, in bytes, not including the + * terminating null character. */ + u16 stream_name_nbytes; - /* Length of stream name (UTF-8) */ - u16 stream_name_utf8_len; - - /* Stream name (UTF-16) */ - char *stream_name; - - /* Stream name (UTF-8) */ - char *stream_name_utf8; + /* Stream name (UTF-16LE) */ + utf16lechar *stream_name; #ifdef WITH_FUSE /* Number to identify an alternate data stream even after it's possibly @@ -95,13 +89,13 @@ struct wim_ads_entry { }; -static inline bool ads_entries_have_same_name(const struct wim_ads_entry *entry_1, - const struct wim_ads_entry *entry_2) +static inline bool +ads_entries_have_same_name(const struct wim_ads_entry *entry_1, + const struct wim_ads_entry *entry_2) { - if (entry_1->stream_name_len != entry_2->stream_name_len) - return false; - return memcmp(entry_1->stream_name, entry_2->stream_name, - entry_1->stream_name_len) == 0; + return entry_1->stream_name_nbytes == entry_2->stream_name_nbytes && + memcmp(entry_1->stream_name, entry_2->stream_name, + entry_1->stream_name_nbytes) == 0; } /* @@ -133,46 +127,31 @@ static inline bool ads_entries_have_same_name(const struct wim_ads_entry *entry_ * dentry_tree_fix_inodes() in hardlink.c). */ struct wim_dentry { - /* Byte 0 */ - /* The inode for this dentry */ struct wim_inode *d_inode; - /* Byte 8 */ - /* Red-black tree of sibling dentries */ struct rb_node rb_node; - /* Byte 32 */ + /* Length of UTF-16LE encoded short filename, in bytes, not including + * the terminating zero wide-character. */ + u16 short_name_nbytes; - /* Length of short filename, in bytes, not including the terminating - * zero wide-character. */ - u16 short_name_len; + /* Length of UTF-16LE encoded "long" file name, in bytes, not including + * the terminating null character. */ + u16 file_name_nbytes; - /* Length of file name, in bytes, not including the terminating zero - * wide-character. */ - u16 file_name_len; - - /* Length of the filename converted into UTF-8, in bytes, not including - * the terminating zero byte. */ - u16 file_name_utf8_len; + /* Length of full path name, in bytes, as a multibyte-encoded string */ + u32 full_path_nbytes; u8 is_extracted : 1; /* Only used during NTFS capture */ u8 is_win32_name : 1; - /* Byte 40 */ - - /* Pointer to the filename converted to UTF-8 (malloc()ed buffer). */ - char *file_name_utf8; - - /* Byte 48 */ - + /* Temporary list */ struct list_head tmp_list; - /* Byte 64 */ - /* List of dentries in the inode (hard link set) */ struct list_head d_alias; @@ -209,16 +188,14 @@ struct wim_dentry { * WIMStructs */ u32 refcnt; - u32 full_path_utf8_len; - - /* Pointer to the UTF-16 short filename (malloc()ed buffer) */ - char *short_name; + /* Pointer to the UTF-16LE short filename (malloc()ed buffer) */ + utf16lechar *short_name; - /* Pointer to the UTF-16 filename (malloc()ed buffer). */ - char *file_name; + /* Pointer to the UTF-16LE filename (malloc()ed buffer). */ + utf16lechar *file_name; - /* Full path (UTF-8) to this dentry (malloc()ed buffer). */ - char *full_path_utf8; + /* Full path of this dentry */ + mbchar *full_path; }; #define rbnode_dentry(node) container_of(node, struct wim_dentry, rb_node) @@ -294,7 +271,7 @@ struct wim_inode { struct list_head i_lte_inode_list; - char *i_extracted_file; + mbchar *i_extracted_file; /* Root of a red-black tree storing the children of this inode (if * non-empty, implies the inode is a directory, although that is also @@ -326,80 +303,119 @@ struct wim_inode { #define inode_first_dentry(inode) \ container_of(inode->i_dentry.next, struct wim_dentry, d_alias) -static inline bool dentry_is_first_in_inode(const struct wim_dentry *dentry) +static inline bool +dentry_is_first_in_inode(const struct wim_dentry *dentry) { return inode_first_dentry(dentry->d_inode) == dentry; } -extern u64 dentry_correct_total_length(const struct wim_dentry *dentry); +extern u64 +dentry_correct_total_length(const struct wim_dentry *dentry); -extern int for_dentry_in_tree(struct wim_dentry *root, - int (*visitor)(struct wim_dentry*, void*), - void *args); +extern int +for_dentry_in_tree(struct wim_dentry *root, + int (*visitor)(struct wim_dentry*, void*), + void *args); -extern int for_dentry_in_rbtree(struct rb_node *node, - int (*visitor)(struct wim_dentry *, void *), - void *arg); +extern int +for_dentry_in_rbtree(struct rb_node *node, + int (*visitor)(struct wim_dentry *, void *), + void *arg); -static inline int for_dentry_child(const struct wim_dentry *dentry, - int (*visitor)(struct wim_dentry *, void *), - void *arg) +static inline int +for_dentry_child(const struct wim_dentry *dentry, + int (*visitor)(struct wim_dentry *, void *), + void *arg) { return for_dentry_in_rbtree(dentry->d_inode->i_children.rb_node, visitor, arg); } -extern int for_dentry_in_tree_depth(struct wim_dentry *root, - int (*visitor)(struct wim_dentry*, void*), - void *args); +extern int +for_dentry_in_tree_depth(struct wim_dentry *root, + int (*visitor)(struct wim_dentry*, void*), + void *args); + +extern int +calculate_dentry_full_path(struct wim_dentry *dentry, void *ignore); + +extern void +calculate_subdir_offsets(struct wim_dentry *dentry, u64 *subdir_offset_p); + +extern int +set_dentry_name(struct wim_dentry *dentry, const mbchar *new_name); -extern int calculate_dentry_full_path(struct wim_dentry *dentry, void *ignore); -extern void calculate_subdir_offsets(struct wim_dentry *dentry, u64 *subdir_offset_p); -extern int set_dentry_name(struct wim_dentry *dentry, const char *new_name); +extern struct wim_dentry * +get_dentry(struct WIMStruct *w, const mbchar *path); + +extern struct wim_inode * +wim_pathname_to_inode(struct WIMStruct *w, const mbchar *path); -extern struct wim_dentry *get_dentry(struct WIMStruct *w, const char *path); +extern struct wim_dentry * +get_dentry_child_with_name(const struct wim_dentry *dentry, + const mbchar *name); -extern struct wim_inode *wim_pathname_to_inode(struct WIMStruct *w, - const char *path); +extern struct wim_dentry * +get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry, + const utf16lechar *name); extern struct wim_dentry * -get_dentry_child_with_name(const struct wim_dentry *dentry, const char *name); +get_parent_dentry(struct WIMStruct *w, const mbchar *path); + +extern int +print_dentry(struct wim_dentry *dentry, void *lookup_table); + +extern int +print_dentry_full_path(struct wim_dentry *entry, void *ignore); + +extern struct +wim_dentry *new_dentry(const mbchar *name); + +extern struct wim_dentry * +new_dentry_with_inode(const mbchar *name); + +extern struct wim_dentry * +new_dentry_with_timeless_inode(const mbchar *name); + +extern void +free_inode(struct wim_inode *inode); + +extern void +free_dentry(struct wim_dentry *dentry); -extern struct wim_dentry *get_parent_dentry(struct WIMStruct *w, - const char *path); +extern void +put_dentry(struct wim_dentry *dentry); -extern int print_dentry(struct wim_dentry *dentry, void *lookup_table); -extern int print_dentry_full_path(struct wim_dentry *entry, void *ignore); +extern void +free_dentry_tree(struct wim_dentry *root, + struct wim_lookup_table *lookup_table); -extern struct wim_dentry *new_dentry(const char *name); -extern struct wim_dentry *new_dentry_with_inode(const char *name); -extern struct wim_dentry *new_dentry_with_timeless_inode(const char *name); +extern int +increment_dentry_refcnt(struct wim_dentry *dentry, void *ignore); -extern void free_inode(struct wim_inode *inode); -extern void free_dentry(struct wim_dentry *dentry); -extern void put_dentry(struct wim_dentry *dentry); +extern void +unlink_dentry(struct wim_dentry *dentry); -extern void free_dentry_tree(struct wim_dentry *root, - struct wim_lookup_table *lookup_table); -extern int increment_dentry_refcnt(struct wim_dentry *dentry, void *ignore); +extern bool +dentry_add_child(struct wim_dentry * restrict parent, + struct wim_dentry * restrict child); -extern void unlink_dentry(struct wim_dentry *dentry); -extern bool dentry_add_child(struct wim_dentry * restrict parent, - struct wim_dentry * restrict child); +extern struct wim_ads_entry * +inode_get_ads_entry(struct wim_inode *inode, const mbchar *stream_name, + u16 *idx_ret); -extern struct wim_ads_entry *inode_get_ads_entry(struct wim_inode *inode, - const char *stream_name, - u16 *idx_ret); +extern struct wim_ads_entry * +inode_add_ads(struct wim_inode *dentry, const mbchar *stream_name); -extern struct wim_ads_entry *inode_add_ads(struct wim_inode *dentry, - const char *stream_name); -extern int inode_add_ads_with_data(struct wim_inode *inode, const char *name, - const u8 *value, size_t size, - struct wim_lookup_table *lookup_table); +extern int +inode_add_ads_with_data(struct wim_inode *inode, const mbchar *name, + const void *value, size_t size, + struct wim_lookup_table *lookup_table); -extern void inode_remove_ads(struct wim_inode *inode, u16 idx, - struct wim_lookup_table *lookup_table); +extern void +inode_remove_ads(struct wim_inode *inode, u16 idx, + struct wim_lookup_table *lookup_table); #define WIMLIB_UNIX_DATA_TAG "$$__wimlib_UNIX_data" @@ -418,72 +434,82 @@ struct wimlib_unix_data { #define NO_UNIX_DATA (-1) #define BAD_UNIX_DATA (-2) -extern int inode_get_unix_data(const struct wim_inode *inode, - struct wimlib_unix_data *unix_data, - u16 *stream_idx_ret); +extern int +inode_get_unix_data(const struct wim_inode *inode, + struct wimlib_unix_data *unix_data, + u16 *stream_idx_ret); #define UNIX_DATA_UID 0x1 #define UNIX_DATA_GID 0x2 #define UNIX_DATA_MODE 0x4 #define UNIX_DATA_ALL (UNIX_DATA_UID | UNIX_DATA_GID | UNIX_DATA_MODE) #define UNIX_DATA_CREATE 0x8 -extern int inode_set_unix_data(struct wim_inode *inode, - uid_t uid, gid_t gid, mode_t mode, - struct wim_lookup_table *lookup_table, - int which); +extern int +inode_set_unix_data(struct wim_inode *inode, uid_t uid, gid_t gid, mode_t mode, + struct wim_lookup_table *lookup_table, int which); #endif -extern int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, - u64 offset, struct wim_dentry *dentry); +extern int +read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, + u64 offset, struct wim_dentry *dentry); -extern int read_dentry_tree(const u8 metadata_resource[], - u64 metadata_resource_len, - struct wim_dentry *dentry); +extern int +read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len, + struct wim_dentry *dentry); -extern u8 *write_dentry_tree(const struct wim_dentry *tree, u8 *p); +extern u8 * +write_dentry_tree(const struct wim_dentry *tree, u8 *p); -static inline bool dentry_is_root(const struct wim_dentry *dentry) +static inline bool +dentry_is_root(const struct wim_dentry *dentry) { return dentry->parent == dentry; } -static inline bool inode_is_directory(const struct wim_inode *inode) +static inline bool +inode_is_directory(const struct wim_inode *inode) { return (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) && !(inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT); } -static inline bool dentry_is_directory(const struct wim_dentry *dentry) +static inline bool +dentry_is_directory(const struct wim_dentry *dentry) { return inode_is_directory(dentry->d_inode); } /* For our purposes, we consider "real" symlinks and "junction points" to both * be symlinks. */ -static inline bool inode_is_symlink(const struct wim_inode *inode) +static inline bool +inode_is_symlink(const struct wim_inode *inode) { return (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) && ((inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK) || inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT); } -static inline bool inode_is_regular_file(const struct wim_inode *inode) +static inline bool +inode_is_regular_file(const struct wim_inode *inode) { return !inode_is_directory(inode) && !inode_is_symlink(inode); } -static inline bool dentry_is_regular_file(const struct wim_dentry *dentry) +static inline bool +dentry_is_regular_file(const struct wim_dentry *dentry) { return inode_is_regular_file(dentry->d_inode); } -static inline bool inode_has_children(const struct wim_inode *inode) +static inline bool +inode_has_children(const struct wim_inode *inode) { return inode->i_children.rb_node != NULL; } -static inline bool dentry_has_children(const struct wim_dentry *dentry) +static inline bool +dentry_has_children(const struct wim_dentry *dentry) { return inode_has_children(dentry->d_inode); } diff --git a/src/encoding.c b/src/encoding.c index bddb1810..de043581 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -1,5 +1,7 @@ /* - * encoding.c: Convert UTF-8 to UTF-16LE strings and vice versa + * 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. */ /* @@ -22,373 +24,256 @@ */ #include "config.h" -#include "wimlib.h" -#include "util.h" -#include "endianness.h" - -#include - -#ifdef WITH_NTFS_3G -# include -# include -#elif defined(__WIN32__) -# include -# include -#else -# include -#endif +#include "wimlib_internal.h" +#include +#include "list.h" -/* - * NOTE: - * - * utf16_to_utf8_size() and utf8_to_utf16_size() were taken from - * libntfs-3g/unistr.c in the NTFS-3g sources. (Modified slightly to remove - * unneeded functionality.) - */ -#if !defined(WITH_NTFS_3G) && !defined(__WIN32__) -/* - * Return the amount of 8-bit elements in UTF-8 needed (without the terminating - * null) to store a given UTF-16LE string. - * - * Return -1 with errno set if string has invalid byte sequence or too long. - */ -static int utf16_to_utf8_size(const u16 *ins, const int ins_len) -{ - int i, ret = -1; - int count = 0; - bool surrog; - - surrog = false; - for (i = 0; i < ins_len && ins[i]; i++) { - unsigned short c = le16_to_cpu(ins[i]); - if (surrog) { - if ((c >= 0xdc00) && (c < 0xe000)) { - surrog = false; - count += 4; - } else - goto fail; - } else - if (c < 0x80) - count++; - else if (c < 0x800) - count += 2; - else if (c < 0xd800) - count += 3; - else if (c < 0xdc00) - surrog = true; -#if NOREVBOM - else if ((c >= 0xe000) && (c < 0xfffe)) -#else - else if (c >= 0xe000) -#endif - count += 3; - else - goto fail; - } - if (surrog) - goto fail; +#include +#include - ret = count; -out: - return ret; -fail: - errno = EILSEQ; - goto out; +bool wimlib_mbs_is_utf8 = false; + +struct iconv_list_head { + const char *from_encoding; + const char *to_encoding; + struct list_head list; + pthread_mutex_t mutex; +}; + +struct iconv_node { + iconv_t cd; + struct list_head list; + struct iconv_list_head *head; +}; + +#define ICONV_LIST(name, from, to) \ +struct iconv_list_head name = { \ + .from_encoding = from, \ + .to_encoding = to, \ + .list = LIST_HEAD_INIT(name.list), \ + .mutex = PTHREAD_MUTEX_INITIALIZER, \ } -/* - * Return the amount of 16-bit elements in UTF-16LE needed - * (without the terminating null) to store given UTF-8 string. - * - * Return -1 with errno set if it's longer than PATH_MAX or string is invalid. - * - * Note: This does not check whether the input sequence is a valid utf8 string, - * and should be used only in context where such check is made! - */ -static int utf8_to_utf16_size(const char *s) +static ICONV_LIST(iconv_mbs_to_utf16le, "", "UTF-16LE"); +static ICONV_LIST(iconv_utf16le_to_mbs, "UTF-16LE", ""); + +static iconv_t * +get_iconv(struct iconv_list_head *head) { - unsigned int byte; - size_t count = 0; - while ((byte = *((const unsigned char *)s++))) { - count++; - if (byte >= 0xc0) { - if (byte >= 0xF5) { - errno = EILSEQ; - return -1; - } - if (!*s) - break; - if (byte >= 0xC0) - s++; - if (!*s) - break; - if (byte >= 0xE0) - s++; - if (!*s) - break; - if (byte >= 0xF0) { - s++; - count++; + iconv_t cd; + struct iconv_node *i; + + pthread_mutex_lock(&head->mutex); + if (list_empty(&head->list)) { + cd = iconv_open(head->to_encoding, head->from_encoding); + if (cd == (iconv_t)-1) { + goto out_unlock; + } else { + i = MALLOC(sizeof(struct iconv_node)); + if (!i) { + iconv_close(cd); + cd = (iconv_t)-1; + goto out_unlock; } + i->head = head; } + } else { + i = container_of(head->list.next, struct iconv_node, list); + list_del(head->list.next); } - return count; + cd = i->cd; +out_unlock: + pthread_mutex_unlock(&head->mutex); + return cd; } -static iconv_t cd_utf8_to_utf16 = (iconv_t)(-1); -static iconv_t cd_utf16_to_utf8 = (iconv_t)(-1); +static void +put_iconv(iconv_t *cd) +{ + struct iconv_node *i = container_of(cd, struct iconv_node, cd); + struct iconv_list_head *head = i->head; + + pthread_mutex_lock(&head->mutex); + list_add(&i->list, &head->list); + pthread_mutex_unlock(&head->mutex); +} -int iconv_global_init() +int +mbs_to_utf16le_nbytes(const mbchar *mbs, size_t mbs_nbytes, + size_t *utf16le_nbytes_ret) { - if (cd_utf16_to_utf8 == (iconv_t)(-1)) { - cd_utf16_to_utf8 = iconv_open("UTF-8", "UTF-16LE"); - if (cd_utf16_to_utf8 == (iconv_t)-1) { - ERROR_WITH_ERRNO("Failed to get conversion descriptor " - "for converting UTF-16LE to UTF-8"); - if (errno == ENOMEM) - return WIMLIB_ERR_NOMEM; - else - return WIMLIB_ERR_ICONV_NOT_AVAILABLE; - } - } + iconv_t *cd = get_iconv(&iconv_mbs_to_utf16le); + if (*cd == (iconv_t)-1) + return WIMLIB_ERR_ICONV_NOT_AVAILABLE; - if (cd_utf8_to_utf16 == (iconv_t)(-1)) { - cd_utf8_to_utf16 = iconv_open("UTF-16LE", "UTF-8"); - if (cd_utf8_to_utf16 == (iconv_t)-1) { - ERROR_WITH_ERRNO("Failed to get conversion descriptor " - "for converting UTF-8 to UTF-16LE"); - if (errno == ENOMEM) - return WIMLIB_ERR_NOMEM; - else - return WIMLIB_ERR_ICONV_NOT_AVAILABLE; - } + /* Worst case length */ + utf16lechar buf[mbs_nbytes * 2]; + char *inbuf = (char*)mbs; + char *outbuf = (char*)buf; + size_t outbytesleft = sizeof(buf); + size_t inbytesleft = mbs_nbytes; + size_t len; + int ret; + + len = iconv(*cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + if (len == (size_t)-1) { + ret = WIMLIB_ERR_INVALID_MULTIBYTE_STRING; + } else { + *utf16le_nbytes_ret = sizeof(buf) - outbytesleft; + ret = 0; } - return 0; + put_iconv(cd); + return ret; } -void iconv_global_cleanup() -{ - if (cd_utf8_to_utf16 != (iconv_t)(-1)) - iconv_close(cd_utf8_to_utf16); - if (cd_utf16_to_utf8 != (iconv_t)(-1)) - iconv_close(cd_utf16_to_utf8); -} -#endif /* !WITH_NTFS_3G && !__WIN32__ */ -/* Converts a string in the UTF-16LE encoding to a newly allocated string in the - * UTF-8 encoding. - * - * If available, do so by calling a similar function from libntfs-3g. - * Otherwise, use iconv() along with the helper function utf16_to_utf8_size(). - */ -int utf16_to_utf8(const char *utf16_str, size_t utf16_nbytes, - char **utf8_str_ret, size_t *utf8_nbytes_ret) +int +utf16le_to_mbs_nbytes(const utf16lechar *utf16le_str, size_t utf16le_nbytes, + size_t *mbs_nbytes_ret) { + iconv_t *cd = get_iconv(&iconv_utf16le_to_mbs); + if (*cd == (iconv_t)-1) + return WIMLIB_ERR_ICONV_NOT_AVAILABLE; + + /* Worst case length */ + mbchar buf[utf16le_nbytes / 2 * MB_CUR_MAX]; + char *inbuf = (char*)utf16le_str; + char *outbuf = (char*)buf; + size_t outbytesleft = sizeof(buf); + size_t inbytesleft = utf16le_nbytes; + size_t len; int ret; - if (utf16_nbytes == 0) { - *utf8_str_ret = NULL; - *utf8_nbytes_ret = 0; - return 0; + len = iconv(*cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + if (len == (size_t)-1) { + ERROR("Could not convert \"%W\" to encoding of current locale", + utf16le_str); + /* EILSEQ is supposed to mean that the *input* is invalid, but + * it's also returned if any input characters are not + * representable in the output encoding. (The actual behavior + * in this case is undefined for some reason...). Assume it's + * the latter error case. */ + ret = WIMLIB_ERR_UNICODE_STRING_NOT_REPRESENTABLE; + } else { + *mbs_nbytes_ret = sizeof(buf) - outbytesleft; + ret = 0; } + put_iconv(cd); + return ret; +} - if (utf16_nbytes & 1) { - ERROR("UTF-16LE string is invalid (odd number of bytes)!"); - return WIMLIB_ERR_INVALID_UTF16_STRING; - } -#ifdef WITH_NTFS_3G - char *outs = NULL; - int outs_len = ntfs_ucstombs((const ntfschar*)utf16_str, - utf16_nbytes / 2, &outs, 0); - if (outs_len >= 0) { - *utf8_str_ret = outs; - *utf8_nbytes_ret = outs_len; - ret = 0; +int +mbs_to_utf16le_buf(const mbchar *mbs, size_t mbs_nbytes, + utf16lechar *utf16le_str) +{ + iconv_t *cd = get_iconv(&iconv_mbs_to_utf16le); + if (*cd == (iconv_t)-1) + return WIMLIB_ERR_ICONV_NOT_AVAILABLE; + + char *inbuf = (char*)mbs; + size_t inbytesleft = mbs_nbytes; + char *outbuf = (char*)utf16le_str; + size_t outbytesleft = SIZE_MAX; + size_t len; + int ret; + + len = iconv(*cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + if (len == (size_t)-1) { + ret = WIMLIB_ERR_INVALID_MULTIBYTE_STRING; } else { - if (errno == ENOMEM) - ret = WIMLIB_ERR_NOMEM; - else - ret = WIMLIB_ERR_INVALID_UTF16_STRING; + ret = 0; } -#elif defined(__WIN32__) - char *utf8_str; - size_t utf8_nbytes; - utf8_nbytes = wcstombs(NULL, (const wchar_t*)utf16_str, 0); - if (utf8_nbytes == (size_t)(-1)) { + put_iconv(cd); + return ret; +} + +int +utf16le_to_mbs_buf(const utf16lechar *utf16le_str, size_t utf16le_nbytes, + mbchar *mbs) +{ + int ret; + iconv_t *cd = get_iconv(&iconv_utf16le_to_mbs); + if (*cd == (iconv_t)-1) + return WIMLIB_ERR_ICONV_NOT_AVAILABLE; + + char *inbuf = (char*)utf16le_str; + size_t inbytesleft; + char *outbuf = (char*)mbs; + size_t outbytesleft = SIZE_MAX; + size_t len; + + len = iconv(*cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); + if (len == (size_t)-1) { ret = WIMLIB_ERR_INVALID_UTF16_STRING; } else { - utf8_str = MALLOC(utf8_nbytes + 1); - if (!utf8_str) { - ret = WIMLIB_ERR_NOMEM; - } else { - wcstombs(utf8_str, (const wchar_t*)utf16_str, utf8_nbytes + 1); - *utf8_str_ret = utf8_str; - *utf8_nbytes_ret = utf8_nbytes; - ret = 0; - } + ret = 0; } -#else - ret = iconv_global_init(); - if (ret != 0) + mbs[SIZE_MAX - inbytesleft] = '\0'; + put_iconv(cd); + return ret; +} + +int +mbs_to_utf16le(const mbchar *mbs, size_t mbs_nbytes, + utf16lechar **utf16le_ret, size_t *utf16le_nbytes_ret) +{ + int ret; + utf16lechar *utf16le_str; + size_t utf16le_nbytes; + + ret = mbs_to_utf16le_nbytes(mbs, mbs_nbytes, + &utf16le_nbytes); + if (ret) return ret; - ret = utf16_to_utf8_size((const u16*)utf16_str, utf16_nbytes / 2); - if (ret >= 0) { - size_t utf8_expected_nbytes; - char *utf8_str; - size_t utf8_bytes_left; - size_t utf16_bytes_left; - size_t num_chars_converted; - char *utf8_str_save; - const char *utf16_str_save; - - utf8_expected_nbytes = ret; - utf8_str = MALLOC(utf8_expected_nbytes + 1); - if (utf8_str) { - utf8_bytes_left = utf8_expected_nbytes; - utf16_bytes_left = utf16_nbytes; - utf8_str_save = utf8_str; - utf16_str_save = utf16_str; - num_chars_converted = iconv(cd_utf16_to_utf8, - (char**)&utf16_str, - &utf16_bytes_left, - &utf8_str, - &utf8_bytes_left); - utf8_str = utf8_str_save; - utf16_str = utf16_str_save; - if (utf16_bytes_left == 0 && - utf8_bytes_left == 0 && - num_chars_converted != (size_t)(-1)) - { - utf8_str[utf8_expected_nbytes] = '\0'; - *utf8_str_ret = utf8_str; - *utf8_nbytes_ret = utf8_expected_nbytes; - ret = 0; - } else { - FREE(utf8_str); - ret = WIMLIB_ERR_INVALID_UTF16_STRING; - } - } else - ret = WIMLIB_ERR_NOMEM; - } else - ret = WIMLIB_ERR_INVALID_UTF16_STRING; -#endif /* WITH_NTFS_3G */ - -#ifdef ENABLE_ERROR_MESSAGES - if (ret != 0) { - ERROR_WITH_ERRNO("Error converting UTF-16LE string to UTF-8"); - ERROR("The failing string was:"); - print_string(utf16_str, utf16_nbytes); - putchar('\n'); + utf16le_str = MALLOC(utf16le_nbytes + 1); + if (!utf16le_str) + return WIMLIB_ERR_NOMEM; + + ret = mbs_to_utf16le_buf(mbs, mbs_nbytes, utf16le_str); + if (ret) { + FREE(utf16le_str); + } else { + *utf16le_ret = utf16le_str; + *utf16le_nbytes_ret = utf16le_nbytes; } -#endif /* ENABLE_ERROR_MESSAGES */ return ret; } -/* Converts a string in the UTF-8 encoding to a newly allocated string in the - * UTF-16 encoding. - * - * If available, do so by calling a similar function from libntfs-3g. - * Otherwise, use iconv() along with the helper function utf8_to_utf16_size(). - */ -int utf8_to_utf16(const char *utf8_str, size_t utf8_nbytes, - char **utf16_str_ret, size_t *utf16_nbytes_ret) +int +utf16le_to_mbs(const utf16lechar *utf16le_str, size_t utf16le_nbytes, + mbchar **mbs_ret, size_t *mbs_nbytes_ret) { int ret; - if (utf8_nbytes == 0) { - *utf16_str_ret = NULL; - *utf16_nbytes_ret = 0; - return 0; - } -#ifdef WITH_NTFS_3G - char *outs = NULL; - int outs_nchars = ntfs_mbstoucs(utf8_str, (ntfschar**)&outs); - if (outs_nchars >= 0) { - *utf16_str_ret = outs; - *utf16_nbytes_ret = (size_t)outs_nchars * 2; - ret = 0; - } else { - if (errno == ENOMEM) - ret = WIMLIB_ERR_NOMEM; - else - ret = WIMLIB_ERR_INVALID_UTF8_STRING; - } -#elif defined(__WIN32__) + mbchar *mbs; + size_t mbs_nbytes; - char *utf16_str; - size_t utf16_nchars; - utf16_nchars = mbstowcs(NULL, utf8_str, 0); - if (utf16_nchars == (size_t)(-1)) { - ret = WIMLIB_ERR_INVALID_UTF8_STRING; - } else { - utf16_str = MALLOC((utf16_nchars + 1) * sizeof(wchar_t)); - if (!utf16_str) { - ret = WIMLIB_ERR_NOMEM; - } else { - mbstowcs((wchar_t*)utf16_str, utf8_str, - utf16_nchars + 1); - *utf16_str_ret = utf16_str; - *utf16_nbytes_ret = utf16_nchars * sizeof(wchar_t); - ret = 0; - } - } - -#else - ret = iconv_global_init(); - if (ret != 0) + ret = utf16le_to_mbs_nbytes(utf16le_str, utf16le_nbytes, + &mbs_nbytes); + if (ret) return ret; - ret = utf8_to_utf16_size(utf8_str); - if (ret >= 0) { - size_t utf16_expected_nbytes; - char *utf16_str; - size_t utf16_bytes_left; - size_t utf8_bytes_left; - size_t num_chars_converted; - const char *utf8_str_save; - char *utf16_str_save; - - utf16_expected_nbytes = (size_t)ret * 2; - utf16_str = MALLOC(utf16_expected_nbytes + 2); - if (utf16_str) { - utf16_bytes_left = utf16_expected_nbytes; - utf8_bytes_left = utf8_nbytes; - utf8_str_save = utf8_str; - utf16_str_save = utf16_str; - num_chars_converted = iconv(cd_utf8_to_utf16, - (char**)&utf8_str, - &utf8_bytes_left, - &utf16_str, - &utf16_bytes_left); - utf8_str = utf8_str_save; - utf16_str = utf16_str_save; - if (utf16_bytes_left == 0 && - utf8_bytes_left == 0 && - num_chars_converted != (size_t)(-1)) - { - utf16_str[utf16_expected_nbytes] = '\0'; - utf16_str[utf16_expected_nbytes + 1] = '\0'; - *utf16_str_ret = utf16_str; - *utf16_nbytes_ret = utf16_expected_nbytes; - ret = 0; - } else { - FREE(utf16_str); - ret = WIMLIB_ERR_INVALID_UTF8_STRING; - } - } else - ret = WIMLIB_ERR_NOMEM; - } else - ret = WIMLIB_ERR_INVALID_UTF8_STRING; -#endif /* WITH_NTFS_3G */ - -#ifdef ENABLE_ERROR_MESSAGES - if (ret != 0) { - ERROR_WITH_ERRNO("Error converting UTF-8 string to UTF-16LE"); - ERROR("The failing string was:"); - print_string(utf8_str, utf8_nbytes); - putchar('\n'); - ERROR("Length: %zu bytes", utf8_nbytes); + + mbs = MALLOC(mbs_nbytes + 1); + if (!mbs) + return WIMLIB_ERR_NOMEM; + + ret = utf16le_to_mbs_buf(utf16le_str, utf16le_nbytes, mbs); + if (ret) { + FREE(mbs); + } else { + *mbs_ret = mbs; + *mbs_nbytes_ret = mbs_nbytes; } -#endif /* ENABLE_ERROR_MESSAGES */ return ret; } + +bool +utf8_str_contains_nonascii_chars(const utf8char *utf8_str) +{ + do { + if ((unsigned char)*utf8_str > 127) + return false; + } while (*++utf8_str); + return true; +} diff --git a/src/extract_image.c b/src/extract_image.c index 19b87d4d..199d20b2 100644 --- a/src/extract_image.c +++ b/src/extract_image.c @@ -58,10 +58,11 @@ #endif #ifndef __WIN32__ -static int extract_regular_file_linked(struct wim_dentry *dentry, - const char *output_path, - struct apply_args *args, - struct wim_lookup_table_entry *lte) +static int +extract_regular_file_linked(struct wim_dentry *dentry, + const mbchar *output_path, + struct apply_args *args, + struct wim_lookup_table_entry *lte) { /* This mode overrides the normal hard-link extraction and * instead either symlinks or hardlinks *all* identical files in @@ -79,12 +80,12 @@ static int extract_regular_file_linked(struct wim_dentry *dentry, int num_path_components; int num_output_dir_path_components; size_t extracted_file_len; - char *p; - const char *p2; + mbchar *p; + const mbchar *p2; size_t i; num_path_components = - get_num_path_components(dentry->full_path_utf8) - 1; + get_num_path_components(dentry->full_path) - 1; num_output_dir_path_components = get_num_path_components(args->target); @@ -94,7 +95,7 @@ static int extract_regular_file_linked(struct wim_dentry *dentry, } extracted_file_len = strlen(lte->extracted_file); - char buf[extracted_file_len + 3 * num_path_components + 1]; + mbchar buf[extracted_file_len + 3 * num_path_components + 1]; p = &buf[0]; for (i = 0; i < num_path_components; i++) { @@ -109,8 +110,7 @@ static int extract_regular_file_linked(struct wim_dentry *dentry, p2 = path_next_part(p2, NULL); strcpy(p, p2); if (symlink(buf, output_path) != 0) { - ERROR_WITH_ERRNO("Failed to symlink `%s' to " - "`%s'", + ERROR_WITH_ERRNO("Failed to symlink `%s' to `%s'", buf, lte->extracted_file); return WIMLIB_ERR_LINK; } @@ -118,8 +118,9 @@ static int extract_regular_file_linked(struct wim_dentry *dentry, return 0; } -static int symlink_apply_unix_data(const char *link, - const struct wimlib_unix_data *unix_data) +static int +symlink_apply_unix_data(const mbchar *link, + const struct wimlib_unix_data *unix_data) { if (lchown(link, unix_data->uid, unix_data->gid)) { if (errno == EPERM) { @@ -133,7 +134,8 @@ static int symlink_apply_unix_data(const char *link, return 0; } -static int fd_apply_unix_data(int fd, const struct wimlib_unix_data *unix_data) +static int +fd_apply_unix_data(int fd, const struct wimlib_unix_data *unix_data) { if (fchown(fd, unix_data->uid, unix_data->gid)) { if (errno == EPERM) { @@ -157,8 +159,8 @@ static int fd_apply_unix_data(int fd, const struct wimlib_unix_data *unix_data) return 0; } -static int dir_apply_unix_data(const char *dir, - const struct wimlib_unix_data *unix_data) +static int +dir_apply_unix_data(const mbchar *dir, const struct wimlib_unix_data *unix_data) { int dfd = open(dir, O_RDONLY); int ret; @@ -175,10 +177,11 @@ static int dir_apply_unix_data(const char *dir, return ret; } -static int extract_regular_file_unlinked(struct wim_dentry *dentry, - struct apply_args *args, - const char *output_path, - struct wim_lookup_table_entry *lte) +static int +extract_regular_file_unlinked(struct wim_dentry *dentry, + struct apply_args *args, + const mbchar *output_path, + struct wim_lookup_table_entry *lte) { /* Normal mode of extraction. Regular files and hard links are * extracted in the way that they appear in the WIM. */ @@ -265,9 +268,10 @@ out: return ret; } -static int extract_regular_file(struct wim_dentry *dentry, - struct apply_args *args, - const char *output_path) +static int +extract_regular_file(struct wim_dentry *dentry, + struct apply_args *args, + const mbchar *output_path) { struct wim_lookup_table_entry *lte; const struct wim_inode *inode = dentry->d_inode; @@ -288,18 +292,19 @@ static int extract_regular_file(struct wim_dentry *dentry, return extract_regular_file_unlinked(dentry, args, output_path, lte); } -static int extract_symlink(struct wim_dentry *dentry, - struct apply_args *args, - const char *output_path) +static int +extract_symlink(struct wim_dentry *dentry, + struct apply_args *args, + const mbchar *output_path) { - char target[4096]; + mbchar target[4096]; ssize_t ret = inode_readlink(dentry->d_inode, target, sizeof(target), args->w, 0); struct wim_lookup_table_entry *lte; if (ret <= 0) { ERROR("Could not read the symbolic link from dentry `%s'", - dentry->full_path_utf8); + dentry->full_path); return WIMLIB_ERR_INVALID_DENTRY; } ret = symlink(target, output_path); @@ -328,8 +333,9 @@ static int extract_symlink(struct wim_dentry *dentry, #endif /* !__WIN32__ */ -static int extract_directory(struct wim_dentry *dentry, - const char *output_path, bool is_root) +static int +extract_directory(struct wim_dentry *dentry, + const mbchar *output_path, bool is_root) { int ret; struct stat stbuf; @@ -350,10 +356,10 @@ static int extract_directory(struct wim_dentry *dentry, return WIMLIB_ERR_STAT; } } - if (mkdir(output_path, S_IRWXU | S_IRGRP | S_IXGRP | - S_IROTH | S_IXOTH) != 0) { - ERROR_WITH_ERRNO("Cannot create directory `%s'", - output_path); + + if (mkdir(output_path, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) + { + ERROR_WITH_ERRNO("Cannot create directory `%s'", output_path); return WIMLIB_ERR_MKDIR; } dir_exists: @@ -374,7 +380,7 @@ dir_exists: } #ifndef __WIN32__ -static int unix_do_apply_dentry(const char *output_path, +static int unix_do_apply_dentry(const mbchar *output_path, size_t output_path_len, struct wim_dentry *dentry, struct apply_args *args) @@ -391,10 +397,11 @@ static int unix_do_apply_dentry(const char *output_path, return extract_regular_file(dentry, args, output_path); } -static int unix_do_apply_dentry_timestamps(const char *output_path, - size_t output_path_len, - const struct wim_dentry *dentry, - struct apply_args *args) +static int +unix_do_apply_dentry_timestamps(const mbchar *output_path, + size_t output_path_len, + const struct wim_dentry *dentry, + struct apply_args *args) { int ret; const struct wim_inode *inode = dentry->d_inode; @@ -452,21 +459,22 @@ static int unix_do_apply_dentry_timestamps(const char *output_path, #endif /* !__WIN32__ */ /* Extracts a file, directory, or symbolic link from the WIM archive. */ -static int apply_dentry_normal(struct wim_dentry *dentry, void *arg) +static int +apply_dentry_normal(struct wim_dentry *dentry, void *arg) { struct apply_args *args = arg; size_t len; - char *output_path; + mbchar *output_path; len = strlen(args->target); if (dentry_is_root(dentry)) { - output_path = (char*)args->target; + output_path = (mbchar*)args->target; } else { - output_path = alloca(len + dentry->full_path_utf8_len + 1); + output_path = alloca(len + dentry->full_path_nbytes + 1); memcpy(output_path, args->target, len); - memcpy(output_path + len, dentry->full_path_utf8, dentry->full_path_utf8_len); - output_path[len + dentry->full_path_utf8_len] = '\0'; - len += dentry->full_path_utf8_len; + memcpy(output_path + len, dentry->full_path, dentry->full_path_nbytes); + output_path[len + dentry->full_path_nbytes] = '\0'; + len += dentry->full_path_nbytes; } #ifdef __WIN32__ return win32_do_apply_dentry(output_path, len, dentry, args); @@ -477,22 +485,24 @@ static int apply_dentry_normal(struct wim_dentry *dentry, void *arg) /* Apply timestamps to an extracted file or directory */ -static int apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg) +static int +apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg) { struct apply_args *args = arg; size_t len; - char *output_path; + mbchar *output_path; len = strlen(args->target); if (dentry_is_root(dentry)) { - output_path = (char*)args->target; + output_path = (mbchar*)args->target; } else { - output_path = alloca(len + dentry->full_path_utf8_len + 1); + output_path = alloca(len + dentry->full_path_nbytes + 1); memcpy(output_path, args->target, len); - memcpy(output_path + len, dentry->full_path_utf8, dentry->full_path_utf8_len); - output_path[len + dentry->full_path_utf8_len] = '\0'; - len += dentry->full_path_utf8_len; + memcpy(output_path + len, dentry->full_path, dentry->full_path_nbytes); + output_path[len + dentry->full_path_nbytes] = '\0'; + len += dentry->full_path_nbytes; } + #ifdef __WIN32__ return win32_do_apply_dentry_timestamps(output_path, len, dentry, args); #else @@ -502,7 +512,8 @@ static int apply_dentry_timestamps_normal(struct wim_dentry *dentry, void *arg) /* Extract a dentry if it hasn't already been extracted, and either the dentry * has no streams or WIMLIB_EXTRACT_FLAG_NO_STREAMS is not specified. */ -static int maybe_apply_dentry(struct wim_dentry *dentry, void *arg) +static int +maybe_apply_dentry(struct wim_dentry *dentry, void *arg) { struct apply_args *args = arg; int ret; @@ -516,7 +527,7 @@ static int maybe_apply_dentry(struct wim_dentry *dentry, void *arg) if ((args->extract_flags & WIMLIB_EXTRACT_FLAG_VERBOSE) && args->progress_func) { - args->progress.extract.cur_path = dentry->full_path_utf8; + args->progress.extract.cur_path = dentry->full_path; args->progress_func(WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY, &args->progress); } @@ -526,7 +537,8 @@ static int maybe_apply_dentry(struct wim_dentry *dentry, void *arg) return ret; } -static int cmp_streams_by_wim_position(const void *p1, const void *p2) +static int +cmp_streams_by_wim_position(const void *p1, const void *p2) { const struct wim_lookup_table_entry *lte1, *lte2; lte1 = *(const struct wim_lookup_table_entry**)p1; @@ -539,7 +551,8 @@ static int cmp_streams_by_wim_position(const void *p1, const void *p2) return 0; } -static int sort_stream_list_by_wim_position(struct list_head *stream_list) +static int +sort_stream_list_by_wim_position(struct list_head *stream_list) { struct list_head *cur; size_t num_streams; @@ -572,9 +585,10 @@ static int sort_stream_list_by_wim_position(struct list_head *stream_list) return 0; } -static void calculate_bytes_to_extract(struct list_head *stream_list, - int extract_flags, - union wimlib_progress_info *progress) +static void +calculate_bytes_to_extract(struct list_head *stream_list, + int extract_flags, + union wimlib_progress_info *progress) { struct wim_lookup_table_entry *lte; u64 total_bytes = 0; @@ -603,8 +617,9 @@ static void calculate_bytes_to_extract(struct list_head *stream_list, progress->extract.completed_bytes = 0; } -static void maybe_add_stream_for_extraction(struct wim_lookup_table_entry *lte, - struct list_head *stream_list) +static void +maybe_add_stream_for_extraction(struct wim_lookup_table_entry *lte, + struct list_head *stream_list) { if (++lte->out_refcnt == 1) { INIT_LIST_HEAD(<e->inode_list); @@ -612,9 +627,10 @@ static void maybe_add_stream_for_extraction(struct wim_lookup_table_entry *lte, } } -static void inode_find_streams_for_extraction(struct wim_inode *inode, - struct list_head *stream_list, - int extract_flags) +static void +inode_find_streams_for_extraction(struct wim_inode *inode, + struct list_head *stream_list, + int extract_flags) { struct wim_lookup_table_entry *lte; bool inode_added = false; @@ -628,7 +644,7 @@ static void inode_find_streams_for_extraction(struct wim_inode *inode, #ifdef WITH_NTFS_3G if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) { for (unsigned i = 0; i < inode->i_num_ads; i++) { - if (inode->i_ads_entries[i].stream_name_len != 0) { + if (inode->i_ads_entries[i].stream_name_nbytes != 0) { lte = inode->i_ads_entries[i].lte; if (lte) { maybe_add_stream_for_extraction(lte, @@ -645,10 +661,11 @@ static void inode_find_streams_for_extraction(struct wim_inode *inode, #endif } -static void find_streams_for_extraction(struct hlist_head *inode_list, - struct list_head *stream_list, - struct wim_lookup_table *lookup_table, - int extract_flags) +static void +find_streams_for_extraction(struct hlist_head *inode_list, + struct list_head *stream_list, + struct wim_lookup_table *lookup_table, + int extract_flags) { struct wim_inode *inode; struct hlist_node *cur; @@ -683,10 +700,11 @@ static const struct apply_operations ntfs_apply_operations = { }; #endif -static int apply_stream_list(struct list_head *stream_list, - struct apply_args *args, - const struct apply_operations *ops, - wimlib_progress_func_t progress_func) +static int +apply_stream_list(struct list_head *stream_list, + struct apply_args *args, + const struct apply_operations *ops, + wimlib_progress_func_t progress_func) { uint64_t bytes_per_progress = args->progress.extract.total_bytes / 100; uint64_t next_progress = bytes_per_progress; @@ -738,9 +756,10 @@ static int apply_stream_list(struct list_head *stream_list, /* Extracts the image @image from the WIM @w to the directory or NTFS volume * @target. */ -static int extract_single_image(WIMStruct *w, int image, - const char *target, int extract_flags, - wimlib_progress_func_t progress_func) +static int +extract_single_image(WIMStruct *w, int image, + const mbchar *target, int extract_flags, + wimlib_progress_func_t progress_func) { int ret; struct list_head stream_list; @@ -862,16 +881,17 @@ out: /* Extracts all images from the WIM to the directory @target, with the images * placed in subdirectories named by their image names. */ -static int extract_all_images(WIMStruct *w, const char *target, - int extract_flags, - wimlib_progress_func_t progress_func) +static int +extract_all_images(WIMStruct *w, const mbchar *target, + int extract_flags, + wimlib_progress_func_t progress_func) { size_t image_name_max_len = max(xml_get_max_image_name_len(w), 20); size_t output_path_len = strlen(target); - char buf[output_path_len + 1 + image_name_max_len + 1]; + mbchar buf[output_path_len + 1 + image_name_max_len + 1]; int ret; int image; - const char *image_name; + const utf8char *image_name; ret = extract_directory(NULL, target, true); if (ret != 0) @@ -881,10 +901,15 @@ static int extract_all_images(WIMStruct *w, const char *target, buf[output_path_len] = '/'; for (image = 1; image <= w->hdr.image_count; image++) { image_name = wimlib_get_image_name(w, image); - if (image_name && *image_name) { + if (image_name && *image_name && + (wimlib_mbs_is_utf8 || !utf8_str_contains_nonascii_chars(image_name)) + && strchr(image_name, '/') == NULL) + { strcpy(buf + output_path_len + 1, image_name); } else { - /* Image name is empty. Use image number instead */ + /* Image name is empty, or may not be representable in + * the current locale, or contains path separators. Use + * the image number instead. */ sprintf(buf + output_path_len + 1, "%d", image); } ret = extract_single_image(w, image, buf, extract_flags, diff --git a/src/hardlink.c b/src/hardlink.c index 45217fdf..da91ac43 100644 --- a/src/hardlink.c +++ b/src/hardlink.c @@ -72,12 +72,8 @@ struct wim_inode_table { struct hlist_head extra_inodes; }; -static inline void destroy_inode_table(struct wim_inode_table *table) -{ - FREE(table->array); -} - -static int init_inode_table(struct wim_inode_table *table, size_t capacity) +static int +init_inode_table(struct wim_inode_table *table, size_t capacity) { table->array = CALLOC(capacity, sizeof(table->array[0])); if (!table->array) { @@ -90,7 +86,14 @@ static int init_inode_table(struct wim_inode_table *table, size_t capacity) return 0; } -static inline size_t inode_link_count(const struct wim_inode *inode) +static inline void +destroy_inode_table(struct wim_inode_table *table) +{ + FREE(table->array); +} + +static inline size_t +inode_link_count(const struct wim_inode *inode) { const struct list_head *cur; size_t size = 0; @@ -102,9 +105,10 @@ static inline size_t inode_link_count(const struct wim_inode *inode) /* Insert a dentry into the inode table based on the inode number of the * attached inode (which came from the hard link group ID field of the on-disk * WIM dentry) */ -static int inode_table_insert(struct wim_dentry *dentry, void *__table) +static int +inode_table_insert(struct wim_dentry *dentry, void *_table) { - struct wim_inode_table *table = __table; + struct wim_inode_table *table = _table; struct wim_inode *d_inode = dentry->d_inode; if (d_inode->i_ino == 0) { @@ -146,25 +150,30 @@ static int inode_table_insert(struct wim_dentry *dentry, void *__table) return 0; } -static void print_inode_dentries(const struct wim_inode *inode) +#ifdef ENABLE_ERROR_MESSAGES +static void +print_inode_dentries(const struct wim_inode *inode) { struct wim_dentry *dentry; inode_for_each_dentry(dentry, inode) - printf("`%s'\n", dentry->full_path_utf8); + printf("`%s'\n", dentry->full_path); } +#endif -static void inconsistent_inode(const struct wim_inode *inode) +static void +inconsistent_inode(const struct wim_inode *inode) { +#ifdef ENABLE_ERROR_MESSAGES ERROR("An inconsistent hard link group that cannot be corrected has " "been detected"); ERROR("The dentries are located at the following paths:"); -#ifdef ENABLE_ERROR_MESSAGES print_inode_dentries(inode); #endif } -static bool ref_inodes_consistent(const struct wim_inode * restrict ref_inode_1, - const struct wim_inode * restrict ref_inode_2) +static bool +ref_inodes_consistent(const struct wim_inode * restrict ref_inode_1, + const struct wim_inode * restrict ref_inode_2) { wimlib_assert(ref_inode_1 != ref_inode_2); @@ -187,8 +196,9 @@ static bool ref_inodes_consistent(const struct wim_inode * restrict ref_inode_1, return true; } -static bool inodes_consistent(const struct wim_inode * restrict ref_inode, - const struct wim_inode * restrict inode) +static bool +inodes_consistent(const struct wim_inode * restrict ref_inode, + const struct wim_inode * restrict inode) { wimlib_assert(ref_inode != inode); @@ -212,7 +222,8 @@ static bool inodes_consistent(const struct wim_inode * restrict ref_inode, } /* Fix up a "true" inode and check for inconsistencies */ -static int fix_true_inode(struct wim_inode *inode, struct hlist_head *inode_list) +static int +fix_true_inode(struct wim_inode *inode, struct hlist_head *inode_list) { struct wim_dentry *dentry; struct wim_dentry *ref_dentry = NULL; @@ -274,8 +285,8 @@ static int fix_true_inode(struct wim_inode *inode, struct hlist_head *inode_list * wim_inode's. There will be just one `struct wim_inode' for each hard link * group remaining. */ -static int fix_nominal_inode(struct wim_inode *inode, - struct hlist_head *inode_list) +static int +fix_nominal_inode(struct wim_inode *inode, struct hlist_head *inode_list) { struct wim_dentry *dentry; struct hlist_node *cur, *tmp; @@ -393,8 +404,8 @@ next_dentry_2: return 0; } -static int fix_inodes(struct wim_inode_table *table, - struct hlist_head *inode_list) +static int +fix_inodes(struct wim_inode_table *table, struct hlist_head *inode_list) { struct wim_inode *inode; struct hlist_node *cur, *tmp; @@ -440,7 +451,8 @@ static int fix_inodes(struct wim_inode_table *table, * failure. On success, the list of "true" inodes, linked by the i_hlist field, * is returned in the hlist @inode_list. */ -int dentry_tree_fix_inodes(struct wim_dentry *root, struct hlist_head *inode_list) +int +dentry_tree_fix_inodes(struct wim_dentry *root, struct hlist_head *inode_list) { struct wim_inode_table inode_tab; int ret; @@ -460,7 +472,8 @@ int dentry_tree_fix_inodes(struct wim_dentry *root, struct hlist_head *inode_lis /* Assign inode numbers to a list of inodes and return the next available * number. */ -u64 assign_inode_numbers(struct hlist_head *inode_list) +u64 +assign_inode_numbers(struct hlist_head *inode_list) { DEBUG("Assigning inode numbers"); struct wim_inode *inode; diff --git a/src/lookup_table.c b/src/lookup_table.c index ab13e5e1..d9301c2c 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -572,18 +572,20 @@ __lookup_resource(const struct wim_lookup_table *table, const u8 hash[]) * * This is only for pre-resolved inodes. */ -int lookup_resource(WIMStruct *w, const char *path, - int lookup_flags, - struct wim_dentry **dentry_ret, - struct wim_lookup_table_entry **lte_ret, - u16 *stream_idx_ret) +int +lookup_resource(WIMStruct *w, + const mbchar *path, + int lookup_flags, + struct wim_dentry **dentry_ret, + struct wim_lookup_table_entry **lte_ret, + u16 *stream_idx_ret) { struct wim_dentry *dentry; struct wim_lookup_table_entry *lte; u16 stream_idx; - const char *stream_name = NULL; + const mbchar *stream_name = NULL; struct wim_inode *inode; - char *p = NULL; + mbchar *p = NULL; if (lookup_flags & LOOKUP_FLAG_ADS_OK) { stream_name = path_stream_name(path); diff --git a/src/lookup_table.h b/src/lookup_table.h index ca418219..699e16ec 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -32,8 +32,8 @@ struct wim_lookup_table { #ifdef WITH_NTFS_3G struct ntfs_location { - char *path_utf8; - char *stream_name_utf16; + utf8char *path_utf8; + utf16lechar *stream_name_utf16; u16 stream_name_utf16_num_chars; struct _ntfs_volume **ntfs_vol_p; bool is_reparse_point; @@ -150,15 +150,15 @@ struct wim_lookup_table_entry { * extraction mode. In these mode, all identical files are linked * together, and @extracted_file will be set to the filename of the * first extracted file containing this stream. */ - char *extracted_file; + mbchar *extracted_file; }; /* Pointers to somewhere where the stream is actually located. See the * comments for the @resource_location field above. */ union { WIMStruct *wim; - char *file_on_disk; - char *staging_file_name; + mbchar *file_on_disk; + mbchar *staging_file_name; u8 *attached_buffer; #ifdef WITH_NTFS_3G struct ntfs_location *ntfs_loc; @@ -290,7 +290,7 @@ extern struct wim_lookup_table_entry * __lookup_resource(const struct wim_lookup_table *table, const u8 hash[]); extern int -lookup_resource(WIMStruct *w, const char *path, +lookup_resource(WIMStruct *w, const mbchar *path, int lookup_flags, struct wim_dentry **dentry_ret, struct wim_lookup_table_entry **lte_ret, u16 *stream_idx_ret); @@ -398,13 +398,13 @@ inode_stream_hash(const struct wim_inode *inode, unsigned stream_idx) } static inline u16 -inode_stream_name_len(const struct wim_inode *inode, unsigned stream_idx) +inode_stream_name_nbytes(const struct wim_inode *inode, unsigned stream_idx) { wimlib_assert(stream_idx <= inode->i_num_ads); if (stream_idx == 0) return 0; else - return inode->i_ads_entries[stream_idx - 1].stream_name_len; + return inode->i_ads_entries[stream_idx - 1].stream_name_nbytes; } static inline struct wim_lookup_table_entry * @@ -412,7 +412,7 @@ inode_unnamed_lte_resolved(const struct wim_inode *inode) { wimlib_assert(inode->i_resolved); for (unsigned i = 0; i <= inode->i_num_ads; i++) { - if (inode_stream_name_len(inode, i) == 0 && + if (inode_stream_name_nbytes(inode, i) == 0 && !is_zero_hash(inode_stream_hash_resolved(inode, i))) { return inode_stream_lte_resolved(inode, i); @@ -427,7 +427,7 @@ inode_unnamed_lte_unresolved(const struct wim_inode *inode, { wimlib_assert(!inode->i_resolved); for (unsigned i = 0; i <= inode->i_num_ads; i++) { - if (inode_stream_name_len(inode, i) == 0 && + if (inode_stream_name_nbytes(inode, i) == 0 && !is_zero_hash(inode_stream_hash_unresolved(inode, i))) { return inode_stream_lte_unresolved(inode, i, table); diff --git a/src/mount_image.c b/src/mount_image.c index d9688765..2f09ce7c 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -78,7 +78,7 @@ struct wimfs_context { * file in the WIM is modified, it is extracted to the staging directory. If * changes are commited when the WIM is unmounted, the file resources are merged * in from the staging directory when writing the new WIM. */ - char *staging_dir_name; + mbchar *staging_dir_name; size_t staging_dir_name_len; /* Flags passed to wimlib_mount(). */ @@ -106,8 +106,8 @@ struct wimfs_context { * wimlib_unmount_image() (i.e. the `imagex unmount' command) needs to * communicate with the filesystem daemon running fuse_main() (i.e. the * daemon created by the `imagex mount' or `imagex mountrw' commands */ - char *unmount_to_daemon_mq_name; - char *daemon_to_unmount_mq_name; + mbchar *unmount_to_daemon_mq_name; + mbchar *daemon_to_unmount_mq_name; mqd_t unmount_to_daemon_mq; mqd_t daemon_to_unmount_mq; @@ -118,7 +118,8 @@ struct wimfs_context { bool have_status; }; -static void init_wimfs_context(struct wimfs_context *ctx) +static void +init_wimfs_context(struct wimfs_context *ctx) { memset(ctx, 0, sizeof(*ctx)); ctx->unmount_to_daemon_mq = (mqd_t)-1; @@ -128,28 +129,33 @@ static void init_wimfs_context(struct wimfs_context *ctx) #define WIMFS_CTX(fuse_ctx) ((struct wimfs_context*)(fuse_ctx)->private_data) -static inline struct wimfs_context *wimfs_get_context() +static inline struct wimfs_context * +wimfs_get_context() { return WIMFS_CTX(fuse_get_context()); } -static inline WIMStruct *wimfs_get_WIMStruct() +static inline WIMStruct * +wimfs_get_WIMStruct() { return wimfs_get_context()->wim; } -static inline bool wimfs_ctx_readonly(const struct wimfs_context *ctx) +static inline bool +wimfs_ctx_readonly(const struct wimfs_context *ctx) { return (ctx->mount_flags & WIMLIB_MOUNT_FLAG_READWRITE) == 0; } -static inline int get_lookup_flags(const struct wimfs_context *ctx) +static inline int +get_lookup_flags(const struct wimfs_context *ctx) { return ctx->default_lookup_flags; } /* Returns nonzero if write permission is requested on the file open flags */ -static inline int flags_writable(int open_flags) +static inline int +flags_writable(int open_flags) { return open_flags & (O_RDWR | O_WRONLY); } @@ -165,11 +171,12 @@ static inline int flags_writable(int open_flags) * * Return 0 iff successful or error code if unsuccessful. */ -static int alloc_wimfs_fd(struct wim_inode *inode, - u32 stream_id, - struct wim_lookup_table_entry *lte, - struct wimfs_fd **fd_ret, - bool readonly) +static int +alloc_wimfs_fd(struct wim_inode *inode, + u32 stream_id, + struct wim_lookup_table_entry *lte, + struct wimfs_fd **fd_ret, + bool readonly) { static const u16 fds_per_alloc = 8; static const u16 max_fds = 0xffff; @@ -232,7 +239,8 @@ out: return ret; } -static void inode_put_fd(struct wim_inode *inode, struct wimfs_fd *fd) +static void +inode_put_fd(struct wim_inode *inode, struct wimfs_fd *fd) { wimlib_assert(inode != NULL); @@ -253,7 +261,8 @@ static void inode_put_fd(struct wim_inode *inode, struct wimfs_fd *fd) } } -static int lte_put_fd(struct wim_lookup_table_entry *lte, struct wimfs_fd *fd) +static int +lte_put_fd(struct wim_lookup_table_entry *lte, struct wimfs_fd *fd) { wimlib_assert(fd->f_lte == lte); @@ -275,7 +284,8 @@ static int lte_put_fd(struct wim_lookup_table_entry *lte, struct wimfs_fd *fd) } /* Close a file descriptor. */ -static int close_wimfs_fd(struct wimfs_fd *fd) +static int +close_wimfs_fd(struct wimfs_fd *fd) { int ret; DEBUG("Closing fd (ino = %#"PRIx64", opened = %u, allocated = %u)", @@ -294,13 +304,13 @@ static int close_wimfs_fd(struct wimfs_fd *fd) * * Returns 0 on success, or negative error number on failure. */ -static int create_dentry(struct fuse_context *fuse_ctx,const char *path, - mode_t mode, int attributes, - struct wim_dentry **dentry_ret) +static int +create_dentry(struct fuse_context *fuse_ctx, const mbchar *path, + mode_t mode, int attributes, struct wim_dentry **dentry_ret) { struct wim_dentry *parent; struct wim_dentry *new; - const char *basename; + const mbchar *basename; struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx); parent = get_parent_dentry(wimfs_ctx->wim, path); @@ -353,8 +363,9 @@ static int create_dentry(struct fuse_context *fuse_ctx,const char *path, * descriptors and no references remaining, it is freed, and the corresponding * staging file is unlinked. */ -static void remove_dentry(struct wim_dentry *dentry, - struct wim_lookup_table *lookup_table) +static void +remove_dentry(struct wim_dentry *dentry, + struct wim_lookup_table *lookup_table) { struct wim_inode *inode = dentry->d_inode; struct wim_lookup_table_entry *lte; @@ -369,7 +380,8 @@ static void remove_dentry(struct wim_dentry *dentry, put_dentry(dentry); } -static mode_t inode_default_unix_mode(const struct wim_inode *inode) +static mode_t +inode_default_unix_mode(const struct wim_inode *inode) { if (inode_is_symlink(inode)) return S_IFLNK | 0777; @@ -384,9 +396,10 @@ static mode_t inode_default_unix_mode(const struct wim_inode *inode) * The lookup table entry tells us which stream in the inode we are statting. * For a named data stream, everything returned is the same as the unnamed data * stream except possibly the size and block count. */ -static int inode_to_stbuf(const struct wim_inode *inode, - const struct wim_lookup_table_entry *lte, - struct stat *stbuf) +static int +inode_to_stbuf(const struct wim_inode *inode, + const struct wim_lookup_table_entry *lte, + struct stat *stbuf) { const struct wimfs_context *ctx = wimfs_get_context(); @@ -433,7 +446,8 @@ static int inode_to_stbuf(const struct wim_inode *inode, return 0; } -static void touch_inode(struct wim_inode *inode) +static void +touch_inode(struct wim_inode *inode) { u64 now = get_wim_timestamp(); inode->i_last_access_time = now; @@ -452,10 +466,11 @@ static void touch_inode(struct wim_inode *inode) * On success, returns the file descriptor for the staging file, opened for * writing. On failure, returns -1 and sets errno. */ -static int create_staging_file(char **name_ret, struct wimfs_context *ctx) +static int +create_staging_file(mbchar **name_ret, struct wimfs_context *ctx) { size_t name_len; - char *name; + mbchar *name; struct stat stbuf; int fd; int errno_save; @@ -519,11 +534,12 @@ static int create_staging_file(char **name_ret, struct wimfs_context *ctx) * * Returns 0 on success or a negative error code on failure. */ -static int extract_resource_to_staging_dir(struct wim_inode *inode, - u32 stream_id, - struct wim_lookup_table_entry **lte, - off_t size, - struct wimfs_context *ctx) +static int +extract_resource_to_staging_dir(struct wim_inode *inode, + u32 stream_id, + struct wim_lookup_table_entry **lte, + off_t size, + struct wimfs_context *ctx) { char *staging_file_name; int ret; @@ -677,17 +693,18 @@ out_delete_staging_file: * Creates a randomly named staging directory and saves its name in the * filesystem context structure. */ -static int make_staging_dir(struct wimfs_context *ctx, const char *user_prefix) +static int +make_staging_dir(struct wimfs_context *ctx, const mbchar *user_prefix) { static const size_t random_suffix_len = 10; - static const char *common_suffix = ".staging"; + static const mbchar *common_suffix = ".staging"; static const size_t common_suffix_len = 8; - char *staging_dir_name = NULL; + mbchar *staging_dir_name = NULL; size_t staging_dir_name_len; size_t prefix_len; - const char *wim_basename; - char *real_user_prefix = NULL; + const mbchar *wim_basename; + mbchar *real_user_prefix = NULL; int ret; if (user_prefix) { @@ -742,8 +759,9 @@ out: return ret; } -static int remove_file_or_directory(const char *fpath, const struct stat *sb, - int typeflag, struct FTW *ftwbuf) +static int +remove_file_or_directory(const mbchar *fpath, const struct stat *sb, + int typeflag, struct FTW *ftwbuf) { if (remove(fpath) == 0) return 0; @@ -756,7 +774,8 @@ static int remove_file_or_directory(const char *fpath, const struct stat *sb, /* * Deletes the staging directory and all the files contained in it. */ -static int delete_staging_dir(struct wimfs_context *ctx) +static int +delete_staging_dir(struct wimfs_context *ctx) { int ret; ret = nftw(ctx->staging_dir_name, remove_file_or_directory, @@ -766,9 +785,10 @@ static int delete_staging_dir(struct wimfs_context *ctx) return ret; } -static void inode_update_lte_ptr(struct wim_inode *inode, - struct wim_lookup_table_entry *old_lte, - struct wim_lookup_table_entry *new_lte) +static void +inode_update_lte_ptr(struct wim_inode *inode, + struct wim_lookup_table_entry *old_lte, + struct wim_lookup_table_entry *new_lte) { if (inode->i_lte == old_lte) { inode->i_lte = new_lte; @@ -782,8 +802,9 @@ static void inode_update_lte_ptr(struct wim_inode *inode, } } -static int update_lte_of_staging_file(struct wim_lookup_table_entry *lte, - struct wim_lookup_table *table) +static int +update_lte_of_staging_file(struct wim_lookup_table_entry *lte, + struct wim_lookup_table *table) { struct wim_lookup_table_entry *duplicate_lte; int ret; @@ -822,7 +843,8 @@ static int update_lte_of_staging_file(struct wim_lookup_table_entry *lte, return 0; } -static int inode_close_fds(struct wim_inode *inode) +static int +inode_close_fds(struct wim_inode *inode) { u16 num_opened_fds = inode->i_num_opened_fds; for (u16 i = 0, j = 0; j < num_opened_fds; i++) { @@ -839,8 +861,9 @@ static int inode_close_fds(struct wim_inode *inode) } /* Overwrites the WIM file, with changes saved. */ -static int rebuild_wim(struct wimfs_context *ctx, int write_flags, - wimlib_progress_func_t progress_func) +static int +rebuild_wim(struct wimfs_context *ctx, int write_flags, + wimlib_progress_func_t progress_func) { int ret; struct wim_lookup_table_entry *lte, *tmp; @@ -867,10 +890,9 @@ static int rebuild_wim(struct wimfs_context *ctx, int write_flags, return ret; } - - /* Simple function that returns the concatenation of 2 strings. */ -static char *strcat_dup(const char *s1, const char *s2, size_t max_len) +static char * +strcat_dup(const char *s1, const char *s2, size_t max_len) { size_t len = strlen(s1) + strlen(s2); if (len > max_len) @@ -882,13 +904,13 @@ static char *strcat_dup(const char *s1, const char *s2, size_t max_len) return p; } -static int set_message_queue_names(struct wimfs_context *ctx, - const char *mount_dir) +static int +set_message_queue_names(struct wimfs_context *ctx, const mbchar *mount_dir) { - static const char *u2d_prefix = "/wimlib-unmount-to-daemon-mq"; - static const char *d2u_prefix = "/wimlib-daemon-to-unmount-mq"; - char *dir_path; - char *p; + static const mbchar *u2d_prefix = "/wimlib-unmount-to-daemon-mq"; + static const mbchar *d2u_prefix = "/wimlib-daemon-to-unmount-mq"; + mbchar *dir_path; + mbchar *p; int ret; dir_path = realpath(mount_dir, NULL); @@ -927,7 +949,8 @@ out_free_dir_path: return ret; } -static void free_message_queue_names(struct wimfs_context *ctx) +static void +free_message_queue_names(struct wimfs_context *ctx) { FREE(ctx->unmount_to_daemon_mq_name); FREE(ctx->daemon_to_unmount_mq_name); @@ -944,7 +967,8 @@ static void free_message_queue_names(struct wimfs_context *ctx) * @daemon specifies whether the calling process is the filesystem daemon or the * unmount process. */ -static int open_message_queues(struct wimfs_context *ctx, bool daemon) +static int +open_message_queues(struct wimfs_context *ctx, bool daemon) { int unmount_to_daemon_mq_flags = O_WRONLY | O_CREAT; int daemon_to_unmount_mq_flags = O_RDONLY | O_CREAT; @@ -991,7 +1015,8 @@ out: /* Try to determine the maximum message size of a message queue. The return * value is the maximum message size, or a guess of 8192 bytes if it cannot be * determined. */ -static long mq_get_msgsize(mqd_t mq) +static long +mq_get_msgsize(mqd_t mq) { static const char *msgsize_max_file = "/proc/sys/fs/mqueue/msgsize_max"; FILE *fp; @@ -1020,8 +1045,9 @@ static long mq_get_msgsize(mqd_t mq) return msgsize; } -static int get_mailbox(mqd_t mq, long needed_msgsize, long *msgsize_ret, - void **mailbox_ret) +static int +get_mailbox(mqd_t mq, long needed_msgsize, long *msgsize_ret, + void **mailbox_ret) { long msgsize; char *mailbox; @@ -1044,14 +1070,16 @@ static int get_mailbox(mqd_t mq, long needed_msgsize, long *msgsize_ret, return 0; } -static void unlink_message_queues(struct wimfs_context *ctx) +static void +unlink_message_queues(struct wimfs_context *ctx) { mq_unlink(ctx->unmount_to_daemon_mq_name); mq_unlink(ctx->daemon_to_unmount_mq_name); } /* Closes the message queues, which are allocated in static variables */ -static void close_message_queues(struct wimfs_context *ctx) +static void +close_message_queues(struct wimfs_context *ctx) { DEBUG("Closing message queues"); mq_close(ctx->unmount_to_daemon_mq); @@ -1116,8 +1144,8 @@ struct daemon_msg_handler_context { struct wimfs_context *wimfs_ctx; }; -static int send_unmount_request_msg(mqd_t mq, int unmount_flags, - u8 want_progress_messages) +static int +send_unmount_request_msg(mqd_t mq, int unmount_flags, u8 want_progress_messages) { DEBUG("Sending unmount request msg"); struct msg_unmount_request msg = { @@ -1138,7 +1166,8 @@ static int send_unmount_request_msg(mqd_t mq, int unmount_flags, return 0; } -static int send_daemon_info_msg(mqd_t mq, pid_t pid, int mount_flags) +static int +send_daemon_info_msg(mqd_t mq, pid_t pid, int mount_flags) { DEBUG("Sending daemon info msg (pid = %d, mount_flags=%x)", pid, mount_flags); @@ -1160,7 +1189,8 @@ static int send_daemon_info_msg(mqd_t mq, pid_t pid, int mount_flags) return 0; } -static void send_unmount_finished_msg(mqd_t mq, int status) +static void +send_unmount_finished_msg(mqd_t mq, int status) { DEBUG("Sending unmount finished msg"); struct msg_unmount_finished msg = { @@ -1176,8 +1206,9 @@ static void send_unmount_finished_msg(mqd_t mq, int status) ERROR_WITH_ERRNO("Failed to send status to unmount process"); } -static int unmount_progress_func(enum wimlib_progress_msg msg, - const union wimlib_progress_info *info) +static int +unmount_progress_func(enum wimlib_progress_msg msg, + const union wimlib_progress_info *info) { if (msg == WIMLIB_PROGRESS_MSG_WRITE_STREAMS) { struct msg_write_streams_progress msg = { @@ -1199,7 +1230,8 @@ static int unmount_progress_func(enum wimlib_progress_msg msg, return 0; } -static int msg_unmount_request_handler(const void *_msg, void *_handler_ctx) +static int +msg_unmount_request_handler(const void *_msg, void *_handler_ctx) { const struct msg_unmount_request *msg = _msg; struct daemon_msg_handler_context *handler_ctx = _handler_ctx; @@ -1261,7 +1293,8 @@ out: return MSG_BREAK_LOOP; } -static int msg_daemon_info_handler(const void *_msg, void *_handler_ctx) +static int +msg_daemon_info_handler(const void *_msg, void *_handler_ctx) { const struct msg_daemon_info *msg = _msg; struct unmount_msg_handler_context *handler_ctx = _handler_ctx; @@ -1278,8 +1311,8 @@ static int msg_daemon_info_handler(const void *_msg, void *_handler_ctx) return 0; } -static int msg_write_streams_progress_handler(const void *_msg, - void *_handler_ctx) +static int +msg_write_streams_progress_handler(const void *_msg, void *_handler_ctx) { const struct msg_write_streams_progress *msg = _msg; struct unmount_msg_handler_context *handler_ctx = _handler_ctx; @@ -1293,7 +1326,8 @@ static int msg_write_streams_progress_handler(const void *_msg, return 0; } -static int msg_unmount_finished_handler(const void *_msg, void *_handler_ctx) +static int +msg_unmount_finished_handler(const void *_msg, void *_handler_ctx) { const struct msg_unmount_finished *msg = _msg; struct unmount_msg_handler_context *handler_ctx = _handler_ctx; @@ -1306,7 +1340,8 @@ static int msg_unmount_finished_handler(const void *_msg, void *_handler_ctx) return MSG_BREAK_LOOP; } -static int unmount_timed_out_cb(void *_handler_ctx) +static int +unmount_timed_out_cb(void *_handler_ctx) { struct unmount_msg_handler_context *handler_ctx = _handler_ctx; @@ -1329,7 +1364,8 @@ out_crashed: return WIMLIB_ERR_FILESYSTEM_DAEMON_CRASHED; } -static int daemon_timed_out_cb(void *_handler_ctx) +static int +daemon_timed_out_cb(void *_handler_ctx) { ERROR("Timed out waiting for unmount request! " "Changes to the mounted WIM will not be committed."); @@ -1359,10 +1395,11 @@ static const struct msg_handler_callbacks daemon_msg_handler_callbacks = { }, }; -static int receive_message(mqd_t mq, - struct msg_handler_context_hdr *handler_ctx, - const msg_handler_t msg_handlers[], - long mailbox_size, void *mailbox) +static int +receive_message(mqd_t mq, + struct msg_handler_context_hdr *handler_ctx, + const msg_handler_t msg_handlers[], + long mailbox_size, void *mailbox) { struct timeval now; struct timespec timeout; @@ -1404,9 +1441,10 @@ static int receive_message(mqd_t mq, return ret; } -static int message_loop(mqd_t mq, - const struct msg_handler_callbacks *callbacks, - struct msg_handler_context_hdr *handler_ctx) +static int +message_loop(mqd_t mq, + const struct msg_handler_callbacks *callbacks, + struct msg_handler_context_hdr *handler_ctx) { static const size_t MAX_MSG_SIZE = 512; long msgsize; @@ -1454,7 +1492,8 @@ static int message_loop(mqd_t mq, * not. However, after that, the unmount process must wait for the filesystem * daemon to finish writing the WIM file. */ -static int execute_fusermount(const char *dir) +static int +execute_fusermount(const mbchar *dir) { pid_t pid; int ret; @@ -1531,7 +1570,8 @@ static int wimfs_access(const char *path, int mask) } #endif -static int wimfs_chmod(const char *path, mode_t mask) +static int +wimfs_chmod(const mbchar *path, mode_t mask) { struct wim_dentry *dentry; struct wimfs_context *ctx = wimfs_get_context(); @@ -1551,7 +1591,8 @@ static int wimfs_chmod(const char *path, mode_t mask) return ret ? -ENOMEM : 0; } -static int wimfs_chown(const char *path, uid_t uid, gid_t gid) +static int +wimfs_chown(const mbchar *path, uid_t uid, gid_t gid) { struct wim_dentry *dentry; struct wimfs_context *ctx = wimfs_get_context(); @@ -1573,7 +1614,8 @@ static int wimfs_chown(const char *path, uid_t uid, gid_t gid) } /* Called when the filesystem is unmounted. */ -static void wimfs_destroy(void *p) +static void +wimfs_destroy(void *p) { struct wimfs_context *wimfs_ctx = wimfs_get_context(); if (open_message_queues(wimfs_ctx, true) == 0) { @@ -1600,15 +1642,16 @@ static int wimfs_fallocate(const char *path, int mode, #endif -static int wimfs_fgetattr(const char *path, struct stat *stbuf, - struct fuse_file_info *fi) +static int +wimfs_fgetattr(const mbchar *path, struct stat *stbuf, + struct fuse_file_info *fi) { struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh; return inode_to_stbuf(fd->f_inode, fd->f_lte, stbuf); } -static int wimfs_ftruncate(const char *path, off_t size, - struct fuse_file_info *fi) +static int +wimfs_ftruncate(const mbchar *path, off_t size, struct fuse_file_info *fi) { struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh; int ret = ftruncate(fd->staging_fd, size); @@ -1622,7 +1665,8 @@ static int wimfs_ftruncate(const char *path, off_t size, /* * Fills in a `struct stat' that corresponds to a file or directory in the WIM. */ -static int wimfs_getattr(const char *path, struct stat *stbuf) +static int +wimfs_getattr(const mbchar *path, struct stat *stbuf) { struct wim_dentry *dentry; struct wim_lookup_table_entry *lte; @@ -1639,8 +1683,9 @@ static int wimfs_getattr(const char *path, struct stat *stbuf) #ifdef ENABLE_XATTR /* Read an alternate data stream through the XATTR interface, or get its size */ -static int wimfs_getxattr(const char *path, const char *name, char *value, - size_t size) +static int +wimfs_getxattr(const mbchar *path, const mbchar *name, char *value, + size_t size) { int ret; struct wim_inode *inode; @@ -1683,10 +1728,11 @@ static int wimfs_getxattr(const char *path, const char *name, char *value, #endif /* Create a hard link */ -static int wimfs_link(const char *to, const char *from) +static int +wimfs_link(const mbchar *to, const mbchar *from) { struct wim_dentry *from_dentry, *from_dentry_parent; - const char *link_name; + const mbchar *link_name; struct wim_inode *inode; struct wim_lookup_table_entry *lte; WIMStruct *w = wimfs_get_WIMStruct(); @@ -1727,13 +1773,15 @@ static int wimfs_link(const char *to, const char *from) } #ifdef ENABLE_XATTR -static int wimfs_listxattr(const char *path, char *list, size_t size) +static int +wimfs_listxattr(const mbchar *path, mbchar *list, size_t size) { size_t needed_size; struct wim_inode *inode; struct wimfs_context *ctx = wimfs_get_context(); u16 i; - char *p; + mbchar *p; + bool size_only = (size == 0); if (!(ctx->mount_flags & WIMLIB_MOUNT_FLAG_STREAM_INTERFACE_XATTR)) return -ENOTSUP; @@ -1744,38 +1792,53 @@ static int wimfs_listxattr(const char *path, char *list, size_t size) if (!inode) return -errno; - if (size == 0) { - needed_size = 0; - for (i = 0; i < inode->i_num_ads; i++) - needed_size += inode->i_ads_entries[i].stream_name_utf8_len + 6; - return needed_size; - } else { - p = list; - for (i = 0; i < inode->i_num_ads; i++) { - needed_size = inode->i_ads_entries[i].stream_name_utf8_len + 6; - if (needed_size > size) + p = list; + for (i = 0; i < inode->i_num_ads; i++) { + mbchar *stream_name_mbs; + 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); + if (ret) { + if (ret == WIMLIB_ERR_NOMEM) + return -ENOMEM; + else + return -EIO; + } + + needed_size = stream_name_mbs_nbytes + 6; + if (!size_only) { + if (needed_size > size) { + FREE(stream_name_mbs); return -ERANGE; - p += sprintf(p, "user.%s", - inode->i_ads_entries[i].stream_name_utf8) + 1; + } + sprintf(p, "user.%s", stream_name_mbs); size -= needed_size; } - return p - list; + p += needed_size; + FREE(stream_name_mbs); } + return p - list; } #endif /* Create a directory in the WIM image. */ -static int wimfs_mkdir(const char *path, mode_t mode) +static int +wimfs_mkdir(const mbchar *path, mode_t mode) { return create_dentry(fuse_get_context(), path, mode | S_IFDIR, FILE_ATTRIBUTE_DIRECTORY, NULL); } /* Create a regular file or alternate data stream in the WIM image. */ -static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev) +static int +wimfs_mknod(const mbchar *path, mode_t mode, dev_t rdev) { - const char *stream_name; + const mbchar *stream_name; struct fuse_context *fuse_ctx = fuse_get_context(); struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx); @@ -1788,7 +1851,7 @@ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev) struct wim_ads_entry *new_entry; struct wim_inode *inode; - char *p = (char*)stream_name - 1; + mbchar *p = (mbchar*)stream_name - 1; wimlib_assert(*p == ':'); *p = '\0'; @@ -1811,9 +1874,9 @@ static int wimfs_mknod(const char *path, mode_t mode, dev_t rdev) } } - /* Open a file. */ -static int wimfs_open(const char *path, struct fuse_file_info *fi) +static int +wimfs_open(const mbchar *path, struct fuse_file_info *fi) { struct wim_dentry *dentry; struct wim_lookup_table_entry *lte; @@ -1870,7 +1933,8 @@ static int wimfs_open(const char *path, struct fuse_file_info *fi) } /* Opens a directory. */ -static int wimfs_opendir(const char *path, struct fuse_file_info *fi) +static int +wimfs_opendir(const mbchar *path, struct fuse_file_info *fi) { struct wim_inode *inode; int ret; @@ -1892,8 +1956,9 @@ static int wimfs_opendir(const char *path, struct fuse_file_info *fi) /* * Read data from a file in the WIM or in the staging directory. */ -static int wimfs_read(const char *path, char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) +static int +wimfs_read(const mbchar *path, char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) { struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh; ssize_t ret; @@ -1924,7 +1989,7 @@ static int wimfs_read(const char *path, char *buf, size_t size, if (offset > res_size) return -EOVERFLOW; size = min(size, res_size - offset); - if (read_wim_resource(fd->f_lte, (u8*)buf, + if (read_wim_resource(fd->f_lte, buf, size, offset, WIMLIB_RESOURCE_FLAG_MULTITHREADED) != 0) return -EIO; @@ -1937,17 +2002,35 @@ struct fill_params { fuse_fill_dir_t filler; }; -static int dentry_fuse_fill(struct wim_dentry *dentry, void *arg) +static int +dentry_fuse_fill(struct wim_dentry *dentry, void *arg) { struct fill_params *fill_params = arg; - return fill_params->filler(fill_params->buf, dentry->file_name_utf8, - NULL, 0); + + mbchar *file_name_mbs; + 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); + if (ret) { + if (ret == WIMLIB_ERR_NOMEM) + return -ENOMEM; + else + return -EILSEQ; + } + ret = fill_params->filler(fill_params->buf, file_name_mbs, NULL, 0); + FREE(file_name_mbs); + return ret; } /* Fills in the entries of the directory specified by @path using the * FUSE-provided function @filler. */ -static int wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, - off_t offset, struct fuse_file_info *fi) +static int +wimfs_readdir(const mbchar *path, void *buf, fuse_fill_dir_t filler, + off_t offset, struct fuse_file_info *fi) { struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh; struct wim_inode *inode; @@ -1970,7 +2053,8 @@ static int wimfs_readdir(const char *path, void *buf, fuse_fill_dir_t filler, } -static int wimfs_readlink(const char *path, char *buf, size_t buf_len) +static int +wimfs_readlink(const mbchar *path, char *buf, size_t buf_len) { struct wimfs_context *ctx = wimfs_get_context(); struct wim_inode *inode = wim_pathname_to_inode(ctx->wim, path); @@ -1988,14 +2072,16 @@ static int wimfs_readlink(const char *path, char *buf, size_t buf_len) } /* Close a file. */ -static int wimfs_release(const char *path, struct fuse_file_info *fi) +static int +wimfs_release(const mbchar *path, struct fuse_file_info *fi) { struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh; return close_wimfs_fd(fd); } /* Close a directory */ -static int wimfs_releasedir(const char *path, struct fuse_file_info *fi) +static int +wimfs_releasedir(const mbchar *path, struct fuse_file_info *fi) { struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh; return close_wimfs_fd(fd); @@ -2003,7 +2089,8 @@ static int wimfs_releasedir(const char *path, struct fuse_file_info *fi) #ifdef ENABLE_XATTR /* Remove an alternate data stream through the XATTR interface */ -static int wimfs_removexattr(const char *path, const char *name) +static int +wimfs_removexattr(const char *path, const mbchar *name) { struct wim_inode *inode; struct wim_ads_entry *ads_entry; @@ -2030,7 +2117,8 @@ static int wimfs_removexattr(const char *path, const char *name) #endif /* Renames a file or directory. See rename (3) */ -static int wimfs_rename(const char *from, const char *to) +static int +wimfs_rename(const mbchar *from, const mbchar *to) { struct wim_dentry *src; struct wim_dentry *dst; @@ -2087,7 +2175,8 @@ static int wimfs_rename(const char *from, const char *to) } /* Remove a directory */ -static int wimfs_rmdir(const char *path) +static int +wimfs_rmdir(const mbchar *path) { struct wim_dentry *dentry; WIMStruct *w = wimfs_get_WIMStruct(); @@ -2108,8 +2197,9 @@ static int wimfs_rmdir(const char *path) #ifdef ENABLE_XATTR /* Write an alternate data stream through the XATTR interface */ -static int wimfs_setxattr(const char *path, const char *name, - const char *value, size_t size, int flags) +static int +wimfs_setxattr(const mbchar *path, const mbchar *name, + const char *value, size_t size, int flags) { struct wim_ads_entry *existing_ads_entry; struct wim_inode *inode; @@ -2137,7 +2227,7 @@ static int wimfs_setxattr(const char *path, const char *name, return -ENOATTR; } - ret = inode_add_ads_with_data(inode, name, (const u8*)value, + ret = inode_add_ads_with_data(inode, name, value, size, ctx->wim->lookup_table); if (ret == 0) { if (existing_ads_entry) @@ -2149,7 +2239,8 @@ static int wimfs_setxattr(const char *path, const char *name, } #endif -static int wimfs_symlink(const char *to, const char *from) +static int +wimfs_symlink(const mbchar *to, const mbchar *from) { struct fuse_context *fuse_ctx = fuse_get_context(); struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx); @@ -2172,7 +2263,8 @@ static int wimfs_symlink(const char *to, const char *from) /* Reduce the size of a file */ -static int wimfs_truncate(const char *path, off_t size) +static int +wimfs_truncate(const mbchar *path, off_t size) { struct wim_dentry *dentry; struct wim_lookup_table_entry *lte; @@ -2211,7 +2303,8 @@ static int wimfs_truncate(const char *path, off_t size) } /* Unlink a non-directory or alternate data stream */ -static int wimfs_unlink(const char *path) +static int +wimfs_unlink(const mbchar *path) { struct wim_dentry *dentry; struct wim_lookup_table_entry *lte; @@ -2239,7 +2332,8 @@ static int wimfs_unlink(const char *path) * * Note that alternate data streams do not have their own timestamps. */ -static int wimfs_utimens(const char *path, const struct timespec tv[2]) +static int +wimfs_utimens(const mbchar *path, const struct timespec tv[2]) { struct wim_dentry *dentry; struct wim_inode *inode; @@ -2264,8 +2358,9 @@ static int wimfs_utimens(const char *path, const struct timespec tv[2]) } return 0; } -#else -static int wimfs_utime(const char *path, struct utimbuf *times) +#else /* HAVE_UTIMENSAT */ +static int +wimfs_utime(const mbchar *path, struct utimbuf *times) { struct wim_dentry *dentry; struct wim_inode *inode; @@ -2280,13 +2375,14 @@ static int wimfs_utime(const char *path, struct utimbuf *times) inode->i_last_access_time = unix_timestamp_to_wim(times->actime); return 0; } -#endif +#endif /* !HAVE_UTIMENSAT */ /* Writes to a file in the WIM filesystem. * It may be an alternate data stream, but here we don't even notice because we * just get a lookup table entry. */ -static int wimfs_write(const char *path, const char *buf, size_t size, - off_t offset, struct fuse_file_info *fi) +static int +wimfs_write(const mbchar *path, const char *buf, size_t size, + off_t offset, struct fuse_file_info *fi) { struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh; int ret; @@ -2375,15 +2471,16 @@ static struct fuse_operations wimfs_operations = { /* Mounts an image from a WIM file. */ -WIMLIBAPI int wimlib_mount_image(WIMStruct *wim, int image, const char *dir, - int mount_flags, WIMStruct **additional_swms, - unsigned num_additional_swms, - const char *staging_dir) +WIMLIBAPI int +wimlib_mount_image(WIMStruct *wim, int image, const mbchar *dir, + int mount_flags, WIMStruct **additional_swms, + unsigned num_additional_swms, + const mbchar *staging_dir) { int argc; char *argv[16]; int ret; - char *dir_copy; + mbchar *dir_copy; struct wim_lookup_table *joined_tab, *wim_tab_save; struct wim_image_metadata *imd; struct wimfs_context ctx; @@ -2589,8 +2686,9 @@ out: * Unmounts the WIM file that was previously mounted on @dir by using * wimlib_mount_image(). */ -WIMLIBAPI int wimlib_unmount_image(const char *dir, int unmount_flags, - wimlib_progress_func_t progress_func) +WIMLIBAPI int +wimlib_unmount_image(const mbchar *dir, int unmount_flags, + wimlib_progress_func_t progress_func) { int ret; struct wimfs_context wimfs_ctx; @@ -2639,7 +2737,8 @@ out: #else /* WITH_FUSE */ -static inline int mount_unsupported_error() +static int +mount_unsupported_error() { #if defined(__WIN32__) ERROR("Sorry-- Mounting WIM images is not supported on Windows!"); @@ -2650,18 +2749,20 @@ static inline int mount_unsupported_error() return WIMLIB_ERR_UNSUPPORTED; } -WIMLIBAPI int wimlib_unmount_image(const char *dir, int unmount_flags, - wimlib_progress_func_t progress_func) +WIMLIBAPI int +wimlib_unmount_image(const mbchar *dir, int unmount_flags, + wimlib_progress_func_t progress_func) { return mount_unsupported_error(); } -WIMLIBAPI int wimlib_mount_image(WIMStruct *wim_p, int image, const char *dir, - int mount_flags, WIMStruct **additional_swms, - unsigned num_additional_swms, - const char *staging_dir) +WIMLIBAPI int +wimlib_mount_image(WIMStruct *wim, int image, const mbchar *dir, + int mount_flags, WIMStruct **additional_swms, + unsigned num_additional_swms, + const mbchar *staging_dir) { return mount_unsupported_error(); } -#endif /* WITH_FUSE */ +#endif /* !WITH_FUSE */ diff --git a/src/resource.c b/src/resource.c index db9c635b..0bffb3a6 100644 --- a/src/resource.c +++ b/src/resource.c @@ -64,10 +64,11 @@ * * Returns zero on success, nonzero on failure. */ -static int read_compressed_resource(FILE *fp, u64 resource_compressed_size, - u64 resource_uncompressed_size, - u64 resource_offset, int resource_ctype, - u64 len, u64 offset, u8 contents_ret[]) +static int +read_compressed_resource(FILE *fp, u64 resource_compressed_size, + u64 resource_uncompressed_size, + u64 resource_offset, int resource_ctype, + u64 len, u64 offset, void *contents_ret) { DEBUG2("comp size = %"PRIu64", uncomp size = %"PRIu64", " @@ -211,7 +212,7 @@ static int read_compressed_resource(FILE *fp, u64 resource_compressed_size, /* Pointer to current position in the output buffer for uncompressed * data. */ - u8 *out_p = (u8*)contents_ret; + u8 *out_p = contents_ret; /* Buffer for compressed data. While most compressed chunks will have a * size much less than WIM_CHUNK_SIZE, WIM_CHUNK_SIZE - 1 is the maximum @@ -353,8 +354,8 @@ err: /* * Reads uncompressed data from an open file stream. */ -int read_uncompressed_resource(FILE *fp, u64 offset, u64 len, - u8 contents_ret[]) +int +read_uncompressed_resource(FILE *fp, u64 offset, u64 len, void *contents_ret) { if (fseeko(fp, offset, SEEK_SET) != 0) { ERROR("Failed to seek to byte %"PRIu64" of input file " @@ -378,7 +379,8 @@ int read_uncompressed_resource(FILE *fp, u64 offset, u64 len, /* Reads the contents of a struct resource_entry, as represented in the on-disk * format, from the memory pointed to by @p, and fills in the fields of @entry. * A pointer to the byte after the memory read at @p is returned. */ -const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry) +const u8 * +get_resource_entry(const u8 *p, struct resource_entry *entry) { u64 size; u8 flags; @@ -408,7 +410,8 @@ const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry) /* Copies the struct resource_entry @entry to the memory pointed to by @p in the * on-disk format. A pointer to the byte after the memory written at @p is * returned. */ -u8 *put_resource_entry(u8 *p, const struct resource_entry *entry) +u8 * +put_resource_entry(u8 *p, const struct resource_entry *entry) { p = put_u56(p, entry->size); p = put_u8(p, entry->flags); @@ -418,7 +421,8 @@ u8 *put_resource_entry(u8 *p, const struct resource_entry *entry) } #ifdef WITH_FUSE -static FILE *wim_get_fp(WIMStruct *w) +static FILE * +wim_get_fp(WIMStruct *w) { pthread_mutex_lock(&w->fp_tab_mutex); FILE *fp; @@ -441,7 +445,8 @@ out: return fp; } -static int wim_release_fp(WIMStruct *w, FILE *fp) +static int +wim_release_fp(WIMStruct *w, FILE *fp) { int ret = 0; FILE **fp_tab; @@ -468,7 +473,7 @@ out: pthread_mutex_unlock(&w->fp_tab_mutex); return ret; } -#endif +#endif /* !WITH_FUSE */ /* * Reads some data from the resource corresponding to a WIM lookup table entry. @@ -480,8 +485,9 @@ out: * * Returns zero on success, nonzero on failure. */ -int read_wim_resource(const struct wim_lookup_table_entry *lte, u8 buf[], - size_t size, u64 offset, int flags) +int +read_wim_resource(const struct wim_lookup_table_entry *lte, void *buf, + size_t size, u64 offset, int flags) { int ctype; int ret = 0; @@ -607,8 +613,9 @@ int read_wim_resource(const struct wim_lookup_table_entry *lte, u8 buf[], * * Returns 0 on success; nonzero on failure. */ -int read_full_wim_resource(const struct wim_lookup_table_entry *lte, u8 buf[], - int flags) +int +read_full_wim_resource(const struct wim_lookup_table_entry *lte, + void *buf, int flags) { return read_wim_resource(lte, buf, wim_resource_size(lte), 0, flags); } @@ -619,10 +626,11 @@ int read_full_wim_resource(const struct wim_lookup_table_entry *lte, u8 buf[], * * @extract_chunk is a function that is called to extract each chunk of the * resource. */ -int extract_wim_resource(const struct wim_lookup_table_entry *lte, - u64 size, - extract_chunk_func_t extract_chunk, - void *extract_chunk_arg) +int +extract_wim_resource(const struct wim_lookup_table_entry *lte, + u64 size, + extract_chunk_func_t extract_chunk, + void *extract_chunk_arg) { u64 bytes_remaining = size; u8 buf[min(WIM_CHUNK_SIZE, bytes_remaining)]; @@ -667,9 +675,10 @@ int extract_wim_resource(const struct wim_lookup_table_entry *lte, * and on short writes. * * Returns short count and set errno on failure. */ -static ssize_t full_write(int fd, const void *buf, size_t n) +static ssize_t +full_write(int fd, const void *buf, size_t n) { - const char *p = buf; + const void *p = buf; ssize_t ret; ssize_t total = 0; @@ -687,7 +696,8 @@ static ssize_t full_write(int fd, const void *buf, size_t n) return total; } -int extract_wim_chunk_to_fd(const u8 *buf, size_t len, u64 offset, void *arg) +int +extract_wim_chunk_to_fd(const void *buf, size_t len, u64 offset, void *arg) { int fd = *(int*)arg; ssize_t ret = full_write(fd, buf, len); @@ -709,7 +719,8 @@ int extract_wim_chunk_to_fd(const u8 *buf, size_t len, u64 offset, void *arg) * * (This function is confusing and should be refactored somehow.) */ -int copy_resource(struct wim_lookup_table_entry *lte, void *wim) +int +copy_resource(struct wim_lookup_table_entry *lte, void *wim) { WIMStruct *w = wim; int ret; diff --git a/src/security.c b/src/security.c index 2e60aa53..ae71c5dd 100644 --- a/src/security.c +++ b/src/security.c @@ -255,7 +255,8 @@ typedef struct { * entries anyway; however this ensures that that the security descriptors pass * the validation in libntfs-3g. */ -static void empty_sacl_fixup(u8 *descr, u64 *size_p) +static void +empty_sacl_fixup(u8 *descr, u64 *size_p) { if (*size_p >= sizeof(SecurityDescriptor)) { SecurityDescriptor *sd = (SecurityDescriptor*)descr; @@ -281,8 +282,9 @@ static void empty_sacl_fixup(u8 *descr, u64 *size_p) * Note: There is no `offset' argument because the security data is located at * the beginning of the metadata resource. */ -int read_security_data(const u8 metadata_resource[], u64 metadata_resource_len, - struct wim_security_data **sd_p) +int +read_security_data(const u8 metadata_resource[], u64 metadata_resource_len, + struct wim_security_data **sd_p) { struct wim_security_data *sd; const u8 *p; @@ -431,7 +433,8 @@ out_free_sd: /* * Writes security data to an in-memory buffer. */ -u8 *write_security_data(const struct wim_security_data *sd, u8 *p) +u8 * +write_security_data(const struct wim_security_data *sd, u8 *p) { DEBUG("Writing security data (total_length = %"PRIu32", num_entries " "= %"PRIu32")", sd->total_length, sd->num_entries); @@ -455,7 +458,8 @@ u8 *write_security_data(const struct wim_security_data *sd, u8 *p) return p; } -static void print_acl(const u8 *p, const char *type) +static void +print_acl(const u8 *p, const char *type) { const ACL *acl = (const ACL*)p; u8 revision = acl->revision; @@ -481,7 +485,8 @@ static void print_acl(const u8 *p, const char *type) putchar('\n'); } -static void print_sid(const u8 *p, const char *type) +static void +print_sid(const u8 *p, const char *type) { const SID *sid = (const SID*)p; printf(" [%s SID]\n", type); @@ -497,7 +502,8 @@ static void print_sid(const u8 *p, const char *type) putchar('\n'); } -static void print_security_descriptor(const u8 *p, u64 size) +static void +print_security_descriptor(const u8 *p, u64 size) { const SecurityDescriptor *sd = (const SecurityDescriptor*)p; u8 revision = sd->revision; @@ -526,7 +532,8 @@ static void print_security_descriptor(const u8 *p, u64 size) /* * Prints the security data for a WIM file. */ -void print_security_data(const struct wim_security_data *sd) +void +print_security_data(const struct wim_security_data *sd) { wimlib_assert(sd != NULL); @@ -543,7 +550,8 @@ void print_security_data(const struct wim_security_data *sd) putchar('\n'); } -void free_security_data(struct wim_security_data *sd) +void +free_security_data(struct wim_security_data *sd) { if (sd) { wimlib_assert(sd->refcnt != 0); @@ -569,7 +577,8 @@ struct sd_node { struct rb_node rb_node; }; -static void free_sd_tree(struct rb_node *node) +static void +free_sd_tree(struct rb_node *node) { if (node) { free_sd_tree(node->rb_left); @@ -579,13 +588,15 @@ static void free_sd_tree(struct rb_node *node) } /* Frees a security descriptor index set. */ -void destroy_sd_set(struct sd_set *sd_set) +void +destroy_sd_set(struct sd_set *sd_set) { free_sd_tree(sd_set->rb_root.rb_node); } /* Inserts a a new node into the security descriptor index tree. */ -static void insert_sd_node(struct sd_set *set, struct sd_node *new) +static void +insert_sd_node(struct sd_set *set, struct sd_node *new) { struct rb_root *root = &set->rb_root; struct rb_node **p = &(root->rb_node); @@ -609,7 +620,8 @@ static void insert_sd_node(struct sd_set *set, struct sd_node *new) /* Returns the index of the security descriptor having a SHA1 message digest of * @hash. If not found, return -1. */ -int lookup_sd(struct sd_set *set, const u8 hash[SHA1_HASH_SIZE]) +int +lookup_sd(struct sd_set *set, const u8 hash[SHA1_HASH_SIZE]) { struct rb_node *node = set->rb_root.rb_node; @@ -633,8 +645,8 @@ int lookup_sd(struct sd_set *set, const u8 hash[SHA1_HASH_SIZE]) * the security ID for it. If a new security descriptor cannot be allocated, * return -1. */ -int sd_set_add_sd(struct sd_set *sd_set, const char descriptor[], - size_t size) +int +sd_set_add_sd(struct sd_set *sd_set, const char descriptor[], size_t size) { u8 hash[SHA1_HASH_SIZE]; int security_id; diff --git a/src/sha1.c b/src/sha1.c index 5fb506ed..ca1ad0eb 100644 --- a/src/sha1.c +++ b/src/sha1.c @@ -224,7 +224,8 @@ static int sha1_stream(FILE *fp, u8 md[SHA1_HASH_SIZE]) /* Calculates the SHA1 message digest of a file. @md must point to a buffer of * length 20 bytes into which the message digest is written. */ -int sha1sum(const char *filename, u8 md[SHA1_HASH_SIZE]) +int +sha1sum(const mbchar *filename, u8 md[SHA1_HASH_SIZE]) { FILE *fp; int ret; diff --git a/src/sha1.h b/src/sha1.h index 8573c543..5238a92c 100644 --- a/src/sha1.h +++ b/src/sha1.h @@ -11,35 +11,39 @@ extern const u8 zero_hash[SHA1_HASH_SIZE]; -static inline void copy_hash(u8 dest[SHA1_HASH_SIZE], - const u8 src[SHA1_HASH_SIZE]) +static inline void +copy_hash(u8 dest[SHA1_HASH_SIZE], const u8 src[SHA1_HASH_SIZE]) { memcpy(dest, src, SHA1_HASH_SIZE); } -static inline void random_hash(u8 hash[SHA1_HASH_SIZE]) +static inline void +random_hash(u8 hash[SHA1_HASH_SIZE]) { randomize_byte_array(hash, SHA1_HASH_SIZE); } -static inline bool hashes_equal(const u8 h1[SHA1_HASH_SIZE], - const u8 h2[SHA1_HASH_SIZE]) +static inline bool +hashes_equal(const u8 h1[SHA1_HASH_SIZE], const u8 h2[SHA1_HASH_SIZE]) { return memcmp(h1, h2, SHA1_HASH_SIZE) == 0; } -static inline int hashes_cmp(const u8 h1[SHA1_HASH_SIZE], + +static inline int +hashes_cmp(const u8 h1[SHA1_HASH_SIZE], const u8 h2[SHA1_HASH_SIZE]) { return memcmp(h1, h2, SHA1_HASH_SIZE); } -/* Prints a hash code field. */ -static inline void print_hash(const u8 hash[SHA1_HASH_SIZE]) +static inline void +print_hash(const u8 hash[SHA1_HASH_SIZE]) { print_byte_field(hash, SHA1_HASH_SIZE); } -static inline bool is_zero_hash(const u8 hash[SHA1_HASH_SIZE]) +static inline bool +is_zero_hash(const u8 hash[SHA1_HASH_SIZE]) { if (hash) for (u8 i = 0; i < SHA1_HASH_SIZE / 4; i++) @@ -48,7 +52,8 @@ static inline bool is_zero_hash(const u8 hash[SHA1_HASH_SIZE]) return true; } -static inline void zero_out_hash(u8 hash[SHA1_HASH_SIZE]) +static inline void +zero_out_hash(u8 hash[SHA1_HASH_SIZE]) { memset(hash, 0, SHA1_HASH_SIZE); } @@ -65,20 +70,26 @@ static inline void zero_out_hash(u8 hash[SHA1_HASH_SIZE]) #else /* WITH_LIBCRYPTO */ typedef struct { - u32 state[5]; - u32 count[2]; - u8 buffer[64]; + u32 state[5]; + u32 count[2]; + u8 buffer[64]; } SHA_CTX; -extern void sha1_buffer(const u8 buffer[], size_t len, u8 hash[SHA1_HASH_SIZE]); -extern void sha1_init(SHA_CTX *ctx); -extern void sha1_update(SHA_CTX *ctx, const u8 data[], size_t len); -extern void sha1_final(u8 hash[SHA1_HASH_SIZE], SHA_CTX *ctx); +extern void +sha1_buffer(const u8 buffer[], size_t len, u8 hash[SHA1_HASH_SIZE]); -#endif /* !WITH_LIBCRYPTO */ +extern void +sha1_init(SHA_CTX *ctx); -extern int sha1sum(const char *filename, u8 hash[SHA1_HASH_SIZE]); +extern void +sha1_update(SHA_CTX *ctx, const u8 data[], size_t len); +extern void +sha1_final(u8 hash[SHA1_HASH_SIZE], SHA_CTX *ctx); + +#endif /* !WITH_LIBCRYPTO */ +extern int +sha1sum(const mbchar *filename, u8 hash[SHA1_HASH_SIZE]); #endif /* _WIMLIB_SHA1_H */ diff --git a/src/symlink.c b/src/symlink.c index f6a66c24..5c8417c7 100644 --- a/src/symlink.c +++ b/src/symlink.c @@ -40,9 +40,10 @@ * dentry, and we already know the reparse tag length from the lookup table * entry resource length. */ -static ssize_t get_symlink_name(const u8 *resource, size_t resource_len, - char *buf, size_t buf_len, - u32 reparse_tag) +static ssize_t +get_symlink_name(const void *resource, size_t resource_len, + void *buf, size_t buf_len, + u32 reparse_tag) { const u8 *p = resource; u16 substitute_name_offset; @@ -128,8 +129,9 @@ out: return ret; } -static int make_symlink_reparse_data_buf(const char *symlink_target, - size_t *len_ret, void **buf_ret) +static int +make_symlink_reparse_data_buf(const mbchar *symlink_target, + size_t *len_ret, void **buf_ret) { size_t utf8_len = strlen(symlink_target); char *name_utf16; @@ -171,8 +173,9 @@ static int make_symlink_reparse_data_buf(const char *symlink_target, * WIM_IO_REPARSE_TAG_SYMLINK), or it may be a junction point (reparse tag * WIM_IO_REPARSE_TAG_MOUNT_POINT). */ -ssize_t inode_readlink(const struct wim_inode *inode, char *buf, size_t buf_len, - const WIMStruct *w, int read_resource_flags) +ssize_t +inode_readlink(const struct wim_inode *inode, mbchar *buf, size_t buf_len, + const WIMStruct *w, int read_resource_flags) { const struct wim_lookup_table_entry *lte; int ret; @@ -205,9 +208,11 @@ ssize_t inode_readlink(const struct wim_inode *inode, char *buf, size_t buf_len, * * On failure @dentry and @lookup_table are not modified. */ -int inode_set_symlink(struct wim_inode *inode, const char *target, - struct wim_lookup_table *lookup_table, - struct wim_lookup_table_entry **lte_ret) +int +inode_set_symlink(struct wim_inode *inode, + const mbchar *target, + struct wim_lookup_table *lookup_table, + struct wim_lookup_table_entry **lte_ret) { int ret; diff --git a/src/util.c b/src/util.c index df813bb9..626fba49 100644 --- a/src/util.c +++ b/src/util.c @@ -39,6 +39,7 @@ #include #include #include +#include #include /* for getpid() */ @@ -47,20 +48,106 @@ # define strerror_r(errnum, buf, bufsize) strerror_s(buf, bufsize, errnum) #endif +static size_t utf16le_strlen(const utf16lechar *s) +{ + const utf16lechar *p = s; + while (p) + p++; + return (p - s) / sizeof(utf16lechar); +} + +/* Handle %W for UTF16-LE printing and %U for UTF-8 printing. + * + * WARNING: 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. + */ +static int +wimlib_vfprintf(FILE *fp, const char *format, va_list va) +{ + const char *p; + + for (p = format; *p; p++) + if (*p == '%' && ((*p + 1) == 'W' || *(p + 1) == 'U')) + goto special; + return vfprintf(fp, format, va); +special: + ; + int n = 0; + for (p = format; *p; p++) { + if (*p == '%' && ((*p + 1) == 'W' || *(p + 1) == 'U')) { + int ret; + mbchar *mbs; + size_t mbs_len; + + if (*(p + 1) == 'W') { + utf16lechar *ucs = va_arg(va, utf16lechar*); + size_t ucs_nbytes = utf16le_strlen(ucs); + ret = utf16le_to_mbs(ucs, ucs_nbytes, + &mbs, &mbs_len); + } else { + utf8char *ucs = va_arg(va, utf8char*); + size_t ucs_nbytes = strlen(ucs); + ret = utf8_to_mbs(ucs, ucs_nbytes, + &mbs, &mbs_len); + } + if (ret) { + ret = fprintf(fp, "???"); + } else { + ret = fprintf(fp, "%s", mbs); + FREE(mbs); + } + if (ret < 0) + return -1; + else + n += ret; + } else { + if (putc(*p, fp) == EOF) + return -1; + n++; + } + } + return n; +} + +int +wimlib_printf(const char *format, ...) +{ + int ret; + va_list va; + + va_start(va, format); + ret = wimlib_vfprintf(stdout, format, va); + va_end(va); + return ret; +} + +int +wimlib_fprintf(FILE *fp, const char *format, ...) +{ + int ret; + va_list va; + + va_start(va, format); + ret = wimlib_vfprintf(fp, format, va); + va_end(va); + return ret; +} + /* True if wimlib is to print an informational message when an error occurs. * This can be turned off by calling wimlib_set_print_errors(false). */ #ifdef ENABLE_ERROR_MESSAGES #include static bool wimlib_print_errors = false; -static void wimlib_vmsg(const char *tag, const char *format, - va_list va, bool perror) +static void +wimlib_vmsg(const char *tag, const char *format, + va_list va, bool perror) { if (wimlib_print_errors) { int errno_save = errno; fflush(stdout); fputs(tag, stderr); - vfprintf(stderr, format, va); + wimlib_vfprintf(stderr, format, va); if (perror && errno_save != 0) { char buf[50]; int res; @@ -76,7 +163,8 @@ static void wimlib_vmsg(const char *tag, const char *format, } } -void wimlib_error(const char *format, ...) +void +wimlib_error(const char *format, ...) { va_list va; @@ -85,7 +173,8 @@ void wimlib_error(const char *format, ...) va_end(va); } -void wimlib_error_with_errno(const char *format, ...) +void +wimlib_error_with_errno(const char *format, ...) { va_list va; @@ -94,7 +183,8 @@ void wimlib_error_with_errno(const char *format, ...) va_end(va); } -void wimlib_warning(const char *format, ...) +void +wimlib_warning(const char *format, ...) { va_list va; @@ -103,7 +193,8 @@ void wimlib_warning(const char *format, ...) va_end(va); } -void wimlib_warning_with_errno(const char *format, ...) +void +wimlib_warning_with_errno(const char *format, ...) { va_list va; @@ -114,7 +205,8 @@ void wimlib_warning_with_errno(const char *format, ...) #endif -WIMLIBAPI int wimlib_set_print_errors(bool show_error_messages) +WIMLIBAPI int +wimlib_set_print_errors(bool show_error_messages) { #ifdef ENABLE_ERROR_MESSAGES wimlib_print_errors = show_error_messages; @@ -127,7 +219,7 @@ WIMLIBAPI int wimlib_set_print_errors(bool show_error_messages) #endif } -static const char *error_strings[] = { +static const mbchar *error_strings[] = { [WIMLIB_ERR_SUCCESS] = "Success", [WIMLIB_ERR_ALREADY_LOCKED] @@ -175,6 +267,8 @@ static const char *error_strings[] = { = "The WIM's integrity table is invalid", [WIMLIB_ERR_INVALID_LOOKUP_TABLE_ENTRY] = "An entry in the WIM's lookup table is invalid", + [WIMLIB_ERR_INVALID_MULTIBYTE_STRING] + = "A string was not valid in the current locale's character encoding", [WIMLIB_ERR_INVALID_OVERLAY] = "Conflicting files in overlay when creating a WIM image", [WIMLIB_ERR_INVALID_PARAM] @@ -239,6 +333,8 @@ static const char *error_strings[] = { = "Could not read the metadata for a file or directory", [WIMLIB_ERR_TIMEOUT] = "Timed out while waiting for a message to arrive from another process", + [WIMLIB_ERR_UNICODE_STRING_NOT_REPRESENTABLE] + = "A Unicode string could not be represented in the current locale's encoding", [WIMLIB_ERR_UNKNOWN_VERSION] = "The WIM file is marked with an unknown version number", [WIMLIB_ERR_UNSUPPORTED] @@ -249,7 +345,8 @@ static const char *error_strings[] = { = "The XML data of the WIM is invalid", }; -WIMLIBAPI const char *wimlib_get_error_string(enum wimlib_error_code code) +WIMLIBAPI const mbchar * +wimlib_get_error_string(enum wimlib_error_code code) { if (code < WIMLIB_ERR_SUCCESS || code > WIMLIB_ERR_XML) return NULL; @@ -264,7 +361,8 @@ void *(*wimlib_malloc_func) (size_t) = malloc; void (*wimlib_free_func) (void *) = free; void *(*wimlib_realloc_func)(void *, size_t) = realloc; -void *wimlib_calloc(size_t nmemb, size_t size) +void * +wimlib_calloc(size_t nmemb, size_t size) { size_t total_size = nmemb * size; void *p = MALLOC(total_size); @@ -273,7 +371,8 @@ void *wimlib_calloc(size_t nmemb, size_t size) return p; } -char *wimlib_strdup(const char *str) +char * +wimlib_strdup(const char *str) { size_t size; char *p; @@ -285,14 +384,16 @@ char *wimlib_strdup(const char *str) return p; } -extern void xml_set_memory_allocator(void *(*malloc_func)(size_t), - void (*free_func)(void *), - void *(*realloc_func)(void *, size_t)); +extern void +xml_set_memory_allocator(void *(*malloc_func)(size_t), + void (*free_func)(void *), + void *(*realloc_func)(void *, size_t)); #endif -WIMLIBAPI int wimlib_set_memory_allocator(void *(*malloc_func)(size_t), - void (*free_func)(void *), - void *(*realloc_func)(void *, size_t)) +WIMLIBAPI int +wimlib_set_memory_allocator(void *(*malloc_func)(size_t), + void (*free_func)(void *), + void *(*realloc_func)(void *, size_t)) { #ifdef ENABLE_CUSTOM_MEMORY_ALLOCATOR wimlib_malloc_func = malloc_func ? malloc_func : malloc; @@ -312,14 +413,16 @@ WIMLIBAPI int wimlib_set_memory_allocator(void *(*malloc_func)(size_t), static bool seeded = false; -static void seed_random() +static void +seed_random() { srand(time(NULL) * getpid()); seeded = true; } /* Fills @n bytes pointed to by @p with random alphanumeric characters. */ -void randomize_char_array_with_alnum(char p[], size_t n) +void +randomize_char_array_with_alnum(char p[], size_t n) { if (!seeded) seed_random(); @@ -335,7 +438,8 @@ void randomize_char_array_with_alnum(char p[], size_t n) } /* Fills @n bytes pointer to by @p with random numbers. */ -void randomize_byte_array(u8 *p, size_t n) +void +randomize_byte_array(u8 *p, size_t n) { if (!seeded) seed_random(); @@ -345,7 +449,8 @@ void randomize_byte_array(u8 *p, size_t n) /* 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(char buf[], size_t len) +void +to_parent_name(char buf[], size_t len) { ssize_t i = (ssize_t)len - 1; while (i >= 0 && buf[i] == '/') @@ -359,7 +464,8 @@ void to_parent_name(char buf[], size_t len) /* Like the basename() function, but does not modify @path; it just returns a * pointer to it. */ -const char *path_basename(const char *path) +const char * +path_basename(const char *path) { const char *p = path; while (*p) @@ -385,7 +491,8 @@ const char *path_basename(const char *path) * Returns a pointer to the part of @path following the first colon in the last * path component, or NULL if the last path component does not contain a colon. */ -const char *path_stream_name(const char *path) +const char * +path_stream_name(const char *path) { const char *base = path_basename(path); const char *stream_name = strchr(base, ':'); @@ -406,7 +513,8 @@ const char *path_stream_name(const char *path) * sequence of '/', or a pointer to the terminating * null byte in the case of a path without any '/'. */ -const char *path_next_part(const char *path, size_t *first_part_len_ret) +const char * +path_next_part(const char *path, size_t *first_part_len_ret) { size_t i; const char *next_part; @@ -423,7 +531,8 @@ const char *path_next_part(const char *path, size_t *first_part_len_ret) } /* Returns the number of components of @path. */ -int get_num_path_components(const char *path) +int +get_num_path_components(const char *path) { int num_components = 0; while (*path) { @@ -442,7 +551,8 @@ int get_num_path_components(const char *path) * 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) +void +print_string(const void *string, size_t len) { const u8 *p = string; @@ -455,14 +565,16 @@ void print_string(const void *string, size_t len) } } -u64 get_wim_timestamp() +u64 +get_wim_timestamp() { struct timeval tv; gettimeofday(&tv, NULL); return timeval_to_wim_timestamp(tv); } -void wim_timestamp_to_str(u64 timestamp, char *buf, size_t len) +void +wim_timestamp_to_str(u64 timestamp, char *buf, size_t len) { struct tm tm; time_t t = wim_timestamp_to_unix(timestamp); diff --git a/src/util.h b/src/util.h index c51fc710..71590ffe 100644 --- a/src/util.h +++ b/src/util.h @@ -49,6 +49,24 @@ typedef uint32_t u32; typedef uint64_t u64; #endif +/* A pointer to 'mbchar' indicates a string of "multibyte characters" provided + * in the default encoding of the user's locale, which may be "UTF-8", + * "ISO-8859-1", "C", or any other ASCII-compatible encoding. + * "ASCII-compatible" here means any encoding where all ASCII characters have + * the same representation, and any non-ASCII character is represented as a + * sequence of one or more bytes not already used by any ASCII character. */ +typedef char mbchar; + +/* A pointer to 'utf8char' indicates a UTF-8 encoded string */ +typedef char utf8char; + +/* Note: in some places in the code, strings of plain old 'char' are still used. + * This means that the string is being operated on in an ASCII-compatible way, + * and may be either a multibyte or UTF-8 string. */ + +/* A pointer to 'utf16lechar' indicates a UTF-16LE encoded string */ +typedef u16 utf16lechar; + #ifndef min #define min(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); \ (__a < __b) ? __a : __b; }) @@ -95,14 +113,17 @@ dummy_printf(const char *format, ...) } #ifdef ENABLE_ERROR_MESSAGES -extern void wimlib_error(const char *format, ...) - FORMAT(printf, 1, 2) COLD; -extern void wimlib_error_with_errno(const char *format, ...) - FORMAT(printf, 1, 2) COLD; -extern void wimlib_warning(const char *format, ...) - FORMAT(printf, 1, 2) COLD; -extern void wimlib_warning_with_errno(const char *format, ...) - FORMAT(printf, 1, 2) COLD; +extern void +wimlib_error(const char *format, ...) FORMAT(printf, 1, 2) COLD; + +extern void +wimlib_error_with_errno(const char *format, ...) FORMAT(printf, 1, 2) COLD; + +extern void +wimlib_warning(const char *format, ...) FORMAT(printf, 1, 2) COLD; + +extern void +wimlib_warning_with_errno(const char *format, ...) FORMAT(printf, 1, 2) COLD; # define ERROR wimlib_error # define ERROR_WITH_ERRNO wimlib_error_with_errno # define WARNING wimlib_warning @@ -119,7 +140,7 @@ extern void wimlib_warning_with_errno(const char *format, ...) # define DEBUG(format, ...) \ ({ \ int __errno_save = errno; \ - fprintf(stdout, "[%s %d] %s(): " format, \ + wimlib_fprintf(stdout, "[%s %d] %s(): " format, \ __FILE__, __LINE__, __func__, ## __VA_ARGS__); \ putchar('\n'); \ fflush(stdout); \ @@ -173,51 +194,40 @@ extern char *wimlib_strdup(const char *str); #endif /* ENABLE_CUSTOM_MEMORY_ALLOCATOR */ -/* encoding.c */ - -#if defined(WITH_NTFS_3G) || defined(__WIN32__) -static inline int iconv_global_init() -{ - return 0; -} - -static inline void iconv_global_cleanup() { } -#else -extern int iconv_global_init(); -extern void iconv_global_cleanup(); -#endif - -extern int utf16_to_utf8(const char *utf16_str, size_t utf16_nbytes, - char **utf8_str_ret, size_t *utf8_nbytes_ret); - -extern int utf8_to_utf16(const char *utf8_str, size_t utf8_nbytes, - char **utf16_str_ret, size_t *utf16_nbytes_ret); - /* util.c */ -extern void randomize_byte_array(u8 *p, size_t n); +extern void +randomize_byte_array(u8 *p, size_t n); -extern void randomize_char_array_with_alnum(char p[], size_t n); +extern void +randomize_char_array_with_alnum(char p[], size_t n); -extern const char *path_next_part(const char *path, - size_t *first_part_len_ret); +extern const char * +path_next_part(const char *path, size_t *first_part_len_ret); -extern const char *path_basename(const char *path); +extern const char * +path_basename(const char *path); -extern const char *path_stream_name(const char *path); +extern const char * +path_stream_name(const char *path); -extern void to_parent_name(char buf[], size_t len); +extern void +to_parent_name(char buf[], size_t len); -extern void print_string(const void *string, size_t len); +extern void +print_string(const void *string, size_t len); -extern int get_num_path_components(const char *path); +extern int +get_num_path_components(const char *path); -static inline void print_byte_field(const u8 field[], size_t len) +static inline void +print_byte_field(const u8 field[], size_t len) { while (len--) printf("%02hhx", *field++); } -static inline u32 bsr32(u32 n) +static inline u32 +bsr32(u32 n) { #if defined(__x86__) || defined(__x86_64__) asm("bsrl %0, %0;" @@ -232,4 +242,10 @@ static inline u32 bsr32(u32 n) #endif } +extern int +wimlib_fprintf(FILE *fp, const char *format, ...) FORMAT(printf, 2, 3); + +extern int +wimlib_printf(const char *format, ...) FORMAT(printf, 1, 2); + #endif /* _WIMLIB_UTIL_H */ diff --git a/src/wim.c b/src/wim.c index 60b2b57e..6df2c71e 100644 --- a/src/wim.c +++ b/src/wim.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -645,11 +646,16 @@ WIMLIBAPI void wimlib_free(WIMStruct *w) DEBUG("Freed WIMStruct"); } +bool wimlib_mbs_is_utf8; + /* Get global memory allocations out of the way. Not strictly necessary in * single-threaded programs like 'imagex'. */ WIMLIBAPI int wimlib_global_init() { + char *encoding; + libxml_global_init(); + wimlib_mbs_is_utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0); return iconv_global_init(); } diff --git a/src/wimlib.h b/src/wimlib.h index 6abb6e5b..f875afb9 100644 --- a/src/wimlib.h +++ b/src/wimlib.h @@ -247,6 +247,9 @@ */ typedef struct WIMStruct WIMStruct; +typedef char wimlib_mbchar; +typedef char wimlib_utf8char; + /** * Specifies the compression type of a WIM file. */ @@ -406,12 +409,12 @@ union wimlib_progress_info { * ::WIMLIB_PROGRESS_MSG_SCAN_END. */ struct wimlib_progress_info_scan { /** Directory or NTFS volume that is being scanned. */ - const char *source; + const wimlib_mbchar *source; /** Path to the file or directory that is about to be scanned, * relative to the root of the image capture or the NTFS volume. * */ - const char *cur_path; + const wimlib_mbchar *cur_path; /** True iff @a cur_path is being excluded from the image * capture due to the capture configuration file. */ @@ -420,7 +423,7 @@ union wimlib_progress_info { /** Target path in the WIM. Only valid on messages * ::WIMLIB_PROGRESS_MSG_SCAN_BEGIN and * ::WIMLIB_PROGRESS_MSG_SCAN_END. */ - const char *wim_target_path; + const wimlib_mbchar *wim_target_path; } scan; /** Valid on messages ::WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN, @@ -436,18 +439,18 @@ union wimlib_progress_info { int extract_flags; /** Full path to the WIM file being extracted. */ - const char *wimfile_name; + const wimlib_mbchar *wimfile_name; /** Name of the image being extracted. */ - const char *image_name; + const wimlib_utf8char *image_name; /** Directory or NTFS volume to which the image is being * extracted. */ - const char *target; + const wimlib_mbchar *target; /** Current dentry being extracted. (Valid only if message is * ::WIMLIB_PROGRESS_MSG_EXTRACT_DENTRY.) */ - const char *cur_path; + const wimlib_mbchar *cur_path; /** Number of bytes of uncompressed data that will be extracted. * Takes into account hard links (they are not counted for each @@ -469,11 +472,11 @@ union wimlib_progress_info { /** Valid on messages ::WIMLIB_PROGRESS_MSG_RENAME. */ struct wimlib_progress_info_rename { /** Name of the temporary file that the WIM was written to. */ - const char *from; + const wimlib_mbchar *from; /** Name of the original WIM file to which the temporary file is * being renamed. */ - const char *to; + const wimlib_mbchar *to; } rename; /** Valid on messages ::WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY and @@ -501,7 +504,7 @@ union wimlib_progress_info { /** Filename of the WIM (only valid if the message is * ::WIMLIB_PROGRESS_MSG_VERIFY_INTEGRITY). */ - const char *filename; + const wimlib_mbchar *filename; } integrity; /** Valid on messages ::WIMLIB_PROGRESS_MSG_JOIN_STREAMS. */ @@ -543,7 +546,7 @@ union wimlib_progress_info { /** Name of the split WIM part that is about to be started * (::WIMLIB_PROGRESS_MSG_SPLIT_BEGIN_PART) or has just been * finished (::WIMLIB_PROGRESS_MSG_SPLIT_END_PART). */ - const char *part_name; + const wimlib_mbchar *part_name; } split; }; @@ -564,12 +567,12 @@ typedef int (*wimlib_progress_func_t)(enum wimlib_progress_msg msg_type, struct wimlib_capture_source { /** Absolute or relative path to a file or directory on the external * filesystem to be included in the WIM image. */ - char *fs_source_path; + wimlib_mbchar *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. */ - char *wim_target_path; + wimlib_mbchar *wim_target_path; /** Reserved; set to 0. */ long reserved; @@ -793,6 +796,8 @@ enum wimlib_error_code { WIMLIB_ERR_WRITE, WIMLIB_ERR_XML, WIMLIB_ERR_INVALID_OVERLAY, + WIMLIB_ERR_INVALID_MULTIBYTE_STRING, + WIMLIB_ERR_UNICODE_STRING_NOT_REPRESENTABLE, }; @@ -885,10 +890,12 @@ enum wimlib_error_code { * ::WIMLIB_ADD_IMAGE_FLAG_NTFS was specified in @a add_image_flags, but * wimlib was configured with the @c --without-ntfs-3g flag. */ -extern int wimlib_add_image(WIMStruct *wim, const char *source, - const char *name, const char *config, - size_t config_len, int add_image_flags, - wimlib_progress_func_t progress_func); +extern int +wimlib_add_image(WIMStruct *wim, const wimlib_mbchar *source, + const wimlib_utf8char *name, + const wimlib_mbchar *config, + size_t config_len, int add_image_flags, + wimlib_progress_func_t progress_func); /** This function is equivalent to wimlib_add_image() except it allows for * multiple sources to be combined into a single WIM image. This is done by @@ -912,14 +919,15 @@ extern int wimlib_add_image(WIMStruct *wim, const char *source, * (In this respect, there is no advantage to using * wimlib_add_image_multisource() instead of wimlib_add_image() when requesting * NTFS mode.) */ -extern int wimlib_add_image_multisource(WIMStruct *w, - struct wimlib_capture_source *sources, - size_t num_sources, - const char *name, - const char *config_str, - size_t config_len, - int add_image_flags, - wimlib_progress_func_t progress_func); +extern int +wimlib_add_image_multisource(WIMStruct *w, + struct wimlib_capture_source *sources, + size_t num_sources, + const wimlib_utf8char *name, + const wimlib_mbchar *config_str, + size_t config_len, + int add_image_flags, + wimlib_progress_func_t progress_func); /** * Creates a ::WIMStruct for a new WIM file. @@ -943,7 +951,8 @@ extern int wimlib_add_image_multisource(WIMStruct *w, * @retval ::WIMLIB_ERR_NOMEM * Failed to allocate needed memory. */ -extern int wimlib_create_new_wim(int ctype, WIMStruct **wim_ret); +extern int +wimlib_create_new_wim(int ctype, WIMStruct **wim_ret); /** * Deletes an image, or all images, from a WIM file. @@ -986,7 +995,8 @@ extern int wimlib_create_new_wim(int ctype, WIMStruct **wim_ret); * @a wim is part of a split WIM. Deleting an image from a split WIM is * unsupported. */ -extern int wimlib_delete_image(WIMStruct *wim, int image); +extern int +wimlib_delete_image(WIMStruct *wim, int image); /** * Exports an image, or all the images, from a WIM file, into another WIM file. @@ -1095,12 +1105,15 @@ extern int wimlib_delete_image(WIMStruct *wim, int image); * @a dest_wim is part of a split WIM. Exporting an image to a split WIM * is unsupported. */ -extern int wimlib_export_image(WIMStruct *src_wim, int src_image, - WIMStruct *dest_wim, const char *dest_name, - const char *dest_description, int export_flags, - WIMStruct **additional_swms, - unsigned num_additional_swms, - wimlib_progress_func_t progress_func); +extern int +wimlib_export_image(WIMStruct *src_wim, int src_image, + WIMStruct *dest_wim, + const wimlib_utf8char *dest_name, + const wimlib_utf8char *dest_description, + int export_flags, + WIMStruct **additional_swms, + unsigned num_additional_swms, + wimlib_progress_func_t progress_func); /** * Extracts an image, or all images, from a standalone or split WIM file to a @@ -1224,11 +1237,13 @@ extern int wimlib_export_image(WIMStruct *src_wim, int src_image, * Failed to write a file being extracted (only if * ::WIMLIB_EXTRACT_FLAG_NTFS was not specified in @a extract_flags). */ -extern int wimlib_extract_image(WIMStruct *wim, int image, - const char *target, int extract_flags, - WIMStruct **additional_swms, - unsigned num_additional_swms, - wimlib_progress_func_t progress_func); +extern int +wimlib_extract_image(WIMStruct *wim, int image, + const wimlib_mbchar *target, + int extract_flags, + WIMStruct **additional_swms, + unsigned num_additional_swms, + wimlib_progress_func_t progress_func); /** * Extracts the XML data of a WIM file to a file stream. Every WIM file @@ -1246,7 +1261,8 @@ extern int wimlib_extract_image(WIMStruct *wim, int image, * @retval ::WIMLIB_ERR_INVALID_PARAM * @a wim is not a ::WIMStruct that was created by wimlib_open_wim(). */ -extern int wimlib_extract_xml_data(WIMStruct *wim, FILE *fp); +extern int +wimlib_extract_xml_data(WIMStruct *wim, FILE *fp); /** * Frees all memory allocated for a WIMStruct and closes all files associated @@ -1257,7 +1273,8 @@ extern int wimlib_extract_xml_data(WIMStruct *wim, FILE *fp); * * @return This function has no return value. */ -extern void wimlib_free(WIMStruct *wim); +extern void +wimlib_free(WIMStruct *wim); /** * Returns the index of the bootable image of the WIM. @@ -1269,7 +1286,8 @@ extern void wimlib_free(WIMStruct *wim); * 0 if no image is marked as bootable, or the number of the image marked * as bootable (numbered starting at 1). */ -extern int wimlib_get_boot_idx(const WIMStruct *wim); +extern int +wimlib_get_boot_idx(const WIMStruct *wim); /** * Returns the compression type used in the WIM. @@ -1281,7 +1299,8 @@ extern int wimlib_get_boot_idx(const WIMStruct *wim); * ::WIMLIB_COMPRESSION_TYPE_NONE, ::WIMLIB_COMPRESSION_TYPE_LZX, or * ::WIMLIB_COMPRESSION_TYPE_XPRESS. */ -extern int wimlib_get_compression_type(const WIMStruct *wim); +extern int +wimlib_get_compression_type(const WIMStruct *wim); /** * Converts a ::wimlib_compression_type value into a string. @@ -1294,7 +1313,8 @@ extern int wimlib_get_compression_type(const WIMStruct *wim); * A statically allocated string: "None", "LZX", "XPRESS", or "Invalid", * respectively. */ -extern const char *wimlib_get_compression_type_string(int ctype); +extern const wimlib_mbchar * +wimlib_get_compression_type_string(int ctype); /** * Converts an error code into a string describing it. @@ -1306,7 +1326,8 @@ extern const char *wimlib_get_compression_type_string(int ctype); * Pointer to a statically allocated string describing the error code, * or @c NULL if the error code is not valid. */ -extern const char *wimlib_get_error_string(enum wimlib_error_code code); +extern const wimlib_mbchar * +wimlib_get_error_string(enum wimlib_error_code code); /** * Returns the description of the specified image. @@ -1324,7 +1345,8 @@ extern const char *wimlib_get_error_string(enum wimlib_error_code code); * in addition, the string will become invalid if the description of the * image is changed, the image is deleted, or the ::WIMStruct is destroyed. */ -extern const char *wimlib_get_image_description(const WIMStruct *wim, int image); +extern const wimlib_utf8char * +wimlib_get_image_description(const WIMStruct *wim, int image); /** * Returns the name of the specified image. @@ -1345,7 +1367,8 @@ extern const char *wimlib_get_image_description(const WIMStruct *wim, int image) * the WIM to be unnamed, in which case an empty string will be returned * when the corresponding name is requested. */ -extern const char *wimlib_get_image_name(const WIMStruct *wim, int image); +extern const wimlib_utf8char * +wimlib_get_image_name(const WIMStruct *wim, int image); /** @@ -1358,7 +1381,8 @@ extern const char *wimlib_get_image_name(const WIMStruct *wim, int image); * @return * The number of images contained in the WIM file. */ -extern int wimlib_get_num_images(const WIMStruct *wim); +extern int +wimlib_get_num_images(const WIMStruct *wim); /** * Returns the part number of a WIM in a split WIM and the total number of parts @@ -1373,7 +1397,8 @@ extern int wimlib_get_num_images(const WIMStruct *wim); * @return * The part number of the WIM (1 for non-split WIMs) */ -extern int wimlib_get_part_number(const WIMStruct *wim, int *total_parts_ret); +extern int +wimlib_get_part_number(const WIMStruct *wim, int *total_parts_ret); /** * Since wimlib 1.2.6: Initialization function for wimlib. This is not @@ -1394,14 +1419,16 @@ extern int wimlib_get_part_number(const WIMStruct *wim, int *total_parts_ret); * indicates that further calls into wimlib will probably fail when they try to * repeat the same initializations. */ -extern int wimlib_global_init(); +extern int +wimlib_global_init(); /** * Since wimlib 1.2.6: Cleanup function for wimlib. This is not re-entrant. * You are not required to call this function, but it will release any global * memory allocated by the library. */ -extern void wimlib_global_cleanup(); +extern void +wimlib_global_cleanup(); /** * Returns true if the WIM has an integrity table. @@ -1414,8 +1441,8 @@ extern void wimlib_global_cleanup(); * wimlib_open_wim(), @c false will be returned, even if wimlib_write() has * been called on @a wim with ::WIMLIB_WRITE_FLAG_CHECK_INTEGRITY set. */ -extern bool wimlib_has_integrity_table(const WIMStruct *wim); - +extern bool +wimlib_has_integrity_table(const WIMStruct *wim); /** * Determines if an image name is already used by some image in the WIM. @@ -1430,7 +1457,8 @@ extern bool wimlib_has_integrity_table(const WIMStruct *wim); * if there is no image named @a name in @a wim. If @a name is @c NULL or * the empty string, @c false is returned. */ -extern bool wimlib_image_name_in_use(const WIMStruct *wim, const char *name); +extern bool +wimlib_image_name_in_use(const WIMStruct *wim, const wimlib_utf8char *name); /** * Joins a split WIM into a stand-alone one-part WIM. @@ -1469,10 +1497,13 @@ extern bool wimlib_image_name_in_use(const WIMStruct *wim, const char *name); * Note: wimlib_export_image() can provide similar functionality to * wimlib_join(), since it is possible to export all images from a split WIM. */ -extern int wimlib_join(const char * const *swms, unsigned num_swms, - const char *output_path, int swm_open_flags, - int wim_write_flags, - wimlib_progress_func_t progress_func); +extern int +wimlib_join(const wimlib_mbchar * const *swms, + unsigned num_swms, + const wimlib_mbchar *output_path, + int swm_open_flags, + int wim_write_flags, + wimlib_progress_func_t progress_func); /** * Mounts an image in a WIM file on a directory read-only or read-write. @@ -1572,10 +1603,11 @@ extern int wimlib_join(const char * const *swms, unsigned num_swms, * The WIM is a split WIM and a read-write mount was requested. We only * support mounting a split WIM read-only. */ -extern int wimlib_mount_image(WIMStruct *wim, int image, const char *dir, - int mount_flags, WIMStruct **additional_swms, - unsigned num_additional_swms, - const char *staging_dir); +extern int +wimlib_mount_image(WIMStruct *wim, int image, const wimlib_mbchar *dir, + int mount_flags, WIMStruct **additional_swms, + unsigned num_additional_swms, + const wimlib_mbchar *staging_dir); /** * Opens a WIM file and creates a ::WIMStruct for it. @@ -1655,9 +1687,9 @@ extern int wimlib_mount_image(WIMStruct *wim, int image, const char *dir, * @retval ::WIMLIB_ERR_XML * The XML data for @a wim_file is invalid. */ -extern int wimlib_open_wim(const char *wim_file, int open_flags, - WIMStruct **wim_ret, - wimlib_progress_func_t progress_func); +extern int +wimlib_open_wim(const wimlib_mbchar *wim_file, int open_flags, + WIMStruct **wim_ret, wimlib_progress_func_t progress_func); /** * Overwrites the file that the WIM was originally read from, with changes made. @@ -1730,9 +1762,9 @@ extern int wimlib_open_wim(const char *wim_file, int open_flags, * accessed, so this limits the functions that can be called on @a wim * before calling wimlib_free(). */ -extern int wimlib_overwrite(WIMStruct *wim, int write_flags, - unsigned num_threads, - wimlib_progress_func_t progress_func); +extern int +wimlib_overwrite(WIMStruct *wim, int write_flags, unsigned num_threads, + wimlib_progress_func_t progress_func); /** * Prints information about one image, or all images, contained in a WIM. @@ -1748,7 +1780,8 @@ extern int wimlib_overwrite(WIMStruct *wim, int write_flags, * printing the information. If @a image is invalid, an error message is * printed. */ -extern void wimlib_print_available_images(const WIMStruct *wim, int image); +extern void +wimlib_print_available_images(const WIMStruct *wim, int image); /** * Prints the full paths to all files contained in an image, or all images, in a @@ -1783,7 +1816,8 @@ extern void wimlib_print_available_images(const WIMStruct *wim, int image); * @a wim was not a standalone WIM and was not the first part of a split * WIM. */ -extern int wimlib_print_files(WIMStruct *wim, int image); +extern int +wimlib_print_files(WIMStruct *wim, int image); /** * Prints detailed information from the header of a WIM file. @@ -1795,7 +1829,8 @@ extern int wimlib_print_files(WIMStruct *wim, int image); * @return This function has no return value. * */ -extern void wimlib_print_header(const WIMStruct *wim); +extern void +wimlib_print_header(const WIMStruct *wim); /** * Prints the lookup table of a WIM file. The lookup table maps SHA1 message @@ -1809,7 +1844,8 @@ extern void wimlib_print_header(const WIMStruct *wim); * * @return This function has no return value. */ -extern void wimlib_print_lookup_table(WIMStruct *wim); +extern void +wimlib_print_lookup_table(WIMStruct *wim); /** * Prints the metadata of the specified image in a WIM file. The metadata @@ -1845,7 +1881,8 @@ extern void wimlib_print_lookup_table(WIMStruct *wim); * @a wim was not a standalone WIM and was not the first part of a split * WIM. */ -extern int wimlib_print_metadata(WIMStruct *wim, int image); +extern int +wimlib_print_metadata(WIMStruct *wim, int image); /** * Prints some basic information about a WIM file. All information printed by @@ -1858,7 +1895,8 @@ extern int wimlib_print_metadata(WIMStruct *wim, int image); * * @return This function has no return value. */ -extern void wimlib_print_wim_information(const WIMStruct *wim); +extern void +wimlib_print_wim_information(const WIMStruct *wim); /** * Translates a string specifying the name or number of an image in the WIM into @@ -1886,7 +1924,9 @@ extern void wimlib_print_wim_information(const WIMStruct *wim); * the empty string, ::WIMLIB_NO_IMAGE is returned, even if one or more * images in @a wim has no name. */ -extern int wimlib_resolve_image(WIMStruct *wim, const char *image_name_or_num); +extern int +wimlib_resolve_image(WIMStruct *wim, + const wimlib_utf8char *image_name_or_num); /** * Sets which image in the WIM is marked as bootable. @@ -1904,7 +1944,8 @@ extern int wimlib_resolve_image(WIMStruct *wim, const char *image_name_or_num); * @a wim is part of a split WIM. We do not support changing the boot * index of a split WIM. */ -extern int wimlib_set_boot_idx(WIMStruct *wim, int boot_idx); +extern int +wimlib_set_boot_idx(WIMStruct *wim, int boot_idx); /** * Changes the description of an image in the WIM. @@ -1926,8 +1967,9 @@ extern int wimlib_set_boot_idx(WIMStruct *wim, int boot_idx); * Failed to allocate the memory needed to duplicate the @a description * string. */ -extern int wimlib_set_image_descripton(WIMStruct *wim, int image, - const char *description); +extern int +wimlib_set_image_descripton(WIMStruct *wim, int image, + const wimlib_utf8char *description); /** * Changes what is written in the \ element in the WIM XML data @@ -1949,7 +1991,8 @@ extern int wimlib_set_image_descripton(WIMStruct *wim, int image, * @retval ::WIMLIB_ERR_NOMEM * Failed to allocate the memory needed to duplicate the @a flags string. */ -extern int wimlib_set_image_flags(WIMStruct *wim, int image, const char *flags); +extern int wimlib_set_image_flags(WIMStruct *wim, int image, + const wimlib_utf8char *flags); /** * Changes the name of an image in the WIM. @@ -1973,7 +2016,8 @@ extern int wimlib_set_image_flags(WIMStruct *wim, int image, const char *flags); * @retval ::WIMLIB_ERR_NOMEM * Failed to allocate the memory needed to duplicate the @a name string. */ -extern int wimlib_set_image_name(WIMStruct *wim, int image, const char *name); +extern int wimlib_set_image_name(WIMStruct *wim, int image, + const wimlib_utf8char *name); /** * Set the functions that wimlib uses to allocate and free memory. @@ -2003,9 +2047,10 @@ extern int wimlib_set_image_name(WIMStruct *wim, int image, const char *name); * wimlib was compiled with the @c --without-custom-memory-allocator flag, * so custom memory allocators are unsupported. */ -int wimlib_set_memory_allocator(void *(*malloc_func)(size_t), - void (*free_func)(void *), - void *(*realloc_func)(void *, size_t)); +extern int +wimlib_set_memory_allocator(void *(*malloc_func)(size_t), + void (*free_func)(void *), + void *(*realloc_func)(void *, size_t)); /** * Sets whether wimlib is to print error messages to @c stderr when a function @@ -2027,7 +2072,8 @@ int wimlib_set_memory_allocator(void *(*malloc_func)(size_t), * --without-error-messages option. Therefore, error messages cannot be * shown. */ -extern int wimlib_set_print_errors(bool show_messages); +extern int +wimlib_set_print_errors(bool show_messages); /** * Splits a WIM into multiple parts. @@ -2063,9 +2109,10 @@ extern int wimlib_set_print_errors(bool show_messages); * when they are copied from the joined WIM to the split WIM parts, nor are * compressed resources re-compressed. */ -extern int wimlib_split(WIMStruct *wim, const char *swm_name, - size_t part_size, int write_flags, - wimlib_progress_func_t progress_func); +extern int +wimlib_split(WIMStruct *wim, const wimlib_mbchar *swm_name, + size_t part_size, int write_flags, + wimlib_progress_func_t progress_func); /** * Unmounts a WIM image that was mounted using wimlib_mount_image(). @@ -2124,8 +2171,9 @@ extern int wimlib_split(WIMStruct *wim, const char *swm_name, * WIM file, or the filesystem daemon was unable to flush changes that had * been made to files in the staging directory. */ -extern int wimlib_unmount_image(const char *dir, int unmount_flags, - wimlib_progress_func_t progress_func); +extern int +wimlib_unmount_image(const wimlib_mbchar *dir, int unmount_flags, + wimlib_progress_func_t progress_func); /** * Writes a standalone WIM to a file. @@ -2195,8 +2243,9 @@ extern int wimlib_unmount_image(const char *dir, int unmount_flags, * An error occurred when trying to write data to the new WIM file at @a * path. */ -extern int wimlib_write(WIMStruct *wim, const char *path, int image, - int write_flags, unsigned num_threads, - wimlib_progress_func_t progress_func); +extern int +wimlib_write(WIMStruct *wim, const wimlib_mbchar *path, int image, + int write_flags, unsigned num_threads, + wimlib_progress_func_t progress_func); #endif /* _WIMLIB_H */ diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 554d3cc4..580960fa 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -281,13 +281,13 @@ struct WIMStruct { FILE *out_fp; /* The name of the WIM file (if any) that has been opened. */ - char *filename; + mbchar *filename; /* The lookup table for the WIM file. */ struct wim_lookup_table *lookup_table; - /* Pointer to the XML data read from the WIM file. */ - u8 *xml_data; + /* Pointer to the XML data read from the WIM file (UTF16LE-encoded). */ + utf16lechar *xml_data; /* Information retrieved from the XML data, arranged in an orderly * manner. */ @@ -321,7 +321,8 @@ struct WIMStruct { /* Inline utility functions for WIMStructs. */ -static inline struct wim_dentry *wim_root_dentry(WIMStruct *w) +static inline struct wim_dentry * +wim_root_dentry(WIMStruct *w) { return w->image_metadata[w->current_image - 1].root_dentry; } @@ -344,7 +345,8 @@ wim_get_current_image_metadata(WIMStruct *w) } /* Nonzero if a struct resource_entry indicates a compressed resource. */ -static inline int resource_is_compressed(const struct resource_entry *entry) +static inline int +resource_is_compressed(const struct resource_entry *entry) { return (entry->flags & WIM_RESHDR_FLAG_COMPRESSED); } @@ -352,7 +354,7 @@ static inline int resource_is_compressed(const struct resource_entry *entry) /* add_image.c */ struct pattern_list { - const char **pats; + const mbchar **pats; size_t num_pats; size_t num_allocated_pats; }; @@ -362,15 +364,66 @@ struct capture_config { struct pattern_list exclusion_exception; struct pattern_list compression_exclusion_list; struct pattern_list alignment_list; - char *config_str; - char *prefix; + mbchar *config_str; + mbchar *prefix; size_t prefix_len; }; -extern bool exclude_path(const char *path, - const struct capture_config *config, - bool exclude_prefix); -extern int add_new_dentry_tree(WIMStruct *dest_wim, struct wim_dentry *root, - struct wim_security_data *sd); +extern bool +exclude_path(const mbchar *path, const struct capture_config *config, + bool exclude_prefix); + +extern int +add_new_dentry_tree(WIMStruct *dest_wim, struct wim_dentry *root, + struct wim_security_data *sd); + +/* encoding.c */ + +#if defined(WITH_NTFS_3G) || defined(__WIN32__) + +static inline int +iconv_global_init() +{ + return 0; +} + +static inline void +iconv_global_cleanup() { } +#else +extern int +iconv_global_init(); + +extern void +iconv_global_cleanup(); +#endif + +extern bool wimlib_mbs_is_utf8; + +extern bool +utf8_str_contains_nonascii_chars(const utf8char *utf8_str); + +extern int +mbs_to_utf16le_nbytes(const mbchar *mbs, size_t mbs_nbytes, + size_t *utf16le_nbytes_ret); + +extern int +utf16le_to_mbs_nbytes(const utf16lechar *utf16le_str, + size_t utf16le_nbytes, size_t *mbs_nbytes_ret); + +extern int +mbs_to_utf16le_buf(const mbchar *mbs, size_t mbs_nbytes, + utf16lechar *utf16le_str); + +extern int +utf16le_to_mbs_buf(const utf16lechar *utf16le_str, size_t utf16le_nbytes, + mbchar *mbs); + +extern int +mbs_to_utf16le(const mbchar *mbs, size_t mbs_nbytes, + utf16lechar **utf16le_str_ret, size_t *utf16le_nbytes_ret); + +extern int +utf16le_to_mbs(const utf16lechar *utf16le_str, size_t utf16le_nbytes, + mbchar **mbs_ret, size_t *mbs_nbytes_ret); /* extract_image.c */ @@ -381,15 +434,22 @@ extern int add_new_dentry_tree(WIMStruct *dest_wim, struct wim_dentry *root, /* hardlink.c */ -extern u64 assign_inode_numbers(struct hlist_head *inode_list); +extern u64 +assign_inode_numbers(struct hlist_head *inode_list); -extern int dentry_tree_fix_inodes(struct wim_dentry *root, - struct hlist_head *inode_list); +extern int +dentry_tree_fix_inodes(struct wim_dentry *root, struct hlist_head *inode_list); /* header.c */ -extern int read_header(FILE *fp, struct wim_header *hdr, int split_ok); -extern int write_header(const struct wim_header *hdr, FILE *out); -extern int init_header(struct wim_header *hdr, int ctype); + +extern int +read_header(FILE *fp, struct wim_header *hdr, int split_ok); + +extern int +write_header(const struct wim_header *hdr, FILE *out); + +extern int +init_header(struct wim_header *hdr, int ctype); /* integrity.c */ @@ -397,33 +457,36 @@ extern int init_header(struct wim_header *hdr, int ctype); #define WIM_INTEGRITY_NOT_OK -1 #define WIM_INTEGRITY_NONEXISTENT -2 -extern int write_integrity_table(FILE *out, - struct resource_entry *integrity_res_entry, - off_t new_lookup_table_end, - off_t old_lookup_table_end, - wimlib_progress_func_t progress_func); +extern int +write_integrity_table(FILE *out, struct resource_entry *integrity_res_entry, + off_t new_lookup_table_end, + off_t old_lookup_table_end, + wimlib_progress_func_t progress_func); -extern int check_wim_integrity(WIMStruct *w, - wimlib_progress_func_t progress_func); +extern int +check_wim_integrity(WIMStruct *w, wimlib_progress_func_t progress_func); /* join.c */ -extern int new_joined_lookup_table(WIMStruct *w, - WIMStruct **additional_swms, - unsigned num_additional_swms, - struct wim_lookup_table **table_ret); +extern int +new_joined_lookup_table(WIMStruct *w, WIMStruct **additional_swms, + unsigned num_additional_swms, + struct wim_lookup_table **table_ret); /* metadata_resource.c */ -extern int read_metadata_resource(WIMStruct *w, +extern int +read_metadata_resource(WIMStruct *w, struct wim_image_metadata *image_metadata); -extern int write_metadata_resource(WIMStruct *w); + +extern int +write_metadata_resource(WIMStruct *w); /* ntfs-apply.c */ struct apply_args { WIMStruct *w; - const char *target; + const mbchar *target; int extract_flags; unsigned num_utime_warnings; struct list_head *stream_list; @@ -435,18 +498,22 @@ struct apply_args { int (*apply_dentry)(struct wim_dentry *, void *); }; -extern int apply_dentry_ntfs(struct wim_dentry *dentry, void *arg); -extern int apply_dentry_timestamps_ntfs(struct wim_dentry *dentry, void *arg); +extern int +apply_dentry_ntfs(struct wim_dentry *dentry, void *arg); + +extern int +apply_dentry_timestamps_ntfs(struct wim_dentry *dentry, void *arg); /* ntfs-capture.c */ -extern int build_dentry_tree_ntfs(struct wim_dentry **root_p, - const char *device, - struct wim_lookup_table *lookup_table, - struct wim_security_data *sd, - const struct capture_config *config, - int add_image_flags, - wimlib_progress_func_t progress_func, - void *extra_arg); +extern int +build_dentry_tree_ntfs(struct wim_dentry **root_p, + const mbchar *device, + struct wim_lookup_table *lookup_table, + struct wim_security_data *sd, + const struct capture_config *config, + int add_image_flags, + wimlib_progress_func_t progress_func, + void *extra_arg); /* resource.c */ @@ -454,31 +521,38 @@ extern int build_dentry_tree_ntfs(struct wim_dentry **root_p, #define WIMLIB_RESOURCE_FLAG_MULTITHREADED 0x2 #define WIMLIB_RESOURCE_FLAG_RECOMPRESS 0x4 -extern const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry); -extern u8 *put_resource_entry(u8 *p, const struct resource_entry *entry); +extern const u8 * +get_resource_entry(const u8 *p, struct resource_entry *entry); + +extern u8 * +put_resource_entry(u8 *p, const struct resource_entry *entry); -extern int read_uncompressed_resource(FILE *fp, u64 offset, u64 size, u8 buf[]); +extern int +read_uncompressed_resource(FILE *fp, u64 offset, u64 size, void *buf); -extern int read_wim_resource(const struct wim_lookup_table_entry *lte, u8 buf[], - size_t size, u64 offset, int flags); +extern int +read_wim_resource(const struct wim_lookup_table_entry *lte, void *buf, + size_t size, u64 offset, int flags); -extern int read_full_wim_resource(const struct wim_lookup_table_entry *lte, - u8 buf[], int flags); +extern int +read_full_wim_resource(const struct wim_lookup_table_entry *lte, + void *buf, int flags); -extern int write_wim_resource(struct wim_lookup_table_entry *lte, - FILE *out_fp, int out_ctype, - struct resource_entry *out_res_entry, - int flags); +extern int +write_wim_resource(struct wim_lookup_table_entry *lte, FILE *out_fp, + int out_ctype, struct resource_entry *out_res_entry, + int flags); -typedef int (*extract_chunk_func_t)(const u8 *, size_t, u64, void *); +typedef int (*extract_chunk_func_t)(const void *, size_t, u64, void *); -extern int extract_wim_chunk_to_fd(const u8 *buf, size_t len, - u64 offset, void *arg); +extern int +extract_wim_chunk_to_fd(const void *buf, size_t len, u64 offset, void *arg); -extern int extract_wim_resource(const struct wim_lookup_table_entry *lte, - u64 size, extract_chunk_func_t extract_chunk, - void *extract_chunk_arg); +extern int +extract_wim_resource(const struct wim_lookup_table_entry *lte, + u64 size, extract_chunk_func_t extract_chunk, + void *extract_chunk_arg); /* * Extracts the first @size bytes of the WIM resource specified by @lte to the @@ -495,38 +569,59 @@ extract_wim_resource_to_fd(const struct wim_lookup_table_entry *lte, } -extern int write_dentry_resources(struct wim_dentry *dentry, void *wim_p); -extern int copy_resource(struct wim_lookup_table_entry *lte, void *w); +extern int +write_dentry_resources(struct wim_dentry *dentry, void *wim_p); + +extern int +copy_resource(struct wim_lookup_table_entry *lte, void *w); /* security.c */ -extern int read_security_data(const u8 metadata_resource[], - u64 metadata_resource_len, - struct wim_security_data **sd_p); -extern void print_security_data(const struct wim_security_data *sd); -extern u8 *write_security_data(const struct wim_security_data *sd, u8 *p); -extern void free_security_data(struct wim_security_data *sd); +extern int +read_security_data(const u8 metadata_resource[], + u64 metadata_resource_len, struct wim_security_data **sd_p); +extern void +print_security_data(const struct wim_security_data *sd); + +extern u8 * +write_security_data(const struct wim_security_data *sd, u8 *p); + +extern void +free_security_data(struct wim_security_data *sd); /* symlink.c */ -ssize_t inode_readlink(const struct wim_inode *inode, char *buf, size_t buf_len, - const WIMStruct *w, int read_resource_flags); -extern int inode_set_symlink(struct wim_inode *inode, - const char *target, - struct wim_lookup_table *lookup_table, - struct wim_lookup_table_entry **lte_ret); +ssize_t +inode_readlink(const struct wim_inode *inode, char *buf, size_t buf_len, + const WIMStruct *w, int read_resource_flags); + +extern int +inode_set_symlink(struct wim_inode *inode, const mbchar *target, + struct wim_lookup_table *lookup_table, + struct wim_lookup_table_entry **lte_ret); /* verify.c */ -extern int verify_dentry(struct wim_dentry *dentry, void *wim); -extern int wim_run_full_verifications(WIMStruct *w); -extern int verify_swm_set(WIMStruct *w, - WIMStruct **additional_swms, - unsigned num_additional_swms); + +extern int +verify_dentry(struct wim_dentry *dentry, void *wim); + +extern int +wim_run_full_verifications(WIMStruct *w); + +extern int +verify_swm_set(WIMStruct *w, + WIMStruct **additional_swms, unsigned num_additional_swms); /* wim.c */ -extern int select_wim_image(WIMStruct *w, int image); -extern int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *)); -extern void destroy_image_metadata(struct wim_image_metadata *imd, - struct wim_lookup_table *lt); + +extern int +select_wim_image(WIMStruct *w, int image); + +extern int +for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *)); + +extern void +destroy_image_metadata(struct wim_image_metadata *imd, + struct wim_lookup_table *lt); /* write.c */ @@ -540,16 +635,22 @@ extern void destroy_image_metadata(struct wim_image_metadata *imd, #define WIMLIB_ADD_IMAGE_FLAG_SOURCE 0x40000000 -extern int begin_write(WIMStruct *w, const char *path, int write_flags); -extern void close_wim_writable(WIMStruct *w); +extern int +begin_write(WIMStruct *w, const mbchar *path, int write_flags); -extern int finish_write(WIMStruct *w, int image, int write_flags, - wimlib_progress_func_t progress_func); +extern void +close_wim_writable(WIMStruct *w); + +extern int +finish_write(WIMStruct *w, int image, int write_flags, + wimlib_progress_func_t progress_func); #if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK) -extern int lock_wim(WIMStruct *w, FILE *fp); +extern int +lock_wim(WIMStruct *w, FILE *fp); #else -static inline int lock_wim(WIMStruct *w, FILE *fp) +static inline int +lock_wim(WIMStruct *w, FILE *fp) { return 0; } diff --git a/src/win32.c b/src/win32.c index 16bdf79c..97d0b44a 100644 --- a/src/win32.c +++ b/src/win32.c @@ -77,7 +77,7 @@ void *win32_open_file_readonly(const void *path) } int win32_read_file(const char *filename, - void *handle, u64 offset, size_t size, u8 *buf) + void *handle, u64 offset, size_t size, void *buf) { HANDLE h = handle; DWORD err; @@ -1205,7 +1205,8 @@ unsigned win32_get_number_of_processors() /* Replacement for POSIX-2008 realpath(). Warning: partial functionality only * (resolved_path must be NULL). Also I highly doubt that GetFullPathName * really does the right thing under all circumstances. */ -char *realpath(const char *path, char *resolved_path) +mbchar * +realpath(const mbchar *path, mbchar *resolved_path) { DWORD ret; wimlib_assert(resolved_path == NULL); diff --git a/src/win32.h b/src/win32.h index 5f4ff567..18513be1 100644 --- a/src/win32.h +++ b/src/win32.h @@ -11,7 +11,7 @@ extern void win32_release_restore_privileges(); extern void win32_acquire_restore_privileges(); extern int win32_build_dentry_tree(struct wim_dentry **root_ret, - const char *root_disk_path, + const mbchar *root_disk_path, struct wim_lookup_table *lookup_table, struct wim_security_data *sd, const struct capture_config *config, @@ -19,8 +19,8 @@ extern int win32_build_dentry_tree(struct wim_dentry **root_ret, wimlib_progress_func_t progress_func, void *extra_arg); -extern int win32_read_file(const char *filename, void *handle, u64 offset, - size_t size, u8 *buf); +extern int win32_read_file(const mbchar *filename, void *handle, u64 offset, + size_t size, void *buf); extern void *win32_open_file_readonly(const void *path_utf16); extern void win32_close_file(void *handle); @@ -32,14 +32,14 @@ extern void win32_error(u32 err); #define FNM_PATHNAME 0x1 #define FNM_NOMATCH 1 -extern int fnmatch(const char *pattern, const char *string, int flags); +extern int fnmatch(const mbchar *pattern, const mbchar *string, int flags); -extern int win32_do_apply_dentry(const char *output_path, +extern int win32_do_apply_dentry(const mbchar *output_path, size_t output_path_len, struct wim_dentry *dentry, struct apply_args *args); -extern int win32_do_apply_dentry_timestamps(const char *output_path, +extern int win32_do_apply_dentry_timestamps(const mbchar *output_path, size_t output_path_len, const struct wim_dentry *dentry, const struct apply_args *args); @@ -48,7 +48,7 @@ extern int fsync(int fd); extern unsigned win32_get_number_of_processors(); -extern char *realpath(const char *path, char *resolved_path); +extern mbchar *realpath(const mbchar *path, mbchar *resolved_path); /* Microsoft's swprintf() violates the C standard and they require programmers * to do this weird define to get the correct function. */ diff --git a/src/xml.c b/src/xml.c index 2ac8cea8..6515ee98 100644 --- a/src/xml.c +++ b/src/xml.c @@ -48,19 +48,19 @@ struct windows_version { }; struct windows_info { - u64 arch; - char *product_name; - char *edition_id; - char *installation_type; - char *hal; - char *product_type; - char *product_suite; - char **languages; - char *default_language; - size_t num_languages; - char *system_root; - bool windows_version_exists; - struct windows_version windows_version; + u64 arch; + utf8char *product_name; + utf8char *edition_id; + utf8char *installation_type; + utf8char *hal; + utf8char *product_type; + utf8char *product_suite; + utf8char **languages; + utf8char *default_language; + size_t num_languages; + utf8char *system_root; + bool windows_version_exists; + struct windows_version windows_version; }; struct image_info { @@ -73,12 +73,12 @@ struct image_info { u64 creation_time; u64 last_modification_time; struct windows_info windows_info; - char *name; - char *description; - char *display_name; - char *display_description; + utf8char *name; + utf8char *description; + utf8char *display_name; + utf8char *display_description; union { - char *flags; + utf8char *flags; struct wim_lookup_table *lookup_table; }; }; @@ -86,9 +86,9 @@ struct image_info { /* Returns a statically allocated string that is a string representation of the * architecture number. */ -static const char *get_arch(int arch) +static const char * +get_arch(int arch) { - static char buf[20]; switch (arch) { case 0: return "x86"; @@ -98,8 +98,7 @@ static const char *get_arch(int arch) return "x86_64"; /* XXX Are there other arch values? */ default: - snprintf(buf, sizeof(buf), "%d (unknown)", arch); - return buf; + return NULL; } } @@ -109,17 +108,20 @@ static const char *get_arch(int arch) for (child = parent->children; child != NULL; child = child->next) /* Utility functions for xmlNodes */ -static inline bool node_is_element(xmlNode *node) +static inline bool +node_is_element(xmlNode *node) { return node->type == XML_ELEMENT_NODE; } -static inline bool node_is_text(xmlNode *node) +static inline bool +node_is_text(xmlNode *node) { return node->type == XML_TEXT_NODE; } -static inline bool node_name_is(xmlNode *node, const char *name) +static inline bool +node_name_is(xmlNode *node, const utf8char *name) { /* For now, both upper case and lower case element names are accepted. */ return strcasecmp((const char *)node->name, name) == 0; @@ -128,7 +130,8 @@ static inline bool node_name_is(xmlNode *node, const char *name) /* 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) +static u64 +node_get_u64(const xmlNode *u64_node) { xmlNode *child; for_node_child(u64_node, child) @@ -138,7 +141,8 @@ static u64 node_get_u64(const xmlNode *u64_node) } /* Like node_get_u64(), but expects a number in base 16. */ -static u64 node_get_hex_u64(const xmlNode *u64_node) +static u64 +node_get_hex_u64(const xmlNode *u64_node) { xmlNode *child; for_node_child(u64_node, child) @@ -147,7 +151,8 @@ static u64 node_get_hex_u64(const xmlNode *u64_node) return 0; } -static int node_get_string(const xmlNode *string_node, char **str) +static int +node_get_string(const xmlNode *string_node, utf8char **str) { xmlNode *child; char *p = NULL; @@ -166,7 +171,8 @@ static int node_get_string(const xmlNode *string_node, char **str) /* Returns the timestamp from a time node. It has child elements and * that are then used to construct a 64-bit timestamp. */ -static u64 node_get_timestamp(const xmlNode *time_node) +static u64 +node_get_timestamp(const xmlNode *time_node) { u32 high_part = 0; u32 low_part = 0; @@ -183,7 +189,8 @@ static u64 node_get_timestamp(const xmlNode *time_node) } /* Used to sort an array of struct image_infos by their image indices. */ -static int sort_by_index(const void *p1, const void *p2) +static int +sort_by_index(const void *p1, const void *p2) { int index_1 = ((const struct image_info*)p1)->index; int index_2 = ((const struct image_info*)p2)->index; @@ -197,7 +204,8 @@ static int sort_by_index(const void *p1, const void *p2) /* Frees memory allocated inside a struct windows_info structure. */ -static void destroy_windows_info(struct windows_info *windows_info) +static void +destroy_windows_info(struct windows_info *windows_info) { FREE(windows_info->product_name); FREE(windows_info->edition_id); @@ -213,7 +221,8 @@ static void destroy_windows_info(struct windows_info *windows_info) } /* Frees memory allocated inside a struct image_info structure. */ -static void destroy_image_info(struct image_info *image_info) +static void +destroy_image_info(struct image_info *image_info) { FREE(image_info->name); FREE(image_info->description); @@ -224,7 +233,8 @@ static void destroy_image_info(struct image_info *image_info) memset(image_info, 0, sizeof(struct image_info)); } -void free_wim_info(struct wim_info *info) +void +free_wim_info(struct wim_info *info) { if (info) { if (info->images) { @@ -238,8 +248,9 @@ void free_wim_info(struct wim_info *info) /* Reads the information from a element inside the element. * */ -static void xml_read_windows_version(const xmlNode *version_node, - struct windows_version* windows_version) +static void +xml_read_windows_version(const xmlNode *version_node, + struct windows_version* windows_version) { xmlNode *child; for_node_child(version_node, child) { @@ -260,14 +271,15 @@ static void xml_read_windows_version(const xmlNode *version_node, /* Reads the information from a element inside a element. * */ -static int xml_read_languages(const xmlNode *languages_node, - char ***languages_ret, - size_t *num_languages_ret, - char **default_language_ret) +static int +xml_read_languages(const xmlNode *languages_node, + utf8char ***languages_ret, + size_t *num_languages_ret, + utf8char **default_language_ret) { xmlNode *child; size_t num_languages = 0; - char **languages; + utf8char **languages; int ret; for_node_child(languages_node, child) @@ -296,8 +308,9 @@ static int xml_read_languages(const xmlNode *languages_node, } /* Reads the information from a element inside an element. */ -static int xml_read_windows_info(const xmlNode *windows_node, - struct windows_info *windows_info) +static int +xml_read_windows_info(const xmlNode *windows_node, + struct windows_info *windows_info) { xmlNode *child; int ret = 0; @@ -343,8 +356,8 @@ static int xml_read_windows_info(const xmlNode *windows_node, } /* Reads the information from an element. */ -static int xml_read_image_info(xmlNode *image_node, - struct image_info *image_info) +static int +xml_read_image_info(xmlNode *image_node, struct image_info *image_info) { xmlNode *child; xmlChar *index_prop; @@ -394,7 +407,7 @@ static int xml_read_image_info(xmlNode *image_node, return ret; } if (!image_info->name) { - char *empty_name; + utf8char *empty_name; WARNING("Image with index %d has no name", image_info->index); empty_name = MALLOC(1); if (!empty_name) @@ -407,8 +420,8 @@ static int xml_read_image_info(xmlNode *image_node, /* Reads the information from a element, which should be the root element * of the XML tree. */ -static int xml_read_wim_info(const xmlNode *wim_node, - struct wim_info **wim_info_ret) +static int +xml_read_wim_info(const xmlNode *wim_node, struct wim_info **wim_info_ret) { struct wim_info *wim_info; xmlNode *child; @@ -477,49 +490,54 @@ err: return ret; } -/* Prints the information contained in a `struct windows_info'. */ -static void print_windows_info(const struct windows_info *windows_info) +/* Prints the information contained in a `struct windows_info'. + * + * Warning: any strings printed here are in UTF-8 encoding. If the locale + * character encoding is not UTF-8, the printed strings may be garbled. */ +static void +print_windows_info(const struct windows_info *windows_info) { const struct windows_version *windows_version; - printf("Architecture: %s\n", get_arch(windows_info->arch)); + wimlib_printf("Architecture: %s\n", + get_arch(windows_info->arch) ?: "unknown"); if (windows_info->product_name) - printf("Product Name: %s\n", - windows_info->product_name); + wimlib_printf("Product Name: %U\n", + windows_info->product_name); if (windows_info->edition_id) - printf("Edition ID: %s\n", - windows_info->edition_id); + wimlib_printf("Edition ID: %U\n", + windows_info->edition_id); if (windows_info->installation_type) - printf("Installation Type: %s\n", - windows_info->installation_type); + wimlib_printf("Installation Type: %U\n", + windows_info->installation_type); if (windows_info->hal) - printf("HAL: %s\n", - windows_info->hal); + wimlib_printf("HAL: %U\n", + windows_info->hal); if (windows_info->product_type) - printf("Product Type: %s\n", - windows_info->product_type); + wimlib_printf("Product Type: %U\n", + windows_info->product_type); if (windows_info->product_suite) - printf("Product Suite: %s\n", - windows_info->product_suite); + wimlib_printf("Product Suite: %U\n", + windows_info->product_suite); printf("Languages: "); for (size_t i = 0; i < windows_info->num_languages; i++) { - fputs(windows_info->languages[i], stdout); + wimlib_printf("%U", windows_info->languages[i]); putchar(' '); } putchar('\n'); if (windows_info->default_language) - printf("Default Language: %s\n", + wimlib_printf("Default Language: %U\n", windows_info->default_language); if (windows_info->system_root) - printf("System Root: %s\n", - windows_info->system_root); + wimlib_printf("System Root: %U\n", + windows_info->system_root); if (windows_info->windows_version_exists) { windows_version = &windows_info->windows_version; printf("Major Version: %"PRIu64"\n", @@ -539,8 +557,9 @@ static void print_windows_info(const struct windows_info *windows_info) /* Writes the information contained in a `struct windows_version' to the XML * document being written. This is the element inside the * element. */ -static int xml_write_windows_version(xmlTextWriter *writer, - const struct windows_version *version) +static int +xml_write_windows_version(xmlTextWriter *writer, + const struct windows_version *version) { int rc; rc = xmlTextWriterStartElement(writer, "VERSION"); @@ -577,8 +596,9 @@ static int xml_write_windows_version(xmlTextWriter *writer, /* Writes the information contained in a `struct windows_info' to the XML * document being written. This is the element. */ -static int xml_write_windows_info(xmlTextWriter *writer, - const struct windows_info *windows_info) +static int +xml_write_windows_info(xmlTextWriter *writer, + const struct windows_info *windows_info) { int rc; rc = xmlTextWriterStartElement(writer, "WINDOWS"); @@ -670,8 +690,8 @@ static int xml_write_windows_info(xmlTextWriter *writer, } /* Writes a time element to the XML document being constructed in memory. */ -static int xml_write_time(xmlTextWriter *writer, const char *element_name, - u64 time) +static int +xml_write_time(xmlTextWriter *writer, const utf8char *element_name, u64 time) { int rc; rc = xmlTextWriterStartElement(writer, element_name); @@ -695,8 +715,8 @@ static int xml_write_time(xmlTextWriter *writer, const char *element_name, } /* Writes an element to the XML document. */ -static int xml_write_image_info(xmlTextWriter *writer, - const struct image_info *image_info) +static int +xml_write_image_info(xmlTextWriter *writer, const struct image_info *image_info) { int rc; rc = xmlTextWriterStartElement(writer, "IMAGE"); @@ -783,7 +803,8 @@ static int xml_write_image_info(xmlTextWriter *writer, /* Makes space for another image in the XML information and return a pointer to * it.*/ -static struct image_info *add_image_info_struct(struct wim_info *wim_info) +static struct image_info * +add_image_info_struct(struct wim_info *wim_info) { struct image_info *images; @@ -798,8 +819,8 @@ static struct image_info *add_image_info_struct(struct wim_info *wim_info) return &images[wim_info->num_images - 1]; } -static int clone_windows_info(const struct windows_info *old, - struct windows_info *new) +static int +clone_windows_info(const struct windows_info *old, struct windows_info *new) { if (old->product_name && !(new->product_name = STRDUP(old->product_name))) return WIMLIB_ERR_NOMEM; @@ -816,7 +837,7 @@ static int clone_windows_info(const struct windows_info *old, return WIMLIB_ERR_NOMEM; if (old->languages) { - new->languages = CALLOC(old->num_languages, sizeof(char*)); + new->languages = CALLOC(old->num_languages, sizeof(new->languages[0])); if (!new->languages) return WIMLIB_ERR_NOMEM; new->num_languages = old->num_languages; @@ -841,7 +862,8 @@ static int clone_windows_info(const struct windows_info *old, return 0; } -static int clone_image_info(const struct image_info *old, struct image_info *new) +static int +clone_image_info(const struct image_info *old, struct image_info *new) { new->dir_count = old->dir_count; new->file_count = old->file_count; @@ -886,11 +908,12 @@ static int clone_image_info(const struct image_info *old, struct image_info *new * On failure, WIMLIB_ERR_NOMEM is returned and no changes are made. Otherwise, * 0 is returned and the WIM information at *new_wim_info_p is modified. */ -int xml_export_image(const struct wim_info *old_wim_info, - int image, - struct wim_info **new_wim_info_p, - const char *dest_image_name, - const char *dest_image_description) +int +xml_export_image(const struct wim_info *old_wim_info, + int image, + struct wim_info **new_wim_info_p, + const utf8char *dest_image_name, + const utf8char *dest_image_description) { struct wim_info *new_wim_info; struct image_info *image_info; @@ -942,7 +965,8 @@ err: } /* Removes an image from the XML information. */ -void xml_delete_image(struct wim_info **wim_info_p, int image) +void +xml_delete_image(struct wim_info **wim_info_p, int image) { struct wim_info *wim_info; @@ -965,7 +989,8 @@ void xml_delete_image(struct wim_info **wim_info_p, int image) } } -size_t xml_get_max_image_name_len(const WIMStruct *w) +size_t +xml_get_max_image_name_len(const WIMStruct *w) { size_t max_len = 0; if (w->wim_info) { @@ -980,15 +1005,17 @@ size_t xml_get_max_image_name_len(const WIMStruct *w) } #ifdef ENABLE_CUSTOM_MEMORY_ALLOCATOR -void xml_set_memory_allocator(void *(*malloc_func)(size_t), - void (*free_func)(void *), - void *(*realloc_func)(void *, size_t)) +void +xml_set_memory_allocator(void *(*malloc_func)(size_t), + void (*free_func)(void *), + void *(*realloc_func)(void *, size_t)) { xmlMemSetup(free_func, malloc_func, realloc_func, STRDUP); } #endif -static int calculate_dentry_statistics(struct wim_dentry *dentry, void *arg) +static int +calculate_dentry_statistics(struct wim_dentry *dentry, void *arg) { struct image_info *info = arg; struct wim_lookup_table *lookup_table = info->lookup_table; @@ -1066,10 +1093,11 @@ static int calculate_dentry_statistics(struct wim_dentry *dentry, void *arg) * Please note there is no official documentation for exactly how this is done. * But, see calculate_dentry_statistics(). */ -void xml_update_image_info(WIMStruct *w, int image) +void +xml_update_image_info(WIMStruct *w, int image) { struct image_info *image_info; - char *flags_save; + utf8char *flags_save; DEBUG("Updating the image info for image %d", image); @@ -1090,7 +1118,8 @@ void xml_update_image_info(WIMStruct *w, int image) } /* Adds an image to the XML information. */ -int xml_add_image(WIMStruct *w, const char *name) +int +xml_add_image(WIMStruct *w, const utf8char *name) { struct wim_info *wim_info; struct image_info *image_info; @@ -1131,7 +1160,8 @@ out_free_wim_info: /* Prints information about the specified image from struct wim_info structure. * */ -void print_image_info(const struct wim_info *wim_info, int image) +void +print_image_info(const struct wim_info *wim_info, int image) { const struct image_info *image_info; const char *desc; @@ -1142,7 +1172,7 @@ void print_image_info(const struct wim_info *wim_info, int image) image_info = &wim_info->images[image - 1]; printf("Index: %d\n", image_info->index); - printf("Name: %s\n", image_info->name); + wimlib_printf("Name: %U\n", image_info->name); /* Always print the Description: part even if there is no * description. */ @@ -1150,15 +1180,15 @@ void print_image_info(const struct wim_info *wim_info, int image) desc = image_info->description; else desc = ""; - printf("Description: %s\n", desc); + wimlib_printf("Description: %U\n", desc); if (image_info->display_name) - printf("Display Name: %s\n", - image_info->display_name); + wimlib_printf("Display Name: %U\n", + image_info->display_name); if (image_info->display_description) - printf("Display Description: %s\n", - image_info->display_description); + wimlib_printf("Display Description: %U\n", + image_info->display_description); printf("Directory Count: %"PRIu64"\n", image_info->dir_count); printf("File Count: %"PRIu64"\n", image_info->file_count); @@ -1177,23 +1207,28 @@ void print_image_info(const struct wim_info *wim_info, int image) putchar('\n'); } -void libxml_global_init() +void +libxml_global_init() { xmlInitParser(); + xmlInitCharEncodingHandlers(); } -void libxml_global_cleanup() +void +libxml_global_cleanup() { xmlCleanupParser(); + xmlCleanupCharEncodingHandlers(); } /* * Reads the XML data from a WIM file. */ -int read_xml_data(FILE *fp, const struct resource_entry *res_entry, - u8 **xml_data_ret, struct wim_info **info_ret) +int +read_xml_data(FILE *fp, const struct resource_entry *res_entry, + utf16lechar **xml_data_ret, struct wim_info **info_ret) { - u8 *xml_data; + utf16lechar *xml_data; xmlDoc *doc; xmlNode *root; int ret; @@ -1213,7 +1248,7 @@ int read_xml_data(FILE *fp, const struct resource_entry *res_entry, goto out; } - xml_data = MALLOC(res_entry->size + 2); + xml_data = MALLOC(res_entry->size + 3); if (!xml_data) { ret = WIMLIB_ERR_NOMEM; goto out; @@ -1225,8 +1260,9 @@ int read_xml_data(FILE *fp, const struct resource_entry *res_entry, goto out_free_xml_data; /* Null-terminate just in case */ - xml_data[res_entry->size] = 0; - xml_data[res_entry->size + 1] = 0; + ((u8*)xml_data)[res_entry->size] = 0; + ((u8*)xml_data)[res_entry->size + 1] = 0; + ((u8*)xml_data)[res_entry->size + 2] = 0; DEBUG("Parsing XML using libxml2 to create XML tree"); @@ -1283,8 +1319,9 @@ out: * element in the XML data. If zero, TOTALBYTES is given the default value of * the offset of the XML data. */ -int write_xml_data(const struct wim_info *wim_info, int image, FILE *out, - u64 total_bytes, struct resource_entry *out_res_entry) +int +write_xml_data(const struct wim_info *wim_info, int image, FILE *out, + u64 total_bytes, struct resource_entry *out_res_entry) { xmlCharEncodingHandler *encoding_handler; xmlOutputBuffer *out_buffer; @@ -1324,21 +1361,19 @@ int write_xml_data(const struct wim_info *wim_info, int image, FILE *out, if (total_bytes == 0) total_bytes = start_offset; - xmlInitCharEncodingHandlers(); - /* The encoding of the XML data must be UTF-16LE. */ encoding_handler = xmlGetCharEncodingHandler(XML_CHAR_ENCODING_UTF16LE); if (!encoding_handler) { ERROR("Failed to get XML character encoding handler for UTF-16LE"); ret = WIMLIB_ERR_LIBXML_UTF16_HANDLER_NOT_AVAILABLE; - goto out_cleanup_char_encoding_handlers; + goto out; } out_buffer = xmlOutputBufferCreateFile(out, encoding_handler); if (!out_buffer) { ERROR("Failed to allocate xmlOutputBuffer"); ret = WIMLIB_ERR_NOMEM; - goto out_cleanup_char_encoding_handlers; + goto out; } writer = xmlNewTextWriter(out_buffer); @@ -1403,8 +1438,6 @@ out_free_text_writer: out_output_buffer_close: if (out_buffer != NULL) xmlOutputBufferClose(out_buffer); -out_cleanup_char_encoding_handlers: - xmlCleanupCharEncodingHandlers(); out: if (ret == 0) DEBUG("Successfully wrote XML data"); @@ -1412,7 +1445,8 @@ out: } /* Returns the name of the specified image. */ -WIMLIBAPI const char *wimlib_get_image_name(const WIMStruct *w, int image) +WIMLIBAPI const utf8char * +wimlib_get_image_name(const WIMStruct *w, int image) { if (image < 1 || image > w->hdr.image_count) return NULL; @@ -1420,8 +1454,8 @@ WIMLIBAPI const char *wimlib_get_image_name(const WIMStruct *w, int image) } /* Returns the description of the specified image. */ -WIMLIBAPI const char *wimlib_get_image_description(const WIMStruct *w, - int image) +WIMLIBAPI const utf8char * +wimlib_get_image_description(const WIMStruct *w, int image) { if (image < 1 || image > w->hdr.image_count) return NULL; @@ -1429,7 +1463,8 @@ WIMLIBAPI const char *wimlib_get_image_description(const WIMStruct *w, } /* Determines if an image name is already used by some image in the WIM. */ -WIMLIBAPI bool wimlib_image_name_in_use(const WIMStruct *w, const char *name) +WIMLIBAPI bool +wimlib_image_name_in_use(const WIMStruct *w, const utf8char *name) { if (!name || !*name) return false; @@ -1440,12 +1475,15 @@ WIMLIBAPI bool wimlib_image_name_in_use(const WIMStruct *w, const char *name) } /* Extracts the raw XML data to a file stream. */ -WIMLIBAPI int wimlib_extract_xml_data(WIMStruct *w, FILE *fp) +WIMLIBAPI int +wimlib_extract_xml_data(WIMStruct *w, FILE *fp) { + size_t bytes_written; + if (!w->xml_data) return WIMLIB_ERR_INVALID_PARAM; - if (fwrite(w->xml_data, 1, w->hdr.xml_res_entry.size, fp) != - w->hdr.xml_res_entry.size) { + bytes_written = fwrite(w->xml_data, 1, w->hdr.xml_res_entry.size, fp); + if (bytes_written != w->hdr.xml_res_entry.size) { ERROR_WITH_ERRNO("Failed to extract XML data"); return WIMLIB_ERR_WRITE; } @@ -1453,9 +1491,10 @@ WIMLIBAPI int wimlib_extract_xml_data(WIMStruct *w, FILE *fp) } /* Sets the name of an image in the WIM. */ -WIMLIBAPI int wimlib_set_image_name(WIMStruct *w, int image, const char *name) +WIMLIBAPI int +wimlib_set_image_name(WIMStruct *w, int image, const utf8char *name) { - char *p; + utf8char *p; int i; DEBUG("Setting the name of image %d to %s", image, name); @@ -1474,8 +1513,8 @@ WIMLIBAPI int wimlib_set_image_name(WIMStruct *w, int image, const char *name) if (i == image) continue; if (strcmp(w->wim_info->images[i - 1].name, name) == 0) { - ERROR("The name `%s' is already used for image %d", - name, i); + ERROR("The name `%U' is already in use in the WIM!", + name); return WIMLIB_ERR_IMAGE_NAME_COLLISION; } } @@ -1490,10 +1529,11 @@ WIMLIBAPI int wimlib_set_image_name(WIMStruct *w, int image, const char *name) } /* Sets the description of an image in the WIM. */ -WIMLIBAPI int wimlib_set_image_descripton(WIMStruct *w, int image, - const char *description) +WIMLIBAPI int +wimlib_set_image_descripton(WIMStruct *w, int image, + const utf8char *description) { - char *p; + utf8char *p; if (image < 1 || image > w->hdr.image_count) { ERROR("%d is not a valid image", image); @@ -1512,8 +1552,8 @@ WIMLIBAPI int wimlib_set_image_descripton(WIMStruct *w, int image, } /* Set the element of a WIM image */ -WIMLIBAPI int wimlib_set_image_flags(WIMStruct *w, int image, - const char *flags) +WIMLIBAPI int +wimlib_set_image_flags(WIMStruct *w, int image, const utf8char *flags) { char *p; diff --git a/src/xml.h b/src/xml.h index 54993cba..63566131 100644 --- a/src/xml.h +++ b/src/xml.h @@ -13,38 +13,53 @@ struct wim_info { }; /* xml.c */ -extern int xml_export_image(const struct wim_info *old_wim_info, int image, - struct wim_info **new_wim_info_p, - const char *dest_image_name, - const char *dest_image_description); +extern int +xml_export_image(const struct wim_info *old_wim_info, int image, + struct wim_info **new_wim_info_p, + const utf8char *dest_image_name, + const utf8char *dest_image_description); -extern size_t xml_get_max_image_name_len(const WIMStruct *w); +extern size_t +xml_get_max_image_name_len(const WIMStruct *w); -extern void xml_update_image_info(WIMStruct *w, int image); +extern void +xml_update_image_info(WIMStruct *w, int image); -extern void xml_delete_image(struct wim_info **wim_info_p, int image); +extern void +xml_delete_image(struct wim_info **wim_info_p, int image); -extern int xml_add_image(WIMStruct *w, const char *name); +extern int +xml_add_image(WIMStruct *w, const utf8char *name); -extern void free_wim_info(struct wim_info *info); +extern void +free_wim_info(struct wim_info *info); -extern void print_image_info(const struct wim_info *wim_info, int image); +extern void +print_image_info(const struct wim_info *wim_info, int image); -extern int read_xml_data(FILE *fp, const struct resource_entry *res, - u8 **xml_data_ret, struct wim_info **info_ret); +extern int +read_xml_data(FILE *fp, const struct resource_entry *res, + utf16lechar **xml_data_ret, + struct wim_info **info_ret); -extern int write_xml_data(const struct wim_info *wim_info, int image, FILE *out, - u64 total_bytes, struct resource_entry *out_res_entry); +extern int +write_xml_data(const struct wim_info *wim_info, int image, FILE *out, + u64 total_bytes, struct resource_entry *out_res_entry); -extern void libxml_global_init(); -extern void libxml_global_cleanup(); +extern void +libxml_global_init(); -static inline u64 wim_info_get_total_bytes(const struct wim_info *info) +extern void +libxml_global_cleanup(); + +static inline u64 +wim_info_get_total_bytes(const struct wim_info *info) { return info->total_bytes; } -static inline unsigned wim_info_get_num_images(const struct wim_info *info) +static inline unsigned +wim_info_get_num_images(const struct wim_info *info) { return info->num_images; } -- 2.43.0