2
* Copyright (c) 2008-2010 Alper Akcan <alper.akcan@gmail.com>
3
* Copyright (c) 2009-2010 Renzo Davoli <renzo@cs.unibo.it>
5
* This program is free software; you can redistribute it and/or modify
6
* it under the terms of the GNU General Public License as published by
7
* the Free Software Foundation; either version 2 of the License, or
8
* (at your option) any later version.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program (in the main directory of the fuse-ext2
17
* distribution in the file COPYING); if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21
#include "fuse-ext2.h"
23
FUSE_EXT2_DEFINE_MUTEX;
25
static const char *V2 = "virtualsquare wiki: http://wiki.virtualsquare.org";
26
static const char *HOME = "original fuse-ext2 home: http://sourceforge.net/projects/fuse-ext2/";
29
static char def_opts[] = "allow_other,local,";
30
static char def_opts_rd[] = "noappledouble,";
32
static char def_opts[] = "";
33
static char def_opts_rd[] = "";
36
static const char *usage_msg =
38
"%s %s %d - FUSE EXT2FS Driver\n"
40
"Copyright (C) 2008-2010 Alper Akcan <alper.akcan@gmail.com>\n"
41
"Copyright (C) 2009 Renzo Davoli <renzo@cs.unibo.it>\n"
42
"(The version number is for the VirtualSquare fork only)\n"
44
"Usage: fuse-ext2 <device|image_file> <mount_point> [-o option[,...]]\n"
46
"Options: ro, force, allow_others\n"
47
" Please see details in the manual.\n"
49
"Example: fuse-ext2 /dev/sda1 /mnt/sda1\n"
55
static int strappend (char **dest, const char *append)
67
size = strlen(append) + 1;
69
size += strlen(*dest);
72
p = realloc(*dest, size);
74
debugf_main("Memory realloction failed");
88
static void usage (void)
90
printf(usage_msg, PACKAGE, VERSION, fuse_version(), V2, HOME);
93
static int parse_options (int argc, char *argv[], struct extfs_data *opts)
97
static const char *sopt = "o:hv";
98
static const struct option lopt[] = {
99
{ "options", required_argument, NULL, 'o' },
100
{ "help", no_argument, NULL, 'h' },
101
{ "verbose", no_argument, NULL, 'v' },
106
printf("arguments;\n");
107
for (c = 0; c < argc; c++) {
108
printf("%d: %s\n", c, argv[c]);
113
opterr = 0; /* We'll handle the errors, thank you. */
115
while ((c = getopt_long(argc, argv, sopt, lopt, NULL)) != -1) {
119
if (strappend(&opts->options, ","))
121
if (strappend(&opts->options, optarg))
129
* We must handle the 'verbose' option even if
130
* we don't use it because mount(8) passes it.
135
debugf_main("Unknown option '%s'", argv[optind - 1]);
141
optarg=argv[optind++];
142
if (optarg[0] != '/') {
143
char fulldevice[PATH_MAX+1];
144
if (!realpath(optarg, fulldevice)) {
145
debugf_main("Cannot mount %s", optarg);
150
opts->device = strdup(fulldevice);
152
opts->device = strdup(optarg);
156
opts->mnt_point = argv[optind++];
160
debugf_main("You must specify exactly one device and exactly one mount point");
165
debugf_main("No device is specified");
168
if (!opts->mnt_point) {
169
debugf_main("No mountpoint is specified");
176
static char * parse_mount_options (const char *orig_opts, struct extfs_data *opts)
178
char *options, *s, *opt, *val, *ret;
180
ret = malloc(strlen(def_opts) + strlen(def_opts_rd) + strlen(orig_opts) + 256 + PATH_MAX);
186
options = strdup(orig_opts);
188
debugf_main("strdup failed");
194
val = strsep(&s, ",");
195
opt = strsep(&val, "=");
196
if (!strcmp(opt, "ro")) { /* Read-only mount. */
198
debugf_main("'ro' option should not have value");
202
} else if (!strcmp(opt, "rw")) { /* Read-write mount */
204
debugf_main("'rw' option should not have value");
208
} else if (!strcmp(opt, "rw+")) { /* Read-write mount */
210
debugf_main("'rw+' option should not have value");
215
} else if (!strcmp(opt, "debug")) { /* enable debug */
217
debugf_main("'debug' option should not have value");
221
strcat(ret, "debug,");
222
} else if (!strcmp(opt, "silent")) { /* keep silent */
224
debugf_main("'silent' option should not have value");
228
} else if (!strcmp(opt, "force")) { /* enable read/write */
230
debugf_main("'force option should no have value");
234
#if __FreeBSD__ == 10
235
strcat(ret, "force,");
237
} else { /* Probably FUSE option. */
247
if (opts->readonly == 0 && opts->force == 0) {
248
fprintf(stderr, "Mounting %s Read-Only.\nUse \'force\' or \'rw+\' options to enable Read-Write mode\n",opts->device);
252
strcat(ret, def_opts);
253
if (opts->readonly == 1) {
254
strcat(ret, def_opts_rd);
258
strcat(ret, "fsname=");
259
strcat(ret, opts->device);
260
#if __FreeBSD__ == 10
261
strcat(ret, ",fstypename=");
263
strcat(ret, ",volname=");
264
if (opts->volname == NULL || opts->volname[0] == '\0') {
265
s = strrchr(opts->device, '/');
269
strcat(ret, opts->device);
272
strcat(ret, opts->volname);
284
static const struct fuse_operations ext2fs_ops = {
285
.getattr = op_getattr,
286
.readlink = op_readlink,
291
.symlink = op_symlink,
296
.truncate = op_truncate,
302
.release = op_release,
309
.readdir = op_readdir,
310
.releasedir = op_release,
311
.fsyncdir = op_fsync,
313
.destroy = op_destroy,
316
.ftruncate = op_ftruncate,
317
.fgetattr = op_fgetattr,
319
.utimens = op_utimens,
323
int main (int argc, char *argv[])
327
char *parsed_options = NULL;
328
struct fuse_args fargs = FUSE_ARGS_INIT(0, NULL);
329
struct extfs_data opts;
331
debugf("version:'%s', fuse_version:'%d'", VERSION, fuse_version());
333
memset(&opts, 0, sizeof(opts));
335
if (parse_options(argc, argv, &opts)) {
340
if (stat(opts.device, &sbuf)) {
341
debugf_main("Failed to access '%s'", opts.device);
346
if (do_probe(&opts) != 0) {
347
debugf_main("Probe failed");
352
parsed_options = parse_mount_options(opts.options ? opts.options : "", &opts);
353
if (!parsed_options) {
358
debugf_main("opts.device: %s", opts.device);
359
debugf_main("opts.mnt_point: %s", opts.mnt_point);
360
debugf_main("opts.volname: %s", (opts.volname != NULL) ? opts.volname : "");
361
debugf_main("opts.options: %s", opts.options);
362
debugf_main("parsed_options: %s", parsed_options);
364
if (fuse_opt_add_arg(&fargs, PACKAGE) == -1 ||
365
fuse_opt_add_arg(&fargs, "-s") == -1 ||
366
fuse_opt_add_arg(&fargs, "-o") == -1 ||
367
fuse_opt_add_arg(&fargs, parsed_options) == -1 ||
368
fuse_opt_add_arg(&fargs, opts.mnt_point) == -1) {
369
debugf_main("Failed to set FUSE options");
370
fuse_opt_free_args(&fargs);
375
if (opts.readonly == 0) {
376
debugf_main("mounting read-write");
378
debugf_main("mounting read-only");
381
fuse_main(fargs.argc, fargs.argv, &ext2fs_ops, &opts);
384
fuse_opt_free_args(&fargs);
385
free(parsed_options);