Add wimlib_iterate_lookup_table()
authorEric Biggers <ebiggers3@gmail.com>
Thu, 23 May 2013 16:03:50 +0000 (11:03 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Thu, 23 May 2013 16:03:50 +0000 (11:03 -0500)
NEWS
include/wimlib.h
include/wimlib/lookup_table.h
programs/imagex.c
src/dentry.c
src/lookup_table.c

diff --git a/NEWS b/NEWS
index 4b82820..88479a6 100644 (file)
--- 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.
index b2ac86c..783182f 100644 (file)
@@ -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,7 +2032,14 @@ 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,
@@ -1994,6 +2047,34 @@ wimlib_iterate_dir_tree(WIMStruct *wim, int image, const wimlib_tchar *path,
                        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.
  *
  * @param swms
@@ -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;
 
index 0977505..caa24de 100644 (file)
@@ -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 *),
index 34eefed..8f0f4b8 100644 (file)
@@ -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;
                        }
index bc1a524..d8c2fd0 100644 (file)
@@ -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)
index 199ea22..66ff69d 100644 (file)
@@ -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;
 }
-