-/*
- * Unlinks and frees a dentry tree.
- *
- * @root: The root of the tree.
- * @lookup_table: The lookup table for dentries. If non-NULL, the
- * reference counts in the lookup table for the lookup
- * table entries corresponding to the dentries will be
- * decremented.
- */
-void
-free_dentry_tree(struct wim_dentry *root, struct wim_lookup_table *lookup_table)
-{
- for_dentry_in_tree_depth(root, do_free_dentry, lookup_table);
-}
-
-#ifdef __WIN32__
-
-/* Insert a dentry into the case insensitive index for a directory.
- *
- * This is a red-black tree, but when multiple dentries share the same
- * case-insensitive name, only one is inserted into the tree itself; the rest
- * are connected in a list.
- */
-static struct wim_dentry *
-dentry_add_child_case_insensitive(struct wim_dentry *parent,
- struct wim_dentry *child)
-{
- struct rb_root *root;
- struct rb_node **new;
- struct rb_node *rb_parent;
-
- root = &parent->d_inode->i_children_case_insensitive;
- new = &root->rb_node;
- rb_parent = NULL;
- while (*new) {
- struct wim_dentry *this = container_of(*new, struct wim_dentry,
- rb_node_case_insensitive);
- int result = dentry_compare_names_case_insensitive(child, this);
-
- rb_parent = *new;
-
- if (result < 0)
- new = &((*new)->rb_left);
- else if (result > 0)
- new = &((*new)->rb_right);
- else
- return this;
- }
- rb_link_node(&child->rb_node_case_insensitive, rb_parent, new);
- rb_insert_color(&child->rb_node_case_insensitive, root);
- return NULL;
-}
-#endif
-
-/*
- * Links a dentry into the directory tree.
- *
- * @parent: The dentry that will be the parent of @child.
- * @child: The dentry to link.
- *
- * Returns NULL if successful. If @parent already contains a dentry with the
- * same case-sensitive name as @child, the pointer to this duplicate dentry is
- * returned.
- */
-struct wim_dentry *
-dentry_add_child(struct wim_dentry * restrict parent,
- struct wim_dentry * restrict child)
-{
- struct rb_root *root;
- struct rb_node **new;
- struct rb_node *rb_parent;
-
- wimlib_assert(dentry_is_directory(parent));
- wimlib_assert(parent != child);
-
- /* Case sensitive child dentry index */
- root = &parent->d_inode->i_children;
- new = &root->rb_node;
- rb_parent = NULL;
- while (*new) {
- struct wim_dentry *this = rbnode_dentry(*new);
- int result = dentry_compare_names_case_sensitive(child, this);
-
- rb_parent = *new;
-
- if (result < 0)
- new = &((*new)->rb_left);
- else if (result > 0)
- new = &((*new)->rb_right);
- else
- return this;
- }
- child->parent = parent;
- rb_link_node(&child->rb_node, rb_parent, new);
- rb_insert_color(&child->rb_node, root);
-
-#ifdef __WIN32__
- {
- struct wim_dentry *existing;
- existing = dentry_add_child_case_insensitive(parent, child);
- if (existing) {
- list_add(&child->case_insensitive_conflict_list,
- &existing->case_insensitive_conflict_list);
- child->rb_node_case_insensitive.__rb_parent_color = 0;
- } else {
- INIT_LIST_HEAD(&child->case_insensitive_conflict_list);
- }
- }
-#endif
- return NULL;
-}
-
-/* Unlink a WIM dentry from the directory entry tree. */
-void
-unlink_dentry(struct wim_dentry *dentry)
-{
- struct wim_dentry *parent = dentry->parent;
-
- if (parent == dentry)
- return;
- rb_erase(&dentry->rb_node, &parent->d_inode->i_children);
-#ifdef __WIN32__
- if (dentry->rb_node_case_insensitive.__rb_parent_color) {
- /* This dentry was in the case-insensitive red-black tree. */
- rb_erase(&dentry->rb_node_case_insensitive,
- &parent->d_inode->i_children_case_insensitive);
- if (!list_empty(&dentry->case_insensitive_conflict_list)) {
- /* Make a different case-insensitively-the-same dentry
- * be the "representative" in the red-black tree. */
- struct list_head *next;
- struct wim_dentry *other;
- struct wim_dentry *existing;
-
- next = dentry->case_insensitive_conflict_list.next;
- other = list_entry(next, struct wim_dentry, case_insensitive_conflict_list);
- existing = dentry_add_child_case_insensitive(parent, other);
- wimlib_assert(existing == NULL);
- }
- }
- list_del(&dentry->case_insensitive_conflict_list);
-#endif
-}
-
-/*
- * 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 tchar *stream_name,
- u16 *idx_ret)
-{
- if (inode->i_num_ads == 0) {
- return NULL;
- } else {
- size_t stream_name_utf16le_nbytes;
- u16 i;
- struct wim_ads_entry *result;
-
- #if TCHAR_IS_UTF16LE
- const utf16lechar *stream_name_utf16le;
-
- stream_name_utf16le = stream_name;
- stream_name_utf16le_nbytes = tstrlen(stream_name) * sizeof(tchar);
- #else
- utf16lechar *stream_name_utf16le;
-
- {
- int ret = tstr_to_utf16le(stream_name,
- tstrlen(stream_name) *
- sizeof(tchar),
- &stream_name_utf16le,
- &stream_name_utf16le_nbytes);
- if (ret)
- return NULL;
- }
- #endif
- i = 0;
- result = NULL;
- do {
- if (ads_entry_has_name(&inode->i_ads_entries[i],
- stream_name_utf16le,
- stream_name_utf16le_nbytes))
- {
- if (idx_ret)
- *idx_ret = i;
- result = &inode->i_ads_entries[i];
- break;
- }
- } while (++i != inode->i_num_ads);
- #if !TCHAR_IS_UTF16LE
- FREE(stream_name_utf16le);
- #endif
- return result;
- }
-}
-
-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;
- struct wim_ads_entry *new_entry;
-
- if (inode->i_num_ads >= 0xfffe) {
- ERROR("Too many alternate data streams in one inode!");
- return NULL;
- }
- num_ads = inode->i_num_ads + 1;
- ads_entries = REALLOC(inode->i_ads_entries,
- num_ads * sizeof(inode->i_ads_entries[0]));
- if (!ads_entries) {
- ERROR("Failed to allocate memory for new alternate data stream");
- return NULL;
- }
- inode->i_ads_entries = ads_entries;
-
- new_entry = &inode->i_ads_entries[num_ads - 1];
- if (init_ads_entry(new_entry, stream_name, stream_name_nbytes, is_utf16le))
- return NULL;
- new_entry->stream_id = inode->i_next_stream_id++;
- inode->i_num_ads = num_ads;
- return new_entry;
-}
-
-struct wim_ads_entry *
-inode_add_ads_utf16le(struct wim_inode *inode,
- const utf16lechar *stream_name,
- size_t stream_name_nbytes)