]> wimlib.net Git - wimlib/blobdiff - src/inode_fixup.c
update_image.c: Fix memory leak in error path
[wimlib] / src / inode_fixup.c
index 799f3ba27868187d20be7806b4c62f81eec7a115..2eb15a87d83d55e6c2cece223f475f58688f2746 100644 (file)
@@ -56,9 +56,9 @@ static void
 inconsistent_inode(const struct wim_inode *inode)
 {
        if (wimlib_print_errors) {
-               ERROR("An inconsistent hard link group that cannot be corrected has "
-                     "been detected");
-               ERROR("The dentries are located at the following paths:");
+               WARNING("An inconsistent hard link group that cannot be corrected has "
+                       "been detected");
+               WARNING("The dentries are located at the following paths:");
                print_inode_dentries(inode);
        }
 }
@@ -73,11 +73,9 @@ ads_entries_have_same_name(const struct wim_ads_entry *entry_1,
 }
 
 static bool
-ref_inodes_consistent(const struct wim_inode * restrict ref_inode_1,
-                     const struct wim_inode * restrict ref_inode_2)
+ref_inodes_consistent(const struct wim_inode *ref_inode_1,
+                     const struct wim_inode *ref_inode_2)
 {
-       wimlib_assert(ref_inode_1 != ref_inode_2);
-
        if (ref_inode_1->i_num_ads != ref_inode_2->i_num_ads)
                return false;
        if (ref_inode_1->i_security_id != ref_inode_2->i_security_id
@@ -97,27 +95,63 @@ ref_inodes_consistent(const struct wim_inode * restrict ref_inode_1,
        return true;
 }
 
+/* Returns true iff the specified inode has any data streams with nonzero hash.
+ */
+static bool
+inode_has_data_streams(const struct wim_inode *inode)
+{
+       for (unsigned i = 0; i <= inode->i_num_ads; i++)
+               if (!is_zero_hash(inode_stream_hash(inode, i)))
+                       return true;
+       return false;
+}
+
+/* Returns true iff the specified dentry has any data streams with nonzero hash.
+ */
 static bool
-inodes_consistent(const struct wim_inode * restrict ref_inode,
-                 const struct wim_inode * restrict inode)
+dentry_has_data_streams(const struct wim_dentry *dentry)
 {
-       wimlib_assert(ref_inode != inode);
+       return inode_has_data_streams(dentry->d_inode);
+}
 
-       if (ref_inode->i_num_ads != inode->i_num_ads &&
-           inode->i_num_ads != 0)
+static bool
+inodes_consistent(const struct wim_inode *ref_inode,
+                 const struct wim_inode *inode)
+{
+       if (ref_inode->i_security_id != inode->i_security_id) {
+               WARNING("Security ID mismatch: %d != %d",
+                       ref_inode->i_security_id, inode->i_security_id);
                return false;
-       if (ref_inode->i_security_id != inode->i_security_id
-           || ref_inode->i_attributes != inode->i_attributes)
+       }
+
+       if (ref_inode->i_attributes != inode->i_attributes) {
+               WARNING("Attributes mismatch: 0x%08x != 0x%08x",
+                       ref_inode->i_attributes, inode->i_attributes);
                return false;
-       for (unsigned i = 0; i <= min(ref_inode->i_num_ads, inode->i_num_ads); i++) {
-               const u8 *ref_hash, *hash;
-               ref_hash = inode_stream_hash(ref_inode, i);
-               hash = inode_stream_hash(inode, i);
-               if (!hashes_equal(ref_hash, hash) && !is_zero_hash(hash))
-                       return false;
-               if (i && !ads_entries_have_same_name(&ref_inode->i_ads_entries[i - 1],
-                                                    &inode->i_ads_entries[i - 1]))
+       }
+
+       if (inode_has_data_streams(inode)) {
+               if (ref_inode->i_num_ads != inode->i_num_ads) {
+                       WARNING("Stream count mismatch: %u != %u",
+                               ref_inode->i_num_ads, inode->i_num_ads);
                        return false;
+               }
+               for (unsigned i = 0; i <= ref_inode->i_num_ads; i++) {
+                       const u8 *ref_hash, *hash;
+
+                       ref_hash = inode_stream_hash(ref_inode, i);
+                       hash = inode_stream_hash(inode, i);
+                       if (!hashes_equal(ref_hash, hash) && !is_zero_hash(hash)) {
+                               WARNING("Stream hash mismatch");
+                               return false;
+                       }
+                       if (i && !ads_entries_have_same_name(&ref_inode->i_ads_entries[i - 1],
+                                                            &inode->i_ads_entries[i - 1]))
+                       {
+                               WARNING("Stream name mismatch");
+                               return false;
+                       }
+               }
        }
        return true;
 }
@@ -153,10 +187,8 @@ fix_true_inode(struct wim_inode *inode, struct list_head *inode_list)
 
        inode_for_each_dentry(dentry, ref_inode) {
                if (dentry != ref_dentry) {
-                       if (!inodes_consistent(ref_inode, dentry->d_inode)) {
+                       if (!inodes_consistent(ref_inode, dentry->d_inode))
                                inconsistent_inode(ref_inode);
-                               return WIMLIB_ERR_INVALID_METADATA_RESOURCE;
-                       }
                        /* Free the unneeded `struct wim_inode'. */
                        wimlib_assert(dentry->d_inode->i_nlink == 1);
                        free_inode(dentry->d_inode);
@@ -202,19 +234,10 @@ fix_nominal_inode(struct wim_inode *inode, struct list_head *inode_list,
          * least one data stream with a non-zero hash, and another list that
          * contains the dentries that have a zero hash for all data streams. */
        inode_for_each_dentry(dentry, inode) {
-               for (unsigned i = 0; i <= dentry->d_inode->i_num_ads; i++) {
-                       const u8 *hash;
-                       hash = inode_stream_hash(dentry->d_inode, i);
-                       if (!is_zero_hash(hash)) {
-                               list_add(&dentry->tmp_list,
-                                        &dentries_with_data_streams);
-                               goto next_dentry;
-                       }
-               }
-               list_add(&dentry->tmp_list,
-                        &dentries_with_no_data_streams);
-       next_dentry:
-               ;
+               if (dentry_has_data_streams(dentry))
+                       list_add(&dentry->tmp_list, &dentries_with_data_streams);
+               else
+                       list_add(&dentry->tmp_list, &dentries_with_no_data_streams);
        }
 
        /* If there are no dentries with data streams, we require the nominal
@@ -322,7 +345,7 @@ fix_inodes(struct wim_inode_table *table, struct list_head *inode_list,
        struct hlist_node *cur, *tmp;
        int ret;
        INIT_LIST_HEAD(inode_list);
-       for (u64 i = 0; i < table->capacity; i++) {
+       for (size_t i = 0; i < table->capacity; i++) {
                hlist_for_each_entry_safe(inode, cur, tmp, &table->array[i], i_hlist) {
                        hlist_del_init(&inode->i_hlist);
                        ret = fix_nominal_inode(inode, inode_list, ino_changes_needed);
@@ -407,8 +430,8 @@ inode_table_insert(struct wim_dentry *dentry, void *_table)
  * WIM) is examined for consistency and may be split into multiple "true" inodes
  * that are maximally sized consistent sets of dentries.
  *
- * On success, the list of "true" inodes, linked by the i_hlist field,
- * is returned in the hlist @inode_list.
+ * On success, the list of "true" inodes, linked by the i_list field,
+ * is returned in the list @inode_list.
  *
  * Return values:
  *     WIMLIB_ERR_SUCCESS (0)
@@ -451,7 +474,7 @@ dentry_tree_fix_inodes(struct wim_dentry *root, struct list_head *inode_list)
                }
        }
        /* On success, all the inodes have been moved to the image inode list,
-        * so there's no need to delete from from the hash lists in the inode
+        * so there's no need to delete from the hash lists in the inode
         * table before freeing the hash buckets array directly. */
        ret = 0;
        goto out_destroy_inode_table_raw;