verify: update progress per-chunk instead of per-blob
[wimlib] / src / verify.c
1 /*
2  * verify.c
3  *
4  * Verify WIM files.
5  */
6
7 /*
8  * Copyright (C) 2012, 2013, 2014 Eric Biggers
9  *
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
13  * later version.
14  *
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
18  * details.
19  *
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/.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
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"
34
35 static int
36 append_blob_to_list(struct blob_descriptor *blob, void *_list)
37 {
38         list_add(&blob->extraction_list, (struct list_head *)_list);
39         return 0;
40 }
41
42 struct verify_blob_list_ctx {
43         wimlib_progress_func_t progfunc;
44         void *progctx;
45         union wimlib_progress_info *progress;
46         u64 next_progress;
47         u64 cur_blob_offset;
48         u64 cur_blob_size;
49 };
50
51 static int
52 verify_begin_blob(struct blob_descriptor *blob, void *_ctx)
53 {
54         struct verify_blob_list_ctx *ctx = _ctx;
55
56         ctx->cur_blob_offset = 0;
57         ctx->cur_blob_size = blob->size;
58         return 0;
59 }
60
61 static int
62 verify_consume_chunk(const void *chunk, size_t size, void *_ctx)
63 {
64         struct verify_blob_list_ctx *ctx = _ctx;
65         union wimlib_progress_info *progress = ctx->progress;
66
67         ctx->cur_blob_offset += size;
68         if (ctx->cur_blob_offset == ctx->cur_blob_size)
69                 progress->verify_streams.completed_streams++;
70
71         progress->verify_streams.completed_bytes += size;
72
73         if (progress->verify_streams.completed_bytes >= ctx->next_progress) {
74
75                 int ret = call_progress(ctx->progfunc,
76                                         WIMLIB_PROGRESS_MSG_VERIFY_STREAMS,
77                                         progress, ctx->progctx);
78                 if (ret)
79                         return ret;
80
81                 set_next_progress(progress->verify_streams.completed_bytes,
82                                   progress->verify_streams.total_bytes,
83                                   &ctx->next_progress);
84         }
85         return 0;
86 }
87
88 static int
89 verify_file_data_present(struct wim_image_metadata *imd,
90                          struct blob_table *blob_table)
91 {
92         struct wim_inode *inode;
93         int ret;
94
95         image_for_each_inode(inode, imd) {
96                 ret = inode_resolve_streams(inode, blob_table, false);
97                 if (ret)
98                         return ret;
99         }
100         return 0;
101 }
102
103 /* API function documented in wimlib.h  */
104 WIMLIBAPI int
105 wimlib_verify_wim(WIMStruct *wim, int verify_flags)
106 {
107         int ret;
108         LIST_HEAD(blob_list);
109         union wimlib_progress_info progress;
110         struct verify_blob_list_ctx ctx;
111         struct blob_descriptor *blob;
112         struct read_blob_callbacks cbs = {
113                 .begin_blob     = verify_begin_blob,
114                 .consume_chunk  = verify_consume_chunk,
115                 .ctx            = &ctx,
116         };
117
118         /* Check parameters  */
119
120         if (!wim)
121                 return WIMLIB_ERR_INVALID_PARAM;
122
123         if (verify_flags)
124                 return WIMLIB_ERR_INVALID_PARAM;
125
126         /* Verify the images  */
127
128         if (wim_has_metadata(wim)) {
129
130                 memset(&progress, 0, sizeof(progress));
131                 progress.verify_image.wimfile = wim->filename;
132                 progress.verify_image.total_images = wim->hdr.image_count;
133
134                 for (int i = 1; i <= wim->hdr.image_count; i++) {
135
136                         progress.verify_image.current_image = i;
137
138                         ret = call_progress(wim->progfunc, WIMLIB_PROGRESS_MSG_BEGIN_VERIFY_IMAGE,
139                                             &progress, wim->progctx);
140                         if (ret)
141                                 return ret;
142
143                         ret = select_wim_image(wim, i);
144                         if (ret)
145                                 return ret;
146
147                         ret = verify_file_data_present(wim_get_current_image_metadata(wim),
148                                                        wim->blob_table);
149                         if (ret)
150                                 return ret;
151
152                         ret = call_progress(wim->progfunc, WIMLIB_PROGRESS_MSG_END_VERIFY_IMAGE,
153                                             &progress, wim->progctx);
154                         if (ret)
155                                 return ret;
156                 }
157         } else {
158                 WARNING("\"%"TS"\" does not contain image metadata.  Skipping image verification.",
159                         wim->filename);
160         }
161
162         /* Verify the blobs: SHA-1 message digests must match  */
163
164         for_blob_in_table(wim->blob_table, append_blob_to_list, &blob_list);
165
166         memset(&progress, 0, sizeof(progress));
167
168         progress.verify_streams.wimfile = wim->filename;
169         list_for_each_entry(blob, &blob_list, extraction_list) {
170                 progress.verify_streams.total_streams++;
171                 progress.verify_streams.total_bytes += blob->size;
172         }
173
174         ctx.progfunc = wim->progfunc;
175         ctx.progctx = wim->progctx;
176         ctx.progress = &progress;
177         ctx.next_progress = 0;
178
179         ret = call_progress(ctx.progfunc, WIMLIB_PROGRESS_MSG_VERIFY_STREAMS,
180                             ctx.progress, ctx.progctx);
181         if (ret)
182                 return ret;
183
184         return read_blob_list(&blob_list,
185                               offsetof(struct blob_descriptor, extraction_list),
186                               &cbs, VERIFY_BLOB_HASHES);
187 }