Moved mount options parsing to ntfs-3g_common.c
parent
453a8aa501
commit
3ae68884f7
418
src/lowntfs-3g.c
418
src/lowntfs-3g.c
|
@ -159,12 +159,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;
|
||||
|
@ -189,66 +183,16 @@ 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
|
||||
};
|
||||
|
||||
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 hide_hid_files;
|
||||
BOOL hide_dot_files;
|
||||
BOOL ignore_case;
|
||||
BOOL windows_names;
|
||||
BOOL compression;
|
||||
BOOL silent;
|
||||
BOOL recover;
|
||||
BOOL hiberfile;
|
||||
BOOL sync;
|
||||
BOOL debug;
|
||||
BOOL no_detach;
|
||||
BOOL blkdev;
|
||||
BOOL mounted;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
BOOL efs_raw;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
char *xattrmap_path;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
#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 ntfs_options opts;
|
||||
|
||||
static struct options {
|
||||
char *mnt_point; /* Mount point */
|
||||
char *options; /* Mount options */
|
||||
char *device; /* Device to mount */
|
||||
} opts;
|
||||
const char *EXEC_NAME = "lowntfs-3g";
|
||||
|
||||
static const char *EXEC_NAME = "ntfs-3g";
|
||||
static char def_opts[] = "allow_other,nonempty,";
|
||||
static ntfs_fuse_context_t *ctx;
|
||||
static u32 ntfs_sequence;
|
||||
static const char ghostformat[] = ".ghost-ntfs-3g-%020llu";
|
||||
|
@ -3512,350 +3456,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 permissions = 0;
|
||||
int want_permissions = 0;
|
||||
|
||||
ctx->secure_flags = 0;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
ctx->efs_raw = FALSE;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
ctx->compression = DEFAULT_COMPRESSION;
|
||||
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. */
|
||||
ctx->silent = FALSE; /* cancel default silent */
|
||||
} else if (!strcmp(opt, "default_permissions")) {
|
||||
default_permissions = 1;
|
||||
} else if (!strcmp(opt, "permissions")) {
|
||||
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, "hide_hid_files")) {
|
||||
if (bogus_option_value(val, "hide_hid_files"))
|
||||
goto err_exit;
|
||||
ctx->hide_hid_files = TRUE;
|
||||
} else if (!strcmp(opt, "hide_dot_files")) {
|
||||
if (bogus_option_value(val, "hide_dot_files"))
|
||||
goto err_exit;
|
||||
ctx->hide_dot_files = TRUE;
|
||||
} else if (!strcmp(opt, "ignore_case")) {
|
||||
if (bogus_option_value(val, "ignore_case"))
|
||||
goto err_exit;
|
||||
ctx->ignore_case = TRUE;
|
||||
} else if (!strcmp(opt, "windows_names")) {
|
||||
if (bogus_option_value(val, "windows_names"))
|
||||
goto err_exit;
|
||||
ctx->windows_names = TRUE;
|
||||
} else if (!strcmp(opt, "compression")) {
|
||||
if (bogus_option_value(val, "compression"))
|
||||
goto err_exit;
|
||||
ctx->compression = TRUE;
|
||||
} else if (!strcmp(opt, "nocompression")) {
|
||||
if (bogus_option_value(val, "nocompression"))
|
||||
goto err_exit;
|
||||
ctx->compression = FALSE;
|
||||
} 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, "sync")) {
|
||||
if (bogus_option_value(val, "sync"))
|
||||
goto err_exit;
|
||||
ctx->sync = TRUE;
|
||||
if (strappend(&ret, "sync,"))
|
||||
goto err_exit;
|
||||
} 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 */
|
||||
#ifdef XATTR_MAPPINGS
|
||||
} else if (!strcmp(opt, "xattrmapping")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'xattrmapping' option should have "
|
||||
"a value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->xattrmap_path = strdup(val);
|
||||
if (!ctx->xattrmap_path) {
|
||||
ntfs_log_error("no more memory to store "
|
||||
"'xattrmapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
} 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 || 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 (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(),
|
||||
|
@ -3922,9 +3522,9 @@ static int parse_options(int argc, char *argv[])
|
|||
break;
|
||||
case 'o':
|
||||
if (opts.options)
|
||||
if (strappend(&opts.options, ","))
|
||||
if (ntfs_strappend(&opts.options, ","))
|
||||
return -1;
|
||||
if (strappend(&opts.options, optarg))
|
||||
if (ntfs_strappend(&opts.options, optarg))
|
||||
return -1;
|
||||
break;
|
||||
case 'h':
|
||||
|
@ -4109,7 +3709,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;
|
||||
}
|
||||
|
@ -4221,7 +3821,7 @@ 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;
|
||||
|
@ -4318,7 +3918,7 @@ int main(int argc, char *argv[])
|
|||
else {
|
||||
permissions_mode = "User mapping built, Posix ACLs in use";
|
||||
#if KERNELACLS
|
||||
if (strappend(&parsed_options,
|
||||
if (ntfs_strappend(&parsed_options,
|
||||
",default_permissions,acl")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
|
@ -4333,7 +3933,7 @@ int main(int argc, char *argv[])
|
|||
*/
|
||||
#if KERNELPERMS
|
||||
ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
|
||||
if (strappend(&parsed_options, ",default_permissions")) {
|
||||
if (ntfs_strappend(&parsed_options, ",default_permissions")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
}
|
||||
|
@ -4350,7 +3950,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_strappend(&parsed_options, ",default_permissions")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
}
|
||||
|
|
412
src/ntfs-3g.c
412
src/ntfs-3g.c
|
@ -140,74 +140,20 @@ typedef enum {
|
|||
FSTYPE_FUSEBLK
|
||||
} fuse_fstype;
|
||||
|
||||
typedef enum {
|
||||
ATIME_ENABLED,
|
||||
ATIME_DISABLED,
|
||||
ATIME_RELATIVE
|
||||
} ntfs_atime_t;
|
||||
|
||||
typedef struct {
|
||||
fuse_fill_dir_t filler;
|
||||
void *buf;
|
||||
} ntfs_fuse_fill_context_t;
|
||||
|
||||
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." */
|
||||
NF_STREAMS_INTERFACE_WINDOWS, /* "file:stream" interface. */
|
||||
} ntfs_fuse_streams_interface;
|
||||
|
||||
enum {
|
||||
CLOSE_COMPRESSED = 1,
|
||||
CLOSE_ENCRYPTED = 2
|
||||
};
|
||||
|
||||
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 hide_hid_files;
|
||||
BOOL hide_dot_files;
|
||||
BOOL windows_names;
|
||||
BOOL compression;
|
||||
BOOL silent;
|
||||
BOOL recover;
|
||||
BOOL hiberfile;
|
||||
BOOL sync;
|
||||
BOOL debug;
|
||||
BOOL no_detach;
|
||||
BOOL blkdev;
|
||||
BOOL mounted;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
BOOL efs_raw;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
char *xattrmap_path;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
#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;
|
||||
} ntfs_fuse_context_t;
|
||||
static struct ntfs_options opts;
|
||||
|
||||
static struct options {
|
||||
char *mnt_point; /* Mount point */
|
||||
char *options; /* Mount options */
|
||||
char *device; /* Device to mount */
|
||||
} opts;
|
||||
const char *EXEC_NAME = "ntfs-3g";
|
||||
|
||||
static const char *EXEC_NAME = "ntfs-3g";
|
||||
static char def_opts[] = "allow_other,nonempty,";
|
||||
static ntfs_fuse_context_t *ctx;
|
||||
static u32 ntfs_sequence;
|
||||
|
||||
|
@ -3425,346 +3371,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 = realloc(*dest, size_dest + size_append + 1);
|
||||
if (!p) {
|
||||
ntfs_log_perror("%s: Memory realloction 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 permissions = 0;
|
||||
int want_permissions = 0;
|
||||
|
||||
ctx->secure_flags = 0;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
ctx->efs_raw = FALSE;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
ctx->compression = DEFAULT_COMPRESSION;
|
||||
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. */
|
||||
ctx->silent = FALSE; /* cancel default silent */
|
||||
} else if (!strcmp(opt, "default_permissions")) {
|
||||
default_permissions = 1;
|
||||
} else if (!strcmp(opt, "permissions")) {
|
||||
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, "hide_hid_files")) {
|
||||
if (bogus_option_value(val, "hide_hid_files"))
|
||||
goto err_exit;
|
||||
ctx->hide_hid_files = TRUE;
|
||||
} else if (!strcmp(opt, "hide_dot_files")) {
|
||||
if (bogus_option_value(val, "hide_dot_files"))
|
||||
goto err_exit;
|
||||
ctx->hide_dot_files = TRUE;
|
||||
} else if (!strcmp(opt, "windows_names")) {
|
||||
if (bogus_option_value(val, "windows_names"))
|
||||
goto err_exit;
|
||||
ctx->windows_names = TRUE;
|
||||
} else if (!strcmp(opt, "compression")) {
|
||||
if (bogus_option_value(val, "compression"))
|
||||
goto err_exit;
|
||||
ctx->compression = TRUE;
|
||||
} else if (!strcmp(opt, "nocompression")) {
|
||||
if (bogus_option_value(val, "nocompression"))
|
||||
goto err_exit;
|
||||
ctx->compression = FALSE;
|
||||
} 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, "sync")) {
|
||||
if (bogus_option_value(val, "sync"))
|
||||
goto err_exit;
|
||||
ctx->sync = TRUE;
|
||||
if (strappend(&ret, "sync,"))
|
||||
goto err_exit;
|
||||
} 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 if (!strcmp(val, "windows"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_WINDOWS;
|
||||
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 */
|
||||
#ifdef XATTR_MAPPINGS
|
||||
} else if (!strcmp(opt, "xattrmapping")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'xattrmapping' option should have "
|
||||
"a value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->xattrmap_path = strdup(val);
|
||||
if (!ctx->xattrmap_path) {
|
||||
ntfs_log_error("no more memory to store "
|
||||
"'xattrmapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
} 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 ((default_permissions || permissions)
|
||||
&& strappend(&ret, "default_permissions,"))
|
||||
goto err_exit;
|
||||
|
||||
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 (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(),
|
||||
|
@ -3831,9 +3437,9 @@ static int parse_options(int argc, char *argv[])
|
|||
break;
|
||||
case 'o':
|
||||
if (opts.options)
|
||||
if (strappend(&opts.options, ","))
|
||||
if (ntfs_strappend(&opts.options, ","))
|
||||
return -1;
|
||||
if (strappend(&opts.options, optarg))
|
||||
if (ntfs_strappend(&opts.options, optarg))
|
||||
return -1;
|
||||
break;
|
||||
case 'h':
|
||||
|
@ -4018,7 +3624,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;
|
||||
}
|
||||
|
@ -4135,7 +3741,7 @@ int main(int argc, char *argv[])
|
|||
goto err2;
|
||||
}
|
||||
|
||||
parsed_options = parse_mount_options(opts.options);
|
||||
parsed_options = parse_mount_options(ctx, &opts, FALSE);
|
||||
if (!parsed_options) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
|
@ -4232,7 +3838,7 @@ int main(int argc, char *argv[])
|
|||
else {
|
||||
permissions_mode = "User mapping built, Posix ACLs in use";
|
||||
#if KERNELACLS
|
||||
if (strappend(&parsed_options, ",default_permissions,acl")) {
|
||||
if (ntfs_strappend(&parsed_options, ",default_permissions,acl")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
}
|
||||
|
@ -4246,7 +3852,7 @@ int main(int argc, char *argv[])
|
|||
* force default security
|
||||
*/
|
||||
ctx->vol->secure_flags |= (1 << SECURITY_DEFAULT);
|
||||
if (strappend(&parsed_options, ",default_permissions")) {
|
||||
if (ntfs_strappend(&parsed_options, ",default_permissions")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
}
|
||||
|
@ -4263,7 +3869,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_strappend(&parsed_options, ",default_permissions")) {
|
||||
err = NTFS_VOLUME_SYNTAX_ERROR;
|
||||
goto err_out;
|
||||
}
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
#include "security.h"
|
||||
#include "xattrs.h"
|
||||
#include "ntfs-3g_common.h"
|
||||
#include "misc.h"
|
||||
|
||||
const char xattr_ntfs_3g[] = "ntfs-3g.";
|
||||
|
||||
|
@ -56,6 +57,412 @@ static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo";
|
|||
|
||||
#ifdef HAVE_SETXATTR
|
||||
|
||||
static const char def_opts[] = "allow_other,nonempty,";
|
||||
|
||||
/*
|
||||
* Table of recognized options
|
||||
* Their order may be significant
|
||||
* The options invalid in some configuration should still
|
||||
* be present, so that an error can be returned
|
||||
*/
|
||||
const struct DEFOPTION optionlist[] = {
|
||||
{ "ro", OPT_RO, FLGOPT_APPEND | FLGOPT_BOGUS },
|
||||
{ "noatime", OPT_NOATIME, FLGOPT_BOGUS },
|
||||
{ "atime", OPT_ATIME, FLGOPT_BOGUS },
|
||||
{ "relatime", OPT_RELATIME, FLGOPT_BOGUS },
|
||||
{ "fake_rw", OPT_FAKE_RW, FLGOPT_BOGUS },
|
||||
{ "fsname", OPT_FSNAME, FLGOPT_NOSUPPORT },
|
||||
{ "no_def_opts", OPT_NO_DEF_OPTS, FLGOPT_BOGUS },
|
||||
{ "default_permissions", OPT_DEFAULT_PERMISSIONS, FLGOPT_BOGUS },
|
||||
{ "permissions", OPT_PERMISSIONS, FLGOPT_BOGUS },
|
||||
{ "umask", OPT_UMASK, FLGOPT_OCTAL },
|
||||
{ "fmask", OPT_FMASK, FLGOPT_OCTAL },
|
||||
{ "dmask", OPT_DMASK, FLGOPT_OCTAL },
|
||||
{ "uid", OPT_UID, FLGOPT_DECIMAL },
|
||||
{ "gid", OPT_GID, FLGOPT_DECIMAL },
|
||||
{ "show_sys_files", OPT_SHOW_SYS_FILES, FLGOPT_BOGUS },
|
||||
{ "hide_hid_files", OPT_HIDE_HID_FILES, FLGOPT_BOGUS },
|
||||
{ "hide_dot_files", OPT_HIDE_DOT_FILES, FLGOPT_BOGUS },
|
||||
{ "ignore_case", OPT_IGNORE_CASE, FLGOPT_BOGUS },
|
||||
{ "windows_names", OPT_WINDOWS_NAMES, FLGOPT_BOGUS },
|
||||
{ "compression", OPT_COMPRESSION, FLGOPT_BOGUS },
|
||||
{ "nocompression", OPT_NOCOMPRESSION, FLGOPT_BOGUS },
|
||||
{ "silent", OPT_SILENT, FLGOPT_BOGUS },
|
||||
{ "recover", OPT_RECOVER, FLGOPT_BOGUS },
|
||||
{ "norecover", OPT_NORECOVER, FLGOPT_BOGUS },
|
||||
{ "remove_hiberfile", OPT_REMOVE_HIBERFILE, FLGOPT_BOGUS },
|
||||
{ "sync", OPT_SYNC, FLGOPT_BOGUS | FLGOPT_APPEND },
|
||||
{ "locale", OPT_LOCALE, FLGOPT_STRING },
|
||||
{ "nfconv", OPT_NFCONV, FLGOPT_BOGUS },
|
||||
{ "nonfconv", OPT_NONFCONV, FLGOPT_BOGUS },
|
||||
{ "streams_interface", OPT_STREAMS_INTERFACE, FLGOPT_STRING },
|
||||
{ "user_xattr", OPT_USER_XATTR, FLGOPT_BOGUS },
|
||||
{ "noauto", OPT_NOAUTO, FLGOPT_BOGUS },
|
||||
{ "debug", OPT_DEBUG, FLGOPT_BOGUS },
|
||||
{ "no_detach", OPT_NO_DETACH, FLGOPT_BOGUS },
|
||||
{ "remount", OPT_REMOUNT, FLGOPT_BOGUS },
|
||||
{ "blksize", OPT_BLKSIZE, FLGOPT_STRING },
|
||||
{ "inherit", OPT_INHERIT, FLGOPT_BOGUS },
|
||||
{ "addsecurids", OPT_ADDSECURIDS, FLGOPT_BOGUS },
|
||||
{ "staticgrps", OPT_STATICGRPS, FLGOPT_BOGUS },
|
||||
{ "usermapping", OPT_USERMAPPING, FLGOPT_STRING },
|
||||
{ "xattrmapping", OPT_XATTRMAPPING, FLGOPT_STRING },
|
||||
{ "efs_raw", OPT_EFS_RAW, FLGOPT_BOGUS },
|
||||
{ (const char*)NULL, 0, 0 } /* end marker */
|
||||
} ;
|
||||
|
||||
#define STRAPPEND_MAX_INSIZE 8192
|
||||
#define strappend_is_large(x) ((x) > STRAPPEND_MAX_INSIZE)
|
||||
|
||||
int ntfs_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 realloction 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;
|
||||
}
|
||||
|
||||
char *parse_mount_options(ntfs_fuse_context_t *ctx,
|
||||
const struct ntfs_options *popts, BOOL low_fuse)
|
||||
{
|
||||
char *options, *s, *opt, *val, *ret = NULL;
|
||||
const char *orig_opts = popts->options;
|
||||
BOOL no_def_opts = FALSE;
|
||||
int default_permissions = 0;
|
||||
int permissions = 0;
|
||||
int want_permissions = 0;
|
||||
int intarg;
|
||||
const struct DEFOPTION *poptl;
|
||||
|
||||
ctx->secure_flags = 0;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
ctx->efs_raw = FALSE;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
ctx->compression = DEFAULT_COMPRESSION;
|
||||
ctx->atime = ATIME_ENABLED;
|
||||
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, "=");
|
||||
poptl = optionlist;
|
||||
while (poptl->name && strcmp(poptl->name,opt))
|
||||
poptl++;
|
||||
if (poptl->name) {
|
||||
if ((poptl->flags & FLGOPT_BOGUS)
|
||||
&& bogus_option_value(val, opt))
|
||||
goto err_exit;
|
||||
if ((poptl->flags & FLGOPT_OCTAL)
|
||||
&& (!val
|
||||
|| !sscanf(val, "%o", &intarg))) {
|
||||
ntfs_log_error("'%s' option needs an octal value\n",
|
||||
opt);
|
||||
goto err_exit;
|
||||
}
|
||||
if ((poptl->flags & FLGOPT_DECIMAL)
|
||||
&& (!val
|
||||
|| !sscanf(val, "%i", &intarg))) {
|
||||
ntfs_log_error("'%s' option needs a decimal value\n",
|
||||
opt);
|
||||
goto err_exit;
|
||||
}
|
||||
if ((poptl->flags & FLGOPT_STRING)
|
||||
&& missing_option_value(val, opt))
|
||||
goto err_exit;
|
||||
|
||||
switch (poptl->type) {
|
||||
case OPT_RO :
|
||||
case OPT_FAKE_RW :
|
||||
ctx->ro = TRUE;
|
||||
break;
|
||||
case OPT_NOATIME :
|
||||
ctx->atime = ATIME_DISABLED;
|
||||
break;
|
||||
case OPT_ATIME :
|
||||
ctx->atime = ATIME_ENABLED;
|
||||
break;
|
||||
case OPT_RELATIME :
|
||||
ctx->atime = ATIME_RELATIVE;
|
||||
break;
|
||||
case OPT_NO_DEF_OPTS :
|
||||
no_def_opts = TRUE; /* Don't add default options. */
|
||||
ctx->silent = FALSE; /* cancel default silent */
|
||||
break;
|
||||
case OPT_DEFAULT_PERMISSIONS :
|
||||
default_permissions = 1;
|
||||
break;
|
||||
case OPT_PERMISSIONS :
|
||||
permissions = 1;
|
||||
break;
|
||||
case OPT_UMASK :
|
||||
ctx->dmask = ctx->fmask = intarg;
|
||||
want_permissions = 1;
|
||||
break;
|
||||
case OPT_FMASK :
|
||||
ctx->fmask = intarg;
|
||||
want_permissions = 1;
|
||||
break;
|
||||
case OPT_DMASK :
|
||||
ctx->dmask = intarg;
|
||||
want_permissions = 1;
|
||||
break;
|
||||
case OPT_UID :
|
||||
ctx->uid = intarg;
|
||||
want_permissions = 1;
|
||||
break;
|
||||
case OPT_GID :
|
||||
ctx->gid = intarg;
|
||||
want_permissions = 1;
|
||||
break;
|
||||
case OPT_SHOW_SYS_FILES :
|
||||
ctx->show_sys_files = TRUE;
|
||||
break;
|
||||
case OPT_HIDE_HID_FILES :
|
||||
ctx->hide_hid_files = TRUE;
|
||||
break;
|
||||
case OPT_HIDE_DOT_FILES :
|
||||
ctx->hide_dot_files = TRUE;
|
||||
break;
|
||||
case OPT_WINDOWS_NAMES :
|
||||
ctx->windows_names = TRUE;
|
||||
break;
|
||||
case OPT_IGNORE_CASE :
|
||||
if (low_fuse)
|
||||
ctx->ignore_case = TRUE;
|
||||
else {
|
||||
ntfs_log_error("'%s' is an unsupported option.\n",
|
||||
poptl->name);
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
case OPT_COMPRESSION :
|
||||
ctx->compression = TRUE;
|
||||
break;
|
||||
case OPT_NOCOMPRESSION :
|
||||
ctx->compression = FALSE;
|
||||
break;
|
||||
case OPT_SILENT :
|
||||
ctx->silent = TRUE;
|
||||
break;
|
||||
case OPT_RECOVER :
|
||||
ctx->recover = TRUE;
|
||||
break;
|
||||
case OPT_NORECOVER :
|
||||
ctx->recover = FALSE;
|
||||
break;
|
||||
case OPT_REMOVE_HIBERFILE :
|
||||
ctx->hiberfile = TRUE;
|
||||
break;
|
||||
case OPT_SYNC :
|
||||
ctx->sync = TRUE;
|
||||
break;
|
||||
case OPT_LOCALE :
|
||||
ntfs_set_char_encoding(val);
|
||||
break;
|
||||
#if defined(__APPLE__) || defined(__DARWIN__)
|
||||
#ifdef ENABLE_NFCONV
|
||||
case OPT_NFCONV :
|
||||
if (ntfs_macosx_normalize_filenames(1)) {
|
||||
ntfs_log_error("ntfs_macosx_normalize_filenames(1) failed!\n");
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
case OPT_NONFCONV :
|
||||
if (ntfs_macosx_normalize_filenames(0)) {
|
||||
ntfs_log_error("ntfs_macosx_normalize_filenames(0) failed!\n");
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
#endif /* ENABLE_NFCONV */
|
||||
#endif /* defined(__APPLE__) || defined(__DARWIN__) */
|
||||
case OPT_STREAMS_INTERFACE :
|
||||
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 if (!low_fuse && !strcmp(val, "windows"))
|
||||
ctx->streams = NF_STREAMS_INTERFACE_WINDOWS;
|
||||
else {
|
||||
ntfs_log_error("Invalid named data streams "
|
||||
"access interface.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
case OPT_USER_XATTR :
|
||||
ctx->streams = NF_STREAMS_INTERFACE_XATTR;
|
||||
break;
|
||||
case OPT_NOAUTO :
|
||||
/* Don't pass noauto option to fuse. */
|
||||
break;
|
||||
case OPT_DEBUG :
|
||||
ctx->debug = TRUE;
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
|
||||
break;
|
||||
case OPT_NO_DETACH :
|
||||
ctx->no_detach = TRUE;
|
||||
break;
|
||||
case 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;
|
||||
case OPT_BLKSIZE :
|
||||
ntfs_log_info("WARNING: blksize option is ignored "
|
||||
"because ntfs-3g must calculate it.\n");
|
||||
break;
|
||||
case OPT_INHERIT :
|
||||
/*
|
||||
* do not overwrite inherited permissions
|
||||
* in create()
|
||||
*/
|
||||
ctx->inherit = TRUE;
|
||||
break;
|
||||
case OPT_ADDSECURIDS :
|
||||
/*
|
||||
* create security ids for files being read
|
||||
* with an individual security attribute
|
||||
*/
|
||||
ctx->secure_flags |= (1 << SECURITY_ADDSECURIDS);
|
||||
break;
|
||||
case OPT_STATICGRPS :
|
||||
/*
|
||||
* use static definition of groups
|
||||
* for file access control
|
||||
*/
|
||||
ctx->secure_flags |= (1 << SECURITY_STATICGRPS);
|
||||
break;
|
||||
case OPT_USERMAPPING :
|
||||
ctx->usermap_path = strdup(val);
|
||||
if (!ctx->usermap_path) {
|
||||
ntfs_log_error("no more memory to store "
|
||||
"'usermapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
#ifdef XATTR_MAPPINGS
|
||||
case OPT_XATTRMAPPING :
|
||||
ctx->xattrmap_path = strdup(val);
|
||||
if (!ctx->xattrmap_path) {
|
||||
ntfs_log_error("no more memory to store "
|
||||
"'xattrmapping' option.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
break;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
case OPT_EFS_RAW :
|
||||
ctx->efs_raw = TRUE;
|
||||
break;
|
||||
#endif /* HAVE_SETXATTR */
|
||||
case OPT_FSNAME : /* Filesystem name. */
|
||||
/*
|
||||
* We need this to be able to check whether filesystem
|
||||
* mounted or not.
|
||||
* (falling through to default)
|
||||
*/
|
||||
default :
|
||||
ntfs_log_error("'%s' is an unsupported option.\n",
|
||||
poptl->name);
|
||||
goto err_exit;
|
||||
}
|
||||
if ((poptl->flags & FLGOPT_APPEND)
|
||||
&& (ntfs_strappend(&ret, poptl->name)
|
||||
|| ntfs_strappend(&ret, ",")))
|
||||
goto err_exit;
|
||||
} else { /* Probably FUSE option. */
|
||||
if (ntfs_strappend(&ret, opt))
|
||||
goto err_exit;
|
||||
if (val) {
|
||||
if (ntfs_strappend(&ret, "="))
|
||||
goto err_exit;
|
||||
if (ntfs_strappend(&ret, val))
|
||||
goto err_exit;
|
||||
}
|
||||
if (ntfs_strappend(&ret, ","))
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
if (!no_def_opts && ntfs_strappend(&ret, def_opts))
|
||||
goto err_exit;
|
||||
if ((default_permissions || permissions)
|
||||
&& ntfs_strappend(&ret, "default_permissions,"))
|
||||
goto err_exit;
|
||||
/* The atime options exclude each other */
|
||||
if (ctx->atime == ATIME_RELATIVE && ntfs_strappend(&ret, "relatime,"))
|
||||
goto err_exit;
|
||||
else if (ctx->atime == ATIME_ENABLED && ntfs_strappend(&ret, "atime,"))
|
||||
goto err_exit;
|
||||
else if (ctx->atime == ATIME_DISABLED && ntfs_strappend(&ret, "noatime,"))
|
||||
goto err_exit;
|
||||
|
||||
if (ntfs_strappend(&ret, "fsname="))
|
||||
goto err_exit;
|
||||
if (ntfs_strappend(&ret, popts->device))
|
||||
goto err_exit;
|
||||
if (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;
|
||||
}
|
||||
|
||||
int ntfs_fuse_listxattr_common(ntfs_inode *ni, ntfs_attr_search_ctx *actx,
|
||||
char *list, size_t size, BOOL prefixing)
|
||||
{
|
||||
|
|
|
@ -25,6 +25,128 @@
|
|||
|
||||
#include "inode.h"
|
||||
|
||||
struct ntfs_options {
|
||||
char *mnt_point; /* Mount point */
|
||||
char *options; /* Mount options */
|
||||
char *device; /* Device to mount */
|
||||
} ;
|
||||
|
||||
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." */
|
||||
NF_STREAMS_INTERFACE_WINDOWS, /* "file:stream" interface. */
|
||||
} ntfs_fuse_streams_interface;
|
||||
|
||||
struct DEFOPTION {
|
||||
const char *name;
|
||||
int type;
|
||||
int flags;
|
||||
} ;
|
||||
/* Options, order not significant */
|
||||
enum {
|
||||
OPT_RO,
|
||||
OPT_NOATIME,
|
||||
OPT_ATIME,
|
||||
OPT_RELATIME,
|
||||
OPT_FAKE_RW,
|
||||
OPT_FSNAME,
|
||||
OPT_NO_DEF_OPTS,
|
||||
OPT_DEFAULT_PERMISSIONS,
|
||||
OPT_PERMISSIONS,
|
||||
OPT_UMASK,
|
||||
OPT_FMASK,
|
||||
OPT_DMASK,
|
||||
OPT_UID,
|
||||
OPT_GID,
|
||||
OPT_SHOW_SYS_FILES,
|
||||
OPT_HIDE_HID_FILES,
|
||||
OPT_HIDE_DOT_FILES,
|
||||
OPT_IGNORE_CASE,
|
||||
OPT_WINDOWS_NAMES,
|
||||
OPT_COMPRESSION,
|
||||
OPT_NOCOMPRESSION,
|
||||
OPT_SILENT,
|
||||
OPT_RECOVER,
|
||||
OPT_NORECOVER,
|
||||
OPT_REMOVE_HIBERFILE,
|
||||
OPT_SYNC,
|
||||
OPT_LOCALE,
|
||||
OPT_NFCONV,
|
||||
OPT_NONFCONV,
|
||||
OPT_STREAMS_INTERFACE,
|
||||
OPT_USER_XATTR,
|
||||
OPT_NOAUTO,
|
||||
OPT_DEBUG,
|
||||
OPT_NO_DETACH,
|
||||
OPT_REMOUNT,
|
||||
OPT_BLKSIZE,
|
||||
OPT_INHERIT,
|
||||
OPT_ADDSECURIDS,
|
||||
OPT_STATICGRPS,
|
||||
OPT_USERMAPPING,
|
||||
OPT_XATTRMAPPING,
|
||||
OPT_EFS_RAW,
|
||||
} ;
|
||||
|
||||
/* Option flags */
|
||||
enum {
|
||||
FLGOPT_BOGUS = 1,
|
||||
FLGOPT_STRING = 2,
|
||||
FLGOPT_OCTAL = 4,
|
||||
FLGOPT_DECIMAL = 8,
|
||||
FLGOPT_APPEND = 16,
|
||||
FLGOPT_NOSUPPORT = 32
|
||||
} ;
|
||||
|
||||
typedef enum {
|
||||
ATIME_ENABLED,
|
||||
ATIME_DISABLED,
|
||||
ATIME_RELATIVE
|
||||
} ntfs_atime_t;
|
||||
|
||||
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 hide_hid_files;
|
||||
BOOL hide_dot_files;
|
||||
BOOL windows_names;
|
||||
BOOL ignore_case;
|
||||
BOOL compression;
|
||||
BOOL silent;
|
||||
BOOL recover;
|
||||
BOOL hiberfile;
|
||||
BOOL sync;
|
||||
BOOL debug;
|
||||
BOOL no_detach;
|
||||
BOOL blkdev;
|
||||
BOOL mounted;
|
||||
#ifdef HAVE_SETXATTR /* extended attributes interface required */
|
||||
BOOL efs_raw;
|
||||
#ifdef XATTR_MAPPINGS
|
||||
char *xattrmap_path;
|
||||
#endif /* XATTR_MAPPINGS */
|
||||
#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; /* only defined in lowntfs-3g */
|
||||
u64 latest_ghost;
|
||||
} ntfs_fuse_context_t;
|
||||
|
||||
extern const char *EXEC_NAME;
|
||||
|
||||
extern const char xattr_ntfs_3g[];
|
||||
|
||||
extern const char nf_ns_user_prefix[];
|
||||
|
@ -36,6 +158,10 @@ extern const int nf_ns_security_prefix_len;
|
|||
extern const char nf_ns_trusted_prefix[];
|
||||
extern const int nf_ns_trusted_prefix_len;
|
||||
|
||||
int ntfs_strappend(char **dest, const char *append);
|
||||
char *parse_mount_options(ntfs_fuse_context_t *ctx,
|
||||
const struct ntfs_options *popts, BOOL low_fuse);
|
||||
|
||||
int ntfs_fuse_listxattr_common(ntfs_inode *ni, ntfs_attr_search_ctx *actx,
|
||||
char *list, size_t size, BOOL prefixing);
|
||||
|
||||
|
|
Loading…
Reference in New Issue