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