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];
106 exfat_debug("[%s] %s", __func__, path);
108 rc = exfat_lookup(&ef, &parent, path);
111 if (!(parent->attrib & EXFAT_ATTRIB_DIR))
113 exfat_put_node(&ef, parent);
114 exfat_error("'%s' is not a directory (%#hx)", path, parent->attrib);
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(&it)))
130 exfat_get_name(node, name);
131 exfat_debug("[%s] %s: %s, %"PRId64" bytes, cluster 0x%x", __func__,
132 name, node->is_contiguous ? "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);
156 static int fuse_exfat_create(const char* path, mode_t mode,
157 struct fuse_file_info* fi)
159 struct exfat_node* node;
162 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
164 rc = exfat_mknod(&ef, path);
167 rc = exfat_lookup(&ef, &node, path);
174 static int fuse_exfat_release(const char* path, struct fuse_file_info* fi)
177 This handler is called by FUSE on close() syscall. If the FUSE
178 implementation does not call flush handler, we will flush node here.
179 But in this case we will not be able to return an error to the caller.
180 See fuse_exfat_flush() below.
182 exfat_debug("[%s] %s", __func__, path);
183 exfat_flush_node(&ef, get_node(fi));
184 exfat_put_node(&ef, get_node(fi));
185 return 0; /* FUSE ignores this return value */
188 static int fuse_exfat_flush(const char* path, struct fuse_file_info* fi)
191 This handler may be called by FUSE on close() syscall. FUSE also deals
192 with removals of open files, so we don't free clusters on close but
193 only on rmdir and unlink. If the FUSE implementation does not call this
194 handler we will flush node on release. See fuse_exfat_relase() above.
196 exfat_debug("[%s] %s", __func__, path);
197 return exfat_flush_node(&ef, get_node(fi));
200 static int fuse_exfat_fsync(const char* path, int datasync,
201 struct fuse_file_info *fi)
205 exfat_debug("[%s] %s", __func__, path);
206 rc = exfat_flush_nodes(&ef);
209 rc = exfat_flush(&ef);
212 return exfat_fsync(ef.dev);
215 static int fuse_exfat_read(const char* path, char* buffer, size_t size,
216 off_t offset, struct fuse_file_info* fi)
218 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
219 return exfat_generic_pread(&ef, get_node(fi), buffer, size, offset);
222 static int fuse_exfat_write(const char* path, const char* buffer, size_t size,
223 off_t offset, struct fuse_file_info* fi)
225 exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
226 return exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset);
229 static int fuse_exfat_unlink(const char* path)
231 struct exfat_node* node;
234 exfat_debug("[%s] %s", __func__, path);
236 rc = exfat_lookup(&ef, &node, path);
240 rc = exfat_unlink(&ef, node);
241 exfat_put_node(&ef, node);
244 return exfat_cleanup_node(&ef, node);
247 static int fuse_exfat_rmdir(const char* path)
249 struct exfat_node* node;
252 exfat_debug("[%s] %s", __func__, path);
254 rc = exfat_lookup(&ef, &node, path);
258 rc = exfat_rmdir(&ef, node);
259 exfat_put_node(&ef, node);
262 return exfat_cleanup_node(&ef, node);
265 static int fuse_exfat_mknod(const char* path, mode_t mode, dev_t dev)
267 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
268 return exfat_mknod(&ef, path);
271 static int fuse_exfat_mkdir(const char* path, mode_t mode)
273 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
274 return exfat_mkdir(&ef, path);
277 static int fuse_exfat_rename(const char* old_path, const char* new_path)
279 exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
280 return exfat_rename(&ef, old_path, new_path);
283 static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
285 struct exfat_node* node;
288 exfat_debug("[%s] %s", __func__, path);
290 rc = exfat_lookup(&ef, &node, path);
294 exfat_utimes(node, tv);
295 rc = exfat_flush_node(&ef, node);
296 exfat_put_node(&ef, node);
300 static int fuse_exfat_chmod(const char* path, mode_t mode)
302 const mode_t VALID_MODE_MASK = S_IFREG | S_IFDIR |
303 S_IRWXU | S_IRWXG | S_IRWXO;
305 exfat_debug("[%s] %s 0%ho", __func__, path, mode);
306 if (mode & ~VALID_MODE_MASK)
311 static int fuse_exfat_chown(const char* path, uid_t uid, gid_t gid)
313 exfat_debug("[%s] %s %u:%u", __func__, path, uid, gid);
314 if (uid != ef.uid || gid != ef.gid)
319 static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
321 exfat_debug("[%s]", __func__);
323 sfs->f_bsize = CLUSTER_SIZE(*ef.sb);
324 sfs->f_frsize = CLUSTER_SIZE(*ef.sb);
325 sfs->f_blocks = le64_to_cpu(ef.sb->sector_count) >> ef.sb->spc_bits;
326 sfs->f_bavail = exfat_count_free_clusters(&ef);
327 sfs->f_bfree = sfs->f_bavail;
328 sfs->f_namemax = EXFAT_NAME_MAX;
331 Below are fake values because in exFAT there is
332 a) no simple way to count files;
333 b) no such thing as inode;
334 So here we assume that inode = cluster.
336 sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
337 sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
338 sfs->f_ffree = sfs->f_bavail;
343 static void* fuse_exfat_init(struct fuse_conn_info* fci)
345 exfat_debug("[%s]", __func__);
346 #ifdef FUSE_CAP_BIG_WRITES
347 fci->want |= FUSE_CAP_BIG_WRITES;
352 static void fuse_exfat_destroy(void* unused)
354 exfat_debug("[%s]", __func__);
358 static void usage(const char* prog)
360 fprintf(stderr, "Usage: %s [-d] [-o options] [-V] <device> <dir>\n", prog);
364 static struct fuse_operations fuse_exfat_ops =
366 .getattr = fuse_exfat_getattr,
367 .truncate = fuse_exfat_truncate,
368 .readdir = fuse_exfat_readdir,
369 .open = fuse_exfat_open,
370 .create = fuse_exfat_create,
371 .release = fuse_exfat_release,
372 .flush = fuse_exfat_flush,
373 .fsync = fuse_exfat_fsync,
374 .fsyncdir = fuse_exfat_fsync,
375 .read = fuse_exfat_read,
376 .write = fuse_exfat_write,
377 .unlink = fuse_exfat_unlink,
378 .rmdir = fuse_exfat_rmdir,
379 .mknod = fuse_exfat_mknod,
380 .mkdir = fuse_exfat_mkdir,
381 .rename = fuse_exfat_rename,
382 .utimens = fuse_exfat_utimens,
383 .chmod = fuse_exfat_chmod,
384 .chown = fuse_exfat_chown,
385 .statfs = fuse_exfat_statfs,
386 .init = fuse_exfat_init,
387 .destroy = fuse_exfat_destroy,
390 static char* add_option(char* options, const char* name, const char* value)
393 char* optionsf = options;
396 size = strlen(options) + strlen(name) + strlen(value) + 3;
398 size = strlen(options) + strlen(name) + 2;
400 options = realloc(options, size);
404 exfat_error("failed to reallocate options string");
407 strcat(options, ",");
408 strcat(options, name);
411 strcat(options, "=");
412 strcat(options, value);
417 static void escape(char* escaped, const char* orig)
421 if (*orig == ',' || *orig == '\\')
424 while ((*escaped++ = *orig++));
427 static char* add_fsname_option(char* options, const char* spec)
429 /* escaped string cannot be more than twice as big as the original one */
430 char* escaped = malloc(strlen(spec) * 2 + 1);
435 exfat_error("failed to allocate escaped string for %s", spec);
439 /* on some platforms (e.g. Android, Solaris) device names can contain
441 escape(escaped, spec);
442 options = add_option(options, "fsname", escaped);
447 static char* add_ro_option(char* options, bool ro)
449 return ro ? add_option(options, "ro", NULL) : options;
452 static char* add_user_option(char* options)
459 pw = getpwuid(getuid());
460 if (pw == NULL || pw->pw_name == NULL)
463 exfat_error("failed to determine username");
466 return add_option(options, "user", pw->pw_name);
469 static char* add_blksize_option(char* options, long cluster_size)
471 long page_size = sysconf(_SC_PAGESIZE);
477 snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
478 return add_option(options, "blksize", blksize);
481 static char* add_fuse_options(char* options, const char* spec, bool ro)
483 options = add_fsname_option(options, spec);
486 options = add_ro_option(options, ro);
489 options = add_user_option(options);
492 options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
499 static int fuse_exfat_main(char* mount_options, char* mount_point)
501 char* argv[] = {"exfat", "-s", "-o", mount_options, mount_point, NULL};
502 return fuse_main(sizeof(argv) / sizeof(argv[0]) - 1, argv,
503 &fuse_exfat_ops, NULL);
506 int main(int argc, char* argv[])
508 const char* spec = NULL;
509 char* mount_point = NULL;
515 printf("FUSE exfat %s\n", VERSION);
517 fuse_options = strdup("allow_other,"
520 "default_permissions");
521 exfat_options = strdup("ro_fallback");
522 if (fuse_options == NULL || exfat_options == NULL)
524 exfat_error("failed to allocate options string");
528 while ((opt = getopt(argc, argv, "dno:Vv")) != -1)
533 fuse_options = add_option(fuse_options, "debug", NULL);
534 if (fuse_options == NULL)
543 exfat_options = add_option(exfat_options, optarg, NULL);
544 if (exfat_options == NULL)
553 puts("Copyright (C) 2010-2018 Andrew Nayenko");
564 if (argc - optind != 2)
571 mount_point = argv[optind + 1];
573 if (exfat_mount(&ef, spec, exfat_options) != 0)
582 fuse_options = add_fuse_options(fuse_options, spec, (ef.ro == -1));
583 if (fuse_options == NULL)
589 /* let FUSE do all its wizardry */
590 rc = fuse_exfat_main(fuse_options, mount_point);