+ /* If there are no dentries with data streams, we require the nominal
+ * inode to be a true inode */
+ if (list_empty(&dentries_with_data_streams)) {
+ #ifdef ENABLE_DEBUG
+ if (inode->link_count > 1) {
+ DEBUG("Found link group of size %u without "
+ "any data streams:", inode->link_count);
+ print_inode_dentries(inode);
+ DEBUG("We are going to interpret it as true "
+ "link group, provided that the dentries "
+ "are consistent.");
+ }
+ #endif
+ return fix_true_inode(inode, inode_list);
+ }
+
+ /* One or more dentries had data streams specified. We check each of
+ * these dentries for consistency with the others to form a set of true
+ * inodes. */
+ num_true_inodes = 0;
+ list_for_each_entry(dentry, &dentries_with_data_streams, tmp_list) {
+ /* Look for a true inode that is consistent with this dentry and
+ * add this dentry to it. Or, if none of the true inodes are
+ * consistent with this dentry, add a new one (if that happens,
+ * we have split the hard link group). */
+ hlist_for_each_entry(inode, cur, &true_inodes, hlist) {
+ if (ref_inodes_consistent(inode, dentry->d_inode)) {
+ inode_add_dentry(dentry, inode);
+ goto next_dentry_2;
+ }
+ }
+ num_true_inodes++;
+ INIT_LIST_HEAD(&dentry->d_inode->dentry_list);
+ inode_add_dentry(dentry, dentry->d_inode);
+ hlist_add_head(&dentry->d_inode->hlist, &true_inodes);
+next_dentry_2:
+ ;
+ }
+
+ wimlib_assert(num_true_inodes != 0);
+
+ /* If there were dentries with no data streams, we require there to only
+ * be one true inode so that we know which inode to assign the
+ * streamless dentries to. */
+ if (!list_empty(&dentries_with_no_data_streams)) {
+ if (num_true_inodes != 1) {
+ ERROR("Hard inode ambiguity detected!");
+ ERROR("We split up inode 0x%"PRIx64" due to "
+ "inconsistencies,", inode->ino);
+ ERROR("but dentries with no stream information remained. "
+ "We don't know which inode");
+ ERROR("to assign them to.");
+ return WIMLIB_ERR_INVALID_DENTRY;
+ }
+ inode = container_of(true_inodes.first, struct inode, hlist);
+ /* Assign the streamless dentries to the one and only true
+ * inode. */
+ list_for_each_entry(dentry, &dentries_with_no_data_streams, tmp_list)
+ inode_add_dentry(dentry, inode);
+ }
+ #ifdef ENABLE_DEBUG
+ if (num_true_inodes != 1) {
+ inode = container_of(true_inodes.first, struct inode, hlist);
+
+ printf("Split nominal inode 0x%"PRIx64" into %zu "
+ "inodes:\n",
+ inode->ino, num_true_inodes);
+ puts("------------------------------------------------------------------------------");
+ size_t i = 1;
+ hlist_for_each_entry(inode, cur, &true_inodes, hlist) {
+ printf("[Split inode %zu]\n", i++);
+ print_inode_dentries(inode);
+ putchar('\n');
+ }
+ puts("------------------------------------------------------------------------------");
+ }
+ #endif
+
+ hlist_for_each_entry_safe(inode, cur, tmp, &true_inodes, hlist) {
+ ret = fix_true_inode(inode, inode_list);
+ if (ret != 0)
+ return ret;
+ }
+ return 0;
+}
+
+/*
+ * Goes through each hard link group (dentries sharing the same hard link group
+ * ID field) that's been inserted into the inode table and shares the `struct
+ * inode's among members of each hard link group.
+ *
+ * In the process, the dentries belonging to each inode are checked for
+ * consistency. If they contain data features that indicate they cannot really
+ * correspond to the same inode, this should be an error, but in reality this
+ * case needs to be handled, so we split the dentries into different inodes.
+ *
+ * After this function returns, the inodes are no longer in the inode table, and
+ * the inode table should be destroyed. A list of the inodes, including all
+ * split inodes as well as the inodes that were good before, is returned in the
+ * list @inode_list.
+ */
+static int fix_inodes(struct inode_table *table, struct hlist_head *inode_list)
+{
+ struct inode *inode;
+ struct hlist_node *cur, *tmp;
+ int ret;
+ INIT_HLIST_HEAD(inode_list);
+ for (u64 i = 0; i < table->capacity; i++) {
+ hlist_for_each_entry_safe(inode, cur, tmp, &table->array[i], hlist) {
+ ret = fix_nominal_inode(inode, inode_list);
+ if (ret != 0)
+ return ret;
+ }