3 FUSE-based exFAT implementation. Requires FUSE 2.6 or later.
5 Free exFAT implementation.
6 Copyright (C) 2010-2013 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)
384 size = strlen(options) + strlen(name) + strlen(value) + 3;
386 size = strlen(options) + strlen(name) + 2;
388 options = realloc(options, size);
391 exfat_error("failed to reallocate options string");
394 strcat(options, ",");
395 strcat(options, name);
398 strcat(options, "=");
399 strcat(options, value);
404 static char* add_user_option(char* options)
411 pw = getpwuid(getuid());
412 if (pw == NULL || pw->pw_name == NULL)
415 exfat_error("failed to determine username");
418 return add_option(options, "user", pw->pw_name);
421 static char* add_blksize_option(char* options, long cluster_size)
423 long page_size = sysconf(_SC_PAGESIZE);
429 snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
430 return add_option(options, "blksize", blksize);
433 static char* add_fuse_options(char* options, const char* spec)
435 options = add_option(options, "fsname", spec);
438 options = add_user_option(options);
441 options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
448 int main(int argc, char* argv[])
450 struct fuse_args mount_args = FUSE_ARGS_INIT(0, NULL);
451 struct fuse_args newfs_args = FUSE_ARGS_INIT(0, NULL);
452 const char* spec = NULL;
453 const char* mount_point = NULL;
456 struct fuse_chan* fc = NULL;
457 struct fuse* fh = NULL;
460 printf("FUSE exfat %u.%u.%u\n",
461 EXFAT_VERSION_MAJOR, EXFAT_VERSION_MINOR, EXFAT_VERSION_PATCH);
463 mount_options = strdup(default_options);
464 if (mount_options == NULL)
466 exfat_error("failed to allocate options string");
470 while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
480 mount_options = add_option(mount_options, optarg, NULL);
481 if (mount_options == NULL)
486 puts("Copyright (C) 2010-2013 Andrew Nayenko");
496 if (argc - optind != 2)
502 mount_point = argv[optind + 1];
504 if (exfat_mount(&ef, spec, mount_options) != 0)
510 if (ef.ro == -1) /* read-only fallback was used */
512 mount_options = add_option(mount_options, "ro", NULL);
513 if (mount_options == NULL)
520 mount_options = add_fuse_options(mount_options, spec);
521 if (mount_options == NULL)
527 /* create arguments for fuse_mount() */
528 if (fuse_opt_add_arg(&mount_args, "exfat") != 0 ||
529 fuse_opt_add_arg(&mount_args, "-o") != 0 ||
530 fuse_opt_add_arg(&mount_args, mount_options) != 0)
539 /* create FUSE mount point */
540 fc = fuse_mount(mount_point, &mount_args);
541 fuse_opt_free_args(&mount_args);
548 /* create arguments for fuse_new() */
549 if (fuse_opt_add_arg(&newfs_args, "") != 0 ||
550 (debug && fuse_opt_add_arg(&newfs_args, "-d") != 0))
552 fuse_unmount(mount_point, fc);
557 /* create new FUSE file system */
558 fh = fuse_new(fc, &newfs_args, &fuse_exfat_ops,
559 sizeof(struct fuse_operations), NULL);
560 fuse_opt_free_args(&newfs_args);
563 fuse_unmount(mount_point, fc);
568 /* exit session on HUP, TERM and INT signals and ignore PIPE signal */
569 if (fuse_set_signal_handlers(fuse_get_session(fh)) != 0)
571 fuse_unmount(mount_point, fc);
574 exfat_error("failed to set signal handlers");
578 /* go to background (unless "-d" option is passed) and run FUSE
580 if (fuse_daemonize(debug) == 0)
582 if (fuse_loop(fh) != 0)
583 exfat_error("FUSE loop failure");
586 exfat_error("failed to daemonize");
588 fuse_remove_signal_handlers(fuse_get_session(fh));
589 /* note that fuse_unmount() must be called BEFORE fuse_destroy() */
590 fuse_unmount(mount_point, fc);