mirror of
https://git.code.sf.net/p/ntfs-3g/ntfs-3g.git
synced 2024-11-23 18:14:24 +08:00
- upgrade to new shiny fuse option parsing API instead of my old hackish one (more readable and -4kb code)
- remove show_sys_files and add case_insensitive options
This commit is contained in:
parent
f6adc3fc78
commit
197a4cc756
@ -1,4 +1,4 @@
|
||||
xx/12/2006 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista.
|
||||
xx/01/2007 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista.
|
||||
|
||||
- ntfsmount now creates files and directories with security descriptor
|
||||
that grant full access to everyone. (Yura)
|
||||
@ -125,6 +125,10 @@ xx/12/2006 - 2.0.0 - ntfsmount sports full r/w and ntfsresize supports Vista.
|
||||
- mkntfs: Remove own generation of upcase table, i.e. delete
|
||||
ntfsprogs/upcase.[ch] and use ntfs_upcase_table_build() supplied by
|
||||
libntfs. (Anton)
|
||||
- Upgrade ntfsmount to new FUSE option parsing API. (Yura)
|
||||
- ntfsmount: Remove "show_sys_files" as potential harmful and
|
||||
introduce new "case_insensitive" option to support both case
|
||||
sensitive and insensitive mounts. (Yura)
|
||||
|
||||
21/06/2006 - 1.13.1 - Various fixes.
|
||||
|
||||
|
@ -1,10 +1,11 @@
|
||||
/**
|
||||
* ntfsmount - Part of the Linux-NTFS project.
|
||||
*
|
||||
* Copyright (c) 2005-2006 Yura Pakhuchiy
|
||||
* Copyright (c) 2005 Yuval Fledel
|
||||
* Copyright (c) 2005-2007 Yura Pakhuchiy
|
||||
* Copyright (c) 2005 Yuval Fledel
|
||||
* Copyright (c) 2006 Szabolcs Szakacsits
|
||||
*
|
||||
* Userspace NTFS driver.
|
||||
* Userspace read/write NTFS driver.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@ -86,6 +87,9 @@ typedef enum {
|
||||
|
||||
typedef struct {
|
||||
ntfs_volume *vol;
|
||||
char *mnt_point;
|
||||
char *device;
|
||||
char *locale;
|
||||
int state;
|
||||
long free_clusters;
|
||||
long free_mft;
|
||||
@ -95,12 +99,14 @@ typedef struct {
|
||||
unsigned int dmask;
|
||||
ntfs_fuse_streams_interface streams;
|
||||
BOOL ro;
|
||||
BOOL show_sys_files;
|
||||
BOOL silent;
|
||||
BOOL force;
|
||||
BOOL debug;
|
||||
BOOL noatime;
|
||||
BOOL no_detach;
|
||||
BOOL quiet;
|
||||
BOOL verbose;
|
||||
BOOL no_def_opts;
|
||||
BOOL case_insensitive;
|
||||
} ntfs_fuse_context_t;
|
||||
|
||||
typedef enum {
|
||||
@ -110,18 +116,61 @@ typedef enum {
|
||||
free MFT records is outdated. */
|
||||
} ntfs_fuse_state_bits;
|
||||
|
||||
static struct options {
|
||||
char *mnt_point; /* Mount point */
|
||||
char *options; /* Mount options */
|
||||
char *device; /* Device to mount */
|
||||
int quiet; /* Less output */
|
||||
int verbose; /* Extra output */
|
||||
} opts;
|
||||
#define NTFS_FUSE_OPT(t, p) { t, offsetof(ntfs_fuse_context_t, p), TRUE }
|
||||
#define NTFS_FUSE_OPT_NEG(t, p) { t, offsetof(ntfs_fuse_context_t, p), FALSE }
|
||||
#define NTFS_FUSE_OPT_VAL(t, p, v) { t, offsetof(ntfs_fuse_context_t, p), v }
|
||||
|
||||
enum {
|
||||
NF_KEY_HELP,
|
||||
NF_KEY_UMASK,
|
||||
};
|
||||
|
||||
static const struct fuse_opt ntfs_fuse_opts[] = {
|
||||
NTFS_FUSE_OPT("-v", verbose),
|
||||
NTFS_FUSE_OPT("--verbose", verbose),
|
||||
NTFS_FUSE_OPT("-q", quiet),
|
||||
NTFS_FUSE_OPT("--quiet", quiet),
|
||||
NTFS_FUSE_OPT("force", force),
|
||||
NTFS_FUSE_OPT("silent", silent),
|
||||
NTFS_FUSE_OPT("ro", ro),
|
||||
NTFS_FUSE_OPT("fake_rw", ro),
|
||||
NTFS_FUSE_OPT("debug", debug),
|
||||
NTFS_FUSE_OPT("no_detach", no_detach),
|
||||
NTFS_FUSE_OPT("no_def_opts", no_def_opts),
|
||||
NTFS_FUSE_OPT("case_insensitive", case_insensitive),
|
||||
NTFS_FUSE_OPT("fmask=%o", fmask),
|
||||
NTFS_FUSE_OPT("dmask=%o", dmask),
|
||||
NTFS_FUSE_OPT("umask=%o", fmask),
|
||||
NTFS_FUSE_OPT("uid=%d", uid),
|
||||
NTFS_FUSE_OPT("gid=%d", gid),
|
||||
NTFS_FUSE_OPT("locale=%s", locale),
|
||||
NTFS_FUSE_OPT_NEG("nosilent", silent),
|
||||
NTFS_FUSE_OPT_NEG("rw", ro),
|
||||
NTFS_FUSE_OPT_VAL("streams_interface=none", streams,
|
||||
NF_STREAMS_INTERFACE_NONE),
|
||||
NTFS_FUSE_OPT_VAL("streams_interface=windows", streams,
|
||||
NF_STREAMS_INTERFACE_WINDOWS),
|
||||
NTFS_FUSE_OPT_VAL("streams_interface=xattr", streams,
|
||||
NF_STREAMS_INTERFACE_XATTR),
|
||||
FUSE_OPT_KEY("-h", NF_KEY_HELP),
|
||||
FUSE_OPT_KEY("-?", NF_KEY_HELP),
|
||||
FUSE_OPT_KEY("--help", NF_KEY_HELP),
|
||||
FUSE_OPT_KEY("umask=", NF_KEY_UMASK),
|
||||
FUSE_OPT_KEY("noauto", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("fsname=", FUSE_OPT_KEY_DISCARD),
|
||||
FUSE_OPT_KEY("ro", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_KEY("rw", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
static const char *EXEC_NAME = "ntfsmount";
|
||||
static char def_opts[] = "default_permissions,allow_other,";
|
||||
static char ntfs_fuse_default_options[] =
|
||||
"default_permissions,allow_other,use_ino,kernel_cache";
|
||||
static ntfs_fuse_context_t *ctx;
|
||||
|
||||
/**
|
||||
* ntfs_fuse_mark_free_space_outdated - forces free space recalculation
|
||||
*/
|
||||
static __inline__ void ntfs_fuse_mark_free_space_outdated(void)
|
||||
{
|
||||
/* Mark information about free MFT record and clusters outdated. */
|
||||
@ -522,8 +571,7 @@ static int ntfs_fuse_filler(ntfs_fuse_fill_context_t *fill_ctx,
|
||||
free(filename);
|
||||
return 0;
|
||||
}
|
||||
if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user ||
|
||||
ctx->show_sys_files)
|
||||
if (MREF(mref) == FILE_root || MREF(mref) >= FILE_first_user)
|
||||
fill_ctx->filler(fill_ctx->buf, filename, NULL, 0);
|
||||
free(filename);
|
||||
return 0;
|
||||
@ -1390,13 +1438,15 @@ exit:
|
||||
static void ntfs_fuse_destroy(void *priv __attribute__((unused)))
|
||||
{
|
||||
if (ctx->vol) {
|
||||
ntfs_log_info("Unmounting %s (%s)\n", opts.device,
|
||||
ntfs_log_info("Unmounting %s (%s)\n", ctx->device,
|
||||
ctx->vol->vol_name);
|
||||
if (ntfs_umount(ctx->vol, FALSE))
|
||||
ntfs_log_perror("Failed to unmount volume");
|
||||
}
|
||||
free(ctx->device);
|
||||
free(ctx->mnt_point);
|
||||
free(ctx->locale);
|
||||
free(ctx);
|
||||
free(opts.device);
|
||||
}
|
||||
|
||||
static struct fuse_operations ntfs_fuse_oper = {
|
||||
@ -1427,247 +1477,23 @@ static struct fuse_operations ntfs_fuse_oper = {
|
||||
#endif /* HAVE_SETXATTR */
|
||||
};
|
||||
|
||||
static int ntfs_fuse_init(void)
|
||||
{
|
||||
ctx = ntfs_malloc(sizeof(ntfs_fuse_context_t));
|
||||
if (!ctx)
|
||||
return -1;
|
||||
|
||||
*ctx = (ntfs_fuse_context_t) {
|
||||
.state = NF_FreeClustersOutdate | NF_FreeMFTOutdate,
|
||||
.uid = geteuid(),
|
||||
.gid = getegid(),
|
||||
.fmask = 0111,
|
||||
.dmask = 0,
|
||||
.streams = NF_STREAMS_INTERFACE_NONE,
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ntfs_fuse_mount(const char *device)
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
|
||||
vol = utils_mount_volume(device, ((ctx->ro) ? NTFS_MNT_RDONLY : 0) |
|
||||
((ctx->noatime) ? NTFS_MNT_NOATIME : 0) |
|
||||
NTFS_MNT_NOT_EXCLUSIVE /*| NTFS_MNT_CASE_SENSITIVE*/,
|
||||
ctx->force);
|
||||
if (!vol) {
|
||||
ntfs_log_error("Mount failed.\n");
|
||||
return -1;
|
||||
}
|
||||
ctx->vol = vol;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void signal_handler(int arg __attribute__((unused)))
|
||||
{
|
||||
fuse_exit((fuse_get_context())->fuse);
|
||||
}
|
||||
|
||||
static char *parse_mount_options(const char *org_options)
|
||||
{
|
||||
char *options, *s, *opt, *val, *ret;
|
||||
BOOL no_def_opts = FALSE;
|
||||
|
||||
/*
|
||||
* +7 for "fsname=".
|
||||
* +1 for comma.
|
||||
* +1 for null-terminator.
|
||||
* +PATH_MAX for resolved by realpath() device name.
|
||||
*/
|
||||
ret = ntfs_malloc(strlen(def_opts) + strlen(org_options) + PATH_MAX +
|
||||
9);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
*ret = 0;
|
||||
options = strdup(org_options);
|
||||
if (!options) {
|
||||
ntfs_log_perror("strdup failed");
|
||||
return NULL;
|
||||
}
|
||||
s = options;
|
||||
while ((val = strsep(&s, ","))) {
|
||||
opt = strsep(&val, "=");
|
||||
if (!strcmp(opt, "ro")) { /* Read-only mount. */
|
||||
if (val) {
|
||||
ntfs_log_error("'ro' option should not have "
|
||||
"value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->ro = TRUE;
|
||||
strcat(ret, "ro,");
|
||||
} else if (!strcmp(opt, "noatime")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'noatime' option should not "
|
||||
"have value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->noatime = TRUE;
|
||||
strcat(ret, "noatime,"); /* Duplicate it for FUSE. */
|
||||
} else if (!strcmp(opt, "fake_rw")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'fake_rw' option should not "
|
||||
"have value.\n");
|
||||
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 (val) {
|
||||
ntfs_log_error("'no_def_opts' option should "
|
||||
"not have value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
no_def_opts = TRUE; /* Don't add default options. */
|
||||
} else if (!strcmp(opt, "umask")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'umask' option should have "
|
||||
"value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
sscanf(val, "%o", &ctx->fmask);
|
||||
ctx->dmask = ctx->fmask;
|
||||
} else if (!strcmp(opt, "fmask")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'fmask' option should have "
|
||||
"value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
sscanf(val, "%o", &ctx->fmask);
|
||||
} else if (!strcmp(opt, "dmask")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'dmask' option should have "
|
||||
"value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
sscanf(val, "%o", &ctx->dmask);
|
||||
} else if (!strcmp(opt, "uid")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'uid' option should have "
|
||||
"value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
sscanf(val, "%i", &ctx->uid);
|
||||
} else if (!strcmp(opt, "gid")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'gid' option should have "
|
||||
"value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
sscanf(val, "%i", &ctx->gid);
|
||||
} else if (!strcmp(opt, "show_sys_files")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'show_sys_files' option should "
|
||||
"not have value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->show_sys_files = TRUE;
|
||||
} else if (!strcmp(opt, "silent")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'silent' option should "
|
||||
"not have value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->silent = TRUE;
|
||||
} else if (!strcmp(opt, "force")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'force' option should not "
|
||||
"have value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
ctx->force = TRUE;
|
||||
} else if (!strcmp(opt, "locale")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'locale' option should have "
|
||||
"value.\n");
|
||||
goto err_exit;
|
||||
}
|
||||
if (!setlocale(LC_ALL, val))
|
||||
ntfs_log_error("Failed to set locale to %s. "
|
||||
"Continue anyway.\n", val);
|
||||
} else if (!strcmp(opt, "streams_interface")) {
|
||||
if (!val) {
|
||||
ntfs_log_error("'streams_interface' option "
|
||||
"should have value.\n");
|
||||
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, "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, "noauto")) {
|
||||
/* Don't pass noauto option to fuse. */
|
||||
} else if (!strcmp(opt, "debug")) {
|
||||
if (val) {
|
||||
ntfs_log_error("'debug' option should not have "
|
||||
"value.\n");
|
||||
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 (val) {
|
||||
ntfs_log_error("'no_detach' option should not "
|
||||
"have value.\n");
|
||||
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 { /* Probably FUSE option. */
|
||||
strcat(ret, opt);
|
||||
if (val) {
|
||||
strcat(ret, "=");
|
||||
strcat(ret, val);
|
||||
}
|
||||
strcat(ret, ",");
|
||||
}
|
||||
}
|
||||
if (!no_def_opts)
|
||||
strcat(ret, def_opts);
|
||||
strcat(ret, "fsname=");
|
||||
strcat(ret, opts.device);
|
||||
exit:
|
||||
free(options);
|
||||
return ret;
|
||||
err_exit:
|
||||
free(ret);
|
||||
ret = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
static void usage(void)
|
||||
{
|
||||
ntfs_log_info("\n%s v%s (libntfs %s) - NTFS module for FUSE.\n\n",
|
||||
EXEC_NAME, VERSION, ntfs_libntfs_version());
|
||||
ntfs_log_info("Copyright (C) 2005-2006 Yura Pakhuchiy\n\n");
|
||||
ntfs_log_info("\n%s v%s (libntfs %s) - Userspace read/write NTFS "
|
||||
"driver.\n\n", EXEC_NAME, VERSION,
|
||||
ntfs_libntfs_version());
|
||||
ntfs_log_info("Copyright (c) 2005-2007 Yura Pakhuchiy\n");
|
||||
ntfs_log_info("Copyright (c) 2005 Yuval Fledel\n");
|
||||
ntfs_log_info("Copyright (c) 2006 Szabolcs Szakacsits\n\n");
|
||||
ntfs_log_info("usage: %s device mount_point [-o options]\n\n",
|
||||
EXEC_NAME);
|
||||
ntfs_log_info("ntfsmount options are:\n\tforce\n\tno_def_opts\n\tumask"
|
||||
"\n\tfmask\n\tdmask\n\tuid\n\tgid\n\tshow_sys_files\n\t"
|
||||
"silent\n\tlocale\n\tstreams_interface\n"
|
||||
"Also look into FUSE documentation about it options "
|
||||
"(NOTE: not all FUSE options are supported by ntfsmount).\n");
|
||||
ntfs_log_info("Default options are: \"%s\".\n\n", def_opts);
|
||||
ntfs_log_info("Default options:\n\t%s\n\n",
|
||||
ntfs_fuse_default_options);
|
||||
ntfs_log_info("%s%s\n", ntfs_bugs, ntfs_home);
|
||||
}
|
||||
|
||||
@ -1681,178 +1507,178 @@ static char *realpath(const char *path, char *resolved_path)
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* parse_options - Read and validate the programs command line
|
||||
*
|
||||
* Read the command line, verify the syntax and parse the options.
|
||||
* This function is very long, but quite simple.
|
||||
*
|
||||
* Return: 1 Success
|
||||
* 0 Error, one or more problems
|
||||
*/
|
||||
static int parse_options(int argc, char *argv[])
|
||||
static int ntfs_fuse_init(void)
|
||||
{
|
||||
int err = 0, help = 0;
|
||||
int c = -1;
|
||||
|
||||
static const char *sopt = "-o:h?qv";
|
||||
static const struct option lopt[] = {
|
||||
{ "options", required_argument, NULL, 'o' },
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "quiet", no_argument, NULL, 'q' },
|
||||
{ "verbose", no_argument, NULL, 'v' },
|
||||
{ NULL, 0, NULL, 0 }
|
||||
};
|
||||
|
||||
opterr = 0; /* We'll handle the errors, thank you. */
|
||||
|
||||
opts.mnt_point = NULL;
|
||||
opts.options = NULL;
|
||||
opts.device = NULL;
|
||||
|
||||
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
|
||||
switch (c) {
|
||||
case 1: /* A non-option argument */
|
||||
if (!opts.device) {
|
||||
opts.device = malloc(PATH_MAX + 1);
|
||||
if (!opts.device) {
|
||||
ntfs_log_perror("malloc");
|
||||
err++;
|
||||
break;
|
||||
}
|
||||
/* We don't want relative path in /etc/mtab. */
|
||||
if (optarg[0] != '/') {
|
||||
if (!realpath(optarg, opts.device)) {
|
||||
ntfs_log_perror("Failed to "
|
||||
"access %s",
|
||||
optarg);
|
||||
free(opts.device);
|
||||
opts.device = NULL;
|
||||
err++;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
strcpy(opts.device, optarg);
|
||||
} else if (!opts.mnt_point)
|
||||
opts.mnt_point = optarg;
|
||||
else {
|
||||
ntfs_log_error("You must specify exactly one "
|
||||
"device and exactly one mount "
|
||||
"point.\n");
|
||||
err++;
|
||||
}
|
||||
break;
|
||||
case 'o':
|
||||
if (!opts.options)
|
||||
opts.options = optarg;
|
||||
else {
|
||||
ntfs_log_error("You must specify exactly one "
|
||||
"set of options.\n");
|
||||
err++;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
case '?':
|
||||
help++;
|
||||
break;
|
||||
case 'q':
|
||||
opts.quiet++;
|
||||
break;
|
||||
case 'v':
|
||||
opts.verbose++;
|
||||
break;
|
||||
default:
|
||||
ntfs_log_error("Unknown option '%s'.\n", optarg);
|
||||
err++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (help) {
|
||||
opts.quiet = 0;
|
||||
} else {
|
||||
if (!opts.device) {
|
||||
ntfs_log_error("No device specified.\n");
|
||||
err++;
|
||||
}
|
||||
|
||||
if (opts.quiet && opts.verbose) {
|
||||
ntfs_log_error("You may not use --quiet and --verbose "
|
||||
"at the same time.\n");
|
||||
err++;
|
||||
}
|
||||
}
|
||||
|
||||
if (help || err)
|
||||
usage();
|
||||
|
||||
return (!help && !err);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *parsed_options;
|
||||
struct fuse_args margs = FUSE_ARGS_INIT(0, NULL);
|
||||
struct fuse *fh;
|
||||
struct fuse_chan *fch;
|
||||
|
||||
utils_set_locale();
|
||||
ntfs_log_set_handler(ntfs_log_handler_stderr);
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
||||
if (!parse_options(argc, argv))
|
||||
return 1;
|
||||
ctx = ntfs_malloc(sizeof(ntfs_fuse_context_t));
|
||||
if (!ctx)
|
||||
return -1;
|
||||
|
||||
*ctx = (ntfs_fuse_context_t) {
|
||||
.state = NF_FreeClustersOutdate | NF_FreeMFTOutdate,
|
||||
.uid = geteuid(),
|
||||
.gid = getegid(),
|
||||
.fmask = 0111,
|
||||
.dmask = 0,
|
||||
.streams = NF_STREAMS_INTERFACE_NONE,
|
||||
.silent = TRUE,
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ntfs_fuse_opt_proc(void *data __attribute__((unused)),
|
||||
const char *arg, int key, struct fuse_args *outargs)
|
||||
{
|
||||
switch (key) {
|
||||
case NF_KEY_HELP:
|
||||
return -1; /* Force usage show. */
|
||||
case NF_KEY_UMASK:
|
||||
ctx->dmask = ctx->fmask;
|
||||
return 0;
|
||||
case FUSE_OPT_KEY_NONOPT: /* All non-option arguments go here. */
|
||||
if (!ctx->device) {
|
||||
/* We don't want relative path in /etc/mtab. */
|
||||
if (arg[0] != '/') {
|
||||
ctx->device = ntfs_malloc(PATH_MAX + 1);
|
||||
if (!ctx->device)
|
||||
return -1;
|
||||
if (!realpath(arg, ctx->device)) {
|
||||
ntfs_log_perror("realpath(): %s", arg);
|
||||
free(ctx->device);
|
||||
ctx->device = NULL;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
ctx->device = strdup(arg);
|
||||
if (!ctx->device) {
|
||||
ntfs_log_perror("strdup()");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (!ctx->mnt_point) {
|
||||
ctx->mnt_point = strdup(arg);
|
||||
if (!ctx->mnt_point) {
|
||||
ntfs_log_perror("strdup()");
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
ntfs_log_error("You must specify exactly one device and "
|
||||
"exactly one mount point.\n");
|
||||
return -1;
|
||||
default:
|
||||
if (!strcmp(arg, "remount")) {
|
||||
ntfs_log_error("Remounting is not supported yet. "
|
||||
"You have to umount volume and then "
|
||||
"mount it once again.\n");
|
||||
return -1;
|
||||
}
|
||||
return 1; /* Just pass all unknown to us options to FUSE. */
|
||||
}
|
||||
}
|
||||
|
||||
static int parse_options(struct fuse_args *args)
|
||||
{
|
||||
int ret;
|
||||
char *fsname;
|
||||
|
||||
ret = fuse_opt_parse(args, ctx, ntfs_fuse_opts, ntfs_fuse_opt_proc);
|
||||
if (!ctx->device) {
|
||||
ntfs_log_error("No device specified.\n");
|
||||
return -1;
|
||||
}
|
||||
if (ctx->quiet && ctx->verbose) {
|
||||
ntfs_log_error("You may not use --quiet and --verbose at the "
|
||||
"same time.\n");
|
||||
return -1;
|
||||
}
|
||||
if (ctx->debug) {
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_DEBUG);
|
||||
ntfs_log_set_levels(NTFS_LOG_LEVEL_TRACE);
|
||||
}
|
||||
if (ctx->locale && !setlocale(LC_ALL, ctx->locale))
|
||||
ntfs_log_error("Failed to set locale to %s "
|
||||
"(continue anyway).\n", ctx->locale);
|
||||
fsname = ntfs_malloc(strlen(ctx->device) + 64);
|
||||
if (!fsname)
|
||||
return -1;
|
||||
sprintf(fsname, "-ofsname=%s", ctx->device);
|
||||
if (fuse_opt_add_arg(args, fsname) == -1) {
|
||||
free(fsname);
|
||||
return -1;
|
||||
}
|
||||
free(fsname);
|
||||
if (!ctx->no_def_opts) {
|
||||
if (fuse_opt_add_arg(args, "-o") == -1)
|
||||
return -1;
|
||||
if (fuse_opt_add_arg(args, ntfs_fuse_default_options) == -1)
|
||||
return -1;
|
||||
}
|
||||
if (ctx->debug || ctx->no_detach) {
|
||||
if (fuse_opt_add_arg(args, "-odebug") == -1)
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ntfs_fuse_mount(void)
|
||||
{
|
||||
ntfs_volume *vol;
|
||||
|
||||
vol = utils_mount_volume(ctx->device, NTFS_MNT_NOATIME |
|
||||
((ctx->ro) ? NTFS_MNT_RDONLY : 0) |
|
||||
((ctx->case_insensitive) ? 0 :
|
||||
NTFS_MNT_CASE_SENSITIVE) |
|
||||
NTFS_MNT_NOT_EXCLUSIVE /* FIXME */, ctx->force);
|
||||
if (!vol) {
|
||||
ntfs_log_error("Mount failed.\n");
|
||||
return -1;
|
||||
}
|
||||
ctx->vol = vol;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
struct fuse_args args = FUSE_ARGS_INIT(argc, argv);
|
||||
struct fuse *fh;
|
||||
struct fuse_chan *fch;
|
||||
|
||||
ntfs_fuse_init();
|
||||
/* Parse options. */
|
||||
parsed_options = parse_mount_options((opts.options) ?
|
||||
opts.options : "");
|
||||
if (!parsed_options) {
|
||||
if (parse_options(&args) == -1) {
|
||||
usage();
|
||||
fuse_opt_free_args(&args);
|
||||
ntfs_fuse_destroy(NULL);
|
||||
return 3;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Mount volume. */
|
||||
if (ntfs_fuse_mount(opts.device)) {
|
||||
/* Mount volume (libntfs part). */
|
||||
if (ntfs_fuse_mount()) {
|
||||
fuse_opt_free_args(&args);
|
||||
ntfs_fuse_destroy(NULL);
|
||||
free(parsed_options);
|
||||
return 4;
|
||||
return 1;
|
||||
}
|
||||
/* Create filesystem. */
|
||||
fch = NULL;
|
||||
if (!(fuse_opt_add_arg(&margs, "") == -1 ||
|
||||
fuse_opt_add_arg(&margs, "-o") == -1 ||
|
||||
fuse_opt_add_arg(&margs, parsed_options)))
|
||||
fch = fuse_mount(opts.mnt_point, &margs);
|
||||
fuse_opt_free_args(&margs);
|
||||
free(parsed_options);
|
||||
/* Create filesystem (FUSE part). */
|
||||
fch = fuse_mount(ctx->mnt_point, &args);
|
||||
if (!fch) {
|
||||
ntfs_log_error("fuse_mount failed.\n");
|
||||
fuse_opt_free_args(&args);
|
||||
ntfs_fuse_destroy(NULL);
|
||||
return 5;
|
||||
return 1;
|
||||
}
|
||||
fh = (struct fuse *)1; /* Cast anything except NULL to handle errors. */
|
||||
margs = (struct fuse_args)FUSE_ARGS_INIT(0, NULL);
|
||||
if (fuse_opt_add_arg(&margs, "") == -1 ||
|
||||
fuse_opt_add_arg(&margs, "-o") == -1)
|
||||
fh = NULL;
|
||||
if (!ctx->debug && !ctx->no_detach) {
|
||||
if (fuse_opt_add_arg(&margs, "use_ino,kernel_cache") == -1)
|
||||
fh = NULL;
|
||||
} else {
|
||||
if (fuse_opt_add_arg(&margs, "use_ino,debug") == -1)
|
||||
fh = NULL;
|
||||
}
|
||||
if (fh)
|
||||
fh = fuse_new(fch, &margs , &ntfs_fuse_oper,
|
||||
sizeof(ntfs_fuse_oper), NULL);
|
||||
fuse_opt_free_args(&margs);
|
||||
fh = fuse_new(fch, &args , &ntfs_fuse_oper, sizeof(ntfs_fuse_oper),
|
||||
NULL);
|
||||
fuse_opt_free_args(&args);
|
||||
if (!fh) {
|
||||
ntfs_log_error("fuse_new failed.\n");
|
||||
fuse_unmount(opts.mnt_point, fch);
|
||||
fuse_unmount(ctx->mnt_point, fch);
|
||||
ntfs_fuse_destroy(NULL);
|
||||
return 6;
|
||||
return 1;
|
||||
}
|
||||
if (!ctx->debug && !ctx->no_detach) {
|
||||
if (daemon(0, 0))
|
||||
@ -1866,13 +1692,13 @@ int main(int argc, char *argv[])
|
||||
ntfs_log_info("Version %s (libntfs %s)\n", VERSION,
|
||||
ntfs_libntfs_version());
|
||||
ntfs_log_info("Mounted %s (%s, label \"%s\", NTFS version %d.%d)\n",
|
||||
opts.device, (ctx->ro) ? "Read-Only" : "Read-Write",
|
||||
ctx->device, (ctx->ro) ? "Read-Only" : "Read-Write",
|
||||
ctx->vol->vol_name, ctx->vol->major_ver,
|
||||
ctx->vol->minor_ver);
|
||||
/* Main loop. */
|
||||
fuse_loop(fh);
|
||||
/* Destroy. */
|
||||
fuse_unmount(opts.mnt_point, fch);
|
||||
fuse_unmount(ctx->mnt_point, fch);
|
||||
fuse_destroy(fh);
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user