+/*
+ * Writes a WIM dentry to an output buffer.
+ *
+ * @dentry: The dentry structure.
+ * @p: The memory location to write the data to.
+ * @return: Pointer to the byte after the last byte we wrote as part of the
+ * dentry.
+ */
+static u8 *write_dentry(const struct dentry *dentry, u8 *p)
+{
+ u8 *orig_p = p;
+ const u8 *hash;
+ const struct inode *inode = dentry->d_inode;
+
+ /* 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...) */
+ u64 length = dentry_correct_length(dentry);
+
+ p = put_u64(p, length);
+ p = put_u32(p, inode->attributes);
+ p = put_u32(p, inode->security_id);
+ p = put_u64(p, dentry->subdir_offset);
+ p = put_u64(p, 0); /* unused1 */
+ p = put_u64(p, 0); /* unused2 */
+ p = put_u64(p, inode->creation_time);
+ p = put_u64(p, inode->last_access_time);
+ p = put_u64(p, inode->last_write_time);
+ hash = inode_stream_hash(inode, 0);
+ p = put_bytes(p, SHA1_HASH_SIZE, hash);
+ if (inode->attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ p = put_zeroes(p, 4);
+ p = put_u32(p, inode->reparse_tag);
+ p = put_zeroes(p, 4);
+ } else {
+ u64 link_group_id;
+ p = put_u32(p, 0);
+ if (inode->link_count == 1)
+ link_group_id = 0;
+ else
+ link_group_id = inode->ino;
+ p = put_u64(p, link_group_id);
+ }
+ 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;
+}
+
+/* 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)