]> wimlib.net Git - wimlib/blob - src/resource.c
Use FUSE multi-threaded mode for read-only mounts
[wimlib] / src / resource.c
1 /*
2  * resource.c
3  *
4  * Read uncompressed and compressed metadata and file resources.
5  */
6
7 /*
8  * Copyright (C) 2012 Eric Biggers
9  *
10  * This file is part of wimlib, a library for working with WIM files.
11  *
12  * wimlib is free software; you can redistribute it and/or modify it under the
13  * terms of the GNU General Public License as published by the Free Software
14  * Foundation; either version 3 of the License, or (at your option) any later
15  * version.
16  *
17  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
18  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
19  * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License along with
22  * wimlib; if not, see http://www.gnu.org/licenses/.
23  */
24
25 #include "config.h"
26
27 #include <stdlib.h>
28 #include <stdarg.h>
29
30 #include "dentry.h"
31
32 #ifdef WITH_NTFS_3G
33 #include <ntfs-3g/attrib.h>
34 #include <ntfs-3g/inode.h>
35 #include <ntfs-3g/dir.h>
36 #endif
37
38 #include "wimlib_internal.h"
39 #include "lookup_table.h"
40 #include "io.h"
41 #include "lzx.h"
42 #include "xpress.h"
43 #include "sha1.h"
44 #include <unistd.h>
45 #include <errno.h>
46 #ifdef HAVE_ALLOCA_H
47 #include <alloca.h>
48 #endif
49
50
51 /*
52  * Reads all or part of a compressed resource into an in-memory buffer.
53  *
54  * @fp:                 The FILE* for the WIM file.
55  * @resource_compressed_size:    The compressed size of the resource.
56  * @resource_uncompressed_size:  The uncompressed size of the resource.
57  * @resource_offset:             The offset of the start of the resource from
58  *                                      the start of the stream @fp.
59  * @resource_ctype:     The compression type of the resource.
60  * @len:                The number of bytes of uncompressed data to read from
61  *                              the resource.
62  * @offset:             The offset of the bytes to read within the uncompressed
63  *                              resource.
64  * @contents_len:       An array into which the uncompressed data is written.
65  *                              It must be at least @len bytes long.
66  *
67  * Returns zero on success, nonzero on failure.
68  */
69 static int read_compressed_resource(FILE *fp, u64 resource_compressed_size,
70                                     u64 resource_uncompressed_size,
71                                     u64 resource_offset, int resource_ctype,
72                                     u64 len, u64 offset, u8  contents_ret[])
73 {
74
75         DEBUG2("comp size = %"PRIu64", uncomp size = %"PRIu64", "
76                "res offset = %"PRIu64"",
77                resource_compressed_size,
78                resource_uncompressed_size,
79                resource_offset);
80         DEBUG2("resource_ctype = %s, len = %"PRIu64", offset = %"PRIu64"",
81                wimlib_get_compression_type_string(resource_ctype), len, offset);
82         /* Trivial case */
83         if (len == 0)
84                 return 0;
85
86         int (*decompress)(const void *, uint, void *, uint);
87         /* Set the appropriate decompress function. */
88         if (resource_ctype == WIM_COMPRESSION_TYPE_LZX)
89                 decompress = lzx_decompress;
90         else
91                 decompress = xpress_decompress;
92
93         /* The structure of a compressed resource consists of a table of chunk
94          * offsets followed by the chunks themselves.  Each chunk consists of
95          * compressed data, and there is one chunk for each WIM_CHUNK_SIZE =
96          * 32768 bytes of the uncompressed file, with the last chunk having any
97          * remaining bytes.
98          *
99          * The chunk offsets are measured relative to the end of the chunk
100          * table.  The first chunk is omitted from the table in the WIM file
101          * because its offset is implicitly given by the fact that it directly
102          * follows the chunk table and therefore must have an offset of 0.
103          */
104
105         /* Calculate how many chunks the resource conists of in its entirety. */
106         u64 num_chunks = (resource_uncompressed_size + WIM_CHUNK_SIZE - 1) /
107                                                                 WIM_CHUNK_SIZE;
108         /* As mentioned, the first chunk has no entry in the chunk table. */
109         u64 num_chunk_entries = num_chunks - 1;
110
111
112         /* The index of the chunk that the read starts at. */
113         u64 start_chunk = offset / WIM_CHUNK_SIZE;
114         /* The byte offset at which the read starts, within the start chunk. */
115         u64 start_chunk_offset = offset % WIM_CHUNK_SIZE;
116
117         /* The index of the chunk that contains the last byte of the read. */
118         u64 end_chunk   = (offset + len - 1) / WIM_CHUNK_SIZE;
119         /* The byte offset of the last byte of the read, within the end chunk */
120         u64 end_chunk_offset = (offset + len - 1) % WIM_CHUNK_SIZE;
121
122         /* Number of chunks that are actually needed to read the requested part
123          * of the file. */
124         u64 num_needed_chunks = end_chunk - start_chunk + 1;
125
126         /* If the end chunk is not the last chunk, an extra chunk entry is
127          * needed because we need to know the offset of the chunk after the last
128          * chunk read to figure out the size of the last read chunk. */
129         if (end_chunk != num_chunks - 1)
130                 num_needed_chunks++;
131
132         /* Declare the chunk table.  It will only contain offsets for the chunks
133          * that are actually needed for this read. */
134         u64 chunk_offsets[num_needed_chunks];
135
136         /* Set the implicit offset of the first chunk if it is included in the
137          * needed chunks.
138          *
139          * Note: M$'s documentation includes a picture that shows the first
140          * chunk starting right after the chunk entry table, labeled as offset
141          * 0x10.  However, in the actual file format, the offset is measured
142          * from the end of the chunk entry table, so the first chunk has an
143          * offset of 0. */
144         if (start_chunk == 0)
145                 chunk_offsets[0] = 0;
146
147         /* According to M$'s documentation, if the uncompressed size of
148          * the file is greater than 4 GB, the chunk entries are 8-byte
149          * integers.  Otherwise, they are 4-byte integers. */
150         u64 chunk_entry_size = (resource_uncompressed_size >= (u64)1 << 32) ?
151                                                                         8 : 4;
152
153         /* Size of the full chunk table in the WIM file. */
154         u64 chunk_table_size = chunk_entry_size * num_chunk_entries;
155
156         /* Read the needed chunk offsets from the table in the WIM file. */
157
158         /* Index, in the WIM file, of the first needed entry in the
159          * chunk table. */
160         u64 start_table_idx = (start_chunk == 0) ? 0 : start_chunk - 1;
161
162         /* Number of entries we need to actually read from the chunk
163          * table (excludes the implicit first chunk). */
164         u64 num_needed_chunk_entries = (start_chunk == 0) ?
165                                 num_needed_chunks - 1 : num_needed_chunks;
166
167         /* Skip over unneeded chunk table entries. */
168         u64 file_offset_of_needed_chunk_entries = resource_offset +
169                                 start_table_idx * chunk_entry_size;
170         if (fseeko(fp, file_offset_of_needed_chunk_entries, SEEK_SET) != 0) {
171                 ERROR_WITH_ERRNO("Failed to seek to byte %"PRIu64" to read "
172                                  "chunk table of compressed resource",
173                                  file_offset_of_needed_chunk_entries);
174                 return WIMLIB_ERR_READ;
175         }
176
177         /* Number of bytes we need to read from the chunk table. */
178         size_t size = num_needed_chunk_entries * chunk_entry_size;
179
180         u8 chunk_tab_buf[size];
181
182         if (fread(chunk_tab_buf, 1, size, fp) != size)
183                 goto err;
184
185         /* Now fill in chunk_offsets from the entries we have read in
186          * chunk_tab_buf. */
187
188         u64 *chunk_tab_p = chunk_offsets;
189         if (start_chunk == 0)
190                 chunk_tab_p++;
191
192         if (chunk_entry_size == 4) {
193                 u32 *entries = (u32*)chunk_tab_buf;
194                 while (num_needed_chunk_entries--)
195                         *chunk_tab_p++ = le32_to_cpu(*entries++);
196         } else {
197                 u64 *entries = (u64*)chunk_tab_buf;
198                 while (num_needed_chunk_entries--)
199                         *chunk_tab_p++ = le64_to_cpu(*entries++);
200         }
201
202         /* Done with the chunk table now.  We must now seek to the first chunk
203          * that is needed for the read. */
204
205         u64 file_offset_of_first_needed_chunk = resource_offset +
206                                 chunk_table_size + chunk_offsets[0];
207         if (fseeko(fp, file_offset_of_first_needed_chunk, SEEK_SET) != 0) {
208                 ERROR_WITH_ERRNO("Failed to seek to byte %"PRIu64" to read "
209                                  "first chunk of compressed resource",
210                                  file_offset_of_first_needed_chunk);
211                 return WIMLIB_ERR_READ;
212         }
213
214         /* Pointer to current position in the output buffer for uncompressed
215          * data. */
216         u8 *out_p = (u8*)contents_ret;
217
218         /* Buffer for compressed data.  While most compressed chunks will have a
219          * size much less than WIM_CHUNK_SIZE, WIM_CHUNK_SIZE - 1 is the maximum
220          * size in the worst-case.  This assumption is valid only if chunks that
221          * happen to compress to more than the uncompressed size (i.e. a
222          * sequence of random bytes) are always stored uncompressed. But this seems
223          * to be the case in M$'s WIM files, even though it is undocumented. */
224         u8 compressed_buf[WIM_CHUNK_SIZE - 1];
225
226
227         /* Decompress all the chunks. */
228         for (u64 i = start_chunk; i <= end_chunk; i++) {
229
230                 DEBUG2("Chunk %"PRIu64" (start %"PRIu64", end %"PRIu64").",
231                        i, start_chunk, end_chunk);
232
233                 /* Calculate the sizes of the compressed chunk and of the
234                  * uncompressed chunk. */
235                 uint compressed_chunk_size, uncompressed_chunk_size;
236                 if (i != num_chunks - 1) {
237                         /* All the chunks except the last one in the resource
238                          * expand to WIM_CHUNK_SIZE uncompressed, and the amount
239                          * of compressed data for the chunk is given by the
240                          * difference of offsets in the chunk offset table. */
241                         compressed_chunk_size = chunk_offsets[i + 1 - start_chunk] -
242                                                 chunk_offsets[i - start_chunk];
243                         uncompressed_chunk_size = WIM_CHUNK_SIZE;
244                 } else {
245                         /* The last compressed chunk consists of the remaining
246                          * bytes in the file resource, and the last uncompressed
247                          * chunk has size equal to however many bytes are left-
248                          * that is, the remainder of the uncompressed size when
249                          * divided by WIM_CHUNK_SIZE.
250                          *
251                          * Note that the resource_compressed_size includes the
252                          * chunk table, so the size of it must be subtracted. */
253                         compressed_chunk_size = resource_compressed_size -
254                                                 chunk_table_size -
255                                                 chunk_offsets[i - start_chunk];
256
257                         uncompressed_chunk_size = resource_uncompressed_size %
258                                                                 WIM_CHUNK_SIZE;
259
260                         /* If the remainder is 0, the last chunk actually
261                          * uncompresses to a full WIM_CHUNK_SIZE bytes. */
262                         if (uncompressed_chunk_size == 0)
263                                 uncompressed_chunk_size = WIM_CHUNK_SIZE;
264                 }
265
266                 DEBUG2("compressed_chunk_size = %u, "
267                        "uncompressed_chunk_size = %u",
268                        compressed_chunk_size, uncompressed_chunk_size);
269
270
271                 /* Figure out how much of this chunk we actually need to read */
272                 u64 start_offset;
273                 if (i == start_chunk)
274                         start_offset = start_chunk_offset;
275                 else
276                         start_offset = 0;
277                 u64 end_offset;
278                 if (i == end_chunk)
279                         end_offset = end_chunk_offset;
280                 else
281                         end_offset = WIM_CHUNK_SIZE - 1;
282
283                 u64 partial_chunk_size = end_offset + 1 - start_offset;
284                 bool is_partial_chunk = (partial_chunk_size !=
285                                                 uncompressed_chunk_size);
286
287                 DEBUG2("start_offset = %u, end_offset = %u", start_offset,
288                                         end_offset);
289                 DEBUG2("partial_chunk_size = %u", partial_chunk_size);
290
291                 /* This is undocumented, but chunks can be uncompressed.  This
292                  * appears to always be the case when the compressed chunk size
293                  * is equal to the uncompressed chunk size. */
294                 if (compressed_chunk_size == uncompressed_chunk_size) {
295                         /* Probably an uncompressed chunk */
296
297                         if (start_offset != 0) {
298                                 if (fseeko(fp, start_offset, SEEK_CUR) != 0) {
299                                         ERROR_WITH_ERRNO("Uncompressed partial "
300                                                          "chunk fseek() error");
301                                         return WIMLIB_ERR_READ;
302                                 }
303                         }
304                         if (fread(out_p, 1, partial_chunk_size, fp) !=
305                                         partial_chunk_size)
306                                 goto err;
307                 } else {
308                         /* Compressed chunk */
309                         int ret;
310
311                         /* Read the compressed data into compressed_buf. */
312                         if (fread(compressed_buf, 1, compressed_chunk_size,
313                                                 fp) != compressed_chunk_size)
314                                 goto err;
315
316                         /* For partial chunks we must buffer the uncompressed
317                          * data because we don't need all of it. */
318                         if (is_partial_chunk) {
319                                 u8 uncompressed_buf[uncompressed_chunk_size];
320
321                                 ret = decompress(compressed_buf,
322                                                 compressed_chunk_size,
323                                                 uncompressed_buf,
324                                                 uncompressed_chunk_size);
325                                 if (ret != 0)
326                                         return WIMLIB_ERR_DECOMPRESSION;
327                                 memcpy(out_p, uncompressed_buf + start_offset,
328                                                 partial_chunk_size);
329                         } else {
330                                 ret = decompress(compressed_buf,
331                                                 compressed_chunk_size,
332                                                 out_p,
333                                                 uncompressed_chunk_size);
334                                 if (ret != 0)
335                                         return WIMLIB_ERR_DECOMPRESSION;
336                         }
337                 }
338
339                 /* Advance the pointer into the uncompressed output data by the
340                  * number of uncompressed bytes that were written.  */
341                 out_p += partial_chunk_size;
342         }
343
344         return 0;
345
346 err:
347         if (feof(fp))
348                 ERROR("Unexpected EOF in compressed file resource");
349         else
350                 ERROR_WITH_ERRNO("Error reading compressed file resource");
351         return WIMLIB_ERR_READ;
352 }
353
354 /*
355  * Reads uncompressed data from an open file stream.
356  */
357 int read_uncompressed_resource(FILE *fp, u64 offset, u64 len,
358                                u8 contents_ret[])
359 {
360         if (fseeko(fp, offset, SEEK_SET) != 0) {
361                 ERROR("Failed to seek to byte %"PRIu64" of input file "
362                       "to read uncompressed resource (len = %"PRIu64")",
363                       offset, len);
364                 return WIMLIB_ERR_READ;
365         }
366         if (fread(contents_ret, 1, len, fp) != len) {
367                 if (feof(fp)) {
368                         ERROR("Unexpected EOF in uncompressed file resource");
369                 } else {
370                         ERROR("Failed to read %"PRIu64" bytes from "
371                               "uncompressed resource at offset %"PRIu64,
372                               len, offset);
373                 }
374                 return WIMLIB_ERR_READ;
375         }
376         return 0;
377 }
378
379
380
381
382 /* Reads the contents of a struct resource_entry, as represented in the on-disk
383  * format, from the memory pointed to by @p, and fills in the fields of @entry.
384  * A pointer to the byte after the memory read at @p is returned. */
385 const u8 *get_resource_entry(const u8 *p, struct resource_entry *entry)
386 {
387         u64 size;
388         u8 flags;
389
390         p = get_u56(p, &size);
391         p = get_u8(p, &flags);
392         entry->size = size;
393         entry->flags = flags;
394
395         /* offset and original_size are truncated to 62 bits to avoid possible
396          * overflows, when converting to a signed 64-bit integer (off_t) or when
397          * adding size or original_size.  This is okay since no one would ever
398          * actually have a WIM bigger than 4611686018427387903 bytes... */
399         p = get_u64(p, &entry->offset);
400         if (entry->offset & 0xc000000000000000ULL) {
401                 WARNING("Truncating offset in resource entry");
402                 entry->offset &= 0x3fffffffffffffffULL;
403         }
404         p = get_u64(p, &entry->original_size);
405         if (entry->original_size & 0xc000000000000000ULL) {
406                 WARNING("Truncating original_size in resource entry");
407                 entry->original_size &= 0x3fffffffffffffffULL;
408         }
409         return p;
410 }
411
412 /* Copies the struct resource_entry @entry to the memory pointed to by @p in the
413  * on-disk format.  A pointer to the byte after the memory written at @p is
414  * returned. */
415 u8 *put_resource_entry(u8 *p, const struct resource_entry *entry)
416 {
417         p = put_u56(p, entry->size);
418         p = put_u8(p, entry->flags);
419         p = put_u64(p, entry->offset);
420         p = put_u64(p, entry->original_size);
421         return p;
422 }
423
424 /*
425  * Reads some data from the resource corresponding to a WIM lookup table entry.
426  *
427  * @lte:        The WIM lookup table entry for the resource.
428  * @buf:        Buffer into which to write the data.
429  * @size:       Number of bytes to read.
430  * @offset:     Offset at which to start reading the resource.
431  * @raw:        If %true, compressed data is read literally rather than being
432  *                      decompressed first.
433  *
434  * Returns zero on success, nonzero on failure.
435  */
436 int read_wim_resource(const struct lookup_table_entry *lte, u8 buf[],
437                       size_t size, u64 offset, bool raw)
438 {
439         int ctype;
440         int ret = 0;
441         FILE *fp;
442
443         /* We shouldn't be allowing read over-runs in any part of the library.
444          * */
445         if (raw)
446                 wimlib_assert(offset + size <= lte->resource_entry.size);
447         else
448                 wimlib_assert(offset + size <= lte->resource_entry.original_size);
449
450         switch (lte->resource_location) {
451         case RESOURCE_IN_WIM:
452                 /* The resource is in a WIM file, and its WIMStruct is given by
453                  * the lte->wim member.  The resource may be either compressed
454                  * or uncompressed. */
455                 wimlib_assert(lte->wim != NULL);
456                 wimlib_assert(lte->wim->fp != NULL);
457                 ctype = wim_resource_compression_type(lte);
458
459                 wimlib_assert(ctype != WIM_COMPRESSION_TYPE_NONE ||
460                               (lte->resource_entry.original_size ==
461                                lte->resource_entry.size));
462
463                 if (raw || ctype == WIM_COMPRESSION_TYPE_NONE)
464                         ret = read_uncompressed_resource(lte->wim->fp,
465                                                          lte->resource_entry.offset + offset,
466                                                          size, buf);
467                 else
468                         ret = read_compressed_resource(lte->wim->fp,
469                                                        lte->resource_entry.size,
470                                                        lte->resource_entry.original_size,
471                                                        lte->resource_entry.offset,
472                                                        ctype, size, offset, buf);
473                 break;
474         case RESOURCE_IN_STAGING_FILE:
475         case RESOURCE_IN_FILE_ON_DISK:
476                 /* The resource is in some file on the external filesystem and
477                  * needs to be read uncompressed */
478                 wimlib_assert(lte->file_on_disk);
479                 wimlib_assert(&lte->file_on_disk == &lte->staging_file_name);
480                 /* Use existing file pointer if available; otherwise open one
481                  * temporarily */
482                 if (lte->file_on_disk_fp) {
483                         fp = lte->file_on_disk_fp;
484                 } else {
485                         fp = fopen(lte->file_on_disk, "rb");
486                         if (!fp) {
487                                 ERROR_WITH_ERRNO("Failed to open the file "
488                                                  "`%s'", lte->file_on_disk);
489                                 ret = WIMLIB_ERR_OPEN;
490                                 break;
491                         }
492                 }
493                 ret = read_uncompressed_resource(fp, offset, size, buf);
494                 if (fp != lte->file_on_disk_fp)
495                         fclose(fp);
496                 break;
497         case RESOURCE_IN_ATTACHED_BUFFER:
498                 /* The resource is directly attached uncompressed in an
499                  * in-memory buffer. */
500                 wimlib_assert(lte->attached_buffer != NULL);
501                 memcpy(buf, lte->attached_buffer + offset, size);
502                 break;
503 #ifdef WITH_NTFS_3G
504         case RESOURCE_IN_NTFS_VOLUME:
505                 wimlib_assert(lte->ntfs_loc != NULL);
506                 wimlib_assert(lte->attr != NULL);
507                 {
508                         if (lte->ntfs_loc->is_reparse_point)
509                                 offset += 8;
510                         if (ntfs_attr_pread(lte->attr, offset, size, buf) != size) {
511                                 ERROR_WITH_ERRNO("Error reading NTFS attribute "
512                                                  "at `%s'",
513                                                  lte->ntfs_loc->path_utf8);
514                                 ret = WIMLIB_ERR_NTFS_3G;
515                         }
516                         break;
517                 }
518 #endif
519         default:
520                 wimlib_assert(0);
521                 ret = -1;
522                 break;
523         }
524         return ret;
525 }
526
527 /*
528  * Reads all the data from the resource corresponding to a WIM lookup table
529  * entry.
530  *
531  * @lte:        The WIM lookup table entry for the resource.
532  * @buf:        Buffer into which to write the data.  It must be at least
533  *              wim_resource_size(lte) bytes long.
534  *
535  * Returns 0 on success; nonzero on failure.
536  */
537 int read_full_wim_resource(const struct lookup_table_entry *lte, u8 buf[])
538 {
539         return read_wim_resource(lte, buf, wim_resource_size(lte), 0, false);
540 }
541
542 /* Chunk table that's located at the beginning of each compressed resource in
543  * the WIM.  (This is not the on-disk format; the on-disk format just has an
544  * array of offsets.) */
545 struct chunk_table {
546         off_t file_offset;
547         u64 num_chunks;
548         u64 original_resource_size;
549         u64 bytes_per_chunk_entry;
550         u64 table_disk_size;
551         u64 cur_offset;
552         u64 *cur_offset_p;
553         u64 offsets[0];
554 };
555
556 /*
557  * Allocates and initializes a chunk table, and reserves space for it in the
558  * output file.
559  */
560 static int
561 begin_wim_resource_chunk_tab(const struct lookup_table_entry *lte,
562                              FILE *out_fp,
563                              off_t file_offset,
564                              struct chunk_table **chunk_tab_ret)
565 {
566         u64 size = wim_resource_size(lte);
567         u64 num_chunks = (size + WIM_CHUNK_SIZE - 1) / WIM_CHUNK_SIZE;
568         size_t alloc_size = sizeof(struct chunk_table) + num_chunks * sizeof(u64);
569         struct chunk_table *chunk_tab = CALLOC(1, alloc_size);
570         int ret;
571
572         if (!chunk_tab) {
573                 ERROR("Failed to allocate chunk table for %"PRIu64" byte "
574                       "resource", size);
575                 ret = WIMLIB_ERR_NOMEM;
576                 goto out;
577         }
578         chunk_tab->file_offset = file_offset;
579         chunk_tab->num_chunks = num_chunks;
580         chunk_tab->original_resource_size = size;
581         chunk_tab->bytes_per_chunk_entry = (size >= (1ULL << 32)) ? 8 : 4;
582         chunk_tab->table_disk_size = chunk_tab->bytes_per_chunk_entry *
583                                      (num_chunks - 1);
584         chunk_tab->cur_offset = 0;
585         chunk_tab->cur_offset_p = chunk_tab->offsets;
586
587         if (fwrite(chunk_tab, 1, chunk_tab->table_disk_size, out_fp) !=
588                    chunk_tab->table_disk_size) {
589                 ERROR_WITH_ERRNO("Failed to write chunk table in compressed "
590                                  "file resource");
591                 ret = WIMLIB_ERR_WRITE;
592                 goto out;
593         }
594
595         ret = 0;
596 out:
597         *chunk_tab_ret = chunk_tab;
598         return ret;
599 }
600
601 /*
602  * Compresses a chunk of a WIM resource.
603  *
604  * @chunk:              Uncompressed data of the chunk.
605  * @chunk_size:         Size of the uncompressed chunk in bytes.
606  * @compressed_chunk:   Pointer to output buffer of size at least
607  *                              (@chunk_size - 1) bytes.
608  * @compressed_chunk_len_ret:   Pointer to an unsigned int into which the size
609  *                                      of the compressed chunk will be
610  *                                      returned.
611  * @ctype:      Type of compression to use.  Must be WIM_COMPRESSION_TYPE_LZX
612  *              or WIM_COMPRESSION_TYPE_XPRESS.
613  *
614  * Returns zero if compressed succeeded, and nonzero if the chunk could not be
615  * compressed to any smaller than @chunk_size.  This function cannot fail for
616  * any other reasons.
617  */
618 static int compress_chunk(const u8 chunk[], unsigned chunk_size,
619                           u8 compressed_chunk[],
620                           unsigned *compressed_chunk_len_ret,
621                           int ctype)
622 {
623         int (*compress)(const void *, unsigned, void *, unsigned *);
624         switch (ctype) {
625         case WIM_COMPRESSION_TYPE_LZX:
626                 compress = lzx_compress;
627                 break;
628         case WIM_COMPRESSION_TYPE_XPRESS:
629                 compress = xpress_compress;
630                 break;
631         default:
632                 wimlib_assert(0);
633                 break;
634         }
635         return (*compress)(chunk, chunk_size, compressed_chunk,
636                            compressed_chunk_len_ret);
637 }
638
639 /*
640  * Writes a chunk of a WIM resource to an output file.
641  *
642  * @chunk:        Uncompressed data of the chunk.
643  * @chunk_size:   Size of the chunk (<= WIM_CHUNK_SIZE)
644  * @out_fp:       FILE * to write tho chunk to.
645  * @out_ctype:    Compression type to use when writing the chunk (ignored if no
646  *                      chunk table provided)
647  * @chunk_tab:    Pointer to chunk table being created.  It is updated with the
648  *                      offset of the chunk we write.
649  *
650  * Returns 0 on success; nonzero on failure.
651  */
652 static int write_wim_resource_chunk(const u8 chunk[], unsigned chunk_size,
653                                     FILE *out_fp, int out_ctype,
654                                     struct chunk_table *chunk_tab)
655 {
656         const u8 *out_chunk;
657         unsigned out_chunk_size;
658
659         wimlib_assert(chunk_size <= WIM_CHUNK_SIZE);
660
661         if (!chunk_tab) {
662                 out_chunk = chunk;
663                 out_chunk_size = chunk_size;
664         } else {
665                 u8 *compressed_chunk = alloca(chunk_size);
666                 int ret;
667
668                 ret = compress_chunk(chunk, chunk_size, compressed_chunk,
669                                      &out_chunk_size, out_ctype);
670                 if (ret == 0) {
671                         out_chunk = compressed_chunk;
672                 } else {
673                         out_chunk = chunk;
674                         out_chunk_size = chunk_size;
675                 }
676                 *chunk_tab->cur_offset_p++ = chunk_tab->cur_offset;
677                 chunk_tab->cur_offset += out_chunk_size;
678         }
679
680         if (fwrite(out_chunk, 1, out_chunk_size, out_fp) != out_chunk_size) {
681                 ERROR_WITH_ERRNO("Failed to write WIM resource chunk");
682                 return WIMLIB_ERR_WRITE;
683         }
684         return 0;
685 }
686
687 /*
688  * Finishes a WIM chunk tale and writes it to the output file at the correct
689  * offset.
690  *
691  * The final size of the full compressed resource is returned in the
692  * @compressed_size_p.
693  */
694 static int
695 finish_wim_resource_chunk_tab(struct chunk_table *chunk_tab,
696                               FILE *out_fp, u64 *compressed_size_p)
697 {
698         size_t bytes_written;
699         if (fseeko(out_fp, chunk_tab->file_offset, SEEK_SET) != 0) {
700                 ERROR_WITH_ERRNO("Failed to seek to byte %"PRIu64" of output "
701                                  "WIM file", chunk_tab->file_offset);
702                 return WIMLIB_ERR_WRITE;
703         }
704
705         if (chunk_tab->bytes_per_chunk_entry == 8) {
706                 array_cpu_to_le64(chunk_tab->offsets, chunk_tab->num_chunks);
707         } else {
708                 for (u64 i = 0; i < chunk_tab->num_chunks; i++)
709                         ((u32*)chunk_tab->offsets)[i] =
710                                 cpu_to_le32(chunk_tab->offsets[i]);
711         }
712         bytes_written = fwrite((u8*)chunk_tab->offsets +
713                                         chunk_tab->bytes_per_chunk_entry,
714                                1, chunk_tab->table_disk_size, out_fp);
715         if (bytes_written != chunk_tab->table_disk_size) {
716                 ERROR_WITH_ERRNO("Failed to write chunk table in compressed "
717                                  "file resource");
718                 return WIMLIB_ERR_WRITE;
719         }
720         if (fseeko(out_fp, 0, SEEK_END) != 0) {
721                 ERROR_WITH_ERRNO("Failed to seek to end of output WIM file");
722                 return WIMLIB_ERR_WRITE;
723         }
724         *compressed_size_p = chunk_tab->cur_offset + chunk_tab->table_disk_size;
725         return 0;
726 }
727
728 /*
729  * Writes a WIM resource to a FILE * opened for writing.  The resource may be
730  * written uncompressed or compressed depending on the @out_ctype parameter.
731  *
732  * If by chance the resource compresses to more than the original size (this may
733  * happen with random data or files than are pre-compressed), the resource is
734  * instead written uncompressed (and this is reflected in the @out_res_entry by
735  * removing the WIM_RESHDR_FLAG_COMPRESSED flag).
736  *
737  * @lte:        The lookup table entry for the WIM resource.
738  * @out_fp:     The FILE * to write the resource to.
739  * @out_ctype:  The compression type of the resource to write.  Note: if this is
740  *                      the same as the compression type of the WIM resource we
741  *                      need to read, we simply copy the data (i.e. we do not
742  *                      uncompress it, then compress it again).
743  * @out_res_entry:  If non-NULL, a resource entry that is filled in with the
744  *                  offset, original size, compressed size, and compression flag
745  *                  of the output resource.
746  *
747  * Returns 0 on success; nonzero on failure.
748  */
749 static int write_wim_resource(struct lookup_table_entry *lte,
750                               FILE *out_fp, int out_ctype,
751                               struct resource_entry *out_res_entry)
752 {
753         u64 bytes_remaining;
754         u64 original_size;
755         u64 old_compressed_size;
756         u64 new_compressed_size;
757         u64 offset;
758         int ret;
759         struct chunk_table *chunk_tab = NULL;
760         bool raw;
761         off_t file_offset;
762 #ifdef WITH_NTFS_3G
763         ntfs_inode *ni = NULL;
764 #endif
765
766         wimlib_assert(lte);
767
768         /* Original size of the resource */
769         original_size = wim_resource_size(lte);
770
771         /* Compressed size of the resource (as it exists now) */
772         old_compressed_size = wim_resource_compressed_size(lte);
773
774         /* Current offset in output file */
775         file_offset = ftello(out_fp);
776         if (file_offset == -1) {
777                 ERROR_WITH_ERRNO("Failed to get offset in output "
778                                  "stream");
779                 return WIMLIB_ERR_WRITE;
780         }
781
782         /* Are the compression types the same?  If so, do a raw copy (copy
783          * without decompressing and recompressing the data). */
784         raw = (wim_resource_compression_type(lte) == out_ctype
785                && out_ctype != WIM_COMPRESSION_TYPE_NONE);
786         if (raw)
787                 bytes_remaining = old_compressed_size;
788         else
789                 bytes_remaining = original_size;
790
791         /* Empty resource; nothing needs to be done, so just return success. */
792         if (bytes_remaining == 0)
793                 return 0;
794
795         /* Buffer for reading chunks for the resource */
796         u8 buf[min(WIM_CHUNK_SIZE, bytes_remaining)];
797
798         /* If we are writing a compressed resource and not doing a raw copy, we
799          * need to initialize the chunk table */
800         if (out_ctype != WIM_COMPRESSION_TYPE_NONE && !raw) {
801                 ret = begin_wim_resource_chunk_tab(lte, out_fp, file_offset,
802                                                    &chunk_tab);
803                 if (ret != 0)
804                         goto out;
805         }
806
807         /* If the WIM resource is in an external file, open a FILE * to it so we
808          * don't have to open a temporary one in read_wim_resource() for each
809          * chunk. */
810         if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK
811              && !lte->file_on_disk_fp)
812         {
813                 wimlib_assert(lte->file_on_disk);
814                 lte->file_on_disk_fp = fopen(lte->file_on_disk, "rb");
815                 if (!lte->file_on_disk_fp) {
816                         ERROR_WITH_ERRNO("Failed to open the file `%s' for "
817                                          "reading", lte->file_on_disk);
818                         ret = WIMLIB_ERR_OPEN;
819                         goto out;
820                 }
821         }
822 #ifdef WITH_NTFS_3G
823         else if (lte->resource_location == RESOURCE_IN_NTFS_VOLUME
824                   && !lte->attr)
825         {
826                 struct ntfs_location *loc = lte->ntfs_loc;
827                 wimlib_assert(loc);
828                 ni = ntfs_pathname_to_inode(*loc->ntfs_vol_p, NULL, loc->path_utf8);
829                 if (!ni) {
830                         ERROR_WITH_ERRNO("Failed to open inode `%s' in NTFS "
831                                          "volume", loc->path_utf8);
832                         ret = WIMLIB_ERR_NTFS_3G;
833                         goto out;
834                 }
835                 lte->attr = ntfs_attr_open(ni,
836                                            loc->is_reparse_point ? AT_REPARSE_POINT : AT_DATA,
837                                            (ntfschar*)loc->stream_name_utf16,
838                                            loc->stream_name_utf16_num_chars);
839                 if (!lte->attr) {
840                         ERROR_WITH_ERRNO("Failed to open attribute of `%s' in "
841                                          "NTFS volume", loc->path_utf8);
842                         ret = WIMLIB_ERR_NTFS_3G;
843                         goto out_fclose;
844                 }
845         }
846 #endif
847
848         /* If we aren't doing a raw copy, we will compute the SHA1 message
849          * digest of the resource as we read it, and verify it's the same as the
850          * hash given in the lookup table entry once we've finished reading the
851          * resource. */
852         SHA_CTX ctx;
853         if (!raw)
854                 sha1_init(&ctx);
855
856         /* While there are still bytes remaining in the WIM resource, read a
857          * chunk of the resource, update SHA1, then write that chunk using the
858          * desired compression type. */
859         offset = 0;
860         do {
861                 u64 to_read = min(bytes_remaining, WIM_CHUNK_SIZE);
862                 ret = read_wim_resource(lte, buf, to_read, offset, raw);
863                 if (ret != 0)
864                         goto out_fclose;
865                 if (!raw)
866                         sha1_update(&ctx, buf, to_read);
867                 ret = write_wim_resource_chunk(buf, to_read, out_fp,
868                                                out_ctype, chunk_tab);
869                 if (ret != 0)
870                         goto out_fclose;
871                 bytes_remaining -= to_read;
872                 offset += to_read;
873         } while (bytes_remaining);
874
875         /* Raw copy:  The new compressed size is the same as the old compressed
876          * size
877          *
878          * Using WIM_COMPRESSION_TYPE_NONE:  The new compressed size is the
879          * original size
880          *
881          * Using a different compression type:  Call
882          * finish_wim_resource_chunk_tab() and it will provide the new
883          * compressed size.
884          */
885         if (raw) {
886                 new_compressed_size = old_compressed_size;
887         } else {
888                 if (out_ctype == WIM_COMPRESSION_TYPE_NONE)
889                         new_compressed_size = original_size;
890                 else {
891                         ret = finish_wim_resource_chunk_tab(chunk_tab, out_fp,
892                                                             &new_compressed_size);
893                         if (ret != 0)
894                                 goto out_fclose;
895                 }
896         }
897
898         /* Verify SHA1 message digest of the resource, unless we are doing a raw
899          * write (in which case we never even saw the uncompressed data).  Or,
900          * if the hash we had before is all 0's, just re-set it to be the new
901          * hash. */
902         if (!raw) {
903                 u8 md[SHA1_HASH_SIZE];
904                 sha1_final(md, &ctx);
905                 if (is_zero_hash(lte->hash)) {
906                         copy_hash(lte->hash, md);
907                 } else if (!hashes_equal(md, lte->hash)) {
908                         ERROR("WIM resource has incorrect hash!");
909                         if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK) {
910                                 ERROR("We were reading it from `%s'; maybe it changed "
911                                       "while we were reading it.",
912                                       lte->file_on_disk);
913                         }
914                         ret = WIMLIB_ERR_INVALID_RESOURCE_HASH;
915                         goto out_fclose;
916                 }
917         }
918
919         if (!raw && new_compressed_size >= original_size &&
920             out_ctype != WIM_COMPRESSION_TYPE_NONE)
921         {
922                 /* Oops!  We compressed the resource to larger than the original
923                  * size.  Write the resource uncompressed instead. */
924                 if (fseeko(out_fp, file_offset, SEEK_SET) != 0) {
925                         ERROR_WITH_ERRNO("Failed to seek to byte %"PRIu64" "
926                                          "of output WIM file", file_offset);
927                         ret = WIMLIB_ERR_WRITE;
928                         goto out_fclose;
929                 }
930                 ret = write_wim_resource(lte, out_fp, WIM_COMPRESSION_TYPE_NONE,
931                                          out_res_entry);
932                 if (ret != 0)
933                         goto out_fclose;
934                 if (fflush(out_fp) != 0) {
935                         ERROR_WITH_ERRNO("Failed to flush output WIM file");
936                         ret = WIMLIB_ERR_WRITE;
937                         goto out_fclose;
938                 }
939                 if (ftruncate(fileno(out_fp), file_offset + out_res_entry->size) != 0) {
940                         ERROR_WITH_ERRNO("Failed to truncate output WIM file");
941                         ret = WIMLIB_ERR_WRITE;
942                         goto out_fclose;
943                 }
944         } else {
945                 if (out_res_entry) {
946                         out_res_entry->size          = new_compressed_size;
947                         out_res_entry->original_size = original_size;
948                         out_res_entry->offset        = file_offset;
949                         out_res_entry->flags         = lte->resource_entry.flags
950                                                         & ~WIM_RESHDR_FLAG_COMPRESSED;
951                         if (out_ctype != WIM_COMPRESSION_TYPE_NONE)
952                                 out_res_entry->flags |= WIM_RESHDR_FLAG_COMPRESSED;
953                 }
954         }
955         ret = 0;
956 out_fclose:
957         if (lte->resource_location == RESOURCE_IN_FILE_ON_DISK
958             && lte->file_on_disk_fp) {
959                 fclose(lte->file_on_disk_fp);
960                 lte->file_on_disk_fp = NULL;
961         }
962 #ifdef WITH_NTFS_3G
963         else if (lte->resource_location == RESOURCE_IN_NTFS_VOLUME) {
964                 if (lte->attr) {
965                         ntfs_attr_close(lte->attr);
966                         lte->attr = NULL;
967                 }
968                 if (ni)
969                         ntfs_inode_close(ni);
970         }
971 #endif
972 out:
973         FREE(chunk_tab);
974         return ret;
975 }
976
977 /* Like write_wim_resource(), but the resource is specified by a buffer of
978  * uncompressed data rather a lookup table entry; also writes the SHA1 hash of
979  * the buffer to @hash.  */
980 static int write_wim_resource_from_buffer(const u8 *buf, u64 buf_size,
981                                           FILE *out_fp, int out_ctype,
982                                           struct resource_entry *out_res_entry,
983                                           u8 hash[SHA1_HASH_SIZE])
984 {
985         /* Set up a temporary lookup table entry to provide to
986          * write_wim_resource(). */
987         struct lookup_table_entry lte;
988         int ret;
989         lte.resource_entry.flags         = 0;
990         lte.resource_entry.original_size = buf_size;
991         lte.resource_entry.size          = buf_size;
992         lte.resource_entry.offset        = 0;
993         lte.resource_location            = RESOURCE_IN_ATTACHED_BUFFER;
994         lte.attached_buffer              = (u8*)buf;
995
996         zero_out_hash(lte.hash);
997         ret = write_wim_resource(&lte, out_fp, out_ctype, out_res_entry);
998         if (ret != 0)
999                 return ret;
1000         copy_hash(hash, lte.hash);
1001         return 0;
1002 }
1003
1004 /*
1005  * Extracts the first @size bytes of the WIM resource specified by @lte to the
1006  * open file descriptor @fd.
1007  *
1008  * Returns 0 on success; nonzero on failure.
1009  */
1010 int extract_wim_resource_to_fd(const struct lookup_table_entry *lte, int fd,
1011                                u64 size)
1012 {
1013         u64 bytes_remaining = size;
1014         u8 buf[min(WIM_CHUNK_SIZE, bytes_remaining)];
1015         u64 offset = 0;
1016         int ret = 0;
1017         u8 hash[SHA1_HASH_SIZE];
1018
1019         SHA_CTX ctx;
1020         sha1_init(&ctx);
1021
1022         while (bytes_remaining) {
1023                 u64 to_read = min(bytes_remaining, WIM_CHUNK_SIZE);
1024                 ret = read_wim_resource(lte, buf, to_read, offset, false);
1025                 if (ret != 0)
1026                         break;
1027                 sha1_update(&ctx, buf, to_read);
1028                 if (full_write(fd, buf, to_read) < to_read) {
1029                         ERROR_WITH_ERRNO("Error extracting WIM resource");
1030                         return WIMLIB_ERR_WRITE;
1031                 }
1032                 bytes_remaining -= to_read;
1033                 offset += to_read;
1034         }
1035         sha1_final(hash, &ctx);
1036         if (!hashes_equal(hash, lte->hash)) {
1037                 ERROR("Invalid checksum on a WIM resource "
1038                       "(detected when extracting to external file)");
1039                 ERROR("The following WIM resource is invalid:");
1040                 print_lookup_table_entry(lte);
1041                 return WIMLIB_ERR_INVALID_RESOURCE_HASH;
1042         }
1043         return 0;
1044 }
1045
1046 /*
1047  * Extracts the WIM resource specified by @lte to the open file descriptor @fd.
1048  *
1049  * Returns 0 on success; nonzero on failure.
1050  */
1051 int extract_full_wim_resource_to_fd(const struct lookup_table_entry *lte, int fd)
1052 {
1053         return extract_wim_resource_to_fd(lte, fd, wim_resource_size(lte));
1054 }
1055
1056 /*
1057  * Copies the file resource specified by the lookup table entry @lte from the
1058  * input WIM to the output WIM that has its FILE * given by
1059  * ((WIMStruct*)wim)->out_fp.
1060  *
1061  * The output_resource_entry, out_refcnt, and part_number fields of @lte are
1062  * updated.
1063  *
1064  * Metadata resources are not copied (they are handled elsewhere for joining and
1065  * splitting).
1066  */
1067 int copy_resource(struct lookup_table_entry *lte, void *wim)
1068 {
1069         WIMStruct *w = wim;
1070         int ret;
1071
1072         if ((lte->resource_entry.flags & WIM_RESHDR_FLAG_METADATA) &&
1073             !w->write_metadata)
1074                 return 0;
1075
1076         ret = write_wim_resource(lte, w->out_fp,
1077                                  wim_resource_compression_type(lte),
1078                                  &lte->output_resource_entry);
1079         if (ret != 0)
1080                 return ret;
1081         lte->out_refcnt = lte->refcnt;
1082         lte->part_number = w->hdr.part_number;
1083         return 0;
1084 }
1085
1086 /*
1087  * Writes a dentry's resources, including the main file resource as well as all
1088  * alternate data streams, to the output file.
1089  *
1090  * @dentry:  The dentry for the file.
1091  * @wim_p:   A pointer to the WIMStruct containing @dentry.
1092  *
1093  * @return zero on success, nonzero on failure.
1094  */
1095 int write_dentry_resources(struct dentry *dentry, void *wim_p)
1096 {
1097         WIMStruct *w = wim_p;
1098         int ret = 0;
1099         struct lookup_table_entry *lte;
1100         int ctype = wimlib_get_compression_type(w);
1101
1102         if (w->write_flags & WIMLIB_WRITE_FLAG_VERBOSE) {
1103                 wimlib_assert(dentry->full_path_utf8);
1104                 printf("Writing streams for `%s'\n", dentry->full_path_utf8);
1105         }
1106
1107         for (unsigned i = 0; i <= dentry->d_inode->num_ads; i++) {
1108                 lte = inode_stream_lte(dentry->d_inode, i, w->lookup_table);
1109                 if (lte && ++lte->out_refcnt == 1) {
1110                         ret = write_wim_resource(lte, w->out_fp, ctype,
1111                                                  &lte->output_resource_entry);
1112                         if (ret != 0)
1113                                 break;
1114                 }
1115         }
1116         return ret;
1117 }
1118
1119 /*
1120  * Reads the metadata metadata resource from the WIM file.  The metadata
1121  * resource consists of the security data, followed by the directory entry for
1122  * the root directory, followed by all the other directory entries in the
1123  * filesystem.  The subdir_offset field of each directory entry gives the start
1124  * of its child entries from the beginning of the metadata resource.  An
1125  * end-of-directory is signaled by a directory entry of length '0', really of
1126  * length 8, because that's how long the 'length' field is.
1127  *
1128  * @fp:         The FILE* for the input WIM file.
1129  * @wim_ctype:  The compression type of the WIM file.
1130  * @imd:        Pointer to the image metadata structure.  Its `metadata_lte'
1131  *              member specifies the lookup table entry for the metadata
1132  *              resource.  The rest of the image metadata entry will be filled
1133  *              in by this function.
1134  *
1135  * @return:     Zero on success, nonzero on failure.
1136  */
1137 int read_metadata_resource(WIMStruct *w, struct image_metadata *imd)
1138 {
1139         u8 *buf;
1140         u32 dentry_offset;
1141         int ret;
1142         struct dentry *dentry;
1143         struct inode_table inode_tab;
1144         const struct lookup_table_entry *metadata_lte;
1145         u64 metadata_len;
1146         u64 metadata_offset;
1147         struct hlist_head inode_list;
1148
1149         metadata_lte = imd->metadata_lte;
1150         metadata_len = wim_resource_size(metadata_lte);
1151         metadata_offset = metadata_lte->resource_entry.offset;
1152
1153         DEBUG("Reading metadata resource: length = %"PRIu64", "
1154               "offset = %"PRIu64"", metadata_len, metadata_offset);
1155
1156         /* There is no way the metadata resource could possibly be less than (8
1157          * + WIM_DENTRY_DISK_SIZE) bytes, where the 8 is for security data (with
1158          * no security descriptors) and WIM_DENTRY_DISK_SIZE is for the root
1159          * dentry. */
1160         if (metadata_len < 8 + WIM_DENTRY_DISK_SIZE) {
1161                 ERROR("Expected at least %u bytes for the metadata resource",
1162                       8 + WIM_DENTRY_DISK_SIZE);
1163                 return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
1164         }
1165
1166         if (sizeof(size_t) < 8 && metadata_len > 0xffffffff) {
1167                 ERROR("Metadata resource is too large (%"PRIu64" bytes",
1168                       metadata_len);
1169                 return WIMLIB_ERR_INVALID_RESOURCE_SIZE;
1170         }
1171
1172         /* Allocate memory for the uncompressed metadata resource. */
1173         buf = MALLOC(metadata_len);
1174
1175         if (!buf) {
1176                 ERROR("Failed to allocate %"PRIu64" bytes for uncompressed "
1177                       "metadata resource", metadata_len);
1178                 return WIMLIB_ERR_NOMEM;
1179         }
1180
1181         /* Read the metadata resource into memory.  (It may be compressed.) */
1182         ret = read_full_wim_resource(metadata_lte, buf);
1183         if (ret != 0)
1184                 goto out_free_buf;
1185
1186         DEBUG("Finished reading metadata resource into memory.");
1187
1188         /* The root directory entry starts after security data, aligned on an
1189          * 8-byte boundary within the metadata resource.
1190          *
1191          * The security data starts with a 4-byte integer giving its total
1192          * length, so if we round that up to an 8-byte boundary that gives us
1193          * the offset of the root dentry.
1194          *
1195          * Here we read the security data into a wim_security_data structure,
1196          * and if successful, go ahead and calculate the offset in the metadata
1197          * resource of the root dentry. */
1198
1199         wimlib_assert(imd->security_data == NULL);
1200         ret = read_security_data(buf, metadata_len, &imd->security_data);
1201         if (ret != 0)
1202                 goto out_free_buf;
1203
1204         dentry_offset = (imd->security_data->total_length + 7) & ~7;
1205
1206         if (dentry_offset == 0) {
1207                 ERROR("Integer overflow while reading metadata resource");
1208                 ret = WIMLIB_ERR_INVALID_SECURITY_DATA;
1209                 goto out_free_security_data;
1210         }
1211
1212         /* Allocate memory for the root dentry and read it into memory */
1213         dentry = MALLOC(sizeof(struct dentry));
1214         if (!dentry) {
1215                 ERROR("Failed to allocate %zu bytes for root dentry",
1216                       sizeof(struct dentry));
1217                 ret = WIMLIB_ERR_NOMEM;
1218                 goto out_free_security_data;
1219         }
1220
1221         ret = read_dentry(buf, metadata_len, dentry_offset, dentry);
1222
1223         /* This is the root dentry, so set its parent to itself. */
1224         dentry->parent = dentry;
1225
1226         if (ret != 0)
1227                 goto out_free_dentry_tree;
1228         inode_add_dentry(dentry, dentry->d_inode);
1229
1230         /* Now read the entire directory entry tree into memory. */
1231         DEBUG("Reading dentry tree");
1232         ret = read_dentry_tree(buf, metadata_len, dentry);
1233         if (ret != 0)
1234                 goto out_free_dentry_tree;
1235
1236         /* Calculate the full paths in the dentry tree. */
1237         DEBUG("Calculating dentry full paths");
1238         ret = for_dentry_in_tree(dentry, calculate_dentry_full_path, NULL);
1239         if (ret != 0)
1240                 goto out_free_dentry_tree;
1241
1242         /* Build hash table that maps hard link group IDs to dentry sets */
1243         DEBUG("Building link group table");
1244         ret = init_inode_table(&inode_tab, 9001);
1245         if (ret != 0)
1246                 goto out_free_dentry_tree;
1247
1248         for_dentry_in_tree(dentry, inode_table_insert, &inode_tab);
1249
1250         DEBUG("Fixing inconsistencies in the hard link groups");
1251         ret = fix_inodes(&inode_tab, &inode_list);
1252         destroy_inode_table(&inode_tab);
1253         if (ret != 0)
1254                 goto out_free_dentry_tree;
1255
1256         DEBUG("Running miscellaneous verifications on the dentry tree");
1257         for_lookup_table_entry(w->lookup_table, lte_zero_real_refcnt, NULL);
1258         ret = for_dentry_in_tree(dentry, verify_dentry, w);
1259         if (ret != 0)
1260                 goto out_free_dentry_tree;
1261
1262         DEBUG("Done reading image metadata");
1263
1264         imd->root_dentry = dentry;
1265         imd->inode_list  = inode_list;
1266         goto out_free_buf;
1267 out_free_dentry_tree:
1268         free_dentry_tree(dentry, NULL);
1269 out_free_security_data:
1270         free_security_data(imd->security_data);
1271         imd->security_data = NULL;
1272 out_free_buf:
1273         FREE(buf);
1274         return ret;
1275 }
1276
1277 /* Write the metadata resource for the current WIM image. */
1278 int write_metadata_resource(WIMStruct *w)
1279 {
1280         u8 *buf;
1281         u8 *p;
1282         int ret;
1283         u64 subdir_offset;
1284         struct dentry *root;
1285         struct lookup_table_entry *lte;
1286         u64 metadata_original_size;
1287         const struct wim_security_data *sd;
1288
1289         DEBUG("Writing metadata resource for image %d", w->current_image);
1290
1291         root = wim_root_dentry(w);
1292         sd = wim_security_data(w);
1293
1294         /* We do not allow the security data pointer to be NULL, although it may
1295          * point to an empty security data with no entries. */
1296         wimlib_assert(root != NULL);
1297         wimlib_assert(sd != NULL);
1298
1299         /* Offset of first child of the root dentry.  It's equal to:
1300          * - The total length of the security data, rounded to the next 8-byte
1301          *   boundary,
1302          * - plus the total length of the root dentry,
1303          * - plus 8 bytes for an end-of-directory entry following the root
1304          *   dentry (shouldn't really be needed, but just in case...)
1305          */
1306         subdir_offset = ((sd->total_length + 7) & ~7) +
1307                         dentry_correct_total_length(root) + 8;
1308
1309         /* Calculate the subdirectory offsets for the entire dentry tree. */
1310         calculate_subdir_offsets(root, &subdir_offset);
1311
1312         /* Total length of the metadata resource (uncompressed) */
1313         metadata_original_size = subdir_offset;
1314
1315         /* Allocate a buffer to contain the uncompressed metadata resource */
1316         buf = MALLOC(metadata_original_size);
1317         if (!buf) {
1318                 ERROR("Failed to allocate %"PRIu64" bytes for "
1319                       "metadata resource", metadata_original_size);
1320                 return WIMLIB_ERR_NOMEM;
1321         }
1322
1323         /* Write the security data into the resource buffer */
1324         p = write_security_data(sd, buf);
1325
1326         /* Write the dentry tree into the resource buffer */
1327         p = write_dentry_tree(root, p);
1328
1329         /* We MUST have exactly filled the buffer; otherwise we calculated its
1330          * size incorrectly or wrote the data incorrectly. */
1331         wimlib_assert(p - buf == metadata_original_size);
1332
1333         /* Get the lookup table entry for the metadata resource so we can update
1334          * it. */
1335         lte = wim_metadata_lookup_table_entry(w);
1336
1337         wimlib_assert(lte != NULL);
1338
1339         /* Write the metadata resource to the output WIM using the proper
1340          * compression type.  The lookup table entry for the metadata resource
1341          * is updated. */
1342         ret = write_wim_resource_from_buffer(buf, metadata_original_size,
1343                                              w->out_fp,
1344                                              wimlib_get_compression_type(w),
1345                                              &lte->output_resource_entry,
1346                                              lte->hash);
1347         if (ret != 0)
1348                 goto out;
1349
1350         /* It's very likely the SHA1 message digest of the metadata resource
1351          * changed, so re-insert the lookup table entry into the lookup table.
1352          *
1353          * We do not check for other lookup table entries having the same SHA1
1354          * message digest.  It's possible for 2 absolutely identical images to
1355          * be added, therefore causing 2 identical metadata resources to be in
1356          * the WIM.  However, in this case, it's expected for 2 separate lookup
1357          * table entries to be created, even though this doesn't make a whole
1358          * lot of sense since they will share the same SHA1 message digest.
1359          * */
1360         lookup_table_unlink(w->lookup_table, lte);
1361         lookup_table_insert(w->lookup_table, lte);
1362
1363         wimlib_assert(lte->out_refcnt == 0);
1364         lte->out_refcnt = 1;
1365
1366         /* Make sure that the resource entry is written marked with the metadata
1367          * flag. */
1368         lte->output_resource_entry.flags |= WIM_RESHDR_FLAG_METADATA;
1369 out:
1370         /* All the data has been written to the new WIM; no need for the buffer
1371          * anymore */
1372         FREE(buf);
1373         return ret;
1374 }