blob: 30ea4bcb237b36f42749940abda9d7a377c81b0e [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.
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -04006 Copyright (C) 2010-2014 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
23#define FUSE_USE_VERSION 26
24#include <fuse.h>
25#include <errno.h>
26#include <fcntl.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <exfat.h>
31#include <inttypes.h>
32#include <limits.h>
33#include <sys/types.h>
34#include <pwd.h>
35#include <unistd.h>
36
37#define exfat_debug(format, ...)
38
39#if !defined(FUSE_VERSION) || (FUSE_VERSION < 26)
40 #error FUSE 2.6 or later is required
41#endif
42
bigbiff bigbiff998716f2013-03-07 09:59:37 -050043const char* default_options = "ro_fallback,allow_other,blkdev,big_writes,"
44 "defer_permissions";
bigbiff bigbiff9c754052013-01-09 09:09:08 -050045
46struct exfat ef;
47
48static struct exfat_node* get_node(const struct fuse_file_info* fi)
49{
50 return (struct exfat_node*) (size_t) fi->fh;
51}
52
53static void set_node(struct fuse_file_info* fi, struct exfat_node* node)
54{
55 fi->fh = (uint64_t) (size_t) node;
56}
57
58static int fuse_exfat_getattr(const char* path, struct stat* stbuf)
59{
60 struct exfat_node* node;
61 int rc;
62
63 exfat_debug("[%s] %s", __func__, path);
64
65 rc = exfat_lookup(&ef, &node, path);
66 if (rc != 0)
67 return rc;
68
69 exfat_stat(&ef, node, stbuf);
70 exfat_put_node(&ef, node);
71 return 0;
72}
73
74static int fuse_exfat_truncate(const char* path, off64_t size)
75{
76 struct exfat_node* node;
77 int rc;
78
79 exfat_debug("[%s] %s, %"PRId64, __func__, path, size);
80
81 rc = exfat_lookup(&ef, &node, path);
82 if (rc != 0)
83 return rc;
84
bigbiff bigbiff998716f2013-03-07 09:59:37 -050085 rc = exfat_truncate(&ef, node, size, true);
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -040086 if (rc != 0)
87 {
88 exfat_flush_node(&ef, node); /* ignore return code */
89 exfat_put_node(&ef, node);
90 return rc;
91 }
92 rc = exfat_flush_node(&ef, node);
bigbiff bigbiff9c754052013-01-09 09:09:08 -050093 exfat_put_node(&ef, node);
94 return rc;
95}
96
97static int fuse_exfat_readdir(const char* path, void* buffer,
98 fuse_fill_dir_t filler, off64_t offset, struct fuse_file_info* fi)
99{
100 struct exfat_node* parent;
101 struct exfat_node* node;
102 struct exfat_iterator it;
103 int rc;
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400104 char name[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500105
106 exfat_debug("[%s] %s", __func__, path);
107
108 rc = exfat_lookup(&ef, &parent, path);
109 if (rc != 0)
110 return rc;
111 if (!(parent->flags & EXFAT_ATTRIB_DIR))
112 {
113 exfat_put_node(&ef, parent);
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400114 exfat_error("'%s' is not a directory (0x%x)", path, parent->flags);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500115 return -ENOTDIR;
116 }
117
118 filler(buffer, ".", NULL, 0);
119 filler(buffer, "..", NULL, 0);
120
121 rc = exfat_opendir(&ef, parent, &it);
122 if (rc != 0)
123 {
124 exfat_put_node(&ef, parent);
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400125 exfat_error("failed to open directory '%s'", path);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500126 return rc;
127 }
128 while ((node = exfat_readdir(&ef, &it)))
129 {
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400130 exfat_get_name(node, name, sizeof(name) - 1);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500131 exfat_debug("[%s] %s: %s, %"PRId64" bytes, cluster 0x%x", __func__,
132 name, IS_CONTIGUOUS(*node) ? "contiguous" : "fragmented",
133 node->size, node->start_cluster);
134 filler(buffer, name, NULL, 0);
135 exfat_put_node(&ef, node);
136 }
137 exfat_closedir(&ef, &it);
138 exfat_put_node(&ef, parent);
139 return 0;
140}
141
142static int fuse_exfat_open(const char* path, struct fuse_file_info* fi)
143{
144 struct exfat_node* node;
145 int rc;
146
147 exfat_debug("[%s] %s", __func__, path);
148
149 rc = exfat_lookup(&ef, &node, path);
150 if (rc != 0)
151 return rc;
152 set_node(fi, node);
153 fi->keep_cache = 1;
154 return 0;
155}
156
157static int fuse_exfat_release(const char* path, struct fuse_file_info* fi)
158{
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400159 /*
160 This handler is called by FUSE on close() syscall. If the FUSE
161 implementation does not call flush handler, we will flush node here.
162 But in this case we will not be able to return an error to the caller.
163 See fuse_exfat_flush() below.
164 */
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500165 exfat_debug("[%s] %s", __func__, path);
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400166 exfat_flush_node(&ef, get_node(fi));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500167 exfat_put_node(&ef, get_node(fi));
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400168 return 0; /* FUSE ignores this return value */
169}
170
171static int fuse_exfat_flush(const char* path, struct fuse_file_info* fi)
172{
173 /*
174 This handler may be called by FUSE on close() syscall. FUSE also deals
175 with removals of open files, so we don't free clusters on close but
176 only on rmdir and unlink. If the FUSE implementation does not call this
177 handler we will flush node on release. See fuse_exfat_relase() above.
178 */
179 exfat_debug("[%s] %s", __func__, path);
180 return exfat_flush_node(&ef, get_node(fi));
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500181}
182
bigbiff bigbiff61cdc022013-08-08 08:35:06 -0400183static int fuse_exfat_fsync(const char* path, int datasync,
184 struct fuse_file_info *fi)
185{
186 int rc;
187
188 exfat_debug("[%s] %s", __func__, path);
bigbiff bigbiff61cdc022013-08-08 08:35:06 -0400189 rc = exfat_flush(&ef);
190 if (rc != 0)
191 return rc;
192 return exfat_fsync(ef.dev);
193}
194
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500195static int fuse_exfat_read(const char* path, char* buffer, size_t size,
196 off64_t offset, struct fuse_file_info* fi)
197{
Dees_Troyb8fdac72013-01-25 19:42:52 +0000198 ssize_t ret;
199
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500200 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
Dees_Troyb8fdac72013-01-25 19:42:52 +0000201 ret = exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
202 if (ret < 0)
203 return -EIO;
204 return ret;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500205}
206
207static int fuse_exfat_write(const char* path, const char* buffer, size_t size,
208 off64_t offset, struct fuse_file_info* fi)
209{
Dees_Troyb8fdac72013-01-25 19:42:52 +0000210 ssize_t ret;
211
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500212 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
Dees_Troyb8fdac72013-01-25 19:42:52 +0000213 ret = exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
214 if (ret < 0)
215 return -EIO;
216 return ret;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500217}
218
219static int fuse_exfat_unlink(const char* path)
220{
221 struct exfat_node* node;
222 int rc;
223
224 exfat_debug("[%s] %s", __func__, path);
225
226 rc = exfat_lookup(&ef, &node, path);
227 if (rc != 0)
228 return rc;
229
230 rc = exfat_unlink(&ef, node);
231 exfat_put_node(&ef, node);
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400232 if (rc != 0)
233 return rc;
234 return exfat_cleanup_node(&ef, node);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500235}
236
237static int fuse_exfat_rmdir(const char* path)
238{
239 struct exfat_node* node;
240 int rc;
241
242 exfat_debug("[%s] %s", __func__, path);
243
244 rc = exfat_lookup(&ef, &node, path);
245 if (rc != 0)
246 return rc;
247
248 rc = exfat_rmdir(&ef, node);
249 exfat_put_node(&ef, node);
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400250 if (rc != 0)
251 return rc;
252 return exfat_cleanup_node(&ef, node);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500253}
254
255static int fuse_exfat_mknod(const char* path, mode_t mode, dev_t dev)
256{
257 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
258 return exfat_mknod(&ef, path);
259}
260
261static int fuse_exfat_mkdir(const char* path, mode_t mode)
262{
263 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
264 return exfat_mkdir(&ef, path);
265}
266
267static int fuse_exfat_rename(const char* old_path, const char* new_path)
268{
269 exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
270 return exfat_rename(&ef, old_path, new_path);
271}
272
273static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
274{
275 struct exfat_node* node;
276 int rc;
277
278 exfat_debug("[%s] %s", __func__, path);
279
280 rc = exfat_lookup(&ef, &node, path);
281 if (rc != 0)
282 return rc;
283
284 exfat_utimes(node, tv);
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400285 rc = exfat_flush_node(&ef, node);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500286 exfat_put_node(&ef, node);
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400287 return rc;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500288}
289
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500290static int fuse_exfat_chmod(const char* path, mode_t mode)
291{
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400292 const mode_t VALID_MODE_MASK = S_IFREG | S_IFDIR |
293 S_IRWXU | S_IRWXG | S_IRWXO;
294
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500295 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400296 if (mode & ~VALID_MODE_MASK)
297 return -EPERM;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500298 return 0;
299}
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400300
301static int fuse_exfat_chown(const char* path, uid_t uid, gid_t gid)
302{
303 exfat_debug("[%s] %s %u:%u", __func__, path, uid, gid);
304 if (uid != ef.uid || gid != ef.gid)
305 return -EPERM;
306 return 0;
307}
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500308
309static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
310{
311 exfat_debug("[%s]", __func__);
312
313 sfs->f_bsize = CLUSTER_SIZE(*ef.sb);
314 sfs->f_frsize = CLUSTER_SIZE(*ef.sb);
315 sfs->f_blocks = le64_to_cpu(ef.sb->sector_count) >> ef.sb->spc_bits;
316 sfs->f_bavail = exfat_count_free_clusters(&ef);
317 sfs->f_bfree = sfs->f_bavail;
318 sfs->f_namemax = EXFAT_NAME_MAX;
319
320 /*
321 Below are fake values because in exFAT there is
322 a) no simple way to count files;
323 b) no such thing as inode;
324 So here we assume that inode = cluster.
325 */
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400326 sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500327 sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
328 sfs->f_ffree = sfs->f_bavail;
329
330 return 0;
331}
332
333static void* fuse_exfat_init(struct fuse_conn_info* fci)
334{
335 exfat_debug("[%s]", __func__);
336#ifdef FUSE_CAP_BIG_WRITES
337 fci->want |= FUSE_CAP_BIG_WRITES;
338#endif
339 return NULL;
340}
341
342static void fuse_exfat_destroy(void* unused)
343{
344 exfat_debug("[%s]", __func__);
345 exfat_unmount(&ef);
346}
347
348static void usage(const char* prog)
349{
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400350 fprintf(stderr, "Usage: %s [-d] [-o options] [-V] <device> <dir>\n", prog);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500351 exit(1);
352}
353
354static struct fuse_operations fuse_exfat_ops =
355{
356 .getattr = fuse_exfat_getattr,
357 .truncate = fuse_exfat_truncate,
358 .readdir = fuse_exfat_readdir,
359 .open = fuse_exfat_open,
360 .release = fuse_exfat_release,
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400361 .flush = fuse_exfat_flush,
bigbiff bigbiff61cdc022013-08-08 08:35:06 -0400362 .fsync = fuse_exfat_fsync,
363 .fsyncdir = fuse_exfat_fsync,
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500364 .read = fuse_exfat_read,
365 .write = fuse_exfat_write,
366 .unlink = fuse_exfat_unlink,
367 .rmdir = fuse_exfat_rmdir,
368 .mknod = fuse_exfat_mknod,
369 .mkdir = fuse_exfat_mkdir,
370 .rename = fuse_exfat_rename,
371 .utimens = fuse_exfat_utimens,
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500372 .chmod = fuse_exfat_chmod,
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400373 .chown = fuse_exfat_chown,
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500374 .statfs = fuse_exfat_statfs,
375 .init = fuse_exfat_init,
376 .destroy = fuse_exfat_destroy,
377};
378
379static char* add_option(char* options, const char* name, const char* value)
380{
381 size_t size;
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400382 char* optionsf = options;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500383
384 if (value)
385 size = strlen(options) + strlen(name) + strlen(value) + 3;
386 else
387 size = strlen(options) + strlen(name) + 2;
388
389 options = realloc(options, size);
390 if (options == NULL)
391 {
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400392 free(optionsf);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500393 exfat_error("failed to reallocate options string");
394 return NULL;
395 }
396 strcat(options, ",");
397 strcat(options, name);
398 if (value)
399 {
400 strcat(options, "=");
401 strcat(options, value);
402 }
403 return options;
404}
405
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500406static char* add_user_option(char* options)
407{
408 struct passwd* pw;
409
410 if (getuid() == 0)
411 return options;
412
413 pw = getpwuid(getuid());
414 if (pw == NULL || pw->pw_name == NULL)
415 {
416 free(options);
417 exfat_error("failed to determine username");
418 return NULL;
419 }
420 return add_option(options, "user", pw->pw_name);
421}
422
423static char* add_blksize_option(char* options, long cluster_size)
424{
425 long page_size = sysconf(_SC_PAGESIZE);
426 char blksize[20];
427
428 if (page_size < 1)
429 page_size = 0x1000;
430
431 snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
432 return add_option(options, "blksize", blksize);
433}
434
435static char* add_fuse_options(char* options, const char* spec)
436{
bigbiff bigbiff998716f2013-03-07 09:59:37 -0500437 options = add_option(options, "fsname", spec);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500438 if (options == NULL)
439 return NULL;
440 options = add_user_option(options);
441 if (options == NULL)
442 return NULL;
443 options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
444 if (options == NULL)
445 return NULL;
446
447 return options;
448}
449
450int main(int argc, char* argv[])
451{
452 struct fuse_args mount_args = FUSE_ARGS_INIT(0, NULL);
453 struct fuse_args newfs_args = FUSE_ARGS_INIT(0, NULL);
454 const char* spec = NULL;
455 const char* mount_point = NULL;
456 char* mount_options;
457 int debug = 0;
458 struct fuse_chan* fc = NULL;
459 struct fuse* fh = NULL;
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400460 int opt;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500461
462 printf("FUSE exfat %u.%u.%u\n",
463 EXFAT_VERSION_MAJOR, EXFAT_VERSION_MINOR, EXFAT_VERSION_PATCH);
464
465 mount_options = strdup(default_options);
466 if (mount_options == NULL)
467 {
468 exfat_error("failed to allocate options string");
469 return 1;
470 }
471
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400472 while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500473 {
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400474 switch (opt)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500475 {
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400476 case 'd':
477 debug = 1;
478 break;
479 case 'n':
480 break;
481 case 'o':
482 mount_options = add_option(mount_options, optarg, NULL);
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500483 if (mount_options == NULL)
484 return 1;
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400485 break;
486 case 'V':
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500487 free(mount_options);
bigbiff bigbiff2e33c5e2014-09-04 20:58:41 -0400488 puts("Copyright (C) 2010-2014 Andrew Nayenko");
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500489 return 0;
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400490 case 'v':
491 break;
492 default:
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500493 free(mount_options);
494 usage(argv[0]);
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400495 break;
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500496 }
497 }
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400498 if (argc - optind != 2)
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500499 {
500 free(mount_options);
501 usage(argv[0]);
502 }
bigbiff bigbiff004e2df2013-07-03 14:52:12 -0400503 spec = argv[optind];
504 mount_point = argv[optind + 1];
bigbiff bigbiff9c754052013-01-09 09:09:08 -0500505
506 if (exfat_mount(&ef, spec, mount_options) != 0)
507 {
508 free(mount_options);
509 return 1;
510 }
511
512 if (ef.ro == -1) /* read-only fallback was used */
513 {
514 mount_options = add_option(mount_options, "ro", NULL);
515 if (mount_options == NULL)
516 {
517 exfat_unmount(&ef);
518 return 1;
519 }
520 }
521
522 mount_options = add_fuse_options(mount_options, spec);
523 if (mount_options == NULL)
524 {
525 exfat_unmount(&ef);
526 return 1;
527 }
528
529 /* create arguments for fuse_mount() */
530 if (fuse_opt_add_arg(&mount_args, "exfat") != 0 ||
531 fuse_opt_add_arg(&mount_args, "-o") != 0 ||
532 fuse_opt_add_arg(&mount_args, mount_options) != 0)
533 {
534 exfat_unmount(&ef);
535 free(mount_options);
536 return 1;
537 }
538
539 free(mount_options);
540
541 /* create FUSE mount point */
542 fc = fuse_mount(mount_point, &mount_args);
543 fuse_opt_free_args(&mount_args);
544 if (fc == NULL)
545 {
546 exfat_unmount(&ef);
547 return 1;
548 }
549
550 /* create arguments for fuse_new() */
551 if (fuse_opt_add_arg(&newfs_args, "") != 0 ||
552 (debug && fuse_opt_add_arg(&newfs_args, "-d") != 0))
553 {
554 fuse_unmount(mount_point, fc);
555 exfat_unmount(&ef);
556 return 1;
557 }
558
559 /* create new FUSE file system */
560 fh = fuse_new(fc, &newfs_args, &fuse_exfat_ops,
561 sizeof(struct fuse_operations), NULL);
562 fuse_opt_free_args(&newfs_args);
563 if (fh == NULL)
564 {
565 fuse_unmount(mount_point, fc);
566 exfat_unmount(&ef);
567 return 1;
568 }
569
570 /* exit session on HUP, TERM and INT signals and ignore PIPE signal */
571 if (fuse_set_signal_handlers(fuse_get_session(fh)) != 0)
572 {
573 fuse_unmount(mount_point, fc);
574 fuse_destroy(fh);
575 exfat_unmount(&ef);
576 exfat_error("failed to set signal handlers");
577 return 1;
578 }
579
580 /* go to background (unless "-d" option is passed) and run FUSE
581 main loop */
582 if (fuse_daemonize(debug) == 0)
583 {
584 if (fuse_loop(fh) != 0)
585 exfat_error("FUSE loop failure");
586 }
587 else
588 exfat_error("failed to daemonize");
589
590 fuse_remove_signal_handlers(fuse_get_session(fh));
591 /* note that fuse_unmount() must be called BEFORE fuse_destroy() */
592 fuse_unmount(mount_point, fc);
593 fuse_destroy(fh);
594 return 0;
595}