Anda di halaman 1dari 13

/**

* ntfs-3g_common.c - Common definitions for ntfs-3g and lowntfs-3g.


*
* Copyright (c) 2010-2015 Jean-Pierre Andre
* Copyright (c) 2010
Erik Larsson
*
* This program/include file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as published
* by the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program/include file is distributed in the hope that it will be
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program (in the main directory of the NTFS-3G
* distribution in the file COPYING); if not, write to the Free Software
* Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#include <getopt.h>
#include <fuse.h>
#include
#include
#include
#include
#include
#include

"inode.h"
"security.h"
"xattrs.h"
"ntfs-3g_common.h"
"realpath.h"
"misc.h"

const char xattr_ntfs_3g[] = "ntfs-3g.";


const
const
const
const
const
const

char nf_ns_user_prefix[] = "user.";


int nf_ns_user_prefix_len = sizeof(nf_ns_user_prefix) - 1;
char nf_ns_system_prefix[] = "system.";
int nf_ns_system_prefix_len = sizeof(nf_ns_system_prefix) - 1;
char nf_ns_security_prefix[] = "security.";
int nf_ns_security_prefix_len = sizeof(nf_ns_security_prefix) - 1;

const char nf_ns_trusted_prefix[] = "trusted.";


const int nf_ns_trusted_prefix_len = sizeof(nf_ns_trusted_prefix) - 1;
static const char nf_ns_alt_xattr_efsinfo[] = "user.ntfs.efsinfo";
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 },
{ "delay_mtime", OPT_DMTIME, FLGOPT_DECIMAL | FLGOPT_OPTIONAL },
{ "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 },
{ "acl", OPT_ACL, 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 },
{ "big_writes", OPT_BIG_WRITES, FLGOPT_BOGUS },
{ "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;
}
/*
*
*
*
*/

Insert an option before ",fsname="


This is for keeping "fsname" as the last option, because on
Solaris device names may contain commas.

int ntfs_strinsert(char **dest, const char *append)


{
char *p, *q;
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*)malloc(size_dest + size_append + 1);
if (!p) {
ntfs_log_perror("%s: Memory reallocation failed", EXEC_NAME);
return -1;
}
strcpy(p, *dest);
q = strstr(p, ",fsname=");
if (q) {
strcpy(q, append);
q = strstr(*dest, ",fsname=");
if (q)
strcat(p, q);
free(*dest);
*dest = p;
} else {
free(*dest);
*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 acl = 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;
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) {
if ((poptl->flags & FLGOPT_OPTIONAL) && !val)
intarg = 0;
else
if (!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_DMTIME :
if (!intarg)
intarg = DEFAULT_DMTIME;
ctx->dmtime = intarg*10000000LL;
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;
#if POSIXACLS
case OPT_ACL :
acl = 1;
break;
#endif
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 o
ption.\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;
#ifdef FUSE_CAP_BIG_WRITES
case OPT_BIG_WRITES :
ctx->big_writes = TRUE;
break;
#endif
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_fi
lenames(1) failed!\n");
goto err_exit;
}
break;
case OPT_NONFCONV :
if (ntfs_macosx_normalize_filenames(0)) {
ntfs_log_error("ntfs_macosx_normalize_fi
lenames(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_XATT
R;
else if (!strcmp(val, "openxattr"))
ctx->streams = NF_STREAMS_INTERFACE_OPEN
XATTR;
else if (!low_fuse && !strcmp(val, "windows"))
ctx->streams = NF_STREAMS_INTERFACE_WIND
OWS;
else {
ntfs_log_error("Invalid named data strea

ms "
"access interface.\n");
goto err_exit;
case
case
case

case
case

}
break;
OPT_USER_XATTR :
ctx->streams = NF_STREAMS_INTERFACE_XATTR;
break;
OPT_NOAUTO :
/* Don't pass noauto option to fuse. */
break;
OPT_DEBUG :
ctx->debug = TRUE;
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
break;
OPT_NO_DETACH :
ctx->no_detach = TRUE;
break;
OPT_REMOUNT :
ntfs_log_error("Remounting is not supported at p

resent."
" 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 ignore
d "
"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;
}

#ifdef HAVE_SETXATTR
#ifdef XATTR_MAPPINGS

break;
/* extended attributes interface required */
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 && !acl))
&& 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 && !acl)
ctx->secure_flags |= (1 << SECURITY_DEFAULT);
if (acl)
ctx->secure_flags |= (1 << SECURITY_ACL);
if (want_permissions)
ctx->secure_flags |= (1 << SECURITY_WANTED);
if (ctx->ro) {
ctx->secure_flags &= ~(1 << SECURITY_ADDSECURIDS);
ctx->hiberfile = FALSE;
}
exit:
free(options);
return ret;
err_exit:
free(ret);
ret = NULL;
goto exit;
}
/**
* 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.
*/
int ntfs_parse_options(struct ntfs_options *popts, void (*usage)(void),
int argc, char *argv[])
{
int c;
static const char *sopt = "-o:hnsvV";
static const struct option lopt[] = {
{ "options",
required_argument,
{ "help",
no_argument,
{ "no-mtab",
no_argument,
{ "verbose",
no_argument,
{ "version",
no_argument,
{ NULL,
0,
};

NULL,
NULL,
NULL,
NULL,
NULL,
NULL,

'o'
'h'
'n'
'v'
'V'
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 (!popts->device) {
popts->device = ntfs_malloc(PATH_MAX + 1);
if (!popts->device)
return -1;
/* Canonicalize device name (mtab, etc) */
popts->arg_device = optarg;
if (!ntfs_realpath_canonicalize(optarg,
popts->device)) {
ntfs_log_perror("%s: Failed to access "
"volume '%s'", EXEC_NAME, optarg);

free(popts->device);
popts->device = NULL;
return -1;
}
} else if (!popts->mnt_point) {
popts->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 (popts->options)
if (ntfs_strappend(&popts->options, ","))
return -1;
if (ntfs_strappend(&popts->options, optarg))
return -1;
break;
case 'h':
usage();
exit(9);
case 'n':
/*
* no effect - automount passes it, meaning 'no-mtab'
*/
break;
case 's':
/*
* no effect - automount passes it, meaning sloppy
*/
break;
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 (!popts->device) {
ntfs_log_error("%s: No device is specified.\n", EXEC_NAME);
return -1;
}
if (!popts->mnt_point) {
ntfs_log_error("%s: No mountpoint is specified.\n", EXEC_NAME);
return -1;
}

return 0;
}
#ifdef HAVE_SETXATTR
int ntfs_fuse_listxattr_common(ntfs_inode *ni, ntfs_attr_search_ctx *actx,
char *list, size_t size, BOOL prefixing)
{
int ret = 0;
char *to = list;
#ifdef XATTR_MAPPINGS
BOOL accepted;
const struct XATTRMAPPING *item;
#endif /* XATTR_MAPPINGS */
/* first list the regular user attributes (ADS) */
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 or system attributes
* (filtered elsewhere anyway)
* otherwise insert "user." prefix
*/
if (prefixing) {
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 (prefixing) {
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);
}
#ifdef XATTR_MAPPINGS
/* now append the system attributes mapped to user space */
for (item=ni->vol->xattr_mapping; item; item=item->next) {
switch (item->xattr) {
case XATTR_NTFS_EFSINFO :
accepted = ni->vol->efs_raw
&& (ni->flags & FILE_ATTR_ENCRYPTED);
break;
case XATTR_NTFS_REPARSE_DATA :
accepted = (ni->flags & FILE_ATTR_REPARSE_POINT)
!= const_cpu_to_le32(0);
break;
// TODO : we are supposed to only return xattrs which are set
// this is more complex for OBJECT_ID and DOS_NAME
default : accepted = TRUE;
break;
}
if (accepted) {
ret += strlen(item->name) + 1;
if (size) {
if ((size_t)ret <= size) {
strcpy(to, item->name);
to += strlen(item->name);
*to++ = 0;
} else {
ret = -ERANGE;
goto exit;
}
}
#else /* XATTR_MAPPINGS */
/* List efs info xattr for encrypted files */
if (ni->vol->efs_raw && (ni->flags & FILE_ATTR_ENCRYPTED)) {
ret += sizeof(nf_ns_alt_xattr_efsinfo);
if ((size_t)ret <= size) {
memcpy(to, nf_ns_alt_xattr_efsinfo,
sizeof(nf_ns_alt_xattr_efsinfo));
to += sizeof(nf_ns_alt_xattr_efsinfo);
#endif /* XATTR_MAPPINGS */
}
}
exit :
return (ret);
}
#endif /* HAVE_SETXATTR */

Anda mungkin juga menyukai