9cd86f9e0fd96e6ef0647407894b98c823933401
[wimlib] / src / metadata_resource.c
1 /*
2  * metadata_resource.c
3  */
4
5 /*
6  * Copyright (C) 2012, 2013 Eric Biggers
7  *
8  * This file is part of wimlib, a library for working with WIM files.
9  *
10  * wimlib is free software; you can redistribute it and/or modify it under the
11  * terms of the GNU General Public License as published by the Free Software
12  * Foundation; either version 3 of the License, or (at your option) any later
13  * version.
14  *
15  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
16  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
17  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License along with
20  * wimlib; if not, see http://www.gnu.org/licenses/.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #endif
26
27 #include "wimlib/dentry.h"
28 #include "wimlib/error.h"
29 #include "wimlib/lookup_table.h"
30 #include "wimlib/metadata.h"
31 #include "wimlib/resource.h"
32 #include "wimlib/security.h"
33 #include "wimlib/write.h"
34
35 /*
36  * Reads a metadata resource for an image in the WIM file.  The metadata
37  * resource consists of the security data, followed by the directory entry for
38  * the root directory, followed by all the other directory entries in the
39  * filesystem.  The subdir_offset field of each directory entry gives the start
40  * of its child entries from the beginning of the metadata resource.  An
41  * end-of-directory is signaled by a directory entry of length '0', really of
42  * length 8, because that's how long the 'length' field is.
43  *
44  * @wim:
45  *      Pointer to the WIMStruct for the WIM file.
46  *
47  * @imd:
48  *      Pointer to the image metadata structure for the image whose metadata
49  *      resource we are reading.  Its `metadata_lte' member specifies the lookup
50  *      table entry for the metadata resource.  The rest of the image metadata
51  *      entry will be filled in by this function.
52  *
53  * Return values:
54  *      WIMLIB_ERR_SUCCESS (0)
55  *      WIMLIB_ERR_INVALID_METADATA_RESOURCE
56  *      WIMLIB_ERR_NOMEM
57  *      WIMLIB_ERR_READ
58  *      WIMLIB_ERR_UNEXPECTED_END_OF_FILE
59  *      WIMLIB_ERR_DECOMPRESSION
60  */
61 int
62 read_metadata_resource(WIMStruct *wim, struct wim_image_metadata *imd)
63 {
64         void *buf;
65         int ret;
66         struct wim_dentry *root;
67         const struct wim_lookup_table_entry *metadata_lte;
68         u64 metadata_len;
69         u8 hash[SHA1_HASH_SIZE];
70         struct wim_security_data *security_data;
71         struct wim_inode *inode;
72
73         metadata_lte = imd->metadata_lte;
74         metadata_len = metadata_lte->size;
75
76         DEBUG("Reading metadata resource.");
77
78         /* There is no way the metadata resource could possibly be less than (8
79          * + WIM_DENTRY_DISK_SIZE) bytes, where the 8 is for security data (with
80          * no security descriptors) and WIM_DENTRY_DISK_SIZE is for the root
81          * entry. */
82         if (metadata_len < 8 + WIM_DENTRY_DISK_SIZE) {
83                 ERROR("Expected at least %u bytes for the metadata resource",
84                       8 + WIM_DENTRY_DISK_SIZE);
85                 return WIMLIB_ERR_INVALID_METADATA_RESOURCE;
86         }
87
88         /* Read the metadata resource into memory.  (It may be compressed.) */
89         ret = read_full_stream_into_alloc_buf(metadata_lte, &buf);
90         if (ret)
91                 return ret;
92
93         if (!metadata_lte->dont_check_metadata_hash) {
94                 sha1_buffer(buf, metadata_len, hash);
95                 if (!hashes_equal(metadata_lte->hash, hash)) {
96                         ERROR("Metadata resource is corrupted "
97                               "(invalid SHA-1 message digest)!");
98                         ret = WIMLIB_ERR_INVALID_METADATA_RESOURCE;
99                         goto out_free_buf;
100                 }
101         }
102
103         DEBUG("Finished reading metadata resource into memory.");
104
105         ret = read_wim_security_data(buf, metadata_len, &security_data);
106         if (ret)
107                 goto out_free_buf;
108
109         DEBUG("Reading root dentry");
110
111         /* Allocate memory for the root dentry and read it into memory */
112         root = MALLOC(sizeof(struct wim_dentry));
113         if (!root) {
114                 ret = WIMLIB_ERR_NOMEM;
115                 goto out_free_security_data;
116         }
117
118         /* The root directory entry starts after security data, aligned on an
119          * 8-byte boundary within the metadata resource.  Since
120          * security_data->total_length was already rounded up to an 8-byte
121          * boundary, its value can be used as the offset of the root directory
122          * entry.  */
123         ret = read_dentry(buf, metadata_len,
124                           security_data->total_length, root);
125
126         if (ret == 0 && root->length == 0) {
127                 WARNING("Metadata resource begins with end-of-directory entry "
128                         "(treating as empty image)");
129                 FREE(root);
130                 root = NULL;
131                 goto out_success;
132         }
133
134         if (ret) {
135                 FREE(root);
136                 goto out_free_security_data;
137         }
138
139         if (dentry_has_long_name(root) || dentry_has_short_name(root)) {
140                 WARNING("The root directory has a nonempty name (removing it)");
141                 FREE(root->file_name);
142                 FREE(root->short_name);
143                 root->file_name = NULL;
144                 root->short_name = NULL;
145                 root->file_name_nbytes = 0;
146                 root->short_name_nbytes = 0;
147         }
148
149         if (!dentry_is_directory(root)) {
150                 ERROR("Root of the WIM image must be a directory!");
151                 FREE(root);
152                 ret = WIMLIB_ERR_INVALID_METADATA_RESOURCE;
153                 goto out_free_security_data;
154         }
155
156         /* This is the root dentry, so set its parent to itself. */
157         root->parent = root;
158
159         inode_add_dentry(root, root->d_inode);
160
161         /* Now read the entire directory entry tree into memory. */
162         DEBUG("Reading dentry tree");
163         ret = read_dentry_tree(buf, metadata_len, root);
164         if (ret)
165                 goto out_free_dentry_tree;
166
167         /* Build hash table that maps hard link group IDs to dentry sets */
168         ret = dentry_tree_fix_inodes(root, &imd->inode_list);
169         if (ret)
170                 goto out_free_dentry_tree;
171
172
173         DEBUG("Running miscellaneous verifications on the dentry tree");
174         image_for_each_inode(inode, imd) {
175                 ret = verify_inode(inode, security_data);
176                 if (ret)
177                         goto out_free_dentry_tree;
178         }
179         DEBUG("Done reading image metadata");
180 out_success:
181         imd->root_dentry = root;
182         imd->security_data = security_data;
183         INIT_LIST_HEAD(&imd->unhashed_streams);
184         ret = 0;
185         goto out_free_buf;
186 out_free_dentry_tree:
187         free_dentry_tree(root, wim->lookup_table);
188 out_free_security_data:
189         free_wim_security_data(security_data);
190 out_free_buf:
191         FREE(buf);
192         return ret;
193 }
194
195 static void
196 recalculate_security_data_length(struct wim_security_data *sd)
197 {
198         u32 total_length = sizeof(u64) * sd->num_entries + 2 * sizeof(u32);
199         for (u32 i = 0; i < sd->num_entries; i++)
200                 total_length += sd->sizes[i];
201         sd->total_length = (total_length + 7) & ~7;
202 }
203
204 static int
205 prepare_metadata_resource(WIMStruct *wim, int image,
206                           u8 **buf_ret, size_t *len_ret)
207 {
208         u8 *buf;
209         u8 *p;
210         int ret;
211         u64 subdir_offset;
212         struct wim_dentry *root;
213         u64 len;
214         struct wim_security_data *sd;
215         struct wim_image_metadata *imd;
216
217         DEBUG("Preparing metadata resource for image %d", image);
218
219         ret = select_wim_image(wim, image);
220         if (ret)
221                 return ret;
222
223         imd = wim->image_metadata[image - 1];
224
225         root = imd->root_dentry;
226         sd = imd->security_data;
227
228         if (!root) {
229                 /* Empty image; create a dummy root.  */
230                 ret = new_filler_directory(T(""), &root);
231                 if (ret)
232                         return ret;
233                 imd->root_dentry = root;
234         }
235
236         /* Offset of first child of the root dentry.  It's equal to:
237          * - The total length of the security data, rounded to the next 8-byte
238          *   boundary,
239          * - plus the total length of the root dentry,
240          * - plus 8 bytes for an end-of-directory entry following the root
241          *   dentry (shouldn't really be needed, but just in case...)
242          */
243         recalculate_security_data_length(sd);
244         subdir_offset = (((u64)sd->total_length + 7) & ~7) +
245                         dentry_out_total_length(root) + 8;
246
247         /* Calculate the subdirectory offsets for the entire dentry tree.  */
248         calculate_subdir_offsets(root, &subdir_offset);
249
250         /* Total length of the metadata resource (uncompressed).  */
251         len = subdir_offset;
252
253         /* Allocate a buffer to contain the uncompressed metadata resource.  */
254         buf = MALLOC(len);
255         if (!buf) {
256                 ERROR("Failed to allocate %"PRIu64" bytes for "
257                       "metadata resource", len);
258                 return WIMLIB_ERR_NOMEM;
259         }
260
261         /* Write the security data into the resource buffer.  */
262         p = write_wim_security_data(sd, buf);
263
264         /* Write the dentry tree into the resource buffer.  */
265         p = write_dentry_tree(root, p);
266
267         /* We MUST have exactly filled the buffer; otherwise we calculated its
268          * size incorrectly or wrote the data incorrectly.  */
269         wimlib_assert(p - buf == len);
270
271         *buf_ret = buf;
272         *len_ret = len;
273         return 0;
274 }
275
276 int
277 write_metadata_resource(WIMStruct *wim, int image, int write_resource_flags)
278 {
279         int ret;
280         u8 *buf;
281         size_t len;
282         struct wim_image_metadata *imd;
283
284         ret = prepare_metadata_resource(wim, image, &buf, &len);
285         if (ret)
286                 return ret;
287
288         imd = wim->image_metadata[image - 1];
289
290         /* Write the metadata resource to the output WIM using the proper
291          * compression type, in the process updating the lookup table entry for
292          * the metadata resource.  */
293         ret = write_wim_resource_from_buffer(buf, len, WIM_RESHDR_FLAG_METADATA,
294                                              &wim->out_fd,
295                                              wim->out_compression_type,
296                                              wim->out_chunk_size,
297                                              &imd->metadata_lte->out_reshdr,
298                                              imd->metadata_lte->hash,
299                                              write_resource_flags);
300
301         /* Original checksum was overridden; set a flag so it isn't used.  */
302         imd->metadata_lte->dont_check_metadata_hash = 1;
303
304         FREE(buf);
305         return ret;
306 }