]> wimlib.net Git - wimlib/blob - src/verify.c
resource reading cleanups
[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 };
48
49 static int
50 end_verify_blob(struct blob_descriptor *blob, int status, void *_ctx)
51 {
52         struct verify_blob_list_ctx *ctx = _ctx;
53         union wimlib_progress_info *progress = ctx->progress;
54
55         if (status)
56                 return status;
57
58         progress->verify_streams.completed_streams++;
59         progress->verify_streams.completed_bytes += blob->size;
60
61         /* Handle rate-limiting of progress messages  */
62
63         if (progress->verify_streams.completed_bytes < ctx->next_progress)
64                 return 0;
65
66         /* Time for another progress message.  */
67
68         status = call_progress(ctx->progfunc, WIMLIB_PROGRESS_MSG_VERIFY_STREAMS,
69                                progress, ctx->progctx);
70         if (status)
71                 return status;
72
73         if (ctx->next_progress == progress->verify_streams.total_bytes) {
74                 ctx->next_progress = ~(u64)0;
75                 return 0;
76         }
77
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;
82
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;
87
88         /* ... But always send a message as soon as we're completely
89          * done.  */
90         if (progress->verify_streams.total_bytes < ctx->next_progress)
91                 ctx->next_progress = progress->verify_streams.total_bytes;
92         return 0;
93 }
94
95 static int
96 verify_file_data_present(struct wim_image_metadata *imd,
97                          struct blob_table *blob_table)
98 {
99         struct wim_inode *inode;
100         int ret;
101
102         image_for_each_inode(inode, imd) {
103                 ret = inode_resolve_streams(inode, blob_table, false);
104                 if (ret)
105                         return ret;
106         }
107         return 0;
108 }
109
110 /* API function documented in wimlib.h  */
111 WIMLIBAPI int
112 wimlib_verify_wim(WIMStruct *wim, int verify_flags)
113 {
114         int ret;
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_callbacks cbs = {
120                 .end_blob       = end_verify_blob,
121                 .ctx            = &ctx,
122         };
123
124         /* Check parameters  */
125
126         if (!wim)
127                 return WIMLIB_ERR_INVALID_PARAM;
128
129         if (verify_flags)
130                 return WIMLIB_ERR_INVALID_PARAM;
131
132         /* Verify the images  */
133
134         if (wim_has_metadata(wim)) {
135
136                 memset(&progress, 0, sizeof(progress));
137                 progress.verify_image.wimfile = wim->filename;
138                 progress.verify_image.total_images = wim->hdr.image_count;
139
140                 for (int i = 1; i <= wim->hdr.image_count; i++) {
141
142                         progress.verify_image.current_image = i;
143
144                         ret = call_progress(wim->progfunc, WIMLIB_PROGRESS_MSG_BEGIN_VERIFY_IMAGE,
145                                             &progress, wim->progctx);
146                         if (ret)
147                                 return ret;
148
149                         ret = select_wim_image(wim, i);
150                         if (ret)
151                                 return ret;
152
153                         ret = verify_file_data_present(wim_get_current_image_metadata(wim),
154                                                        wim->blob_table);
155                         if (ret)
156                                 return ret;
157
158                         ret = call_progress(wim->progfunc, WIMLIB_PROGRESS_MSG_END_VERIFY_IMAGE,
159                                             &progress, wim->progctx);
160                         if (ret)
161                                 return ret;
162                 }
163         } else {
164                 WARNING("\"%"TS"\" does not contain image metadata.  Skipping image verification.",
165                         wim->filename);
166         }
167
168         /* Verify the blobs: SHA-1 message digests must match  */
169
170         for_blob_in_table(wim->blob_table, append_blob_to_list, &blob_list);
171
172         memset(&progress, 0, sizeof(progress));
173
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;
178         }
179
180         ctx.progfunc = wim->progfunc;
181         ctx.progctx = wim->progctx;
182         ctx.progress = &progress;
183         ctx.next_progress = 0;
184
185         ret = call_progress(ctx.progfunc, WIMLIB_PROGRESS_MSG_VERIFY_STREAMS,
186                             ctx.progress, ctx.progctx);
187         if (ret)
188                 return ret;
189
190         return read_blob_list(&blob_list,
191                               offsetof(struct blob_descriptor, extraction_list),
192                               &cbs, VERIFY_BLOB_HASHES);
193 }