+/*
+ * Changes the name of an alternate data stream */
+static int change_ads_name(struct wim_ads_entry *entry, const char *new_name)
+{
+ return get_names(&entry->stream_name, &entry->stream_name_utf8,
+ &entry->stream_name_len,
+ &entry->stream_name_utf8_len,
+ new_name);
+}
+
+/* Returns the total length of a WIM alternate data stream entry on-disk,
+ * including the stream name, the null terminator, AND the padding after the
+ * entry to align the next ADS entry or dentry on an 8-byte boundary. */
+static u64 ads_entry_total_length(const struct wim_ads_entry *entry)
+{
+ u64 len = WIM_ADS_ENTRY_DISK_SIZE;
+ if (entry->stream_name_len)
+ len += entry->stream_name_len + 2;
+ return (len + 7) & ~7;
+}
+
+
+static u64 __dentry_total_length(const struct wim_dentry *dentry, u64 length)
+{
+ const struct wim_inode *inode = dentry->d_inode;
+ for (u16 i = 0; i < inode->i_num_ads; i++)
+ length += ads_entry_total_length(&inode->i_ads_entries[i]);
+ return (length + 7) & ~7;
+}
+
+/* Calculate the aligned *total* length of an on-disk WIM dentry. This includes
+ * all alternate data streams. */
+u64 dentry_correct_total_length(const struct wim_dentry *dentry)
+{
+ return __dentry_total_length(dentry,
+ dentry_correct_length_unaligned(dentry));
+}
+
+/* Like dentry_correct_total_length(), but use the existing dentry->length field
+ * instead of calculating its "correct" value. */
+static u64 dentry_total_length(const struct wim_dentry *dentry)
+{
+ return __dentry_total_length(dentry, dentry->length);
+}
+
+int for_dentry_in_rbtree(struct rb_node *root,
+ int (*visitor)(struct wim_dentry *, void *),
+ void *arg)
+{
+ int ret;
+ struct rb_node *node = root;
+ LIST_HEAD(stack);
+ while (1) {
+ if (node) {
+ list_add(&rbnode_dentry(node)->tmp_list, &stack);
+ node = node->rb_left;
+ } else {
+ struct list_head *next;
+ struct wim_dentry *dentry;
+
+ next = stack.next;
+ if (next == &stack)
+ return 0;
+ dentry = container_of(next, struct wim_dentry, tmp_list);
+ list_del(next);
+ ret = visitor(dentry, arg);
+ if (ret != 0)
+ return ret;
+ node = dentry->rb_node.rb_right;
+ }
+ }
+}
+
+static int for_dentry_tree_in_rbtree_depth(struct rb_node *node,
+ int (*visitor)(struct wim_dentry*, void*),
+ void *arg)
+{
+ int ret;
+ if (node) {
+ ret = for_dentry_tree_in_rbtree_depth(node->rb_left,
+ visitor, arg);
+ if (ret != 0)
+ return ret;
+ ret = for_dentry_tree_in_rbtree_depth(node->rb_right,
+ visitor, arg);
+ if (ret != 0)
+ return ret;
+ ret = for_dentry_in_tree_depth(rbnode_dentry(node), visitor, arg);
+ if (ret != 0)
+ return ret;
+ }
+ 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)
+{
+ int ret;
+ if (node) {
+ ret = for_dentry_tree_in_rbtree(node->rb_left, visitor, arg);
+ if (ret != 0)
+ return ret;
+ ret = for_dentry_in_tree(rbnode_dentry(node), visitor, arg);
+ if (ret != 0)
+ return ret;
+ ret = for_dentry_tree_in_rbtree(node->rb_right, visitor, arg);
+ if (ret != 0)
+ return ret;
+ }
+ return 0;
+}
+#endif
+
+/*
+ * Calls a function on all directory entries in a WIM dentry tree. Logically,
+ * this is a pre-order traversal (the function is called on a parent dentry
+ * before its children), but sibling dentries will be visited in order as well.
+ *
+ * In reality, the data structures are more complicated than the above might
+ * suggest because there is a separate red-black tree for each dentry that
+ * contains its direct children.