8 * Copyright (C) 2012, 2013, 2014 Eric Biggers
10 * This file is free software; you can redistribute it and/or modify it under
11 * the terms of the GNU Lesser General Public License as published by the Free
12 * Software Foundation; either version 3 of the License, or (at your option) any
15 * This file is distributed in the hope that it will be useful, but WITHOUT
16 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this file; if not, see http://www.gnu.org/licenses/.
28 #include "wimlib/blob_table.h"
29 #include "wimlib/dentry.h"
30 #include "wimlib/error.h"
31 #include "wimlib/metadata.h"
32 #include "wimlib/progress.h"
33 #include "wimlib/security.h"
36 append_blob_to_list(struct blob_descriptor *blob, void *_list)
38 list_add(&blob->extraction_list, (struct list_head *)_list);
42 struct verify_blob_list_ctx {
43 wimlib_progress_func_t progfunc;
45 union wimlib_progress_info *progress;
50 end_verify_blob(struct blob_descriptor *blob, int status, void *_ctx)
52 struct verify_blob_list_ctx *ctx = _ctx;
53 union wimlib_progress_info *progress = ctx->progress;
58 progress->verify_streams.completed_streams++;
59 progress->verify_streams.completed_bytes += blob->size;
61 /* Handle rate-limiting of progress messages */
63 if (progress->verify_streams.completed_bytes < ctx->next_progress)
66 /* Time for another progress message. */
68 status = call_progress(ctx->progfunc, WIMLIB_PROGRESS_MSG_VERIFY_STREAMS,
69 progress, ctx->progctx);
73 if (ctx->next_progress == progress->verify_streams.total_bytes) {
74 ctx->next_progress = ~(uint64_t)0;
78 /* Send new message as soon as another 1/128 of the total has
79 * been verified. (Arbitrary number.) */
80 ctx->next_progress = progress->verify_streams.completed_bytes +
81 progress->verify_streams.total_bytes / 128;
83 /* ... Unless that would be more than 5000000 bytes, in which case send
84 * the next after the next 5000000 bytes. (Another arbitrary number.) */
85 if (progress->verify_streams.completed_bytes + 5000000 < ctx->next_progress)
86 ctx->next_progress = progress->verify_streams.completed_bytes + 5000000;
88 /* ... But always send a message as soon as we're completely
90 if (progress->verify_streams.total_bytes < ctx->next_progress)
91 ctx->next_progress = progress->verify_streams.total_bytes;
96 verify_image_blobs_present(struct wim_image_metadata *imd,
97 struct blob_table *blob_table)
99 struct wim_inode *inode;
102 image_for_each_inode(inode, imd) {
103 ret = inode_resolve_streams(inode, blob_table, false);
110 /* API function documented in wimlib.h */
112 wimlib_verify_wim(WIMStruct *wim, int verify_flags)
115 LIST_HEAD(blob_list);
116 union wimlib_progress_info progress;
117 struct verify_blob_list_ctx ctx;
118 struct blob_descriptor *blob;
119 struct read_blob_list_callbacks cbs = {
120 .end_blob = end_verify_blob,
121 .end_blob_ctx = &ctx,
124 /* Check parameters */
127 return WIMLIB_ERR_INVALID_PARAM;
130 return WIMLIB_ERR_INVALID_PARAM;
132 /* Verify the images */
134 if (wim_has_metadata(wim)) {
136 memset(&progress, 0, sizeof(progress));
137 progress.verify_image.wimfile = wim->filename;
138 progress.verify_image.total_images = wim->hdr.image_count;
140 for (int i = 1; i <= wim->hdr.image_count; i++) {
142 progress.verify_image.current_image = i;
144 ret = call_progress(wim->progfunc, WIMLIB_PROGRESS_MSG_BEGIN_VERIFY_IMAGE,
145 &progress, wim->progctx);
149 ret = select_wim_image(wim, i);
153 ret = verify_image_blobs_present(wim_get_current_image_metadata(wim),
158 ret = call_progress(wim->progfunc, WIMLIB_PROGRESS_MSG_END_VERIFY_IMAGE,
159 &progress, wim->progctx);
164 WARNING("\"%"TS"\" does not contain image metadata. Skipping image verification.",
168 /* Verify the blobs: SHA-1 message digests must match */
170 for_blob_in_table(wim->blob_table, append_blob_to_list, &blob_list);
172 memset(&progress, 0, sizeof(progress));
174 progress.verify_streams.wimfile = wim->filename;
175 list_for_each_entry(blob, &blob_list, extraction_list) {
176 progress.verify_streams.total_streams++;
177 progress.verify_streams.total_bytes += blob->size;
180 ctx.progfunc = wim->progfunc;
181 ctx.progctx = wim->progctx;
182 ctx.progress = &progress;
183 ctx.next_progress = 0;
185 ret = call_progress(ctx.progfunc, WIMLIB_PROGRESS_MSG_VERIFY_STREAMS,
186 ctx.progress, ctx.progctx);
190 return read_blob_list(&blob_list,
191 offsetof(struct blob_descriptor, extraction_list),
192 &cbs, VERIFY_BLOB_HASHES);