Add wimlib_verify_wim()
authorEric Biggers <ebiggers3@gmail.com>
Mon, 28 Jul 2014 02:38:16 +0000 (21:38 -0500)
committerEric Biggers <ebiggers3@gmail.com>
Mon, 28 Jul 2014 03:12:58 +0000 (22:12 -0500)
include/wimlib.h
src/verify.c

index 76c7923..db8d5d5 100644 (file)
@@ -626,6 +626,19 @@ enum wimlib_progress_msg {
         * ::wimlib_progress_info.done_with_file.  This message is only received
         * if ::WIMLIB_WRITE_FLAG_SEND_DONE_WITH_FILE_MESSAGES was provided.  */
        WIMLIB_PROGRESS_MSG_DONE_WITH_FILE = 26,
+
+       /** wimlib_verify_wim() is starting to verify the metadata for an image.
+        * @p info will point to ::wimlib_progress_info.verify_image.  */
+       WIMLIB_PROGRESS_MSG_BEGIN_VERIFY_IMAGE = 27,
+
+       /** wimlib_verify_wim() has finished verifying the metadata for an
+        * image.  @p info will point to ::wimlib_progress_info.verify_image.
+        */
+       WIMLIB_PROGRESS_MSG_END_VERIFY_IMAGE = 28,
+
+       /** wimlib_verify_wim() is verifying stream integrity.  @p info will
+        * point to ::wimlib_progress_info.verify_streams.  */
+       WIMLIB_PROGRESS_MSG_VERIFY_STREAMS = 29,
 };
 
 /** Valid return values from user-provided progress functions
@@ -1053,6 +1066,23 @@ union wimlib_progress_info {
                 */
                const wimlib_tchar *path_to_file;
        } done_with_file;
+
+       /** Valid on messages ::WIMLIB_PROGRESS_MSG_BEGIN_VERIFY_IMAGE and
+        * ::WIMLIB_PROGRESS_MSG_END_VERIFY_IMAGE.  */
+       struct wimlib_progress_info_verify_image {
+               const wimlib_tchar *wimfile;
+               uint32_t total_images;
+               uint32_t current_image;
+       } verify_image;
+
+       /** Valid on messages ::WIMLIB_PROGRESS_MSG_VERIFY_STREAMS.  */
+       struct wimlib_progress_info_verify_streams {
+               const wimlib_tchar *wimfile;
+               uint64_t total_streams;
+               uint64_t total_bytes;
+               uint64_t completed_streams;
+               uint64_t completed_bytes;
+       } verify_streams;
 };
 
 /**
@@ -3997,6 +4027,45 @@ wimlib_split(WIMStruct *wim,
             int write_flags);
 
 /**
+ * @ingroup G_general
+ *
+ * Perform verification checks on a WIM file.
+ *
+ * @param wim
+ *     The ::WIMStruct for the WIM file to verify.  Note: for an extra layer of
+ *     verification, it is a good idea to have used
+ *     ::WIMLIB_OPEN_FLAG_CHECK_INTEGRITY when you opened the file.
+ *     <br/>
+ *     If verifying a split WIM, specify the first part of the split WIM here,
+ *     and reference the other parts using wimlib_reference_resource_files()
+ *     before calling this function.
+ *
+ * @param verify_flags
+ *     Reserved; must be 0.
+ *
+ * @retval 0 if the WIM file was successfully verified; nonzero if it failed
+ * verification or another error occurred.  Some of the possible error codes
+ * are:
+ *
+ * @retval ::WIMLIB_ERR_DECOMPRESSION
+ *     A compressed resource could not be decompressed.
+ * @retval ::WIMLIB_ERR_INVALID_METADATA_RESOURCE
+ *     The metadata resource for an image is invalid.
+ * @retval ::WIMLIB_ERR_INVALID_RESOURCE_HASH
+ *     One of the files did not decompress to its original data, as given by a
+ *     cryptographic checksum.
+ * @retval ::WIMLIB_ERR_RESOURCE_NOT_FOUND
+ *     One of the files referenced by an image could not be located.
+ *
+ * If a progress function is registered with @p wim, it will receive the
+ * following progress messages: ::WIMLIB_PROGRESS_MSG_BEGIN_VERIFY_IMAGE,
+ * ::WIMLIB_PROGRESS_MSG_END_VERIFY_IMAGE, and
+ * ::WIMLIB_PROGRESS_MSG_VERIFY_STREAMS.
+ */
+extern int
+wimlib_verify_wim(WIMStruct *wim, int verify_flags);
+
+/**
  * @ingroup G_mounting_wim_images
  *
  * Unmounts a WIM image that was mounted using wimlib_mount_image().
index 2c0105b..a83b1d3 100644 (file)
@@ -1,11 +1,11 @@
 /*
  * verify.c
  *
- * Verify stream reference counts.
+ * Verify WIM files.
  */
 
 /*
- * Copyright (C) 2012, 2013 Eric Biggers
+ * Copyright (C) 2012, 2013, 2014 Eric Biggers
  *
  * This file is part of wimlib, a library for working with WIM files.
  *
@@ -31,6 +31,7 @@
 #include "wimlib/error.h"
 #include "wimlib/lookup_table.h"
 #include "wimlib/metadata.h"
+#include "wimlib/progress.h"
 #include "wimlib/security.h"
 
 static int
@@ -97,3 +98,131 @@ wim_recalculate_refcnts(WIMStruct *wim)
        wim->refcnts_ok = 1;
        return 0;
 }
+
+static int
+append_lte_to_list(struct wim_lookup_table_entry *lte, void *_list)
+{
+       list_add(&lte->extraction_list, (struct list_head *)_list);
+       return 0;
+}
+
+struct verify_stream_list_ctx {
+       wimlib_progress_func_t progfunc;
+       void *progctx;
+       union wimlib_progress_info *progress;
+};
+
+static int
+end_verify_stream(struct wim_lookup_table_entry *lte, int status, void *_ctx)
+{
+       struct verify_stream_list_ctx *ctx = _ctx;
+
+       if (status)
+               return status;
+
+       ctx->progress->verify_streams.completed_streams++;
+       ctx->progress->verify_streams.completed_bytes += lte->size;
+
+       return call_progress(ctx->progfunc, WIMLIB_PROGRESS_MSG_VERIFY_STREAMS,
+                            ctx->progress, ctx->progctx);
+}
+
+static int
+verify_image_streams_present(struct wim_image_metadata *imd,
+                            struct wim_lookup_table *lookup_table)
+{
+       struct wim_inode *inode;
+       int ret;
+
+       image_for_each_inode(inode, imd) {
+               ret = inode_resolve_streams(inode, lookup_table, false);
+               if (ret)
+                       return ret;
+       }
+       return 0;
+}
+
+/* API function documented in wimlib.h  */
+WIMLIBAPI int
+wimlib_verify_wim(WIMStruct *wim, int verify_flags)
+{
+       int ret;
+       LIST_HEAD(stream_list);
+       union wimlib_progress_info progress;
+       struct verify_stream_list_ctx ctx;
+       struct wim_lookup_table_entry *lte;
+       struct read_stream_list_callbacks cbs = {
+               .end_stream = end_verify_stream,
+               .end_stream_ctx = &ctx,
+       };
+
+       /* Check parameters  */
+
+       if (!wim)
+               return WIMLIB_ERR_INVALID_PARAM;
+
+       if (verify_flags)
+               return WIMLIB_ERR_INVALID_PARAM;
+
+       /* Verify the images  */
+
+       if (wim_has_metadata(wim)) {
+
+               memset(&progress, 0, sizeof(progress));
+               progress.verify_image.wimfile = wim->filename;
+               progress.verify_image.total_images = wim->hdr.image_count;
+
+               for (int i = 1; i <= wim->hdr.image_count; i++) {
+
+                       progress.verify_image.current_image = i;
+
+                       ret = call_progress(wim->progfunc, WIMLIB_PROGRESS_MSG_BEGIN_VERIFY_IMAGE,
+                                           &progress, wim->progctx);
+                       if (ret)
+                               return ret;
+
+                       ret = select_wim_image(wim, i);
+                       if (ret)
+                               return ret;
+
+                       ret = verify_image_streams_present(wim_get_current_image_metadata(wim),
+                                                          wim->lookup_table);
+                       if (ret)
+                               return ret;
+
+                       ret = call_progress(wim->progfunc, WIMLIB_PROGRESS_MSG_END_VERIFY_IMAGE,
+                                           &progress, wim->progctx);
+                       if (ret)
+                               return ret;
+               }
+       } else {
+               WARNING("\"%"TS"\" does not contain image metadata.  Skipping image verification.",
+                       wim->filename);
+       }
+
+       /* Verify the streams  */
+
+       for_lookup_table_entry(wim->lookup_table, append_lte_to_list, &stream_list);
+
+       memset(&progress, 0, sizeof(progress));
+
+       progress.verify_streams.wimfile = wim->filename;
+       list_for_each_entry(lte, &stream_list, extraction_list) {
+               progress.verify_streams.total_streams++;
+               progress.verify_streams.total_bytes += lte->size;
+       }
+
+       ctx.progfunc = wim->progfunc;
+       ctx.progctx = wim->progctx;
+       ctx.progress = &progress;
+
+       ret = call_progress(ctx.progfunc, WIMLIB_PROGRESS_MSG_VERIFY_STREAMS,
+                           ctx.progress, ctx.progctx);
+       if (ret)
+               return ret;
+
+       return read_stream_list(&stream_list,
+                               offsetof(struct wim_lookup_table_entry,
+                                        extraction_list),
+                               &cbs, VERIFY_STREAM_HASHES);
+}