summaryrefslogtreecommitdiff
path: root/src/lowntfs-3g.c (plain)
blob: b6cdafdb2ef5ec923c9516bcb3cd7b1a9f836584
1/**
2 * ntfs-3g - Third Generation NTFS Driver
3 *
4 * Copyright (c) 2005-2007 Yura Pakhuchiy
5 * Copyright (c) 2005 Yuval Fledel
6 * Copyright (c) 2006-2009 Szabolcs Szakacsits
7 * Copyright (c) 2007-2010 Jean-Pierre Andre
8 * Copyright (c) 2009 Erik Larsson
9 *
10 * This file is originated from the Linux-NTFS project.
11 *
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.
16 *
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.
21 *
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
26 */
27
28#include "config.h"
29
30#include <fuse.h>
31#include <fuse_lowlevel.h>
32
33#if !defined(FUSE_VERSION) || (FUSE_VERSION < 26)
34#error "***********************************************************"
35#error "* *"
36#error "* Compilation requires at least FUSE version 2.6.0! *"
37#error "* *"
38#error "***********************************************************"
39#endif
40
41#ifdef FUSE_INTERNAL
42#define FUSE_TYPE "integrated FUSE low"
43#else
44#define FUSE_TYPE "external FUSE low"
45#endif
46
47#ifdef HAVE_STDIO_H
48#include <stdio.h>
49#endif
50#ifdef HAVE_STRING_H
51#include <string.h>
52#endif
53#ifdef HAVE_ERRNO_H
54#include <errno.h>
55#endif
56#ifdef HAVE_FCNTL_H
57#include <fcntl.h>
58#endif
59#ifdef HAVE_UNISTD_H
60#include <unistd.h>
61#endif
62#ifdef HAVE_STDLIB_H
63#include <stdlib.h>
64#endif
65#ifdef HAVE_LOCALE_H
66#include <locale.h>
67#endif
68#include <signal.h>
69#ifdef HAVE_LIMITS_H
70#include <limits.h>
71#endif
72#include <getopt.h>
73#include <syslog.h>
74#include <sys/wait.h>
75
76#ifdef HAVE_SETXATTR
77#include <sys/xattr.h>
78#endif
79
80#ifdef HAVE_SYS_TYPES_H
81#include <sys/types.h>
82#endif
83#ifdef HAVE_SYS_MKDEV_H
84#include <sys/mkdev.h>
85#endif
86
87#if defined(__APPLE__) || defined(__DARWIN__)
88#include <sys/dirent.h>
89#endif /* defined(__APPLE__) || defined(__DARWIN__) */
90
91#include "compat.h"
92#include "attrib.h"
93#include "inode.h"
94#include "volume.h"
95#include "dir.h"
96#include "unistr.h"
97#include "layout.h"
98#include "index.h"
99#include "ntfstime.h"
100#include "security.h"
101#include "reparse.h"
102#include "object_id.h"
103#include "efs.h"
104#include "logging.h"
105#include "misc.h"
106
107/*
108 * The following permission checking modes are governed by
109 * the LPERMSCONFIG value in param.h
110 */
111
112/* ACLS may be checked by kernel (requires a fuse patch) or here */
113#define KERNELACLS ((LPERMSCONFIG > 6) & (LPERMSCONFIG < 10))
114/* basic permissions may be checked by kernel or here */
115#define KERNELPERMS (((LPERMSCONFIG - 1) % 6) < 3)
116/* may want to use fuse/kernel cacheing */
117#define CACHEING (!(LPERMSCONFIG % 3))
118
119#if KERNELACLS & !KERNELPERMS
120#error "Incompatible options KERNELACLS and KERNELPERMS"
121#endif
122
123#if CACHEING & (KERNELACLS | !KERNELPERMS)
124#warning "Fuse cacheing is broken unless basic permissions checked by kernel"
125#endif
126
127#if !CACHEING
128 /*
129 * FUSE cacheing is broken except for basic permissions
130 * checked by the kernel
131 * So do not use cacheing until this is fixed
132 */
133#define ATTR_TIMEOUT 0.0
134#define ENTRY_TIMEOUT 0.0
135#else
136#define ATTR_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0)
137#define ENTRY_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0)
138#endif
139#define GHOSTLTH 40 /* max length of a ghost file name - see ghostformat */
140
141 /* sometimes the kernel cannot check access */
142#define ntfs_real_allowed_access(scx, ni, type) ntfs_allowed_access(scx, ni, type)
143#if POSIXACLS & KERNELPERMS & !KERNELACLS
144 /* short-circuit if PERMS checked by kernel and ACLs by fs */
145#define ntfs_allowed_access(scx, ni, type) \
146 ((scx)->vol->secure_flags & (1 << SECURITY_DEFAULT) \
147 ? 1 : ntfs_allowed_access(scx, ni, type))
148#endif
149
150#define set_archive(ni) (ni)->flags |= FILE_ATTR_ARCHIVE
151#define INODE(ino) ((ino) == 1 ? (MFT_REF)FILE_root : (MFT_REF)(ino))
152
153typedef enum {
154 FSTYPE_NONE,
155 FSTYPE_UNKNOWN,
156 FSTYPE_FUSE,
157 FSTYPE_FUSEBLK
158} fuse_fstype;
159
160typedef enum {
161 ATIME_ENABLED,
162 ATIME_DISABLED,
163 ATIME_RELATIVE
164} ntfs_atime_t;
165
166typedef struct fill_item {
167 struct fill_item *next;
168 size_t bufsize;
169 size_t off;
170 char buf[0];
171} ntfs_fuse_fill_item_t;
172
173typedef struct fill_context {
174 struct fill_item *first;
175 struct fill_item *last;
176 fuse_req_t req;
177 fuse_ino_t ino;
178 BOOL filled;
179} ntfs_fuse_fill_context_t;
180
181struct open_file {
182 struct open_file *next;
183 struct open_file *previous;
184 long long ghost;
185 fuse_ino_t ino;
186 fuse_ino_t parent;
187 int state;
188} ;
189
190typedef enum {
191 NF_STREAMS_INTERFACE_NONE, /* No access to named data streams. */
192 NF_STREAMS_INTERFACE_XATTR, /* Map named data streams to xattrs. */
193 NF_STREAMS_INTERFACE_OPENXATTR, /* Same, not limited to "user." */
194} ntfs_fuse_streams_interface;
195
196enum {
197 CLOSE_GHOST = 1,
198 CLOSE_COMPRESSED = 2,
199 CLOSE_ENCRYPTED = 4
200};
201
202typedef struct {
203 ntfs_volume *vol;
204 unsigned int uid;
205 unsigned int gid;
206 unsigned int fmask;
207 unsigned int dmask;
208 ntfs_fuse_streams_interface streams;
209 ntfs_atime_t atime;
210 BOOL ro;
211 BOOL show_sys_files;
212 BOOL silent;
213 BOOL recover;
214 BOOL hiberfile;
215 BOOL debug;
216 BOOL no_detach;
217 BOOL blkdev;
218 BOOL mounted;
219#ifdef HAVE_SETXATTR /* extended attributes interface required */
220 BOOL efs_raw;
221#endif /* HAVE_SETXATTR */
222 struct fuse_chan *fc;
223 BOOL inherit;
224 unsigned int secure_flags;
225 char *usermap_path;
226 char *abs_mnt_point;
227 struct PERMISSIONS_CACHE *seccache;
228 struct SECURITY_CONTEXT security;
229 struct open_file *open_files;
230 u64 latest_ghost;
231} ntfs_fuse_context_t;
232
233static struct options {
234 char *mnt_point; /* Mount point */
235 char *options; /* Mount options */
236 char *device; /* Device to mount */
237} opts;
238
239static const char *EXEC_NAME = "ntfs-3g";
240static char def_opts[] = "silent,allow_other,nonempty,";
241static ntfs_fuse_context_t *ctx;
242static u32 ntfs_sequence;
243static const char ghostformat[] = ".ghost-ntfs-3g-%020llu";
244
245static const char *usage_msg =
246"\n"
247"%s %s %s %d - Third Generation NTFS Driver\n"
248"\t\tConfiguration type %d, "
249#ifdef HAVE_SETXATTR
250"XATTRS are on, "
251#else
252"XATTRS are off, "
253#endif
254#if POSIXACLS
255"POSIX ACLS are on\n"
256#else
257"POSIX ACLS are off\n"
258#endif
259"\n"
260"Copyright (C) 2005-2007 Yura Pakhuchiy\n"
261"Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
262"Copyright (C) 2007-2010 Jean-Pierre Andre\n"
263"Copyright (C) 2009 Erik Larsson\n"
264"\n"
265"Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n"
266"\n"
267"Options: ro (read-only mount), remove_hiberfile, uid=, gid=,\n"
268" umask=, fmask=, dmask=, streams_interface=.\n"
269" Please see the details in the manual (type: man ntfs-3g).\n"
270"\n"
271"Example: ntfs-3g /dev/sda1 /mnt/windows\n"
272"\n"
273"%s";
274
275static const char ntfs_bad_reparse[] = "unsupported reparse point";
276
277#ifdef FUSE_INTERNAL
278int drop_privs(void);
279int restore_privs(void);
280#else
281/*
282 * setuid and setgid root ntfs-3g denies to start with external FUSE,
283 * therefore the below functions are no-op in such case.
284 */
285static int drop_privs(void) { return 0; }
286#if defined(linux) || defined(__uClinux__)
287static int restore_privs(void) { return 0; }
288#endif
289
290static const char *setuid_msg =
291"Mount is denied because setuid and setgid root ntfs-3g is insecure with the\n"
292"external FUSE library. Either remove the setuid/setgid bit from the binary\n"
293"or rebuild NTFS-3G with integrated FUSE support and make it setuid root.\n"
294"Please see more information at http://ntfs-3g.org/support.html#unprivileged\n";
295
296static const char *unpriv_fuseblk_msg =
297"Unprivileged user can not mount NTFS block devices using the external FUSE\n"
298"library. Either mount the volume as root, or rebuild NTFS-3G with integrated\n"
299"FUSE support and make it setuid root. Please see more information at\n"
300"http://ntfs-3g.org/support.html#unprivileged\n";
301#endif
302
303
304static void ntfs_fuse_update_times(ntfs_inode *ni, ntfs_time_update_flags mask)
305{
306 if (ctx->atime == ATIME_DISABLED)
307 mask &= ~NTFS_UPDATE_ATIME;
308 else if (ctx->atime == ATIME_RELATIVE && mask == NTFS_UPDATE_ATIME &&
309 (le64_to_cpu(ni->last_access_time)
310 >= le64_to_cpu(ni->last_data_change_time)) &&
311 (le64_to_cpu(ni->last_access_time)
312 >= le64_to_cpu(ni->last_mft_change_time)))
313 return;
314 ntfs_inode_update_times(ni, mask);
315}
316
317static s64 ntfs_get_nr_free_mft_records(ntfs_volume *vol)
318{
319 ntfs_attr *na = vol->mftbmp_na;
320 s64 nr_free = ntfs_attr_get_free_bits(na);
321
322 if (nr_free >= 0)
323 nr_free += (na->allocated_size - na->data_size) << 3;
324 return nr_free;
325}
326
327/*
328 * Fill a security context as needed by security functions
329 * returns TRUE if there is a user mapping,
330 * FALSE if there is none
331 * This is not an error and the context is filled anyway,
332 * it is used for implicit Windows-like inheritance
333 */
334
335static BOOL ntfs_fuse_fill_security_context(fuse_req_t req,
336 struct SECURITY_CONTEXT *scx)
337{
338 const struct fuse_ctx *fusecontext;
339
340 scx->vol = ctx->vol;
341 scx->mapping[MAPUSERS] = ctx->security.mapping[MAPUSERS];
342 scx->mapping[MAPGROUPS] = ctx->security.mapping[MAPGROUPS];
343 scx->pseccache = &ctx->seccache;
344 if (req) {
345 fusecontext = fuse_req_ctx(req);
346 scx->uid = fusecontext->uid;
347 scx->gid = fusecontext->gid;
348 scx->tid = fusecontext->pid;
349#ifdef FUSE_CAP_DONT_MASK
350 /* the umask can be processed by the file system */
351 scx->umask = fusecontext->umask;
352#else
353 /* the umask if forced by fuse on creation */
354 scx->umask = 0;
355#endif
356
357 } else {
358 scx->uid = 0;
359 scx->gid = 0;
360 scx->tid = 0;
361 scx->umask = 0;
362 }
363 return (ctx->security.mapping[MAPUSERS] != (struct MAPPING*)NULL);
364}
365
366static u64 ntfs_fuse_inode_lookup(fuse_ino_t parent, const char *name)
367{
368 u64 ino = (u64)-1;
369 u64 inum;
370 ntfs_inode *dir_ni;
371
372 /* Open target directory. */
373 dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
374 if (dir_ni) {
375 /* Lookup file */
376 inum = ntfs_inode_lookup_by_mbsname(dir_ni, name);
377 if (ntfs_inode_close(dir_ni)
378 || (inum == (u64)-1))
379 ino = (u64)-1;
380 else
381 ino = MREF(inum);
382 }
383 return (ino);
384}
385
386#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
387
388/*
389 * Check access to parent directory
390 *
391 * file inode is only opened when not fed in and S_ISVTX is requested,
392 * when already open and S_ISVTX, it *HAS TO* be fed in.
393 *
394 * returns 1 if allowed,
395 * 0 if not allowed or some error occurred (errno tells why)
396 */
397
398static int ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
399 ntfs_inode *dir_ni, fuse_ino_t ino,
400 ntfs_inode *ni, mode_t accesstype)
401{
402 int allowed;
403 ntfs_inode *ni2;
404 struct stat stbuf;
405
406 allowed = ntfs_allowed_access(scx, dir_ni, accesstype);
407 /*
408 * for an not-owned sticky directory, have to
409 * check whether file itself is owned
410 */
411 if ((accesstype == (S_IWRITE + S_IEXEC + S_ISVTX))
412 && (allowed == 2)) {
413 if (ni)
414 ni2 = ni;
415 else
416 ni2 = ntfs_inode_open(ctx->vol, INODE(ino));
417 allowed = 0;
418 if (ni2) {
419 allowed = (ntfs_get_owner_mode(scx,ni2,&stbuf) >= 0)
420 && (stbuf.st_uid == scx->uid);
421 if (!ni)
422 ntfs_inode_close(ni2);
423 }
424 }
425 return (allowed);
426}
427
428#endif /* !KERNELPERMS | (POSIXACLS & !KERNELACLS) */
429
430/**
431 * ntfs_fuse_statfs - return information about mounted NTFS volume
432 * @path: ignored (but fuse requires it)
433 * @sfs: statfs structure in which to return the information
434 *
435 * Return information about the mounted NTFS volume @sb in the statfs structure
436 * pointed to by @sfs (this is initialized with zeros before ntfs_statfs is
437 * called). We interpret the values to be correct of the moment in time at
438 * which we are called. Most values are variable otherwise and this isn't just
439 * the free values but the totals as well. For example we can increase the
440 * total number of file nodes if we run out and we can keep doing this until
441 * there is no more space on the volume left at all.
442 *
443 * This code based on ntfs_statfs from ntfs kernel driver.
444 *
445 * Returns 0 on success or -errno on error.
446 */
447
448static void ntfs_fuse_statfs(fuse_req_t req,
449 fuse_ino_t ino __attribute__((unused)))
450{
451 struct statvfs sfs;
452 s64 size;
453 int delta_bits;
454 ntfs_volume *vol;
455
456 vol = ctx->vol;
457 if (vol) {
458 /*
459 * File system block size. Used to calculate used/free space by df.
460 * Incorrectly documented as "optimal transfer block size".
461 */
462 sfs.f_bsize = vol->cluster_size;
463
464 /* Fundamental file system block size, used as the unit. */
465 sfs.f_frsize = vol->cluster_size;
466
467 /*
468 * Total number of blocks on file system in units of f_frsize.
469 * Since inodes are also stored in blocks ($MFT is a file) hence
470 * this is the number of clusters on the volume.
471 */
472 sfs.f_blocks = vol->nr_clusters;
473
474 /* Free blocks available for all and for non-privileged processes. */
475 size = vol->free_clusters;
476 if (size < 0)
477 size = 0;
478 sfs.f_bavail = sfs.f_bfree = size;
479
480 /* Free inodes on the free space */
481 delta_bits = vol->cluster_size_bits - vol->mft_record_size_bits;
482 if (delta_bits >= 0)
483 size <<= delta_bits;
484 else
485 size >>= -delta_bits;
486
487 /* Number of inodes at this point in time. */
488 sfs.f_files = (vol->mftbmp_na->allocated_size << 3) + size;
489
490 /* Free inodes available for all and for non-privileged processes. */
491 size += vol->free_mft_records;
492 if (size < 0)
493 size = 0;
494 sfs.f_ffree = sfs.f_favail = size;
495
496 /* Maximum length of filenames. */
497 sfs.f_namemax = NTFS_MAX_NAME_LEN;
498 fuse_reply_statfs(req, &sfs);
499 } else
500 fuse_reply_err(req, ENODEV);
501
502}
503
504static void set_fuse_error(int *err)
505{
506 if (!*err)
507 *err = -errno;
508}
509
510#if 0 && (defined(__APPLE__) || defined(__DARWIN__)) /* Unfinished. */
511static int ntfs_macfuse_getxtimes(const char *org_path,
512 struct timespec *bkuptime, struct timespec *crtime)
513{
514 int res = 0;
515 ntfs_inode *ni;
516 char *path = NULL;
517 ntfschar *stream_name;
518 int stream_name_len;
519
520 stream_name_len = ntfs_fuse_parse_path(org_path, &path, &stream_name);
521 if (stream_name_len < 0)
522 return stream_name_len;
523 memset(bkuptime, 0, sizeof(struct timespec));
524 memset(crtime, 0, sizeof(struct timespec));
525 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
526 if (!ni) {
527 res = -errno;
528 goto exit;
529 }
530
531 /* We have no backup timestamp in NTFS. */
532 crtime->tv_sec = ni->creation_time;
533exit:
534 if (ntfs_inode_close(ni))
535 set_fuse_error(&res);
536 free(path);
537 if (stream_name_len)
538 free(stream_name);
539 return res;
540}
541
542int ntfs_macfuse_setcrtime(const char *path, const struct timespec *tv)
543{
544 ntfs_inode *ni;
545 int res = 0;
546
547 if (ntfs_fuse_is_named_data_stream(path))
548 return -EINVAL; /* n/a for named data streams. */
549 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
550 if (!ni)
551 return -errno;
552
553 if (tv) {
554 ni->creation_time = tv->tv_sec;
555 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
556 }
557
558 if (ntfs_inode_close(ni))
559 set_fuse_error(&res);
560 return res;
561}
562
563int ntfs_macfuse_setbkuptime(const char *path, const struct timespec *tv)
564{
565 ntfs_inode *ni;
566 int res = 0;
567
568 if (ntfs_fuse_is_named_data_stream(path))
569 return -EINVAL; /* n/a for named data streams. */
570 ni = ntfs_pathname_to_inode(ctx->vol, NULL, path);
571 if (!ni)
572 return -errno;
573
574 /*
575 * Only pretending to set backup time successfully to please the APIs of
576 * Mac OS X. In reality, NTFS has no backup time.
577 */
578
579 if (ntfs_inode_close(ni))
580 set_fuse_error(&res);
581 return res;
582}
583
584int ntfs_macfuse_setchgtime(const char *path, const struct timespec *tv)
585{
586 ntfs_inode *ni;
587 int res = 0;
588
589 if (ntfs_fuse_is_named_data_stream(path))
590 return -EINVAL; /* n/a for named data streams. */
591 ni = ntfs_pathname_to_inode(ctx-&gt;vol, NULL, path);
592 if (!ni)
593 return -errno;
594
595 if (tv) {
596 ni-&gt;last_mft_change_time = tv-&gt;tv_sec;
597 ntfs_fuse_update_times(ni, 0);
598 }
599
600 if (ntfs_inode_close(ni))
601 set_fuse_error(&amp;res);
602 return res;
603}
604#endif /* defined(__APPLE__) || defined(__DARWIN__) */
605
606#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__))
607static void ntfs_init(void *userdata __attribute__((unused)),
608 struct fuse_conn_info *conn)
609{
610#if defined(__APPLE__) || defined(__DARWIN__)
611 FUSE_ENABLE_XTIMES(conn);
612#endif
613#ifdef FUSE_CAP_DONT_MASK
614 /* request umask not to be enforced by fuse */
615 conn->want |= FUSE_CAP_DONT_MASK;
616#endif /* defined FUSE_CAP_DONT_MASK */
617}
618#endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */
619
620static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
621 ntfs_inode *ni, struct stat *stbuf)
622{
623 int res = 0;
624 ntfs_attr *na;
625 BOOL withusermapping;
626
627 memset(stbuf, 0, sizeof(struct stat));
628 withusermapping = (scx->mapping[MAPUSERS] != (struct MAPPING*)NULL);
629 if ((ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)
630 || (ni->flags & FILE_ATTR_REPARSE_POINT)) {
631 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
632 char *target;
633 int attr_size;
634
635 errno = 0;
636 target = ntfs_make_symlink(ni, ctx->abs_mnt_point,
637 &attr_size);
638 /*
639 * If the reparse point is not a valid
640 * directory junction, and there is no error
641 * we still display as a symlink
642 */
643 if (target || (errno == EOPNOTSUPP)) {
644 /* returning attribute size */
645 if (target)
646 stbuf->st_size = attr_size;
647 else
648 stbuf->st_size =
649 sizeof(ntfs_bad_reparse);
650 stbuf->st_blocks =
651 (ni->allocated_size + 511) >> 9;
652 stbuf->st_nlink =
653 le16_to_cpu(ni->mrec->link_count);
654 stbuf->st_mode = S_IFLNK;
655 free(target);
656 } else {
657 res = -errno;
658 goto exit;
659 }
660 } else {
661 /* Directory. */
662 stbuf->st_mode = S_IFDIR | (0777 & ~ctx->dmask);
663 /* get index size, if not known */
664 if (!test_nino_flag(ni, KnownSize)) {
665 na = ntfs_attr_open(ni, AT_INDEX_ALLOCATION,
666 NTFS_INDEX_I30, 4);
667 if (na) {
668 ni->data_size = na->data_size;
669 ni->allocated_size = na->allocated_size;
670 set_nino_flag(ni, KnownSize);
671 ntfs_attr_close(na);
672 }
673 }
674 stbuf->st_size = ni->data_size;
675 stbuf->st_blocks = ni->allocated_size >> 9;
676 stbuf->st_nlink = 1; /* Make find(1) work */
677 }
678 } else {
679 /* Regular or Interix (INTX) file. */
680 stbuf->st_mode = S_IFREG;
681 stbuf->st_size = ni->data_size;
682#ifdef HAVE_SETXATTR /* extended attributes interface required */
683 /*
684 * return data size rounded to next 512 byte boundary for
685 * encrypted files to include padding required for decryption
686 * also include 2 bytes for padding info
687 */
688 if (ctx->efs_raw && ni->flags & FILE_ATTR_ENCRYPTED)
689 stbuf->st_size = ((ni->data_size + 511) & ~511) + 2;
690#endif /* HAVE_SETXATTR */
691 /*
692 * Temporary fix to make ActiveSync work via Samba 3.0.
693 * See more on the ntfs-3g-devel list.
694 */
695 stbuf->st_blocks = (ni->allocated_size + 511) >> 9;
696 stbuf->st_nlink = le16_to_cpu(ni->mrec->link_count);
697 if (ni->flags & FILE_ATTR_SYSTEM) {
698 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
699 if (!na) {
700 goto exit;
701 }
702 /* Check whether it's Interix FIFO or socket. */
703 if (!(ni->flags & FILE_ATTR_HIDDEN)) {
704 /* FIFO. */
705 if (na->data_size == 0)
706 stbuf->st_mode = S_IFIFO;
707 /* Socket link. */
708 if (na->data_size == 1)
709 stbuf->st_mode = S_IFSOCK;
710 }
711 /*
712 * Check whether it's Interix symbolic link, block or
713 * character device.
714 */
715 if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)
716 + sizeof(ntfschar) * PATH_MAX
717 && (size_t)na->data_size >
718 sizeof(INTX_FILE_TYPES)) {
719 INTX_FILE *intx_file;
720
721 intx_file =
722 (INTX_FILE*)ntfs_malloc(na->data_size);
723 if (!intx_file) {
724 res = -errno;
725 ntfs_attr_close(na);
726 goto exit;
727 }
728 if (ntfs_attr_pread(na, 0, na->data_size,
729 intx_file) != na->data_size) {
730 res = -errno;
731 free(intx_file);
732 ntfs_attr_close(na);
733 goto exit;
734 }
735 if (intx_file->magic == INTX_BLOCK_DEVICE &&
736 na->data_size == (s64)offsetof(
737 INTX_FILE, device_end)) {
738 stbuf->st_mode = S_IFBLK;
739 stbuf->st_rdev = makedev(le64_to_cpu(
740 intx_file->major),
741 le64_to_cpu(
742 intx_file->minor));
743 }
744 if (intx_file->magic == INTX_CHARACTER_DEVICE &&
745 na->data_size == (s64)offsetof(
746 INTX_FILE, device_end)) {
747 stbuf->st_mode = S_IFCHR;
748 stbuf->st_rdev = makedev(le64_to_cpu(
749 intx_file->major),
750 le64_to_cpu(
751 intx_file->minor));
752 }
753 if (intx_file->magic == INTX_SYMBOLIC_LINK)
754 stbuf->st_mode = S_IFLNK;
755 free(intx_file);
756 }
757 ntfs_attr_close(na);
758 }
759 stbuf->st_mode |= (0777 & ~ctx->fmask);
760 }
761 if (withusermapping) {
762 if (ntfs_get_owner_mode(scx,ni,stbuf) < 0)
763 set_fuse_error(&res);
764 } else {
765 stbuf->st_uid = ctx->uid;
766 stbuf->st_gid = ctx->gid;
767 }
768 if (S_ISLNK(stbuf->st_mode))
769 stbuf->st_mode |= 0777;
770 stbuf->st_ino = ni->mft_no;
771#ifdef HAVE_STRUCT_STAT_ST_ATIMESPEC
772 stbuf->st_atimespec = ntfs2timespec(ni->last_access_time);
773 stbuf->st_ctimespec = ntfs2timespec(ni->last_mft_change_time);
774 stbuf->st_mtimespec = ntfs2timespec(ni->last_data_change_time);
775#elif defined(HAVE_STRUCT_STAT_ST_ATIM)
776 stbuf->st_atim = ntfs2timespec(ni->last_access_time);
777 stbuf->st_ctim = ntfs2timespec(ni->last_mft_change_time);
778 stbuf->st_mtim = ntfs2timespec(ni->last_data_change_time);
779#elif defined(HAVE_STRUCT_STAT_ST_ATIMENSEC)
780 {
781 struct timespec ts;
782
783 ts = ntfs2timespec(ni->last_access_time);
784 stbuf->st_atime = ts.tv_sec;
785 stbuf->st_atimensec = ts.tv_nsec;
786 ts = ntfs2timespec(ni->last_mft_change_time);
787 stbuf->st_ctime = ts.tv_sec;
788 stbuf->st_ctimensec = ts.tv_nsec;
789 ts = ntfs2timespec(ni->last_data_change_time);
790 stbuf->st_mtime = ts.tv_sec;
791 stbuf->st_mtimensec = ts.tv_nsec;
792 }
793#else
794#warning "No known way to set nanoseconds in struct stat !"
795 {
796 struct timespec ts;
797
798 ts = ntfs2timespec(ni->last_access_time);
799 stbuf->st_atime = ts.tv_sec;
800 ts = ntfs2timespec(ni->last_mft_change_time);
801 stbuf->st_ctime = ts.tv_sec;
802 ts = ntfs2timespec(ni->last_data_change_time);
803 stbuf->st_mtime = ts.tv_sec;
804 }
805#endif
806exit:
807 return (res);
808}
809
810static void ntfs_fuse_getattr(fuse_req_t req, fuse_ino_t ino,
811 struct fuse_file_info *fi __attribute__((unused)))
812{
813 int res;
814 ntfs_inode *ni;
815 struct stat stbuf;
816 struct SECURITY_CONTEXT security;
817
818 ni = ntfs_inode_open(ctx->vol, INODE(ino));
819 if (!ni)
820 res = -errno;
821 else {
822 ntfs_fuse_fill_security_context(req, &security);
823 res = ntfs_fuse_getstat(&security, ni, &stbuf);
824 if (ntfs_inode_close(ni))
825 set_fuse_error(&res);
826 }
827 if (!res)
828 fuse_reply_attr(req, &stbuf, ATTR_TIMEOUT);
829 else
830 fuse_reply_err(req, -res);
831}
832
833static __inline__ BOOL ntfs_fuse_fillstat(struct SECURITY_CONTEXT *scx,
834 struct fuse_entry_param *pentry, u64 iref)
835{
836 ntfs_inode *ni;
837 BOOL ok = FALSE;
838
839 pentry->ino = MREF(iref);
840 ni = ntfs_inode_open(ctx->vol, pentry->ino);
841 if (ni) {
842 if (!ntfs_fuse_getstat(scx, ni, &pentry->attr)) {
843 pentry->generation = 1;
844 pentry->attr_timeout = ATTR_TIMEOUT;
845 pentry->entry_timeout = ENTRY_TIMEOUT;
846 ok = TRUE;
847 }
848 if (ntfs_inode_close(ni))
849 ok = FALSE;
850 }
851 return (ok);
852}
853
854
855static void ntfs_fuse_lookup(fuse_req_t req, fuse_ino_t parent,
856 const char *name)
857{
858 struct SECURITY_CONTEXT security;
859 struct fuse_entry_param entry;
860 ntfs_inode *dir_ni;
861 u64 iref;
862 BOOL ok = FALSE;
863
864 if (strlen(name) < 256) {
865 dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
866 if (dir_ni) {
867#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
868 /*
869 * make sure the parent directory is searchable
870 */
871 if (ntfs_fuse_fill_security_context(req, &security)
872 && !ntfs_allowed_access(&security,dir_ni,S_IEXEC)) {
873 ntfs_inode_close(dir_ni);
874 errno = EACCES;
875 } else {
876#else
877 ntfs_fuse_fill_security_context(req, &security);
878#endif
879 iref = ntfs_inode_lookup_by_mbsname(dir_ni,
880 name);
881 ok = !ntfs_inode_close(dir_ni)
882 && (iref != (u64)-1)
883 && ntfs_fuse_fillstat(
884 &security,&entry,iref);
885#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
886 }
887#endif
888 }
889 } else
890 errno = ENAMETOOLONG;
891 if (!ok)
892 fuse_reply_err(req, errno);
893 else
894 fuse_reply_entry(req, &entry);
895}
896
897static void ntfs_fuse_readlink(fuse_req_t req, fuse_ino_t ino)
898{
899 ntfs_inode *ni = NULL;
900 ntfs_attr *na = NULL;
901 INTX_FILE *intx_file = NULL;
902 char *buf = (char*)NULL;
903 int res = 0;
904
905 /* Get inode. */
906 ni = ntfs_inode_open(ctx->vol, INODE(ino));
907 if (!ni) {
908 res = -errno;
909 goto exit;
910 }
911 /*
912 * Reparse point : analyze as a junction point
913 */
914 if (ni->flags & FILE_ATTR_REPARSE_POINT) {
915 int attr_size;
916
917 errno = 0;
918 res = 0;
919 buf = ntfs_make_symlink(ni, ctx->abs_mnt_point, &attr_size);
920 if (!buf) {
921 if (errno == EOPNOTSUPP)
922 buf = strdup(ntfs_bad_reparse);
923 if (!buf)
924 res = -errno;
925 }
926 goto exit;
927 }
928 /* Sanity checks. */
929 if (!(ni->flags & FILE_ATTR_SYSTEM)) {
930 res = -EINVAL;
931 goto exit;
932 }
933 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
934 if (!na) {
935 res = -errno;
936 goto exit;
937 }
938 if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)) {
939 res = -EINVAL;
940 goto exit;
941 }
942 if ((size_t)na->data_size > sizeof(INTX_FILE_TYPES) +
943 sizeof(ntfschar) * PATH_MAX) {
944 res = -ENAMETOOLONG;
945 goto exit;
946 }
947 /* Receive file content. */
948 intx_file = (INTX_FILE*)ntfs_malloc(na->data_size);
949 if (!intx_file) {
950 res = -errno;
951 goto exit;
952 }
953 if (ntfs_attr_pread(na, 0, na->data_size, intx_file) != na->data_size) {
954 res = -errno;
955 goto exit;
956 }
957 /* Sanity check. */
958 if (intx_file->magic != INTX_SYMBOLIC_LINK) {
959 res = -EINVAL;
960 goto exit;
961 }
962 /* Convert link from unicode to local encoding. */
963 if (ntfs_ucstombs(intx_file->target, (na->data_size -
964 offsetof(INTX_FILE, target)) / sizeof(ntfschar),
965 &buf, 0) < 0) {
966 res = -errno;
967 goto exit;
968 }
969exit:
970 if (intx_file)
971 free(intx_file);
972 if (na)
973 ntfs_attr_close(na);
974 if (ntfs_inode_close(ni))
975 set_fuse_error(&res);
976
977 if (res < 0)
978 fuse_reply_err(req, -res);
979 else
980 fuse_reply_readlink(req, buf);
981 if (buf != ntfs_bad_reparse)
982 free(buf);
983}
984
985static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx,
986 const ntfschar *name, const int name_len, const int name_type,
987 const s64 pos __attribute__((unused)), const MFT_REF mref,
988 const unsigned dt_type __attribute__((unused)))
989{
990 char *filename = NULL;
991 int ret = 0;
992 int filenamelen = -1;
993 size_t sz;
994 ntfs_fuse_fill_item_t *current;
995 ntfs_fuse_fill_item_t *newone;
996
997 if (name_type == FILE_NAME_DOS)
998 return 0;
999
1000 if ((filenamelen = ntfs_ucstombs(name, name_len, &filename, 0)) < 0) {
1001 ntfs_log_perror("Filename decoding failed (inode %llu)",
1002 (unsigned long long)MREF(mref));
1003 return -1;
1004 }
1005
1006 if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user ||
1007 ctx->show_sys_files) {
1008 struct stat st = { .st_ino = MREF(mref) };
1009
1010 if (dt_type == NTFS_DT_REG)
1011 st.st_mode = S_IFREG | (0777 & ~ctx->fmask);
1012 else if (dt_type == NTFS_DT_DIR)
1013 st.st_mode = S_IFDIR | (0777 & ~ctx->dmask);
1014
1015#if defined(__APPLE__) || defined(__DARWIN__)
1016 /*
1017 * Returning file names larger than MAXNAMLEN (255) bytes
1018 * causes Darwin/Mac OS X to bug out and skip the entry.
1019 */
1020 if (filenamelen > MAXNAMLEN) {
1021 ntfs_log_debug("Truncating %d byte filename to "
1022 "%d bytes.\n", filenamelen, MAXNAMLEN);
1023 ntfs_log_debug(" before: '%s'\n", filename);
1024 memset(filename + MAXNAMLEN, 0, filenamelen - MAXNAMLEN);
1025 ntfs_log_debug(" after: '%s'\n", filename);
1026 }
1027#endif /* defined(__APPLE__) || defined(__DARWIN__) */
1028
1029 current = fill_ctx->last;
1030 sz = fuse_add_direntry(fill_ctx->req,
1031 &current->buf[current->off],
1032 current->bufsize - current->off,
1033 filename, &st, current->off);
1034 if (!sz || ((current->off + sz) > current->bufsize)) {
1035 newone = (ntfs_fuse_fill_item_t*)ntfs_malloc
1036 (sizeof(ntfs_fuse_fill_item_t)
1037 + current->bufsize);
1038 if (newone) {
1039 newone->off = 0;
1040 newone->bufsize = current->bufsize;
1041 newone->next = (ntfs_fuse_fill_item_t*)NULL;
1042 current->next = newone;
1043 fill_ctx->last = newone;
1044 current = newone;
1045 sz = fuse_add_direntry(fill_ctx->req,
1046 current->buf,
1047 current->bufsize - current->off,
1048 filename, &st, current->off);
1049 if (!sz) {
1050 errno = EIO;
1051 ntfs_log_error("Could not add a"
1052 " directory entry (inode %lld)\n",
1053 (unsigned long long)MREF(mref));
1054 }
1055 } else {
1056 sz = 0;
1057 errno = ENOMEM;
1058 }
1059 }
1060 if (sz) {
1061 current->off += sz;
1062 } else {
1063 ret = -1;
1064 }
1065 }
1066
1067 free(filename);
1068 return ret;
1069}
1070
1071static void ntfs_fuse_opendir(fuse_req_t req, fuse_ino_t ino,
1072 struct fuse_file_info *fi)
1073{
1074 int res = 0;
1075 ntfs_inode *ni;
1076 int accesstype;
1077 ntfs_fuse_fill_context_t *fill;
1078 struct SECURITY_CONTEXT security;
1079
1080 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1081 if (ni) {
1082 if (ntfs_fuse_fill_security_context(req, &security)) {
1083 if (fi->flags & O_WRONLY)
1084 accesstype = S_IWRITE;
1085 else
1086 if (fi->flags & O_RDWR)
1087 accesstype = S_IWRITE | S_IREAD;
1088 else
1089 accesstype = S_IREAD;
1090 if (!ntfs_allowed_access(&security,ni,accesstype))
1091 res = -EACCES;
1092 }
1093 if (ntfs_inode_close(ni))
1094 set_fuse_error(&res);
1095 if (!res) {
1096 fill = (ntfs_fuse_fill_context_t*)
1097 ntfs_malloc(sizeof(ntfs_fuse_fill_context_t));
1098 if (!fill)
1099 res = -errno;
1100 else {
1101 fill->first = fill->last
1102 = (ntfs_fuse_fill_item_t*)NULL;
1103 fill->filled = FALSE;
1104 fill->ino = ino;
1105 }
1106 fi->fh = (long)fill;
1107 }
1108 } else
1109 res = -errno;
1110 if (!res)
1111 fuse_reply_open(req, fi);
1112 else
1113 fuse_reply_err(req, -res);
1114}
1115
1116
1117static void ntfs_fuse_releasedir(fuse_req_t req,
1118 fuse_ino_t ino __attribute__((unused)),
1119 struct fuse_file_info *fi)
1120{
1121 ntfs_fuse_fill_context_t *fill;
1122 ntfs_fuse_fill_item_t *current;
1123
1124 fill = (ntfs_fuse_fill_context_t*)(long)fi->fh;
1125 /* make sure to clear results */
1126 current = fill->first;
1127 while (current) {
1128 current = current->next;
1129 free(fill->first);
1130 fill->first = current;
1131 }
1132 free(fill);
1133 fuse_reply_err(req, 0);
1134}
1135
1136static void ntfs_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
1137 off_t off __attribute__((unused)),
1138 struct fuse_file_info *fi __attribute__((unused)))
1139{
1140 ntfs_fuse_fill_item_t *first;
1141 ntfs_fuse_fill_item_t *current;
1142 ntfs_fuse_fill_context_t *fill;
1143 ntfs_inode *ni;
1144 s64 pos = 0;
1145 int err = 0;
1146
1147 fill = (ntfs_fuse_fill_context_t*)(long)fi->fh;
1148 if (fill) {
1149 if (!fill->filled) {
1150 /* initial call : build the full list */
1151 first = (ntfs_fuse_fill_item_t*)ntfs_malloc
1152 (sizeof(ntfs_fuse_fill_item_t) + size);
1153 if (first) {
1154 first->bufsize = size;
1155 first->off = 0;
1156 first->next = (ntfs_fuse_fill_item_t*)NULL;
1157 fill->req = req;
1158 fill->first = first;
1159 fill->last = first;
1160 ni = ntfs_inode_open(ctx->vol,INODE(ino));
1161 if (!ni)
1162 err = -errno;
1163 else {
1164 if (ntfs_readdir(ni, &pos, fill,
1165 (ntfs_filldir_t)
1166 ntfs_fuse_filler))
1167 err = -errno;
1168 fill->filled = TRUE;
1169 ntfs_fuse_update_times(ni,
1170 NTFS_UPDATE_ATIME);
1171 if (ntfs_inode_close(ni))
1172 set_fuse_error(&err);
1173 }
1174 if (!err)
1175 fuse_reply_buf(req, first->buf,
1176 first->off);
1177 /* reply sent, now must exit with no error */
1178 fill->first = first->next;
1179 free(first);
1180 } else
1181 err = -errno;
1182 } else {
1183 /* subsequent call : return next non-empty buffer */
1184 current = fill->first;
1185 while (current && !current->off) {
1186 current = current->next;
1187 free(fill->first);
1188 fill->first = current;
1189 }
1190 if (current) {
1191 fuse_reply_buf(req, current->buf, current->off);
1192 fill->first = current->next;
1193 free(current);
1194 } else {
1195 fuse_reply_buf(req, (char*)NULL, 0);
1196 /* reply sent, now must exit with no error */
1197 }
1198 }
1199 } else {
1200 errno = EIO;
1201 err = -errno;
1202 ntfs_log_error("Uninitialized fuse_readdir()\n");
1203 }
1204 if (err)
1205 fuse_reply_err(req, -err);
1206}
1207
1208static void ntfs_fuse_open(fuse_req_t req, fuse_ino_t ino,
1209 struct fuse_file_info *fi)
1210{
1211 ntfs_inode *ni;
1212 ntfs_attr *na;
1213 struct open_file *of;
1214 int state = 0;
1215 char *path = NULL;
1216 int res = 0;
1217#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1218 int accesstype;
1219 struct SECURITY_CONTEXT security;
1220#endif
1221
1222 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1223 if (ni) {
1224 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
1225 if (na) {
1226#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1227 if (ntfs_fuse_fill_security_context(req, &security)) {
1228 if (fi->flags & O_WRONLY)
1229 accesstype = S_IWRITE;
1230 else
1231 if (fi->flags & O_RDWR)
1232 accesstype = S_IWRITE | S_IREAD;
1233 else
1234 accesstype = S_IREAD;
1235 /* check whether requested access is allowed */
1236 if (!ntfs_allowed_access(&security,
1237 ni,accesstype))
1238 res = -EACCES;
1239 }
1240#endif
1241 if ((res >= 0)
1242 && (fi->flags & (O_WRONLY | O_RDWR))) {
1243 /* mark a future need to compress the last chunk */
1244 if (na->data_flags & ATTR_COMPRESSION_MASK)
1245 state |= CLOSE_COMPRESSED;
1246#ifdef HAVE_SETXATTR /* extended attributes interface required */
1247 /* mark a future need to fixup encrypted inode */
1248 if (ctx->efs_raw
1249 && !(na->data_flags & ATTR_IS_ENCRYPTED)
1250 && (ni->flags & FILE_ATTR_ENCRYPTED))
1251 state |= CLOSE_ENCRYPTED;
1252#endif /* HAVE_SETXATTR */
1253 }
1254 ntfs_attr_close(na);
1255 } else
1256 res = -errno;
1257 if (ntfs_inode_close(ni))
1258 set_fuse_error(&res);
1259 } else
1260 res = -errno;
1261 free(path);
1262 if (res >= 0) {
1263 of = (struct open_file*)malloc(sizeof(struct open_file));
1264 if (of) {
1265 of->parent = 0;
1266 of->ino = ino;
1267 of->state = state;
1268 of->next = ctx->open_files;
1269 of->previous = (struct open_file*)NULL;
1270 if (ctx->open_files)
1271 ctx->open_files->previous = of;
1272 ctx->open_files = of;
1273 fi->fh = (long)of;
1274 }
1275 }
1276 if (res)
1277 fuse_reply_err(req, -res);
1278 else
1279 fuse_reply_open(req, fi);
1280}
1281
1282static void ntfs_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size,
1283 off_t offset,
1284 struct fuse_file_info *fi __attribute__((unused)))
1285{
1286 ntfs_inode *ni = NULL;
1287 ntfs_attr *na = NULL;
1288 int res;
1289 char *buf = (char*)NULL;
1290 s64 total = 0;
1291 s64 max_read;
1292
1293 if (!size)
1294 goto exit;
1295 buf = (char*)ntfs_malloc(size);
1296 if (!buf) {
1297 res = -errno;
1298 goto exit;
1299 }
1300
1301 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1302 if (!ni) {
1303 res = -errno;
1304 goto exit;
1305 }
1306 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
1307 if (!na) {
1308 res = -errno;
1309 goto exit;
1310 }
1311 max_read = na->data_size;
1312#ifdef HAVE_SETXATTR /* extended attributes interface required */
1313 /* limit reads at next 512 byte boundary for encrypted attributes */
1314 if (ctx->efs_raw && (na->data_flags & ATTR_IS_ENCRYPTED) &&
1315 NAttrNonResident(na)) {
1316 max_read = ((na->data_size+511) & ~511) + 2;
1317 }
1318#endif /* HAVE_SETXATTR */
1319 if (offset + (off_t)size > max_read) {
1320 if (max_read < offset)
1321 goto ok;
1322 size = max_read - offset;
1323 }
1324 while (size > 0) {
1325 s64 ret = ntfs_attr_pread(na, offset, size, buf + total);
1326 if (ret != (s64)size)
1327 ntfs_log_perror("ntfs_attr_pread error reading inode %lld at "
1328 "offset %lld: %lld <> %lld", (long long)ni->mft_no,
1329 (long long)offset, (long long)size, (long long)ret);
1330 if (ret <= 0 || ret > (s64)size) {
1331 res = (ret < 0) ? -errno : -EIO;
1332 goto exit;
1333 }
1334 size -= ret;
1335 offset += ret;
1336 total += ret;
1337 }
1338ok:
1339 ntfs_fuse_update_times(na->ni, NTFS_UPDATE_ATIME);
1340 res = total;
1341exit:
1342 if (na)
1343 ntfs_attr_close(na);
1344 if (ntfs_inode_close(ni))
1345 set_fuse_error(&res);
1346 if (res < 0)
1347 fuse_reply_err(req, -res);
1348 else
1349 fuse_reply_buf(req, buf, res);
1350 free(buf);
1351}
1352
1353static void ntfs_fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
1354 size_t size, off_t offset,
1355 struct fuse_file_info *fi __attribute__((unused)))
1356{
1357 ntfs_inode *ni = NULL;
1358 ntfs_attr *na = NULL;
1359 int res, total = 0;
1360
1361 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1362 if (!ni) {
1363 res = -errno;
1364 goto exit;
1365 }
1366 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
1367 if (!na) {
1368 res = -errno;
1369 goto exit;
1370 }
1371 while (size) {
1372 s64 ret = ntfs_attr_pwrite(na, offset, size, buf + total);
1373 if (ret <= 0) {
1374 res = -errno;
1375 goto exit;
1376 }
1377 size -= ret;
1378 offset += ret;
1379 total += ret;
1380 }
1381 res = total;
1382 if (res > 0)
1383 ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
1384exit:
1385 if (na)
1386 ntfs_attr_close(na);
1387 if (total)
1388 set_archive(ni);
1389 if (ntfs_inode_close(ni))
1390 set_fuse_error(&res);
1391 if (res < 0)
1392 fuse_reply_err(req, -res);
1393 else
1394 fuse_reply_write(req, res);
1395}
1396
1397static int ntfs_fuse_chmod(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
1398 mode_t mode, struct stat *stbuf)
1399{
1400 int res = 0;
1401 ntfs_inode *ni;
1402
1403 /* return unsupported if no user mapping has been defined */
1404 if (!scx->mapping[MAPUSERS] && !ctx->silent) {
1405 res = -EOPNOTSUPP;
1406 } else {
1407 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1408 if (!ni)
1409 res = -errno;
1410 else {
1411 if (scx->mapping[MAPUSERS]) {
1412 if (ntfs_set_mode(scx, ni, mode))
1413 res = -errno;
1414 else {
1415 ntfs_fuse_update_times(ni,
1416 NTFS_UPDATE_CTIME);
1417 /*
1418 * Must return updated times, and
1419 * inode has been updated, so hope
1420 * we get no further errors
1421 */
1422 res = ntfs_fuse_getstat(scx, ni, stbuf);
1423 }
1424 NInoSetDirty(ni);
1425 } else
1426 res = ntfs_fuse_getstat(scx, ni, stbuf);
1427 if (ntfs_inode_close(ni))
1428 set_fuse_error(&res);
1429 }
1430 }
1431 return res;
1432}
1433
1434static int ntfs_fuse_chown(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
1435 uid_t uid, gid_t gid, struct stat *stbuf)
1436{
1437 ntfs_inode *ni;
1438 int res;
1439
1440 if (!scx->mapping[MAPUSERS]
1441 && !ctx->silent
1442 && ((uid != ctx->uid) || (gid != ctx->gid)))
1443 res = -EOPNOTSUPP;
1444 else {
1445 res = 0;
1446 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1447 if (!ni)
1448 res = -errno;
1449 else {
1450 if (scx->mapping[MAPUSERS]
1451 && (((int)uid != -1) || ((int)gid != -1))) {
1452 if (ntfs_set_owner(scx, ni, uid, gid))
1453 res = -errno;
1454 else {
1455 ntfs_fuse_update_times(ni,
1456 NTFS_UPDATE_CTIME);
1457 /*
1458 * Must return updated times, and
1459 * inode has been updated, so hope
1460 * we get no further errors
1461 */
1462 res = ntfs_fuse_getstat(scx, ni, stbuf);
1463 }
1464 } else
1465 res = ntfs_fuse_getstat(scx, ni, stbuf);
1466 if (ntfs_inode_close(ni))
1467 set_fuse_error(&res);
1468 }
1469 }
1470 return (res);
1471}
1472
1473static int ntfs_fuse_chownmod(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
1474 uid_t uid, gid_t gid, mode_t mode, struct stat *stbuf)
1475{
1476 ntfs_inode *ni;
1477 int res;
1478
1479 if (!scx->mapping[MAPUSERS]
1480 && !ctx->silent
1481 && ((uid != ctx->uid) || (gid != ctx->gid)))
1482 res = -EOPNOTSUPP;
1483 else {
1484 res = 0;
1485 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1486 if (!ni)
1487 res = -errno;
1488 else {
1489 if (scx->mapping[MAPUSERS]) {
1490 if (ntfs_set_ownmod(scx, ni, uid, gid, mode))
1491 res = -errno;
1492 else {
1493 ntfs_fuse_update_times(ni,
1494 NTFS_UPDATE_CTIME);
1495 /*
1496 * Must return updated times, and
1497 * inode has been updated, so hope
1498 * we get no further errors
1499 */
1500 res = ntfs_fuse_getstat(scx, ni, stbuf);
1501 }
1502 } else
1503 res = ntfs_fuse_getstat(scx, ni, stbuf);
1504 if (ntfs_inode_close(ni))
1505 set_fuse_error(&res);
1506 }
1507 }
1508 return (res);
1509}
1510
1511static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
1512#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1513 off_t size, BOOL chkwrite, struct stat *stbuf)
1514#else
1515 off_t size, BOOL chkwrite __attribute__((unused)),
1516 struct stat *stbuf)
1517#endif
1518{
1519 ntfs_inode *ni = NULL;
1520 ntfs_attr *na = NULL;
1521 int res;
1522 s64 oldsize;
1523
1524 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1525 if (!ni)
1526 goto exit;
1527
1528 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
1529 if (!na)
1530 goto exit;
1531#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1532 /*
1533 * deny truncation if cannot write to file
1534 * (already checked for ftruncate())
1535 */
1536 if (scx->mapping[MAPUSERS]
1537 && chkwrite
1538 && !ntfs_allowed_access(scx, ni, S_IWRITE)) {
1539 errno = EACCES;
1540 goto exit;
1541 }
1542#endif
1543 /*
1544 * for compressed files, only deleting contents and expanding
1545 * are implemented. Expanding is done by inserting a final
1546 * zero, which is optimized as creating a hole when possible.
1547 */
1548 if ((na->data_flags & ATTR_COMPRESSION_MASK)
1549 && size
1550 && (size < na->initialized_size)) {
1551 errno = EOPNOTSUPP;
1552 goto exit;
1553 }
1554 oldsize = na->data_size;
1555 if ((na->data_flags & ATTR_COMPRESSION_MASK)
1556 && (size > na->initialized_size)) {
1557 char zero = 0;
1558 if (ntfs_attr_pwrite(na, size - 1, 1, &zero) <= 0)
1559 goto exit;
1560 } else
1561 if (ntfs_attr_truncate(na, size))
1562 goto exit;
1563 if (oldsize != size)
1564 set_archive(ni);
1565
1566 ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
1567 res = ntfs_fuse_getstat(scx, ni, stbuf);
1568 errno = (res ? -res : 0);
1569exit:
1570 res = -errno;
1571 ntfs_attr_close(na);
1572 if (ntfs_inode_close(ni))
1573 set_fuse_error(&res);
1574 return res;
1575}
1576
1577#ifdef HAVE_UTIMENSAT
1578
1579static int ntfs_fuse_utimens(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
1580 struct stat *stin, struct stat *stbuf, int to_set)
1581{
1582 ntfs_inode *ni;
1583 int res = 0;
1584
1585 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1586 if (!ni)
1587 return -errno;
1588
1589 /* no check or update if both UTIME_OMIT */
1590 if (to_set & (FUSE_SET_ATTR_ATIME + FUSE_SET_ATTR_MTIME)) {
1591#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1592 if (ntfs_allowed_as_owner(scx, ni)
1593 || ((to_set & FUSE_SET_ATTR_ATIME_NOW)
1594 && (to_set & FUSE_SET_ATTR_MTIME_NOW)
1595 && ntfs_allowed_access(scx, ni, S_IWRITE))) {
1596#endif
1597 ntfs_time_update_flags mask = NTFS_UPDATE_CTIME;
1598
1599 if (to_set & FUSE_SET_ATTR_ATIME_NOW)
1600 mask |= NTFS_UPDATE_ATIME;
1601 else
1602 if (to_set & FUSE_SET_ATTR_ATIME)
1603 ni->last_access_time
1604 = timespec2ntfs(stin->st_atim);
1605 if (to_set & FUSE_SET_ATTR_MTIME_NOW)
1606 mask |= NTFS_UPDATE_MTIME;
1607 else
1608 if (to_set & FUSE_SET_ATTR_MTIME)
1609 ni->last_data_change_time
1610 = timespec2ntfs(stin->st_mtim);
1611 ntfs_inode_update_times(ni, mask);
1612#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1613 } else
1614 res = -errno;
1615#endif
1616 }
1617 if (!res)
1618 res = ntfs_fuse_getstat(scx, ni, stbuf);
1619 if (ntfs_inode_close(ni))
1620 set_fuse_error(&res);
1621 return res;
1622}
1623
1624#else /* HAVE_UTIMENSAT */
1625
1626static int ntfs_fuse_utime(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
1627 struct stat *stin, struct stat *stbuf)
1628{
1629 ntfs_inode *ni;
1630 int res = 0;
1631 struct timespec actime;
1632 struct timespec modtime;
1633#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1634 BOOL ownerok;
1635 BOOL writeok;
1636#endif
1637
1638 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1639 if (!ni)
1640 return -errno;
1641
1642#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1643 ownerok = ntfs_allowed_as_owner(scx, ni);
1644 if (stin) {
1645 /*
1646 * fuse never calls with a NULL buf and we do not
1647 * know whether the specific condition can be applied
1648 * So we have to accept updating by a non-owner having
1649 * write access.
1650 */
1651 writeok = !ownerok
1652 && (stin->st_atime == stin->st_mtime)
1653 && ntfs_allowed_access(scx, ni, S_IWRITE);
1654 /* Must be owner */
1655 if (!ownerok && !writeok)
1656 res = (stin->st_atime == stin->st_mtime
1657 ? -EACCES : -EPERM);
1658 else {
1659 actime.tv_sec = stin->st_atime;
1660 actime.tv_nsec = 0;
1661 modtime.tv_sec = stin->st_mtime;
1662 modtime.tv_nsec = 0;
1663 ni->last_access_time = timespec2ntfs(actime);
1664 ni->last_data_change_time = timespec2ntfs(modtime);
1665 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
1666 }
1667 } else {
1668 /* Must be owner or have write access */
1669 writeok = !ownerok
1670 && ntfs_allowed_access(scx, ni, S_IWRITE);
1671 if (!ownerok && !writeok)
1672 res = -EACCES;
1673 else
1674 ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME);
1675 }
1676#else
1677 if (stin) {
1678 actime.tv_sec = stin->st_atime;
1679 actime.tv_nsec = 0;
1680 modtime.tv_sec = stin->st_mtime;
1681 modtime.tv_nsec = 0;
1682 ni->last_access_time = timespec2ntfs(actime);
1683 ni->last_data_change_time = timespec2ntfs(modtime);
1684 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
1685 } else
1686 ntfs_inode_update_times(ni, NTFS_UPDATE_AMCTIME);
1687#endif
1688
1689 res = ntfs_fuse_getstat(scx, ni, stbuf);
1690 if (ntfs_inode_close(ni))
1691 set_fuse_error(&res);
1692 return res;
1693}
1694
1695#endif /* HAVE_UTIMENSAT */
1696
1697static void ntfs_fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
1698 int to_set, struct fuse_file_info *fi __attribute__((unused)))
1699{
1700 struct stat stbuf;
1701 ntfs_inode *ni;
1702 int res;
1703 struct SECURITY_CONTEXT security;
1704
1705 res = 0;
1706 ntfs_fuse_fill_security_context(req, &security);
1707 /* no flags */
1708 if (!(to_set
1709 & (FUSE_SET_ATTR_MODE
1710 | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID
1711 | FUSE_SET_ATTR_SIZE
1712 | FUSE_SET_ATTR_ATIME | FUSE_SET_ATTR_MTIME))) {
1713 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1714 if (!ni)
1715 res = -errno;
1716 else {
1717 res = ntfs_fuse_getstat(&security, ni, &stbuf);
1718 if (ntfs_inode_close(ni))
1719 set_fuse_error(&res);
1720 }
1721 }
1722 /* some set of uid/gid/mode */
1723 if (to_set
1724 & (FUSE_SET_ATTR_MODE
1725 | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
1726 switch (to_set
1727 & (FUSE_SET_ATTR_MODE
1728 | FUSE_SET_ATTR_UID | FUSE_SET_ATTR_GID)) {
1729 case FUSE_SET_ATTR_MODE :
1730 res = ntfs_fuse_chmod(&security, ino,
1731 attr->st_mode & 07777, &stbuf);
1732 break;
1733 case FUSE_SET_ATTR_UID :
1734 res = ntfs_fuse_chown(&security, ino, attr->st_uid,
1735 (gid_t)-1, &stbuf);
1736 break;
1737 case FUSE_SET_ATTR_GID :
1738 res = ntfs_fuse_chown(&security, ino, (uid_t)-1,
1739 attr->st_gid, &stbuf);
1740 break;
1741 case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_GID :
1742 res = ntfs_fuse_chown(&security, ino, attr->st_uid,
1743 attr->st_gid, &stbuf);
1744 break;
1745 case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_MODE:
1746 res = ntfs_fuse_chownmod(&security, ino, attr->st_uid,
1747 (gid_t)-1,attr->st_mode,
1748 &stbuf);
1749 break;
1750 case FUSE_SET_ATTR_GID + FUSE_SET_ATTR_MODE:
1751 res = ntfs_fuse_chownmod(&security, ino, (uid_t)-1,
1752 attr->st_gid,attr->st_mode,
1753 &stbuf);
1754 break;
1755 case FUSE_SET_ATTR_UID + FUSE_SET_ATTR_GID + FUSE_SET_ATTR_MODE:
1756 res = ntfs_fuse_chownmod(&security, ino, attr->st_uid,
1757 attr->st_gid,attr->st_mode, &stbuf);
1758 break;
1759 default :
1760 break;
1761 }
1762 }
1763 /* size */
1764 if (!res && (to_set & FUSE_SET_ATTR_SIZE)) {
1765 res = ntfs_fuse_trunc(&security, ino, attr->st_size,
1766 !fi, &stbuf);
1767 }
1768 /* some set of atime/mtime */
1769 if (!res && (to_set & (FUSE_SET_ATTR_ATIME + FUSE_SET_ATTR_MTIME))) {
1770#ifdef HAVE_UTIMENSAT
1771 res = ntfs_fuse_utimens(&security, ino, attr, &stbuf, to_set);
1772#else /* HAVE_UTIMENSAT */
1773 res = ntfs_fuse_utime(&security, ino, attr, &stbuf);
1774#endif /* HAVE_UTIMENSAT */
1775 }
1776 if (res)
1777 fuse_reply_err(req, -res);
1778 else
1779 fuse_reply_attr(req, &stbuf, ATTR_TIMEOUT);
1780}
1781
1782#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1783
1784static void ntfs_fuse_access(fuse_req_t req, fuse_ino_t ino, int mask)
1785{
1786 int res = 0;
1787 int mode;
1788 ntfs_inode *ni;
1789 struct SECURITY_CONTEXT security;
1790
1791 /* JPA return unsupported if no user mapping has been defined */
1792 if (!ntfs_fuse_fill_security_context(req, &security)) {
1793 if (ctx->silent)
1794 res = 0;
1795 else
1796 res = -EOPNOTSUPP;
1797 } else {
1798 ni = ntfs_inode_open(ctx->vol, INODE(ino));
1799 if (!ni) {
1800 res = -errno;
1801 } else {
1802 mode = 0;
1803 if (mask & (X_OK | W_OK | R_OK)) {
1804 if (mask & X_OK) mode += S_IEXEC;
1805 if (mask & W_OK) mode += S_IWRITE;
1806 if (mask & R_OK) mode += S_IREAD;
1807 if (!ntfs_allowed_access(&security,
1808 ni, mode))
1809 res = -errno;
1810 }
1811 if (ntfs_inode_close(ni))
1812 set_fuse_error(&res);
1813 }
1814 }
1815 if (res < 0)
1816 fuse_reply_err(req, -res);
1817 else
1818 fuse_reply_err(req, 0);
1819}
1820
1821#endif /* !KERNELPERMS | (POSIXACLS & !KERNELACLS) */
1822
1823static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
1824 mode_t typemode, dev_t dev,
1825 struct fuse_entry_param *e,
1826 const char *target, struct fuse_file_info *fi)
1827{
1828 ntfschar *uname = NULL, *utarget = NULL;
1829 ntfs_inode *dir_ni = NULL, *ni;
1830 struct open_file *of;
1831 int state = 0;
1832 le32 securid;
1833 mode_t type = typemode & ~07777;
1834 mode_t perm;
1835 struct SECURITY_CONTEXT security;
1836 int res = 0, uname_len, utarget_len;
1837
1838 /* Generate unicode filename. */
1839 uname_len = ntfs_mbstoucs(name, &uname);
1840 if (uname_len < 0) {
1841 res = -errno;
1842 goto exit;
1843 }
1844 /* Open parent directory. */
1845 dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
1846 if (!dir_ni) {
1847 res = -errno;
1848 goto exit;
1849 }
1850#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1851 /* make sure parent directory is writeable and executable */
1852 if (!ntfs_fuse_fill_security_context(req, &security)
1853 || ntfs_allowed_access(&security,
1854 dir_ni,S_IWRITE + S_IEXEC)) {
1855#else
1856 ntfs_fuse_fill_security_context(req, &security);
1857#endif
1858 if (S_ISDIR(type))
1859 perm = typemode & ~ctx->dmask & 0777;
1860 else
1861 perm = typemode & ~ctx->fmask & 0777;
1862 /*
1863 * Try to get a security id available for
1864 * file creation (from inheritance or argument).
1865 * This is not possible for NTFS 1.x, and we will
1866 * have to build a security attribute later.
1867 */
1868 if (!ctx->security.mapping[MAPUSERS])
1869 securid = const_cpu_to_le32(0);
1870 else
1871 if (ctx->inherit)
1872 securid = ntfs_inherited_id(&security,
1873 dir_ni, S_ISDIR(type));
1874 else
1875#if POSIXACLS
1876 securid = ntfs_alloc_securid(&security,
1877 security.uid, security.gid,
1878 dir_ni, perm, S_ISDIR(type));
1879#else
1880 securid = ntfs_alloc_securid(&security,
1881 security.uid, security.gid,
1882 perm & ~security.umask, S_ISDIR(type));
1883#endif
1884 /* Create object specified in @type. */
1885 switch (type) {
1886 case S_IFCHR:
1887 case S_IFBLK:
1888 ni = ntfs_create_device(dir_ni, securid,
1889 uname, uname_len, type, dev);
1890 break;
1891 case S_IFLNK:
1892 utarget_len = ntfs_mbstoucs(target, &utarget);
1893 if (utarget_len < 0) {
1894 res = -errno;
1895 goto exit;
1896 }
1897 ni = ntfs_create_symlink(dir_ni, securid,
1898 uname, uname_len,
1899 utarget, utarget_len);
1900 break;
1901 default:
1902 ni = ntfs_create(dir_ni, securid, uname,
1903 uname_len, type);
1904 break;
1905 }
1906 if (ni) {
1907 /*
1908 * set the security attribute if a security id
1909 * could not be allocated (eg NTFS 1.x)
1910 */
1911 if (ctx->security.mapping[MAPUSERS]) {
1912#if POSIXACLS
1913 if (!securid
1914 && ntfs_set_inherited_posix(&security, ni,
1915 security.uid, security.gid,
1916 dir_ni, perm) < 0)
1917 set_fuse_error(&res);
1918#else
1919 if (!securid
1920 && ntfs_set_owner_mode(&security, ni,
1921 security.uid, security.gid,
1922 perm & ~security.umask) < 0)
1923 set_fuse_error(&res);
1924#endif
1925 }
1926 set_archive(ni);
1927 /* mark a need to compress the end of file */
1928 if (fi && (ni->flags & FILE_ATTR_COMPRESSED)) {
1929 state |= CLOSE_COMPRESSED;
1930 }
1931#ifdef HAVE_SETXATTR /* extended attributes interface required */
1932 /* mark a future need to fixup encrypted inode */
1933 if (fi
1934 && ctx->efs_raw
1935 && (ni->flags & FILE_ATTR_ENCRYPTED))
1936 state |= CLOSE_ENCRYPTED;
1937#endif /* HAVE_SETXATTR */
1938 ntfs_inode_update_mbsname(dir_ni, name, ni->mft_no);
1939 NInoSetDirty(ni);
1940 e->ino = ni->mft_no;
1941 e->generation = 1;
1942 e->attr_timeout = ATTR_TIMEOUT;
1943 e->entry_timeout = ENTRY_TIMEOUT;
1944 res = ntfs_fuse_getstat(&security, ni, &e->attr);
1945 /*
1946 * closing ni requires access to dir_ni to
1947 * synchronize the index, avoid double opening.
1948 */
1949 if (ntfs_inode_close_in_dir(ni, dir_ni))
1950 set_fuse_error(&res);
1951 ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME);
1952 } else
1953 res = -errno;
1954#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
1955 } else
1956 res = -errno;
1957#endif
1958
1959exit:
1960 free(uname);
1961 if (ntfs_inode_close(dir_ni))
1962 set_fuse_error(&res);
1963 if (utarget)
1964 free(utarget);
1965 if ((res >= 0) && fi) {
1966 of = (struct open_file*)malloc(sizeof(struct open_file));
1967 if (of) {
1968 of->parent = 0;
1969 of->ino = e->ino;
1970 of->state = state;
1971 of->next = ctx->open_files;
1972 of->previous = (struct open_file*)NULL;
1973 if (ctx->open_files)
1974 ctx->open_files->previous = of;
1975 ctx->open_files = of;
1976 fi->fh = (long)of;
1977 }
1978 }
1979 return res;
1980}
1981
1982static void ntfs_fuse_create_file(fuse_req_t req, fuse_ino_t parent,
1983 const char *name, mode_t mode,
1984 struct fuse_file_info *fi)
1985{
1986 int res;
1987 struct fuse_entry_param entry;
1988
1989 res = ntfs_fuse_create(req, parent, name, mode & (S_IFMT | 07777),
1990 0, &entry, NULL, fi);
1991 if (res < 0)
1992 fuse_reply_err(req, -res);
1993 else
1994 fuse_reply_create(req, &entry, fi);
1995}
1996
1997static void ntfs_fuse_mknod(fuse_req_t req, fuse_ino_t parent, const char *name,
1998 mode_t mode, dev_t rdev)
1999{
2000 int res;
2001 struct fuse_entry_param e;
2002
2003 res = ntfs_fuse_create(req, parent, name, mode & (S_IFMT | 07777),
2004 rdev, &e,NULL,(struct fuse_file_info*)NULL);
2005 if (res < 0)
2006 fuse_reply_err(req, -res);
2007 else
2008 fuse_reply_entry(req, &e);
2009}
2010
2011static void ntfs_fuse_symlink(fuse_req_t req, const char *target,
2012 fuse_ino_t parent, const char *name)
2013{
2014 int res;
2015 struct fuse_entry_param entry;
2016
2017 res = ntfs_fuse_create(req, parent, name, S_IFLNK, 0,
2018 &entry, target, (struct fuse_file_info*)NULL);
2019 if (res < 0)
2020 fuse_reply_err(req, -res);
2021 else
2022 fuse_reply_entry(req, &entry);
2023}
2024
2025
2026static int ntfs_fuse_newlink(fuse_req_t req __attribute__((unused)),
2027 fuse_ino_t ino, fuse_ino_t newparent,
2028 const char *newname, struct fuse_entry_param *e)
2029{
2030 ntfschar *uname = NULL;
2031 ntfs_inode *dir_ni = NULL, *ni;
2032 int res = 0, uname_len;
2033 struct SECURITY_CONTEXT security;
2034
2035 /* Open file for which create hard link. */
2036 ni = ntfs_inode_open(ctx->vol, INODE(ino));
2037 if (!ni) {
2038 res = -errno;
2039 goto exit;
2040 }
2041
2042 /* Generate unicode filename. */
2043 uname_len = ntfs_mbstoucs(newname, &uname);
2044 if (uname_len < 0) {
2045 res = -errno;
2046 goto exit;
2047 }
2048 /* Open parent directory. */
2049 dir_ni = ntfs_inode_open(ctx->vol, INODE(newparent));
2050 if (!dir_ni) {
2051 res = -errno;
2052 goto exit;
2053 }
2054
2055#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
2056 /* make sure the target parent directory is writeable */
2057 if (ntfs_fuse_fill_security_context(req, &security)
2058 && !ntfs_allowed_access(&security,dir_ni,S_IWRITE + S_IEXEC))
2059 res = -EACCES;
2060 else
2061#else
2062 ntfs_fuse_fill_security_context(req, &security);
2063#endif
2064 {
2065 if (ntfs_link(ni, dir_ni, uname, uname_len)) {
2066 res = -errno;
2067 goto exit;
2068 }
2069 ntfs_inode_update_mbsname(dir_ni, newname, ni->mft_no);
2070 if (e) {
2071 e->ino = ni->mft_no;
2072 e->generation = 1;
2073 e->attr_timeout = ATTR_TIMEOUT;
2074 e->entry_timeout = ENTRY_TIMEOUT;
2075 res = ntfs_fuse_getstat(&security, ni, &e->attr);
2076 }
2077 set_archive(ni);
2078 ntfs_fuse_update_times(ni, NTFS_UPDATE_CTIME);
2079 ntfs_fuse_update_times(dir_ni, NTFS_UPDATE_MCTIME);
2080 }
2081exit:
2082 /*
2083 * Must close dir_ni first otherwise ntfs_inode_sync_file_name(ni)
2084 * may fail because ni may not be in parent's index on the disk yet.
2085 */
2086 if (ntfs_inode_close(dir_ni))
2087 set_fuse_error(&res);
2088 if (ntfs_inode_close(ni))
2089 set_fuse_error(&res);
2090 free(uname);
2091 return (res);
2092}
2093
2094static void ntfs_fuse_link(fuse_req_t req, fuse_ino_t ino,
2095 fuse_ino_t newparent, const char *newname)
2096{
2097 struct fuse_entry_param entry;
2098 int res;
2099
2100 res = ntfs_fuse_newlink(req, ino, newparent, newname, &entry);
2101 if (res)
2102 fuse_reply_err(req, -res);
2103 else
2104 fuse_reply_entry(req, &entry);
2105}
2106
2107static int ntfs_fuse_rm(fuse_req_t req, fuse_ino_t parent, const char *name)
2108{
2109 ntfschar *uname = NULL;
2110 ntfs_inode *dir_ni = NULL, *ni = NULL;
2111 int res = 0, uname_len;
2112 u64 iref;
2113 fuse_ino_t ino;
2114 struct open_file *of;
2115 char ghostname[GHOSTLTH];
2116#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
2117 struct SECURITY_CONTEXT security;
2118#endif
2119
2120 /* Open parent directory. */
2121 dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
2122 if (!dir_ni) {
2123 res = -errno;
2124 goto exit;
2125 }
2126 /* Generate unicode filename. */
2127 uname_len = ntfs_mbstoucs(name, &uname);
2128 if (uname_len < 0) {
2129 res = -errno;
2130 goto exit;
2131 }
2132 /* Open object for delete. */
2133 iref = ntfs_inode_lookup_by_mbsname(dir_ni, name);
2134 if (iref == (u64)-1) {
2135 res = -errno;
2136 goto exit;
2137 }
2138
2139{ /* temporary */
2140struct open_file *prev = (struct open_file*)NULL;
2141for (of=ctx->open_files; of; of=of->next)
2142{
2143if (of->previous != prev) ntfs_log_error("bad chaining\n");
2144prev = of;
2145}
2146}
2147 of = ctx->open_files;
2148 ino = (fuse_ino_t)MREF(iref);
2149 /* improvable search in open files list... */
2150 while (of
2151 && (of->ino != ino))
2152 of = of->next;
2153 if (of && !(of->state & CLOSE_GHOST)) {
2154 /* file was open, create a ghost in unlink parent */
2155 of->state |= CLOSE_GHOST;
2156 of->parent = parent;
2157 of->ghost = ++ctx->latest_ghost;
2158 sprintf(ghostname,ghostformat,of->ghost);
2159 /* need to close the dir for linking the ghost */
2160 if (ntfs_inode_close(dir_ni)) {
2161 res = -errno;
2162 goto out;
2163 }
2164 /* sweep existing ghost if any */
2165 ntfs_fuse_rm(req, parent, ghostname);
2166 res = ntfs_fuse_newlink(req, of->ino, parent, ghostname,
2167 (struct fuse_entry_param*)NULL);
2168 if (res)
2169 goto out;
2170 /* now reopen then parent directory */
2171 dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
2172 if (!dir_ni) {
2173 res = -errno;
2174 goto exit;
2175 }
2176 }
2177
2178 ni = ntfs_inode_open(ctx->vol, MREF(iref));
2179 if (!ni) {
2180 res = -errno;
2181 goto exit;
2182 }
2183
2184#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
2185 /* JPA deny unlinking if directory is not writable and executable */
2186 if (!ntfs_fuse_fill_security_context(req, &security)
2187 || ntfs_allowed_dir_access(&security, dir_ni, ino, ni,
2188 S_IEXEC + S_IWRITE + S_ISVTX)) {
2189#endif
2190 if (ntfs_delete(ctx->vol, (char*)NULL, ni, dir_ni,
2191 uname, uname_len))
2192 res = -errno;
2193 /* ntfs_delete() always closes ni and dir_ni */
2194 ni = dir_ni = NULL;
2195#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
2196 } else
2197 res = -EACCES;
2198#endif
2199exit:
2200 if (ntfs_inode_close(ni))
2201 set_fuse_error(&res);
2202 if (ntfs_inode_close(dir_ni))
2203 set_fuse_error(&res);
2204out :
2205 free(uname);
2206 return res;
2207}
2208
2209static void ntfs_fuse_unlink(fuse_req_t req, fuse_ino_t parent,
2210 const char *name)
2211{
2212 int res;
2213
2214 res = ntfs_fuse_rm(req, parent, name);
2215 if (res)
2216 fuse_reply_err(req, -res);
2217 else
2218 fuse_reply_err(req, 0);
2219}
2220
2221static int ntfs_fuse_safe_rename(fuse_req_t req, fuse_ino_t ino,
2222 fuse_ino_t parent, const char *name, fuse_ino_t xino,
2223 fuse_ino_t newparent, const char *newname,
2224 const char *tmp)
2225{
2226 int ret;
2227
2228 ntfs_log_trace("Entering\n");
2229
2230 ret = ntfs_fuse_newlink(req, xino, newparent, tmp,
2231 (struct fuse_entry_param*)NULL);
2232 if (ret)
2233 return ret;
2234
2235 ret = ntfs_fuse_rm(req, newparent, newname);
2236 if (!ret) {
2237
2238 ret = ntfs_fuse_newlink(req, ino, newparent, newname,
2239 (struct fuse_entry_param*)NULL);
2240 if (ret)
2241 goto restore;
2242
2243 ret = ntfs_fuse_rm(req, parent, name);
2244 if (ret) {
2245 if (ntfs_fuse_rm(req, newparent, newname))
2246 goto err;
2247 goto restore;
2248 }
2249 }
2250
2251 goto cleanup;
2252restore:
2253 if (ntfs_fuse_newlink(req, xino, newparent, newname,
2254 (struct fuse_entry_param*)NULL)) {
2255err:
2256 ntfs_log_perror("Rename failed. Existing file '%s' was renamed "
2257 "to '%s'", newname, tmp);
2258 } else {
2259cleanup:
2260 /*
2261 * Condition for this unlink has already been checked in
2262 * "ntfs_fuse_rename_existing_dest()", so it should never
2263 * fail (unless concurrent access to directories when fuse
2264 * is multithreaded)
2265 */
2266 if (ntfs_fuse_rm(req, newparent, tmp) < 0)
2267 ntfs_log_perror("Rename failed. Existing file '%s' still present "
2268 "as '%s'", newname, tmp);
2269 }
2270 return ret;
2271}
2272
2273static int ntfs_fuse_rename_existing_dest(fuse_req_t req, fuse_ino_t ino,
2274 fuse_ino_t parent, const char *name,
2275 fuse_ino_t xino, fuse_ino_t newparent,
2276 const char *newname)
2277{
2278 int ret, len;
2279 char *tmp;
2280 const char *ext = ".ntfs-3g-";
2281#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
2282 ntfs_inode *newdir_ni;
2283 struct SECURITY_CONTEXT security;
2284#endif
2285
2286 ntfs_log_trace("Entering\n");
2287
2288 len = strlen(newname) + strlen(ext) + 10 + 1; /* wc(str(2^32)) + \0 */
2289 tmp = (char*)ntfs_malloc(len);
2290 if (!tmp)
2291 return -errno;
2292
2293 ret = snprintf(tmp, len, "%s%s%010d", newname, ext, ++ntfs_sequence);
2294 if (ret != len - 1) {
2295 ntfs_log_error("snprintf failed: %d != %d\n", ret, len - 1);
2296 ret = -EOVERFLOW;
2297 } else {
2298#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
2299 /*
2300 * Make sure existing dest can be removed.
2301 * This is only needed if parent directory is
2302 * sticky, because in this situation condition
2303 * for unlinking is different from condition for
2304 * linking
2305 */
2306 newdir_ni = ntfs_inode_open(ctx->vol, INODE(newparent));
2307 if (newdir_ni) {
2308 if (!ntfs_fuse_fill_security_context(req,&security)
2309 || ntfs_allowed_dir_access(&security, newdir_ni,
2310 xino, (ntfs_inode*)NULL,
2311 S_IEXEC + S_IWRITE + S_ISVTX)) {
2312 if (ntfs_inode_close(newdir_ni))
2313 ret = -errno;
2314 else
2315 ret = ntfs_fuse_safe_rename(req, ino,
2316 parent, name, xino,
2317 newparent, newname,
2318 tmp);
2319 } else {
2320 ntfs_inode_close(newdir_ni);
2321 ret = -EACCES;
2322 }
2323 } else
2324 ret = -errno;
2325#else
2326 ret = ntfs_fuse_safe_rename(req, ino, parent, name,
2327 xino, newparent, newname, tmp);
2328#endif
2329 }
2330 free(tmp);
2331 return ret;
2332}
2333
2334static void ntfs_fuse_rename(fuse_req_t req, fuse_ino_t parent,
2335 const char *name, fuse_ino_t newparent,
2336 const char *newname)
2337{
2338 int ret;
2339 fuse_ino_t ino;
2340 fuse_ino_t xino;
2341 ntfs_inode *ni;
2342
2343 ntfs_log_debug("rename: old: '%s' new: '%s'\n", name, newname);
2344
2345 /*
2346 * FIXME: Rename should be atomic.
2347 */
2348
2349 ino = ntfs_fuse_inode_lookup(parent, name);
2350 if (ino == (fuse_ino_t)-1) {
2351 ret = -errno;
2352 goto out;
2353 }
2354 /* Check whether target is present */
2355 xino = ntfs_fuse_inode_lookup(newparent, newname);
2356 if (xino != (fuse_ino_t)-1) {
2357 /*
2358 * Target exists : no need to check whether it
2359 * designates the same inode, this has already
2360 * been checked (by fuse ?)
2361 */
2362 ni = ntfs_inode_open(ctx->vol, INODE(xino));
2363 if (!ni)
2364 ret = -errno;
2365 else {
2366 ret = ntfs_check_empty_dir(ni);
2367 if (ret < 0) {
2368 ret = -errno;
2369 ntfs_inode_close(ni);
2370 goto out;
2371 }
2372
2373 if (ntfs_inode_close(ni)) {
2374 set_fuse_error(&ret);
2375 goto out;
2376 }
2377 ret = ntfs_fuse_rename_existing_dest(req, ino, parent,
2378 name, xino, newparent, newname);
2379 }
2380 } else {
2381 /* target does not exist */
2382 ret = ntfs_fuse_newlink(req, ino, newparent, newname,
2383 (struct fuse_entry_param*)NULL);
2384 if (ret)
2385 goto out;
2386
2387 ret = ntfs_fuse_rm(req, parent, name);
2388 if (ret)
2389 ntfs_fuse_rm(req, newparent, newname);
2390 }
2391out:
2392 if (ret)
2393 fuse_reply_err(req, -ret);
2394 else
2395 fuse_reply_err(req, 0);
2396}
2397
2398static void ntfs_fuse_release(fuse_req_t req, fuse_ino_t ino,
2399 struct fuse_file_info *fi)
2400{
2401 ntfs_inode *ni = NULL;
2402 ntfs_attr *na = NULL;
2403 struct open_file *of;
2404 char ghostname[GHOSTLTH];
2405 int res;
2406
2407 of = (struct open_file*)(long)fi->fh;
2408 /* Only for marked descriptors there is something to do */
2409 if (!of || !(of->state & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED))) {
2410 res = 0;
2411 goto out;
2412 }
2413 ni = ntfs_inode_open(ctx->vol, INODE(ino));
2414 if (!ni) {
2415 res = -errno;
2416 goto exit;
2417 }
2418 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
2419 if (!na) {
2420 res = -errno;
2421 goto exit;
2422 }
2423 res = 0;
2424 if (of->state & CLOSE_COMPRESSED)
2425 res = ntfs_attr_pclose(na);
2426#ifdef HAVE_SETXATTR /* extended attributes interface required */
2427 if (of->state & CLOSE_ENCRYPTED)
2428 res = ntfs_efs_fixup_attribute(NULL, na);
2429#endif /* HAVE_SETXATTR */
2430exit:
2431 if (na)
2432 ntfs_attr_close(na);
2433 if (ntfs_inode_close(ni))
2434 set_fuse_error(&res);
2435out:
2436 /* remove the associate ghost file (even if release failed) */
2437 if (of) {
2438 if (of->state & CLOSE_GHOST) {
2439 sprintf(ghostname,ghostformat,of->ghost);
2440 ntfs_fuse_rm(req, of->parent, ghostname);
2441 }
2442 /* remove from open files list */
2443 if (of->next)
2444 of->next->previous = of->previous;
2445 if (of->previous)
2446 of->previous->next = of->next;
2447 else
2448 ctx->open_files = of->next;
2449 free(of);
2450 }
2451 if (res)
2452 fuse_reply_err(req, -res);
2453 else
2454 fuse_reply_err(req, 0);
2455}
2456
2457static void ntfs_fuse_mkdir(fuse_req_t req, fuse_ino_t parent,
2458 const char *name, mode_t mode)
2459{
2460 int res;
2461 struct fuse_entry_param entry;
2462
2463 res = ntfs_fuse_create(req, parent, name, S_IFDIR | (mode & 07777),
2464 0, &entry, (char*)NULL, (struct fuse_file_info*)NULL);
2465 if (res < 0)
2466 fuse_reply_err(req, -res);
2467 else
2468 fuse_reply_entry(req, &entry);
2469}
2470
2471static void ntfs_fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
2472{
2473 int res;
2474
2475 res = ntfs_fuse_rm(req, parent, name);
2476 if (res)
2477 fuse_reply_err(req, -res);
2478 else
2479 fuse_reply_err(req, 0);
2480}
2481
2482static void ntfs_fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
2483 uint64_t vidx)
2484{
2485 ntfs_inode *ni;
2486 ntfs_attr *na;
2487 LCN lcn;
2488 uint64_t lidx = 0;
2489 int ret = 0;
2490 int cl_per_bl = ctx->vol->cluster_size / blocksize;
2491
2492 if (blocksize > ctx->vol->cluster_size) {
2493 ret = -EINVAL;
2494 goto done;
2495 }
2496
2497 ni = ntfs_inode_open(ctx->vol, INODE(ino));
2498 if (!ni) {
2499 ret = -errno;
2500 goto done;
2501 }
2502
2503 na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
2504 if (!na) {
2505 ret = -errno;
2506 goto close_inode;
2507 }
2508
2509 if ((na->data_flags & (ATTR_COMPRESSION_MASK | ATTR_IS_ENCRYPTED))
2510 || !NAttrNonResident(na)) {
2511 ret = -EINVAL;
2512 goto close_attr;
2513 }
2514
2515 if (ntfs_attr_map_whole_runlist(na)) {
2516 ret = -errno;
2517 goto close_attr;
2518 }
2519
2520 lcn = ntfs_rl_vcn_to_lcn(na->rl, vidx / cl_per_bl);
2521 lidx = (lcn > 0) ? lcn * cl_per_bl + vidx % cl_per_bl : 0;
2522
2523close_attr:
2524 ntfs_attr_close(na);
2525close_inode:
2526 if (ntfs_inode_close(ni))
2527 set_fuse_error(&ret);
2528done :
2529 if (ret < 0)
2530 fuse_reply_err(req, -ret);
2531 else
2532 fuse_reply_bmap(req, lidx);
2533}
2534
2535#ifdef HAVE_SETXATTR
2536
2537/*
2538 * Name space identifications and prefixes
2539 */
2540
2541enum { XATTRNS_NONE,
2542 XATTRNS_USER,
2543 XATTRNS_SYSTEM,
2544 XATTRNS_SECURITY,
2545 XATTRNS_TRUSTED,
2546 XATTRNS_OPEN } ;
2547
2548static const char nf_ns_user_prefix[] = "user.";
2549static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
2550static const char nf_ns_system_prefix[] = "system.";
2551static const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1;
2552static const char nf_ns_security_prefix[] = "security.";
2553static const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1;
2554static const char nf_ns_trusted_prefix[] = "trusted.";
2555static const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1;
2556
2557static const char xattr_ntfs_3g[] = "ntfs-3g.";
2558
2559/*
2560 * Identification of data mapped to the system name space
2561 */
2562
2563enum { XATTR_UNMAPPED,
2564 XATTR_NTFS_ACL,
2565 XATTR_NTFS_ATTRIB,
2566 XATTR_NTFS_EFSINFO,
2567 XATTR_NTFS_REPARSE_DATA,
2568 XATTR_NTFS_OBJECT_ID,
2569 XATTR_NTFS_DOS_NAME,
2570 XATTR_NTFS_TIMES,
2571 XATTR_POSIX_ACC,
2572 XATTR_POSIX_DEF } ;
2573
2574static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl";
2575static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
2576static const char nf_ns_xattr_efsinfo[] = "user.ntfs.efsinfo";
2577static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data";
2578static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id";
2579static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name";
2580static const char nf_ns_xattr_times[] = "system.ntfs_times";
2581static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
2582static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
2583
2584struct XATTRNAME {
2585 int xattr;
2586 const char *name;
2587} ;
2588
2589static struct XATTRNAME nf_ns_xattr_names[] = {
2590 { XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl },
2591 { XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib },
2592 { XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo },
2593 { XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse },
2594 { XATTR_NTFS_OBJECT_ID, nf_ns_xattr_object_id },
2595 { XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name },
2596 { XATTR_NTFS_TIMES, nf_ns_xattr_times },
2597 { XATTR_POSIX_ACC, nf_ns_xattr_posix_access },
2598 { XATTR_POSIX_DEF, nf_ns_xattr_posix_default },
2599 { XATTR_UNMAPPED, (char*)NULL } /* terminator */
2600};
2601
2602/*
2603 * Check whether access to internal data as an extended
2604 * attribute in system name space is allowed
2605 *
2606 * Returns pointer to inode if allowed,
2607 * NULL and errno set if not allowed
2608 */
2609
2610static ntfs_inode *ntfs_check_access_xattr(fuse_req_t req,
2611 struct SECURITY_CONTEXT *security,
2612 fuse_ino_t ino, int attr, BOOL setting)
2613{
2614 ntfs_inode *dir_ni;
2615 ntfs_inode *ni;
2616 BOOL foracl;
2617 BOOL bad;
2618 mode_t acctype;
2619
2620 ni = (ntfs_inode*)NULL;
2621 foracl = (attr == XATTR_POSIX_ACC)
2622 || (attr == XATTR_POSIX_DEF);
2623 /*
2624 * When accessing Posix ACL, return unsupported if ACL
2625 * were disabled or no user mapping has been defined.
2626 * However no error will be returned to getfacl
2627 */
2628 if ((!ntfs_fuse_fill_security_context(req, security)
2629 || (ctx->secure_flags
2630 & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_RAW))))
2631 && foracl) {
2632 errno = EOPNOTSUPP;
2633 } else {
2634 /*
2635 * parent directory must be executable, and
2636 * for setting a DOS name it must be writeable
2637 */
2638 if (setting && (attr == XATTR_NTFS_DOS_NAME))
2639 acctype = S_IEXEC | S_IWRITE;
2640 else
2641 acctype = S_IEXEC;
2642 ni = ntfs_inode_open(ctx->vol, INODE(ino));
2643 /* basic access was checked previously in a lookup */
2644 if (ni && (acctype != S_IEXEC)) {
2645 bad = FALSE;
2646 /* do not reopen root */
2647 if (ni->mft_no == FILE_root) {
2648 /* forbid getting/setting names on root */
2649 if ((attr == XATTR_NTFS_DOS_NAME)
2650 || !ntfs_real_allowed_access(security,
2651 ni, acctype))
2652 bad = TRUE;
2653 } else {
2654 dir_ni = ntfs_dir_parent_inode(ni);
2655 if (dir_ni) {
2656 if (!ntfs_real_allowed_access(security,
2657 dir_ni, acctype))
2658 bad = TRUE;
2659 if (ntfs_inode_close(dir_ni))
2660 bad = TRUE;
2661 } else
2662 bad = TRUE;
2663 }
2664 if (bad) {
2665 ntfs_inode_close(ni);
2666 ni = (ntfs_inode*)NULL;
2667 }
2668 }
2669 }
2670 return (ni);
2671}
2672
2673/*
2674 * Determine whether an extended attribute is in the system
2675 * name space and mapped to internal data
2676 */
2677
2678static int mapped_xattr_system(const char *name)
2679{
2680 struct XATTRNAME *p;
2681
2682 p = nf_ns_xattr_names;
2683 while (p->name && strcmp(p->name,name))
2684 p++;
2685 return (p->xattr);
2686}
2687
2688/*
2689 * Determine the name space of an extended attribute
2690 */
2691
2692static int xattr_namespace(const char *name)
2693{
2694 int namespace;
2695
2696 if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) {
2697 namespace = XATTRNS_NONE;
2698 if (!strncmp(name, nf_ns_user_prefix,
2699 nf_ns_user_prefix_len)
2700 && (strlen(name) != (size_t)nf_ns_user_prefix_len))
2701 namespace = XATTRNS_USER;
2702 else if (!strncmp(name, nf_ns_system_prefix,
2703 nf_ns_system_prefix_len)
2704 && (strlen(name) != (size_t)nf_ns_system_prefix_len))
2705 namespace = XATTRNS_SYSTEM;
2706 else if (!strncmp(name, nf_ns_security_prefix,
2707 nf_ns_security_prefix_len)
2708 && (strlen(name) != (size_t)nf_ns_security_prefix_len))
2709 namespace = XATTRNS_SECURITY;
2710 else if (!strncmp(name, nf_ns_trusted_prefix,
2711 nf_ns_trusted_prefix_len)
2712 && (strlen(name) != (size_t)nf_ns_trusted_prefix_len))
2713 namespace = XATTRNS_TRUSTED;
2714 } else
2715 namespace = XATTRNS_OPEN;
2716 return (namespace);
2717}
2718
2719/*
2720 * Fix the prefix of an extended attribute
2721 */
2722
2723static int fix_xattr_prefix(const char *name, int namespace, ntfschar **lename)
2724{
2725 int len;
2726 char *prefixed;
2727
2728 *lename = (ntfschar*)NULL;
2729 switch (namespace) {
2730 case XATTRNS_USER :
2731 /*
2732 * user name space : remove user prefix
2733 */
2734 len = ntfs_mbstoucs(name + nf_ns_user_prefix_len, lename);
2735 break;
2736 case XATTRNS_SYSTEM :
2737 case XATTRNS_SECURITY :
2738 case XATTRNS_TRUSTED :
2739 /*
2740 * security, trusted and unmapped system name spaces :
2741 * insert ntfs-3g prefix
2742 */
2743 prefixed = (char*)ntfs_malloc(strlen(xattr_ntfs_3g)
2744 + strlen(name) + 1);
2745 if (prefixed) {
2746 strcpy(prefixed,xattr_ntfs_3g);
2747 strcat(prefixed,name);
2748 len = ntfs_mbstoucs(prefixed, lename);
2749 free(prefixed);
2750 } else
2751 len = -1;
2752 break;
2753 case XATTRNS_OPEN :
2754 /*
2755 * in open name space mode : do no fix prefix
2756 */
2757 len = ntfs_mbstoucs(name, lename);
2758 break;
2759 default :
2760 len = -1;
2761 }
2762 return (len);
2763}
2764
2765static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
2766{
2767 ntfs_attr_search_ctx *actx = NULL;
2768 ntfs_inode *ni;
2769 char *to;
2770 char *list = (char*)NULL;
2771 int ret = 0;
2772#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
2773 struct SECURITY_CONTEXT security;
2774#endif
2775
2776#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
2777 ntfs_fuse_fill_security_context(req, &security);
2778#endif
2779 ni = ntfs_inode_open(ctx->vol, INODE(ino));
2780 if (!ni) {
2781 ret = -errno;
2782 goto out;
2783 }
2784#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
2785 /* file must be readable */
2786// condition on fill_security ?
2787 if (!ntfs_allowed_access(&security,ni,S_IREAD)) {
2788 ret = -EACCES;
2789 goto exit;
2790 }
2791#endif
2792 actx = ntfs_attr_get_search_ctx(ni, NULL);
2793 if (!actx) {
2794 ret = -errno;
2795 goto exit;
2796 }
2797 if (size) {
2798 list = (char*)malloc(size);
2799 if (!list) {
2800 ret = -errno;
2801 goto exit;
2802 }
2803 }
2804 to = list;
2805
2806 if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR)
2807 || (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) {
2808 while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
2809 0, NULL, 0, actx)) {
2810 char *tmp_name = NULL;
2811 int tmp_name_len;
2812
2813 if (!actx->attr->name_length)
2814 continue;
2815 tmp_name_len = ntfs_ucstombs(
2816 (ntfschar *)((u8*)actx->attr +
2817 le16_to_cpu(actx->attr->name_offset)),
2818 actx->attr->name_length, &tmp_name, 0);
2819 if (tmp_name_len < 0) {
2820 ret = -errno;
2821 goto exit;
2822 }
2823 /*
2824 * When using name spaces, do not return
2825 * security, trusted nor system attributes
2826 * (filtered elsewhere anyway)
2827 * otherwise insert "user." prefix
2828 */
2829 if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) {
2830 if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g))
2831 && !strncmp(tmp_name,xattr_ntfs_3g,
2832 sizeof(xattr_ntfs_3g)-1))
2833 tmp_name_len = 0;
2834 else
2835 ret += tmp_name_len
2836 + nf_ns_user_prefix_len + 1;
2837 } else
2838 ret += tmp_name_len + 1;
2839 if (size && tmp_name_len) {
2840 if ((size_t)ret <= size) {
2841 if (ctx->streams
2842 == NF_STREAMS_INTERFACE_XATTR) {
2843 strcpy(to, nf_ns_user_prefix);
2844 to += nf_ns_user_prefix_len;
2845 }
2846 strncpy(to, tmp_name, tmp_name_len);
2847 to += tmp_name_len;
2848 *to = 0;
2849 to++;
2850 } else {
2851 free(tmp_name);
2852 ret = -ERANGE;
2853 goto exit;
2854 }
2855 }
2856 free(tmp_name);
2857 }
2858 }
2859
2860 /* List efs info xattr for encrypted files */
2861 if (ctx->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) {
2862 ret += sizeof(nf_ns_xattr_efsinfo);
2863 if ((size_t)ret <= size) {
2864 memcpy(to, nf_ns_xattr_efsinfo,
2865 sizeof(nf_ns_xattr_efsinfo));
2866 to += sizeof(nf_ns_xattr_efsinfo);
2867 }
2868 }
2869
2870 if (errno != ENOENT)
2871 ret = -errno;
2872exit:
2873 if (actx)
2874 ntfs_attr_put_search_ctx(actx);
2875 if (ntfs_inode_close(ni))
2876 set_fuse_error(&ret);
2877out :
2878 if (ret < 0)
2879 fuse_reply_err(req, -ret);
2880 else
2881 if (size)
2882 fuse_reply_buf(req, list, ret);
2883 else
2884 fuse_reply_xattr(req, ret);
2885 free(list);
2886}
2887
2888static __inline__ int ntfs_system_getxattr(struct SECURITY_CONTEXT *scx,
2889 int attr, ntfs_inode *ni, char *value, size_t size)
2890{
2891 int res;
2892 ntfs_inode *dir_ni;
2893
2894 /*
2895 * the returned value is the needed
2896 * size. If it is too small, no copy
2897 * is done, and the caller has to
2898 * issue a new call with correct size.
2899 */
2900 switch (attr) {
2901 case XATTR_NTFS_ACL :
2902 res = ntfs_get_ntfs_acl(scx, ni, value, size);
2903 break;
2904#if POSIXACLS
2905 case XATTR_POSIX_ACC :
2906 res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access,
2907 value, size);
2908 break;
2909 case XATTR_POSIX_DEF :
2910 res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default,
2911 value, size);
2912 break;
2913#endif
2914 case XATTR_NTFS_ATTRIB :
2915 res = ntfs_get_ntfs_attrib(ni, value, size);
2916 break;
2917 case XATTR_NTFS_EFSINFO :
2918 if (ctx->efs_raw)
2919 res = ntfs_get_efs_info(ni, value, size);
2920 else
2921 res = -EPERM;
2922 break;
2923 case XATTR_NTFS_REPARSE_DATA :
2924 res = ntfs_get_ntfs_reparse_data(ni, value, size);
2925 break;
2926 case XATTR_NTFS_OBJECT_ID :
2927 res = ntfs_get_ntfs_object_id(ni, value, size);
2928 break;
2929 case XATTR_NTFS_DOS_NAME:
2930 dir_ni = ntfs_dir_parent_inode(ni);
2931 if (dir_ni) {
2932 res = ntfs_get_ntfs_dos_name(ni, dir_ni, value, size);
2933 if (ntfs_inode_close(dir_ni))
2934 set_fuse_error(&res);
2935 } else
2936 res = -errno;
2937 break;
2938 case XATTR_NTFS_TIMES:
2939 res = ntfs_inode_get_times(ni, value, size);
2940 break;
2941 default :
2942 errno = EOPNOTSUPP;
2943 res = -errno;
2944 break;
2945 }
2946 return (res);
2947}
2948
2949static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
2950 size_t size)
2951{
2952 ntfs_inode *ni;
2953 ntfs_attr *na = NULL;
2954 char *value = (char*)NULL;
2955 ntfschar *lename = (ntfschar*)NULL;
2956 int lename_len;
2957 int res;
2958 s64 rsize;
2959 int attr;
2960 int namespace;
2961 struct SECURITY_CONTEXT security;
2962
2963 attr = mapped_xattr_system(name);
2964 if (attr != XATTR_UNMAPPED) {
2965 /*
2966 * hijack internal data and ACL retrieval, whatever
2967 * mode was selected for xattr (from the user's
2968 * point of view, ACLs are not xattr)
2969 */
2970 if (size)
2971 value = (char*)ntfs_malloc(size);
2972#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
2973 if (!size || value) {
2974 ni = ntfs_check_access_xattr(req, &security, ino,
2975 attr, FALSE);
2976 if (ni) {
2977 if (ntfs_allowed_access(&security,ni,S_IREAD))
2978 res = ntfs_system_getxattr(&security,
2979 attr, ni, value, size);
2980 else
2981 res = -errno;
2982 if (ntfs_inode_close(ni))
2983 set_fuse_error(&res);
2984 } else
2985 res = -errno;
2986 }
2987#else
2988 /*
2989 * Standard access control has been done by fuse/kernel
2990 */
2991 if (!size || value) {
2992 ni = ntfs_inode_open(ctx->vol, INODE(ino));
2993 if (ni) {
2994 /* user mapping not mandatory */
2995 ntfs_fuse_fill_security_context(req, &security);
2996 res = ntfs_system_getxattr(&security,
2997 attr, ni, value, size);
2998 if (ntfs_inode_close(ni))
2999 set_fuse_error(&res);
3000 } else
3001 res = -errno;
3002 } else
3003 res = -errno;
3004#endif
3005 if (res < 0)
3006 fuse_reply_err(req, -res);
3007 else
3008 if (size)
3009 fuse_reply_buf(req, value, res);
3010 else
3011 fuse_reply_xattr(req, res);
3012 free(value);
3013 return;
3014 }
3015 if (ctx->streams == NF_STREAMS_INTERFACE_NONE) {
3016 res = -EOPNOTSUPP;
3017 goto out;
3018 }
3019 if (ctx->streams == NF_STREAMS_INTERFACE_NONE) {
3020 res = -EOPNOTSUPP;
3021 goto out;
3022 }
3023 namespace = xattr_namespace(name);
3024 if (namespace == XATTRNS_NONE) {
3025 res = -EOPNOTSUPP;
3026 goto out;
3027 }
3028#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
3029 ntfs_fuse_fill_security_context(req,&security);
3030 /* trusted only readable by root */
3031 if ((namespace == XATTRNS_TRUSTED)
3032 && security.uid) {
3033 res = -EPERM;
3034 goto out;
3035 }
3036#endif
3037 ni = ntfs_inode_open(ctx->vol, INODE(ino));
3038 if (!ni) {
3039 res = -errno;
3040 goto out;
3041 }
3042#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
3043 /* file must be readable */
3044// condition on fill_security
3045 if (!ntfs_allowed_access(&security, ni, S_IREAD)) {
3046 res = -errno;
3047 goto exit;
3048 }
3049#endif
3050 lename_len = fix_xattr_prefix(name, namespace, &lename);
3051 if (lename_len == -1) {
3052 res = -errno;
3053 goto exit;
3054 }
3055 na = ntfs_attr_open(ni, AT_DATA, lename, lename_len);
3056 if (!na) {
3057 res = -ENODATA;
3058 goto exit;
3059 }
3060 rsize = na->data_size;
3061 if (ctx->efs_raw &&
3062 (na->data_flags & ATTR_IS_ENCRYPTED) &&
3063 NAttrNonResident(na))
3064 rsize = ((na->data_size + 511) & ~511)+2;
3065 if (size) {
3066 if (size >= (size_t)rsize) {
3067 value = (char*)ntfs_malloc(rsize);
3068 if (value)
3069 res = ntfs_attr_pread(na, 0, rsize, value);
3070 if (!value || (res != rsize))
3071 res = -errno;
3072 } else
3073 res = -ERANGE;
3074 } else
3075 res = rsize;
3076exit:
3077 if (na)
3078 ntfs_attr_close(na);
3079 free(lename);
3080 if (ntfs_inode_close(ni))
3081 set_fuse_error(&res);
3082
3083out :
3084 if (res < 0)
3085 fuse_reply_err(req, -res);
3086 else
3087 if (size)
3088 fuse_reply_buf(req, value, res);
3089 else
3090 fuse_reply_xattr(req, res);
3091 free(value);
3092}
3093
3094static __inline__ int ntfs_system_setxattr(struct SECURITY_CONTEXT *scx,
3095 int attr, ntfs_inode *ni, const char *value,
3096 size_t size, int flags)
3097{
3098 int res;
3099 ntfs_inode *dir_ni;
3100
3101 switch (attr) {
3102 case XATTR_NTFS_ACL :
3103 res = ntfs_set_ntfs_acl(scx, ni, value, size, flags);
3104 break;
3105#if POSIXACLS
3106 case XATTR_POSIX_ACC :
3107 res = ntfs_set_posix_acl(scx ,ni , nf_ns_xattr_posix_access,
3108 value, size, flags);
3109 break;
3110 case XATTR_POSIX_DEF :
3111 res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default,
3112 value, size, flags);
3113 break;
3114#endif
3115 case XATTR_NTFS_ATTRIB :
3116 res = ntfs_set_ntfs_attrib(ni, value, size, flags);
3117 break;
3118 case XATTR_NTFS_EFSINFO :
3119 if (ctx->efs_raw)
3120 res = ntfs_set_efs_info(ni, value, size, flags);
3121 else
3122 res = -EPERM;
3123 break;
3124 case XATTR_NTFS_REPARSE_DATA :
3125 res = ntfs_set_ntfs_reparse_data(ni, value, size, flags);
3126 break;
3127 case XATTR_NTFS_OBJECT_ID :
3128 res = ntfs_set_ntfs_object_id(ni, value, size, flags);
3129 break;
3130 case XATTR_NTFS_DOS_NAME:
3131 dir_ni = ntfs_dir_parent_inode(ni);
3132 if (dir_ni)
3133 /* warning : this closes both inodes */
3134 res = ntfs_set_ntfs_dos_name(ni, dir_ni, value,
3135 size, flags);
3136 else
3137 res = -errno;
3138 break;
3139 case XATTR_NTFS_TIMES:
3140 res = ntfs_inode_set_times(ni, value, size, flags);
3141 break;
3142 default :
3143 errno = EOPNOTSUPP;
3144 res = -errno;
3145 break;
3146 }
3147 return (res);
3148}
3149
3150static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
3151 const char *value, size_t size, int flags)
3152{
3153 ntfs_inode *ni;
3154 ntfs_attr *na = NULL;
3155 ntfschar *lename = NULL;
3156 int res, lename_len;
3157 size_t part, total;
3158 int attr;
3159 int namespace;
3160 struct SECURITY_CONTEXT security;
3161
3162 attr = mapped_xattr_system(name);
3163 if (attr != XATTR_UNMAPPED) {
3164 /*
3165 * hijack internal data and ACL setting, whatever
3166 * mode was selected for xattr (from the user's
3167 * point of view, ACLs are not xattr)
3168 * Note : updating an ACL does not set ctime
3169 */
3170#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
3171 ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE);
3172 if (ni) {
3173 if (ntfs_allowed_as_owner(&security, ni)) {
3174 res = ntfs_system_setxattr(&security,
3175 attr, ni, value, size, flags);
3176 if (res)
3177 res = -errno;
3178 } else
3179 res = -errno;
3180 if ((attr != XATTR_NTFS_DOS_NAME)
3181 && ntfs_inode_close(ni))
3182 set_fuse_error(&res);
3183 } else
3184 res = -errno;
3185#else
3186 /* creation of a new name is not controlled by fuse */
3187 if (attr == XATTR_NTFS_DOS_NAME)
3188 ni = ntfs_check_access_xattr(req, &security,
3189 ino, attr, TRUE);
3190 else
3191 ni = ntfs_inode_open(ctx->vol, INODE(ino));
3192 if (ni) {
3193 /*
3194 * user mapping is not mandatory
3195 * if defined, only owner is allowed
3196 */
3197 if (!ntfs_fuse_fill_security_context(req, &security)
3198 || ntfs_allowed_as_owner(&security, ni)) {
3199 res = ntfs_system_setxattr(&security,
3200 attr, ni, value, size, flags);
3201 if (res)
3202 res = -errno;
3203 } else
3204 res = -errno;
3205 if ((attr != XATTR_NTFS_DOS_NAME)
3206 && ntfs_inode_close(ni))
3207 set_fuse_error(&res);
3208 } else
3209 res = -errno;
3210#endif
3211 if (res < 0)
3212 fuse_reply_err(req, -res);
3213 else
3214 fuse_reply_err(req, 0);
3215 return;
3216 }
3217 if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR)
3218 && (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR)) {
3219 res = -EOPNOTSUPP;
3220 goto out;
3221 }
3222 namespace = xattr_namespace(name);
3223 if (namespace == XATTRNS_NONE) {
3224 res = -EOPNOTSUPP;
3225 goto out;
3226 }
3227#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
3228 ntfs_fuse_fill_security_context(req,&security);
3229 /* security and trusted only settable by root */
3230 if (((namespace == XATTRNS_SECURITY)
3231 || (namespace == XATTRNS_TRUSTED))
3232 && security.uid) {
3233 res = -EPERM;
3234 goto out;
3235 }
3236#endif
3237 ni = ntfs_inode_open(ctx->vol, INODE(ino));
3238 if (!ni) {
3239 res = -errno;
3240 goto out;
3241 }
3242#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
3243 switch (namespace) {
3244 case XATTRNS_SECURITY :
3245 case XATTRNS_TRUSTED :
3246 if (security.uid) {
3247 res = -EPERM;
3248 goto exit;
3249 }
3250 break;
3251 case XATTRNS_SYSTEM :
3252 if (!ntfs_allowed_as_owner(&security, ni)) {
3253 res = -EACCES;
3254 goto exit;
3255 }
3256 break;
3257 default :
3258 if (!ntfs_allowed_access(&security,ni,S_IWRITE)) {
3259 res = -EACCES;
3260 goto exit;
3261 }
3262 break;
3263 }
3264#endif
3265 lename_len = fix_xattr_prefix(name, namespace, &lename);
3266 if (lename_len == -1) {
3267 res = -errno;
3268 goto exit;
3269 }
3270 na = ntfs_attr_open(ni, AT_DATA, lename, lename_len);
3271 if (na && flags == XATTR_CREATE) {
3272 res = -EEXIST;
3273 goto exit;
3274 }
3275 if (!na) {
3276 if (flags == XATTR_REPLACE) {
3277 res = -ENODATA;
3278 goto exit;
3279 }
3280 if (ntfs_attr_add(ni, AT_DATA, lename, lename_len, NULL, 0)) {
3281 res = -errno;
3282 goto exit;
3283 }
3284 if (!(ni->flags & FILE_ATTR_ARCHIVE)) {
3285 set_archive(ni);
3286 NInoFileNameSetDirty(ni);
3287 }
3288 na = ntfs_attr_open(ni, AT_DATA, lename, lename_len);
3289 if (!na) {
3290 res = -errno;
3291 goto exit;
3292 }
3293 } else {
3294 /* currently compressed streams can only be wiped out */
3295 if (ntfs_attr_truncate(na, (s64)0 /* size */)) {
3296 res = -errno;
3297 goto exit;
3298 }
3299 }
3300 total = 0;
3301 if (size) {
3302 do {
3303 part = ntfs_attr_pwrite(na, total, size - total,
3304 &value[total]);
3305 if (part > 0)
3306 total += part;
3307 } while ((part > 0) && (total < size));
3308 if (total != size)
3309 res = -errno;
3310 else
3311 if (!(res = ntfs_attr_pclose(na)))
3312 if (ctx->efs_raw
3313 && (ni->flags & FILE_ATTR_ENCRYPTED))
3314 res = ntfs_efs_fixup_attribute(NULL,
3315 na);
3316 if (total && !(ni->flags & FILE_ATTR_ARCHIVE)) {
3317 set_archive(ni);
3318 NInoFileNameSetDirty(ni);
3319 }
3320 } else
3321 res = 0;
3322exit:
3323 if (na)
3324 ntfs_attr_close(na);
3325 free(lename);
3326 if (ntfs_inode_close(ni))
3327 set_fuse_error(&res);
3328out :
3329 if (res < 0)
3330 fuse_reply_err(req, -res);
3331 else
3332 fuse_reply_err(req, 0);
3333}
3334
3335static __inline__ int ntfs_system_removexattr(fuse_req_t req, fuse_ino_t ino,
3336 int attr)
3337{
3338 int res;
3339 ntfs_inode *dir_ni;
3340 ntfs_inode *ni;
3341 struct SECURITY_CONTEXT security;
3342
3343 res = 0;
3344 switch (attr) {
3345 /*
3346 * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
3347 * is never allowed
3348 */
3349 case XATTR_NTFS_ACL :
3350 case XATTR_NTFS_ATTRIB :
3351 case XATTR_NTFS_EFSINFO :
3352 case XATTR_NTFS_TIMES :
3353 res = -EPERM;
3354 break;
3355#if POSIXACLS
3356 case XATTR_POSIX_ACC :
3357 case XATTR_POSIX_DEF :
3358 ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE);
3359 if (ni) {
3360 if (!ntfs_allowed_as_owner(&security, ni)
3361 || ntfs_remove_posix_acl(&security, ni,
3362 (attr == XATTR_POSIX_ACC ?
3363 nf_ns_xattr_posix_access :
3364 nf_ns_xattr_posix_default)))
3365 res = -errno;
3366 if (ntfs_inode_close(ni))
3367 set_fuse_error(&res);
3368 } else
3369 res = -errno;
3370 break;
3371#endif
3372 case XATTR_NTFS_REPARSE_DATA :
3373 ni = ntfs_check_access_xattr(req, &security, ino, attr, TRUE);
3374 if (ni) {
3375 if (!ntfs_allowed_as_owner(&security, ni)
3376 || ntfs_remove_ntfs_reparse_data(ni))
3377 res = -errno;
3378 if (ntfs_inode_close(ni))
3379 set_fuse_error(&res);
3380 } else
3381 res = -errno;
3382 break;
3383 case XATTR_NTFS_OBJECT_ID :
3384 ni = ntfs_check_access_xattr(req, &security, ino, attr, TRUE);
3385 if (ni) {
3386 if (!ntfs_allowed_as_owner(&security, ni)
3387 || ntfs_remove_ntfs_object_id(ni))
3388 res = -errno;
3389 if (ntfs_inode_close(ni))
3390 set_fuse_error(&res);
3391 } else
3392 res = -errno;
3393 break;
3394 case XATTR_NTFS_DOS_NAME:
3395 ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE);
3396 if (ni) {
3397 dir_ni = ntfs_dir_parent_inode(ni);
3398 if (!dir_ni
3399 || ntfs_remove_ntfs_dos_name(ni,dir_ni))
3400 res = -errno;
3401 } else
3402 res = -errno;
3403 break;
3404 default :
3405 errno = EOPNOTSUPP;
3406 res = -errno;
3407 break;
3408 }
3409 return (res);
3410}
3411
3412static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
3413{
3414 ntfs_inode *ni;
3415 ntfschar *lename = NULL;
3416 int res = 0, lename_len;
3417 int attr;
3418 int namespace;
3419#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
3420 struct SECURITY_CONTEXT security;
3421#endif
3422
3423 attr = mapped_xattr_system(name);
3424 if (attr != XATTR_UNMAPPED) {
3425 /*
3426 * hijack internal data and ACL removal, whatever
3427 * mode was selected for xattr (from the user's
3428 * point of view, ACLs are not xattr)
3429 * Note : updating an ACL does not set ctime
3430 */
3431 res = ntfs_system_removexattr(req, ino, attr);
3432 if (res < 0)
3433 fuse_reply_err(req, -res);
3434 else
3435 fuse_reply_err(req, 0);
3436 return;
3437 }
3438 if ((ctx->streams != NF_STREAMS_INTERFACE_XATTR)
3439 && (ctx->streams != NF_STREAMS_INTERFACE_OPENXATTR)) {
3440 res = -EOPNOTSUPP;
3441 goto out;
3442 }
3443 namespace = xattr_namespace(name);
3444 if (namespace == XATTRNS_NONE) {
3445 res = -EOPNOTSUPP;
3446 goto out;
3447 }
3448#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
3449 ntfs_fuse_fill_security_context(req,&security);
3450 /* security and trusted only settable by root */
3451 if (((namespace == XATTRNS_SECURITY)
3452 || (namespace == XATTRNS_TRUSTED))
3453 && security.uid) {
3454 res = -EACCES;
3455 goto out;
3456 }
3457#endif
3458 ni = ntfs_inode_open(ctx->vol, INODE(ino));
3459 if (!ni) {
3460 res = -errno;
3461 goto out;
3462 }
3463#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
3464 switch (namespace) {
3465 case XATTRNS_SECURITY :
3466 case XATTRNS_TRUSTED :
3467 if (security.uid) {
3468 res = -EPERM;
3469 goto exit;
3470 }
3471 break;
3472 case XATTRNS_SYSTEM :
3473 if (!ntfs_allowed_as_owner(&security, ni)) {
3474 res = -EACCES;
3475 goto exit;
3476 }
3477 break;
3478 default :
3479 if (!ntfs_allowed_access(&security,ni,S_IWRITE)) {
3480 res = -EACCES;
3481 goto exit;
3482 }
3483 break;
3484 }
3485#endif
3486 lename_len = fix_xattr_prefix(name, namespace, &lename);
3487 if (lename_len == -1) {
3488 res = -errno;
3489 goto exit;
3490 }
3491 if (ntfs_attr_remove(ni, AT_DATA, lename, lename_len)) {
3492 if (errno == ENOENT)
3493 errno = ENODATA;
3494 res = -errno;
3495 }
3496 if (!(ni->flags & FILE_ATTR_ARCHIVE)) {
3497 set_archive(ni);
3498 NInoFileNameSetDirty(ni);
3499 }
3500exit:
3501 free(lename);
3502 if (ntfs_inode_close(ni))
3503 set_fuse_error(&res);
3504out :
3505 if (res < 0)
3506 fuse_reply_err(req, -res);
3507 else
3508 fuse_reply_err(req, 0);
3509 return;
3510
3511}
3512
3513#else
3514#if POSIXACLS
3515#error "Option inconsistency : POSIXACLS requires SETXATTR"
3516#endif
3517#endif /* HAVE_SETXATTR */
3518
3519static void ntfs_close(void)
3520{
3521 struct SECURITY_CONTEXT security;
3522
3523 if (!ctx)
3524 return;
3525
3526 if (!ctx->vol)
3527 return;
3528
3529 if (ctx->mounted) {
3530 ntfs_log_info("Unmounting %s (%s)\n", opts.device,
3531 ctx->vol->vol_name);
3532 if (ntfs_fuse_fill_security_context((fuse_req_t)NULL, &security)) {
3533 if (ctx->seccache && ctx->seccache->head.p_reads) {
3534 ntfs_log_info("Permissions cache : %lu writes, "
3535 "%lu reads, %lu.%1lu%% hits\n",
3536 ctx->seccache->head.p_writes,
3537 ctx->seccache->head.p_reads,
3538 100 * ctx->seccache->head.p_hits
3539 / ctx->seccache->head.p_reads,
3540 1000 * ctx->seccache->head.p_hits
3541 / ctx->seccache->head.p_reads % 10);
3542 }
3543 }
3544 ntfs_close_secure(&security);
3545 }
3546
3547 if (ntfs_umount(ctx->vol, FALSE))
3548 ntfs_log_perror("Failed to close volume %s", opts.device);
3549
3550 ctx->vol = NULL;
3551}
3552
3553static void ntfs_fuse_destroy2(void *notused __attribute__((unused)))
3554{
3555 ntfs_close();
3556}
3557
3558static struct fuse_lowlevel_ops ntfs_3g_ops = {
3559 .lookup = ntfs_fuse_lookup,
3560 .getattr = ntfs_fuse_getattr,
3561 .readlink = ntfs_fuse_readlink,
3562 .opendir = ntfs_fuse_opendir,
3563 .readdir = ntfs_fuse_readdir,
3564 .releasedir = ntfs_fuse_releasedir,
3565 .open = ntfs_fuse_open,
3566 .release = ntfs_fuse_release,
3567 .read = ntfs_fuse_read,
3568 .write = ntfs_fuse_write,
3569 .setattr = ntfs_fuse_setattr,
3570 .statfs = ntfs_fuse_statfs,
3571 .create = ntfs_fuse_create_file,
3572 .mknod = ntfs_fuse_mknod,
3573 .symlink = ntfs_fuse_symlink,
3574 .link = ntfs_fuse_link,
3575 .unlink = ntfs_fuse_unlink,
3576 .rename = ntfs_fuse_rename,
3577 .mkdir = ntfs_fuse_mkdir,
3578 .rmdir = ntfs_fuse_rmdir,
3579 .bmap = ntfs_fuse_bmap,
3580 .destroy = ntfs_fuse_destroy2,
3581#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
3582 .access = ntfs_fuse_access,
3583#endif
3584#ifdef HAVE_SETXATTR
3585 .getxattr = ntfs_fuse_getxattr,
3586 .setxattr = ntfs_fuse_setxattr,
3587 .removexattr = ntfs_fuse_removexattr,
3588 .listxattr = ntfs_fuse_listxattr,
3589#endif /* HAVE_SETXATTR */
3590#if 0 && (defined(__APPLE__) || defined(__DARWIN__)) /* Unfinished. */
3591 /* MacFUSE extensions. */
3592 .getxtimes = ntfs_macfuse_getxtimes,
3593 .setcrtime = ntfs_macfuse_setcrtime,
3594 .setbkuptime = ntfs_macfuse_setbkuptime,
3595 .setchgtime = ntfs_macfuse_setchgtime,
3596#endif /* defined(__APPLE__) || defined(__DARWIN__) */
3597#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__))
3598 .init = ntfs_init
3599#endif
3600};
3601
3602static int ntfs_fuse_init(void)
3603{
3604 ctx = (ntfs_fuse_context_t*)ntfs_calloc(sizeof(ntfs_fuse_context_t));
3605 if (!ctx)
3606 return -1;
3607
3608 *ctx = (ntfs_fuse_context_t) {
3609 .uid = getuid(),
3610 .gid = getgid(),
3611#if defined(linux)
3612 .streams = NF_STREAMS_INTERFACE_XATTR,
3613#else
3614 .streams = NF_STREAMS_INTERFACE_NONE,
3615#endif
3616 .atime = ATIME_RELATIVE,
3617 .silent = TRUE,
3618 .recover = TRUE
3619 };
3620 return 0;
3621}
3622
3623static int ntfs_open(const char *device)
3624{
3625 unsigned long flags = 0;
3626
3627 if (!ctx->blkdev)
3628 flags |= MS_EXCLUSIVE;
3629 if (ctx->ro)
3630 flags |= MS_RDONLY;
3631 if (ctx->recover)
3632 flags |= MS_RECOVER;
3633 if (ctx->hiberfile)
3634 flags |= MS_IGNORE_HIBERFILE;
3635
3636 ctx->vol = ntfs_mount(device, flags);
3637 if (!ctx->vol) {
3638 ntfs_log_perror("Failed to mount '%s'", device);
3639 goto err_out;
3640 }
3641
3642 ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na);
3643 if (ctx->vol->free_clusters < 0) {
3644 ntfs_log_perror("Failed to read NTFS $Bitmap");
3645 goto err_out;
3646 }
3647
3648 ctx->vol->free_mft_records = ntfs_get_nr_free_mft_records(ctx->vol);
3649 if (ctx->vol->free_mft_records < 0) {
3650 ntfs_log_perror("Failed to calculate free MFT records");
3651 goto err_out;
3652 }
3653
3654 if (ctx->hiberfile && ntfs_volume_check_hiberfile(ctx->vol, 0)) {
3655 if (errno != EPERM)
3656 goto err_out;
3657 if (ntfs_fuse_rm((fuse_req_t)NULL,FILE_root,"hiberfil.sys"))
3658 goto err_out;
3659 }
3660
3661 errno = 0;
3662err_out:
3663 return ntfs_volume_error(errno);
3664
3665}
3666
3667#define STRAPPEND_MAX_INSIZE 8192
3668#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
3669
3670static int strappend(char **dest, const char *append)
3671{
3672 char *p;
3673 size_t size_append, size_dest = 0;
3674
3675 if (!dest)
3676 return -1;
3677 if (!append)
3678 return 0;
3679
3680 size_append = strlen(append);
3681 if (*dest)
3682 size_dest = strlen(*dest);
3683
3684 if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
3685 errno = EOVERFLOW;
3686 ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
3687 return -1;
3688 }
3689
3690 p = (char*)realloc(*dest, size_dest + size_append + 1);
3691 if (!p) {
3692 ntfs_log_perror("%s: Memory reallocation failed", EXEC_NAME);
3693 return -1;
3694 }
3695
3696 *dest = p;
3697 strcpy(*dest + size_dest, append);
3698
3699 return 0;
3700}
3701
3702static int bogus_option_value(char *val, const char *s)
3703{
3704 if (val) {
3705 ntfs_log_error("'%s' option shouldn't have value.\n", s);
3706 return -1;
3707 }
3708 return 0;
3709}
3710
3711static int missing_option_value(char *val, const char *s)
3712{
3713 if (!val) {
3714 ntfs_log_error("'%s' option should have a value.\n", s);
3715 return -1;
3716 }
3717 return 0;
3718}
3719
3720static char *parse_mount_options(const char *orig_opts)
3721{
3722 char *options, *s, *opt, *val, *ret = NULL;
3723 BOOL no_def_opts = FALSE;
3724 int default_permissions = 0;
3725 int want_permissions = 0;
3726
3727 ctx->secure_flags = 0;
3728#ifdef HAVE_SETXATTR /* extended attributes interface required */
3729 ctx->efs_raw = FALSE;
3730#endif /* HAVE_SETXATTR */
3731 options = strdup(orig_opts ? orig_opts : "");
3732 if (!options) {
3733 ntfs_log_perror("%s: strdup failed", EXEC_NAME);
3734 return NULL;
3735 }
3736
3737 s = options;
3738 while (s && *s && (val = strsep(&s, ","))) {
3739 opt = strsep(&val, "=");
3740 if (!strcmp(opt, "ro")) { /* Read-only mount. */
3741 if (bogus_option_value(val, "ro"))
3742 goto err_exit;
3743 ctx->ro = TRUE;
3744 if (strappend(&ret, "ro,"))
3745 goto err_exit;
3746 } else if (!strcmp(opt, "noatime")) {
3747 if (bogus_option_value(val, "noatime"))
3748 goto err_exit;
3749 ctx->atime = ATIME_DISABLED;
3750 } else if (!strcmp(opt, "atime")) {
3751 if (bogus_option_value(val, "atime"))
3752 goto err_exit;
3753 ctx->atime = ATIME_ENABLED;
3754 } else if (!strcmp(opt, "relatime")) {
3755 if (bogus_option_value(val, "relatime"))
3756 goto err_exit;
3757 ctx->atime = ATIME_RELATIVE;
3758 } else if (!strcmp(opt, "fake_rw")) {
3759 if (bogus_option_value(val, "fake_rw"))
3760 goto err_exit;
3761 ctx->ro = TRUE;
3762 } else if (!strcmp(opt, "fsname")) { /* Filesystem name. */
3763 /*
3764 * We need this to be able to check whether filesystem
3765 * mounted or not.
3766 */
3767 ntfs_log_error("'fsname' is unsupported option.\n");
3768 goto err_exit;
3769 } else if (!strcmp(opt, "no_def_opts")) {
3770 if (bogus_option_value(val, "no_def_opts"))
3771 goto err_exit;
3772 no_def_opts = TRUE; /* Don't add default options. */
3773 } else if (!strcmp(opt, "default_permissions")) {
3774 default_permissions = 1;
3775 } else if (!strcmp(opt, "umask")) {
3776 if (missing_option_value(val, "umask"))
3777 goto err_exit;
3778 sscanf(val, "%o", &ctx->fmask);
3779 ctx->dmask = ctx->fmask;
3780 want_permissions = 1;
3781 } else if (!strcmp(opt, "fmask")) {
3782 if (missing_option_value(val, "fmask"))
3783 goto err_exit;
3784 sscanf(val, "%o", &ctx->fmask);
3785 want_permissions = 1;
3786 } else if (!strcmp(opt, "dmask")) {
3787 if (missing_option_value(val, "dmask"))
3788 goto err_exit;
3789 sscanf(val, "%o", &ctx->dmask);
3790 want_permissions = 1;
3791 } else if (!strcmp(opt, "uid")) {
3792 if (missing_option_value(val, "uid"))
3793 goto err_exit;
3794 sscanf(val, "%i", &ctx->uid);
3795 want_permissions = 1;
3796 } else if (!strcmp(opt, "gid")) {
3797 if (missing_option_value(val, "gid"))
3798 goto err_exit;
3799 sscanf(val, "%i", &ctx->gid);
3800 want_permissions = 1;
3801 } else if (!strcmp(opt, "show_sys_files")) {
3802 if (bogus_option_value(val, "show_sys_files"))
3803 goto err_exit;
3804 ctx->show_sys_files = TRUE;
3805 } else if (!strcmp(opt, "silent")) {
3806 if (bogus_option_value(val, "silent"))
3807 goto err_exit;
3808 ctx->silent = TRUE;
3809 } else if (!strcmp(opt, "recover")) {
3810 if (bogus_option_value(val, "recover"))
3811 goto err_exit;
3812 ctx->recover = TRUE;
3813 } else if (!strcmp(opt, "norecover")) {
3814 if (bogus_option_value(val, "norecover"))
3815 goto err_exit;
3816 ctx->recover = FALSE;
3817 } else if (!strcmp(opt, "remove_hiberfile")) {
3818 if (bogus_option_value(val, "remove_hiberfile"))
3819 goto err_exit;
3820 ctx->hiberfile = TRUE;
3821 } else if (!strcmp(opt, "locale")) {
3822 if (missing_option_value(val, "locale"))
3823 goto err_exit;
3824 ntfs_set_char_encoding(val);
3825#if defined(__APPLE__) || defined(__DARWIN__)
3826#ifdef ENABLE_NFCONV
3827 } else if (!strcmp(opt, "nfconv")) {
3828 if (bogus_option_value(val, "nfconv"))
3829 goto err_exit;
3830 if (ntfs_macosx_normalize_filenames(1)) {
3831 ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n");
3832 goto err_exit;
3833 }
3834 } else if (!strcmp(opt, "nonfconv")) {
3835 if (bogus_option_value(val, "nonfconv"))
3836 goto err_exit;
3837 if (ntfs_macosx_normalize_filenames(0)) {
3838 ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n");
3839 goto err_exit;
3840 }
3841#endif /* ENABLE_NFCONV */
3842#endif /* defined(__APPLE__) || defined(__DARWIN__) */
3843 } else if (!strcmp(opt, "streams_interface")) {
3844 if (missing_option_value(val, "streams_interface"))
3845 goto err_exit;
3846 if (!strcmp(val, "none"))
3847 ctx->streams = NF_STREAMS_INTERFACE_NONE;
3848 else if (!strcmp(val, "xattr"))
3849 ctx->streams = NF_STREAMS_INTERFACE_XATTR;
3850 else if (!strcmp(val, "openxattr"))
3851 ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR;
3852 else {
3853 ntfs_log_error("Invalid named data streams "
3854 "access interface.\n");
3855 goto err_exit;
3856 }
3857 } else if (!strcmp(opt, "user_xattr")) {
3858 ctx->streams = NF_STREAMS_INTERFACE_XATTR;
3859 } else if (!strcmp(opt, "noauto")) {
3860 /* Don't pass noauto option to fuse. */
3861 } else if (!strcmp(opt, "debug")) {
3862 if (bogus_option_value(val, "debug"))
3863 goto err_exit;
3864 ctx->debug = TRUE;
3865 ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
3866 ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
3867 } else if (!strcmp(opt, "no_detach")) {
3868 if (bogus_option_value(val, "no_detach"))
3869 goto err_exit;
3870 ctx->no_detach = TRUE;
3871 } else if (!strcmp(opt, "remount")) {
3872 ntfs_log_error("Remounting is not supported at present."
3873 " You have to umount volume and then "
3874 "mount it once again.\n");
3875 goto err_exit;
3876 } else if (!strcmp(opt, "blksize")) {
3877 ntfs_log_info("WARNING: blksize option is ignored "
3878 "because ntfs-3g must calculate it.\n");
3879 } else if (!strcmp(opt, "inherit")) {
3880 /*
3881 * JPA do not overwrite inherited permissions
3882 * in create()
3883 */
3884 ctx->inherit = TRUE;
3885 } else if (!strcmp(opt, "addsecurids")) {
3886 /*
3887 * JPA create security ids for files being read
3888 * with an individual security attribute
3889 */
3890 ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS);
3891 } else if (!strcmp(opt, "staticgrps")) {
3892 /*
3893 * JPA use static definition of groups
3894 * for file access control
3895 */
3896 ctx->secure_flags |= (1 << SECURITY_STATICGRPS);
3897 } else if (!strcmp(opt, "usermapping")) {
3898 if (!val) {
3899 ntfs_log_error("'usermapping' option should have "
3900 "a value.\n");
3901 goto err_exit;
3902 }
3903 ctx->usermap_path = strdup(val);
3904 if (!ctx->usermap_path) {
3905 ntfs_log_error("no more memory to store "
3906 "'usermapping' option.\n");
3907 goto err_exit;
3908 }
3909#ifdef HAVE_SETXATTR /* extended attributes interface required */
3910 } else if (!strcmp(opt, "efs_raw")) {
3911 if (bogus_option_value(val, "efs_raw"))
3912 goto err_exit;
3913 ctx->efs_raw = TRUE;
3914#endif /* HAVE_SETXATTR */
3915 } else { /* Probably FUSE option. */
3916 if (strappend(&ret, opt))
3917 goto err_exit;
3918 if (val) {
3919 if (strappend(&ret, "="))
3920 goto err_exit;
3921 if (strappend(&ret, val))
3922 goto err_exit;
3923 }
3924 if (strappend(&ret, ","))
3925 goto err_exit;
3926 }
3927 }
3928 if (!no_def_opts && strappend(&ret, def_opts))
3929 goto err_exit;
3930#if KERNELPERMS
3931 if (default_permissions && strappend(&ret, "default_permissions,"))
3932 goto err_exit;
3933#endif
3934
3935 if (ctx->atime == ATIME_RELATIVE && strappend(&ret, "relatime,"))
3936 goto err_exit;
3937 else if (ctx->atime == ATIME_ENABLED && strappend(&ret, "atime,"))
3938 goto err_exit;
3939 else if (ctx->atime == ATIME_DISABLED && strappend(&ret, "noatime,"))
3940 goto err_exit;
3941
3942 if (strappend(&ret, "fsname="))
3943 goto err_exit;
3944 if (strappend(&ret, opts.device))
3945 goto err_exit;
3946 if (default_permissions)
3947 ctx->secure_flags |= (1 << SECURITY_DEFAULT);
3948 if (want_permissions)
3949 ctx->secure_flags |= (1 << SECURITY_WANTED);
3950 if (ctx->ro)
3951 ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS);
3952exit:
3953 free(options);
3954 return ret;
3955err_exit:
3956 free(ret);
3957 ret = NULL;
3958 goto exit;
3959}
3960
3961static void usage(void)
3962{
3963 ntfs_log_info(usage_msg, EXEC_NAME, VERSION, FUSE_TYPE, fuse_version(),
3964 5 + POSIXACLS*6 - KERNELPERMS*3 + CACHEING,
3965 EXEC_NAME, ntfs_home);
3966}
3967
3968#ifndef HAVE_REALPATH
3969/* If there is no realpath() on the system, provide a dummy one. */
3970static char *realpath(const char *path, char *resolved_path)
3971{
3972 strncpy(resolved_path, path, PATH_MAX);
3973 resolved_path[PATH_MAX] = '\0';
3974 return resolved_path;
3975}
3976#endif
3977
3978/**
3979 * parse_options - Read and validate the programs command line
3980 * Read the command line, verify the syntax and parse the options.
3981 *
3982 * Return: 0 success, -1 error.
3983 */
3984static int parse_options(int argc, char *argv[])
3985{
3986 int c;
3987
3988 static const char *sopt = "-o:hvV";
3989 static const struct option lopt[] = {
3990 { "options", required_argument, NULL, 'o' },
3991 { "help", no_argument, NULL, 'h' },
3992 { "verbose", no_argument, NULL, 'v' },
3993 { "version", no_argument, NULL, 'V' },
3994 { NULL, 0, NULL, 0 }
3995 };
3996
3997 opterr = 0; /* We'll handle the errors, thank you. */
3998
3999 while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
4000 switch (c) {
4001 case 1: /* A non-option argument */
4002 if (!opts.device) {
4003 opts.device = (char*)ntfs_malloc(PATH_MAX + 1);
4004 if (!opts.device)
4005 return -1;
4006
4007 /* Canonicalize device name (mtab, etc) */
4008 if (!realpath(optarg, opts.device)) {
4009 ntfs_log_perror("%s: Failed to access "
4010 "volume '%s'", EXEC_NAME, optarg);
4011 free(opts.device);
4012 opts.device = NULL;
4013 return -1;
4014 }
4015 } else if (!opts.mnt_point) {
4016 opts.mnt_point = optarg;
4017 } else {
4018 ntfs_log_error("%s: You must specify exactly one "
4019 "device and exactly one mount "
4020 "point.\n", EXEC_NAME);
4021 return -1;
4022 }
4023 break;
4024 case 'o':
4025 if (opts.options)
4026 if (strappend(&opts.options, ","))
4027 return -1;
4028 if (strappend(&opts.options, optarg))
4029 return -1;
4030 break;
4031 case 'h':
4032 usage();
4033 exit(9);
4034 case 'v':
4035 /*
4036 * We must handle the 'verbose' option even if
4037 * we don't use it because mount(8) passes it.
4038 */
4039 break;
4040 case 'V':
4041 ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION,
4042 FUSE_TYPE, fuse_version());
4043 exit(0);
4044 default:
4045 ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
4046 argv[optind - 1]);
4047 return -1;
4048 }
4049 }
4050
4051 if (!opts.device) {
4052 ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
4053 return -1;
4054 }
4055 if (!opts.mnt_point) {
4056 ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
4057 return -1;
4058 }
4059
4060 return 0;
4061}
4062
4063#if defined(linux) || defined(__uClinux__)
4064
4065static const char *dev_fuse_msg =
4066"HINT: You should be root, or make ntfs-3g setuid root, or load the FUSE\n"
4067" kernel module as root ('modprobe fuse' or 'insmod <path_to>/fuse.ko'"
4068" or insmod <path_to>/fuse.o'). Make also sure that the fuse device"
4069" exists. It's usually either /dev/fuse or /dev/misc/fuse.";
4070
4071static const char *fuse26_kmod_msg =
4072"WARNING: Deficient Linux kernel detected. Some driver features are\n"
4073" not available (swap file on NTFS, boot from NTFS by LILO), and\n"
4074" unmount is not safe unless it's made sure the ntfs-3g process\n"
4075" naturally terminates after calling 'umount'. If you wish this\n"
4076" message to disappear then you should upgrade to at least kernel\n"
4077" version 2.6.20, or request help from your distribution to fix\n"
4078" the kernel problem. The below web page has more information:\n"
4079" http://ntfs-3g.org/support.html#fuse26\n"
4080"\n";
4081
4082static void mknod_dev_fuse(const char *dev)
4083{
4084 struct stat st;
4085
4086 if (stat(dev, &st) && (errno == ENOENT)) {
4087 mode_t mask = umask(0);
4088 if (mknod(dev, S_IFCHR | 0666, makedev(10, 229))) {
4089 ntfs_log_perror("Failed to create '%s'", dev);
4090 if (errno == EPERM)
4091 ntfs_log_error("%s", dev_fuse_msg);
4092 }
4093 umask(mask);
4094 }
4095}
4096
4097static void create_dev_fuse(void)
4098{
4099 mknod_dev_fuse("/dev/fuse");
4100
4101#ifdef __UCLIBC__
4102 {
4103 struct stat st;
4104 /* The fuse device is under /dev/misc using devfs. */
4105 if (stat("/dev/misc", &st) && (errno == ENOENT)) {
4106 mode_t mask = umask(0);
4107 mkdir("/dev/misc", 0775);
4108 umask(mask);
4109 }
4110 mknod_dev_fuse("/dev/misc/fuse");
4111 }
4112#endif
4113}
4114
4115static fuse_fstype get_fuse_fstype(void)
4116{
4117 char buf[256];
4118 fuse_fstype fstype = FSTYPE_NONE;
4119
4120 FILE *f = fopen("/proc/filesystems", "r");
4121 if (!f) {
4122 ntfs_log_perror("Failed to open /proc/filesystems");
4123 return FSTYPE_UNKNOWN;
4124 }
4125
4126 while (fgets(buf, sizeof(buf), f)) {
4127 if (strstr(buf, "fuseblk\n")) {
4128 fstype = FSTYPE_FUSEBLK;
4129 break;
4130 }
4131 if (strstr(buf, "fuse\n"))
4132 fstype = FSTYPE_FUSE;
4133 }
4134
4135 fclose(f);
4136 return fstype;
4137}
4138
4139static fuse_fstype load_fuse_module(void)
4140{
4141 int i;
4142 struct stat st;
4143 pid_t pid;
4144 const char *cmd = "/sbin/modprobe";
4145 struct timespec req = { 0, 100000000 }; /* 100 msec */
4146 fuse_fstype fstype;
4147
4148 if (!stat(cmd, &st) && !geteuid()) {
4149 pid = fork();
4150 if (!pid) {
4151 execl(cmd, cmd, "fuse", NULL);
4152 _exit(1);
4153 } else if (pid != -1)
4154 waitpid(pid, NULL, 0);
4155 }
4156
4157 for (i = 0; i < 10; i++) {
4158 /*
4159 * We sleep first because despite the detection of the loaded
4160 * FUSE kernel module, fuse_mount() can still fail if it's not
4161 * fully functional/initialized. Note, of course this is still
4162 * unreliable but usually helps.
4163 */
4164 nanosleep(&req, NULL);
4165 fstype = get_fuse_fstype();
4166 if (fstype != FSTYPE_NONE)
4167 break;
4168 }
4169 return fstype;
4170}
4171
4172#endif
4173
4174static struct fuse_chan *try_fuse_mount(char *parsed_options)
4175{
4176 struct fuse_chan *fc = NULL;
4177 struct fuse_args margs = FUSE_ARGS_INIT(0, NULL);
4178
4179 /* The fuse_mount() options get modified, so we always rebuild it */
4180 if ((fuse_opt_add_arg(&margs, EXEC_NAME) == -1 ||
4181 fuse_opt_add_arg(&margs, "-o") == -1 ||
4182 fuse_opt_add_arg(&margs, parsed_options) == -1)) {
4183 ntfs_log_error("Failed to set FUSE options.\n");
4184 goto free_args;
4185 }
4186
4187 fc = fuse_mount(opts.mnt_point, &margs);
4188free_args:
4189 fuse_opt_free_args(&margs);
4190 return fc;
4191
4192}
4193
4194static int set_fuseblk_options(char **parsed_options)
4195{
4196 char options[64];
4197 long pagesize;
4198 u32 blksize = ctx->vol->cluster_size;
4199
4200 pagesize = sysconf(_SC_PAGESIZE);
4201 if (pagesize < 1)
4202 pagesize = 4096;
4203
4204 if (blksize > (u32)pagesize)
4205 blksize = pagesize;
4206
4207 snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize);
4208 if (strappend(parsed_options, options))
4209 return -1;
4210 return 0;
4211}
4212
4213static struct fuse_session *mount_fuse(char *parsed_options)
4214{
4215 struct fuse_session *se = NULL;
4216 struct fuse_args args = FUSE_ARGS_INIT(0, NULL);
4217
4218 ctx->fc = try_fuse_mount(parsed_options);
4219 if (!ctx->fc)
4220 return NULL;
4221
4222 if (fuse_opt_add_arg(&args, "") == -1)
4223 goto err;
4224 if (ctx->debug)
4225 if (fuse_opt_add_arg(&args, "-odebug") == -1)
4226 goto err;
4227
4228 se = fuse_lowlevel_new(&args , &ntfs_3g_ops, sizeof(ntfs_3g_ops), NULL);
4229 if (!se)
4230 goto err;
4231
4232
4233 if (fuse_set_signal_handlers(se))
4234 goto err_destroy;
4235 fuse_session_add_chan(se, ctx->fc);
4236out:
4237 fuse_opt_free_args(&args);
4238 return se;
4239err_destroy:
4240 fuse_session_destroy(se);
4241 se = NULL;
4242err:
4243 fuse_unmount(opts.mnt_point, ctx->fc);
4244 goto out;
4245}
4246
4247static void setup_logging(char *parsed_options)
4248{
4249 if (!ctx->no_detach) {
4250 if (daemon(0, ctx->debug))
4251 ntfs_log_error("Failed to daemonize.\n");
4252 else if (!ctx->debug) {
4253#ifndef DEBUG
4254 ntfs_log_set_handler(ntfs_log_handler_syslog);
4255 /* Override default libntfs identify. */
4256 openlog(EXEC_NAME, LOG_PID, LOG_DAEMON);
4257#endif
4258 }
4259 }
4260
4261 ctx->seccache = (struct PERMISSIONS_CACHE*)NULL;
4262
4263 ntfs_log_info("Version %s %s %d\n", VERSION, FUSE_TYPE, fuse_version());
4264 ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS %d.%d)\n",
4265 opts.device, (ctx->ro) ? "Read-Only" : "Read-Write",
4266 ctx->vol->vol_name, ctx->vol->major_ver,
4267 ctx->vol->minor_ver);
4268 ntfs_log_info("Cmdline options: %s\n", opts.options ? opts.options : "");
4269 ntfs_log_info("Mount options: %s\n", parsed_options);
4270}
4271
4272int main(int argc, char *argv[])
4273{
4274 char *parsed_options = NULL;
4275 struct fuse_session *se;
4276#if !(defined(__sun) && defined (__SVR4))
4277 fuse_fstype fstype = FSTYPE_UNKNOWN;
4278#endif
4279 const char *permissions_mode = (const char*)NULL;
4280 const char *failed_secure = (const char*)NULL;
4281 struct stat sbuf;
4282 int err, fd;
4283
4284 /*
4285 * Make sure file descriptors 0, 1 and 2 are open,
4286 * otherwise chaos would ensue.
4287 */
4288 do {
4289 fd = open("/dev/null", O_RDWR);
4290 if (fd > 2)
4291 close(fd);
4292 } while (fd >= 0 && fd <= 2);
4293
4294#ifndef FUSE_INTERNAL
4295 if ((getuid() != geteuid()) || (getgid() != getegid())) {
4296 fprintf(stderr, "%s", setuid_msg);
4297 return NTFS_VOLUME_INSECURE;
4298 }
4299#endif
4300 if (drop_privs())
4301 return NTFS_VOLUME_NO_PRIVILEGE;
4302
4303 ntfs_set_locale();
4304 ntfs_log_set_handler(ntfs_log_handler_stderr);
4305
4306 if (parse_options(argc, argv)) {
4307 usage();
4308 return NTFS_VOLUME_SYNTAX_ERROR;
4309 }
4310
4311 if (ntfs_fuse_init()) {
4312 err = NTFS_VOLUME_OUT_OF_MEMORY;
4313 goto err2;
4314 }
4315
4316 parsed_options = parse_mount_options(opts.options);
4317 if (!parsed_options) {
4318 err = NTFS_VOLUME_SYNTAX_ERROR;
4319 goto err_out;
4320 }
4321
4322 /* need absolute mount point for junctions */
4323 if (opts.mnt_point[0] == '/')
4324 ctx->abs_mnt_point = strdup(opts.mnt_point);
4325 else {
4326 ctx->abs_mnt_point = (char*)ntfs_malloc(PATH_MAX);
4327 if (ctx->abs_mnt_point) {
4328 if (getcwd(ctx->abs_mnt_point,
4329 PATH_MAX - strlen(opts.mnt_point) - 1)) {
4330 strcat(ctx->abs_mnt_point, "/");
4331 strcat(ctx->abs_mnt_point, opts.mnt_point);
4332 }
4333 }
4334 }
4335 if (!ctx->abs_mnt_point) {
4336 err = NTFS_VOLUME_OUT_OF_MEMORY;
4337 goto err_out;
4338 }
4339
4340 ctx->security.uid = 0;
4341 ctx->security.gid = 0;
4342 if ((opts.mnt_point[0] == '/')
4343 && !stat(opts.mnt_point,&sbuf)) {
4344 /* collect owner of mount point, useful for default mapping */
4345 ctx->security.uid = sbuf.st_uid;
4346 ctx->security.gid = sbuf.st_gid;
4347 }
4348
4349#if defined(linux) || defined(__uClinux__)
4350 fstype = get_fuse_fstype();
4351
4352 err = NTFS_VOLUME_NO_PRIVILEGE;
4353 if (restore_privs())
4354 goto err_out;
4355
4356 if (fstype == FSTYPE_NONE || fstype == FSTYPE_UNKNOWN)
4357 fstype = load_fuse_module();
4358 create_dev_fuse();
4359
4360 if (drop_privs())
4361 goto err_out;
4362#endif
4363 if (stat(opts.device, &sbuf)) {
4364 ntfs_log_perror("Failed to access '%s'", opts.device);
4365 err = NTFS_VOLUME_NO_PRIVILEGE;
4366 goto err_out;
4367 }
4368
4369#if !(defined(__sun) && defined (__SVR4))
4370 /* Always use fuseblk for block devices unless it's surely missing. */
4371 if (S_ISBLK(sbuf.st_mode) && (fstype != FSTYPE_FUSE))
4372 ctx->blkdev = TRUE;
4373#endif
4374
4375#ifndef FUSE_INTERNAL
4376 if (getuid() && ctx->blkdev) {
4377 ntfs_log_error("%s", unpriv_fuseblk_msg);
4378 err = NTFS_VOLUME_NO_PRIVILEGE;
4379 goto err2;
4380 }
4381#endif
4382 err = ntfs_open(opts.device);
4383 if (err)
4384 goto err_out;
4385
4386 /* We must do this after ntfs_open() to be able to set the blksize */
4387 if (ctx->blkdev && set_fuseblk_options(&parsed_options))
4388 goto err_out;
4389
4390 ctx->security.vol = ctx->vol;
4391 ctx->vol->secure_flags = ctx->secure_flags;
4392#ifdef HAVE_SETXATTR /* extended attributes interface required */
4393 ctx->vol->efs_raw = ctx->efs_raw;
4394#endif /* HAVE_SETXATTR */
4395 /* JPA open $Secure, (whatever NTFS version !) */
4396 /* to initialize security data */
4397 if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3))
4398 failed_secure = "Could not open file $Secure";
4399 if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path)) {
4400#if POSIXACLS
4401 if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))
4402 permissions_mode = "User mapping built, Posix ACLs not used";
4403 else {
4404 permissions_mode = "User mapping built, Posix ACLs in use";
4405#if KERNELACLS
4406 if (strappend(&parsed_options,
4407 ",default_permissions,acl")) {
4408 err = NTFS_VOLUME_SYNTAX_ERROR;
4409 goto err_out;
4410 }
4411#endif /* KERNELACLS */
4412 }
4413#else /* POSIXACLS */
4414 if (!(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) {
4415 /*
4416 * No explicit option but user mapping found
4417 * force default security
4418 */
4419#if KERNELPERMS
4420 ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
4421 if (strappend(&parsed_options, ",default_permissions")) {
4422 err = NTFS_VOLUME_SYNTAX_ERROR;
4423 goto err_out;
4424 }
4425#endif /* KERNELPERMS */
4426 }
4427 permissions_mode = "User mapping built";
4428#endif /* POSIXACLS */
4429 } else {
4430 ctx->security.uid = ctx->uid;
4431 ctx->security.gid = ctx->gid;
4432 /* same ownership/permissions for all files */
4433 ctx->security.mapping[MAPUSERS] = (struct MAPPING*)NULL;
4434 ctx->security.mapping[MAPGROUPS] = (struct MAPPING*)NULL;
4435 if ((ctx->vol->secure_flags & (1 << SECURITY_WANTED))
4436 && !(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) {
4437 ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
4438 if (strappend(&parsed_options, ",default_permissions")) {
4439 err = NTFS_VOLUME_SYNTAX_ERROR;
4440 goto err_out;
4441 }
4442 }
4443 if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT)) {
4444 ctx->vol->secure_flags |= (1 << SECURITY_RAW);
4445 permissions_mode = "Global ownership and permissions enforced";
4446 } else {
4447 ctx->vol->secure_flags &= ~(1 << SECURITY_RAW);
4448 permissions_mode = "Ownership and permissions disabled";
4449 }
4450 }
4451 if (ctx->usermap_path)
4452 free (ctx->usermap_path);
4453
4454 se = mount_fuse(parsed_options);
4455 if (!se) {
4456 err = NTFS_VOLUME_FUSE_ERROR;
4457 goto err_out;
4458 }
4459
4460 ctx->mounted = TRUE;
4461
4462#if defined(linux) || defined(__uClinux__)
4463 if (S_ISBLK(sbuf.st_mode) && (fstype == FSTYPE_FUSE))
4464 ntfs_log_info("%s", fuse26_kmod_msg);
4465#endif
4466 setup_logging(parsed_options);
4467 if (failed_secure)
4468 ntfs_log_info("%s\n",failed_secure);
4469 if (permissions_mode)
4470 ntfs_log_info("%s, configuration type %d\n",permissions_mode,
4471 5 + POSIXACLS*6 - KERNELPERMS*3 + CACHEING);
4472
4473 fuse_session_loop(se);
4474 fuse_remove_signal_handlers(se);
4475
4476 err = 0;
4477
4478 fuse_unmount(opts.mnt_point, ctx->fc);
4479 fuse_session_destroy(se);
4480err_out:
4481 ntfs_mount_error(opts.device, opts.mnt_point, err);
4482 if (ctx->abs_mnt_point)
4483 free(ctx->abs_mnt_point);
4484err2:
4485 ntfs_close();
4486 free(ctx);
4487 free(parsed_options);
4488 free(opts.options);
4489 free(opts.device);
4490 return err;
4491}
4492
4493