+ DEBUG("Assigning inode numbers");
+ struct inode *inode;
+ struct hlist_node *cur;
+ u64 cur_ino = 1;
+ hlist_for_each_entry(inode, cur, inode_list, hlist) {
+ inode->ino = cur_ino;
+ cur_ino++;
+ }
+ return cur_ino;
+}
+
+
+static void print_inode_dentries(const struct inode *inode)
+{
+ struct dentry *dentry;
+ inode_for_each_dentry(dentry, inode)
+ printf("`%s'\n", dentry->full_path_utf8);
+}
+
+static void inconsistent_inode(const struct inode *inode)
+{
+ ERROR("An inconsistent hard link group that cannot be corrected has "
+ "been detected");
+ ERROR("The dentries are located at the following paths:");
+#ifdef ENABLE_ERROR_MESSAGES
+ print_inode_dentries(inode);
+#endif
+}
+
+static bool ref_inodes_consistent(const struct inode * restrict ref_inode_1,
+ const struct inode * restrict ref_inode_2)
+{
+ wimlib_assert(ref_inode_1 != ref_inode_2);
+
+ if (ref_inode_1->num_ads != ref_inode_2->num_ads)
+ return false;
+ if (ref_inode_1->security_id != ref_inode_2->security_id
+ || ref_inode_1->attributes != ref_inode_2->attributes)
+ return false;
+ for (unsigned i = 0; i <= ref_inode_1->num_ads; i++) {
+ const u8 *ref_1_hash, *ref_2_hash;
+ ref_1_hash = inode_stream_hash(ref_inode_1, i);
+ ref_2_hash = inode_stream_hash(ref_inode_2, i);
+ if (!hashes_equal(ref_1_hash, ref_2_hash))
+ return false;
+ if (i && !ads_entries_have_same_name(&ref_inode_1->ads_entries[i - 1],
+ &ref_inode_2->ads_entries[i - 1]))
+ return false;
+
+ }
+ return true;
+}
+
+static bool inodes_consistent(const struct inode * restrict ref_inode,
+ const struct inode * restrict inode)
+{
+ wimlib_assert(ref_inode != inode);
+
+ if (ref_inode->num_ads != inode->num_ads &&
+ inode->num_ads != 0)
+ return false;
+ if (ref_inode->security_id != inode->security_id
+ || ref_inode->attributes != inode->attributes)
+ return false;
+ for (unsigned i = 0; i <= min(ref_inode->num_ads, inode->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->ads_entries[i - 1],
+ &inode->ads_entries[i - 1]))
+ return false;
+ }
+ return true;
+}
+
+/* Fix up a "true" inode and check for inconsistencies */
+static int fix_true_inode(struct inode *inode, struct hlist_head *inode_list)
+{
+ struct dentry *dentry;
+ struct dentry *ref_dentry = NULL;
+ struct inode *ref_inode;
+ u64 last_ctime = 0;
+ u64 last_mtime = 0;
+ u64 last_atime = 0;
+
+ inode_for_each_dentry(dentry, inode) {
+ if (!ref_dentry || dentry->d_inode->num_ads > ref_dentry->d_inode->num_ads)
+ ref_dentry = dentry;
+ if (dentry->d_inode->creation_time > last_ctime)
+ last_ctime = dentry->d_inode->creation_time;
+ if (dentry->d_inode->last_write_time > last_mtime)
+ last_mtime = dentry->d_inode->last_write_time;
+ if (dentry->d_inode->last_access_time > last_atime)
+ last_atime = dentry->d_inode->last_access_time;
+ }
+
+ ref_inode = ref_dentry->d_inode;
+ ref_inode->link_count = 1;
+ hlist_add_head(&ref_inode->hlist, inode_list);
+
+ list_del(&inode->dentry_list);
+ list_add(&ref_inode->dentry_list, &ref_dentry->inode_dentry_list);
+
+ inode_for_each_dentry(dentry, ref_inode) {
+ if (dentry != ref_dentry) {
+ if (!inodes_consistent(ref_inode, dentry->d_inode)) {
+ inconsistent_inode(ref_inode);
+ return WIMLIB_ERR_INVALID_DENTRY;