]> wimlib.net Git - wimlib/blob - src/ntfs-3g_apply.c
read_wim_lookup_table(): Allow multiple "subpacks" per packed run
[wimlib] / src / ntfs-3g_apply.c
1 /*
2  * ntfs-3g_apply.c
3  *
4  * Apply a WIM image directly to a NTFS volume using libntfs-3g.  Restore as
5  * much information as possible, including security data, file attributes, DOS
6  * names, and alternate data streams.
7  */
8
9 /*
10  * Copyright (C) 2012, 2013 Eric Biggers
11  *
12  * This file is part of wimlib, a library for working with WIM files.
13  *
14  * wimlib is free software; you can redistribute it and/or modify it under the
15  * terms of the GNU General Public License as published by the Free
16  * Software Foundation; either version 3 of the License, or (at your option)
17  * any later version.
18  *
19  * wimlib is distributed in the hope that it will be useful, but WITHOUT ANY
20  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
21  * A PARTICULAR PURPOSE. See the GNU General Public License for more
22  * details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with wimlib; if not, see http://www.gnu.org/licenses/.
26  */
27
28 #ifdef HAVE_CONFIG_H
29 #  include "config.h"
30 #endif
31
32 #ifdef WITH_NTFS_3G
33
34 #include <errno.h>
35 #include <locale.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #ifdef HAVE_ALLOCA_H
39 #  include <alloca.h>
40 #endif
41
42 #include <ntfs-3g/attrib.h>
43 #include <ntfs-3g/reparse.h>
44 #include <ntfs-3g/security.h>
45
46 #include "wimlib/apply.h"
47 #include "wimlib/encoding.h"
48 #include "wimlib/error.h"
49 #include "wimlib/lookup_table.h"
50 #include "wimlib/ntfs_3g.h"
51 #include "wimlib/paths.h"
52 #include "wimlib/resource.h"
53 #include "wimlib/security_descriptor.h"
54
55 static ntfs_volume *
56 ntfs_3g_apply_ctx_get_volume(struct apply_ctx *ctx)
57 {
58         return (ntfs_volume*)ctx->private[0];
59 }
60
61 static void
62 ntfs_3g_apply_ctx_set_volume(struct apply_ctx *ctx, ntfs_volume *vol)
63 {
64         ctx->private[0] = (intptr_t)vol;
65 }
66
67 static ntfs_inode *
68 ntfs_3g_apply_pathname_to_inode(const char *path, struct apply_ctx *ctx)
69 {
70         ntfs_volume *vol = ntfs_3g_apply_ctx_get_volume(ctx);
71         return ntfs_pathname_to_inode(vol, NULL, path);
72 }
73
74 struct ntfs_attr_extract_ctx {
75         u64 offset;
76         ntfs_attr *na;
77 };
78
79 static int
80 ntfs_3g_extract_wim_chunk(const void *buf, size_t len, void *_ctx)
81 {
82         struct ntfs_attr_extract_ctx *ctx = _ctx;
83
84         if (ntfs_attr_pwrite(ctx->na, ctx->offset, len, buf) != len)
85                 return WIMLIB_ERR_WRITE;
86         ctx->offset += len;
87         return 0;
88 }
89
90 static ntfs_inode *
91 ntfs_3g_open_parent_inode(const char *path, ntfs_volume *vol)
92 {
93         char *p;
94         ntfs_inode *dir_ni;
95
96         p = strrchr(path, '/');
97         *p = '\0';
98         dir_ni = ntfs_pathname_to_inode(vol, NULL, path);
99         *p = '/';
100         return dir_ni;
101 }
102
103 static int
104 ntfs_3g_create(const char *path, struct apply_ctx *ctx, u64 *cookie_ret,
105                mode_t mode)
106 {
107         ntfs_volume *vol;
108         ntfs_inode *dir_ni, *ni;
109         const char *name;
110         utf16lechar *name_utf16le;
111         size_t name_utf16le_nbytes;
112         int ret;
113
114         vol = ntfs_3g_apply_ctx_get_volume(ctx);
115
116         ret = WIMLIB_ERR_OPEN;
117         dir_ni = ntfs_3g_open_parent_inode(path, vol);
118         if (!dir_ni)
119                 goto out;
120
121         name = path_basename(path);
122         ret = tstr_to_utf16le(name, strlen(name),
123                               &name_utf16le, &name_utf16le_nbytes);
124         if (ret)
125                 goto out_close_dir_ni;
126
127         ret = WIMLIB_ERR_OPEN;
128         ni = ntfs_create(dir_ni, 0, name_utf16le,
129                          name_utf16le_nbytes / 2, mode);
130         if (!ni)
131                 goto out_free_name_utf16le;
132         *cookie_ret = MK_MREF(ni->mft_no, le16_to_cpu(ni->mrec->sequence_number));
133         if (ntfs_inode_close_in_dir(ni, dir_ni))
134                 goto out_free_name_utf16le;
135         ret = 0;
136 out_free_name_utf16le:
137         FREE(name_utf16le);
138 out_close_dir_ni:
139         if (ntfs_inode_close(dir_ni))
140                 ret = WIMLIB_ERR_WRITE;
141 out:
142         return ret;
143 }
144
145 static int
146 ntfs_3g_create_file(const char *path, struct apply_ctx *ctx,
147                     u64 *cookie_ret)
148 {
149         return ntfs_3g_create(path, ctx, cookie_ret, S_IFREG);
150 }
151
152 static int
153 ntfs_3g_create_directory(const char *path, struct apply_ctx *ctx,
154                          u64 *cookie_ret)
155 {
156         return ntfs_3g_create(path, ctx, cookie_ret, S_IFDIR);
157 }
158
159 static int
160 ntfs_3g_create_hardlink(const char *oldpath, const char *newpath,
161                         struct apply_ctx *ctx)
162 {
163         ntfs_volume *vol;
164         ntfs_inode *dir_ni, *ni;
165         const char *name;
166         utf16lechar *name_utf16le;
167         size_t name_utf16le_nbytes;
168         int ret;
169
170         vol = ntfs_3g_apply_ctx_get_volume(ctx);
171
172         ret = WIMLIB_ERR_OPEN;
173         ni = ntfs_pathname_to_inode(vol, NULL, oldpath);
174         if (!ni)
175                 goto out;
176
177         ret = WIMLIB_ERR_OPEN;
178         dir_ni = ntfs_3g_open_parent_inode(newpath, vol);
179         if (!dir_ni)
180                 goto out_close_ni;
181
182         name = path_basename(newpath);
183         ret = tstr_to_utf16le(name, strlen(name),
184                               &name_utf16le, &name_utf16le_nbytes);
185         if (ret)
186                 goto out_close_dir_ni;
187         ret = 0;
188         if (ntfs_link(ni, dir_ni, name_utf16le, name_utf16le_nbytes / 2))
189                 ret = WIMLIB_ERR_LINK;
190         FREE(name_utf16le);
191 out_close_dir_ni:
192         if (ntfs_inode_close(dir_ni))
193                 ret = WIMLIB_ERR_WRITE;
194 out_close_ni:
195         if (ntfs_inode_close(ni))
196                 ret = WIMLIB_ERR_WRITE;
197 out:
198         return ret;
199 }
200
201 /*
202  * Extract a stream (default or alternate data) to an attribute of a NTFS file.
203  */
204 static int
205 ntfs_3g_extract_stream(file_spec_t file, const utf16lechar *raw_stream_name,
206                        size_t stream_name_nchars,
207                        struct wim_lookup_table_entry *lte, struct apply_ctx *ctx)
208 {
209         ntfs_inode *ni;
210         ntfs_attr *na;
211         int ret;
212         struct ntfs_attr_extract_ctx extract_ctx;
213         utf16lechar *stream_name;
214
215         if (stream_name_nchars == 0) {
216                 stream_name = AT_UNNAMED;
217         } else {
218                 stream_name = alloca((stream_name_nchars + 1) * sizeof(utf16lechar));
219                 memcpy(stream_name, raw_stream_name,
220                        stream_name_nchars * sizeof(utf16lechar));
221                 stream_name[stream_name_nchars] = 0;
222         }
223
224         ret = 0;
225         if (!stream_name_nchars && !lte)
226                 goto out;
227
228         /* Open NTFS inode to which to extract the stream.  */
229         ret = WIMLIB_ERR_OPEN;
230         ni = ntfs_inode_open(ntfs_3g_apply_ctx_get_volume(ctx), file.cookie);
231         if (!ni)
232                 goto out;
233
234         /* Add the stream if it's not the default (unnamed) stream.  */
235         ret = WIMLIB_ERR_OPEN;
236         if (stream_name_nchars)
237                 if (ntfs_attr_add(ni, AT_DATA, stream_name,
238                                   stream_name_nchars, NULL, 0))
239                         goto out_close;
240
241         /* If stream is empty, no need to open and extract it.  */
242         ret = 0;
243         if (!lte)
244                 goto out_close;
245
246         /* Open the stream (NTFS attribute).  */
247         ret = WIMLIB_ERR_OPEN;
248         na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_nchars);
249         if (!na)
250                 goto out_close;
251
252         /* (Optional) Immediately resize attribute to size of stream.
253          *
254          * This dramatically speeds up extraction, as demonstrated with the
255          * following timing results:
256          *
257          * 18 mins. 27 sec. to apply Windows 7 image (with resize)
258          * 32 mins. 45 sec. to apply Windows 7 image (no resize)
259          *
260          * It probably would speed things up even more if we could get NTFS-3g
261          * to skip even more useless work (for example it fills resized
262          * attributes with 0's, then we just override it.)  */
263         ret = WIMLIB_ERR_WRITE;
264         if (ntfs_attr_truncate_solid(na, lte->size))
265                 goto out_attr_close;
266
267         /* Extract stream data to the NTFS attribute.  */
268         extract_ctx.na = na;
269         extract_ctx.offset = 0;
270         ret = extract_stream(lte, lte->size,
271                              ntfs_3g_extract_wim_chunk, &extract_ctx);
272         /* Clean up and return.  */
273 out_attr_close:
274         ntfs_attr_close(na);
275 out_close:
276         if (ntfs_inode_close(ni))
277                 ret = WIMLIB_ERR_WRITE;
278 out:
279         if (ret && !errno)
280                 errno = -1;
281         return ret;
282 }
283
284 static int
285 ntfs_3g_extract_unnamed_stream(file_spec_t file,
286                                struct wim_lookup_table_entry *lte,
287                                struct apply_ctx *ctx,
288                                struct wim_dentry *_ignore)
289 {
290         return ntfs_3g_extract_stream(file, NULL, 0, lte, ctx);
291 }
292
293 static int
294 ntfs_3g_extract_named_stream(file_spec_t file, const utf16lechar *stream_name,
295                              size_t stream_name_nchars,
296                              struct wim_lookup_table_entry *lte, struct apply_ctx *ctx)
297 {
298         return ntfs_3g_extract_stream(file, stream_name,
299                                       stream_name_nchars, lte, ctx);
300 }
301
302 static int
303 ntfs_3g_set_file_attributes(const char *path, u32 attributes,
304                             struct apply_ctx *ctx, unsigned pass)
305 {
306         ntfs_inode *ni;
307         int ret = 0;
308
309         ni = ntfs_3g_apply_pathname_to_inode(path, ctx);
310         if (!ni)
311                 return WIMLIB_ERR_OPEN;
312         if (ntfs_set_ntfs_attrib(ni, (const char*)&attributes, sizeof(u32), 0))
313                 ret = WIMLIB_ERR_SET_ATTRIBUTES;
314         if (ntfs_inode_close(ni))
315                 ret = WIMLIB_ERR_WRITE;
316         return ret;
317 }
318
319 static int
320 ntfs_3g_set_reparse_data(const char *path, const u8 *rpbuf, u16 rpbuflen,
321                          struct apply_ctx *ctx)
322 {
323         ntfs_inode *ni;
324         int ret = 0;
325
326         ni = ntfs_3g_apply_pathname_to_inode(path, ctx);
327         if (!ni)
328                 return WIMLIB_ERR_OPEN;
329         if (ntfs_set_ntfs_reparse_data(ni, rpbuf, rpbuflen, 0))
330                 ret = WIMLIB_ERR_SET_REPARSE_DATA;
331         if (ntfs_inode_close(ni))
332                 ret = WIMLIB_ERR_WRITE;
333         return ret;
334 }
335
336 static int
337 ntfs_3g_set_short_name(const char *path, const utf16lechar *short_name,
338                        size_t short_name_nchars, struct apply_ctx *ctx)
339 {
340         ntfs_inode *ni, *dir_ni;
341         ntfs_volume *vol;
342         int ret;
343         char *dosname = NULL;
344         size_t dosname_nbytes;
345
346         ret = 0;
347         if (short_name_nchars == 0)
348                 goto out;
349
350         vol = ntfs_3g_apply_ctx_get_volume(ctx);
351
352         ret = WIMLIB_ERR_OPEN;
353         dir_ni = ntfs_3g_open_parent_inode(path, vol);
354         if (!dir_ni)
355                 goto out;
356
357         ret = WIMLIB_ERR_OPEN;
358         ni = ntfs_pathname_to_inode(vol, NULL, path);
359         if (!ni)
360                 goto out_close_dir_ni;
361
362         ret = utf16le_to_tstr(short_name, short_name_nchars * 2,
363                               &dosname, &dosname_nbytes);
364         if (ret)
365                 goto out_close_ni;
366
367         ret = 0;
368         if (ntfs_set_ntfs_dos_name(ni, dir_ni, dosname,
369                                    dosname_nbytes, 0))
370                 ret = WIMLIB_ERR_SET_SHORT_NAME;
371         /* ntfs_set_ntfs_dos_name() always closes the inodes.  */
372         FREE(dosname);
373         goto out;
374 out_close_ni:
375         if (ntfs_inode_close_in_dir(ni, dir_ni))
376                 ret = WIMLIB_ERR_WRITE;
377 out_close_dir_ni:
378         if (ntfs_inode_close(dir_ni))
379                 ret = WIMLIB_ERR_WRITE;
380 out:
381         return ret;
382 }
383
384 static size_t
385 sid_size(const wimlib_SID *sid)
386 {
387         return offsetof(wimlib_SID, sub_authority) +
388                 sizeof(le32) * sid->sub_authority_count;
389 }
390
391 /*
392  * sd_fixup - Fix up a Windows NT security descriptor for libntfs-3g.
393  *
394  * libntfs-3g validates security descriptors before setting them, but old
395  * versions contain bugs causing it to reject unusual but valid security
396  * descriptors:
397  *
398  * - Versions before 2013.1.13 reject security descriptors ending with an empty
399  *   SACL (System Access Control List).  This bug can be worked around either by
400  *   moving the empty SACL earlier in the security descriptor or by removing the
401  *   SACL entirely.  The latter work-around is valid because an empty SACL is
402  *   equivalent to a "null", or non-existent, SACL.
403  * - Versions up to and including 2013.1.13 reject security descriptors ending
404  *   with an empty DACL (Discretionary Access Control List).  This is very
405  *   similar to the SACL bug and should be fixed in the next release after
406  *   2013.1.13.  However, removing the DACL is not a valid workaround because
407  *   this changes the meaning of the security descriptor--- an empty DACL allows
408  *   no access, whereas a "null" DACL allows all access.
409  *
410  * If the security descriptor was fixed, this function returns an allocated
411  * buffer containing the fixed security descriptor, and its size is updated.
412  * Otherwise (or if no memory is available) the original descriptor is returned.
413  */
414 static u8 *
415 sd_fixup(const u8 *_desc, size_t *size_p)
416 {
417         u32 owner_offset, group_offset, dacl_offset, sacl_offset;
418         bool owner_valid, group_valid;
419         size_t size = *size_p;
420         const wimlib_SECURITY_DESCRIPTOR_RELATIVE *desc =
421                         (const wimlib_SECURITY_DESCRIPTOR_RELATIVE*)_desc;
422         wimlib_SECURITY_DESCRIPTOR_RELATIVE *desc_new;
423         const wimlib_SID *owner, *group, *sid;
424
425         /* Don't attempt to fix clearly invalid security descriptors.  */
426         if (size < sizeof(wimlib_SECURITY_DESCRIPTOR_RELATIVE))
427                 return (u8*)_desc;
428
429         if (le16_to_cpu(desc->control) & wimlib_SE_DACL_PRESENT)
430                 dacl_offset = le32_to_cpu(desc->dacl_offset);
431         else
432                 dacl_offset = 0;
433
434         if (le16_to_cpu(desc->control) & wimlib_SE_SACL_PRESENT)
435                 sacl_offset = le32_to_cpu(desc->sacl_offset);
436         else
437                 sacl_offset = 0;
438
439         /* Check if the security descriptor will be affected by one of the bugs.
440          * If not, do nothing and return.
441          *
442          * Note: HAVE_NTFS_MNT_RDONLY is defined if libntfs-3g is
443          * version 2013.1.13 or later.  */
444         if (!(
445         #if !defined(HAVE_NTFS_MNT_RDONLY)
446             (sacl_offset != 0 && sacl_offset == size - sizeof(wimlib_ACL)) ||
447         #endif
448             (dacl_offset != 0 && dacl_offset == size - sizeof(wimlib_ACL))))
449                 return (u8*)_desc;
450
451         owner_offset = le32_to_cpu(desc->owner_offset);
452         group_offset = le32_to_cpu(desc->group_offset);
453         owner = (const wimlib_SID*)((const u8*)desc + owner_offset);
454         group = (const wimlib_SID*)((const u8*)desc + group_offset);
455
456         /* We'll try to move the owner or group SID to the end of the security
457          * descriptor to avoid the bug.  This is only possible if at least one
458          * is valid.  */
459         owner_valid = (owner_offset != 0) &&
460                         (owner_offset % 4 == 0) &&
461                         (owner_offset <= size - sizeof(SID)) &&
462                         (owner_offset + sid_size(owner) <= size) &&
463                         (owner_offset >= sizeof(wimlib_SECURITY_DESCRIPTOR_RELATIVE));
464         group_valid = (group_offset != 0) &&
465                         (group_offset % 4 == 0) &&
466                         (group_offset <= size - sizeof(SID)) &&
467                         (group_offset + sid_size(group) <= size) &&
468                         (group_offset >= sizeof(wimlib_SECURITY_DESCRIPTOR_RELATIVE));
469         if (owner_valid) {
470                 sid = owner;
471         } else if (group_valid) {
472                 sid = group;
473         } else {
474                 return (u8*)_desc;
475         }
476
477         desc_new = MALLOC(size + sid_size(sid));
478         if (desc_new == NULL)
479                 return (u8*)_desc;
480
481         memcpy(desc_new, desc, size);
482         if (owner_valid)
483                 desc_new->owner_offset = cpu_to_le32(size);
484         else if (group_valid)
485                 desc_new->group_offset = cpu_to_le32(size);
486         memcpy((u8*)desc_new + size, sid, sid_size(sid));
487         *size_p = size + sid_size(sid);
488         return (u8*)desc_new;
489 }
490
491 static int
492 ntfs_3g_set_security_descriptor(const char *path, const u8 *desc, size_t desc_size,
493                                 struct apply_ctx *ctx)
494 {
495         ntfs_volume *vol;
496         ntfs_inode *ni;
497         struct SECURITY_CONTEXT sec_ctx;
498         u8 *desc_fixed;
499         int ret;
500
501         vol = ntfs_3g_apply_ctx_get_volume(ctx);
502
503         ni = ntfs_pathname_to_inode(vol, NULL, path);
504         if (!ni)
505                 return WIMLIB_ERR_OPEN;
506
507         memset(&sec_ctx, 0, sizeof(sec_ctx));
508         sec_ctx.vol = vol;
509
510         desc_fixed = sd_fixup(desc, &desc_size);
511
512         ret = 0;
513
514         if (ntfs_set_ntfs_acl(&sec_ctx, ni, desc_fixed, desc_size, 0))
515                 ret = WIMLIB_ERR_SET_SECURITY;
516
517         if (desc_fixed != desc)
518                 FREE(desc_fixed);
519
520         if (ntfs_inode_close(ni))
521                 ret = WIMLIB_ERR_WRITE;
522
523         return ret;
524 }
525
526 static int
527 ntfs_3g_set_timestamps(const char *path, u64 creation_time,
528                        u64 last_write_time, u64 last_access_time,
529                        struct apply_ctx *ctx)
530 {
531         u64 ntfs_timestamps[3];
532         ntfs_inode *ni;
533         int ret = 0;
534
535         ni = ntfs_3g_apply_pathname_to_inode(path, ctx);
536         if (!ni)
537                 return WIMLIB_ERR_OPEN;
538
539         /* Note: ntfs_inode_set_times() expects the times in native byte order,
540          * not little endian. */
541         ntfs_timestamps[0] = creation_time;
542         ntfs_timestamps[1] = last_write_time;
543         ntfs_timestamps[2] = last_access_time;
544
545         if (ntfs_inode_set_times(ni, (const char*)ntfs_timestamps,
546                                  sizeof(ntfs_timestamps), 0))
547                 ret = WIMLIB_ERR_SET_TIMESTAMPS;
548         if (ntfs_inode_close(ni))
549                 ret = WIMLIB_ERR_WRITE;
550         return ret;
551 }
552
553 static bool
554 ntfs_3g_target_is_root(const char *target)
555 {
556         /* We always extract to the root of the NTFS volume.  */
557         return true;
558 }
559
560 static int
561 ntfs_3g_start_extract(const char *path, struct apply_ctx *ctx)
562 {
563         ntfs_volume *vol;
564
565         vol = ntfs_mount(ctx->target, 0);
566         if (!vol) {
567                 ERROR_WITH_ERRNO("Failed to mount \"%"TS"\" with NTFS-3g", ctx->target);
568                 return WIMLIB_ERR_OPEN;
569         }
570         ntfs_3g_apply_ctx_set_volume(ctx, vol);
571
572         ctx->supported_features.archive_files             = 1;
573         ctx->supported_features.hidden_files              = 1;
574         ctx->supported_features.system_files              = 1;
575         ctx->supported_features.compressed_files          = 1;
576         ctx->supported_features.encrypted_files           = 0;
577         ctx->supported_features.not_context_indexed_files = 1;
578         ctx->supported_features.sparse_files              = 1;
579         ctx->supported_features.named_data_streams        = 1;
580         ctx->supported_features.hard_links                = 1;
581         ctx->supported_features.reparse_points            = 1;
582         ctx->supported_features.security_descriptors      = 1;
583         ctx->supported_features.short_names               = 1;
584         return 0;
585 }
586
587 static int
588 ntfs_3g_finish_or_abort_extract(struct apply_ctx *ctx)
589 {
590         ntfs_volume *vol;
591
592         vol = ntfs_3g_apply_ctx_get_volume(ctx);
593         if (ntfs_umount(vol, FALSE)) {
594                 ERROR_WITH_ERRNO("Failed to unmount \"%"TS"\" with NTFS-3g",
595                                  ctx->target);
596                 return WIMLIB_ERR_WRITE;
597         }
598         return 0;
599 }
600
601 void
602 libntfs3g_global_init(void)
603 {
604         ntfs_set_char_encoding(setlocale(LC_ALL, ""));
605 }
606
607 const struct apply_operations ntfs_3g_apply_ops = {
608         .name = "NTFS-3g",
609
610         .target_is_root          = ntfs_3g_target_is_root,
611         .start_extract           = ntfs_3g_start_extract,
612         .create_file             = ntfs_3g_create_file,
613         .create_directory        = ntfs_3g_create_directory,
614         .create_hardlink         = ntfs_3g_create_hardlink,
615         .extract_unnamed_stream  = ntfs_3g_extract_unnamed_stream,
616         .extract_named_stream    = ntfs_3g_extract_named_stream,
617         .set_file_attributes     = ntfs_3g_set_file_attributes,
618         .set_reparse_data        = ntfs_3g_set_reparse_data,
619         .set_short_name          = ntfs_3g_set_short_name,
620         .set_security_descriptor = ntfs_3g_set_security_descriptor,
621         .set_timestamps          = ntfs_3g_set_timestamps,
622         .abort_extract           = ntfs_3g_finish_or_abort_extract,
623         .finish_extract          = ntfs_3g_finish_or_abort_extract,
624
625         .path_prefix = "/",
626         .path_prefix_nchars = 1,
627         .path_separator = '/',
628         .path_max = 32768,
629
630         /* By default, NTFS-3g creates names in the NTFS POSIX namespace, which
631          * is case-sensitive.  */
632         .supports_case_sensitive_filenames = 1,
633
634         /* The root directory of the NTFS volume should not be created
635          * explicitly.  */
636         .root_directory_is_special = 1,
637
638         /* NTFS-3g can open files by MFT reference.  */
639         .uses_cookies = 1,
640
641         /*
642          * With NTFS-3g, the extraction order of the names of a file that has a
643          * short name needs to be:
644          *
645          * 1. Create file using the long name that has an associated short name.
646          *    This long name is temporarily placed in the POSIX namespace.
647          * 2. Set the short name on the file.  This will either change the POSIX
648          *    name to Win32 and create a new DOS name, or replace the POSIX name
649          *    with a Win32+DOS name.
650          * 3. Create additional long names (links) of the file, which are placed
651          *    in the POSIX namespace.
652          *
653          * The reason for this is that two issues can come up when the
654          * extraction is done otherwise:
655          *
656          * - If a DOS name is set on a file in a directory with several long
657          *   names, it is ambiguous which long name to use (at least with the
658          *   exported ntfs_set_ntfs_dos_name() function).
659          * - NTFS-3g 2013.1.13 will no longer allow even setting the DOS name on
660          *   a file with multiple existing long names, even if those long names
661          *   are in different directories and the ntfs_set_ntfs_dos_name() call
662          *   is therefore unambiguous.  (This was apparently changed with the
663          *   FUSE interface in mind.)
664          */
665         .requires_short_name_reordering    = 1,
666 };
667
668 #endif /* WITH_NTFS_3G */