]> wimlib.net Git - wimlib/blob - src/win32_apply.c
win32_apply.c: simplify inode_longest_named_data_stream_spec()
[wimlib] / src / win32_apply.c
1 /*
2  * win32_apply.c - Windows-specific code for applying files from a WIM image.
3  */
4
5 /*
6  * Copyright (C) 2013, 2014, 2015 Eric Biggers
7  *
8  * This file is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU Lesser General Public License as published by the Free
10  * Software Foundation; either version 3 of the License, or (at your option) any
11  * later version.
12  *
13  * This file is distributed in the hope that it will be useful, but WITHOUT
14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public License
19  * along with this file; if not, see http://www.gnu.org/licenses/.
20  */
21
22 #ifdef __WIN32__
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #include "wimlib/win32_common.h"
29
30 #include "wimlib/apply.h"
31 #include "wimlib/assert.h"
32 #include "wimlib/blob_table.h"
33 #include "wimlib/capture.h" /* for mangle_pat() and match_pattern_list()  */
34 #include "wimlib/dentry.h"
35 #include "wimlib/encoding.h"
36 #include "wimlib/error.h"
37 #include "wimlib/metadata.h"
38 #include "wimlib/paths.h"
39 #include "wimlib/reparse.h"
40 #include "wimlib/textfile.h"
41 #include "wimlib/xml.h"
42 #include "wimlib/wildcard.h"
43 #include "wimlib/wimboot.h"
44
45 struct win32_apply_ctx {
46
47         /* Extract flags, the pointer to the WIMStruct, etc.  */
48         struct apply_ctx common;
49
50         /* WIMBoot information, only filled in if WIMLIB_EXTRACT_FLAG_WIMBOOT
51          * was provided  */
52         struct {
53                 u64 data_source_id;
54                 struct string_set *prepopulate_pats;
55                 void *mem_prepopulate_pats;
56                 u8 blob_table_hash[SHA1_HASH_SIZE];
57                 bool wof_running;
58                 bool tried_to_load_prepopulate_list;
59         } wimboot;
60
61         /* Open handle to the target directory  */
62         HANDLE h_target;
63
64         /* NT namespace path to the target directory (buffer allocated)  */
65         UNICODE_STRING target_ntpath;
66
67         /* Temporary buffer for building paths (buffer allocated)  */
68         UNICODE_STRING pathbuf;
69
70         /* Object attributes to reuse for opening files in the target directory.
71          * (attr.ObjectName == &pathbuf) and (attr.RootDirectory == h_target).
72          */
73         OBJECT_ATTRIBUTES attr;
74
75         /* Temporary I/O status block for system calls  */
76         IO_STATUS_BLOCK iosb;
77
78         /* Allocated buffer for creating "printable" paths from our
79          * target-relative NT paths  */
80         wchar_t *print_buffer;
81
82         /* Allocated buffer for reading blob data when it cannot be extracted
83          * directly  */
84         u8 *data_buffer;
85
86         /* Pointer to the next byte in @data_buffer to fill  */
87         u8 *data_buffer_ptr;
88
89         /* Size allocated in @data_buffer  */
90         size_t data_buffer_size;
91
92         /* Current offset in the raw encrypted file being written  */
93         size_t encrypted_offset;
94
95         /* Current size of the raw encrypted file being written  */
96         size_t encrypted_size;
97
98         /* Temporary buffer for reparse data  */
99         struct reparse_buffer_disk rpbuf;
100
101         /* Temporary buffer for reparse data of "fixed" absolute symbolic links
102          * and junctions  */
103         struct reparse_buffer_disk rpfixbuf;
104
105         /* Array of open handles to filesystem streams currently being written
106          */
107         HANDLE open_handles[MAX_OPEN_FILES];
108
109         /* Number of handles in @open_handles currently open (filled in from the
110          * beginning of the array)  */
111         unsigned num_open_handles;
112
113         /* List of dentries, joined by @tmp_list, that need to have reparse data
114          * extracted as soon as the whole blob has been read into @data_buffer.
115          * */
116         struct list_head reparse_dentries;
117
118         /* List of dentries, joined by @tmp_list, that need to have raw
119          * encrypted data extracted as soon as the whole blob has been read into
120          * @data_buffer.  */
121         struct list_head encrypted_dentries;
122
123         /* Number of files for which we didn't have permission to set the full
124          * security descriptor.  */
125         unsigned long partial_security_descriptors;
126
127         /* Number of files for which we didn't have permission to set any part
128          * of the security descriptor.  */
129         unsigned long no_security_descriptors;
130
131         /* Number of files for which we couldn't set the short name.  */
132         unsigned long num_set_short_name_failures;
133
134         /* Number of files for which we couldn't remove the short name.  */
135         unsigned long num_remove_short_name_failures;
136
137         /* Have we tried to enable short name support on the target volume yet?
138          */
139         bool tried_to_enable_short_names;
140 };
141
142 /* Get the drive letter from a Windows path, or return the null character if the
143  * path is relative.  */
144 static wchar_t
145 get_drive_letter(const wchar_t *path)
146 {
147         /* Skip \\?\ prefix  */
148         if (!wcsncmp(path, L"\\\\?\\", 4))
149                 path += 4;
150
151         /* Return drive letter if valid  */
152         if (((path[0] >= L'a' && path[0] <= L'z') ||
153              (path[0] >= L'A' && path[0] <= L'Z')) && path[1] == L':')
154                 return path[0];
155
156         return L'\0';
157 }
158
159 static void
160 get_vol_flags(const wchar_t *target, DWORD *vol_flags_ret,
161               bool *short_names_supported_ret)
162 {
163         wchar_t filesystem_name[MAX_PATH + 1];
164         wchar_t drive[4];
165         wchar_t *volume = NULL;
166
167         *vol_flags_ret = 0;
168         *short_names_supported_ret = false;
169
170         drive[0] = get_drive_letter(target);
171         if (drive[0]) {
172                 drive[1] = L':';
173                 drive[2] = L'\\';
174                 drive[3] = L'\0';
175                 volume = drive;
176         }
177
178         if (!GetVolumeInformation(volume, NULL, 0, NULL, NULL,
179                                   vol_flags_ret, filesystem_name,
180                                   ARRAY_LEN(filesystem_name)))
181         {
182                 win32_warning(GetLastError(),
183                               L"Failed to get volume information for \"%ls\"",
184                               target);
185                 return;
186         }
187
188         if (wcsstr(filesystem_name, L"NTFS")) {
189                 /* FILE_SUPPORTS_HARD_LINKS is only supported on Windows 7 and
190                  * later.  Force it on anyway if filesystem is NTFS.  */
191                 *vol_flags_ret |= FILE_SUPPORTS_HARD_LINKS;
192
193                 /* There's no volume flag for short names, but according to the
194                  * MS documentation they are only user-settable on NTFS.  */
195                 *short_names_supported_ret = true;
196         }
197 }
198
199 static const wchar_t *
200 current_path(struct win32_apply_ctx *ctx);
201
202 static void
203 build_extraction_path(const struct wim_dentry *dentry,
204                       struct win32_apply_ctx *ctx);
205
206 static int
207 report_dentry_apply_error(const struct wim_dentry *dentry,
208                           struct win32_apply_ctx *ctx, int ret)
209 {
210         build_extraction_path(dentry, ctx);
211         return report_apply_error(&ctx->common, ret, current_path(ctx));
212 }
213
214 static inline int
215 check_apply_error(const struct wim_dentry *dentry,
216                   struct win32_apply_ctx *ctx, int ret)
217 {
218         if (unlikely(ret))
219                 ret = report_dentry_apply_error(dentry, ctx, ret);
220         return ret;
221 }
222
223 static int
224 win32_get_supported_features(const wchar_t *target,
225                              struct wim_features *supported_features)
226 {
227         DWORD vol_flags;
228         bool short_names_supported;
229
230         /* Query the features of the target volume.  */
231
232         get_vol_flags(target, &vol_flags, &short_names_supported);
233
234         supported_features->archive_files = 1;
235         supported_features->hidden_files = 1;
236         supported_features->system_files = 1;
237
238         if (vol_flags & FILE_FILE_COMPRESSION)
239                 supported_features->compressed_files = 1;
240
241         if (vol_flags & FILE_SUPPORTS_ENCRYPTION) {
242                 supported_features->encrypted_files = 1;
243                 supported_features->encrypted_directories = 1;
244         }
245
246         supported_features->not_context_indexed_files = 1;
247
248         /* Don't do anything with FILE_SUPPORTS_SPARSE_FILES.  */
249
250         if (vol_flags & FILE_NAMED_STREAMS)
251                 supported_features->named_data_streams = 1;
252
253         if (vol_flags & FILE_SUPPORTS_HARD_LINKS)
254                 supported_features->hard_links = 1;
255
256         if (vol_flags & FILE_SUPPORTS_REPARSE_POINTS)
257                 supported_features->reparse_points = 1;
258
259         if (vol_flags & FILE_PERSISTENT_ACLS)
260                 supported_features->security_descriptors = 1;
261
262         if (short_names_supported)
263                 supported_features->short_names = 1;
264
265         supported_features->timestamps = 1;
266
267         /* Note: Windows does not support case sensitive filenames!  At least
268          * not without changing the registry and rebooting...  */
269
270         return 0;
271 }
272
273 /* Load the patterns from [PrepopulateList] of WimBootCompress.ini in the WIM
274  * image being extracted.  */
275 static int
276 load_prepopulate_pats(struct win32_apply_ctx *ctx)
277 {
278         const wchar_t *path = L"\\Windows\\System32\\WimBootCompress.ini";
279         struct wim_dentry *dentry;
280         struct blob_descriptor *blob;
281         int ret;
282         void *buf;
283         struct string_set *s;
284         void *mem;
285         struct text_file_section sec;
286
287         ctx->wimboot.tried_to_load_prepopulate_list = true;
288
289         dentry = get_dentry(ctx->common.wim, path, WIMLIB_CASE_INSENSITIVE);
290         if (!dentry ||
291             (dentry->d_inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
292                                               FILE_ATTRIBUTE_REPARSE_POINT |
293                                               FILE_ATTRIBUTE_ENCRYPTED)) ||
294             !(blob = inode_get_blob_for_unnamed_data_stream(dentry->d_inode,
295                                                             ctx->common.wim->blob_table)))
296         {
297                 WARNING("%ls does not exist in WIM image!", path);
298                 return WIMLIB_ERR_PATH_DOES_NOT_EXIST;
299         }
300
301         ret = read_full_blob_into_alloc_buf(blob, &buf);
302         if (ret)
303                 return ret;
304
305         s = CALLOC(1, sizeof(struct string_set));
306         if (!s) {
307                 FREE(buf);
308                 return WIMLIB_ERR_NOMEM;
309         }
310
311         sec.name = T("PrepopulateList");
312         sec.strings = s;
313
314         ret = do_load_text_file(path, buf, blob->size, &mem, &sec, 1,
315                                 LOAD_TEXT_FILE_REMOVE_QUOTES |
316                                         LOAD_TEXT_FILE_NO_WARNINGS,
317                                 mangle_pat);
318         BUILD_BUG_ON(OS_PREFERRED_PATH_SEPARATOR != WIM_PATH_SEPARATOR);
319         FREE(buf);
320         if (ret) {
321                 FREE(s);
322                 return ret;
323         }
324         ctx->wimboot.prepopulate_pats = s;
325         ctx->wimboot.mem_prepopulate_pats = mem;
326         return 0;
327 }
328
329 /* Returns %true if the specified absolute path to a file in the WIM image
330  * matches a pattern in [PrepopulateList] of WimBootCompress.ini.  Otherwise
331  * returns %false.  */
332 static bool
333 in_prepopulate_list(const wchar_t *path, size_t path_nchars,
334                     const struct win32_apply_ctx *ctx)
335 {
336         const struct string_set *pats = ctx->wimboot.prepopulate_pats;
337
338         if (!pats || !pats->num_strings)
339                 return false;
340
341         return match_pattern_list(path, path_nchars, pats);
342 }
343
344 /* Returns %true if the specified absolute path to a file in the WIM image can
345  * be subject to external backing when extracted.  Otherwise returns %false.  */
346 static bool
347 can_externally_back_path(const wchar_t *path, size_t path_nchars,
348                          const struct win32_apply_ctx *ctx)
349 {
350         if (in_prepopulate_list(path, path_nchars, ctx))
351                 return false;
352
353         /* Since we attempt to modify the SYSTEM registry after it's extracted
354          * (see end_wimboot_extraction()), it can't be extracted as externally
355          * backed.  This extends to associated files such as SYSTEM.LOG that
356          * also must be writable in order to write to the registry.  Normally,
357          * SYSTEM is in [PrepopulateList], and the SYSTEM.* files match patterns
358          * in [ExclusionList] and therefore are not captured in the WIM at all.
359          * However, a WIM that wasn't specifically captured in "WIMBoot mode"
360          * may contain SYSTEM.* files.  So to make things "just work", hard-code
361          * the pattern.  */
362         if (match_path(path, path_nchars, L"\\Windows\\System32\\config\\SYSTEM*",
363                        OS_PREFERRED_PATH_SEPARATOR, false))
364                 return false;
365
366         return true;
367 }
368
369 #define WIM_BACKING_NOT_ENABLED         -1
370 #define WIM_BACKING_NOT_POSSIBLE        -2
371 #define WIM_BACKING_EXCLUDED            -3
372
373 static int
374 will_externally_back_inode(struct wim_inode *inode, struct win32_apply_ctx *ctx,
375                            const struct wim_dentry **excluded_dentry_ret)
376 {
377         struct list_head *next;
378         struct wim_dentry *dentry;
379         struct blob_descriptor *blob;
380         int ret;
381
382         if (inode->i_can_externally_back)
383                 return 0;
384
385         /* This may do redundant checks because the cached value
386          * i_can_externally_back is 2-state (as opposed to 3-state:
387          * unknown/no/yes).  But most files can be externally backed, so this
388          * way is fine.  */
389
390         if (inode->i_attributes & (FILE_ATTRIBUTE_DIRECTORY |
391                                    FILE_ATTRIBUTE_REPARSE_POINT |
392                                    FILE_ATTRIBUTE_ENCRYPTED))
393                 return WIM_BACKING_NOT_POSSIBLE;
394
395         blob = inode_get_blob_for_unnamed_data_stream_resolved(inode);
396
397         /* Note: Microsoft's WoF driver errors out if it tries to satisfy a
398          * read, with ending offset >= 4 GiB, from an externally backed file. */
399         if (!blob ||
400             blob->blob_location != BLOB_IN_WIM ||
401             blob->rdesc->wim != ctx->common.wim ||
402             blob->size != blob->rdesc->uncompressed_size ||
403             blob->size > 4200000000)
404                 return WIM_BACKING_NOT_POSSIBLE;
405
406         /*
407          * We need to check the patterns in [PrepopulateList] against every name
408          * of the inode, in case any of them match.
409          */
410         next = inode->i_extraction_aliases.next;
411         do {
412                 dentry = list_entry(next, struct wim_dentry,
413                                     d_extraction_alias_node);
414
415                 ret = calculate_dentry_full_path(dentry);
416                 if (ret)
417                         return ret;
418
419                 if (!can_externally_back_path(dentry->_full_path,
420                                               wcslen(dentry->_full_path), ctx))
421                 {
422                         if (excluded_dentry_ret)
423                                 *excluded_dentry_ret = dentry;
424                         return WIM_BACKING_EXCLUDED;
425                 }
426                 next = next->next;
427         } while (next != &inode->i_extraction_aliases);
428
429         inode->i_can_externally_back = 1;
430         return 0;
431 }
432
433 /*
434  * Determines if the unnamed data stream of a file will be created as an
435  * external backing, as opposed to a standard extraction.
436  */
437 static int
438 win32_will_externally_back(struct wim_dentry *dentry, struct apply_ctx *_ctx)
439 {
440         struct win32_apply_ctx *ctx = (struct win32_apply_ctx *)_ctx;
441
442         if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT))
443                 return WIM_BACKING_NOT_ENABLED;
444
445         if (!ctx->wimboot.tried_to_load_prepopulate_list)
446                 if (load_prepopulate_pats(ctx) == WIMLIB_ERR_NOMEM)
447                         return WIMLIB_ERR_NOMEM;
448
449         return will_externally_back_inode(dentry->d_inode, ctx, NULL);
450 }
451
452 static int
453 set_external_backing(HANDLE h, struct wim_inode *inode, struct win32_apply_ctx *ctx)
454 {
455         int ret;
456         const struct wim_dentry *excluded_dentry;
457
458         ret = will_externally_back_inode(inode, ctx, &excluded_dentry);
459         if (ret > 0) /* Error.  */
460                 return ret;
461
462         if (ret < 0 && ret != WIM_BACKING_EXCLUDED)
463                 return 0; /* Not externally backing, other than due to exclusion.  */
464
465         if (unlikely(ret == WIM_BACKING_EXCLUDED)) {
466                 /* Not externally backing due to exclusion.  */
467                 union wimlib_progress_info info;
468
469                 build_extraction_path(excluded_dentry, ctx);
470
471                 info.wimboot_exclude.path_in_wim = excluded_dentry->_full_path;
472                 info.wimboot_exclude.extraction_path = current_path(ctx);
473
474                 return call_progress(ctx->common.progfunc,
475                                      WIMLIB_PROGRESS_MSG_WIMBOOT_EXCLUDE,
476                                      &info, ctx->common.progctx);
477         } else {
478                 /* Externally backing.  */
479                 if (unlikely(!wimboot_set_pointer(h,
480                                                   inode_get_blob_for_unnamed_data_stream_resolved(inode),
481                                                   ctx->wimboot.data_source_id,
482                                                   ctx->wimboot.blob_table_hash,
483                                                   ctx->wimboot.wof_running)))
484                 {
485                         const DWORD err = GetLastError();
486
487                         build_extraction_path(inode_first_extraction_dentry(inode), ctx);
488                         win32_error(err, L"\"%ls\": Couldn't set WIMBoot pointer data",
489                                     current_path(ctx));
490                         return WIMLIB_ERR_WIMBOOT;
491                 }
492                 return 0;
493         }
494 }
495
496 /* Calculates the SHA-1 message digest of the WIM's blob table.  */
497 static int
498 hash_blob_table(WIMStruct *wim, u8 hash[SHA1_HASH_SIZE])
499 {
500         return wim_reshdr_to_hash(&wim->hdr.blob_table_reshdr, wim, hash);
501 }
502
503 /* Prepare for doing a "WIMBoot" extraction by loading patterns from
504  * [PrepopulateList] of WimBootCompress.ini and allocating a WOF data source ID
505  * on the target volume.  */
506 static int
507 start_wimboot_extraction(struct win32_apply_ctx *ctx)
508 {
509         int ret;
510         WIMStruct *wim = ctx->common.wim;
511
512         if (!ctx->wimboot.tried_to_load_prepopulate_list)
513                 if (load_prepopulate_pats(ctx) == WIMLIB_ERR_NOMEM)
514                         return WIMLIB_ERR_NOMEM;
515
516         if (!wim_info_get_wimboot(wim->wim_info, wim->current_image))
517                 WARNING("Image is not marked as WIMBoot compatible!");
518
519         ret = hash_blob_table(ctx->common.wim, ctx->wimboot.blob_table_hash);
520         if (ret)
521                 return ret;
522
523         return wimboot_alloc_data_source_id(wim->filename,
524                                             wim->hdr.guid,
525                                             wim->current_image,
526                                             ctx->common.target,
527                                             &ctx->wimboot.data_source_id,
528                                             &ctx->wimboot.wof_running);
529 }
530
531 static void
532 build_win32_extraction_path(const struct wim_dentry *dentry,
533                             struct win32_apply_ctx *ctx);
534
535 /* Sets WimBoot=1 in the extracted SYSTEM registry hive.
536  *
537  * WIMGAPI does this, and it's possible that it's important.
538  * But I don't know exactly what this value means to Windows.  */
539 static int
540 end_wimboot_extraction(struct win32_apply_ctx *ctx)
541 {
542         struct wim_dentry *dentry;
543         wchar_t subkeyname[32];
544         LONG res;
545         LONG res2;
546         HKEY key;
547         DWORD value;
548
549         dentry = get_dentry(ctx->common.wim, L"\\Windows\\System32\\config\\SYSTEM",
550                             WIMLIB_CASE_INSENSITIVE);
551
552         if (!dentry || !will_extract_dentry(dentry))
553                 goto out;
554
555         if (!will_extract_dentry(wim_get_current_root_dentry(ctx->common.wim)))
556                 goto out;
557
558         /* Not bothering to use the native routines (e.g. NtLoadKey()) for this.
559          * If this doesn't work, you probably also have many other problems.  */
560
561         build_win32_extraction_path(dentry, ctx);
562
563         randomize_char_array_with_alnum(subkeyname, 20);
564         subkeyname[20] = L'\0';
565
566         res = RegLoadKey(HKEY_LOCAL_MACHINE, subkeyname, ctx->pathbuf.Buffer);
567         if (res)
568                 goto out_check_res;
569
570         wcscpy(&subkeyname[20], L"\\Setup");
571
572         res = RegCreateKeyEx(HKEY_LOCAL_MACHINE, subkeyname, 0, NULL,
573                              REG_OPTION_BACKUP_RESTORE, 0, NULL, &key, NULL);
574         if (res)
575                 goto out_unload_key;
576
577         value = 1;
578
579         res = RegSetValueEx(key, L"WimBoot", 0, REG_DWORD,
580                             (const BYTE *)&value, sizeof(DWORD));
581         if (res)
582                 goto out_close_key;
583
584         res = RegFlushKey(key);
585
586 out_close_key:
587         res2 = RegCloseKey(key);
588         if (!res)
589                 res = res2;
590 out_unload_key:
591         subkeyname[20] = L'\0';
592         RegUnLoadKey(HKEY_LOCAL_MACHINE, subkeyname);
593 out_check_res:
594         if (res) {
595                 /* Warning only.  */
596                 win32_warning(res, L"Failed to set \\Setup: dword \"WimBoot\"=1 "
597                               "value in registry hive \"%ls\"",
598                               ctx->pathbuf.Buffer);
599         }
600 out:
601         return 0;
602 }
603
604 /* Returns the number of wide characters needed to represent the path to the
605  * specified @dentry, relative to the target directory, when extracted.
606  *
607  * Does not include null terminator (not needed for NtCreateFile).  */
608 static size_t
609 dentry_extraction_path_length(const struct wim_dentry *dentry)
610 {
611         size_t len = 0;
612         const struct wim_dentry *d;
613
614         d = dentry;
615         do {
616                 len += d->d_extraction_name_nchars + 1;
617                 d = d->d_parent;
618         } while (!dentry_is_root(d) && will_extract_dentry(d));
619
620         return --len;  /* No leading slash  */
621 }
622
623 /* Returns the length of the longest string that might need to be appended to
624  * the path to an alias of an inode to open or create a named data stream.
625  *
626  * If the inode has no named data streams, this will be 0.  Otherwise, this will
627  * be 1 plus the length of the longest-named data stream, since the data stream
628  * name must be separated from the path by the ':' character.  */
629 static size_t
630 inode_longest_named_data_stream_spec(const struct wim_inode *inode)
631 {
632         size_t max = 0;
633         for (unsigned i = 0; i < inode->i_num_streams; i++) {
634                 const struct wim_inode_stream *strm = &inode->i_streams[i];
635                 if (!stream_is_named_data_stream(strm))
636                         continue;
637                 size_t len = utf16le_len_chars(strm->stream_name);
638                 if (len > max)
639                         max = len;
640         }
641         if (max)
642                 max += 1;
643         return max;
644 }
645
646 /* Find the length, in wide characters, of the longest path needed for
647  * extraction of any file in @dentry_list relative to the target directory.
648  *
649  * Accounts for named data streams, but does not include null terminator (not
650  * needed for NtCreateFile).  */
651 static size_t
652 compute_path_max(struct list_head *dentry_list)
653 {
654         size_t max = 0;
655         const struct wim_dentry *dentry;
656
657         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
658                 size_t len;
659
660                 len = dentry_extraction_path_length(dentry);
661
662                 /* Account for named data streams  */
663                 len += inode_longest_named_data_stream_spec(dentry->d_inode);
664
665                 if (len > max)
666                         max = len;
667         }
668
669         return max;
670 }
671
672 /* Build the path at which to extract the @dentry, relative to the target
673  * directory.
674  *
675  * The path is saved in ctx->pathbuf.  */
676 static void
677 build_extraction_path(const struct wim_dentry *dentry,
678                       struct win32_apply_ctx *ctx)
679 {
680         size_t len;
681         wchar_t *p;
682         const struct wim_dentry *d;
683
684         len = dentry_extraction_path_length(dentry);
685
686         ctx->pathbuf.Length = len * sizeof(wchar_t);
687         p = ctx->pathbuf.Buffer + len;
688         for (d = dentry;
689              !dentry_is_root(d->d_parent) && will_extract_dentry(d->d_parent);
690              d = d->d_parent)
691         {
692                 p -= d->d_extraction_name_nchars;
693                 wmemcpy(p, d->d_extraction_name, d->d_extraction_name_nchars);
694                 *--p = '\\';
695         }
696         /* No leading slash  */
697         p -= d->d_extraction_name_nchars;
698         wmemcpy(p, d->d_extraction_name, d->d_extraction_name_nchars);
699 }
700
701 /* Build the path at which to extract the @dentry, relative to the target
702  * directory, adding the suffix for a named data stream.
703  *
704  * The path is saved in ctx->pathbuf.  */
705 static void
706 build_extraction_path_with_ads(const struct wim_dentry *dentry,
707                                struct win32_apply_ctx *ctx,
708                                const wchar_t *stream_name,
709                                size_t stream_name_nchars)
710 {
711         wchar_t *p;
712
713         build_extraction_path(dentry, ctx);
714
715         /* Add :NAME for named data stream  */
716         p = ctx->pathbuf.Buffer + (ctx->pathbuf.Length / sizeof(wchar_t));
717         *p++ = L':';
718         wmemcpy(p, stream_name, stream_name_nchars);
719         ctx->pathbuf.Length += (1 + stream_name_nchars) * sizeof(wchar_t);
720 }
721
722 /* Build the Win32 namespace path to the specified @dentry when extracted.
723  *
724  * The path is saved in ctx->pathbuf and will be null terminated.
725  *
726  * XXX: We could get rid of this if it wasn't needed for the file encryption
727  * APIs, and the registry manipulation in WIMBoot mode.  */
728 static void
729 build_win32_extraction_path(const struct wim_dentry *dentry,
730                             struct win32_apply_ctx *ctx)
731 {
732         build_extraction_path(dentry, ctx);
733
734         /* Prepend target_ntpath to our relative path, then change \??\ into \\?\  */
735
736         memmove(ctx->pathbuf.Buffer +
737                         (ctx->target_ntpath.Length / sizeof(wchar_t)) + 1,
738                 ctx->pathbuf.Buffer, ctx->pathbuf.Length);
739         memcpy(ctx->pathbuf.Buffer, ctx->target_ntpath.Buffer,
740                 ctx->target_ntpath.Length);
741         ctx->pathbuf.Buffer[ctx->target_ntpath.Length / sizeof(wchar_t)] = L'\\';
742         ctx->pathbuf.Length += ctx->target_ntpath.Length + sizeof(wchar_t);
743         ctx->pathbuf.Buffer[ctx->pathbuf.Length / sizeof(wchar_t)] = L'\0';
744
745         wimlib_assert(ctx->pathbuf.Length >= 4 * sizeof(wchar_t) &&
746                       !wmemcmp(ctx->pathbuf.Buffer, L"\\??\\", 4));
747
748         ctx->pathbuf.Buffer[1] = L'\\';
749
750 }
751
752 /* Returns a "printable" representation of the last relative NT path that was
753  * constructed with build_extraction_path() or build_extraction_path_with_ads().
754  *
755  * This will be overwritten by the next call to this function.  */
756 static const wchar_t *
757 current_path(struct win32_apply_ctx *ctx)
758 {
759         wchar_t *p = ctx->print_buffer;
760
761         p = wmempcpy(p, ctx->common.target, ctx->common.target_nchars);
762         *p++ = L'\\';
763         p = wmempcpy(p, ctx->pathbuf.Buffer, ctx->pathbuf.Length / sizeof(wchar_t));
764         *p = L'\0';
765         return ctx->print_buffer;
766 }
767
768 /* Open handle to the target directory if it is not already open.  If the target
769  * directory does not exist, this creates it.  */
770 static int
771 open_target_directory(struct win32_apply_ctx *ctx)
772 {
773         NTSTATUS status;
774
775         if (ctx->h_target)
776                 return 0;
777
778         ctx->attr.Length = sizeof(ctx->attr);
779         ctx->attr.RootDirectory = NULL;
780         ctx->attr.ObjectName = &ctx->target_ntpath;
781         status = (*func_NtCreateFile)(&ctx->h_target,
782                                       FILE_TRAVERSE,
783                                       &ctx->attr,
784                                       &ctx->iosb,
785                                       NULL,
786                                       0,
787                                       FILE_SHARE_VALID_FLAGS,
788                                       FILE_OPEN_IF,
789                                       FILE_DIRECTORY_FILE |
790                                               FILE_OPEN_REPARSE_POINT |
791                                               FILE_OPEN_FOR_BACKUP_INTENT,
792                                       NULL,
793                                       0);
794         if (!NT_SUCCESS(status)) {
795                 winnt_error(status, L"Can't open or create directory \"%ls\"",
796                             ctx->common.target);
797                 return WIMLIB_ERR_OPENDIR;
798         }
799         ctx->attr.RootDirectory = ctx->h_target;
800         ctx->attr.ObjectName = &ctx->pathbuf;
801         return 0;
802 }
803
804 static void
805 close_target_directory(struct win32_apply_ctx *ctx)
806 {
807         if (ctx->h_target) {
808                 (*func_NtClose)(ctx->h_target);
809                 ctx->h_target = NULL;
810                 ctx->attr.RootDirectory = NULL;
811         }
812 }
813
814 /*
815  * Ensures the target directory exists and opens a handle to it, in preparation
816  * of using paths relative to it.
817  */
818 static int
819 prepare_target(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
820 {
821         int ret;
822         size_t path_max;
823
824         ret = win32_path_to_nt_path(ctx->common.target, &ctx->target_ntpath);
825         if (ret)
826                 return ret;
827
828         ret = open_target_directory(ctx);
829         if (ret)
830                 return ret;
831
832         path_max = compute_path_max(dentry_list);
833         /* Add some extra for building Win32 paths for the file encryption APIs,
834          * and ensure we have at least enough to potentially use a 8.3 name for
835          * the last component.  */
836         path_max += max(2 + (ctx->target_ntpath.Length / sizeof(wchar_t)),
837                         8 + 1 + 3);
838
839         ctx->pathbuf.MaximumLength = path_max * sizeof(wchar_t);
840         ctx->pathbuf.Buffer = MALLOC(ctx->pathbuf.MaximumLength);
841         if (!ctx->pathbuf.Buffer)
842                 return WIMLIB_ERR_NOMEM;
843
844         ctx->print_buffer = MALLOC((ctx->common.target_nchars + 1 + path_max + 1) *
845                                    sizeof(wchar_t));
846         if (!ctx->print_buffer)
847                 return WIMLIB_ERR_NOMEM;
848
849         return 0;
850 }
851
852 /* When creating an inode that will have a short (DOS) name, we create it using
853  * the long name associated with the short name.  This ensures that the short
854  * name gets associated with the correct long name.  */
855 static struct wim_dentry *
856 first_extraction_alias(const struct wim_inode *inode)
857 {
858         struct list_head *next = inode->i_extraction_aliases.next;
859         struct wim_dentry *dentry;
860
861         do {
862                 dentry = list_entry(next, struct wim_dentry,
863                                     d_extraction_alias_node);
864                 if (dentry_has_short_name(dentry))
865                         break;
866                 next = next->next;
867         } while (next != &inode->i_extraction_aliases);
868         return dentry;
869 }
870
871 /*
872  * Set or clear FILE_ATTRIBUTE_COMPRESSED if the inherited value is different
873  * from the desired value.
874  *
875  * Note that you can NOT override the inherited value of
876  * FILE_ATTRIBUTE_COMPRESSED directly with NtCreateFile().
877  */
878 static int
879 adjust_compression_attribute(HANDLE h, const struct wim_dentry *dentry,
880                              struct win32_apply_ctx *ctx)
881 {
882         const bool compressed = (dentry->d_inode->i_attributes &
883                                  FILE_ATTRIBUTE_COMPRESSED);
884
885         if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES)
886                 return 0;
887
888         if (!ctx->common.supported_features.compressed_files)
889                 return 0;
890
891         FILE_BASIC_INFORMATION info;
892         NTSTATUS status;
893         USHORT compression_state;
894
895         /* Get current attributes  */
896         status = (*func_NtQueryInformationFile)(h, &ctx->iosb,
897                                                 &info, sizeof(info),
898                                                 FileBasicInformation);
899         if (NT_SUCCESS(status) &&
900             compressed == !!(info.FileAttributes & FILE_ATTRIBUTE_COMPRESSED))
901         {
902                 /* Nothing needs to be done.  */
903                 return 0;
904         }
905
906         /* Set the new compression state  */
907
908         if (compressed)
909                 compression_state = COMPRESSION_FORMAT_DEFAULT;
910         else
911                 compression_state = COMPRESSION_FORMAT_NONE;
912
913         status = (*func_NtFsControlFile)(h,
914                                          NULL,
915                                          NULL,
916                                          NULL,
917                                          &ctx->iosb,
918                                          FSCTL_SET_COMPRESSION,
919                                          &compression_state,
920                                          sizeof(USHORT),
921                                          NULL,
922                                          0);
923         if (NT_SUCCESS(status))
924                 return 0;
925
926         winnt_error(status, L"Can't %s compression attribute on \"%ls\"",
927                     (compressed ? "set" : "clear"), current_path(ctx));
928         return WIMLIB_ERR_SET_ATTRIBUTES;
929 }
930
931 /* Try to enable short name support on the target volume.  If successful, return
932  * true.  If unsuccessful, issue a warning and return false.  */
933 static bool
934 try_to_enable_short_names(const wchar_t *volume)
935 {
936         HANDLE h;
937         FILE_FS_PERSISTENT_VOLUME_INFORMATION info;
938         BOOL bret;
939         DWORD bytesReturned;
940
941         h = CreateFile(volume, GENERIC_WRITE,
942                        FILE_SHARE_VALID_FLAGS, NULL, OPEN_EXISTING,
943                        FILE_FLAG_BACKUP_SEMANTICS, NULL);
944         if (h == INVALID_HANDLE_VALUE)
945                 goto fail;
946
947         info.VolumeFlags = 0;
948         info.FlagMask = PERSISTENT_VOLUME_STATE_SHORT_NAME_CREATION_DISABLED;
949         info.Version = 1;
950         info.Reserved = 0;
951
952         bret = DeviceIoControl(h, FSCTL_SET_PERSISTENT_VOLUME_STATE,
953                                &info, sizeof(info), NULL, 0,
954                                &bytesReturned, NULL);
955
956         CloseHandle(h);
957
958         if (!bret)
959                 goto fail;
960         return true;
961
962 fail:
963         win32_warning(GetLastError(),
964                       L"Failed to enable short name support on %ls",
965                       volume + 4);
966         return false;
967 }
968
969 static NTSTATUS
970 remove_conflicting_short_name(const struct wim_dentry *dentry, struct win32_apply_ctx *ctx)
971 {
972         wchar_t *name;
973         wchar_t *end;
974         NTSTATUS status;
975         HANDLE h;
976         size_t bufsize = offsetof(FILE_NAME_INFORMATION, FileName) +
977                          (13 * sizeof(wchar_t));
978         u8 buf[bufsize] _aligned_attribute(8);
979         bool retried = false;
980         FILE_NAME_INFORMATION *info = (FILE_NAME_INFORMATION *)buf;
981
982         memset(buf, 0, bufsize);
983
984         /* Build the path with the short name.  */
985         name = &ctx->pathbuf.Buffer[ctx->pathbuf.Length / sizeof(wchar_t)];
986         while (name != ctx->pathbuf.Buffer && *(name - 1) != L'\\')
987                 name--;
988         end = mempcpy(name, dentry->short_name, dentry->short_name_nbytes);
989         ctx->pathbuf.Length = ((u8 *)end - (u8 *)ctx->pathbuf.Buffer);
990
991         /* Open the conflicting file (by short name).  */
992         status = (*func_NtOpenFile)(&h, GENERIC_WRITE | DELETE,
993                                     &ctx->attr, &ctx->iosb,
994                                     FILE_SHARE_VALID_FLAGS,
995                                     FILE_OPEN_REPARSE_POINT | FILE_OPEN_FOR_BACKUP_INTENT);
996         if (!NT_SUCCESS(status)) {
997                 winnt_warning(status, L"Can't open \"%ls\"", current_path(ctx));
998                 goto out;
999         }
1000
1001 #if 0
1002         WARNING("Overriding conflicting short name; path=\"%ls\"",
1003                 current_path(ctx));
1004 #endif
1005
1006         /* Try to remove the short name on the conflicting file.  */
1007
1008 retry:
1009         status = (*func_NtSetInformationFile)(h, &ctx->iosb, info, bufsize,
1010                                               FileShortNameInformation);
1011
1012         if (status == STATUS_INVALID_PARAMETER && !retried) {
1013
1014                 /* Microsoft forgot to make it possible to remove short names
1015                  * until Windows 7.  Oops.  Use a random short name instead.  */
1016
1017                 info->FileNameLength = 12 * sizeof(wchar_t);
1018                 for (int i = 0; i < 8; i++)
1019                         info->FileName[i] = 'A' + (rand() % 26);
1020                 info->FileName[8] = L'.';
1021                 info->FileName[9] = L'W';
1022                 info->FileName[10] = L'L';
1023                 info->FileName[11] = L'B';
1024                 info->FileName[12] = L'\0';
1025                 retried = true;
1026                 goto retry;
1027         }
1028         (*func_NtClose)(h);
1029 out:
1030         build_extraction_path(dentry, ctx);
1031         return status;
1032 }
1033
1034 /* Set the short name on the open file @h which has been created at the location
1035  * indicated by @dentry.
1036  *
1037  * Note that this may add, change, or remove the short name.
1038  *
1039  * @h must be opened with DELETE access.
1040  *
1041  * Returns 0 or WIMLIB_ERR_SET_SHORT_NAME.  The latter only happens in
1042  * STRICT_SHORT_NAMES mode.
1043  */
1044 static int
1045 set_short_name(HANDLE h, const struct wim_dentry *dentry,
1046                struct win32_apply_ctx *ctx)
1047 {
1048
1049         if (!ctx->common.supported_features.short_names)
1050                 return 0;
1051
1052         /*
1053          * Note: The size of the FILE_NAME_INFORMATION buffer must be such that
1054          * FileName contains at least 2 wide characters (4 bytes).  Otherwise,
1055          * NtSetInformationFile() will return STATUS_INFO_LENGTH_MISMATCH.  This
1056          * is despite the fact that FileNameLength can validly be 0 or 2 bytes,
1057          * with the former case being removing the existing short name if
1058          * present, rather than setting one.
1059          *
1060          * The null terminator is seemingly optional, but to be safe we include
1061          * space for it and zero all unused space.
1062          */
1063
1064         size_t bufsize = offsetof(FILE_NAME_INFORMATION, FileName) +
1065                          max(dentry->short_name_nbytes, sizeof(wchar_t)) +
1066                          sizeof(wchar_t);
1067         u8 buf[bufsize] _aligned_attribute(8);
1068         FILE_NAME_INFORMATION *info = (FILE_NAME_INFORMATION *)buf;
1069         NTSTATUS status;
1070         bool tried_to_remove_existing = false;
1071
1072         memset(buf, 0, bufsize);
1073
1074         info->FileNameLength = dentry->short_name_nbytes;
1075         memcpy(info->FileName, dentry->short_name, dentry->short_name_nbytes);
1076
1077 retry:
1078         status = (*func_NtSetInformationFile)(h, &ctx->iosb, info, bufsize,
1079                                               FileShortNameInformation);
1080         if (NT_SUCCESS(status))
1081                 return 0;
1082
1083         if (status == STATUS_SHORT_NAMES_NOT_ENABLED_ON_VOLUME) {
1084                 if (dentry->short_name_nbytes == 0)
1085                         return 0;
1086                 if (!ctx->tried_to_enable_short_names) {
1087                         wchar_t volume[7];
1088                         int ret;
1089
1090                         ctx->tried_to_enable_short_names = true;
1091
1092                         ret = win32_get_drive_path(ctx->common.target,
1093                                                    volume);
1094                         if (ret)
1095                                 return ret;
1096                         if (try_to_enable_short_names(volume))
1097                                 goto retry;
1098                 }
1099         }
1100
1101         /*
1102          * Short names can conflict in several cases:
1103          *
1104          * - a file being extracted has a short name conflicting with an
1105          *   existing file
1106          *
1107          * - a file being extracted has a short name conflicting with another
1108          *   file being extracted (possible, but shouldn't happen)
1109          *
1110          * - a file being extracted has a short name that conflicts with the
1111          *   automatically generated short name of a file we previously
1112          *   extracted, but failed to set the short name for.  Sounds unlikely,
1113          *   but this actually does happen fairly often on versions of Windows
1114          *   prior to Windows 7 because they do not support removing short names
1115          *   from files.
1116          */
1117         if (unlikely(status == STATUS_OBJECT_NAME_COLLISION) &&
1118             dentry->short_name_nbytes && !tried_to_remove_existing)
1119         {
1120                 tried_to_remove_existing = true;
1121                 status = remove_conflicting_short_name(dentry, ctx);
1122                 if (NT_SUCCESS(status))
1123                         goto retry;
1124         }
1125
1126         /* By default, failure to set short names is not an error (since short
1127          * names aren't too important anymore...).  */
1128         if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SHORT_NAMES)) {
1129                 if (dentry->short_name_nbytes)
1130                         ctx->num_set_short_name_failures++;
1131                 else
1132                         ctx->num_remove_short_name_failures++;
1133                 return 0;
1134         }
1135
1136         winnt_error(status, L"Can't set short name on \"%ls\"", current_path(ctx));
1137         return WIMLIB_ERR_SET_SHORT_NAME;
1138 }
1139
1140 /*
1141  * A wrapper around NtCreateFile() to make it slightly more usable...
1142  * This uses the path currently constructed in ctx->pathbuf.
1143  *
1144  * Also, we always specify FILE_OPEN_FOR_BACKUP_INTENT and
1145  * FILE_OPEN_REPARSE_POINT.
1146  */
1147 static NTSTATUS
1148 do_create_file(PHANDLE FileHandle,
1149                ACCESS_MASK DesiredAccess,
1150                PLARGE_INTEGER AllocationSize,
1151                ULONG FileAttributes,
1152                ULONG CreateDisposition,
1153                ULONG CreateOptions,
1154                struct win32_apply_ctx *ctx)
1155 {
1156         return (*func_NtCreateFile)(FileHandle,
1157                                     DesiredAccess,
1158                                     &ctx->attr,
1159                                     &ctx->iosb,
1160                                     AllocationSize,
1161                                     FileAttributes,
1162                                     FILE_SHARE_VALID_FLAGS,
1163                                     CreateDisposition,
1164                                     CreateOptions |
1165                                         FILE_OPEN_FOR_BACKUP_INTENT |
1166                                         FILE_OPEN_REPARSE_POINT,
1167                                     NULL,
1168                                     0);
1169 }
1170
1171 /* Like do_create_file(), but builds the extraction path of the @dentry first.
1172  */
1173 static NTSTATUS
1174 create_file(PHANDLE FileHandle,
1175             ACCESS_MASK DesiredAccess,
1176             PLARGE_INTEGER AllocationSize,
1177             ULONG FileAttributes,
1178             ULONG CreateDisposition,
1179             ULONG CreateOptions,
1180             const struct wim_dentry *dentry,
1181             struct win32_apply_ctx *ctx)
1182 {
1183         build_extraction_path(dentry, ctx);
1184         return do_create_file(FileHandle,
1185                               DesiredAccess,
1186                               AllocationSize,
1187                               FileAttributes,
1188                               CreateDisposition,
1189                               CreateOptions,
1190                               ctx);
1191 }
1192
1193 static int
1194 delete_file_or_stream(struct win32_apply_ctx *ctx)
1195 {
1196         NTSTATUS status;
1197         HANDLE h;
1198         FILE_DISPOSITION_INFORMATION disposition_info;
1199         FILE_BASIC_INFORMATION basic_info;
1200         bool retried = false;
1201
1202         status = do_create_file(&h,
1203                                 DELETE,
1204                                 NULL,
1205                                 0,
1206                                 FILE_OPEN,
1207                                 FILE_NON_DIRECTORY_FILE,
1208                                 ctx);
1209         if (unlikely(!NT_SUCCESS(status))) {
1210                 winnt_error(status, L"Can't open \"%ls\" for deletion",
1211                             current_path(ctx));
1212                 return WIMLIB_ERR_OPEN;
1213         }
1214
1215 retry:
1216         disposition_info.DoDeleteFile = TRUE;
1217         status = (*func_NtSetInformationFile)(h, &ctx->iosb,
1218                                               &disposition_info,
1219                                               sizeof(disposition_info),
1220                                               FileDispositionInformation);
1221         (*func_NtClose)(h);
1222         if (likely(NT_SUCCESS(status)))
1223                 return 0;
1224
1225         if (status == STATUS_CANNOT_DELETE && !retried) {
1226                 /* Clear file attributes and try again.  This is necessary for
1227                  * FILE_ATTRIBUTE_READONLY files.  */
1228                 status = do_create_file(&h,
1229                                         FILE_WRITE_ATTRIBUTES | DELETE,
1230                                         NULL,
1231                                         0,
1232                                         FILE_OPEN,
1233                                         FILE_NON_DIRECTORY_FILE,
1234                                         ctx);
1235                 if (!NT_SUCCESS(status)) {
1236                         winnt_error(status,
1237                                     L"Can't open \"%ls\" to reset attributes",
1238                                     current_path(ctx));
1239                         return WIMLIB_ERR_OPEN;
1240                 }
1241                 memset(&basic_info, 0, sizeof(basic_info));
1242                 basic_info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
1243                 status = (*func_NtSetInformationFile)(h, &ctx->iosb,
1244                                                       &basic_info,
1245                                                       sizeof(basic_info),
1246                                                       FileBasicInformation);
1247                 if (!NT_SUCCESS(status)) {
1248                         winnt_error(status,
1249                                     L"Can't reset file attributes on \"%ls\"",
1250                                     current_path(ctx));
1251                         (*func_NtClose)(h);
1252                         return WIMLIB_ERR_SET_ATTRIBUTES;
1253                 }
1254                 retried = true;
1255                 goto retry;
1256         }
1257         winnt_error(status, L"Can't delete \"%ls\"", current_path(ctx));
1258         return WIMLIB_ERR_OPEN;
1259 }
1260
1261 /*
1262  * Create a nondirectory file or named data stream at the current path,
1263  * superseding any that already exists at that path.  If successful, return an
1264  * open handle to the file or named data stream.
1265  */
1266 static int
1267 supersede_file_or_stream(struct win32_apply_ctx *ctx, HANDLE *h_ret)
1268 {
1269         NTSTATUS status;
1270         bool retried = false;
1271
1272         /* FILE_ATTRIBUTE_SYSTEM is needed to ensure that
1273          * FILE_ATTRIBUTE_ENCRYPTED doesn't get set before we want it to be.  */
1274 retry:
1275         status = do_create_file(h_ret,
1276                                 GENERIC_READ | GENERIC_WRITE | DELETE,
1277                                 NULL,
1278                                 FILE_ATTRIBUTE_SYSTEM,
1279                                 FILE_CREATE,
1280                                 FILE_NON_DIRECTORY_FILE,
1281                                 ctx);
1282         if (likely(NT_SUCCESS(status)))
1283                 return 0;
1284
1285         /* STATUS_OBJECT_NAME_COLLISION means that the file or stream already
1286          * exists.  Delete the existing file or stream, then try again.
1287          *
1288          * Note: we don't use FILE_OVERWRITE_IF or FILE_SUPERSEDE because of
1289          * problems with certain file attributes, especially
1290          * FILE_ATTRIBUTE_ENCRYPTED.  FILE_SUPERSEDE is also broken in the
1291          * Windows PE ramdisk.  */
1292         if (status == STATUS_OBJECT_NAME_COLLISION && !retried) {
1293                 int ret = delete_file_or_stream(ctx);
1294                 if (ret)
1295                         return ret;
1296                 retried = true;
1297                 goto retry;
1298         }
1299         winnt_error(status, L"Can't create \"%ls\"", current_path(ctx));
1300         return WIMLIB_ERR_OPEN;
1301 }
1302
1303 /*
1304  * Create empty named data streams for the specified file, if there are any.
1305  *
1306  * Since these won't have blob descriptors, they won't show up in the call to
1307  * extract_blob_list().  Hence the need for the special case.
1308  */
1309 static int
1310 create_empty_named_data_streams(const struct wim_dentry *dentry,
1311                                 struct win32_apply_ctx *ctx)
1312 {
1313         const struct wim_inode *inode = dentry->d_inode;
1314         bool path_modified = false;
1315         int ret = 0;
1316
1317         if (!ctx->common.supported_features.named_data_streams)
1318                 return 0;
1319
1320         for (unsigned i = 0; i < inode->i_num_streams; i++) {
1321                 const struct wim_inode_stream *strm = &inode->i_streams[i];
1322                 HANDLE h;
1323
1324                 if (!stream_is_named_data_stream(strm) ||
1325                     stream_blob_resolved(strm) != NULL)
1326                         continue;
1327
1328                 build_extraction_path_with_ads(dentry, ctx,
1329                                                strm->stream_name,
1330                                                utf16le_len_chars(strm->stream_name));
1331                 path_modified = true;
1332                 ret = supersede_file_or_stream(ctx, &h);
1333                 if (ret)
1334                         break;
1335                 (*func_NtClose)(h);
1336         }
1337         /* Restore the path to the dentry itself  */
1338         if (path_modified)
1339                 build_extraction_path(dentry, ctx);
1340         return ret;
1341 }
1342
1343 /*
1344  * Creates the directory named by @dentry, or uses an existing directory at that
1345  * location.  If necessary, sets the short name and/or fixes compression and
1346  * encryption attributes.
1347  *
1348  * Returns 0, WIMLIB_ERR_MKDIR, or WIMLIB_ERR_SET_SHORT_NAME.
1349  */
1350 static int
1351 create_directory(const struct wim_dentry *dentry, struct win32_apply_ctx *ctx)
1352 {
1353         DWORD perms;
1354         NTSTATUS status;
1355         HANDLE h;
1356         int ret;
1357
1358         /* DELETE is needed for set_short_name(); GENERIC_READ and GENERIC_WRITE
1359          * are needed for adjust_compression_attribute().  */
1360         perms = GENERIC_READ | GENERIC_WRITE;
1361         if (!dentry_is_root(dentry))
1362                 perms |= DELETE;
1363
1364         /* FILE_ATTRIBUTE_SYSTEM is needed to ensure that
1365          * FILE_ATTRIBUTE_ENCRYPTED doesn't get set before we want it to be.  */
1366         status = create_file(&h, perms, NULL, FILE_ATTRIBUTE_SYSTEM,
1367                              FILE_OPEN_IF, FILE_DIRECTORY_FILE, dentry, ctx);
1368         if (!NT_SUCCESS(status)) {
1369                 winnt_error(status, L"Can't create directory \"%ls\"",
1370                             current_path(ctx));
1371                 return WIMLIB_ERR_MKDIR;
1372         }
1373
1374         if (ctx->iosb.Information == FILE_OPENED) {
1375                 /* If we opened an existing directory, try to clear its file
1376                  * attributes.  As far as I know, this only actually makes a
1377                  * difference in the case where a FILE_ATTRIBUTE_READONLY
1378                  * directory has a named data stream which needs to be
1379                  * extracted.  You cannot create a named data stream of such a
1380                  * directory, even though this contradicts Microsoft's
1381                  * documentation for FILE_ATTRIBUTE_READONLY which states it is
1382                  * not honored for directories!  */
1383                 FILE_BASIC_INFORMATION basic_info = { .FileAttributes = FILE_ATTRIBUTE_NORMAL };
1384                 (*func_NtSetInformationFile)(h, &ctx->iosb, &basic_info,
1385                                              sizeof(basic_info), FileBasicInformation);
1386         }
1387
1388         if (!dentry_is_root(dentry)) {
1389                 ret = set_short_name(h, dentry, ctx);
1390                 if (ret)
1391                         goto out;
1392         }
1393
1394         ret = adjust_compression_attribute(h, dentry, ctx);
1395 out:
1396         (*func_NtClose)(h);
1397         return ret;
1398 }
1399
1400 /*
1401  * Create all the directories being extracted, other than the target directory
1402  * itself.
1403  *
1404  * Note: we don't honor directory hard links.  However, we don't allow them to
1405  * exist in WIM images anyway (see inode_fixup.c).
1406  */
1407 static int
1408 create_directories(struct list_head *dentry_list,
1409                    struct win32_apply_ctx *ctx)
1410 {
1411         const struct wim_dentry *dentry;
1412         int ret;
1413
1414         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1415
1416                 if (!(dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY))
1417                         continue;
1418
1419                 /* Note: Here we include files with
1420                  * FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_REPARSE_POINT, but we
1421                  * wait until later to actually set the reparse data.  */
1422
1423                 ret = create_directory(dentry, ctx);
1424
1425                 if (!ret)
1426                         ret = create_empty_named_data_streams(dentry, ctx);
1427
1428                 ret = check_apply_error(dentry, ctx, ret);
1429                 if (ret)
1430                         return ret;
1431
1432                 ret = report_file_created(&ctx->common);
1433                 if (ret)
1434                         return ret;
1435         }
1436         return 0;
1437 }
1438
1439 /*
1440  * Creates the nondirectory file named by @dentry.
1441  *
1442  * On success, returns an open handle to the file in @h_ret, with GENERIC_READ,
1443  * GENERIC_WRITE, and DELETE access.  Also, the path to the file will be saved
1444  * in ctx->pathbuf.  On failure, returns an error code.
1445  */
1446 static int
1447 create_nondirectory_inode(HANDLE *h_ret, const struct wim_dentry *dentry,
1448                           struct win32_apply_ctx *ctx)
1449 {
1450         int ret;
1451         HANDLE h;
1452
1453         build_extraction_path(dentry, ctx);
1454
1455         ret = supersede_file_or_stream(ctx, &h);
1456         if (ret)
1457                 goto out;
1458
1459         ret = adjust_compression_attribute(h, dentry, ctx);
1460         if (ret)
1461                 goto out_close;
1462
1463         ret = create_empty_named_data_streams(dentry, ctx);
1464         if (ret)
1465                 goto out_close;
1466
1467         *h_ret = h;
1468         return 0;
1469
1470 out_close:
1471         (*func_NtClose)(h);
1472 out:
1473         return ret;
1474 }
1475
1476 /* Creates a hard link at the location named by @dentry to the file represented
1477  * by the open handle @h.  Or, if the target volume does not support hard links,
1478  * create a separate file instead.  */
1479 static int
1480 create_link(HANDLE h, const struct wim_dentry *dentry,
1481             struct win32_apply_ctx *ctx)
1482 {
1483         if (ctx->common.supported_features.hard_links) {
1484
1485                 build_extraction_path(dentry, ctx);
1486
1487                 size_t bufsize = offsetof(FILE_LINK_INFORMATION, FileName) +
1488                                  ctx->pathbuf.Length + sizeof(wchar_t);
1489                 u8 buf[bufsize] _aligned_attribute(8);
1490                 FILE_LINK_INFORMATION *info = (FILE_LINK_INFORMATION *)buf;
1491                 NTSTATUS status;
1492
1493                 info->ReplaceIfExists = TRUE;
1494                 info->RootDirectory = ctx->attr.RootDirectory;
1495                 info->FileNameLength = ctx->pathbuf.Length;
1496                 memcpy(info->FileName, ctx->pathbuf.Buffer, ctx->pathbuf.Length);
1497                 info->FileName[info->FileNameLength / 2] = L'\0';
1498
1499                 /* Note: the null terminator isn't actually necessary,
1500                  * but if you don't add the extra character, you get
1501                  * STATUS_INFO_LENGTH_MISMATCH when FileNameLength
1502                  * happens to be 2  */
1503
1504                 status = (*func_NtSetInformationFile)(h, &ctx->iosb,
1505                                                       info, bufsize,
1506                                                       FileLinkInformation);
1507                 if (NT_SUCCESS(status))
1508                         return 0;
1509                 winnt_error(status, L"Failed to create link \"%ls\"",
1510                             current_path(ctx));
1511                 return WIMLIB_ERR_LINK;
1512         } else {
1513                 HANDLE h2;
1514                 int ret;
1515
1516                 ret = create_nondirectory_inode(&h2, dentry, ctx);
1517                 if (ret)
1518                         return ret;
1519
1520                 (*func_NtClose)(h2);
1521                 return 0;
1522         }
1523 }
1524
1525 /* Given an inode (represented by the open handle @h) for which one link has
1526  * been created (named by @first_dentry), create the other links.
1527  *
1528  * Or, if the target volume does not support hard links, create separate files.
1529  *
1530  * Note: This uses ctx->pathbuf and does not reset it.
1531  */
1532 static int
1533 create_links(HANDLE h, const struct wim_dentry *first_dentry,
1534              struct win32_apply_ctx *ctx)
1535 {
1536         const struct wim_inode *inode;
1537         const struct list_head *next;
1538         const struct wim_dentry *dentry;
1539         int ret;
1540
1541         inode = first_dentry->d_inode;
1542         next = inode->i_extraction_aliases.next;
1543         do {
1544                 dentry = list_entry(next, struct wim_dentry,
1545                                     d_extraction_alias_node);
1546                 if (dentry != first_dentry) {
1547                         ret = create_link(h, dentry, ctx);
1548                         if (ret)
1549                                 return ret;
1550                 }
1551                 next = next->next;
1552         } while (next != &inode->i_extraction_aliases);
1553         return 0;
1554 }
1555
1556 /* Create a nondirectory file, including all links.  */
1557 static int
1558 create_nondirectory(struct wim_inode *inode, struct win32_apply_ctx *ctx)
1559 {
1560         struct wim_dentry *first_dentry;
1561         HANDLE h;
1562         int ret;
1563
1564         first_dentry = first_extraction_alias(inode);
1565
1566         /* Create first link.  */
1567         ret = create_nondirectory_inode(&h, first_dentry, ctx);
1568         if (ret)
1569                 return ret;
1570
1571         /* Set short name.  */
1572         ret = set_short_name(h, first_dentry, ctx);
1573
1574         /* Create additional links, OR if hard links are not supported just
1575          * create more files.  */
1576         if (!ret)
1577                 ret = create_links(h, first_dentry, ctx);
1578
1579         /* "WIMBoot" extraction: set external backing by the WIM file if needed.  */
1580         if (!ret && unlikely(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT))
1581                 ret = set_external_backing(h, inode, ctx);
1582
1583         (*func_NtClose)(h);
1584         return ret;
1585 }
1586
1587 /* Create all the nondirectory files being extracted, including all aliases
1588  * (hard links).  */
1589 static int
1590 create_nondirectories(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
1591 {
1592         struct wim_dentry *dentry;
1593         struct wim_inode *inode;
1594         int ret;
1595
1596         list_for_each_entry(dentry, dentry_list, d_extraction_list_node) {
1597                 inode = dentry->d_inode;
1598                 if (inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
1599                         continue;
1600                 /* Call create_nondirectory() only once per inode  */
1601                 if (dentry == inode_first_extraction_dentry(inode)) {
1602                         ret = create_nondirectory(inode, ctx);
1603                         ret = check_apply_error(dentry, ctx, ret);
1604                         if (ret)
1605                                 return ret;
1606                 }
1607                 ret = report_file_created(&ctx->common);
1608                 if (ret)
1609                         return ret;
1610         }
1611         return 0;
1612 }
1613
1614 static void
1615 close_handles(struct win32_apply_ctx *ctx)
1616 {
1617         for (unsigned i = 0; i < ctx->num_open_handles; i++)
1618                 (*func_NtClose)(ctx->open_handles[i]);
1619 }
1620
1621 /* Prepare to read the next blob, which has size @blob_size, into an in-memory
1622  * buffer.  */
1623 static bool
1624 prepare_data_buffer(struct win32_apply_ctx *ctx, u64 blob_size)
1625 {
1626         if (blob_size > ctx->data_buffer_size) {
1627                 /* Larger buffer needed.  */
1628                 void *new_buffer;
1629                 if ((size_t)blob_size != blob_size)
1630                         return false;
1631                 new_buffer = REALLOC(ctx->data_buffer, blob_size);
1632                 if (!new_buffer)
1633                         return false;
1634                 ctx->data_buffer = new_buffer;
1635                 ctx->data_buffer_size = blob_size;
1636         }
1637         /* On the first call this changes data_buffer_ptr from NULL, which tells
1638          * extract_chunk() that the data buffer needs to be filled while reading
1639          * the stream data.  */
1640         ctx->data_buffer_ptr = ctx->data_buffer;
1641         return true;
1642 }
1643
1644 static int
1645 begin_extract_blob_instance(const struct blob_descriptor *blob,
1646                             struct wim_dentry *dentry,
1647                             const struct wim_inode_stream *strm,
1648                             struct win32_apply_ctx *ctx)
1649 {
1650         FILE_ALLOCATION_INFORMATION alloc_info;
1651         HANDLE h;
1652         NTSTATUS status;
1653
1654         if (unlikely(strm->stream_type == STREAM_TYPE_REPARSE_POINT)) {
1655                 /* We can't write the reparse point stream directly; we must set
1656                  * it with FSCTL_SET_REPARSE_POINT, which requires that all the
1657                  * data be available.  So, stage the data in a buffer.  */
1658                 if (!prepare_data_buffer(ctx, blob->size))
1659                         return WIMLIB_ERR_NOMEM;
1660                 list_add_tail(&dentry->tmp_list, &ctx->reparse_dentries);
1661                 return 0;
1662         }
1663
1664         if (unlikely(strm->stream_type == STREAM_TYPE_EFSRPC_RAW_DATA)) {
1665                 /* We can't write encrypted files directly; we must use
1666                  * WriteEncryptedFileRaw(), which requires providing the data
1667                  * through a callback function.  This can't easily be combined
1668                  * with our own callback-based approach.
1669                  *
1670                  * The current workaround is to simply read the blob into memory
1671                  * and write the encrypted file from that.
1672                  *
1673                  * TODO: This isn't sufficient for extremely large encrypted
1674                  * files.  Perhaps we should create an extra thread to write
1675                  * such files...  */
1676                 if (!prepare_data_buffer(ctx, blob->size))
1677                         return WIMLIB_ERR_NOMEM;
1678                 list_add_tail(&dentry->tmp_list, &ctx->encrypted_dentries);
1679                 return 0;
1680         }
1681
1682         /* It's a data stream (may be unnamed or named).  */
1683         wimlib_assert(strm->stream_type == STREAM_TYPE_DATA);
1684
1685         if (ctx->num_open_handles == MAX_OPEN_FILES) {
1686                 /* XXX: Fix this.  But because of the checks in
1687                  * extract_blob_list(), this can now only happen on a filesystem
1688                  * that does not support hard links.  */
1689                 ERROR("Can't extract data: too many open files!");
1690                 return WIMLIB_ERR_UNSUPPORTED;
1691         }
1692
1693
1694         if (unlikely(stream_is_named(strm))) {
1695                 build_extraction_path_with_ads(dentry, ctx,
1696                                                strm->stream_name,
1697                                                utf16le_len_chars(strm->stream_name));
1698         } else {
1699                 build_extraction_path(dentry, ctx);
1700         }
1701
1702
1703         /* Open a new handle  */
1704         status = do_create_file(&h,
1705                                 FILE_WRITE_DATA | SYNCHRONIZE,
1706                                 NULL, 0, FILE_OPEN_IF,
1707                                 FILE_SEQUENTIAL_ONLY |
1708                                         FILE_SYNCHRONOUS_IO_NONALERT,
1709                                 ctx);
1710         if (!NT_SUCCESS(status)) {
1711                 winnt_error(status, L"Can't open \"%ls\" for writing",
1712                             current_path(ctx));
1713                 return WIMLIB_ERR_OPEN;
1714         }
1715
1716         ctx->open_handles[ctx->num_open_handles++] = h;
1717
1718         /* Allocate space for the data.  */
1719         alloc_info.AllocationSize.QuadPart = blob->size;
1720         (*func_NtSetInformationFile)(h, &ctx->iosb,
1721                                      &alloc_info, sizeof(alloc_info),
1722                                      FileAllocationInformation);
1723         return 0;
1724 }
1725
1726 /* Set the reparse data @rpbuf of length @rpbuflen on the extracted file
1727  * corresponding to the WIM dentry @dentry.  */
1728 static int
1729 do_set_reparse_data(const struct wim_dentry *dentry,
1730                     const void *rpbuf, u16 rpbuflen,
1731                     struct win32_apply_ctx *ctx)
1732 {
1733         NTSTATUS status;
1734         HANDLE h;
1735
1736         status = create_file(&h, GENERIC_WRITE, NULL,
1737                              0, FILE_OPEN, 0, dentry, ctx);
1738         if (!NT_SUCCESS(status))
1739                 goto fail;
1740
1741         status = (*func_NtFsControlFile)(h, NULL, NULL, NULL,
1742                                          &ctx->iosb, FSCTL_SET_REPARSE_POINT,
1743                                          (void *)rpbuf, rpbuflen,
1744                                          NULL, 0);
1745         (*func_NtClose)(h);
1746
1747         if (NT_SUCCESS(status))
1748                 return 0;
1749
1750         /* On Windows, by default only the Administrator can create symbolic
1751          * links for some reason.  By default we just issue a warning if this
1752          * appears to be the problem.  Use WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS
1753          * to get a hard error.  */
1754         if (!(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_SYMLINKS)
1755             && (status == STATUS_PRIVILEGE_NOT_HELD ||
1756                 status == STATUS_ACCESS_DENIED)
1757             && (dentry->d_inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK ||
1758                 dentry->d_inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT))
1759         {
1760                 WARNING("Can't create symbolic link \"%ls\"!              \n"
1761                         "          (Need Administrator rights, or at least "
1762                         "the\n"
1763                         "          SeCreateSymbolicLink privilege.)",
1764                         current_path(ctx));
1765                 return 0;
1766         }
1767
1768 fail:
1769         winnt_error(status, L"Can't set reparse data on \"%ls\"",
1770                     current_path(ctx));
1771         return WIMLIB_ERR_SET_REPARSE_DATA;
1772 }
1773
1774 /* Given a Windows NT namespace path, such as \??\e:\Windows\System32, return a
1775  * pointer to the suffix of the path that begins with the device directly, such
1776  * as e:\Windows\System32.  */
1777 static const wchar_t *
1778 skip_nt_toplevel_component(const wchar_t *path, size_t path_nchars)
1779 {
1780         static const wchar_t * const dirs[] = {
1781                 L"\\??\\",
1782                 L"\\DosDevices\\",
1783                 L"\\Device\\",
1784         };
1785         size_t first_dir_len = 0;
1786         const wchar_t * const end = path + path_nchars;
1787
1788         for (size_t i = 0; i < ARRAY_LEN(dirs); i++) {
1789                 size_t len = wcslen(dirs[i]);
1790                 if (len <= (end - path) && !wcsnicmp(path, dirs[i], len)) {
1791                         first_dir_len = len;
1792                         break;
1793                 }
1794         }
1795         if (first_dir_len == 0)
1796                 return path;
1797         path += first_dir_len;
1798         while (path != end && *path == L'\\')
1799                 path++;
1800         return path;
1801 }
1802
1803 /* Given a Windows NT namespace path, such as \??\e:\Windows\System32, return a
1804  * pointer to the suffix of the path that is device-relative, such as
1805  * Windows\System32.
1806  *
1807  * The path has an explicit length and is not necessarily null terminated.
1808  *
1809  * If the path just something like \??\e: then the returned pointer will point
1810  * just past the colon.  In this case the length of the result will be 0
1811  * characters.  */
1812 static const wchar_t *
1813 get_device_relative_path(const wchar_t *path, size_t path_nchars)
1814 {
1815         const wchar_t * const orig_path = path;
1816         const wchar_t * const end = path + path_nchars;
1817
1818         path = skip_nt_toplevel_component(path, path_nchars);
1819         if (path == orig_path)
1820                 return orig_path;
1821
1822         path = wmemchr(path, L'\\', (end - path));
1823         if (!path)
1824                 return end;
1825         do {
1826                 path++;
1827         } while (path != end && *path == L'\\');
1828         return path;
1829 }
1830
1831 /*
1832  * Given a reparse point buffer for a symbolic link or junction, adjust its
1833  * contents so that the target of the link is consistent with the new location
1834  * of the files.
1835  */
1836 static void
1837 try_rpfix(u8 *rpbuf, u16 *rpbuflen_p, struct win32_apply_ctx *ctx)
1838 {
1839         struct reparse_data rpdata;
1840         size_t orig_subst_name_nchars;
1841         const wchar_t *relpath;
1842         size_t relpath_nchars;
1843         size_t target_ntpath_nchars;
1844         size_t fixed_subst_name_nchars;
1845         const wchar_t *fixed_print_name;
1846         size_t fixed_print_name_nchars;
1847
1848         if (parse_reparse_data(rpbuf, *rpbuflen_p, &rpdata)) {
1849                 /* Do nothing if the reparse data is invalid.  */
1850                 return;
1851         }
1852
1853         if (rpdata.rptag == WIM_IO_REPARSE_TAG_SYMLINK &&
1854             (rpdata.rpflags & SYMBOLIC_LINK_RELATIVE))
1855         {
1856                 /* Do nothing if it's a relative symbolic link.  */
1857                 return;
1858         }
1859
1860         /* Build the new substitute name from the NT namespace path to the
1861          * target directory, then a path separator, then the "device relative"
1862          * part of the old substitute name.  */
1863
1864         orig_subst_name_nchars = rpdata.substitute_name_nbytes / sizeof(wchar_t);
1865
1866         relpath = get_device_relative_path(rpdata.substitute_name,
1867                                            orig_subst_name_nchars);
1868         relpath_nchars = orig_subst_name_nchars -
1869                          (relpath - rpdata.substitute_name);
1870
1871         target_ntpath_nchars = ctx->target_ntpath.Length / sizeof(wchar_t);
1872
1873         fixed_subst_name_nchars = target_ntpath_nchars;
1874         if (relpath_nchars)
1875                 fixed_subst_name_nchars += 1 + relpath_nchars;
1876         wchar_t fixed_subst_name[fixed_subst_name_nchars];
1877
1878         wmemcpy(fixed_subst_name, ctx->target_ntpath.Buffer,
1879                 target_ntpath_nchars);
1880         if (relpath_nchars) {
1881                 fixed_subst_name[target_ntpath_nchars] = L'\\';
1882                 wmemcpy(&fixed_subst_name[target_ntpath_nchars + 1],
1883                         relpath, relpath_nchars);
1884         }
1885         /* Doesn't need to be null-terminated.  */
1886
1887         /* Print name should be Win32, but not all NT names can even be
1888          * translated to Win32 names.  But we can at least delete the top-level
1889          * directory, such as \??\, and this will have the expected result in
1890          * the usual case.  */
1891         fixed_print_name = skip_nt_toplevel_component(fixed_subst_name,
1892                                                       fixed_subst_name_nchars);
1893         fixed_print_name_nchars = fixed_subst_name_nchars - (fixed_print_name -
1894                                                              fixed_subst_name);
1895
1896         rpdata.substitute_name = fixed_subst_name;
1897         rpdata.substitute_name_nbytes = fixed_subst_name_nchars * sizeof(wchar_t);
1898         rpdata.print_name = (wchar_t *)fixed_print_name;
1899         rpdata.print_name_nbytes = fixed_print_name_nchars * sizeof(wchar_t);
1900         make_reparse_buffer(&rpdata, rpbuf, rpbuflen_p);
1901 }
1902
1903 /* Sets reparse data on the specified file.  This handles "fixing" the targets
1904  * of absolute symbolic links and junctions if WIMLIB_EXTRACT_FLAG_RPFIX was
1905  * specified.  */
1906 static int
1907 set_reparse_data(const struct wim_dentry *dentry,
1908                  const void *_rpbuf, u16 rpbuflen, struct win32_apply_ctx *ctx)
1909 {
1910         const struct wim_inode *inode = dentry->d_inode;
1911         const void *rpbuf = _rpbuf;
1912
1913         if ((ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_RPFIX)
1914             && !inode->i_not_rpfixed
1915             && (inode->i_reparse_tag == WIM_IO_REPARSE_TAG_SYMLINK ||
1916                 inode->i_reparse_tag == WIM_IO_REPARSE_TAG_MOUNT_POINT))
1917         {
1918                 memcpy(&ctx->rpfixbuf, _rpbuf, rpbuflen);
1919                 try_rpfix((u8 *)&ctx->rpfixbuf, &rpbuflen, ctx);
1920                 rpbuf = &ctx->rpfixbuf;
1921         }
1922         return do_set_reparse_data(dentry, rpbuf, rpbuflen, ctx);
1923
1924 }
1925
1926 /* Import the next block of raw encrypted data  */
1927 static DWORD WINAPI
1928 import_encrypted_data(PBYTE pbData, PVOID pvCallbackContext, PULONG Length)
1929 {
1930         struct win32_apply_ctx *ctx = pvCallbackContext;
1931         ULONG copy_len;
1932
1933         copy_len = min(ctx->encrypted_size - ctx->encrypted_offset, *Length);
1934         memcpy(pbData, &ctx->data_buffer[ctx->encrypted_offset], copy_len);
1935         ctx->encrypted_offset += copy_len;
1936         *Length = copy_len;
1937         return ERROR_SUCCESS;
1938 }
1939
1940 /*
1941  * Write the raw encrypted data to the already-created file (or directory)
1942  * corresponding to @dentry.
1943  *
1944  * The raw encrypted data is provided in ctx->data_buffer, and its size is
1945  * ctx->encrypted_size.
1946  *
1947  * This function may close the target directory, in which case the caller needs
1948  * to re-open it if needed.
1949  */
1950 static int
1951 extract_encrypted_file(const struct wim_dentry *dentry,
1952                        struct win32_apply_ctx *ctx)
1953 {
1954         void *rawctx;
1955         DWORD err;
1956         ULONG flags;
1957         bool retried;
1958
1959         /* Temporarily build a Win32 path for OpenEncryptedFileRaw()  */
1960         build_win32_extraction_path(dentry, ctx);
1961
1962         flags = CREATE_FOR_IMPORT | OVERWRITE_HIDDEN;
1963         if (dentry->d_inode->i_attributes & FILE_ATTRIBUTE_DIRECTORY)
1964                 flags |= CREATE_FOR_DIR;
1965
1966         retried = false;
1967 retry:
1968         err = OpenEncryptedFileRaw(ctx->pathbuf.Buffer, flags, &rawctx);
1969         if (err == ERROR_SHARING_VIOLATION && !retried) {
1970                 /* This can be caused by the handle we have open to the target
1971                  * directory.  Try closing it temporarily.  */
1972                 close_target_directory(ctx);
1973                 retried = true;
1974                 goto retry;
1975         }
1976
1977         /* Restore the NT namespace path  */
1978         build_extraction_path(dentry, ctx);
1979
1980         if (err != ERROR_SUCCESS) {
1981                 win32_error(err, L"Can't open \"%ls\" for encrypted import",
1982                             current_path(ctx));
1983                 return WIMLIB_ERR_OPEN;
1984         }
1985
1986         ctx->encrypted_offset = 0;
1987
1988         err = WriteEncryptedFileRaw(import_encrypted_data, ctx, rawctx);
1989
1990         CloseEncryptedFileRaw(rawctx);
1991
1992         if (err != ERROR_SUCCESS) {
1993                 win32_error(err, L"Can't import encrypted file \"%ls\"",
1994                             current_path(ctx));
1995                 return WIMLIB_ERR_WRITE;
1996         }
1997
1998         return 0;
1999 }
2000
2001 /* Called when starting to read a blob for extraction on Windows  */
2002 static int
2003 begin_extract_blob(struct blob_descriptor *blob, void *_ctx)
2004 {
2005         struct win32_apply_ctx *ctx = _ctx;
2006         const struct blob_extraction_target *targets = blob_extraction_targets(blob);
2007         int ret;
2008
2009         ctx->num_open_handles = 0;
2010         ctx->data_buffer_ptr = NULL;
2011         INIT_LIST_HEAD(&ctx->reparse_dentries);
2012         INIT_LIST_HEAD(&ctx->encrypted_dentries);
2013
2014         for (u32 i = 0; i < blob->out_refcnt; i++) {
2015                 const struct wim_inode *inode = targets[i].inode;
2016                 const struct wim_inode_stream *strm = targets[i].stream;
2017                 struct wim_dentry *dentry;
2018
2019                 /* A copy of the blob needs to be extracted to @inode.  */
2020
2021                 if (ctx->common.supported_features.hard_links) {
2022                         dentry = inode_first_extraction_dentry(inode);
2023                         ret = begin_extract_blob_instance(blob, dentry, strm, ctx);
2024                         ret = check_apply_error(dentry, ctx, ret);
2025                         if (ret)
2026                                 goto fail;
2027                 } else {
2028                         /* Hard links not supported.  Extract the blob
2029                          * separately to each alias of the inode.  */
2030                         struct list_head *next;
2031
2032                         next = inode->i_extraction_aliases.next;
2033                         do {
2034                                 dentry = list_entry(next, struct wim_dentry,
2035                                                     d_extraction_alias_node);
2036                                 ret = begin_extract_blob_instance(blob, dentry, strm, ctx);
2037                                 ret = check_apply_error(dentry, ctx, ret);
2038                                 if (ret)
2039                                         goto fail;
2040                                 next = next->next;
2041                         } while (next != &inode->i_extraction_aliases);
2042                 }
2043         }
2044
2045         return 0;
2046
2047 fail:
2048         close_handles(ctx);
2049         return ret;
2050 }
2051
2052 /* Called when the next chunk of a blob has been read for extraction on Windows
2053  */
2054 static int
2055 extract_chunk(const void *chunk, size_t size, void *_ctx)
2056 {
2057         struct win32_apply_ctx *ctx = _ctx;
2058
2059         /* Write the data chunk to each open handle  */
2060         for (unsigned i = 0; i < ctx->num_open_handles; i++) {
2061                 u8 *bufptr = (u8 *)chunk;
2062                 size_t bytes_remaining = size;
2063                 NTSTATUS status;
2064                 while (bytes_remaining) {
2065                         ULONG count = min(0xFFFFFFFF, bytes_remaining);
2066
2067                         status = (*func_NtWriteFile)(ctx->open_handles[i],
2068                                                      NULL, NULL, NULL,
2069                                                      &ctx->iosb, bufptr, count,
2070                                                      NULL, NULL);
2071                         if (!NT_SUCCESS(status)) {
2072                                 winnt_error(status, L"Error writing data to target volume");
2073                                 return WIMLIB_ERR_WRITE;
2074                         }
2075                         bufptr += ctx->iosb.Information;
2076                         bytes_remaining -= ctx->iosb.Information;
2077                 }
2078         }
2079
2080         /* Copy the data chunk into the buffer (if needed)  */
2081         if (ctx->data_buffer_ptr)
2082                 ctx->data_buffer_ptr = mempcpy(ctx->data_buffer_ptr,
2083                                                chunk, size);
2084         return 0;
2085 }
2086
2087 /* Called when a blob has been fully read for extraction on Windows  */
2088 static int
2089 end_extract_blob(struct blob_descriptor *blob, int status, void *_ctx)
2090 {
2091         struct win32_apply_ctx *ctx = _ctx;
2092         int ret;
2093         const struct wim_dentry *dentry;
2094
2095         close_handles(ctx);
2096
2097         if (status)
2098                 return status;
2099
2100         if (likely(!ctx->data_buffer_ptr))
2101                 return 0;
2102
2103         if (!list_empty(&ctx->reparse_dentries)) {
2104                 if (blob->size > REPARSE_DATA_MAX_SIZE) {
2105                         dentry = list_first_entry(&ctx->reparse_dentries,
2106                                                   struct wim_dentry, tmp_list);
2107                         build_extraction_path(dentry, ctx);
2108                         ERROR("Reparse data of \"%ls\" has size "
2109                               "%"PRIu64" bytes (exceeds %u bytes)",
2110                               current_path(ctx), blob->size,
2111                               REPARSE_DATA_MAX_SIZE);
2112                         ret = WIMLIB_ERR_INVALID_REPARSE_DATA;
2113                         return check_apply_error(dentry, ctx, ret);
2114                 }
2115                 /* In the WIM format, reparse point streams are just the reparse
2116                  * data and omit the header.  But we can reconstruct the header.
2117                  */
2118                 memcpy(ctx->rpbuf.rpdata, ctx->data_buffer, blob->size);
2119                 ctx->rpbuf.rpdatalen = blob->size;
2120                 ctx->rpbuf.rpreserved = 0;
2121                 list_for_each_entry(dentry, &ctx->reparse_dentries, tmp_list) {
2122                         ctx->rpbuf.rptag = dentry->d_inode->i_reparse_tag;
2123                         ret = set_reparse_data(dentry, &ctx->rpbuf,
2124                                                blob->size + REPARSE_DATA_OFFSET,
2125                                                ctx);
2126                         ret = check_apply_error(dentry, ctx, ret);
2127                         if (ret)
2128                                 return ret;
2129                 }
2130         }
2131
2132         if (!list_empty(&ctx->encrypted_dentries)) {
2133                 ctx->encrypted_size = blob->size;
2134                 list_for_each_entry(dentry, &ctx->encrypted_dentries, tmp_list) {
2135                         ret = extract_encrypted_file(dentry, ctx);
2136                         ret = check_apply_error(dentry, ctx, ret);
2137                         if (ret)
2138                                 return ret;
2139                         /* Re-open the target directory if needed.  */
2140                         ret = open_target_directory(ctx);
2141                         if (ret)
2142                                 return ret;
2143                 }
2144         }
2145
2146         return 0;
2147 }
2148
2149 /* Attributes that can't be set directly  */
2150 #define SPECIAL_ATTRIBUTES                      \
2151         (FILE_ATTRIBUTE_REPARSE_POINT   |       \
2152          FILE_ATTRIBUTE_DIRECTORY       |       \
2153          FILE_ATTRIBUTE_ENCRYPTED       |       \
2154          FILE_ATTRIBUTE_SPARSE_FILE     |       \
2155          FILE_ATTRIBUTE_COMPRESSED)
2156
2157 /* Set the security descriptor @desc, of @desc_size bytes, on the file with open
2158  * handle @h.  */
2159 static NTSTATUS
2160 set_security_descriptor(HANDLE h, const void *_desc,
2161                         size_t desc_size, struct win32_apply_ctx *ctx)
2162 {
2163         SECURITY_INFORMATION info;
2164         NTSTATUS status;
2165         SECURITY_DESCRIPTOR_RELATIVE *desc;
2166
2167         /*
2168          * Ideally, we would just pass in the security descriptor buffer as-is.
2169          * But it turns out that Windows can mess up the security descriptor
2170          * even when using the low-level NtSetSecurityObject() function:
2171          *
2172          * - Windows will clear SE_DACL_AUTO_INHERITED if it is set in the
2173          *   passed buffer.  To actually get Windows to set
2174          *   SE_DACL_AUTO_INHERITED, the application must set the non-persistent
2175          *   flag SE_DACL_AUTO_INHERIT_REQ.  As usual, Microsoft didn't bother
2176          *   to properly document either of these flags.  It's unclear how
2177          *   important SE_DACL_AUTO_INHERITED actually is, but to be safe we use
2178          *   the SE_DACL_AUTO_INHERIT_REQ workaround to set it if needed.
2179          *
2180          * - The above also applies to the equivalent SACL flags,
2181          *   SE_SACL_AUTO_INHERITED and SE_SACL_AUTO_INHERIT_REQ.
2182          *
2183          * - If the application says that it's setting
2184          *   DACL_SECURITY_INFORMATION, then Windows sets SE_DACL_PRESENT in the
2185          *   resulting security descriptor, even if the security descriptor the
2186          *   application provided did not have a DACL.  This seems to be
2187          *   unavoidable, since omitting DACL_SECURITY_INFORMATION would cause a
2188          *   default DACL to remain.  Fortunately, this behavior seems harmless,
2189          *   since the resulting DACL will still be "null" --- but it will be
2190          *   "the other representation of null".
2191          *
2192          * - The above also applies to SACL_SECURITY_INFORMATION and
2193          *   SE_SACL_PRESENT.  Again, it's seemingly unavoidable but "harmless"
2194          *   that Windows changes the representation of a "null SACL".
2195          */
2196         if (likely(desc_size <= STACK_MAX)) {
2197                 desc = alloca(desc_size);
2198         } else {
2199                 desc = MALLOC(desc_size);
2200                 if (!desc)
2201                         return STATUS_NO_MEMORY;
2202         }
2203
2204         memcpy(desc, _desc, desc_size);
2205
2206         if (likely(desc_size >= 4)) {
2207
2208                 if (desc->Control & SE_DACL_AUTO_INHERITED)
2209                         desc->Control |= SE_DACL_AUTO_INHERIT_REQ;
2210
2211                 if (desc->Control & SE_SACL_AUTO_INHERITED)
2212                         desc->Control |= SE_SACL_AUTO_INHERIT_REQ;
2213         }
2214
2215         /*
2216          * More API insanity.  We want to set the entire security descriptor
2217          * as-is.  But all available APIs require specifying the specific parts
2218          * of the security descriptor being set.  Especially annoying is that
2219          * mandatory integrity labels are part of the SACL, but they aren't set
2220          * with SACL_SECURITY_INFORMATION.  Instead, applications must also
2221          * specify LABEL_SECURITY_INFORMATION (Windows Vista, Windows 7) or
2222          * BACKUP_SECURITY_INFORMATION (Windows 8).  But at least older versions
2223          * of Windows don't error out if you provide these newer flags...
2224          *
2225          * Also, if the process isn't running as Administrator, then it probably
2226          * doesn't have SE_RESTORE_PRIVILEGE.  In this case, it will always get
2227          * the STATUS_PRIVILEGE_NOT_HELD error by trying to set the SACL, even
2228          * if the security descriptor it provided did not have a SACL.  By
2229          * default, in this case we try to recover and set as much of the
2230          * security descriptor as possible --- potentially excluding the DACL, and
2231          * even the owner, as well as the SACL.
2232          */
2233
2234         info = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION |
2235                DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION |
2236                LABEL_SECURITY_INFORMATION | BACKUP_SECURITY_INFORMATION;
2237
2238
2239         /*
2240          * It's also worth noting that SetFileSecurity() is unusable because it
2241          * doesn't request "backup semantics" when it opens the file internally.
2242          * NtSetSecurityObject() seems to be the best function to use in backup
2243          * applications.  (SetSecurityInfo() should also work, but it's harder
2244          * to use and must call NtSetSecurityObject() internally anyway.
2245          * BackupWrite() is theoretically usable as well, but it's inflexible
2246          * and poorly documented.)
2247          */
2248
2249 retry:
2250         status = (*func_NtSetSecurityObject)(h, info, desc);
2251         if (NT_SUCCESS(status))
2252                 goto out_maybe_free_desc;
2253
2254         /* Failed to set the requested parts of the security descriptor.  If the
2255          * error was permissions-related, try to set fewer parts of the security
2256          * descriptor, unless WIMLIB_EXTRACT_FLAG_STRICT_ACLS is enabled.  */
2257         if ((status == STATUS_PRIVILEGE_NOT_HELD ||
2258              status == STATUS_ACCESS_DENIED) &&
2259             !(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
2260         {
2261                 if (info & SACL_SECURITY_INFORMATION) {
2262                         info &= ~(SACL_SECURITY_INFORMATION |
2263                                   LABEL_SECURITY_INFORMATION |
2264                                   BACKUP_SECURITY_INFORMATION);
2265                         ctx->partial_security_descriptors++;
2266                         goto retry;
2267                 }
2268                 if (info & DACL_SECURITY_INFORMATION) {
2269                         info &= ~DACL_SECURITY_INFORMATION;
2270                         goto retry;
2271                 }
2272                 if (info & OWNER_SECURITY_INFORMATION) {
2273                         info &= ~OWNER_SECURITY_INFORMATION;
2274                         goto retry;
2275                 }
2276                 /* Nothing left except GROUP, and if we removed it we
2277                  * wouldn't have anything at all.  */
2278         }
2279
2280         /* No part of the security descriptor could be set, or
2281          * WIMLIB_EXTRACT_FLAG_STRICT_ACLS is enabled and the full security
2282          * descriptor could not be set.  */
2283         if (!(info & SACL_SECURITY_INFORMATION))
2284                 ctx->partial_security_descriptors--;
2285         ctx->no_security_descriptors++;
2286
2287 out_maybe_free_desc:
2288         if (unlikely(desc_size > STACK_MAX))
2289                 FREE(desc);
2290         return status;
2291 }
2292
2293 /* Set metadata on the open file @h from the WIM inode @inode.  */
2294 static int
2295 do_apply_metadata_to_file(HANDLE h, const struct wim_inode *inode,
2296                           struct win32_apply_ctx *ctx)
2297 {
2298         FILE_BASIC_INFORMATION info;
2299         NTSTATUS status;
2300
2301         /* Set security descriptor if present and not in NO_ACLS mode  */
2302         if (inode->i_security_id >= 0 &&
2303             !(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ACLS))
2304         {
2305                 const struct wim_security_data *sd;
2306                 const void *desc;
2307                 size_t desc_size;
2308
2309                 sd = wim_get_current_security_data(ctx->common.wim);
2310                 desc = sd->descriptors[inode->i_security_id];
2311                 desc_size = sd->sizes[inode->i_security_id];
2312
2313                 status = set_security_descriptor(h, desc, desc_size, ctx);
2314                 if (!NT_SUCCESS(status) &&
2315                     (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_STRICT_ACLS))
2316                 {
2317                         winnt_error(status,
2318                                     L"Can't set security descriptor on \"%ls\"",
2319                                     current_path(ctx));
2320                         return WIMLIB_ERR_SET_SECURITY;
2321                 }
2322         }
2323
2324         /* Set attributes and timestamps  */
2325         info.CreationTime.QuadPart = inode->i_creation_time;
2326         info.LastAccessTime.QuadPart = inode->i_last_access_time;
2327         info.LastWriteTime.QuadPart = inode->i_last_write_time;
2328         info.ChangeTime.QuadPart = 0;
2329         if (ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_NO_ATTRIBUTES) {
2330                 info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
2331         } else {
2332                 info.FileAttributes = inode->i_attributes & ~SPECIAL_ATTRIBUTES;
2333                 if (info.FileAttributes == 0)
2334                         info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
2335         }
2336
2337         status = (*func_NtSetInformationFile)(h, &ctx->iosb,
2338                                               &info, sizeof(info),
2339                                               FileBasicInformation);
2340         /* On FAT volumes we get STATUS_INVALID_PARAMETER if we try to set
2341          * attributes on the root directory.  (Apparently because FAT doesn't
2342          * actually have a place to store those attributes!)  */
2343         if (!NT_SUCCESS(status)
2344             && !(status == STATUS_INVALID_PARAMETER &&
2345                  dentry_is_root(inode_first_extraction_dentry(inode))))
2346         {
2347                 winnt_error(status, L"Can't set basic metadata on \"%ls\"",
2348                             current_path(ctx));
2349                 return WIMLIB_ERR_SET_ATTRIBUTES;
2350         }
2351
2352         return 0;
2353 }
2354
2355 static int
2356 apply_metadata_to_file(const struct wim_dentry *dentry,
2357                        struct win32_apply_ctx *ctx)
2358 {
2359         const struct wim_inode *inode = dentry->d_inode;
2360         DWORD perms;
2361         HANDLE h;
2362         NTSTATUS status;
2363         int ret;
2364
2365         perms = FILE_WRITE_ATTRIBUTES | WRITE_DAC |
2366                 WRITE_OWNER | ACCESS_SYSTEM_SECURITY;
2367
2368         build_extraction_path(dentry, ctx);
2369
2370         /* Open a handle with as many relevant permissions as possible.  */
2371         while (!NT_SUCCESS(status = do_create_file(&h, perms, NULL,
2372                                                    0, FILE_OPEN, 0, ctx)))
2373         {
2374                 if (status == STATUS_PRIVILEGE_NOT_HELD ||
2375                     status == STATUS_ACCESS_DENIED)
2376                 {
2377                         if (perms & ACCESS_SYSTEM_SECURITY) {
2378                                 perms &= ~ACCESS_SYSTEM_SECURITY;
2379                                 continue;
2380                         }
2381                         if (perms & WRITE_DAC) {
2382                                 perms &= ~WRITE_DAC;
2383                                 continue;
2384                         }
2385                         if (perms & WRITE_OWNER) {
2386                                 perms &= ~WRITE_OWNER;
2387                                 continue;
2388                         }
2389                 }
2390                 winnt_error(status, L"Can't open \"%ls\" to set metadata",
2391                             current_path(ctx));
2392                 return WIMLIB_ERR_OPEN;
2393         }
2394
2395         ret = do_apply_metadata_to_file(h, inode, ctx);
2396
2397         (*func_NtClose)(h);
2398
2399         return ret;
2400 }
2401
2402 static int
2403 apply_metadata(struct list_head *dentry_list, struct win32_apply_ctx *ctx)
2404 {
2405         const struct wim_dentry *dentry;
2406         int ret;
2407
2408         /* We go in reverse so that metadata is set on all a directory's
2409          * children before the directory itself.  This avoids any potential
2410          * problems with attributes, timestamps, or security descriptors.  */
2411         list_for_each_entry_reverse(dentry, dentry_list, d_extraction_list_node)
2412         {
2413                 ret = apply_metadata_to_file(dentry, ctx);
2414                 ret = check_apply_error(dentry, ctx, ret);
2415                 if (ret)
2416                         return ret;
2417                 ret = report_file_metadata_applied(&ctx->common);
2418                 if (ret)
2419                         return ret;
2420         }
2421         return 0;
2422 }
2423
2424 /* Issue warnings about problems during the extraction for which warnings were
2425  * not already issued (due to the high number of potential warnings if we issued
2426  * them per-file).  */
2427 static void
2428 do_warnings(const struct win32_apply_ctx *ctx)
2429 {
2430         if (ctx->partial_security_descriptors == 0
2431             && ctx->no_security_descriptors == 0
2432             && ctx->num_set_short_name_failures == 0
2433         #if 0
2434             && ctx->num_remove_short_name_failures == 0
2435         #endif
2436             )
2437                 return;
2438
2439         WARNING("Extraction to \"%ls\" complete, but with one or more warnings:",
2440                 ctx->common.target);
2441         if (ctx->num_set_short_name_failures) {
2442                 WARNING("- Could not set short names on %lu files or directories",
2443                         ctx->num_set_short_name_failures);
2444         }
2445 #if 0
2446         if (ctx->num_remove_short_name_failures) {
2447                 WARNING("- Could not remove short names on %lu files or directories"
2448                         "          (This is expected on Vista and earlier)",
2449                         ctx->num_remove_short_name_failures);
2450         }
2451 #endif
2452         if (ctx->partial_security_descriptors) {
2453                 WARNING("- Could only partially set the security descriptor\n"
2454                         "            on %lu files or directories.",
2455                         ctx->partial_security_descriptors);
2456         }
2457         if (ctx->no_security_descriptors) {
2458                 WARNING("- Could not set security descriptor at all\n"
2459                         "            on %lu files or directories.",
2460                         ctx->no_security_descriptors);
2461         }
2462         if (ctx->partial_security_descriptors || ctx->no_security_descriptors) {
2463                 WARNING("To fully restore all security descriptors, run the program\n"
2464                         "          with Administrator rights.");
2465         }
2466 }
2467
2468 static uint64_t
2469 count_dentries(const struct list_head *dentry_list)
2470 {
2471         const struct list_head *cur;
2472         uint64_t count = 0;
2473
2474         list_for_each(cur, dentry_list)
2475                 count++;
2476
2477         return count;
2478 }
2479
2480 /* Extract files from a WIM image to a directory on Windows  */
2481 static int
2482 win32_extract(struct list_head *dentry_list, struct apply_ctx *_ctx)
2483 {
2484         int ret;
2485         struct win32_apply_ctx *ctx = (struct win32_apply_ctx *)_ctx;
2486         uint64_t dentry_count;
2487
2488         ret = prepare_target(dentry_list, ctx);
2489         if (ret)
2490                 goto out;
2491
2492         if (unlikely(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT)) {
2493                 ret = start_wimboot_extraction(ctx);
2494                 if (ret)
2495                         goto out;
2496         }
2497
2498         dentry_count = count_dentries(dentry_list);
2499
2500         ret = start_file_structure_phase(&ctx->common, dentry_count);
2501         if (ret)
2502                 goto out;
2503
2504         ret = create_directories(dentry_list, ctx);
2505         if (ret)
2506                 goto out;
2507
2508         ret = create_nondirectories(dentry_list, ctx);
2509         if (ret)
2510                 goto out;
2511
2512         ret = end_file_structure_phase(&ctx->common);
2513         if (ret)
2514                 goto out;
2515
2516         struct read_blob_list_callbacks cbs = {
2517                 .begin_blob        = begin_extract_blob,
2518                 .begin_blob_ctx    = ctx,
2519                 .consume_chunk     = extract_chunk,
2520                 .consume_chunk_ctx = ctx,
2521                 .end_blob          = end_extract_blob,
2522                 .end_blob_ctx      = ctx,
2523         };
2524         ret = extract_blob_list(&ctx->common, &cbs);
2525         if (ret)
2526                 goto out;
2527
2528         ret = start_file_metadata_phase(&ctx->common, dentry_count);
2529         if (ret)
2530                 goto out;
2531
2532         ret = apply_metadata(dentry_list, ctx);
2533         if (ret)
2534                 goto out;
2535
2536         ret = end_file_metadata_phase(&ctx->common);
2537         if (ret)
2538                 goto out;
2539
2540         if (unlikely(ctx->common.extract_flags & WIMLIB_EXTRACT_FLAG_WIMBOOT)) {
2541                 ret = end_wimboot_extraction(ctx);
2542                 if (ret)
2543                         goto out;
2544         }
2545
2546         do_warnings(ctx);
2547 out:
2548         close_target_directory(ctx);
2549         if (ctx->target_ntpath.Buffer)
2550                 HeapFree(GetProcessHeap(), 0, ctx->target_ntpath.Buffer);
2551         FREE(ctx->pathbuf.Buffer);
2552         FREE(ctx->print_buffer);
2553         if (ctx->wimboot.prepopulate_pats) {
2554                 FREE(ctx->wimboot.prepopulate_pats->strings);
2555                 FREE(ctx->wimboot.prepopulate_pats);
2556         }
2557         FREE(ctx->wimboot.mem_prepopulate_pats);
2558         FREE(ctx->data_buffer);
2559         return ret;
2560 }
2561
2562 const struct apply_operations win32_apply_ops = {
2563         .name                   = "Windows",
2564         .get_supported_features = win32_get_supported_features,
2565         .extract                = win32_extract,
2566         .will_externally_back   = win32_will_externally_back,
2567         .context_size           = sizeof(struct win32_apply_ctx),
2568 };
2569
2570 #endif /* __WIN32__ */