return memcmp(dentry->file_name_utf8, name, name_len) == 0;
}
+static u64 __dentry_correct_length_unaligned(u16 file_name_len,
+ u16 short_name_len)
+{
+ u64 length = WIM_DENTRY_DISK_SIZE;
+ if (file_name_len)
+ length += file_name_len + 2;
+ if (short_name_len)
+ length += short_name_len + 2;
+ return length;
+}
+
+static u64 dentry_correct_length_unaligned(const struct dentry *dentry)
+{
+ return __dentry_correct_length_unaligned(dentry->file_name_len,
+ dentry->short_name_len);
+}
+
+/* Return the "correct" value to write in the length field of the dentry, based
+ * on the file name length and short name length */
+static u64 dentry_correct_length(const struct dentry *dentry)
+{
+ return (dentry_correct_length_unaligned(dentry) + 7) & ~7;
+}
+
+static u64 __dentry_total_length(const struct dentry *dentry, u64 length)
+{
+ for (u16 i = 0; i < dentry->num_ads; i++)
+ length += ads_entry_total_length(&dentry->ads_entries[i]);
+ return (length + 7) & ~7;
+}
+
+u64 dentry_correct_total_length(const struct dentry *dentry)
+{
+ return __dentry_total_length(dentry,
+ dentry_correct_length_unaligned(dentry));
+}
+
/* Real length of a dentry, including the alternate data stream entries, which
* are not included in the dentry->length field... */
u64 dentry_total_length(const struct dentry *dentry)
{
- u64 length = (dentry->length + 7) & ~7;
- for (u16 i = 0; i < dentry->num_ads; i++)
- length += ads_entry_total_length(&dentry->ads_entries[i]);
- return length;
+ return __dentry_total_length(dentry, dentry->length);
}
/* Transfers file attributes from a `stat' buffer to a struct dentry. */
dentry->attributes = FILE_ATTRIBUTE_NORMAL;
}
if (sizeof(ino_t) >= 8)
- dentry->hard_link = (u64)stbuf->st_ino;
+ dentry->link_group_id = (u64)stbuf->st_ino;
else
- dentry->hard_link = (u64)stbuf->st_ino |
+ dentry->link_group_id = (u64)stbuf->st_ino |
((u64)stbuf->st_dev << (sizeof(ino_t) * 8));
/* Set timestamps */
dentry->creation_time = timespec_to_wim_timestamp(&stbuf->st_mtim);
DEBUG("Add alternate data stream %s:%s",
dentry->file_name_utf8, stream_name);
- if (dentry->num_ads == 0xffff)
+ if (dentry->num_ads == 0xffff) {
+ ERROR("Too many alternate data streams in one dentry!");
return NULL;
+ }
num_ads = dentry->num_ads + 1;
ads_entries = REALLOC(dentry->ads_entries,
num_ads * sizeof(struct ads_entry));
- if (!ads_entries)
+ if (!ads_entries) {
+ ERROR("Failed to allocate memory for new alternate data stream");
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++) {
/* Advance the subdir offset by the amount of space the children
* of this dentry take up. */
do {
- *subdir_offset_p += dentry_total_length(child);
+ *subdir_offset_p += dentry_correct_total_length(child);
child = child->next;
} while (child != dentry->children);
{
const u8 *hash;
struct lookup_table_entry *lte;
+ time_t time;
+ char *p;
printf("[DENTRY]\n");
printf("Length = %"PRIu64"\n", dentry->length);
#endif
/* Translate the timestamps into something readable */
- time_t creat_time = wim_timestamp_to_unix(dentry->creation_time);
- time_t access_time = wim_timestamp_to_unix(dentry->last_access_time);
- time_t mod_time = wim_timestamp_to_unix(dentry->last_write_time);
- printf("Creation Time = %s", asctime(gmtime(&creat_time)));
- printf("Last Access Time = %s", asctime(gmtime(&access_time)));
- printf("Last Write Time = %s", asctime(gmtime(&mod_time)));
+ time = wim_timestamp_to_unix(dentry->creation_time);
+ p = asctime(gmtime(&time));
+ *(strrchr(p, '\n')) = '\0';
+ printf("Creation Time = %s UTC\n", p);
+
+ time = wim_timestamp_to_unix(dentry->last_access_time);
+ p = asctime(gmtime(&time));
+ *(strrchr(p, '\n')) = '\0';
+ printf("Last Access Time = %s UTC\n", p);
+
+ time = wim_timestamp_to_unix(dentry->last_write_time);
+ p = asctime(gmtime(&time));
+ *(strrchr(p, '\n')) = '\0';
+ printf("Last Write Time = %s UTC\n", p);
printf("Reparse Tag = 0x%"PRIx32"\n", dentry->reparse_tag);
- printf("Hard Link Group = 0x%"PRIx64"\n", dentry->hard_link);
+ printf("Hard Link Group = 0x%"PRIx64"\n", dentry->link_group_id);
printf("Number of Alternate Data Streams = %hu\n", dentry->num_ads);
printf("Filename = \"");
print_string(dentry->file_name, dentry->file_name_len);
}
dentry->ads_entries_status = ADS_ENTRIES_USER;
}
- struct list_head *next;
list_del(&dentry->link_group_list);
free_dentry(dentry);
}
}
}
-
-/* Recalculates the length of @dentry based on its file name length and short
- * name length. */
-static inline void recalculate_dentry_size(struct dentry *dentry)
-{
- dentry->length = WIM_DENTRY_DISK_SIZE + dentry->file_name_len +
- 2 + dentry->short_name_len;
- /* Must be multiple of 8. */
- dentry->length = (dentry->length + 7) & ~7;
-}
-
/* Duplicates a UTF-8 name into UTF-8 and UTF-16 strings and returns the strings
* and their lengths in the pointer arguments */
int get_names(char **name_utf16_ret, char **name_utf8_ret,
ret = get_names(&dentry->file_name, &dentry->file_name_utf8,
&dentry->file_name_len, &dentry->file_name_utf8_len,
new_name);
+ FREE(dentry->short_name);
+ dentry->short_name_len = 0;
if (ret == 0)
- recalculate_dentry_size(dentry);
+ dentry->length = dentry_correct_length(dentry);
return ret;
}
*
* struct ads_entry_on_disk {
* u64 length; // Length of the entry, in bytes. This includes
- * all fields (including the stream name, the
- * null terminator, AND the padding!).
+ * all fields (including the stream name and
+ * null terminator if present, AND the padding!).
* u64 reserved; // Seems to be unused
* u8 hash[20]; // SHA1 message digest of the uncompressed stream
* u16 stream_name_len; // Length of the stream name, in bytes
* char stream_name[]; // Stream name in UTF-16LE, @stream_name_len bytes long,
* not including null terminator
* u16 zero; // UTF-16 null terminator for the stream name, NOT
- * included in @stream_name_len
+ * included in @stream_name_len. Based on what
+ * I've observed from filenames in dentries,
+ * this field should not exist when
+ * (@stream_name_len == 0), but you can't
+ * actually tell because of the padding anyway
+ * (provided that the padding is zeroed, which
+ * it always seems to be).
* char padding[]; // Padding to make the size a multiple of 8 bytes.
* };
*
u64 length_no_padding;
u64 total_length;
size_t utf8_len;
- const char *p_save = p;
+ const u8 *p_save = p;
/* Read the base stream entry, excluding the stream name. */
if (remaining_size < WIM_ADS_ENTRY_DISK_SIZE) {
}
p = get_u64(p, &length);
- p += 8;
+ p += 8; /* Skip the reserved field */
p = get_bytes(p, SHA1_HASH_SIZE, (u8*)cur_entry->hash);
p = get_u16(p, &cur_entry->stream_name_len);
* */
length_no_padding = WIM_ADS_ENTRY_DISK_SIZE +
cur_entry->stream_name_len;
+
+ /* Length including the null terminator and the padding */
total_length = ((length_no_padding + 2) + 7) & ~7;
wimlib_assert(total_length == ads_entry_total_length(cur_entry));
if (remaining_size < length_no_padding) {
ERROR("Stream entries go past end of metadata resource");
ERROR("(remaining_size = %"PRIu64" bytes, "
- "length_no_padding = %"PRIu16" bytes",
+ "length_no_padding = %"PRIu64" bytes)",
remaining_size, length_no_padding);
ret = WIMLIB_ERR_INVALID_DENTRY;
goto out_free_ads_entries;
goto out_free_ads_entries;
}
- cur_entry->stream_name = MALLOC(cur_entry->stream_name_len);
- if (!cur_entry->stream_name) {
- ret = WIMLIB_ERR_NOMEM;
- goto out_free_ads_entries;
- }
- get_bytes(p, cur_entry->stream_name_len,
- (u8*)cur_entry->stream_name);
- cur_entry->stream_name_utf8 = utf16_to_utf8(cur_entry->stream_name,
- cur_entry->stream_name_len,
- &utf8_len);
- cur_entry->stream_name_utf8_len = utf8_len;
-
- if (!cur_entry->stream_name_utf8) {
- ret = WIMLIB_ERR_NOMEM;
- goto out_free_ads_entries;
+ if (cur_entry->stream_name_len) {
+ cur_entry->stream_name = MALLOC(cur_entry->stream_name_len);
+ if (!cur_entry->stream_name) {
+ ret = WIMLIB_ERR_NOMEM;
+ goto out_free_ads_entries;
+ }
+ get_bytes(p, cur_entry->stream_name_len,
+ (u8*)cur_entry->stream_name);
+ cur_entry->stream_name_utf8 = utf16_to_utf8(cur_entry->stream_name,
+ cur_entry->stream_name_len,
+ &utf8_len);
+ cur_entry->stream_name_utf8_len = utf8_len;
+
+ if (!cur_entry->stream_name_utf8) {
+ ret = WIMLIB_ERR_NOMEM;
+ goto out_free_ads_entries;
+ }
}
/* It's expected that the size of every ADS entry is a multiple
* of 8. However, to be safe, I'm allowing the possibility of
{
const u8 *p;
u64 calculated_size;
- char *file_name;
- char *file_name_utf8;
- char *short_name;
+ char *file_name = NULL;
+ char *file_name_utf8 = NULL;
+ char *short_name = NULL;
u16 short_name_len;
u16 file_name_len;
- size_t file_name_utf8_len;
+ size_t file_name_utf8_len = 0;
int ret;
dentry_common_init(dentry);
/*Make sure the dentry really fits into the metadata resource.*/
- if (offset + 8 > metadata_resource_len) {
+ if (offset + 8 > metadata_resource_len || offset + 8 < offset) {
ERROR("Directory entry starting at %"PRIu64" ends past the "
"end of the metadata resource (size %"PRIu64")",
offset, metadata_resource_len);
* not too short, read the rest of it (excluding the alternate data
* streams, but including the file name and short name variable-length
* fields) into memory. */
- if (offset + dentry->length >= metadata_resource_len) {
+ if (offset + dentry->length >= metadata_resource_len
+ || offset + dentry->length < offset)
+ {
ERROR("Directory entry at offset %"PRIu64" and with size "
"%"PRIu64" ends past the end of the metadata resource "
"(size %"PRIu64")",
p += 4;
} else {
p = get_u32(p, &dentry->reparse_tag);
- p = get_u64(p, &dentry->hard_link);
+ p = get_u64(p, &dentry->link_group_id);
}
/* By the way, the reparse_reserved field does not actually exist (at
p = get_u16(p, &short_name_len);
p = get_u16(p, &file_name_len);
- /* We now know the length of the file name and short name. These should
- * be included in the dentry length, but make sure the numbers are
- * consistent. */
- calculated_size = WIM_DENTRY_DISK_SIZE + file_name_len + 2 +
- short_name_len;
+ /* We now know the length of the file name and short name. Make sure
+ * the length of the dentry is large enough to actually hold them.
+ *
+ * The calculated length here is unaligned to allow for the possibility
+ * that the dentry->length names an unaligned length, although this
+ * would be unexpected. */
+ calculated_size = __dentry_correct_length_unaligned(file_name_len,
+ short_name_len);
if (dentry->length < calculated_size) {
ERROR("Unexpected end of directory entry! (Expected "
- "%"PRIu64" bytes, got %"PRIu64" bytes. "
+ "at least %"PRIu64" bytes, got %"PRIu64" bytes. "
"short_name_len = %hu, file_name_len = %hu)",
calculated_size, dentry->length,
short_name_len, file_name_len);
return WIMLIB_ERR_INVALID_DENTRY;
}
- /* Read the filename. */
- file_name = MALLOC(file_name_len);
- if (!file_name) {
- ERROR("Failed to allocate %hu bytes for dentry file name",
- file_name_len);
- return WIMLIB_ERR_NOMEM;
- }
- p = get_bytes(p, file_name_len, file_name);
+ /* Read the filename if present. Note: if the filename is empty, there
+ * is no null terminator following it. */
+ if (file_name_len) {
+ file_name = MALLOC(file_name_len);
+ if (!file_name) {
+ ERROR("Failed to allocate %hu bytes for dentry file name",
+ file_name_len);
+ return WIMLIB_ERR_NOMEM;
+ }
+ p = get_bytes(p, file_name_len, file_name);
- /* Convert filename to UTF-8. */
- file_name_utf8 = utf16_to_utf8(file_name, file_name_len,
- &file_name_utf8_len);
+ /* Convert filename to UTF-8. */
+ file_name_utf8 = utf16_to_utf8(file_name, file_name_len,
+ &file_name_utf8_len);
- if (!file_name_utf8) {
- ERROR("Failed to allocate memory to convert UTF-16 "
- "filename (%hu bytes) to UTF-8", file_name_len);
- ret = WIMLIB_ERR_NOMEM;
- goto out_free_file_name;
+ if (!file_name_utf8) {
+ ERROR("Failed to allocate memory to convert UTF-16 "
+ "filename (%hu bytes) to UTF-8", file_name_len);
+ ret = WIMLIB_ERR_NOMEM;
+ goto out_free_file_name;
+ }
+ if (*(u16*)p)
+ WARNING("Expected two zero bytes following the file name "
+ "`%s', but found non-zero bytes", file_name_utf8);
+ p += 2;
}
- /* Undocumented padding between file name and short name. This probably
- * is supposed to be a terminating null character. */
- p += 2;
-
- /* Read the short filename. */
- short_name = MALLOC(short_name_len);
- if (!short_name) {
- ERROR("Failed to allocate %hu bytes for short filename",
- short_name_len);
- ret = WIMLIB_ERR_NOMEM;
- goto out_free_file_name_utf8;
+ /* Align the calculated size */
+ calculated_size = (calculated_size + 7) & ~7;
+
+ if (dentry->length > calculated_size) {
+ /* Weird; the dentry says it's longer than it should be. Note
+ * that the length field does NOT include the size of the
+ * alternate stream entries. */
+
+ /* Strangely, some directory entries inexplicably have a little
+ * over 70 bytes of extra data. The exact amount of data seems
+ * to be 72 bytes, but it is aligned on the next 8-byte
+ * boundary. It does NOT seem to be alternate data stream
+ * entries. Here's an example of the aligned data:
+ *
+ * 01000000 40000000 6c786bba c58ede11 b0bb0026 1870892a b6adb76f
+ * e63a3e46 8fca8653 0d2effa1 6c786bba c58ede11 b0bb0026 1870892a
+ * 00000000 00000000 00000000 00000000
+ *
+ * Here's one interpretation of how the data is laid out.
+ *
+ * struct unknown {
+ * u32 field1; (always 0x00000001)
+ * u32 field2; (always 0x40000000)
+ * u8 data[48]; (???)
+ * u64 reserved1; (always 0)
+ * u64 reserved2; (always 0)
+ * };*/
+ DEBUG("Dentry for file or directory `%s' has %zu extra "
+ "bytes of data",
+ file_name_utf8, dentry->length - calculated_size);
}
- p = get_bytes(p, short_name_len, short_name);
+ /* Read the short filename if present. Note: if there is no short
+ * filename, there is no null terminator following it. */
+ if (short_name_len) {
+ short_name = MALLOC(short_name_len);
+ if (!short_name) {
+ ERROR("Failed to allocate %hu bytes for short filename",
+ short_name_len);
+ ret = WIMLIB_ERR_NOMEM;
+ goto out_free_file_name_utf8;
+ }
- /* Some directory entries inexplicably have a little over 70 bytes of
- * extra data. The exact amount of data seems to be 72 bytes, but it is
- * aligned on the next 8-byte boundary. It does NOT seem to be
- * alternate data stream entries. Here's an example of the aligned
- * data:
- *
- * 01000000 40000000 6c786bba c58ede11 b0bb0026 1870892a b6adb76f
- * e63a3e46 8fca8653 0d2effa1 6c786bba c58ede11 b0bb0026 1870892a
- * 00000000 00000000 00000000 00000000
- *
- * Here's one interpretation of how the data is laid out.
- *
- * struct unknown {
- * u32 field1; (always 0x00000001)
- * u32 field2; (always 0x40000000)
- * u8 data[48]; (???)
- * u64 reserved1; (always 0)
- * u64 reserved2; (always 0)
- * };*/
-#if 0
- if (dentry->length - calculated_size >= WIM_ADS_ENTRY_DISK_SIZE) {
- printf("%s: %lu / %lu (", file_name_utf8,
- calculated_size, dentry->length);
- print_string(p + WIM_ADS_ENTRY_DISK_SIZE, dentry->length - calculated_size - WIM_ADS_ENTRY_DISK_SIZE);
- puts(")");
- print_byte_field(p, dentry->length - calculated_size);
- putchar('\n');
+ p = get_bytes(p, short_name_len, short_name);
+ if (*(u16*)p)
+ WARNING("Expected two zero bytes following the file name "
+ "`%s', but found non-zero bytes", file_name_utf8);
+ p += 2;
}
-#endif
/*
* Read the alternate data streams, if present. dentry->num_ads tells
* included in the dentry->length field for some reason.
*/
if (dentry->num_ads != 0) {
- calculated_size = (calculated_size + 7) & ~7;
if (calculated_size > metadata_resource_len - offset) {
ERROR("Not enough space in metadata resource for "
"alternate stream entries");
return ret;
}
+/* Run some miscellaneous verifications on a WIM dentry */
+int verify_dentry(struct dentry *dentry, void *wim)
+{
+ const WIMStruct *w = wim;
+ const struct lookup_table *table = w->lookup_table;
+ const struct wim_security_data *sd = wim_const_security_data(w);
+ int ret = WIMLIB_ERR_INVALID_DENTRY;
+
+ /* Check the security ID */
+ if (dentry->security_id < -1) {
+ ERROR("Dentry `%s' has an invalid security ID (%d)",
+ dentry->full_path_utf8, dentry->security_id);
+ goto out;
+ }
+ if (dentry->security_id >= sd->num_entries) {
+ ERROR("Dentry `%s' has an invalid security ID (%d) "
+ "(there are only %u entries in the security table)",
+ dentry->full_path_utf8, dentry->security_id,
+ sd->num_entries);
+ goto out;
+ }
+
+ /* Check that lookup table entries for all the resources exist, except
+ * if the SHA1 message digest is all 0's, which indicates there is
+ * intentionally no resource there. */
+ if (w->hdr.total_parts == 1) {
+ for (unsigned i = 0; i <= dentry->num_ads; i++) {
+ struct lookup_table_entry *lte;
+ const u8 *hash;
+ hash = dentry_stream_hash_unresolved(dentry, i);
+ lte = __lookup_resource(table, hash);
+ if (!lte && !is_zero_hash(hash)) {
+ ERROR("Could not find lookup table entry for stream "
+ "%u of dentry `%s'", i, dentry->full_path_utf8);
+ goto out;
+ }
+ }
+ }
+
+ /* Make sure there is only one un-named stream. */
+ unsigned num_unnamed_streams = 0;
+ for (unsigned i = 0; i <= dentry->num_ads; i++) {
+ const u8 *hash;
+ hash = dentry_stream_hash_unresolved(dentry, i);
+ if (!dentry_stream_name_len(dentry, i) && !is_zero_hash(hash))
+ num_unnamed_streams++;
+ }
+ if (num_unnamed_streams > 1) {
+ ERROR("Dentry `%s' has multiple (%u) un-named streams",
+ dentry->full_path_utf8, num_unnamed_streams);
+ goto out;
+ }
+
+ /* Cannot have a short name but no long name */
+ if (dentry->short_name_len && !dentry->file_name_len) {
+ ERROR("Dentry `%s' has a short name but no long name",
+ dentry->full_path_utf8);
+ goto out;
+ }
+
+ /* Make sure root dentry is unnamed */
+ if (dentry_is_root(dentry)) {
+ if (dentry->file_name_len) {
+ ERROR("The root dentry is named `%s', but it must "
+ "be unnamed", dentry->file_name_utf8);
+ goto out;
+ }
+ }
+
+#if 0
+ /* Check timestamps */
+ if (dentry->last_access_time < dentry->creation_time ||
+ dentry->last_write_time < dentry->creation_time) {
+ WARNING("Dentry `%s' was created after it was last accessed or "
+ "written to", dentry->full_path_utf8);
+ }
+#endif
+
+ ret = 0;
+out:
+ return ret;
+}
+
/*
* Writes a WIM dentry to an output buffer.
*
static u8 *write_dentry(const struct dentry *dentry, u8 *p)
{
u8 *orig_p = p;
- unsigned padding;
const u8 *hash;
- p = put_u64(p, dentry->length);
+ /* We calculate the correct length of the dentry ourselves because the
+ * dentry->length field may been set to an unexpected value from when we
+ * read the dentry in (for example, there may have been unknown data
+ * appended to the end of the dentry...) */
+ u64 length = dentry_correct_length(dentry);
+
+ p = put_u64(p, length);
p = put_u32(p, dentry->attributes);
p = put_u32(p, dentry->security_id);
p = put_u64(p, dentry->subdir_offset);
p = put_u64(p, dentry->creation_time);
p = put_u64(p, dentry->last_access_time);
p = put_u64(p, dentry->last_write_time);
- if (dentry->resolved && dentry->lte)
- hash = dentry->lte->hash;
- else
- hash = dentry->hash;
+ hash = dentry_stream_hash(dentry, 0);
p = put_bytes(p, SHA1_HASH_SIZE, hash);
if (dentry->attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
p = put_zeroes(p, 4);
p = put_u32(p, dentry->reparse_tag);
p = put_zeroes(p, 4);
} else {
- u64 hard_link;
+ u64 link_group_id;
p = put_u32(p, 0);
if (dentry->link_group_list.next == &dentry->link_group_list)
- hard_link = 0;
+ link_group_id = 0;
else
- hard_link = dentry->hard_link;
- p = put_u64(p, hard_link);
+ link_group_id = dentry->link_group_id;
+ p = put_u64(p, link_group_id);
}
p = put_u16(p, dentry->num_ads);
p = put_u16(p, dentry->short_name_len);
p = put_u16(p, dentry->file_name_len);
- p = put_bytes(p, dentry->file_name_len, (u8*)dentry->file_name);
- p = put_u16(p, 0); /* filename padding, 2 bytes. */
- p = put_bytes(p, dentry->short_name_len, (u8*)dentry->short_name);
-
- wimlib_assert(p - orig_p <= dentry->length);
- if (p - orig_p < dentry->length)
- p = put_zeroes(p, dentry->length - (p - orig_p));
+ if (dentry->file_name_len) {
+ p = put_bytes(p, dentry->file_name_len, (u8*)dentry->file_name);
+ p = put_u16(p, 0); /* filename padding, 2 bytes. */
+ }
+ if (dentry->short_name) {
+ p = put_bytes(p, dentry->short_name_len, (u8*)dentry->short_name);
+ p = put_u16(p, 0); /* short name padding, 2 bytes */
+ }
/* Align to 8-byte boundary */
- p = put_zeroes(p, (8 - dentry->length % 8) % 8);
+ wimlib_assert(length >= (p - orig_p)
+ && length - (p - orig_p) <= 7);
+ p = put_zeroes(p, length - (p - orig_p));
/* Write the alternate data streams, if there are any. Please see
* read_ads_entries() for comments about the format of the on-disk
for (u16 i = 0; i < dentry->num_ads; i++) {
p = put_u64(p, ads_entry_total_length(&dentry->ads_entries[i]));
p = put_u64(p, 0); /* Unused */
- if (dentry->resolved && dentry->ads_entries[i].lte)
- hash = dentry->ads_entries[i].lte->hash;
- else
- hash = dentry->ads_entries[i].hash;
+ hash = dentry_stream_hash(dentry, i + 1);
p = put_bytes(p, SHA1_HASH_SIZE, hash);
p = put_u16(p, dentry->ads_entries[i].stream_name_len);
- p = put_bytes(p, dentry->ads_entries[i].stream_name_len,
- (u8*)dentry->ads_entries[i].stream_name);
- p = put_u16(p, 0);
+ if (dentry->ads_entries[i].stream_name_len) {
+ p = put_bytes(p, dentry->ads_entries[i].stream_name_len,
+ (u8*)dentry->ads_entries[i].stream_name);
+ p = put_u16(p, 0);
+ }
p = put_zeroes(p, (8 - (p - orig_p) % 8) % 8);
}
+#ifdef ENABLE_ASSERTIONS
+ wimlib_assert(p - orig_p == __dentry_total_length(dentry, length));
+#endif
return p;
}
break;
}
- /* Advance to the offset of the next child. */
+ /* Advance to the offset of the next child. Note: We need to
+ * advance by the TOTAL length of the dentry, not by the length
+ * child->length, which although it does take into account the
+ * padding, it DOES NOT take into account alternate stream
+ * entries. */
cur_offset += dentry_total_length(child);
}