+/* Returns the alternate data stream entry belonging to @dentry that has the
+ * stream name @stream_name. */
+struct ads_entry *dentry_get_ads_entry(struct dentry *dentry,
+ const char *stream_name)
+{
+ size_t stream_name_len;
+ if (!stream_name)
+ return NULL;
+ if (dentry->num_ads) {
+ u16 i = 0;
+ stream_name_len = strlen(stream_name);
+ do {
+ if (ads_entry_has_name(&dentry->ads_entries[i],
+ stream_name, stream_name_len))
+ return &dentry->ads_entries[i];
+ } while (++i != dentry->num_ads);
+ }
+ return NULL;
+}
+
+static void ads_entry_init(struct ads_entry *ads_entry)
+{
+ memset(ads_entry, 0, sizeof(struct ads_entry));
+ INIT_LIST_HEAD(&ads_entry->lte_group_list.list);
+ ads_entry->lte_group_list.type = STREAM_TYPE_ADS;
+}
+
+/*
+ * Add an alternate stream entry to a dentry and return a pointer to it, or NULL
+ * if memory could not be allocated.
+ */
+struct ads_entry *dentry_add_ads(struct dentry *dentry, const char *stream_name)
+{
+ u16 num_ads;
+ struct ads_entry *ads_entries;
+ struct ads_entry *new_entry;
+
+ DEBUG("Add alternate data stream %s:%s",
+ dentry->file_name_utf8, stream_name);
+
+ if (dentry->num_ads == 0xffff)
+ return NULL;
+ num_ads = dentry->num_ads + 1;
+ ads_entries = REALLOC(dentry->ads_entries,
+ num_ads * sizeof(struct ads_entry));
+ if (!ads_entries)
+ return NULL;
+ if (ads_entries != dentry->ads_entries) {
+ /* We moved the ADS entries. Adjust the stream lists. */
+ for (u16 i = 0; i < dentry->num_ads; i++) {
+ struct list_head *cur = &ads_entries[i].lte_group_list.list;
+ cur->prev->next = cur;
+ cur->next->prev = cur;
+ }
+ }
+
+ new_entry = &ads_entries[num_ads - 1];
+ ads_entry_init(new_entry);
+ if (change_ads_name(new_entry, stream_name) != 0)
+ return NULL;
+ dentry->ads_entries = ads_entries;
+ dentry->num_ads = num_ads;
+ return new_entry;
+}
+
+/* Remove an alternate data stream from a dentry.
+ *
+ * The corresponding lookup table entry for the stream is NOT changed.
+ *
+ * @dentry: The dentry
+ * @ads_entry: The alternate data stream entry (it MUST be one of the
+ * ads_entry's in the array dentry->ads_entries).
+ */
+void dentry_remove_ads(struct dentry *dentry, struct ads_entry *ads_entry)
+{
+ u16 idx;
+ u16 following;
+
+ wimlib_assert(dentry->num_ads);
+ idx = ads_entry - dentry->ads_entries;
+ wimlib_assert(idx < dentry->num_ads);
+ following = dentry->num_ads - idx - 1;
+
+ destroy_ads_entry(ads_entry);
+ memcpy(ads_entry, ads_entry + 1, following * sizeof(struct ads_entry));
+
+ /* We moved the ADS entries. Adjust the stream lists. */
+ for (u16 i = 0; i < following; i++) {
+ struct list_head *cur = &ads_entry[i].lte_group_list.list;
+ cur->prev->next = cur;
+ cur->next->prev = cur;
+ }
+
+ dentry->num_ads--;
+}
+