+ p = put_u16(p, inode->num_ads);
+ p = put_u16(p, dentry->short_name_len);
+ p = put_u16(p, dentry->file_name_len);
+ if (dentry->file_name_len) {
+ p = put_bytes(p, dentry->file_name_len, (u8*)dentry->file_name);
+ p = put_u16(p, 0); /* filename padding, 2 bytes. */
+ }
+ if (dentry->short_name) {
+ p = put_bytes(p, dentry->short_name_len, (u8*)dentry->short_name);
+ p = put_u16(p, 0); /* short name padding, 2 bytes */
+ }
+
+ /* Align to 8-byte boundary */
+ wimlib_assert(length >= (p - orig_p) && length - (p - orig_p) <= 7);
+ p = put_zeroes(p, length - (p - orig_p));
+
+ /* Write the alternate data streams, if there are any. Please see
+ * read_ads_entries() for comments about the format of the on-disk
+ * alternate data stream entries. */
+ for (u16 i = 0; i < inode->num_ads; i++) {
+ p = put_u64(p, ads_entry_total_length(&inode->ads_entries[i]));
+ p = put_u64(p, 0); /* Unused */
+ hash = inode_stream_hash(inode, i + 1);
+ p = put_bytes(p, SHA1_HASH_SIZE, hash);
+ p = put_u16(p, inode->ads_entries[i].stream_name_len);
+ if (inode->ads_entries[i].stream_name_len) {
+ p = put_bytes(p, inode->ads_entries[i].stream_name_len,
+ (u8*)inode->ads_entries[i].stream_name);
+ p = put_u16(p, 0);
+ }
+ p = put_zeroes(p, (8 - (p - orig_p) % 8) % 8);
+ }
+ wimlib_assert(p - orig_p == __dentry_total_length(dentry, length));
+ return p;
+}
+
+static int write_dentry_cb(struct dentry *dentry, void *_p)
+{
+ u8 **p = _p;
+ *p = write_dentry(dentry, *p);
+ return 0;
+}
+
+static u8 *write_dentry_tree_recursive(const struct dentry *parent, u8 *p);
+
+static int write_dentry_tree_recursive_cb(struct dentry *dentry, void *_p)
+{
+ u8 **p = _p;
+ *p = write_dentry_tree_recursive(dentry, *p);
+ return 0;
+}
+
+/* Recursive function that writes a dentry tree rooted at @parent, not including
+ * @parent itself, which has already been written. */
+static u8 *write_dentry_tree_recursive(const struct dentry *parent, u8 *p)
+{
+ /* Nothing to do if this dentry has no children. */
+ if (parent->subdir_offset == 0)
+ return p;
+
+ /* Write child dentries and end-of-directory entry.
+ *
+ * Note: we need to write all of this dentry's children before
+ * 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->children.rb_node, write_dentry_cb, &p);
+
+ /* write end of directory entry */
+ p = put_u64(p, 0);
+
+ /* Recurse on children. */
+ for_dentry_in_rbtree(parent->d_inode->children.rb_node,
+ write_dentry_tree_recursive_cb, &p);
+ return p;
+}
+
+/* Writes a directory tree to the metadata resource.
+ *
+ * @root: Root of the dentry tree.
+ * @p: Pointer to a buffer with enough space for the dentry tree.
+ *
+ * Returns pointer to the byte after the last byte we wrote.
+ */
+u8 *write_dentry_tree(const struct dentry *root, u8 *p)
+{
+ DEBUG("Writing dentry tree.");
+ wimlib_assert(dentry_is_root(root));
+
+ /* If we're the root dentry, we have no parent that already
+ * wrote us, so we need to write ourselves. */
+ p = write_dentry(root, p);
+
+ /* Write end of directory entry after the root dentry just to be safe;
+ * however the root dentry obviously cannot have any siblings. */
+ p = put_u64(p, 0);
+
+ /* Recursively write the rest of the dentry tree. */
+ return write_dentry_tree_recursive(root, p);