]> wimlib.net Git - wimlib/blobdiff - src/dentry.c
write_dentry(): Remove unhelpful comment
[wimlib] / src / dentry.c
index 59e97572bc0c49e538dc43e2306bf24ed16b9f5e..3e462a6e38f472e623ab4ea887e257f05c257177 100644 (file)
@@ -214,6 +214,17 @@ dentry_correct_length_aligned(const struct wim_dentry *dentry)
        return (len + 7) & ~7;
 }
 
+static int
+dentry_clear_short_name(struct wim_dentry *dentry)
+{
+       if (dentry_has_short_name(dentry)) {
+               FREE(dentry->short_name);
+               dentry->short_name = NULL;
+               dentry->short_name_nbytes = 0;
+       }
+       return 0;
+}
+
 /* Sets the name of a WIM dentry from a multibyte string.
  * Only use this on dentries not inserted into the tree.  Use rename_wim_path()
  * to do a real rename.  */
@@ -221,17 +232,42 @@ int
 dentry_set_name(struct wim_dentry *dentry, const tchar *new_name)
 {
        int ret;
+
        ret = get_utf16le_string(new_name, &dentry->file_name,
                                 &dentry->file_name_nbytes);
-       if (ret == 0) {
-               /* Clear the short name and recalculate the dentry length */
-               if (dentry_has_short_name(dentry)) {
-                       FREE(dentry->short_name);
-                       dentry->short_name = NULL;
-                       dentry->short_name_nbytes = 0;
-               }
+       if (ret)
+               return ret;
+
+       return dentry_clear_short_name(dentry);
+}
+
+/* Sets the name of a WIM dentry from a UTF-16LE string.
+ * Only use this on dentries not inserted into the tree.  Use rename_wim_path()
+ * to do a real rename.  */
+int
+dentry_set_name_utf16le(struct wim_dentry *dentry, const utf16lechar *new_name)
+{
+       utf16lechar *name = NULL;
+       size_t name_nbytes = 0;
+
+       if (new_name && *new_name) {
+               const utf16lechar *tmp;
+
+               tmp = new_name;
+               do {
+                       name_nbytes += sizeof(utf16lechar);
+               } while (*++tmp);
+
+               name = memdup(new_name, name_nbytes + sizeof(utf16lechar));
+               if (!name)
+                       return WIMLIB_ERR_NOMEM;
        }
-       return ret;
+
+       FREE(dentry->file_name);
+       dentry->file_name = name;
+       dentry->file_name_nbytes = name_nbytes;
+
+       return dentry_clear_short_name(dentry);
 }
 
 /* Returns the total length of a WIM alternate data stream entry on-disk,
@@ -313,7 +349,7 @@ do_for_dentry_in_tree(struct wim_dentry *dentry,
                return ret;
 
        for_dentry_child(child, dentry) {
-               ret = for_dentry_in_tree(child, visitor, arg);
+               ret = do_for_dentry_in_tree(child, visitor, arg);
                if (unlikely(ret))
                        return ret;
        }
@@ -329,7 +365,7 @@ do_for_dentry_in_tree_depth(struct wim_dentry *dentry,
        struct wim_dentry *child;
 
        for_dentry_child_postorder(child, dentry) {
-               ret = for_dentry_in_tree_depth(child, visitor, arg);
+               ret = do_for_dentry_in_tree_depth(child, visitor, arg);
                if (unlikely(ret))
                        return ret;
        }
@@ -360,8 +396,7 @@ for_dentry_in_tree_depth(struct wim_dentry *root,
        return do_for_dentry_in_tree_depth(root, visitor, arg);
 }
 
-/* Calculate the full path of @dentry.  The full path of its parent must have
- * already been calculated, or it must be the root dentry. */
+/* Calculate the full path of @dentry.  */
 int
 calculate_dentry_full_path(struct wim_dentry *dentry)
 {
@@ -435,18 +470,6 @@ calculate_dentry_full_path(struct wim_dentry *dentry)
        return 0;
 }
 
-static int
-do_calculate_dentry_full_path(struct wim_dentry *dentry, void *_ignore)
-{
-       return calculate_dentry_full_path(dentry);
-}
-
-int
-calculate_dentry_tree_full_paths(struct wim_dentry *root)
-{
-       return for_dentry_in_tree(root, do_calculate_dentry_full_path, NULL);
-}
-
 tchar *
 dentry_full_path(struct wim_dentry *dentry)
 {
@@ -487,6 +510,7 @@ calculate_subdir_offsets(struct wim_dentry *root, u64 *subdir_offset_p)
        for_dentry_in_tree(root, dentry_calculate_subdir_offset, subdir_offset_p);
 }
 
+/* Compare the UTF-16LE long filenames of two dentries case insensitively.  */
 static int
 dentry_compare_names_case_insensitive(const struct wim_dentry *d1,
                                      const struct wim_dentry *d2)
@@ -498,6 +522,7 @@ dentry_compare_names_case_insensitive(const struct wim_dentry *d1,
                                   true);
 }
 
+/* Compare the UTF-16LE long filenames of two dentries case sensitively.  */
 static int
 dentry_compare_names_case_sensitive(const struct wim_dentry *d1,
                                    const struct wim_dentry *d2)
@@ -509,6 +534,28 @@ dentry_compare_names_case_sensitive(const struct wim_dentry *d1,
                                   false);
 }
 
+static int
+_avl_dentry_compare_names_ci(const struct avl_tree_node *n1,
+                            const struct avl_tree_node *n2)
+{
+       const struct wim_dentry *d1, *d2;
+
+       d1 = avl_tree_entry(n1, struct wim_dentry, d_index_node_ci);
+       d2 = avl_tree_entry(n2, struct wim_dentry, d_index_node_ci);
+       return dentry_compare_names_case_insensitive(d1, d2);
+}
+
+static int
+_avl_dentry_compare_names(const struct avl_tree_node *n1,
+                         const struct avl_tree_node *n2)
+{
+       const struct wim_dentry *d1, *d2;
+
+       d1 = avl_tree_entry(n1, struct wim_dentry, d_index_node);
+       d2 = avl_tree_entry(n2, struct wim_dentry, d_index_node);
+       return dentry_compare_names_case_sensitive(d1, d2);
+}
+
 /* Default case sensitivity behavior for searches with
  * WIMLIB_CASE_PLATFORM_DEFAULT specified.  This can be modified by
  * wimlib_global_init().  */
@@ -520,6 +567,36 @@ bool default_ignore_case =
 #endif
 ;
 
+/* Case-sensitive dentry lookup.  Only @file_name and @file_name_nbytes of
+ * @dummy must be valid.  */
+static struct wim_dentry *
+dir_lookup(const struct wim_inode *dir, const struct wim_dentry *dummy)
+{
+       struct avl_tree_node *node;
+
+       node = avl_tree_lookup_node(dir->i_children,
+                                   &dummy->d_index_node,
+                                   _avl_dentry_compare_names);
+       if (!node)
+               return NULL;
+       return avl_tree_entry(node, struct wim_dentry, d_index_node);
+}
+
+/* Case-insensitive dentry lookup.  Only @file_name and @file_name_nbytes of
+ * @dummy must be valid.  */
+static struct wim_dentry *
+dir_lookup_ci(const struct wim_inode *dir, const struct wim_dentry *dummy)
+{
+       struct avl_tree_node *node;
+
+       node = avl_tree_lookup_node(dir->i_children_ci,
+                                   &dummy->d_index_node_ci,
+                                   _avl_dentry_compare_names_ci);
+       if (!node)
+               return NULL;
+       return avl_tree_entry(node, struct wim_dentry, d_index_node_ci);
+}
+
 /* Given a UTF-16LE filename and a directory, look up the dentry for the file.
  * Return it if found, otherwise NULL.  This is case-sensitive on UNIX and
  * case-insensitive on Windows. */
@@ -529,68 +606,52 @@ get_dentry_child_with_utf16le_name(const struct wim_dentry *dentry,
                                   size_t name_nbytes,
                                   CASE_SENSITIVITY_TYPE case_ctype)
 {
-       struct rb_node *node;
-
+       const struct wim_inode *dir = dentry->d_inode;
        bool ignore_case = will_ignore_case(case_ctype);
+       struct wim_dentry dummy;
+       struct wim_dentry *child;
 
-       if (ignore_case)
-               node = dentry->d_inode->i_children_case_insensitive.rb_node;
-       else
-               node = dentry->d_inode->i_children.rb_node;
+       dummy.file_name = (utf16lechar*)name;
+       dummy.file_name_nbytes = name_nbytes;
 
-       struct wim_dentry *child;
-       while (node) {
-               if (ignore_case)
-                       child = rb_entry(node, struct wim_dentry, rb_node_case_insensitive);
-               else
-                       child = rb_entry(node, struct wim_dentry, rb_node);
-
-               int result = cmp_utf16le_strings(name,
-                                                name_nbytes / 2,
-                                                child->file_name,
-                                                child->file_name_nbytes / 2,
-                                                ignore_case);
-               if (result < 0) {
-                       node = node->rb_left;
-               } else if (result > 0) {
-                       node = node->rb_right;
-               } else if (!ignore_case ||
-                       list_empty(&child->case_insensitive_conflict_list)) {
-                       return child;
-               } else {
-                       /* Multiple dentries have the same case-insensitive
-                        * name, and a case-insensitive lookup is being
-                        * performed.  Choose the dentry with the same
-                        * case-sensitive name, if one exists; otherwise print a
-                        * warning and choose one arbitrarily.  */
-                       struct wim_dentry *alt = child;
-                       size_t num_alts = 0;
-
-                       do {
-                               num_alts++;
-                               if (0 == cmp_utf16le_strings(name,
-                                                            name_nbytes / 2,
-                                                            alt->file_name,
-                                                            alt->file_name_nbytes / 2,
-                                                            false))
-                                       return alt;
-                               alt = list_entry(alt->case_insensitive_conflict_list.next,
-                                                struct wim_dentry,
-                                                case_insensitive_conflict_list);
-                       } while (alt != child);
-
-                       WARNING("Result of case-insensitive lookup is ambiguous\n"
-                               "          (returning \"%"TS"\" of %zu "
-                               "possible files, including \"%"TS"\")",
-                               dentry_full_path(child),
-                               num_alts,
-                               dentry_full_path(list_entry(child->case_insensitive_conflict_list.next,
-                                                           struct wim_dentry,
-                                                           case_insensitive_conflict_list)));
-                       return child;
-               }
-       }
-       return NULL;
+       if (!ignore_case)
+               /* Case-sensitive lookup.  */
+               return dir_lookup(dir, &dummy);
+
+       /* Case-insensitive lookup.  */
+
+       child = dir_lookup_ci(dir, &dummy);
+       if (!child)
+               return NULL;
+
+       if (likely(list_empty(&child->d_ci_conflict_list)))
+               /* Only one dentry has this case-insensitive name; return it */
+               return child;
+
+       /* Multiple dentries have the same case-insensitive name.  Choose the
+        * dentry with the same case-sensitive name, if one exists; otherwise
+        * print a warning and choose one of the possible dentries arbitrarily.
+        */
+       struct wim_dentry *alt = child;
+       size_t num_alts = 0;
+
+       do {
+               num_alts++;
+               if (!dentry_compare_names_case_sensitive(&dummy, alt))
+                       return alt;
+               alt = list_entry(alt->d_ci_conflict_list.next,
+                                struct wim_dentry, d_ci_conflict_list);
+       } while (alt != child);
+
+       WARNING("Result of case-insensitive lookup is ambiguous\n"
+               "          (returning \"%"TS"\" of %zu "
+               "possible files, including \"%"TS"\")",
+               dentry_full_path(child),
+               num_alts,
+               dentry_full_path(list_entry(child->d_ci_conflict_list.next,
+                                           struct wim_dentry,
+                                           d_ci_conflict_list)));
+       return child;
 }
 
 /* Returns the child of @dentry that has the file name @name.  Returns NULL if
@@ -829,14 +890,12 @@ wim_pathname_to_stream(WIMStruct *wim,
                if (ads_entry) {
                        stream_idx = ads_idx + 1;
                        lte = ads_entry->lte;
-                       goto out;
                } else {
                        return -ENOENT;
                }
        } else {
                lte = inode_unnamed_stream_resolved(inode, &stream_idx);
        }
-out:
        if (dentry_ret)
                *dentry_ret = dentry;
        if (lte_ret)
@@ -847,13 +906,6 @@ out:
 }
 #endif /* WITH_FUSE  */
 
-/* Initializations done on every `struct wim_dentry'. */
-static void
-dentry_common_init(struct wim_dentry *dentry)
-{
-       memset(dentry, 0, sizeof(struct wim_dentry));
-}
-
 /* Creates an unlinked directory entry. */
 int
 new_dentry(const tchar *name, struct wim_dentry **dentry_ret)
@@ -861,11 +913,10 @@ new_dentry(const tchar *name, struct wim_dentry **dentry_ret)
        struct wim_dentry *dentry;
        int ret;
 
-       dentry = MALLOC(sizeof(struct wim_dentry));
-       if (dentry == NULL)
+       dentry = CALLOC(1, sizeof(struct wim_dentry));
+       if (!dentry)
                return WIMLIB_ERR_NOMEM;
 
-       dentry_common_init(dentry);
        if (*name) {
                ret = dentry_set_name(dentry, name);
                if (ret) {
@@ -918,13 +969,12 @@ new_dentry_with_inode(const tchar *name, struct wim_dentry **dentry_ret)
 }
 
 int
-new_filler_directory(const tchar *name, struct wim_dentry **dentry_ret)
+new_filler_directory(struct wim_dentry **dentry_ret)
 {
        int ret;
        struct wim_dentry *dentry;
 
-       DEBUG("Creating filler directory \"%"TS"\"", name);
-       ret = new_dentry_with_inode(name, &dentry);
+       ret = new_dentry_with_inode(T(""), &dentry);
        if (ret)
                return ret;
        /* Leave the inode number as 0; this is allowed for non
@@ -948,10 +998,13 @@ dentry_tree_clear_inode_visited(struct wim_dentry *root)
        for_dentry_in_tree(root, dentry_clear_inode_visited, NULL);
 }
 
-/* Frees a WIM dentry.
+/*
+ * Free a WIM dentry.
  *
- * The corresponding inode (if any) is freed only if its link count is
- * decremented to 0.  */
+ * In addition to freeing the dentry itself, this decrements the link count of
+ * the corresponding inode (if any).  If the inode's link count reaches 0, the
+ * inode is freed as well.
+ */
 void
 free_dentry(struct wim_dentry *dentry)
 {
@@ -965,29 +1018,23 @@ free_dentry(struct wim_dentry *dentry)
        }
 }
 
-/* This function is passed as an argument to for_dentry_in_tree_depth() in order
- * to free a directory tree. */
 static int
-do_free_dentry(struct wim_dentry *dentry, void *_lookup_table)
+do_free_dentry(struct wim_dentry *dentry, void *_ignore)
 {
-       struct wim_lookup_table *lookup_table = _lookup_table;
-
-       if (lookup_table) {
-               struct wim_inode *inode = dentry->d_inode;
-               for (unsigned i = 0; i <= inode->i_num_ads; i++) {
-                       struct wim_lookup_table_entry *lte;
+       free_dentry(dentry);
+       return 0;
+}
 
-                       lte = inode_stream_lte(inode, i, lookup_table);
-                       if (lte)
-                               lte_decrement_refcnt(lte, lookup_table);
-               }
-       }
+static int
+do_free_dentry_and_unref_streams(struct wim_dentry *dentry, void *lookup_table)
+{
+       inode_unref_streams(dentry->d_inode, lookup_table);
        free_dentry(dentry);
        return 0;
 }
 
 /*
- * Unlinks and frees a dentry tree.
+ * Recursively frees all directory entries in the specified tree.
  *
  * @root:
  *     The root of the tree.
@@ -996,47 +1043,76 @@ do_free_dentry(struct wim_dentry *dentry, void *_lookup_table)
  *     The lookup table for dentries.  If non-NULL, the reference counts in the
  *     lookup table for the lookup table entries corresponding to the dentries
  *     will be decremented.
+ *
+ * This also puts references to the corresponding inodes.
+ *
+ * This does *not* unlink @root from its parent directory (if it has one).
  */
 void
 free_dentry_tree(struct wim_dentry *root, struct wim_lookup_table *lookup_table)
 {
-       for_dentry_in_tree_depth(root, do_free_dentry, lookup_table);
+       int (*f)(struct wim_dentry *, void *);
+
+       if (lookup_table)
+               f = do_free_dentry_and_unref_streams;
+       else
+               f = do_free_dentry;
+
+       for_dentry_in_tree_depth(root, f, lookup_table);
+}
+
+/* Insert the @child dentry into the case sensitive index of the @dir directory.
+ * Return NULL if successfully inserted, otherwise a pointer to the
+ * already-inserted duplicate.  */
+static struct wim_dentry *
+dir_index_child(struct wim_inode *dir, struct wim_dentry *child)
+{
+       struct avl_tree_node *duplicate;
+
+       duplicate = avl_tree_insert(&dir->i_children,
+                                   &child->d_index_node,
+                                   _avl_dentry_compare_names);
+       if (!duplicate)
+               return NULL;
+       return avl_tree_entry(duplicate, struct wim_dentry, d_index_node);
 }
 
-/* Insert a dentry into the case insensitive index for a directory.
- *
- * This is a red-black tree, but when multiple dentries share the same
- * case-insensitive name, only one is inserted into the tree itself; the rest
- * are connected in a list.
- */
+/* Insert the @child dentry into the case insensitive index of the @dir
+ * directory.  Return NULL if successfully inserted, otherwise a pointer to the
+ * already-inserted duplicate.  */
 static struct wim_dentry *
-dentry_add_child_case_insensitive(struct wim_dentry *parent,
-                                 struct wim_dentry *child)
+dir_index_child_ci(struct wim_inode *dir, struct wim_dentry *child)
 {
-       struct rb_root *root;
-       struct rb_node **new;
-       struct rb_node *rb_parent;
-
-       root = &parent->d_inode->i_children_case_insensitive;
-       new = &root->rb_node;
-       rb_parent = NULL;
-       while (*new) {
-               struct wim_dentry *this = container_of(*new, struct wim_dentry,
-                                                      rb_node_case_insensitive);
-               int result = dentry_compare_names_case_insensitive(child, this);
-
-               rb_parent = *new;
-
-               if (result < 0)
-                       new = &((*new)->rb_left);
-               else if (result > 0)
-                       new = &((*new)->rb_right);
-               else
-                       return this;
-       }
-       rb_link_node(&child->rb_node_case_insensitive, rb_parent, new);
-       rb_insert_color(&child->rb_node_case_insensitive, root);
-       return NULL;
+       struct avl_tree_node *duplicate;
+
+       duplicate = avl_tree_insert(&dir->i_children_ci,
+                                   &child->d_index_node_ci,
+                                   _avl_dentry_compare_names_ci);
+       if (!duplicate)
+               return NULL;
+       return avl_tree_entry(duplicate, struct wim_dentry, d_index_node_ci);
+}
+
+/* Removes the specified dentry from its directory's case-sensitive index.  */
+static void
+dir_unindex_child(struct wim_inode *dir, struct wim_dentry *child)
+{
+       avl_tree_remove(&dir->i_children, &child->d_index_node);
+}
+
+/* Removes the specified dentry from its directory's case-insensitive index.  */
+static void
+dir_unindex_child_ci(struct wim_inode *dir, struct wim_dentry *child)
+{
+       avl_tree_remove(&dir->i_children_ci, &child->d_index_node_ci);
+}
+
+/* Returns true iff the specified dentry is in its parent directory's
+ * case-insensitive index.  */
+static bool
+dentry_in_ci_index(const struct wim_dentry *dentry)
+{
+       return !avl_tree_node_is_unlinked(&dentry->d_index_node_ci);
 }
 
 /*
@@ -1046,154 +1122,67 @@ dentry_add_child_case_insensitive(struct wim_dentry *parent,
  * @child: The dentry to link.
  *
  * Returns NULL if successful.  If @parent already contains a dentry with the
- * same case-sensitive name as @child, the pointer to this duplicate dentry is
- * returned.
+ * same case-sensitive name as @child, returns a pointer to this duplicate
+ * dentry.
  */
 struct wim_dentry *
-dentry_add_child(struct wim_dentry * restrict parent,
-                struct wim_dentry * restrict child)
+dentry_add_child(struct wim_dentry *parent, struct wim_dentry *child)
 {
-       struct rb_root *root;
-       struct rb_node **new;
-       struct rb_node *rb_parent;
+       struct wim_dentry *duplicate;
+       struct wim_inode *dir;
 
-       wimlib_assert(dentry_is_directory(parent));
        wimlib_assert(parent != child);
 
-       /* Case sensitive child dentry index */
-       root = &parent->d_inode->i_children;
-       new = &root->rb_node;
-       rb_parent = NULL;
-       while (*new) {
-               struct wim_dentry *this = rbnode_dentry(*new);
-               int result = dentry_compare_names_case_sensitive(child, this);
-
-               rb_parent = *new;
-
-               if (result < 0)
-                       new = &((*new)->rb_left);
-               else if (result > 0)
-                       new = &((*new)->rb_right);
-               else
-                       return this;
-       }
-       child->parent = parent;
-       rb_link_node(&child->rb_node, rb_parent, new);
-       rb_insert_color(&child->rb_node, root);
+       dir = parent->d_inode;
 
-       /* Case insensitive child dentry index */
-       {
-               struct wim_dentry *existing;
-               existing = dentry_add_child_case_insensitive(parent, child);
-               if (existing) {
-                       list_add(&child->case_insensitive_conflict_list,
-                                &existing->case_insensitive_conflict_list);
-                       rb_clear_node(&child->rb_node_case_insensitive);
-               } else {
-                       INIT_LIST_HEAD(&child->case_insensitive_conflict_list);
-               }
+       wimlib_assert(inode_is_directory(dir));
+
+       duplicate = dir_index_child(dir, child);
+       if (duplicate)
+               return duplicate;
+
+       duplicate = dir_index_child_ci(dir, child);
+       if (duplicate) {
+               list_add(&child->d_ci_conflict_list, &duplicate->d_ci_conflict_list);
+               avl_tree_node_set_unlinked(&child->d_index_node_ci);
+       } else {
+               INIT_LIST_HEAD(&child->d_ci_conflict_list);
        }
+       child->parent = parent;
        return NULL;
 }
 
-/* Unlink a WIM dentry from the directory entry tree. */
+/* Unlink a WIM dentry from the directory entry tree.  */
 void
 unlink_dentry(struct wim_dentry *dentry)
 {
-       struct wim_dentry *parent = dentry->parent;
+       struct wim_inode *dir;
 
-       if (parent == dentry)
+       if (dentry_is_root(dentry))
                return;
-       rb_erase(&dentry->rb_node, &parent->d_inode->i_children);
 
-       if (!rb_empty_node(&dentry->rb_node_case_insensitive)) {
-               /* This dentry was in the case-insensitive red-black tree. */
-               rb_erase(&dentry->rb_node_case_insensitive,
-                        &parent->d_inode->i_children_case_insensitive);
-               if (!list_empty(&dentry->case_insensitive_conflict_list)) {
+       dir = dentry->parent->d_inode;
+
+       dir_unindex_child(dir, dentry);
+
+       if (dentry_in_ci_index(dentry)) {
+
+               dir_unindex_child_ci(dir, dentry);
+
+               if (!list_empty(&dentry->d_ci_conflict_list)) {
                        /* Make a different case-insensitively-the-same dentry
-                        * be the "representative" in the red-black tree. */
+                        * be the "representative" in the search index. */
                        struct list_head *next;
                        struct wim_dentry *other;
                        struct wim_dentry *existing;
 
-                       next = dentry->case_insensitive_conflict_list.next;
-                       other = list_entry(next, struct wim_dentry, case_insensitive_conflict_list);
-                       existing = dentry_add_child_case_insensitive(parent, other);
+                       next = dentry->d_ci_conflict_list.next;
+                       other = list_entry(next, struct wim_dentry, d_ci_conflict_list);
+                       existing = dir_index_child_ci(dir, other);
                        wimlib_assert(existing == NULL);
                }
        }
-       list_del(&dentry->case_insensitive_conflict_list);
-}
-
-static int
-free_dentry_full_path(struct wim_dentry *dentry, void *_ignore)
-{
-       FREE(dentry->_full_path);
-       dentry->_full_path = NULL;
-       return 0;
-}
-
-/* Rename a file or directory in the WIM.  */
-int
-rename_wim_path(WIMStruct *wim, const tchar *from, const tchar *to,
-               CASE_SENSITIVITY_TYPE case_type)
-{
-       struct wim_dentry *src;
-       struct wim_dentry *dst;
-       struct wim_dentry *parent_of_dst;
-       int ret;
-
-       /* This rename() implementation currently only supports actual files
-        * (not alternate data streams) */
-
-       src = get_dentry(wim, from, case_type);
-       if (!src)
-               return -errno;
-
-       dst = get_dentry(wim, to, case_type);
-
-       if (dst) {
-               /* Destination file exists */
-
-               if (src == dst) /* Same file */
-                       return 0;
-
-               if (!dentry_is_directory(src)) {
-                       /* Cannot rename non-directory to directory. */
-                       if (dentry_is_directory(dst))
-                               return -EISDIR;
-               } else {
-                       /* Cannot rename directory to a non-directory or a non-empty
-                        * directory */
-                       if (!dentry_is_directory(dst))
-                               return -ENOTDIR;
-                       if (dentry_has_children(dst))
-                               return -ENOTEMPTY;
-               }
-               parent_of_dst = dst->parent;
-       } else {
-               /* Destination does not exist */
-               parent_of_dst = get_parent_dentry(wim, to, case_type);
-               if (!parent_of_dst)
-                       return -errno;
-
-               if (!dentry_is_directory(parent_of_dst))
-                       return -ENOTDIR;
-       }
-
-       ret = dentry_set_name(src, path_basename(to));
-       if (ret)
-               return -ENOMEM;
-       if (dst) {
-               unlink_dentry(dst);
-               free_dentry_tree(dst, wim->lookup_table);
-       }
-       unlink_dentry(src);
-       dentry_add_child(parent_of_dst, src);
-       if (src->_full_path)
-               for_dentry_in_tree(src, free_dentry_full_path, NULL);
-       return 0;
+       list_del(&dentry->d_ci_conflict_list);
 }
 
 /* Reads a WIM directory entry, including all alternate data stream entries that
@@ -1232,9 +1221,6 @@ read_dentry(const u8 * restrict buf, size_t buf_len,
        p = &buf[offset];
        disk_dentry = (const struct wim_dentry_on_disk*)p;
 
-       if (unlikely((uintptr_t)p & 7))
-               WARNING("WIM dentry is not 8-byte aligned");
-
        /* Get dentry length.  */
        length = le64_to_cpu(disk_dentry->length);
 
@@ -1389,18 +1375,6 @@ err_free_dentry:
        return ret;
 }
 
-static const tchar *
-dentry_get_file_type_string(const struct wim_dentry *dentry)
-{
-       const struct wim_inode *inode = dentry->d_inode;
-       if (inode_is_directory(inode))
-               return T("directory");
-       else if (inode_is_symlink(inode))
-               return T("symbolic link");
-       else
-               return T("file");
-}
-
 static bool
 dentry_is_dot_or_dotdot(const struct wim_dentry *dentry)
 {
@@ -1479,14 +1453,10 @@ read_dentry_tree_recursive(const u8 * restrict buf, size_t buf_len,
                        /* We already found a dentry with this same
                         * case-sensitive long name.  Only keep the first one.
                         */
-                       const tchar *child_type, *duplicate_type;
-                       child_type = dentry_get_file_type_string(child);
-                       duplicate_type = dentry_get_file_type_string(duplicate);
-                       WARNING("Ignoring duplicate %"TS" \"%"TS"\" "
-                               "(the WIM image already contains a %"TS" "
+                       WARNING("Ignoring duplicate file \"%"TS"\" "
+                               "(the WIM image already contains a file "
                                "at that path with the exact same name)",
-                               child_type, dentry_full_path(duplicate),
-                               duplicate_type);
+                               dentry_full_path(duplicate));
                        free_dentry(child);
                        continue;
                }
@@ -1682,11 +1652,6 @@ write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p)
        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);
 
        if (use_dummy_stream) {
@@ -1706,7 +1671,7 @@ write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p)
 static int
 write_dir_dentries(struct wim_dentry *dir, void *_pp)
 {
-       if (dentry_is_directory(dir)) {
+       if (dir->subdir_offset != 0) {
                u8 **pp = _pp;
                u8 *p = *pp;
                struct wim_dentry *child;