+/* Calculates the unaligned length, in bytes, of an on-disk WIM dentry, based on
+ * the file name length and short name length. Note that dentry->length is
+ * ignored; also, this excludes any alternate data stream entries that may
+ * follow the dentry. */
+static u64 dentry_correct_length_unaligned(const struct dentry *dentry)
+{
+ return __dentry_correct_length_unaligned(dentry->file_name_len,
+ dentry->short_name_len);
+}
+
+/* Return the "correct" value to write in the length field of a WIM dentry,
+ * based on the file name length and short name length. */
+static u64 dentry_correct_length(const struct dentry *dentry)
+{
+ return (dentry_correct_length_unaligned(dentry) + 7) & ~7;
+}
+
+/* Return %true iff @dentry has the UTF-8 file name @name that has length
+ * @name_len bytes. */
+static bool dentry_has_name(const struct dentry *dentry, const char *name,
+ size_t name_len)
+{
+ if (dentry->file_name_utf8_len != name_len)
+ return false;
+ return memcmp(dentry->file_name_utf8, name, name_len) == 0;
+}
+
+/* Return %true iff the alternate data stream entry @entry has the UTF-8 stream
+ * name @name that has length @name_len bytes. */
+static inline bool ads_entry_has_name(const struct ads_entry *entry,
+ const char *name, size_t name_len)
+{
+ if (entry->stream_name_utf8_len != name_len)
+ return false;
+ return memcmp(entry->stream_name_utf8, name, name_len) == 0;
+}
+
+/* Duplicates a UTF-8 name into UTF-8 and UTF-16 strings and returns the strings
+ * and their lengths in the pointer arguments */
+int get_names(char **name_utf16_ret, char **name_utf8_ret,
+ u16 *name_utf16_len_ret, u16 *name_utf8_len_ret,
+ const char *name)
+{
+ size_t utf8_len;
+ size_t utf16_len;
+ char *name_utf16, *name_utf8;
+
+ utf8_len = strlen(name);
+
+ name_utf16 = utf8_to_utf16(name, utf8_len, &utf16_len);
+
+ if (!name_utf16)
+ return WIMLIB_ERR_NOMEM;
+
+ name_utf8 = MALLOC(utf8_len + 1);
+ if (!name_utf8) {
+ FREE(name_utf8);
+ return WIMLIB_ERR_NOMEM;
+ }
+ memcpy(name_utf8, name, utf8_len + 1);
+ FREE(*name_utf8_ret);
+ FREE(*name_utf16_ret);
+ *name_utf8_ret = name_utf8;
+ *name_utf16_ret = name_utf16;
+ *name_utf8_len_ret = utf8_len;
+ *name_utf16_len_ret = utf16_len;
+ return 0;
+}
+
+/* Changes the name of a dentry to @new_name. Only changes the file_name and
+ * file_name_utf8 fields; does not change the short_name, short_name_utf8, or
+ * full_path_utf8 fields. Also recalculates its length. */
+static int change_dentry_name(struct dentry *dentry, const char *new_name)
+{
+ int ret;
+
+ ret = get_names(&dentry->file_name, &dentry->file_name_utf8,
+ &dentry->file_name_len, &dentry->file_name_utf8_len,
+ new_name);
+ FREE(dentry->short_name);
+ dentry->short_name_len = 0;
+ if (ret == 0)
+ dentry->length = dentry_correct_length(dentry);
+ return ret;
+}
+
+/*
+ * Changes the name of an alternate data stream */
+static int change_ads_name(struct 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 one (or the next dentry) on an 8-byte boundary. */
+static u64 ads_entry_total_length(const struct 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 dentry *dentry, u64 length)
+{
+ const struct inode *inode = dentry->d_inode;
+ for (u16 i = 0; i < inode->num_ads; i++)
+ length += ads_entry_total_length(&inode->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 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 dentry *dentry)
+{
+ return __dentry_total_length(dentry, dentry->length);
+}
+
+/* Transfers file attributes from a `stat' buffer to a WIM "inode". */
+void stbuf_to_inode(const struct stat *stbuf, struct inode *inode)