* @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. */
if (child->subdir_offset != 0) {
ret = read_dentry_tree(metadata_resource,
metadata_resource_len, child);
- if (ret != 0)
+ if (ret)
break;
}
* @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);
* Returns: Zero on success, nonzero on failure.
*/
int
-read_metadata_resource(WIMStruct *w, struct wim_image_metadata *imd)
+read_metadata_resource(WIMStruct *wim, struct wim_image_metadata *imd)
{
u8 *buf;
- u32 dentry_offset;
int ret;
- struct wim_dentry *dentry;
+ struct wim_dentry *root;
const struct wim_lookup_table_entry *metadata_lte;
u64 metadata_len;
+ struct wim_security_data *security_data;
metadata_lte = imd->metadata_lte;
metadata_len = wim_resource_size(metadata_lte);
/* There is no way the metadata resource could possibly be less than (8
* + WIM_DENTRY_DISK_SIZE) bytes, where the 8 is for security data (with
* no security descriptors) and WIM_DENTRY_DISK_SIZE is for the root
- * dentry. */
+ * entry. */
if (metadata_len < 8 + WIM_DENTRY_DISK_SIZE) {
ERROR("Expected at least %u bytes for the metadata resource",
8 + WIM_DENTRY_DISK_SIZE);
* the offset of the root dentry.
*
* Here we read the security data into a wim_security_data structure,
- * and if successful, go ahead and calculate the offset in the metadata
- * resource of the root dentry. */
+ * which takes case of rouding total_length. If successful, go ahead
+ * and calculate the offset in the metadata resource of the root dentry.
+ * */
- wimlib_assert(imd->security_data == NULL);
- ret = read_wim_security_data(buf, metadata_len, &imd->security_data);
+ ret = read_wim_security_data(buf, metadata_len, &security_data);
if (ret)
goto out_free_buf;
- dentry_offset = (imd->security_data->total_length + 7) & ~7;
-
- if (dentry_offset == 0) {
- ERROR("Integer overflow while reading metadata resource");
- ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
- goto out_free_security_data;
- }
-
DEBUG("Reading root dentry");
/* Allocate memory for the root dentry and read it into memory */
- dentry = MALLOC(sizeof(struct wim_dentry));
- if (!dentry) {
- ERROR("Failed to allocate %zu bytes for root dentry",
- sizeof(struct wim_dentry));
+ root = MALLOC(sizeof(struct wim_dentry));
+ if (!root) {
ret = WIMLIB_ERR_NOMEM;
goto out_free_security_data;
}
- ret = read_dentry(buf, metadata_len, dentry_offset, dentry);
-
- /* This is the root dentry, so set its parent to itself. */
- dentry->parent = dentry;
+ ret = read_dentry(buf, metadata_len,
+ security_data->total_length, root);
- if (ret == 0 && dentry->length == 0) {
+ if (ret == 0 && root->length == 0) {
ERROR("Metadata resource cannot begin with end-of-directory entry!");
ret = WIMLIB_ERR_INVALID_DENTRY;
}
- if (ret != 0) {
- FREE(dentry);
+ if (ret) {
+ FREE(root);
goto out_free_security_data;
}
- inode_add_dentry(dentry, dentry->d_inode);
+ /* This is the root dentry, so set its parent to itself. */
+ root->parent = root;
+
+ inode_add_dentry(root, root->d_inode);
/* Now read the entire directory entry tree into memory. */
DEBUG("Reading dentry tree");
- ret = read_dentry_tree(buf, metadata_len, dentry);
+ ret = read_dentry_tree(buf, metadata_len, root);
if (ret)
goto out_free_dentry_tree;
/* Build hash table that maps hard link group IDs to dentry sets */
- ret = dentry_tree_fix_inodes(dentry, &imd->inode_list);
+ ret = dentry_tree_fix_inodes(root, &imd->inode_list);
if (ret)
goto out_free_dentry_tree;
- if (!w->all_images_verified) {
+ if (!wim->all_images_verified) {
DEBUG("Running miscellaneous verifications on the dentry tree");
- for_lookup_table_entry(w->lookup_table, lte_zero_real_refcnt, NULL);
- ret = for_dentry_in_tree(dentry, verify_dentry, w);
+ for_lookup_table_entry(wim->lookup_table, lte_zero_real_refcnt, NULL);
+ ret = for_dentry_in_tree(root, verify_dentry, wim);
if (ret)
goto out_free_dentry_tree;
}
DEBUG("Done reading image metadata");
- imd->root_dentry = dentry;
+ imd->root_dentry = root;
+ imd->security_data = security_data;
INIT_LIST_HEAD(&imd->unhashed_streams);
goto out_free_buf;
out_free_dentry_tree:
- free_dentry_tree(dentry, NULL);
+ free_dentry_tree(root, wim->lookup_table);
out_free_security_data:
- free_wim_security_data(imd->security_data);
- imd->security_data = NULL;
+ free_wim_security_data(security_data);
out_free_buf:
FREE(buf);
return ret;
"%u bytes, but calculated %u bytes",
sd->total_length, (unsigned)total_len);
}
-out_return_sd:
*sd_ret = sd;
ret = 0;
goto out;
u8 *orig_p = p;
struct wim_security_data_disk *sd_disk = (struct wim_security_data_disk*)p;
+ u32 num_entries = sd->num_entries;
sd_disk->total_length = cpu_to_le32(sd->total_length);
- sd_disk->num_entries = cpu_to_le32(sd->num_entries);
+ sd_disk->num_entries = cpu_to_le32(num_entries);
- for (u32 i = 0; i < sd->num_entries; i++)
+ for (u32 i = 0; i < num_entries; i++)
sd_disk->sizes[i] = cpu_to_le64(sd->sizes[i]);
- p = (u8*)&sd_disk->sizes[sd_disk->num_entries];
+ p = (u8*)&sd_disk->sizes[num_entries];
- for (u32 i = 0; i < sd->num_entries; i++)
+ for (u32 i = 0; i < num_entries; i++)
p = mempcpy(p, sd->descriptors[i], sd->sizes[i]);
- while (p - orig_p < sd->total_length)
+ while ((uintptr_t)p & 7)
*p++ = 0;
wimlib_assert(p - orig_p == sd->total_length);
- wimlib_assert(((uintptr_t)p & 7) == 0);
DEBUG("Successfully wrote security data.");
return p;
struct sd_node *new;
u8 **descriptors;
u64 *sizes;
- char *descr_copy;
+ u8 *descr_copy;
struct wim_security_data *sd;
bool bret;
const struct wim_security_data *sd = wim_const_security_data(w);
struct wim_dentry *first_dentry = inode_first_dentry(inode);
struct wim_dentry *dentry;
- int ret = WIMLIB_ERR_INVALID_DENTRY;
/* Check the security ID. -1 is valid and means "no security
* descriptor". Anything else has to be a valid index into the WIM
if (inode->i_security_id < -1) {
ERROR("Dentry `%"TS"' has an invalid security ID (%d)",
dentry_full_path(first_dentry), inode->i_security_id);
- goto out;
+ return WIMLIB_ERR_INVALID_DENTRY;
}
if (inode->i_security_id >= 0 &&
"(there are only %u entries in the security table)",
dentry_full_path(first_dentry), inode->i_security_id,
sd->num_entries);
- goto out;
+ return WIMLIB_ERR_INVALID_DENTRY;
}
/* Check that lookup table entries for all the inode's stream exist,
ERROR("Could not find lookup table entry for stream "
"%u of dentry `%"TS"'",
i, dentry_full_path(first_dentry));
- goto out;
+ return WIMLIB_ERR_INVALID_DENTRY;
}
if (lte)
lte->real_refcnt += inode->i_nlink;
if (num_unnamed_streams > 1) {
ERROR("Dentry `%"TS"' has multiple (%u) un-named streams",
dentry_full_path(first_dentry), num_unnamed_streams);
- goto out;
+ return WIMLIB_ERR_INVALID_DENTRY;
}
/* Files cannot have multiple DOS names, even if they have multiple
"both `%"TS"' and `%"TS"'",
dentry_full_path(dentry_with_dos_name),
dentry_full_path(dentry));
- goto out;
+ return WIMLIB_ERR_INVALID_DENTRY;
}
dentry_with_dos_name = dentry;
}
if (inode->i_nlink > 1 && inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY) {
ERROR("Hard-linked directory `%"TS"' is unsupported",
dentry_full_path(first_dentry));
- goto out;
+ return WIMLIB_ERR_INVALID_DENTRY;
}
inode->i_verified = 1;
- ret = 0;
-out:
- return ret;
+ return 0;
}
/* Run some miscellaneous verifications on a WIM dentry */
* in which case we need to force the inode to be verified again.) */
if (!dentry->d_inode->i_verified) {
ret = verify_inode(dentry->d_inode, w);
- if (ret != 0)
+ if (ret)
return ret;
}