Check for missing streams when resolving them
authorEric Biggers <ebiggers3@gmail.com>
Wed, 22 May 2013 06:28:05 +0000 (01:28 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Wed, 22 May 2013 06:28:05 +0000 (01:28 -0500)
include/wimlib.h
include/wimlib/lookup_table.h
src/extract.c
src/lookup_table.c
src/mount_image.c
src/util.c

index a5a73e3..09059eb 100644 (file)
@@ -1035,6 +1035,7 @@ enum wimlib_error_code {
        WIMLIB_ERR_WRITE,
        WIMLIB_ERR_XML,
        WIMLIB_ERR_WIM_IS_READONLY,
+       WIMLIB_ERR_RESOURCE_NOT_FOUND,
 };
 
 
@@ -1518,6 +1519,10 @@ wimlib_extract_files(WIMStruct *wim,
  * @retval ::WIMLIB_ERR_READ
  *     A unexpected end-of-file or read error occurred when trying to read data
  *     from the WIM file associated with @a wim.
+ * @retval ::WIMLIB_ERR_RESOURCE_NOT_FOUND
+ *     One of the dentries in the image referenced a stream not present in the
+ *     WIM's lookup table (or in any of the lookup tables of the split WIM
+ *     parts).
  * @retval ::WIMLIB_ERR_SPLIT_INVALID
  *     The WIM is a split WIM, but the parts specified do not form a complete
  *     split WIM because they do not include all the parts of the original WIM,
@@ -1937,6 +1942,10 @@ wimlib_lzx_decompress(const void *compressed_data, unsigned compressed_len,
  * @retval ::WIMLIB_ERR_READ
  *     An unexpected end-of-file or read error occurred when trying to read
  *     data from the WIM file associated with @a wim.
+ * @retval ::WIMLIB_ERR_RESOURCE_NOT_FOUND
+ *     One of the dentries in the image referenced a stream not present in the
+ *     WIM's lookup table (or in any of the lookup tables of the split WIM
+ *     parts).
  * @retval ::WIMLIB_ERR_SPLIT_INVALID
  *     The WIM is a split WIM, but the parts specified do not form a complete
  *     split WIM because they do not include all the parts of the original WIM,
index d6bd5ee..aad400d 100644 (file)
@@ -370,7 +370,7 @@ lte_zero_real_refcnt(struct wim_lookup_table_entry *entry, void *ignore);
 extern int
 lte_free_extracted_file(struct wim_lookup_table_entry *lte, void *ignore);
 
-extern void
+extern int
 inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table);
 
 extern void
index cfeb489..f9c4ee9 100644 (file)
@@ -294,8 +294,11 @@ dentry_resolve_and_zero_lte_refcnt(struct wim_dentry *dentry, void *_lookup_tabl
        struct wim_inode *inode = dentry->d_inode;
        struct wim_lookup_table *lookup_table = _lookup_table;
        struct wim_lookup_table_entry *lte;
+       int ret;
 
-       inode_resolve_ltes(inode, lookup_table);
+       ret = inode_resolve_ltes(inode, lookup_table);
+       if (ret)
+               return ret;
        for (unsigned i = 0; i <= inode->i_num_ads; i++) {
                lte = inode_stream_lte_resolved(inode, i);
                if (lte)
@@ -304,19 +307,23 @@ dentry_resolve_and_zero_lte_refcnt(struct wim_dentry *dentry, void *_lookup_tabl
        return 0;
 }
 
-static void
+static int
 find_streams_for_extraction(struct wim_dentry *root,
                            struct list_head *stream_list,
                            struct wim_lookup_table *lookup_table,
                            int extract_flags)
 {
        struct find_streams_ctx ctx;
+       int ret;
 
        INIT_LIST_HEAD(&ctx.stream_list);
        ctx.extract_flags = extract_flags;
-       for_dentry_in_tree(root, dentry_resolve_and_zero_lte_refcnt, lookup_table);
+       ret = for_dentry_in_tree(root, dentry_resolve_and_zero_lte_refcnt, lookup_table);
+       if (ret)
+               return ret;
        for_dentry_in_tree(root, dentry_find_streams_to_extract, &ctx);
        list_transfer(&ctx.stream_list, stream_list);
+       return 0;
 }
 
 struct apply_operations {
@@ -764,9 +771,11 @@ extract_tree(WIMStruct *wim, const tchar *wim_source_path, const tchar *target,
                goto out_dentry_reset_needs_extraction;
 
        /* Build a list of the streams that need to be extracted */
-       find_streams_for_extraction(root,
-                                   &stream_list,
-                                   wim->lookup_table, extract_flags);
+       ret = find_streams_for_extraction(root,
+                                         &stream_list,
+                                         wim->lookup_table, extract_flags);
+       if (ret)
+               goto out_dentry_reset_needs_extraction;
 
        /* Calculate the number of bytes of data that will be extracted */
        calculate_bytes_to_extract(&stream_list, extract_flags,
index b79381f..47e6038 100644 (file)
@@ -892,24 +892,53 @@ wim_resource_compression_type(const struct wim_lookup_table_entry *lte)
  * This function always succeeds; unresolved lookup table entries are given a
  * NULL pointer.
  */
-void
+int
 inode_resolve_ltes(struct wim_inode *inode, struct wim_lookup_table *table)
 {
+       int ret;
+       const u8 *hash;
 
        if (!inode->i_resolved) {
-               struct wim_lookup_table_entry *lte;
+               struct wim_lookup_table_entry *lte, *ads_lte;
+
                /* Resolve the default file stream */
-               lte = __lookup_resource(table, inode->i_hash);
-               inode->i_lte = lte;
-               inode->i_resolved = 1;
+               lte = NULL;
+               hash = inode->i_hash;
+               if (!is_zero_hash(hash)) {
+                       lte = __lookup_resource(table, hash);
+                       if (unlikely(!lte))
+                               goto resource_not_found;
+               }
 
                /* Resolve the alternate data streams */
+               struct wim_lookup_table_entry *ads_ltes[inode->i_num_ads];
                for (u16 i = 0; i < inode->i_num_ads; i++) {
-                       struct wim_ads_entry *cur_entry = &inode->i_ads_entries[i];
-                       lte = __lookup_resource(table, cur_entry->hash);
-                       cur_entry->lte = lte;
+                       struct wim_ads_entry *cur_entry;
+
+                       ads_lte = NULL;
+                       cur_entry = &inode->i_ads_entries[i];
+                       hash = cur_entry->hash;
+                       if (!is_zero_hash(hash)) {
+                               ads_lte = __lookup_resource(table, hash);
+                               if (unlikely(!ads_lte))
+                                       goto resource_not_found;
+                       }
+                       ads_ltes[i] = ads_lte;
                }
+               inode->i_lte = lte;
+               for (u16 i = 0; i < inode->i_num_ads; i++)
+                       inode->i_ads_entries[i].lte = ads_ltes[i];
+               inode->i_resolved = 1;
+       }
+       return 0;
+resource_not_found:
+       if (wimlib_print_errors) {
+               ERROR("\"%"TS"\": resource not found", inode_first_full_path(inode));
+               tfprintf(stderr, T("        SHA-1 message digest of missing resource:\n        "));
+               print_hash(hash, stderr);
+               tputc(T('\n'), stderr);
        }
+       return WIMLIB_ERR_RESOURCE_NOT_FOUND;
 }
 
 void
index fbcc1ea..0883638 100644 (file)
@@ -2534,7 +2534,9 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
        DEBUG("Resolving lookup table entries and assigning inode numbers");
        ctx.next_ino = 1;
        image_for_each_inode(inode, imd) {
-               inode_resolve_ltes(inode, wim->lookup_table);
+               ret = inode_resolve_ltes(inode, wim->lookup_table);
+               if (ret)
+                       goto out_delete_staging_dir;
                inode->i_ino = ctx.next_ino++;
        }
        DEBUG("(next_ino = %"PRIu64")", ctx.next_ino);
@@ -2560,6 +2562,7 @@ wimlib_mount_image(WIMStruct *wim, int image, const char *dir,
 
        /* Try to delete the staging directory if a deletion wasn't yet
         * attempted due to an earlier error */
+out_delete_staging_dir:
        if (ctx.staging_dir_name)
                delete_staging_dir(&ctx);
 out_free_dir_copy:
index f5a8ca2..08bcb39 100644 (file)
@@ -369,6 +369,8 @@ static const tchar *error_strings[] = {
                = T("Could not rename a file"),
        [WIMLIB_ERR_REPARSE_POINT_FIXUP_FAILED]
                = T("Unable to complete reparse point fixup"),
+       [WIMLIB_ERR_RESOURCE_NOT_FOUND]
+               = T("A file resource needed to complete the operation was missing from the WIM"),
        [WIMLIB_ERR_RESOURCE_ORDER]
                = T("The components of the WIM were arranged in an unexpected order"),
        [WIMLIB_ERR_SPECIAL_FILE]