blob: 38ccd74274c04d5b232e4a9e5d1b9cbf0967909d [file] [log] [blame]
Steve Kondik2111ad72013-07-07 12:07:44 -07001/**
2 * ntfs-3g_common.c - Common definitions for ntfs-3g and lowntfs-3g.
3 *
Steve Kondik79165c32015-11-09 19:43:00 -08004 * Copyright (c) 2010-2015 Jean-Pierre Andre
Steve Kondik2111ad72013-07-07 12:07:44 -07005 * 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_STRING_H
32#include <string.h>
33#endif
34
35#ifdef HAVE_LIMITS_H
36#include <limits.h>
37#endif
38
39#ifdef HAVE_ERRNO_H
40#include <errno.h>
41#endif
42
43#include <getopt.h>
44#include <fuse.h>
45
46#include "inode.h"
47#include "security.h"
48#include "xattrs.h"
49#include "ntfs-3g_common.h"
50#include "realpath.h"
51#include "misc.h"
52
53const char xattr_ntfs_3g[] = "ntfs-3g.";
54
55const char nf_ns_user_prefix[] = "user.";
56const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
57const char nf_ns_system_prefix[] = "system.";
58const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1;
59const char nf_ns_security_prefix[] = "security.";
60const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1;
61const char nf_ns_trusted_prefix[] = "trusted.";
62const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1;
63
64static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo";
65
66static const char def_opts[] = "allow_other,nonempty,";
67
68 /*
69 * Table of recognized options
70 * Their order may be significant
71 * The options invalid in some configuration should still
72 * be present, so that an error can be returned
73 */
74const struct DEFOPTION optionlist[] = {
75 { "ro", OPT_RO, FLGOPT_APPEND | FLGOPT_BOGUS },
76 { "noatime", OPT_NOATIME, FLGOPT_BOGUS },
77 { "atime", OPT_ATIME, FLGOPT_BOGUS },
78 { "relatime", OPT_RELATIME, FLGOPT_BOGUS },
79 { "delay_mtime", OPT_DMTIME, FLGOPT_DECIMAL | FLGOPT_OPTIONAL },
80 { "fake_rw", OPT_FAKE_RW, FLGOPT_BOGUS },
81 { "fsname", OPT_FSNAME, FLGOPT_NOSUPPORT },
82 { "no_def_opts", OPT_NO_DEF_OPTS, FLGOPT_BOGUS },
83 { "default_permissions", OPT_DEFAULT_PERMISSIONS, FLGOPT_BOGUS },
84 { "permissions", OPT_PERMISSIONS, FLGOPT_BOGUS },
85 { "acl", OPT_ACL, FLGOPT_BOGUS },
86 { "umask", OPT_UMASK, FLGOPT_OCTAL },
87 { "fmask", OPT_FMASK, FLGOPT_OCTAL },
88 { "dmask", OPT_DMASK, FLGOPT_OCTAL },
89 { "uid", OPT_UID, FLGOPT_DECIMAL },
90 { "gid", OPT_GID, FLGOPT_DECIMAL },
91 { "show_sys_files", OPT_SHOW_SYS_FILES, FLGOPT_BOGUS },
92 { "hide_hid_files", OPT_HIDE_HID_FILES, FLGOPT_BOGUS },
93 { "hide_dot_files", OPT_HIDE_DOT_FILES, FLGOPT_BOGUS },
94 { "ignore_case", OPT_IGNORE_CASE, FLGOPT_BOGUS },
95 { "windows_names", OPT_WINDOWS_NAMES, FLGOPT_BOGUS },
96 { "compression", OPT_COMPRESSION, FLGOPT_BOGUS },
97 { "nocompression", OPT_NOCOMPRESSION, FLGOPT_BOGUS },
98 { "silent", OPT_SILENT, FLGOPT_BOGUS },
99 { "recover", OPT_RECOVER, FLGOPT_BOGUS },
100 { "norecover", OPT_NORECOVER, FLGOPT_BOGUS },
101 { "remove_hiberfile", OPT_REMOVE_HIBERFILE, FLGOPT_BOGUS },
102 { "sync", OPT_SYNC, FLGOPT_BOGUS | FLGOPT_APPEND },
103 { "big_writes", OPT_BIG_WRITES, FLGOPT_BOGUS },
104 { "locale", OPT_LOCALE, FLGOPT_STRING },
105 { "nfconv", OPT_NFCONV, FLGOPT_BOGUS },
106 { "nonfconv", OPT_NONFCONV, FLGOPT_BOGUS },
107 { "streams_interface", OPT_STREAMS_INTERFACE, FLGOPT_STRING },
108 { "user_xattr", OPT_USER_XATTR, FLGOPT_BOGUS },
109 { "noauto", OPT_NOAUTO, FLGOPT_BOGUS },
110 { "debug", OPT_DEBUG, FLGOPT_BOGUS },
111 { "no_detach", OPT_NO_DETACH, FLGOPT_BOGUS },
112 { "remount", OPT_REMOUNT, FLGOPT_BOGUS },
113 { "blksize", OPT_BLKSIZE, FLGOPT_STRING },
114 { "inherit", OPT_INHERIT, FLGOPT_BOGUS },
115 { "addsecurids", OPT_ADDSECURIDS, FLGOPT_BOGUS },
116 { "staticgrps", OPT_STATICGRPS, FLGOPT_BOGUS },
117 { "usermapping", OPT_USERMAPPING, FLGOPT_STRING },
118 { "xattrmapping", OPT_XATTRMAPPING, FLGOPT_STRING },
119 { "efs_raw", OPT_EFS_RAW, FLGOPT_BOGUS },
120 { (const char*)NULL, 0, 0 } /* end marker */
121} ;
122
123#define STRAPPEND_MAX_INSIZE 8192
124#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
125
126int ntfs_strappend(char **dest, const char *append)
127{
128 char *p;
129 size_t size_append, size_dest = 0;
130
131 if (!dest)
132 return -1;
133 if (!append)
134 return 0;
135
136 size_append = strlen(append);
137 if (*dest)
138 size_dest = strlen(*dest);
139
140 if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
141 errno = EOVERFLOW;
142 ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
143 return -1;
144 }
145
146 p = (char*)realloc(*dest, size_dest + size_append + 1);
147 if (!p) {
148 ntfs_log_perror("%s: Memory realloction failed", EXEC_NAME);
149 return -1;
150 }
151
152 *dest = p;
153 strcpy(*dest + size_dest, append);
154
155 return 0;
156}
157
158/*
159 * Insert an option before ",fsname="
160 * This is for keeping "fsname" as the last option, because on
161 * Solaris device names may contain commas.
162 */
163
164int ntfs_strinsert(char **dest, const char *append)
165{
166 char *p, *q;
167 size_t size_append, size_dest = 0;
168
169 if (!dest)
170 return -1;
171 if (!append)
172 return 0;
173
174 size_append = strlen(append);
175 if (*dest)
176 size_dest = strlen(*dest);
177
178 if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
179 errno = EOVERFLOW;
180 ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
181 return -1;
182 }
183
184 p = (char*)malloc(size_dest + size_append + 1);
185 if (!p) {
186 ntfs_log_perror("%s: Memory reallocation failed", EXEC_NAME);
187 return -1;
188 }
189 strcpy(p, *dest);
190 q = strstr(p, ",fsname=");
191 if (q) {
192 strcpy(q, append);
193 q = strstr(*dest, ",fsname=");
194 if (q)
195 strcat(p, q);
196 free(*dest);
197 *dest = p;
198 } else {
199 free(*dest);
200 *dest = p;
201 strcpy(*dest + size_dest, append);
202 }
203 return 0;
204}
205
206static int bogus_option_value(char *val, const char *s)
207{
208 if (val) {
209 ntfs_log_error("'%s' option shouldn't have value.\n", s);
210 return -1;
211 }
212 return 0;
213}
214
215static int missing_option_value(char *val, const char *s)
216{
217 if (!val) {
218 ntfs_log_error("'%s' option should have a value.\n", s);
219 return -1;
220 }
221 return 0;
222}
223
224char *parse_mount_options(ntfs_fuse_context_t *ctx,
225 const struct ntfs_options *popts, BOOL low_fuse)
226{
227 char *options, *s, *opt, *val, *ret = NULL;
228 const char *orig_opts = popts->options;
229 BOOL no_def_opts = FALSE;
230 int default_permissions = 0;
231 int permissions = 0;
232 int acl = 0;
233 int want_permissions = 0;
234 int intarg;
235 const struct DEFOPTION *poptl;
236
237 ctx->secure_flags = 0;
238#ifdef HAVE_SETXATTR /* extended attributes interface required */
239 ctx->efs_raw = FALSE;
240#endif /* HAVE_SETXATTR */
241 ctx->compression = DEFAULT_COMPRESSION;
242 options = strdup(orig_opts ? orig_opts : "");
243 if (!options) {
244 ntfs_log_perror("%s: strdup failed", EXEC_NAME);
245 return NULL;
246 }
247
248 s = options;
249 while (s && *s && (val = strsep(&s, ","))) {
250 opt = strsep(&val, "=");
251 poptl = optionlist;
252 while (poptl->name && strcmp(poptl->name,opt))
253 poptl++;
254 if (poptl->name) {
255 if ((poptl->flags & FLGOPT_BOGUS)
256 && bogus_option_value(val, opt))
257 goto err_exit;
258 if ((poptl->flags & FLGOPT_OCTAL)
259 && (!val
260 || !sscanf(val, "%o", &intarg))) {
261 ntfs_log_error("'%s' option needs an octal value\n",
262 opt);
263 goto err_exit;
264 }
265 if (poptl->flags & FLGOPT_DECIMAL) {
266 if ((poptl->flags & FLGOPT_OPTIONAL) && !val)
267 intarg = 0;
268 else
269 if (!val
270 || !sscanf(val, "%i", &intarg)) {
271 ntfs_log_error("'%s' option "
272 "needs a decimal value\n",
273 opt);
274 goto err_exit;
275 }
276 }
277 if ((poptl->flags & FLGOPT_STRING)
278 && missing_option_value(val, opt))
279 goto err_exit;
280
281 switch (poptl->type) {
282 case OPT_RO :
283 case OPT_FAKE_RW :
284 ctx->ro = TRUE;
285 break;
286 case OPT_NOATIME :
287 ctx->atime = ATIME_DISABLED;
288 break;
289 case OPT_ATIME :
290 ctx->atime = ATIME_ENABLED;
291 break;
292 case OPT_RELATIME :
293 ctx->atime = ATIME_RELATIVE;
294 break;
295 case OPT_DMTIME :
296 if (!intarg)
297 intarg = DEFAULT_DMTIME;
298 ctx->dmtime = intarg*10000000LL;
299 break;
300 case OPT_NO_DEF_OPTS :
301 no_def_opts = TRUE; /* Don't add default options. */
302 ctx->silent = FALSE; /* cancel default silent */
303 break;
304 case OPT_DEFAULT_PERMISSIONS :
305 default_permissions = 1;
306 break;
307 case OPT_PERMISSIONS :
308 permissions = 1;
309 break;
310#if POSIXACLS
311 case OPT_ACL :
312 acl = 1;
313 break;
314#endif
315 case OPT_UMASK :
316 ctx->dmask = ctx->fmask = intarg;
317 want_permissions = 1;
318 break;
319 case OPT_FMASK :
320 ctx->fmask = intarg;
321 want_permissions = 1;
322 break;
323 case OPT_DMASK :
324 ctx->dmask = intarg;
325 want_permissions = 1;
326 break;
327 case OPT_UID :
328 ctx->uid = intarg;
329 want_permissions = 1;
330 break;
331 case OPT_GID :
332 ctx->gid = intarg;
333 want_permissions = 1;
334 break;
335 case OPT_SHOW_SYS_FILES :
336 ctx->show_sys_files = TRUE;
337 break;
338 case OPT_HIDE_HID_FILES :
339 ctx->hide_hid_files = TRUE;
340 break;
341 case OPT_HIDE_DOT_FILES :
342 ctx->hide_dot_files = TRUE;
343 break;
344 case OPT_WINDOWS_NAMES :
345 ctx->windows_names = TRUE;
346 break;
347 case OPT_IGNORE_CASE :
348 if (low_fuse)
349 ctx->ignore_case = TRUE;
350 else {
351 ntfs_log_error("'%s' is an unsupported option.\n",
352 poptl->name);
353 goto err_exit;
354 }
355 break;
356 case OPT_COMPRESSION :
357 ctx->compression = TRUE;
358 break;
359 case OPT_NOCOMPRESSION :
360 ctx->compression = FALSE;
361 break;
362 case OPT_SILENT :
363 ctx->silent = TRUE;
364 break;
365 case OPT_RECOVER :
366 ctx->recover = TRUE;
367 break;
368 case OPT_NORECOVER :
369 ctx->recover = FALSE;
370 break;
371 case OPT_REMOVE_HIBERFILE :
372 ctx->hiberfile = TRUE;
373 break;
374 case OPT_SYNC :
375 ctx->sync = TRUE;
376 break;
377#ifdef FUSE_CAP_BIG_WRITES
378 case OPT_BIG_WRITES :
379 ctx->big_writes = TRUE;
380 break;
381#endif
382 case OPT_LOCALE :
383 ntfs_set_char_encoding(val);
384 break;
385#if defined(__APPLE__) || defined(__DARWIN__)
386#ifdef ENABLE_NFCONV
387 case OPT_NFCONV :
388 if (ntfs_macosx_normalize_filenames(1)) {
389 ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n");
390 goto err_exit;
391 }
392 break;
393 case OPT_NONFCONV :
394 if (ntfs_macosx_normalize_filenames(0)) {
395 ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n");
396 goto err_exit;
397 }
398 break;
399#endif /* ENABLE_NFCONV */
400#endif /* defined(__APPLE__) || defined(__DARWIN__) */
401 case OPT_STREAMS_INTERFACE :
402 if (!strcmp(val, "none"))
403 ctx->streams = NF_STREAMS_INTERFACE_NONE;
404 else if (!strcmp(val, "xattr"))
405 ctx->streams = NF_STREAMS_INTERFACE_XATTR;
406 else if (!strcmp(val, "openxattr"))
407 ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR;
408 else if (!low_fuse && !strcmp(val, "windows"))
409 ctx->streams = NF_STREAMS_INTERFACE_WINDOWS;
410 else {
411 ntfs_log_error("Invalid named data streams "
412 "access interface.\n");
413 goto err_exit;
414 }
415 break;
416 case OPT_USER_XATTR :
417 ctx->streams = NF_STREAMS_INTERFACE_XATTR;
418 break;
419 case OPT_NOAUTO :
420 /* Don't pass noauto option to fuse. */
421 break;
422 case OPT_DEBUG :
423 ctx->debug = TRUE;
424 ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
425 ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
426 break;
427 case OPT_NO_DETACH :
428 ctx->no_detach = TRUE;
429 break;
430 case OPT_REMOUNT :
431 ntfs_log_error("Remounting is not supported at present."
432 " You have to umount volume and then "
433 "mount it once again.\n");
434 goto err_exit;
435 case OPT_BLKSIZE :
436 ntfs_log_info("WARNING: blksize option is ignored "
437 "because ntfs-3g must calculate it.\n");
438 break;
439 case OPT_INHERIT :
440 /*
441 * do not overwrite inherited permissions
442 * in create()
443 */
444 ctx->inherit = TRUE;
445 break;
446 case OPT_ADDSECURIDS :
447 /*
448 * create security ids for files being read
449 * with an individual security attribute
450 */
451 ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS);
452 break;
453 case OPT_STATICGRPS :
454 /*
455 * use static definition of groups
456 * for file access control
457 */
458 ctx->secure_flags |= (1 << SECURITY_STATICGRPS);
459 break;
460 case OPT_USERMAPPING :
461 ctx->usermap_path = strdup(val);
462 if (!ctx->usermap_path) {
463 ntfs_log_error("no more memory to store "
464 "'usermapping' option.\n");
465 goto err_exit;
466 }
467 break;
468#ifdef HAVE_SETXATTR /* extended attributes interface required */
469#ifdef XATTR_MAPPINGS
470 case OPT_XATTRMAPPING :
471 ctx->xattrmap_path = strdup(val);
472 if (!ctx->xattrmap_path) {
473 ntfs_log_error("no more memory to store "
474 "'xattrmapping' option.\n");
475 goto err_exit;
476 }
477 break;
478#endif /* XATTR_MAPPINGS */
479 case OPT_EFS_RAW :
480 ctx->efs_raw = TRUE;
481 break;
482#endif /* HAVE_SETXATTR */
483 case OPT_FSNAME : /* Filesystem name. */
484 /*
485 * We need this to be able to check whether filesystem
486 * mounted or not.
487 * (falling through to default)
488 */
489 default :
490 ntfs_log_error("'%s' is an unsupported option.\n",
491 poptl->name);
492 goto err_exit;
493 }
494 if ((poptl->flags & FLGOPT_APPEND)
495 && (ntfs_strappend(&ret, poptl->name)
496 || ntfs_strappend(&ret, ",")))
497 goto err_exit;
498 } else { /* Probably FUSE option. */
499 if (ntfs_strappend(&ret, opt))
500 goto err_exit;
501 if (val) {
502 if (ntfs_strappend(&ret, "="))
503 goto err_exit;
504 if (ntfs_strappend(&ret, val))
505 goto err_exit;
506 }
507 if (ntfs_strappend(&ret, ","))
508 goto err_exit;
509 }
510 }
511 if (!no_def_opts && ntfs_strappend(&ret, def_opts))
512 goto err_exit;
513 if ((default_permissions || (permissions && !acl))
514 && ntfs_strappend(&ret, "default_permissions,"))
515 goto err_exit;
516 /* The atime options exclude each other */
517 if (ctx->atime == ATIME_RELATIVE && ntfs_strappend(&ret, "relatime,"))
518 goto err_exit;
519 else if (ctx->atime == ATIME_ENABLED && ntfs_strappend(&ret, "atime,"))
520 goto err_exit;
521 else if (ctx->atime == ATIME_DISABLED && ntfs_strappend(&ret, "noatime,"))
522 goto err_exit;
523
524 if (ntfs_strappend(&ret, "fsname="))
525 goto err_exit;
526 if (ntfs_strappend(&ret, popts->device))
527 goto err_exit;
528 if (permissions && !acl)
529 ctx->secure_flags |= (1 << SECURITY_DEFAULT);
530 if (acl)
531 ctx->secure_flags |= (1 << SECURITY_ACL);
532 if (want_permissions)
533 ctx->secure_flags |= (1 << SECURITY_WANTED);
Steve Kondik79165c32015-11-09 19:43:00 -0800534 if (ctx->ro) {
Steve Kondik2111ad72013-07-07 12:07:44 -0700535 ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS);
Steve Kondik79165c32015-11-09 19:43:00 -0800536 ctx->hiberfile = FALSE;
537 }
Steve Kondik2111ad72013-07-07 12:07:44 -0700538exit:
539 free(options);
540 return ret;
541err_exit:
542 free(ret);
543 ret = NULL;
544 goto exit;
545}
546
547/**
548 * parse_options - Read and validate the programs command line
549 * Read the command line, verify the syntax and parse the options.
550 *
551 * Return: 0 success, -1 error.
552 */
553int ntfs_parse_options(struct ntfs_options *popts, void (*usage)(void),
554 int argc, char *argv[])
555{
556 int c;
557
Steve Kondik79165c32015-11-09 19:43:00 -0800558 static const char *sopt = "-o:hnsvV";
Steve Kondik2111ad72013-07-07 12:07:44 -0700559 static const struct option lopt[] = {
560 { "options", required_argument, NULL, 'o' },
561 { "help", no_argument, NULL, 'h' },
562 { "no-mtab", no_argument, NULL, 'n' },
563 { "verbose", no_argument, NULL, 'v' },
564 { "version", no_argument, NULL, 'V' },
565 { NULL, 0, NULL, 0 }
566 };
567
568 opterr = 0; /* We'll handle the errors, thank you. */
569
570 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
571 switch (c) {
572 case 1: /* A non-option argument */
573 if (!popts->device) {
574 popts->device = ntfs_malloc(PATH_MAX + 1);
575 if (!popts->device)
576 return -1;
577
578 /* Canonicalize device name (mtab, etc) */
579 popts->arg_device = optarg;
580 if (!ntfs_realpath_canonicalize(optarg,
581 popts->device)) {
582 ntfs_log_perror("%s: Failed to access "
583 "volume '%s'", EXEC_NAME, optarg);
584 free(popts->device);
585 popts->device = NULL;
586 return -1;
587 }
588 } else if (!popts->mnt_point) {
589 popts->mnt_point = optarg;
590 } else {
591 ntfs_log_error("%s: You must specify exactly one "
592 "device and exactly one mount "
593 "point.\n", EXEC_NAME);
594 return -1;
595 }
596 break;
597 case 'o':
598 if (popts->options)
599 if (ntfs_strappend(&popts->options, ","))
600 return -1;
601 if (ntfs_strappend(&popts->options, optarg))
602 return -1;
603 break;
604 case 'h':
605 usage();
606 exit(9);
607 case 'n':
608 /*
609 * no effect - automount passes it, meaning 'no-mtab'
610 */
611 break;
Steve Kondik79165c32015-11-09 19:43:00 -0800612 case 's':
613 /*
614 * no effect - automount passes it, meaning sloppy
615 */
616 break;
Steve Kondik2111ad72013-07-07 12:07:44 -0700617 case 'v':
618 /*
619 * We must handle the 'verbose' option even if
620 * we don't use it because mount(8) passes it.
621 */
622 break;
623 case 'V':
624 ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION,
625 FUSE_TYPE, fuse_version());
626 exit(0);
627 default:
628 ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
629 argv[optind - 1]);
630 return -1;
631 }
632 }
633
634 if (!popts->device) {
635 ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
636 return -1;
637 }
638 if (!popts->mnt_point) {
639 ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
640 return -1;
641 }
642
643 return 0;
644}
645
646#ifdef HAVE_SETXATTR
647
648int ntfs_fuse_listxattr_common(ntfs_inode *ni, ntfs_attr_search_ctx *actx,
649 char *list, size_t size, BOOL prefixing)
650{
651 int ret = 0;
652 char *to = list;
653#ifdef XATTR_MAPPINGS
654 BOOL accepted;
655 const struct XATTRMAPPING *item;
656#endif /* XATTR_MAPPINGS */
657
658 /* first list the regular user attributes (ADS) */
659 while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
660 0, NULL, 0, actx)) {
661 char *tmp_name = NULL;
662 int tmp_name_len;
663
664 if (!actx->attr->name_length)
665 continue;
666 tmp_name_len = ntfs_ucstombs(
667 (ntfschar *)((u8*)actx->attr +
668 le16_to_cpu(actx->attr->name_offset)),
669 actx->attr->name_length, &tmp_name, 0);
670 if (tmp_name_len < 0) {
671 ret = -errno;
672 goto exit;
673 }
674 /*
675 * When using name spaces, do not return
676 * security, trusted or system attributes
677 * (filtered elsewhere anyway)
678 * otherwise insert "user." prefix
679 */
680 if (prefixing) {
681 if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g))
682 && !strncmp(tmp_name,xattr_ntfs_3g,
683 sizeof(xattr_ntfs_3g)-1))
684 tmp_name_len = 0;
685 else
686 ret += tmp_name_len
687 + nf_ns_user_prefix_len + 1;
688 } else
689 ret += tmp_name_len + 1;
690 if (size && tmp_name_len) {
691 if ((size_t)ret <= size) {
692 if (prefixing) {
693 strcpy(to, nf_ns_user_prefix);
694 to += nf_ns_user_prefix_len;
695 }
696 strncpy(to, tmp_name, tmp_name_len);
697 to += tmp_name_len;
698 *to = 0;
699 to++;
700 } else {
701 free(tmp_name);
702 ret = -ERANGE;
703 goto exit;
704 }
705 }
706 free(tmp_name);
707 }
708#ifdef XATTR_MAPPINGS
709 /* now append the system attributes mapped to user space */
710 for (item=ni->vol->xattr_mapping; item; item=item->next) {
711 switch (item->xattr) {
712 case XATTR_NTFS_EFSINFO :
713 accepted = ni->vol->efs_raw
714 && (ni->flags & FILE_ATTR_ENCRYPTED);
715 break;
716 case XATTR_NTFS_REPARSE_DATA :
717 accepted = (ni->flags & FILE_ATTR_REPARSE_POINT)
718 != const_cpu_to_le32(0);
719 break;
720// TODO : we are supposed to only return xattrs which are set
721// this is more complex for OBJECT_ID and DOS_NAME
722 default : accepted = TRUE;
723 break;
724 }
725 if (accepted) {
726 ret += strlen(item->name) + 1;
727 if (size) {
728 if ((size_t)ret <= size) {
729 strcpy(to, item->name);
730 to += strlen(item->name);
731 *to++ = 0;
732 } else {
733 ret = -ERANGE;
734 goto exit;
735 }
736 }
737#else /* XATTR_MAPPINGS */
738 /* List efs info xattr for encrypted files */
739 if (ni->vol->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) {
740 ret += sizeof(nf_ns_alt_xattr_efsinfo);
741 if ((size_t)ret <= size) {
742 memcpy(to, nf_ns_alt_xattr_efsinfo,
743 sizeof(nf_ns_alt_xattr_efsinfo));
744 to += sizeof(nf_ns_alt_xattr_efsinfo);
745#endif /* XATTR_MAPPINGS */
746 }
747 }
748exit :
749 return (ret);
750}
751
752#endif /* HAVE_SETXATTR */