blob: 30958f69f4731254719bc5c7aea03b2517b83515 [file] [log] [blame]
bigbiff bigbiff9c754052013-01-09 09:09:08 -05001/*
2 main.c (01.09.09)
3 FUSE-based exFAT implementation. Requires FUSE 2.6 or later.
4
bigbiff bigbiff61cdc022013-08-08 08:35:06 -04005 Free exFAT implementation.
Matt Mower09ef1e42015-12-13 11:29:45 -06006 Copyright (C) 2010-2015 Andrew Nayenko
bigbiff bigbiff9c754052013-01-09 09:09:08 -05007
bigbiff bigbiff61cdc022013-08-08 08:35:06 -04008 This program is free software; you can redistribute it and/or modify
bigbiff bigbiff9c754052013-01-09 09:09:08 -05009 it under the terms of the GNU General Public License as published by
bigbiff bigbiff61cdc022013-08-08 08:35:06 -040010 the Free Software Foundation, either version 2 of the License, or
bigbiff bigbiff9c754052013-01-09 09:09:08 -050011 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
bigbiff bigbiff61cdc022013-08-08 08:35:06 -040018 You should have received a copy of the GNU General Public License along
19 with this program; if not, write to the Free Software Foundation, Inc.,
20 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
bigbiff bigbiff9c754052013-01-09 09:09:08 -050021*/
22
Matt Mower09ef1e42015-12-13 11:29:45 -060023#include <exfat.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050024#define FUSE_USE_VERSION 26
25#include <fuse.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
bigbiff bigbiff9c754052013-01-09 09:09:08 -050031#include <inttypes.h>
32#include <limits.h>
33#include <sys/types.h>
34#include <pwd.h>
35#include <unistd.h>
36
Matt Mower09ef1e42015-12-13 11:29:45 -060037#ifndef DEBUG
38 #define exfat_debug(format, ...)
39#endif
bigbiff bigbiff9c754052013-01-09 09:09:08 -050040
41#if !defined(FUSE_VERSION) || (FUSE_VERSION < 26)
42 #error FUSE 2.6 or later is required
43#endif
44
bigbiff bigbiff998716f2013-03-07 09:59:37 -050045const char* default_options = "ro_fallback,allow_other,blkdev,big_writes,"
Matt Mower09ef1e42015-12-13 11:29:45 -060046 "default_permissions";
bigbiff bigbiff9c754052013-01-09 09:09:08 -050047
48struct exfat ef;
49
50static struct exfat_node* get_node(const struct fuse_file_info* fi)
51{
52 return (struct exfat_node*) (size_t) fi->fh;
53}
54
55static void set_node(struct fuse_file_info* fi, struct exfat_node* node)
56{
57 fi->fh = (uint64_t) (size_t) node;
Matt Mower09ef1e42015-12-13 11:29:45 -060058 fi->keep_cache = 1;
bigbiff bigbiff9c754052013-01-09 09:09:08 -050059}
60
61static int fuse_exfat_getattr(const char* path, struct stat* stbuf)
62{
63 struct exfat_node* node;
64 int rc;
65
66 exfat_debug("[%s] %s", __func__, path);
67
68 rc = exfat_lookup(&ef, &node, path);
69 if (rc != 0)
70 return rc;
71
72 exfat_stat(&ef, node, stbuf);
73 exfat_put_node(&ef, node);
74 return 0;
75}
76
Spegeliusd69ac2b2014-11-23 15:15:06 +020077static int fuse_exfat_truncate(const char* path, loff_t size)
bigbiff bigbiff9c754052013-01-09 09:09:08 -050078{
79 struct exfat_node* node;
80 int rc;
81
82 exfat_debug("[%s] %s, %"PRId64, __func__, path, size);
83
84 rc = exfat_lookup(&ef, &node, path);
85 if (rc != 0)
86 return rc;
87
bigbiff bigbiff998716f2013-03-07 09:59:37 -050088 rc = exfat_truncate(&ef, node, size, true);
Matt Mower09ef1e42015-12-13 11:29:45 -060089 if (rc != 0)
90 {
91 exfat_flush_node(&ef, node); /* ignore return code */
92 exfat_put_node(&ef, node);
93 return rc;
94 }
95 rc = exfat_flush_node(&ef, node);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050096 exfat_put_node(&ef, node);
97 return rc;
98}
99
100static int fuse_exfat_readdir(const char* path, void* buffer,
Spegeliusd69ac2b2014-11-23 15:15:06 +0200101 fuse_fill_dir_t filler, loff_t offset, struct fuse_file_info* fi)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500102{
103 struct exfat_node* parent;
104 struct exfat_node* node;
105 struct exfat_iterator it;
106 int rc;
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400107 char name[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500108
109 exfat_debug("[%s] %s", __func__, path);
110
111 rc = exfat_lookup(&ef, &parent, path);
112 if (rc != 0)
113 return rc;
114 if (!(parent->flags & EXFAT_ATTRIB_DIR))
115 {
116 exfat_put_node(&ef, parent);
Matt Mower09ef1e42015-12-13 11:29:45 -0600117 exfat_error("'%s' is not a directory (0x%x)", path, parent->flags);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500118 return -ENOTDIR;
119 }
120
121 filler(buffer, ".", NULL, 0);
122 filler(buffer, "..", NULL, 0);
123
124 rc = exfat_opendir(&ef, parent, &it);
125 if (rc != 0)
126 {
127 exfat_put_node(&ef, parent);
Matt Mower09ef1e42015-12-13 11:29:45 -0600128 exfat_error("failed to open directory '%s'", path);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500129 return rc;
130 }
131 while ((node = exfat_readdir(&ef, &it)))
132 {
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400133 exfat_get_name(node, name, sizeof(name) - 1);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500134 exfat_debug("[%s] %s: %s, %"PRId64" bytes, cluster 0x%x", __func__,
135 name, IS_CONTIGUOUS(*node) ? "contiguous" : "fragmented",
136 node->size, node->start_cluster);
137 filler(buffer, name, NULL, 0);
138 exfat_put_node(&ef, node);
139 }
140 exfat_closedir(&ef, &it);
141 exfat_put_node(&ef, parent);
142 return 0;
143}
144
145static int fuse_exfat_open(const char* path, struct fuse_file_info* fi)
146{
147 struct exfat_node* node;
148 int rc;
149
150 exfat_debug("[%s] %s", __func__, path);
151
152 rc = exfat_lookup(&ef, &node, path);
153 if (rc != 0)
154 return rc;
155 set_node(fi, node);
Matt Mower09ef1e42015-12-13 11:29:45 -0600156 return 0;
157}
158
159static int fuse_exfat_create(const char* path, mode_t mode,
160 struct fuse_file_info* fi)
161{
162 struct exfat_node* node;
163 int rc;
164
165 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
166
167 rc = exfat_mknod(&ef, path);
168 if (rc != 0)
169 return rc;
170 rc = exfat_lookup(&ef, &node, path);
171 if (rc != 0)
172 return rc;
173 set_node(fi, node);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500174 return 0;
175}
176
177static int fuse_exfat_release(const char* path, struct fuse_file_info* fi)
178{
Matt Mower09ef1e42015-12-13 11:29:45 -0600179 /*
180 This handler is called by FUSE on close() syscall. If the FUSE
181 implementation does not call flush handler, we will flush node here.
182 But in this case we will not be able to return an error to the caller.
183 See fuse_exfat_flush() below.
184 */
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500185 exfat_debug("[%s] %s", __func__, path);
Matt Mower09ef1e42015-12-13 11:29:45 -0600186 exfat_flush_node(&ef, get_node(fi));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500187 exfat_put_node(&ef, get_node(fi));
Matt Mower09ef1e42015-12-13 11:29:45 -0600188 return 0; /* FUSE ignores this return value */
189}
190
191static int fuse_exfat_flush(const char* path, struct fuse_file_info* fi)
192{
193 /*
194 This handler may be called by FUSE on close() syscall. FUSE also deals
195 with removals of open files, so we don't free clusters on close but
196 only on rmdir and unlink. If the FUSE implementation does not call this
197 handler we will flush node on release. See fuse_exfat_relase() above.
198 */
199 exfat_debug("[%s] %s", __func__, path);
200 return exfat_flush_node(&ef, get_node(fi));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500201}
202
bigbiff bigbiff61cdc022013-08-08 08:35:06 -0400203static int fuse_exfat_fsync(const char* path, int datasync,
204 struct fuse_file_info *fi)
205{
206 int rc;
207
208 exfat_debug("[%s] %s", __func__, path);
Matt Mower09ef1e42015-12-13 11:29:45 -0600209 rc = exfat_flush_nodes(&ef);
bigbiffc40c1c52014-11-01 09:34:57 -0400210 if (rc != 0)
211 return rc;
bigbiff bigbiff61cdc022013-08-08 08:35:06 -0400212 rc = exfat_flush(&ef);
213 if (rc != 0)
214 return rc;
215 return exfat_fsync(ef.dev);
216}
217
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500218static int fuse_exfat_read(const char* path, char* buffer, size_t size,
Spegeliusd69ac2b2014-11-23 15:15:06 +0200219 loff_t offset, struct fuse_file_info* fi)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500220{
Dees_Troyb8fdac72013-01-25 19:42:52 +0000221 ssize_t ret;
222
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500223 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
Dees_Troyb8fdac72013-01-25 19:42:52 +0000224 ret = exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
225 if (ret < 0)
226 return -EIO;
227 return ret;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500228}
229
230static int fuse_exfat_write(const char* path, const char* buffer, size_t size,
Spegeliusd69ac2b2014-11-23 15:15:06 +0200231 loff_t offset, struct fuse_file_info* fi)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500232{
Dees_Troyb8fdac72013-01-25 19:42:52 +0000233 ssize_t ret;
234
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500235 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
Dees_Troyb8fdac72013-01-25 19:42:52 +0000236 ret = exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
237 if (ret < 0)
238 return -EIO;
239 return ret;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500240}
241
242static int fuse_exfat_unlink(const char* path)
243{
244 struct exfat_node* node;
245 int rc;
246
247 exfat_debug("[%s] %s", __func__, path);
248
249 rc = exfat_lookup(&ef, &node, path);
250 if (rc != 0)
251 return rc;
252
253 rc = exfat_unlink(&ef, node);
254 exfat_put_node(&ef, node);
Matt Mower09ef1e42015-12-13 11:29:45 -0600255 if (rc != 0)
256 return rc;
257 return exfat_cleanup_node(&ef, node);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500258}
259
260static int fuse_exfat_rmdir(const char* path)
261{
262 struct exfat_node* node;
263 int rc;
264
265 exfat_debug("[%s] %s", __func__, path);
266
267 rc = exfat_lookup(&ef, &node, path);
268 if (rc != 0)
269 return rc;
270
271 rc = exfat_rmdir(&ef, node);
272 exfat_put_node(&ef, node);
Matt Mower09ef1e42015-12-13 11:29:45 -0600273 if (rc != 0)
274 return rc;
275 return exfat_cleanup_node(&ef, node);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500276}
277
278static int fuse_exfat_mknod(const char* path, mode_t mode, dev_t dev)
279{
280 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
281 return exfat_mknod(&ef, path);
282}
283
284static int fuse_exfat_mkdir(const char* path, mode_t mode)
285{
286 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
287 return exfat_mkdir(&ef, path);
288}
289
290static int fuse_exfat_rename(const char* old_path, const char* new_path)
291{
292 exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
293 return exfat_rename(&ef, old_path, new_path);
294}
295
296static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
297{
298 struct exfat_node* node;
299 int rc;
300
301 exfat_debug("[%s] %s", __func__, path);
302
303 rc = exfat_lookup(&ef, &node, path);
304 if (rc != 0)
305 return rc;
306
307 exfat_utimes(node, tv);
Matt Mower09ef1e42015-12-13 11:29:45 -0600308 rc = exfat_flush_node(&ef, node);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500309 exfat_put_node(&ef, node);
Matt Mower09ef1e42015-12-13 11:29:45 -0600310 return rc;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500311}
312
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500313static int fuse_exfat_chmod(const char* path, mode_t mode)
314{
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400315 const mode_t VALID_MODE_MASK = S_IFREG | S_IFDIR |
316 S_IRWXU | S_IRWXG | S_IRWXO;
317
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500318 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400319 if (mode & ~VALID_MODE_MASK)
320 return -EPERM;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500321 return 0;
322}
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400323
324static int fuse_exfat_chown(const char* path, uid_t uid, gid_t gid)
325{
326 exfat_debug("[%s] %s %u:%u", __func__, path, uid, gid);
327 if (uid != ef.uid || gid != ef.gid)
328 return -EPERM;
329 return 0;
330}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500331
332static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
333{
334 exfat_debug("[%s]", __func__);
335
336 sfs->f_bsize = CLUSTER_SIZE(*ef.sb);
337 sfs->f_frsize = CLUSTER_SIZE(*ef.sb);
338 sfs->f_blocks = le64_to_cpu(ef.sb->sector_count) >> ef.sb->spc_bits;
339 sfs->f_bavail = exfat_count_free_clusters(&ef);
340 sfs->f_bfree = sfs->f_bavail;
341 sfs->f_namemax = EXFAT_NAME_MAX;
342
343 /*
344 Below are fake values because in exFAT there is
345 a) no simple way to count files;
346 b) no such thing as inode;
347 So here we assume that inode = cluster.
348 */
Matt Mower09ef1e42015-12-13 11:29:45 -0600349 sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500350 sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
351 sfs->f_ffree = sfs->f_bavail;
352
353 return 0;
354}
355
356static void* fuse_exfat_init(struct fuse_conn_info* fci)
357{
358 exfat_debug("[%s]", __func__);
359#ifdef FUSE_CAP_BIG_WRITES
360 fci->want |= FUSE_CAP_BIG_WRITES;
361#endif
362 return NULL;
363}
364
365static void fuse_exfat_destroy(void* unused)
366{
367 exfat_debug("[%s]", __func__);
368 exfat_unmount(&ef);
369}
370
371static void usage(const char* prog)
372{
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400373 fprintf(stderr, "Usage: %s [-d] [-o options] [-V] <device> <dir>\n", prog);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500374 exit(1);
375}
376
377static struct fuse_operations fuse_exfat_ops =
378{
379 .getattr = fuse_exfat_getattr,
380 .truncate = fuse_exfat_truncate,
381 .readdir = fuse_exfat_readdir,
382 .open = fuse_exfat_open,
Matt Mower09ef1e42015-12-13 11:29:45 -0600383 .create = fuse_exfat_create,
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500384 .release = fuse_exfat_release,
Matt Mower09ef1e42015-12-13 11:29:45 -0600385 .flush = fuse_exfat_flush,
bigbiff bigbiff61cdc022013-08-08 08:35:06 -0400386 .fsync = fuse_exfat_fsync,
387 .fsyncdir = fuse_exfat_fsync,
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500388 .read = fuse_exfat_read,
389 .write = fuse_exfat_write,
390 .unlink = fuse_exfat_unlink,
391 .rmdir = fuse_exfat_rmdir,
392 .mknod = fuse_exfat_mknod,
393 .mkdir = fuse_exfat_mkdir,
394 .rename = fuse_exfat_rename,
395 .utimens = fuse_exfat_utimens,
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500396 .chmod = fuse_exfat_chmod,
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400397 .chown = fuse_exfat_chown,
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500398 .statfs = fuse_exfat_statfs,
399 .init = fuse_exfat_init,
400 .destroy = fuse_exfat_destroy,
401};
402
403static char* add_option(char* options, const char* name, const char* value)
404{
405 size_t size;
Matt Mower09ef1e42015-12-13 11:29:45 -0600406 char* optionsf = options;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500407
408 if (value)
409 size = strlen(options) + strlen(name) + strlen(value) + 3;
410 else
411 size = strlen(options) + strlen(name) + 2;
412
413 options = realloc(options, size);
414 if (options == NULL)
415 {
Matt Mower09ef1e42015-12-13 11:29:45 -0600416 free(optionsf);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500417 exfat_error("failed to reallocate options string");
418 return NULL;
419 }
420 strcat(options, ",");
421 strcat(options, name);
422 if (value)
423 {
424 strcat(options, "=");
425 strcat(options, value);
426 }
427 return options;
428}
429
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500430static char* add_user_option(char* options)
431{
432 struct passwd* pw;
433
434 if (getuid() == 0)
435 return options;
436
437 pw = getpwuid(getuid());
438 if (pw == NULL || pw->pw_name == NULL)
439 {
440 free(options);
441 exfat_error("failed to determine username");
442 return NULL;
443 }
444 return add_option(options, "user", pw->pw_name);
445}
446
447static char* add_blksize_option(char* options, long cluster_size)
448{
449 long page_size = sysconf(_SC_PAGESIZE);
450 char blksize[20];
451
452 if (page_size < 1)
453 page_size = 0x1000;
454
455 snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
456 return add_option(options, "blksize", blksize);
457}
458
459static char* add_fuse_options(char* options, const char* spec)
460{
bigbiff bigbiff998716f2013-03-07 09:59:37 -0500461 options = add_option(options, "fsname", spec);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500462 if (options == NULL)
463 return NULL;
464 options = add_user_option(options);
465 if (options == NULL)
466 return NULL;
467 options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
468 if (options == NULL)
469 return NULL;
470
471 return options;
472}
473
474int main(int argc, char* argv[])
475{
476 struct fuse_args mount_args = FUSE_ARGS_INIT(0, NULL);
477 struct fuse_args newfs_args = FUSE_ARGS_INIT(0, NULL);
478 const char* spec = NULL;
479 const char* mount_point = NULL;
480 char* mount_options;
481 int debug = 0;
482 struct fuse_chan* fc = NULL;
483 struct fuse* fh = NULL;
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400484 int opt;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500485
Matt Mower09ef1e42015-12-13 11:29:45 -0600486 printf("FUSE exfat %s\n", VERSION);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500487
488 mount_options = strdup(default_options);
489 if (mount_options == NULL)
490 {
491 exfat_error("failed to allocate options string");
492 return 1;
493 }
494
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400495 while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500496 {
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400497 switch (opt)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500498 {
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400499 case 'd':
500 debug = 1;
501 break;
502 case 'n':
503 break;
504 case 'o':
505 mount_options = add_option(mount_options, optarg, NULL);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500506 if (mount_options == NULL)
507 return 1;
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400508 break;
509 case 'V':
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500510 free(mount_options);
Matt Mower09ef1e42015-12-13 11:29:45 -0600511 puts("Copyright (C) 2010-2015 Andrew Nayenko");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500512 return 0;
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400513 case 'v':
514 break;
515 default:
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500516 free(mount_options);
517 usage(argv[0]);
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400518 break;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500519 }
520 }
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400521 if (argc - optind != 2)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500522 {
523 free(mount_options);
524 usage(argv[0]);
525 }
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400526 spec = argv[optind];
527 mount_point = argv[optind + 1];
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500528
529 if (exfat_mount(&ef, spec, mount_options) != 0)
530 {
531 free(mount_options);
532 return 1;
533 }
534
535 if (ef.ro == -1) /* read-only fallback was used */
536 {
537 mount_options = add_option(mount_options, "ro", NULL);
538 if (mount_options == NULL)
539 {
540 exfat_unmount(&ef);
541 return 1;
542 }
543 }
544
545 mount_options = add_fuse_options(mount_options, spec);
546 if (mount_options == NULL)
547 {
548 exfat_unmount(&ef);
549 return 1;
550 }
551
552 /* create arguments for fuse_mount() */
553 if (fuse_opt_add_arg(&mount_args, "exfat") != 0 ||
554 fuse_opt_add_arg(&mount_args, "-o") != 0 ||
555 fuse_opt_add_arg(&mount_args, mount_options) != 0)
556 {
557 exfat_unmount(&ef);
558 free(mount_options);
559 return 1;
560 }
561
562 free(mount_options);
563
564 /* create FUSE mount point */
565 fc = fuse_mount(mount_point, &mount_args);
566 fuse_opt_free_args(&mount_args);
567 if (fc == NULL)
568 {
569 exfat_unmount(&ef);
570 return 1;
571 }
572
573 /* create arguments for fuse_new() */
574 if (fuse_opt_add_arg(&newfs_args, "") != 0 ||
575 (debug && fuse_opt_add_arg(&newfs_args, "-d") != 0))
576 {
577 fuse_unmount(mount_point, fc);
578 exfat_unmount(&ef);
579 return 1;
580 }
581
582 /* create new FUSE file system */
583 fh = fuse_new(fc, &newfs_args, &fuse_exfat_ops,
584 sizeof(struct fuse_operations), NULL);
585 fuse_opt_free_args(&newfs_args);
586 if (fh == NULL)
587 {
588 fuse_unmount(mount_point, fc);
589 exfat_unmount(&ef);
590 return 1;
591 }
592
593 /* exit session on HUP, TERM and INT signals and ignore PIPE signal */
594 if (fuse_set_signal_handlers(fuse_get_session(fh)) != 0)
595 {
596 fuse_unmount(mount_point, fc);
597 fuse_destroy(fh);
598 exfat_unmount(&ef);
599 exfat_error("failed to set signal handlers");
600 return 1;
601 }
602
603 /* go to background (unless "-d" option is passed) and run FUSE
604 main loop */
605 if (fuse_daemonize(debug) == 0)
606 {
607 if (fuse_loop(fh) != 0)
608 exfat_error("FUSE loop failure");
609 }
610 else
611 exfat_error("failed to daemonize");
612
613 fuse_remove_signal_handlers(fuse_get_session(fh));
614 /* note that fuse_unmount() must be called BEFORE fuse_destroy() */
615 fuse_unmount(mount_point, fc);
616 fuse_destroy(fh);
617 return 0;
618}