summaryrefslogtreecommitdiff
Diffstat
-rwxr-xr-xAndroid.mk138
-rwxr-xr-xAndroid.mk.bak89
-rwxr-xr-xCREDITS20
-rwxr-xr-xINSTALL200
-rwxr-xr-xMakefile715
-rwxr-xr-xMakefile.am106
-rwxr-xr-xMakefile.in955
-rwxr-xr-xNEWS4
-rwxr-xr-xREADME80
-rwxr-xr-xTODO.ntfsprogs126
-rwxr-xr-xaclocal.m47091
-rwxr-xr-xcompile21
-rwxr-xr-xconfig.guess292
-rw-r--r--[-rwxr-xr-x]config.h165
-rwxr-xr-xconfig.h.in110
-rwxr-xr-xconfig.log3290
-rwxr-xr-xconfig.status1220
-rwxr-xr-xconfig.sub104
-rwxr-xr-xconfigure26448
-rwxr-xr-xconfigure.ac291
-rwxr-xr-xdepcomp87
-rwxr-xr-xinclude/Makefile.in181
-rwxr-xr-xinclude/fuse-lite/Makefile.in112
-rwxr-xr-xinclude/fuse-lite/fuse.h61
-rwxr-xr-xinclude/fuse-lite/fuse_common.h49
-rwxr-xr-xinclude/fuse-lite/fuse_kernel.h6
-rwxr-xr-xinclude/fuse-lite/fuse_lowlevel.h20
-rwxr-xr-xinclude/ntfs-3g/Makefile.am4
-rwxr-xr-xinclude/ntfs-3g/Makefile.in163
-rwxr-xr-xinclude/ntfs-3g/acls.h3
-rwxr-xr-xinclude/ntfs-3g/attrib.h50
-rwxr-xr-xinclude/ntfs-3g/cache.h7
-rwxr-xr-xinclude/ntfs-3g/compat.h6
-rwxr-xr-xinclude/ntfs-3g/compress.h6
-rwxr-xr-xinclude/ntfs-3g/debug.h4
-rwxr-xr-xinclude/ntfs-3g/device.h18
-rwxr-xr-xinclude/ntfs-3g/device_io.h21
-rwxr-xr-xinclude/ntfs-3g/dir.h11
-rwxr-xr-xinclude/ntfs-3g/layout.h32
-rwxr-xr-xinclude/ntfs-3g/lcnalloc.h1
-rwxr-xr-xinclude/ntfs-3g/logging.h3
-rwxr-xr-xinclude/ntfs-3g/mst.h3
-rwxr-xr-xinclude/ntfs-3g/ntfstime.h12
-rwxr-xr-xinclude/ntfs-3g/param.h72
-rwxr-xr-xinclude/ntfs-3g/realpath.h24
-rwxr-xr-xinclude/ntfs-3g/runlist.h3
-rwxr-xr-xinclude/ntfs-3g/security.h20
-rwxr-xr-xinclude/ntfs-3g/types.h8
-rwxr-xr-xinclude/ntfs-3g/unistr.h13
-rwxr-xr-xinclude/ntfs-3g/volume.h78
-rwxr-xr-xinclude/ntfs-3g/xattrs.h75
-rwxr-xr-xinstall-sh5
-rwxr-xr-xlibfuse-lite/Makefile.am3
-rwxr-xr-xlibfuse-lite/Makefile.in188
-rwxr-xr-xlibfuse-lite/fuse.c418
-rwxr-xr-xlibfuse-lite/fuse_kern_chan.c2
-rwxr-xr-xlibfuse-lite/fuse_lowlevel.c53
-rwxr-xr-xlibfuse-lite/fuse_opt.c20
-rwxr-xr-xlibfuse-lite/fuse_session.c12
-rwxr-xr-xlibfuse-lite/fusermount.c97
-rwxr-xr-xlibfuse-lite/helper.c21
-rwxr-xr-xlibfuse-lite/mount.c486
-rwxr-xr-xlibfuse-lite/mount_util.c246
-rwxr-xr-xlibfuse-lite/mount_util.h11
-rwxr-xr-xlibntfs-3g/Makefile.am15
-rwxr-xr-xlibntfs-3g/Makefile.in420
-rwxr-xr-xlibntfs-3g/acls.c219
-rwxr-xr-xlibntfs-3g/attrib.c1205
-rwxr-xr-xlibntfs-3g/bootsect.c4
-rwxr-xr-xlibntfs-3g/cache.c7
-rwxr-xr-xlibntfs-3g/compress.c962
-rwxr-xr-xlibntfs-3g/device.c252
-rwxr-xr-xlibntfs-3g/dir.c374
-rwxr-xr-xlibntfs-3g/efs.c217
-rwxr-xr-xlibntfs-3g/index.c30
-rwxr-xr-xlibntfs-3g/inode.c46
-rwxr-xr-xlibntfs-3g/lcnalloc.c36
-rw-r--r--libntfs-3g/libntfs-3g.pc10
-rw-r--r--libntfs-3g/libntfs-3g.script.so2
-rwxr-xr-xlibntfs-3g/logfile.c23
-rwxr-xr-xlibntfs-3g/logging.c24
-rwxr-xr-xlibntfs-3g/mft.c12
-rwxr-xr-xlibntfs-3g/mst.c24
-rwxr-xr-xlibntfs-3g/object_id.c9
-rwxr-xr-xlibntfs-3g/realpath.c103
-rwxr-xr-xlibntfs-3g/reparse.c67
-rwxr-xr-xlibntfs-3g/runlist.c62
-rwxr-xr-xlibntfs-3g/security.c345
-rwxr-xr-xlibntfs-3g/unistr.c244
-rwxr-xr-xlibntfs-3g/unix_io.c19
-rwxr-xr-xlibntfs-3g/volume.c365
-rwxr-xr-xlibntfs-3g/win32_io.c708
-rwxr-xr-xlibntfs-3g/xattrs.c791
-rwxr-xr-xlibtool9301
-rwxr-xr-xltmain.sh8439
-rwxr-xr-xm4/libtool.m47377
-rwxr-xr-xm4/ltoptions.m4368
-rwxr-xr-xm4/ltsugar.m4123
-rwxr-xr-xm4/ltversion.m423
-rwxr-xr-xm4/lt~obsolete.m492
-rwxr-xr-xmissing49
-rwxr-xr-xntfsprogs/Makefile.am154
-rwxr-xr-xntfsprogs/Makefile.in1199
-rwxr-xr-xntfsprogs/attrdef.c168
-rwxr-xr-xntfsprogs/attrdef.h7
-rwxr-xr-xntfsprogs/boot.c268
-rwxr-xr-xntfsprogs/boot.h7
-rwxr-xr-xntfsprogs/cluster.c118
-rwxr-xr-xntfsprogs/cluster.h39
-rwxr-xr-xntfsprogs/list.h194
-rw-r--r--ntfsprogs/mkntfs.8290
-rwxr-xr-xntfsprogs/mkntfs.8.in290
-rwxr-xr-xntfsprogs/mkntfs.c5177
-rw-r--r--ntfsprogs/ntfscat.8136
-rwxr-xr-xntfsprogs/ntfscat.8.in136
-rwxr-xr-xntfsprogs/ntfscat.c440
-rwxr-xr-xntfsprogs/ntfscat.h46
-rwxr-xr-xntfsprogs/ntfsck.c883
-rw-r--r--ntfsprogs/ntfsclone.8391
-rwxr-xr-xntfsprogs/ntfsclone.8.in391
-rwxr-xr-xntfsprogs/ntfsclone.c2701
-rw-r--r--ntfsprogs/ntfscluster.8124
-rwxr-xr-xntfsprogs/ntfscluster.8.in124
-rwxr-xr-xntfsprogs/ntfscluster.c563
-rwxr-xr-xntfsprogs/ntfscluster.h63
-rw-r--r--ntfsprogs/ntfscmp.877
-rwxr-xr-xntfsprogs/ntfscmp.8.in77
-rwxr-xr-xntfsprogs/ntfscmp.c1012
-rw-r--r--ntfsprogs/ntfscp.8111
-rwxr-xr-xntfsprogs/ntfscp.8.in111
-rwxr-xr-xntfsprogs/ntfscp.c590
-rwxr-xr-xntfsprogs/ntfsdecrypt.c1436
-rwxr-xr-xntfsprogs/ntfsdump_logfile.c779
-rw-r--r--ntfsprogs/ntfsfix.881
-rwxr-xr-xntfsprogs/ntfsfix.8.in81
-rwxr-xr-xntfsprogs/ntfsfix.c1657
-rw-r--r--ntfsprogs/ntfsinfo.889
-rwxr-xr-xntfsprogs/ntfsinfo.8.in89
-rwxr-xr-xntfsprogs/ntfsinfo.c2384
-rw-r--r--ntfsprogs/ntfslabel.8118
-rwxr-xr-xntfsprogs/ntfslabel.8.in118
-rwxr-xr-xntfsprogs/ntfslabel.c458
-rw-r--r--ntfsprogs/ntfsls.8172
-rwxr-xr-xntfsprogs/ntfsls.8.in172
-rwxr-xr-xntfsprogs/ntfsls.c717
-rwxr-xr-xntfsprogs/ntfsmftalloc.c368
-rwxr-xr-xntfsprogs/ntfsmove.c923
-rwxr-xr-xntfsprogs/ntfsmove.h46
-rw-r--r--ntfsprogs/ntfsprogs.869
-rwxr-xr-xntfsprogs/ntfsprogs.8.in69
-rw-r--r--ntfsprogs/ntfsresize.8326
-rwxr-xr-xntfsprogs/ntfsresize.8.in326
-rwxr-xr-xntfsprogs/ntfsresize.c4497
-rwxr-xr-xntfsprogs/ntfstruncate.c809
-rw-r--r--ntfsprogs/ntfsundelete.8324
-rwxr-xr-xntfsprogs/ntfsundelete.8.in324
-rwxr-xr-xntfsprogs/ntfsundelete.c2490
-rwxr-xr-xntfsprogs/ntfsundelete.h112
-rwxr-xr-xntfsprogs/ntfswipe.c2131
-rwxr-xr-xntfsprogs/ntfswipe.h54
-rwxr-xr-xntfsprogs/sd.c607
-rwxr-xr-xntfsprogs/sd.h11
-rwxr-xr-xntfsprogs/utils.c1184
-rwxr-xr-xntfsprogs/utils.h137
-rwxr-xr-xprog.IAB1071
-rwxr-xr-xprog.IAD5
-rwxr-xr-xprog.IMB466
-rwxr-xr-xprog.IMD2
-rwxr-xr-xprog.PFI2
-rwxr-xr-xprog.PO1
-rwxr-xr-xprog.PR14
-rwxr-xr-xprog.PRI219
-rwxr-xr-xprog.PS979
-rwxr-xr-xprog.SearchResults3
-rwxr-xr-xprog.WK39
-rwxr-xr-xsrc/Makefile.am86
-rwxr-xr-xsrc/Makefile.in938
-rwxr-xr-xsrc/lowntfs-3g.c1538
-rw-r--r--src/ntfs-3g.8448
-rwxr-xr-xsrc/ntfs-3g.8.in217
-rwxr-xr-xsrc/ntfs-3g.c1357
-rw-r--r--src/ntfs-3g.probe.881
-rwxr-xr-xsrc/ntfs-3g.probe.8.in4
-rwxr-xr-xsrc/ntfs-3g.probe.c9
-rw-r--r--src/ntfs-3g.secaudit.8184
-rwxr-xr-xsrc/ntfs-3g.secaudit.8.in15
-rw-r--r--src/ntfs-3g.usermap.896
-rwxr-xr-xsrc/ntfs-3g_common.c745
-rwxr-xr-xsrc/ntfs-3g_common.h185
-rwxr-xr-xsrc/secaudit.c673
-rwxr-xr-xsrc/secaudit.h32
-rwxr-xr-xsrc/usermap.c3
-rw-r--r--[-rwxr-xr-x]stamp-h10
193 files changed, 80411 insertions, 44563 deletions
diff --git a/src/lowntfs-3g.c b/src/lowntfs-3g.c
index a943e60..25940c3 100755
--- a/src/lowntfs-3g.c
+++ b/src/lowntfs-3g.c
@@ -4,7 +4,7 @@
* Copyright (c) 2005-2007 Yura Pakhuchiy
* Copyright (c) 2005 Yuval Fledel
* Copyright (c) 2006-2009 Szabolcs Szakacsits
- * Copyright (c) 2007-2010 Jean-Pierre Andre
+ * Copyright (c) 2007-2013 Jean-Pierre Andre
* Copyright (c) 2009 Erik Larsson
*
* This file is originated from the Linux-NTFS project.
@@ -38,12 +38,6 @@
#error "***********************************************************"
#endif
-#ifdef FUSE_INTERNAL
-#define FUSE_TYPE "integrated FUSE low"
-#else
-#define FUSE_TYPE "external FUSE low"
-#endif
-
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
@@ -69,7 +63,6 @@
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
-#include <getopt.h>
#include <syslog.h>
#include <sys/wait.h>
@@ -102,8 +95,11 @@
#include "object_id.h"
#include "efs.h"
#include "logging.h"
+#include "xattrs.h"
#include "misc.h"
+#include "ntfs-3g_common.h"
+
/*
* The following permission checking modes are governed by
* the LPERMSCONFIG value in param.h
@@ -121,18 +117,17 @@
#endif
#if CACHEING & (KERNELACLS | !KERNELPERMS)
-#warning "Fuse cacheing is broken unless basic permissions checked by kernel"
+#warning "Fuse cacheing is only usable with basic permissions checked by kernel"
#endif
#if !CACHEING
- /*
- * FUSE cacheing is broken except for basic permissions
- * checked by the kernel
- * So do not use cacheing until this is fixed
- */
#define ATTR_TIMEOUT 0.0
#define ENTRY_TIMEOUT 0.0
#else
+ /*
+ * FUSE cacheing is only usable with basic permissions
+ * checked by the kernel with external fuse >= 2.8
+ */
#define ATTR_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0)
#define ENTRY_TIMEOUT (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT) ? 1.0 : 0.0)
#endif
@@ -157,12 +152,6 @@ typedef enum {
FSTYPE_FUSEBLK
} fuse_fstype;
-typedef enum {
- ATIME_ENABLED,
- ATIME_DISABLED,
- ATIME_RELATIVE
-} ntfs_atime_t;
-
typedef struct fill_item {
struct fill_item *next;
size_t bufsize;
@@ -187,57 +176,23 @@ struct open_file {
int state;
} ;
-typedef enum {
- NF_STREAMS_INTERFACE_NONE, /* No access to named data streams. */
- NF_STREAMS_INTERFACE_XATTR, /* Map named data streams to xattrs. */
- NF_STREAMS_INTERFACE_OPENXATTR, /* Same, not limited to "user." */
-} ntfs_fuse_streams_interface;
-
enum {
CLOSE_GHOST = 1,
CLOSE_COMPRESSED = 2,
- CLOSE_ENCRYPTED = 4
+ CLOSE_ENCRYPTED = 4,
+ CLOSE_DMTIME = 8
};
-typedef struct {
- ntfs_volume *vol;
- unsigned int uid;
- unsigned int gid;
- unsigned int fmask;
- unsigned int dmask;
- ntfs_fuse_streams_interface streams;
- ntfs_atime_t atime;
- BOOL ro;
- BOOL show_sys_files;
- BOOL silent;
- BOOL recover;
- BOOL hiberfile;
- BOOL debug;
- BOOL no_detach;
- BOOL blkdev;
- BOOL mounted;
-#ifdef HAVE_SETXATTR /* extended attributes interface required */
- BOOL efs_raw;
-#endif /* HAVE_SETXATTR */
- struct fuse_chan *fc;
- BOOL inherit;
- unsigned int secure_flags;
- char *usermap_path;
- char *abs_mnt_point;
- struct PERMISSIONS_CACHE *seccache;
- struct SECURITY_CONTEXT security;
- struct open_file *open_files;
- u64 latest_ghost;
-} ntfs_fuse_context_t;
-
-static struct options {
- char *mnt_point; /* Mount point */
- char *options; /* Mount options */
- char *device; /* Device to mount */
-} opts;
-
-static const char *EXEC_NAME = "ntfs-3g";
-static char def_opts[] = "silent,allow_other,nonempty,";
+enum RM_TYPES {
+ RM_LINK,
+ RM_DIR,
+ RM_ANY,
+} ;
+
+static struct ntfs_options opts;
+
+const char *EXEC_NAME = "lowntfs-3g";
+
static ntfs_fuse_context_t *ctx;
static u32 ntfs_sequence;
static const char ghostformat[] = ".ghost-ntfs-3g-%020llu";
@@ -259,12 +214,12 @@ static const char *usage_msg =
"\n"
"Copyright (C) 2005-2007 Yura Pakhuchiy\n"
"Copyright (C) 2006-2009 Szabolcs Szakacsits\n"
-"Copyright (C) 2007-2010 Jean-Pierre Andre\n"
+"Copyright (C) 2007-2013 Jean-Pierre Andre\n"
"Copyright (C) 2009 Erik Larsson\n"
"\n"
"Usage: %s [-o option[,...]] <device|image_file> <mount_point>\n"
"\n"
-"Options: ro (read-only mount), remove_hiberfile, uid=, gid=,\n"
+"Options: ro (read-only mount), windows_names, uid=, gid=,\n"
" umask=, fmask=, dmask=, streams_interface=.\n"
" Please see the details in the manual (type: man ntfs-3g).\n"
"\n"
@@ -291,13 +246,14 @@ static const char *setuid_msg =
"Mount is denied because setuid and setgid root ntfs-3g is insecure with the\n"
"external FUSE library. Either remove the setuid/setgid bit from the binary\n"
"or rebuild NTFS-3G with integrated FUSE support and make it setuid root.\n"
-"Please see more information at http://ntfs-3g.org/support.html#unprivileged\n";
+"Please see more information at\n"
+"http://tuxera.com/community/ntfs-3g-faq/#unprivileged\n";
static const char *unpriv_fuseblk_msg =
"Unprivileged user can not mount NTFS block devices using the external FUSE\n"
"library. Either mount the volume as root, or rebuild NTFS-3G with integrated\n"
"FUSE support and make it setuid root. Please see more information at\n"
-"http://ntfs-3g.org/support.html#unprivileged\n";
+"http://tuxera.com/community/ntfs-3g-faq/#unprivileged\n";
#endif
@@ -374,6 +330,11 @@ static u64 ntfs_fuse_inode_lookup(fuse_ino_t parent, const char *name)
if (dir_ni) {
/* Lookup file */
inum = ntfs_inode_lookup_by_mbsname(dir_ni, name);
+ /* never return inodes 0 and 1 */
+ if (MREF(inum) <= 1) {
+ inum = (u64)-1;
+ errno = ENOENT;
+ }
if (ntfs_inode_close(dir_ni)
|| (inum == (u64)-1))
ino = (u64)-1;
@@ -444,7 +405,7 @@ static int ntfs_allowed_dir_access(struct SECURITY_CONTEXT *scx,
*
* Returns 0 on success or -errno on error.
*/
-
+#if HAVE_SYS_STATVFS_H
static void ntfs_fuse_statfs(fuse_req_t req,
fuse_ino_t ino __attribute__((unused)))
{
@@ -491,7 +452,7 @@ static void ntfs_fuse_statfs(fuse_req_t req,
size += vol->free_mft_records;
if (size < 0)
size = 0;
- sfs.f_ffree = /*sfs.f_favail =*/ size;
+ sfs.f_ffree = sfs.f_favail = size;
/* Maximum length of filenames. */
sfs.f_namemax = NTFS_MAX_NAME_LEN;
@@ -500,6 +461,7 @@ static void ntfs_fuse_statfs(fuse_req_t req,
fuse_reply_err(req, ENODEV);
}
+#endif
static void set_fuse_error(int *err)
{
@@ -603,7 +565,8 @@ int ntfs_macfuse_setchgtime(const char *path, const struct timespec *tv)
}
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
-#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__))
+#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
+ || (defined(__APPLE__) || defined(__DARWIN__))
static void ntfs_init(void *userdata __attribute__((unused)),
struct fuse_conn_info *conn)
{
@@ -614,6 +577,12 @@ static void ntfs_init(void *userdata __attribute__((unused)),
/* request umask not to be enforced by fuse */
conn->want |= FUSE_CAP_DONT_MASK;
#endif /* defined FUSE_CAP_DONT_MASK */
+#ifdef FUSE_CAP_BIG_WRITES
+ if (ctx->big_writes
+ && ((ctx->vol->nr_clusters << ctx->vol->cluster_size_bits)
+ >= SAFE_CAPACITY_FOR_BIG_WRITES))
+ conn->want |= FUSE_CAP_BIG_WRITES;
+#endif
}
#endif /* defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__)) */
@@ -685,7 +654,9 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
* encrypted files to include padding required for decryption
* also include 2 bytes for padding info
*/
- if (ctx->efs_raw && ni->flags & FILE_ATTR_ENCRYPTED)
+ if (ctx->efs_raw
+ && (ni->flags & FILE_ATTR_ENCRYPTED)
+ && ni->data_size)
stbuf->st_size = ((ni->data_size + 511) & ~511) + 2;
#endif /* HAVE_SETXATTR */
/*
@@ -697,7 +668,8 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
if (ni->flags & FILE_ATTR_SYSTEM) {
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
if (!na) {
- goto exit;
+ stbuf->st_ino = ni->mft_no;
+ goto nodata;
}
/* Check whether it's Interix FIFO or socket. */
if (!(ni->flags & FILE_ATTR_HIDDEN)) {
@@ -712,9 +684,9 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
* Check whether it's Interix symbolic link, block or
* character device.
*/
- if ((size_t)na->data_size <= sizeof(INTX_FILE_TYPES)
+ if ((u64)na->data_size <= sizeof(INTX_FILE_TYPES)
+ sizeof(ntfschar) * PATH_MAX
- && (size_t)na->data_size >
+ && (u64)na->data_size >
sizeof(INTX_FILE_TYPES)) {
INTX_FILE *intx_file;
@@ -767,6 +739,7 @@ static int ntfs_fuse_getstat(struct SECURITY_CONTEXT *scx,
}
if (S_ISLNK(stbuf->st_mode))
stbuf->st_mode |= 0777;
+nodata :
stbuf->st_ino = ni->mft_no;
#ifdef HAVE_STRUCT_STAT_ST_ATIMESPEC
stbuf->st_atimespec = ntfs2timespec(ni->last_access_time);
@@ -878,6 +851,11 @@ static void ntfs_fuse_lookup(fuse_req_t req, fuse_ino_t parent,
#endif
iref = ntfs_inode_lookup_by_mbsname(dir_ni,
name);
+ /* never return inodes 0 and 1 */
+ if (MREF(iref) <= 1) {
+ iref = (u64)-1;
+ errno = ENOENT;
+ }
ok = !ntfs_inode_close(dir_ni)
&& (iref != (u64)-1)
&& ntfs_fuse_fillstat(
@@ -1002,15 +980,34 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx,
(unsigned long long)MREF(mref));
return -1;
}
-
- if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user ||
- ctx->show_sys_files) {
+ /* never return inodes 0 and 1 */
+ if (MREF(mref) > 1) {
struct stat st = { .st_ino = MREF(mref) };
- if (dt_type == NTFS_DT_REG)
- st.st_mode = S_IFREG | (0777 & ~ctx->fmask);
- else if (dt_type == NTFS_DT_DIR)
+ switch (dt_type) {
+ case NTFS_DT_DIR :
st.st_mode = S_IFDIR | (0777 & ~ctx->dmask);
+ break;
+ case NTFS_DT_LNK :
+ st.st_mode = S_IFLNK | 0777;
+ break;
+ case NTFS_DT_FIFO :
+ st.st_mode = S_IFIFO;
+ break;
+ case NTFS_DT_SOCK :
+ st.st_mode = S_IFSOCK;
+ break;
+ case NTFS_DT_BLK :
+ st.st_mode = S_IFBLK;
+ break;
+ case NTFS_DT_CHR :
+ st.st_mode = S_IFCHR;
+ break;
+ default : /* unexpected types shown as plain files */
+ case NTFS_DT_REG :
+ st.st_mode = S_IFREG | (0777 & ~ctx->fmask);
+ break;
+ }
#if defined(__APPLE__) || defined(__DARWIN__)
/*
@@ -1122,14 +1119,17 @@ static void ntfs_fuse_releasedir(fuse_req_t req,
ntfs_fuse_fill_item_t *current;
fill = (ntfs_fuse_fill_context_t*)(long)fi->fh;
- /* make sure to clear results */
- current = fill->first;
- while (current) {
- current = current->next;
- free(fill->first);
- fill->first = current;
- }
- free(fill);
+ if (fill && (fill->ino == ino)) {
+ /* make sure to clear results */
+ current = fill->first;
+ while (current) {
+ current = current->next;
+ free(fill->first);
+ fill->first = current;
+ }
+ fill->ino = 0;
+ free(fill);
+ }
fuse_reply_err(req, 0);
}
@@ -1145,7 +1145,7 @@ static void ntfs_fuse_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
int err = 0;
fill = (ntfs_fuse_fill_context_t*)(long)fi->fh;
- if (fill) {
+ if (fill && (fill->ino == ino)) {
if (!fill->filled) {
/* initial call : build the full list */
first = (ntfs_fuse_fill_item_t*)ntfs_malloc
@@ -1250,6 +1250,12 @@ static void ntfs_fuse_open(fuse_req_t req, fuse_ino_t ino,
&& (ni->flags & FILE_ATTR_ENCRYPTED))
state |= CLOSE_ENCRYPTED;
#endif /* HAVE_SETXATTR */
+ /* mark a future need to update the mtime */
+ if (ctx->dmtime)
+ state |= CLOSE_DMTIME;
+ /* deny opening metadata files for writing */
+ if (ino < FILE_first_user)
+ res = -EPERM;
}
ntfs_attr_close(na);
} else
@@ -1290,8 +1296,10 @@ static void ntfs_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size,
s64 total = 0;
s64 max_read;
- if (!size)
+ if (!size) {
+ res = 0;
goto exit;
+ }
buf = (char*)ntfs_malloc(size);
if (!buf) {
res = -errno;
@@ -1311,8 +1319,10 @@ static void ntfs_fuse_read(fuse_req_t req, fuse_ino_t ino, size_t size,
max_read = na->data_size;
#ifdef HAVE_SETXATTR /* extended attributes interface required */
/* limit reads at next 512 byte boundary for encrypted attributes */
- if (ctx->efs_raw && (na->data_flags & ATTR_IS_ENCRYPTED) &&
- NAttrNonResident(na)) {
+ if (ctx->efs_raw
+ && max_read
+ && (na->data_flags & ATTR_IS_ENCRYPTED)
+ && NAttrNonResident(na)) {
max_read = ((na->data_size+511) & ~511) + 2;
}
#endif /* HAVE_SETXATTR */
@@ -1379,7 +1389,10 @@ static void ntfs_fuse_write(fuse_req_t req, fuse_ino_t ino, const char *buf,
total += ret;
}
res = total;
- if (res > 0)
+ if ((res > 0)
+ && (!ctx->dmtime
+ || (le64_to_cpu(ntfs_current_time())
+ - le64_to_cpu(ni->last_data_change_time)) > ctx->dmtime))
ntfs_fuse_update_times(na->ni, NTFS_UPDATE_MCTIME);
exit:
if (na)
@@ -1525,6 +1538,11 @@ static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
if (!ni)
goto exit;
+ /* deny truncating metadata files */
+ if (ino < FILE_first_user) {
+ errno = EPERM;
+ goto exit;
+ }
na = ntfs_attr_open(ni, AT_DATA, AT_UNNAMED, 0);
if (!na)
goto exit;
@@ -1541,16 +1559,9 @@ static int ntfs_fuse_trunc(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
}
#endif
/*
- * for compressed files, only deleting contents and expanding
- * are implemented. Expanding is done by inserting a final
+ * for compressed files, upsizing is done by inserting a final
* zero, which is optimized as creating a hole when possible.
*/
- if ((na->data_flags & ATTR_COMPRESSION_MASK)
- && size
- && (size < na->initialized_size)) {
- errno = EOPNOTSUPP;
- goto exit;
- }
oldsize = na->data_size;
if ((na->data_flags & ATTR_COMPRESSION_MASK)
&& (size > na->initialized_size)) {
@@ -1574,7 +1585,7 @@ exit:
return res;
}
-#ifdef HAVE_UTIMENSAT
+#if defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW)
static int ntfs_fuse_utimens(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
struct stat *stin, struct stat *stbuf, int to_set)
@@ -1621,7 +1632,7 @@ static int ntfs_fuse_utimens(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
return res;
}
-#else /* HAVE_UTIMENSAT */
+#else /* defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW) */
static int ntfs_fuse_utime(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
struct stat *stin, struct stat *stbuf)
@@ -1692,7 +1703,7 @@ static int ntfs_fuse_utime(struct SECURITY_CONTEXT *scx, fuse_ino_t ino,
return res;
}
-#endif /* HAVE_UTIMENSAT */
+#endif /* defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW) */
static void ntfs_fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
int to_set, struct fuse_file_info *fi __attribute__((unused)))
@@ -1767,11 +1778,11 @@ static void ntfs_fuse_setattr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
}
/* some set of atime/mtime */
if (!res && (to_set & (FUSE_SET_ATTR_ATIME + FUSE_SET_ATTR_MTIME))) {
-#ifdef HAVE_UTIMENSAT
+#if defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW)
res = ntfs_fuse_utimens(&security, ino, attr, &stbuf, to_set);
-#else /* HAVE_UTIMENSAT */
+#else /* defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW) */
res = ntfs_fuse_utime(&security, ino, attr, &stbuf);
-#endif /* HAVE_UTIMENSAT */
+#endif /* defined(HAVE_UTIMENSAT) & defined(FUSE_SET_ATTR_ATIME_NOW) */
}
if (res)
fuse_reply_err(req, -res);
@@ -1830,6 +1841,8 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
struct open_file *of;
int state = 0;
le32 securid;
+ gid_t gid;
+ mode_t dsetgid;
mode_t type = typemode & ~07777;
mode_t perm;
struct SECURITY_CONTEXT security;
@@ -1837,7 +1850,9 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
/* Generate unicode filename. */
uname_len = ntfs_mbstoucs(name, &uname);
- if (uname_len < 0) {
+ if ((uname_len < 0)
+ || (ctx->windows_names
+ && ntfs_forbidden_chars(uname,uname_len))) {
res = -errno;
goto exit;
}
@@ -1850,13 +1865,15 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
/* make sure parent directory is writeable and executable */
if (!ntfs_fuse_fill_security_context(req, &security)
- || ntfs_allowed_access(&security,
- dir_ni,S_IWRITE + S_IEXEC)) {
+ || ntfs_allowed_create(&security,
+ dir_ni, &gid, &dsetgid)) {
#else
ntfs_fuse_fill_security_context(req, &security);
+ ntfs_allowed_create(&security, dir_ni, &gid, &dsetgid);
#endif
if (S_ISDIR(type))
- perm = typemode & ~ctx->dmask & 0777;
+ perm = (typemode & ~ctx->dmask & 0777)
+ | (dsetgid & S_ISGID);
else
perm = typemode & ~ctx->fmask & 0777;
/*
@@ -1874,11 +1891,11 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
else
#if POSIXACLS
securid = ntfs_alloc_securid(&security,
- security.uid, security.gid,
+ security.uid, gid,
dir_ni, perm, S_ISDIR(type));
#else
securid = ntfs_alloc_securid(&security,
- security.uid, security.gid,
+ security.uid, gid,
perm & ~security.umask, S_ISDIR(type));
#endif
/* Create object specified in @type. */
@@ -1912,13 +1929,13 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
#if POSIXACLS
if (!securid
&& ntfs_set_inherited_posix(&security, ni,
- security.uid, security.gid,
+ security.uid, gid,
dir_ni, perm) < 0)
set_fuse_error(&res);
#else
if (!securid
&& ntfs_set_owner_mode(&security, ni,
- security.uid, security.gid,
+ security.uid, gid,
perm & ~security.umask) < 0)
set_fuse_error(&res);
#endif
@@ -1935,6 +1952,8 @@ static int ntfs_fuse_create(fuse_req_t req, fuse_ino_t parent, const char *name,
&& (ni->flags & FILE_ATTR_ENCRYPTED))
state |= CLOSE_ENCRYPTED;
#endif /* HAVE_SETXATTR */
+ if (fi && ctx->dmtime)
+ state |= CLOSE_DMTIME;
ntfs_inode_update_mbsname(dir_ni, name, ni->mft_no);
NInoSetDirty(ni);
e->ino = ni->mft_no;
@@ -2039,9 +2058,17 @@ static int ntfs_fuse_newlink(fuse_req_t req __attribute__((unused)),
goto exit;
}
+ /* Do not accept linking to a directory (except for renaming) */
+ if (e && (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY)) {
+ errno = EPERM;
+ res = -errno;
+ goto exit;
+ }
/* Generate unicode filename. */
uname_len = ntfs_mbstoucs(newname, &uname);
- if (uname_len < 0) {
+ if ((uname_len < 0)
+ || (ctx->windows_names
+ && ntfs_forbidden_chars(uname,uname_len))) {
res = -errno;
goto exit;
}
@@ -2104,11 +2131,14 @@ static void ntfs_fuse_link(fuse_req_t req, fuse_ino_t ino,
fuse_reply_entry(req, &entry);
}
-static int ntfs_fuse_rm(fuse_req_t req, fuse_ino_t parent, const char *name)
+static int ntfs_fuse_rm(fuse_req_t req, fuse_ino_t parent, const char *name,
+ enum RM_TYPES rm_type __attribute__((unused)))
{
ntfschar *uname = NULL;
+ ntfschar *ugname;
ntfs_inode *dir_ni = NULL, *ni = NULL;
int res = 0, uname_len;
+ int ugname_len;
u64 iref;
fuse_ino_t ino;
struct open_file *of;
@@ -2135,72 +2165,121 @@ static int ntfs_fuse_rm(fuse_req_t req, fuse_ino_t parent, const char *name)
res = -errno;
goto exit;
}
-
-{ /* temporary */
-struct open_file *prev = (struct open_file*)NULL;
-for (of=ctx->open_files; of; of=of->next)
-{
-if (of->previous != prev) ntfs_log_error("bad chaining\n");
-prev = of;
-}
-}
- of = ctx->open_files;
ino = (fuse_ino_t)MREF(iref);
- /* improvable search in open files list... */
- while (of
- && (of->ino != ino))
- of = of->next;
- if (of && !(of->state & CLOSE_GHOST)) {
- /* file was open, create a ghost in unlink parent */
- of->state |= CLOSE_GHOST;
- of->parent = parent;
- of->ghost = ++ctx->latest_ghost;
- sprintf(ghostname,ghostformat,of->ghost);
- /* need to close the dir for linking the ghost */
- if (ntfs_inode_close(dir_ni)) {
- res = -errno;
- goto out;
- }
- /* sweep existing ghost if any */
- ntfs_fuse_rm(req, parent, ghostname);
- res = ntfs_fuse_newlink(req, of->ino, parent, ghostname,
- (struct fuse_entry_param*)NULL);
- if (res)
- goto out;
- /* now reopen then parent directory */
- dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
- if (!dir_ni) {
- res = -errno;
- goto exit;
- }
+ /* deny unlinking metadata files */
+ if (ino < FILE_first_user) {
+ res = -EPERM;
+ goto exit;
}
- ni = ntfs_inode_open(ctx->vol, MREF(iref));
+ ni = ntfs_inode_open(ctx->vol, ino);
if (!ni) {
res = -errno;
goto exit;
}
+#if defined(__sun) && defined (__SVR4)
+ /* on Solaris : deny unlinking directories */
+ if (rm_type
+ == (ni->mrec->flags & MFT_RECORD_IS_DIRECTORY ? RM_LINK : RM_DIR)) {
+ errno = EPERM;
+ res = -errno;
+ goto exit;
+ }
+#endif /* defined(__sun) && defined (__SVR4) */
+
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
/* JPA deny unlinking if directory is not writable and executable */
- if (!ntfs_fuse_fill_security_context(req, &security)
- || ntfs_allowed_dir_access(&security, dir_ni, ino, ni,
+ if (ntfs_fuse_fill_security_context(req, &security)
+ && !ntfs_allowed_dir_access(&security, dir_ni, ino, ni,
S_IEXEC + S_IWRITE + S_ISVTX)) {
+ errno = EACCES;
+ res = -errno;
+ goto exit;
+ }
#endif
- if (ntfs_delete(ctx->vol, (char*)NULL, ni, dir_ni,
- uname, uname_len))
+ /*
+ * We keep one open_file record per opening, to avoid
+ * having to check the list of open files when opening
+ * and closing (which are more frequent than unlinking).
+ * As a consequence, we may have to create several
+ * ghosts names for the same file.
+ * The file may have been opened with a different name
+ * in a different parent directory. The ghost is
+ * nevertheless created in the parent directory of the
+ * name being unlinked, and permissions to do so are the
+ * same as required for unlinking.
+ */
+ for (of=ctx->open_files; of; of = of->next) {
+ if ((of->ino == ino) && !(of->state & CLOSE_GHOST)) {
+ /* file was open, create a ghost in unlink parent */
+ ntfs_inode *gni;
+ u64 gref;
+
+ /* ni has to be closed for linking ghost */
+ if (ni) {
+ if (ntfs_inode_close(ni)) {
+ res = -errno;
+ goto exit;
+ }
+ ni = (ntfs_inode*)NULL;
+ }
+ of->state |= CLOSE_GHOST;
+ of->parent = parent;
+ of->ghost = ++ctx->latest_ghost;
+ sprintf(ghostname,ghostformat,of->ghost);
+ /* Generate unicode filename. */
+ ugname = (ntfschar*)NULL;
+ ugname_len = ntfs_mbstoucs(ghostname, &ugname);
+ if (ugname_len < 0) {
+ res = -errno;
+ goto exit;
+ }
+ /* sweep existing ghost if any, ignoring errors */
+ gref = ntfs_inode_lookup_by_mbsname(dir_ni, ghostname);
+ if (gref != (u64)-1) {
+ gni = ntfs_inode_open(ctx->vol, MREF(gref));
+ ntfs_delete(ctx->vol, (char*)NULL, gni, dir_ni,
+ ugname, ugname_len);
+ /* ntfs_delete() always closes gni and dir_ni */
+ dir_ni = (ntfs_inode*)NULL;
+ } else {
+ if (ntfs_inode_close(dir_ni)) {
+ res = -errno;
+ goto out;
+ }
+ dir_ni = (ntfs_inode*)NULL;
+ }
+ free(ugname);
+ res = ntfs_fuse_newlink(req, of->ino, parent, ghostname,
+ (struct fuse_entry_param*)NULL);
+ if (res)
+ goto out;
+ /* now reopen then parent directory */
+ dir_ni = ntfs_inode_open(ctx->vol, INODE(parent));
+ if (!dir_ni) {
+ res = -errno;
+ goto exit;
+ }
+ }
+ }
+ if (!ni) {
+ ni = ntfs_inode_open(ctx->vol, ino);
+ if (!ni) {
res = -errno;
+ goto exit;
+ }
+ }
+ if (ntfs_delete(ctx->vol, (char*)NULL, ni, dir_ni,
+ uname, uname_len))
+ res = -errno;
/* ntfs_delete() always closes ni and dir_ni */
- ni = dir_ni = NULL;
-#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
- } else
- res = -EACCES;
-#endif
+ ni = dir_ni = NULL;
exit:
- if (ntfs_inode_close(ni))
- set_fuse_error(&res);
- if (ntfs_inode_close(dir_ni))
- set_fuse_error(&res);
+ if (ntfs_inode_close(ni) && !res)
+ res = -errno;
+ if (ntfs_inode_close(dir_ni) && !res)
+ res = -errno;
out :
free(uname);
return res;
@@ -2211,7 +2290,7 @@ static void ntfs_fuse_unlink(fuse_req_t req, fuse_ino_t parent,
{
int res;
- res = ntfs_fuse_rm(req, parent, name);
+ res = ntfs_fuse_rm(req, parent, name, RM_LINK);
if (res)
fuse_reply_err(req, -res);
else
@@ -2232,7 +2311,7 @@ static int ntfs_fuse_safe_rename(fuse_req_t req, fuse_ino_t ino,
if (ret)
return ret;
- ret = ntfs_fuse_rm(req, newparent, newname);
+ ret = ntfs_fuse_rm(req, newparent, newname, RM_ANY);
if (!ret) {
ret = ntfs_fuse_newlink(req, ino, newparent, newname,
@@ -2240,9 +2319,9 @@ static int ntfs_fuse_safe_rename(fuse_req_t req, fuse_ino_t ino,
if (ret)
goto restore;
- ret = ntfs_fuse_rm(req, parent, name);
+ ret = ntfs_fuse_rm(req, parent, name, RM_ANY);
if (ret) {
- if (ntfs_fuse_rm(req, newparent, newname))
+ if (ntfs_fuse_rm(req, newparent, newname, RM_ANY))
goto err;
goto restore;
}
@@ -2263,7 +2342,7 @@ cleanup:
* fail (unless concurrent access to directories when fuse
* is multithreaded)
*/
- if (ntfs_fuse_rm(req, newparent, tmp) < 0)
+ if (ntfs_fuse_rm(req, newparent, tmp, RM_ANY) < 0)
ntfs_log_perror("Rename failed. Existing file '%s' still present "
"as '%s'", newname, tmp);
}
@@ -2384,9 +2463,9 @@ static void ntfs_fuse_rename(fuse_req_t req, fuse_ino_t parent,
if (ret)
goto out;
- ret = ntfs_fuse_rm(req, parent, name);
+ ret = ntfs_fuse_rm(req, parent, name, RM_ANY);
if (ret)
- ntfs_fuse_rm(req, newparent, newname);
+ ntfs_fuse_rm(req, newparent, newname, RM_ANY);
}
out:
if (ret)
@@ -2406,7 +2485,9 @@ static void ntfs_fuse_release(fuse_req_t req, fuse_ino_t ino,
of = (struct open_file*)(long)fi->fh;
/* Only for marked descriptors there is something to do */
- if (!of || !(of->state & (CLOSE_COMPRESSED | CLOSE_ENCRYPTED))) {
+ if (!of
+ || !(of->state & (CLOSE_COMPRESSED
+ | CLOSE_ENCRYPTED | CLOSE_DMTIME))) {
res = 0;
goto out;
}
@@ -2421,6 +2502,8 @@ static void ntfs_fuse_release(fuse_req_t req, fuse_ino_t ino,
goto exit;
}
res = 0;
+ if (of->state & CLOSE_DMTIME)
+ ntfs_inode_update_times(ni,NTFS_UPDATE_MCTIME);
if (of->state & CLOSE_COMPRESSED)
res = ntfs_attr_pclose(na);
#ifdef HAVE_SETXATTR /* extended attributes interface required */
@@ -2437,7 +2520,7 @@ out:
if (of) {
if (of->state & CLOSE_GHOST) {
sprintf(ghostname,ghostformat,of->ghost);
- ntfs_fuse_rm(req, of->parent, ghostname);
+ ntfs_fuse_rm(req, of->parent, ghostname, RM_ANY);
}
/* remove from open files list */
if (of->next)
@@ -2472,13 +2555,25 @@ static void ntfs_fuse_rmdir(fuse_req_t req, fuse_ino_t parent, const char *name)
{
int res;
- res = ntfs_fuse_rm(req, parent, name);
+ res = ntfs_fuse_rm(req, parent, name, RM_DIR);
if (res)
fuse_reply_err(req, -res);
else
fuse_reply_err(req, 0);
}
+static void ntfs_fuse_fsync(fuse_req_t req,
+ fuse_ino_t ino __attribute__((unused)),
+ int type __attribute__((unused)),
+ struct fuse_file_info *fi __attribute__((unused)))
+{
+ /* sync the full device */
+ if (ntfs_device_sync(ctx->vol->dev))
+ fuse_reply_err(req, errno);
+ else
+ fuse_reply_err(req, 0);
+}
+
static void ntfs_fuse_bmap(fuse_req_t req, fuse_ino_t ino, size_t blocksize,
uint64_t vidx)
{
@@ -2538,67 +2633,15 @@ done :
* Name space identifications and prefixes
*/
-enum { XATTRNS_NONE,
+enum {
+ XATTRNS_NONE,
XATTRNS_USER,
XATTRNS_SYSTEM,
XATTRNS_SECURITY,
XATTRNS_TRUSTED,
- XATTRNS_OPEN } ;
-
-static const char nf_ns_user_prefix[] = "user.";
-static const int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
-static const char nf_ns_system_prefix[] = "system.";
-static const int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1;
-static const char nf_ns_security_prefix[] = "security.";
-static const int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1;
-static const char nf_ns_trusted_prefix[] = "trusted.";
-static const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1;
-
-static const char xattr_ntfs_3g[] = "ntfs-3g.";
-
-/*
- * Identification of data mapped to the system name space
- */
-
-enum { XATTR_UNMAPPED,
- XATTR_NTFS_ACL,
- XATTR_NTFS_ATTRIB,
- XATTR_NTFS_EFSINFO,
- XATTR_NTFS_REPARSE_DATA,
- XATTR_NTFS_OBJECT_ID,
- XATTR_NTFS_DOS_NAME,
- XATTR_NTFS_TIMES,
- XATTR_POSIX_ACC,
- XATTR_POSIX_DEF } ;
-
-static const char nf_ns_xattr_ntfs_acl[] = "system.ntfs_acl";
-static const char nf_ns_xattr_attrib[] = "system.ntfs_attrib";
-static const char nf_ns_xattr_efsinfo[] = "user.ntfs.efsinfo";
-static const char nf_ns_xattr_reparse[] = "system.ntfs_reparse_data";
-static const char nf_ns_xattr_object_id[] = "system.ntfs_object_id";
-static const char nf_ns_xattr_dos_name[] = "system.ntfs_dos_name";
-static const char nf_ns_xattr_times[] = "system.ntfs_times";
-static const char nf_ns_xattr_posix_access[] = "system.posix_acl_access";
-static const char nf_ns_xattr_posix_default[] = "system.posix_acl_default";
-
-struct XATTRNAME {
- int xattr;
- const char *name;
+ XATTRNS_OPEN
} ;
-static struct XATTRNAME nf_ns_xattr_names[] = {
- { XATTR_NTFS_ACL, nf_ns_xattr_ntfs_acl },
- { XATTR_NTFS_ATTRIB, nf_ns_xattr_attrib },
- { XATTR_NTFS_EFSINFO, nf_ns_xattr_efsinfo },
- { XATTR_NTFS_REPARSE_DATA, nf_ns_xattr_reparse },
- { XATTR_NTFS_OBJECT_ID, nf_ns_xattr_object_id },
- { XATTR_NTFS_DOS_NAME, nf_ns_xattr_dos_name },
- { XATTR_NTFS_TIMES, nf_ns_xattr_times },
- { XATTR_POSIX_ACC, nf_ns_xattr_posix_access },
- { XATTR_POSIX_DEF, nf_ns_xattr_posix_default },
- { XATTR_UNMAPPED, (char*)NULL } /* terminator */
-};
-
/*
* Check whether access to internal data as an extended
* attribute in system name space is allowed
@@ -2671,21 +2714,6 @@ static ntfs_inode *ntfs_check_access_xattr(fuse_req_t req,
}
/*
- * Determine whether an extended attribute is in the system
- * name space and mapped to internal data
- */
-
-static int mapped_xattr_system(const char *name)
-{
- struct XATTRNAME *p;
-
- p = nf_ns_xattr_names;
- while (p->name && strcmp(p->name,name))
- p++;
- return (p->xattr);
-}
-
-/*
* Determine the name space of an extended attribute
*/
@@ -2766,7 +2794,6 @@ static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
{
ntfs_attr_search_ctx *actx = NULL;
ntfs_inode *ni;
- char *to;
char *list = (char*)NULL;
int ret = 0;
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
@@ -2781,9 +2808,11 @@ static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
ret = -errno;
goto out;
}
+ /* Return with no result for symlinks, fifo, etc. */
+ if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))
+ goto exit;
+ /* otherwise file must be readable */
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
- /* file must be readable */
-// condition on fill_security ?
if (!ntfs_allowed_access(&security,ni,S_IREAD)) {
ret = -EACCES;
goto exit;
@@ -2801,72 +2830,14 @@ static void ntfs_fuse_listxattr(fuse_req_t req, fuse_ino_t ino, size_t size)
goto exit;
}
}
- to = list;
if ((ctx->streams == NF_STREAMS_INTERFACE_XATTR)
|| (ctx->streams == NF_STREAMS_INTERFACE_OPENXATTR)) {
- while (!ntfs_attr_lookup(AT_DATA, NULL, 0, CASE_SENSITIVE,
- 0, NULL, 0, actx)) {
- char *tmp_name = NULL;
- int tmp_name_len;
-
- if (!actx->attr->name_length)
- continue;
- tmp_name_len = ntfs_ucstombs(
- (ntfschar *)((u8*)actx->attr +
- le16_to_cpu(actx->attr->name_offset)),
- actx->attr->name_length, &tmp_name, 0);
- if (tmp_name_len < 0) {
- ret = -errno;
- goto exit;
- }
- /*
- * When using name spaces, do not return
- * security, trusted nor system attributes
- * (filtered elsewhere anyway)
- * otherwise insert "user." prefix
- */
- if (ctx->streams == NF_STREAMS_INTERFACE_XATTR) {
- if ((strlen(tmp_name) > sizeof(xattr_ntfs_3g))
- && !strncmp(tmp_name,xattr_ntfs_3g,
- sizeof(xattr_ntfs_3g)-1))
- tmp_name_len = 0;
- else
- ret += tmp_name_len
- + nf_ns_user_prefix_len + 1;
- } else
- ret += tmp_name_len + 1;
- if (size && tmp_name_len) {
- if ((size_t)ret <= size) {
- if (ctx->streams
- == NF_STREAMS_INTERFACE_XATTR) {
- strcpy(to, nf_ns_user_prefix);
- to += nf_ns_user_prefix_len;
- }
- strncpy(to, tmp_name, tmp_name_len);
- to += tmp_name_len;
- *to = 0;
- to++;
- } else {
- free(tmp_name);
- ret = -ERANGE;
- goto exit;
- }
- }
- free(tmp_name);
- }
- }
-
- /* List efs info xattr for encrypted files */
- if (ctx->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) {
- ret += sizeof(nf_ns_xattr_efsinfo);
- if ((size_t)ret <= size) {
- memcpy(to, nf_ns_xattr_efsinfo,
- sizeof(nf_ns_xattr_efsinfo));
- to += sizeof(nf_ns_xattr_efsinfo);
- }
+ ret = ntfs_fuse_listxattr_common(ni, actx, list, size,
+ ctx->streams == NF_STREAMS_INTERFACE_XATTR);
+ if (ret < 0)
+ goto exit;
}
-
if (errno != ENOENT)
ret = -errno;
exit:
@@ -2885,82 +2856,22 @@ out :
free(list);
}
-static __inline__ int ntfs_system_getxattr(struct SECURITY_CONTEXT *scx,
- int attr, ntfs_inode *ni, char *value, size_t size)
-{
- int res;
- ntfs_inode *dir_ni;
-
- /*
- * the returned value is the needed
- * size. If it is too small, no copy
- * is done, and the caller has to
- * issue a new call with correct size.
- */
- switch (attr) {
- case XATTR_NTFS_ACL :
- res = ntfs_get_ntfs_acl(scx, ni, value, size);
- break;
-#if POSIXACLS
- case XATTR_POSIX_ACC :
- res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_access,
- value, size);
- break;
- case XATTR_POSIX_DEF :
- res = ntfs_get_posix_acl(scx, ni, nf_ns_xattr_posix_default,
- value, size);
- break;
-#endif
- case XATTR_NTFS_ATTRIB :
- res = ntfs_get_ntfs_attrib(ni, value, size);
- break;
- case XATTR_NTFS_EFSINFO :
- if (ctx->efs_raw)
- res = ntfs_get_efs_info(ni, value, size);
- else
- res = -EPERM;
- break;
- case XATTR_NTFS_REPARSE_DATA :
- res = ntfs_get_ntfs_reparse_data(ni, value, size);
- break;
- case XATTR_NTFS_OBJECT_ID :
- res = ntfs_get_ntfs_object_id(ni, value, size);
- break;
- case XATTR_NTFS_DOS_NAME:
- dir_ni = ntfs_dir_parent_inode(ni);
- if (dir_ni) {
- res = ntfs_get_ntfs_dos_name(ni, dir_ni, value, size);
- if (ntfs_inode_close(dir_ni))
- set_fuse_error(&res);
- } else
- res = -errno;
- break;
- case XATTR_NTFS_TIMES:
- res = ntfs_inode_get_times(ni, value, size);
- break;
- default :
- errno = EOPNOTSUPP;
- res = -errno;
- break;
- }
- return (res);
-}
-
static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
size_t size)
{
ntfs_inode *ni;
+ ntfs_inode *dir_ni;
ntfs_attr *na = NULL;
char *value = (char*)NULL;
ntfschar *lename = (ntfschar*)NULL;
int lename_len;
int res;
s64 rsize;
- int attr;
+ enum SYSTEMXATTRS attr;
int namespace;
struct SECURITY_CONTEXT security;
- attr = mapped_xattr_system(name);
+ attr = ntfs_xattr_system_type(name,ctx->vol);
if (attr != XATTR_UNMAPPED) {
/*
* hijack internal data and ACL retrieval, whatever
@@ -2974,10 +2885,16 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
ni = ntfs_check_access_xattr(req, &security, ino,
attr, FALSE);
if (ni) {
- if (ntfs_allowed_access(&security,ni,S_IREAD))
- res = ntfs_system_getxattr(&security,
- attr, ni, value, size);
- else
+ if (ntfs_allowed_access(&security,ni,S_IREAD)) {
+ if (attr == XATTR_NTFS_DOS_NAME)
+ dir_ni = ntfs_dir_parent_inode(ni);
+ else
+ dir_ni = (ntfs_inode*)NULL;
+ res = ntfs_xattr_system_getxattr(&security,
+ attr, ni, dir_ni, value, size);
+ if (dir_ni && ntfs_inode_close(dir_ni))
+ set_fuse_error(&res);
+ } else
res = -errno;
if (ntfs_inode_close(ni))
set_fuse_error(&res);
@@ -2993,8 +2910,14 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
if (ni) {
/* user mapping not mandatory */
ntfs_fuse_fill_security_context(req, &security);
- res = ntfs_system_getxattr(&security,
- attr, ni, value, size);
+ if (attr == XATTR_NTFS_DOS_NAME)
+ dir_ni = ntfs_dir_parent_inode(ni);
+ else
+ dir_ni = (ntfs_inode*)NULL;
+ res = ntfs_xattr_system_getxattr(&security,
+ attr, ni, dir_ni, value, size);
+ if (dir_ni && ntfs_inode_close(dir_ni))
+ set_fuse_error(&res);
if (ntfs_inode_close(ni))
set_fuse_error(&res);
} else
@@ -3016,10 +2939,6 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
res = -EOPNOTSUPP;
goto out;
}
- if (ctx->streams == NF_STREAMS_INTERFACE_NONE) {
- res = -EOPNOTSUPP;
- goto out;
- }
namespace = xattr_namespace(name);
if (namespace == XATTRNS_NONE) {
res = -EOPNOTSUPP;
@@ -3030,7 +2949,7 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
/* trusted only readable by root */
if ((namespace == XATTRNS_TRUSTED)
&& security.uid) {
- res = -EPERM;
+ res = -ENODATA;
goto out;
}
#endif
@@ -3039,9 +2958,13 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
res = -errno;
goto out;
}
+ /* Return with no result for symlinks, fifo, etc. */
+ if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) {
+ res = -ENODATA;
+ goto exit;
+ }
+ /* otherwise file must be readable */
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
- /* file must be readable */
-// condition on fill_security
if (!ntfs_allowed_access(&security, ni, S_IREAD)) {
res = -errno;
goto exit;
@@ -3058,10 +2981,11 @@ static void ntfs_fuse_getxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
goto exit;
}
rsize = na->data_size;
- if (ctx->efs_raw &&
- (na->data_flags & ATTR_IS_ENCRYPTED) &&
- NAttrNonResident(na))
- rsize = ((na->data_size + 511) & ~511)+2;
+ if (ctx->efs_raw
+ && rsize
+ && (na->data_flags & ATTR_IS_ENCRYPTED)
+ && NAttrNonResident(na))
+ rsize = ((na->data_size + 511) & ~511) + 2;
if (size) {
if (size >= (size_t)rsize) {
value = (char*)ntfs_malloc(rsize);
@@ -3091,75 +3015,21 @@ out :
free(value);
}
-static __inline__ int ntfs_system_setxattr(struct SECURITY_CONTEXT *scx,
- int attr, ntfs_inode *ni, const char *value,
- size_t size, int flags)
-{
- int res;
- ntfs_inode *dir_ni;
-
- switch (attr) {
- case XATTR_NTFS_ACL :
- res = ntfs_set_ntfs_acl(scx, ni, value, size, flags);
- break;
-#if POSIXACLS
- case XATTR_POSIX_ACC :
- res = ntfs_set_posix_acl(scx ,ni , nf_ns_xattr_posix_access,
- value, size, flags);
- break;
- case XATTR_POSIX_DEF :
- res = ntfs_set_posix_acl(scx, ni, nf_ns_xattr_posix_default,
- value, size, flags);
- break;
-#endif
- case XATTR_NTFS_ATTRIB :
- res = ntfs_set_ntfs_attrib(ni, value, size, flags);
- break;
- case XATTR_NTFS_EFSINFO :
- if (ctx->efs_raw)
- res = ntfs_set_efs_info(ni, value, size, flags);
- else
- res = -EPERM;
- break;
- case XATTR_NTFS_REPARSE_DATA :
- res = ntfs_set_ntfs_reparse_data(ni, value, size, flags);
- break;
- case XATTR_NTFS_OBJECT_ID :
- res = ntfs_set_ntfs_object_id(ni, value, size, flags);
- break;
- case XATTR_NTFS_DOS_NAME:
- dir_ni = ntfs_dir_parent_inode(ni);
- if (dir_ni)
- /* warning : this closes both inodes */
- res = ntfs_set_ntfs_dos_name(ni, dir_ni, value,
- size, flags);
- else
- res = -errno;
- break;
- case XATTR_NTFS_TIMES:
- res = ntfs_inode_set_times(ni, value, size, flags);
- break;
- default :
- errno = EOPNOTSUPP;
- res = -errno;
- break;
- }
- return (res);
-}
-
static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
const char *value, size_t size, int flags)
{
ntfs_inode *ni;
+ ntfs_inode *dir_ni;
ntfs_attr *na = NULL;
ntfschar *lename = NULL;
int res, lename_len;
- size_t part, total;
- int attr;
+ size_t total;
+ s64 part;
+ enum SYSTEMXATTRS attr;
int namespace;
struct SECURITY_CONTEXT security;
- attr = mapped_xattr_system(name);
+ attr = ntfs_xattr_system_type(name,ctx->vol);
if (attr != XATTR_UNMAPPED) {
/*
* hijack internal data and ACL setting, whatever
@@ -3171,8 +3041,13 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE);
if (ni) {
if (ntfs_allowed_as_owner(&security, ni)) {
- res = ntfs_system_setxattr(&security,
- attr, ni, value, size, flags);
+ if (attr == XATTR_NTFS_DOS_NAME)
+ dir_ni = ntfs_dir_parent_inode(ni);
+ else
+ dir_ni = (ntfs_inode*)NULL;
+ res = ntfs_xattr_system_setxattr(&security,
+ attr, ni, dir_ni, value, size, flags);
+ /* never have to close dir_ni */
if (res)
res = -errno;
} else
@@ -3196,8 +3071,13 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
*/
if (!ntfs_fuse_fill_security_context(req, &security)
|| ntfs_allowed_as_owner(&security, ni)) {
- res = ntfs_system_setxattr(&security,
- attr, ni, value, size, flags);
+ if (attr == XATTR_NTFS_DOS_NAME)
+ dir_ni = ntfs_dir_parent_inode(ni);
+ else
+ dir_ni = (ntfs_inode*)NULL;
+ res = ntfs_xattr_system_setxattr(&security,
+ attr, ni, dir_ni, value, size, flags);
+ /* never have to close dir_ni */
if (res)
res = -errno;
} else
@@ -3208,6 +3088,18 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
} else
res = -errno;
#endif
+#if CACHEING && !defined(FUSE_INTERNAL)
+ /*
+ * Most of system xattr settings cause changes to some
+ * file attribute (st_mode, st_nlink, st_mtime, etc.),
+ * so we must invalidate cached data when cacheing is
+ * in use (not possible with internal fuse or external
+ * fuse before 2.8)
+ */
+ if ((res >= 0)
+ && fuse_lowlevel_notify_inval_inode(ctx->fc, ino, -1, 0))
+ res = -errno;
+#endif
if (res < 0)
fuse_reply_err(req, -res);
else
@@ -3255,15 +3147,29 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
}
break;
default :
+ /* User xattr not allowed for symlinks, fifo, etc. */
+ if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) {
+ res = -EPERM;
+ goto exit;
+ }
if (!ntfs_allowed_access(&security,ni,S_IWRITE)) {
res = -EACCES;
goto exit;
}
break;
}
+#else
+ /* User xattr not allowed for symlinks, fifo, etc. */
+ if ((namespace == XATTRNS_USER)
+ && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) {
+ res = -EPERM;
+ goto exit;
+ }
#endif
lename_len = fix_xattr_prefix(name, namespace, &lename);
- if (lename_len == -1) {
+ if ((lename_len == -1)
+ || (ctx->windows_names
+ && ntfs_forbidden_chars(lename,lename_len))) {
res = -errno;
goto exit;
}
@@ -3298,6 +3204,7 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
}
}
total = 0;
+ res = 0;
if (size) {
do {
part = ntfs_attr_pwrite(na, total, size - total,
@@ -3305,20 +3212,20 @@ static void ntfs_fuse_setxattr(fuse_req_t req, fuse_ino_t ino, const char *name,
if (part > 0)
total += part;
} while ((part > 0) && (total < size));
- if (total != size)
- res = -errno;
- else
- if (!(res = ntfs_attr_pclose(na)))
- if (ctx->efs_raw
- && (ni->flags & FILE_ATTR_ENCRYPTED))
- res = ntfs_efs_fixup_attribute(NULL,
- na);
- if (total && !(ni->flags & FILE_ATTR_ARCHIVE)) {
- set_archive(ni);
- NInoFileNameSetDirty(ni);
+ }
+ if ((total != size) || ntfs_attr_pclose(na))
+ res = -errno;
+ else {
+ if (ctx->efs_raw
+ && (ni->flags & FILE_ATTR_ENCRYPTED)) {
+ if (ntfs_efs_fixup_attribute(NULL,na))
+ res = -errno;
}
- } else
- res = 0;
+ }
+ if (!res && !(ni->flags & FILE_ATTR_ARCHIVE)) {
+ set_archive(ni);
+ NInoFileNameSetDirty(ni);
+ }
exit:
if (na)
ntfs_attr_close(na);
@@ -3332,103 +3239,101 @@ out :
fuse_reply_err(req, 0);
}
-static __inline__ int ntfs_system_removexattr(fuse_req_t req, fuse_ino_t ino,
- int attr)
-{
- int res;
- ntfs_inode *dir_ni;
- ntfs_inode *ni;
- struct SECURITY_CONTEXT security;
-
- res = 0;
- switch (attr) {
- /*
- * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
- * is never allowed
- */
- case XATTR_NTFS_ACL :
- case XATTR_NTFS_ATTRIB :
- case XATTR_NTFS_EFSINFO :
- case XATTR_NTFS_TIMES :
- res = -EPERM;
- break;
-#if POSIXACLS
- case XATTR_POSIX_ACC :
- case XATTR_POSIX_DEF :
- ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE);
- if (ni) {
- if (!ntfs_allowed_as_owner(&security, ni)
- || ntfs_remove_posix_acl(&security, ni,
- (attr == XATTR_POSIX_ACC ?
- nf_ns_xattr_posix_access :
- nf_ns_xattr_posix_default)))
- res = -errno;
- if (ntfs_inode_close(ni))
- set_fuse_error(&res);
- } else
- res = -errno;
- break;
-#endif
- case XATTR_NTFS_REPARSE_DATA :
- ni = ntfs_check_access_xattr(req, &security, ino, attr, TRUE);
- if (ni) {
- if (!ntfs_allowed_as_owner(&security, ni)
- || ntfs_remove_ntfs_reparse_data(ni))
- res = -errno;
- if (ntfs_inode_close(ni))
- set_fuse_error(&res);
- } else
- res = -errno;
- break;
- case XATTR_NTFS_OBJECT_ID :
- ni = ntfs_check_access_xattr(req, &security, ino, attr, TRUE);
- if (ni) {
- if (!ntfs_allowed_as_owner(&security, ni)
- || ntfs_remove_ntfs_object_id(ni))
- res = -errno;
- if (ntfs_inode_close(ni))
- set_fuse_error(&res);
- } else
- res = -errno;
- break;
- case XATTR_NTFS_DOS_NAME:
- ni = ntfs_check_access_xattr(req,&security,ino,attr,TRUE);
- if (ni) {
- dir_ni = ntfs_dir_parent_inode(ni);
- if (!dir_ni
- || ntfs_remove_ntfs_dos_name(ni,dir_ni))
- res = -errno;
- } else
- res = -errno;
- break;
- default :
- errno = EOPNOTSUPP;
- res = -errno;
- break;
- }
- return (res);
-}
-
static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *name)
{
ntfs_inode *ni;
+ ntfs_inode *dir_ni;
ntfschar *lename = NULL;
int res = 0, lename_len;
- int attr;
+ enum SYSTEMXATTRS attr;
int namespace;
-#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
struct SECURITY_CONTEXT security;
-#endif
- attr = mapped_xattr_system(name);
+ attr = ntfs_xattr_system_type(name,ctx->vol);
if (attr != XATTR_UNMAPPED) {
+ switch (attr) {
+ /*
+ * Removal of NTFS ACL, ATTRIB, EFSINFO or TIMES
+ * is never allowed
+ */
+ case XATTR_NTFS_ACL :
+ case XATTR_NTFS_ATTRIB :
+ case XATTR_NTFS_ATTRIB_BE :
+ case XATTR_NTFS_EFSINFO :
+ case XATTR_NTFS_TIMES :
+ case XATTR_NTFS_TIMES_BE :
+ case XATTR_NTFS_CRTIME :
+ case XATTR_NTFS_CRTIME_BE :
+ res = -EPERM;
+ break;
+ default :
+#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
+ ni = ntfs_check_access_xattr(req, &security, ino,
+ attr,TRUE);
+ if (ni) {
+ if (ntfs_allowed_as_owner(&security, ni)) {
+ if (attr == XATTR_NTFS_DOS_NAME)
+ dir_ni = ntfs_dir_parent_inode(ni);
+ else
+ dir_ni = (ntfs_inode*)NULL;
+ res = ntfs_xattr_system_removexattr(&security,
+ attr, ni, dir_ni);
+ if (res)
+ res = -errno;
+ /* never have to close dir_ni */
+ } else
+ res = -errno;
+ if ((attr != XATTR_NTFS_DOS_NAME)
+ && ntfs_inode_close(ni))
+ set_fuse_error(&res);
+ } else
+ res = -errno;
+#else
+ /* creation of a new name is not controlled by fuse */
+ if (attr == XATTR_NTFS_DOS_NAME)
+ ni = ntfs_check_access_xattr(req, &security,
+ ino, attr, TRUE);
+ else
+ ni = ntfs_inode_open(ctx->vol, INODE(ino));
+ if (ni) {
+ /*
+ * user mapping is not mandatory
+ * if defined, only owner is allowed
+ */
+ if (!ntfs_fuse_fill_security_context(req, &security)
+ || ntfs_allowed_as_owner(&security, ni)) {
+ if (attr == XATTR_NTFS_DOS_NAME)
+ dir_ni = ntfs_dir_parent_inode(ni);
+ else
+ dir_ni = (ntfs_inode*)NULL;
+ res = ntfs_xattr_system_removexattr(&security,
+ attr, ni, dir_ni);
+ /* never have to close dir_ni */
+ if (res)
+ res = -errno;
+ } else
+ res = -errno;
+ if ((attr != XATTR_NTFS_DOS_NAME)
+ && ntfs_inode_close(ni))
+ set_fuse_error(&res);
+ } else
+ res = -errno;
+#endif
+#if CACHEING && !defined(FUSE_INTERNAL)
/*
- * hijack internal data and ACL removal, whatever
- * mode was selected for xattr (from the user's
- * point of view, ACLs are not xattr)
- * Note : updating an ACL does not set ctime
+ * Some allowed system xattr removals cause changes to
+ * some file attribute (st_mode, st_nlink, etc.),
+ * so we must invalidate cached data when cacheing is
+ * in use (not possible with internal fuse or external
+ * fuse before 2.8)
*/
- res = ntfs_system_removexattr(req, ino, attr);
+ if ((res >= 0)
+ && fuse_lowlevel_notify_inval_inode(ctx->fc,
+ ino, -1, 0))
+ res = -errno;
+#endif
+ break;
+ }
if (res < 0)
fuse_reply_err(req, -res);
else
@@ -3476,12 +3381,24 @@ static void ntfs_fuse_removexattr(fuse_req_t req, fuse_ino_t ino, const char *na
}
break;
default :
+ /* User xattr not allowed for symlinks, fifo, etc. */
+ if (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT)) {
+ res = -EPERM;
+ goto exit;
+ }
if (!ntfs_allowed_access(&security,ni,S_IWRITE)) {
res = -EACCES;
goto exit;
}
break;
}
+#else
+ /* User xattr not allowed for symlinks, fifo, etc. */
+ if ((namespace == XATTRNS_USER)
+ && (ni->flags & (FILE_ATTR_SYSTEM | FILE_ATTR_REPARSE_POINT))) {
+ res = -EPERM;
+ goto exit;
+ }
#endif
lename_len = fix_xattr_prefix(name, namespace, &lename);
if (lename_len == -1) {
@@ -3567,7 +3484,9 @@ static struct fuse_lowlevel_ops ntfs_3g_ops = {
.read = ntfs_fuse_read,
.write = ntfs_fuse_write,
.setattr = ntfs_fuse_setattr,
+#if HAVE_SYS_STATVFS_H
.statfs = ntfs_fuse_statfs,
+#endif
.create = ntfs_fuse_create_file,
.mknod = ntfs_fuse_mknod,
.symlink = ntfs_fuse_symlink,
@@ -3576,6 +3495,8 @@ static struct fuse_lowlevel_ops ntfs_3g_ops = {
.rename = ntfs_fuse_rename,
.mkdir = ntfs_fuse_mkdir,
.rmdir = ntfs_fuse_rmdir,
+ .fsync = ntfs_fuse_fsync,
+ .fsyncdir = ntfs_fuse_fsync,
.bmap = ntfs_fuse_bmap,
.destroy = ntfs_fuse_destroy2,
#if !KERNELPERMS | (POSIXACLS & !KERNELACLS)
@@ -3594,7 +3515,8 @@ static struct fuse_lowlevel_ops ntfs_3g_ops = {
.setbkuptime = ntfs_macfuse_setbkuptime,
.setchgtime = ntfs_macfuse_setchgtime,
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
-#if defined(FUSE_CAP_DONT_MASK) || (defined(__APPLE__) || defined(__DARWIN__))
+#if defined(FUSE_CAP_DONT_MASK) || defined(FUSE_CAP_BIG_WRITES) \
+ || (defined(__APPLE__) || defined(__DARWIN__))
.init = ntfs_init
#endif
};
@@ -3623,38 +3545,57 @@ static int ntfs_fuse_init(void)
static int ntfs_open(const char *device)
{
unsigned long flags = 0;
+ ntfs_volume *vol;
if (!ctx->blkdev)
- flags |= MS_EXCLUSIVE;
+ flags |= NTFS_MNT_EXCLUSIVE;
if (ctx->ro)
- flags |= MS_RDONLY;
+ flags |= NTFS_MNT_RDONLY;
if (ctx->recover)
- flags |= MS_RECOVER;
+ flags |= NTFS_MNT_RECOVER;
if (ctx->hiberfile)
- flags |= MS_IGNORE_HIBERFILE;
+ flags |= NTFS_MNT_IGNORE_HIBERFILE;
- ctx->vol = ntfs_mount(device, flags);
- if (!ctx->vol) {
+ ctx->vol = vol = ntfs_mount(device, flags);
+ if (!vol) {
ntfs_log_perror("Failed to mount '%s'", device);
goto err_out;
}
+ if (ctx->sync && ctx->vol->dev)
+ NDevSetSync(ctx->vol->dev);
+ if (ctx->compression)
+ NVolSetCompression(ctx->vol);
+ else
+ NVolClearCompression(ctx->vol);
+#ifdef HAVE_SETXATTR
+ /* archivers must see hidden files */
+ if (ctx->efs_raw)
+ ctx->hide_hid_files = FALSE;
+#endif
+ if (ntfs_set_shown_files(ctx->vol, ctx->show_sys_files,
+ !ctx->hide_hid_files, ctx->hide_dot_files))
+ goto err_out;
+
+ if (ctx->ignore_case && ntfs_set_ignore_case(vol))
+ goto err_out;
- ctx->vol->free_clusters = ntfs_attr_get_free_bits(ctx->vol->lcnbmp_na);
- if (ctx->vol->free_clusters < 0) {
+ vol->free_clusters = ntfs_attr_get_free_bits(vol->lcnbmp_na);
+ if (vol->free_clusters < 0) {
ntfs_log_perror("Failed to read NTFS $Bitmap");
goto err_out;
}
- ctx->vol->free_mft_records = ntfs_get_nr_free_mft_records(ctx->vol);
- if (ctx->vol->free_mft_records < 0) {
+ vol->free_mft_records = ntfs_get_nr_free_mft_records(vol);
+ if (vol->free_mft_records < 0) {
ntfs_log_perror("Failed to calculate free MFT records");
goto err_out;
}
- if (ctx->hiberfile && ntfs_volume_check_hiberfile(ctx->vol, 0)) {
+ if (ctx->hiberfile && ntfs_volume_check_hiberfile(vol, 0)) {
if (errno != EPERM)
goto err_out;
- if (ntfs_fuse_rm((fuse_req_t)NULL,FILE_root,"hiberfil.sys"))
+ if (ntfs_fuse_rm((fuse_req_t)NULL,FILE_root,"hiberfil.sys",
+ RM_LINK))
goto err_out;
}
@@ -3664,300 +3605,6 @@ err_out:
}
-#define STRAPPEND_MAX_INSIZE 8192
-#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
-
-static int strappend(char **dest, const char *append)
-{
- char *p;
- size_t size_append, size_dest = 0;
-
- if (!dest)
- return -1;
- if (!append)
- return 0;
-
- size_append = strlen(append);
- if (*dest)
- size_dest = strlen(*dest);
-
- if (strappend_is_large(size_dest) || strappend_is_large(size_append)) {
- errno = EOVERFLOW;
- ntfs_log_perror("%s: Too large input buffer", EXEC_NAME);
- return -1;
- }
-
- p = (char*)realloc(*dest, size_dest + size_append + 1);
- if (!p) {
- ntfs_log_perror("%s: Memory reallocation failed", EXEC_NAME);
- return -1;
- }
-
- *dest = p;
- strcpy(*dest + size_dest, append);
-
- return 0;
-}
-
-static int bogus_option_value(char *val, const char *s)
-{
- if (val) {
- ntfs_log_error("'%s' option shouldn't have value.\n", s);
- return -1;
- }
- return 0;
-}
-
-static int missing_option_value(char *val, const char *s)
-{
- if (!val) {
- ntfs_log_error("'%s' option should have a value.\n", s);
- return -1;
- }
- return 0;
-}
-
-static char *parse_mount_options(const char *orig_opts)
-{
- char *options, *s, *opt, *val, *ret = NULL;
- BOOL no_def_opts = FALSE;
- int default_permissions = 0;
- int want_permissions = 0;
-
- ctx->secure_flags = 0;
-#ifdef HAVE_SETXATTR /* extended attributes interface required */
- ctx->efs_raw = FALSE;
-#endif /* HAVE_SETXATTR */
- options = strdup(orig_opts ? orig_opts : "");
- if (!options) {
- ntfs_log_perror("%s: strdup failed", EXEC_NAME);
- return NULL;
- }
-
- s = options;
- while (s && *s && (val = strsep(&s, ","))) {
- opt = strsep(&val, "=");
- if (!strcmp(opt, "ro")) { /* Read-only mount. */
- if (bogus_option_value(val, "ro"))
- goto err_exit;
- ctx->ro = TRUE;
- if (strappend(&ret, "ro,"))
- goto err_exit;
- } else if (!strcmp(opt, "noatime")) {
- if (bogus_option_value(val, "noatime"))
- goto err_exit;
- ctx->atime = ATIME_DISABLED;
- } else if (!strcmp(opt, "atime")) {
- if (bogus_option_value(val, "atime"))
- goto err_exit;
- ctx->atime = ATIME_ENABLED;
- } else if (!strcmp(opt, "relatime")) {
- if (bogus_option_value(val, "relatime"))
- goto err_exit;
- ctx->atime = ATIME_RELATIVE;
- } else if (!strcmp(opt, "fake_rw")) {
- if (bogus_option_value(val, "fake_rw"))
- goto err_exit;
- ctx->ro = TRUE;
- } else if (!strcmp(opt, "fsname")) { /* Filesystem name. */
- /*
- * We need this to be able to check whether filesystem
- * mounted or not.
- */
- ntfs_log_error("'fsname' is unsupported option.\n");
- goto err_exit;
- } else if (!strcmp(opt, "no_def_opts")) {
- if (bogus_option_value(val, "no_def_opts"))
- goto err_exit;
- no_def_opts = TRUE; /* Don't add default options. */
- } else if (!strcmp(opt, "default_permissions")) {
- default_permissions = 1;
- } else if (!strcmp(opt, "umask")) {
- if (missing_option_value(val, "umask"))
- goto err_exit;
- sscanf(val, "%o", &ctx->fmask);
- ctx->dmask = ctx->fmask;
- want_permissions = 1;
- } else if (!strcmp(opt, "fmask")) {
- if (missing_option_value(val, "fmask"))
- goto err_exit;
- sscanf(val, "%o", &ctx->fmask);
- want_permissions = 1;
- } else if (!strcmp(opt, "dmask")) {
- if (missing_option_value(val, "dmask"))
- goto err_exit;
- sscanf(val, "%o", &ctx->dmask);
- want_permissions = 1;
- } else if (!strcmp(opt, "uid")) {
- if (missing_option_value(val, "uid"))
- goto err_exit;
- sscanf(val, "%i", &ctx->uid);
- want_permissions = 1;
- } else if (!strcmp(opt, "gid")) {
- if (missing_option_value(val, "gid"))
- goto err_exit;
- sscanf(val, "%i", &ctx->gid);
- want_permissions = 1;
- } else if (!strcmp(opt, "show_sys_files")) {
- if (bogus_option_value(val, "show_sys_files"))
- goto err_exit;
- ctx->show_sys_files = TRUE;
- } else if (!strcmp(opt, "silent")) {
- if (bogus_option_value(val, "silent"))
- goto err_exit;
- ctx->silent = TRUE;
- } else if (!strcmp(opt, "recover")) {
- if (bogus_option_value(val, "recover"))
- goto err_exit;
- ctx->recover = TRUE;
- } else if (!strcmp(opt, "norecover")) {
- if (bogus_option_value(val, "norecover"))
- goto err_exit;
- ctx->recover = FALSE;
- } else if (!strcmp(opt, "remove_hiberfile")) {
- if (bogus_option_value(val, "remove_hiberfile"))
- goto err_exit;
- ctx->hiberfile = TRUE;
- } else if (!strcmp(opt, "locale")) {
- if (missing_option_value(val, "locale"))
- goto err_exit;
- ntfs_set_char_encoding(val);
-#if defined(__APPLE__) || defined(__DARWIN__)
-#ifdef ENABLE_NFCONV
- } else if (!strcmp(opt, "nfconv")) {
- if (bogus_option_value(val, "nfconv"))
- goto err_exit;
- if (ntfs_macosx_normalize_filenames(1)) {
- ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n");
- goto err_exit;
- }
- } else if (!strcmp(opt, "nonfconv")) {
- if (bogus_option_value(val, "nonfconv"))
- goto err_exit;
- if (ntfs_macosx_normalize_filenames(0)) {
- ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n");
- goto err_exit;
- }
-#endif /* ENABLE_NFCONV */
-#endif /* defined(__APPLE__) || defined(__DARWIN__) */
- } else if (!strcmp(opt, "streams_interface")) {
- if (missing_option_value(val, "streams_interface"))
- goto err_exit;
- if (!strcmp(val, "none"))
- ctx->streams = NF_STREAMS_INTERFACE_NONE;
- else if (!strcmp(val, "xattr"))
- ctx->streams = NF_STREAMS_INTERFACE_XATTR;
- else if (!strcmp(val, "openxattr"))
- ctx->streams = NF_STREAMS_INTERFACE_OPENXATTR;
- else {
- ntfs_log_error("Invalid named data streams "
- "access interface.\n");
- goto err_exit;
- }
- } else if (!strcmp(opt, "user_xattr")) {
- ctx->streams = NF_STREAMS_INTERFACE_XATTR;
- } else if (!strcmp(opt, "noauto")) {
- /* Don't pass noauto option to fuse. */
- } else if (!strcmp(opt, "debug")) {
- if (bogus_option_value(val, "debug"))
- goto err_exit;
- ctx->debug = TRUE;
- ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
- ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
- } else if (!strcmp(opt, "no_detach")) {
- if (bogus_option_value(val, "no_detach"))
- goto err_exit;
- ctx->no_detach = TRUE;
- } else if (!strcmp(opt, "remount")) {
- ntfs_log_error("Remounting is not supported at present."
- " You have to umount volume and then "
- "mount it once again.\n");
- goto err_exit;
- } else if (!strcmp(opt, "blksize")) {
- ntfs_log_info("WARNING: blksize option is ignored "
- "because ntfs-3g must calculate it.\n");
- } else if (!strcmp(opt, "inherit")) {
- /*
- * JPA do not overwrite inherited permissions
- * in create()
- */
- ctx->inherit = TRUE;
- } else if (!strcmp(opt, "addsecurids")) {
- /*
- * JPA create security ids for files being read
- * with an individual security attribute
- */
- ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS);
- } else if (!strcmp(opt, "staticgrps")) {
- /*
- * JPA use static definition of groups
- * for file access control
- */
- ctx->secure_flags |= (1 << SECURITY_STATICGRPS);
- } else if (!strcmp(opt, "usermapping")) {
- if (!val) {
- ntfs_log_error("'usermapping' option should have "
- "a value.\n");
- goto err_exit;
- }
- ctx->usermap_path = strdup(val);
- if (!ctx->usermap_path) {
- ntfs_log_error("no more memory to store "
- "'usermapping' option.\n");
- goto err_exit;
- }
-#ifdef HAVE_SETXATTR /* extended attributes interface required */
- } else if (!strcmp(opt, "efs_raw")) {
- if (bogus_option_value(val, "efs_raw"))
- goto err_exit;
- ctx->efs_raw = TRUE;
-#endif /* HAVE_SETXATTR */
- } else { /* Probably FUSE option. */
- if (strappend(&ret, opt))
- goto err_exit;
- if (val) {
- if (strappend(&ret, "="))
- goto err_exit;
- if (strappend(&ret, val))
- goto err_exit;
- }
- if (strappend(&ret, ","))
- goto err_exit;
- }
- }
- if (!no_def_opts && strappend(&ret, def_opts))
- goto err_exit;
-#if KERNELPERMS
- if (default_permissions && strappend(&ret, "default_permissions,"))
- goto err_exit;
-#endif
-
- if (ctx->atime == ATIME_RELATIVE && strappend(&ret, "relatime,"))
- goto err_exit;
- else if (ctx->atime == ATIME_ENABLED && strappend(&ret, "atime,"))
- goto err_exit;
- else if (ctx->atime == ATIME_DISABLED && strappend(&ret, "noatime,"))
- goto err_exit;
-
- if (strappend(&ret, "fsname="))
- goto err_exit;
- if (strappend(&ret, opts.device))
- goto err_exit;
- if (default_permissions)
- ctx->secure_flags |= (1 << SECURITY_DEFAULT);
- if (want_permissions)
- ctx->secure_flags |= (1 << SECURITY_WANTED);
- if (ctx->ro)
- ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS);
-exit:
- free(options);
- return ret;
-err_exit:
- free(ret);
- ret = NULL;
- goto exit;
-}
-
static void usage(void)
{
ntfs_log_info(usage_msg, EXEC_NAME, VERSION, FUSE_TYPE, fuse_version(),
@@ -3965,101 +3612,6 @@ static void usage(void)
EXEC_NAME, ntfs_home);
}
-#ifndef HAVE_REALPATH
-/* If there is no realpath() on the system, provide a dummy one. */
-static char *realpath(const char *path, char *resolved_path)
-{
- strncpy(resolved_path, path, PATH_MAX);
- resolved_path[PATH_MAX] = '\0';
- return resolved_path;
-}
-#endif
-
-/**
- * parse_options - Read and validate the programs command line
- * Read the command line, verify the syntax and parse the options.
- *
- * Return: 0 success, -1 error.
- */
-static int parse_options(int argc, char *argv[])
-{
- int c;
-
- static const char *sopt = "-o:hvV";
- static const struct option lopt[] = {
- { "options", required_argument, NULL, 'o' },
- { "help", no_argument, NULL, 'h' },
- { "verbose", no_argument, NULL, 'v' },
- { "version", no_argument, NULL, 'V' },
- { NULL, 0, NULL, 0 }
- };
-
- opterr = 0; /* We'll handle the errors, thank you. */
-
- while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
- switch (c) {
- case 1: /* A non-option argument */
- if (!opts.device) {
- opts.device = (char*)ntfs_malloc(PATH_MAX + 1);
- if (!opts.device)
- return -1;
-
- /* Canonicalize device name (mtab, etc) */
- if (!realpath(optarg, opts.device)) {
- ntfs_log_perror("%s: Failed to access "
- "volume '%s'", EXEC_NAME, optarg);
- free(opts.device);
- opts.device = NULL;
- return -1;
- }
- } else if (!opts.mnt_point) {
- opts.mnt_point = optarg;
- } else {
- ntfs_log_error("%s: You must specify exactly one "
- "device and exactly one mount "
- "point.\n", EXEC_NAME);
- return -1;
- }
- break;
- case 'o':
- if (opts.options)
- if (strappend(&opts.options, ","))
- return -1;
- if (strappend(&opts.options, optarg))
- return -1;
- break;
- case 'h':
- usage();
- exit(9);
- case 'v':
- /*
- * We must handle the 'verbose' option even if
- * we don't use it because mount(8) passes it.
- */
- break;
- case 'V':
- ntfs_log_info("%s %s %s %d\n", EXEC_NAME, VERSION,
- FUSE_TYPE, fuse_version());
- exit(0);
- default:
- ntfs_log_error("%s: Unknown option '%s'.\n", EXEC_NAME,
- argv[optind - 1]);
- return -1;
- }
- }
-
- if (!opts.device) {
- ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
- return -1;
- }
- if (!opts.mnt_point) {
- ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
- return -1;
- }
-
- return 0;
-}
-
#if defined(linux) || defined(__uClinux__)
static const char *dev_fuse_msg =
@@ -4076,7 +3628,7 @@ static const char *fuse26_kmod_msg =
" message to disappear then you should upgrade to at least kernel\n"
" version 2.6.20, or request help from your distribution to fix\n"
" the kernel problem. The below web page has more information:\n"
-" http://ntfs-3g.org/support.html#fuse26\n"
+" http://tuxera.com/community/ntfs-3g-faq/#fuse26\n"
"\n";
static void mknod_dev_fuse(const char *dev)
@@ -4205,7 +3757,7 @@ static int set_fuseblk_options(char **parsed_options)
blksize = pagesize;
snprintf(options, sizeof(options), ",blkdev,blksize=%u", blksize);
- if (strappend(parsed_options, options))
+ if (ntfs_strappend(parsed_options, options))
return -1;
return 0;
}
@@ -4261,6 +3813,9 @@ static void setup_logging(char *parsed_options)
ctx->seccache = (struct PERMISSIONS_CACHE*)NULL;
ntfs_log_info("Version %s %s %d\n", VERSION, FUSE_TYPE, fuse_version());
+ if (strcmp(opts.arg_device,opts.device))
+ ntfs_log_info("Requested device %s canonicalized as %s\n",
+ opts.arg_device,opts.device);
ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS %d.%d)\n",
opts.device, (ctx->ro) ? "Read-Only" : "Read-Write",
ctx->vol->vol_name, ctx->vol->major_ver,
@@ -4278,7 +3833,11 @@ int main(int argc, char *argv[])
#endif
const char *permissions_mode = (const char*)NULL;
const char *failed_secure = (const char*)NULL;
+#if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS)
+ struct XATTRMAPPING *xattr_mapping = (struct XATTRMAPPING*)NULL;
+#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */
struct stat sbuf;
+ unsigned long existing_mount;
int err, fd;
/*
@@ -4303,7 +3862,7 @@ int main(int argc, char *argv[])
ntfs_set_locale();
ntfs_log_set_handler(ntfs_log_handler_stderr);
- if (parse_options(argc, argv)) {
+ if (ntfs_parse_options(&opts, usage, argc, argv)) {
usage();
return NTFS_VOLUME_SYNTAX_ERROR;
}
@@ -4313,12 +3872,19 @@ int main(int argc, char *argv[])
goto err2;
}
- parsed_options = parse_mount_options(opts.options);
+ parsed_options = parse_mount_options(ctx, &opts, TRUE);
if (!parsed_options) {
err = NTFS_VOLUME_SYNTAX_ERROR;
goto err_out;
}
-
+ if (!ntfs_check_if_mounted(opts.device,&existing_mount)
+ && (existing_mount & NTFS_MF_MOUNTED)
+ /* accept multiple read-only mounts */
+ && (!(existing_mount & NTFS_MF_READONLY) || !ctx->ro)) {
+ err = NTFS_VOLUME_LOCKED;
+ goto err_out;
+ }
+
/* need absolute mount point for junctions */
if (opts.mnt_point[0] == '/')
ctx->abs_mnt_point = strdup(opts.mnt_point);
@@ -4329,6 +3895,10 @@ int main(int argc, char *argv[])
PATH_MAX - strlen(opts.mnt_point) - 1)) {
strcat(ctx->abs_mnt_point, "/");
strcat(ctx->abs_mnt_point, opts.mnt_point);
+#if defined(__sun) && defined (__SVR4)
+ /* Solaris also wants the absolute mount point */
+ opts.mnt_point = ctx->abs_mnt_point;
+#endif /* defined(__sun) && defined (__SVR4) */
}
}
}
@@ -4383,6 +3953,12 @@ int main(int argc, char *argv[])
if (err)
goto err_out;
+ /* Force read-only mount if the device was found read-only */
+ if (!ctx->ro && NVolReadOnly(ctx->vol)) {
+ ctx->ro = TRUE;
+ if (ntfs_strinsert(&parsed_options, ",ro"))
+ goto err_out;
+ }
/* We must do this after ntfs_open() to be able to set the blksize */
if (ctx->blkdev && set_fuseblk_options(&parsed_options))
goto err_out;
@@ -4396,14 +3972,18 @@ int main(int argc, char *argv[])
/* to initialize security data */
if (ntfs_open_secure(ctx->vol) && (ctx->vol->major_ver >= 3))
failed_secure = "Could not open file $Secure";
- if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path)) {
+ if (!ntfs_build_mapping(&ctx->security,ctx->usermap_path,
+ (ctx->vol->secure_flags
+ & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL)))
+ && !(ctx->vol->secure_flags & (1 << SECURITY_WANTED)))) {
#if POSIXACLS
+ /* use basic permissions if requested */
if (ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))
permissions_mode = "User mapping built, Posix ACLs not used";
else {
permissions_mode = "User mapping built, Posix ACLs in use";
#if KERNELACLS
- if (strappend(&parsed_options,
+ if (ntfs_strinsert(&parsed_options,
",default_permissions,acl")) {
err = NTFS_VOLUME_SYNTAX_ERROR;
goto err_out;
@@ -4411,14 +3991,15 @@ int main(int argc, char *argv[])
#endif /* KERNELACLS */
}
#else /* POSIXACLS */
- if (!(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) {
+ if (!(ctx->vol->secure_flags
+ & ((1 << SECURITY_DEFAULT) | (1 << SECURITY_ACL)))) {
/*
* No explicit option but user mapping found
* force default security
*/
#if KERNELPERMS
ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
- if (strappend(&parsed_options, ",default_permissions")) {
+ if (ntfs_strinsert(&parsed_options, ",default_permissions")) {
err = NTFS_VOLUME_SYNTAX_ERROR;
goto err_out;
}
@@ -4435,7 +4016,7 @@ int main(int argc, char *argv[])
if ((ctx->vol->secure_flags & (1 << SECURITY_WANTED))
&& !(ctx->vol->secure_flags & (1 << SECURITY_DEFAULT))) {
ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
- if (strappend(&parsed_options, ",default_permissions")) {
+ if (ntfs_strinsert(&parsed_options, ",default_permissions")) {
err = NTFS_VOLUME_SYNTAX_ERROR;
goto err_out;
}
@@ -4451,6 +4032,18 @@ int main(int argc, char *argv[])
if (ctx->usermap_path)
free (ctx->usermap_path);
+#if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS)
+ xattr_mapping = ntfs_xattr_build_mapping(ctx->vol,
+ ctx->xattrmap_path);
+ ctx->vol->xattr_mapping = xattr_mapping;
+ /*
+ * Errors are logged, do not refuse mounting, it would be
+ * too difficult to fix the unmountable mapping file.
+ */
+ if (ctx->xattrmap_path)
+ free(ctx->xattrmap_path);
+#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */
+
se = mount_fuse(parsed_options);
if (!se) {
err = NTFS_VOLUME_FUSE_ERROR;
@@ -4481,6 +4074,9 @@ err_out:
ntfs_mount_error(opts.device, opts.mnt_point, err);
if (ctx->abs_mnt_point)
free(ctx->abs_mnt_point);
+#if defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS)
+ ntfs_xattr_free_mapping(xattr_mapping);
+#endif /* defined(HAVE_SETXATTR) && defined(XATTR_MAPPINGS) */
err2:
ntfs_close();
free(ctx);