-int
-stream_not_found_error(const struct wim_inode *inode, const u8 *hash)
-{
- if (wimlib_print_errors) {
- ERROR("\"%"TS"\": stream not found", inode_first_full_path(inode));
- tfprintf(stderr, T(" SHA-1 message digest of missing stream:\n "));
- print_hash(hash, stderr);
- tputc(T('\n'), stderr);
- }
- return WIMLIB_ERR_RESOURCE_NOT_FOUND;
-}
-
-/*
- * Reads the alternate data stream entries of a WIM dentry.
- *
- * @p:
- * Pointer to buffer that starts with the first alternate stream entry.
- *
- * @inode:
- * Inode to load the alternate data streams into. @inode->i_num_ads must
- * have been set to the number of alternate data streams that are expected.
- *
- * @remaining_size:
- * Number of bytes of data remaining in the buffer pointed to by @p.
- *
- * On success, inode->i_ads_entries is set to an array of `struct
- * wim_ads_entry's of length inode->i_num_ads. On failure, @inode is not
- * modified.
- *
- * Return values:
- * WIMLIB_ERR_SUCCESS (0)
- * WIMLIB_ERR_INVALID_METADATA_RESOURCE
- * WIMLIB_ERR_NOMEM
- */
-int
-read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
- size_t nbytes_remaining)
-{
- u16 num_ads;
- struct wim_ads_entry *ads_entries;
- int ret;
-
- BUILD_BUG_ON(sizeof(struct wim_ads_entry_on_disk) != WIM_ADS_ENTRY_DISK_SIZE);
-
- /* Allocate an array for our in-memory representation of the alternate
- * data stream entries. */
- num_ads = inode->i_num_ads;
- ads_entries = CALLOC(num_ads, sizeof(inode->i_ads_entries[0]));
- if (ads_entries == NULL)
- goto out_of_memory;
-
- /* Read the entries into our newly allocated buffer. */
- for (u16 i = 0; i < num_ads; i++) {
- u64 length;
- struct wim_ads_entry *cur_entry;
- const struct wim_ads_entry_on_disk *disk_entry =
- (const struct wim_ads_entry_on_disk*)p;
-
- cur_entry = &ads_entries[i];
- ads_entries[i].stream_id = i + 1;
-
- /* Do we have at least the size of the fixed-length data we know
- * need? */
- if (nbytes_remaining < sizeof(struct wim_ads_entry_on_disk))
- goto out_invalid;
-
- /* Read the length field */
- length = le64_to_cpu(disk_entry->length);
-
- /* Make sure the length field is neither so small it doesn't
- * include all the fixed-length data nor so large it overflows
- * the metadata resource buffer. */
- if (length < sizeof(struct wim_ads_entry_on_disk) ||
- length > nbytes_remaining)
- goto out_invalid;
-
- /* Read the rest of the fixed-length data. */
-
- cur_entry->reserved = le64_to_cpu(disk_entry->reserved);
- copy_hash(cur_entry->hash, disk_entry->hash);
- cur_entry->stream_name_nbytes = le16_to_cpu(disk_entry->stream_name_nbytes);
-
- /* If stream_name_nbytes != 0, this is a named stream.
- * Otherwise this is an unnamed stream, or in some cases (bugs
- * in Microsoft's software I guess) a meaningless entry
- * distinguished from the real unnamed stream entry, if any, by
- * the fact that the real unnamed stream entry has a nonzero
- * hash field. */
- if (cur_entry->stream_name_nbytes) {
- /* The name is encoded in UTF16-LE, which uses 2-byte
- * coding units, so the length of the name had better be
- * an even number of bytes... */
- if (cur_entry->stream_name_nbytes & 1)
- goto out_invalid;
-
- /* Add the length of the stream name to get the length
- * we actually need to read. Make sure this isn't more
- * than the specified length of the entry. */
- if (sizeof(struct wim_ads_entry_on_disk) +
- cur_entry->stream_name_nbytes > length)
- goto out_invalid;
-
- cur_entry->stream_name = MALLOC(cur_entry->stream_name_nbytes + 2);
- if (cur_entry->stream_name == NULL)
- goto out_of_memory;
-
- memcpy(cur_entry->stream_name,
- disk_entry->stream_name,
- cur_entry->stream_name_nbytes);
- cur_entry->stream_name[cur_entry->stream_name_nbytes / 2] = cpu_to_le16(0);
- } else {
- /* Mark inode as having weird stream entries. */
- inode->i_canonical_streams = 0;
- }