]> wimlib.net Git - wimlib/blob - src/extract.c
39899c4094e2c5eb80b296bc93d6e09161123de0
[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                 inode->i_can_externally_back = 0;
741                 if ((void *)dentry->d_extraction_name != (void *)dentry->file_name)
742                         FREE(dentry->d_extraction_name);
743                 dentry->d_extraction_name = NULL;
744                 dentry->d_extraction_name_nchars = 0;
745         }
746 }
747
748 static void
749 destroy_stream_list(struct list_head *stream_list)
750 {
751         struct wim_lookup_table_entry *lte;
752
753         list_for_each_entry(lte, stream_list, extraction_list)
754                 if (lte->out_refcnt > ARRAY_LEN(lte->inline_stream_owners))
755                         FREE(lte->stream_owners);
756 }
757
758 #ifdef __WIN32__
759 static const utf16lechar replacement_char = cpu_to_le16(0xfffd);
760 #else
761 static const utf16lechar replacement_char = cpu_to_le16('?');
762 #endif
763
764 static bool
765 file_name_valid(utf16lechar *name, size_t num_chars, bool fix)
766 {
767         size_t i;
768
769         if (num_chars == 0)
770                 return true;
771         for (i = 0; i < num_chars; i++) {
772                 switch (name[i]) {
773         #ifdef __WIN32__
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                 case cpu_to_le16('|'):
782         #endif
783                 case cpu_to_le16('/'):
784                 case cpu_to_le16('\0'):
785                         if (fix)
786                                 name[i] = replacement_char;
787                         else
788                                 return false;
789                 }
790         }
791
792 #ifdef __WIN32__
793         if (name[num_chars - 1] == cpu_to_le16(' ') ||
794             name[num_chars - 1] == cpu_to_le16('.'))
795         {
796                 if (fix)
797                         name[num_chars - 1] = replacement_char;
798                 else
799                         return false;
800         }
801 #endif
802         return true;
803 }
804
805 static int
806 dentry_calculate_extraction_name(struct wim_dentry *dentry,
807                                  struct apply_ctx *ctx)
808 {
809         int ret;
810
811         if (!dentry_is_supported(dentry, &ctx->supported_features))
812                 goto skip_dentry;
813
814         if (dentry_is_root(dentry))
815                 return 0;
816
817 #ifdef WITH_NTFS_3G
818         if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
819                 dentry->d_extraction_name = dentry->file_name;
820                 dentry->d_extraction_name_nchars = dentry->file_name_nbytes /
821                                                    sizeof(utf16lechar);
822                 return 0;
823         }
824 #endif
825
826         if (!ctx->supported_features.case_sensitive_filenames) {
827                 struct wim_dentry *other;
828                 list_for_each_entry(other, &dentry->d_ci_conflict_list,
829                                     d_ci_conflict_list)
830                 {
831                         if (will_extract_dentry(other)) {
832                                 if (ctx->extract_flags &
833                                     WIMLIB_EXTRACT_FLAG_ALL_CASE_CONFLICTS) {
834                                         WARNING("\"%"TS"\" has the same "
835                                                 "case-insensitive name as "
836                                                 "\"%"TS"\"; extracting "
837                                                 "dummy name instead",
838                                                 dentry_full_path(dentry),
839                                                 dentry_full_path(other));
840                                         goto out_replace;
841                                 } else {
842                                         WARNING("Not extracting \"%"TS"\": "
843                                                 "has same case-insensitive "
844                                                 "name as \"%"TS"\"",
845                                                 dentry_full_path(dentry),
846                                                 dentry_full_path(other));
847                                         goto skip_dentry;
848                                 }
849                         }
850                 }
851         }
852
853         if (file_name_valid(dentry->file_name, dentry->file_name_nbytes / 2, false)) {
854                 ret = utf16le_get_tstr(dentry->file_name,
855                                        dentry->file_name_nbytes,
856                                        (const tchar **)&dentry->d_extraction_name,
857                                        &dentry->d_extraction_name_nchars);
858                 dentry->d_extraction_name_nchars /= sizeof(tchar);
859                 return ret;
860         } else {
861                 if (ctx->extract_flags & WIMLIB_EXTRACT_FLAG_REPLACE_INVALID_FILENAMES)
862                 {
863                         WARNING("\"%"TS"\" has an invalid filename "
864                                 "that is not supported on this platform; "
865                                 "extracting dummy name instead",
866                                 dentry_full_path(dentry));
867                         goto out_replace;
868                 } else {
869                         WARNING("Not extracting \"%"TS"\": has an invalid filename "
870                                 "that is not supported on this platform",
871                                 dentry_full_path(dentry));
872                         goto skip_dentry;
873                 }
874         }
875
876 out_replace:
877         {
878                 utf16lechar utf16_name_copy[dentry->file_name_nbytes / 2];
879
880                 memcpy(utf16_name_copy, dentry->file_name, dentry->file_name_nbytes);
881                 file_name_valid(utf16_name_copy, dentry->file_name_nbytes / 2, true);
882
883                 const tchar *tchar_name;
884                 size_t tchar_nchars;
885
886                 ret = utf16le_get_tstr(utf16_name_copy,
887                                        dentry->file_name_nbytes,
888                                        &tchar_name, &tchar_nchars);
889                 if (ret)
890                         return ret;
891
892                 tchar_nchars /= sizeof(tchar);
893
894                 size_t fixed_name_num_chars = tchar_nchars;
895                 tchar fixed_name[tchar_nchars + 50];
896
897                 tmemcpy(fixed_name, tchar_name, tchar_nchars);
898                 fixed_name_num_chars += tsprintf(fixed_name + tchar_nchars,
899                                                  T(" (invalid filename #%lu)"),
900                                                  ++ctx->invalid_sequence);
901
902                 utf16le_put_tstr(tchar_name);
903
904                 dentry->d_extraction_name = memdup(fixed_name,
905                                                    2 * fixed_name_num_chars + 2);
906                 if (!dentry->d_extraction_name)
907                         return WIMLIB_ERR_NOMEM;
908                 dentry->d_extraction_name_nchars = fixed_name_num_chars;
909         }
910         return 0;
911
912 skip_dentry:
913         for_dentry_in_tree(dentry, dentry_delete_from_list, NULL);
914         return 0;
915 }
916
917 /*
918  * Calculate the actual filename component at which each WIM dentry will be
919  * extracted, with special handling for dentries that are unsupported by the
920  * extraction backend or have invalid names.
921  *
922  * ctx->supported_features must be filled in.
923  *
924  * Possible error codes: WIMLIB_ERR_NOMEM, WIMLIB_ERR_INVALID_UTF16_STRING
925  */
926 static int
927 dentry_list_calculate_extraction_names(struct list_head *dentry_list,
928                                        struct apply_ctx *ctx)
929 {
930         struct list_head *prev, *cur;
931
932         /* Can't use list_for_each_entry() because a call to
933          * dentry_calculate_extraction_name() may delete the current dentry and
934          * its children from the list.  */
935
936         prev = dentry_list;
937         for (;;) {
938                 struct wim_dentry *dentry;
939                 int ret;
940
941                 cur = prev->next;
942                 if (cur == dentry_list)
943                         break;
944
945                 dentry = list_entry(cur, struct wim_dentry, d_extraction_list_node);
946
947                 ret = dentry_calculate_extraction_name(dentry, ctx);
948                 if (ret)
949                         return ret;
950
951                 if (prev->next == cur)
952                         prev = cur;
953                 else
954                         ; /* Current dentry and its children (which follow in
955                              the list) were deleted.  prev stays the same.  */
956         }
957         return 0;
958 }
959
960 static int
961 dentry_resolve_streams(struct wim_dentry *dentry, int extract_flags,
962                        struct wim_lookup_table *lookup_table)
963 {
964         struct wim_inode *inode = dentry->d_inode;
965         struct wim_lookup_table_entry *lte;
966         int ret;
967         bool force = false;
968
969         /* Special case:  when extracting from a pipe, the WIM lookup table is
970          * initially empty, so "resolving" an inode's streams is initially not
971          * possible.  However, we still need to keep track of which streams,
972          * identified by SHA1 message digests, need to be extracted, so we
973          * "resolve" the inode's streams anyway by allocating new entries.  */
974         if (extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE)
975                 force = true;
976         ret = inode_resolve_streams(inode, lookup_table, force);
977         if (ret)
978                 return ret;
979         for (u32 i = 0; i <= inode->i_num_ads; i++) {
980                 lte = inode_stream_lte_resolved(inode, i);
981                 if (lte)
982                         lte->out_refcnt = 0;
983         }
984         return 0;
985 }
986
987 /*
988  * For each dentry to be extracted, resolve all streams in the corresponding
989  * inode and set 'out_refcnt' in each to 0.
990  *
991  * Possible error codes: WIMLIB_ERR_RESOURCE_NOT_FOUND, WIMLIB_ERR_NOMEM.
992  */
993 static int
994 dentry_list_resolve_streams(struct list_head *dentry_list,
995                             struct apply_ctx *ctx)
996 {
997         struct wim_dentry *dentry;
998         int ret;
999
1000         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1001                 ret = dentry_resolve_streams(dentry,
1002                                              ctx->extract_flags,
1003                                              ctx->wim->lookup_table);
1004                 if (ret)
1005                         return ret;
1006         }
1007         return 0;
1008 }
1009
1010 static int
1011 ref_stream(struct wim_lookup_table_entry *lte, u32 stream_idx,
1012            struct wim_dentry *dentry, struct apply_ctx *ctx)
1013 {
1014         struct wim_inode *inode = dentry->d_inode;
1015         struct stream_owner *stream_owners;
1016
1017         if (!lte)
1018                 return 0;
1019
1020         /* Tally the size only for each extraction of the stream (not hard
1021          * links).  */
1022         if (inode->i_visited && ctx->supported_features.hard_links)
1023                 return 0;
1024
1025         ctx->progress.extract.total_bytes += lte->size;
1026         ctx->progress.extract.total_streams++;
1027
1028         if (inode->i_visited)
1029                 return 0;
1030
1031         /* Add stream to the dentry_list only one time, even if it's going
1032          * to be extracted to multiple inodes.  */
1033         if (lte->out_refcnt == 0) {
1034                 list_add_tail(&lte->extraction_list, &ctx->stream_list);
1035                 ctx->num_streams_remaining++;
1036         }
1037
1038         /* If inode not yet been visited, append it to the stream_owners array.  */
1039         if (lte->out_refcnt < ARRAY_LEN(lte->inline_stream_owners)) {
1040                 stream_owners = lte->inline_stream_owners;
1041         } else {
1042                 struct stream_owner *prev_stream_owners;
1043                 size_t alloc_stream_owners;
1044
1045                 if (lte->out_refcnt == ARRAY_LEN(lte->inline_stream_owners)) {
1046                         prev_stream_owners = NULL;
1047                         alloc_stream_owners = ARRAY_LEN(lte->inline_stream_owners);
1048                 } else {
1049                         prev_stream_owners = lte->stream_owners;
1050                         alloc_stream_owners = lte->alloc_stream_owners;
1051                 }
1052
1053                 if (lte->out_refcnt == alloc_stream_owners) {
1054                         alloc_stream_owners *= 2;
1055                         stream_owners = REALLOC(prev_stream_owners,
1056                                                alloc_stream_owners *
1057                                                 sizeof(stream_owners[0]));
1058                         if (!stream_owners)
1059                                 return WIMLIB_ERR_NOMEM;
1060                         if (!prev_stream_owners) {
1061                                 memcpy(stream_owners,
1062                                        lte->inline_stream_owners,
1063                                        sizeof(lte->inline_stream_owners));
1064                         }
1065                         lte->stream_owners = stream_owners;
1066                         lte->alloc_stream_owners = alloc_stream_owners;
1067                 }
1068                 stream_owners = lte->stream_owners;
1069         }
1070         stream_owners[lte->out_refcnt].inode = inode;
1071         if (stream_idx == 0) {
1072                 stream_owners[lte->out_refcnt].stream_name = NULL;
1073         } else {
1074                 stream_owners[lte->out_refcnt].stream_name =
1075                         inode->i_ads_entries[stream_idx - 1].stream_name;
1076         }
1077         lte->out_refcnt++;
1078         return 0;
1079 }
1080
1081 static int
1082 ref_unnamed_stream(struct wim_dentry *dentry, struct apply_ctx *ctx)
1083 {
1084         struct wim_inode *inode = dentry->d_inode;
1085         int ret;
1086         u16 stream_idx;
1087         struct wim_lookup_table_entry *stream;
1088
1089         if (unlikely(inode_is_encrypted_directory(inode)))
1090                 return 0;
1091
1092         if (unlikely(ctx->apply_ops->will_externally_back)) {
1093                 ret = (*ctx->apply_ops->will_externally_back)(dentry, ctx);
1094                 if (ret >= 0) {
1095                         if (ret) /* Error */
1096                                 return ret;
1097                         /* Will externally back */
1098                         return 0;
1099                 }
1100                 /* Won't externally back */
1101         }
1102
1103         stream = inode_unnamed_stream_resolved(inode, &stream_idx);
1104         return ref_stream(stream, stream_idx, dentry, ctx);
1105 }
1106
1107 static int
1108 dentry_ref_streams(struct wim_dentry *dentry, struct apply_ctx *ctx)
1109 {
1110         struct wim_inode *inode = dentry->d_inode;
1111         int ret;
1112
1113         /* The unnamed data stream will almost always be extracted, but there
1114          * exist cases in which it won't be.  */
1115         ret = ref_unnamed_stream(dentry, ctx);
1116         if (ret)
1117                 return ret;
1118
1119         /* Named data streams will be extracted only if supported in the current
1120          * extraction mode and volume, and to avoid complications, if not doing
1121          * a linked extraction.  */
1122         if (ctx->supported_features.named_data_streams) {
1123                 for (u16 i = 0; i < inode->i_num_ads; i++) {
1124                         if (!ads_entry_is_named_stream(&inode->i_ads_entries[i]))
1125                                 continue;
1126                         ret = ref_stream(inode->i_ads_entries[i].lte, i + 1,
1127                                          dentry, ctx);
1128                         if (ret)
1129                                 return ret;
1130                 }
1131         }
1132         inode->i_visited = 1;
1133         return 0;
1134 }
1135
1136 /*
1137  * For each dentry to be extracted, iterate through the data streams of the
1138  * corresponding inode.  For each such stream that is not to be ignored due to
1139  * the supported features or extraction flags, add it to the list of streams to
1140  * be extracted (ctx->stream_list) if not already done so.
1141  *
1142  * Also builds a mapping from each stream to the inodes referencing it.
1143  *
1144  * This also initializes the extract progress info with byte and stream
1145  * information.
1146  *
1147  * ctx->supported_features must be filled in.
1148  *
1149  * Possible error codes: WIMLIB_ERR_NOMEM.
1150  */
1151 static int
1152 dentry_list_ref_streams(struct list_head *dentry_list, struct apply_ctx *ctx)
1153 {
1154         struct wim_dentry *dentry;
1155         int ret;
1156
1157         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1158                 ret = dentry_ref_streams(dentry, ctx);
1159                 if (ret)
1160                         return ret;
1161         }
1162         list_for_each_entry(dentry, dentry_list, d_extraction_list_node)
1163                 dentry->d_inode->i_visited = 0;
1164         return 0;
1165 }
1166
1167 static void
1168 dentry_list_build_inode_alias_lists(struct list_head *dentry_list)
1169 {
1170         struct wim_dentry *dentry;
1171         struct wim_inode *inode;
1172
1173         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1174                 inode = dentry->d_inode;
1175                 if (!inode->i_visited)
1176                         INIT_LIST_HEAD(&inode->i_extraction_aliases);
1177                 list_add_tail(&dentry->d_extraction_alias_node,
1178                               &inode->i_extraction_aliases);
1179                 inode->i_visited = 1;
1180         }
1181         list_for_each_entry(dentry, dentry_list, d_extraction_list_node)
1182                 dentry->d_inode->i_visited = 0;
1183 }
1184
1185 static void
1186 inode_tally_features(const struct wim_inode *inode,
1187                      struct wim_features *features)
1188 {
1189         if (inode->i_attributes & FILE_ATTRIBUTE_ARCHIVE)
1190                 features->archive_files++;
1191         if (inode->i_attributes & FILE_ATTRIBUTE_HIDDEN)
1192                 features->hidden_files++;
1193         if (inode->i_attributes & FILE_ATTRIBUTE_SYSTEM)
1194                 features->system_files++;
1195         if (inode->i_attributes & FILE_ATTRIBUTE_COMPRESSED)
1196                 features->compressed_files++;
1197         if (inode->i_attributes & FILE_ATTRIBUTE_ENCRYPTED) {
1198                 if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
1199                         features->encrypted_directories++;
1200                 else
1201                         features->encrypted_files++;
1202         }
1203         if (inode->i_attributes & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED)
1204                 features->not_context_indexed_files++;
1205         if (inode->i_attributes & FILE_ATTRIBUTE_SPARSE_FILE)
1206                 features->sparse_files++;
1207         if (inode_has_named_stream(inode))
1208                 features->named_data_streams++;
1209         if (inode->i_attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
1210                 features->reparse_points++;
1211                 if (inode_is_symlink(inode))
1212                         features->symlink_reparse_points++;
1213                 else
1214                         features->other_reparse_points++;
1215         }
1216         if (inode->i_security_id != -1)
1217                 features->security_descriptors++;
1218         if (inode_has_unix_data(inode))
1219                 features->unix_data++;
1220 }
1221
1222 /* Tally features necessary to extract a dentry and the corresponding inode.  */
1223 static void
1224 dentry_tally_features(struct wim_dentry *dentry, struct wim_features *features)
1225 {
1226         struct wim_inode *inode = dentry->d_inode;
1227
1228         if (dentry_has_short_name(dentry))
1229                 features->short_names++;
1230
1231         if (inode->i_visited) {
1232                 features->hard_links++;
1233         } else {
1234                 inode_tally_features(inode, features);
1235                 inode->i_visited = 1;
1236         }
1237 }
1238
1239 /* Tally the features necessary to extract the specified dentries.  */
1240 static void
1241 dentry_list_get_features(struct list_head *dentry_list,
1242                          struct wim_features *features)
1243 {
1244         struct wim_dentry *dentry;
1245
1246         list_for_each_entry(dentry, dentry_list, d_extraction_list_node)
1247                 dentry_tally_features(dentry, features);
1248
1249         list_for_each_entry(dentry, dentry_list, d_extraction_list_node)
1250                 dentry->d_inode->i_visited = 0;
1251 }
1252
1253 static int
1254 do_feature_check(const struct wim_features *required_features,
1255                  const struct wim_features *supported_features,
1256                  int extract_flags)
1257 {
1258         /* File attributes.  */
1259         if (!(extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)) {
1260                 /* Note: Don't bother the user about FILE_ATTRIBUTE_ARCHIVE.
1261                  * We're an archive program, so theoretically we can do what we
1262                  * want with it.  */
1263
1264                 if (required_features->hidden_files &&
1265                     !supported_features->hidden_files)
1266                         WARNING("Ignoring FILE_ATTRIBUTE_HIDDEN of %lu files",
1267                                 required_features->hidden_files);
1268
1269                 if (required_features->system_files &&
1270                     !supported_features->system_files)
1271                         WARNING("Ignoring FILE_ATTRIBUTE_SYSTEM of %lu files",
1272                                 required_features->system_files);
1273
1274                 if (required_features->compressed_files &&
1275                     !supported_features->compressed_files)
1276                         WARNING("Ignoring FILE_ATTRIBUTE_COMPRESSED of %lu files",
1277                                 required_features->compressed_files);
1278
1279                 if (required_features->not_context_indexed_files &&
1280                     !supported_features->not_context_indexed_files)
1281                         WARNING("Ignoring FILE_ATTRIBUTE_NOT_CONTENT_INDEXED of %lu files",
1282                                 required_features->not_context_indexed_files);
1283
1284                 if (required_features->sparse_files &&
1285                     !supported_features->sparse_files)
1286                         WARNING("Ignoring FILE_ATTRIBUTE_SPARSE_FILE of %lu files",
1287                                 required_features->sparse_files);
1288
1289                 if (required_features->encrypted_directories &&
1290                     !supported_features->encrypted_directories)
1291                         WARNING("Ignoring FILE_ATTRIBUTE_ENCRYPTED of %lu directories",
1292                                 required_features->encrypted_directories);
1293         }
1294
1295         /* Encrypted files.  */
1296         if (required_features->encrypted_files &&
1297             !supported_features->encrypted_files)
1298                 WARNING("Ignoring %lu encrypted files",
1299                         required_features->encrypted_files);
1300
1301         /* Named data streams.  */
1302         if (required_features->named_data_streams &&
1303             (!supported_features->named_data_streams))
1304                 WARNING("Ignoring named data streams of %lu files",
1305                         required_features->named_data_streams);
1306
1307         /* Hard links.  */
1308         if (required_features->hard_links && !supported_features->hard_links)
1309                 WARNING("Extracting %lu hard links as independent files",
1310                         required_features->hard_links);
1311
1312         /* Symbolic links and reparse points.  */
1313         if ((extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS) &&
1314             required_features->symlink_reparse_points &&
1315             !supported_features->symlink_reparse_points &&
1316             !supported_features->reparse_points)
1317         {
1318                 ERROR("Extraction backend does not support symbolic links!");
1319                 return WIMLIB_ERR_UNSUPPORTED;
1320         }
1321         if (required_features->reparse_points &&
1322             !supported_features->reparse_points)
1323         {
1324                 if (supported_features->symlink_reparse_points) {
1325                         if (required_features->other_reparse_points) {
1326                                 WARNING("Ignoring %lu non-symlink/junction "
1327                                         "reparse point files",
1328                                         required_features->other_reparse_points);
1329                         }
1330                 } else {
1331                         WARNING("Ignoring %lu reparse point files",
1332                                 required_features->reparse_points);
1333                 }
1334         }
1335
1336         /* Security descriptors.  */
1337         if (((extract_flags & (WIMLIB_EXTRACT_FLAG_STRICT_ACLS |
1338                                WIMLIB_EXTRACT_FLAG_UNIX_DATA))
1339              == WIMLIB_EXTRACT_FLAG_STRICT_ACLS) &&
1340             required_features->security_descriptors &&
1341             !supported_features->security_descriptors)
1342         {
1343                 ERROR("Extraction backend does not support security descriptors!");
1344                 return WIMLIB_ERR_UNSUPPORTED;
1345         }
1346         if (!(extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS) &&
1347             required_features->security_descriptors &&
1348             !supported_features->security_descriptors)
1349                 WARNING("Ignoring Windows NT security descriptors of %lu files",
1350                         required_features->security_descriptors);
1351
1352         /* UNIX data.  */
1353         if ((extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA) &&
1354             required_features->unix_data && !supported_features->unix_data)
1355         {
1356                 ERROR("Extraction backend does not support UNIX data!");
1357                 return WIMLIB_ERR_UNSUPPORTED;
1358         }
1359
1360         if (required_features->unix_data &&
1361             !(extract_flags & WIMLIB_EXTRACT_FLAG_UNIX_DATA))
1362         {
1363                 WARNING("Ignoring UNIX metadata of %lu files",
1364                         required_features->unix_data);
1365         }
1366
1367         /* DOS Names.  */
1368         if (required_features->short_names &&
1369             !supported_features->short_names)
1370         {
1371                 if (extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES) {
1372                         ERROR("Extraction backend does not support DOS names!");
1373                         return WIMLIB_ERR_UNSUPPORTED;
1374                 }
1375                 WARNING("Ignoring DOS names of %lu files",
1376                         required_features->short_names);
1377         }
1378
1379         /* Timestamps.  */
1380         if ((extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_TIMESTAMPS) &&
1381             !supported_features->timestamps)
1382         {
1383                 ERROR("Extraction backend does not support timestamps!");
1384                 return WIMLIB_ERR_UNSUPPORTED;
1385         }
1386
1387         return 0;
1388 }
1389
1390 static const struct apply_operations *
1391 select_apply_operations(int extract_flags)
1392 {
1393 #ifdef WITH_NTFS_3G
1394         if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS)
1395                 return &ntfs_3g_apply_ops;
1396 #endif
1397 #ifdef __WIN32__
1398         return &win32_apply_ops;
1399 #else
1400         return &unix_apply_ops;
1401 #endif
1402 }
1403
1404 static int
1405 extract_trees(WIMStruct *wim, struct wim_dentry **trees, size_t num_trees,
1406               const tchar *target, int extract_flags)
1407 {
1408         const struct apply_operations *ops;
1409         struct apply_ctx *ctx;
1410         int ret;
1411         LIST_HEAD(dentry_list);
1412
1413         if (extract_flags & WIMLIB_EXTRACT_FLAG_TO_STDOUT) {
1414                 ret = extract_dentries_to_stdout(trees, num_trees,
1415                                                  wim->lookup_table);
1416                 goto out;
1417         }
1418
1419         num_trees = remove_duplicate_trees(trees, num_trees);
1420         num_trees = remove_contained_trees(trees, num_trees);
1421
1422         ops = select_apply_operations(extract_flags);
1423
1424         if (num_trees > 1 && ops->single_tree_only) {
1425                 ERROR("Extracting multiple directory trees "
1426                       "at once is not supported in %s extraction mode!",
1427                       ops->name);
1428                 ret = WIMLIB_ERR_UNSUPPORTED;
1429                 goto out;
1430         }
1431
1432         ctx = CALLOC(1, ops->context_size);
1433         if (!ctx) {
1434                 ret = WIMLIB_ERR_NOMEM;
1435                 goto out;
1436         }
1437
1438         ctx->wim = wim;
1439         ctx->target = target;
1440         ctx->target_nchars = tstrlen(target);
1441         ctx->extract_flags = extract_flags;
1442         if (ctx->wim->progfunc) {
1443                 ctx->progfunc = ctx->wim->progfunc;
1444                 ctx->progctx = ctx->wim->progctx;
1445                 ctx->progress.extract.image = wim->current_image;
1446                 ctx->progress.extract.extract_flags = (extract_flags &
1447                                                        WIMLIB_EXTRACT_MASK_PUBLIC);
1448                 ctx->progress.extract.wimfile_name = wim->filename;
1449                 ctx->progress.extract.image_name = wimlib_get_image_name(wim,
1450                                                                          wim->current_image);
1451                 ctx->progress.extract.target = target;
1452         }
1453         INIT_LIST_HEAD(&ctx->stream_list);
1454         filedes_invalidate(&ctx->tmpfile_fd);
1455         ctx->apply_ops = ops;
1456
1457         ret = (*ops->get_supported_features)(target, &ctx->supported_features);
1458         if (ret)
1459                 goto out_cleanup;
1460
1461         build_dentry_list(&dentry_list, trees, num_trees,
1462                           !(extract_flags &
1463                             WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE));
1464
1465         dentry_list_get_features(&dentry_list, &ctx->required_features);
1466
1467         ret = do_feature_check(&ctx->required_features, &ctx->supported_features,
1468                                ctx->extract_flags);
1469         if (ret)
1470                 goto out_cleanup;
1471
1472         ret = dentry_list_calculate_extraction_names(&dentry_list, ctx);
1473         if (ret)
1474                 goto out_cleanup;
1475
1476         ret = dentry_list_resolve_streams(&dentry_list, ctx);
1477         if (ret)
1478                 goto out_cleanup;
1479
1480         dentry_list_build_inode_alias_lists(&dentry_list);
1481
1482         ret = dentry_list_ref_streams(&dentry_list, ctx);
1483         if (ret)
1484                 goto out_cleanup;
1485
1486         if (extract_flags & WIMLIB_EXTRACT_FLAG_FROM_PIPE) {
1487                 /* When extracting from a pipe, the number of bytes of data to
1488                  * extract can't be determined in the normal way (examining the
1489                  * lookup table), since at this point all we have is a set of
1490                  * SHA1 message digests of streams that need to be extracted.
1491                  * However, we can get a reasonably accurate estimate by taking
1492                  * <TOTALBYTES> from the corresponding <IMAGE> in the WIM XML
1493                  * data.  This does assume that a full image is being extracted,
1494                  * but currently there is no API for doing otherwise.  (Also,
1495                  * subtract <HARDLINKBYTES> from this if hard links are
1496                  * supported by the extraction mode.)  */
1497                 ctx->progress.extract.total_bytes =
1498                         wim_info_get_image_total_bytes(wim->wim_info,
1499                                                        wim->current_image);
1500                 if (ctx->supported_features.hard_links) {
1501                         ctx->progress.extract.total_bytes -=
1502                                 wim_info_get_image_hard_link_bytes(wim->wim_info,
1503                                                                    wim->current_image);
1504                 }
1505         }
1506
1507         ret = extract_progress(ctx,
1508                                ((extract_flags & WIMLIB_EXTRACT_FLAG_IMAGEMODE) ?
1509                                        WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_BEGIN :
1510                                        WIMLIB_PROGRESS_MSG_EXTRACT_TREE_BEGIN));
1511         if (ret)
1512                 goto out_cleanup;
1513
1514         ret = (*ops->extract)(&dentry_list, ctx);
1515         if (ret)
1516                 goto out_cleanup;
1517
1518         if (ctx->progress.extract.completed_bytes <
1519             ctx->progress.extract.total_bytes)
1520         {
1521                 ctx->progress.extract.completed_bytes =
1522                         ctx->progress.extract.total_bytes;
1523                 ret = extract_progress(ctx, WIMLIB_PROGRESS_MSG_EXTRACT_STREAMS);
1524                 if (ret)
1525                         goto out_cleanup;
1526         }
1527
1528         ret = extract_progress(ctx,
1529                                ((extract_flags & WIMLIB_EXTRACT_FLAG_IMAGEMODE) ?
1530                                        WIMLIB_PROGRESS_MSG_EXTRACT_IMAGE_END :
1531                                        WIMLIB_PROGRESS_MSG_EXTRACT_TREE_END));
1532 out_cleanup:
1533         destroy_stream_list(&ctx->stream_list);
1534         destroy_dentry_list(&dentry_list);
1535         FREE(ctx);
1536 out:
1537         return ret;
1538 }
1539
1540 static int
1541 mkdir_if_needed(const tchar *target)
1542 {
1543         if (!tmkdir(target, 0755))
1544                 return 0;
1545
1546         if (errno == EEXIST)
1547                 return 0;
1548
1549 #ifdef __WIN32__
1550         /* _wmkdir() fails with EACCES if called on a drive root directory.  */
1551         if (errno == EACCES)
1552                 return 0;
1553 #endif
1554
1555         ERROR_WITH_ERRNO("Failed to create directory \"%"TS"\"", target);
1556         return WIMLIB_ERR_MKDIR;
1557 }
1558
1559 /* Make sure the extraction flags make sense, and update them if needed.  */
1560 static int
1561 check_extract_flags(const WIMStruct *wim, int *extract_flags_p)
1562 {
1563         int extract_flags = *extract_flags_p;
1564
1565         /* Check for invalid flag combinations  */
1566
1567         if ((extract_flags &
1568              (WIMLIB_EXTRACT_FLAG_NO_ACLS |
1569               WIMLIB_EXTRACT_FLAG_STRICT_ACLS)) == (WIMLIB_EXTRACT_FLAG_NO_ACLS |
1570                                                     WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
1571                 return WIMLIB_ERR_INVALID_PARAM;
1572
1573         if ((extract_flags &
1574              (WIMLIB_EXTRACT_FLAG_RPFIX |
1575               WIMLIB_EXTRACT_FLAG_NORPFIX)) == (WIMLIB_EXTRACT_FLAG_RPFIX |
1576                                                 WIMLIB_EXTRACT_FLAG_NORPFIX))
1577                 return WIMLIB_ERR_INVALID_PARAM;
1578
1579 #ifndef WITH_NTFS_3G
1580         if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
1581                 ERROR("wimlib was compiled without support for NTFS-3g, so\n"
1582                       "        it cannot apply a WIM image directly to an NTFS volume.");
1583                 return WIMLIB_ERR_UNSUPPORTED;
1584         }
1585 #endif
1586
1587         if (extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT) {
1588 #ifdef __WIN32__
1589                 if (!wim->filename)
1590                         return WIMLIB_ERR_NO_FILENAME;
1591 #else
1592                 ERROR("WIMBoot extraction is only supported on Windows!");
1593                 return WIMLIB_ERR_UNSUPPORTED;
1594 #endif
1595         }
1596
1597
1598         if ((extract_flags & (WIMLIB_EXTRACT_FLAG_RPFIX |
1599                               WIMLIB_EXTRACT_FLAG_NORPFIX |
1600                               WIMLIB_EXTRACT_FLAG_IMAGEMODE)) ==
1601                                         WIMLIB_EXTRACT_FLAG_IMAGEMODE)
1602         {
1603                 /* For full-image extraction, do reparse point fixups by default
1604                  * if the WIM header says they are enabled.  */
1605                 if (wim->hdr.flags & WIM_HDR_FLAG_RP_FIX)
1606                         extract_flags |= WIMLIB_EXTRACT_FLAG_RPFIX;
1607         }
1608
1609         *extract_flags_p = extract_flags;
1610         return 0;
1611 }
1612
1613 static u32
1614 get_wildcard_flags(int extract_flags)
1615 {
1616         u32 wildcard_flags = 0;
1617
1618         if (extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_GLOB)
1619                 wildcard_flags |= WILDCARD_FLAG_ERROR_IF_NO_MATCH;
1620         else
1621                 wildcard_flags |= WILDCARD_FLAG_WARN_IF_NO_MATCH;
1622
1623         if (default_ignore_case)
1624                 wildcard_flags |= WILDCARD_FLAG_CASE_INSENSITIVE;
1625
1626         return wildcard_flags;
1627 }
1628
1629 struct append_dentry_ctx {
1630         struct wim_dentry **dentries;
1631         size_t num_dentries;
1632         size_t num_alloc_dentries;
1633 };
1634
1635 static int
1636 append_dentry_cb(struct wim_dentry *dentry, void *_ctx)
1637 {
1638         struct append_dentry_ctx *ctx = _ctx;
1639
1640         if (ctx->num_dentries == ctx->num_alloc_dentries) {
1641                 struct wim_dentry **new_dentries;
1642                 size_t new_length;
1643
1644                 new_length = max(ctx->num_alloc_dentries + 8,
1645                                  ctx->num_alloc_dentries * 3 / 2);
1646                 new_dentries = REALLOC(ctx->dentries,
1647                                        new_length * sizeof(ctx->dentries[0]));
1648                 if (new_dentries == NULL)
1649                         return WIMLIB_ERR_NOMEM;
1650                 ctx->dentries = new_dentries;
1651                 ctx->num_alloc_dentries = new_length;
1652         }
1653         ctx->dentries[ctx->num_dentries++] = dentry;
1654         return 0;
1655 }
1656
1657 static int
1658 do_wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target,
1659                         const tchar * const *paths, size_t num_paths,
1660                         int extract_flags)
1661 {
1662         int ret;
1663         struct wim_dentry **trees;
1664         size_t num_trees;
1665
1666         if (wim == NULL || target == NULL || target[0] == T('\0') ||
1667             (num_paths != 0 && paths == NULL))
1668                 return WIMLIB_ERR_INVALID_PARAM;
1669
1670         ret = check_extract_flags(wim, &extract_flags);
1671         if (ret)
1672                 return ret;
1673
1674         ret = select_wim_image(wim, image);
1675         if (ret)
1676                 return ret;
1677
1678         ret = wim_checksum_unhashed_streams(wim);
1679         if (ret)
1680                 return ret;
1681
1682         if ((extract_flags & (WIMLIB_EXTRACT_FLAG_NTFS |
1683                               WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE)) ==
1684             (WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE))
1685         {
1686                 ret = mkdir_if_needed(target);
1687                 if (ret)
1688                         return ret;
1689         }
1690
1691         if (extract_flags & WIMLIB_EXTRACT_FLAG_GLOB_PATHS) {
1692
1693                 struct append_dentry_ctx append_dentry_ctx = {
1694                         .dentries = NULL,
1695                         .num_dentries = 0,
1696                         .num_alloc_dentries = 0,
1697                 };
1698
1699                 u32 wildcard_flags = get_wildcard_flags(extract_flags);
1700
1701                 for (size_t i = 0; i < num_paths; i++) {
1702                         tchar *path = canonicalize_wim_path(paths[i]);
1703                         if (path == NULL) {
1704                                 ret = WIMLIB_ERR_NOMEM;
1705                                 trees = append_dentry_ctx.dentries;
1706                                 goto out_free_trees;
1707                         }
1708                         ret = expand_wildcard(wim, path,
1709                                               append_dentry_cb,
1710                                               &append_dentry_ctx,
1711                                               wildcard_flags);
1712                         FREE(path);
1713                         if (ret) {
1714                                 trees = append_dentry_ctx.dentries;
1715                                 goto out_free_trees;
1716                         }
1717                 }
1718                 trees = append_dentry_ctx.dentries;
1719                 num_trees = append_dentry_ctx.num_dentries;
1720         } else {
1721                 trees = MALLOC(num_paths * sizeof(trees[0]));
1722                 if (trees == NULL)
1723                         return WIMLIB_ERR_NOMEM;
1724
1725                 for (size_t i = 0; i < num_paths; i++) {
1726
1727                         tchar *path = canonicalize_wim_path(paths[i]);
1728                         if (path == NULL) {
1729                                 ret = WIMLIB_ERR_NOMEM;
1730                                 goto out_free_trees;
1731                         }
1732
1733                         trees[i] = get_dentry(wim, path,
1734                                               WIMLIB_CASE_PLATFORM_DEFAULT);
1735                         FREE(path);
1736                         if (trees[i] == NULL) {
1737                                   ERROR("Path \"%"TS"\" does not exist "
1738                                         "in WIM image %d",
1739                                         paths[i], wim->current_image);
1740                                   ret = WIMLIB_ERR_PATH_DOES_NOT_EXIST;
1741                                   goto out_free_trees;
1742                         }
1743                 }
1744                 num_trees = num_paths;
1745         }
1746
1747         if (num_trees == 0) {
1748                 ret = 0;
1749                 goto out_free_trees;
1750         }
1751
1752         ret = extract_trees(wim, trees, num_trees, target, extract_flags);
1753 out_free_trees:
1754         FREE(trees);
1755         return ret;
1756 }
1757
1758 static int
1759 extract_single_image(WIMStruct *wim, int image,
1760                      const tchar *target, int extract_flags)
1761 {
1762         const tchar *path = WIMLIB_WIM_ROOT_PATH;
1763         extract_flags |= WIMLIB_EXTRACT_FLAG_IMAGEMODE;
1764         return do_wimlib_extract_paths(wim, image, target, &path, 1, extract_flags);
1765 }
1766
1767 static const tchar * const filename_forbidden_chars =
1768 T(
1769 #ifdef __WIN32__
1770 "<>:\"/\\|?*"
1771 #else
1772 "/"
1773 #endif
1774 );
1775
1776 /* This function checks if it is okay to use a WIM image's name as a directory
1777  * name.  */
1778 static bool
1779 image_name_ok_as_dir(const tchar *image_name)
1780 {
1781         return image_name && *image_name &&
1782                 !tstrpbrk(image_name, filename_forbidden_chars) &&
1783                 tstrcmp(image_name, T(".")) &&
1784                 tstrcmp(image_name, T(".."));
1785 }
1786
1787 /* Extracts all images from the WIM to the directory @target, with the images
1788  * placed in subdirectories named by their image names. */
1789 static int
1790 extract_all_images(WIMStruct *wim, const tchar *target, int extract_flags)
1791 {
1792         size_t image_name_max_len = max(xml_get_max_image_name_len(wim), 20);
1793         size_t output_path_len = tstrlen(target);
1794         tchar buf[output_path_len + 1 + image_name_max_len + 1];
1795         int ret;
1796         int image;
1797         const tchar *image_name;
1798
1799         if (extract_flags & WIMLIB_EXTRACT_FLAG_NTFS) {
1800                 ERROR("Cannot extract multiple images in NTFS extraction mode.");
1801                 return WIMLIB_ERR_INVALID_PARAM;
1802         }
1803
1804         ret = mkdir_if_needed(target);
1805         if (ret)
1806                 return ret;
1807         tmemcpy(buf, target, output_path_len);
1808         buf[output_path_len] = OS_PREFERRED_PATH_SEPARATOR;
1809         for (image = 1; image <= wim->hdr.image_count; image++) {
1810                 image_name = wimlib_get_image_name(wim, image);
1811                 if (image_name_ok_as_dir(image_name)) {
1812                         tstrcpy(buf + output_path_len + 1, image_name);
1813                 } else {
1814                         /* Image name is empty or contains forbidden characters.
1815                          * Use image number instead. */
1816                         tsprintf(buf + output_path_len + 1, T("%d"), image);
1817                 }
1818                 ret = extract_single_image(wim, image, buf, extract_flags);
1819                 if (ret)
1820                         return ret;
1821         }
1822         return 0;
1823 }
1824
1825 static int
1826 do_wimlib_extract_image(WIMStruct *wim, int image, const tchar *target,
1827                         int extract_flags)
1828 {
1829         if (extract_flags & (WIMLIB_EXTRACT_FLAG_NO_PRESERVE_DIR_STRUCTURE |
1830                              WIMLIB_EXTRACT_FLAG_TO_STDOUT |
1831                              WIMLIB_EXTRACT_FLAG_GLOB_PATHS))
1832                 return WIMLIB_ERR_INVALID_PARAM;
1833
1834         if (image == WIMLIB_ALL_IMAGES)
1835                 return extract_all_images(wim, target, extract_flags);
1836         else
1837                 return extract_single_image(wim, image, target, extract_flags);
1838 }
1839
1840
1841 /****************************************************************************
1842  *                          Extraction API                                  *
1843  ****************************************************************************/
1844
1845 WIMLIBAPI int
1846 wimlib_extract_paths(WIMStruct *wim, int image, const tchar *target,
1847                      const tchar * const *paths, size_t num_paths,
1848                      int extract_flags)
1849 {
1850         if (extract_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC)
1851                 return WIMLIB_ERR_INVALID_PARAM;
1852
1853         return do_wimlib_extract_paths(wim, image, target, paths, num_paths,
1854                                        extract_flags);
1855 }
1856
1857 WIMLIBAPI int
1858 wimlib_extract_pathlist(WIMStruct *wim, int image, const tchar *target,
1859                         const tchar *path_list_file, int extract_flags)
1860 {
1861         int ret;
1862         tchar **paths;
1863         size_t num_paths;
1864         void *mem;
1865
1866         ret = read_path_list_file(path_list_file, &paths, &num_paths, &mem);
1867         if (ret) {
1868                 ERROR("Failed to read path list file \"%"TS"\"",
1869                       path_list_file);
1870                 return ret;
1871         }
1872
1873         ret = wimlib_extract_paths(wim, image, target,
1874                                    (const tchar * const *)paths, num_paths,
1875                                    extract_flags);
1876         FREE(paths);
1877         FREE(mem);
1878         return ret;
1879 }
1880
1881 WIMLIBAPI int
1882 wimlib_extract_image_from_pipe_with_progress(int pipe_fd,
1883                                              const tchar *image_num_or_name,
1884                                              const tchar *target,
1885                                              int extract_flags,
1886                                              wimlib_progress_func_t progfunc,
1887                                              void *progctx)
1888 {
1889         int ret;
1890         WIMStruct *pwm;
1891         struct filedes *in_fd;
1892         int image;
1893         unsigned i;
1894
1895         if (extract_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC)
1896                 return WIMLIB_ERR_INVALID_PARAM;
1897
1898         /* Read the WIM header from the pipe and get a WIMStruct to represent
1899          * the pipable WIM.  Caveats:  Unlike getting a WIMStruct with
1900          * wimlib_open_wim(), getting a WIMStruct in this way will result in
1901          * an empty lookup table, no XML data read, and no filename set.  */
1902         ret = open_wim_as_WIMStruct(&pipe_fd, WIMLIB_OPEN_FLAG_FROM_PIPE, &pwm,
1903                                     progfunc, progctx);
1904         if (ret)
1905                 return ret;
1906
1907         /* Sanity check to make sure this is a pipable WIM.  */
1908         if (pwm->hdr.magic != PWM_MAGIC) {
1909                 ERROR("The WIM being read from file descriptor %d "
1910                       "is not pipable!", pipe_fd);
1911                 ret = WIMLIB_ERR_NOT_PIPABLE;
1912                 goto out_wimlib_free;
1913         }
1914
1915         /* Sanity check to make sure the first part of a pipable split WIM is
1916          * sent over the pipe first.  */
1917         if (pwm->hdr.part_number != 1) {
1918                 ERROR("The first part of the split WIM must be "
1919                       "sent over the pipe first.");
1920                 ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
1921                 goto out_wimlib_free;
1922         }
1923
1924         in_fd = &pwm->in_fd;
1925         wimlib_assert(in_fd->offset == WIM_HEADER_DISK_SIZE);
1926
1927         /* As mentioned, the WIMStruct we created from the pipe does not have
1928          * XML data yet.  Fix this by reading the extra copy of the XML data
1929          * that directly follows the header in pipable WIMs.  (Note: see
1930          * write_pipable_wim() for more details about the format of pipable
1931          * WIMs.)  */
1932         {
1933                 struct wim_lookup_table_entry xml_lte;
1934                 struct wim_resource_spec xml_rspec;
1935                 ret = read_pwm_stream_header(pwm, &xml_lte, &xml_rspec, 0, NULL);
1936                 if (ret)
1937                         goto out_wimlib_free;
1938
1939                 if (!(xml_lte.flags & WIM_RESHDR_FLAG_METADATA))
1940                 {
1941                         ERROR("Expected XML data, but found non-metadata "
1942                               "stream.");
1943                         ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
1944                         goto out_wimlib_free;
1945                 }
1946
1947                 wim_res_spec_to_hdr(&xml_rspec, &pwm->hdr.xml_data_reshdr);
1948
1949                 ret = read_wim_xml_data(pwm);
1950                 if (ret)
1951                         goto out_wimlib_free;
1952
1953                 if (wim_info_get_num_images(pwm->wim_info) != pwm->hdr.image_count) {
1954                         ERROR("Image count in XML data is not the same as in WIM header.");
1955                         ret = WIMLIB_ERR_IMAGE_COUNT;
1956                         goto out_wimlib_free;
1957                 }
1958         }
1959
1960         /* Get image index (this may use the XML data that was just read to
1961          * resolve an image name).  */
1962         if (image_num_or_name) {
1963                 image = wimlib_resolve_image(pwm, image_num_or_name);
1964                 if (image == WIMLIB_NO_IMAGE) {
1965                         ERROR("\"%"TS"\" is not a valid image in the pipable WIM!",
1966                               image_num_or_name);
1967                         ret = WIMLIB_ERR_INVALID_IMAGE;
1968                         goto out_wimlib_free;
1969                 } else if (image == WIMLIB_ALL_IMAGES) {
1970                         ERROR("Applying all images from a pipe is not supported!");
1971                         ret = WIMLIB_ERR_INVALID_IMAGE;
1972                         goto out_wimlib_free;
1973                 }
1974         } else {
1975                 if (pwm->hdr.image_count != 1) {
1976                         ERROR("No image was specified, but the pipable WIM "
1977                               "did not contain exactly 1 image");
1978                         ret = WIMLIB_ERR_INVALID_IMAGE;
1979                         goto out_wimlib_free;
1980                 }
1981                 image = 1;
1982         }
1983
1984         /* Load the needed metadata resource.  */
1985         for (i = 1; i <= pwm->hdr.image_count; i++) {
1986                 struct wim_lookup_table_entry *metadata_lte;
1987                 struct wim_image_metadata *imd;
1988                 struct wim_resource_spec *metadata_rspec;
1989
1990                 metadata_lte = new_lookup_table_entry();
1991                 if (metadata_lte == NULL) {
1992                         ret = WIMLIB_ERR_NOMEM;
1993                         goto out_wimlib_free;
1994                 }
1995                 metadata_rspec = MALLOC(sizeof(struct wim_resource_spec));
1996                 if (metadata_rspec == NULL) {
1997                         ret = WIMLIB_ERR_NOMEM;
1998                         free_lookup_table_entry(metadata_lte);
1999                         goto out_wimlib_free;
2000                 }
2001
2002                 ret = read_pwm_stream_header(pwm, metadata_lte, metadata_rspec, 0, NULL);
2003                 imd = pwm->image_metadata[i - 1];
2004                 imd->metadata_lte = metadata_lte;
2005                 if (ret) {
2006                         FREE(metadata_rspec);
2007                         goto out_wimlib_free;
2008                 }
2009
2010                 if (!(metadata_lte->flags & WIM_RESHDR_FLAG_METADATA)) {
2011                         ERROR("Expected metadata resource, but found "
2012                               "non-metadata stream.");
2013                         ret = WIMLIB_ERR_INVALID_PIPABLE_WIM;
2014                         goto out_wimlib_free;
2015                 }
2016
2017                 if (i == image) {
2018                         /* Metadata resource is for the image being extracted.
2019                          * Parse it and save the metadata in memory.  */
2020                         ret = read_metadata_resource(imd);
2021                         if (ret)
2022                                 goto out_wimlib_free;
2023                         imd->modified = 1;
2024                 } else {
2025                         /* Metadata resource is not for the image being
2026                          * extracted.  Skip over it.  */
2027                         ret = skip_wim_stream(metadata_lte);
2028                         if (ret)
2029                                 goto out_wimlib_free;
2030                 }
2031         }
2032         /* Extract the image.  */
2033         extract_flags |= WIMLIB_EXTRACT_FLAG_FROM_PIPE;
2034         ret = do_wimlib_extract_image(pwm, image, target, extract_flags);
2035         /* Clean up and return.  */
2036 out_wimlib_free:
2037         wimlib_free(pwm);
2038         return ret;
2039 }
2040
2041
2042 WIMLIBAPI int
2043 wimlib_extract_image_from_pipe(int pipe_fd, const tchar *image_num_or_name,
2044                                const tchar *target, int extract_flags)
2045 {
2046         return wimlib_extract_image_from_pipe_with_progress(pipe_fd,
2047                                                             image_num_or_name,
2048                                                             target,
2049                                                             extract_flags,
2050                                                             NULL,
2051                                                             NULL);
2052 }
2053
2054 WIMLIBAPI int
2055 wimlib_extract_image(WIMStruct *wim, int image, const tchar *target,
2056                      int extract_flags)
2057 {
2058         if (extract_flags & ~WIMLIB_EXTRACT_MASK_PUBLIC)
2059                 return WIMLIB_ERR_INVALID_PARAM;
2060         return do_wimlib_extract_image(wim, image, target, extract_flags);
2061 }