ntfs-3g ver. 2009.11.14
[tomato.git] / release / src / router / ntfs-3g / src / ntfs-3g.c
blob2ec127aaa583a4e6a301160e3a50e21f4d67cce1
1 /**
2 * ntfs-3g - Third Generation NTFS Driver
4 * Copyright (c) 2005-2007 Yura Pakhuchiy
5 * Copyright (c) 2005 Yuval Fledel
6 * Copyright (c) 2006-2009 Szabolcs Szakacsits
7 * Copyright (c) 2007-2009 Jean-Pierre Andre
8 * Copyright (c) 2009 Erik Larsson
10 * This file is originated from the Linux-NTFS project.
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program (in the main directory of the NTFS-3G
24 * distribution in the file COPYING); if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 #include "config.h"
30 #include <fuse.h>
32 #if !defined(FUSE_VERSION) || (FUSE_VERSION < 26)
33 #error "***********************************************************"
34 #error "* *"
35 #error "* Compilation requires at least FUSE version 2.6.0! *"
36 #error "* *"
37 #error "***********************************************************"
38 #endif
40 #ifdef FUSE_INTERNAL
41 #define FUSE_TYPE "integrated FUSE"
42 #else
43 #define FUSE_TYPE "external FUSE"
44 #endif
46 #ifdef HAVE_STDIO_H
47 #include <stdio.h>
48 #endif
49 #ifdef HAVE_STRING_H
50 #include <string.h>
51 #endif
52 #ifdef HAVE_ERRNO_H
53 #include <errno.h>
54 #endif
55 #ifdef HAVE_FCNTL_H
56 #include <fcntl.h>
57 #endif
58 #ifdef HAVE_UNISTD_H
59 #include <unistd.h>
60 #endif
61 #ifdef HAVE_STDLIB_H
62 #include <stdlib.h>
63 #endif
64 #ifdef HAVE_LOCALE_H
65 #include <locale.h>
66 #endif
67 #include <signal.h>
68 #ifdef HAVE_LIMITS_H
69 #include <limits.h>
70 #endif
71 #include <getopt.h>
72 #include <syslog.h>
73 #include <sys/wait.h>
75 #ifdef HAVE_SETXATTR
76 #include <sys/xattr.h>
77 #endif
79 #ifdef HAVE_SYS_TYPES_H
80 #include <sys/types.h>
81 #endif
82 #ifdef HAVE_SYS_MKDEV_H
83 #include <sys/mkdev.h>
84 #endif
86 #if defined(__APPLE__) || defined(__DARWIN__)
87 #include <sys/dirent.h>
88 #endif /* defined(__APPLE__) || defined(__DARWIN__) */
90 #include "compat.h"
91 #include "attrib.h"
92 #include "inode.h"
93 #include "volume.h"
94 #include "dir.h"
95 #include "unistr.h"
96 #include "layout.h"
97 #include "index.h"
98 #include "ntfstime.h"
99 #include "security.h"
100 #include "reparse.h"
101 #include "efs.h"
102 #include "logging.h"
103 #include "misc.h"
105 #define set_archive(ni) (ni)->flags |= FILE_ATTR_ARCHIVE
107 typedef enum {
108 FSTYPE_NONE,
109 FSTYPE_UNKNOWN,
110 FSTYPE_FUSE,
111 FSTYPE_FUSEBLK
112 } fuse_fstype;
114 typedef enum {
115 ATIME_ENABLED,
116 ATIME_DISABLED,
117 ATIME_RELATIVE
118 } ntfs_atime_t;
120 typedef struct {
121 fuse_fill_dir_t filler;
122 void *buf;
123 } ntfs_fuse_fill_context_t;
125 typedef enum {
126 NF_STREAMS_INTERFACE_NONE, /* No access to named data streams. */
127 NF_STREAMS_INTERFACE_XATTR, /* Map named data streams to xattrs. */
128 NF_STREAMS_INTERFACE_OPENXATTR, /* Same, not limited to "user." */
129 NF_STREAMS_INTERFACE_WINDOWS, /* "file:stream" interface. */
130 } ntfs_fuse_streams_interface;
132 enum {
133 CLOSE_COMPRESSED = 1,
134 CLOSE_ENCRYPTED = 2
137 typedef struct {
138 ntfs_volume *vol;
139 unsigned int uid;
140 unsigned int gid;
141 unsigned int fmask;
142 unsigned int dmask;
143 ntfs_fuse_streams_interface streams;
144 ntfs_atime_t atime;
145 BOOL ro;
146 BOOL show_sys_files;
147 BOOL silent;
148 BOOL recover;
149 BOOL hiberfile;
150 BOOL debug;
151 BOOL no_detach;
152 BOOL blkdev;
153 BOOL mounted;
154 BOOL efs_raw;
155 struct fuse_chan *fc;
156 BOOL inherit;
157 unsigned int secure_flags;
158 char *usermap_path;
159 struct PERMISSIONS_CACHE *seccache;
160 struct SECURITY_CONTEXT security;
161 } ntfs_fuse_context_t;
163 static struct options {
164 char *mnt_point; /* Mount point */
165 char *options; /* Mount options */
166 char *device; /* Device to mount */
167 } opts;
169 static const char *EXEC_NAME = "ntfs-3g";
170 static char def_opts[] = "silent,allow_other,nonempty,";
171 static ntfs_fuse_context_t *ctx;
172 static u32 ntfs_sequence;
174 static const char *usage_msg =
175 "\n"
176 "%s %s %s %d - Third Generation NTFS Driver\n"
177 "\t\t"
178 #ifdef HAVE_SETXATTR
179 "XATTRS are on, "
180 #else
181 "XATTRS are off, "
182 #endif
183 #if POSIXACLS
184 "POSIX ACLS are on\n"
185 #else
186 "POSIX ACLS are off\n"
187 #endif
188 "\n"
189 "Copyright (C) 2005-2007 Yura Pakhuchiy\n"
190 "Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
191 "Copyright (C) 2007-2009 Jean-Pierre Andre\n"
192 "Copyright (C) 2009 Erik Larsson\n"
193 "\n"
194 "Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n"
195 "\n"
196 "Options: ro (read-only mount), remove_hiberfile, uid=, gid=,\n"
197 " umask=, fmask=, dmask=, streams_interface=.\n"
198 " Please see the details in the manual (type: man ntfs-3g).\n"
199 "\n"
200 "Example: ntfs-3g /dev/sda1 /mnt/windows\n"
201 "\n"
202 "%s";
204 static const char ntfs_bad_reparse[] = "unsupported reparse point";
206 #ifdef FUSE_INTERNAL
207 int drop_privs(void);
208 int restore_privs(void);
209 #else
211 * setuid and setgid root ntfs-3g denies to start with external FUSE,
212 * therefore the below functions are no-op in such case.
214 static int drop_privs(void) { return 0; }
215 static int restore_privs(void) { return 0; }
217 static const char *setuid_msg =
218 "Mount is denied because setuid and setgid root ntfs-3g is insecure with the\n"
219 "external FUSE library. Either remove the setuid/setgid bit from the binary\n"
220 "or rebuild NTFS-3G with integrated FUSE support and make it setuid root.\n"
221 "Please see more information at http://ntfs-3g.org/support.html#unprivileged\n";
223 static const char *unpriv_fuseblk_msg =
224 "Unprivileged user can not mount NTFS block devices using the external FUSE\n"
225 "library. Either mount the volume as root, or rebuild NTFS-3G with integrated\n"
226 "FUSE support and make it setuid root. Please see more information at\n"
227 "http://ntfs-3g.org/support.html#unprivileged\n";
228 #endif
232 * ntfs_fuse_is_named_data_stream - check path to be to named data stream
233 * @path: path to check
235 * Returns 1 if path is to named data stream or 0 otherwise.
237 static int ntfs_fuse_is_named_data_stream(const char *path)
239 if (strchr(path, ':') && ctx->streams == NF_STREAMS_INTERFACE_WINDOWS)
240 return 1;
241 return 0;
244 static void ntfs_fuse_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
246 if (ctx->atime == ATIME_DISABLED)
247 mask &= ~NTFS_UPDATE_ATIME;
248 else if (ctx->atime == ATIME_RELATIVE && mask == NTFS_UPDATE_ATIME &&
249 ni->last_access_time >= ni->last_data_change_time &&
250 ni->last_access_time >= ni->last_mft_change_time)
251 return;
252 ntfs_inode_update_times(ni, mask);
255 static s64 ntfs_get_nr_free_mft_records(ntfs_volume *vol)
257 ntfs_attr *na = vol->mftbmp_na;
258 s64 nr_free = ntfs_attr_get_free_bits(na);
260 if (nr_free >= 0)
261 nr_free += (na->allocated_size - na->data_size) << 3;
262 return nr_free;
266 * Fill a security context as needed by security functions
267 * returns TRUE if there is a user mapping,
268 * FALSE if there is none
269 * This is not an error and the context is filled anyway,
270 * it is used for implicit Windows-like inheritance
273 static BOOL ntfs_fuse_fill_security_context(struct SECURITY_CONTEXT *scx)
275 struct fuse_context *fusecontext;
277 scx->vol = ctx->vol;
278 scx->mapping[MAPUSERS] = ctx->security.mapping[MAPUSERS];
279 scx->mapping[MAPGROUPS] = ctx->security.mapping[MAPGROUPS];
280 scx->pseccache = &ctx->seccache;
281 fusecontext = fuse_get_context();
282 scx->uid = fusecontext->uid;
283 scx->gid = fusecontext->gid;
284 scx->tid = fusecontext->pid;
285 #ifdef FUSE_CAP_DONT_MASK
286 /* the umask can be processed by the file system */
287 scx->umask = fusecontext->umask;
288 #else
289 /* the umask if forced by fuse on creation */
290 scx->umask = 0;
291 #endif
293 return (ctx->security.mapping[MAPUSERS] != (struct MAPPING*)NULL);
297 * ntfs_fuse_statfs - return information about mounted NTFS volume
298 * @path: ignored (but fuse requires it)
299 * @sfs: statfs structure in which to return the information
301 * Return information about the mounted NTFS volume @sb in the statfs structure
302 * pointed to by @sfs (this is initialized with zeros before ntfs_statfs is
303 * called). We interpret the values to be correct of the moment in time at
304 * which we are called. Most values are variable otherwise and this isn't just
305 * the free values but the totals as well. For example we can increase the
306 * total number of file nodes if we run out and we can keep doing this until
307 * there is no more space on the volume left at all.
309 * This code based on ntfs_statfs from ntfs kernel driver.
311 * Returns 0 on success or -errno on error.
313 static int ntfs_fuse_statfs(const char *path __attribute__((unused)),
314 struct statvfs *sfs)
316 s64 size;
317 int delta_bits;
318 ntfs_volume *vol;
320 vol = ctx->vol;
321 if (!vol)
322 return -ENODEV;
325 * File system block size. Used to calculate used/free space by df.
326 * Incorrectly documented as "optimal transfer block size".
328 sfs->f_bsize = vol->cluster_size;
330 /* Fundamental file system block size, used as the unit. */
331 sfs->f_frsize = vol->cluster_size;
334 * Total number of blocks on file system in units of f_frsize.
335 * Since inodes are also stored in blocks ($MFT is a file) hence
336 * this is the number of clusters on the volume.
338 sfs->f_blocks = vol->nr_clusters;
340 /* Free blocks available for all and for non-privileged processes. */
341 size = vol->free_clusters;
342 if (size < 0)
343 size = 0;
344 sfs->f_bavail = sfs->f_bfree = size;
346 /* Free inodes on the free space */
347 delta_bits = vol->cluster_size_bits - vol->mft_record_size_bits;
348 if (delta_bits >= 0)
349 size <<= delta_bits;
350 else
351 size >>= -delta_bits;
353 /* Number of inodes at this point in time. */
354 sfs->f_files = (vol->mftbmp_na->allocated_size << 3) + size;
356 /* Free inodes available for all and for non-privileged processes. */
357 size += vol->free_mft_records;
358 if (size < 0)
359 size = 0;
360 sfs->f_ffree = sfs->f_favail = size;
362 /* Maximum length of filenames. */
363 sfs->f_namemax = NTFS_MAX_NAME_LEN;
364 return 0;
368 * ntfs_fuse_parse_path - split path to path and stream name.
369 * @org_path: path to split
370 * @path: pointer to buffer in which parsed path saved
371 * @stream_name: pointer to buffer where stream name in unicode saved
373 * This function allocates buffers for @*path and @*stream, user must free them
374 * after use.
376 * Return values:
377 * <0 Error occurred, return -errno;
378 * 0 No stream name, @*stream is not allocated and set to AT_UNNAMED.
379 * >0 Stream name length in unicode characters.
381 static int ntfs_fuse_parse_path(const char *org_path, char **path,
382 ntfschar **stream_name)
384 char *stream_name_mbs;
385 int res;
387 stream_name_mbs = strdup(org_path);
388 if (!stream_name_mbs)
389 return -errno;
390 if (ctx->streams == NF_STREAMS_INTERFACE_WINDOWS) {
391 *path = strsep(&stream_name_mbs, ":");
392 if (stream_name_mbs) {
393 *stream_name = NULL;
394 res = ntfs_mbstoucs(stream_name_mbs, stream_name);
395 if (res < 0)
396 return -errno;
397 return res;
399 } else
400 *path = stream_name_mbs;
401 *stream_name = AT_UNNAMED;
402 return 0;
405 static void set_fuse_error(int *err)
407 if (!*err)
408 *err = -errno;
411 #if defined(__APPLE__) || defined(__DARWIN__)
412 static void *ntfs_macfuse_init(struct fuse_conn_info *conn)
414 FUSE_ENABLE_XTIMES(conn);
415 return NULL;
418 static int ntfs_macfuse_getxtimes(const char *org_path,
419 struct timespec *bkuptime, struct timespec *crtime)
421 int res = 0;
422 ntfs_inode *ni;
423 char *path = NULL;
424 ntfschar *stream_name;
425 int stream_name_len;
427 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
428 if (stream_name_len < 0)
429 return stream_name_len;
430 memset(bkuptime, 0, sizeof(struct timespec));
431 memset(crtime, 0, sizeof(struct timespec));
432 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
433 if (!ni) {
434 res = -errno;
435 goto exit;
438 /* We have no backup timestamp in NTFS. */
439 crtime->tv_sec = ni->creation_time;
440 exit:
441 if (ntfs_inode_close(ni))
442 set_fuse_error(&res);
443 free(path);
444 if (stream_name_len)
445 free(stream_name);
446 return res;
449 int ntfs_macfuse_setcrtime(const char *path, const struct timespec *tv)
451 ntfs_inode *ni;
452 int res = 0;
454 if (ntfs_fuse_is_named_data_stream(path))
455 return -EINVAL; /* n/a for named data streams. */
456 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
457 if (!ni)
458 return -errno;
460 if (tv) {
461 ni->creation_time = tv->tv_sec;
462 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
465 if (ntfs_inode_close(ni))
466 set_fuse_error(&res);
467 return res;
470 int ntfs_macfuse_setbkuptime(const char *path, const struct timespec *tv)
472 ntfs_inode *ni;
473 int res = 0;
475 if (ntfs_fuse_is_named_data_stream(path))
476 return -EINVAL; /* n/a for named data streams. */
477 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
478 if (!ni)
479 return -errno;
482 * Only pretending to set backup time successfully to please the APIs of
483 * Mac OS X. In reality, NTFS has no backup time.
486 if (ntfs_inode_close(ni))
487 set_fuse_error(&res);
488 return res;
491 int ntfs_macfuse_setchgtime(const char *path, const struct timespec *tv)
493 ntfs_inode *ni;
494 int res = 0;
496 if (ntfs_fuse_is_named_data_stream(path))
497 return -EINVAL; /* n/a for named data streams. */
498 ni = ntfs_pathname_to_inode(ctx-&gt;vol, NULL, path);
499 if (!ni)
500 return -errno;
502 if (tv) {
503 ni-&gt;last_mft_change_time = tv-&gt;tv_sec;
504 ntfs_fuse_update_times(ni, 0);
507 if (ntfs_inode_close(ni))
508 set_fuse_error(&amp;res);
509 return res;
511 #else /* defined(__APPLE__) || defined(__DARWIN__) */
512 #ifdef FUSE_CAP_DONT_MASK
513 static void *ntfs_init(struct fuse_conn_info *conn)
515 /* request umask not to be enforced by fuse */
516 conn->want |= FUSE_CAP_DONT_MASK;
517 return NULL;
519 #endif
520 #endif /* defined(__APPLE__) || defined(__DARWIN__) */
522 static int ntfs_fuse_getattr(const char *org_path, struct stat *stbuf)
524 int res = 0;
525 ntfs_inode *ni;
526 ntfs_attr *na;
527 char *path = NULL;
528 ntfschar *stream_name;
529 int stream_name_len;
530 BOOL withusermapping;
531 struct SECURITY_CONTEXT security;
533 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
534 if (stream_name_len < 0)
535 return stream_name_len;
536 memset(stbuf, 0, sizeof(struct stat));
537 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
538 if (!ni) {
539 res = -errno;
540 goto exit;
542 withusermapping = ntfs_fuse_fill_security_context(&security);
543 #if POSIXACLS
545 * make sure the parent directory is searchable
547 if (withusermapping
548 && !ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
549 res = -EACCES;
550 goto exit;
552 #endif
553 if (((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
554 || (ni->flags & FILE_ATTR_REPARSE_POINT))
555 && !stream_name_len) {
556 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
557 char *target;
558 int attr_size;
560 errno = 0;
561 target = ntfs_make_symlink(org_path, ni, &attr_size);
563 * If the reparse point is not a valid
564 * directory junction, and there is no error
565 * we still display as a symlink
567 if (target || (errno == EOPNOTSUPP)) {
568 /* returning attribute size */
569 if (target)
570 stbuf->st_size = attr_size;
571 else
572 stbuf->st_size = sizeof(ntfs_bad_reparse);
573 stbuf->st_blocks = (ni->allocated_size + 511) >> 9;
574 stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
575 stbuf->st_mode = S_IFLNK;
576 free(target);
577 } else {
578 res = -errno;
579 goto exit;
581 } else {
582 /* Directory. */
583 stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask);
584 na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION, NTFS_INDEX_I30, 4);
585 if (na) {
586 stbuf->st_size = na->data_size;
587 stbuf->st_blocks = na->allocated_size >> 9;
588 ntfs_attr_close(na);
590 stbuf->st_nlink = 1; /* Make find(1) work */
592 } else {
593 /* Regular or Interix (INTX) file. */
594 stbuf->st_mode = S_IFREG;
595 stbuf->st_size = ni->data_size;
597 * return data size rounded to next 512 byte boundary for
598 * encrypted files to include padding required for decryption
599 * also include 2 bytes for padding info
601 if (ctx->efs_raw && ni->flags & FILE_ATTR_ENCRYPTED)
602 stbuf->st_size = ((ni->data_size + 511) & ~511) + 2;
605 * Temporary fix to make ActiveSync work via Samba 3.0.
606 * See more on the ntfs-3g-devel list.
608 stbuf->st_blocks = (ni->allocated_size + 511) >> 9;
609 stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
610 if (ni->flags & FILE_ATTR_SYSTEM || stream_name_len) {
611 na = ntfs_attr_open(ni, AT_DATA, stream_name,
612 stream_name_len);
613 if (!na) {
614 if (stream_name_len)
615 res = -ENOENT;
616 goto exit;
618 if (stream_name_len) {
619 stbuf->st_size = na->data_size;
620 stbuf->st_blocks = na->allocated_size >> 9;
622 /* Check whether it's Interix FIFO or socket. */
623 if (!(ni->flags & FILE_ATTR_HIDDEN) &&
624 !stream_name_len) {
625 /* FIFO. */
626 if (na->data_size == 0)
627 stbuf->st_mode = S_IFIFO;
628 /* Socket link. */
629 if (na->data_size == 1)
630 stbuf->st_mode = S_IFSOCK;
632 /* encrypted named stream */
633 /* round size up to next 512 byte boundary */
634 if (ctx->efs_raw && stream_name_len &&
635 (na->data_flags & ATTR_IS_ENCRYPTED) &&
636 NAttrNonResident(na))
637 stbuf->st_size = ((na->data_size+511) & ~511)+2;
639 * Check whether it's Interix symbolic link, block or
640 * character device.
642 if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)
643 + sizeof(ntfschar) * PATH_MAX
644 && (size_t)na->data_size >
645 sizeof(INTX_FILE_TYPES)
646 && !stream_name_len) {
648 INTX_FILE *intx_file;
650 intx_file = ntfs_malloc(na->data_size);
651 if (!intx_file) {
652 res = -errno;
653 ntfs_attr_close(na);
654 goto exit;
656 if (ntfs_attr_pread(na, 0, na->data_size,
657 intx_file) != na->data_size) {
658 res = -errno;
659 free(intx_file);
660 ntfs_attr_close(na);
661 goto exit;
663 if (intx_file->magic == INTX_BLOCK_DEVICE &&
664 na->data_size == offsetof(
665 INTX_FILE, device_end)) {
666 stbuf->st_mode = S_IFBLK;
667 stbuf->st_rdev = makedev(le64_to_cpu(
668 intx_file->major),
669 le64_to_cpu(
670 intx_file->minor));
672 if (intx_file->magic == INTX_CHARACTER_DEVICE &&
673 na->data_size == offsetof(
674 INTX_FILE, device_end)) {
675 stbuf->st_mode = S_IFCHR;
676 stbuf->st_rdev = makedev(le64_to_cpu(
677 intx_file->major),
678 le64_to_cpu(
679 intx_file->minor));
681 if (intx_file->magic == INTX_SYMBOLIC_LINK)
682 stbuf->st_mode = S_IFLNK;
683 free(intx_file);
685 ntfs_attr_close(na);
687 stbuf->st_mode |= (0777 & ~ctx->fmask);
689 if (withusermapping) {
690 if (ntfs_get_owner_mode(&security,path,ni,stbuf) < 0)
691 set_fuse_error(&res);
692 } else {
693 stbuf->st_uid = ctx->uid;
694 stbuf->st_gid = ctx->gid;
696 if (S_ISLNK(stbuf->st_mode))
697 stbuf->st_mode |= 0777;
698 stbuf->st_ino = ni->mft_no;
699 stbuf->st_atime = ni->last_access_time;
700 stbuf->st_ctime = ni->last_mft_change_time;
701 stbuf->st_mtime = ni->last_data_change_time;
702 exit:
703 if (ntfs_inode_close(ni))
704 set_fuse_error(&res);
705 free(path);
706 if (stream_name_len)
707 free(stream_name);
708 return res;
711 static int ntfs_fuse_readlink(const char *org_path, char *buf, size_t buf_size)
713 char *path;
714 ntfschar *stream_name;
715 ntfs_inode *ni = NULL;
716 ntfs_attr *na = NULL;
717 INTX_FILE *intx_file = NULL;
718 int stream_name_len, res = 0;
720 /* Get inode. */
721 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
722 if (stream_name_len < 0)
723 return stream_name_len;
724 if (stream_name_len > 0) {
725 res = -EINVAL;
726 goto exit;
728 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
729 if (!ni) {
730 res = -errno;
731 goto exit;
734 * Reparse point : analyze as a junction point
736 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
737 char *target;
738 int attr_size;
740 errno = 0;
741 res = 0;
742 target = ntfs_make_symlink(org_path, ni, &attr_size);
743 if (target) {
744 strncpy(buf,target,buf_size);
745 free(target);
746 } else
747 if (errno == EOPNOTSUPP)
748 strcpy(buf,ntfs_bad_reparse);
749 else
750 res = -errno;
751 goto exit;
753 /* Sanity checks. */
754 if (!(ni->flags & FILE_ATTR_SYSTEM)) {
755 res = -EINVAL;
756 goto exit;
758 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
759 if (!na) {
760 res = -errno;
761 goto exit;
763 if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)) {
764 res = -EINVAL;
765 goto exit;
767 if ((size_t)na->data_size > sizeof(INTX_FILE_TYPES) +
768 sizeof(ntfschar) * PATH_MAX) {
769 res = -ENAMETOOLONG;
770 goto exit;
772 /* Receive file content. */
773 intx_file = ntfs_malloc(na->data_size);
774 if (!intx_file) {
775 res = -errno;
776 goto exit;
778 if (ntfs_attr_pread(na, 0, na->data_size, intx_file) != na->data_size) {
779 res = -errno;
780 goto exit;
782 /* Sanity check. */
783 if (intx_file->magic != INTX_SYMBOLIC_LINK) {
784 res = -EINVAL;
785 goto exit;
787 /* Convert link from unicode to local encoding. */
788 if (ntfs_ucstombs(intx_file->target, (na->data_size -
789 offsetof(INTX_FILE, target)) / sizeof(ntfschar),
790 &buf, buf_size) < 0) {
791 res = -errno;
792 goto exit;
794 exit:
795 if (intx_file)
796 free(intx_file);
797 if (na)
798 ntfs_attr_close(na);
799 if (ntfs_inode_close(ni))
800 set_fuse_error(&res);
801 free(path);
802 if (stream_name_len)
803 free(stream_name);
804 return res;
807 static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx,
808 const ntfschar *name, const int name_len, const int name_type,
809 const s64 pos __attribute__((unused)), const MFT_REF mref,
810 const unsigned dt_type __attribute__((unused)))
812 char *filename = NULL;
813 int ret = 0;
814 int filenamelen = -1;
816 if (name_type == FILE_NAME_DOS)
817 return 0;
819 if ((filenamelen = ntfs_ucstombs(name, name_len, &filename, 0)) < 0) {
820 ntfs_log_perror("Filename decoding failed (inode %llu)",
821 (unsigned long long)MREF(mref));
822 return -1;
825 if (ntfs_fuse_is_named_data_stream(filename)) {
826 ntfs_log_error("Unable to access '%s' (inode %llu) with "
827 "current named streams access interface.\n",
828 filename, (unsigned long long)MREF(mref));
829 free(filename);
830 return 0;
833 if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user ||
834 ctx->show_sys_files) {
835 struct stat st = { .st_ino = MREF(mref) };
837 if (dt_type == NTFS_DT_REG)
838 st.st_mode = S_IFREG | (0777 & ~ctx->fmask);
839 else if (dt_type == NTFS_DT_DIR)
840 st.st_mode = S_IFDIR | (0777 & ~ctx->dmask);
842 #if defined(__APPLE__) || defined(__DARWIN__)
844 * Returning file names larger than MAXNAMLEN (255) bytes
845 * causes Darwin/Mac OS X to bug out and skip the entry.
847 if (filenamelen > MAXNAMLEN) {
848 ntfs_log_debug("Truncating %d byte filename to "
849 "%d bytes.\n", filenamelen, MAXNAMLEN);
850 ntfs_log_debug(" before: '%s'\n", filename);
851 memset(filename + MAXNAMLEN, 0, filenamelen - MAXNAMLEN);
852 ntfs_log_debug(" after: '%s'\n", filename);
854 #endif /* defined(__APPLE__) || defined(__DARWIN__) */
856 ret = fill_ctx->filler(fill_ctx->buf, filename, &st, 0);
859 free(filename);
860 return ret;
863 #if POSIXACLS
865 static int ntfs_fuse_opendir(const char *path,
866 struct fuse_file_info *fi)
868 int res = 0;
869 ntfs_inode *ni;
870 int accesstype;
871 struct SECURITY_CONTEXT security;
873 if (ntfs_fuse_is_named_data_stream(path))
874 return -EINVAL; /* n/a for named data streams. */
876 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
877 if (ni) {
878 if (ntfs_fuse_fill_security_context(&security)) {
879 if (fi->flags & O_WRONLY)
880 accesstype = S_IWRITE;
881 else
882 if (fi->flags & O_RDWR)
883 accesstype = S_IWRITE | S_IREAD;
884 else
885 accesstype = S_IREAD;
886 /* directory must be searchable */
887 if (!ntfs_allowed_dir_access(&security,path,S_IEXEC)
888 /* check whether requested access is allowed */
889 || !ntfs_allowed_access(&security,path,ni,accesstype))
890 res = -EACCES;
892 if (ntfs_inode_close(ni))
893 set_fuse_error(&res);
894 } else
895 res = -errno;
896 return res;
899 #endif
901 static int ntfs_fuse_readdir(const char *path, void *buf,
902 fuse_fill_dir_t filler, off_t offset __attribute__((unused)),
903 struct fuse_file_info *fi __attribute__((unused)))
905 ntfs_fuse_fill_context_t fill_ctx;
906 ntfs_inode *ni;
907 s64 pos = 0;
908 int err = 0;
910 fill_ctx.filler = filler;
911 fill_ctx.buf = buf;
912 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
913 if (!ni)
914 return -errno;
915 if (ntfs_readdir(ni, &pos, &fill_ctx,
916 (ntfs_filldir_t)ntfs_fuse_filler))
917 err = -errno;
918 ntfs_fuse_update_times(ni, NTFS_UPDATE_ATIME);
919 if (ntfs_inode_close(ni))
920 set_fuse_error(&err);
921 return err;
924 static int ntfs_fuse_open(const char *org_path,
925 #if POSIXACLS
926 struct fuse_file_info *fi)
927 #else
928 struct fuse_file_info *fi __attribute__((unused)))
929 #endif
931 ntfs_inode *ni;
932 ntfs_attr *na;
933 int res = 0;
934 char *path = NULL;
935 ntfschar *stream_name;
936 int stream_name_len;
937 #if POSIXACLS
938 int accesstype;
939 struct SECURITY_CONTEXT security;
940 #endif
942 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
943 if (stream_name_len < 0)
944 return stream_name_len;
945 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
946 if (ni) {
947 na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
948 if (na) {
949 #if POSIXACLS
950 if (ntfs_fuse_fill_security_context(&security)) {
951 if (fi->flags & O_WRONLY)
952 accesstype = S_IWRITE;
953 else
954 if (fi->flags & O_RDWR)
955 accesstype = S_IWRITE | S_IREAD;
956 else
957 accesstype = S_IREAD;
958 /* JPA directory must be searchable */
959 if (!ntfs_allowed_dir_access(&security,
960 path,S_IEXEC)
961 /* JPA check whether requested access is allowed */
962 || !ntfs_allowed_access(&security,
963 path,ni,accesstype))
964 res = -EACCES;
966 #endif
967 if ((res >= 0)
968 && (fi->flags & (O_WRONLY | O_RDWR))) {
969 /* mark a future need to compress the last chunk */
970 if (na->data_flags & ATTR_COMPRESSION_MASK)
971 fi->fh |= CLOSE_COMPRESSED;
972 /* mark a future need to fixup encrypted inode */
973 if (ctx->efs_raw
974 && !(na->data_flags & ATTR_IS_ENCRYPTED)
975 && (ni->flags & FILE_ATTR_ENCRYPTED))
976 fi->fh |= CLOSE_ENCRYPTED;
978 ntfs_attr_close(na);
979 } else
980 res = -errno;
981 if (ntfs_inode_close(ni))
982 set_fuse_error(&res);
983 } else
984 res = -errno;
985 free(path);
986 if (stream_name_len)
987 free(stream_name);
988 return res;
991 static int ntfs_fuse_read(const char *org_path, char *buf, size_t size,
992 off_t offset, struct fuse_file_info *fi __attribute__((unused)))
994 ntfs_inode *ni = NULL;
995 ntfs_attr *na = NULL;
996 char *path = NULL;
997 ntfschar *stream_name;
998 int stream_name_len, res;
999 s64 total = 0;
1000 s64 max_read;
1002 if (!size)
1003 return 0;
1005 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
1006 if (stream_name_len < 0)
1007 return stream_name_len;
1008 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1009 if (!ni) {
1010 res = -errno;
1011 goto exit;
1013 na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
1014 if (!na) {
1015 res = -errno;
1016 goto exit;
1018 /* limit reads at next 512 byte boundary for encrypted attributes */
1019 max_read = na->data_size;
1020 if (ctx->efs_raw && (na->data_flags & ATTR_IS_ENCRYPTED) &&
1021 NAttrNonResident(na)) {
1022 max_read = ((na->data_size+511) & ~511) + 2;
1024 if (offset + (off_t)size > max_read) {
1025 if (max_read < offset)
1026 goto ok;
1027 size = max_read - offset;
1029 while (size > 0) {
1030 s64 ret = ntfs_attr_pread(na, offset, size, buf + total);
1031 if (ret != (s64)size)
1032 ntfs_log_perror("ntfs_attr_pread error reading '%s' at "
1033 "offset %lld: %lld <> %lld", org_path,
1034 (long long)offset, (long long)size, (long long)ret);
1035 if (ret <= 0 || ret > (s64)size) {
1036 res = (ret < 0) ? -errno : -EIO;
1037 goto exit;
1039 size -= ret;
1040 offset += ret;
1041 total += ret;
1044 ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME);
1045 res = total;
1046 exit:
1047 if (na)
1048 ntfs_attr_close(na);
1049 if (ntfs_inode_close(ni))
1050 set_fuse_error(&res);
1051 free(path);
1052 if (stream_name_len)
1053 free(stream_name);
1054 return res;
1057 static int ntfs_fuse_write(const char *org_path, const char *buf, size_t size,
1058 off_t offset, struct fuse_file_info *fi __attribute__((unused)))
1060 ntfs_inode *ni = NULL;
1061 ntfs_attr *na = NULL;
1062 char *path = NULL;
1063 ntfschar *stream_name;
1064 int stream_name_len, res, total = 0;
1066 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
1067 if (stream_name_len < 0) {
1068 res = stream_name_len;
1069 goto out;
1071 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1072 if (!ni) {
1073 res = -errno;
1074 goto exit;
1076 na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
1077 if (!na) {
1078 res = -errno;
1079 goto exit;
1081 while (size) {
1082 s64 ret = ntfs_attr_pwrite(na, offset, size, buf + total);
1083 if (ret <= 0) {
1084 res = -errno;
1085 goto exit;
1087 size -= ret;
1088 offset += ret;
1089 total += ret;
1091 res = total;
1092 if (res > 0)
1093 ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
1094 exit:
1095 if (na)
1096 ntfs_attr_close(na);
1097 if (total)
1098 set_archive(ni);
1099 if (ntfs_inode_close(ni))
1100 set_fuse_error(&res);
1101 free(path);
1102 if (stream_name_len)
1103 free(stream_name);
1104 out:
1105 return res;
1108 static int ntfs_fuse_release(const char *org_path,
1109 struct fuse_file_info *fi)
1111 ntfs_inode *ni = NULL;
1112 ntfs_attr *na = NULL;
1113 char *path = NULL;
1114 ntfschar *stream_name;
1115 int stream_name_len, res;
1117 /* Only for marked descriptors there is something to do */
1118 if (!(fi->fh & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED))) {
1119 res = 0;
1120 goto out;
1122 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
1123 if (stream_name_len < 0) {
1124 res = stream_name_len;
1125 goto out;
1127 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1128 if (!ni) {
1129 res = -errno;
1130 goto exit;
1132 na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
1133 if (!na) {
1134 res = -errno;
1135 goto exit;
1137 res = 0;
1138 if (fi->fh & CLOSE_COMPRESSED)
1139 res = ntfs_attr_pclose(na);
1140 if (fi->fh & CLOSE_ENCRYPTED)
1141 res = ntfs_efs_fixup_attribute(NULL, na);
1142 exit:
1143 if (na)
1144 ntfs_attr_close(na);
1145 if (ntfs_inode_close(ni))
1146 set_fuse_error(&res);
1147 free(path);
1148 if (stream_name_len)
1149 free(stream_name);
1150 out:
1151 return res;
1155 * Common part for truncate() and ftruncate()
1158 static int ntfs_fuse_trunc(const char *org_path, off_t size,
1159 #if POSIXACLS
1160 BOOL chkwrite)
1161 #else
1162 BOOL chkwrite __attribute__((unused)))
1163 #endif
1165 ntfs_inode *ni = NULL;
1166 ntfs_attr *na = NULL;
1167 int res;
1168 char *path = NULL;
1169 ntfschar *stream_name;
1170 int stream_name_len;
1171 s64 oldsize;
1172 #if POSIXACLS
1173 struct SECURITY_CONTEXT security;
1174 #endif
1176 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
1177 if (stream_name_len < 0)
1178 return stream_name_len;
1179 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1180 if (!ni)
1181 goto exit;
1183 na = ntfs_attr_open(ni, AT_DATA, stream_name, stream_name_len);
1184 if (!na)
1185 goto exit;
1186 #if POSIXACLS
1188 * JPA deny truncation if cannot search in parent directory
1189 * or cannot write to file (already checked for ftruncate())
1191 if (ntfs_fuse_fill_security_context(&security)
1192 && (!ntfs_allowed_dir_access(&security, path, S_IEXEC)
1193 || (chkwrite
1194 && !ntfs_allowed_access(&security, path, ni, S_IWRITE)))) {
1195 errno = EACCES;
1196 goto exit;
1198 #endif
1200 * for compressed files, only deleting contents and expanding
1201 * are implemented. Expanding is done by inserting a final
1202 * zero, which is optimized as creating a hole when possible.
1204 if ((na->data_flags & ATTR_COMPRESSION_MASK)
1205 && size
1206 && (size < na->initialized_size)) {
1207 errno = EOPNOTSUPP;
1208 goto exit;
1210 oldsize = na->data_size;
1211 if ((na->data_flags & ATTR_COMPRESSION_MASK)
1212 && (size > na->initialized_size)) {
1213 char zero = 0;
1214 if (ntfs_attr_pwrite(na, size - 1, 1, &zero) <= 0)
1215 goto exit;
1216 } else
1217 if (ntfs_attr_truncate(na, size))
1218 goto exit;
1219 if (oldsize != size)
1220 set_archive(ni);
1222 ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
1223 errno = 0;
1224 exit:
1225 res = -errno;
1226 ntfs_attr_close(na);
1227 if (ntfs_inode_close(ni))
1228 set_fuse_error(&res);
1229 free(path);
1230 if (stream_name_len)
1231 free(stream_name);
1232 return res;
1235 static int ntfs_fuse_truncate(const char *org_path, off_t size)
1237 return ntfs_fuse_trunc(org_path, size, TRUE);
1240 static int ntfs_fuse_ftruncate(const char *org_path, off_t size,
1241 struct fuse_file_info *fi __attribute__((unused)))
1244 * in ->ftruncate() the file handle is guaranteed
1245 * to have been opened for write.
1247 return (ntfs_fuse_trunc(org_path, size, FALSE));
1250 static int ntfs_fuse_chmod(const char *path,
1251 mode_t mode)
1253 int res = 0;
1254 ntfs_inode *ni;
1255 struct SECURITY_CONTEXT security;
1257 if (ntfs_fuse_is_named_data_stream(path))
1258 return -EINVAL; /* n/a for named data streams. */
1260 /* JPA return unsupported if no user mapping has been defined */
1261 if (!ntfs_fuse_fill_security_context(&security)) {
1262 if (ctx->silent)
1263 res = 0;
1264 else
1265 res = -EOPNOTSUPP;
1266 } else {
1267 #if POSIXACLS
1268 /* parent directory must be executable */
1269 if (ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
1270 #endif
1271 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1272 if (!ni)
1273 res = -errno;
1274 else {
1275 if (ntfs_set_mode(&security,path,ni,mode))
1276 res = -errno;
1277 else
1278 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
1279 NInoSetDirty(ni);
1280 if (ntfs_inode_close(ni))
1281 set_fuse_error(&res);
1283 #if POSIXACLS
1284 } else
1285 res = -errno;
1286 #endif
1288 return res;
1291 static int ntfs_fuse_chown(const char *path, uid_t uid, gid_t gid)
1293 ntfs_inode *ni;
1294 int res;
1295 struct SECURITY_CONTEXT security;
1297 if (ntfs_fuse_is_named_data_stream(path))
1298 return -EINVAL; /* n/a for named data streams. */
1299 if (!ntfs_fuse_fill_security_context(&security)) {
1300 if (ctx->silent)
1301 return 0;
1302 if (uid == ctx->uid && gid == ctx->gid)
1303 return 0;
1304 return -EOPNOTSUPP;
1305 } else {
1306 res = 0;
1307 if (((int)uid != -1) || ((int)gid != -1)) {
1308 #if POSIXACLS
1309 /* parent directory must be executable */
1311 if (ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
1312 #endif
1313 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1314 if (!ni)
1315 res = -errno;
1316 else {
1317 if (ntfs_set_owner(&security,
1318 path,ni,uid,gid))
1319 res = -errno;
1320 else
1321 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
1322 if (ntfs_inode_close(ni))
1323 set_fuse_error(&res);
1325 #if POSIXACLS
1326 } else
1327 res = -errno;
1328 #endif
1331 return (res);
1334 #if POSIXACLS
1336 static int ntfs_fuse_access(const char *path, int type)
1338 int res = 0;
1339 int mode;
1340 ntfs_inode *ni;
1341 struct SECURITY_CONTEXT security;
1343 if (ntfs_fuse_is_named_data_stream(path))
1344 return -EINVAL; /* n/a for named data streams. */
1346 /* JPA return unsupported if no user mapping has been defined */
1347 if (!ntfs_fuse_fill_security_context(&security)) {
1348 if (ctx->silent)
1349 res = 0;
1350 else
1351 res = -EOPNOTSUPP;
1352 } else {
1353 /* parent directory must be readable */
1354 if (ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
1355 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1356 if (!ni) {
1357 res = -errno;
1358 } else {
1359 mode = 0;
1360 if (type & (X_OK | W_OK | R_OK)) {
1361 if (type & X_OK) mode += S_IEXEC;
1362 if (type & W_OK) mode += S_IWRITE;
1363 if (type & R_OK) mode += S_IREAD;
1364 if (!ntfs_allowed_access(&security,
1365 path, ni, mode))
1366 res = -errno;
1368 if (ntfs_inode_close(ni))
1369 set_fuse_error(&res);
1371 } else
1372 res = -errno;
1374 return (res);
1377 #endif
1379 static int ntfs_fuse_create(const char *org_path, mode_t typemode, dev_t dev,
1380 const char *target, struct fuse_file_info *fi)
1382 char *name;
1383 ntfschar *uname = NULL, *utarget = NULL;
1384 ntfs_inode *dir_ni = NULL, *ni;
1385 char *dir_path;
1386 le32 securid;
1387 char *path;
1388 ntfschar *stream_name;
1389 int stream_name_len;
1390 mode_t type = typemode & ~07777;
1391 mode_t perm;
1392 struct SECURITY_CONTEXT security;
1393 int res = 0, uname_len, utarget_len;
1395 dir_path = strdup(org_path);
1396 if (!dir_path)
1397 return -errno;
1398 /* Generate unicode filename. */
1399 name = strrchr(dir_path, '/');
1400 name++;
1401 uname_len = ntfs_mbstoucs(name, &uname);
1402 if (uname_len < 0) {
1403 res = -errno;
1404 goto exit;
1406 stream_name_len = ntfs_fuse_parse_path(org_path,
1407 &path, &stream_name);
1408 if (stream_name_len < 0) {
1409 res = stream_name_len;
1410 goto exit;
1412 /* Open parent directory. */
1413 *--name = 0;
1414 dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, dir_path);
1415 if (!dir_ni) {
1416 free(path);
1417 res = -errno;
1418 goto exit;
1420 #if POSIXACLS
1421 /* make sure parent directory is writeable and executable */
1422 if (!ntfs_fuse_fill_security_context(&security)
1423 || ntfs_allowed_access(&security,dir_path,
1424 dir_ni,S_IWRITE + S_IEXEC)) {
1425 #else
1426 ntfs_fuse_fill_security_context(&security);
1427 #endif
1428 if (S_ISDIR(type))
1429 perm = typemode & ~ctx->dmask & 0777;
1430 else
1431 perm = typemode & ~ctx->fmask & 0777;
1433 * Try to get a security id available for
1434 * file creation (from inheritance or argument).
1435 * This is not possible for NTFS 1.x, and we will
1436 * have to build a security attribute later.
1438 if (!ctx->security.mapping[MAPUSERS])
1439 securid = 0;
1440 else
1441 if (ctx->inherit)
1442 securid = ntfs_inherited_id(&security, dir_path,
1443 dir_ni, S_ISDIR(type));
1444 else
1445 #if POSIXACLS
1446 securid = ntfs_alloc_securid(&security,
1447 security.uid, security.gid,
1448 dir_path, dir_ni, perm, S_ISDIR(type));
1449 #else
1450 securid = ntfs_alloc_securid(&security,
1451 security.uid, security.gid,
1452 perm & ~security.umask, S_ISDIR(type));
1453 #endif
1454 /* Create object specified in @type. */
1455 switch (type) {
1456 case S_IFCHR:
1457 case S_IFBLK:
1458 ni = ntfs_create_device(dir_ni, securid,
1459 uname, uname_len, type, dev);
1460 break;
1461 case S_IFLNK:
1462 utarget_len = ntfs_mbstoucs(target, &utarget);
1463 if (utarget_len < 0) {
1464 res = -errno;
1465 goto exit;
1467 ni = ntfs_create_symlink(dir_ni, securid,
1468 uname, uname_len,
1469 utarget, utarget_len);
1470 break;
1471 default:
1472 ni = ntfs_create(dir_ni, securid, uname,
1473 uname_len, type);
1474 break;
1476 if (ni) {
1478 * set the security attribute if a security id
1479 * could not be allocated (eg NTFS 1.x)
1481 if (ctx->security.mapping[MAPUSERS]) {
1482 #if POSIXACLS
1483 if (!securid
1484 && ntfs_set_inherited_posix(&security, ni,
1485 security.uid, security.gid,
1486 dir_path, dir_ni, perm) < 0)
1487 set_fuse_error(&res);
1488 #else
1489 if (!securid
1490 && ntfs_set_owner_mode(&security, ni,
1491 security.uid, security.gid,
1492 perm & ~security.umask) < 0)
1493 set_fuse_error(&res);
1494 #endif
1496 set_archive(ni);
1497 /* mark a need to compress the end of file */
1498 if (fi && (ni->flags & FILE_ATTR_COMPRESSED)) {
1499 fi->fh |= CLOSE_COMPRESSED;
1501 /* mark a future need to fixup encrypted inode */
1502 if (fi
1503 && ctx->efs_raw
1504 && (ni->flags & FILE_ATTR_ENCRYPTED))
1505 fi->fh |= CLOSE_ENCRYPTED;
1506 NInoSetDirty(ni);
1508 * closing ni will necessitate to open dir_ni to
1509 * synchronize the index.
1510 * Better avoid a dangerous double opening.
1512 ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME);
1513 if (ntfs_inode_close(dir_ni))
1514 set_fuse_error(&res);
1515 dir_ni = (ntfs_inode*)NULL;
1516 if (ntfs_inode_close(ni))
1517 set_fuse_error(&res);
1518 } else
1519 res = -errno;
1520 #if POSIXACLS
1521 } else
1522 res = -errno;
1523 #endif
1524 free(path);
1526 exit:
1527 free(uname);
1528 if (ntfs_inode_close(dir_ni))
1529 set_fuse_error(&res);
1530 if (utarget)
1531 free(utarget);
1532 free(dir_path);
1533 return res;
1536 static int ntfs_fuse_create_stream(const char *path,
1537 ntfschar *stream_name, const int stream_name_len,
1538 struct fuse_file_info *fi)
1540 ntfs_inode *ni;
1541 int res = 0;
1543 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1544 if (!ni) {
1545 res = -errno;
1546 if (res == -ENOENT) {
1548 * If such file does not exist, create it and try once
1549 * again to add stream to it.
1550 * Note : no fuse_file_info for creation of main file
1552 res = ntfs_fuse_create(path, S_IFREG, 0, NULL,
1553 (struct fuse_file_info*)NULL);
1554 if (!res)
1555 return ntfs_fuse_create_stream(path,
1556 stream_name, stream_name_len,fi);
1557 else
1558 res = -errno;
1560 return res;
1562 if (ntfs_attr_add(ni, AT_DATA, stream_name, stream_name_len, NULL, 0))
1563 res = -errno;
1565 if ((res >= 0)
1566 && (fi->flags & (O_WRONLY | O_RDWR))) {
1567 set_archive(ni);
1568 /* mark a future need to compress the last block */
1569 if (ni->flags & FILE_ATTR_COMPRESSED)
1570 fi->fh |= CLOSE_COMPRESSED;
1571 /* mark a future need to fixup encrypted inode */
1572 if (ctx->efs_raw
1573 && (ni->flags & FILE_ATTR_ENCRYPTED))
1574 fi->fh |= CLOSE_ENCRYPTED;
1577 if (ntfs_inode_close(ni))
1578 set_fuse_error(&res);
1579 return res;
1582 static int ntfs_fuse_mknod_common(const char *org_path, mode_t mode, dev_t dev,
1583 struct fuse_file_info *fi)
1585 char *path = NULL;
1586 ntfschar *stream_name;
1587 int stream_name_len;
1588 int res = 0;
1590 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
1591 if (stream_name_len < 0)
1592 return stream_name_len;
1593 if (stream_name_len && !S_ISREG(mode)) {
1594 res = -EINVAL;
1595 goto exit;
1597 if (!stream_name_len)
1598 res = ntfs_fuse_create(path, mode & (S_IFMT | 07777), dev,
1599 NULL,fi);
1600 else
1601 res = ntfs_fuse_create_stream(path, stream_name,
1602 stream_name_len,fi);
1603 exit:
1604 free(path);
1605 if (stream_name_len)
1606 free(stream_name);
1607 return res;
1610 static int ntfs_fuse_mknod(const char *path, mode_t mode, dev_t dev)
1612 return ntfs_fuse_mknod_common(path, mode, dev,
1613 (struct fuse_file_info*)NULL);
1616 static int ntfs_fuse_create_file(const char *path, mode_t mode,
1617 struct fuse_file_info *fi)
1619 return ntfs_fuse_mknod_common(path, mode, 0, fi);
1622 static int ntfs_fuse_symlink(const char *to, const char *from)
1624 if (ntfs_fuse_is_named_data_stream(from))
1625 return -EINVAL; /* n/a for named data streams. */
1626 return ntfs_fuse_create(from, S_IFLNK, 0, to,
1627 (struct fuse_file_info*)NULL);
1630 static int ntfs_fuse_link(const char *old_path, const char *new_path)
1632 char *name;
1633 ntfschar *uname = NULL;
1634 ntfs_inode *dir_ni = NULL, *ni;
1635 char *path;
1636 int res = 0, uname_len;
1637 #if POSIXACLS
1638 struct SECURITY_CONTEXT security;
1639 #endif
1641 if (ntfs_fuse_is_named_data_stream(old_path))
1642 return -EINVAL; /* n/a for named data streams. */
1643 if (ntfs_fuse_is_named_data_stream(new_path))
1644 return -EINVAL; /* n/a for named data streams. */
1645 path = strdup(new_path);
1646 if (!path)
1647 return -errno;
1648 /* Open file for which create hard link. */
1649 ni = ntfs_pathname_to_inode(ctx->vol, NULL, old_path);
1650 if (!ni) {
1651 res = -errno;
1652 goto exit;
1655 /* Generate unicode filename. */
1656 name = strrchr(path, '/');
1657 name++;
1658 uname_len = ntfs_mbstoucs(name, &uname);
1659 if (uname_len < 0) {
1660 res = -errno;
1661 goto exit;
1663 /* Open parent directory. */
1664 *--name = 0;
1665 dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1666 if (!dir_ni) {
1667 res = -errno;
1668 goto exit;
1671 #if POSIXACLS
1672 /* JPA make sure the parent directories are writeable */
1673 if (ntfs_fuse_fill_security_context(&security)
1674 && (!ntfs_allowed_dir_access(&security,old_path,S_IWRITE + S_IEXEC)
1675 || !ntfs_allowed_access(&security,path,dir_ni,S_IWRITE + S_IEXEC)))
1676 res = -EACCES;
1677 else
1678 #endif
1680 if (ntfs_link(ni, dir_ni, uname, uname_len)) {
1681 res = -errno;
1682 goto exit;
1685 set_archive(ni);
1686 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
1687 ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME);
1689 exit:
1691 * Must close dir_ni first otherwise ntfs_inode_sync_file_name(ni)
1692 * may fail because ni may not be in parent's index on the disk yet.
1694 if (ntfs_inode_close(dir_ni))
1695 set_fuse_error(&res);
1696 if (ntfs_inode_close(ni))
1697 set_fuse_error(&res);
1698 free(uname);
1699 free(path);
1700 return res;
1703 static int ntfs_fuse_rm(const char *org_path)
1705 char *name;
1706 ntfschar *uname = NULL;
1707 ntfs_inode *dir_ni = NULL, *ni;
1708 char *path;
1709 int res = 0, uname_len;
1710 #if POSIXACLS
1711 struct SECURITY_CONTEXT security;
1712 #endif
1714 path = strdup(org_path);
1715 if (!path)
1716 return -errno;
1717 /* Open object for delete. */
1718 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1719 if (!ni) {
1720 res = -errno;
1721 goto exit;
1723 /* Generate unicode filename. */
1724 name = strrchr(path, '/');
1725 name++;
1726 uname_len = ntfs_mbstoucs(name, &uname);
1727 if (uname_len < 0) {
1728 res = -errno;
1729 goto exit;
1731 /* Open parent directory. */
1732 *--name = 0;
1733 dir_ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1734 if (!dir_ni) {
1735 res = -errno;
1736 goto exit;
1739 #if POSIXACLS
1740 /* JPA deny unlinking if directory is not writable and executable */
1741 if (!ntfs_fuse_fill_security_context(&security)
1742 || ntfs_allowed_dir_access(&security, org_path,
1743 S_IEXEC + S_IWRITE + S_ISVTX)) {
1744 #endif
1745 if (ntfs_delete(ctx->vol, org_path, ni, dir_ni,
1746 uname, uname_len))
1747 res = -errno;
1748 /* ntfs_delete() always closes ni and dir_ni */
1749 ni = dir_ni = NULL;
1750 #if POSIXACLS
1751 } else
1752 res = -EACCES;
1753 #endif
1754 exit:
1755 if (ntfs_inode_close(dir_ni))
1756 set_fuse_error(&res);
1757 if (ntfs_inode_close(ni))
1758 set_fuse_error(&res);
1759 free(uname);
1760 free(path);
1761 return res;
1764 static int ntfs_fuse_rm_stream(const char *path, ntfschar *stream_name,
1765 const int stream_name_len)
1767 ntfs_inode *ni;
1768 int res = 0;
1770 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1771 if (!ni)
1772 return -errno;
1774 if (ntfs_attr_remove(ni, AT_DATA, stream_name, stream_name_len))
1775 res = -errno;
1777 if (ntfs_inode_close(ni))
1778 set_fuse_error(&res);
1779 return res;
1782 static int ntfs_fuse_unlink(const char *org_path)
1784 char *path = NULL;
1785 ntfschar *stream_name;
1786 int stream_name_len;
1787 int res = 0;
1788 #if POSIXACLS
1789 struct SECURITY_CONTEXT security;
1790 #endif
1792 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
1793 if (stream_name_len < 0)
1794 return stream_name_len;
1795 if (!stream_name_len)
1796 res = ntfs_fuse_rm(path);
1797 else {
1798 #if POSIXACLS
1800 * JPA deny unlinking stream if directory is not
1801 * writable and executable (debatable)
1803 if (!ntfs_fuse_fill_security_context(&security)
1804 || ntfs_allowed_dir_access(&security, path,
1805 S_IEXEC + S_IWRITE + S_ISVTX))
1806 res = ntfs_fuse_rm_stream(path, stream_name, stream_name_len);
1807 else
1808 res = -errno;
1809 #else
1810 res = ntfs_fuse_rm_stream(path, stream_name, stream_name_len);
1811 #endif
1813 free(path);
1814 if (stream_name_len)
1815 free(stream_name);
1816 return res;
1819 static int ntfs_fuse_safe_rename(const char *old_path,
1820 const char *new_path,
1821 const char *tmp)
1823 int ret;
1825 ntfs_log_trace("Entering\n");
1827 ret = ntfs_fuse_link(new_path, tmp);
1828 if (ret)
1829 return ret;
1831 ret = ntfs_fuse_unlink(new_path);
1832 if (!ret) {
1834 ret = ntfs_fuse_link(old_path, new_path);
1835 if (ret)
1836 goto restore;
1838 ret = ntfs_fuse_unlink(old_path);
1839 if (ret) {
1840 if (ntfs_fuse_unlink(new_path))
1841 goto err;
1842 goto restore;
1846 goto cleanup;
1847 restore:
1848 if (ntfs_fuse_link(tmp, new_path)) {
1849 err:
1850 ntfs_log_perror("Rename failed. Existing file '%s' was renamed "
1851 "to '%s'", new_path, tmp);
1852 } else {
1853 cleanup:
1855 * Condition for this unlink has already been checked in
1856 * "ntfs_fuse_rename_existing_dest()", so it should never
1857 * fail (unless concurrent access to directories when fuse
1858 * is multithreaded)
1860 if (ntfs_fuse_unlink(tmp) < 0)
1861 ntfs_log_perror("Rename failed. Existing file '%s' still present "
1862 "as '%s'", new_path, tmp);
1864 return ret;
1867 static int ntfs_fuse_rename_existing_dest(const char *old_path, const char *new_path)
1869 int ret, len;
1870 char *tmp;
1871 const char *ext = ".ntfs-3g-";
1872 #if POSIXACLS
1873 struct SECURITY_CONTEXT security;
1874 #endif
1876 ntfs_log_trace("Entering\n");
1878 len = strlen(new_path) + strlen(ext) + 10 + 1; /* wc(str(2^32)) + \0 */
1879 tmp = ntfs_malloc(len);
1880 if (!tmp)
1881 return -errno;
1883 ret = snprintf(tmp, len, "%s%s%010d", new_path, ext, ++ntfs_sequence);
1884 if (ret != len - 1) {
1885 ntfs_log_error("snprintf failed: %d != %d\n", ret, len - 1);
1886 ret = -EOVERFLOW;
1887 } else {
1888 #if POSIXACLS
1890 * Make sure existing dest can be removed.
1891 * This is only needed if parent directory is
1892 * sticky, because in this situation condition
1893 * for unlinking is different from condition for
1894 * linking
1896 if (!ntfs_fuse_fill_security_context(&security)
1897 || ntfs_allowed_dir_access(&security, new_path,
1898 S_IEXEC + S_IWRITE + S_ISVTX))
1899 ret = ntfs_fuse_safe_rename(old_path, new_path, tmp);
1900 else
1901 ret = -EACCES;
1902 #else
1903 ret = ntfs_fuse_safe_rename(old_path, new_path, tmp);
1904 #endif
1906 free(tmp);
1907 return ret;
1910 static int ntfs_fuse_rename(const char *old_path, const char *new_path)
1912 int ret, stream_name_len;
1913 char *path = NULL;
1914 ntfschar *stream_name;
1915 ntfs_inode *ni;
1917 ntfs_log_debug("rename: old: '%s' new: '%s'\n", old_path, new_path);
1920 * FIXME: Rename should be atomic.
1922 stream_name_len = ntfs_fuse_parse_path(new_path, &path, &stream_name);
1923 if (stream_name_len < 0)
1924 return stream_name_len;
1926 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1927 if (ni) {
1928 ret = ntfs_check_empty_dir(ni);
1929 if (ret < 0) {
1930 ret = -errno;
1931 ntfs_inode_close(ni);
1932 goto out;
1935 if (ntfs_inode_close(ni)) {
1936 set_fuse_error(&ret);
1937 goto out;
1940 ret = ntfs_fuse_rename_existing_dest(old_path, new_path);
1941 goto out;
1944 ret = ntfs_fuse_link(old_path, new_path);
1945 if (ret)
1946 goto out;
1948 ret = ntfs_fuse_unlink(old_path);
1949 if (ret)
1950 ntfs_fuse_unlink(new_path);
1951 out:
1952 free(path);
1953 if (stream_name_len)
1954 free(stream_name);
1955 return ret;
1958 static int ntfs_fuse_mkdir(const char *path,
1959 mode_t mode)
1961 if (ntfs_fuse_is_named_data_stream(path))
1962 return -EINVAL; /* n/a for named data streams. */
1963 return ntfs_fuse_create(path, S_IFDIR | (mode & 07777), 0, NULL,
1964 (struct fuse_file_info*)NULL);
1967 static int ntfs_fuse_rmdir(const char *path)
1969 if (ntfs_fuse_is_named_data_stream(path))
1970 return -EINVAL; /* n/a for named data streams. */
1971 return ntfs_fuse_rm(path);
1974 static int ntfs_fuse_utime(const char *path, struct utimbuf *buf)
1976 ntfs_inode *ni;
1977 int res = 0;
1978 #if POSIXACLS
1979 BOOL ownerok;
1980 BOOL writeok;
1981 struct SECURITY_CONTEXT security;
1982 #endif
1984 if (ntfs_fuse_is_named_data_stream(path))
1985 return -EINVAL; /* n/a for named data streams. */
1986 #if POSIXACLS
1987 /* parent directory must be executable */
1988 if (ntfs_fuse_fill_security_context(&security)
1989 && !ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
1990 return (-errno);
1992 #endif
1993 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
1994 if (!ni)
1995 return -errno;
1996 #if POSIXACLS
1997 ownerok = ntfs_allowed_as_owner(&security, path, ni);
1998 if (buf) {
2000 * fuse never calls with a NULL buf and we do not
2001 * know whether the specific condition can be applied
2002 * So we have to accept updating by a non-owner having
2003 * write access.
2005 writeok = !ownerok
2006 && (buf->actime == buf->modtime)
2007 && ntfs_allowed_access(&security, path, ni, S_IWRITE);
2008 /* Must be owner */
2009 if (!ownerok && !writeok)
2010 res = (buf->actime == buf->modtime ? -EACCES : -EPERM);
2011 else {
2012 ni->last_access_time = buf->actime;
2013 ni->last_data_change_time = buf->modtime;
2014 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
2016 } else {
2017 /* Must be owner or have write access */
2018 writeok = !ownerok
2019 && ntfs_allowed_access(&security, path, ni, S_IWRITE);
2020 if (!ownerok && !writeok)
2021 res = -EACCES;
2022 else
2023 ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME);
2025 #else
2026 if (buf) {
2027 ni->last_access_time = buf->actime;
2028 ni->last_data_change_time = buf->modtime;
2029 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
2030 } else
2031 ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME);
2032 #endif
2034 if (ntfs_inode_close(ni))
2035 set_fuse_error(&res);
2036 return res;
2039 static int ntfs_fuse_bmap(const char *path, size_t blocksize, uint64_t *idx)
2041 ntfs_inode *ni;
2042 ntfs_attr *na;
2043 LCN lcn;
2044 int ret = 0;
2045 int cl_per_bl = ctx->vol->cluster_size / blocksize;
2047 if (blocksize > ctx->vol->cluster_size)
2048 return -EINVAL;
2050 if (ntfs_fuse_is_named_data_stream(path))
2051 return -EINVAL;
2053 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
2054 if (!ni)
2055 return -errno;
2057 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
2058 if (!na) {
2059 ret = -errno;
2060 goto close_inode;
2063 if ((na->data_flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED))
2064 || !NAttrNonResident(na)) {
2065 ret = -EINVAL;
2066 goto close_attr;
2069 if (ntfs_attr_map_whole_runlist(na)) {
2070 ret = -errno;
2071 goto close_attr;
2074 lcn = ntfs_rl_vcn_to_lcn(na->rl, *idx / cl_per_bl);
2075 *idx = (lcn > 0) ? lcn * cl_per_bl + *idx % cl_per_bl : 0;
2077 close_attr:
2078 ntfs_attr_close(na);
2079 close_inode:
2080 if (ntfs_inode_close(ni))
2081 set_fuse_error(&ret);
2082 return ret;
2085 #ifdef HAVE_SETXATTR
2088 * Name space identifications and prefixes
2091 enum { XATTRNS_NONE,
2092 XATTRNS_USER,
2093 XATTRNS_SYSTEM,
2094 XATTRNS_SECURITY,
2095 XATTRNS_TRUSTED,
2096 XATTRNS_OPEN } ;
2098 static const char nf_ns_user_prefix[] = "user.";
2099 static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
2100 static const char nf_ns_system_prefix[] = "system.";
2101 static const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1;
2102 static const char nf_ns_security_prefix[] = "security.";
2103 static const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1;
2104 static const char nf_ns_trusted_prefix[] = "trusted.";
2105 static const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1;
2107 static const char xattr_ntfs_3g[] = "ntfs-3g.";
2110 * Identification of data mapped to the system name space
2113 enum { XATTR_UNMAPPED,
2114 XATTR_NTFS_ACL,
2115 XATTR_NTFS_ATTRIB,
2116 XATTR_NTFS_EFSINFO,
2117 XATTR_NTFS_REPARSE_DATA,
2118 XATTR_NTFS_DOS_NAME,
2119 XATTR_NTFS_TIMES,
2120 XATTR_POSIX_ACC,
2121 XATTR_POSIX_DEF } ;
2123 static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl";
2124 static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
2125 static const char nf_ns_xattr_efsinfo[] = "user.ntfs.efsinfo";
2126 static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data";
2127 static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name";
2128 static const char nf_ns_xattr_times[] = "system.ntfs_times";
2129 static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
2130 static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
2132 struct XATTRNAME {
2133 int xattr;
2134 const char *name;
2137 static struct XATTRNAME nf_ns_xattr_names[] = {
2138 { XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl },
2139 { XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib },
2140 { XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo },
2141 { XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse },
2142 { XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name },
2143 { XATTR_NTFS_TIMES, nf_ns_xattr_times },
2144 { XATTR_POSIX_ACC, nf_ns_xattr_posix_access },
2145 { XATTR_POSIX_DEF, nf_ns_xattr_posix_default },
2146 { XATTR_UNMAPPED, (char*)NULL } /* terminator */
2150 * Check whether access to internal data as an extended
2151 * attribute in system name space is allowed
2153 * Returns pointer to inode if allowed,
2154 * NULL and errno set if not allowed
2157 static ntfs_inode *ntfs_check_access_xattr(struct SECURITY_CONTEXT *security,
2158 const char *path, int attr, BOOL setting)
2160 ntfs_inode *ni;
2161 BOOL foracl;
2162 mode_t acctype;
2164 ni = (ntfs_inode*)NULL;
2165 if (ntfs_fuse_is_named_data_stream(path))
2166 errno = EINVAL; /* n/a for named data streams. */
2167 else {
2168 foracl = (attr == XATTR_POSIX_ACC)
2169 || (attr == XATTR_POSIX_DEF);
2171 * When accessing Posix ACL, return unsupported if ACL
2172 * were disabled or no user mapping has been defined.
2173 * However no error will be returned to getfacl
2175 if ((!ntfs_fuse_fill_security_context(security)
2176 || (ctx->secure_flags
2177 & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_RAW))))
2178 && foracl) {
2179 errno = EOPNOTSUPP;
2180 } else {
2182 * parent directory must be executable, and
2183 * for setting a DOS name it must be writeable
2185 if (setting && (attr == XATTR_NTFS_DOS_NAME))
2186 acctype = S_IEXEC | S_IWRITE;
2187 else
2188 acctype = S_IEXEC;
2189 if (ntfs_allowed_dir_access(security,path,acctype)) {
2190 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
2194 return (ni);
2198 * Determine whether an extended attribute is in the system
2199 * name space and mapped to internal data
2202 static int mapped_xattr_system(const char *name)
2204 struct XATTRNAME *p;
2206 p = nf_ns_xattr_names;
2207 while (p->name && strcmp(p->name,name))
2208 p++;
2209 return (p->xattr);
2213 * Determine the name space of an extended attribute
2216 static int xattr_namespace(const char *name)
2218 int namespace;
2220 if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) {
2221 namespace = XATTRNS_NONE;
2222 if (!strncmp(name, nf_ns_user_prefix,
2223 nf_ns_user_prefix_len)
2224 && (strlen(name) != (size_t)nf_ns_user_prefix_len))
2225 namespace = XATTRNS_USER;
2226 else if (!strncmp(name, nf_ns_system_prefix,
2227 nf_ns_system_prefix_len)
2228 && (strlen(name) != (size_t)nf_ns_system_prefix_len))
2229 namespace = XATTRNS_SYSTEM;
2230 else if (!strncmp(name, nf_ns_security_prefix,
2231 nf_ns_security_prefix_len)
2232 && (strlen(name) != (size_t)nf_ns_security_prefix_len))
2233 namespace = XATTRNS_SECURITY;
2234 else if (!strncmp(name, nf_ns_trusted_prefix,
2235 nf_ns_trusted_prefix_len)
2236 && (strlen(name) != (size_t)nf_ns_trusted_prefix_len))
2237 namespace = XATTRNS_TRUSTED;
2238 } else
2239 namespace = XATTRNS_OPEN;
2240 return (namespace);
2244 * Fix the prefix of an extended attribute
2247 static int fix_xattr_prefix(const char *name, int namespace, ntfschar **lename)
2249 int len;
2250 char *prefixed;
2252 *lename = (ntfschar*)NULL;
2253 switch (namespace) {
2254 case XATTRNS_USER :
2256 * user name space : remove user prefix
2258 len = ntfs_mbstoucs(name + nf_ns_user_prefix_len, lename);
2259 break;
2260 case XATTRNS_SYSTEM :
2261 case XATTRNS_SECURITY :
2262 case XATTRNS_TRUSTED :
2264 * security, trusted and unmapped system name spaces :
2265 * insert ntfs-3g prefix
2267 prefixed = ntfs_malloc(strlen(xattr_ntfs_3g)
2268 + strlen(name) + 1);
2269 if (prefixed) {
2270 strcpy(prefixed,xattr_ntfs_3g);
2271 strcat(prefixed,name);
2272 len = ntfs_mbstoucs(prefixed, lename);
2273 free(prefixed);
2274 } else
2275 len = -1;
2276 break;
2277 case XATTRNS_OPEN :
2279 * in open name space mode : do no fix prefix
2281 len = ntfs_mbstoucs(name, lename);
2282 break;
2283 default :
2284 len = -1;
2286 return (len);
2289 static int ntfs_fuse_listxattr(const char *path, char *list, size_t size)
2291 ntfs_attr_search_ctx *actx = NULL;
2292 ntfs_inode *ni;
2293 char *to = list;
2294 int ret = 0;
2295 #if POSIXACLS
2296 struct SECURITY_CONTEXT security;
2297 #endif
2298 #if POSIXACLS
2299 /* parent directory must be executable */
2300 if (ntfs_fuse_fill_security_context(&security)
2301 && !ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
2302 return (-errno);
2304 #endif
2305 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
2306 if (!ni)
2307 return -errno;
2308 #if POSIXACLS
2309 /* file must be readable */
2310 if (!ntfs_allowed_access(&security,path,ni,S_IREAD)) {
2311 ret = -EACCES;
2312 goto exit;
2314 #endif
2315 actx = ntfs_attr_get_search_ctx(ni, NULL);
2316 if (!actx) {
2317 ret = -errno;
2318 goto exit;
2321 if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR)
2322 || (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) {
2323 while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
2324 0, NULL, 0, actx)) {
2325 char *tmp_name = NULL;
2326 int tmp_name_len;
2328 if (!actx->attr->name_length)
2329 continue;
2330 tmp_name_len = ntfs_ucstombs(
2331 (ntfschar *)((u8*)actx->attr +
2332 le16_to_cpu(actx->attr->name_offset)),
2333 actx->attr->name_length, &tmp_name, 0);
2334 if (tmp_name_len < 0) {
2335 ret = -errno;
2336 goto exit;
2339 * When using name spaces, do not return
2340 * security, trusted nor system attributes
2341 * (filtered elsewhere anyway)
2342 * otherwise insert "user." prefix
2344 if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) {
2345 if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g))
2346 && !strncmp(tmp_name,xattr_ntfs_3g,
2347 sizeof(xattr_ntfs_3g)-1))
2348 tmp_name_len = 0;
2349 else
2350 ret += tmp_name_len
2351 + nf_ns_user_prefix_len + 1;
2352 } else
2353 ret += tmp_name_len + 1;
2354 if (size && tmp_name_len) {
2355 if ((size_t)ret <= size) {
2356 if (ctx->streams
2357 == NF_STREAMS_INTERFACE_XATTR) {
2358 strcpy(to, nf_ns_user_prefix);
2359 to += nf_ns_user_prefix_len;
2361 strncpy(to, tmp_name, tmp_name_len);
2362 to += tmp_name_len;
2363 *to = 0;
2364 to++;
2365 } else {
2366 free(tmp_name);
2367 ret = -ERANGE;
2368 goto exit;
2371 free(tmp_name);
2375 /* List efs info xattr for encrypted files */
2376 if (ctx->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) {
2377 ret += sizeof(nf_ns_xattr_efsinfo);
2378 if ((size_t)ret <= size) {
2379 memcpy(to, nf_ns_xattr_efsinfo,
2380 sizeof(nf_ns_xattr_efsinfo));
2381 to += sizeof(nf_ns_xattr_efsinfo);
2385 if (errno != ENOENT)
2386 ret = -errno;
2387 exit:
2388 if (actx)
2389 ntfs_attr_put_search_ctx(actx);
2390 if (ntfs_inode_close(ni))
2391 set_fuse_error(&ret);
2392 return ret;
2395 static int ntfs_fuse_getxattr_windows(const char *path, const char *name,
2396 char *value, size_t size)
2398 ntfs_attr_search_ctx *actx = NULL;
2399 ntfs_inode *ni;
2400 char *to = value;
2401 int ret = 0;
2402 #if POSIXACLS
2403 struct SECURITY_CONTEXT security;
2404 #endif
2406 if (strcmp(name, "ntfs.streams.list"))
2407 return -EOPNOTSUPP;
2408 #if POSIXACLS
2409 /* parent directory must be executable */
2410 if (ntfs_fuse_fill_security_context(&security)
2411 && !ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
2412 return (-errno);
2414 #endif
2415 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
2416 if (!ni)
2417 return -errno;
2418 #if POSIXACLS
2419 if (!ntfs_allowed_access(&security,path,ni,S_IREAD)) {
2420 ret = -errno;
2421 goto exit;
2423 #endif
2424 actx = ntfs_attr_get_search_ctx(ni, NULL);
2425 if (!actx) {
2426 ret = -errno;
2427 goto exit;
2429 while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
2430 0, NULL, 0, actx)) {
2431 char *tmp_name = NULL;
2432 int tmp_name_len;
2434 if (!actx->attr->name_length)
2435 continue;
2436 tmp_name_len = ntfs_ucstombs((ntfschar *)((u8*)actx->attr +
2437 le16_to_cpu(actx->attr->name_offset)),
2438 actx->attr->name_length, &tmp_name, 0);
2439 if (tmp_name_len < 0) {
2440 ret = -errno;
2441 goto exit;
2443 if (ret)
2444 ret++; /* For space delimiter. */
2445 ret += tmp_name_len;
2446 if (size) {
2447 if ((size_t)ret <= size) {
2448 /* Don't add space to the beginning of line. */
2449 if (to != value) {
2450 *to = '\0';
2451 to++;
2453 strncpy(to, tmp_name, tmp_name_len);
2454 to += tmp_name_len;
2455 } else {
2456 free(tmp_name);
2457 ret = -ERANGE;
2458 goto exit;
2461 free(tmp_name);
2463 if (errno != ENOENT)
2464 ret = -errno;
2465 exit:
2466 if (actx)
2467 ntfs_attr_put_search_ctx(actx);
2468 if (ntfs_inode_close(ni))
2469 set_fuse_error(&ret);
2470 return ret;
2473 static int ntfs_fuse_getxattr(const char *path, const char *name,
2474 char *value, size_t size)
2476 ntfs_inode *ni;
2477 ntfs_attr *na = NULL;
2478 ntfschar *lename = NULL;
2479 int res, lename_len;
2480 s64 rsize;
2481 int attr;
2482 int namespace;
2483 struct SECURITY_CONTEXT security;
2485 attr = mapped_xattr_system(name);
2486 if (attr != XATTR_UNMAPPED) {
2487 #if POSIXACLS
2489 * hijack internal data and ACL retrieval, whatever
2490 * mode was selected for xattr (from the user's
2491 * point of view, ACLs are not xattr)
2493 ni = ntfs_check_access_xattr(&security,path,attr,FALSE);
2494 if (ni) {
2495 if (ntfs_allowed_access(&security,path,ni,S_IREAD)) {
2497 * the returned value is the needed
2498 * size. If it is too small, no copy
2499 * is done, and the caller has to
2500 * issue a new call with correct size.
2502 switch (attr) {
2503 case XATTR_NTFS_ACL :
2504 res = ntfs_get_ntfs_acl(&security,path,
2505 name,value,size,ni);
2506 break;
2507 case XATTR_POSIX_ACC :
2508 case XATTR_POSIX_DEF :
2509 res = ntfs_get_posix_acl(&security,path,
2510 name,value,size,ni);
2511 break;
2512 case XATTR_NTFS_ATTRIB :
2513 res = ntfs_get_ntfs_attrib(path,
2514 value,size,ni);
2515 break;
2516 case XATTR_NTFS_EFSINFO :
2517 if (ctx->efs_raw)
2518 res = ntfs_get_efs_info(path,
2519 value,size,ni);
2520 else
2521 res = -EPERM;
2522 break;
2523 case XATTR_NTFS_REPARSE_DATA :
2524 res = ntfs_get_ntfs_reparse_data(path,
2525 value,size,ni);
2526 break;
2527 case XATTR_NTFS_DOS_NAME:
2528 res = ntfs_get_ntfs_dos_name(path,
2529 value,size,ni);
2530 break;
2531 case XATTR_NTFS_TIMES:
2532 res = ntfs_inode_get_times(path,
2533 value,size,ni);
2534 break;
2535 default : /* not possible */
2536 break;
2538 } else {
2539 res = -errno;
2541 if (ntfs_inode_close(ni))
2542 set_fuse_error(&res);
2543 } else
2544 res = -errno;
2545 #else
2547 * Only hijack NTFS ACL retrieval if POSIX ACLS
2548 * option is not selected
2549 * Access control is done by fuse
2551 if (ntfs_fuse_is_named_data_stream(path))
2552 res = -EINVAL; /* n/a for named data streams. */
2553 else {
2554 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
2555 if (ni) {
2556 /* user mapping not mandatory */
2557 ntfs_fuse_fill_security_context(&security);
2559 * the returned value is the needed
2560 * size. If it is too small, no copy
2561 * is done, and the caller has to
2562 * issue a new call with correct size.
2564 switch (attr) {
2565 case XATTR_NTFS_ACL :
2566 res = ntfs_get_ntfs_acl(&security,path,
2567 name,value,size,ni);
2568 break;
2569 case XATTR_NTFS_ATTRIB :
2570 res = ntfs_get_ntfs_attrib(path,
2571 value,size,ni);
2572 break;
2573 case XATTR_NTFS_EFSINFO :
2574 if (ctx->efs_raw)
2575 res = ntfs_get_efs_info(path,
2576 value,size,ni);
2577 else
2578 res = -EPERM;
2579 break;
2580 case XATTR_NTFS_REPARSE_DATA :
2581 res = ntfs_get_ntfs_reparse_data(path,
2582 value,size,ni);
2583 break;
2584 case XATTR_NTFS_DOS_NAME:
2585 res = ntfs_get_ntfs_dos_name(path,
2586 value,size,ni);
2587 break;
2588 case XATTR_NTFS_TIMES:
2589 res = ntfs_inode_get_times(path,
2590 value,size,ni);
2591 break;
2592 default :
2594 * make sure applications do not see
2595 * Posix ACL not consistent with mode
2597 errno = EOPNOTSUPP;
2598 res = -errno;
2599 break;
2601 if (ntfs_inode_close(ni))
2602 set_fuse_error(&res);
2603 } else
2604 res = -errno;
2606 #endif
2607 return (res);
2609 if (ctx->streams == NF_STREAMS_INTERFACE_WINDOWS)
2610 return ntfs_fuse_getxattr_windows(path, name, value, size);
2611 if (ctx->streams == NF_STREAMS_INTERFACE_NONE)
2612 return -EOPNOTSUPP;
2613 namespace = xattr_namespace(name);
2614 if (namespace == XATTRNS_NONE)
2615 return -EOPNOTSUPP;
2616 #if POSIXACLS
2617 /* parent directory must be executable */
2618 if (ntfs_fuse_fill_security_context(&security)
2619 && !ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
2620 return (-errno);
2622 /* trusted only readable by root */
2623 if ((namespace == XATTRNS_TRUSTED)
2624 && security.uid)
2625 return -EPERM;
2626 #endif
2627 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
2628 if (!ni)
2629 return -errno;
2630 #if POSIXACLS
2631 /* file must be readable */
2632 if (!ntfs_allowed_access(&security, path, ni, S_IREAD)) {
2633 res = -errno;
2634 goto exit;
2636 #endif
2637 lename_len = fix_xattr_prefix(name, namespace, &lename);
2638 if (lename_len == -1) {
2639 res = -errno;
2640 goto exit;
2642 na = ntfs_attr_open(ni, AT_DATA, lename, lename_len);
2643 if (!na) {
2644 res = -ENODATA;
2645 goto exit;
2647 rsize = na->data_size;
2648 if (ctx->efs_raw &&
2649 (na->data_flags & ATTR_IS_ENCRYPTED) &&
2650 NAttrNonResident(na))
2651 rsize = ((na->data_size + 511) & ~511)+2;
2652 if (size) {
2653 if (size >= (size_t)rsize) {
2654 res = ntfs_attr_pread(na, 0, rsize, value);
2655 if (res != rsize)
2656 res = -errno;
2657 } else
2658 res = -ERANGE;
2659 } else
2660 res = rsize;
2661 exit:
2662 if (na)
2663 ntfs_attr_close(na);
2664 free(lename);
2665 if (ntfs_inode_close(ni))
2666 set_fuse_error(&res);
2667 return res;
2670 static int ntfs_fuse_setxattr(const char *path, const char *name,
2671 const char *value, size_t size, int flags)
2673 ntfs_inode *ni;
2674 ntfs_attr *na = NULL;
2675 ntfschar *lename = NULL;
2676 int res, lename_len;
2677 size_t part, total;
2678 int attr;
2679 int namespace;
2680 struct SECURITY_CONTEXT security;
2682 attr = mapped_xattr_system(name);
2683 if (attr != XATTR_UNMAPPED) {
2684 #if POSIXACLS
2686 * hijack internal data and ACL setting, whatever
2687 * mode was selected for xattr (from the user's
2688 * point of view, ACLs are not xattr)
2689 * Note : updating an ACL does not set ctime
2691 ni = ntfs_check_access_xattr(&security,path,attr,TRUE);
2692 if (ni) {
2693 if (ntfs_allowed_as_owner(&security,path,ni)) {
2694 switch (attr) {
2695 case XATTR_NTFS_ACL :
2696 res = ntfs_set_ntfs_acl(&security,path,
2697 name,value,size,flags,ni);
2698 break;
2699 case XATTR_POSIX_ACC :
2700 case XATTR_POSIX_DEF :
2701 res = ntfs_set_posix_acl(&security,path,
2702 name,value,size,flags,ni);
2703 break;
2704 case XATTR_NTFS_ATTRIB :
2705 res = ntfs_set_ntfs_attrib(path,
2706 value,size,flags,ni);
2707 break;
2708 case XATTR_NTFS_EFSINFO :
2709 if (ctx->efs_raw)
2710 res = ntfs_set_efs_info(path,
2711 value,size,flags,ni);
2712 else
2713 res = -EPERM;
2714 break;
2715 case XATTR_NTFS_REPARSE_DATA :
2716 res = ntfs_set_ntfs_reparse_data(path,
2717 value,size,flags,ni);
2718 break;
2719 case XATTR_NTFS_DOS_NAME:
2720 /* warning : this closes the inode */
2721 res = ntfs_set_ntfs_dos_name(path,
2722 value,size,flags,ni);
2723 break;
2724 case XATTR_NTFS_TIMES:
2725 res = ntfs_inode_set_times(path,
2726 value,size,flags,ni);
2727 break;
2728 default : /* not possible */
2729 break;
2731 if (res)
2732 res = -errno;
2733 } else
2734 res = -errno;
2735 if ((attr != XATTR_NTFS_DOS_NAME)
2736 && ntfs_inode_close(ni))
2737 set_fuse_error(&res);
2738 } else
2739 res = -errno;
2740 #else
2742 * Only hijack NTFS ACL setting if POSIX ACLS
2743 * option is not selected
2744 * Access control is partially done by fuse
2746 if (ntfs_fuse_is_named_data_stream(path))
2747 res = -EINVAL; /* n/a for named data streams. */
2748 else {
2749 /* creation of a new name is not controlled by fuse */
2750 if (attr == XATTR_NTFS_DOS_NAME)
2751 ni = ntfs_check_access_xattr(&security,path,attr,TRUE);
2752 else
2753 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
2754 if (ni) {
2756 * user mapping is not mandatory
2757 * if defined, only owner is allowed
2759 if (!ntfs_fuse_fill_security_context(&security)
2760 || ntfs_allowed_as_owner(&security,path,ni)) {
2761 switch (attr) {
2762 case XATTR_NTFS_ACL :
2763 res = ntfs_set_ntfs_acl(&security,path,
2764 name,value,size,flags,ni);
2765 break;
2766 case XATTR_NTFS_ATTRIB :
2767 res = ntfs_set_ntfs_attrib(path,
2768 value,size,flags,ni);
2769 break;
2770 case XATTR_NTFS_EFSINFO :
2771 if (ctx->efs_raw)
2772 res = ntfs_set_efs_info(path,
2773 value,size,flags,ni);
2774 else
2775 res = -EPERM;
2776 break;
2777 case XATTR_NTFS_REPARSE_DATA :
2778 res = ntfs_set_ntfs_reparse_data(path,
2779 value,size,flags,ni);
2780 break;
2781 case XATTR_NTFS_DOS_NAME:
2782 /* warning : this closes the inode */
2783 res = ntfs_set_ntfs_dos_name(path,
2784 value,size,flags,ni);
2785 break;
2786 case XATTR_NTFS_TIMES:
2787 res = ntfs_inode_set_times(path,
2788 value,size,flags,ni);
2789 break;
2790 default :
2792 * make sure applications do not see
2793 * Posix ACL not consistent with mode
2795 errno = EOPNOTSUPP;
2796 res = -errno;
2797 break;
2799 if (res)
2800 res = -errno;
2801 } else
2802 res = -errno;
2803 if ((attr != XATTR_NTFS_DOS_NAME)
2804 && ntfs_inode_close(ni))
2805 set_fuse_error(&res);
2806 } else
2807 res = -errno;
2809 #endif
2810 return (res);
2812 if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR)
2813 && (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR))
2814 return -EOPNOTSUPP;
2815 namespace = xattr_namespace(name);
2816 if (namespace == XATTRNS_NONE)
2817 return -EOPNOTSUPP;
2818 #if POSIXACLS
2819 /* parent directory must be executable */
2820 if (ntfs_fuse_fill_security_context(&security)
2821 && !ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
2822 return (-errno);
2824 /* security and trusted only settable by root */
2825 if (((namespace == XATTRNS_SECURITY)
2826 || (namespace == XATTRNS_TRUSTED))
2827 && security.uid)
2828 return -EPERM;
2829 #endif
2830 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
2831 if (!ni)
2832 return -errno;
2833 #if POSIXACLS
2834 switch (namespace) {
2835 case XATTRNS_SECURITY :
2836 case XATTRNS_TRUSTED :
2837 if (security.uid) {
2838 res = -EPERM;
2839 goto exit;
2841 break;
2842 case XATTRNS_SYSTEM :
2843 if (!ntfs_allowed_as_owner(&security,path,ni)) {
2844 res = -EACCES;
2845 goto exit;
2847 break;
2848 default :
2849 if (!ntfs_allowed_access(&security,path,ni,S_IWRITE)) {
2850 res = -EACCES;
2851 goto exit;
2853 break;
2855 #endif
2856 lename_len = fix_xattr_prefix(name, namespace, &lename);
2857 if (lename_len == -1) {
2858 res = -errno;
2859 goto exit;
2861 na = ntfs_attr_open(ni, AT_DATA, lename, lename_len);
2862 if (na && flags == XATTR_CREATE) {
2863 res = -EEXIST;
2864 goto exit;
2866 if (!na) {
2867 if (flags == XATTR_REPLACE) {
2868 res = -ENODATA;
2869 goto exit;
2871 if (ntfs_attr_add(ni, AT_DATA, lename, lename_len, NULL, 0)) {
2872 res = -errno;
2873 goto exit;
2875 set_archive(ni);
2876 na = ntfs_attr_open(ni, AT_DATA, lename, lename_len);
2877 if (!na) {
2878 res = -errno;
2879 goto exit;
2881 } else {
2882 /* currently compressed streams can only be wiped out */
2883 if (ntfs_attr_truncate(na, (s64)0 /* size */)) {
2884 res = -errno;
2885 goto exit;
2888 total = 0;
2889 if (size) {
2890 do {
2891 part = ntfs_attr_pwrite(na, total, size - total,
2892 &value[total]);
2893 if (part > 0)
2894 total += part;
2895 } while ((part > 0) && (total < size));
2896 if (total != size)
2897 res = -errno;
2898 else
2899 if (!(res = ntfs_attr_pclose(na)))
2900 if (ctx->efs_raw
2901 && (ni->flags & FILE_ATTR_ENCRYPTED))
2902 res = ntfs_efs_fixup_attribute(NULL,
2903 na);
2904 if (total)
2905 set_archive(ni);
2906 } else
2907 res = 0;
2908 exit:
2909 if (na)
2910 ntfs_attr_close(na);
2911 free(lename);
2912 if (ntfs_inode_close(ni))
2913 set_fuse_error(&res);
2914 return res;
2917 static int ntfs_fuse_removexattr(const char *path, const char *name)
2919 ntfs_inode *ni;
2920 ntfschar *lename = NULL;
2921 int res = 0, lename_len;
2922 int attr;
2923 int namespace;
2924 struct SECURITY_CONTEXT security;
2926 attr = mapped_xattr_system(name);
2927 if (attr != XATTR_UNMAPPED) {
2928 #if POSIXACLS
2931 * hijack internal data and ACL removal, whatever
2932 * mode was selected for xattr (from the user's
2933 * point of view, ACLs are not xattr)
2934 * Note : updating an ACL does not set ctime
2936 res = 0;
2937 switch (attr) {
2939 * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
2940 * is never allowed
2942 case XATTR_NTFS_ACL :
2943 case XATTR_NTFS_ATTRIB :
2944 case XATTR_NTFS_EFSINFO :
2945 case XATTR_NTFS_TIMES :
2946 res = -EPERM;
2947 break;
2948 case XATTR_POSIX_ACC :
2949 case XATTR_POSIX_DEF :
2950 ni = ntfs_check_access_xattr(&security,path,attr,TRUE);
2951 if (ni) {
2952 if (!ntfs_allowed_as_owner(&security,path,ni)
2953 || ntfs_remove_posix_acl(&security,path,
2954 name,ni))
2955 res = -errno;
2956 if (ntfs_inode_close(ni))
2957 set_fuse_error(&res);
2958 } else
2959 res = -errno;
2960 break;
2961 case XATTR_NTFS_REPARSE_DATA :
2962 ni = ntfs_check_access_xattr(&security,path,attr,TRUE);
2963 if (ni) {
2964 if (!ntfs_allowed_as_owner(&security,path,ni)
2965 || ntfs_remove_ntfs_reparse_data(path,ni))
2966 res = -errno;
2967 if (ntfs_inode_close(ni))
2968 set_fuse_error(&res);
2969 } else
2970 res = -errno;
2971 break;
2972 case XATTR_NTFS_DOS_NAME:
2973 ni = ntfs_check_access_xattr(&security,path,attr,TRUE);
2974 if (ni) {
2975 if (ntfs_remove_ntfs_dos_name(path,ni))
2976 res = -errno;
2977 } else
2978 res = -errno;
2979 break;
2980 default :
2981 errno = EOPNOTSUPP;
2982 res = -errno;
2983 break;
2984 break;
2986 #else
2988 * Only hijack NTFS ACL and ATTRIB removal if POSIX ACLS
2989 * option is not selected
2990 * Access control is partially done by fuse
2992 if (ntfs_fuse_is_named_data_stream(path))
2993 res = -EINVAL; /* n/a for named data streams. */
2994 else {
2995 switch (attr) {
2997 * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
2998 * is never allowed
3000 case XATTR_NTFS_ACL :
3001 case XATTR_NTFS_ATTRIB :
3002 case XATTR_NTFS_EFSINFO :
3003 case XATTR_NTFS_TIMES :
3004 res = -EPERM;
3005 break;
3006 case XATTR_NTFS_REPARSE_DATA :
3007 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
3008 if (ni) {
3010 * user mapping is not mandatory
3011 * if defined, only owner is allowed
3013 if ((ntfs_fuse_fill_security_context(&security)
3014 && !ntfs_allowed_as_owner(&security,path,ni))
3015 || ntfs_remove_ntfs_reparse_data(path,ni))
3016 res = -errno;
3017 if (ntfs_inode_close(ni))
3018 set_fuse_error(&res);
3019 } else
3020 res = -errno;
3021 break;
3022 case XATTR_NTFS_DOS_NAME:
3023 ni = ntfs_check_access_xattr(&security,path,attr,TRUE);
3024 if (ni) {
3025 if (ntfs_remove_ntfs_dos_name(path,ni))
3026 res = -errno;
3027 } else
3028 res = -errno;
3029 break;
3030 default :
3032 * make sure applications do not see
3033 * Posix ACL not consistent with mode
3035 errno = EOPNOTSUPP;
3036 res = -errno;
3037 break;
3040 #endif
3041 return (res);
3043 if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR)
3044 && (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR))
3045 return -EOPNOTSUPP;
3046 namespace = xattr_namespace(name);
3047 if (namespace == XATTRNS_NONE)
3048 return -EOPNOTSUPP;
3049 #if POSIXACLS
3050 /* parent directory must be executable */
3051 if (ntfs_fuse_fill_security_context(&security)
3052 && !ntfs_allowed_dir_access(&security,path,S_IEXEC)) {
3053 return (-errno);
3055 /* security and trusted only settable by root */
3056 if (((namespace == XATTRNS_SECURITY)
3057 || (namespace == XATTRNS_TRUSTED))
3058 && security.uid)
3059 return -EACCES;
3060 #endif
3061 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
3062 if (!ni)
3063 return -errno;
3064 #if POSIXACLS
3065 switch (namespace) {
3066 case XATTRNS_SECURITY :
3067 case XATTRNS_TRUSTED :
3068 if (security.uid) {
3069 res = -EPERM;
3070 goto exit;
3072 break;
3073 case XATTRNS_SYSTEM :
3074 if (!ntfs_allowed_as_owner(&security,path,ni)) {
3075 res = -EACCES;
3076 goto exit;
3078 break;
3079 default :
3080 if (!ntfs_allowed_access(&security,path,ni,S_IWRITE)) {
3081 res = -EACCES;
3082 goto exit;
3084 break;
3086 #endif
3087 lename_len = fix_xattr_prefix(name, namespace, &lename);
3088 if (lename_len == -1) {
3089 res = -errno;
3090 goto exit;
3092 if (ntfs_attr_remove(ni, AT_DATA, lename, lename_len)) {
3093 if (errno == ENOENT)
3094 errno = ENODATA;
3095 res = -errno;
3097 set_archive(ni);
3098 exit:
3099 free(lename);
3100 if (ntfs_inode_close(ni))
3101 set_fuse_error(&res);
3102 return res;
3105 #else
3106 #if POSIXACLS
3107 #error "Option inconsistency : POSIXACLS requires SETXATTR"
3108 #endif
3109 #endif /* HAVE_SETXATTR */
3111 static void ntfs_close(void)
3113 struct SECURITY_CONTEXT security;
3115 if (!ctx)
3116 return;
3118 if (!ctx->vol)
3119 return;
3121 if (ctx->mounted) {
3122 ntfs_log_info("Unmounting %s (%s)\n", opts.device,
3123 ctx->vol->vol_name);
3124 if (ntfs_fuse_fill_security_context(&security)) {
3125 if (ctx->seccache && ctx->seccache->head.p_reads) {
3126 ntfs_log_info("Permissions cache : %lu writes, "
3127 "%lu reads, %lu.%1lu%% hits\n",
3128 ctx->seccache->head.p_writes,
3129 ctx->seccache->head.p_reads,
3130 100 * ctx->seccache->head.p_hits
3131 / ctx->seccache->head.p_reads,
3132 1000 * ctx->seccache->head.p_hits
3133 / ctx->seccache->head.p_reads % 10);
3136 ntfs_close_secure(&security);
3139 if (ntfs_umount(ctx->vol, FALSE))
3140 ntfs_log_perror("Failed to close volume %s", opts.device);
3142 ctx->vol = NULL;
3145 static void ntfs_fuse_destroy2(void *unused __attribute__((unused)))
3147 ntfs_close();
3150 static struct fuse_operations ntfs_3g_ops = {
3151 .getattr = ntfs_fuse_getattr,
3152 .readlink = ntfs_fuse_readlink,
3153 .readdir = ntfs_fuse_readdir,
3154 .open = ntfs_fuse_open,
3155 .release = ntfs_fuse_release,
3156 .read = ntfs_fuse_read,
3157 .write = ntfs_fuse_write,
3158 .truncate = ntfs_fuse_truncate,
3159 .ftruncate = ntfs_fuse_ftruncate,
3160 .statfs = ntfs_fuse_statfs,
3161 .chmod = ntfs_fuse_chmod,
3162 .chown = ntfs_fuse_chown,
3163 .create = ntfs_fuse_create_file,
3164 .mknod = ntfs_fuse_mknod,
3165 .symlink = ntfs_fuse_symlink,
3166 .link = ntfs_fuse_link,
3167 .unlink = ntfs_fuse_unlink,
3168 .rename = ntfs_fuse_rename,
3169 .mkdir = ntfs_fuse_mkdir,
3170 .rmdir = ntfs_fuse_rmdir,
3171 .utime = ntfs_fuse_utime,
3172 .bmap = ntfs_fuse_bmap,
3173 .destroy = ntfs_fuse_destroy2,
3174 #if POSIXACLS
3175 .access = ntfs_fuse_access,
3176 .opendir = ntfs_fuse_opendir,
3177 #endif
3178 #ifdef HAVE_SETXATTR
3179 .getxattr = ntfs_fuse_getxattr,
3180 .setxattr = ntfs_fuse_setxattr,
3181 .removexattr = ntfs_fuse_removexattr,
3182 .listxattr = ntfs_fuse_listxattr,
3183 #endif /* HAVE_SETXATTR */
3184 #if defined(__APPLE__) || defined(__DARWIN__)
3185 .init = ntfs_macfuse_init,
3186 /* MacFUSE extensions. */
3187 .getxtimes = ntfs_macfuse_getxtimes,
3188 .setcrtime = ntfs_macfuse_setcrtime,
3189 .setbkuptime = ntfs_macfuse_setbkuptime,
3190 .setchgtime = ntfs_macfuse_setchgtime,
3191 #else /* defined(__APPLE__) || defined(__DARWIN__) */
3192 #ifdef FUSE_CAP_DONT_MASK
3193 .init = ntfs_init
3194 #endif
3195 #endif /* defined(__APPLE__) || defined(__DARWIN__) */
3198 static int ntfs_fuse_init(void)
3200 ctx = ntfs_calloc(sizeof(ntfs_fuse_context_t));
3201 if (!ctx)
3202 return -1;
3204 *ctx = (ntfs_fuse_context_t) {
3205 .uid = getuid(),
3206 .gid = getgid(),
3207 #if defined(linux)
3208 .streams = NF_STREAMS_INTERFACE_XATTR,
3209 #else
3210 .streams = NF_STREAMS_INTERFACE_NONE,
3211 #endif
3212 .atime = ATIME_RELATIVE,
3213 .silent = TRUE,
3214 .recover = TRUE
3216 return 0;
3219 static int ntfs_open(const char *device)
3221 unsigned long flags = 0;
3223 if (!ctx->blkdev)
3224 flags |= MS_EXCLUSIVE;
3225 if (ctx->ro)
3226 flags |= MS_RDONLY;
3227 if (ctx->recover)
3228 flags |= MS_RECOVER;
3229 if (ctx->hiberfile)
3230 flags |= MS_IGNORE_HIBERFILE;
3232 ctx->vol = ntfs_mount(device, flags);
3233 if (!ctx->vol) {
3234 ntfs_log_perror("Failed to mount '%s'", device);
3235 goto err_out;
3238 ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na);
3239 if (ctx->vol->free_clusters < 0) {
3240 ntfs_log_perror("Failed to read NTFS $Bitmap");
3241 goto err_out;
3244 ctx->vol->free_mft_records = ntfs_get_nr_free_mft_records(ctx->vol);
3245 if (ctx->vol->free_mft_records < 0) {
3246 ntfs_log_perror("Failed to calculate free MFT records");
3247 goto err_out;
3250 if (ctx->hiberfile && ntfs_volume_check_hiberfile(ctx->vol, 0)) {
3251 if (errno != EPERM)
3252 goto err_out;
3253 if (ntfs_fuse_rm("/hiberfil.sys"))
3254 goto err_out;
3257 errno = 0;
3258 err_out:
3259 return ntfs_volume_error(errno);
3263 #define STRAPPEND_MAX_INSIZE 8192
3264 #define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
3266 static int strappend(char **dest, const char *append)
3268 char *p;
3269 size_t size_append, size_dest = 0;
3271 if (!dest)
3272 return -1;
3273 if (!append)
3274 return 0;
3276 size_append = strlen(append);
3277 if (*dest)
3278 size_dest = strlen(*dest);
3280 if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
3281 errno = EOVERFLOW;
3282 ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
3283 return -1;
3286 p = realloc(*dest, size_dest + size_append + 1);
3287 if (!p) {
3288 ntfs_log_perror("%s: Memory realloction failed", EXEC_NAME);
3289 return -1;
3292 *dest = p;
3293 strcpy(*dest + size_dest, append);
3295 return 0;
3298 static int bogus_option_value(char *val, const char *s)
3300 if (val) {
3301 ntfs_log_error("'%s' option shouldn't have value.\n", s);
3302 return -1;
3304 return 0;
3307 static int missing_option_value(char *val, const char *s)
3309 if (!val) {
3310 ntfs_log_error("'%s' option should have a value.\n", s);
3311 return -1;
3313 return 0;
3316 static char *parse_mount_options(const char *orig_opts)
3318 char *options, *s, *opt, *val, *ret = NULL;
3319 BOOL no_def_opts = FALSE;
3320 int default_permissions = 0;
3321 int want_permissions = 0;
3323 ctx->secure_flags = 0;
3324 ctx->efs_raw = FALSE;
3325 options = strdup(orig_opts ? orig_opts : "");
3326 if (!options) {
3327 ntfs_log_perror("%s: strdup failed", EXEC_NAME);
3328 return NULL;
3331 s = options;
3332 while (s && *s && (val = strsep(&s, ","))) {
3333 opt = strsep(&val, "=");
3334 if (!strcmp(opt, "ro")) { /* Read-only mount. */
3335 if (bogus_option_value(val, "ro"))
3336 goto err_exit;
3337 ctx->ro = TRUE;
3338 if (strappend(&ret, "ro,"))
3339 goto err_exit;
3340 } else if (!strcmp(opt, "noatime")) {
3341 if (bogus_option_value(val, "noatime"))
3342 goto err_exit;
3343 ctx->atime = ATIME_DISABLED;
3344 } else if (!strcmp(opt, "atime")) {
3345 if (bogus_option_value(val, "atime"))
3346 goto err_exit;
3347 ctx->atime = ATIME_ENABLED;
3348 } else if (!strcmp(opt, "relatime")) {
3349 if (bogus_option_value(val, "relatime"))
3350 goto err_exit;
3351 ctx->atime = ATIME_RELATIVE;
3352 } else if (!strcmp(opt, "fake_rw")) {
3353 if (bogus_option_value(val, "fake_rw"))
3354 goto err_exit;
3355 ctx->ro = TRUE;
3356 } else if (!strcmp(opt, "fsname")) { /* Filesystem name. */
3358 * We need this to be able to check whether filesystem
3359 * mounted or not.
3361 ntfs_log_error("'fsname' is unsupported option.\n");
3362 goto err_exit;
3363 } else if (!strcmp(opt, "no_def_opts")) {
3364 if (bogus_option_value(val, "no_def_opts"))
3365 goto err_exit;
3366 no_def_opts = TRUE; /* Don't add default options. */
3367 } else if (!strcmp(opt, "default_permissions")) {
3368 default_permissions = 1;
3369 } else if (!strcmp(opt, "umask")) {
3370 if (missing_option_value(val, "umask"))
3371 goto err_exit;
3372 sscanf(val, "%o", &ctx->fmask);
3373 ctx->dmask = ctx->fmask;
3374 #if !POSIXACLS
3375 default_permissions = 1;
3376 #endif
3377 } else if (!strcmp(opt, "fmask")) {
3378 if (missing_option_value(val, "fmask"))
3379 goto err_exit;
3380 sscanf(val, "%o", &ctx->fmask);
3381 want_permissions = 1;
3382 } else if (!strcmp(opt, "dmask")) {
3383 if (missing_option_value(val, "dmask"))
3384 goto err_exit;
3385 sscanf(val, "%o", &ctx->dmask);
3386 want_permissions = 1;
3387 } else if (!strcmp(opt, "uid")) {
3388 if (missing_option_value(val, "uid"))
3389 goto err_exit;
3390 sscanf(val, "%i", &ctx->uid);
3391 want_permissions = 1;
3392 } else if (!strcmp(opt, "gid")) {
3393 if (missing_option_value(val, "gid"))
3394 goto err_exit;
3395 sscanf(val, "%i", &ctx->gid);
3396 want_permissions = 1;
3397 } else if (!strcmp(opt, "show_sys_files")) {
3398 if (bogus_option_value(val, "show_sys_files"))
3399 goto err_exit;
3400 ctx->show_sys_files = TRUE;
3401 } else if (!strcmp(opt, "silent")) {
3402 if (bogus_option_value(val, "silent"))
3403 goto err_exit;
3404 ctx->silent = TRUE;
3405 } else if (!strcmp(opt, "recover")) {
3406 if (bogus_option_value(val, "recover"))
3407 goto err_exit;
3408 ctx->recover = TRUE;
3409 } else if (!strcmp(opt, "norecover")) {
3410 if (bogus_option_value(val, "norecover"))
3411 goto err_exit;
3412 ctx->recover = FALSE;
3413 } else if (!strcmp(opt, "remove_hiberfile")) {
3414 if (bogus_option_value(val, "remove_hiberfile"))
3415 goto err_exit;
3416 ctx->hiberfile = TRUE;
3417 } else if (!strcmp(opt, "locale")) {
3418 if (missing_option_value(val, "locale"))
3419 goto err_exit;
3420 ntfs_set_char_encoding(val);
3421 #if defined(__APPLE__) || defined(__DARWIN__)
3422 #ifdef ENABLE_NFCONV
3423 } else if (!strcmp(opt, "nfconv")) {
3424 if (bogus_option_value(val, "nfconv"))
3425 goto err_exit;
3426 if (ntfs_macosx_normalize_filenames(1)) {
3427 ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n");
3428 goto err_exit;
3430 } else if (!strcmp(opt, "nonfconv")) {
3431 if (bogus_option_value(val, "nonfconv"))
3432 goto err_exit;
3433 if (ntfs_macosx_normalize_filenames(0)) {
3434 ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n");
3435 goto err_exit;
3437 #endif /* ENABLE_NFCONV */
3438 #endif /* defined(__APPLE__) || defined(__DARWIN__) */
3439 } else if (!strcmp(opt, "streams_interface")) {
3440 if (missing_option_value(val, "streams_interface"))
3441 goto err_exit;
3442 if (!strcmp(val, "none"))
3443 ctx->streams = NF_STREAMS_INTERFACE_NONE;
3444 else if (!strcmp(val, "xattr"))
3445 ctx->streams = NF_STREAMS_INTERFACE_XATTR;
3446 else if (!strcmp(val, "openxattr"))
3447 ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR;
3448 else if (!strcmp(val, "windows"))
3449 ctx->streams = NF_STREAMS_INTERFACE_WINDOWS;
3450 else {
3451 ntfs_log_error("Invalid named data streams "
3452 "access interface.\n");
3453 goto err_exit;
3455 } else if (!strcmp(opt, "user_xattr")) {
3456 ctx->streams = NF_STREAMS_INTERFACE_XATTR;
3457 } else if (!strcmp(opt, "noauto")) {
3458 /* Don't pass noauto option to fuse. */
3459 } else if (!strcmp(opt, "debug")) {
3460 if (bogus_option_value(val, "debug"))
3461 goto err_exit;
3462 ctx->debug = TRUE;
3463 ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
3464 ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
3465 } else if (!strcmp(opt, "no_detach")) {
3466 if (bogus_option_value(val, "no_detach"))
3467 goto err_exit;
3468 ctx->no_detach = TRUE;
3469 } else if (!strcmp(opt, "remount")) {
3470 ntfs_log_error("Remounting is not supported at present."
3471 " You have to umount volume and then "
3472 "mount it once again.\n");
3473 goto err_exit;
3474 } else if (!strcmp(opt, "blksize")) {
3475 ntfs_log_info("WARNING: blksize option is ignored "
3476 "because ntfs-3g must calculate it.\n");
3477 } else if (!strcmp(opt, "inherit")) {
3479 * JPA do not overwrite inherited permissions
3480 * in create()
3482 ctx->inherit = TRUE;
3483 } else if (!strcmp(opt, "addsecurids")) {
3485 * JPA create security ids for files being read
3486 * with an individual security attribute
3488 ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS);
3489 } else if (!strcmp(opt, "staticgrps")) {
3491 * JPA use static definition of groups
3492 * for file access control
3494 ctx->secure_flags |= (1 << SECURITY_STATICGRPS);
3495 } else if (!strcmp(opt, "usermapping")) {
3496 if (!val) {
3497 ntfs_log_error("'usermapping' option should have "
3498 "a value.\n");
3499 goto err_exit;
3501 ctx->usermap_path = strdup(val);
3502 if (!ctx->usermap_path) {
3503 ntfs_log_error("no more memory to store "
3504 "'usermapping' option.\n");
3505 goto err_exit;
3507 } else if (!strcmp(opt, "efs_raw")) {
3508 if (bogus_option_value(val, "efs_raw"))
3509 goto err_exit;
3510 ctx->efs_raw = TRUE;
3511 } else { /* Probably FUSE option. */
3512 if (strappend(&ret, opt))
3513 goto err_exit;
3514 if (val) {
3515 if (strappend(&ret, "="))
3516 goto err_exit;
3517 if (strappend(&ret, val))
3518 goto err_exit;
3520 if (strappend(&ret, ","))
3521 goto err_exit;
3524 if (!no_def_opts && strappend(&ret, def_opts))
3525 goto err_exit;
3526 if (default_permissions && strappend(&ret, "default_permissions,"))
3527 goto err_exit;
3529 if (ctx->atime == ATIME_RELATIVE && strappend(&ret, "relatime,"))
3530 goto err_exit;
3531 else if (ctx->atime == ATIME_ENABLED && strappend(&ret, "atime,"))
3532 goto err_exit;
3533 else if (ctx->atime == ATIME_DISABLED && strappend(&ret, "noatime,"))
3534 goto err_exit;
3536 if (strappend(&ret, "fsname="))
3537 goto err_exit;
3538 if (strappend(&ret, opts.device))
3539 goto err_exit;
3540 if (default_permissions)
3541 ctx->secure_flags |= (1 << SECURITY_DEFAULT);
3542 if (want_permissions)
3543 ctx->secure_flags |= (1 << SECURITY_WANTED);
3544 if (ctx->ro)
3545 ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS);
3546 exit:
3547 free(options);
3548 return ret;
3549 err_exit:
3550 free(ret);
3551 ret = NULL;
3552 goto exit;
3555 static void usage(void)
3557 ntfs_log_info(usage_msg, EXEC_NAME, VERSION, FUSE_TYPE, fuse_version(),
3558 EXEC_NAME, ntfs_home);
3561 #ifndef HAVE_REALPATH
3562 /* If there is no realpath() on the system, provide a dummy one. */
3563 static char *realpath(const char *path, char *resolved_path)
3565 strncpy(resolved_path, path, PATH_MAX);
3566 resolved_path[PATH_MAX] = '\0';
3567 return resolved_path;
3569 #endif
3572 * parse_options - Read and validate the programs command line
3573 * Read the command line, verify the syntax and parse the options.
3575 * Return: 0 success, -1 error.
3577 static int parse_options(int argc, char *argv[])
3579 int c;
3581 static const char *sopt = "-o:hvV";
3582 static const struct option lopt[] = {
3583 { "options", required_argument, NULL, 'o' },
3584 { "help", no_argument, NULL, 'h' },
3585 { "verbose", no_argument, NULL, 'v' },
3586 { "version", no_argument, NULL, 'V' },
3587 { NULL, 0, NULL, 0 }
3590 opterr = 0; /* We'll handle the errors, thank you. */
3592 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
3593 switch (c) {
3594 case 1: /* A non-option argument */
3595 if (!opts.device) {
3596 opts.device = ntfs_malloc(PATH_MAX + 1);
3597 if (!opts.device)
3598 return -1;
3600 /* Canonicalize device name (mtab, etc) */
3601 if (!realpath(optarg, opts.device)) {
3602 ntfs_log_perror("%s: Failed to access "
3603 "volume '%s'", EXEC_NAME, optarg);
3604 free(opts.device);
3605 opts.device = NULL;
3606 return -1;
3608 } else if (!opts.mnt_point) {
3609 opts.mnt_point = optarg;
3610 } else {
3611 ntfs_log_error("%s: You must specify exactly one "
3612 "device and exactly one mount "
3613 "point.\n", EXEC_NAME);
3614 return -1;
3616 break;
3617 case 'o':
3618 if (opts.options)
3619 if (strappend(&opts.options, ","))
3620 return -1;
3621 if (strappend(&opts.options, optarg))
3622 return -1;
3623 break;
3624 case 'h':
3625 usage();
3626 exit(9);
3627 case 'v':
3629 * We must handle the 'verbose' option even if
3630 * we don't use it because mount(8) passes it.
3632 break;
3633 case 'V':
3634 ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION,
3635 FUSE_TYPE, fuse_version());
3636 exit(0);
3637 default:
3638 ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
3639 argv[optind - 1]);
3640 return -1;
3644 if (!opts.device) {
3645 ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
3646 return -1;
3648 if (!opts.mnt_point) {
3649 ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
3650 return -1;
3653 return 0;
3656 #if defined(linux) || defined(__uClinux__)
3658 static const char *dev_fuse_msg =
3659 "HINT: You should be root, or make ntfs-3g setuid root, or load the FUSE\n"
3660 " kernel module as root ('modprobe fuse' or 'insmod <path_to>/fuse.ko'"
3661 " or insmod <path_to>/fuse.o'). Make also sure that the fuse device"
3662 " exists. It's usually either /dev/fuse or /dev/misc/fuse.";
3664 static const char *fuse26_kmod_msg =
3665 "WARNING: Deficient Linux kernel detected. Some driver features are\n"
3666 " not available (swap file on NTFS, boot from NTFS by LILO), and\n"
3667 " unmount is not safe unless it's made sure the ntfs-3g process\n"
3668 " naturally terminates after calling 'umount'. If you wish this\n"
3669 " message to disappear then you should upgrade to at least kernel\n"
3670 " version 2.6.20, or request help from your distribution to fix\n"
3671 " the kernel problem. The below web page has more information:\n"
3672 " http://ntfs-3g.org/support.html#fuse26\n"
3673 "\n";
3675 static void mknod_dev_fuse(const char *dev)
3677 struct stat st;
3679 if (stat(dev, &st) && (errno == ENOENT)) {
3680 mode_t mask = umask(0);
3681 if (mknod(dev, S_IFCHR | 0666, makedev(10, 229))) {
3682 ntfs_log_perror("Failed to create '%s'", dev);
3683 if (errno == EPERM)
3684 ntfs_log_error("%s", dev_fuse_msg);
3686 umask(mask);
3690 static void create_dev_fuse(void)
3692 mknod_dev_fuse("/dev/fuse");
3694 #ifdef __UCLIBC__
3696 struct stat st;
3697 /* The fuse device is under /dev/misc using devfs. */
3698 if (stat("/dev/misc", &st) && (errno == ENOENT)) {
3699 mode_t mask = umask(0);
3700 mkdir("/dev/misc", 0775);
3701 umask(mask);
3703 mknod_dev_fuse("/dev/misc/fuse");
3705 #endif
3708 static fuse_fstype get_fuse_fstype(void)
3710 char buf[256];
3711 fuse_fstype fstype = FSTYPE_NONE;
3713 FILE *f = fopen("/proc/filesystems", "r");
3714 if (!f) {
3715 ntfs_log_perror("Failed to open /proc/filesystems");
3716 return FSTYPE_UNKNOWN;
3719 while (fgets(buf, sizeof(buf), f)) {
3720 if (strstr(buf, "fuseblk\n")) {
3721 fstype = FSTYPE_FUSEBLK;
3722 break;
3724 if (strstr(buf, "fuse\n"))
3725 fstype = FSTYPE_FUSE;
3728 fclose(f);
3729 return fstype;
3732 static fuse_fstype load_fuse_module(void)
3734 int i;
3735 struct stat st;
3736 pid_t pid;
3737 const char *cmd = "/sbin/modprobe";
3738 struct timespec req = { 0, 100000000 }; /* 100 msec */
3739 fuse_fstype fstype;
3741 if (!stat(cmd, &st) && !geteuid()) {
3742 pid = fork();
3743 if (!pid) {
3744 execl(cmd, cmd, "fuse", NULL);
3745 _exit(1);
3746 } else if (pid != -1)
3747 waitpid(pid, NULL, 0);
3750 for (i = 0; i < 10; i++) {
3752 * We sleep first because despite the detection of the loaded
3753 * FUSE kernel module, fuse_mount() can still fail if it's not
3754 * fully functional/initialized. Note, of course this is still
3755 * unreliable but usually helps.
3757 nanosleep(&req, NULL);
3758 fstype = get_fuse_fstype();
3759 if (fstype != FSTYPE_NONE)
3760 break;
3762 return fstype;
3765 #endif
3767 static struct fuse_chan *try_fuse_mount(char *parsed_options)
3769 struct fuse_chan *fc = NULL;
3770 struct fuse_args margs = FUSE_ARGS_INIT(0, NULL);
3772 /* The fuse_mount() options get modified, so we always rebuild it */
3773 if ((fuse_opt_add_arg(&margs, EXEC_NAME) == -1 ||
3774 fuse_opt_add_arg(&margs, "-o") == -1 ||
3775 fuse_opt_add_arg(&margs, parsed_options) == -1)) {
3776 ntfs_log_error("Failed to set FUSE options.\n");
3777 goto free_args;
3780 fc = fuse_mount(opts.mnt_point, &margs);
3781 free_args:
3782 fuse_opt_free_args(&margs);
3783 return fc;
3787 static int set_fuseblk_options(char **parsed_options)
3789 char options[64];
3790 long pagesize;
3791 u32 blksize = ctx->vol->cluster_size;
3793 pagesize = sysconf(_SC_PAGESIZE);
3794 if (pagesize < 1)
3795 pagesize = 4096;
3797 if (blksize > (u32)pagesize)
3798 blksize = pagesize;
3800 snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize);
3801 if (strappend(parsed_options, options))
3802 return -1;
3803 return 0;
3806 static struct fuse *mount_fuse(char *parsed_options)
3808 struct fuse *fh = NULL;
3809 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
3811 ctx->fc = try_fuse_mount(parsed_options);
3812 if (!ctx->fc)
3813 return NULL;
3815 if (fuse_opt_add_arg(&args, "") == -1)
3816 goto err;
3817 if (fuse_opt_add_arg(&args, "-ouse_ino,kernel_cache,attr_timeout=0") == -1)
3818 goto err;
3819 if (ctx->debug)
3820 if (fuse_opt_add_arg(&args, "-odebug") == -1)
3821 goto err;
3823 fh = fuse_new(ctx->fc, &args , &ntfs_3g_ops, sizeof(ntfs_3g_ops), NULL);
3824 if (!fh)
3825 goto err;
3827 if (fuse_set_signal_handlers(fuse_get_session(fh)))
3828 goto err_destory;
3829 out:
3830 fuse_opt_free_args(&args);
3831 return fh;
3832 err_destory:
3833 fuse_destroy(fh);
3834 fh = NULL;
3835 err:
3836 fuse_unmount(opts.mnt_point, ctx->fc);
3837 goto out;
3840 static void setup_logging(char *parsed_options)
3842 if (!ctx->no_detach) {
3843 if (daemon(0, ctx->debug))
3844 ntfs_log_error("Failed to daemonize.\n");
3845 else if (!ctx->debug) {
3846 #ifndef DEBUG
3847 ntfs_log_set_handler(ntfs_log_handler_syslog);
3848 /* Override default libntfs identify. */
3849 openlog(EXEC_NAME, LOG_PID, LOG_DAEMON);
3850 #endif
3854 ctx->seccache = (struct PERMISSIONS_CACHE*)NULL;
3856 ntfs_log_info("Version %s %s %d\n", VERSION, FUSE_TYPE, fuse_version());
3857 ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS %d.%d)\n",
3858 opts.device, (ctx->ro) ? "Read-Only" : "Read-Write",
3859 ctx->vol->vol_name, ctx->vol->major_ver,
3860 ctx->vol->minor_ver);
3861 ntfs_log_info("Cmdline options: %s\n", opts.options ? opts.options : "");
3862 ntfs_log_info("Mount options: %s\n", parsed_options);
3865 int main(int argc, char *argv[])
3867 char *parsed_options = NULL;
3868 struct fuse *fh;
3869 fuse_fstype fstype = FSTYPE_UNKNOWN;
3870 const char *permissions_mode = (const char*)NULL;
3871 const char *failed_secure = (const char*)NULL;
3872 struct stat sbuf;
3873 int err, fd;
3876 * Make sure file descriptors 0, 1 and 2 are open,
3877 * otherwise chaos would ensue.
3879 do {
3880 fd = open("/dev/null", O_RDWR);
3881 if (fd > 2)
3882 close(fd);
3883 } while (fd >= 0 && fd <= 2);
3885 #ifndef FUSE_INTERNAL
3886 if ((getuid() != geteuid()) || (getgid() != getegid())) {
3887 fprintf(stderr, "%s", setuid_msg);
3888 return NTFS_VOLUME_INSECURE;
3890 #endif
3891 if (drop_privs())
3892 return NTFS_VOLUME_NO_PRIVILEGE;
3894 ntfs_set_locale();
3895 ntfs_log_set_handler(ntfs_log_handler_stderr);
3897 if (parse_options(argc, argv)) {
3898 usage();
3899 return NTFS_VOLUME_SYNTAX_ERROR;
3902 if (ntfs_fuse_init()) {
3903 err = NTFS_VOLUME_OUT_OF_MEMORY;
3904 goto err2;
3907 parsed_options = parse_mount_options(opts.options);
3908 if (!parsed_options) {
3909 err = NTFS_VOLUME_SYNTAX_ERROR;
3910 goto err_out;
3913 ctx->security.uid = 0;
3914 ctx->security.gid = 0;
3915 if ((opts.mnt_point[0] == '/')
3916 && !stat(opts.mnt_point,&sbuf)) {
3917 /* collect owner of mount point, useful for default mapping */
3918 ctx->security.uid = sbuf.st_uid;
3919 ctx->security.gid = sbuf.st_gid;
3922 #if defined(linux) || defined(__uClinux__)
3923 fstype = get_fuse_fstype();
3925 err = NTFS_VOLUME_NO_PRIVILEGE;
3926 if (restore_privs())
3927 goto err_out;
3929 if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN)
3930 fstype = load_fuse_module();
3932 create_dev_fuse();
3934 if (drop_privs())
3935 goto err_out;
3936 #endif
3937 if (stat(opts.device, &sbuf)) {
3938 ntfs_log_perror("Failed to access '%s'", opts.device);
3939 err = NTFS_VOLUME_NO_PRIVILEGE;
3940 goto err_out;
3943 #if !(defined(__sun) && defined (__SVR4))
3944 /* Always use fuseblk for block devices unless it's surely missing. */
3945 if (S_ISBLK(sbuf.st_mode) && (fstype != FSTYPE_FUSE))
3946 ctx->blkdev = TRUE;
3947 #endif
3949 #ifndef FUSE_INTERNAL
3950 if (getuid() && ctx->blkdev) {
3951 ntfs_log_error("%s", unpriv_fuseblk_msg);
3952 goto err2;
3954 #endif
3955 err = ntfs_open(opts.device);
3956 if (err)
3957 goto err_out;
3959 /* We must do this after ntfs_open() to be able to set the blksize */
3960 if (ctx->blkdev && set_fuseblk_options(&parsed_options))
3961 goto err_out;
3963 ctx->security.vol = ctx->vol;
3964 ctx->vol->secure_flags = ctx->secure_flags;
3965 ctx->vol->efs_raw = ctx->efs_raw;
3966 /* JPA open $Secure, (whatever NTFS version !) */
3967 /* to initialize security data */
3968 if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3))
3969 failed_secure = "Could not open file $Secure";
3970 if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path)) {
3971 #if POSIXACLS
3972 if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))
3973 permissions_mode = "User mapping built, Posix ACLs not used";
3974 else
3975 permissions_mode = "User mapping built, Posix ACLs in use";
3976 #else
3977 if (!(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) {
3979 * No explicit option but user mapping found
3980 * force default security
3982 ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
3983 if (strappend(&parsed_options, ",default_permissions")) {
3984 err = NTFS_VOLUME_SYNTAX_ERROR;
3985 goto err_out;
3988 permissions_mode = "User mapping built";
3989 #endif
3990 } else {
3991 ctx->security.uid = ctx->uid;
3992 ctx->security.gid = ctx->gid;
3993 /* same ownership/permissions for all files */
3994 ctx->security.mapping[MAPUSERS] = (struct MAPPING*)NULL;
3995 ctx->security.mapping[MAPGROUPS] = (struct MAPPING*)NULL;
3996 if (ctx->secure_flags & (1 << SECURITY_WANTED))
3997 ctx->secure_flags |= (1 << SECURITY_DEFAULT);
3998 if (ctx->secure_flags & (1 << SECURITY_DEFAULT)) {
3999 ctx->secure_flags |= (1 << SECURITY_RAW);
4000 permissions_mode = "Global ownership and permissions enforced";
4001 } else {
4002 ctx->secure_flags &= ~(1 << SECURITY_RAW);
4003 permissions_mode = "Ownership and permissions disabled";
4006 if (ctx->usermap_path)
4007 free (ctx->usermap_path);
4009 fh = mount_fuse(parsed_options);
4010 if (!fh) {
4011 err = NTFS_VOLUME_FUSE_ERROR;
4012 goto err_out;
4015 ctx->mounted = TRUE;
4017 #if defined(linux) || defined(__uClinux__)
4018 if (S_ISBLK(sbuf.st_mode) && (fstype == FSTYPE_FUSE))
4019 ntfs_log_info("%s", fuse26_kmod_msg);
4020 #endif
4021 setup_logging(parsed_options);
4022 if (failed_secure)
4023 ntfs_log_info("%s\n",failed_secure);
4024 if (permissions_mode)
4025 ntfs_log_info("%s\n",permissions_mode);
4027 fuse_loop(fh);
4029 err = 0;
4031 fuse_unmount(opts.mnt_point, ctx->fc);
4032 fuse_destroy(fh);
4033 err_out:
4034 ntfs_mount_error(opts.device, opts.mnt_point, err);
4035 err2:
4036 ntfs_close();
4037 free(ctx);
4038 free(parsed_options);
4039 free(opts.options);
4040 free(opts.device);
4041 return err;