+ found_short_name = true;
+ }
+ }
+ if (dentry->creation_time > last_ctime)
+ last_ctime = dentry->creation_time;
+ if (dentry->last_write_time > last_mtime)
+ last_mtime = dentry->last_write_time;
+ if (dentry->last_access_time > last_atime)
+ last_atime = dentry->last_access_time;
+ } while ((dentry = container_of(dentry->link_group_list.next,
+ struct dentry,
+ link_group_list)) != first_dentry);
+
+
+ ref_dentry->ads_entries_status = ADS_ENTRIES_OWNER;
+ dentry = first_dentry;
+ do {
+ if (dentry != ref_dentry) {
+ if (!dentries_consistent(ref_dentry, dentry)) {
+ inconsistent_link_group(first_dentry);
+ return WIMLIB_ERR_INVALID_DENTRY;
+ }
+ copy_hash(dentry->hash, ref_dentry->hash);
+ dentry_free_ads_entries(dentry);
+ dentry->num_ads = ref_dentry->num_ads;
+ dentry->ads_entries = ref_dentry->ads_entries;
+ dentry->ads_entries_status = ADS_ENTRIES_USER;
+ }
+ dentry->creation_time = last_ctime;
+ dentry->last_write_time = last_mtime;
+ dentry->last_access_time = last_atime;
+ } while ((dentry = container_of(dentry->link_group_list.next,
+ struct dentry,
+ link_group_list)) != first_dentry);
+ return 0;
+}
+
+/*
+ * Fixes up a nominal link group.
+ *
+ * By a nominal link group we mean a group of two or more dentries that share
+ * the same hard link group ID.
+ *
+ * If dentries in the group are found to be inconsistent, we may split the group
+ * into several "true" hard link groups. @new_groups points to a linked list of
+ * these split groups, and if we create any, they will be added to this list.
+ *
+ * After splitting up each nominal link group into the "true" link groups we
+ * will canonicalize the link groups. To do this, we:
+ *
+ * - Assign all the dentries in the link group the most recent timestamp
+ * among all the corresponding timestamps in the link group, for each of
+ * the three categories of time stamps.
+ *
+ * - Make sure the dentry->hash field is valid in all the dentries, if
+ * possible (this field may be all zeroes, and in the context of a hard
+ * link group this must be interpreted as implicitly refering to the same
+ * stream as another dentry in the hard link group that does NOT have all
+ * zeroes for this field).
+ *
+ * - Make sure dentry->num_ads is the same in all the dentries in the link
+ * group. In some cases, it's possible for it to be set to 0 when it
+ * actually must be interpreted as being the same as the number of
+ * alternate data streams in another dentry in the hard link group that has
+ * a nonzero number of alternate data streams.
+ *
+ * - Make sure only the dentry->ads_entries array is only allocated for one
+ * dentry in the hard link group. This dentry will have
+ * dentry->ads_entries_status set to ADS_ENTRIES_OWNER, while the others
+ * will have dentry->ads_entries_status set to ADS_ENTRIES_USER.
+ */
+static int
+fix_nominal_link_group(struct link_group *group,
+ struct link_group **new_groups)
+{
+ struct dentry *tmp, *dentry, *ref_dentry;
+ int ret;
+ size_t num_true_link_groups;
+ struct list_head *head;
+
+ LIST_HEAD(dentries_with_data_streams);
+ LIST_HEAD(dentries_with_no_data_streams);
+ LIST_HEAD(true_link_groups);
+
+ /* Create a list of dentries in the nominal hard link group that have at
+ * 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. */
+ dentry = container_of(group->dentry_list, struct dentry,
+ link_group_list);
+ do {
+ for (unsigned i = 0; i <= dentry->num_ads; i++) {
+ const u8 *hash;
+ hash = dentry_stream_hash(dentry, i);
+ if (!is_zero_hash(hash)) {
+ list_add(&dentry->tmp_list,
+ &dentries_with_data_streams);
+ goto next_dentry;