+ disk_dentry->num_alternate_data_streams = cpu_to_le16(inode->i_num_ads);
+ disk_dentry->short_name_nbytes = cpu_to_le16(dentry->short_name_nbytes);
+ disk_dentry->file_name_nbytes = cpu_to_le16(dentry->file_name_nbytes);
+ p += sizeof(struct wim_dentry_on_disk);
+
+ if (dentry_has_long_name(dentry))
+ p = mempcpy(p, dentry->file_name, dentry->file_name_nbytes + 2);
+
+ if (dentry_has_short_name(dentry))
+ p = mempcpy(p, dentry->short_name, dentry->short_name_nbytes + 2);
+
+ /* Align to 8-byte boundary */
+ while ((uintptr_t)p & 7)
+ *p++ = 0;
+
+ /* We calculate the correct length of the dentry ourselves because the
+ * dentry->length field may been set to an unexpected value from when we
+ * read the dentry in (for example, there may have been unknown data
+ * appended to the end of the dentry...). Furthermore, the dentry may
+ * have been renamed, thus changing its needed length. */
+ disk_dentry->length = cpu_to_le64(p - orig_p);
+
+ /* Write the alternate data streams entries, if any. */
+ for (u16 i = 0; i < inode->i_num_ads; i++) {
+ const struct wim_ads_entry *ads_entry =
+ &inode->i_ads_entries[i];
+ struct wim_ads_entry_on_disk *disk_ads_entry =
+ (struct wim_ads_entry_on_disk*)p;
+ orig_p = p;
+
+ disk_ads_entry->reserved = cpu_to_le64(ads_entry->reserved);
+
+ hash = inode_stream_hash(inode, i + 1);
+ copy_hash(disk_ads_entry->hash, hash);
+ disk_ads_entry->stream_name_nbytes = cpu_to_le16(ads_entry->stream_name_nbytes);
+ p += sizeof(struct wim_ads_entry_on_disk);
+ if (ads_entry->stream_name_nbytes) {
+ p = mempcpy(p, ads_entry->stream_name,
+ ads_entry->stream_name_nbytes + 2);
+ }
+ /* Align to 8-byte boundary */
+ while ((uintptr_t)p & 7)
+ *p++ = 0;
+ disk_ads_entry->length = cpu_to_le64(p - orig_p);
+ }
+ return p;
+}
+
+static int
+write_dentry_cb(struct wim_dentry *dentry, void *_p)
+{
+ u8 **p = _p;
+ *p = write_dentry(dentry, *p);
+ return 0;
+}
+
+static u8 *
+write_dentry_tree_recursive(const struct wim_dentry *parent, u8 *p);
+
+static int
+write_dentry_tree_recursive_cb(struct wim_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 wim_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_child(parent, write_dentry_cb, &p);
+
+ /* write end of directory entry */
+ *(le64*)p = cpu_to_le64(0);
+ p += 8;
+
+ /* Recurse on children. */
+ for_dentry_child(parent, 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 wim_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. */
+ *(le64*)p = cpu_to_le64(0);
+ p += 8;
+
+ /* Recursively write the rest of the dentry tree. */
+ return write_dentry_tree_recursive(root, p);