From 16176f3b7ce78da85646e814bd2f3ffe5babb82b Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 20 Mar 2013 00:35:52 -0500 Subject: [PATCH] Character encoding changes (IN PROGRESS) --- src/add_image.c | 50 ++++--- src/buffer_io.h | 52 ++++--- src/dentry.c | 245 +++++++++++++++++++-------------- src/dentry.h | 37 +++-- src/encoding.c | 306 +++++++++++++++++++----------------------- src/lookup_table.c | 26 ++-- src/lookup_table.h | 6 +- src/mount_image.c | 16 ++- src/ntfs-apply.c | 157 ++++++++++++---------- src/ntfs-capture.c | 207 +++++++++++++--------------- src/resource.c | 2 +- src/symlink.c | 41 +++--- src/util.c | 17 +-- src/util.h | 34 +++++ src/verify.c | 31 +++-- src/wim.c | 98 +++++++++----- src/wimlib_internal.h | 51 +------ src/write.c | 224 ++++++++++++++++++------------- src/xml.c | 6 +- 19 files changed, 847 insertions(+), 759 deletions(-) diff --git a/src/add_image.c b/src/add_image.c index 4dce5bbb..0d410a16 100644 --- a/src/add_image.c +++ b/src/add_image.c @@ -214,16 +214,10 @@ unix_build_dentry_tree(struct wim_dentry **root_ret, goto out; } - root = new_dentry_with_timeless_inode(path_basename(root_disk_path)); - if (!root) { - if (errno == EILSEQ) - ret = WIMLIB_ERR_INVALID_UTF8_STRING; - else if (errno == ENOMEM) - ret = WIMLIB_ERR_NOMEM; - else - ret = WIMLIB_ERR_ICONV_NOT_AVAILABLE; + ret = new_dentry_with_timeless_inode(path_basename(root_disk_path), + &root); + if (ret) goto out; - } inode = root->d_inode; @@ -777,19 +771,21 @@ check_sorted_sources(struct wimlib_capture_source *sources, size_t num_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 mbchar *name) +static int +new_filler_directory(const mbchar *name, struct wim_dentry **dentry_ret) { + int ret; struct wim_dentry *dentry; + DEBUG("Creating filler directory \"%s\"", name); - dentry = new_dentry_with_inode(name); - if (dentry) { + ret = new_dentry_with_inode(name, &dentry); + if (ret == 0) { /* Leave the inode number as 0 for now. The final inode number * will be assigned later by assign_inode_numbers(). */ dentry->d_inode->i_resolved = 1; dentry->d_inode->i_attributes = FILE_ATTRIBUTE_DIRECTORY; } - return dentry; + return ret; } /* Transfers the children of @branch to @target. It is an error if @target is @@ -846,6 +842,7 @@ attach_branch(struct wim_dentry **root_p, struct wim_dentry *branch, { char *slash; struct wim_dentry *dentry, *parent, *target; + int ret; DEBUG("Attaching branch \"%W\" => \"%s\"", branch->file_name, target_path); @@ -865,9 +862,9 @@ attach_branch(struct wim_dentry **root_p, struct wim_dentry *branch, /* Adding a non-root branch. Create root if it hasn't been created * already. */ if (!*root_p) { - *root_p = new_filler_directory(""); - if (!*root_p) - return WIMLIB_ERR_NOMEM; + ret = new_filler_directory("", root_p); + if (ret) + return ret; } /* Walk the path to the branch, creating filler directories as needed. @@ -877,9 +874,9 @@ attach_branch(struct wim_dentry **root_p, struct wim_dentry *branch, *slash = '\0'; dentry = get_dentry_child_with_name(parent, target_path); if (!dentry) { - dentry = new_filler_directory(target_path); - if (!dentry) - return WIMLIB_ERR_NOMEM; + ret = new_filler_directory(target_path, &dentry); + if (ret) + return ret; dentry_add_child(parent, dentry); } parent = dentry; @@ -894,7 +891,8 @@ attach_branch(struct wim_dentry **root_p, struct wim_dentry *branch, /* If the target path already existed, overlay the branch onto it. * Otherwise, set the branch as the target path. */ - target = get_dentry_child_with_utf16le_name(parent, branch->file_name); + target = get_dentry_child_with_utf16le_name(parent, branch->file_name, + branch->file_name_nbytes); if (target) { return do_overlay(target, branch); } else { @@ -978,8 +976,8 @@ wimlib_add_image_multisource(WIMStruct *w, } if (wimlib_image_name_in_use(w, name)) { - ERROR("There is already an image named \"%s\" in `%s'", - name, w->filename); + ERROR("There is already an image named \"%U\" in the WIM!", + name); return WIMLIB_ERR_IMAGE_NAME_COLLISION; } @@ -1012,11 +1010,9 @@ wimlib_add_image_multisource(WIMStruct *w, DEBUG("Building dentry tree."); if (num_sources == 0) { - root_dentry = new_filler_directory(""); - if (!root_dentry) { - ret = WIMLIB_ERR_NOMEM; + ret = new_filler_directory("", &root_dentry); + if (ret) goto out_free_security_data; - } } else { size_t i; diff --git a/src/buffer_io.h b/src/buffer_io.h index 685ffa8a..9a38286c 100644 --- a/src/buffer_io.h +++ b/src/buffer_io.h @@ -20,38 +20,42 @@ * the output location, with the size indicated in the function name, in little * endian format. A pointer to the input location directly following the bytes * read is returned. */ -static inline const u8 *get_u8(const u8 *p, u8 *res) +static inline const void * +get_u8(const void *p, u8 *res) { - *res = *p; + *res = *(const u8*)p; return p + 1; } - -static inline const u8 *get_u16(const u8 *p, u16 *res) +static inline const void * +get_u16(const void *p, u16 *res) { - *res = le16_to_cpu(*(u16*)p); + *res = le16_to_cpu(*(const u16*)p); return p + 2; } -static inline const u8 *get_u32(const u8 *p, u32 *res) +static inline const void * +get_u32(const void *p, u32 *res) { - *res = le32_to_cpu(*(u32*)p); + *res = le32_to_cpu(*(const u32*)p); return p + 4; } -static inline const u8 *get_u56(const u8 *p, u64 *res) +static inline const void * +get_u56(const void *p, u64 *res) { - *res = le64_to_cpu(*(u64*)p) & 0x00ffffffffffffff; + *res = le64_to_cpu(*(const u64*)p) & 0x00ffffffffffffff; return p + 7; } -static inline const u8 *get_u64(const u8 *p, u64 *res) +static inline const void * +get_u64(const void *p, u64 *res) { - *res = le64_to_cpu(*(u64*)p); + *res = le64_to_cpu(*(const u64*)p); return p + 8; } @@ -61,25 +65,29 @@ static inline const u8 *get_u64(const u8 *p, u64 *res) * location in little-endian format as the data type indicated in the function * name, and a pointer to the output location directory following the bytes * written is returned. */ -static inline u8 *put_u8(u8 *res, u8 val) +static inline void * +put_u8(void *res, u8 val) { - *res = val; + *(u8*)res = val; return res + 1; } -static inline u8 *put_u16(u8 *res, u16 val) +static inline void * +put_u16(void *res, u16 val) { *(uint16_t*)res = cpu_to_le16(val); return res + 2; } -static inline u8 *put_u32(u8 *res, u32 val) +static inline void * +put_u32(void *res, u32 val) { *(uint32_t*)res = cpu_to_le32(val); return res + 4; } -static inline u8 *put_u56(u8 *res, u64 val) +static inline void * +put_u56(void *res, u64 val) { const u8 *__p = (const u8*)&val; #ifdef WORDS_BIGENDIAN @@ -96,24 +104,28 @@ static inline u8 *put_u56(u8 *res, u64 val) return res + 7; } -static inline u8 *put_u64(u8 *res, u64 val) +static inline void * +put_u64(void *res, u64 val) { *(u64*)res = cpu_to_le64(val); return res + 8; } -static inline const u8 *get_bytes(const u8 *p, size_t num_bytes, void *res) +static inline const void * +get_bytes(const void *p, size_t num_bytes, void *res) { memcpy(res, p, num_bytes); return p + num_bytes; } -static inline u8 *put_zeroes(u8 *p, size_t num_bytes) +static inline void * +put_zeroes(void *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 void *input) +static inline void * +put_bytes(void *p, size_t num_bytes, const void *input) { return (u8*)memcpy(p, input, num_bytes) + num_bytes; } diff --git a/src/dentry.c b/src/dentry.c index ea2cdb1b..683a11e6 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -89,15 +89,16 @@ get_utf16le_name(const mbchar *name, utf16lechar **name_utf16le_ret, 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; - } if (ret == 0) { - FREE(*name_utf16le_ret); - *name_utf16le_ret = name_utf16le; - *name_utf16le_nbytes_ret = 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; + } else { + FREE(*name_utf16le_ret); + *name_utf16le_ret = name_utf16le; + *name_utf16le_nbytes_ret = name_utf16le_nbytes; + } } return ret; } @@ -111,7 +112,7 @@ set_dentry_name(struct wim_dentry *dentry, const mbchar *new_name) &dentry->file_name_nbytes); if (ret == 0) { /* Clear the short name and recalculate the dentry length */ - if (dentry->short_name_nbytes) { + if (dentry_has_short_name(dentry)) { FREE(dentry->short_name); dentry->short_name = NULL; dentry->short_name_nbytes = 0; @@ -284,7 +285,6 @@ calculate_dentry_full_path(struct wim_dentry *dentry, void *ignore) char *parent_full_path; u32 parent_full_path_nbytes; const struct wim_dentry *parent; - char *name_mbs; size_t name_mbs_nbytes; int ret; @@ -370,25 +370,36 @@ calculate_subdir_offsets(struct wim_dentry *dentry, u64 *subdir_offset_p) } static int -dentry_compare_names(const struct wim_dentry *d1, const struct wim_dentry *d2) +compare_utf16le_names(const utf16lechar *name1, size_t nbytes1, + const utf16lechar *name2, size_t nbytes2) { - int result = memcmp(d1->file_name, d2->file_name, - min(d1->file_name_nbytes, d2->file_name_nbytes)); + int result = memcmp(name1, name2, min(nbytes1, nbytes2)); if (result) return result; else - return d1->file_name_nbytes - d2->file_name_nbytes; + return (int)nbytes1 - (int)nbytes2; +} + +static int +dentry_compare_names(const struct wim_dentry *d1, const struct wim_dentry *d2) +{ + return compare_utf16le_names(d1->file_name, d1->file_name_nbytes, + d2->file_name, d2->file_name_nbytes); } struct wim_dentry * get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry, - const utf16lechar *name) + const utf16lechar *name, + size_t name_nbytes) { struct rb_node *node = dentry->d_inode->i_children.rb_node; + struct wim_dentry *child; while (node) { - struct wim_dentry *child = rbnode_dentry(node); - int result = dentry_compare_names(dentry, child); + child = rbnode_dentry(node); + int result = compare_utf16le_names(name, name_nbytes, + child->file_name, + child->file_name_nbytes); if (result < 0) node = node->rb_left; else if (result > 0) @@ -415,7 +426,8 @@ get_dentry_child_with_name(const struct wim_dentry *dentry, const mbchar *name) child = NULL; } else { child = get_dentry_child_with_utf16le_name(dentry, - utf16le_name); + utf16le_name, + utf16le_name_nbytes); FREE(utf16le_name); } return child; @@ -431,35 +443,31 @@ get_dentry(WIMStruct *w, const mbchar *path) 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; + if (ret) return NULL; - } parent_dentry = wim_root_dentry(w); p = path_utf16le; while (1) { - while (*p == '/') + while (*p == cpu_to_le16('/')) p++; cur_dentry = parent_dentry; if (*p == '\0') break; pp = p; - while (*pp != '/' && *pp != '\0') + while (*pp != cpu_to_le16('/') && *pp != '\0') pp++; - save = *pp; - *pp = '\0'; - cur_dentry = get_dentry_child_with_utf16le_name(parent_dentry, p); + cur_dentry = get_dentry_child_with_utf16le_name(parent_dentry, p, + (void*)pp - (void*)p); if (cur_dentry == NULL) break; - *pp = save; p = pp; + parent_dentry = cur_dentry; } FREE(path_utf16le); if (cur_dentry == NULL) { @@ -484,7 +492,8 @@ wim_pathname_to_inode(WIMStruct *w, const mbchar *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 mbchar *path) +struct wim_dentry * +get_parent_dentry(WIMStruct *w, const mbchar *path) { size_t path_len = strlen(path); mbchar buf[path_len + 1]; @@ -495,7 +504,8 @@ struct wim_dentry *get_parent_dentry(WIMStruct *w, const mbchar *path) } /* Prints the full path of a dentry. */ -int print_dentry_full_path(struct wim_dentry *dentry, void *ignore) +int +print_dentry_full_path(struct wim_dentry *dentry, void *ignore) { if (dentry->full_path) puts(dentry->full_path); @@ -529,7 +539,8 @@ struct file_attr_flag file_attr_flags[] = { /* Prints a directory entry. @lookup_table is a pointer to the lookup table, if * available. If the dentry is unresolved and the lookup table is NULL, the * lookup table entries will not be printed. Otherwise, they will be. */ -int print_dentry(struct wim_dentry *dentry, void *lookup_table) +int +print_dentry(struct wim_dentry *dentry, void *lookup_table) { const u8 *hash; struct wim_lookup_table_entry *lte; @@ -559,9 +570,12 @@ 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); - 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); + if (dentry_has_long_name(dentry)) + wimlib_printf("Filename = \"%W\"\n", dentry->file_name); + if (dentry_has_short_name(dentry)) + wimlib_printf("Short Name \"%W\"\n", dentry->short_name); + if (dentry->full_path) + printf("Full Path = \"%s\"\n", dentry->full_path); lte = inode_stream_lte(dentry->d_inode, 0, lookup_table); if (lte) { @@ -593,13 +607,15 @@ int print_dentry(struct wim_dentry *dentry, void *lookup_table) } /* Initializations done on every `struct wim_dentry'. */ -static void dentry_common_init(struct wim_dentry *dentry) +static void +dentry_common_init(struct wim_dentry *dentry) { memset(dentry, 0, sizeof(struct wim_dentry)); dentry->refcnt = 1; } -static struct wim_inode *new_timeless_inode() +static struct wim_inode * +new_timeless_inode() { struct wim_inode *inode = CALLOC(1, sizeof(struct wim_inode)); if (inode) { @@ -618,7 +634,8 @@ static struct wim_inode *new_timeless_inode() return inode; } -static struct wim_inode *new_inode() +static struct wim_inode * +new_inode() { struct wim_inode *inode = new_timeless_inode(); if (inode) { @@ -630,76 +647,87 @@ static struct wim_inode *new_inode() return inode; } -/* - * Creates an unlinked directory entry. - * - * @name: The UTF-8 filename of the new dentry. - * - * Returns a pointer to the new dentry, or NULL if out of memory. - */ -struct wim_dentry *new_dentry(const mbchar *name) +/* Creates an unlinked directory entry. */ +int new_dentry(const mbchar *name, struct wim_dentry **dentry_ret) { struct wim_dentry *dentry; + int ret; dentry = MALLOC(sizeof(struct wim_dentry)); if (!dentry) - goto err; + return WIMLIB_ERR_NOMEM; dentry_common_init(dentry); - if (set_dentry_name(dentry, name) != 0) - goto err; - - dentry->parent = dentry; - - return dentry; -err: - FREE(dentry); - ERROR_WITH_ERRNO("Failed to create new dentry with name \"%s\"", name); - return NULL; + ret = set_dentry_name(dentry, name); + if (ret == 0) { + dentry->parent = dentry; + *dentry_ret = dentry; + } else { + FREE(dentry); + ERROR("Failed to set name on new dentry with name \"%s\"", name); + } + return ret; } -static struct wim_dentry * -__new_dentry_with_inode(const mbchar *name, bool timeless) +static int +__new_dentry_with_inode(const mbchar *name, struct wim_dentry **dentry_ret, + bool timeless) { struct wim_dentry *dentry; - dentry = new_dentry(name); - if (dentry) { - if (timeless) - dentry->d_inode = new_timeless_inode(); - else - dentry->d_inode = new_inode(); - if (dentry->d_inode) { - inode_add_dentry(dentry, dentry->d_inode); - } else { - free_dentry(dentry); - dentry = NULL; - } + int ret; + + ret = new_dentry(name, &dentry); + if (ret) + return ret; + + if (timeless) + dentry->d_inode = new_timeless_inode(); + else + dentry->d_inode = new_inode(); + if (!dentry->d_inode) { + free_dentry(dentry); + return WIMLIB_ERR_NOMEM; } - return dentry; + + inode_add_dentry(dentry, dentry->d_inode); + *dentry_ret = dentry; + return 0; } -struct wim_dentry * -new_dentry_with_timeless_inode(const mbchar *name) +int +new_dentry_with_timeless_inode(const mbchar *name, struct wim_dentry **dentry_ret) { - return __new_dentry_with_inode(name, true); + return __new_dentry_with_inode(name, dentry_ret, true); } -struct wim_dentry * -new_dentry_with_inode(const mbchar *name) +int +new_dentry_with_inode(const mbchar *name, struct wim_dentry **dentry_ret) { - return __new_dentry_with_inode(name, false); + return __new_dentry_with_inode(name, dentry_ret, false); } static int -init_ads_entry(struct wim_ads_entry *ads_entry, const mbchar *name) +init_ads_entry(struct wim_ads_entry *ads_entry, const void *name, + size_t name_nbytes, bool is_utf16le) { int ret = 0; memset(ads_entry, 0, sizeof(*ads_entry)); - if (name && *name) { - ret = get_utf16le_name(name, &ads_entry->stream_name, - &ads_entry->stream_name_nbytes); + + if (is_utf16le) { + utf16lechar *p = MALLOC(name_nbytes + sizeof(utf16lechar)); + if (!p) + return WIMLIB_ERR_NOMEM; + memcpy(p, name, name_nbytes); + p[name_nbytes / 2] = 0; + ads_entry->stream_name = p; + ads_entry->stream_name_nbytes = name_nbytes; + } else { + if (name && *(const char*)name) { + ret = get_utf16le_name(name, &ads_entry->stream_name, + &ads_entry->stream_name_nbytes); + } } return ret; } @@ -897,12 +925,9 @@ inode_get_ads_entry(struct wim_inode *inode, const mbchar *stream_name, } } -/* - * 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) +static struct wim_ads_entry * +do_inode_add_ads(struct wim_inode *inode, const void *stream_name, + size_t stream_name_nbytes, bool is_utf16le) { u16 num_ads; struct wim_ads_entry *ads_entries; @@ -924,7 +949,7 @@ inode_add_ads(struct wim_inode *inode, const char *stream_name) inode->i_ads_entries = ads_entries; new_entry = &inode->i_ads_entries[num_ads - 1]; - if (init_ads_entry(new_entry, stream_name) != 0) + if (init_ads_entry(new_entry, stream_name, stream_name_nbytes, is_utf16le)) return NULL; #ifdef WITH_FUSE new_entry->stream_id = inode->i_next_stream_id++; @@ -933,6 +958,24 @@ inode_add_ads(struct wim_inode *inode, const char *stream_name) return new_entry; } +struct wim_ads_entry * +inode_add_ads_utf16le(struct wim_inode *inode, + const utf16lechar *stream_name, + size_t stream_name_nbytes) +{ + return do_inode_add_ads(inode, stream_name, stream_name_nbytes, true); +} + +/* + * 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) +{ + return do_inode_add_ads(inode, stream_name, strlen(stream_name), false); +} + int inode_add_ads_with_data(struct wim_inode *inode, const mbchar *name, const void *value, size_t size, @@ -1141,7 +1184,6 @@ read_ads_entries(const u8 *p, struct wim_inode *inode, u64 remaining_size) u64 length; u64 length_no_padding; u64 total_length; - size_t utf8_len; const u8 *p_save = p; cur_entry = &ads_entries[i]; @@ -1160,7 +1202,7 @@ read_ads_entries(const u8 *p, struct wim_inode *inode, u64 remaining_size) p = get_u64(p, &length); p += 8; /* Skip the reserved field */ - p = get_bytes(p, SHA1_HASH_SIZE, (u8*)cur_entry->hash); + p = get_bytes(p, SHA1_HASH_SIZE, cur_entry->hash); p = get_u16(p, &cur_entry->stream_name_nbytes); cur_entry->stream_name = NULL; @@ -1201,8 +1243,7 @@ read_ads_entries(const u8 *p, struct wim_inode *inode, u64 remaining_size) } if (cur_entry->stream_name_nbytes) { - cur_entry->stream_name = MALLOC((size_t) - cur_entry->stream_name_nbytes + 2); + cur_entry->stream_name = MALLOC(cur_entry->stream_name_nbytes + 2); if (!cur_entry->stream_name) { ret = WIMLIB_ERR_NOMEM; goto out_free_ads_entries; @@ -1373,14 +1414,14 @@ read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, /* Read the filename if present. Note: if the filename is empty, there * is no null terminator following it. */ if (file_name_nbytes) { - file_name = MALLOC((size_t)file_name_nbytes + 2); + file_name = MALLOC(file_name_nbytes + 2); if (!file_name) { - ERROR("Failed to allocate %zu bytes for dentry file name", - (size_t)file_name_nbytes + 2); + ERROR("Failed to allocate %d bytes for dentry file name", + file_name_nbytes + 2); ret = WIMLIB_ERR_NOMEM; goto out_free_inode; } - p = get_bytes(p, (size_t)file_name_nbytes + 2, file_name); + p = get_bytes(p, 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 " @@ -1423,14 +1464,14 @@ read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, /* Read the short filename if present. Note: if there is no short * filename, there is no null terminator following it. */ if (short_name_nbytes) { - short_name = MALLOC((size_t)short_name_nbytes + 2); + short_name = MALLOC(short_name_nbytes + 2); if (!short_name) { - ERROR("Failed to allocate %zu bytes for dentry short name", - (size_t)short_name_nbytes + 2); + ERROR("Failed to allocate %d bytes for dentry short name", + short_name_nbytes + 2); ret = WIMLIB_ERR_NOMEM; goto out_free_file_name; } - p = get_bytes(p, (size_t)short_name_nbytes + 2, short_name); + p = get_bytes(p, 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 " @@ -1621,11 +1662,11 @@ write_dentry(const struct wim_dentry *dentry, u8 *p) p = put_u16(p, inode->i_num_ads); p = put_u16(p, dentry->short_name_nbytes); p = put_u16(p, dentry->file_name_nbytes); - if (dentry->file_name_nbytes) { + if (dentry_has_long_name(dentry)) { p = put_bytes(p, dentry->file_name_nbytes + 2, dentry->file_name); } - if (dentry->short_name_nbytes) { + if (dentry_has_short_name(dentry)) { p = put_bytes(p, dentry->short_name_nbytes + 2, dentry->short_name); } diff --git a/src/dentry.h b/src/dentry.h index dfbcafca..6442b106 100644 --- a/src/dentry.h +++ b/src/dentry.h @@ -358,7 +358,8 @@ get_dentry_child_with_name(const struct wim_dentry *dentry, extern struct wim_dentry * get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry, - const utf16lechar *name); + const utf16lechar *name, + size_t name_nbytes); extern struct wim_dentry * get_parent_dentry(struct WIMStruct *w, const mbchar *path); @@ -369,14 +370,14 @@ 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 int +new_dentry(const mbchar *name, struct wim_dentry **dentry_ret); -extern struct wim_dentry * -new_dentry_with_inode(const mbchar *name); +extern int +new_dentry_with_inode(const mbchar *name, struct wim_dentry **dentry_ret); -extern struct wim_dentry * -new_dentry_with_timeless_inode(const mbchar *name); +extern int +new_dentry_with_timeless_inode(const mbchar *name, struct wim_dentry **dentry_ret); extern void free_inode(struct wim_inode *inode); @@ -405,6 +406,11 @@ 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_add_ads_utf16le(struct wim_inode *inode, + const utf16lechar *stream_name, + size_t stream_name_nbytes); + extern struct wim_ads_entry * inode_add_ads(struct wim_inode *dentry, const mbchar *stream_name); @@ -417,9 +423,12 @@ 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" +#define WIMLIB_UNIX_DATA_TAG_NBYTES (sizeof(WIMLIB_UNIX_DATA_TAG) - 1) -#define WIMLIB_UNIX_DATA_TAG_LEN (sizeof(WIMLIB_UNIX_DATA_TAG) - 1) +#define WIMLIB_UNIX_DATA_TAG_UTF16LE "$\0$\0_\0_\0w\0i\0m\0l\0i\0b\0_\0U\0N\0I\0X\0_\0d\0a\0t\0a\0" +#define WIMLIB_UNIX_DATA_TAG_UTF16LE_NBYTES (sizeof(WIMLIB_UNIX_DATA_TAG_UTF16LE) - 1) /* Format for special alternate data stream entries to store UNIX data for files * and directories (see: WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) */ @@ -514,4 +523,16 @@ dentry_has_children(const struct wim_dentry *dentry) return inode_has_children(dentry->d_inode); } +static inline bool +dentry_has_short_name(const struct wim_dentry *dentry) +{ + return dentry->short_name_nbytes != 0; +} + +static inline bool +dentry_has_long_name(const struct wim_dentry *dentry) +{ + return dentry->file_name_nbytes != 0; +} + #endif diff --git a/src/encoding.c b/src/encoding.c index de043581..e0f4e2d0 100644 --- a/src/encoding.c +++ b/src/encoding.c @@ -54,219 +54,193 @@ struct iconv_list_head name = { \ .mutex = PTHREAD_MUTEX_INITIALIZER, \ } -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) { iconv_t cd; + iconv_t *cd_p; 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; + ERROR_WITH_ERRNO("Failed to open iconv from %s to %s", + head->from_encoding, head->to_encoding); + cd_p = NULL; } else { i = MALLOC(sizeof(struct iconv_node)); - if (!i) { + if (i) { + i->head = head; + i->cd = cd; + cd_p = &i->cd; + } else { iconv_close(cd); - cd = (iconv_t)-1; - goto out_unlock; + cd_p = NULL; } - i->head = head; } } else { i = container_of(head->list.next, struct iconv_node, list); list_del(head->list.next); + cd_p = &i->cd; } - cd = i->cd; -out_unlock: pthread_mutex_unlock(&head->mutex); - return cd; + return cd_p; } static void put_iconv(iconv_t *cd) { + int errno_save = errno; 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); + errno = errno_save; } -int -mbs_to_utf16le_nbytes(const mbchar *mbs, size_t mbs_nbytes, - size_t *utf16le_nbytes_ret) -{ - iconv_t *cd = get_iconv(&iconv_mbs_to_utf16le); - if (*cd == (iconv_t)-1) - 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; - } - put_iconv(cd); - return ret; +#define DEFINE_CHAR_CONVERSION_FUNCTIONS(varname1, longname1, chartype1,\ + varname2, longname2, chartype2,\ + worst_case_len_expr, \ + err_return, \ + err_msg) \ +static ICONV_LIST(iconv_##varname1##_to_##varname2, \ + longname1, longname2); \ + \ +int \ +varname1##_to_##varname2##_nbytes(const chartype1 *in, size_t in_nbytes,\ + size_t *out_nbytes_ret) \ +{ \ + iconv_t *cd = get_iconv(&iconv_##varname1##_to_##varname2); \ + if (cd == NULL) \ + return WIMLIB_ERR_ICONV_NOT_AVAILABLE; \ + \ + /* Worst case length */ \ + chartype2 buf[worst_case_len_expr]; \ + char *inbuf = (char*)in; \ + size_t inbytesleft = in_nbytes; \ + char *outbuf = (char*)buf; \ + size_t outbytesleft = sizeof(buf); \ + size_t len; \ + int ret; \ + \ + len = iconv(*cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); \ + if (len == (size_t)-1) { \ + err_msg; \ + ret = err_return; \ + } else { \ + *out_nbytes_ret = sizeof(buf) - outbytesleft; \ + ret = 0; \ + } \ + put_iconv(cd); \ + return ret; \ +} \ + \ +int \ +varname1##_to_##varname2##_buf(const chartype1 *in, size_t in_nbytes, \ + chartype2 *out) \ +{ \ + iconv_t *cd = get_iconv(&iconv_##varname1##_to_##varname2); \ + if (cd == NULL) \ + return WIMLIB_ERR_ICONV_NOT_AVAILABLE; \ + \ + char *inbuf = (char*)in; \ + size_t inbytesleft = in_nbytes; \ + char *outbuf = (char*)out; \ + const size_t LARGE_NUMBER = 1000000000; \ + size_t outbytesleft = LARGE_NUMBER; \ + size_t len; \ + int ret; \ + \ + len = iconv(*cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft); \ + if (len == (size_t)-1) { \ + err_msg; \ + ret = err_return; \ + } else { \ + out[(LARGE_NUMBER-outbytesleft)/sizeof(chartype2)] = 0; \ + ret = 0; \ + } \ + put_iconv(cd); \ + return ret; \ +} \ + \ +int \ +varname1##_to_##varname2(const chartype1 *in, size_t in_nbytes, \ + chartype2 **out_ret, \ + size_t *out_nbytes_ret) \ +{ \ + int ret; \ + chartype2 *out; \ + size_t out_nbytes; \ + \ + ret = varname1##_to_##varname2##_nbytes(in, in_nbytes, \ + &out_nbytes); \ + if (ret) \ + return ret; \ + \ + out = MALLOC(out_nbytes + sizeof(chartype2)); \ + if (!out) \ + return WIMLIB_ERR_NOMEM; \ + \ + ret = varname1##_to_##varname2##_buf(in, in_nbytes, out); \ + if (ret) { \ + int errno_save = errno; \ + FREE(out); \ + errno = errno_save; \ + } else { \ + *out_ret = out; \ + *out_nbytes_ret = out_nbytes; \ + } \ + return ret; \ } +DEFINE_CHAR_CONVERSION_FUNCTIONS(utf16le, "UTF-16LE", utf16lechar, + mbs, "", mbchar, + in_nbytes / 2 * MB_CUR_MAX, + WIMLIB_ERR_UNICODE_STRING_NOT_REPRESENTABLE, + ERROR_WITH_ERRNO("Failed to convert UTF-16LE " + "string %U to multibyte string", in)) -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; +DEFINE_CHAR_CONVERSION_FUNCTIONS(mbs, "", mbchar, + utf16le, "UTF-16LE", utf16lechar, + in_nbytes * 2, + WIMLIB_ERR_INVALID_MULTIBYTE_STRING, + ERROR_WITH_ERRNO("Failed to convert multibyte " + "string %s to UTF-16LE string", in)) - /* 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; +DEFINE_CHAR_CONVERSION_FUNCTIONS(utf8, "UTF-8", utf8char, + mbs, "", mbchar, + in_nbytes, + WIMLIB_ERR_INVALID_UTF8_STRING, + ERROR_WITH_ERRNO("Failed to convert UTF-8 " + "string %U to multibyte string", in)) - 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; -} - -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 { - ret = 0; - } - put_iconv(cd); - return ret; -} -int -utf16le_to_mbs_buf(const utf16lechar *utf16le_str, size_t utf16le_nbytes, - mbchar *mbs) +static void +iconv_cleanup(struct iconv_list_head *head) { - 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 { - ret = 0; + pthread_mutex_destroy(&head->mutex); + while (!list_empty(&head->list)) { + struct iconv_node *i; + + i = container_of(head->list.next, struct iconv_node, list); + list_del(&i->list); + iconv_close(i->cd); + FREE(i); } - 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) +void +iconv_global_cleanup() { - int ret; - utf16lechar *utf16le_str; - size_t utf16le_nbytes; - - ret = mbs_to_utf16le_nbytes(mbs, mbs_nbytes, - &utf16le_nbytes); - if (ret) - return ret; - - 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; - } - return ret; + iconv_cleanup(&iconv_utf16le_to_mbs); + iconv_cleanup(&iconv_mbs_to_utf16le); + iconv_cleanup(&iconv_utf8_to_mbs); } -int -utf16le_to_mbs(const utf16lechar *utf16le_str, size_t utf16le_nbytes, - mbchar **mbs_ret, size_t *mbs_nbytes_ret) -{ - int ret; - mbchar *mbs; - size_t mbs_nbytes; - - ret = utf16le_to_mbs_nbytes(utf16le_str, utf16le_nbytes, - &mbs_nbytes); - if (ret) - return ret; - - 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; - } - return ret; -} bool utf8_str_contains_nonascii_chars(const utf8char *utf8_str) diff --git a/src/lookup_table.c b/src/lookup_table.c index d9301c2c..f8a2aef0 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -110,18 +110,18 @@ clone_lookup_table_entry(const struct wim_lookup_table_entry *old) if (!loc) goto out_free; memcpy(loc, old->ntfs_loc, sizeof(*loc)); - loc->path_utf8 = NULL; - loc->stream_name_utf16 = NULL; + loc->path = NULL; + loc->stream_name = NULL; new->ntfs_loc = loc; - loc->path_utf8 = STRDUP(old->ntfs_loc->path_utf8); - if (!loc->path_utf8) + loc->path = STRDUP(old->ntfs_loc->path); + if (!loc->path) goto out_free; - loc->stream_name_utf16 = MALLOC(loc->stream_name_utf16_num_chars * 2); - if (!loc->stream_name_utf16) + loc->stream_name = MALLOC((loc->stream_name_nchars + 1) * 2); + if (!loc->stream_name) goto out_free; - memcpy(loc->stream_name_utf16, - old->ntfs_loc->stream_name_utf16, - loc->stream_name_utf16_num_chars * 2); + memcpy(loc->stream_name, + old->ntfs_loc->stream_name, + (loc->stream_name_nchars + 1) * 2); } break; #endif @@ -153,8 +153,8 @@ void free_lookup_table_entry(struct wim_lookup_table_entry *lte) #ifdef WITH_NTFS_3G case RESOURCE_IN_NTFS_VOLUME: if (lte->ntfs_loc) { - FREE(lte->ntfs_loc->path_utf8); - FREE(lte->ntfs_loc->stream_name_utf16); + FREE(lte->ntfs_loc->path); + FREE(lte->ntfs_loc->stream_name); FREE(lte->ntfs_loc); } break; @@ -590,7 +590,7 @@ lookup_resource(WIMStruct *w, if (lookup_flags & LOOKUP_FLAG_ADS_OK) { stream_name = path_stream_name(path); if (stream_name) { - p = (char*)stream_name - 1; + p = (mbchar*)stream_name - 1; *p = '\0'; } } @@ -599,7 +599,7 @@ lookup_resource(WIMStruct *w, if (p) *p = ':'; if (!dentry) - return -ENOENT; + return -errno; inode = dentry->d_inode; diff --git a/src/lookup_table.h b/src/lookup_table.h index 699e16ec..d172cac9 100644 --- a/src/lookup_table.h +++ b/src/lookup_table.h @@ -32,9 +32,9 @@ struct wim_lookup_table { #ifdef WITH_NTFS_3G struct ntfs_location { - utf8char *path_utf8; - utf16lechar *stream_name_utf16; - u16 stream_name_utf16_num_chars; + mbchar *path; + utf16lechar *stream_name; + u16 stream_name_nchars; struct _ntfs_volume **ntfs_vol_p; bool is_reparse_point; }; diff --git a/src/mount_image.c b/src/mount_image.c index 2f09ce7c..fc5fa45e 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -312,6 +312,7 @@ create_dentry(struct fuse_context *fuse_ctx, const mbchar *path, struct wim_dentry *new; const mbchar *basename; struct wimfs_context *wimfs_ctx = WIMFS_CTX(fuse_ctx); + int ret; parent = get_parent_dentry(wimfs_ctx->wim, path); if (!parent) @@ -324,9 +325,9 @@ create_dentry(struct fuse_context *fuse_ctx, const mbchar *path, if (get_dentry_child_with_name(parent, basename)) return -EEXIST; - new = new_dentry_with_inode(basename); - if (!new) - return -errno; + ret = new_dentry_with_inode(basename, &new); + if (ret) + return -ENOMEM; new->d_inode->i_resolved = 1; new->d_inode->i_ino = wimfs_ctx->next_ino++; @@ -1737,6 +1738,7 @@ wimfs_link(const mbchar *to, const mbchar *from) struct wim_lookup_table_entry *lte; WIMStruct *w = wimfs_get_WIMStruct(); u16 i; + int ret; inode = wim_pathname_to_inode(w, to); if (!inode) @@ -1755,9 +1757,10 @@ wimfs_link(const mbchar *to, const mbchar *from) link_name = path_basename(from); if (get_dentry_child_with_name(from_dentry_parent, link_name)) return -EEXIST; - from_dentry = new_dentry(link_name); - if (!from_dentry) - return -errno; + + ret = new_dentry(link_name, &from_dentry); + if (ret) + return -ENOMEM; inode_add_dentry(from_dentry, inode); from_dentry->d_inode = inode; @@ -2386,7 +2389,6 @@ wimfs_write(const mbchar *path, const char *buf, size_t size, { struct wimfs_fd *fd = (struct wimfs_fd*)(uintptr_t)fi->fh; int ret; - u64 now; if (!fd) return -EBADF; diff --git a/src/ntfs-apply.c b/src/ntfs-apply.c index 9dcf6b0a..8bc6c49b 100644 --- a/src/ntfs-apply.c +++ b/src/ntfs-apply.c @@ -41,8 +41,9 @@ #include #include #include +#include -static int extract_wim_chunk_to_ntfs_attr(const u8 *buf, size_t len, +static int extract_wim_chunk_to_ntfs_attr(const void *buf, size_t len, u64 offset, void *arg) { ntfs_attr *na = arg; @@ -87,36 +88,34 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent int ret = 0; unsigned stream_idx = 0; ntfschar *stream_name = AT_UNNAMED; - u32 stream_name_len = 0; - const char *stream_name_utf8; + u32 stream_name_nbytes = 0; const struct wim_inode *inode = dentry->d_inode; struct wim_lookup_table_entry *lte; DEBUG("Writing %u NTFS data stream%s for `%s'", inode->i_num_ads + 1, (inode->i_num_ads == 0 ? "" : "s"), - dentry->full_path_utf8); + dentry->full_path); lte = inode->i_lte; while (1) { - if (stream_name_len) { - + if (stream_name_nbytes) { /* Skip special UNIX data entries (see documentation for * WIMLIB_ADD_IMAGE_FLAG_UNIX_DATA) */ - if (stream_name_len == WIMLIB_UNIX_DATA_TAG_LEN - && !memcmp(stream_name_utf8, - WIMLIB_UNIX_DATA_TAG, - WIMLIB_UNIX_DATA_TAG_LEN)) + if (stream_name_nbytes == WIMLIB_UNIX_DATA_TAG_UTF16LE_NBYTES + && !memcmp(stream_name, + WIMLIB_UNIX_DATA_TAG_UTF16LE, + WIMLIB_UNIX_DATA_TAG_UTF16LE_NBYTES)) goto cont; /* Create an empty named stream. */ ret = ntfs_attr_add(ni, AT_DATA, stream_name, - stream_name_len, NULL, 0); + stream_name_nbytes / 2, NULL, 0); if (ret != 0) { - ERROR_WITH_ERRNO("Failed to create name data " + ERROR_WITH_ERRNO("Failed to create named data " "stream for extracted file " "`%s'", - dentry->full_path_utf8); + dentry->full_path); ret = WIMLIB_ERR_NTFS_3G; break; @@ -128,11 +127,12 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent if (lte) { ntfs_attr *na; - na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len); + na = ntfs_attr_open(ni, AT_DATA, stream_name, + stream_name_nbytes / 2); if (!na) { ERROR_WITH_ERRNO("Failed to open a data stream of " "extracted file `%s'", - dentry->full_path_utf8); + dentry->full_path); ret = WIMLIB_ERR_NTFS_3G; break; } @@ -163,9 +163,8 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent break; /* Get the name and lookup table entry for the next stream. */ - stream_name = (ntfschar*)inode->i_ads_entries[stream_idx].stream_name; - stream_name_utf8 = inode->i_ads_entries[stream_idx].stream_name_utf8; - stream_name_len = inode->i_ads_entries[stream_idx].stream_name_len / 2; + stream_name = inode->i_ads_entries[stream_idx].stream_name; + stream_name_nbytes = inode->i_ads_entries[stream_idx].stream_name_nbytes; lte = inode->i_ads_entries[stream_idx].lte; stream_idx++; } @@ -174,22 +173,22 @@ static int write_ntfs_data_streams(ntfs_inode *ni, const struct wim_dentry *dent /* Open the NTFS inode that corresponds to the parent of a WIM dentry. Returns * the opened inode, or NULL on failure. */ -static ntfs_inode *dentry_open_parent_ni(const struct wim_dentry *dentry, - ntfs_volume *vol) +static ntfs_inode * +dentry_open_parent_ni(const struct wim_dentry *dentry, ntfs_volume *vol) { - char *p; - const char *dir_name; + mbchar *p; + const mbchar *dir_name; ntfs_inode *dir_ni; - char orig; + mbchar orig; - p = dentry->full_path_utf8 + dentry->full_path_utf8_len; + p = dentry->full_path + dentry->full_path_nbytes; do { p--; } while (*p != '/'); orig = *p; *p = '\0'; - dir_name = dentry->full_path_utf8; + dir_name = dentry->full_path; dir_ni = ntfs_pathname_to_inode(vol, NULL, dir_name); if (!dir_ni) { ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", @@ -206,7 +205,7 @@ static ntfs_inode *dentry_open_parent_ni(const struct wim_dentry *dentry, * directory specified by @dir_ni, and it is made to point to the previously * extracted file located at @inode->i_extracted_file. * - * Or, in other words, this adds a new name @from_dentry->full_path_utf8 to an + * Or, in other words, this adds a new name @from_dentry->full_path to an * existing NTFS inode which already has a name @inode->i_extracted_file. * * The new name is made in the POSIX namespace (this is the behavior of @@ -214,9 +213,10 @@ static ntfs_inode *dentry_open_parent_ni(const struct wim_dentry *dentry, * * Return 0 on success, nonzero on failure. dir_ni is closed either way. */ -static int apply_ntfs_hardlink(const struct wim_dentry *from_dentry, - const struct wim_inode *inode, - ntfs_inode *dir_ni) +static int +apply_ntfs_hardlink(const struct wim_dentry *from_dentry, + const struct wim_inode *inode, + ntfs_inode *dir_ni) { int ret; ntfs_inode *to_ni; @@ -230,7 +230,7 @@ static int apply_ntfs_hardlink(const struct wim_dentry *from_dentry, } DEBUG("Extracting NTFS hard link `%s' => `%s'", - from_dentry->full_path_utf8, inode->i_extracted_file); + from_dentry->full_path, inode->i_extracted_file); to_ni = ntfs_pathname_to_inode(vol, NULL, inode->i_extracted_file); if (!to_ni) { @@ -246,13 +246,13 @@ static int apply_ntfs_hardlink(const struct wim_dentry *from_dentry, } ret = ntfs_link(to_ni, dir_ni, - (ntfschar*)from_dentry->file_name, - from_dentry->file_name_len / 2); + from_dentry->file_name, + from_dentry->file_name_nbytes / 2); ret |= ntfs_inode_close(dir_ni); ret |= ntfs_inode_close(to_ni); if (ret) { ERROR_WITH_ERRNO("Could not create hard link `%s' => `%s'", - from_dentry->full_path_utf8, + from_dentry->full_path, inode->i_extracted_file); ret = WIMLIB_ERR_NTFS_3G; } @@ -284,7 +284,7 @@ apply_file_attributes_and_security_data(ntfs_inode *ni, inode = dentry->d_inode; DEBUG("Setting NTFS file attributes on `%s' to %#"PRIx32, - dentry->full_path_utf8, inode->i_attributes); + dentry->full_path, inode->i_attributes); attributes_le32 = cpu_to_le32(inode->i_attributes); memset(&ctx, 0, sizeof(ctx)); @@ -295,7 +295,7 @@ apply_file_attributes_and_security_data(ntfs_inode *ni, sizeof(u32), 0); if (ret != 0) { ERROR("Failed to set NTFS file attributes on `%s'", - dentry->full_path_utf8); + dentry->full_path); return WIMLIB_ERR_NTFS_3G; } if (inode->i_security_id != -1) { @@ -306,7 +306,7 @@ apply_file_attributes_and_security_data(ntfs_inode *ni, wimlib_assert(inode->i_security_id < sd->num_entries); desc = (const char *)sd->descriptors[inode->i_security_id]; DEBUG("Applying security descriptor %d to `%s'", - inode->i_security_id, dentry->full_path_utf8); + inode->i_security_id, dentry->full_path); ret = ntfs_xattr_system_setxattr(&ctx, XATTR_NTFS_ACL, ni, dir_ni, desc, @@ -314,7 +314,7 @@ apply_file_attributes_and_security_data(ntfs_inode *ni, if (ret != 0) { ERROR_WITH_ERRNO("Failed to set security data on `%s'", - dentry->full_path_utf8); + dentry->full_path); return WIMLIB_ERR_NTFS_3G; } } @@ -333,17 +333,17 @@ static int apply_reparse_data(ntfs_inode *ni, const struct wim_dentry *dentry, lte = inode_unnamed_lte_resolved(dentry->d_inode); - DEBUG("Applying reparse data to `%s'", dentry->full_path_utf8); + DEBUG("Applying reparse data to `%s'", dentry->full_path); if (!lte) { ERROR("Could not find reparse data for `%s'", - dentry->full_path_utf8); + dentry->full_path); return WIMLIB_ERR_INVALID_DENTRY; } if (wim_resource_size(lte) >= 0xffff) { ERROR("Reparse data of `%s' is too long (%"PRIu64" bytes)", - dentry->full_path_utf8, wim_resource_size(lte)); + dentry->full_path, wim_resource_size(lte)); return WIMLIB_ERR_INVALID_DENTRY; } @@ -362,7 +362,7 @@ static int apply_reparse_data(ntfs_inode *ni, const struct wim_dentry *dentry, wim_resource_size(lte) + 8, 0); if (ret != 0) { ERROR_WITH_ERRNO("Failed to set NTFS reparse data on `%s'", - dentry->full_path_utf8); + dentry->full_path); return WIMLIB_ERR_NTFS_3G; } progress_info->extract.completed_bytes += wim_resource_size(lte); @@ -377,8 +377,9 @@ static int apply_reparse_data(ntfs_inode *ni, const struct wim_dentry *dentry, * * @return: 0 on success; nonzero on failure. */ -static int do_apply_dentry_ntfs(struct wim_dentry *dentry, ntfs_inode *dir_ni, - struct apply_args *args) +static int +do_apply_dentry_ntfs(struct wim_dentry *dentry, ntfs_inode *dir_ni, + struct apply_args *args) { int ret = 0; mode_t type; @@ -404,7 +405,7 @@ static int do_apply_dentry_ntfs(struct wim_dentry *dentry, ntfs_inode *dir_ni, * extracted yet, so go ahead and extract the * first one. */ FREE(inode->i_extracted_file); - inode->i_extracted_file = STRDUP(dentry->full_path_utf8); + inode->i_extracted_file = STRDUP(dentry->full_path); if (!inode->i_extracted_file) { ret = WIMLIB_ERR_NOMEM; goto out_close_dir_ni; @@ -418,12 +419,12 @@ static int do_apply_dentry_ntfs(struct wim_dentry *dentry, ntfs_inode *dir_ni, * Note: For symbolic links that are not directory junctions, S_IFREG is * passed here, since the reparse data and file attributes are set * later. */ - ni = ntfs_create(dir_ni, 0, (ntfschar*)dentry->file_name, - dentry->file_name_len / 2, type); + ni = ntfs_create(dir_ni, 0, dentry->file_name, + dentry->file_name_nbytes / 2, type); if (!ni) { ERROR_WITH_ERRNO("Could not create NTFS inode for `%s'", - dentry->full_path_utf8); + dentry->full_path); ret = WIMLIB_ERR_NTFS_3G; goto out_close_dir_ni; } @@ -437,7 +438,6 @@ static int do_apply_dentry_ntfs(struct wim_dentry *dentry, ntfs_inode *dir_ni, goto out_close_dir_ni; } - ret = apply_file_attributes_and_security_data(ni, dir_ni, dentry, args->w); if (ret != 0) @@ -450,25 +450,25 @@ static int do_apply_dentry_ntfs(struct wim_dentry *dentry, ntfs_inode *dir_ni, } /* Set DOS (short) name if given */ - if (dentry->short_name_len != 0) { - char *short_name_utf8; - size_t short_name_utf8_len; - ret = utf16_to_utf8(dentry->short_name, - dentry->short_name_len, - &short_name_utf8, - &short_name_utf8_len); + if (dentry_has_short_name(dentry)) { + mbchar *short_name_mbs; + size_t short_name_mbs_nbytes; + ret = utf16le_to_mbs(dentry->short_name, + dentry->short_name_nbytes, + &short_name_mbs, + &short_name_mbs_nbytes); if (ret != 0) goto out_close_dir_ni; DEBUG("Setting short (DOS) name of `%s' to %s", - dentry->full_path_utf8, short_name_utf8); + dentry->full_path, short_name_mbs); - ret = ntfs_set_ntfs_dos_name(ni, dir_ni, short_name_utf8, - short_name_utf8_len, 0); - FREE(short_name_utf8); + ret = ntfs_set_ntfs_dos_name(ni, dir_ni, short_name_mbs, + short_name_mbs_nbytes, 0); + FREE(short_name_mbs); if (ret != 0) { ERROR_WITH_ERRNO("Could not set DOS (short) name for `%s'", - dentry->full_path_utf8); + dentry->full_path); ret = WIMLIB_ERR_NTFS_3G; } /* inodes have been closed by ntfs_set_ntfs_dos_name(). */ @@ -481,22 +481,23 @@ out_close_dir_ni: if (ret == 0) ret = WIMLIB_ERR_NTFS_3G; ERROR_WITH_ERRNO("Failed to close inode for `%s'", - dentry->full_path_utf8); + dentry->full_path); } } if (ntfs_inode_close(dir_ni)) { if (ret == 0) ret = WIMLIB_ERR_NTFS_3G; ERROR_WITH_ERRNO("Failed to close inode of directory " - "containing `%s'", dentry->full_path_utf8); + "containing `%s'", dentry->full_path); } } out: return ret; } -static int apply_root_dentry_ntfs(const struct wim_dentry *dentry, - ntfs_volume *vol, const WIMStruct *w) +static int +apply_root_dentry_ntfs(const struct wim_dentry *dentry, + ntfs_volume *vol, const WIMStruct *w) { ntfs_inode *ni; int ret = 0; @@ -516,7 +517,8 @@ static int apply_root_dentry_ntfs(const struct wim_dentry *dentry, } /* Applies a WIM dentry to the NTFS volume */ -int apply_dentry_ntfs(struct wim_dentry *dentry, void *arg) +int +apply_dentry_ntfs(struct wim_dentry *dentry, void *arg) { struct apply_args *args = arg; ntfs_volume *vol = args->vol; @@ -562,7 +564,7 @@ int apply_dentry_ntfs(struct wim_dentry *dentry, void *arg) * file. So, this implies that the correct ordering of function calls * to extract a NTFS file are: * - * if (file has a DOS name) { + if (file has a DOS name) { * - Call ntfs_create() to create long name associated with * the DOS name (this initially creates a POSIX name) * - Call ntfs_set_ntfs_dos_name() to associate a DOS name @@ -579,10 +581,10 @@ int apply_dentry_ntfs(struct wim_dentry *dentry, void *arg) again: orig_dentry = NULL; if (!dentry->d_inode->i_dos_name_extracted && - dentry->short_name_len == 0) + !dentry_has_short_name(dentry)) { inode_for_each_dentry(other, dentry->d_inode) { - if (other->short_name_len != 0) { + if (dentry_has_short_name(other)) { orig_dentry = dentry; dentry = other; break; @@ -605,7 +607,8 @@ again: /* Transfers the 100-nanosecond precision timestamps from a WIM dentry to a NTFS * inode */ -int apply_dentry_timestamps_ntfs(struct wim_dentry *dentry, void *arg) +int +apply_dentry_timestamps_ntfs(struct wim_dentry *dentry, void *arg) { struct apply_args *args = arg; ntfs_volume *vol = args->vol; @@ -614,12 +617,12 @@ int apply_dentry_timestamps_ntfs(struct wim_dentry *dentry, void *arg) ntfs_inode *ni; int ret; - DEBUG("Setting timestamps on `%s'", dentry->full_path_utf8); + DEBUG("Setting timestamps on `%s'", dentry->full_path); - ni = ntfs_pathname_to_inode(vol, NULL, dentry->full_path_utf8); + ni = ntfs_pathname_to_inode(vol, NULL, dentry->full_path); if (!ni) { ERROR_WITH_ERRNO("Could not find NTFS inode for `%s'", - dentry->full_path_utf8); + dentry->full_path); return WIMLIB_ERR_NTFS_3G; } @@ -630,7 +633,7 @@ int apply_dentry_timestamps_ntfs(struct wim_dentry *dentry, void *arg) ret = ntfs_inode_set_times(ni, (const char*)buf, 3 * sizeof(u64), 0); if (ret != 0) { ERROR_WITH_ERRNO("Failed to set NTFS timestamps on `%s'", - dentry->full_path_utf8); + dentry->full_path); ret = WIMLIB_ERR_NTFS_3G; } @@ -638,7 +641,13 @@ int apply_dentry_timestamps_ntfs(struct wim_dentry *dentry, void *arg) if (ret == 0) ret = WIMLIB_ERR_NTFS_3G; ERROR_WITH_ERRNO("Failed to close NTFS inode for `%s'", - dentry->full_path_utf8); + dentry->full_path); } return ret; } + +void +libntfs3g_global_init() +{ + ntfs_set_char_encoding(setlocale(LC_ALL, "")); +} diff --git a/src/ntfs-capture.c b/src/ntfs-capture.c index d692633a..7c04e9b8 100644 --- a/src/ntfs-capture.c +++ b/src/ntfs-capture.c @@ -52,7 +52,8 @@ #include #endif -static inline ntfschar *attr_record_name(ATTR_RECORD *ar) +static inline ntfschar * +attr_record_name(ATTR_RECORD *ar) { return (ntfschar*)((u8*)ar + le16_to_cpu(ar->name_offset)); } @@ -68,10 +69,11 @@ static inline ntfschar *attr_record_name(ATTR_RECORD *ar) * * Return 0 on success or nonzero on error. */ -static int ntfs_attr_sha1sum(ntfs_inode *ni, ATTR_RECORD *ar, - u8 md[SHA1_HASH_SIZE], - bool is_reparse_point, - u32 *reparse_tag_ret) +static int +ntfs_attr_sha1sum(ntfs_inode *ni, ATTR_RECORD *ar, + u8 md[SHA1_HASH_SIZE], + bool is_reparse_point, + u32 *reparse_tag_ret) { s64 pos = 0; s64 bytes_remaining; @@ -116,11 +118,14 @@ out_error: /* Load the streams from a file or reparse point in the NTFS volume into the WIM * lookup table */ -static int capture_ntfs_streams(struct wim_dentry *dentry, ntfs_inode *ni, - char path[], size_t path_len, - struct wim_lookup_table *lookup_table, - ntfs_volume **ntfs_vol_p, - ATTR_TYPES type) +static int +capture_ntfs_streams(struct wim_dentry *dentry, + ntfs_inode *ni, + mbchar *path, + size_t path_len, + struct wim_lookup_table *lookup_table, + ntfs_volume **ntfs_vol_p, + ATTR_TYPES type) { ntfs_attr_search_ctx *actx; u8 attr_hash[SHA1_HASH_SIZE]; @@ -142,11 +147,9 @@ static int capture_ntfs_streams(struct wim_dentry *dentry, ntfs_inode *ni, while (!ntfs_attr_lookup(type, NULL, 0, CASE_SENSITIVE, 0, NULL, 0, actx)) { - char *stream_name_utf8; u32 reparse_tag; u64 data_size = ntfs_get_attribute_value_length(actx->attr); u64 name_length = actx->attr->name_length; - if (data_size == 0) { if (errno != 0) { ERROR_WITH_ERRNO("Failed to get size of attribute of " @@ -183,18 +186,18 @@ static int capture_ntfs_streams(struct wim_dentry *dentry, ntfs_inode *ni, if (!ntfs_loc) goto out_put_actx; ntfs_loc->ntfs_vol_p = ntfs_vol_p; - ntfs_loc->path_utf8 = MALLOC(path_len + 1); - if (!ntfs_loc->path_utf8) + ntfs_loc->path = MALLOC(path_len + 1); + if (!ntfs_loc->path) goto out_free_ntfs_loc; - memcpy(ntfs_loc->path_utf8, path, path_len + 1); + memcpy(ntfs_loc->path, path, path_len + 1); if (name_length) { - ntfs_loc->stream_name_utf16 = MALLOC(name_length * 2); - if (!ntfs_loc->stream_name_utf16) + ntfs_loc->stream_name = MALLOC(name_length * 2); + if (!ntfs_loc->stream_name) goto out_free_ntfs_loc; - memcpy(ntfs_loc->stream_name_utf16, + memcpy(ntfs_loc->stream_name, attr_record_name(actx->attr), actx->attr->name_length * 2); - ntfs_loc->stream_name_utf16_num_chars = name_length; + ntfs_loc->stream_name_nchars = name_length; } lte = new_lookup_table_entry(); @@ -212,9 +215,6 @@ static int capture_ntfs_streams(struct wim_dentry *dentry, ntfs_inode *ni, lte->resource_entry.size = data_size; } ntfs_loc = NULL; - DEBUG("Add resource for `%s' (size = %"PRIu64")", - dentry->file_name_utf8, - lte->resource_entry.original_size); copy_hash(lte->hash, attr_hash); lookup_table_insert(lookup_table, lte); } @@ -222,15 +222,6 @@ static int capture_ntfs_streams(struct wim_dentry *dentry, ntfs_inode *ni, if (name_length == 0) { /* Unnamed data stream. Put the reference to it in the * dentry's inode. */ - #if 0 - if (dentry->d_inode->i_lte) { - ERROR("Found two un-named data streams for " - "`%s'", path); - ret = WIMLIB_ERR_NTFS_3G; - goto out_free_lte; - } - dentry->d_inode->i_lte = lte; - #else if (dentry->d_inode->i_lte) { WARNING("Found two un-named data streams for " "`%s'", path); @@ -238,26 +229,17 @@ static int capture_ntfs_streams(struct wim_dentry *dentry, ntfs_inode *ni, } else { dentry->d_inode->i_lte = lte; } - #endif } else { /* Named data stream. Put the reference to it in the * alternate data stream entries */ struct wim_ads_entry *new_ads_entry; - size_t stream_name_utf8_len; - ret = utf16_to_utf8((const char*)attr_record_name(actx->attr), - name_length * 2, - &stream_name_utf8, - &stream_name_utf8_len); - if (ret != 0) - goto out_free_lte; - new_ads_entry = inode_add_ads(dentry->d_inode, stream_name_utf8); - FREE(stream_name_utf8); + new_ads_entry = inode_add_ads_utf16le(dentry->d_inode, + attr_record_name(actx->attr), + name_length * 2); if (!new_ads_entry) goto out_free_lte; - - wimlib_assert(new_ads_entry->stream_name_len == name_length * 2); - + wimlib_assert(new_ads_entry->stream_name_nbytes == name_length * 2); new_ads_entry->lte = lte; } } @@ -267,8 +249,8 @@ out_free_lte: free_lookup_table_entry(lte); out_free_ntfs_loc: if (ntfs_loc) { - FREE(ntfs_loc->path_utf8); - FREE(ntfs_loc->stream_name_utf16); + FREE(ntfs_loc->path); + FREE(ntfs_loc->stream_name); FREE(ntfs_loc); } out_put_actx: @@ -288,33 +270,33 @@ struct dos_name_map { struct dos_name_node { struct rb_node rb_node; char dos_name[24]; - int name_len_bytes; + int name_nbytes; u64 ntfs_ino; }; /* Inserts a new DOS name into the map */ -static int insert_dos_name(struct dos_name_map *map, - const ntfschar *dos_name, int name_len, - u64 ntfs_ino) +static int +insert_dos_name(struct dos_name_map *map, const ntfschar *dos_name, + size_t name_nbytes, u64 ntfs_ino) { struct dos_name_node *new_node; struct rb_node **p; struct rb_root *root; struct rb_node *rb_parent; - DEBUG("DOS name_len = %d", name_len); + DEBUG("DOS name_len = %zu", name_nbytes); new_node = MALLOC(sizeof(struct dos_name_node)); if (!new_node) return -1; /* DOS names are supposed to be 12 characters max (that's 24 bytes, * assuming 2-byte ntfs characters) */ - wimlib_assert(name_len * sizeof(ntfschar) <= sizeof(new_node->dos_name)); + wimlib_assert(name_nbytes <= sizeof(new_node->dos_name)); /* Initialize the DOS name, DOS name length, and NTFS inode number of * the red-black tree node */ - memcpy(new_node->dos_name, dos_name, name_len * sizeof(ntfschar)); - new_node->name_len_bytes = name_len * sizeof(ntfschar); + memcpy(new_node->dos_name, dos_name, name_nbytes); + new_node->name_nbytes = name_nbytes; new_node->ntfs_ino = ntfs_ino; /* Insert the red-black tree node */ @@ -364,7 +346,8 @@ lookup_dos_name(const struct dos_name_map *map, u64 ntfs_ino) return NULL; } -static int set_dentry_dos_name(struct wim_dentry *dentry, void *arg) +static int +set_dentry_dos_name(struct wim_dentry *dentry, void *arg) { const struct dos_name_map *map = arg; const struct dos_name_node *node; @@ -372,12 +355,13 @@ static int set_dentry_dos_name(struct wim_dentry *dentry, void *arg) if (dentry->is_win32_name) { node = lookup_dos_name(map, dentry->d_inode->i_ino); if (node) { - dentry->short_name = MALLOC(node->name_len_bytes); + dentry->short_name = MALLOC(node->name_nbytes + 2); if (!dentry->short_name) return WIMLIB_ERR_NOMEM; memcpy(dentry->short_name, node->dos_name, - node->name_len_bytes); - dentry->short_name_len = node->name_len_bytes; + node->name_nbytes); + dentry->short_name[node->name_nbytes / 2] = 0; + dentry->short_name_nbytes = node->name_nbytes; DEBUG("Assigned DOS name to ino %"PRIu64, dentry->d_inode->i_ino); } else { @@ -389,7 +373,8 @@ static int set_dentry_dos_name(struct wim_dentry *dentry, void *arg) return 0; } -static void free_dos_name_tree(struct rb_node *node) { +static void +free_dos_name_tree(struct rb_node *node) { if (node) { free_dos_name_tree(node->rb_left); free_dos_name_tree(node->rb_right); @@ -397,7 +382,8 @@ static void free_dos_name_tree(struct rb_node *node) { } } -static void destroy_dos_name_map(struct dos_name_map *map) +static void +destroy_dos_name_map(struct dos_name_map *map) { free_dos_name_tree(map->rb_root.rb_node); } @@ -405,7 +391,7 @@ static void destroy_dos_name_map(struct dos_name_map *map) struct readdir_ctx { struct wim_dentry *parent; ntfs_inode *dir_ni; - char *path; + mbchar *path; size_t path_len; struct wim_lookup_table *lookup_table; struct sd_set *sd_set; @@ -427,43 +413,45 @@ build_dentry_tree_ntfs_recursive(struct wim_dentry **root_p, ntfs_inode *dir_ni, int add_image_flags, wimlib_progress_func_t progress_func); -static int wim_ntfs_capture_filldir(void *dirent, const ntfschar *name, - const int name_len, const int name_type, - const s64 pos, const MFT_REF mref, - const unsigned dt_type) +static int +wim_ntfs_capture_filldir(void *dirent, const ntfschar *name, + const int name_nchars, const int name_type, + const s64 pos, const MFT_REF mref, + const unsigned dt_type) { struct readdir_ctx *ctx; - size_t utf8_name_len; - char *utf8_name; + size_t mbs_name_nbytes; + char *mbs_name; struct wim_dentry *child; int ret; size_t path_len; + size_t name_nbytes = name_nchars * sizeof(ntfschar); ctx = dirent; if (name_type & FILE_NAME_DOS) { /* If this is the entry for a DOS name, store it for later. */ ret = insert_dos_name(ctx->dos_name_map, name, - name_len, mref & MFT_REF_MASK_CPU); + name_nbytes, mref & MFT_REF_MASK_CPU); /* Return now if an error occurred or if this is just a DOS name * and not a Win32+DOS name. */ if (ret != 0 || name_type == FILE_NAME_DOS) return ret; } - ret = utf16_to_utf8((const char*)name, name_len * 2, - &utf8_name, &utf8_name_len); + ret = utf16le_to_mbs(name, name_nbytes, + &mbs_name, &mbs_name_nbytes); if (ret != 0) return -1; - if (utf8_name[0] == '.' && - (utf8_name[1] == '\0' || - (utf8_name[1] == '.' && utf8_name[2] == '\0'))) { + if (mbs_name[0] == '.' && + (mbs_name[1] == '\0' || + (mbs_name[1] == '.' && mbs_name[2] == '\0'))) { /* . or .. entries * * note: name_type is POSIX for these, so DOS names will not * have been inserted for them. */ ret = 0; - goto out_free_utf8_name; + goto out_free_mbs_name; } /* Open the inode for this directory entry and recursively capture the @@ -471,13 +459,13 @@ static int wim_ntfs_capture_filldir(void *dirent, const ntfschar *name, ntfs_inode *ni = ntfs_inode_open(ctx->dir_ni->vol, mref); if (!ni) { ERROR_WITH_ERRNO("Failed to open NTFS inode"); - goto out_free_utf8_name; + goto out_free_mbs_name; } path_len = ctx->path_len; if (path_len != 1) ctx->path[path_len++] = '/'; - memcpy(ctx->path + path_len, utf8_name, utf8_name_len + 1); - path_len += utf8_name_len; + memcpy(ctx->path + path_len, mbs_name, mbs_name_nbytes + 1); + path_len += mbs_name_nbytes; child = NULL; ret = build_dentry_tree_ntfs_recursive(&child, ctx->dir_ni, ni, ctx->path, path_len, name_type, @@ -488,8 +476,8 @@ static int wim_ntfs_capture_filldir(void *dirent, const ntfschar *name, if (child) dentry_add_child(ctx->parent, child); ntfs_inode_close(ni); -out_free_utf8_name: - FREE(utf8_name); +out_free_mbs_name: + FREE(mbs_name); return ret; } @@ -497,18 +485,19 @@ out_free_utf8_name: * At the same time, update the WIM lookup table with lookup table entries for * the NTFS streams, and build an array of security descriptors. */ -static int build_dentry_tree_ntfs_recursive(struct wim_dentry **root_p, - ntfs_inode *dir_ni, - ntfs_inode *ni, - char path[], - size_t path_len, - int name_type, - struct wim_lookup_table *lookup_table, - struct sd_set *sd_set, - const struct capture_config *config, - ntfs_volume **ntfs_vol_p, - int add_image_flags, - wimlib_progress_func_t progress_func) +static int +build_dentry_tree_ntfs_recursive(struct wim_dentry **root_p, + ntfs_inode *dir_ni, + ntfs_inode *ni, + mbchar *path, + size_t path_len, + int name_type, + struct wim_lookup_table *lookup_table, + struct sd_set *sd_set, + const struct capture_config *config, + ntfs_volume **ntfs_vol_p, + int add_image_flags, + wimlib_progress_func_t progress_func) { u32 attributes; int ret; @@ -552,15 +541,10 @@ static int build_dentry_tree_ntfs_recursive(struct wim_dentry **root_p, } /* Create the new WIM dentry */ - root = new_dentry_with_timeless_inode(path_basename(path)); - if (!root) { - if (errno == EILSEQ) - return WIMLIB_ERR_INVALID_UTF8_STRING; - else if (errno == ENOMEM) - return WIMLIB_ERR_NOMEM; - else - return WIMLIB_ERR_ICONV_NOT_AVAILABLE; - } + ret = new_dentry_with_timeless_inode(path_basename(path), &root); + if (ret) + return ret; + *root_p = root; if (name_type & FILE_NAME_WIN32) /* Win32 or Win32+DOS name */ @@ -645,14 +629,15 @@ static int build_dentry_tree_ntfs_recursive(struct wim_dentry **root_p, return ret; } -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) +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) { ntfs_volume *vol; ntfs_inode *root_ni; @@ -693,9 +678,9 @@ int build_dentry_tree_ntfs(struct wim_dentry **root_p, goto out; } - /* Currently we assume that all the UTF-8 paths fit into this length and - * there is no check for overflow. */ - char *path = MALLOC(32768); + /* Currently we assume that all the paths fit into this length and there + * is no check for overflow. */ + mbchar *path = MALLOC(32768); if (!path) { ERROR("Could not allocate memory for NTFS pathname"); ret = WIMLIB_ERR_NOMEM; diff --git a/src/resource.c b/src/resource.c index 0bffb3a6..24730ab4 100644 --- a/src/resource.c +++ b/src/resource.c @@ -590,7 +590,7 @@ read_wim_resource(const struct wim_lookup_table_entry *lte, void *buf, if (ntfs_attr_pread(lte->attr, offset, size, buf) != size) { ERROR_WITH_ERRNO("Error reading NTFS attribute " "at `%s'", - lte->ntfs_loc->path_utf8); + lte->ntfs_loc->path); ret = WIMLIB_ERR_NTFS_3G; } break; diff --git a/src/symlink.c b/src/symlink.c index 5c8417c7..49f2053b 100644 --- a/src/symlink.c +++ b/src/symlink.c @@ -41,20 +41,19 @@ * entry resource length. */ static ssize_t -get_symlink_name(const void *resource, size_t resource_len, - void *buf, size_t buf_len, - u32 reparse_tag) +get_symlink_name(const void *resource, size_t resource_len, mbchar *buf, + size_t buf_len, u32 reparse_tag) { const u8 *p = resource; u16 substitute_name_offset; u16 substitute_name_len; u16 print_name_offset; u16 print_name_len; - char *link_target; + mbchar *link_target; size_t link_target_len; ssize_t ret; unsigned header_size; - char *translated_target; + mbchar *translated_target; bool is_absolute; u32 flags; @@ -79,7 +78,7 @@ get_symlink_name(const void *resource, size_t resource_len, if (header_size + substitute_name_offset + substitute_name_len > resource_len) return -EIO; - ret = utf16_to_utf8((const char *)p + substitute_name_offset, + ret = utf16le_to_mbs((const utf16lechar*)(p + substitute_name_offset), substitute_name_len, &link_target, &link_target_len); if (ret == WIMLIB_ERR_INVALID_UTF16_STRING) @@ -133,37 +132,37 @@ 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; - size_t utf16_len; + utf16lechar *name_utf16le; + size_t name_utf16le_nbytes; int ret; - ret = utf8_to_utf16(symlink_target, utf8_len, - &name_utf16, &utf16_len); + ret = mbs_to_utf16le(symlink_target, strlen(symlink_target), + &name_utf16le, &name_utf16le_nbytes); if (ret != 0) return ret; - for (size_t i = 0; i < utf16_len / 2; i++) - if (((u16*)name_utf16)[i] == cpu_to_le16('/')) - ((u16*)name_utf16)[i] = cpu_to_le16('\\'); - size_t len = 12 + utf16_len * 2; + for (size_t i = 0; i < name_utf16le_nbytes / 2; i++) + if (name_utf16le[i] == cpu_to_le16('/')) + name_utf16le[i] = cpu_to_le16('\\'); + + size_t len = 12 + name_utf16le_nbytes * 2; void *buf = MALLOC(len); if (buf) { u8 *p = buf; - p = put_u16(p, utf16_len); /* Substitute name offset */ - p = put_u16(p, utf16_len); /* Substitute name length */ + p = put_u16(p, name_utf16le_nbytes); /* Substitute name offset */ + p = put_u16(p, name_utf16le_nbytes); /* Substitute name length */ p = put_u16(p, 0); /* Print name offset */ - p = put_u16(p, utf16_len); /* Print name length */ + p = put_u16(p, name_utf16le_nbytes); /* Print name length */ p = put_u32(p, 1); /* flags: 0 iff *full* target, including drive letter??? */ - p = put_bytes(p, utf16_len, (const u8*)name_utf16); - p = put_bytes(p, utf16_len, (const u8*)name_utf16); + p = put_bytes(p, name_utf16le_nbytes, name_utf16le); + p = put_bytes(p, name_utf16le_nbytes, name_utf16le); *len_ret = len; *buf_ret = buf; ret = 0; } else { ret = WIMLIB_ERR_NOMEM; } - FREE(name_utf16); + FREE(name_utf16le); return ret; } diff --git a/src/util.c b/src/util.c index 626fba49..eb0ea9af 100644 --- a/src/util.c +++ b/src/util.c @@ -51,7 +51,7 @@ static size_t utf16le_strlen(const utf16lechar *s) { const utf16lechar *p = s; - while (p) + while (*p) p++; return (p - s) / sizeof(utf16lechar); } @@ -67,31 +67,31 @@ 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')) + 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')) { + if (*p == '%' && (*(p + 1) == 'W' || *(p + 1) == 'U')) { int ret; mbchar *mbs; - size_t mbs_len; + size_t mbs_nbytes; 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); + &mbs, &mbs_nbytes); } else { utf8char *ucs = va_arg(va, utf8char*); size_t ucs_nbytes = strlen(ucs); ret = utf8_to_mbs(ucs, ucs_nbytes, - &mbs, &mbs_len); + &mbs, &mbs_nbytes); } if (ret) { - ret = fprintf(fp, "???"); + ret = fprintf(fp, "???CONVERSION FAILURE???"); } else { ret = fprintf(fp, "%s", mbs); FREE(mbs); @@ -100,6 +100,7 @@ special: return -1; else n += ret; + p++; } else { if (putc(*p, fp) == EOF) return -1; @@ -348,7 +349,7 @@ static const mbchar *error_strings[] = { WIMLIBAPI const mbchar * wimlib_get_error_string(enum wimlib_error_code code) { - if (code < WIMLIB_ERR_SUCCESS || code > WIMLIB_ERR_XML) + if (code < 0 || code >= ARRAY_LEN(error_strings)) return NULL; else return error_strings[code]; diff --git a/src/util.h b/src/util.h index 71590ffe..58a2f2b4 100644 --- a/src/util.h +++ b/src/util.h @@ -67,6 +67,40 @@ typedef char utf8char; /* A pointer to 'utf16lechar' indicates a UTF-16LE encoded string */ typedef u16 utf16lechar; +/* encoding.c */ +extern void +iconv_global_cleanup(); + +extern bool wimlib_mbs_is_utf8; + +#define DECLARE_CHAR_CONVERSION_FUNCTIONS(varname1, varname2, \ + chartype1, chartype2) \ + \ +extern int \ +varname1##_to_##varname2##_nbytes(const chartype1 *in, size_t in_nbytes,\ + size_t *out_nbytes_ret); \ + \ +extern int \ +varname1##_to_##varname2##_buf(const chartype1 *in, size_t in_nbytes, \ + chartype2 *out); \ + \ +extern int \ +varname1##_to_##varname2(const chartype1 *in, size_t in_nbytes, \ + chartype2 **out_ret, \ + size_t *out_nbytes_ret); \ + +/* multi-byte string to UTF16-LE string */ +DECLARE_CHAR_CONVERSION_FUNCTIONS(mbs, utf16le, mbchar, utf16lechar); + +/* UTF16-LE string to multi-byte string */ +DECLARE_CHAR_CONVERSION_FUNCTIONS(utf16le, mbs, utf16lechar, mbchar); + +/* UTF-8 string to multi-byte string */ +DECLARE_CHAR_CONVERSION_FUNCTIONS(utf8, mbs, utf8char, mbchar); + +extern bool +utf8_str_contains_nonascii_chars(const utf8char *utf8_str); + #ifndef min #define min(a, b) ({ typeof(a) __a = (a); typeof(b) __b = (b); \ (__a < __b) ? __a : __b; }) diff --git a/src/verify.c b/src/verify.c index eae4b386..62e9547e 100644 --- a/src/verify.c +++ b/src/verify.c @@ -43,15 +43,15 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w) * image's security descriptors table. */ if (inode->i_security_id < -1) { ERROR("Dentry `%s' has an invalid security ID (%d)", - first_dentry->full_path_utf8, inode->i_security_id); + first_dentry->full_path, inode->i_security_id); goto out; } if (inode->i_security_id >= sd->num_entries) { ERROR("Dentry `%s' has an invalid security ID (%d) " "(there are only %u entries in the security table)", - first_dentry->full_path_utf8, inode->i_security_id, - sd->num_entries); + first_dentry->full_path, inode->i_security_id, + sd->num_entries); goto out; } @@ -68,7 +68,7 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w) lte = __lookup_resource(table, hash); if (!lte && !is_zero_hash(hash)) { ERROR("Could not find lookup table entry for stream " - "%u of dentry `%s'", i, first_dentry->full_path_utf8); + "%u of dentry `%s'", i, first_dentry->full_path); goto out; } if (lte) @@ -119,12 +119,12 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w) for (unsigned i = 0; i <= inode->i_num_ads; i++) { const u8 *hash; hash = inode_stream_hash_unresolved(inode, i); - if (inode_stream_name_len(inode, i) == 0 && !is_zero_hash(hash)) + if (inode_stream_name_nbytes(inode, i) == 0 && !is_zero_hash(hash)) num_unnamed_streams++; } if (num_unnamed_streams > 1) { ERROR("Dentry `%s' has multiple (%u) un-named streams", - first_dentry->full_path_utf8, num_unnamed_streams); + first_dentry->full_path, num_unnamed_streams); goto out; } @@ -133,12 +133,12 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w) * Source: NTFS-3g authors. */ const struct wim_dentry *dentry_with_dos_name = NULL; inode_for_each_dentry(dentry, inode) { - if (dentry->short_name_len) { + if (dentry_has_short_name(dentry)) { if (dentry_with_dos_name) { ERROR("Hard-linked file has a DOS name at " "both `%s' and `%s'", - dentry_with_dos_name->full_path_utf8, - dentry->full_path_utf8); + dentry_with_dos_name->full_path, + dentry->full_path); goto out; } dentry_with_dos_name = dentry; @@ -148,7 +148,7 @@ static int verify_inode(struct wim_inode *inode, const WIMStruct *w) /* Directories with multiple links have not been tested. XXX */ if (inode->i_nlink > 1 && inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) { ERROR("Hard-linked directory `%s' is unsupported", - first_dentry->full_path_utf8); + first_dentry->full_path); goto out; } @@ -179,15 +179,14 @@ int verify_dentry(struct wim_dentry *dentry, void *wim) * into a single WIM dentry, even if they are stored separately on NTFS. * (This seems to be the case...) */ if (dentry_is_root(dentry)) { - if (dentry->file_name_len || dentry->short_name_len) { - ERROR("The root dentry is named `%s', but it must " - "be unnamed", dentry->file_name_utf8); + if (dentry_has_long_name(dentry) || dentry_has_short_name(dentry)) { + ERROR("The root dentry has a nonempty name!"); return WIMLIB_ERR_INVALID_DENTRY; } } else { - if (!dentry->file_name_len) { - ERROR("Dentry `%s' has no long name", - dentry->full_path_utf8); + if (!dentry_has_long_name(dentry)) { + ERROR("Dentry `%s' has no long name!", + dentry->full_path); return WIMLIB_ERR_INVALID_DENTRY; } } diff --git a/src/wim.c b/src/wim.c index 6df2c71e..45b9fd62 100644 --- a/src/wim.c +++ b/src/wim.c @@ -48,7 +48,8 @@ #include "wimlib_internal.h" #include "xml.h" -static int image_print_metadata(WIMStruct *w) +static int +image_print_metadata(WIMStruct *w) { DEBUG("Printing metadata for image %d", w->current_image); print_security_data(wim_security_data(w)); @@ -57,13 +58,15 @@ static int image_print_metadata(WIMStruct *w) } -static int image_print_files(WIMStruct *w) +static int +image_print_files(WIMStruct *w) { return for_dentry_in_tree(wim_root_dentry(w), print_dentry_full_path, NULL); } -static WIMStruct *new_wim_struct() +static WIMStruct * +new_wim_struct() { WIMStruct *w = CALLOC(1, sizeof(WIMStruct)); #ifdef WITH_FUSE @@ -83,7 +86,8 @@ static WIMStruct *new_wim_struct() * current image in turn. If @image is a certain image, @visitor is called on * the WIM only once, with that image selected. */ -int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *)) +int +for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *)) { int ret; int start; @@ -110,7 +114,8 @@ int for_image(WIMStruct *w, int image, int (*visitor)(WIMStruct *)) return 0; } -static int sort_image_metadata_by_position(const void *p1, const void *p2) +static int +sort_image_metadata_by_position(const void *p1, const void *p2) { const struct wim_image_metadata *imd1 = p1; const struct wim_image_metadata *imd2 = p2; @@ -128,8 +133,8 @@ static int sort_image_metadata_by_position(const void *p1, const void *p2) * If @lte points to a metadata resource, append it to the list of metadata * resources in the WIMStruct. Otherwise, do nothing. */ -static int append_metadata_resource_entry(struct wim_lookup_table_entry *lte, - void *wim_p) +static int +append_metadata_resource_entry(struct wim_lookup_table_entry *lte, void *wim_p) { WIMStruct *w = wim_p; int ret = 0; @@ -153,7 +158,8 @@ static int append_metadata_resource_entry(struct wim_lookup_table_entry *lte, } /* Returns the compression type given in the flags of a WIM header. */ -static int wim_hdr_flags_compression_type(int wim_hdr_flags) +static int +wim_hdr_flags_compression_type(int wim_hdr_flags) { if (wim_hdr_flags & WIM_HDR_FLAG_COMPRESSION) { if (wim_hdr_flags & WIM_HDR_FLAG_COMPRESS_LZX) @@ -170,7 +176,8 @@ static int wim_hdr_flags_compression_type(int wim_hdr_flags) /* * Creates a WIMStruct for a new WIM file. */ -WIMLIBAPI int wimlib_create_new_wim(int ctype, WIMStruct **w_ret) +WIMLIBAPI int +wimlib_create_new_wim(int ctype, WIMStruct **w_ret) { WIMStruct *w; struct wim_lookup_table *table; @@ -201,12 +208,14 @@ out_free: return ret; } -WIMLIBAPI int wimlib_get_num_images(const WIMStruct *w) +WIMLIBAPI int +wimlib_get_num_images(const WIMStruct *w) { return w->hdr.image_count; } -int select_wim_image(WIMStruct *w, int image) +int +select_wim_image(WIMStruct *w, int image) { struct wim_image_metadata *imd; int ret; @@ -258,12 +267,14 @@ int select_wim_image(WIMStruct *w, int image) /* Returns the compression type of the WIM file. */ -WIMLIBAPI int wimlib_get_compression_type(const WIMStruct *w) +WIMLIBAPI int +wimlib_get_compression_type(const WIMStruct *w) { return wim_hdr_flags_compression_type(w->hdr.flags); } -WIMLIBAPI const char *wimlib_get_compression_type_string(int ctype) +WIMLIBAPI const char * +wimlib_get_compression_type_string(int ctype) { switch (ctype) { case WIMLIB_COMPRESSION_TYPE_NONE: @@ -282,7 +293,8 @@ WIMLIBAPI const char *wimlib_get_compression_type_string(int ctype) * the number of the image, or the name of the image. The images are numbered * starting at 1. */ -WIMLIBAPI int wimlib_resolve_image(WIMStruct *w, const char *image_name_or_num) +WIMLIBAPI int +wimlib_resolve_image(WIMStruct *w, const utf8char *image_name_or_num) { char *p; int image; @@ -311,7 +323,8 @@ WIMLIBAPI int wimlib_resolve_image(WIMStruct *w, const char *image_name_or_num) /* Prints some basic information about a WIM file. */ -WIMLIBAPI void wimlib_print_wim_information(const WIMStruct *w) +WIMLIBAPI void +wimlib_print_wim_information(const WIMStruct *w) { const struct wim_header *hdr; @@ -333,12 +346,14 @@ WIMLIBAPI void wimlib_print_wim_information(const WIMStruct *w) putchar('\n'); } -WIMLIBAPI bool wimlib_has_integrity_table(const WIMStruct *w) +WIMLIBAPI bool +wimlib_has_integrity_table(const WIMStruct *w) { return w->hdr.integrity.size != 0; } -WIMLIBAPI void wimlib_print_available_images(const WIMStruct *w, int image) +WIMLIBAPI void +wimlib_print_available_images(const WIMStruct *w, int image) { int first; int last; @@ -367,7 +382,8 @@ WIMLIBAPI void wimlib_print_available_images(const WIMStruct *w, int image) /* Prints the metadata for the specified image, which may be WIMLIB_ALL_IMAGES, but * not WIMLIB_NO_IMAGE. */ -WIMLIBAPI int wimlib_print_metadata(WIMStruct *w, int image) +WIMLIBAPI int +wimlib_print_metadata(WIMStruct *w, int image) { if (w->hdr.part_number != 1) { ERROR("Cannot show the metadata from part %hu of a %hu-part split WIM!", @@ -378,7 +394,8 @@ WIMLIBAPI int wimlib_print_metadata(WIMStruct *w, int image) return for_image(w, image, image_print_metadata); } -WIMLIBAPI int wimlib_print_files(WIMStruct *w, int image) +WIMLIBAPI int +wimlib_print_files(WIMStruct *w, int image) { if (w->hdr.part_number != 1) { ERROR("Cannot list the files from part %hu of a %hu-part split WIM!", @@ -390,7 +407,8 @@ WIMLIBAPI int wimlib_print_files(WIMStruct *w, int image) } /* Sets the index of the bootable image. */ -WIMLIBAPI int wimlib_set_boot_idx(WIMStruct *w, int boot_idx) +WIMLIBAPI int +wimlib_set_boot_idx(WIMStruct *w, int boot_idx) { if (w->hdr.total_parts != 1) { ERROR("Cannot modify the boot index of a split WIM!"); @@ -413,7 +431,8 @@ WIMLIBAPI int wimlib_set_boot_idx(WIMStruct *w, int boot_idx) return 0; } -WIMLIBAPI int wimlib_get_part_number(const WIMStruct *w, int *total_parts_ret) +WIMLIBAPI int +wimlib_get_part_number(const WIMStruct *w, int *total_parts_ret) { if (total_parts_ret) *total_parts_ret = w->hdr.total_parts; @@ -421,7 +440,8 @@ WIMLIBAPI int wimlib_get_part_number(const WIMStruct *w, int *total_parts_ret) } -WIMLIBAPI int wimlib_get_boot_idx(const WIMStruct *w) +WIMLIBAPI int +wimlib_get_boot_idx(const WIMStruct *w) { return w->hdr.boot_idx; } @@ -430,8 +450,9 @@ WIMLIBAPI int wimlib_get_boot_idx(const WIMStruct *w) * Begins the reading of a WIM file; opens the file and reads its header and * lookup table, and optionally checks the integrity. */ -static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags, - wimlib_progress_func_t progress_func) +static int +begin_read(WIMStruct *w, const mbchar *in_wim_path, int open_flags, + wimlib_progress_func_t progress_func) { int ret; int xml_num_images; @@ -563,13 +584,13 @@ static int begin_read(WIMStruct *w, const char *in_wim_path, int open_flags, return 0; } - /* * Opens a WIM file and creates a WIMStruct for it. */ -WIMLIBAPI int wimlib_open_wim(const char *wim_file, int open_flags, - WIMStruct **w_ret, - wimlib_progress_func_t progress_func) +WIMLIBAPI int +wimlib_open_wim(const mbchar *wim_file, int open_flags, + WIMStruct **w_ret, + wimlib_progress_func_t progress_func) { WIMStruct *w; int ret; @@ -589,8 +610,9 @@ WIMLIBAPI int wimlib_open_wim(const char *wim_file, int open_flags, return ret; } -void destroy_image_metadata(struct wim_image_metadata *imd, - struct wim_lookup_table *table) +void +destroy_image_metadata(struct wim_image_metadata *imd, + struct wim_lookup_table *table) { free_dentry_tree(imd->root_dentry, table); free_security_data(imd->security_data); @@ -605,7 +627,8 @@ void destroy_image_metadata(struct wim_image_metadata *imd, /* Frees the memory for the WIMStruct, including all internal memory; also * closes all files associated with the WIMStruct. */ -WIMLIBAPI void wimlib_free(WIMStruct *w) +WIMLIBAPI void +wimlib_free(WIMStruct *w) { DEBUG("Freeing WIMStruct"); @@ -650,18 +673,21 @@ 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() +WIMLIBAPI int +wimlib_global_init() { - char *encoding; - libxml_global_init(); +#ifdef WITH_NTFS_3G + libntfs3g_global_init(); +#endif wimlib_mbs_is_utf8 = (strcmp(nl_langinfo(CODESET), "UTF-8") == 0); - return iconv_global_init(); + return 0; } /* Free global memory allocations. Not strictly necessary if the process using * wimlib is just about to exit (as is the case for 'imagex'). */ -WIMLIBAPI void wimlib_global_cleanup() +WIMLIBAPI void +wimlib_global_cleanup() { libxml_global_cleanup(); iconv_global_cleanup(); diff --git a/src/wimlib_internal.h b/src/wimlib_internal.h index 580960fa..be06dafd 100644 --- a/src/wimlib_internal.h +++ b/src/wimlib_internal.h @@ -376,54 +376,6 @@ 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 */ @@ -504,6 +456,9 @@ apply_dentry_ntfs(struct wim_dentry *dentry, void *arg); extern int apply_dentry_timestamps_ntfs(struct wim_dentry *dentry, void *arg); +extern void +libntfs3g_global_init(); + /* ntfs-capture.c */ extern int build_dentry_tree_ntfs(struct wim_dentry **root_p, diff --git a/src/write.c b/src/write.c index a05d281e..bd5b05ef 100644 --- a/src/write.c +++ b/src/write.c @@ -67,7 +67,8 @@ #include -static int fflush_and_ftruncate(FILE *fp, off_t size) +static int +fflush_and_ftruncate(FILE *fp, off_t size) { int ret; @@ -161,7 +162,8 @@ out: */ typedef int (*compress_func_t)(const void *, unsigned, void *, unsigned *); -compress_func_t get_compress_func(int out_ctype) +compress_func_t +get_compress_func(int out_ctype) { if (out_ctype == WIMLIB_COMPRESSION_TYPE_LZX) return lzx_compress; @@ -182,9 +184,10 @@ compress_func_t get_compress_func(int out_ctype) * * Returns 0 on success; nonzero on failure. */ -static int write_wim_resource_chunk(const u8 chunk[], unsigned chunk_size, - FILE *out_fp, compress_func_t compress, - struct chunk_table *chunk_tab) +static int +write_wim_resource_chunk(const u8 chunk[], unsigned chunk_size, + FILE *out_fp, compress_func_t compress, + struct chunk_table *chunk_tab) { const u8 *out_chunk; unsigned out_chunk_size; @@ -256,12 +259,13 @@ finish_wim_resource_chunk_tab(struct chunk_table *chunk_tab, /* Prepare for multiple reads to a resource by caching a FILE * or NTFS * attribute pointer in the lookup table entry. */ -static int prepare_resource_for_read(struct wim_lookup_table_entry *lte +static int +prepare_resource_for_read(struct wim_lookup_table_entry *lte - #ifdef WITH_NTFS_3G - , ntfs_inode **ni_ret - #endif - ) + #ifdef WITH_NTFS_3G + , ntfs_inode **ni_ret + #endif + ) { switch (lte->resource_location) { case RESOURCE_IN_FILE_ON_DISK: @@ -280,19 +284,19 @@ static int prepare_resource_for_read(struct wim_lookup_table_entry *lte struct ntfs_location *loc = lte->ntfs_loc; ntfs_inode *ni; wimlib_assert(loc); - ni = ntfs_pathname_to_inode(*loc->ntfs_vol_p, NULL, loc->path_utf8); + ni = ntfs_pathname_to_inode(*loc->ntfs_vol_p, NULL, loc->path); if (!ni) { ERROR_WITH_ERRNO("Failed to open inode `%s' in NTFS " - "volume", loc->path_utf8); + "volume", loc->path); return WIMLIB_ERR_NTFS_3G; } lte->attr = ntfs_attr_open(ni, loc->is_reparse_point ? AT_REPARSE_POINT : AT_DATA, - (ntfschar*)loc->stream_name_utf16, - loc->stream_name_utf16_num_chars); + loc->stream_name, + loc->stream_name_nchars); if (!lte->attr) { ERROR_WITH_ERRNO("Failed to open attribute of `%s' in " - "NTFS volume", loc->path_utf8); + "NTFS volume", loc->path); ntfs_inode_close(ni); return WIMLIB_ERR_NTFS_3G; } @@ -317,11 +321,12 @@ static int prepare_resource_for_read(struct wim_lookup_table_entry *lte /* Undo prepare_resource_for_read() by closing the cached FILE * or NTFS * attribute. */ -static void end_wim_resource_read(struct wim_lookup_table_entry *lte - #ifdef WITH_NTFS_3G - , ntfs_inode *ni - #endif - ) +static void +end_wim_resource_read(struct wim_lookup_table_entry *lte + #ifdef WITH_NTFS_3G + , ntfs_inode *ni + #endif + ) { if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK && lte->file_on_disk_fp) @@ -391,10 +396,11 @@ write_uncompressed_resource_and_truncate(struct wim_lookup_table_entry *lte, * * Returns 0 on success; nonzero on failure. */ -int write_wim_resource(struct wim_lookup_table_entry *lte, - FILE *out_fp, int out_ctype, - struct resource_entry *out_res_entry, - int flags) +int +write_wim_resource(struct wim_lookup_table_entry *lte, + FILE *out_fp, int out_ctype, + struct resource_entry *out_res_entry, + int flags) { u64 bytes_remaining; u64 original_size; @@ -588,7 +594,8 @@ struct shared_queue { pthread_cond_t space_avail_cond; }; -static int shared_queue_init(struct shared_queue *q, unsigned size) +static int +shared_queue_init(struct shared_queue *q, unsigned size) { wimlib_assert(size != 0); q->array = CALLOC(sizeof(q->array[0]), size); @@ -604,7 +611,8 @@ static int shared_queue_init(struct shared_queue *q, unsigned size) return 0; } -static void shared_queue_destroy(struct shared_queue *q) +static void +shared_queue_destroy(struct shared_queue *q) { FREE(q->array); pthread_mutex_destroy(&q->lock); @@ -612,7 +620,8 @@ static void shared_queue_destroy(struct shared_queue *q) pthread_cond_destroy(&q->space_avail_cond); } -static void shared_queue_put(struct shared_queue *q, void *obj) +static void +shared_queue_put(struct shared_queue *q, void *obj) { pthread_mutex_lock(&q->lock); while (q->filled_slots == q->size) @@ -626,7 +635,8 @@ static void shared_queue_put(struct shared_queue *q, void *obj) pthread_mutex_unlock(&q->lock); } -static void *shared_queue_get(struct shared_queue *q) +static void * +shared_queue_get(struct shared_queue *q) { void *obj; @@ -665,7 +675,8 @@ struct message { u64 begin_chunk; }; -static void compress_chunks(struct message *msg, compress_func_t compress) +static void +compress_chunks(struct message *msg, compress_func_t compress) { for (unsigned i = 0; i < msg->num_chunks; i++) { DEBUG2("compress chunk %u of %u", i, msg->num_chunks); @@ -687,7 +698,8 @@ static void compress_chunks(struct message *msg, compress_func_t compress) * res_to_compress_queue, compress them, and put them in the * compressed_res_queue. A NULL pointer indicates that the thread should stop. * */ -static void *compressor_thread_proc(void *arg) +static void * +compressor_thread_proc(void *arg) { struct compressor_thread_params *params = arg; struct shared_queue *res_to_compress_queue = params->res_to_compress_queue; @@ -703,14 +715,15 @@ static void *compressor_thread_proc(void *arg) DEBUG("Compressor thread terminating"); return NULL; } -#endif +#endif /* ENABLE_MULTITHREADED_COMPRESSION */ -static int do_write_stream_list(struct list_head *my_resources, - FILE *out_fp, - int out_ctype, - wimlib_progress_func_t progress_func, - union wimlib_progress_info *progress, - int write_resource_flags) +static int +do_write_stream_list(struct list_head *my_resources, + FILE *out_fp, + int out_ctype, + wimlib_progress_func_t progress_func, + union wimlib_progress_info *progress, + int write_resource_flags) { int ret; struct wim_lookup_table_entry *lte, *tmp; @@ -735,12 +748,13 @@ static int do_write_stream_list(struct list_head *my_resources, return 0; } -static int write_stream_list_serial(struct list_head *stream_list, - FILE *out_fp, - int out_ctype, - int write_flags, - wimlib_progress_func_t progress_func, - union wimlib_progress_info *progress) +static int +write_stream_list_serial(struct list_head *stream_list, + FILE *out_fp, + int out_ctype, + int write_flags, + wimlib_progress_func_t progress_func, + union wimlib_progress_info *progress) { int write_resource_flags; @@ -757,8 +771,9 @@ static int write_stream_list_serial(struct list_head *stream_list, } #ifdef ENABLE_MULTITHREADED_COMPRESSION -static int write_wim_chunks(struct message *msg, FILE *out_fp, - struct chunk_table *chunk_tab) +static int +write_wim_chunks(struct message *msg, FILE *out_fp, + struct chunk_table *chunk_tab) { for (unsigned i = 0; i < msg->num_chunks; i++) { unsigned chunk_csize = msg->compressed_chunk_sizes[i]; @@ -791,15 +806,16 @@ static int write_wim_chunks(struct message *msg, FILE *out_fp, * res_to_compress_queue, and it is passed back through the * compressed_res_queue. */ -static int main_writer_thread_proc(struct list_head *stream_list, - FILE *out_fp, - int out_ctype, - struct shared_queue *res_to_compress_queue, - struct shared_queue *compressed_res_queue, - size_t num_messages, - int write_flags, - wimlib_progress_func_t progress_func, - union wimlib_progress_info *progress) +static int +main_writer_thread_proc(struct list_head *stream_list, + FILE *out_fp, + int out_ctype, + struct shared_queue *res_to_compress_queue, + struct shared_queue *compressed_res_queue, + size_t num_messages, + int write_flags, + wimlib_progress_func_t progress_func, + union wimlib_progress_info *progress) { int ret; struct chunk_table *cur_chunk_tab = NULL; @@ -1211,7 +1227,8 @@ out: return ret; } -static long get_default_num_threads() +static long +get_default_num_threads() { #ifdef __WIN32__ return win32_get_number_of_processors(); @@ -1220,13 +1237,14 @@ static long get_default_num_threads() #endif } -static int write_stream_list_parallel(struct list_head *stream_list, - FILE *out_fp, - int out_ctype, - int write_flags, - unsigned num_threads, - wimlib_progress_func_t progress_func, - union wimlib_progress_info *progress) +static int +write_stream_list_parallel(struct list_head *stream_list, + FILE *out_fp, + int out_ctype, + int write_flags, + unsigned num_threads, + wimlib_progress_func_t progress_func, + union wimlib_progress_info *progress) { int ret; struct shared_queue res_to_compress_queue; @@ -1328,10 +1346,11 @@ out_serial: * Write a list of streams to a WIM (@out_fp) using the compression type * @out_ctype and up to @num_threads compressor threads. */ -static int write_stream_list(struct list_head *stream_list, FILE *out_fp, - int out_ctype, int write_flags, - unsigned num_threads, - wimlib_progress_func_t progress_func) +static int +write_stream_list(struct list_head *stream_list, FILE *out_fp, + int out_ctype, int write_flags, + unsigned num_threads, + wimlib_progress_func_t progress_func) { struct wim_lookup_table_entry *lte; size_t num_streams = 0; @@ -1381,7 +1400,8 @@ struct lte_overwrite_prepare_args { struct list_head *stream_list; }; -static int lte_overwrite_prepare(struct wim_lookup_table_entry *lte, void *arg) +static int +lte_overwrite_prepare(struct wim_lookup_table_entry *lte, void *arg) { struct lte_overwrite_prepare_args *args = arg; @@ -1407,8 +1427,9 @@ static int lte_overwrite_prepare(struct wim_lookup_table_entry *lte, void *arg) return 0; } -static int wim_find_new_streams(WIMStruct *wim, off_t end_offset, - struct list_head *stream_list) +static int +wim_find_new_streams(WIMStruct *wim, off_t end_offset, + struct list_head *stream_list) { struct lte_overwrite_prepare_args args = { .wim = wim, @@ -1420,9 +1441,10 @@ static int wim_find_new_streams(WIMStruct *wim, off_t end_offset, lte_overwrite_prepare, &args); } -static int inode_find_streams_to_write(struct wim_inode *inode, - struct wim_lookup_table *table, - struct list_head *stream_list) +static int +inode_find_streams_to_write(struct wim_inode *inode, + struct wim_lookup_table *table, + struct list_head *stream_list) { struct wim_lookup_table_entry *lte; for (unsigned i = 0; i <= inode->i_num_ads; i++) { @@ -1436,7 +1458,8 @@ static int inode_find_streams_to_write(struct wim_inode *inode, return 0; } -static int image_find_streams_to_write(WIMStruct *w) +static int +image_find_streams_to_write(WIMStruct *w) { struct wim_inode *inode; struct hlist_node *cur; @@ -1450,7 +1473,8 @@ static int image_find_streams_to_write(WIMStruct *w) return 0; } -static int write_wim_streams(WIMStruct *w, int image, int write_flags, +static int +write_wim_streams(WIMStruct *w, int image, int write_flags, unsigned num_threads, wimlib_progress_func_t progress_func) { @@ -1493,8 +1517,9 @@ static int write_wim_streams(WIMStruct *w, int image, int write_flags, * fsync() the output file before closing it. * */ -int finish_write(WIMStruct *w, int image, int write_flags, - wimlib_progress_func_t progress_func) +int +finish_write(WIMStruct *w, int image, int write_flags, + wimlib_progress_func_t progress_func) { int ret; struct wim_header hdr; @@ -1627,7 +1652,8 @@ out: } #if defined(HAVE_SYS_FILE_H) && defined(HAVE_FLOCK) -int lock_wim(WIMStruct *w, FILE *fp) +int +lock_wim(WIMStruct *w, FILE *fp) { int ret = 0; if (fp && !w->wim_locked) { @@ -1651,8 +1677,9 @@ int lock_wim(WIMStruct *w, FILE *fp) } #endif -static int open_wim_writable(WIMStruct *w, const char *path, - bool trunc, bool readable) +static int +open_wim_writable(WIMStruct *w, const mbchar *path, + bool trunc, bool readable) { const char *mode; if (trunc) @@ -1674,7 +1701,8 @@ static int open_wim_writable(WIMStruct *w, const char *path, } -void close_wim_writable(WIMStruct *w) +void +close_wim_writable(WIMStruct *w) { if (w->out_fp) { if (fclose(w->out_fp) != 0) { @@ -1685,7 +1713,8 @@ void close_wim_writable(WIMStruct *w) } /* Open file stream and write dummy header for WIM. */ -int begin_write(WIMStruct *w, const char *path, int write_flags) +int +begin_write(WIMStruct *w, const mbchar *path, int write_flags) { int ret; ret = open_wim_writable(w, path, true, @@ -1697,9 +1726,10 @@ int begin_write(WIMStruct *w, const char *path, int write_flags) } /* Writes a stand-alone WIM to a file. */ -WIMLIBAPI int wimlib_write(WIMStruct *w, const char *path, - int image, int write_flags, unsigned num_threads, - wimlib_progress_func_t progress_func) +WIMLIBAPI int +wimlib_write(WIMStruct *w, const mbchar *path, + int image, int write_flags, unsigned num_threads, + wimlib_progress_func_t progress_func) { int ret; @@ -1743,7 +1773,8 @@ out: return ret; } -static bool any_images_modified(WIMStruct *w) +static bool +any_images_modified(WIMStruct *w) { for (int i = 0; i < w->hdr.image_count; i++) if (w->image_metadata[i].modified) @@ -1808,9 +1839,10 @@ static bool any_images_modified(WIMStruct *w) * table, xml data, and integrity table were. (These usually only take up a * small amount of space compared to the streams, however.) */ -static int overwrite_wim_inplace(WIMStruct *w, int write_flags, - unsigned num_threads, - wimlib_progress_func_t progress_func) +static int +overwrite_wim_inplace(WIMStruct *w, int write_flags, + unsigned num_threads, + wimlib_progress_func_t progress_func) { int ret; struct list_head stream_list; @@ -1913,9 +1945,10 @@ out_ftruncate: return ret; } -static int overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags, - unsigned num_threads, - wimlib_progress_func_t progress_func) +static int +overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags, + unsigned num_threads, + wimlib_progress_func_t progress_func) { size_t wim_name_len; int ret; @@ -1925,7 +1958,7 @@ static int overwrite_wim_via_tmpfile(WIMStruct *w, int write_flags, /* Write the WIM to a temporary file in the same directory as the * original WIM. */ wim_name_len = strlen(w->filename); - char tmpfile[wim_name_len + 10]; + mbchar tmpfile[wim_name_len + 10]; memcpy(tmpfile, w->filename, wim_name_len); randomize_char_array_with_alnum(tmpfile + wim_name_len, 9); tmpfile[wim_name_len + 9] = '\0'; @@ -1981,9 +2014,10 @@ err: /* * Writes a WIM file to the original file that it was read from, overwriting it. */ -WIMLIBAPI int wimlib_overwrite(WIMStruct *w, int write_flags, - unsigned num_threads, - wimlib_progress_func_t progress_func) +WIMLIBAPI int +wimlib_overwrite(WIMStruct *w, int write_flags, + unsigned num_threads, + wimlib_progress_func_t progress_func) { write_flags &= WIMLIB_WRITE_MASK_PUBLIC; diff --git a/src/xml.c b/src/xml.c index 6515ee98..0ea13f83 100644 --- a/src/xml.c +++ b/src/xml.c @@ -1074,7 +1074,7 @@ calculate_dentry_statistics(struct wim_dentry *dentry, void *arg) if (inode->i_nlink >= 2 && dentry_is_first_in_inode(dentry)) { for (unsigned i = 0; i < inode->i_num_ads; i++) { - if (inode->i_ads_entries[i].stream_name_len) { + if (inode->i_ads_entries[i].stream_name_nbytes) { lte = inode_stream_lte(inode, i + 1, lookup_table); if (lte) { info->hard_link_bytes += inode->i_nlink * @@ -1266,8 +1266,8 @@ read_xml_data(FILE *fp, const struct resource_entry *res_entry, DEBUG("Parsing XML using libxml2 to create XML tree"); - doc = xmlReadMemory(xml_data, res_entry->size, - "noname.xml", "UTF-16", 0); + doc = xmlReadMemory((const char *)xml_data, + res_entry->size, "noname.xml", "UTF-16", 0); if (!doc) { ERROR("Failed to parse XML data"); -- 2.43.0