3 FUSE-based exFAT implementation. Requires FUSE 2.6 or later.
5 Free exFAT implementation.
6 Copyright (C) 2010-2016 Andrew Nayenko
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 2 of the License, or
11 (at your option) any later version.
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.
18 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.
24 #define FUSE_USE_VERSION 26
33 #include <sys/types.h>
38 #define exfat_debug(format, ...)
41 #if !defined(FUSE_VERSION) || (FUSE_VERSION < 26)
42 #error FUSE 2.6 or later is required
45 const char* default_options = "ro_fallback,allow_other,blkdev,big_writes,"
46 "default_permissions";
50 static struct exfat_node* get_node(const struct fuse_file_info* fi)
52 return (struct exfat_node*) (size_t) fi->fh;
55 static void set_node(struct fuse_file_info* fi, struct exfat_node* node)
57 fi->fh = (uint64_t) (size_t) node;
61 static int fuse_exfat_getattr(const char* path, struct stat* stbuf)
63 struct exfat_node* node;
66 exfat_debug("[%s] %s", __func__, path);
68 rc = exfat_lookup(&ef, &node, path);
72 exfat_stat(&ef, node, stbuf);
73 exfat_put_node(&ef, node);
77 static int fuse_exfat_truncate(const char* path, off_t size)
79 struct exfat_node* node;
82 exfat_debug("[%s] %s, %"PRId64, __func__, path, size);
84 rc = exfat_lookup(&ef, &node, path);
88 rc = exfat_truncate(&ef, node, size, true);
91 exfat_flush_node(&ef, node); /* ignore return code */
92 exfat_put_node(&ef, node);
95 rc = exfat_flush_node(&ef, node);
96 exfat_put_node(&ef, node);
100 static int fuse_exfat_readdir(const char* path, void* buffer,
101 fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* fi)
103 struct exfat_node* parent;
104 struct exfat_node* node;
105 struct exfat_iterator it;
107 char name[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
109 exfat_debug("[%s] %s", __func__, path);
111 rc = exfat_lookup(&ef, &parent, path);
114 if (!(parent->flags & EXFAT_ATTRIB_DIR))
116 exfat_put_node(&ef, parent);
117 exfat_error("'%s' is not a directory (0x%x)", path, parent->flags);
121 filler(buffer, ".", NULL, 0);
122 filler(buffer, "..", NULL, 0);
124 rc = exfat_opendir(&ef, parent, &it);
127 exfat_put_node(&ef, parent);
128 exfat_error("failed to open directory '%s'", path);
131 while ((node = exfat_readdir(&ef, &it)))
133 exfat_get_name(node, name, sizeof(name) - 1);
134 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);
140 exfat_closedir(&ef, &it);
141 exfat_put_node(&ef, parent);
145 static int fuse_exfat_open(const char* path, struct fuse_file_info* fi)
147 struct exfat_node* node;
150 exfat_debug("[%s] %s", __func__, path);
152 rc = exfat_lookup(&ef, &node, path);
159 static int fuse_exfat_create(const char* path, mode_t mode,
160 struct fuse_file_info* fi)
162 struct exfat_node* node;
165 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
167 rc = exfat_mknod(&ef, path);
170 rc = exfat_lookup(&ef, &node, path);
177 static int fuse_exfat_release(const char* path, struct fuse_file_info* fi)
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.
185 exfat_debug("[%s] %s", __func__, path);
186 exfat_flush_node(&ef, get_node(fi));
187 exfat_put_node(&ef, get_node(fi));
188 return 0; /* FUSE ignores this return value */
191 static int fuse_exfat_flush(const char* path, struct fuse_file_info* fi)
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.
199 exfat_debug("[%s] %s", __func__, path);
200 return exfat_flush_node(&ef, get_node(fi));
203 static int fuse_exfat_fsync(const char* path, int datasync,
204 struct fuse_file_info *fi)
208 exfat_debug("[%s] %s", __func__, path);
209 rc = exfat_flush_nodes(&ef);
212 rc = exfat_flush(&ef);
215 return exfat_fsync(ef.dev);
218 static int fuse_exfat_read(const char* path, char* buffer, size_t size,
219 off_t offset, struct fuse_file_info* fi)
223 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
224 ret = exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
230 static int fuse_exfat_write(const char* path, const char* buffer, size_t size,
231 off_t offset, struct fuse_file_info* fi)
235 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
236 ret = exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
242 static int fuse_exfat_unlink(const char* path)
244 struct exfat_node* node;
247 exfat_debug("[%s] %s", __func__, path);
249 rc = exfat_lookup(&ef, &node, path);
253 rc = exfat_unlink(&ef, node);
254 exfat_put_node(&ef, node);
257 return exfat_cleanup_node(&ef, node);
260 static int fuse_exfat_rmdir(const char* path)
262 struct exfat_node* node;
265 exfat_debug("[%s] %s", __func__, path);
267 rc = exfat_lookup(&ef, &node, path);
271 rc = exfat_rmdir(&ef, node);
272 exfat_put_node(&ef, node);
275 return exfat_cleanup_node(&ef, node);
278 static int fuse_exfat_mknod(const char* path, mode_t mode, dev_t dev)
280 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
281 return exfat_mknod(&ef, path);
284 static int fuse_exfat_mkdir(const char* path, mode_t mode)
286 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
287 return exfat_mkdir(&ef, path);
290 static int fuse_exfat_rename(const char* old_path, const char* new_path)
292 exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
293 return exfat_rename(&ef, old_path, new_path);
296 static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
298 struct exfat_node* node;
301 exfat_debug("[%s] %s", __func__, path);
303 rc = exfat_lookup(&ef, &node, path);
307 exfat_utimes(node, tv);
308 rc = exfat_flush_node(&ef, node);
309 exfat_put_node(&ef, node);
313 static int fuse_exfat_chmod(const char* path, mode_t mode)
315 const mode_t VALID_MODE_MASK = S_IFREG | S_IFDIR |
316 S_IRWXU | S_IRWXG | S_IRWXO;
318 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
319 if (mode & ~VALID_MODE_MASK)
324 static int fuse_exfat_chown(const char* path, uid_t uid, gid_t gid)
326 exfat_debug("[%s] %s %u:%u", __func__, path, uid, gid);
327 if (uid != ef.uid || gid != ef.gid)
332 static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
334 exfat_debug("[%s]", __func__);
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;
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.
349 sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
350 sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
351 sfs->f_ffree = sfs->f_bavail;
356 static void* fuse_exfat_init(struct fuse_conn_info* fci)
358 exfat_debug("[%s]", __func__);
359 #ifdef FUSE_CAP_BIG_WRITES
360 fci->want |= FUSE_CAP_BIG_WRITES;
365 static void fuse_exfat_destroy(void* unused)
367 exfat_debug("[%s]", __func__);
371 static void usage(const char* prog)
373 fprintf(stderr, "Usage: %s [-d] [-o options] [-V] <device> <dir>\n", prog);
377 static struct fuse_operations fuse_exfat_ops =
379 .getattr = fuse_exfat_getattr,
380 .truncate = fuse_exfat_truncate,
381 .readdir = fuse_exfat_readdir,
382 .open = fuse_exfat_open,
383 .create = fuse_exfat_create,
384 .release = fuse_exfat_release,
385 .flush = fuse_exfat_flush,
386 .fsync = fuse_exfat_fsync,
387 .fsyncdir = fuse_exfat_fsync,
388 .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,
396 .chmod = fuse_exfat_chmod,
397 .chown = fuse_exfat_chown,
398 .statfs = fuse_exfat_statfs,
399 .init = fuse_exfat_init,
400 .destroy = fuse_exfat_destroy,
403 static char* add_option(char* options, const char* name, const char* value)
406 char* optionsf = options;
409 size = strlen(options) + strlen(name) + strlen(value) + 3;
411 size = strlen(options) + strlen(name) + 2;
413 options = realloc(options, size);
417 exfat_error("failed to reallocate options string");
420 strcat(options, ",");
421 strcat(options, name);
424 strcat(options, "=");
425 strcat(options, value);
430 static void escape(char* escaped, const char* orig)
434 if (*orig == ',' || *orig == '\\')
437 while ((*escaped++ = *orig++));
440 static char* add_fsname_option(char* options, const char* spec)
442 /* escaped string cannot be more than twice as big as the original one */
443 char* escaped = malloc(strlen(spec) * 2 + 1);
448 exfat_error("failed to allocate escaped string for %s", spec);
452 /* on some platforms (e.g. Android, Solaris) device names can contain
454 escape(escaped, spec);
455 options = add_option(options, "fsname", escaped);
460 static char* add_user_option(char* options)
467 pw = getpwuid(getuid());
468 if (pw == NULL || pw->pw_name == NULL)
471 exfat_error("failed to determine username");
474 return add_option(options, "user", pw->pw_name);
477 static char* add_blksize_option(char* options, long cluster_size)
479 long page_size = sysconf(_SC_PAGESIZE);
485 snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
486 return add_option(options, "blksize", blksize);
489 static char* add_fuse_options(char* options, const char* spec)
491 options = add_fsname_option(options, spec);
494 options = add_user_option(options);
497 options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
504 int main(int argc, char* argv[])
506 struct fuse_args mount_args = FUSE_ARGS_INIT(0, NULL);
507 struct fuse_args newfs_args = FUSE_ARGS_INIT(0, NULL);
508 const char* spec = NULL;
509 const char* mount_point = NULL;
512 struct fuse_chan* fc = NULL;
513 struct fuse* fh = NULL;
516 printf("FUSE exfat %s\n", VERSION);
518 mount_options = strdup(default_options);
519 if (mount_options == NULL)
521 exfat_error("failed to allocate options string");
525 while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
535 mount_options = add_option(mount_options, optarg, NULL);
536 if (mount_options == NULL)
541 puts("Copyright (C) 2010-2016 Andrew Nayenko");
551 if (argc - optind != 2)
557 mount_point = argv[optind + 1];
559 if (exfat_mount(&ef, spec, mount_options) != 0)
565 if (ef.ro == -1) /* read-only fallback was used */
567 mount_options = add_option(mount_options, "ro", NULL);
568 if (mount_options == NULL)
575 mount_options = add_fuse_options(mount_options, spec);
576 if (mount_options == NULL)
582 /* create arguments for fuse_mount() */
583 if (fuse_opt_add_arg(&mount_args, "exfat") != 0 ||
584 fuse_opt_add_arg(&mount_args, "-o") != 0 ||
585 fuse_opt_add_arg(&mount_args, mount_options) != 0)
594 /* create FUSE mount point */
595 fc = fuse_mount(mount_point, &mount_args);
596 fuse_opt_free_args(&mount_args);
603 /* create arguments for fuse_new() */
604 if (fuse_opt_add_arg(&newfs_args, "") != 0 ||
605 (debug && fuse_opt_add_arg(&newfs_args, "-d") != 0))
607 fuse_unmount(mount_point, fc);
612 /* create new FUSE file system */
613 fh = fuse_new(fc, &newfs_args, &fuse_exfat_ops,
614 sizeof(struct fuse_operations), NULL);
615 fuse_opt_free_args(&newfs_args);
618 fuse_unmount(mount_point, fc);
623 /* exit session on HUP, TERM and INT signals and ignore PIPE signal */
624 if (fuse_set_signal_handlers(fuse_get_session(fh)) != 0)
626 fuse_unmount(mount_point, fc);
629 exfat_error("failed to set signal handlers");
633 /* go to background (unless "-d" option is passed) and run FUSE
635 if (fuse_daemonize(debug) == 0)
637 if (fuse_loop(fh) != 0)
638 exfat_error("FUSE loop failure");
641 exfat_error("failed to daemonize");
643 fuse_remove_signal_handlers(fuse_get_session(fh));
644 /* note that fuse_unmount() must be called BEFORE fuse_destroy() */
645 fuse_unmount(mount_point, fc);