+static bool dentries_have_same_ads(const struct dentry *d1,
+ const struct dentry *d2)
+{
+ /* Verify stream names and hashes are the same */
+ for (u16 i = 0; i < d1->num_ads; i++) {
+ if (strcmp(d1->ads_entries[i].stream_name_utf8,
+ d2->ads_entries[i].stream_name_utf8) != 0)
+ return false;
+ if (!hashes_equal(d1->ads_entries[i].hash,
+ d2->ads_entries[i].hash))
+ return false;
+ }
+ return true;
+}
+
+/* Share the alternate stream entries between hard-linked dentries. */
+static int share_dentry_ads(struct dentry *owner, struct dentry *user)
+{
+ const char *mismatch_type;
+ wimlib_assert(owner->num_ads == 0 ||
+ owner->ads_entries != user->ads_entries);
+ if (owner->attributes != user->attributes) {
+ mismatch_type = "attributes";
+ goto mismatch;
+ }
+ if (owner->attributes & FILE_ATTRIBUTE_DIRECTORY) {
+ WARNING("`%s' is hard-linked to `%s', which is a directory ",
+ user->full_path_utf8, owner->full_path_utf8);
+ return WIMLIB_ERR_INVALID_DENTRY;
+ }
+ if (owner->security_id != user->security_id) {
+ mismatch_type = "security ID";
+ goto mismatch;
+ }
+ if (!hashes_equal(owner->hash, user->hash)) {
+ mismatch_type = "main file resource";
+ goto mismatch;
+ }
+ if (!dentries_have_same_ads(owner, user)) {
+ mismatch_type = "Alternate Stream Entries";
+ goto mismatch;
+ }
+ dentry_free_ads_entries(user);
+ user->ads_entries = owner->ads_entries;
+ user->ads_entries_status = ADS_ENTRIES_USER;
+ return 0;
+mismatch:
+ WARNING("Dentries `%s' and `%s' in the same hard-link group but "
+ "do not share the same %s",
+ owner->full_path_utf8, user->full_path_utf8,
+ mismatch_type);
+ return WIMLIB_ERR_INVALID_DENTRY;
+}
+