dentry.c, security.c: Cleanups, fixes
authorEric Biggers <ebiggers3@gmail.com>
Fri, 17 May 2013 15:17:28 +0000 (10:17 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Fri, 17 May 2013 15:17:28 +0000 (10:17 -0500)
src/dentry.c
src/metadata_resource.c
src/security.c
src/verify.c

index 9411f85..5082eac 100644 (file)
@@ -1368,11 +1368,11 @@ replace_forbidden_characters(utf16lechar *name)
  * @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
@@ -1387,11 +1387,14 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
        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;
@@ -1410,7 +1413,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
                length = le64_to_cpu(disk_entry->length);
 
                /* Make sure the length field is neither so small it doesn't
-                * include all the fixed-length dataor 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)
@@ -1419,9 +1422,8 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
                /* 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
@@ -1430,8 +1432,6 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
                 * 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... */
@@ -1452,7 +1452,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
                        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);
                }
 
@@ -1472,9 +1472,7 @@ read_ads_entries(const u8 * restrict p, struct wim_inode * restrict inode,
                        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:
@@ -1512,6 +1510,10 @@ out:
  * 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,
@@ -1525,44 +1527,41 @@ 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 "
@@ -1706,7 +1705,6 @@ read_dentry(const u8 * restrict metadata_resource, u64 metadata_resource_len,
                        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;
@@ -1761,12 +1759,12 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
                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. */
@@ -1791,7 +1789,7 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
                if (child->subdir_offset != 0) {
                        ret = read_dentry_tree(metadata_resource,
                                               metadata_resource_len, child);
-                       if (ret != 0)
+                       if (ret)
                                break;
                }
 
@@ -1812,7 +1810,7 @@ read_dentry_tree(const u8 metadata_resource[], u64 metadata_resource_len,
  * @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)
@@ -1836,12 +1834,8 @@ 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);
@@ -1870,19 +1864,19 @@ write_dentry(const struct wim_dentry * restrict dentry, u8 * restrict p)
        /* 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);
index da0be28..5b22ab6 100644 (file)
  * 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);
@@ -73,7 +73,7 @@ read_metadata_resource(WIMStruct *w, struct wim_image_metadata *imd)
        /* 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);
@@ -110,79 +110,70 @@ read_metadata_resource(WIMStruct *w, struct wim_image_metadata *imd)
         * 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;
index dc3c409..4cd898b 100644 (file)
@@ -287,7 +287,6 @@ out_align_total_length:
                        "%u bytes, but calculated %u bytes",
                        sd->total_length, (unsigned)total_len);
        }
-out_return_sd:
        *sd_ret = sd;
        ret = 0;
        goto out;
@@ -316,23 +315,23 @@ write_wim_security_data(const struct wim_security_data * restrict sd,
 
        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;
@@ -554,7 +553,7 @@ sd_set_add_sd(struct wim_sd_set *sd_set, const char *descriptor, size_t size)
        struct sd_node *new;
        u8 **descriptors;
        u64 *sizes;
-       char *descr_copy;
+       u8 *descr_copy;
        struct wim_security_data *sd;
        bool bret;
 
index 89da4b8..56e77ef 100644 (file)
@@ -41,7 +41,6 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w)
        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
@@ -49,7 +48,7 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w)
        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 &&
@@ -59,7 +58,7 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w)
                      "(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,
@@ -77,7 +76,7 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w)
                                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;
@@ -95,7 +94,7 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w)
        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
@@ -109,7 +108,7 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w)
                                      "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;
                }
@@ -119,13 +118,11 @@ verify_inode(struct wim_inode *inode, const WIMStruct *w)
        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 */
@@ -140,7 +137,7 @@ verify_dentry(struct wim_dentry *dentry, void *wim)
         * 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;
        }