]> wimlib.net Git - wimlib/blobdiff - src/dentry.c
read_dentry_tree(): Do not leak duplicate dentries
[wimlib] / src / dentry.c
index 45093069001ea6a94c7df3614690675e6e914cb0..86a82eb6ffe771581ef358d77137a9856df61cb4 100644 (file)
@@ -1032,7 +1032,8 @@ free_inode(struct wim_inode *inode)
        #endif
                /* HACK: This may instead delete the inode from i_list, but the
                 * hlist_del() behaves the same as list_del(). */
-               hlist_del(&inode->i_hlist);
+               if (!hlist_unhashed(&inode->i_hlist))
+                       hlist_del(&inode->i_hlist);
                FREE(inode->i_extracted_file);
                FREE(inode);
        }
@@ -1905,6 +1906,7 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
        u64 cur_offset = dentry->subdir_offset;
        struct wim_dentry *child;
        struct wim_dentry *duplicate;
+       struct wim_dentry *parent;
        struct wim_dentry cur_child;
        int ret;
 
@@ -1917,6 +1919,18 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
        if (cur_offset == 0)
                return 0;
 
+       /* Check for cyclic directory structure */
+       for (parent = dentry->parent; !dentry_is_root(parent); parent = parent->parent)
+       {
+               if (unlikely(parent->subdir_offset == cur_offset)) {
+                       ERROR("Cyclic directory structure directed: children "
+                             "of \"%"TS"\" coincide with children of \"%"TS"\"",
+                             dentry_full_path(dentry),
+                             dentry_full_path(parent));
+                       return WIMLIB_ERR_INVALID_DENTRY;
+               }
+       }
+
        /* Find and read all the children of @dentry. */
        for (;;) {
 
@@ -1947,7 +1961,7 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
                cur_offset += dentry_total_length(child);
 
                duplicate = dentry_add_child(dentry, child);
-               if (duplicate) {
+               if (unlikely(duplicate)) {
                        const tchar *child_type, *duplicate_type;
                        child_type = dentry_get_file_type_string(child);
                        duplicate_type = dentry_get_file_type_string(duplicate);
@@ -1956,12 +1970,13 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
                                "at that path with the exact same name)",
                                child_type, dentry_full_path(duplicate),
                                duplicate_type);
+                       free_dentry(child);
                } else {
                        inode_add_dentry(child, child->d_inode);
                        /* If there are children of this child, call this
                         * procedure recursively. */
                        if (child->subdir_offset != 0) {
-                               if (dentry_is_directory(child)) {
+                               if (likely(dentry_is_directory(child))) {
                                        ret = read_dentry_tree(metadata_resource,
                                                               metadata_resource_len,
                                                               child);