+
+ 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;
+ }
+ }
+ list_add(&dentry->tmp_list,
+ &dentries_with_no_data_streams);
+ next_dentry:
+ dentry = container_of(dentry->link_group_list.next,
+ struct dentry,
+ link_group_list);
+ } while (&dentry->link_group_list != group->dentry_list);
+
+ /* If there are no dentries with data streams, we require the nominal
+ * link group to be a true link group */
+ if (list_empty(&dentries_with_data_streams)) {
+ #ifdef ENABLE_DEBUG
+ {
+ size_t size = dentry_link_group_size(dentry);
+ if (size > 1) {
+ DEBUG("Found link group of size %zu without "
+ "any data streams:", size);
+ print_dentry_list(dentry);
+ DEBUG("We are going to interpret it as true "
+ "link group, provided that the dentries "
+ "are consistent.");
+ }
+ }
+ #endif
+ return fix_true_link_group(container_of(group->dentry_list,
+ struct dentry,
+ link_group_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
+ * link groups. */
+ num_true_link_groups = 0;
+ list_for_each_entry_safe(dentry, tmp, &dentries_with_data_streams,
+ tmp_list)
+ {
+ list_del(&dentry->tmp_list);
+
+ /* Look for a true link group that is consistent with
+ * this dentry and add this dentry to it. Or, if none
+ * of the true link groups are consistent with this
+ * dentry, make a new one. */
+ list_for_each_entry(ref_dentry, &true_link_groups, tmp_list) {
+ if (ref_dentries_consistent(ref_dentry, dentry)) {
+ list_add(&dentry->link_group_list,
+ &ref_dentry->link_group_list);
+ goto next_dentry_2;
+ }
+ }
+ num_true_link_groups++;
+ list_add(&dentry->tmp_list, &true_link_groups);
+ INIT_LIST_HEAD(&dentry->link_group_list);
+next_dentry_2:
+ ;
+ }
+
+ wimlib_assert(num_true_link_groups != 0);
+
+ /* If there were dentries with no data streams, we require there to only
+ * be one true link group so that we know which link group to assign the
+ * streamless dentries to. */
+ if (!list_empty(&dentries_with_no_data_streams)) {
+ if (num_true_link_groups != 1) {
+ ERROR("Hard link group ambiguity detected!");
+ ERROR("We split up hard link group 0x%"PRIx64" due to "
+ "inconsistencies,", group->link_group_id);
+ ERROR("but dentries with no stream information remained. "
+ "We don't know which true hard link");
+ ERROR("group to assign them to.");
+ return WIMLIB_ERR_INVALID_DENTRY;
+ }
+ /* Assign the streamless dentries to the one and only true link
+ * group. */
+ ref_dentry = container_of(true_link_groups.next,
+ struct dentry,
+ tmp_list);
+ list_for_each_entry(dentry, &dentries_with_no_data_streams, tmp_list)
+ list_add(&dentry->link_group_list, &ref_dentry->link_group_list);
+ }
+ if (num_true_link_groups != 1) {
+ #ifdef ENABLE_DEBUG
+ {
+ printf("Split nominal link group 0x%"PRIx64" into %zu "
+ "link groups:\n",
+ group->link_group_id, num_true_link_groups);
+ puts("------------------------------------------------------------------------------");
+ size_t i = 1;
+ list_for_each_entry(dentry, &true_link_groups, tmp_list) {
+ printf("[Split link group %zu]\n", i++);
+ print_dentry_list(dentry);
+ putchar('\n');
+ }
+ puts("------------------------------------------------------------------------------");
+ }
+ #endif
+ }
+
+ list_for_each_entry(dentry, &true_link_groups, tmp_list) {
+ ret = fix_true_link_group(dentry);