3 FUSE-based exFAT implementation. Requires FUSE 2.6 or later.
5 Free exFAT implementation.
6 Copyright (C) 2010-2014 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.
23 #define FUSE_USE_VERSION 26
33 #include <sys/types.h>
37 #define exfat_debug(format, ...)
39 #if !defined(FUSE_VERSION) || (FUSE_VERSION < 26)
40 #error FUSE 2.6 or later is required
43 const char* default_options = "ro_fallback,allow_other,blkdev,big_writes,"
48 static struct exfat_node* get_node(const struct fuse_file_info* fi)
50 return (struct exfat_node*) (size_t) fi->fh;
53 static void set_node(struct fuse_file_info* fi, struct exfat_node* node)
55 fi->fh = (uint64_t) (size_t) node;
58 static int fuse_exfat_getattr(const char* path, struct stat* stbuf)
60 struct exfat_node* node;
63 exfat_debug("[%s] %s", __func__, path);
65 rc = exfat_lookup(&ef, &node, path);
69 exfat_stat(&ef, node, stbuf);
70 exfat_put_node(&ef, node);
74 static int fuse_exfat_truncate(const char* path, off_t size)
76 struct exfat_node* node;
79 exfat_debug("[%s] %s, %"PRId64, __func__, path, size);
81 rc = exfat_lookup(&ef, &node, path);
85 rc = exfat_truncate(&ef, node, size, true);
88 exfat_flush_node(&ef, node); /* ignore return code */
89 exfat_put_node(&ef, node);
92 rc = exfat_flush_node(&ef, node);
93 exfat_put_node(&ef, node);
97 static int fuse_exfat_readdir(const char* path, void* buffer,
98 fuse_fill_dir_t filler, off_t offset, struct fuse_file_info* fi)
100 struct exfat_node* parent;
101 struct exfat_node* node;
102 struct exfat_iterator it;
104 char name[UTF8_BYTES(EXFAT_NAME_MAX) + 1];
106 exfat_debug("[%s] %s", __func__, path);
108 rc = exfat_lookup(&ef, &parent, path);
111 if (!(parent->flags & EXFAT_ATTRIB_DIR))
113 exfat_put_node(&ef, parent);
114 exfat_error("'%s' is not a directory (0x%x)", path, parent->flags);
118 filler(buffer, ".", NULL, 0);
119 filler(buffer, "..", NULL, 0);
121 rc = exfat_opendir(&ef, parent, &it);
124 exfat_put_node(&ef, parent);
125 exfat_error("failed to open directory '%s'", path);
128 while ((node = exfat_readdir(&ef, &it)))
130 exfat_get_name(node, name, sizeof(name) - 1);
131 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);
137 exfat_closedir(&ef, &it);
138 exfat_put_node(&ef, parent);
142 static int fuse_exfat_open(const char* path, struct fuse_file_info* fi)
144 struct exfat_node* node;
147 exfat_debug("[%s] %s", __func__, path);
149 rc = exfat_lookup(&ef, &node, path);
157 static int fuse_exfat_release(const char* path, struct fuse_file_info* fi)
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.
165 exfat_debug("[%s] %s", __func__, path);
166 exfat_flush_node(&ef, get_node(fi));
167 exfat_put_node(&ef, get_node(fi));
168 return 0; /* FUSE ignores this return value */
171 static int fuse_exfat_flush(const char* path, struct fuse_file_info* fi)
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.
179 exfat_debug("[%s] %s", __func__, path);
180 return exfat_flush_node(&ef, get_node(fi));
183 static int fuse_exfat_fsync(const char* path, int datasync,
184 struct fuse_file_info *fi)
188 exfat_debug("[%s] %s", __func__, path);
189 rc = exfat_flush(&ef);
192 return exfat_fsync(ef.dev);
195 static int fuse_exfat_read(const char* path, char* buffer, size_t size,
196 off_t offset, struct fuse_file_info* fi)
200 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
201 ret = exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
207 static int fuse_exfat_write(const char* path, const char* buffer, size_t size,
208 off_t offset, struct fuse_file_info* fi)
212 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
213 ret = exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
219 static int fuse_exfat_unlink(const char* path)
221 struct exfat_node* node;
224 exfat_debug("[%s] %s", __func__, path);
226 rc = exfat_lookup(&ef, &node, path);
230 rc = exfat_unlink(&ef, node);
231 exfat_put_node(&ef, node);
234 return exfat_cleanup_node(&ef, node);
237 static int fuse_exfat_rmdir(const char* path)
239 struct exfat_node* node;
242 exfat_debug("[%s] %s", __func__, path);
244 rc = exfat_lookup(&ef, &node, path);
248 rc = exfat_rmdir(&ef, node);
249 exfat_put_node(&ef, node);
252 return exfat_cleanup_node(&ef, node);
255 static int fuse_exfat_mknod(const char* path, mode_t mode, dev_t dev)
257 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
258 return exfat_mknod(&ef, path);
261 static int fuse_exfat_mkdir(const char* path, mode_t mode)
263 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
264 return exfat_mkdir(&ef, path);
267 static int fuse_exfat_rename(const char* old_path, const char* new_path)
269 exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
270 return exfat_rename(&ef, old_path, new_path);
273 static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
275 struct exfat_node* node;
278 exfat_debug("[%s] %s", __func__, path);
280 rc = exfat_lookup(&ef, &node, path);
284 exfat_utimes(node, tv);
285 rc = exfat_flush_node(&ef, node);
286 exfat_put_node(&ef, node);
290 static int fuse_exfat_chmod(const char* path, mode_t mode)
292 const mode_t VALID_MODE_MASK = S_IFREG | S_IFDIR |
293 S_IRWXU | S_IRWXG | S_IRWXO;
295 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
296 if (mode & ~VALID_MODE_MASK)
301 static int fuse_exfat_chown(const char* path, uid_t uid, gid_t gid)
303 exfat_debug("[%s] %s %u:%u", __func__, path, uid, gid);
304 if (uid != ef.uid || gid != ef.gid)
309 static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
311 exfat_debug("[%s]", __func__);
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;
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.
326 sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
327 sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
328 sfs->f_ffree = sfs->f_bavail;
333 static void* fuse_exfat_init(struct fuse_conn_info* fci)
335 exfat_debug("[%s]", __func__);
336 #ifdef FUSE_CAP_BIG_WRITES
337 fci->want |= FUSE_CAP_BIG_WRITES;
342 static void fuse_exfat_destroy(void* unused)
344 exfat_debug("[%s]", __func__);
348 static void usage(const char* prog)
350 fprintf(stderr, "Usage: %s [-d] [-o options] [-V] <device> <dir>\n", prog);
354 static struct fuse_operations fuse_exfat_ops =
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,
361 .flush = fuse_exfat_flush,
362 .fsync = fuse_exfat_fsync,
363 .fsyncdir = fuse_exfat_fsync,
364 .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,
372 .chmod = fuse_exfat_chmod,
373 .chown = fuse_exfat_chown,
374 .statfs = fuse_exfat_statfs,
375 .init = fuse_exfat_init,
376 .destroy = fuse_exfat_destroy,
379 static char* add_option(char* options, const char* name, const char* value)
382 char* optionsf = options;
385 size = strlen(options) + strlen(name) + strlen(value) + 3;
387 size = strlen(options) + strlen(name) + 2;
389 options = realloc(options, size);
393 exfat_error("failed to reallocate options string");
396 strcat(options, ",");
397 strcat(options, name);
400 strcat(options, "=");
401 strcat(options, value);
406 static char* add_user_option(char* options)
413 pw = getpwuid(getuid());
414 if (pw == NULL || pw->pw_name == NULL)
417 exfat_error("failed to determine username");
420 return add_option(options, "user", pw->pw_name);
423 static char* add_blksize_option(char* options, long cluster_size)
425 long page_size = sysconf(_SC_PAGESIZE);
431 snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
432 return add_option(options, "blksize", blksize);
435 static char* add_fuse_options(char* options, const char* spec)
437 options = add_option(options, "fsname", spec);
440 options = add_user_option(options);
443 options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
450 int main(int argc, char* argv[])
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;
458 struct fuse_chan* fc = NULL;
459 struct fuse* fh = NULL;
462 printf("FUSE exfat %u.%u.%u\n",
463 EXFAT_VERSION_MAJOR, EXFAT_VERSION_MINOR, EXFAT_VERSION_PATCH);
465 mount_options = strdup(default_options);
466 if (mount_options == NULL)
468 exfat_error("failed to allocate options string");
472 while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
482 mount_options = add_option(mount_options, optarg, NULL);
483 if (mount_options == NULL)
488 puts("Copyright (C) 2010-2014 Andrew Nayenko");
498 if (argc - optind != 2)
504 mount_point = argv[optind + 1];
506 if (exfat_mount(&ef, spec, mount_options) != 0)
512 if (ef.ro == -1) /* read-only fallback was used */
514 mount_options = add_option(mount_options, "ro", NULL);
515 if (mount_options == NULL)
522 mount_options = add_fuse_options(mount_options, spec);
523 if (mount_options == NULL)
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)
541 /* create FUSE mount point */
542 fc = fuse_mount(mount_point, &mount_args);
543 fuse_opt_free_args(&mount_args);
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))
554 fuse_unmount(mount_point, fc);
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);
565 fuse_unmount(mount_point, fc);
570 /* exit session on HUP, TERM and INT signals and ignore PIPE signal */
571 if (fuse_set_signal_handlers(fuse_get_session(fh)) != 0)
573 fuse_unmount(mount_point, fc);
576 exfat_error("failed to set signal handlers");
580 /* go to background (unless "-d" option is passed) and run FUSE
582 if (fuse_daemonize(debug) == 0)
584 if (fuse_loop(fh) != 0)
585 exfat_error("FUSE loop failure");
588 exfat_error("failed to daemonize");
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);