From bb11c4650a416d1eaf6c8f8385c3c6e4d5e0eff3 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Thu, 23 May 2013 11:03:50 -0500 Subject: [PATCH] Add wimlib_iterate_lookup_table() --- NEWS | 4 +- include/wimlib.h | 139 ++++++++++++++++++++++++++++------ include/wimlib/lookup_table.h | 4 + programs/imagex.c | 95 +++++++++++++++-------- src/dentry.c | 14 ++-- src/lookup_table.c | 55 +++++++++++++- 6 files changed, 246 insertions(+), 65 deletions(-) diff --git a/NEWS b/NEWS index 4b82820b..88479a6f 100644 --- a/NEWS +++ b/NEWS @@ -40,7 +40,9 @@ Version 1.4.1: Progress callbacks have been added to wimlib's wimlib_update_image() function. - Added wimlib_get_wim_info() and wimlib_set_wim_info() functions. + Added wimlib_get_wim_info(), wimlib_set_wim_info(), + wimlib_iterate_dir_tree(), and wimlib_iterate_lookup_table() functions + to the library. NTFS-3g capture now only warns about two conditions previously treated as errors. diff --git a/include/wimlib.h b/include/wimlib.h index b2ac86cf..783182f7 100644 --- a/include/wimlib.h +++ b/include/wimlib.h @@ -718,28 +718,57 @@ struct wimlib_wim_info { uint32_t reserved[9]; }; -/** Iterate recursively on children rather than just on the specified path. */ -#define WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE 0x00000001 +/** Information about a unique resource in the WIM file. + */ +struct wimlib_resource_entry { + /** Uncompressed size of the resource in bytes. */ + uint64_t uncompressed_size; -/** Don't iterate on the file or directory itself; only its children (in the - * case of a non-empty directory) */ -#define WIMLIB_ITERATE_DIR_TREE_FLAG_CHILDREN 0x00000002 + /** Compressed size of the resource in bytes. This will be the same as + * @a uncompressed_size if the resource is uncompressed. */ + uint64_t compressed_size; + + /** Offset, in bytes, of this resource from the start of the WIM file. + */ + uint64_t offset; + + /** SHA1 message digest of the resource's uncompressed contents. */ + uint8_t sha1_hash[20]; + + /** Which part number of the split WIM this resource is in. This should + * be the same as the part number provided by wimlib_get_wim_info(). */ + uint32_t part_number; + + /** Number of times this resource is referenced over all WIM images. */ + uint32_t reference_count; + + /** 1 if this resource is compressed. */ + uint32_t is_compressed : 1; + + /** 1 if this resource is a metadata resource rather than a file + * resource. */ + uint32_t is_metadata : 1; + + uint32_t is_free : 1; + uint32_t is_spanned : 1; + uint32_t reserved_flags : 28; + uint64_t reserved[4]; +}; /** A stream of a file in the WIM. */ struct wimlib_stream_entry { /** Name of the stream, or NULL if the stream is unnamed. */ const wimlib_tchar *stream_name; - - /** Size of the stream (uncompressed) in bytes. */ - uint64_t stream_size; - - uint64_t reserved[10]; + /** Location, size, etc. of the stream within the WIM file. */ + struct wimlib_resource_entry resource; + uint64_t reserved[4]; }; -/** Roughly, the information about "file" in the WIM--- really a directory entry - * ("dentry") because hard links are allowed. The hard_link_group_id field - * can be used to distinguish actual file inodes. */ -struct wimlib_wim_dentry { +/** Structure passed to the wimlib_iterate_dir_tree() callback function. + * Roughly, the information about a "file" in the WIM--- but really a directory + * entry ("dentry") because hard links are allowed. The hard_link_group_id + * field can be used to distinguish actual file inodes. */ +struct wimlib_dir_entry { /** Name of the file, or NULL if this file is unnamed (only possible for * the root directory) */ const wimlib_tchar *filename; @@ -830,11 +859,28 @@ struct wimlib_wim_dentry { }; /** - * Type of a callback function to wimlib_iterate_dir_tree(). + * Type of a callback function to wimlib_iterate_dir_tree(). Must return 0 on + * success. */ -typedef int (*wimlib_iterate_dir_tree_callback_t)(const struct wimlib_wim_dentry *dentry, +typedef int (*wimlib_iterate_dir_tree_callback_t)(const struct wimlib_dir_entry *dentry, void *user_ctx); +/** + * Type of a callback function to wimlib_iterate_lookup_table(). Must return 0 + * on success. + */ +typedef int (*wimlib_iterate_lookup_table_callback_t)(const struct wimlib_resource_entry *resource, + void *user_ctx); + +/** For wimlib_iterate_dir_tree(): Iterate recursively on children rather than + * just on the specified path. */ +#define WIMLIB_ITERATE_DIR_TREE_FLAG_RECURSIVE 0x00000001 + +/** For wimlib_iterate_dir_tree(): Don't iterate on the file or directory + * itself; only its children (in the case of a non-empty directory) */ +#define WIMLIB_ITERATE_DIR_TREE_FLAG_CHILDREN 0x00000002 + + /***************************** * WIMLIB_ADD_FLAG_* @@ -1986,13 +2032,48 @@ wimlib_image_name_in_use(const WIMStruct *wim, const wimlib_tchar *name); * An extra parameter that will always be passed to the callback function * @a cb. * - * @return 0 on success; nonzero on failure. + * @return Normally, returns 0 if all calls to @a cb returned 0; otherwise the + * first nonzero value that was returned from @a cb. However, additional error + * codes may be returned, including the following: + * + * @retval ::WIMLIB_ERR_PATH_DOES_NOT_EXIST + * @a path did not exist in the WIM image. + * @retval ::WIMLIB_ERR_NOMEM + * Failed to allocate memory needed to create a ::wimlib_dir_entry. */ extern int wimlib_iterate_dir_tree(WIMStruct *wim, int image, const wimlib_tchar *path, int flags, wimlib_iterate_dir_tree_callback_t cb, void *user_ctx); +/** + * Iterate through the lookup table of a WIM file. This can be used to directly + * get a listing of the unique resources contained in a WIM file. Both file + * resources and metadata resources are included. + * + * @param wim + * Pointer to the ::WIMStruct of a standalone WIM file or a split WIM part. + * Note: metadata resources will only be included if the WIM is standalone + * or the first part of the split WIM. + * + * @param flags + * Reserved; set to 0. + * + * @param cb + * A callback function that will receive each resource. + * + * @param user_ctx + * An extra parameter that will always be passed to the callback function + * @a cb. + * + * @return 0 if all calls to @a cb returned 0; otherwise the first nonzero value + * that was returned from @a cb. + */ +extern int +wimlib_iterate_lookup_table(WIMStruct *wim, int flags, + wimlib_iterate_lookup_table_callback_t cb, + void *user_ctx); + /** * Joins a split WIM into a stand-alone one-part WIM. * @@ -2378,23 +2459,31 @@ wimlib_overwrite(WIMStruct *wim, int write_flags, unsigned num_threads, extern void wimlib_print_available_images(const WIMStruct *wim, int image); -/** TODO: wimlib-imagex uses this for the 'dir' command, but a better API is - * needed for this. */ +/** + * Deprecated in favor of wimlib_iterate_dir_tree(), which provides the + * information in a way that can be accessed programatically. + */ extern int wimlib_print_files(WIMStruct *wim, int image) _wimlib_deprecated; -/** TODO: wimlib-imagex uses this for the 'info --header' command, but a better - * API is needed for this. */ +/** + * Deprecated in favor of wimlib_get_wim_info(), which provides the information + * in a way that can be accessed programatically. + */ extern void wimlib_print_header(const WIMStruct *wim) _wimlib_deprecated; -/** TODO: wimlib-imagex uses this for the 'info --lookup-table' command, but a - * better API is needed for this. */ +/** + * Deprecated in favor of wimlib_iterate_lookup_table(), which provides the + * information in a way that can be accessed programatically. + */ extern void wimlib_print_lookup_table(WIMStruct *wim) _wimlib_deprecated; -/** TODO: wimlib-imagex uses this for the 'info --metadata' command, but a - * better API is needed for this. */ +/** + * Deprecated in favor of wimlib_iterate_dir_tree(), which provides the + * information in a way that can be accessed programatically. + */ extern int wimlib_print_metadata(WIMStruct *wim, int image) _wimlib_deprecated; diff --git a/include/wimlib/lookup_table.h b/include/wimlib/lookup_table.h index 09775058..caa24de8 100644 --- a/include/wimlib/lookup_table.h +++ b/include/wimlib/lookup_table.h @@ -341,6 +341,10 @@ print_lookup_table_entry(const struct wim_lookup_table_entry *entry, extern void free_lookup_table_entry(struct wim_lookup_table_entry *lte); +extern void +lte_to_wimlib_resource_entry(const struct wim_lookup_table_entry *lte, + struct wimlib_resource_entry *wentry); + extern int for_lookup_table_entry(struct wim_lookup_table *table, int (*visitor)(struct wim_lookup_table_entry *, void *), diff --git a/programs/imagex.c b/programs/imagex.c index 34eefedf..8f0f4b87 100644 --- a/programs/imagex.c +++ b/programs/imagex.c @@ -1975,7 +1975,7 @@ out: } static int -print_full_path(const struct wimlib_wim_dentry *wdentry, void *_ignore) +print_full_path(const struct wimlib_dir_entry *wdentry, void *_ignore) { int ret = tprintf(T("%"TS"\n"), wdentry->full_path); return (ret >= 0) ? 0 : -1; @@ -2406,29 +2406,67 @@ static void print_byte_field(const uint8_t field[], size_t len) } static void -print_wim_information(const tchar *wimfile, WIMStruct *wim) +print_wim_information(const tchar *wimfile, const struct wimlib_wim_info *info) { - struct wimlib_wim_info info; - - wimlib_get_wim_info((WIMStruct*)wim, &info); - tputs(T("WIM Information:")); tputs(T("----------------")); tprintf(T("Path: %"TS"\n"), wimfile); - tfputs(T("GUID: 0x"), stdout); - print_byte_field(info.guid, WIMLIB_GUID_LEN); + tprintf(T("GUID: 0x")); + print_byte_field(info->guid, sizeof(info->guid)); tputchar(T('\n')); - tprintf(T("Image Count: %d\n"), info.image_count); + tprintf(T("Image Count: %d\n"), info->image_count); tprintf(T("Compression: %"TS"\n"), - wimlib_get_compression_type_string(info.compression_type)); - tprintf(T("Part Number: %d/%d\n"), info.part_number, info.total_parts); - tprintf(T("Boot Index: %d\n"), info.boot_index); - tprintf(T("Size: %"PRIu64" bytes\n"), info.total_bytes); + wimlib_get_compression_type_string(info->compression_type)); + tprintf(T("Part Number: %d/%d\n"), info->part_number, info->total_parts); + tprintf(T("Boot Index: %d\n"), info->boot_index); + tprintf(T("Size: %"PRIu64" bytes\n"), info->total_bytes); tprintf(T("Integrity Info: %"TS"\n"), - info.has_integrity_table ? T("yes") : T("no")); + info->has_integrity_table ? T("yes") : T("no")); tprintf(T("Relative path junction: %"TS"\n"), - info.has_rpfix ? T("yes") : T("no")); + info->has_rpfix ? T("yes") : T("no")); + tputchar(T('\n')); +} + +static int +print_resource(const struct wimlib_resource_entry *resource, + void *_ignore) +{ + + tprintf(T("Uncompressed size = %"PRIu64" bytes\n"), + resource->uncompressed_size); + + tprintf(T("Compressed size = %"PRIu64" bytes\n"), + resource->compressed_size); + + tprintf(T("Offset = %"PRIu64" bytes\n"), + resource->offset); + + + tprintf(T("Part Number = %u\n"), resource->part_number); + tprintf(T("Reference Count = %u\n"), resource->reference_count); + + tprintf(T("Hash = 0x")); + print_byte_field(resource->sha1_hash, sizeof(resource->sha1_hash)); + tputchar(T('\n')); + + tprintf(T("Flags = ")); + if (resource->is_compressed) + tprintf(T("WIM_RESHDR_FLAG_COMPRESSED ")); + if (resource->is_metadata) + tprintf(T("WIM_RESHDR_FLAG_METADATA ")); + if (resource->is_free) + tprintf(T("WIM_RESHDR_FLAG_FREE ")); + if (resource->is_spanned) + tprintf(T("WIM_RESHDR_FLAG_SPANNED ")); + tputchar(T('\n')); tputchar(T('\n')); + return 0; +} + +static void +print_lookup_table(WIMStruct *wim) +{ + wimlib_iterate_lookup_table(wim, 0, print_resource, NULL); } /* Prints information about a WIM file; also can mark an image as bootable, @@ -2454,9 +2492,7 @@ imagex_info(int argc, tchar **argv) int image; int ret; int open_flags = WIMLIB_OPEN_FLAG_SPLIT_OK; - int part_number; - int total_parts; - int num_images; + struct wimlib_wim_info info; for_opt(c, info_options) { switch (c) { @@ -2517,7 +2553,7 @@ imagex_info(int argc, tchar **argv) if (ret != 0) return ret; - part_number = wimlib_get_part_number(w, &total_parts); + wimlib_get_wim_info(w, &info); image = wimlib_resolve_image(w, image_num_or_name); if (image == WIMLIB_NO_IMAGE && tstrcmp(image_num_or_name, T("0"))) { @@ -2532,9 +2568,7 @@ imagex_info(int argc, tchar **argv) goto out; } - num_images = wimlib_get_num_images(w); - - if (num_images == 0) { + if (info.image_count == 0) { if (boot) { imagex_error(T("--boot is meaningless on a WIM with no " "images")); @@ -2543,7 +2577,7 @@ imagex_info(int argc, tchar **argv) } } - if (image == WIMLIB_ALL_IMAGES && num_images > 1) { + if (image == WIMLIB_ALL_IMAGES && info.image_count > 1) { if (boot) { imagex_error(T("Cannot specify the --boot flag " "without specifying a specific " @@ -2574,18 +2608,18 @@ imagex_info(int argc, tchar **argv) } if (image == WIMLIB_ALL_IMAGES && short_header) - print_wim_information(wimfile, w); + print_wim_information(wimfile, &info); if (header) wimlib_print_header(w); if (lookup_table) { - if (total_parts != 1) { - tprintf(T("Warning: Only showing the lookup table " - "for part %d of a %d-part WIM.\n"), - part_number, total_parts); + if (info.total_parts != 1) { + tfprintf(stderr, T("Warning: Only showing the lookup table " + "for part %d of a %d-part WIM.\n"), + info.part_number, info.total_parts); } - wimlib_print_lookup_table(w); + print_lookup_table(w); } if (xml) { @@ -2646,7 +2680,8 @@ imagex_info(int argc, tchar **argv) } else { tprintf(T("Marking image %d as bootable.\n"), image); - ret = wimlib_set_boot_idx(w, image); + info.boot_index = image; + ret = wimlib_set_wim_info(w, &info, WIMLIB_CHANGE_BOOT_INDEX); if (ret) goto out; } diff --git a/src/dentry.c b/src/dentry.c index bc1a524f..d8c2fd0a 100644 --- a/src/dentry.c +++ b/src/dentry.c @@ -2259,7 +2259,7 @@ write_dentry_tree(const struct wim_dentry * restrict root, u8 * restrict p) static int -init_wimlib_dentry(struct wimlib_wim_dentry *wdentry, +init_wimlib_dentry(struct wimlib_dir_entry *wdentry, struct wim_dentry *dentry, const WIMStruct *wim) { @@ -2312,7 +2312,7 @@ init_wimlib_dentry(struct wimlib_wim_dentry *wdentry, lte = inode_unnamed_lte(inode, wim->lookup_table); if (lte) - wdentry->streams[0].stream_size = wim_resource_size(lte); + lte_to_wimlib_resource_entry(lte, &wdentry->streams[0].resource); for (unsigned i = 0; i < inode->i_num_ads; i++) { if (inode->i_ads_entries[i].stream_name == NULL) @@ -2320,8 +2320,8 @@ init_wimlib_dentry(struct wimlib_wim_dentry *wdentry, lte = inode_stream_lte(inode, i + 1, wim->lookup_table); wdentry->num_named_streams++; if (lte) { - wdentry->streams[wdentry->num_named_streams].stream_size = - wim_resource_size(lte); + lte_to_wimlib_resource_entry(lte, &wdentry->streams[ + wdentry->num_named_streams].resource); } #if TCHAR_IS_UTF16LE wdentry->streams[wdentry->num_named_streams].stream_name = @@ -2342,7 +2342,7 @@ init_wimlib_dentry(struct wimlib_wim_dentry *wdentry, } static void -free_wimlib_dentry(struct wimlib_wim_dentry *wdentry) +free_wimlib_dentry(struct wimlib_dir_entry *wdentry) { #if !TCHAR_IS_UTF16LE FREE((tchar*)wdentry->filename); @@ -2381,11 +2381,11 @@ do_iterate_dir_tree(WIMStruct *wim, void *user_ctx) { u32 level; - struct wimlib_wim_dentry *wdentry; + struct wimlib_dir_entry *wdentry; int ret = WIMLIB_ERR_NOMEM; - wdentry = CALLOC(1, sizeof(struct wimlib_wim_dentry) + + wdentry = CALLOC(1, sizeof(struct wimlib_dir_entry) + (1 + dentry->d_inode->i_num_ads) * sizeof(struct wimlib_stream_entry)); if (!wdentry) diff --git a/src/lookup_table.c b/src/lookup_table.c index 199ea221..66ff69dd 100644 --- a/src/lookup_table.c +++ b/src/lookup_table.c @@ -767,6 +767,58 @@ print_lookup_table_entry(const struct wim_lookup_table_entry *lte, FILE *out) tputc(T('\n'), out); } +void +lte_to_wimlib_resource_entry(const struct wim_lookup_table_entry *lte, + struct wimlib_resource_entry *wentry) +{ + wentry->uncompressed_size = lte->resource_entry.original_size; + wentry->compressed_size = lte->resource_entry.size; + wentry->offset = lte->resource_entry.offset; + copy_hash(wentry->sha1_hash, lte->hash); + wentry->part_number = lte->part_number; + wentry->reference_count = lte->refcnt; + wentry->is_compressed = (lte->resource_entry.flags & WIM_RESHDR_FLAG_COMPRESSED) != 0; + wentry->is_metadata = (lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA) != 0; + wentry->is_free = (lte->resource_entry.flags & WIM_RESHDR_FLAG_FREE) != 0; + wentry->is_spanned = (lte->resource_entry.flags & WIM_RESHDR_FLAG_SPANNED) != 0; +} + +struct iterate_lte_context { + wimlib_iterate_lookup_table_callback_t cb; + void *user_ctx; +}; + +static int +do_iterate_lte(struct wim_lookup_table_entry *lte, void *_ctx) +{ + struct iterate_lte_context *ctx = _ctx; + struct wimlib_resource_entry entry; + + lte_to_wimlib_resource_entry(lte, &entry); + return (*ctx->cb)(&entry, ctx->user_ctx); +} + +WIMLIBAPI int +wimlib_iterate_lookup_table(WIMStruct *wim, int flags, + wimlib_iterate_lookup_table_callback_t cb, + void *user_ctx) +{ + struct iterate_lte_context ctx = { + .cb = cb, + .user_ctx = user_ctx, + }; + if (wim->hdr.part_number == 1) { + int ret; + for (int i = 0; i < wim->hdr.image_count; i++) { + ret = do_iterate_lte(wim->image_metadata[i]->metadata_lte, + &ctx); + if (ret) + return ret; + } + } + return for_lookup_table_entry(wim->lookup_table, do_iterate_lte, &ctx); +} + static int do_print_lookup_table_entry(struct wim_lookup_table_entry *lte, void *fp) { @@ -775,7 +827,7 @@ do_print_lookup_table_entry(struct wim_lookup_table_entry *lte, void *fp) } /* - * Prints the lookup table of a WIM file. + * Deprecated */ WIMLIBAPI void wimlib_print_lookup_table(WIMStruct *wim) @@ -1117,4 +1169,3 @@ hash_unhashed_stream(struct wim_lookup_table_entry *lte, *lte_ret = lte; return 0; } - -- 2.43.0