]> wimlib.net Git - wimlib/blob - src/extract.c
Use LGPLv3+ for src/*.c
[wimlib] / src / extract.c
1 /*
2  * extract.c
3  *
4  * Support for extracting WIM images, or files or directories contained in a WIM
5  * image.
6  */
7
8 /*
9  * Copyright (C) 2012, 2013, 2014 Eric Biggers
10  *
11  * This file is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU Lesser General Public License as published by the Free
13  * Software Foundation; either version 3 of the License, or (at your option) any
14  * later version.
15  *
16  * This file is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with this file; if not, see http://www.gnu.org/licenses/.
23  */
24
25 /*
26  * This file provides the API functions wimlib_extract_image(),
27  * wimlib_extract_image_from_pipe(), wimlib_extract_paths(), and
28  * wimlib_extract_pathlist().  Internally, all end up calling
29  * do_wimlib_extract_paths() and extract_trees().
30  *
31  * Although wimlib supports multiple extraction modes/backends (NTFS-3g, UNIX,
32  * Win32), this file does not itself have code to extract files or directories
33  * to any specific target; instead, it handles generic functionality and relies
34  * on lower-level callback functions declared in `struct apply_operations' to do
35  * the actual extraction.
36  */
37
38 #ifdef HAVE_CONFIG_H
39 #  include "config.h"
40 #endif
41
42 #include "wimlib/apply.h"
43 #include "wimlib/dentry.h"
44 #include "wimlib/encoding.h"
45 #include "wimlib/endianness.h"
46 #include "wimlib/error.h"
47 #include "wimlib/lookup_table.h"
48 #include "wimlib/metadata.h"
49 #include "wimlib/pathlist.h"
50 #include "wimlib/paths.h"
51 #include "wimlib/reparse.h"
52 #include "wimlib/resource.h"
53 #include "wimlib/security.h"
54 #include "wimlib/unix_data.h"
55 #ifdef __WIN32__
56 #  include "wimlib/win32.h" /* for realpath() equivalent */
57 #endif
58 #include "wimlib/xml.h"
59 #include "wimlib/wildcard.h"
60 #include "wimlib/wim.h"
61
62 #include <errno.h>
63 #include <fcntl.h>
64 #include <stdlib.h>
65 #include <sys/stat.h>
66 #include <unistd.h>
67
68 #define WIMLIB_EXTRACT_FLAG_FROM_PIPE   0x80000000
69 #define WIMLIB_EXTRACT_FLAG_IMAGEMODE   0x40000000
70
71 /* Keep in sync with wimlib.h  */
72 #define WIMLIB_EXTRACT_MASK_PUBLIC                              \
73         (WIMLIB_EXTRACT_FLAG_NTFS                       |       \
74          WIMLIB_EXTRACT_FLAG_UNIX_DATA                  |       \
75          WIMLIB_EXTRACT_FLAG_NO_ACLS                    |       \
76          WIMLIB_EXTRACT_FLAG_STRICT_ACLS                |       \
77          WIMLIB_EXTRACT_FLAG_RPFIX                      |       \
78          WIMLIB_EXTRACT_FLAG_NORPFIX                    |       \
79          WIMLIB_EXTRACT_FLAG_TO_STDOUT                  |       \
80          WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES  |       \
81          WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS         |       \
82          WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS          |       \
83          WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES         |       \
84          WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS            |       \
85          WIMLIB_EXTRACT_FLAG_GLOB_PATHS                 |       \
86          WIMLIB_EXTRACT_FLAG_STRICT_GLOB                |       \
87          WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES              |       \
88          WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE  |       \
89          WIMLIB_EXTRACT_FLAG_WIMBOOT)
90
91 /* Send WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE or
92  * WIMLIB_PROGRESS_MSG_EXTRACT_METADATA.  */
93 int
94 do_file_extract_progress(struct apply_ctx *ctx, enum wimlib_progress_msg msg)
95 {
96         ctx->count_until_file_progress = 500;  /* Arbitrary value to limit calls  */
97         return extract_progress(ctx, msg);
98 }
99
100 static int
101 start_file_phase(struct apply_ctx *ctx, uint64_t end_file_count, enum wimlib_progress_msg msg)
102 {
103         ctx->progress.extract.current_file_count = 0;
104         ctx->progress.extract.end_file_count = end_file_count;
105         return do_file_extract_progress(ctx, msg);
106 }
107
108 int
109 start_file_structure_phase(struct apply_ctx *ctx, uint64_t end_file_count)
110 {
111         return start_file_phase(ctx, end_file_count, WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE);
112 }
113
114 int
115 start_file_metadata_phase(struct apply_ctx *ctx, uint64_t end_file_count)
116 {
117         return start_file_phase(ctx, end_file_count, WIMLIB_PROGRESS_MSG_EXTRACT_METADATA);
118 }
119
120 static int
121 end_file_phase(struct apply_ctx *ctx, enum wimlib_progress_msg msg)
122 {
123         ctx->progress.extract.current_file_count = ctx->progress.extract.end_file_count;
124         return do_file_extract_progress(ctx, msg);
125 }
126
127 int
128 end_file_structure_phase(struct apply_ctx *ctx)
129 {
130         return end_file_phase(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_FILE_STRUCTURE);
131 }
132
133 int
134 end_file_metadata_phase(struct apply_ctx *ctx)
135 {
136         return end_file_phase(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_METADATA);
137 }
138
139 /* Check whether the extraction of a dentry should be skipped completely.  */
140 static bool
141 dentry_is_supported(struct wim_dentry *dentry,
142                     const struct wim_features *supported_features)
143 {
144         struct wim_inode *inode = dentry->d_inode;
145
146         if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
147                 return supported_features->reparse_points ||
148                         (inode_is_symlink(inode) &&
149                          supported_features->symlink_reparse_points);
150         }
151         if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
152                 if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
153                         return supported_features->encrypted_directories != 0;
154                 else
155                         return supported_features->encrypted_files != 0;
156         }
157         return true;
158 }
159
160
161 #define PWM_ALLOW_WIM_HDR 0x00001
162
163 /* Read the header from a stream in a pipable WIM.  */
164 static int
165 read_pwm_stream_header(WIMStruct *pwm, struct wim_lookup_table_entry *lte,
166                        struct wim_resource_spec *rspec,
167                        int flags, struct wim_header_disk *hdr_ret)
168 {
169         union {
170                 struct pwm_stream_hdr stream_hdr;
171                 struct wim_header_disk pwm_hdr;
172         } buf;
173         struct wim_reshdr reshdr;
174         int ret;
175
176         ret = full_read(&pwm->in_fd, &buf.stream_hdr, sizeof(buf.stream_hdr));
177         if (ret)
178                 goto read_error;
179
180         if ((flags & PWM_ALLOW_WIM_HDR) &&
181             le64_to_cpu(buf.stream_hdr.magic) == PWM_MAGIC)
182         {
183                 BUILD_BUG_ON(sizeof(buf.pwm_hdr) < sizeof(buf.stream_hdr));
184                 ret = full_read(&pwm->in_fd, &buf.stream_hdr + 1,
185                                 sizeof(buf.pwm_hdr) - sizeof(buf.stream_hdr));
186
187                 if (ret)
188                         goto read_error;
189                 lte->resource_location = RESOURCE_NONEXISTENT;
190                 memcpy(hdr_ret, &buf.pwm_hdr, sizeof(buf.pwm_hdr));
191                 return 0;
192         }
193
194         if (le64_to_cpu(buf.stream_hdr.magic) != PWM_STREAM_MAGIC) {
195                 ERROR("Data read on pipe is invalid (expected stream header).");
196                 return WIMLIB_ERR_INVALID_PIPABLE_WIM;
197         }
198
199         copy_hash(lte->hash, buf.stream_hdr.hash);
200
201         reshdr.size_in_wim = 0;
202         reshdr.flags = le32_to_cpu(buf.stream_hdr.flags);
203         reshdr.offset_in_wim = pwm->in_fd.offset;
204         reshdr.uncompressed_size = le64_to_cpu(buf.stream_hdr.uncompressed_size);
205         wim_res_hdr_to_spec(&reshdr, pwm, rspec);
206         lte_bind_wim_resource_spec(lte, rspec);
207         lte->flags = rspec->flags;
208         lte->size = rspec->uncompressed_size;
209         lte->offset_in_res = 0;
210         return 0;
211
212 read_error:
213         ERROR_WITH_ERRNO("Error reading pipable WIM from pipe");
214         return ret;
215 }
216
217 static int
218 load_streams_from_pipe(struct apply_ctx *ctx,
219                        const struct read_stream_list_callbacks *cbs)
220 {
221         struct wim_lookup_table_entry *found_lte = NULL;
222         struct wim_resource_spec *rspec = NULL;
223         struct wim_lookup_table *lookup_table;
224         int ret;
225
226         ret = WIMLIB_ERR_NOMEM;
227         found_lte = new_lookup_table_entry();
228         if (!found_lte)
229                 goto out;
230
231         rspec = MALLOC(sizeof(struct wim_resource_spec));
232         if (!rspec)
233                 goto out;
234
235         lookup_table = ctx->wim->lookup_table;
236         memcpy(ctx->progress.extract.guid, ctx->wim->hdr.guid, WIM_GUID_LEN);
237         ctx->progress.extract.part_number = ctx->wim->hdr.part_number;
238         ctx->progress.extract.total_parts = ctx->wim->hdr.total_parts;
239         ret = extract_progress(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN);
240         if (ret)
241                 goto out;
242
243         while (ctx->num_streams_remaining) {
244                 struct wim_header_disk pwm_hdr;
245                 struct wim_lookup_table_entry *needed_lte;
246
247                 if (found_lte->resource_location != RESOURCE_NONEXISTENT)
248                         lte_unbind_wim_resource_spec(found_lte);
249                 ret = read_pwm_stream_header(ctx->wim, found_lte, rspec,
250                                              PWM_ALLOW_WIM_HDR, &pwm_hdr);
251                 if (ret)
252                         goto out;
253
254                 if ((found_lte->resource_location != RESOURCE_NONEXISTENT)
255                     && !(found_lte->flags & WIM_RESHDR_FLAG_METADATA)
256                     && (needed_lte = lookup_stream(lookup_table, found_lte->hash))
257                     && (needed_lte->out_refcnt))
258                 {
259                         needed_lte->offset_in_res = found_lte->offset_in_res;
260                         needed_lte->flags = found_lte->flags;
261                         needed_lte->size = found_lte->size;
262
263                         lte_unbind_wim_resource_spec(found_lte);
264                         lte_bind_wim_resource_spec(needed_lte, rspec);
265
266                         ret = (*cbs->begin_stream)(needed_lte,
267                                                    cbs->begin_stream_ctx);
268                         if (ret) {
269                                 lte_unbind_wim_resource_spec(needed_lte);
270                                 goto out;
271                         }
272
273                         ret = extract_stream(needed_lte, needed_lte->size,
274                                              cbs->consume_chunk,
275                                              cbs->consume_chunk_ctx);
276
277                         ret = (*cbs->end_stream)(needed_lte, ret,
278                                                  cbs->end_stream_ctx);
279                         lte_unbind_wim_resource_spec(needed_lte);
280                         if (ret)
281                                 goto out;
282                         ctx->num_streams_remaining--;
283                 } else if (found_lte->resource_location != RESOURCE_NONEXISTENT) {
284                         ret = skip_wim_stream(found_lte);
285                         if (ret)
286                                 goto out;
287                 } else {
288                         u16 part_number = le16_to_cpu(pwm_hdr.part_number);
289                         u16 total_parts = le16_to_cpu(pwm_hdr.total_parts);
290
291                         if (part_number != ctx->progress.extract.part_number ||
292                             total_parts != ctx->progress.extract.total_parts ||
293                             memcmp(pwm_hdr.guid, ctx->progress.extract.guid,
294                                    WIM_GUID_LEN))
295                         {
296                                 ctx->progress.extract.part_number = part_number;
297                                 ctx->progress.extract.total_parts = total_parts;
298                                 memcpy(ctx->progress.extract.guid,
299                                        pwm_hdr.guid, WIM_GUID_LEN);
300                                 ret = extract_progress(ctx,
301                                                        WIMLIB_PROGRESS_MSG_EXTRACT_SPWM_PART_BEGIN);
302                                 if (ret)
303                                         goto out;
304                         }
305                 }
306         }
307         ret = 0;
308 out:
309         if (found_lte && found_lte->resource_location != RESOURCE_IN_WIM)
310                 FREE(rspec);
311         free_lookup_table_entry(found_lte);
312         return ret;
313 }
314
315 /* Creates a temporary file opened for writing.  The open file descriptor is
316  * returned in @fd_ret and its name is returned in @name_ret (dynamically
317  * allocated).  */
318 static int
319 create_temporary_file(struct filedes *fd_ret, tchar **name_ret)
320 {
321         tchar *name;
322         int open_flags;
323         int raw_fd;
324
325 retry:
326         name = ttempnam(NULL, T("wimlib"));
327         if (!name) {
328                 ERROR_WITH_ERRNO("Failed to create temporary filename");
329                 return WIMLIB_ERR_NOMEM;
330         }
331
332         open_flags = O_WRONLY | O_CREAT | O_EXCL | O_BINARY;
333 #ifdef __WIN32__
334         open_flags |= _O_SHORT_LIVED;
335 #endif
336         raw_fd = topen(name, open_flags, 0600);
337
338         if (raw_fd < 0) {
339                 if (errno == EEXIST) {
340                         FREE(name);
341                         goto retry;
342                 }
343                 ERROR_WITH_ERRNO("Failed to create temporary file "
344                                  "\"%"TS"\"", name);
345                 FREE(name);
346                 return WIMLIB_ERR_OPEN;
347         }
348
349         filedes_init(fd_ret, raw_fd);
350         *name_ret = name;
351         return 0;
352 }
353
354 static int
355 begin_extract_stream_wrapper(struct wim_lookup_table_entry *lte, void *_ctx)
356 {
357         struct apply_ctx *ctx = _ctx;
358
359         ctx->cur_stream = lte;
360         ctx->cur_stream_offset = 0;
361
362         if (unlikely(lte->out_refcnt > MAX_OPEN_STREAMS))
363                 return create_temporary_file(&ctx->tmpfile_fd, &ctx->tmpfile_name);
364         else
365                 return (*ctx->saved_cbs->begin_stream)(lte, ctx->saved_cbs->begin_stream_ctx);
366 }
367
368 static int
369 extract_chunk_wrapper(const void *chunk, size_t size, void *_ctx)
370 {
371         struct apply_ctx *ctx = _ctx;
372         union wimlib_progress_info *progress = &ctx->progress;
373         int ret;
374
375         ctx->cur_stream_offset += size;
376
377         if (likely(ctx->supported_features.hard_links)) {
378                 progress->extract.completed_bytes +=
379                         (u64)size * ctx->cur_stream->out_refcnt;
380                 if (ctx->cur_stream_offset == ctx->cur_stream->size)
381                         progress->extract.completed_streams += ctx->cur_stream->out_refcnt;
382         } else {
383                 const struct stream_owner *owners = stream_owners(ctx->cur_stream);
384                 for (u32 i = 0; i < ctx->cur_stream->out_refcnt; i++) {
385                         const struct wim_inode *inode = owners[i].inode;
386                         const struct wim_dentry *dentry;
387
388                         list_for_each_entry(dentry,
389                                             &inode->i_extraction_aliases,
390                                             d_extraction_alias_node)
391                         {
392                                 progress->extract.completed_bytes += size;
393                                 if (ctx->cur_stream_offset == ctx->cur_stream->size)
394                                         progress->extract.completed_streams++;
395                         }
396                 }
397         }
398         if (progress->extract.completed_bytes >= ctx->next_progress) {
399
400                 ret = extract_progress(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS);
401                 if (ret)
402                         return ret;
403
404                 if (progress->extract.completed_bytes >=
405                     progress->extract.total_bytes)
406                 {
407                         ctx->next_progress = UINT64_MAX;
408                 } else {
409                         /* Send new message as soon as another 1/128 of the
410                          * total has been extracted.  (Arbitrary number.)  */
411                         ctx->next_progress =
412                                 progress->extract.completed_bytes +
413                                         progress->extract.total_bytes / 128;
414
415                         /* ... Unless that would be more than 5000000 bytes, in
416                          * which case send the next after the next 5000000
417                          * bytes.  (Another arbitrary number.)  */
418                         if (progress->extract.completed_bytes + 5000000 <
419                             ctx->next_progress)
420                                 ctx->next_progress =
421                                         progress->extract.completed_bytes + 5000000;
422
423                         /* ... But always send a message as soon as we're
424                          * completely done.  */
425                         if (progress->extract.total_bytes < ctx->next_progress)
426                                 ctx->next_progress = progress->extract.total_bytes;
427                 }
428         }
429
430         if (unlikely(filedes_valid(&ctx->tmpfile_fd))) {
431                 /* Just extracting to temporary file for now.  */
432                 ret = full_write(&ctx->tmpfile_fd, chunk, size);
433                 if (ret) {
434                         ERROR_WITH_ERRNO("Error writing data to "
435                                          "temporary file \"%"TS"\"",
436                                          ctx->tmpfile_name);
437                 }
438                 return ret;
439         } else {
440                 return (*ctx->saved_cbs->consume_chunk)(chunk, size,
441                                                         ctx->saved_cbs->consume_chunk_ctx);
442         }
443 }
444
445 static int
446 extract_from_tmpfile(const tchar *tmpfile_name, struct apply_ctx *ctx)
447 {
448         struct wim_lookup_table_entry tmpfile_lte;
449         struct wim_lookup_table_entry *orig_lte = ctx->cur_stream;
450         const struct read_stream_list_callbacks *cbs = ctx->saved_cbs;
451         int ret;
452         const u32 orig_refcnt = orig_lte->out_refcnt;
453
454         BUILD_BUG_ON(MAX_OPEN_STREAMS < ARRAY_LEN(orig_lte->inline_stream_owners));
455
456         struct stream_owner *owners = orig_lte->stream_owners;
457
458         /* Copy the stream's data from the temporary file to each of its
459          * destinations.
460          *
461          * This is executed only in the very uncommon case that a
462          * single-instance stream is being extracted to more than
463          * MAX_OPEN_STREAMS locations!  */
464
465         memcpy(&tmpfile_lte, orig_lte, sizeof(struct wim_lookup_table_entry));
466         tmpfile_lte.resource_location = RESOURCE_IN_FILE_ON_DISK;
467         tmpfile_lte.file_on_disk = ctx->tmpfile_name;
468         ret = 0;
469         for (u32 i = 0; i < orig_refcnt; i++) {
470
471                 /* Note: it usually doesn't matter whether we pass the original
472                  * stream entry to callbacks provided by the extraction backend
473                  * as opposed to the tmpfile stream entry, since they shouldn't
474                  * actually read data from the stream other than through the
475                  * read_stream_prefix() call below.  But for
476                  * WIMLIB_EXTRACT_FLAG_WIMBOOT mode on Windows it does matter
477                  * because it needs the original stream location in order to
478                  * create the external backing reference.  */
479
480                 orig_lte->out_refcnt = 1;
481                 orig_lte->inline_stream_owners[0] = owners[i];
482
483                 ret = (*cbs->begin_stream)(orig_lte, cbs->begin_stream_ctx);
484                 if (ret)
485                         break;
486
487                 /* Extra SHA-1 isn't necessary here, but it shouldn't hurt as
488                  * this case is very rare anyway.  */
489                 ret = extract_stream(&tmpfile_lte, tmpfile_lte.size,
490                                      cbs->consume_chunk,
491                                      cbs->consume_chunk_ctx);
492
493                 ret = (*cbs->end_stream)(orig_lte, ret, cbs->end_stream_ctx);
494                 if (ret)
495                         break;
496         }
497         FREE(owners);
498         orig_lte->out_refcnt = 0;
499         return ret;
500 }
501
502 static int
503 end_extract_stream_wrapper(struct wim_lookup_table_entry *stream,
504                            int status, void *_ctx)
505 {
506         struct apply_ctx *ctx = _ctx;
507
508         if (unlikely(filedes_valid(&ctx->tmpfile_fd))) {
509                 filedes_close(&ctx->tmpfile_fd);
510                 if (!status)
511                         status = extract_from_tmpfile(ctx->tmpfile_name, ctx);
512                 filedes_invalidate(&ctx->tmpfile_fd);
513                 tunlink(ctx->tmpfile_name);
514                 FREE(ctx->tmpfile_name);
515                 return status;
516         } else {
517                 return (*ctx->saved_cbs->end_stream)(stream, status,
518                                                      ctx->saved_cbs->end_stream_ctx);
519         }
520 }
521
522 /*
523  * Read the list of single-instance streams to extract and feed their data into
524  * the specified callback functions.
525  *
526  * This handles checksumming each stream.
527  *
528  * This also handles sending WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS.
529  *
530  * This also works if the WIM is being read from a pipe, whereas attempting to
531  * read streams directly (e.g. with read_full_stream_into_buf()) will not.
532  *
533  * This also will split up streams that will need to be extracted to more than
534  * MAX_OPEN_STREAMS locations, as measured by the 'out_refcnt' of each stream.
535  * Therefore, the apply_operations implementation need not worry about running
536  * out of file descriptors, unless it might open more than one file descriptor
537  * per nominal destination (e.g. Win32 currently might because the destination
538  * file system might not support hard links).
539  */
540 int
541 extract_stream_list(struct apply_ctx *ctx,
542                     const struct read_stream_list_callbacks *cbs)
543 {
544         struct read_stream_list_callbacks wrapper_cbs = {
545                 .begin_stream      = begin_extract_stream_wrapper,
546                 .begin_stream_ctx  = ctx,
547                 .consume_chunk     = extract_chunk_wrapper,
548                 .consume_chunk_ctx = ctx,
549                 .end_stream        = end_extract_stream_wrapper,
550                 .end_stream_ctx    = ctx,
551         };
552         ctx->saved_cbs = cbs;
553         if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) {
554                 return load_streams_from_pipe(ctx, &wrapper_cbs);
555         } else {
556                 return read_stream_list(&ctx->stream_list,
557                                         offsetof(struct wim_lookup_table_entry,
558                                                  extraction_list),
559                                         &wrapper_cbs, VERIFY_STREAM_HASHES);
560         }
561 }
562
563 /* Extract a WIM dentry to standard output.
564  *
565  * This obviously doesn't make sense in all cases.  We return an error if the
566  * dentry does not correspond to a regular file.  Otherwise we extract the
567  * unnamed data stream only.  */
568 static int
569 extract_dentry_to_stdout(struct wim_dentry *dentry,
570                          const struct wim_lookup_table *lookup_table)
571 {
572         struct wim_inode *inode = dentry->d_inode;
573         struct wim_lookup_table_entry *lte;
574         struct filedes _stdout;
575
576         if (inode->i_attributes & (FILE_ATTRIBUTE_REPARSE_POINT |
577                                    FILE_ATTRIBUTE_DIRECTORY))
578         {
579                 ERROR("\"%"TS"\" is not a regular file and therefore cannot be "
580                       "extracted to standard output", dentry_full_path(dentry));
581                 return WIMLIB_ERR_NOT_A_REGULAR_FILE;
582         }
583
584         lte = inode_unnamed_lte(inode, lookup_table);
585         if (!lte) {
586                 const u8 *hash = inode_unnamed_stream_hash(inode);
587                 if (!is_zero_hash(hash))
588                         return stream_not_found_error(inode, hash);
589                 return 0;
590         }
591
592         filedes_init(&_stdout, STDOUT_FILENO);
593         return extract_full_stream_to_fd(lte, &_stdout);
594 }
595
596 static int
597 extract_dentries_to_stdout(struct wim_dentry **dentries, size_t num_dentries,
598                            const struct wim_lookup_table *lookup_table)
599 {
600         for (size_t i = 0; i < num_dentries; i++) {
601                 int ret = extract_dentry_to_stdout(dentries[i], lookup_table);
602                 if (ret)
603                         return ret;
604         }
605         return 0;
606 }
607
608 /**********************************************************************/
609
610 /*
611  * Removes duplicate dentries from the array.
612  *
613  * Returns the new number of dentries, packed at the front of the array.
614  */
615 static size_t
616 remove_duplicate_trees(struct wim_dentry **trees, size_t num_trees)
617 {
618         size_t i, j = 0;
619         for (i = 0; i < num_trees; i++) {
620                 if (!trees[i]->tmp_flag) {
621                         /* Found distinct dentry.  */
622                         trees[i]->tmp_flag = 1;
623                         trees[j++] = trees[i];
624                 }
625         }
626         for (i = 0; i < j; i++)
627                 trees[i]->tmp_flag = 0;
628         return j;
629 }
630
631 /*
632  * Remove dentries that are descendants of other dentries in the array.
633  *
634  * Returns the new number of dentries, packed at the front of the array.
635  */
636 static size_t
637 remove_contained_trees(struct wim_dentry **trees, size_t num_trees)
638 {
639         size_t i, j = 0;
640         for (i = 0; i < num_trees; i++)
641                 trees[i]->tmp_flag = 1;
642         for (i = 0; i < num_trees; i++) {
643                 struct wim_dentry *d = trees[i];
644                 while (!dentry_is_root(d)) {
645                         d = d->d_parent;
646                         if (d->tmp_flag)
647                                 goto tree_contained;
648                 }
649                 trees[j++] = trees[i];
650                 continue;
651
652         tree_contained:
653                 trees[i]->tmp_flag = 0;
654         }
655
656         for (i = 0; i < j; i++)
657                 trees[i]->tmp_flag = 0;
658         return j;
659 }
660
661 static int
662 dentry_append_to_list(struct wim_dentry *dentry, void *_dentry_list)
663 {
664         struct list_head *dentry_list = _dentry_list;
665         list_add_tail(&dentry->d_extraction_list_node, dentry_list);
666         return 0;
667 }
668
669 static void
670 dentry_reset_extraction_list_node(struct wim_dentry *dentry)
671 {
672         dentry->d_extraction_list_node = (struct list_head){NULL, NULL};
673 }
674
675 static int
676 dentry_delete_from_list(struct wim_dentry *dentry, void *_ignore)
677 {
678         list_del(&dentry->d_extraction_list_node);
679         dentry_reset_extraction_list_node(dentry);
680         return 0;
681 }
682
683 /*
684  * Build the preliminary list of dentries to be extracted.
685  *
686  * The list maintains the invariant that if d1 and d2 are in the list and d1 is
687  * an ancestor of d2, then d1 appears before d2 in the list.
688  */
689 static void
690 build_dentry_list(struct list_head *dentry_list, struct wim_dentry **trees,
691                   size_t num_trees, bool add_ancestors)
692 {
693         INIT_LIST_HEAD(dentry_list);
694
695         /* Add the trees recursively.  */
696         for (size_t i = 0; i < num_trees; i++)
697                 for_dentry_in_tree(trees[i], dentry_append_to_list, dentry_list);
698
699         /* If requested, add ancestors of the trees.  */
700         if (add_ancestors) {
701                 for (size_t i = 0; i < num_trees; i++) {
702                         struct wim_dentry *dentry = trees[i];
703                         struct wim_dentry *ancestor;
704                         struct list_head *place_after;
705
706                         if (dentry_is_root(dentry))
707                                 continue;
708
709                         place_after = dentry_list;
710                         ancestor = dentry;
711                         do {
712                                 ancestor = ancestor->d_parent;
713                                 if (will_extract_dentry(ancestor)) {
714                                         place_after = &ancestor->d_extraction_list_node;
715                                         break;
716                                 }
717                         } while (!dentry_is_root(ancestor));
718
719                         ancestor = dentry;
720                         do {
721                                 ancestor = ancestor->d_parent;
722                                 if (will_extract_dentry(ancestor))
723                                         break;
724                                 list_add(&ancestor->d_extraction_list_node, place_after);
725                         } while (!dentry_is_root(ancestor));
726                 }
727         }
728 }
729
730 static void
731 destroy_dentry_list(struct list_head *dentry_list)
732 {
733         struct wim_dentry *dentry, *tmp;
734         struct wim_inode *inode;
735
736         list_for_each_entry_safe(dentry, tmp, dentry_list, d_extraction_list_node) {
737                 inode = dentry->d_inode;
738                 dentry_reset_extraction_list_node(dentry);
739                 inode->i_visited = 0;
740                 if ((void *)dentry->d_extraction_name != (void *)dentry->file_name)
741                         FREE(dentry->d_extraction_name);
742                 dentry->d_extraction_name = NULL;
743                 dentry->d_extraction_name_nchars = 0;
744         }
745 }
746
747 static void
748 destroy_stream_list(struct list_head *stream_list)
749 {
750         struct wim_lookup_table_entry *lte;
751
752         list_for_each_entry(lte, stream_list, extraction_list)
753                 if (lte->out_refcnt > ARRAY_LEN(lte->inline_stream_owners))
754                         FREE(lte->stream_owners);
755 }
756
757 #ifdef __WIN32__
758 static const utf16lechar replacement_char = cpu_to_le16(0xfffd);
759 #else
760 static const utf16lechar replacement_char = cpu_to_le16('?');
761 #endif
762
763 static bool
764 file_name_valid(utf16lechar *name, size_t num_chars, bool fix)
765 {
766         size_t i;
767
768         if (num_chars == 0)
769                 return true;
770         for (i = 0; i < num_chars; i++) {
771                 switch (name[i]) {
772         #ifdef __WIN32__
773                 case cpu_to_le16('\\'):
774                 case cpu_to_le16(':'):
775                 case cpu_to_le16('*'):
776                 case cpu_to_le16('?'):
777                 case cpu_to_le16('"'):
778                 case cpu_to_le16('<'):
779                 case cpu_to_le16('>'):
780                 case cpu_to_le16('|'):
781         #endif
782                 case cpu_to_le16('/'):
783                 case cpu_to_le16('\0'):
784                         if (fix)
785                                 name[i] = replacement_char;
786                         else
787                                 return false;
788                 }
789         }
790
791 #ifdef __WIN32__
792         if (name[num_chars - 1] == cpu_to_le16(' ') ||
793             name[num_chars - 1] == cpu_to_le16('.'))
794         {
795                 if (fix)
796                         name[num_chars - 1] = replacement_char;
797                 else
798                         return false;
799         }
800 #endif
801         return true;
802 }
803
804 static int
805 dentry_calculate_extraction_name(struct wim_dentry *dentry,
806                                  struct apply_ctx *ctx)
807 {
808         int ret;
809
810         if (!dentry_is_supported(dentry, &ctx->supported_features))
811                 goto skip_dentry;
812
813         if (dentry_is_root(dentry))
814                 return 0;
815
816 #ifdef WITH_NTFS_3G
817         if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
818                 dentry->d_extraction_name = dentry->file_name;
819                 dentry->d_extraction_name_nchars = dentry->file_name_nbytes /
820                                                    sizeof(utf16lechar);
821                 return 0;
822         }
823 #endif
824
825         if (!ctx->supported_features.case_sensitive_filenames) {
826                 struct wim_dentry *other;
827                 list_for_each_entry(other, &dentry->d_ci_conflict_list,
828                                     d_ci_conflict_list)
829                 {
830                         if (will_extract_dentry(other)) {
831                                 if (ctx->extract_flags &
832                                     WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS) {
833                                         WARNING("\"%"TS"\" has the same "
834                                                 "case-insensitive name as "
835                                                 "\"%"TS"\"; extracting "
836                                                 "dummy name instead",
837                                                 dentry_full_path(dentry),
838                                                 dentry_full_path(other));
839                                         goto out_replace;
840                                 } else {
841                                         WARNING("Not extracting \"%"TS"\": "
842                                                 "has same case-insensitive "
843                                                 "name as \"%"TS"\"",
844                                                 dentry_full_path(dentry),
845                                                 dentry_full_path(other));
846                                         goto skip_dentry;
847                                 }
848                         }
849                 }
850         }
851
852         if (file_name_valid(dentry->file_name, dentry->file_name_nbytes / 2, false)) {
853                 ret = utf16le_get_tstr(dentry->file_name,
854                                        dentry->file_name_nbytes,
855                                        (const tchar **)&dentry->d_extraction_name,
856                                        &dentry->d_extraction_name_nchars);
857                 dentry->d_extraction_name_nchars /= sizeof(tchar);
858                 return ret;
859         } else {
860                 if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES)
861                 {
862                         WARNING("\"%"TS"\" has an invalid filename "
863                                 "that is not supported on this platform; "
864                                 "extracting dummy name instead",
865                                 dentry_full_path(dentry));
866                         goto out_replace;
867                 } else {
868                         WARNING("Not extracting \"%"TS"\": has an invalid filename "
869                                 "that is not supported on this platform",
870                                 dentry_full_path(dentry));
871                         goto skip_dentry;
872                 }
873         }
874
875 out_replace:
876         {
877                 utf16lechar utf16_name_copy[dentry->file_name_nbytes / 2];
878
879                 memcpy(utf16_name_copy, dentry->file_name, dentry->file_name_nbytes);
880                 file_name_valid(utf16_name_copy, dentry->file_name_nbytes / 2, true);
881
882                 const tchar *tchar_name;
883                 size_t tchar_nchars;
884
885                 ret = utf16le_get_tstr(utf16_name_copy,
886                                        dentry->file_name_nbytes,
887                                        &tchar_name, &tchar_nchars);
888                 if (ret)
889                         return ret;
890
891                 tchar_nchars /= sizeof(tchar);
892
893                 size_t fixed_name_num_chars = tchar_nchars;
894                 tchar fixed_name[tchar_nchars + 50];
895
896                 tmemcpy(fixed_name, tchar_name, tchar_nchars);
897                 fixed_name_num_chars += tsprintf(fixed_name + tchar_nchars,
898                                                  T(" (invalid filename #%lu)"),
899                                                  ++ctx->invalid_sequence);
900
901                 utf16le_put_tstr(tchar_name);
902
903                 dentry->d_extraction_name = memdup(fixed_name,
904                                                    2 * fixed_name_num_chars + 2);
905                 if (!dentry->d_extraction_name)
906                         return WIMLIB_ERR_NOMEM;
907                 dentry->d_extraction_name_nchars = fixed_name_num_chars;
908         }
909         return 0;
910
911 skip_dentry:
912         for_dentry_in_tree(dentry, dentry_delete_from_list, NULL);
913         return 0;
914 }
915
916 /*
917  * Calculate the actual filename component at which each WIM dentry will be
918  * extracted, with special handling for dentries that are unsupported by the
919  * extraction backend or have invalid names.
920  *
921  * ctx->supported_features must be filled in.
922  *
923  * Possible error codes: WIMLIB_ERR_NOMEM, WIMLIB_ERR_INVALID_UTF16_STRING
924  */
925 static int
926 dentry_list_calculate_extraction_names(struct list_head *dentry_list,
927                                        struct apply_ctx *ctx)
928 {
929         struct list_head *prev, *cur;
930
931         /* Can't use list_for_each_entry() because a call to
932          * dentry_calculate_extraction_name() may delete the current dentry and
933          * its children from the list.  */
934
935         prev = dentry_list;
936         for (;;) {
937                 struct wim_dentry *dentry;
938                 int ret;
939
940                 cur = prev->next;
941                 if (cur == dentry_list)
942                         break;
943
944                 dentry = list_entry(cur, struct wim_dentry, d_extraction_list_node);
945
946                 ret = dentry_calculate_extraction_name(dentry, ctx);
947                 if (ret)
948                         return ret;
949
950                 if (prev->next == cur)
951                         prev = cur;
952                 else
953                         ; /* Current dentry and its children (which follow in
954                              the list) were deleted.  prev stays the same.  */
955         }
956         return 0;
957 }
958
959 static int
960 dentry_resolve_streams(struct wim_dentry *dentry, int extract_flags,
961                        struct wim_lookup_table *lookup_table)
962 {
963         struct wim_inode *inode = dentry->d_inode;
964         struct wim_lookup_table_entry *lte;
965         int ret;
966         bool force = false;
967
968         /* Special case:  when extracting from a pipe, the WIM lookup table is
969          * initially empty, so "resolving" an inode's streams is initially not
970          * possible.  However, we still need to keep track of which streams,
971          * identified by SHA1 message digests, need to be extracted, so we
972          * "resolve" the inode's streams anyway by allocating new entries.  */
973         if (extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE)
974                 force = true;
975         ret = inode_resolve_streams(inode, lookup_table, force);
976         if (ret)
977                 return ret;
978         for (u32 i = 0; i <= inode->i_num_ads; i++) {
979                 lte = inode_stream_lte_resolved(inode, i);
980                 if (lte)
981                         lte->out_refcnt = 0;
982         }
983         return 0;
984 }
985
986 /*
987  * For each dentry to be extracted, resolve all streams in the corresponding
988  * inode and set 'out_refcnt' in each to 0.
989  *
990  * Possible error codes: WIMLIB_ERR_RESOURCE_NOT_FOUND, WIMLIB_ERR_NOMEM.
991  */
992 static int
993 dentry_list_resolve_streams(struct list_head *dentry_list,
994                             struct apply_ctx *ctx)
995 {
996         struct wim_dentry *dentry;
997         int ret;
998
999         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1000                 ret = dentry_resolve_streams(dentry,
1001                                              ctx->extract_flags,
1002                                              ctx->wim->lookup_table);
1003                 if (ret)
1004                         return ret;
1005         }
1006         return 0;
1007 }
1008
1009 static int
1010 ref_stream(struct wim_lookup_table_entry *lte, u32 stream_idx,
1011            struct wim_dentry *dentry, struct apply_ctx *ctx)
1012 {
1013         struct wim_inode *inode = dentry->d_inode;
1014         struct stream_owner *stream_owners;
1015
1016         if (!lte)
1017                 return 0;
1018
1019         /* Tally the size only for each extraction of the stream (not hard
1020          * links).  */
1021         if (inode->i_visited && ctx->supported_features.hard_links)
1022                 return 0;
1023
1024         ctx->progress.extract.total_bytes += lte->size;
1025         ctx->progress.extract.total_streams++;
1026
1027         if (inode->i_visited)
1028                 return 0;
1029
1030         /* Add stream to the dentry_list only one time, even if it's going
1031          * to be extracted to multiple inodes.  */
1032         if (lte->out_refcnt == 0) {
1033                 list_add_tail(&lte->extraction_list, &ctx->stream_list);
1034                 ctx->num_streams_remaining++;
1035         }
1036
1037         /* If inode not yet been visited, append it to the stream_owners array.  */
1038         if (lte->out_refcnt < ARRAY_LEN(lte->inline_stream_owners)) {
1039                 stream_owners = lte->inline_stream_owners;
1040         } else {
1041                 struct stream_owner *prev_stream_owners;
1042                 size_t alloc_stream_owners;
1043
1044                 if (lte->out_refcnt == ARRAY_LEN(lte->inline_stream_owners)) {
1045                         prev_stream_owners = NULL;
1046                         alloc_stream_owners = ARRAY_LEN(lte->inline_stream_owners);
1047                 } else {
1048                         prev_stream_owners = lte->stream_owners;
1049                         alloc_stream_owners = lte->alloc_stream_owners;
1050                 }
1051
1052                 if (lte->out_refcnt == alloc_stream_owners) {
1053                         alloc_stream_owners *= 2;
1054                         stream_owners = REALLOC(prev_stream_owners,
1055                                                alloc_stream_owners *
1056                                                 sizeof(stream_owners[0]));
1057                         if (!stream_owners)
1058                                 return WIMLIB_ERR_NOMEM;
1059                         if (!prev_stream_owners) {
1060                                 memcpy(stream_owners,
1061                                        lte->inline_stream_owners,
1062                                        sizeof(lte->inline_stream_owners));
1063                         }
1064                         lte->stream_owners = stream_owners;
1065                         lte->alloc_stream_owners = alloc_stream_owners;
1066                 }
1067                 stream_owners = lte->stream_owners;
1068         }
1069         stream_owners[lte->out_refcnt].inode = inode;
1070         if (stream_idx == 0) {
1071                 stream_owners[lte->out_refcnt].stream_name = NULL;
1072         } else {
1073                 stream_owners[lte->out_refcnt].stream_name =
1074                         inode->i_ads_entries[stream_idx - 1].stream_name;
1075         }
1076         lte->out_refcnt++;
1077         return 0;
1078 }
1079
1080 static int
1081 ref_unnamed_stream(struct wim_dentry *dentry, struct apply_ctx *ctx)
1082 {
1083         struct wim_inode *inode = dentry->d_inode;
1084         int ret;
1085         u16 stream_idx;
1086         struct wim_lookup_table_entry *stream;
1087
1088         if (unlikely(inode_is_encrypted_directory(inode)))
1089                 return 0;
1090
1091         if (unlikely(ctx->apply_ops->will_externally_back)) {
1092                 ret = (*ctx->apply_ops->will_externally_back)(dentry, ctx);
1093                 if (ret >= 0) {
1094                         if (ret) /* Error */
1095                                 return ret;
1096                         /* Will externally back */
1097                         return 0;
1098                 }
1099                 /* Won't externally back */
1100         }
1101
1102         stream = inode_unnamed_stream_resolved(inode, &stream_idx);
1103         return ref_stream(stream, stream_idx, dentry, ctx);
1104 }
1105
1106 static int
1107 dentry_ref_streams(struct wim_dentry *dentry, struct apply_ctx *ctx)
1108 {
1109         struct wim_inode *inode = dentry->d_inode;
1110         int ret;
1111
1112         /* The unnamed data stream will almost always be extracted, but there
1113          * exist cases in which it won't be.  */
1114         ret = ref_unnamed_stream(dentry, ctx);
1115         if (ret)
1116                 return ret;
1117
1118         /* Named data streams will be extracted only if supported in the current
1119          * extraction mode and volume, and to avoid complications, if not doing
1120          * a linked extraction.  */
1121         if (ctx->supported_features.named_data_streams) {
1122                 for (u16 i = 0; i < inode->i_num_ads; i++) {
1123                         if (!ads_entry_is_named_stream(&inode->i_ads_entries[i]))
1124                                 continue;
1125                         ret = ref_stream(inode->i_ads_entries[i].lte, i + 1,
1126                                          dentry, ctx);
1127                         if (ret)
1128                                 return ret;
1129                 }
1130         }
1131         inode->i_visited = 1;
1132         return 0;
1133 }
1134
1135 /*
1136  * For each dentry to be extracted, iterate through the data streams of the
1137  * corresponding inode.  For each such stream that is not to be ignored due to
1138  * the supported features or extraction flags, add it to the list of streams to
1139  * be extracted (ctx->stream_list) if not already done so.
1140  *
1141  * Also builds a mapping from each stream to the inodes referencing it.
1142  *
1143  * This also initializes the extract progress info with byte and stream
1144  * information.
1145  *
1146  * ctx->supported_features must be filled in.
1147  *
1148  * Possible error codes: WIMLIB_ERR_NOMEM.
1149  */
1150 static int
1151 dentry_list_ref_streams(struct list_head *dentry_list, struct apply_ctx *ctx)
1152 {
1153         struct wim_dentry *dentry;
1154         int ret;
1155
1156         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1157                 ret = dentry_ref_streams(dentry, ctx);
1158                 if (ret)
1159                         return ret;
1160         }
1161         list_for_each_entry(dentry, dentry_list, d_extraction_list_node)
1162                 dentry->d_inode->i_visited = 0;
1163         return 0;
1164 }
1165
1166 static void
1167 dentry_list_build_inode_alias_lists(struct list_head *dentry_list)
1168 {
1169         struct wim_dentry *dentry;
1170         struct wim_inode *inode;
1171
1172         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1173                 inode = dentry->d_inode;
1174                 if (!inode->i_visited)
1175                         INIT_LIST_HEAD(&inode->i_extraction_aliases);
1176                 list_add_tail(&dentry->d_extraction_alias_node,
1177                               &inode->i_extraction_aliases);
1178                 inode->i_visited = 1;
1179         }
1180         list_for_each_entry(dentry, dentry_list, d_extraction_list_node)
1181                 dentry->d_inode->i_visited = 0;
1182 }
1183
1184 static void
1185 inode_tally_features(const struct wim_inode *inode,
1186                      struct wim_features *features)
1187 {
1188         if (inode->i_attributes & FILE_ATTRIBUTE_ARCHIVE)
1189                 features->archive_files++;
1190         if (inode->i_attributes & FILE_ATTRIBUTE_HIDDEN)
1191                 features->hidden_files++;
1192         if (inode->i_attributes & FILE_ATTRIBUTE_SYSTEM)
1193                 features->system_files++;
1194         if (inode->i_attributes & FILE_ATTRIBUTE_COMPRESSED)
1195                 features->compressed_files++;
1196         if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
1197                 if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
1198                         features->encrypted_directories++;
1199                 else
1200                         features->encrypted_files++;
1201         }
1202         if (inode->i_attributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
1203                 features->not_context_indexed_files++;
1204         if (inode->i_attributes & FILE_ATTRIBUTE_SPARSE_FILE)
1205                 features->sparse_files++;
1206         if (inode_has_named_stream(inode))
1207                 features->named_data_streams++;
1208         if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1209                 features->reparse_points++;
1210                 if (inode_is_symlink(inode))
1211                         features->symlink_reparse_points++;
1212                 else
1213                         features->other_reparse_points++;
1214         }
1215         if (inode->i_security_id != -1)
1216                 features->security_descriptors++;
1217         if (inode_has_unix_data(inode))
1218                 features->unix_data++;
1219 }
1220
1221 /* Tally features necessary to extract a dentry and the corresponding inode.  */
1222 static void
1223 dentry_tally_features(struct wim_dentry *dentry, struct wim_features *features)
1224 {
1225         struct wim_inode *inode = dentry->d_inode;
1226
1227         if (dentry_has_short_name(dentry))
1228                 features->short_names++;
1229
1230         if (inode->i_visited) {
1231                 features->hard_links++;
1232         } else {
1233                 inode_tally_features(inode, features);
1234                 inode->i_visited = 1;
1235         }
1236 }
1237
1238 /* Tally the features necessary to extract the specified dentries.  */
1239 static void
1240 dentry_list_get_features(struct list_head *dentry_list,
1241                          struct wim_features *features)
1242 {
1243         struct wim_dentry *dentry;
1244
1245         list_for_each_entry(dentry, dentry_list, d_extraction_list_node)
1246                 dentry_tally_features(dentry, features);
1247
1248         list_for_each_entry(dentry, dentry_list, d_extraction_list_node)
1249                 dentry->d_inode->i_visited = 0;
1250 }
1251
1252 static int
1253 do_feature_check(const struct wim_features *required_features,
1254                  const struct wim_features *supported_features,
1255                  int extract_flags)
1256 {
1257         /* File attributes.  */
1258         if (!(extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)) {
1259                 /* Note: Don't bother the user about FILE_ATTRIBUTE_ARCHIVE.
1260                  * We're an archive program, so theoretically we can do what we
1261                  * want with it.  */
1262
1263                 if (required_features->hidden_files &&
1264                     !supported_features->hidden_files)
1265                         WARNING("Ignoring FILE_ATTRIBUTE_HIDDEN of %lu files",
1266                                 required_features->hidden_files);
1267
1268                 if (required_features->system_files &&
1269                     !supported_features->system_files)
1270                         WARNING("Ignoring FILE_ATTRIBUTE_SYSTEM of %lu files",
1271                                 required_features->system_files);
1272
1273                 if (required_features->compressed_files &&
1274                     !supported_features->compressed_files)
1275                         WARNING("Ignoring FILE_ATTRIBUTE_COMPRESSED of %lu files",
1276                                 required_features->compressed_files);
1277
1278                 if (required_features->not_context_indexed_files &&
1279                     !supported_features->not_context_indexed_files)
1280                         WARNING("Ignoring FILE_ATTRIBUTE_NOT_CONTENT_INDEXED of %lu files",
1281                                 required_features->not_context_indexed_files);
1282
1283                 if (required_features->sparse_files &&
1284                     !supported_features->sparse_files)
1285                         WARNING("Ignoring FILE_ATTRIBUTE_SPARSE_FILE of %lu files",
1286                                 required_features->sparse_files);
1287
1288                 if (required_features->encrypted_directories &&
1289                     !supported_features->encrypted_directories)
1290                         WARNING("Ignoring FILE_ATTRIBUTE_ENCRYPTED of %lu directories",
1291                                 required_features->encrypted_directories);
1292         }
1293
1294         /* Encrypted files.  */
1295         if (required_features->encrypted_files &&
1296             !supported_features->encrypted_files)
1297                 WARNING("Ignoring %lu encrypted files",
1298                         required_features->encrypted_files);
1299
1300         /* Named data streams.  */
1301         if (required_features->named_data_streams &&
1302             (!supported_features->named_data_streams))
1303                 WARNING("Ignoring named data streams of %lu files",
1304                         required_features->named_data_streams);
1305
1306         /* Hard links.  */
1307         if (required_features->hard_links && !supported_features->hard_links)
1308                 WARNING("Extracting %lu hard links as independent files",
1309                         required_features->hard_links);
1310
1311         /* Symbolic links and reparse points.  */
1312         if ((extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS) &&
1313             required_features->symlink_reparse_points &&
1314             !supported_features->symlink_reparse_points &&
1315             !supported_features->reparse_points)
1316         {
1317                 ERROR("Extraction backend does not support symbolic links!");
1318                 return WIMLIB_ERR_UNSUPPORTED;
1319         }
1320         if (required_features->reparse_points &&
1321             !supported_features->reparse_points)
1322         {
1323                 if (supported_features->symlink_reparse_points) {
1324                         if (required_features->other_reparse_points) {
1325                                 WARNING("Ignoring %lu non-symlink/junction "
1326                                         "reparse point files",
1327                                         required_features->other_reparse_points);
1328                         }
1329                 } else {
1330                         WARNING("Ignoring %lu reparse point files",
1331                                 required_features->reparse_points);
1332                 }
1333         }
1334
1335         /* Security descriptors.  */
1336         if (((extract_flags & (WIMLIB_EXTRACT_FLAG_STRICT_ACLS |
1337                                WIMLIB_EXTRACT_FLAG_UNIX_DATA))
1338              == WIMLIB_EXTRACT_FLAG_STRICT_ACLS) &&
1339             required_features->security_descriptors &&
1340             !supported_features->security_descriptors)
1341         {
1342                 ERROR("Extraction backend does not support security descriptors!");
1343                 return WIMLIB_ERR_UNSUPPORTED;
1344         }
1345         if (!(extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS) &&
1346             required_features->security_descriptors &&
1347             !supported_features->security_descriptors)
1348                 WARNING("Ignoring Windows NT security descriptors of %lu files",
1349                         required_features->security_descriptors);
1350
1351         /* UNIX data.  */
1352         if ((extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) &&
1353             required_features->unix_data && !supported_features->unix_data)
1354         {
1355                 ERROR("Extraction backend does not support UNIX data!");
1356                 return WIMLIB_ERR_UNSUPPORTED;
1357         }
1358
1359         if (required_features->unix_data &&
1360             !(extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA))
1361         {
1362                 WARNING("Ignoring UNIX metadata of %lu files",
1363                         required_features->unix_data);
1364         }
1365
1366         /* DOS Names.  */
1367         if (required_features->short_names &&
1368             !supported_features->short_names)
1369         {
1370                 if (extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES) {
1371                         ERROR("Extraction backend does not support DOS names!");
1372                         return WIMLIB_ERR_UNSUPPORTED;
1373                 }
1374                 WARNING("Ignoring DOS names of %lu files",
1375                         required_features->short_names);
1376         }
1377
1378         /* Timestamps.  */
1379         if ((extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS) &&
1380             !supported_features->timestamps)
1381         {
1382                 ERROR("Extraction backend does not support timestamps!");
1383                 return WIMLIB_ERR_UNSUPPORTED;
1384         }
1385
1386         return 0;
1387 }
1388
1389 static const struct apply_operations *
1390 select_apply_operations(int extract_flags)
1391 {
1392 #ifdef WITH_NTFS_3G
1393         if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS)
1394                 return &ntfs_3g_apply_ops;
1395 #endif
1396 #ifdef __WIN32__
1397         return &win32_apply_ops;
1398 #else
1399         return &unix_apply_ops;
1400 #endif
1401 }
1402
1403 static int
1404 extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees,
1405               const tchar *target, int extract_flags)
1406 {
1407         const struct apply_operations *ops;
1408         struct apply_ctx *ctx;
1409         int ret;
1410         LIST_HEAD(dentry_list);
1411
1412         if (extract_flags & WIMLIB_EXTRACT_FLAG_TO_STDOUT) {
1413                 ret = extract_dentries_to_stdout(trees, num_trees,
1414                                                  wim->lookup_table);
1415                 goto out;
1416         }
1417
1418         num_trees = remove_duplicate_trees(trees, num_trees);
1419         num_trees = remove_contained_trees(trees, num_trees);
1420
1421         ops = select_apply_operations(extract_flags);
1422
1423         if (num_trees > 1 && ops->single_tree_only) {
1424                 ERROR("Extracting multiple directory trees "
1425                       "at once is not supported in %s extraction mode!",
1426                       ops->name);
1427                 ret = WIMLIB_ERR_UNSUPPORTED;
1428                 goto out;
1429         }
1430
1431         ctx = CALLOC(1, ops->context_size);
1432         if (!ctx) {
1433                 ret = WIMLIB_ERR_NOMEM;
1434                 goto out;
1435         }
1436
1437         ctx->wim = wim;
1438         ctx->target = target;
1439         ctx->target_nchars = tstrlen(target);
1440         ctx->extract_flags = extract_flags;
1441         if (ctx->wim->progfunc) {
1442                 ctx->progfunc = ctx->wim->progfunc;
1443                 ctx->progctx = ctx->wim->progctx;
1444                 ctx->progress.extract.image = wim->current_image;
1445                 ctx->progress.extract.extract_flags = (extract_flags &
1446                                                        WIMLIB_EXTRACT_MASK_PUBLIC);
1447                 ctx->progress.extract.wimfile_name = wim->filename;
1448                 ctx->progress.extract.image_name = wimlib_get_image_name(wim,
1449                                                                          wim->current_image);
1450                 ctx->progress.extract.target = target;
1451         }
1452         INIT_LIST_HEAD(&ctx->stream_list);
1453         filedes_invalidate(&ctx->tmpfile_fd);
1454         ctx->apply_ops = ops;
1455
1456         ret = (*ops->get_supported_features)(target, &ctx->supported_features);
1457         if (ret)
1458                 goto out_cleanup;
1459
1460         build_dentry_list(&dentry_list, trees, num_trees,
1461                           !(extract_flags &
1462                             WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE));
1463
1464         dentry_list_get_features(&dentry_list, &ctx->required_features);
1465
1466         ret = do_feature_check(&ctx->required_features, &ctx->supported_features,
1467                                ctx->extract_flags);
1468         if (ret)
1469                 goto out_cleanup;
1470
1471         ret = dentry_list_calculate_extraction_names(&dentry_list, ctx);
1472         if (ret)
1473                 goto out_cleanup;
1474
1475         ret = dentry_list_resolve_streams(&dentry_list, ctx);
1476         if (ret)
1477                 goto out_cleanup;
1478
1479         ret = dentry_list_ref_streams(&dentry_list, ctx);
1480         if (ret)
1481                 goto out_cleanup;
1482
1483         dentry_list_build_inode_alias_lists(&dentry_list);
1484
1485         if (extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) {
1486                 /* When extracting from a pipe, the number of bytes of data to
1487                  * extract can't be determined in the normal way (examining the
1488                  * lookup table), since at this point all we have is a set of
1489                  * SHA1 message digests of streams that need to be extracted.
1490                  * However, we can get a reasonably accurate estimate by taking
1491                  * <TOTALBYTES> from the corresponding <IMAGE> in the WIM XML
1492                  * data.  This does assume that a full image is being extracted,
1493                  * but currently there is no API for doing otherwise.  (Also,
1494                  * subtract <HARDLINKBYTES> from this if hard links are
1495                  * supported by the extraction mode.)  */
1496                 ctx->progress.extract.total_bytes =
1497                         wim_info_get_image_total_bytes(wim->wim_info,
1498                                                        wim->current_image);
1499                 if (ctx->supported_features.hard_links) {
1500                         ctx->progress.extract.total_bytes -=
1501                                 wim_info_get_image_hard_link_bytes(wim->wim_info,
1502                                                                    wim->current_image);
1503                 }
1504         }
1505
1506         ret = extract_progress(ctx,
1507                                ((extract_flags & WIMLIB_EXTRACT_FLAG_IMAGEMODE) ?
1508                                        WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN :
1509                                        WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN));
1510         if (ret)
1511                 goto out_cleanup;
1512
1513         ret = (*ops->extract)(&dentry_list, ctx);
1514         if (ret)
1515                 goto out_cleanup;
1516
1517         if (ctx->progress.extract.completed_bytes <
1518             ctx->progress.extract.total_bytes)
1519         {
1520                 ctx->progress.extract.completed_bytes =
1521                         ctx->progress.extract.total_bytes;
1522                 ret = extract_progress(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS);
1523                 if (ret)
1524                         goto out_cleanup;
1525         }
1526
1527         ret = extract_progress(ctx,
1528                                ((extract_flags & WIMLIB_EXTRACT_FLAG_IMAGEMODE) ?
1529                                        WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END :
1530                                        WIMLIB_PROGRESS_MSG_EXTRACT_TREE_END));
1531 out_cleanup:
1532         destroy_stream_list(&ctx->stream_list);
1533         destroy_dentry_list(&dentry_list);
1534         FREE(ctx);
1535 out:
1536         return ret;
1537 }
1538
1539 static int
1540 mkdir_if_needed(const tchar *target)
1541 {
1542         if (!tmkdir(target, 0755))
1543                 return 0;
1544
1545         if (errno == EEXIST)
1546                 return 0;
1547
1548 #ifdef __WIN32__
1549         /* _wmkdir() fails with EACCES if called on a drive root directory.  */
1550         if (errno == EACCES)
1551                 return 0;
1552 #endif
1553
1554         ERROR_WITH_ERRNO("Failed to create directory \"%"TS"\"", target);
1555         return WIMLIB_ERR_MKDIR;
1556 }
1557
1558 /* Make sure the extraction flags make sense, and update them if needed.  */
1559 static int
1560 check_extract_flags(const WIMStruct *wim, int *extract_flags_p)
1561 {
1562         int extract_flags = *extract_flags_p;
1563
1564         /* Check for invalid flag combinations  */
1565
1566         if ((extract_flags &
1567              (WIMLIB_EXTRACT_FLAG_NO_ACLS |
1568               WIMLIB_EXTRACT_FLAG_STRICT_ACLS)) == (WIMLIB_EXTRACT_FLAG_NO_ACLS |
1569                                                     WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
1570                 return WIMLIB_ERR_INVALID_PARAM;
1571
1572         if ((extract_flags &
1573              (WIMLIB_EXTRACT_FLAG_RPFIX |
1574               WIMLIB_EXTRACT_FLAG_NORPFIX)) == (WIMLIB_EXTRACT_FLAG_RPFIX |
1575                                                 WIMLIB_EXTRACT_FLAG_NORPFIX))
1576                 return WIMLIB_ERR_INVALID_PARAM;
1577
1578 #ifndef WITH_NTFS_3G
1579         if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
1580                 ERROR("wimlib was compiled without support for NTFS-3g, so\n"
1581                       "        it cannot apply a WIM image directly to an NTFS volume.");
1582                 return WIMLIB_ERR_UNSUPPORTED;
1583         }
1584 #endif
1585
1586         if (extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT) {
1587 #ifdef __WIN32__
1588                 if (!wim->filename)
1589                         return WIMLIB_ERR_NO_FILENAME;
1590 #else
1591                 ERROR("WIMBoot extraction is only supported on Windows!");
1592                 return WIMLIB_ERR_UNSUPPORTED;
1593 #endif
1594         }
1595
1596
1597         if ((extract_flags & (WIMLIB_EXTRACT_FLAG_RPFIX |
1598                               WIMLIB_EXTRACT_FLAG_NORPFIX |
1599                               WIMLIB_EXTRACT_FLAG_IMAGEMODE)) ==
1600                                         WIMLIB_EXTRACT_FLAG_IMAGEMODE)
1601         {
1602                 /* For full-image extraction, do reparse point fixups by default
1603                  * if the WIM header says they are enabled.  */
1604                 if (wim->hdr.flags & WIM_HDR_FLAG_RP_FIX)
1605                         extract_flags |= WIMLIB_EXTRACT_FLAG_RPFIX;
1606         }
1607
1608         *extract_flags_p = extract_flags;
1609         return 0;
1610 }
1611
1612 static u32
1613 get_wildcard_flags(int extract_flags)
1614 {
1615         u32 wildcard_flags = 0;
1616
1617         if (extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_GLOB)
1618                 wildcard_flags |= WILDCARD_FLAG_ERROR_IF_NO_MATCH;
1619         else
1620                 wildcard_flags |= WILDCARD_FLAG_WARN_IF_NO_MATCH;
1621
1622         if (default_ignore_case)
1623                 wildcard_flags |= WILDCARD_FLAG_CASE_INSENSITIVE;
1624
1625         return wildcard_flags;
1626 }
1627
1628 struct append_dentry_ctx {
1629         struct wim_dentry **dentries;
1630         size_t num_dentries;
1631         size_t num_alloc_dentries;
1632 };
1633
1634 static int
1635 append_dentry_cb(struct wim_dentry *dentry, void *_ctx)
1636 {
1637         struct append_dentry_ctx *ctx = _ctx;
1638
1639         if (ctx->num_dentries == ctx->num_alloc_dentries) {
1640                 struct wim_dentry **new_dentries;
1641                 size_t new_length;
1642
1643                 new_length = max(ctx->num_alloc_dentries + 8,
1644                                  ctx->num_alloc_dentries * 3 / 2);
1645                 new_dentries = REALLOC(ctx->dentries,
1646                                        new_length * sizeof(ctx->dentries[0]));
1647                 if (new_dentries == NULL)
1648                         return WIMLIB_ERR_NOMEM;
1649                 ctx->dentries = new_dentries;
1650                 ctx->num_alloc_dentries = new_length;
1651         }
1652         ctx->dentries[ctx->num_dentries++] = dentry;
1653         return 0;
1654 }
1655
1656 static int
1657 do_wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target,
1658                         const tchar * const *paths, size_t num_paths,
1659                         int extract_flags)
1660 {
1661         int ret;
1662         struct wim_dentry **trees;
1663         size_t num_trees;
1664
1665         if (wim == NULL || target == NULL || target[0] == T('\0') ||
1666             (num_paths != 0 && paths == NULL))
1667                 return WIMLIB_ERR_INVALID_PARAM;
1668
1669         ret = check_extract_flags(wim, &extract_flags);
1670         if (ret)
1671                 return ret;
1672
1673         ret = select_wim_image(wim, image);
1674         if (ret)
1675                 return ret;
1676
1677         ret = wim_checksum_unhashed_streams(wim);
1678         if (ret)
1679                 return ret;
1680
1681         if ((extract_flags & (WIMLIB_EXTRACT_FLAG_NTFS |
1682                               WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE)) ==
1683             (WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE))
1684         {
1685                 ret = mkdir_if_needed(target);
1686                 if (ret)
1687                         return ret;
1688         }
1689
1690         if (extract_flags & WIMLIB_EXTRACT_FLAG_GLOB_PATHS) {
1691
1692                 struct append_dentry_ctx append_dentry_ctx = {
1693                         .dentries = NULL,
1694                         .num_dentries = 0,
1695                         .num_alloc_dentries = 0,
1696                 };
1697
1698                 u32 wildcard_flags = get_wildcard_flags(extract_flags);
1699
1700                 for (size_t i = 0; i < num_paths; i++) {
1701                         tchar *path = canonicalize_wim_path(paths[i]);
1702                         if (path == NULL) {
1703                                 ret = WIMLIB_ERR_NOMEM;
1704                                 trees = append_dentry_ctx.dentries;
1705                                 goto out_free_trees;
1706                         }
1707                         ret = expand_wildcard(wim, path,
1708                                               append_dentry_cb,
1709                                               &append_dentry_ctx,
1710                                               wildcard_flags);
1711                         FREE(path);
1712                         if (ret) {
1713                                 trees = append_dentry_ctx.dentries;
1714                                 goto out_free_trees;
1715                         }
1716                 }
1717                 trees = append_dentry_ctx.dentries;
1718                 num_trees = append_dentry_ctx.num_dentries;
1719         } else {
1720                 trees = MALLOC(num_paths * sizeof(trees[0]));
1721                 if (trees == NULL)
1722                         return WIMLIB_ERR_NOMEM;
1723
1724                 for (size_t i = 0; i < num_paths; i++) {
1725
1726                         tchar *path = canonicalize_wim_path(paths[i]);
1727                         if (path == NULL) {
1728                                 ret = WIMLIB_ERR_NOMEM;
1729                                 goto out_free_trees;
1730                         }
1731
1732                         trees[i] = get_dentry(wim, path,
1733                                               WIMLIB_CASE_PLATFORM_DEFAULT);
1734                         FREE(path);
1735                         if (trees[i] == NULL) {
1736                                   ERROR("Path \"%"TS"\" does not exist "
1737                                         "in WIM image %d",
1738                                         paths[i], wim->current_image);
1739                                   ret = WIMLIB_ERR_PATH_DOES_NOT_EXIST;
1740                                   goto out_free_trees;
1741                         }
1742                 }
1743                 num_trees = num_paths;
1744         }
1745
1746         if (num_trees == 0) {
1747                 ret = 0;
1748                 goto out_free_trees;
1749         }
1750
1751         ret = extract_trees(wim, trees, num_trees, target, extract_flags);
1752 out_free_trees:
1753         FREE(trees);
1754         return ret;
1755 }
1756
1757 static int
1758 extract_single_image(WIMStruct *wim, int image,
1759                      const tchar *target, int extract_flags)
1760 {
1761         const tchar *path = WIMLIB_WIM_ROOT_PATH;
1762         extract_flags |= WIMLIB_EXTRACT_FLAG_IMAGEMODE;
1763         return do_wimlib_extract_paths(wim, image, target, &path, 1, extract_flags);
1764 }
1765
1766 static const tchar * const filename_forbidden_chars =
1767 T(
1768 #ifdef __WIN32__
1769 "<>:\"/\\|?*"
1770 #else
1771 "/"
1772 #endif
1773 );
1774
1775 /* This function checks if it is okay to use a WIM image's name as a directory
1776  * name.  */
1777 static bool
1778 image_name_ok_as_dir(const tchar *image_name)
1779 {
1780         return image_name && *image_name &&
1781                 !tstrpbrk(image_name, filename_forbidden_chars) &&
1782                 tstrcmp(image_name, T(".")) &&
1783                 tstrcmp(image_name, T(".."));
1784 }
1785
1786 /* Extracts all images from the WIM to the directory @target, with the images
1787  * placed in subdirectories named by their image names. */
1788 static int
1789 extract_all_images(WIMStruct *wim, const tchar *target, int extract_flags)
1790 {
1791         size_t image_name_max_len = max(xml_get_max_image_name_len(wim), 20);
1792         size_t output_path_len = tstrlen(target);
1793         tchar buf[output_path_len + 1 + image_name_max_len + 1];
1794         int ret;
1795         int image;
1796         const tchar *image_name;
1797
1798         if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
1799                 ERROR("Cannot extract multiple images in NTFS extraction mode.");
1800                 return WIMLIB_ERR_INVALID_PARAM;
1801         }
1802
1803         ret = mkdir_if_needed(target);
1804         if (ret)
1805                 return ret;
1806         tmemcpy(buf, target, output_path_len);
1807         buf[output_path_len] = OS_PREFERRED_PATH_SEPARATOR;
1808         for (image = 1; image <= wim->hdr.image_count; image++) {
1809                 image_name = wimlib_get_image_name(wim, image);
1810                 if (image_name_ok_as_dir(image_name)) {
1811                         tstrcpy(buf + output_path_len + 1, image_name);
1812                 } else {
1813                         /* Image name is empty or contains forbidden characters.
1814                          * Use image number instead. */
1815                         tsprintf(buf + output_path_len + 1, T("%d"), image);
1816                 }
1817                 ret = extract_single_image(wim, image, buf, extract_flags);
1818                 if (ret)
1819                         return ret;
1820         }
1821         return 0;
1822 }
1823
1824 static int
1825 do_wimlib_extract_image(WIMStruct *wim, int image, const tchar *target,
1826                         int extract_flags)
1827 {
1828         if (extract_flags & (WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE |
1829                              WIMLIB_EXTRACT_FLAG_TO_STDOUT |
1830                              WIMLIB_EXTRACT_FLAG_GLOB_PATHS))
1831                 return WIMLIB_ERR_INVALID_PARAM;
1832
1833         if (image == WIMLIB_ALL_IMAGES)
1834                 return extract_all_images(wim, target, extract_flags);
1835         else
1836                 return extract_single_image(wim, image, target, extract_flags);
1837 }
1838
1839
1840 /****************************************************************************
1841  *                          Extraction API                                  *
1842  ****************************************************************************/
1843
1844 WIMLIBAPI int
1845 wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target,
1846                      const tchar * const *paths, size_t num_paths,
1847                      int extract_flags)
1848 {
1849         if (extract_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC)
1850                 return WIMLIB_ERR_INVALID_PARAM;
1851
1852         return do_wimlib_extract_paths(wim, image, target, paths, num_paths,
1853                                        extract_flags);
1854 }
1855
1856 WIMLIBAPI int
1857 wimlib_extract_pathlist(WIMStruct *wim, int image, const tchar *target,
1858                         const tchar *path_list_file, int extract_flags)
1859 {
1860         int ret;
1861         tchar **paths;
1862         size_t num_paths;
1863         void *mem;
1864
1865         ret = read_path_list_file(path_list_file, &paths, &num_paths, &mem);
1866         if (ret) {
1867                 ERROR("Failed to read path list file \"%"TS"\"",
1868                       path_list_file);
1869                 return ret;
1870         }
1871
1872         ret = wimlib_extract_paths(wim, image, target,
1873                                    (const tchar * const *)paths, num_paths,
1874                                    extract_flags);
1875         FREE(paths);
1876         FREE(mem);
1877         return ret;
1878 }
1879
1880 WIMLIBAPI int
1881 wimlib_extract_image_from_pipe_with_progress(int pipe_fd,
1882                                              const tchar *image_num_or_name,
1883                                              const tchar *target,
1884                                              int extract_flags,
1885                                              wimlib_progress_func_t progfunc,
1886                                              void *progctx)
1887 {
1888         int ret;
1889         WIMStruct *pwm;
1890         struct filedes *in_fd;
1891         int image;
1892         unsigned i;
1893
1894         if (extract_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC)
1895                 return WIMLIB_ERR_INVALID_PARAM;
1896
1897         /* Read the WIM header from the pipe and get a WIMStruct to represent
1898          * the pipable WIM.  Caveats:  Unlike getting a WIMStruct with
1899          * wimlib_open_wim(), getting a WIMStruct in this way will result in
1900          * an empty lookup table, no XML data read, and no filename set.  */
1901         ret = open_wim_as_WIMStruct(&pipe_fd, WIMLIB_OPEN_FLAG_FROM_PIPE, &pwm,
1902                                     progfunc, progctx);
1903         if (ret)
1904                 return ret;
1905
1906         /* Sanity check to make sure this is a pipable WIM.  */
1907         if (pwm->hdr.magic != PWM_MAGIC) {
1908                 ERROR("The WIM being read from file descriptor %d "
1909                       "is not pipable!", pipe_fd);
1910                 ret = WIMLIB_ERR_NOT_PIPABLE;
1911                 goto out_wimlib_free;
1912         }
1913
1914         /* Sanity check to make sure the first part of a pipable split WIM is
1915          * sent over the pipe first.  */
1916         if (pwm->hdr.part_number != 1) {
1917                 ERROR("The first part of the split WIM must be "
1918                       "sent over the pipe first.");
1919                 ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
1920                 goto out_wimlib_free;
1921         }
1922
1923         in_fd = &pwm->in_fd;
1924         wimlib_assert(in_fd->offset == WIM_HEADER_DISK_SIZE);
1925
1926         /* As mentioned, the WIMStruct we created from the pipe does not have
1927          * XML data yet.  Fix this by reading the extra copy of the XML data
1928          * that directly follows the header in pipable WIMs.  (Note: see
1929          * write_pipable_wim() for more details about the format of pipable
1930          * WIMs.)  */
1931         {
1932                 struct wim_lookup_table_entry xml_lte;
1933                 struct wim_resource_spec xml_rspec;
1934                 ret = read_pwm_stream_header(pwm, &xml_lte, &xml_rspec, 0, NULL);
1935                 if (ret)
1936                         goto out_wimlib_free;
1937
1938                 if (!(xml_lte.flags & WIM_RESHDR_FLAG_METADATA))
1939                 {
1940                         ERROR("Expected XML data, but found non-metadata "
1941                               "stream.");
1942                         ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
1943                         goto out_wimlib_free;
1944                 }
1945
1946                 wim_res_spec_to_hdr(&xml_rspec, &pwm->hdr.xml_data_reshdr);
1947
1948                 ret = read_wim_xml_data(pwm);
1949                 if (ret)
1950                         goto out_wimlib_free;
1951
1952                 if (wim_info_get_num_images(pwm->wim_info) != pwm->hdr.image_count) {
1953                         ERROR("Image count in XML data is not the same as in WIM header.");
1954                         ret = WIMLIB_ERR_IMAGE_COUNT;
1955                         goto out_wimlib_free;
1956                 }
1957         }
1958
1959         /* Get image index (this may use the XML data that was just read to
1960          * resolve an image name).  */
1961         if (image_num_or_name) {
1962                 image = wimlib_resolve_image(pwm, image_num_or_name);
1963                 if (image == WIMLIB_NO_IMAGE) {
1964                         ERROR("\"%"TS"\" is not a valid image in the pipable WIM!",
1965                               image_num_or_name);
1966                         ret = WIMLIB_ERR_INVALID_IMAGE;
1967                         goto out_wimlib_free;
1968                 } else if (image == WIMLIB_ALL_IMAGES) {
1969                         ERROR("Applying all images from a pipe is not supported!");
1970                         ret = WIMLIB_ERR_INVALID_IMAGE;
1971                         goto out_wimlib_free;
1972                 }
1973         } else {
1974                 if (pwm->hdr.image_count != 1) {
1975                         ERROR("No image was specified, but the pipable WIM "
1976                               "did not contain exactly 1 image");
1977                         ret = WIMLIB_ERR_INVALID_IMAGE;
1978                         goto out_wimlib_free;
1979                 }
1980                 image = 1;
1981         }
1982
1983         /* Load the needed metadata resource.  */
1984         for (i = 1; i <= pwm->hdr.image_count; i++) {
1985                 struct wim_lookup_table_entry *metadata_lte;
1986                 struct wim_image_metadata *imd;
1987                 struct wim_resource_spec *metadata_rspec;
1988
1989                 metadata_lte = new_lookup_table_entry();
1990                 if (metadata_lte == NULL) {
1991                         ret = WIMLIB_ERR_NOMEM;
1992                         goto out_wimlib_free;
1993                 }
1994                 metadata_rspec = MALLOC(sizeof(struct wim_resource_spec));
1995                 if (metadata_rspec == NULL) {
1996                         ret = WIMLIB_ERR_NOMEM;
1997                         free_lookup_table_entry(metadata_lte);
1998                         goto out_wimlib_free;
1999                 }
2000
2001                 ret = read_pwm_stream_header(pwm, metadata_lte, metadata_rspec, 0, NULL);
2002                 imd = pwm->image_metadata[i - 1];
2003                 imd->metadata_lte = metadata_lte;
2004                 if (ret) {
2005                         FREE(metadata_rspec);
2006                         goto out_wimlib_free;
2007                 }
2008
2009                 if (!(metadata_lte->flags & WIM_RESHDR_FLAG_METADATA)) {
2010                         ERROR("Expected metadata resource, but found "
2011                               "non-metadata stream.");
2012                         ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
2013                         goto out_wimlib_free;
2014                 }
2015
2016                 if (i == image) {
2017                         /* Metadata resource is for the image being extracted.
2018                          * Parse it and save the metadata in memory.  */
2019                         ret = read_metadata_resource(pwm, imd);
2020                         if (ret)
2021                                 goto out_wimlib_free;
2022                         imd->modified = 1;
2023                 } else {
2024                         /* Metadata resource is not for the image being
2025                          * extracted.  Skip over it.  */
2026                         ret = skip_wim_stream(metadata_lte);
2027                         if (ret)
2028                                 goto out_wimlib_free;
2029                 }
2030         }
2031         /* Extract the image.  */
2032         extract_flags |= WIMLIB_EXTRACT_FLAG_FROM_PIPE;
2033         ret = do_wimlib_extract_image(pwm, image, target, extract_flags);
2034         /* Clean up and return.  */
2035 out_wimlib_free:
2036         wimlib_free(pwm);
2037         return ret;
2038 }
2039
2040
2041 WIMLIBAPI int
2042 wimlib_extract_image_from_pipe(int pipe_fd, const tchar *image_num_or_name,
2043                                const tchar *target, int extract_flags)
2044 {
2045         return wimlib_extract_image_from_pipe_with_progress(pipe_fd,
2046                                                             image_num_or_name,
2047                                                             target,
2048                                                             extract_flags,
2049                                                             NULL,
2050                                                             NULL);
2051 }
2052
2053 WIMLIBAPI int
2054 wimlib_extract_image(WIMStruct *wim, int image, const tchar *target,
2055                      int extract_flags)
2056 {
2057         if (extract_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC)
2058                 return WIMLIB_ERR_INVALID_PARAM;
2059         return do_wimlib_extract_image(wim, image, target, extract_flags);
2060 }