1 /**
2 * ntfs-3g_common.c - Common definitions for ntfs-3g and lowntfs-3g.
3 *
4 * Copyright (c) 2010-2021 Jean-Pierre Andre
5 * Copyright (c) 2010 Erik Larsson
6 *
7 * This program/include file is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as published
9 * by the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program/include file is distributed in the hope that it will be
13 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program (in the main directory of the NTFS-3G
19 * distribution in the file COPYING); if not, write to the Free Software
20 * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #ifdef HAVE_STDLIB_H
28 #include <stdlib.h>
29 #endif
30
31 #ifdef HAVE_DLFCN_H
32 #include <dlfcn.h>
33 #endif
34
35 #ifdef HAVE_STRING_H
36 #include <string.h>
37 #endif
38
39 #ifdef HAVE_LIMITS_H
40 #include <limits.h>
41 #endif
42
43 #ifdef HAVE_ERRNO_H
44 #include <errno.h>
45 #endif
46
47 #include <getopt.h>
48 #include <fuse.h>
49
50 #include "compat.h"
51 #include "inode.h"
52 #include "dir.h"
53 #include "security.h"
54 #include "xattrs.h"
55 #include "reparse.h"
56 #include "plugin.h"
57 #include "ntfs-3g_common.h"
58 #include "realpath.h"
59 #include "misc.h"
60
61 const char xattr_ntfs_3g[] = "ntfs-3g.";
62
63 const char nf_ns_user_prefix[] = "user.";
64 const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
65 const char nf_ns_system_prefix[] = "system.";
66 const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1;
67 const char nf_ns_security_prefix[] = "security.";
68 const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1;
69 const char nf_ns_trusted_prefix[] = "trusted.";
70 const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1;
71
72 static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo";
73
74 static const char def_opts[] = "allow_other,nonempty,";
75
76 /*
77 * Table of recognized options
78 * Their order may be significant
79 * The options invalid in some configuration should still
80 * be present, so that an error can be returned
81 */
82 const struct DEFOPTION optionlist[] = {
83 { "ro", OPT_RO, FLGOPT_APPEND | FLGOPT_BOGUS },
84 { "noatime", OPT_NOATIME, FLGOPT_BOGUS },
85 { "atime", OPT_ATIME, FLGOPT_BOGUS },
86 { "relatime", OPT_RELATIME, FLGOPT_BOGUS },
87 { "delay_mtime", OPT_DMTIME, FLGOPT_DECIMAL | FLGOPT_OPTIONAL },
88 { "rw", OPT_RW, FLGOPT_BOGUS },
89 { "fake_rw", OPT_FAKE_RW, FLGOPT_BOGUS },
90 { "fsname", OPT_FSNAME, FLGOPT_NOSUPPORT },
91 { "no_def_opts", OPT_NO_DEF_OPTS, FLGOPT_BOGUS },
92 { "default_permissions", OPT_DEFAULT_PERMISSIONS, FLGOPT_BOGUS },
93 { "permissions", OPT_PERMISSIONS, FLGOPT_BOGUS },
94 { "acl", OPT_ACL, FLGOPT_BOGUS },
95 { "umask", OPT_UMASK, FLGOPT_OCTAL },
96 { "fmask", OPT_FMASK, FLGOPT_OCTAL },
97 { "dmask", OPT_DMASK, FLGOPT_OCTAL },
98 { "uid", OPT_UID, FLGOPT_DECIMAL },
99 { "gid", OPT_GID, FLGOPT_DECIMAL },
100 { "show_sys_files", OPT_SHOW_SYS_FILES, FLGOPT_BOGUS },
101 { "hide_hid_files", OPT_HIDE_HID_FILES, FLGOPT_BOGUS },
102 { "hide_dot_files", OPT_HIDE_DOT_FILES, FLGOPT_BOGUS },
103 { "ignore_case", OPT_IGNORE_CASE, FLGOPT_BOGUS },
104 { "windows_names", OPT_WINDOWS_NAMES, FLGOPT_BOGUS },
105 { "compression", OPT_COMPRESSION, FLGOPT_BOGUS },
106 { "nocompression", OPT_NOCOMPRESSION, FLGOPT_BOGUS },
107 { "silent", OPT_SILENT, FLGOPT_BOGUS },
108 { "recover", OPT_RECOVER, FLGOPT_BOGUS },
109 { "norecover", OPT_NORECOVER, FLGOPT_BOGUS },
110 { "remove_hiberfile", OPT_REMOVE_HIBERFILE, FLGOPT_BOGUS },
111 { "sync", OPT_SYNC, FLGOPT_BOGUS | FLGOPT_APPEND },
112 { "big_writes", OPT_BIG_WRITES, FLGOPT_BOGUS },
113 { "locale", OPT_LOCALE, FLGOPT_STRING },
114 { "nfconv", OPT_NFCONV, FLGOPT_BOGUS },
115 { "nonfconv", OPT_NONFCONV, FLGOPT_BOGUS },
116 { "streams_interface", OPT_STREAMS_INTERFACE, FLGOPT_STRING },
117 { "user_xattr", OPT_USER_XATTR, FLGOPT_BOGUS },
118 { "noauto", OPT_NOAUTO, FLGOPT_BOGUS },
119 { "debug", OPT_DEBUG, FLGOPT_BOGUS },
120 { "no_detach", OPT_NO_DETACH, FLGOPT_BOGUS },
121 { "remount", OPT_REMOUNT, FLGOPT_BOGUS },
122 { "blksize", OPT_BLKSIZE, FLGOPT_STRING },
123 { "inherit", OPT_INHERIT, FLGOPT_BOGUS },
124 { "addsecurids", OPT_ADDSECURIDS, FLGOPT_BOGUS },
125 { "staticgrps", OPT_STATICGRPS, FLGOPT_BOGUS },
126 { "usermapping", OPT_USERMAPPING, FLGOPT_STRING },
127 { "xattrmapping", OPT_XATTRMAPPING, FLGOPT_STRING },
128 { "efs_raw", OPT_EFS_RAW, FLGOPT_BOGUS },
129 { "posix_nlink", OPT_POSIX_NLINK, FLGOPT_BOGUS },
130 { "special_files", OPT_SPECIAL_FILES, FLGOPT_STRING },
131 { "--help", OPT_HELP, FLGOPT_BOGUS },
132 { "-h", OPT_HELP, FLGOPT_BOGUS },
133 { "--version", OPT_VERSION, FLGOPT_BOGUS },
134 { "-V", OPT_VERSION, FLGOPT_BOGUS },
135 { (const char*)NULL, 0, 0 } /* end marker */
136 } ;
137
138 #define STRAPPEND_MAX_INSIZE 8192
139 #define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
140
ntfs_strappend(char ** dest,const char * append)141 int ntfs_strappend(char **dest, const char *append)
142 {
143 char *p;
144 size_t size_append, size_dest = 0;
145
146 if (!dest)
147 return -1;
148 if (!append)
149 return 0;
150
151 size_append = strlen(append);
152 if (*dest)
153 size_dest = strlen(*dest);
154
155 if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
156 errno = EOVERFLOW;
157 ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
158 return -1;
159 }
160
161 p = (char*)realloc(*dest, size_dest + size_append + 1);
162 if (!p) {
163 ntfs_log_perror("%s: Memory realloction failed", EXEC_NAME);
164 return -1;
165 }
166
167 *dest = p;
168 strcpy(*dest + size_dest, append);
169
170 return 0;
171 }
172
173 /*
174 * Insert an option before ",fsname="
175 * This is for keeping "fsname" as the last option, because on
176 * Solaris device names may contain commas.
177 */
178
ntfs_strinsert(char ** dest,const char * append)179 int ntfs_strinsert(char **dest, const char *append)
180 {
181 char *p, *q;
182 size_t size_append, size_dest = 0;
183
184 if (!dest)
185 return -1;
186 if (!append)
187 return 0;
188
189 size_append = strlen(append);
190 if (*dest)
191 size_dest = strlen(*dest);
192
193 if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
194 errno = EOVERFLOW;
195 ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
196 return -1;
197 }
198
199 p = (char*)malloc(size_dest + size_append + 1);
200 if (!p) {
201 ntfs_log_perror("%s: Memory reallocation failed", EXEC_NAME);
202 return -1;
203 }
204 strcpy(p, *dest);
205 q = strstr(p, ",fsname=");
206 if (q) {
207 strcpy(q, append);
208 q = strstr(*dest, ",fsname=");
209 if (q)
210 strcat(p, q);
211 free(*dest);
212 *dest = p;
213 } else {
214 free(*dest);
215 *dest = p;
216 strcpy(*dest + size_dest, append);
217 }
218 return 0;
219 }
220
bogus_option_value(char * val,const char * s)221 static int bogus_option_value(char *val, const char *s)
222 {
223 if (val) {
224 ntfs_log_error("'%s' option shouldn't have value.\n", s);
225 return -1;
226 }
227 return 0;
228 }
229
missing_option_value(char * val,const char * s)230 static int missing_option_value(char *val, const char *s)
231 {
232 if (!val) {
233 ntfs_log_error("'%s' option should have a value.\n", s);
234 return -1;
235 }
236 return 0;
237 }
238
parse_mount_options(ntfs_fuse_context_t * ctx,const struct ntfs_options * popts,BOOL low_fuse)239 char *parse_mount_options(ntfs_fuse_context_t *ctx,
240 const struct ntfs_options *popts, BOOL low_fuse)
241 {
242 char *options, *s, *opt, *val, *ret = NULL;
243 const char *orig_opts = popts->options;
244 BOOL no_def_opts = FALSE;
245 int default_permissions = 0;
246 int permissions = 0;
247 int acl = 0;
248 int want_permissions = 0;
249 int intarg;
250 const struct DEFOPTION *poptl;
251
252 ctx->secure_flags = 0;
253 #ifdef HAVE_SETXATTR /* extended attributes interface required */
254 ctx->efs_raw = FALSE;
255 #endif /* HAVE_SETXATTR */
256 ctx->compression = DEFAULT_COMPRESSION;
257 options = strdup(orig_opts ? orig_opts : "");
258 if (!options) {
259 ntfs_log_perror("%s: strdup failed", EXEC_NAME);
260 return NULL;
261 }
262
263 s = options;
264 while (s && *s && (val = strsep(&s, ","))) {
265 opt = strsep(&val, "=");
266 poptl = optionlist;
267 while (poptl->name && strcmp(poptl->name,opt))
268 poptl++;
269 if (poptl->name) {
270 if ((poptl->flags & FLGOPT_BOGUS)
271 && bogus_option_value(val, opt))
272 goto err_exit;
273 if ((poptl->flags & FLGOPT_OCTAL)
274 && (!val
275 || !sscanf(val, "%o", &intarg))) {
276 ntfs_log_error("'%s' option needs an octal value\n",
277 opt);
278 goto err_exit;
279 }
280 if (poptl->flags & FLGOPT_DECIMAL) {
281 if ((poptl->flags & FLGOPT_OPTIONAL) && !val)
282 intarg = 0;
283 else
284 if (!val
285 || !sscanf(val, "%i", &intarg)) {
286 ntfs_log_error("'%s' option "
287 "needs a decimal value\n",
288 opt);
289 goto err_exit;
290 }
291 }
292 if ((poptl->flags & FLGOPT_STRING)
293 && missing_option_value(val, opt))
294 goto err_exit;
295
296 switch (poptl->type) {
297 case OPT_RO :
298 case OPT_FAKE_RW :
299 ctx->ro = TRUE;
300 break;
301 case OPT_RW :
302 ctx->rw = TRUE;
303 break;
304 case OPT_NOATIME :
305 ctx->atime = ATIME_DISABLED;
306 break;
307 case OPT_ATIME :
308 ctx->atime = ATIME_ENABLED;
309 break;
310 case OPT_RELATIME :
311 ctx->atime = ATIME_RELATIVE;
312 break;
313 case OPT_DMTIME :
314 if (!intarg)
315 intarg = DEFAULT_DMTIME;
316 ctx->dmtime = intarg*10000000LL;
317 break;
318 case OPT_NO_DEF_OPTS :
319 no_def_opts = TRUE; /* Don't add default options. */
320 ctx->silent = FALSE; /* cancel default silent */
321 break;
322 case OPT_DEFAULT_PERMISSIONS :
323 default_permissions = 1;
324 break;
325 case OPT_PERMISSIONS :
326 permissions = 1;
327 break;
328 #if POSIXACLS
329 case OPT_ACL :
330 acl = 1;
331 break;
332 #endif
333 case OPT_UMASK :
334 ctx->dmask = ctx->fmask = intarg;
335 want_permissions = 1;
336 break;
337 case OPT_FMASK :
338 ctx->fmask = intarg;
339 want_permissions = 1;
340 break;
341 case OPT_DMASK :
342 ctx->dmask = intarg;
343 want_permissions = 1;
344 break;
345 case OPT_UID :
346 ctx->uid = intarg;
347 want_permissions = 1;
348 break;
349 case OPT_GID :
350 ctx->gid = intarg;
351 want_permissions = 1;
352 break;
353 case OPT_SHOW_SYS_FILES :
354 ctx->show_sys_files = TRUE;
355 break;
356 case OPT_HIDE_HID_FILES :
357 ctx->hide_hid_files = TRUE;
358 break;
359 case OPT_HIDE_DOT_FILES :
360 ctx->hide_dot_files = TRUE;
361 break;
362 case OPT_WINDOWS_NAMES :
363 ctx->windows_names = TRUE;
364 break;
365 case OPT_IGNORE_CASE :
366 if (low_fuse)
367 ctx->ignore_case = TRUE;
368 else {
369 ntfs_log_error("'%s' is an unsupported option.\n",
370 poptl->name);
371 goto err_exit;
372 }
373 break;
374 case OPT_COMPRESSION :
375 ctx->compression = TRUE;
376 break;
377 case OPT_NOCOMPRESSION :
378 ctx->compression = FALSE;
379 break;
380 case OPT_SILENT :
381 ctx->silent = TRUE;
382 break;
383 case OPT_RECOVER :
384 ctx->recover = TRUE;
385 break;
386 case OPT_NORECOVER :
387 ctx->recover = FALSE;
388 break;
389 case OPT_REMOVE_HIBERFILE :
390 ctx->hiberfile = TRUE;
391 break;
392 case OPT_SYNC :
393 ctx->sync = TRUE;
394 break;
395 #ifdef FUSE_CAP_BIG_WRITES
396 case OPT_BIG_WRITES :
397 ctx->big_writes = TRUE;
398 break;
399 #endif
400 case OPT_LOCALE :
401 ntfs_set_char_encoding(val);
402 break;
403 #if defined(__APPLE__) || defined(__DARWIN__)
404 #ifdef ENABLE_NFCONV
405 case OPT_NFCONV :
406 if (ntfs_macosx_normalize_filenames(1)) {
407 ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n");
408 goto err_exit;
409 }
410 break;
411 case OPT_NONFCONV :
412 if (ntfs_macosx_normalize_filenames(0)) {
413 ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n");
414 goto err_exit;
415 }
416 break;
417 #endif /* ENABLE_NFCONV */
418 #endif /* defined(__APPLE__) || defined(__DARWIN__) */
419 case OPT_STREAMS_INTERFACE :
420 if (!strcmp(val, "none"))
421 ctx->streams = NF_STREAMS_INTERFACE_NONE;
422 else if (!strcmp(val, "xattr"))
423 ctx->streams = NF_STREAMS_INTERFACE_XATTR;
424 else if (!strcmp(val, "openxattr"))
425 ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR;
426 else if (!low_fuse && !strcmp(val, "windows"))
427 ctx->streams = NF_STREAMS_INTERFACE_WINDOWS;
428 else {
429 ntfs_log_error("Invalid named data streams "
430 "access interface.\n");
431 goto err_exit;
432 }
433 break;
434 case OPT_USER_XATTR :
435 #if defined(__APPLE__) || defined(__DARWIN__)
436 /* macOS builds use non-namespaced extended
437 * attributes by default since it matches the
438 * standard behaviour of macOS filesystems. */
439 ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR;
440 #else
441 ctx->streams = NF_STREAMS_INTERFACE_XATTR;
442 #endif
443 break;
444 case OPT_NOAUTO :
445 /* Don't pass noauto option to fuse. */
446 break;
447 case OPT_DEBUG :
448 ctx->debug = TRUE;
449 ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
450 ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
451 break;
452 case OPT_NO_DETACH :
453 ctx->no_detach = TRUE;
454 break;
455 case OPT_REMOUNT :
456 ntfs_log_error("Remounting is not supported at present."
457 " You have to umount volume and then "
458 "mount it once again.\n");
459 goto err_exit;
460 case OPT_BLKSIZE :
461 ntfs_log_info("WARNING: blksize option is ignored "
462 "because ntfs-3g must calculate it.\n");
463 break;
464 case OPT_INHERIT :
465 /*
466 * do not overwrite inherited permissions
467 * in create()
468 */
469 ctx->inherit = TRUE;
470 break;
471 case OPT_ADDSECURIDS :
472 /*
473 * create security ids for files being read
474 * with an individual security attribute
475 */
476 ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS);
477 break;
478 case OPT_STATICGRPS :
479 /*
480 * use static definition of groups
481 * for file access control
482 */
483 ctx->secure_flags |= (1 << SECURITY_STATICGRPS);
484 break;
485 case OPT_USERMAPPING :
486 ctx->usermap_path = strdup(val);
487 if (!ctx->usermap_path) {
488 ntfs_log_error("no more memory to store "
489 "'usermapping' option.\n");
490 goto err_exit;
491 }
492 break;
493 #ifdef HAVE_SETXATTR /* extended attributes interface required */
494 #ifdef XATTR_MAPPINGS
495 case OPT_XATTRMAPPING :
496 ctx->xattrmap_path = strdup(val);
497 if (!ctx->xattrmap_path) {
498 ntfs_log_error("no more memory to store "
499 "'xattrmapping' option.\n");
500 goto err_exit;
501 }
502 break;
503 #endif /* XATTR_MAPPINGS */
504 case OPT_EFS_RAW :
505 ctx->efs_raw = TRUE;
506 break;
507 #endif /* HAVE_SETXATTR */
508 case OPT_POSIX_NLINK :
509 ctx->posix_nlink = TRUE;
510 break;
511 case OPT_SPECIAL_FILES :
512 if (!strcmp(val, "interix"))
513 ctx->special_files = NTFS_FILES_INTERIX;
514 else if (!strcmp(val, "wsl"))
515 ctx->special_files = NTFS_FILES_WSL;
516 else {
517 ntfs_log_error("Invalid special_files"
518 " mode.\n");
519 goto err_exit;
520 }
521 break;
522 case OPT_FSNAME : /* Filesystem name. */
523 /*
524 * We need this to be able to check whether filesystem
525 * mounted or not.
526 * (falling through to default)
527 */
528 case OPT_HELP : /* Could lead to unclean condition */
529 case OPT_VERSION : /* Could lead to unclean condition */
530 default :
531 ntfs_log_error("'%s' is an unsupported option.\n",
532 poptl->name);
533 goto err_exit;
534 }
535 if ((poptl->flags & FLGOPT_APPEND)
536 && (ntfs_strappend(&ret, poptl->name)
537 || ntfs_strappend(&ret, ",")))
538 goto err_exit;
539 } else { /* Probably FUSE option. */
540 if (ntfs_strappend(&ret, opt))
541 goto err_exit;
542 if (val) {
543 if (ntfs_strappend(&ret, "="))
544 goto err_exit;
545 if (ntfs_strappend(&ret, val))
546 goto err_exit;
547 }
548 if (ntfs_strappend(&ret, ","))
549 goto err_exit;
550 }
551 }
552 if (!no_def_opts && ntfs_strappend(&ret, def_opts))
553 goto err_exit;
554 if ((default_permissions || (permissions && !acl))
555 && ntfs_strappend(&ret, "default_permissions,"))
556 goto err_exit;
557 /* The atime options exclude each other */
558 if (ctx->atime == ATIME_RELATIVE && ntfs_strappend(&ret, "relatime,"))
559 goto err_exit;
560 else if (ctx->atime == ATIME_ENABLED && ntfs_strappend(&ret, "atime,"))
561 goto err_exit;
562 else if (ctx->atime == ATIME_DISABLED && ntfs_strappend(&ret, "noatime,"))
563 goto err_exit;
564
565 if (ntfs_strappend(&ret, "fsname="))
566 goto err_exit;
567 if (ntfs_strappend(&ret, popts->device))
568 goto err_exit;
569 if (permissions && !acl)
570 ctx->secure_flags |= (1 << SECURITY_DEFAULT);
571 if (acl)
572 ctx->secure_flags |= (1 << SECURITY_ACL);
573 if (want_permissions)
574 ctx->secure_flags |= (1 << SECURITY_WANTED);
575 if (ctx->ro) {
576 ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS);
577 ctx->hiberfile = FALSE;
578 ctx->rw = FALSE;
579 }
580 exit:
581 free(options);
582 return ret;
583 err_exit:
584 free(ret);
585 ret = NULL;
586 goto exit;
587 }
588
589 /**
590 * parse_options - Read and validate the programs command line
591 * Read the command line, verify the syntax and parse the options.
592 *
593 * Return: 0 success, -1 error.
594 */
ntfs_parse_options(struct ntfs_options * popts,void (* usage)(void),int argc,char * argv[])595 int ntfs_parse_options(struct ntfs_options *popts, void (*usage)(void),
596 int argc, char *argv[])
597 {
598 int c;
599
600 static const char *sopt = "-o:hnsvV";
601 static const struct option lopt[] = {
602 { "options", required_argument, NULL, 'o' },
603 { "help", no_argument, NULL, 'h' },
604 { "no-mtab", no_argument, NULL, 'n' },
605 { "verbose", no_argument, NULL, 'v' },
606 { "version", no_argument, NULL, 'V' },
607 { NULL, 0, NULL, 0 }
608 };
609
610 opterr = 0; /* We'll handle the errors, thank you. */
611
612 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
613 switch (c) {
614 case 1: /* A non-option argument */
615 if (!popts->device) {
616 popts->device = ntfs_malloc(PATH_MAX + 1);
617 if (!popts->device)
618 return -1;
619
620 /* Canonicalize device name (mtab, etc) */
621 popts->arg_device = optarg;
622 if (!ntfs_realpath_canonicalize(optarg,
623 popts->device)) {
624 ntfs_log_perror("%s: Failed to access "
625 "volume '%s'", EXEC_NAME, optarg);
626 free(popts->device);
627 popts->device = NULL;
628 return -1;
629 }
630 } else if (!popts->mnt_point) {
631 popts->mnt_point = optarg;
632 } else {
633 ntfs_log_error("%s: You must specify exactly one "
634 "device and exactly one mount "
635 "point.\n", EXEC_NAME);
636 return -1;
637 }
638 break;
639 case 'o':
640 if (popts->options)
641 if (ntfs_strappend(&popts->options, ","))
642 return -1;
643 if (ntfs_strappend(&popts->options, optarg))
644 return -1;
645 break;
646 case 'h':
647 usage();
648 exit(9);
649 case 'n':
650 /*
651 * no effect - automount passes it, meaning 'no-mtab'
652 */
653 break;
654 case 's':
655 /*
656 * no effect - automount passes it, meaning sloppy
657 */
658 break;
659 case 'v':
660 /*
661 * We must handle the 'verbose' option even if
662 * we don't use it because mount(8) passes it.
663 */
664 break;
665 case 'V':
666 ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION,
667 FUSE_TYPE, fuse_version());
668 exit(0);
669 default:
670 ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
671 argv[optind - 1]);
672 return -1;
673 }
674 }
675
676 if (!popts->device) {
677 ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
678 return -1;
679 }
680 if (!popts->mnt_point) {
681 ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
682 return -1;
683 }
684
685 return 0;
686 }
687
688 #ifdef HAVE_SETXATTR
689
ntfs_fuse_listxattr_common(ntfs_inode * ni,ntfs_attr_search_ctx * actx,char * list,size_t size,BOOL prefixing)690 int ntfs_fuse_listxattr_common(ntfs_inode *ni, ntfs_attr_search_ctx *actx,
691 char *list, size_t size, BOOL prefixing)
692 {
693 int ret = 0;
694 char *to = list;
695 #ifdef XATTR_MAPPINGS
696 BOOL accepted;
697 const struct XATTRMAPPING *item;
698 #endif /* XATTR_MAPPINGS */
699
700 /* first list the regular user attributes (ADS) */
701 while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
702 0, NULL, 0, actx)) {
703 char *tmp_name = NULL;
704 int tmp_name_len;
705
706 if (!actx->attr->name_length)
707 continue;
708 tmp_name_len = ntfs_ucstombs(
709 (ntfschar *)((u8*)actx->attr +
710 le16_to_cpu(actx->attr->name_offset)),
711 actx->attr->name_length, &tmp_name, 0);
712 if (tmp_name_len < 0) {
713 ret = -errno;
714 goto exit;
715 }
716 /*
717 * When using name spaces, do not return
718 * security, trusted or system attributes
719 * (filtered elsewhere anyway)
720 * otherwise insert "user." prefix
721 */
722 if (prefixing) {
723 if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g))
724 && !strncmp(tmp_name,xattr_ntfs_3g,
725 sizeof(xattr_ntfs_3g)-1))
726 tmp_name_len = 0;
727 else
728 ret += tmp_name_len
729 + nf_ns_user_prefix_len + 1;
730 } else
731 ret += tmp_name_len + 1;
732 if (size && tmp_name_len) {
733 if ((size_t)ret <= size) {
734 if (prefixing) {
735 strcpy(to, nf_ns_user_prefix);
736 to += nf_ns_user_prefix_len;
737 }
738 strncpy(to, tmp_name, tmp_name_len);
739 to += tmp_name_len;
740 *to = 0;
741 to++;
742 } else {
743 free(tmp_name);
744 ret = -ERANGE;
745 goto exit;
746 }
747 }
748 free(tmp_name);
749 }
750 #ifdef XATTR_MAPPINGS
751 /* now append the system attributes mapped to user space */
752 for (item=ni->vol->xattr_mapping; item; item=item->next) {
753 switch (item->xattr) {
754 case XATTR_NTFS_EFSINFO :
755 accepted = ni->vol->efs_raw
756 && (ni->flags & FILE_ATTR_ENCRYPTED);
757 break;
758 case XATTR_NTFS_REPARSE_DATA :
759 accepted = (ni->flags & FILE_ATTR_REPARSE_POINT)
760 != const_cpu_to_le32(0);
761 break;
762 // TODO : we are supposed to only return xattrs which are set
763 // this is more complex for OBJECT_ID and DOS_NAME
764 default : accepted = TRUE;
765 break;
766 }
767 if (accepted) {
768 ret += strlen(item->name) + 1;
769 if (size) {
770 if ((size_t)ret <= size) {
771 strcpy(to, item->name);
772 to += strlen(item->name);
773 *to++ = 0;
774 } else {
775 ret = -ERANGE;
776 goto exit;
777 }
778 }
779 #else /* XATTR_MAPPINGS */
780 /* List efs info xattr for encrypted files */
781 if (ni->vol->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) {
782 ret += sizeof(nf_ns_alt_xattr_efsinfo);
783 if ((size_t)ret <= size) {
784 memcpy(to, nf_ns_alt_xattr_efsinfo,
785 sizeof(nf_ns_alt_xattr_efsinfo));
786 to += sizeof(nf_ns_alt_xattr_efsinfo);
787 #endif /* XATTR_MAPPINGS */
788 }
789 }
790 exit :
791 return (ret);
792 }
793
794 #endif /* HAVE_SETXATTR */
795
796 #ifndef DISABLE_PLUGINS
797
798 int register_reparse_plugin(ntfs_fuse_context_t *ctx, le32 tag,
799 const plugin_operations_t *ops, void *handle)
800 {
801 plugin_list_t *plugin;
802 int res;
803
804 res = -1;
805 plugin = (plugin_list_t*)ntfs_malloc(sizeof(plugin_list_t));
806 if (plugin) {
807 plugin->tag = tag;
808 plugin->ops = ops;
809 plugin->handle = handle;
810 plugin->next = ctx->plugins;
811 ctx->plugins = plugin;
812 res = 0;
813 }
814 return (res);
815 }
816
817 /*
818 * Get the reparse operations associated to an inode
819 *
820 * The plugin able to process the reparse point is dynamically loaded
821 *
822 * When successful, returns the operations vector and the reparse
823 * data if requested,
824 * Otherwise returns NULL, with errno set.
825 */
826
827 const struct plugin_operations *select_reparse_plugin(ntfs_fuse_context_t *ctx,
828 ntfs_inode *ni, REPARSE_POINT **reparse_wanted)
829 {
830 const struct plugin_operations *ops;
831 void *handle;
832 REPARSE_POINT *reparse;
833 le32 tag, seltag;
834 plugin_list_t *plugin;
835 plugin_init_t pinit;
836
837 ops = (struct plugin_operations*)NULL;
838 reparse = ntfs_get_reparse_point(ni);
839 if (reparse) {
840 tag = reparse->reparse_tag;
841 seltag = tag & IO_REPARSE_PLUGIN_SELECT;
842 for (plugin=ctx->plugins; plugin && (plugin->tag != seltag);
843 plugin = plugin->next) { }
844 if (plugin) {
845 ops = plugin->ops;
846 } else {
847 #ifdef PLUGIN_DIR
848 char name[sizeof(PLUGIN_DIR) + 64];
849
850 snprintf(name,sizeof(name), PLUGIN_DIR
851 "/ntfs-plugin-%08lx.so",
852 (long)le32_to_cpu(seltag));
853 #else
854 char name[64];
855
856 snprintf(name,sizeof(name), "ntfs-plugin-%08lx.so",
857 (long)le32_to_cpu(seltag));
858 #endif
859 handle = dlopen(name, RTLD_LAZY);
860 if (handle) {
861 pinit = (plugin_init_t)dlsym(handle, "init");
862 if (pinit) {
863 /* pinit() should set errno if it fails */
864 ops = (*pinit)(tag);
865 if (ops && register_reparse_plugin(ctx,
866 seltag, ops, handle))
867 ops = (struct plugin_operations*)NULL;
868 } else
869 errno = ELIBBAD;
870 if (!ops)
871 dlclose(handle);
872 } else {
873 errno = ELIBACC;
874 if (!(ctx->errors_logged & ERR_PLUGIN)) {
875 ntfs_log_perror(
876 "Could not load plugin %s",
877 name);
878 ntfs_log_error("Hint %s\n",dlerror());
879 }
880 ctx->errors_logged |= ERR_PLUGIN;
881 }
882 }
883 if (ops && reparse_wanted)
884 *reparse_wanted = reparse;
885 else
886 free(reparse);
887 }
888 return (ops);
889 }
890
891 void close_reparse_plugins(ntfs_fuse_context_t *ctx)
892 {
893 while (ctx->plugins) {
894 plugin_list_t *next;
895
896 next = ctx->plugins->next;
897 if (ctx->plugins->handle)
898 dlclose(ctx->plugins->handle);
899 free(ctx->plugins);
900 ctx->plugins = next;
901 }
902 }
903
904 #endif /* DISABLE_PLUGINS */
905
906 #ifdef HAVE_SETXATTR
907
908 /*
909 * Check whether a user xattr is allowed
910 *
911 * The inode must be a plain file or a directory. The only allowed
912 * metadata file is the root directory (useful for MacOSX and hopefully
913 * does not harm Windows).
914 */
915
916 BOOL user_xattrs_allowed(ntfs_fuse_context_t *ctx __attribute__((unused)),
917 ntfs_inode *ni)
918 {
919 u32 dt_type;
920 BOOL res;
921
922 /* Quick return for common cases and root */
923 if (!(ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))
924 || (ni->mft_no == FILE_root))
925 res = TRUE;
926 else {
927 /* Reparse point depends on kind, see plugin */
928 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
929 #ifndef DISABLE_PLUGINS
930 struct stat stbuf;
931 REPARSE_POINT *reparse;
932 const plugin_operations_t *ops;
933
934 res = FALSE; /* default for error cases */
935 ops = select_reparse_plugin(ctx, ni, &reparse);
936 if (ops) {
937 if (ops->getattr
938 && !ops->getattr(ni,reparse,&stbuf)) {
939 res = S_ISREG(stbuf.st_mode)
940 || S_ISDIR(stbuf.st_mode);
941 }
942 free(reparse);
943 }
944 #else /* DISABLE_PLUGINS */
945 res = FALSE; /* mountpoints, symlinks, ... */
946 #endif /* DISABLE_PLUGINS */
947 } else {
948 /* Metadata */
949 if (ni->mft_no < FILE_first_user)
950 res = FALSE;
951 else {
952 /* Interix types */
953 dt_type = ntfs_interix_types(ni);
954 res = (dt_type == NTFS_DT_REG)
955 || (dt_type == NTFS_DT_DIR);
956 }
957 }
958 }
959 return (res);
960 }
961
962 #endif /* HAVE_SETXATTR */
963