]> wimlib.net Git - wimlib/blob - src/ntfs-3g_capture.c
f9825f73946ca6c629690d587dc3d74c2af25a8e
[wimlib] / src / ntfs-3g_capture.c
1 /*
2  * ntfs-3g_capture.c
3  *
4  * Capture a WIM image directly from an NTFS volume using libntfs-3g.  We capture
5  * everything we can, including security data and alternate data streams.
6  */
7
8 /*
9  * Copyright (C) 2012, 2013, 2014, 2015 Eric Biggers
10  *
11  * This file is free software; you can redistribute it and/or modify it under
12  * the terms of the GNU Lesser General Public License as published by the Free
13  * Software Foundation; either version 3 of the License, or (at your option) any
14  * later version.
15  *
16  * This file is distributed in the hope that it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
19  * details.
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * along with this file; if not, see http://www.gnu.org/licenses/.
23  */
24
25 #ifdef HAVE_CONFIG_H
26 #  include "config.h"
27 #endif
28
29 #ifdef WITH_NTFS_3G
30
31 #include <errno.h>
32
33 #include <ntfs-3g/attrib.h>
34 #include <ntfs-3g/reparse.h>
35 #include <ntfs-3g/security.h>
36 #include <ntfs-3g/volume.h>
37
38 #include "wimlib/alloca.h"
39 #include "wimlib/assert.h"
40 #include "wimlib/blob_table.h"
41 #include "wimlib/capture.h"
42 #include "wimlib/dentry.h"
43 #include "wimlib/encoding.h"
44 #include "wimlib/endianness.h"
45 #include "wimlib/error.h"
46 #include "wimlib/ntfs_3g.h"
47 #include "wimlib/paths.h"
48 #include "wimlib/reparse.h"
49 #include "wimlib/security.h"
50
51 /* A reference-counted NTFS volume than is automatically unmounted when the
52  * reference count reaches 0  */
53 struct ntfs_volume_wrapper {
54         ntfs_volume *vol;
55         size_t refcnt;
56 };
57
58 /* Description of where data is located in an NTFS volume  */
59 struct ntfs_location {
60         struct ntfs_volume_wrapper *volume;
61         u64 mft_no;
62         ATTR_TYPES attr_type;
63         u32 attr_name_nchars;
64         utf16lechar *attr_name;
65         u64 sort_key;
66 };
67
68 static struct ntfs_volume_wrapper *
69 get_ntfs_volume(struct ntfs_volume_wrapper *volume)
70 {
71         volume->refcnt++;
72         return volume;
73 }
74
75 static void
76 put_ntfs_volume(struct ntfs_volume_wrapper *volume)
77 {
78         if (--volume->refcnt == 0) {
79                 ntfs_umount(volume->vol, FALSE);
80                 FREE(volume);
81         }
82 }
83
84 static inline const ntfschar *
85 attr_record_name(const ATTR_RECORD *record)
86 {
87         return (const ntfschar *)
88                 ((const u8 *)record + le16_to_cpu(record->name_offset));
89 }
90
91 static ntfs_attr *
92 open_ntfs_attr(ntfs_inode *ni, const struct ntfs_location *loc)
93 {
94         ntfs_attr *na;
95
96         na = ntfs_attr_open(ni, loc->attr_type, loc->attr_name,
97                             loc->attr_name_nchars);
98         if (!na) {
99                 ERROR_WITH_ERRNO("Failed to open attribute of NTFS inode %"PRIu64,
100                                  loc->mft_no);
101         }
102         return na;
103 }
104
105 int
106 read_ntfs_attribute_prefix(const struct blob_descriptor *blob, u64 size,
107                            const struct read_blob_callbacks *cbs)
108 {
109         const struct ntfs_location *loc = blob->ntfs_loc;
110         ntfs_volume *vol = loc->volume->vol;
111         ntfs_inode *ni;
112         ntfs_attr *na;
113         s64 pos;
114         s64 bytes_remaining;
115         int ret;
116         u8 buf[BUFFER_SIZE];
117
118         ni = ntfs_inode_open(vol, loc->mft_no);
119         if (!ni) {
120                 ERROR_WITH_ERRNO("Failed to open NTFS inode %"PRIu64,
121                                  loc->mft_no);
122                 ret = WIMLIB_ERR_NTFS_3G;
123                 goto out;
124         }
125
126         na = open_ntfs_attr(ni, loc);
127         if (!na) {
128                 ret = WIMLIB_ERR_NTFS_3G;
129                 goto out_close_ntfs_inode;
130         }
131
132         pos = (loc->attr_type == AT_REPARSE_POINT) ? REPARSE_DATA_OFFSET : 0;
133         bytes_remaining = size;
134         while (bytes_remaining) {
135                 s64 to_read = min(bytes_remaining, sizeof(buf));
136                 if (ntfs_attr_pread(na, pos, to_read, buf) != to_read) {
137                         ERROR_WITH_ERRNO("Error reading data from NTFS inode "
138                                          "%"PRIu64, loc->mft_no);
139                         ret = WIMLIB_ERR_NTFS_3G;
140                         goto out_close_ntfs_attr;
141                 }
142                 pos += to_read;
143                 bytes_remaining -= to_read;
144                 ret = call_consume_chunk(buf, to_read, cbs);
145                 if (ret)
146                         goto out_close_ntfs_attr;
147         }
148         ret = 0;
149 out_close_ntfs_attr:
150         ntfs_attr_close(na);
151 out_close_ntfs_inode:
152         ntfs_inode_close(ni);
153 out:
154         return ret;
155 }
156
157 void
158 free_ntfs_location(struct ntfs_location *loc)
159 {
160         put_ntfs_volume(loc->volume);
161         FREE(loc->attr_name);
162         FREE(loc);
163 }
164
165 struct ntfs_location *
166 clone_ntfs_location(const struct ntfs_location *loc)
167 {
168         struct ntfs_location *new = memdup(loc, sizeof(*loc));
169         if (!new)
170                 goto err0;
171         if (loc->attr_name) {
172                 new->attr_name = utf16le_dup(loc->attr_name);
173                 if (!new->attr_name)
174                         goto err1;
175         }
176         new->volume = get_ntfs_volume(loc->volume);
177         return new;
178
179 err1:
180         FREE(new);
181 err0:
182         return NULL;
183 }
184
185 int
186 cmp_ntfs_locations(const struct ntfs_location *loc1,
187                    const struct ntfs_location *loc2)
188 {
189         return cmp_u64(loc1->sort_key, loc2->sort_key);
190 }
191
192 /* Read rptag and rpreserved from the NTFS inode and save them in the WIM inode.
193  */
194 static int
195 read_reparse_header(ntfs_inode *ni, struct wim_inode *inode)
196 {
197         struct {
198                 le32 rptag;
199                 le16 rpdatalen;
200                 le16 rpreserved;
201         } hdr;
202         s64 res;
203         ntfs_attr *na;
204
205         na = ntfs_attr_open(ni, AT_REPARSE_POINT, AT_UNNAMED, 0);
206         if (!na)
207                 return WIMLIB_ERR_NTFS_3G;
208
209         res = ntfs_attr_pread(na, 0, sizeof(hdr), &hdr);
210
211         ntfs_attr_close(na);
212
213         if (res != sizeof(hdr))
214                 return WIMLIB_ERR_NTFS_3G;
215
216         inode->i_reparse_tag = le32_to_cpu(hdr.rptag);
217         inode->i_rp_reserved = le16_to_cpu(hdr.rpreserved);
218         return 0;
219 }
220
221 static int
222 attr_type_to_wimlib_stream_type(ATTR_TYPES type)
223 {
224         switch (type) {
225         case AT_DATA:
226                 return STREAM_TYPE_DATA;
227         case AT_REPARSE_POINT:
228                 return STREAM_TYPE_REPARSE_POINT;
229         default:
230                 wimlib_assert(0);
231                 return STREAM_TYPE_UNKNOWN;
232         }
233 }
234
235 /* When sorting blobs located in NTFS volumes for sequential reading, we sort
236  * first by starting LCN of the attribute if available, otherwise no sort order
237  * is defined.  This usually results in better sequential access to the volume.
238  */
239 static int
240 set_attr_sort_key(ntfs_inode *ni, struct ntfs_location *loc)
241 {
242         ntfs_attr *na;
243         runlist_element *rl;
244
245         na = open_ntfs_attr(ni, loc);
246         if (!na)
247                 return WIMLIB_ERR_NTFS_3G;
248
249         rl = ntfs_attr_find_vcn(na, 0);
250         if (rl && rl->lcn != LCN_HOLE)
251                 loc->sort_key = rl->lcn;
252         else
253                 loc->sort_key = 0;
254
255         ntfs_attr_close(na);
256         return 0;
257 }
258
259 /* Save information about an NTFS attribute (stream) to a WIM inode.  */
260 static int
261 scan_ntfs_attr(struct wim_inode *inode,
262                ntfs_inode *ni,
263                const char *path,
264                struct list_head *unhashed_blobs,
265                struct ntfs_volume_wrapper *volume,
266                ATTR_TYPES type,
267                const ATTR_RECORD *record)
268 {
269         u64 data_size = ntfs_get_attribute_value_length(record);
270         const u32 name_nchars = record->name_length;
271         struct blob_descriptor *blob = NULL;
272         utf16lechar *stream_name = NULL;
273         struct wim_inode_stream *strm;
274         int ret;
275
276         if (unlikely(name_nchars)) {
277                 /* Named stream  */
278                 stream_name = utf16le_dupz(attr_record_name(record),
279                                            name_nchars * sizeof(ntfschar));
280                 if (!stream_name) {
281                         ret = WIMLIB_ERR_NOMEM;
282                         goto out_cleanup;
283                 }
284         }
285
286         if (unlikely(type == AT_REPARSE_POINT)) {
287                 if (data_size < REPARSE_DATA_OFFSET) {
288                         ERROR("Reparse point attribute of \"%s\" "
289                               "is too short!", path);
290                         ret = WIMLIB_ERR_INVALID_REPARSE_DATA;
291                         goto out_cleanup;
292                 }
293                 data_size -= REPARSE_DATA_OFFSET;
294
295                 ret = read_reparse_header(ni, inode);
296                 if (ret) {
297                         ERROR_WITH_ERRNO("Error reading reparse point header "
298                                          "of \"%s\"", path);
299                         goto out_cleanup;
300                 }
301         }
302
303         /* If the stream is non-empty, set up a blob descriptor for it.  */
304         if (data_size != 0) {
305                 blob = new_blob_descriptor();
306                 if (unlikely(!blob)) {
307                         ret = WIMLIB_ERR_NOMEM;
308                         goto out_cleanup;
309                 }
310
311                 blob->ntfs_loc = CALLOC(1, sizeof(struct ntfs_location));
312                 if (unlikely(!blob->ntfs_loc)) {
313                         ret = WIMLIB_ERR_NOMEM;
314                         goto out_cleanup;
315                 }
316
317                 blob->blob_location = BLOB_IN_NTFS_VOLUME;
318                 blob->size = data_size;
319                 blob->ntfs_loc->volume = get_ntfs_volume(volume);
320                 blob->ntfs_loc->attr_type = type;
321                 blob->ntfs_loc->mft_no = ni->mft_no;
322
323                 if (unlikely(name_nchars)) {
324                         blob->ntfs_loc->attr_name = utf16le_dup(stream_name);
325                         if (!blob->ntfs_loc->attr_name) {
326                                 ret = WIMLIB_ERR_NOMEM;
327                                 goto out_cleanup;
328                         }
329                         blob->ntfs_loc->attr_name_nchars = name_nchars;
330                 }
331
332                 ret = set_attr_sort_key(ni, blob->ntfs_loc);
333                 if (ret)
334                         goto out_cleanup;
335         }
336
337         strm = inode_add_stream(inode,
338                                 attr_type_to_wimlib_stream_type(type),
339                                 stream_name ? stream_name : NO_STREAM_NAME,
340                                 blob);
341         if (unlikely(!strm)) {
342                 ret = WIMLIB_ERR_NOMEM;
343                 goto out_cleanup;
344         }
345         prepare_unhashed_blob(blob, inode, strm->stream_id, unhashed_blobs);
346         blob = NULL;
347         ret = 0;
348 out_cleanup:
349         free_blob_descriptor(blob);
350         FREE(stream_name);
351         return ret;
352 }
353
354 /* Scan attributes of the specified type from a file in the NTFS volume  */
355 static int
356 scan_ntfs_attrs_with_type(struct wim_inode *inode,
357                           ntfs_inode *ni,
358                           const char *path,
359                           struct list_head *unhashed_blobs,
360                           struct ntfs_volume_wrapper *volume,
361                           ATTR_TYPES type)
362 {
363         ntfs_attr_search_ctx *actx;
364         int ret;
365
366         actx = ntfs_attr_get_search_ctx(ni, NULL);
367         if (!actx) {
368                 ERROR_WITH_ERRNO("Failed to get NTFS attribute search "
369                                  "context for \"%s\"", path);
370                 return WIMLIB_ERR_NTFS_3G;
371         }
372
373         while (!ntfs_attr_lookup(type, NULL, 0,
374                                  CASE_SENSITIVE, 0, NULL, 0, actx))
375         {
376                 ret = scan_ntfs_attr(inode,
377                                      ni,
378                                      path,
379                                      unhashed_blobs,
380                                      volume,
381                                      type,
382                                      actx->attr);
383                 if (ret)
384                         goto out_put_actx;
385         }
386         if (errno != ENOENT) {
387                 ERROR_WITH_ERRNO("Error listing NTFS attributes of \"%s\"", path);
388                 ret = WIMLIB_ERR_NTFS_3G;
389                 goto out_put_actx;
390         }
391         ret = 0;
392 out_put_actx:
393         ntfs_attr_put_search_ctx(actx);
394         return ret;
395 }
396
397 /* Load the security descriptor of an NTFS inode into the corresponding WIM
398  * inode and the WIM image's security descriptor set.  */
399 static noinline_for_stack int
400 get_security_descriptor(ntfs_inode *ni, struct wim_inode *inode,
401                         ntfs_volume *vol, struct wim_sd_set *sd_set)
402 {
403         struct SECURITY_CONTEXT scx = {.vol = vol};
404         char _buf[4096];
405         char *buf = _buf;
406         size_t avail_size = sizeof(_buf);
407         int ret;
408
409 retry:
410         ret = ntfs_get_ntfs_acl(&scx, ni, buf, avail_size);
411         if (unlikely(ret < 0)) {
412                 ret = WIMLIB_ERR_NTFS_3G;
413                 goto out;
414         }
415
416         if (unlikely(ret > avail_size)) {
417                 if (unlikely(buf != _buf))
418                         FREE(buf);
419                 buf = MALLOC(ret);
420                 if (!buf) {
421                         ret = WIMLIB_ERR_NOMEM;
422                         goto out;
423                 }
424                 avail_size = ret;
425                 goto retry;
426         }
427
428         if (likely(ret > 0)) {
429                 inode->i_security_id = sd_set_add_sd(sd_set, buf, ret);
430                 if (unlikely(inode->i_security_id < 0)) {
431                         ret = WIMLIB_ERR_NOMEM;
432                         goto out;
433                 }
434         }
435
436         ret = 0;
437 out:
438         if (unlikely(buf != _buf))
439                 FREE(buf);
440         return ret;
441 }
442
443 /* Binary tree that maps NTFS inode numbers to DOS names */
444 struct dos_name_map {
445         struct avl_tree_node *root;
446 };
447
448 struct dos_name_node {
449         struct avl_tree_node index_node;
450         char dos_name[24];
451         int name_nbytes;
452         u64 ntfs_ino;
453 };
454
455 #define DOS_NAME_NODE(avl_node) \
456         avl_tree_entry(avl_node, struct dos_name_node, index_node)
457
458 static int
459 _avl_cmp_by_ntfs_ino(const struct avl_tree_node *n1,
460                      const struct avl_tree_node *n2)
461 {
462         return cmp_u64(DOS_NAME_NODE(n1)->ntfs_ino,
463                        DOS_NAME_NODE(n2)->ntfs_ino);
464 }
465
466 /* Inserts a new DOS name into the map */
467 static int
468 insert_dos_name(struct dos_name_map *map, const ntfschar *dos_name,
469                 size_t name_nbytes, u64 ntfs_ino)
470 {
471         struct dos_name_node *new_node;
472
473         new_node = MALLOC(sizeof(struct dos_name_node));
474         if (!new_node)
475                 return WIMLIB_ERR_NOMEM;
476
477         /* DOS names are supposed to be 12 characters max (that's 24 bytes,
478          * assuming 2-byte ntfs characters) */
479         wimlib_assert(name_nbytes <= sizeof(new_node->dos_name));
480
481         /* Initialize the DOS name, DOS name length, and NTFS inode number of
482          * the search tree node */
483         memcpy(new_node->dos_name, dos_name, name_nbytes);
484         new_node->name_nbytes = name_nbytes;
485         new_node->ntfs_ino = ntfs_ino;
486
487         /* Insert the search tree node */
488         if (avl_tree_insert(&map->root, &new_node->index_node,
489                             _avl_cmp_by_ntfs_ino))
490         {
491                 /* This should be impossible since an NTFS inode cannot have
492                  * multiple DOS names, and we only should get each DOS name
493                  * entry once from the ntfs_readdir() calls. */
494                 WARNING("NTFS inode %"PRIu64" has multiple DOS names", ntfs_ino);
495                 FREE(new_node);
496         }
497         return 0;
498 }
499
500 /* Returns a structure that contains the DOS name and its length for an NTFS
501  * inode, or NULL if the inode has no DOS name. */
502 static struct dos_name_node *
503 lookup_dos_name(const struct dos_name_map *map, u64 ntfs_ino)
504 {
505         struct dos_name_node dummy;
506         struct avl_tree_node *res;
507
508         dummy.ntfs_ino = ntfs_ino;
509
510         res = avl_tree_lookup_node(map->root, &dummy.index_node,
511                                    _avl_cmp_by_ntfs_ino);
512         if (!res)
513                 return NULL;
514         return DOS_NAME_NODE(res);
515 }
516
517 static int
518 set_dentry_dos_name(struct wim_dentry *dentry, const struct dos_name_map *map)
519 {
520         const struct dos_name_node *node;
521
522         if (dentry->d_is_win32_name) {
523                 node = lookup_dos_name(map, dentry->d_inode->i_ino);
524                 if (node) {
525                         dentry->d_short_name = utf16le_dupz(node->dos_name,
526                                                             node->name_nbytes);
527                         if (!dentry->d_short_name)
528                                 return WIMLIB_ERR_NOMEM;
529                         dentry->d_short_name_nbytes = node->name_nbytes;
530                 } else {
531                         WARNING("NTFS inode %"PRIu64" has Win32 name with no "
532                                 "corresponding DOS name",
533                                 dentry->d_inode->i_ino);
534                 }
535         }
536         return 0;
537 }
538
539 static void
540 destroy_dos_name_map(struct dos_name_map *map)
541 {
542         struct dos_name_node *node;
543         avl_tree_for_each_in_postorder(node, map->root,
544                                        struct dos_name_node, index_node)
545                 FREE(node);
546 }
547
548 struct readdir_ctx {
549         struct wim_dentry *parent;
550         char *path;
551         size_t path_len;
552         struct dos_name_map dos_name_map;
553         struct ntfs_volume_wrapper *volume;
554         struct capture_params *params;
555         int ret;
556 };
557
558 static int
559 ntfs_3g_build_dentry_tree_recursive(struct wim_dentry **root_p,
560                                     const MFT_REF mref,
561                                     char *path,
562                                     size_t path_len,
563                                     int name_type,
564                                     struct ntfs_volume_wrapper *volume,
565                                     struct capture_params *params);
566
567 static int
568 filldir(void *_ctx, const ntfschar *name, const int name_nchars,
569         const int name_type, const s64 pos, const MFT_REF mref,
570         const unsigned dt_type)
571 {
572         struct readdir_ctx *ctx = _ctx;
573         const size_t name_nbytes = name_nchars * sizeof(ntfschar);
574         char *mbs_name;
575         size_t mbs_name_nbytes;
576         size_t path_len;
577         struct wim_dentry *child;
578         int ret;
579
580         if (name_type & FILE_NAME_DOS) {
581                 /* If this is the entry for a DOS name, store it for later. */
582                 ret = insert_dos_name(&ctx->dos_name_map, name,
583                                       name_nbytes, MREF(mref));
584
585                 /* Return now if an error occurred or if this is just a DOS name
586                  * and not a Win32+DOS name. */
587                 if (ret != 0 || name_type == FILE_NAME_DOS)
588                         goto out;
589         }
590
591         ret = utf16le_to_tstr(name, name_nbytes, &mbs_name, &mbs_name_nbytes);
592         if (ret)
593                 goto out;
594
595         if (should_ignore_filename(mbs_name, mbs_name_nbytes))
596                 goto out_free_mbs_name;
597
598         path_len = ctx->path_len;
599         if (path_len != 1)
600                 ctx->path[path_len++] = '/';
601         memcpy(ctx->path + path_len, mbs_name, mbs_name_nbytes + 1);
602         path_len += mbs_name_nbytes;
603         child = NULL;
604         ret = ntfs_3g_build_dentry_tree_recursive(&child, mref, ctx->path,
605                                                   path_len, name_type,
606                                                   ctx->volume, ctx->params);
607         attach_scanned_tree(ctx->parent, child, ctx->params->blob_table);
608 out_free_mbs_name:
609         FREE(mbs_name);
610 out:
611         ctx->ret = ret;
612         return ret;
613 }
614
615 static int
616 ntfs_3g_recurse_directory(ntfs_inode *ni, char *path, size_t path_len,
617                           struct wim_dentry *parent,
618                           struct ntfs_volume_wrapper *volume,
619                           struct capture_params *params)
620 {
621         int ret;
622         s64 pos = 0;
623         struct readdir_ctx ctx = {
624                 .parent          = parent,
625                 .path            = path,
626                 .path_len        = path_len,
627                 .dos_name_map    = { .root = NULL },
628                 .volume          = volume,
629                 .params          = params,
630                 .ret             = 0,
631         };
632         ret = ntfs_readdir(ni, &pos, &ctx, filldir);
633         path[path_len] = '\0';
634         if (unlikely(ret)) {
635                 if (ctx.ret) {
636                         /* wimlib error  */
637                         ret = ctx.ret;
638                 } else {
639                         /* error from ntfs_readdir() itself  */
640                         ERROR_WITH_ERRNO("Error reading directory \"%s\"", path);
641                         ret = WIMLIB_ERR_NTFS_3G;
642                 }
643         } else {
644                 struct wim_dentry *child;
645
646                 ret = 0;
647                 for_dentry_child(child, parent) {
648                         ret = set_dentry_dos_name(child, &ctx.dos_name_map);
649                         if (ret)
650                                 break;
651                 }
652         }
653         destroy_dos_name_map(&ctx.dos_name_map);
654         return ret;
655 }
656
657 static int
658 ntfs_3g_build_dentry_tree_recursive(struct wim_dentry **root_ret,
659                                     const MFT_REF mref,
660                                     char *path,
661                                     size_t path_len,
662                                     int name_type,
663                                     struct ntfs_volume_wrapper *volume,
664                                     struct capture_params *params)
665 {
666         u32 attributes;
667         int ret;
668         struct wim_dentry *root = NULL;
669         struct wim_inode *inode = NULL;
670         ntfs_inode *ni = NULL;
671
672         ret = try_exclude(path, params);
673         if (unlikely(ret < 0)) /* Excluded? */
674                 goto out_progress;
675         if (unlikely(ret > 0)) /* Error? */
676                 goto out;
677
678         ni = ntfs_inode_open(volume->vol, mref);
679         if (!ni) {
680                 ERROR_WITH_ERRNO("Failed to open NTFS file \"%s\"", path);
681                 ret = WIMLIB_ERR_NTFS_3G;
682                 goto out;
683         }
684
685         /* Get file attributes */
686         ret = ntfs_get_ntfs_attrib(ni, (char*)&attributes, sizeof(attributes));
687         if (ret != sizeof(attributes)) {
688                 ERROR_WITH_ERRNO("Failed to get NTFS attributes from \"%s\"", path);
689                 ret = WIMLIB_ERR_NTFS_3G;
690                 goto out;
691         }
692
693         if (unlikely(attributes & FILE_ATTRIBUTE_ENCRYPTED)) {
694                 if (params->add_flags & WIMLIB_ADD_FLAG_NO_UNSUPPORTED_EXCLUDE)
695                 {
696                         ERROR("Can't archive \"%s\" because NTFS-3g capture mode "
697                               "does not support encrypted files and directories", path);
698                         ret = WIMLIB_ERR_UNSUPPORTED_FILE;
699                         goto out;
700                 }
701                 params->progress.scan.cur_path = path;
702                 ret = do_capture_progress(params, WIMLIB_SCAN_DENTRY_UNSUPPORTED, NULL);
703                 goto out;
704         }
705
706         /* Create a WIM dentry with an associated inode, which may be shared */
707         ret = inode_table_new_dentry(params->inode_table,
708                                      path_basename_with_len(path, path_len),
709                                      ni->mft_no, 0, false, &root);
710         if (ret)
711                 goto out;
712
713         if (name_type & FILE_NAME_WIN32) /* Win32 or Win32+DOS name (rather than POSIX) */
714                 root->d_is_win32_name = 1;
715
716         inode = root->d_inode;
717
718         if (inode->i_nlink > 1) {
719                 /* Shared inode; nothing more to do */
720                 goto out_progress;
721         }
722
723         inode->i_creation_time    = le64_to_cpu(ni->creation_time);
724         inode->i_last_write_time  = le64_to_cpu(ni->last_data_change_time);
725         inode->i_last_access_time = le64_to_cpu(ni->last_access_time);
726         inode->i_attributes       = attributes;
727
728         if (attributes & FILE_ATTRIBUTE_REPARSE_POINT) {
729                 /* Scan the reparse point stream.  */
730                 ret = scan_ntfs_attrs_with_type(inode, ni, path,
731                                                 params->unhashed_blobs,
732                                                 volume, AT_REPARSE_POINT);
733                 if (ret)
734                         goto out;
735         }
736
737         /* Scan the data streams.
738          *
739          * Note: directories should not have an unnamed data stream, but they
740          * may have named data streams.  Nondirectories (including reparse
741          * points) can have an unnamed data stream as well as named data
742          * streams.  */
743         ret = scan_ntfs_attrs_with_type(inode, ni, path, params->unhashed_blobs,
744                                         volume, AT_DATA);
745         if (ret)
746                 goto out;
747
748         /* Reparse-point fixups are a no-op because in NTFS-3g capture mode we
749          * only allow capturing an entire volume. */
750         if (params->add_flags & WIMLIB_ADD_FLAG_RPFIX &&
751             inode_is_symlink(inode))
752                 inode->i_rp_flags &= ~WIM_RP_FLAG_NOT_FIXED;
753
754         if (!(params->add_flags & WIMLIB_ADD_FLAG_NO_ACLS)) {
755                 ret = get_security_descriptor(ni, inode, volume->vol,
756                                               params->sd_set);
757                 if (ret) {
758                         ERROR_WITH_ERRNO("Error reading security descriptor "
759                                          "of \"%s\"", path);
760                         goto out;
761                 }
762         }
763
764         if (inode_is_directory(inode)) {
765                 ret = ntfs_3g_recurse_directory(ni, path, path_len, root,
766                                                 volume, params);
767                 if (ret)
768                         goto out;
769         }
770
771 out_progress:
772         params->progress.scan.cur_path = path;
773         if (root == NULL)
774                 ret = do_capture_progress(params, WIMLIB_SCAN_DENTRY_EXCLUDED, NULL);
775         else
776                 ret = do_capture_progress(params, WIMLIB_SCAN_DENTRY_OK, inode);
777 out:
778         if (ni)
779                 ntfs_inode_close(ni);
780         if (unlikely(ret)) {
781                 free_dentry_tree(root, params->blob_table);
782                 root = NULL;
783                 ret = report_capture_error(params, ret, path);
784         }
785         *root_ret = root;
786         return ret;
787 }
788
789 int
790 ntfs_3g_build_dentry_tree(struct wim_dentry **root_ret,
791                           const char *device,
792                           struct capture_params *params)
793 {
794         struct ntfs_volume_wrapper *volume;
795         ntfs_volume *vol;
796         char *path;
797         int ret;
798
799         volume = MALLOC(sizeof(struct ntfs_volume_wrapper));
800         if (!volume)
801                 return WIMLIB_ERR_NOMEM;
802
803         /* NTFS-3g 2013 renamed the "read-only" mount flag from MS_RDONLY to
804          * NTFS_MNT_RDONLY.
805          *
806          * Unfortunately we can't check for defined(NTFS_MNT_RDONLY) because
807          * NTFS_MNT_RDONLY is an enumerated constant.  Also, the NTFS-3g headers
808          * don't seem to contain any explicit version information.  So we have
809          * to rely on a test done at configure time to detect whether
810          * NTFS_MNT_RDONLY should be used.  */
811 #ifdef HAVE_NTFS_MNT_RDONLY
812         /* NTFS-3g 2013 */
813         vol = ntfs_mount(device, NTFS_MNT_RDONLY);
814 #elif defined(MS_RDONLY)
815         /* NTFS-3g 2011, 2012 */
816         vol = ntfs_mount(device, MS_RDONLY);
817 #else
818   #error "Can't find NTFS_MNT_RDONLY or MS_RDONLY flags"
819 #endif
820         if (!vol) {
821                 ERROR_WITH_ERRNO("Failed to mount NTFS volume \"%s\" read-only",
822                                  device);
823                 FREE(volume);
824                 return WIMLIB_ERR_NTFS_3G;
825         }
826
827         volume->vol = vol;
828         volume->refcnt = 1;
829
830         ntfs_open_secure(vol);
831
832         /* We don't want to capture the special NTFS files such as $Bitmap.  Not
833          * to be confused with "hidden" or "system" files which are real files
834          * that we do need to capture.  */
835         NVolClearShowSysFiles(vol);
836
837         /* Currently we assume that all the paths fit into this length and there
838          * is no check for overflow.  */
839         path = MALLOC(32768);
840         if (!path) {
841                 ret = WIMLIB_ERR_NOMEM;
842                 goto out_put_ntfs_volume;
843         }
844
845         path[0] = '/';
846         path[1] = '\0';
847         ret = ntfs_3g_build_dentry_tree_recursive(root_ret, FILE_root, path, 1,
848                                                   FILE_NAME_POSIX, volume,
849                                                   params);
850         FREE(path);
851 out_put_ntfs_volume:
852         ntfs_index_ctx_put(vol->secure_xsii);
853         ntfs_index_ctx_put(vol->secure_xsdh);
854         ntfs_inode_close(vol->secure_ni);
855         put_ntfs_volume(volume);
856         return ret;
857 }
858 #endif /* WITH_NTFS_3G */