]> wimlib.net Git - wimlib/blob - src/resource.c
e2a39991e2e4115a121134a67ac1046cbff22f8f
[wimlib] / src / resource.c
1 /*
2  * resource.c
3  *
4  * Code for reading blobs and resources, including compressed WIM resources.
5  */
6
7 /*
8  * Copyright (C) 2012, 2013, 2015 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 <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31
32 #include "wimlib/alloca.h"
33 #include "wimlib/assert.h"
34 #include "wimlib/bitops.h"
35 #include "wimlib/blob_table.h"
36 #include "wimlib/endianness.h"
37 #include "wimlib/error.h"
38 #include "wimlib/file_io.h"
39 #include "wimlib/ntfs_3g.h"
40 #include "wimlib/resource.h"
41 #include "wimlib/sha1.h"
42 #include "wimlib/wim.h"
43 #include "wimlib/win32.h"
44
45 /*
46  *                         Compressed WIM resources
47  *
48  * A compressed resource in a WIM consists of a number of compressed chunks,
49  * each of which decompresses to a fixed chunk size (given in the WIM header;
50  * usually 32768) except possibly the last, which always decompresses to any
51  * remaining bytes.  In addition, immediately before the chunks, a table (the
52  * "chunk table") provides the offset, in bytes relative to the end of the chunk
53  * table, of the start of each compressed chunk, except for the first chunk
54  * which is omitted as it always has an offset of 0.  Therefore, a compressed
55  * resource with N chunks will have a chunk table with N - 1 entries.
56  *
57  * Additional information:
58  *
59  * - Entries in the chunk table are 4 bytes each, except if the uncompressed
60  *   size of the resource is greater than 4 GiB, in which case the entries in
61  *   the chunk table are 8 bytes each.  In either case, the entries are unsigned
62  *   little-endian integers.
63  *
64  * - The chunk table is included in the compressed size of the resource provided
65  *   in the corresponding entry in the WIM's blob table.
66  *
67  * - The compressed size of a chunk is never greater than the uncompressed size.
68  *   From the compressor's point of view, chunks that would have compressed to a
69  *   size greater than or equal to their original size are in fact stored
70  *   uncompressed.  From the decompresser's point of view, chunks with
71  *   compressed size equal to their uncompressed size are in fact uncompressed.
72  *
73  * Furthermore, wimlib supports its own "pipable" WIM format, and for this the
74  * structure of compressed resources was modified to allow piped reading and
75  * writing.  To make sequential writing possible, the chunk table is placed
76  * after the chunks rather than before the chunks, and to make sequential
77  * reading possible, each chunk is prefixed with a 4-byte header giving its
78  * compressed size as a 32-bit, unsigned, little-endian integer.  Otherwise the
79  * details are the same.
80  */
81
82
83 struct data_range {
84         u64 offset;
85         u64 size;
86 };
87
88 /*
89  * read_compressed_wim_resource() -
90  *
91  * Read data from a compressed WIM resource.
92  *
93  * @rdesc
94  *      Description of the compressed WIM resource to read from.
95  * @ranges
96  *      Nonoverlapping, nonempty ranges of the uncompressed resource data to
97  *      read, sorted by increasing offset.
98  * @num_ranges
99  *      Number of ranges in @ranges; must be at least 1.
100  * @cb
101  *      Callback function to feed the data being read.  Each call provides the
102  *      next chunk of the requested data, uncompressed.  Each chunk will be of
103  *      nonzero size and will not cross range boundaries, but otherwise will be
104  *      of unspecified size.
105  * @cb_ctx
106  *      Parameter to pass to @cb_ctx.
107  *
108  * Possible return values:
109  *
110  *      WIMLIB_ERR_SUCCESS (0)
111  *      WIMLIB_ERR_READ                   (errno set)
112  *      WIMLIB_ERR_UNEXPECTED_END_OF_FILE (errno set to 0)
113  *      WIMLIB_ERR_NOMEM                  (errno set to ENOMEM)
114  *      WIMLIB_ERR_DECOMPRESSION          (errno set to EINVAL)
115  *
116  *      or other error code returned by the @cb function.
117  */
118 static int
119 read_compressed_wim_resource(const struct wim_resource_descriptor * const rdesc,
120                              const struct data_range * const ranges,
121                              const size_t num_ranges,
122                              const consume_data_callback_t cb,
123                              void * const cb_ctx)
124 {
125         int ret;
126         int errno_save;
127
128         u64 *chunk_offsets = NULL;
129         u8 *ubuf = NULL;
130         void *cbuf = NULL;
131         bool chunk_offsets_malloced = false;
132         bool ubuf_malloced = false;
133         bool cbuf_malloced = false;
134         struct wimlib_decompressor *decompressor = NULL;
135
136         /* Sanity checks  */
137         wimlib_assert(rdesc != NULL);
138         wimlib_assert(resource_is_compressed(rdesc));
139         wimlib_assert(cb != NULL);
140         wimlib_assert(num_ranges != 0);
141         for (size_t i = 0; i < num_ranges; i++) {
142                 DEBUG("Range %zu/%zu: %"PRIu64"@+%"PRIu64" / %"PRIu64,
143                       i + 1, num_ranges, ranges[i].size, ranges[i].offset,
144                       rdesc->uncompressed_size);
145                 wimlib_assert(ranges[i].size != 0);
146                 wimlib_assert(ranges[i].offset + ranges[i].size >= ranges[i].size);
147                 wimlib_assert(ranges[i].offset + ranges[i].size <= rdesc->uncompressed_size);
148         }
149         for (size_t i = 0; i < num_ranges - 1; i++)
150                 wimlib_assert(ranges[i].offset + ranges[i].size <= ranges[i + 1].offset);
151
152         /* Get the offsets of the first and last bytes of the read.  */
153         const u64 first_offset = ranges[0].offset;
154         const u64 last_offset = ranges[num_ranges - 1].offset + ranges[num_ranges - 1].size - 1;
155
156         /* Get the file descriptor for the WIM.  */
157         struct filedes * const in_fd = &rdesc->wim->in_fd;
158
159         /* Determine if we're reading a pipable resource from a pipe or not.  */
160         const bool is_pipe_read = (rdesc->is_pipable && !filedes_is_seekable(in_fd));
161
162         /* Determine if the chunk table is in an alternate format.  */
163         const bool alt_chunk_table = (rdesc->flags & WIM_RESHDR_FLAG_SOLID)
164                                         && !is_pipe_read;
165
166         /* Get the maximum size of uncompressed chunks in this resource, which
167          * we require be a power of 2.  */
168         u64 cur_read_offset = rdesc->offset_in_wim;
169         int ctype = rdesc->compression_type;
170         u32 chunk_size = rdesc->chunk_size;
171         if (alt_chunk_table) {
172                 /* Alternate chunk table format.  Its header specifies the chunk
173                  * size and compression format.  Note: it could be read here;
174                  * however, the relevant data was already loaded into @rdesc by
175                  * read_blob_table().  */
176                 cur_read_offset += sizeof(struct alt_chunk_table_header_disk);
177         }
178
179         if (!is_power_of_2(chunk_size)) {
180                 ERROR("Invalid compressed resource: "
181                       "expected power-of-2 chunk size (got %"PRIu32")",
182                       chunk_size);
183                 ret = WIMLIB_ERR_INVALID_CHUNK_SIZE;
184                 errno = EINVAL;
185                 goto out_free_memory;
186         }
187
188         /* Get valid decompressor.  */
189         if (ctype == rdesc->wim->decompressor_ctype &&
190             chunk_size == rdesc->wim->decompressor_max_block_size)
191         {
192                 /* Cached decompressor.  */
193                 decompressor = rdesc->wim->decompressor;
194                 rdesc->wim->decompressor_ctype = WIMLIB_COMPRESSION_TYPE_NONE;
195                 rdesc->wim->decompressor = NULL;
196         } else {
197                 ret = wimlib_create_decompressor(ctype, chunk_size,
198                                                  &decompressor);
199                 if (ret) {
200                         if (ret != WIMLIB_ERR_NOMEM)
201                                 errno = EINVAL;
202                         goto out_free_memory;
203                 }
204         }
205
206         const u32 chunk_order = fls32(chunk_size);
207
208         /* Calculate the total number of chunks the resource is divided into.  */
209         const u64 num_chunks = (rdesc->uncompressed_size + chunk_size - 1) >> chunk_order;
210
211         /* Calculate the 0-based indices of the first and last chunks containing
212          * data that needs to be passed to the callback.  */
213         const u64 first_needed_chunk = first_offset >> chunk_order;
214         const u64 last_needed_chunk = last_offset >> chunk_order;
215
216         /* Calculate the 0-based index of the first chunk that actually needs to
217          * be read.  This is normally first_needed_chunk, but for pipe reads we
218          * must always start from the 0th chunk.  */
219         const u64 read_start_chunk = (is_pipe_read ? 0 : first_needed_chunk);
220
221         /* Calculate the number of chunk offsets that are needed for the chunks
222          * being read.  */
223         const u64 num_needed_chunk_offsets =
224                 last_needed_chunk - read_start_chunk + 1 +
225                 (last_needed_chunk < num_chunks - 1);
226
227         /* Calculate the number of entries in the chunk table.  Normally, it's
228          * one less than the number of chunks, since the first chunk has no
229          * entry.  But in the alternate chunk table format, the chunk entries
230          * contain chunk sizes, not offsets, and there is one per chunk.  */
231         const u64 num_chunk_entries = (alt_chunk_table ? num_chunks : num_chunks - 1);
232
233         /* Set the size of each chunk table entry based on the resource's
234          * uncompressed size.  */
235         const u64 chunk_entry_size = get_chunk_entry_size(rdesc->uncompressed_size,
236                                                           alt_chunk_table);
237
238         /* Calculate the size of the chunk table in bytes.  */
239         const u64 chunk_table_size = num_chunk_entries * chunk_entry_size;
240
241         /* Calculate the size of the chunk table in bytes, including the header
242          * in the case of the alternate chunk table format.  */
243         const u64 chunk_table_full_size =
244                 (alt_chunk_table) ? chunk_table_size + sizeof(struct alt_chunk_table_header_disk)
245                                   : chunk_table_size;
246
247         if (!is_pipe_read) {
248                 /* Read the needed chunk table entries into memory and use them
249                  * to initialize the chunk_offsets array.  */
250
251                 u64 first_chunk_entry_to_read;
252                 u64 last_chunk_entry_to_read;
253
254                 if (alt_chunk_table) {
255                         /* The alternate chunk table contains chunk sizes, not
256                          * offsets, so we always must read all preceding entries
257                          * in order to determine offsets.  */
258                         first_chunk_entry_to_read = 0;
259                         last_chunk_entry_to_read = last_needed_chunk;
260                 } else {
261                         /* Here we must account for the fact that the first
262                          * chunk has no explicit chunk table entry.  */
263
264                         if (read_start_chunk == 0)
265                                 first_chunk_entry_to_read = 0;
266                         else
267                                 first_chunk_entry_to_read = read_start_chunk - 1;
268
269                         if (last_needed_chunk == 0)
270                                 last_chunk_entry_to_read = 0;
271                         else
272                                 last_chunk_entry_to_read = last_needed_chunk - 1;
273
274                         if (last_needed_chunk < num_chunks - 1)
275                                 last_chunk_entry_to_read++;
276                 }
277
278                 const u64 num_chunk_entries_to_read =
279                         last_chunk_entry_to_read - first_chunk_entry_to_read + 1;
280
281                 const u64 chunk_offsets_alloc_size =
282                         max(num_chunk_entries_to_read,
283                             num_needed_chunk_offsets) * sizeof(chunk_offsets[0]);
284
285                 if ((size_t)chunk_offsets_alloc_size != chunk_offsets_alloc_size)
286                         goto oom;
287
288                 if (chunk_offsets_alloc_size <= STACK_MAX) {
289                         chunk_offsets = alloca(chunk_offsets_alloc_size);
290                 } else {
291                         chunk_offsets = MALLOC(chunk_offsets_alloc_size);
292                         if (chunk_offsets == NULL)
293                                 goto oom;
294                         chunk_offsets_malloced = true;
295                 }
296
297                 const size_t chunk_table_size_to_read =
298                         num_chunk_entries_to_read * chunk_entry_size;
299
300                 const u64 file_offset_of_needed_chunk_entries =
301                         cur_read_offset
302                         + (first_chunk_entry_to_read * chunk_entry_size)
303                         + (rdesc->is_pipable ? (rdesc->size_in_wim - chunk_table_size) : 0);
304
305                 void * const chunk_table_data =
306                         (u8*)chunk_offsets +
307                         chunk_offsets_alloc_size -
308                         chunk_table_size_to_read;
309
310                 ret = full_pread(in_fd, chunk_table_data, chunk_table_size_to_read,
311                                  file_offset_of_needed_chunk_entries);
312                 if (ret)
313                         goto read_error;
314
315                 /* Now fill in chunk_offsets from the entries we have read in
316                  * chunk_tab_data.  We break aliasing rules here to avoid having
317                  * to allocate yet another array.  */
318                 typedef le64 _may_alias_attribute aliased_le64_t;
319                 typedef le32 _may_alias_attribute aliased_le32_t;
320                 u64 * chunk_offsets_p = chunk_offsets;
321
322                 if (alt_chunk_table) {
323                         u64 cur_offset = 0;
324                         aliased_le32_t *raw_entries = chunk_table_data;
325
326                         for (size_t i = 0; i < num_chunk_entries_to_read; i++) {
327                                 u32 entry = le32_to_cpu(raw_entries[i]);
328                                 if (i >= read_start_chunk)
329                                         *chunk_offsets_p++ = cur_offset;
330                                 cur_offset += entry;
331                         }
332                         if (last_needed_chunk < num_chunks - 1)
333                                 *chunk_offsets_p = cur_offset;
334                 } else {
335                         if (read_start_chunk == 0)
336                                 *chunk_offsets_p++ = 0;
337
338                         if (chunk_entry_size == 4) {
339                                 aliased_le32_t *raw_entries = chunk_table_data;
340                                 for (size_t i = 0; i < num_chunk_entries_to_read; i++)
341                                         *chunk_offsets_p++ = le32_to_cpu(raw_entries[i]);
342                         } else {
343                                 aliased_le64_t *raw_entries = chunk_table_data;
344                                 for (size_t i = 0; i < num_chunk_entries_to_read; i++)
345                                         *chunk_offsets_p++ = le64_to_cpu(raw_entries[i]);
346                         }
347                 }
348
349                 /* Set offset to beginning of first chunk to read.  */
350                 cur_read_offset += chunk_offsets[0];
351                 if (rdesc->is_pipable)
352                         cur_read_offset += read_start_chunk * sizeof(struct pwm_chunk_hdr);
353                 else
354                         cur_read_offset += chunk_table_size;
355         }
356
357         /* Allocate buffer for holding the uncompressed data of each chunk.  */
358         if (chunk_size <= STACK_MAX) {
359                 ubuf = alloca(chunk_size);
360         } else {
361                 ubuf = MALLOC(chunk_size);
362                 if (ubuf == NULL)
363                         goto oom;
364                 ubuf_malloced = true;
365         }
366
367         /* Allocate a temporary buffer for reading compressed chunks, each of
368          * which can be at most @chunk_size - 1 bytes.  This excludes compressed
369          * chunks that are a full @chunk_size bytes, which are actually stored
370          * uncompressed.  */
371         if (chunk_size - 1 <= STACK_MAX) {
372                 cbuf = alloca(chunk_size - 1);
373         } else {
374                 cbuf = MALLOC(chunk_size - 1);
375                 if (cbuf == NULL)
376                         goto oom;
377                 cbuf_malloced = true;
378         }
379
380         /* Set current data range.  */
381         const struct data_range *cur_range = ranges;
382         const struct data_range * const end_range = &ranges[num_ranges];
383         u64 cur_range_pos = cur_range->offset;
384         u64 cur_range_end = cur_range->offset + cur_range->size;
385
386         /* Read and process each needed chunk.  */
387         for (u64 i = read_start_chunk; i <= last_needed_chunk; i++) {
388
389                 /* Calculate uncompressed size of next chunk.  */
390                 u32 chunk_usize;
391                 if ((i == num_chunks - 1) && (rdesc->uncompressed_size & (chunk_size - 1)))
392                         chunk_usize = (rdesc->uncompressed_size & (chunk_size - 1));
393                 else
394                         chunk_usize = chunk_size;
395
396                 /* Calculate compressed size of next chunk.  */
397                 u32 chunk_csize;
398                 if (is_pipe_read) {
399                         struct pwm_chunk_hdr chunk_hdr;
400
401                         ret = full_pread(in_fd, &chunk_hdr,
402                                          sizeof(chunk_hdr), cur_read_offset);
403                         if (ret)
404                                 goto read_error;
405                         chunk_csize = le32_to_cpu(chunk_hdr.compressed_size);
406                 } else {
407                         if (i == num_chunks - 1) {
408                                 chunk_csize = rdesc->size_in_wim -
409                                               chunk_table_full_size -
410                                               chunk_offsets[i - read_start_chunk];
411                                 if (rdesc->is_pipable)
412                                         chunk_csize -= num_chunks * sizeof(struct pwm_chunk_hdr);
413                         } else {
414                                 chunk_csize = chunk_offsets[i + 1 - read_start_chunk] -
415                                               chunk_offsets[i - read_start_chunk];
416                         }
417                 }
418                 if (chunk_csize == 0 || chunk_csize > chunk_usize) {
419                         ERROR("Invalid chunk size in compressed resource!");
420                         errno = EINVAL;
421                         ret = WIMLIB_ERR_DECOMPRESSION;
422                         goto out_free_memory;
423                 }
424                 if (rdesc->is_pipable)
425                         cur_read_offset += sizeof(struct pwm_chunk_hdr);
426
427                 /* Offsets in the uncompressed resource at which this chunk
428                  * starts and ends.  */
429                 const u64 chunk_start_offset = i << chunk_order;
430                 const u64 chunk_end_offset = chunk_start_offset + chunk_usize;
431
432                 if (chunk_end_offset <= cur_range_pos) {
433
434                         /* The next range does not require data in this chunk,
435                          * so skip it.  */
436                         cur_read_offset += chunk_csize;
437                         if (is_pipe_read) {
438                                 u8 dummy;
439
440                                 ret = full_pread(in_fd, &dummy, 1, cur_read_offset - 1);
441                                 if (ret)
442                                         goto read_error;
443                         }
444                 } else {
445
446                         /* Read the chunk and feed data to the callback
447                          * function.  */
448                         u8 *read_buf;
449
450                         if (chunk_csize == chunk_usize)
451                                 read_buf = ubuf;
452                         else
453                                 read_buf = cbuf;
454
455                         ret = full_pread(in_fd,
456                                          read_buf,
457                                          chunk_csize,
458                                          cur_read_offset);
459                         if (ret)
460                                 goto read_error;
461
462                         if (read_buf == cbuf) {
463                                 DEBUG("Decompressing chunk %"PRIu64" "
464                                       "(csize=%"PRIu32" usize=%"PRIu32")",
465                                       i, chunk_csize, chunk_usize);
466                                 ret = wimlib_decompress(cbuf,
467                                                         chunk_csize,
468                                                         ubuf,
469                                                         chunk_usize,
470                                                         decompressor);
471                                 if (ret) {
472                                         ERROR("Failed to decompress data!");
473                                         ret = WIMLIB_ERR_DECOMPRESSION;
474                                         errno = EINVAL;
475                                         goto out_free_memory;
476                                 }
477                         }
478                         cur_read_offset += chunk_csize;
479
480                         /* At least one range requires data in this chunk.  */
481                         do {
482                                 size_t start, end, size;
483
484                                 /* Calculate how many bytes of data should be
485                                  * sent to the callback function, taking into
486                                  * account that data sent to the callback
487                                  * function must not overlap range boundaries.
488                                  */
489                                 start = cur_range_pos - chunk_start_offset;
490                                 end = min(cur_range_end, chunk_end_offset) - chunk_start_offset;
491                                 size = end - start;
492
493                                 ret = (*cb)(&ubuf[start], size, cb_ctx);
494
495                                 if (ret)
496                                         goto out_free_memory;
497
498                                 cur_range_pos += size;
499                                 if (cur_range_pos == cur_range_end) {
500                                         /* Advance to next range.  */
501                                         if (++cur_range == end_range) {
502                                                 cur_range_pos = ~0ULL;
503                                         } else {
504                                                 cur_range_pos = cur_range->offset;
505                                                 cur_range_end = cur_range->offset + cur_range->size;
506                                         }
507                                 }
508                         } while (cur_range_pos < chunk_end_offset);
509                 }
510         }
511
512         if (is_pipe_read &&
513             last_offset == rdesc->uncompressed_size - 1 &&
514             chunk_table_size)
515         {
516                 u8 dummy;
517                 /* If reading a pipable resource from a pipe and the full data
518                  * was requested, skip the chunk table at the end so that the
519                  * file descriptor is fully clear of the resource after this
520                  * returns.  */
521                 cur_read_offset += chunk_table_size;
522                 ret = full_pread(in_fd, &dummy, 1, cur_read_offset - 1);
523                 if (ret)
524                         goto read_error;
525         }
526         ret = 0;
527
528 out_free_memory:
529         errno_save = errno;
530         if (decompressor) {
531                 wimlib_free_decompressor(rdesc->wim->decompressor);
532                 rdesc->wim->decompressor = decompressor;
533                 rdesc->wim->decompressor_ctype = ctype;
534                 rdesc->wim->decompressor_max_block_size = chunk_size;
535         }
536         if (chunk_offsets_malloced)
537                 FREE(chunk_offsets);
538         if (ubuf_malloced)
539                 FREE(ubuf);
540         if (cbuf_malloced)
541                 FREE(cbuf);
542         errno = errno_save;
543         return ret;
544
545 oom:
546         ERROR("Not enough memory available to read size=%"PRIu64" bytes "
547               "from compressed WIM resource!", last_offset - first_offset + 1);
548         errno = ENOMEM;
549         ret = WIMLIB_ERR_NOMEM;
550         goto out_free_memory;
551
552 read_error:
553         ERROR_WITH_ERRNO("Error reading compressed WIM resource!");
554         goto out_free_memory;
555 }
556
557 /* Read raw data from a file descriptor at the specified offset, feeding the
558  * data it in chunks into the specified callback function.  */
559 static int
560 read_raw_file_data(struct filedes *in_fd, u64 offset, u64 size,
561                    consume_data_callback_t cb, void *cb_ctx)
562 {
563         u8 buf[BUFFER_SIZE];
564         size_t bytes_to_read;
565         int ret;
566
567         while (size) {
568                 bytes_to_read = min(sizeof(buf), size);
569                 ret = full_pread(in_fd, buf, bytes_to_read, offset);
570                 if (ret) {
571                         ERROR_WITH_ERRNO("Read error");
572                         return ret;
573                 }
574                 ret = cb(buf, bytes_to_read, cb_ctx);
575                 if (ret)
576                         return ret;
577                 size -= bytes_to_read;
578                 offset += bytes_to_read;
579         }
580         return 0;
581 }
582
583 /* A consume_data_callback_t implementation that simply concatenates all chunks
584  * into a buffer.  */
585 static int
586 bufferer_cb(const void *chunk, size_t size, void *_ctx)
587 {
588         u8 **buf_p = _ctx;
589
590         *buf_p = mempcpy(*buf_p, chunk, size);
591         return 0;
592 }
593
594 /*
595  * read_partial_wim_resource()-
596  *
597  * Read a range of data from an uncompressed or compressed resource in a WIM
598  * file.
599  *
600  * @rdesc
601  *      Description of the WIM resource to read from.
602  * @offset
603  *      Offset within the uncompressed resource at which to start reading.
604  * @size
605  *      Number of bytes to read.
606  * @cb
607  *      Callback function to feed the data being read.  Each call provides the
608  *      next chunk of the requested data, uncompressed.  Each chunk will be of
609  *      nonzero size and will not cross range boundaries, but otherwise will be
610  *      of unspecified size.
611  * @cb_ctx
612  *      Parameter to pass to @cb_ctx.
613  *
614  * Return values:
615  *      WIMLIB_ERR_SUCCESS (0)
616  *      WIMLIB_ERR_READ                   (errno set)
617  *      WIMLIB_ERR_UNEXPECTED_END_OF_FILE (errno set to 0)
618  *      WIMLIB_ERR_NOMEM                  (errno set to ENOMEM)
619  *      WIMLIB_ERR_DECOMPRESSION          (errno set to EINVAL)
620  *
621  *      or other error code returned by the @cb function.
622  */
623 static int
624 read_partial_wim_resource(const struct wim_resource_descriptor *rdesc,
625                           u64 offset, u64 size,
626                           consume_data_callback_t cb, void *cb_ctx)
627 {
628         /* Sanity checks.  */
629         wimlib_assert(offset + size >= offset);
630         wimlib_assert(offset + size <= rdesc->uncompressed_size);
631
632         DEBUG("Reading %"PRIu64" @ %"PRIu64" from WIM resource  "
633               "%"PRIu64" => %"PRIu64" @ %"PRIu64,
634               size, offset, rdesc->uncompressed_size,
635               rdesc->size_in_wim, rdesc->offset_in_wim);
636
637         /* Trivial case.  */
638         if (size == 0)
639                 return 0;
640
641         if (resource_is_compressed(rdesc)) {
642                 struct data_range range = {
643                         .offset = offset,
644                         .size = size,
645                 };
646                 return read_compressed_wim_resource(rdesc, &range, 1,
647                                                     cb, cb_ctx);
648         } else {
649                 return read_raw_file_data(&rdesc->wim->in_fd,
650                                           rdesc->offset_in_wim + offset,
651                                           size, cb, cb_ctx);
652         }
653 }
654
655 /* Read the specified range of uncompressed data from the specified blob, which
656  * must be located into a WIM file, into the specified buffer.  */
657 int
658 read_partial_wim_blob_into_buf(const struct blob_descriptor *blob,
659                                size_t size, u64 offset, void *_buf)
660 {
661         u8 *buf = _buf;
662
663         wimlib_assert(blob->blob_location == BLOB_IN_WIM);
664
665         return read_partial_wim_resource(blob->rdesc,
666                                          blob->offset_in_res + offset,
667                                          size,
668                                          bufferer_cb,
669                                          &buf);
670 }
671
672 /* A consume_data_callback_t implementation that simply ignores the data
673  * received.  */
674 static int
675 skip_chunk_cb(const void *chunk, size_t size, void *_ctx)
676 {
677         return 0;
678 }
679
680 /* Skip over the data of the specified WIM resource.  */
681 int
682 skip_wim_resource(struct wim_resource_descriptor *rdesc)
683 {
684         DEBUG("Skipping resource (size=%"PRIu64")", rdesc->uncompressed_size);
685         return read_partial_wim_resource(rdesc, 0, rdesc->uncompressed_size,
686                                          skip_chunk_cb, NULL);
687 }
688
689 static int
690 read_wim_blob_prefix(const struct blob_descriptor *blob, u64 size,
691                      consume_data_callback_t cb, void *cb_ctx)
692 {
693         return read_partial_wim_resource(blob->rdesc, blob->offset_in_res, size,
694                                          cb, cb_ctx);
695 }
696
697 /* This function handles reading blob data that is located in an external file,
698  * such as a file that has been added to the WIM image through execution of a
699  * wimlib_add_command.
700  *
701  * This assumes the file can be accessed using the standard POSIX open(),
702  * read(), and close().  On Windows this will not necessarily be the case (since
703  * the file may need FILE_FLAG_BACKUP_SEMANTICS to be opened, or the file may be
704  * encrypted), so Windows uses its own code for its equivalent case.  */
705 static int
706 read_file_on_disk_prefix(const struct blob_descriptor *blob, u64 size,
707                          consume_data_callback_t cb, void *cb_ctx)
708 {
709         int ret;
710         int raw_fd;
711         struct filedes fd;
712
713         DEBUG("Reading %"PRIu64" bytes from \"%"TS"\"", size, blob->file_on_disk);
714
715         raw_fd = topen(blob->file_on_disk, O_BINARY | O_RDONLY);
716         if (raw_fd < 0) {
717                 ERROR_WITH_ERRNO("Can't open \"%"TS"\"", blob->file_on_disk);
718                 return WIMLIB_ERR_OPEN;
719         }
720         filedes_init(&fd, raw_fd);
721         ret = read_raw_file_data(&fd, 0, size, cb, cb_ctx);
722         filedes_close(&fd);
723         return ret;
724 }
725
726 #ifdef WITH_FUSE
727 static int
728 read_staging_file_prefix(const struct blob_descriptor *blob, u64 size,
729                          consume_data_callback_t cb, void *cb_ctx)
730 {
731         int raw_fd;
732         struct filedes fd;
733         int ret;
734
735         DEBUG("Reading %"PRIu64" bytes from staging file \"%s\"",
736               size, blob->staging_file_name);
737
738         raw_fd = openat(blob->staging_dir_fd, blob->staging_file_name,
739                         O_RDONLY | O_NOFOLLOW);
740         if (raw_fd < 0) {
741                 ERROR_WITH_ERRNO("Can't open staging file \"%s\"",
742                                  blob->staging_file_name);
743                 return WIMLIB_ERR_OPEN;
744         }
745         filedes_init(&fd, raw_fd);
746         ret = read_raw_file_data(&fd, 0, size, cb, cb_ctx);
747         filedes_close(&fd);
748         return ret;
749 }
750 #endif
751
752 /* This function handles the trivial case of reading blob data that is, in fact,
753  * already located in an in-memory buffer.  */
754 static int
755 read_buffer_prefix(const struct blob_descriptor *blob,
756                    u64 size, consume_data_callback_t cb, void *cb_ctx)
757 {
758         return (*cb)(blob->attached_buffer, size, cb_ctx);
759 }
760
761 typedef int (*read_blob_prefix_handler_t)(const struct blob_descriptor *blob,
762                                           u64 size,
763                                           consume_data_callback_t cb,
764                                           void *cb_ctx);
765
766 /*
767  * read_blob_prefix()-
768  *
769  * Reads the first @size bytes from a generic "blob", which may be located in
770  * any one of several locations, such as in a WIM file (compressed or
771  * uncompressed), in an external file, or directly in an in-memory buffer.
772  *
773  * This function feeds the data to a callback function @cb in chunks of
774  * unspecified size.
775  *
776  * Returns 0 on success; nonzero on error.  A nonzero value will be returned if
777  * the blob data cannot be successfully read (for a number of different reasons,
778  * depending on the blob location), or if @cb returned nonzero in which case
779  * that error code will be returned.
780  */
781 static int
782 read_blob_prefix(const struct blob_descriptor *blob, u64 size,
783                  consume_data_callback_t cb, void *cb_ctx)
784 {
785         static const read_blob_prefix_handler_t handlers[] = {
786                 [BLOB_IN_WIM] = read_wim_blob_prefix,
787                 [BLOB_IN_FILE_ON_DISK] = read_file_on_disk_prefix,
788                 [BLOB_IN_ATTACHED_BUFFER] = read_buffer_prefix,
789         #ifdef WITH_FUSE
790                 [BLOB_IN_STAGING_FILE] = read_staging_file_prefix,
791         #endif
792         #ifdef WITH_NTFS_3G
793                 [BLOB_IN_NTFS_VOLUME] = read_ntfs_attribute_prefix,
794         #endif
795         #ifdef __WIN32__
796                 [BLOB_IN_WINNT_FILE_ON_DISK] = read_winnt_stream_prefix,
797                 [BLOB_WIN32_ENCRYPTED] = read_win32_encrypted_file_prefix,
798         #endif
799         };
800         wimlib_assert(blob->blob_location < ARRAY_LEN(handlers)
801                       && handlers[blob->blob_location] != NULL);
802         wimlib_assert(size <= blob->size);
803         return handlers[blob->blob_location](blob, size, cb, cb_ctx);
804 }
805
806 /* Read the full uncompressed data of the specified blob into the specified
807  * buffer, which must have space for at least blob->size bytes.  */
808 int
809 read_full_blob_into_buf(const struct blob_descriptor *blob, void *_buf)
810 {
811         u8 *buf = _buf;
812         return read_blob_prefix(blob, blob->size, bufferer_cb, &buf);
813 }
814
815 /* Retrieve the full uncompressed data of the specified blob.  A buffer large
816  * enough hold the data is allocated and returned in @buf_ret.  */
817 int
818 read_full_blob_into_alloc_buf(const struct blob_descriptor *blob, void **buf_ret)
819 {
820         int ret;
821         void *buf;
822
823         if ((size_t)blob->size != blob->size) {
824                 ERROR("Can't read %"PRIu64" byte blob into memory", blob->size);
825                 return WIMLIB_ERR_NOMEM;
826         }
827
828         buf = MALLOC(blob->size);
829         if (buf == NULL)
830                 return WIMLIB_ERR_NOMEM;
831
832         ret = read_full_blob_into_buf(blob, buf);
833         if (ret) {
834                 FREE(buf);
835                 return ret;
836         }
837
838         *buf_ret = buf;
839         return 0;
840 }
841
842 /* Retrieve the full uncompressed data of a WIM resource specified as a raw
843  * `wim_reshdr' and the corresponding WIM file.  A buffer large enough hold the
844  * data is allocated and returned in @buf_ret.  */
845 int
846 wim_reshdr_to_data(const struct wim_reshdr *reshdr, WIMStruct *wim, void **buf_ret)
847 {
848         struct wim_resource_descriptor rdesc;
849         struct blob_descriptor blob;
850
851         wim_res_hdr_to_desc(reshdr, wim, &rdesc);
852         blob_set_is_located_in_nonsolid_wim_resource(&blob, &rdesc);
853
854         return read_full_blob_into_alloc_buf(&blob, buf_ret);
855 }
856
857 int
858 wim_reshdr_to_hash(const struct wim_reshdr *reshdr, WIMStruct *wim,
859                    u8 hash[SHA1_HASH_SIZE])
860 {
861         struct wim_resource_descriptor rdesc;
862         struct blob_descriptor blob;
863         int ret;
864
865         wim_res_hdr_to_desc(reshdr, wim, &rdesc);
866         blob_set_is_located_in_nonsolid_wim_resource(&blob, &rdesc);
867         blob.unhashed = 1;
868
869         ret = sha1_blob(&blob);
870         if (ret)
871                 return ret;
872         copy_hash(hash, blob.hash);
873         return 0;
874 }
875
876 struct blobifier_context {
877         struct read_blob_list_callbacks cbs;
878         struct blob_descriptor *cur_blob;
879         struct blob_descriptor *next_blob;
880         u64 cur_blob_offset;
881         struct blob_descriptor *final_blob;
882         size_t list_head_offset;
883 };
884
885 static struct blob_descriptor *
886 next_blob(struct blob_descriptor *blob, size_t list_head_offset)
887 {
888         struct list_head *cur;
889
890         cur = (struct list_head*)((u8*)blob + list_head_offset);
891
892         return (struct blob_descriptor*)((u8*)cur->next - list_head_offset);
893 }
894
895 /* A consume_data_callback_t implementation that translates raw resource data
896  * into blobs, calling the begin_blob, consume_chunk, and end_blob callback
897  * functions as appropriate.  */
898 static int
899 blobifier_cb(const void *chunk, size_t size, void *_ctx)
900 {
901         struct blobifier_context *ctx = _ctx;
902         int ret;
903
904         DEBUG("%zu bytes passed to blobifier", size);
905
906         wimlib_assert(ctx->cur_blob != NULL);
907         wimlib_assert(size <= ctx->cur_blob->size - ctx->cur_blob_offset);
908
909         if (ctx->cur_blob_offset == 0) {
910
911                 /* Starting a new blob.  */
912                 DEBUG("Begin new blob (size=%"PRIu64").", ctx->cur_blob->size);
913
914                 ret = (*ctx->cbs.begin_blob)(ctx->cur_blob,
915                                              ctx->cbs.begin_blob_ctx);
916                 if (ret)
917                         return ret;
918         }
919
920         /* Consume the chunk.  */
921         ret = (*ctx->cbs.consume_chunk)(chunk, size,
922                                         ctx->cbs.consume_chunk_ctx);
923         ctx->cur_blob_offset += size;
924         if (ret)
925                 return ret;
926
927         if (ctx->cur_blob_offset == ctx->cur_blob->size) {
928                 /* Finished reading all the data for a blob.  */
929
930                 ctx->cur_blob_offset = 0;
931
932                 DEBUG("End blob (size=%"PRIu64").", ctx->cur_blob->size);
933                 ret = (*ctx->cbs.end_blob)(ctx->cur_blob, 0,
934                                            ctx->cbs.end_blob_ctx);
935                 if (ret)
936                         return ret;
937
938                 /* Advance to next blob.  */
939                 ctx->cur_blob = ctx->next_blob;
940                 if (ctx->cur_blob != NULL) {
941                         if (ctx->cur_blob != ctx->final_blob)
942                                 ctx->next_blob = next_blob(ctx->cur_blob,
943                                                            ctx->list_head_offset);
944                         else
945                                 ctx->next_blob = NULL;
946                 }
947         }
948         return 0;
949 }
950
951 struct hasher_context {
952         SHA_CTX sha_ctx;
953         int flags;
954         struct read_blob_list_callbacks cbs;
955 };
956
957 /* Callback for starting to read a blob while calculating its SHA-1 message
958  * digest.  */
959 static int
960 hasher_begin_blob(struct blob_descriptor *blob, void *_ctx)
961 {
962         struct hasher_context *ctx = _ctx;
963
964         sha1_init(&ctx->sha_ctx);
965
966         if (ctx->cbs.begin_blob == NULL)
967                 return 0;
968         else
969                 return (*ctx->cbs.begin_blob)(blob, ctx->cbs.begin_blob_ctx);
970 }
971
972 /* A consume_data_callback_t implementation that continues calculating the SHA-1
973  * message digest of the blob being read, then optionally passes the data on to
974  * another consume_data_callback_t implementation.  This allows checking the
975  * SHA-1 message digest of a blob being extracted, for example.  */
976 static int
977 hasher_consume_chunk(const void *chunk, size_t size, void *_ctx)
978 {
979         struct hasher_context *ctx = _ctx;
980
981         sha1_update(&ctx->sha_ctx, chunk, size);
982         if (ctx->cbs.consume_chunk == NULL)
983                 return 0;
984         else
985                 return (*ctx->cbs.consume_chunk)(chunk, size, ctx->cbs.consume_chunk_ctx);
986 }
987
988 /* Callback for finishing reading a blob while calculating its SHA-1 message
989  * digest.  */
990 static int
991 hasher_end_blob(struct blob_descriptor *blob, int status, void *_ctx)
992 {
993         struct hasher_context *ctx = _ctx;
994         u8 hash[SHA1_HASH_SIZE];
995         int ret;
996
997         if (status) {
998                 /* Error occurred; the full blob may not have been read.  */
999                 ret = status;
1000                 goto out_next_cb;
1001         }
1002
1003         /* Retrieve the final SHA-1 message digest.  */
1004         sha1_final(hash, &ctx->sha_ctx);
1005
1006         if (blob->unhashed) {
1007                 if (ctx->flags & COMPUTE_MISSING_BLOB_HASHES) {
1008                         /* No SHA-1 message digest was previously present for the
1009                          * blob.  Set it to the one just calculated.  */
1010                         DEBUG("Set SHA-1 message digest for blob "
1011                               "(size=%"PRIu64").", blob->size);
1012                         copy_hash(blob->hash, hash);
1013                 }
1014         } else {
1015                 if (ctx->flags & VERIFY_BLOB_HASHES) {
1016                         /* The blob already had a SHA-1 message digest present.
1017                          * Verify that it is the same as the calculated value.
1018                          */
1019                         if (!hashes_equal(hash, blob->hash)) {
1020                                 if (wimlib_print_errors) {
1021                                         tchar expected_hashstr[SHA1_HASH_SIZE * 2 + 1];
1022                                         tchar actual_hashstr[SHA1_HASH_SIZE * 2 + 1];
1023                                         sprint_hash(blob->hash, expected_hashstr);
1024                                         sprint_hash(hash, actual_hashstr);
1025                                         ERROR("The data is corrupted!\n"
1026                                               "        (Expected SHA-1=%"TS",\n"
1027                                               "              got SHA-1=%"TS")",
1028                                               expected_hashstr, actual_hashstr);
1029                                 }
1030                                 ret = WIMLIB_ERR_INVALID_RESOURCE_HASH;
1031                                 errno = EINVAL;
1032                                 goto out_next_cb;
1033                         }
1034                         DEBUG("SHA-1 message digest okay for "
1035                               "blob (size=%"PRIu64").", blob->size);
1036                 }
1037         }
1038         ret = 0;
1039 out_next_cb:
1040         if (ctx->cbs.end_blob == NULL)
1041                 return ret;
1042         else
1043                 return (*ctx->cbs.end_blob)(blob, ret, ctx->cbs.end_blob_ctx);
1044 }
1045
1046 static int
1047 read_full_blob_with_cbs(struct blob_descriptor *blob,
1048                         const struct read_blob_list_callbacks *cbs)
1049 {
1050         int ret;
1051
1052         ret = (*cbs->begin_blob)(blob, cbs->begin_blob_ctx);
1053         if (ret)
1054                 return ret;
1055
1056         ret = read_blob_prefix(blob, blob->size, cbs->consume_chunk,
1057                                cbs->consume_chunk_ctx);
1058
1059         return (*cbs->end_blob)(blob, ret, cbs->end_blob_ctx);
1060 }
1061
1062 /* Read the full data of the specified blob, passing the data into the specified
1063  * callbacks (all of which are optional) and either checking or computing the
1064  * SHA-1 message digest of the blob.  */
1065 static int
1066 read_full_blob_with_sha1(struct blob_descriptor *blob,
1067                          const struct read_blob_list_callbacks *cbs)
1068 {
1069         struct hasher_context hasher_ctx = {
1070                 .flags = VERIFY_BLOB_HASHES | COMPUTE_MISSING_BLOB_HASHES,
1071                 .cbs = *cbs,
1072         };
1073         struct read_blob_list_callbacks hasher_cbs = {
1074                 .begin_blob             = hasher_begin_blob,
1075                 .begin_blob_ctx         = &hasher_ctx,
1076                 .consume_chunk          = hasher_consume_chunk,
1077                 .consume_chunk_ctx      = &hasher_ctx,
1078                 .end_blob               = hasher_end_blob,
1079                 .end_blob_ctx           = &hasher_ctx,
1080         };
1081         return read_full_blob_with_cbs(blob, &hasher_cbs);
1082 }
1083
1084 static int
1085 read_blobs_in_solid_resource(struct blob_descriptor *first_blob,
1086                              struct blob_descriptor *last_blob,
1087                              u64 blob_count,
1088                              size_t list_head_offset,
1089                              const struct read_blob_list_callbacks *sink_cbs)
1090 {
1091         struct data_range *ranges;
1092         bool ranges_malloced;
1093         struct blob_descriptor *cur_blob;
1094         size_t i;
1095         int ret;
1096         u64 ranges_alloc_size;
1097
1098         DEBUG("Reading %"PRIu64" blobs combined in same WIM resource",
1099               blob_count);
1100
1101         /* Setup data ranges array (one range per blob to read); this way
1102          * read_compressed_wim_resource() does not need to be aware of blobs.
1103          */
1104
1105         ranges_alloc_size = blob_count * sizeof(ranges[0]);
1106
1107         if (unlikely((size_t)ranges_alloc_size != ranges_alloc_size)) {
1108                 ERROR("Too many blobs in one resource!");
1109                 return WIMLIB_ERR_NOMEM;
1110         }
1111         if (likely(ranges_alloc_size <= STACK_MAX)) {
1112                 ranges = alloca(ranges_alloc_size);
1113                 ranges_malloced = false;
1114         } else {
1115                 ranges = MALLOC(ranges_alloc_size);
1116                 if (ranges == NULL) {
1117                         ERROR("Too many blobs in one resource!");
1118                         return WIMLIB_ERR_NOMEM;
1119                 }
1120                 ranges_malloced = true;
1121         }
1122
1123         for (i = 0, cur_blob = first_blob;
1124              i < blob_count;
1125              i++, cur_blob = next_blob(cur_blob, list_head_offset))
1126         {
1127                 ranges[i].offset = cur_blob->offset_in_res;
1128                 ranges[i].size = cur_blob->size;
1129         }
1130
1131         struct blobifier_context blobifier_ctx = {
1132                 .cbs                    = *sink_cbs,
1133                 .cur_blob               = first_blob,
1134                 .next_blob              = next_blob(first_blob, list_head_offset),
1135                 .cur_blob_offset        = 0,
1136                 .final_blob             = last_blob,
1137                 .list_head_offset       = list_head_offset,
1138         };
1139
1140         ret = read_compressed_wim_resource(first_blob->rdesc,
1141                                            ranges,
1142                                            blob_count,
1143                                            blobifier_cb,
1144                                            &blobifier_ctx);
1145
1146         if (ranges_malloced)
1147                 FREE(ranges);
1148
1149         if (ret) {
1150                 if (blobifier_ctx.cur_blob_offset != 0) {
1151                         ret = (*blobifier_ctx.cbs.end_blob)
1152                                 (blobifier_ctx.cur_blob,
1153                                  ret,
1154                                  blobifier_ctx.cbs.end_blob_ctx);
1155                 }
1156         }
1157         return ret;
1158 }
1159
1160 /*
1161  * Read a list of blobs, each of which may be in any supported location (e.g.
1162  * in a WIM or in an external file).  This function optimizes the case where
1163  * multiple blobs are combined into a single solid compressed WIM resource by
1164  * reading the blobs in sequential order, only decompressing the solid resource
1165  * one time.
1166  *
1167  * @blob_list
1168  *      List of blobs to read.
1169  * @list_head_offset
1170  *      Offset of the `struct list_head' within each `struct blob_descriptor' that makes up
1171  *      the @blob_list.
1172  * @cbs
1173  *      Callback functions to accept the blob data.
1174  * @flags
1175  *      Bitwise OR of zero or more of the following flags:
1176  *
1177  *      VERIFY_BLOB_HASHES:
1178  *              For all blobs being read that have already had SHA-1 message
1179  *              digests computed, calculate the SHA-1 message digest of the read
1180  *              data and compare it with the previously computed value.  If they
1181  *              do not match, return WIMLIB_ERR_INVALID_RESOURCE_HASH.
1182  *
1183  *      COMPUTE_MISSING_BLOB_HASHES
1184  *              For all blobs being read that have not yet had their SHA-1
1185  *              message digests computed, calculate and save their SHA-1 message
1186  *              digests.
1187  *
1188  *      BLOB_LIST_ALREADY_SORTED
1189  *              @blob_list is already sorted in sequential order for reading.
1190  *
1191  * The callback functions are allowed to delete the current blob from the list
1192  * if necessary.
1193  *
1194  * Returns 0 on success; a nonzero error code on failure.  Failure can occur due
1195  * to an error reading the data or due to an error status being returned by any
1196  * of the callback functions.
1197  */
1198 int
1199 read_blob_list(struct list_head *blob_list,
1200                size_t list_head_offset,
1201                const struct read_blob_list_callbacks *cbs,
1202                int flags)
1203 {
1204         int ret;
1205         struct list_head *cur, *next;
1206         struct blob_descriptor *blob;
1207         struct hasher_context *hasher_ctx;
1208         struct read_blob_list_callbacks *sink_cbs;
1209
1210         if (!(flags & BLOB_LIST_ALREADY_SORTED)) {
1211                 ret = sort_blob_list_by_sequential_order(blob_list, list_head_offset);
1212                 if (ret)
1213                         return ret;
1214         }
1215
1216         if (flags & (VERIFY_BLOB_HASHES | COMPUTE_MISSING_BLOB_HASHES)) {
1217                 hasher_ctx = alloca(sizeof(*hasher_ctx));
1218                 *hasher_ctx = (struct hasher_context) {
1219                         .flags  = flags,
1220                         .cbs    = *cbs,
1221                 };
1222                 sink_cbs = alloca(sizeof(*sink_cbs));
1223                 *sink_cbs = (struct read_blob_list_callbacks) {
1224                         .begin_blob             = hasher_begin_blob,
1225                         .begin_blob_ctx         = hasher_ctx,
1226                         .consume_chunk          = hasher_consume_chunk,
1227                         .consume_chunk_ctx      = hasher_ctx,
1228                         .end_blob               = hasher_end_blob,
1229                         .end_blob_ctx           = hasher_ctx,
1230                 };
1231         } else {
1232                 sink_cbs = (struct read_blob_list_callbacks*)cbs;
1233         }
1234
1235         for (cur = blob_list->next, next = cur->next;
1236              cur != blob_list;
1237              cur = next, next = cur->next)
1238         {
1239                 blob = (struct blob_descriptor*)((u8*)cur - list_head_offset);
1240
1241                 if (blob->blob_location == BLOB_IN_WIM &&
1242                     blob->size != blob->rdesc->uncompressed_size)
1243                 {
1244                         struct blob_descriptor *blob_next, *blob_last;
1245                         struct list_head *next2;
1246                         u64 blob_count;
1247
1248                         /* The next blob is a proper sub-sequence of a WIM
1249                          * resource.  See if there are other blobs in the same
1250                          * resource that need to be read.  Since
1251                          * sort_blob_list_by_sequential_order() sorted the blobs
1252                          * by offset in the WIM, this can be determined by
1253                          * simply scanning forward in the list.  */
1254
1255                         blob_last = blob;
1256                         blob_count = 1;
1257                         for (next2 = next;
1258                              next2 != blob_list
1259                              && (blob_next = (struct blob_descriptor*)
1260                                                 ((u8*)next2 - list_head_offset),
1261                                  blob_next->blob_location == BLOB_IN_WIM
1262                                  && blob_next->rdesc == blob->rdesc);
1263                              next2 = next2->next)
1264                         {
1265                                 blob_last = blob_next;
1266                                 blob_count++;
1267                         }
1268                         if (blob_count > 1) {
1269                                 /* Reading multiple blobs combined into a single
1270                                  * WIM resource.  They are in the blob list,
1271                                  * sorted by offset; @blob specifies the first
1272                                  * blob in the resource that needs to be read
1273                                  * and @blob_last specifies the last blob in the
1274                                  * resource that needs to be read.  */
1275                                 next = next2;
1276                                 ret = read_blobs_in_solid_resource(blob, blob_last,
1277                                                                    blob_count,
1278                                                                    list_head_offset,
1279                                                                    sink_cbs);
1280                                 if (ret)
1281                                         return ret;
1282                                 continue;
1283                         }
1284                 }
1285
1286                 ret = read_full_blob_with_cbs(blob, sink_cbs);
1287                 if (ret && ret != BEGIN_BLOB_STATUS_SKIP_BLOB)
1288                         return ret;
1289         }
1290         return 0;
1291 }
1292
1293 /*
1294  * Extract the first @size bytes of the specified blob.
1295  *
1296  * If @size specifies the full uncompressed size of the blob, then the SHA-1
1297  * message digest of the uncompressed blob is checked while being extracted.
1298  *
1299  * The uncompressed data of the blob is passed in chunks of unspecified size to
1300  * the @extract_chunk function, passing it @extract_chunk_arg.
1301  */
1302 int
1303 extract_blob(struct blob_descriptor *blob, u64 size,
1304              consume_data_callback_t extract_chunk, void *extract_chunk_arg)
1305 {
1306         wimlib_assert(size <= blob->size);
1307         if (size == blob->size) {
1308                 /* Do SHA-1.  */
1309                 struct read_blob_list_callbacks cbs = {
1310                         .consume_chunk          = extract_chunk,
1311                         .consume_chunk_ctx      = extract_chunk_arg,
1312                 };
1313                 return read_full_blob_with_sha1(blob, &cbs);
1314         } else {
1315                 /* Don't do SHA-1.  */
1316                 return read_blob_prefix(blob, size, extract_chunk,
1317                                         extract_chunk_arg);
1318         }
1319 }
1320
1321 /* A consume_data_callback_t implementation that writes the chunk of data to a
1322  * file descriptor.  */
1323 static int
1324 extract_chunk_to_fd(const void *chunk, size_t size, void *_fd_p)
1325 {
1326         struct filedes *fd = _fd_p;
1327
1328         int ret = full_write(fd, chunk, size);
1329         if (ret) {
1330                 ERROR_WITH_ERRNO("Error writing to file descriptor");
1331                 return ret;
1332         }
1333         return 0;
1334 }
1335
1336 /* Extract the first @size bytes of the specified blob to the specified file
1337  * descriptor.  */
1338 int
1339 extract_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd, u64 size)
1340 {
1341         return extract_blob(blob, size, extract_chunk_to_fd, fd);
1342 }
1343
1344 /* Extract the full uncompressed contents of the specified blob to the specified
1345  * file descriptor.  */
1346 int
1347 extract_full_blob_to_fd(struct blob_descriptor *blob, struct filedes *fd)
1348 {
1349         return extract_blob_to_fd(blob, fd, blob->size);
1350 }
1351
1352 /* Calculate the SHA-1 message digest of a blob and store it in @blob->hash.  */
1353 int
1354 sha1_blob(struct blob_descriptor *blob)
1355 {
1356         wimlib_assert(blob->unhashed);
1357         struct read_blob_list_callbacks cbs = {
1358         };
1359         return read_full_blob_with_sha1(blob, &cbs);
1360 }
1361
1362 /*
1363  * Convert a short WIM resource header to a stand-alone WIM resource descriptor.
1364  *
1365  * Note: for solid resources some fields still need to be overridden.
1366  */
1367 void
1368 wim_res_hdr_to_desc(const struct wim_reshdr *reshdr, WIMStruct *wim,
1369                     struct wim_resource_descriptor *rdesc)
1370 {
1371         rdesc->wim = wim;
1372         rdesc->offset_in_wim = reshdr->offset_in_wim;
1373         rdesc->size_in_wim = reshdr->size_in_wim;
1374         rdesc->uncompressed_size = reshdr->uncompressed_size;
1375         INIT_LIST_HEAD(&rdesc->blob_list);
1376         rdesc->flags = reshdr->flags;
1377         rdesc->is_pipable = wim_is_pipable(wim);
1378         if (rdesc->flags & WIM_RESHDR_FLAG_COMPRESSED) {
1379                 rdesc->compression_type = wim->compression_type;
1380                 rdesc->chunk_size = wim->chunk_size;
1381         } else {
1382                 rdesc->compression_type = WIMLIB_COMPRESSION_TYPE_NONE;
1383                 rdesc->chunk_size = 0;
1384         }
1385 }
1386
1387 /* Convert a stand-alone resource descriptor to a WIM resource header.  */
1388 void
1389 wim_res_desc_to_hdr(const struct wim_resource_descriptor *rdesc,
1390                     struct wim_reshdr *reshdr)
1391 {
1392         reshdr->offset_in_wim     = rdesc->offset_in_wim;
1393         reshdr->size_in_wim       = rdesc->size_in_wim;
1394         reshdr->flags             = rdesc->flags;
1395         reshdr->uncompressed_size = rdesc->uncompressed_size;
1396 }
1397
1398 /* Translates a WIM resource header from the on-disk format into an in-memory
1399  * format.  */
1400 void
1401 get_wim_reshdr(const struct wim_reshdr_disk *disk_reshdr,
1402                struct wim_reshdr *reshdr)
1403 {
1404         reshdr->offset_in_wim = le64_to_cpu(disk_reshdr->offset_in_wim);
1405         reshdr->size_in_wim = (((u64)disk_reshdr->size_in_wim[0] <<  0) |
1406                                ((u64)disk_reshdr->size_in_wim[1] <<  8) |
1407                                ((u64)disk_reshdr->size_in_wim[2] << 16) |
1408                                ((u64)disk_reshdr->size_in_wim[3] << 24) |
1409                                ((u64)disk_reshdr->size_in_wim[4] << 32) |
1410                                ((u64)disk_reshdr->size_in_wim[5] << 40) |
1411                                ((u64)disk_reshdr->size_in_wim[6] << 48));
1412         reshdr->uncompressed_size = le64_to_cpu(disk_reshdr->uncompressed_size);
1413         reshdr->flags = disk_reshdr->flags;
1414 }
1415
1416 /* Translates a WIM resource header from an in-memory format into the on-disk
1417  * format.  */
1418 void
1419 put_wim_reshdr(const struct wim_reshdr *reshdr,
1420                struct wim_reshdr_disk *disk_reshdr)
1421 {
1422         disk_reshdr->size_in_wim[0] = reshdr->size_in_wim  >>  0;
1423         disk_reshdr->size_in_wim[1] = reshdr->size_in_wim  >>  8;
1424         disk_reshdr->size_in_wim[2] = reshdr->size_in_wim  >> 16;
1425         disk_reshdr->size_in_wim[3] = reshdr->size_in_wim  >> 24;
1426         disk_reshdr->size_in_wim[4] = reshdr->size_in_wim  >> 32;
1427         disk_reshdr->size_in_wim[5] = reshdr->size_in_wim  >> 40;
1428         disk_reshdr->size_in_wim[6] = reshdr->size_in_wim  >> 48;
1429         disk_reshdr->flags = reshdr->flags;
1430         disk_reshdr->offset_in_wim = cpu_to_le64(reshdr->offset_in_wim);
1431         disk_reshdr->uncompressed_size = cpu_to_le64(reshdr->uncompressed_size);
1432 }