3 FUSE-based exFAT implementation. Requires FUSE 2.6 or later.
5 Free exFAT implementation.
6 Copyright (C) 2010-2018 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
47 static struct exfat_node* get_node(const struct fuse_file_info* fi)
49 return (struct exfat_node*) (size_t) fi->fh;
52 static void set_node(struct fuse_file_info* fi, struct exfat_node* node)
54 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[EXFAT_UTF8_NAME_BUFFER_MAX];
107 exfat_debug("[%s] %s", __func__, path);
109 rc = exfat_lookup(&ef, &parent, path);
112 if (!(parent->attrib & EXFAT_ATTRIB_DIR))
114 exfat_put_node(&ef, parent);
115 exfat_error("'%s' is not a directory (%#hx)", path, parent->attrib);
119 filler(buffer, ".", NULL, 0);
120 filler(buffer, "..", NULL, 0);
122 rc = exfat_opendir(&ef, parent, &it);
125 exfat_put_node(&ef, parent);
126 exfat_error("failed to open directory '%s'", path);
129 while ((node = exfat_readdir(&it)))
131 exfat_get_name(node, name);
132 exfat_debug("[%s] %s: %s, %"PRId64" bytes, cluster 0x%x", __func__,
133 name, node->is_contiguous ? "contiguous" : "fragmented",
134 node->size, node->start_cluster);
135 exfat_stat(&ef, node, &stbuf);
136 filler(buffer, name, &stbuf, 0);
137 exfat_put_node(&ef, node);
139 exfat_closedir(&ef, &it);
140 exfat_put_node(&ef, parent);
144 static int fuse_exfat_open(const char* path, struct fuse_file_info* fi)
146 struct exfat_node* node;
149 exfat_debug("[%s] %s", __func__, path);
151 rc = exfat_lookup(&ef, &node, path);
158 static int fuse_exfat_create(const char* path, mode_t mode,
159 struct fuse_file_info* fi)
161 struct exfat_node* node;
164 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
166 rc = exfat_mknod(&ef, path);
169 rc = exfat_lookup(&ef, &node, path);
176 static int fuse_exfat_release(const char* path, struct fuse_file_info* fi)
179 This handler is called by FUSE on close() syscall. If the FUSE
180 implementation does not call flush handler, we will flush node here.
181 But in this case we will not be able to return an error to the caller.
182 See fuse_exfat_flush() below.
184 exfat_debug("[%s] %s", __func__, path);
185 exfat_flush_node(&ef, get_node(fi));
186 exfat_put_node(&ef, get_node(fi));
187 return 0; /* FUSE ignores this return value */
190 static int fuse_exfat_flush(const char* path, struct fuse_file_info* fi)
193 This handler may be called by FUSE on close() syscall. FUSE also deals
194 with removals of open files, so we don't free clusters on close but
195 only on rmdir and unlink. If the FUSE implementation does not call this
196 handler we will flush node on release. See fuse_exfat_relase() above.
198 exfat_debug("[%s] %s", __func__, path);
199 return exfat_flush_node(&ef, get_node(fi));
202 static int fuse_exfat_fsync(const char* path, int datasync,
203 struct fuse_file_info *fi)
207 exfat_debug("[%s] %s", __func__, path);
208 rc = exfat_flush_nodes(&ef);
211 rc = exfat_flush(&ef);
214 return exfat_fsync(ef.dev);
217 static int fuse_exfat_read(const char* path, char* buffer, size_t size,
218 off_t offset, struct fuse_file_info* fi)
220 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
221 return exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
224 static int fuse_exfat_write(const char* path, const char* buffer, size_t size,
225 off_t offset, struct fuse_file_info* fi)
227 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
228 return exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
231 static int fuse_exfat_unlink(const char* path)
233 struct exfat_node* node;
236 exfat_debug("[%s] %s", __func__, path);
238 rc = exfat_lookup(&ef, &node, path);
242 rc = exfat_unlink(&ef, node);
243 exfat_put_node(&ef, node);
246 return exfat_cleanup_node(&ef, node);
249 static int fuse_exfat_rmdir(const char* path)
251 struct exfat_node* node;
254 exfat_debug("[%s] %s", __func__, path);
256 rc = exfat_lookup(&ef, &node, path);
260 rc = exfat_rmdir(&ef, node);
261 exfat_put_node(&ef, node);
264 return exfat_cleanup_node(&ef, node);
267 static int fuse_exfat_mknod(const char* path, mode_t mode, dev_t dev)
269 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
270 return exfat_mknod(&ef, path);
273 static int fuse_exfat_mkdir(const char* path, mode_t mode)
275 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
276 return exfat_mkdir(&ef, path);
279 static int fuse_exfat_rename(const char* old_path, const char* new_path)
281 exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
282 return exfat_rename(&ef, old_path, new_path);
285 static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
287 struct exfat_node* node;
290 exfat_debug("[%s] %s", __func__, path);
292 rc = exfat_lookup(&ef, &node, path);
296 exfat_utimes(node, tv);
297 rc = exfat_flush_node(&ef, node);
298 exfat_put_node(&ef, node);
302 static int fuse_exfat_chmod(const char* path, mode_t mode)
304 const mode_t VALID_MODE_MASK = S_IFREG | S_IFDIR |
305 S_IRWXU | S_IRWXG | S_IRWXO;
307 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
308 if (mode & ~VALID_MODE_MASK)
313 static int fuse_exfat_chown(const char* path, uid_t uid, gid_t gid)
315 exfat_debug("[%s] %s %u:%u", __func__, path, uid, gid);
316 if (uid != ef.uid || gid != ef.gid)
321 static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
323 exfat_debug("[%s]", __func__);
325 sfs->f_bsize = CLUSTER_SIZE(*ef.sb);
326 sfs->f_frsize = CLUSTER_SIZE(*ef.sb);
327 sfs->f_blocks = le64_to_cpu(ef.sb->sector_count) >> ef.sb->spc_bits;
328 sfs->f_bavail = exfat_count_free_clusters(&ef);
329 sfs->f_bfree = sfs->f_bavail;
330 sfs->f_namemax = EXFAT_NAME_MAX;
333 Below are fake values because in exFAT there is
334 a) no simple way to count files;
335 b) no such thing as inode;
336 So here we assume that inode = cluster.
338 sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
339 sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
340 sfs->f_ffree = sfs->f_bavail;
345 static void* fuse_exfat_init(struct fuse_conn_info* fci)
347 exfat_debug("[%s]", __func__);
348 #ifdef FUSE_CAP_BIG_WRITES
349 fci->want |= FUSE_CAP_BIG_WRITES;
354 static void fuse_exfat_destroy(void* unused)
356 exfat_debug("[%s]", __func__);
360 static void usage(const char* prog)
362 fprintf(stderr, "Usage: %s [-d] [-o options] [-V] <device> <dir>\n", prog);
366 static struct fuse_operations fuse_exfat_ops =
368 .getattr = fuse_exfat_getattr,
369 .truncate = fuse_exfat_truncate,
370 .readdir = fuse_exfat_readdir,
371 .open = fuse_exfat_open,
372 .create = fuse_exfat_create,
373 .release = fuse_exfat_release,
374 .flush = fuse_exfat_flush,
375 .fsync = fuse_exfat_fsync,
376 .fsyncdir = fuse_exfat_fsync,
377 .read = fuse_exfat_read,
378 .write = fuse_exfat_write,
379 .unlink = fuse_exfat_unlink,
380 .rmdir = fuse_exfat_rmdir,
381 .mknod = fuse_exfat_mknod,
382 .mkdir = fuse_exfat_mkdir,
383 .rename = fuse_exfat_rename,
384 .utimens = fuse_exfat_utimens,
385 .chmod = fuse_exfat_chmod,
386 .chown = fuse_exfat_chown,
387 .statfs = fuse_exfat_statfs,
388 .init = fuse_exfat_init,
389 .destroy = fuse_exfat_destroy,
392 static char* add_option(char* options, const char* name, const char* value)
395 char* optionsf = options;
398 size = strlen(options) + strlen(name) + strlen(value) + 3;
400 size = strlen(options) + strlen(name) + 2;
402 options = realloc(options, size);
406 exfat_error("failed to reallocate options string");
409 strcat(options, ",");
410 strcat(options, name);
413 strcat(options, "=");
414 strcat(options, value);
419 static void escape(char* escaped, const char* orig)
423 if (*orig == ',' || *orig == '\\')
426 while ((*escaped++ = *orig++));
429 static char* add_fsname_option(char* options, const char* spec)
431 /* escaped string cannot be more than twice as big as the original one */
432 char* escaped = malloc(strlen(spec) * 2 + 1);
437 exfat_error("failed to allocate escaped string for %s", spec);
441 /* on some platforms (e.g. Android, Solaris) device names can contain
443 escape(escaped, spec);
444 options = add_option(options, "fsname", escaped);
449 static char* add_ro_option(char* options, bool ro)
451 return ro ? add_option(options, "ro", NULL) : options;
454 #if defined(__linux__) || defined(__FreeBSD__)
455 static char* add_user_option(char* options)
462 pw = getpwuid(getuid());
463 if (pw == NULL || pw->pw_name == NULL)
466 exfat_error("failed to determine username");
469 return add_option(options, "user", pw->pw_name);
473 #if defined(__linux__)
474 static char* add_blksize_option(char* options, long cluster_size)
476 long page_size = sysconf(_SC_PAGESIZE);
482 snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
483 return add_option(options, "blksize", blksize);
487 static char* add_fuse_options(char* options, const char* spec, bool ro)
489 options = add_fsname_option(options, spec);
492 options = add_ro_option(options, ro);
495 #if defined(__linux__) || defined(__FreeBSD__)
496 options = add_user_option(options);
500 #if defined(__linux__)
501 options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
508 static int fuse_exfat_main(char* mount_options, char* mount_point)
510 char* argv[] = {"exfat", "-s", "-o", mount_options, mount_point, NULL};
511 return fuse_main(sizeof(argv) / sizeof(argv[0]) - 1, argv,
512 &fuse_exfat_ops, NULL);
515 int main(int argc, char* argv[])
517 const char* spec = NULL;
518 char* mount_point = NULL;
524 printf("FUSE exfat %s\n", VERSION);
526 fuse_options = strdup("allow_other,"
527 #if defined(__linux__) || defined(__FreeBSD__)
530 #if defined(__linux__)
533 "default_permissions");
534 exfat_options = strdup("ro_fallback");
535 if (fuse_options == NULL || exfat_options == NULL)
537 exfat_error("failed to allocate options string");
541 while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
546 fuse_options = add_option(fuse_options, "debug", NULL);
547 if (fuse_options == NULL)
556 exfat_options = add_option(exfat_options, optarg, NULL);
557 if (exfat_options == NULL)
566 puts("Copyright (C) 2010-2018 Andrew Nayenko");
577 if (argc - optind != 2)
584 mount_point = argv[optind + 1];
586 if (exfat_mount(&ef, spec, exfat_options) != 0)
595 fuse_options = add_fuse_options(fuse_options, spec, ef.ro != 0);
596 if (fuse_options == NULL)
602 /* let FUSE do all its wizardry */
603 rc = fuse_exfat_main(fuse_options, mount_point);