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