X-Git-Url: https://wimlib.net/git/?p=wimlib;a=blobdiff_plain;f=src%2Fdentry.c;h=58869af4b6b921fb18d84d4fdca302a05a594c66;hp=1165ed723a638a99a42e8fbf8a0eb93f2a37819c;hb=922ad680d3e260262372fd1a9dad65045ffe6074;hpb=1530b6dab02a9e1e5faf81529ab502aee68d8cd2 diff --git a/src/dentry.c b/src/dentry.c index 1165ed72..58869af4 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -9,7 +9,7 @@ */ /* - * Copyright (C) 2012 Eric Biggers + * Copyright (C) 2012, 2013 Eric Biggers * * This file is part of wimlib, a library for working with WIM files. * @@ -66,7 +66,7 @@ static u64 dentry_correct_length(const struct wim_dentry *dentry) /* Return %true iff the alternate data stream entry @entry has the UTF-8 stream * name @name that has length @name_len bytes. */ -static inline bool ads_entry_has_name(const struct ads_entry *entry, +static inline bool ads_entry_has_name(const struct wim_ads_entry *entry, const char *name, size_t name_len) { if (entry->stream_name_utf8_len != name_len) @@ -126,7 +126,7 @@ int set_dentry_name(struct wim_dentry *dentry, const char *new_name) /* * Changes the name of an alternate data stream */ -static int change_ads_name(struct ads_entry *entry, const char *new_name) +static int change_ads_name(struct wim_ads_entry *entry, const char *new_name) { return get_names(&entry->stream_name, &entry->stream_name_utf8, &entry->stream_name_len, @@ -137,7 +137,7 @@ static int change_ads_name(struct ads_entry *entry, const char *new_name) /* Returns the total length of a WIM alternate data stream entry on-disk, * including the stream name, the null terminator, AND the padding after the * entry to align the next ADS entry or dentry on an 8-byte boundary. */ -static u64 ads_entry_total_length(const struct ads_entry *entry) +static u64 ads_entry_total_length(const struct wim_ads_entry *entry) { u64 len = WIM_ADS_ENTRY_DISK_SIZE; if (entry->stream_name_len) @@ -218,9 +218,6 @@ static int for_dentry_tree_in_rbtree_depth(struct rb_node *node, return 0; } -/*#define RECURSIVE_FOR_DENTRY_IN_TREE*/ - -#ifdef RECURSIVE_FOR_DENTRY_IN_TREE static int for_dentry_tree_in_rbtree(struct rb_node *node, int (*visitor)(struct wim_dentry*, void*), void *arg) @@ -239,7 +236,6 @@ static int for_dentry_tree_in_rbtree(struct rb_node *node, } return 0; } -#endif /* * Calls a function on all directory entries in a WIM dentry tree. Logically, @@ -253,112 +249,10 @@ static int for_dentry_tree_in_rbtree(struct rb_node *node, int for_dentry_in_tree(struct wim_dentry *root, int (*visitor)(struct wim_dentry*, void*), void *arg) { -#ifdef RECURSIVE_FOR_DENTRY_IN_TREE int ret = visitor(root, arg); if (ret != 0) return ret; return for_dentry_tree_in_rbtree(root->d_inode->i_children.rb_node, visitor, arg); -#else - int ret; - struct list_head main_stack; - struct list_head sibling_stack; - struct list_head *sibling_stack_bottom; - struct wim_dentry *main_dentry; - struct rb_node *node; - struct list_head *next_sibling; - struct wim_dentry *dentry; - - ret = visitor(root, arg); - if (ret != 0) - return ret; - - main_dentry = root; - sibling_stack_bottom = &sibling_stack; - INIT_LIST_HEAD(&main_stack); - INIT_LIST_HEAD(&sibling_stack); - - list_add(&root->tmp_list, &main_stack); - node = root->d_inode->i_children.rb_node; - - while (1) { - // Prepare for non-recursive in-order traversal of the red-black - // tree of this dentry's children - - while (node) { - // Push this node to the sibling stack and examine the - // left neighbor, if any - list_add(&rbnode_dentry(node)->tmp_list, &sibling_stack); - node = node->rb_left; - } - - next_sibling = sibling_stack.next; - if (next_sibling == sibling_stack_bottom) { - // Done with all siblings. Pop the main dentry to move - // back up one level. - main_dentry = container_of(main_stack.next, - struct wim_dentry, - tmp_list); - list_del(&main_dentry->tmp_list); - - if (main_dentry == root) - goto out; - - // Restore sibling stack bottom from the previous level - sibling_stack_bottom = (void*)main_dentry->parent; - - // Restore the just-popped main dentry's parent - main_dentry->parent = container_of(main_stack.next, - struct wim_dentry, - tmp_list); - - // The next sibling to traverse in the previous level, - // in the in-order traversal of the red-black tree, is - // the one to the right. - node = main_dentry->rb_node.rb_right; - } else { - // The sibling stack is not empty, so there are more to - // go! - - // Pop a sibling from the stack. - list_del(next_sibling); - dentry = container_of(next_sibling, struct wim_dentry, tmp_list); - - // Visit the sibling. - ret = visitor(dentry, arg); - if (ret != 0) { - // Failed. Restore parent pointers for the - // dentries in the main stack - list_for_each_entry(dentry, &main_stack, tmp_list) { - dentry->parent = container_of(dentry->tmp_list.next, - struct wim_dentry, - tmp_list); - } - goto out; - } - - // We'd like to recursively visit the dentry tree rooted - // at this sibling. To do this, add it to the main - // stack, save the bottom of this level's sibling stack - // in the dentry->parent field, re-set the bottom of the - // sibling stack to be its current height, and set - // main_dentry to the sibling so it becomes the parent - // dentry in the next iteration through the outer loop. - if (inode_has_children(dentry->d_inode)) { - list_add(&dentry->tmp_list, &main_stack); - dentry->parent = (void*)sibling_stack_bottom; - sibling_stack_bottom = sibling_stack.next; - - main_dentry = dentry; - node = main_dentry->d_inode->i_children.rb_node; - } else { - node = dentry->rb_node.rb_right; - } - } - } -out: - root->parent = root; - return ret; -#endif } /* @@ -368,96 +262,12 @@ out: int for_dentry_in_tree_depth(struct wim_dentry *root, int (*visitor)(struct wim_dentry*, void*), void *arg) { -#if 1 int ret; ret = for_dentry_tree_in_rbtree_depth(root->d_inode->i_children.rb_node, visitor, arg); if (ret != 0) return ret; return visitor(root, arg); - -#else - int ret; - struct list_head main_stack; - struct list_head sibling_stack; - struct list_head *sibling_stack_bottom; - struct wim_dentry *main_dentry; - struct rb_node *node; - struct list_head *next_sibling; - struct wim_dentry *dentry; - - main_dentry = root; - sibling_stack_bottom = &sibling_stack; - INIT_LIST_HEAD(&main_stack); - INIT_LIST_HEAD(&sibling_stack); - - list_add(&main_dentry->tmp_list, &main_stack); - - while (1) { - node = main_dentry->d_inode->i_children.rb_node; - - while (1) { - if (node->rb_left) { - list_add(&rbnode_dentry(node)->tmp_list, &sibling_stack); - node = node->rb_left; - continue; - } - if (node->rb_right) { - list_add(&rbnode_dentry(node)->tmp_list, &sibling_stack); - node = node->rb_right; - continue; - } - list_add(&rbnode_dentry(node)->tmp_list, &sibling_stack); - } - - pop_sibling: - next_sibling = sibling_stack.next; - if (next_sibling == sibling_stack_bottom) { - main_dentry = container_of(main_stack.next, - struct wim_dentry, - tmp_list); - list_del(&main_dentry->tmp_list); - - - sibling_stack_bottom = (void*)main_dentry->parent; - - if (main_dentry == root) { - main_dentry->parent = main_dentry; - ret = visitor(dentry, arg); - return ret; - } else { - main_dentry->parent = container_of(main_stack.next, - struct wim_dentry, - tmp_list); - } - - ret = visitor(main_dentry, arg); - - if (ret != 0) { - list_del(&root->tmp_list); - list_for_each_entry(dentry, &main_stack, tmp_list) { - dentry->parent = container_of(dentry->tmp_list.next, - struct wim_dentry, - tmp_list); - } - root->parent = root; - return ret; - } - goto pop_sibling; - } else { - - list_del(next_sibling); - dentry = container_of(next_sibling, struct wim_dentry, tmp_list); - - - list_add(&dentry->tmp_list, &main_stack); - dentry->parent = (void*)sibling_stack_bottom; - sibling_stack_bottom = sibling_stack.next; - - main_dentry = dentry; - } - } -#endif } /* @@ -561,7 +371,7 @@ void calculate_subdir_offsets(struct wim_dentry *dentry, u64 *subdir_offset_p) static int compare_names(const char *name_1, u16 len_1, const char *name_2, u16 len_2) { - int result = strncasecmp(name_1, name_2, min(len_1, len_2)); + int result = strncmp(name_1, name_2, min(len_1, len_2)); if (result) { return result; } else { @@ -745,7 +555,7 @@ int print_dentry(struct wim_dentry *dentry, void *lookup_table) printf("Full Path (UTF-8) = \"%s\"\n", dentry->full_path_utf8); lte = inode_stream_lte(dentry->d_inode, 0, lookup_table); if (lte) { - print_lookup_table_entry(lte); + print_lookup_table_entry(lte, stdout); } else { hash = inode_stream_hash(inode, 0); if (hash) { @@ -766,8 +576,8 @@ int print_dentry(struct wim_dentry *dentry, void *lookup_table) print_hash(hash); putchar('\n'); } - print_lookup_table_entry(inode_stream_lte(inode, i + 1, - lookup_table)); + print_lookup_table_entry(inode_stream_lte(inode, i + 1, lookup_table), + stdout); } return 0; } @@ -870,7 +680,7 @@ struct wim_dentry *new_dentry_with_inode(const char *name) } -static int init_ads_entry(struct ads_entry *ads_entry, const char *name) +static int init_ads_entry(struct wim_ads_entry *ads_entry, const char *name) { int ret = 0; memset(ads_entry, 0, sizeof(*ads_entry)); @@ -879,7 +689,7 @@ static int init_ads_entry(struct ads_entry *ads_entry, const char *name) return ret; } -static void destroy_ads_entry(struct ads_entry *ads_entry) +static void destroy_ads_entry(struct wim_ads_entry *ads_entry) { FREE(ads_entry->stream_name); FREE(ads_entry->stream_name_utf8); @@ -991,8 +801,8 @@ int increment_dentry_refcnt(struct wim_dentry *dentry, void *ignore) /* * Links a dentry into the directory tree. * - * @dentry: The dentry to link. * @parent: The dentry that will be the parent of @dentry. + * @dentry: The dentry to link. */ bool dentry_add_child(struct wim_dentry * restrict parent, struct wim_dentry * restrict child) @@ -1022,12 +832,7 @@ bool dentry_add_child(struct wim_dentry * restrict parent, return true; } -#ifdef WITH_FUSE -/* - * Unlink a dentry from the directory tree. - * - * Note: This merely removes it from the in-memory tree structure. - */ +/* Unlink a WIM dentry from the directory entry tree. */ void unlink_dentry(struct wim_dentry *dentry) { struct wim_dentry *parent = dentry->parent; @@ -1035,12 +840,12 @@ void unlink_dentry(struct wim_dentry *dentry) return; rb_erase(&dentry->rb_node, &parent->d_inode->i_children); } -#endif -#ifdef WITH_FUSE -/* Returns the alternate data stream entry belonging to @inode that has the - * stream name @stream_name. */ -struct ads_entry *inode_get_ads_entry(struct wim_inode *inode, +/* + * Returns the alternate data stream entry belonging to @inode that has the + * stream name @stream_name. + */ +struct wim_ads_entry *inode_get_ads_entry(struct wim_inode *inode, const char *stream_name, u16 *idx_ret) { @@ -1059,18 +864,16 @@ struct ads_entry *inode_get_ads_entry(struct wim_inode *inode, } return NULL; } -#endif -#if defined(WITH_FUSE) || defined(WITH_NTFS_3G) /* - * Add an alternate stream entry to an inode and return a pointer to it, or NULL - * if memory could not be allocated. + * Add an alternate stream entry to a WIM inode and return a pointer to it, or + * NULL if memory could not be allocated. */ -struct ads_entry *inode_add_ads(struct wim_inode *inode, const char *stream_name) +struct wim_ads_entry *inode_add_ads(struct wim_inode *inode, const char *stream_name) { u16 num_ads; - struct ads_entry *ads_entries; - struct ads_entry *new_entry; + struct wim_ads_entry *ads_entries; + struct wim_ads_entry *new_entry; DEBUG("Add alternate data stream \"%s\"", stream_name); @@ -1096,14 +899,60 @@ struct ads_entry *inode_add_ads(struct wim_inode *inode, const char *stream_name inode->i_num_ads = num_ads; return new_entry; } -#endif -#ifdef WITH_FUSE -/* Remove an alternate data stream from the inode */ +int inode_add_ads_with_data(struct wim_inode *inode, const char *name, + const u8 *value, size_t size, + struct wim_lookup_table *lookup_table) +{ + int ret = WIMLIB_ERR_NOMEM; + struct wim_ads_entry *new_ads_entry; + struct wim_lookup_table_entry *existing_lte; + struct wim_lookup_table_entry *lte; + u8 value_hash[SHA1_HASH_SIZE]; + + wimlib_assert(inode->i_resolved); + new_ads_entry = inode_add_ads(inode, name); + if (!new_ads_entry) + goto out; + sha1_buffer((const u8*)value, size, value_hash); + existing_lte = __lookup_resource(lookup_table, value_hash); + if (existing_lte) { + lte = existing_lte; + lte->refcnt++; + } else { + u8 *value_copy; + lte = new_lookup_table_entry(); + if (!lte) + goto out_free_ads_entry; + value_copy = MALLOC(size); + if (!value_copy) { + FREE(lte); + goto out_free_ads_entry; + } + memcpy(value_copy, value, size); + lte->resource_location = RESOURCE_IN_ATTACHED_BUFFER; + lte->attached_buffer = value_copy; + lte->resource_entry.original_size = size; + lte->resource_entry.size = size; + lte->resource_entry.flags = 0; + copy_hash(lte->hash, value_hash); + lookup_table_insert(lookup_table, lte); + } + new_ads_entry->lte = lte; + ret = 0; + goto out; +out_free_ads_entry: + inode_remove_ads(inode, new_ads_entry - inode->i_ads_entries, + lookup_table); +out: + return ret; +} + +/* Remove an alternate data stream from a WIM inode */ void inode_remove_ads(struct wim_inode *inode, u16 idx, struct wim_lookup_table *lookup_table) { - struct ads_entry *ads_entry; + struct wim_ads_entry *ads_entry; struct wim_lookup_table_entry *lte; wimlib_assert(idx < inode->i_num_ads); @@ -1119,17 +968,84 @@ void inode_remove_ads(struct wim_inode *inode, u16 idx, destroy_ads_entry(ads_entry); - memcpy(&inode->i_ads_entries[idx], - &inode->i_ads_entries[idx + 1], - (inode->i_num_ads - idx - 1) * sizeof(inode->i_ads_entries[0])); + memmove(&inode->i_ads_entries[idx], + &inode->i_ads_entries[idx + 1], + (inode->i_num_ads - idx - 1) * sizeof(inode->i_ads_entries[0])); inode->i_num_ads--; } -#endif +int inode_get_unix_data(const struct wim_inode *inode, + struct wimlib_unix_data *unix_data, + u16 *stream_idx_ret) +{ + const struct wim_ads_entry *ads_entry; + const struct wim_lookup_table_entry *lte; + size_t size; + int ret; + + wimlib_assert(inode->i_resolved); + + ads_entry = inode_get_ads_entry((struct wim_inode*)inode, + WIMLIB_UNIX_DATA_TAG, NULL); + if (!ads_entry) + return NO_UNIX_DATA; + + if (stream_idx_ret) + *stream_idx_ret = ads_entry - inode->i_ads_entries; + lte = ads_entry->lte; + if (!lte) + return NO_UNIX_DATA; + + size = wim_resource_size(lte); + if (size != sizeof(struct wimlib_unix_data)) + return BAD_UNIX_DATA; + + ret = read_full_wim_resource(lte, (u8*)unix_data, 0); + if (ret) + return ret; + + if (unix_data->version != 0) + return BAD_UNIX_DATA; + return 0; +} + +int inode_set_unix_data(struct wim_inode *inode, + uid_t uid, gid_t gid, mode_t mode, + struct wim_lookup_table *lookup_table, + int which) +{ + struct wimlib_unix_data unix_data; + int ret; + bool have_good_unix_data = false; + bool have_unix_data = false; + u16 stream_idx; + + if (!(which & UNIX_DATA_CREATE)) { + ret = inode_get_unix_data(inode, &unix_data, &stream_idx); + if (ret == 0 || ret == BAD_UNIX_DATA || ret > 0) + have_unix_data = true; + if (ret == 0) + have_good_unix_data = true; + } + unix_data.version = 0; + if (which & UNIX_DATA_UID || !have_good_unix_data) + unix_data.uid = uid; + if (which & UNIX_DATA_GID || !have_good_unix_data) + unix_data.gid = gid; + if (which & UNIX_DATA_MODE || !have_good_unix_data) + unix_data.mode = mode; + ret = inode_add_ads_with_data(inode, WIMLIB_UNIX_DATA_TAG, + (const u8*)&unix_data, + sizeof(struct wimlib_unix_data), + lookup_table); + if (ret == 0 && have_unix_data) + inode_remove_ads(inode, stream_idx, lookup_table); + return ret; +} /* - * Reads the alternate data stream entries for a dentry. + * Reads the alternate data stream entries of a WIM dentry. * * @p: Pointer to buffer that starts with the first alternate stream entry. * @@ -1142,7 +1058,7 @@ void inode_remove_ads(struct wim_inode *inode, u16 idx, * * The format of the on-disk alternate stream entries is as follows: * - * struct ads_entry_on_disk { + * struct wim_ads_entry_on_disk { * u64 length; // Length of the entry, in bytes. This includes * all fields (including the stream name and * null terminator if present, AND the padding!). @@ -1165,14 +1081,14 @@ void inode_remove_ads(struct wim_inode *inode, u16 idx, * In addition, the entries are 8-byte aligned. * * Return 0 on success or nonzero on failure. On success, inode->i_ads_entries - * is set to an array of `struct ads_entry's of length inode->i_num_ads. On + * is set to an array of `struct wim_ads_entry's of length inode->i_num_ads. On * failure, @inode is not modified. */ static int read_ads_entries(const u8 *p, struct wim_inode *inode, u64 remaining_size) { u16 num_ads; - struct ads_entry *ads_entries; + struct wim_ads_entry *ads_entries; int ret; num_ads = inode->i_num_ads; @@ -1184,7 +1100,7 @@ static int read_ads_entries(const u8 *p, struct wim_inode *inode, } for (u16 i = 0; i < num_ads; i++) { - struct ads_entry *cur_entry; + struct wim_ads_entry *cur_entry; u64 length; u64 length_no_padding; u64 total_length; @@ -1292,7 +1208,7 @@ out_free_ads_entries: } /* - * Reads a directory entry, including all alternate data stream entries that + * Reads a WIM directory entry, including all alternate data stream entries that * follow it, from the WIM image's metadata resource. * * @metadata_resource: Buffer containing the uncompressed metadata resource. @@ -1475,7 +1391,7 @@ int read_dentry(const u8 metadata_resource[], u64 metadata_resource_len, * u64 reserved1; (always 0) * u64 reserved2; (always 0) * };*/ - DEBUG("Dentry for file or directory `%s' has %zu extra " + DEBUG("Dentry for file or directory `%s' has %"PRIu64" extra " "bytes of data", file_name_utf8, dentry->length - calculated_size); } @@ -1747,14 +1663,13 @@ static u8 *write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p) * recursively writing the directory trees rooted at each of the child * dentries, since the on-disk dentries for a dentry's children are * always located at consecutive positions in the metadata resource! */ - for_dentry_in_rbtree(parent->d_inode->i_children.rb_node, write_dentry_cb, &p); + for_dentry_child(parent, write_dentry_cb, &p); /* write end of directory entry */ p = put_u64(p, 0); /* Recurse on children. */ - for_dentry_in_rbtree(parent->d_inode->i_children.rb_node, - write_dentry_tree_recursive_cb, &p); + for_dentry_child(parent, write_dentry_tree_recursive_cb, &p); return p; }