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
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[EXFAT_UTF8_NAME_BUFFER_MAX];
110 exfat_debug("[%s] %s", __func__, path);
112 rc = exfat_lookup(&ef, &parent, path);
115 if (!(parent->attrib & EXFAT_ATTRIB_DIR))
117 exfat_put_node(&ef, parent);
118 exfat_error("'%s' is not a directory (%#hx)", path, parent->attrib);
122 filler(buffer, ".", NULL, 0);
123 filler(buffer, "..", NULL, 0);
125 rc = exfat_opendir(&ef, parent, &it);
128 exfat_put_node(&ef, parent);
129 exfat_error("failed to open directory '%s'", path);
132 while ((node = exfat_readdir(&it)))
134 exfat_get_name(node, name);
135 exfat_debug("[%s] %s: %s, %"PRId64" bytes, cluster 0x%x", __func__,
136 name, node->is_contiguous ? "contiguous" : "fragmented",
137 node->size, node->start_cluster);
138 exfat_stat(&ef, node, &stbuf);
139 filler(buffer, name, &stbuf, 0);
140 exfat_put_node(&ef, node);
142 exfat_closedir(&ef, &it);
143 exfat_put_node(&ef, parent);
147 static int fuse_exfat_open(const char* path, struct fuse_file_info* fi)
149 struct exfat_node* node;
152 exfat_debug("[%s] %s", __func__, path);
154 rc = exfat_lookup(&ef, &node, path);
161 static int fuse_exfat_create(const char* path, mode_t mode,
162 struct fuse_file_info* fi)
164 struct exfat_node* node;
167 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
169 rc = exfat_mknod(&ef, path);
172 rc = exfat_lookup(&ef, &node, path);
179 static int fuse_exfat_release(const char* path, struct fuse_file_info* fi)
182 This handler is called by FUSE on close() syscall. If the FUSE
183 implementation does not call flush handler, we will flush node here.
184 But in this case we will not be able to return an error to the caller.
185 See fuse_exfat_flush() below.
187 exfat_debug("[%s] %s", __func__, path);
188 exfat_flush_node(&ef, get_node(fi));
189 exfat_put_node(&ef, get_node(fi));
190 return 0; /* FUSE ignores this return value */
193 static int fuse_exfat_flush(const char* path, struct fuse_file_info* fi)
196 This handler may be called by FUSE on close() syscall. FUSE also deals
197 with removals of open files, so we don't free clusters on close but
198 only on rmdir and unlink. If the FUSE implementation does not call this
199 handler we will flush node on release. See fuse_exfat_relase() above.
201 exfat_debug("[%s] %s", __func__, path);
202 return exfat_flush_node(&ef, get_node(fi));
205 static int fuse_exfat_fsync(const char* path, int datasync,
206 struct fuse_file_info *fi)
210 exfat_debug("[%s] %s", __func__, path);
211 rc = exfat_flush_nodes(&ef);
214 rc = exfat_flush(&ef);
217 return exfat_fsync(ef.dev);
220 static int fuse_exfat_read(const char* path, char* buffer, size_t size,
221 off_t offset, struct fuse_file_info* fi)
223 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
224 return exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
227 static int fuse_exfat_write(const char* path, const char* buffer, size_t size,
228 off_t offset, struct fuse_file_info* fi)
230 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
231 return exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
234 static int fuse_exfat_unlink(const char* path)
236 struct exfat_node* node;
239 exfat_debug("[%s] %s", __func__, path);
241 rc = exfat_lookup(&ef, &node, path);
245 rc = exfat_unlink(&ef, node);
246 exfat_put_node(&ef, node);
249 return exfat_cleanup_node(&ef, node);
252 static int fuse_exfat_rmdir(const char* path)
254 struct exfat_node* node;
257 exfat_debug("[%s] %s", __func__, path);
259 rc = exfat_lookup(&ef, &node, path);
263 rc = exfat_rmdir(&ef, node);
264 exfat_put_node(&ef, node);
267 return exfat_cleanup_node(&ef, node);
270 static int fuse_exfat_mknod(const char* path, mode_t mode, dev_t dev)
272 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
273 return exfat_mknod(&ef, path);
276 static int fuse_exfat_mkdir(const char* path, mode_t mode)
278 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
279 return exfat_mkdir(&ef, path);
282 static int fuse_exfat_rename(const char* old_path, const char* new_path)
284 exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
285 return exfat_rename(&ef, old_path, new_path);
288 static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
290 struct exfat_node* node;
293 exfat_debug("[%s] %s", __func__, path);
295 rc = exfat_lookup(&ef, &node, path);
299 exfat_utimes(node, tv);
300 rc = exfat_flush_node(&ef, node);
301 exfat_put_node(&ef, node);
305 static int fuse_exfat_chmod(const char* path, mode_t mode)
307 const mode_t VALID_MODE_MASK = S_IFREG | S_IFDIR |
308 S_IRWXU | S_IRWXG | S_IRWXO;
310 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
311 if (mode & ~VALID_MODE_MASK)
316 static int fuse_exfat_chown(const char* path, uid_t uid, gid_t gid)
318 exfat_debug("[%s] %s %u:%u", __func__, path, uid, gid);
319 if (uid != ef.uid || gid != ef.gid)
324 static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
326 exfat_debug("[%s]", __func__);
328 sfs->f_bsize = CLUSTER_SIZE(*ef.sb);
329 sfs->f_frsize = CLUSTER_SIZE(*ef.sb);
330 sfs->f_blocks = le64_to_cpu(ef.sb->sector_count) >> ef.sb->spc_bits;
331 sfs->f_bavail = exfat_count_free_clusters(&ef);
332 sfs->f_bfree = sfs->f_bavail;
333 sfs->f_namemax = EXFAT_NAME_MAX;
336 Below are fake values because in exFAT there is
337 a) no simple way to count files;
338 b) no such thing as inode;
339 So here we assume that inode = cluster.
341 sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
342 sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
343 sfs->f_ffree = sfs->f_bavail;
348 static void* fuse_exfat_init(struct fuse_conn_info* fci)
350 exfat_debug("[%s]", __func__);
351 #ifdef FUSE_CAP_BIG_WRITES
352 fci->want |= FUSE_CAP_BIG_WRITES;
357 static void fuse_exfat_destroy(void* unused)
359 exfat_debug("[%s]", __func__);
363 static void usage(const char* prog)
365 fprintf(stderr, "Usage: %s [-d] [-o options] [-V] <device> <dir>\n", prog);
369 static struct fuse_operations fuse_exfat_ops =
371 .getattr = fuse_exfat_getattr,
372 .truncate = fuse_exfat_truncate,
373 .readdir = fuse_exfat_readdir,
374 .open = fuse_exfat_open,
375 .create = fuse_exfat_create,
376 .release = fuse_exfat_release,
377 .flush = fuse_exfat_flush,
378 .fsync = fuse_exfat_fsync,
379 .fsyncdir = fuse_exfat_fsync,
380 .read = fuse_exfat_read,
381 .write = fuse_exfat_write,
382 .unlink = fuse_exfat_unlink,
383 .rmdir = fuse_exfat_rmdir,
384 .mknod = fuse_exfat_mknod,
385 .mkdir = fuse_exfat_mkdir,
386 .rename = fuse_exfat_rename,
387 .utimens = fuse_exfat_utimens,
388 .chmod = fuse_exfat_chmod,
389 .chown = fuse_exfat_chown,
390 .statfs = fuse_exfat_statfs,
391 .init = fuse_exfat_init,
392 .destroy = fuse_exfat_destroy,
395 static char* add_option(char* options, const char* name, const char* value)
398 char* optionsf = options;
401 size = strlen(options) + strlen(name) + strlen(value) + 3;
403 size = strlen(options) + strlen(name) + 2;
405 options = realloc(options, size);
409 exfat_error("failed to reallocate options string");
412 strcat(options, ",");
413 strcat(options, name);
416 strcat(options, "=");
417 strcat(options, value);
422 static void escape(char* escaped, const char* orig)
426 if (*orig == ',' || *orig == '\\')
429 while ((*escaped++ = *orig++));
432 static char* add_fsname_option(char* options, const char* spec)
434 /* escaped string cannot be more than twice as big as the original one */
435 char* escaped = malloc(strlen(spec) * 2 + 1);
440 exfat_error("failed to allocate escaped string for %s", spec);
444 /* on some platforms (e.g. Android, Solaris) device names can contain
446 escape(escaped, spec);
447 options = add_option(options, "fsname", escaped);
452 static char* add_ro_option(char* options, bool ro)
454 return ro ? add_option(options, "ro", NULL) : options;
457 static char* add_user_option(char* options)
464 pw = getpwuid(getuid());
465 if (pw == NULL || pw->pw_name == NULL)
468 exfat_error("failed to determine username");
471 return add_option(options, "user", pw->pw_name);
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);
486 static char* add_fuse_options(char* options, const char* spec, bool ro)
488 options = add_fsname_option(options, spec);
491 options = add_ro_option(options, ro);
494 options = add_user_option(options);
497 options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
504 static int fuse_exfat_main(char* mount_options, char* mount_point)
506 char* argv[] = {"exfat", "-s", "-o", mount_options, mount_point, NULL};
507 return fuse_main(sizeof(argv) / sizeof(argv[0]) - 1, argv,
508 &fuse_exfat_ops, NULL);
511 int main(int argc, char* argv[])
513 const char* spec = NULL;
514 char* mount_point = NULL;
519 printf("FUSE exfat %s\n", VERSION);
521 mount_options = strdup(default_options);
522 if (mount_options == NULL)
524 exfat_error("failed to allocate options string");
528 while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
533 mount_options = add_option(mount_options, "debug", NULL);
534 if (mount_options == NULL)
540 mount_options = add_option(mount_options, optarg, NULL);
541 if (mount_options == NULL)
546 puts("Copyright (C) 2010-2018 Andrew Nayenko");
556 if (argc - optind != 2)
562 mount_point = argv[optind + 1];
564 if (exfat_mount(&ef, spec, mount_options) != 0)
570 mount_options = add_fuse_options(mount_options, spec, (ef.ro != 0));
571 if (mount_options == NULL)
577 /* let FUSE do all its wizardry */
578 rc = fuse_exfat_main(mount_options, mount_point);