struct wim_dentry * restrict child)
{
wimlib_assert(dentry_is_directory(parent));
+ wimlib_assert(parent != child);
struct rb_root *root = &parent->d_inode->i_children;
struct rb_node **new = &(root->rb_node);
lte = new_lookup_table_entry();
if (!lte)
return NULL;
- buffer_copy = MALLOC(size);
+ buffer_copy = memdup(buffer, size);
if (!buffer_copy) {
free_lookup_table_entry(lte);
return NULL;
}
- memcpy(buffer_copy, buffer, size);
lte->resource_location = RESOURCE_IN_ATTACHED_BUFFER;
lte->attached_buffer = buffer_copy;
lte->resource_entry.original_size = size;
* @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.
+ * @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.
+ * to by @p.
*
*
* Return 0 on success or nonzero on failure. On success, inode->i_ads_entries
struct wim_ads_entry *ads_entries;
int ret;
+ /* 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)
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;
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, or so large it overflows
+ * 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)
/* 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(cur_entry->stream_name_nbytes);
+ 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
* the fact that the real unnamed stream entry has a nonzero
* hash field. */
if (cur_entry->stream_name_nbytes) {
- u64 length_no_padding;
-
/* 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... */
memcpy(cur_entry->stream_name,
disk_entry->stream_name,
cur_entry->stream_name_nbytes);
- cur_entry->stream_name[cur_entry->stream_name_nbytes / 2] = 0;
+ cur_entry->stream_name[cur_entry->stream_name_nbytes / 2] = cpu_to_le16(0);
replace_forbidden_characters(cur_entry->stream_name);
}
nbytes_remaining -= length;
}
inode->i_ads_entries = ads_entries;
-#ifdef WITH_FUSE
inode->i_next_stream_id = inode->i_num_ads + 1;
-#endif
ret = 0;
goto out;
out_of_memory:
* buffers. On success, the dentry->length field must be examined. If zero,
* this was a special "end of directory" dentry and not a real dentry. If
* nonzero, this was a real dentry.
+ *
+ * Possible errors include:
+ * WIMLIB_ERR_NOMEM
+ * WIMLIB_ERR_INVALID_DENTRY
*/
int
read_dentry(const u8 * restrict metadata_resource, u64 metadata_resource_len,
u16 file_name_nbytes;
int ret;
struct wim_inode *inode;
- const struct wim_dentry_on_disk *disk_dentry;
const u8 *p = &metadata_resource[offset];
+ const struct wim_dentry_on_disk *disk_dentry =
+ (const struct wim_dentry_on_disk*)p;
if ((uintptr_t)p & 7)
WARNING("WIM dentry is not 8-byte aligned");
dentry_common_init(dentry);
- /*Make sure the dentry really fits into the metadata resource.*/
- if (offset + sizeof(u64) < offset ||
- offset + sizeof(u64) > metadata_resource_len)
+ /* Before reading the whole dentry, we need to read just the length.
+ * This is because a dentry of length 8 (that is, just the length field)
+ * terminates the list of sibling directory entries. */
+ if (offset + sizeof(u64) > metadata_resource_len ||
+ offset + sizeof(u64) < offset)
{
ERROR("Directory entry starting at %"PRIu64" ends past the "
"end of the metadata resource (size %"PRIu64")",
offset, metadata_resource_len);
return WIMLIB_ERR_INVALID_DENTRY;
}
-
- disk_dentry = (const struct wim_dentry_on_disk*)p;
-
- /* Before reading the whole dentry, we need to read just the length.
- * This is because a dentry of length 8 (that is, just the length field)
- * terminates the list of sibling directory entries. */
dentry->length = le64_to_cpu(disk_dentry->length);
/* A zero length field (really a length of 8, since that's how big the
* directory entry is...) indicates that this is the end of directory
* dentry. We do not read it into memory as an actual dentry, so just
- * return successfully in that case. */
+ * return successfully in this case. */
if (dentry->length == 8)
dentry->length = 0;
if (dentry->length == 0)
return 0;
/* Now that we have the actual length provided in the on-disk structure,
- * make sure it doesn't overflow the metadata buffer. */
- if (offset + dentry->length >= metadata_resource_len
- || offset + dentry->length < offset)
+ * again make sure it doesn't overflow the metadata resource buffer. */
+ 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 "
goto out_free_short_name;
}
}
-out_success:
/* We've read all the data for this dentry. Set the names and their
* lengths, and we've done. */
dentry->d_inode = inode;
return 0;
/* Find and read all the children of @dentry. */
- while (1) {
+ for (;;) {
/* Read next child of @dentry into @cur_child. */
ret = read_dentry(metadata_resource, metadata_resource_len,
cur_offset, &cur_child);
- if (ret != 0)
+ if (ret)
break;
/* Check for end of directory. */
/* Not end of directory. Allocate this child permanently and
* link it to the parent and previous child. */
- child = MALLOC(sizeof(struct wim_dentry));
+ child = memdup(&cur_child, sizeof(struct wim_dentry));
if (!child) {
- ERROR("Failed to allocate %zu bytes for new dentry",
- sizeof(struct wim_dentry));
+ ERROR("Failed to allocate new dentry!");
ret = WIMLIB_ERR_NOMEM;
break;
}
- memcpy(child, &cur_child, sizeof(struct wim_dentry));
- dentry_add_child(dentry, child);
- inode_add_dentry(child, child->d_inode);
-
- /* If there are children of this child, call this procedure
- * recursively. */
- if (child->subdir_offset != 0) {
- ret = read_dentry_tree(metadata_resource,
- metadata_resource_len, child);
- if (ret != 0)
- break;
- }
/* 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
+ * cur_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);
+
+ if (dentry_add_child(dentry, child)) {
+ WARNING("Ignoring duplicate dentry \"%"WS"\"",
+ child->file_name);
+ WARNING("(In directory \"%"TS"\")", dentry_full_path(dentry));
+ free_dentry(child);
+ } else {
+ inode_add_dentry(child, child->d_inode);
+ /* If there are children of this child, call this
+ * procedure recursively. */
+ if (child->subdir_offset != 0) {
+ if (dentry_is_directory(child)) {
+ ret = read_dentry_tree(metadata_resource,
+ metadata_resource_len,
+ child);
+ if (ret)
+ break;
+ } else {
+ WARNING("Ignoring children of non-directory \"%"TS"\"",
+ dentry_full_path(child));
+ }
+ }
+
+ }
}
return ret;
}
* @p: The memory location to write the data to.
*
* Returns the pointer to the byte after the last byte we wrote as part of the
- * dentry, including any alternate data streams entry.
+ * dentry, including any alternate data stream entries.
*/
static u8 *
write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p)
disk_dentry->creation_time = cpu_to_le64(inode->i_creation_time);
disk_dentry->last_access_time = cpu_to_le64(inode->i_last_access_time);
disk_dentry->last_write_time = cpu_to_le64(inode->i_last_write_time);
-
- if (inode->i_resolved)
- hash = inode->i_lte->hash;
- else
- hash = inode->i_hash;
- copy_hash(disk_dentry->unnamed_stream_hash, inode_stream_hash(inode, 0));
+ hash = inode_stream_hash(inode, 0);
+ copy_hash(disk_dentry->unnamed_stream_hash, hash);
if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
disk_dentry->reparse.rp_unknown_1 = cpu_to_le32(inode->i_rp_unknown_1);
disk_dentry->reparse.reparse_tag = cpu_to_le32(inode->i_reparse_tag);
/* 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...) */
+ * appended to the end of the dentry...). Furthermore, the dentry may
+ * have been renamed, thus changing its needed length. */
disk_dentry->length = cpu_to_le64(p - orig_p);
- /* Write the alternate data streams entries, if there are any. */
- for (u16 i = 0; i < inode->i_num_ads; i++)
- {
+ /* Write the alternate data streams entries, if any. */
+ for (u16 i = 0; i < inode->i_num_ads; i++) {
const struct wim_ads_entry *ads_entry =
- &inode->i_ads_entries[i];
+ &inode->i_ads_entries[i];
struct wim_ads_entry_on_disk *disk_ads_entry =
(struct wim_ads_entry_on_disk*)p;
+ orig_p = p;
disk_ads_entry->reserved = cpu_to_le64(ads_entry->reserved);
- orig_p = p;
hash = inode_stream_hash(inode, i + 1);
copy_hash(disk_ads_entry->hash, hash);