+ size_t stream_name_utf16le_nbytes;
+ u16 i;
+ struct wim_ads_entry *result;
+
+ #if TCHAR_IS_UTF16LE
+ const utf16lechar *stream_name_utf16le;
+
+ stream_name_utf16le = stream_name;
+ stream_name_utf16le_nbytes = tstrlen(stream_name) * sizeof(tchar);
+ #else
+ utf16lechar *stream_name_utf16le;
+
+ {
+ int ret = tstr_to_utf16le(stream_name,
+ tstrlen(stream_name) *
+ sizeof(tchar),
+ &stream_name_utf16le,
+ &stream_name_utf16le_nbytes);
+ if (ret)
+ return NULL;
+ }
+ #endif
+ i = 0;
+ result = NULL;
+ do {
+ if (ads_entry_has_name(&inode->i_ads_entries[i],
+ stream_name_utf16le,
+ stream_name_utf16le_nbytes))
+ {
+ if (idx_ret)
+ *idx_ret = i;
+ result = &inode->i_ads_entries[i];
+ break;
+ }
+ } while (++i != inode->i_num_ads);
+ #if !TCHAR_IS_UTF16LE
+ FREE(stream_name_utf16le);
+ #endif
+ return result;
+ }
+}
+
+static struct wim_ads_entry *
+do_inode_add_ads(struct wim_inode *inode, const void *stream_name,
+ size_t stream_name_nbytes, bool is_utf16le)
+{
+ u16 num_ads;
+ struct wim_ads_entry *ads_entries;
+ struct wim_ads_entry *new_entry;
+
+ if (inode->i_num_ads >= 0xfffe) {
+ ERROR("Too many alternate data streams in one inode!");
+ return NULL;
+ }
+ num_ads = inode->i_num_ads + 1;
+ ads_entries = REALLOC(inode->i_ads_entries,
+ num_ads * sizeof(inode->i_ads_entries[0]));
+ if (!ads_entries) {
+ ERROR("Failed to allocate memory for new alternate data stream");
+ return NULL;
+ }
+ inode->i_ads_entries = ads_entries;
+
+ new_entry = &inode->i_ads_entries[num_ads - 1];
+ if (init_ads_entry(new_entry, stream_name, stream_name_nbytes, is_utf16le))
+ return NULL;
+ new_entry->stream_id = inode->i_next_stream_id++;
+ inode->i_num_ads = num_ads;
+ return new_entry;
+}
+
+struct wim_ads_entry *
+inode_add_ads_utf16le(struct wim_inode *inode,
+ const utf16lechar *stream_name,
+ size_t stream_name_nbytes)
+{
+ DEBUG("Add alternate data stream \"%"WS"\"", stream_name);
+ return do_inode_add_ads(inode, stream_name, stream_name_nbytes, true);
+}
+
+/*
+ * Add an alternate stream entry to a WIM inode and return a pointer to it, or
+ * NULL if memory could not be allocated.
+ */
+struct wim_ads_entry *
+inode_add_ads(struct wim_inode *inode, const tchar *stream_name)
+{
+ DEBUG("Add alternate data stream \"%"TS"\"", stream_name);
+ return do_inode_add_ads(inode, stream_name,
+ tstrlen(stream_name) * sizeof(tchar),
+ TCHAR_IS_UTF16LE);
+}
+
+static struct wim_lookup_table_entry *
+add_stream_from_data_buffer(const void *buffer, size_t size,
+ struct wim_lookup_table *lookup_table)
+{
+ u8 hash[SHA1_HASH_SIZE];
+ struct wim_lookup_table_entry *lte, *existing_lte;
+
+ sha1_buffer(buffer, size, hash);
+ existing_lte = __lookup_resource(lookup_table, hash);
+ if (existing_lte) {
+ wimlib_assert(wim_resource_size(existing_lte) == size);
+ lte = existing_lte;
+ lte->refcnt++;
+ } else {
+ void *buffer_copy;
+ lte = new_lookup_table_entry();
+ if (!lte)
+ return NULL;
+ buffer_copy = memdup(buffer, size);
+ if (!buffer_copy) {
+ free_lookup_table_entry(lte);
+ return NULL;
+ }
+ lte->resource_location = RESOURCE_IN_ATTACHED_BUFFER;
+ lte->attached_buffer = buffer_copy;
+ lte->resource_entry.original_size = size;
+ copy_hash(lte->hash, hash);
+ lookup_table_insert(lookup_table, lte);
+ }
+ return lte;
+}
+
+int
+inode_add_ads_with_data(struct wim_inode *inode, const tchar *name,
+ const void *value, size_t size,
+ struct wim_lookup_table *lookup_table)
+{
+ struct wim_ads_entry *new_ads_entry;
+
+ wimlib_assert(inode->i_resolved);
+
+ new_ads_entry = inode_add_ads(inode, name);
+ if (!new_ads_entry)
+ return WIMLIB_ERR_NOMEM;
+
+ new_ads_entry->lte = add_stream_from_data_buffer(value, size,
+ lookup_table);
+ if (!new_ads_entry->lte) {
+ inode_remove_ads(inode, new_ads_entry - inode->i_ads_entries,
+ lookup_table);
+ return WIMLIB_ERR_NOMEM;