From 26ba6eaef7f310b682513696930013225f658044 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Wed, 22 May 2013 01:28:05 -0500 Subject: [PATCH] Check for missing streams when resolving them --- include/wimlib.h | 9 +++++++ include/wimlib/lookup_table.h | 2 +- src/extract.c | 21 +++++++++++----- src/lookup_table.c | 45 ++++++++++++++++++++++++++++------- src/mount_image.c | 5 +++- src/util.c | 2 ++ 6 files changed, 68 insertions(+), 16 deletions(-) diff --git a/include/wimlib.h b/include/wimlib.h index a5a73e38..09059eb5 100644 --- a/include/wimlib.h +++ b/include/wimlib.h @@ -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, diff --git a/include/wimlib/lookup_table.h b/include/wimlib/lookup_table.h index d6bd5ee3..aad400de 100644 --- a/include/wimlib/lookup_table.h +++ b/include/wimlib/lookup_table.h @@ -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 diff --git a/src/extract.c b/src/extract.c index cfeb4898..f9c4ee98 100644 --- a/src/extract.c +++ b/src/extract.c @@ -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, diff --git a/src/lookup_table.c b/src/lookup_table.c index b79381f0..47e60388 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -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 diff --git a/src/mount_image.c b/src/mount_image.c index fbcc1ea7..08836382 100644 --- a/src/mount_image.c +++ b/src/mount_image.c @@ -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: diff --git a/src/util.c b/src/util.c index f5a8ca29..08bcb39b 100644 --- a/src/util.c +++ b/src/util.c @@ -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] -- 2.43.0