main.c (01.09.09)
FUSE-based exFAT implementation. Requires FUSE 2.6 or later.
- Copyright (C) 2009, 2010 Andrew Nayenko
+ Copyright (C) 2010-2013 Andrew Nayenko
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#define FUSE_USE_VERSION 26
#include <fuse.h>
#include <errno.h>
#include <fcntl.h>
#error FUSE 2.6 or later is required
#endif
-const char* default_options = "ro_fallback,allow_other,blkdev";
+const char* default_options = "ro_fallback,allow_other,blkdev,big_writes,"
+ "defer_permissions";
struct exfat ef;
struct exfat_node* node;
int rc;
- exfat_debug("[fuse_exfat_getattr] %s", path);
+ exfat_debug("[%s] %s", __func__, path);
rc = exfat_lookup(&ef, &node, path);
if (rc != 0)
struct exfat_node* node;
int rc;
- exfat_debug("[fuse_exfat_truncate] %s, %"PRIu64, path, (uint64_t) size);
+ exfat_debug("[%s] %s, %"PRId64, __func__, path, size);
rc = exfat_lookup(&ef, &node, path);
if (rc != 0)
int rc;
char name[EXFAT_NAME_MAX + 1];
- exfat_debug("[fuse_exfat_readdir] %s", path);
+ exfat_debug("[%s] %s", __func__, path);
rc = exfat_lookup(&ef, &parent, path);
if (rc != 0)
while ((node = exfat_readdir(&ef, &it)))
{
exfat_get_name(node, name, EXFAT_NAME_MAX);
- exfat_debug("[fuse_exfat_readdir] %s: %s, %"PRIu64" bytes, cluster %u",
+ exfat_debug("[%s] %s: %s, %"PRId64" bytes, cluster 0x%x", __func__,
name, IS_CONTIGUOUS(*node) ? "contiguous" : "fragmented",
- (uint64_t) node->size, node->start_cluster);
+ node->size, node->start_cluster);
filler(buffer, name, NULL, 0);
exfat_put_node(&ef, node);
}
struct exfat_node* node;
int rc;
- exfat_debug("[fuse_exfat_open] %s", path);
+ exfat_debug("[%s] %s", __func__, path);
rc = exfat_lookup(&ef, &node, path);
if (rc != 0)
static int fuse_exfat_release(const char* path, struct fuse_file_info* fi)
{
+ exfat_debug("[%s] %s", __func__, path);
exfat_put_node(&ef, get_node(fi));
return 0;
}
static int fuse_exfat_read(const char* path, char* buffer, size_t size,
off_t offset, struct fuse_file_info* fi)
{
- exfat_debug("[fuse_exfat_read] %s (%zu bytes)", path, size);
- return exfat_read(&ef, get_node(fi), buffer, size, offset);
+ exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
+ if (exfat_generic_pread(&ef, get_node(fi), buffer, size, offset) != size)
+ return EOF;
+ return size;
}
static int fuse_exfat_write(const char* path, const char* buffer, size_t size,
off_t offset, struct fuse_file_info* fi)
{
- exfat_debug("[fuse_exfat_write] %s (%zu bytes)", path, size);
- return exfat_write(&ef, get_node(fi), buffer, size, offset);
+ exfat_debug("[%s] %s (%zu bytes)", __func__, path, size);
+ if (exfat_generic_pwrite(&ef, get_node(fi), buffer, size, offset) != size)
+ return EOF;
+ return size;
}
static int fuse_exfat_unlink(const char* path)
struct exfat_node* node;
int rc;
- exfat_debug("[fuse_exfat_unlink] %s", path);
+ exfat_debug("[%s] %s", __func__, path);
rc = exfat_lookup(&ef, &node, path);
if (rc != 0)
struct exfat_node* node;
int rc;
- exfat_debug("[fuse_exfat_rmdir] %s", path);
+ exfat_debug("[%s] %s", __func__, path);
rc = exfat_lookup(&ef, &node, path);
if (rc != 0)
static int fuse_exfat_mknod(const char* path, mode_t mode, dev_t dev)
{
- exfat_debug("[fuse_exfat_mknod] %s", path);
+ exfat_debug("[%s] %s 0%ho", __func__, path, mode);
return exfat_mknod(&ef, path);
}
static int fuse_exfat_mkdir(const char* path, mode_t mode)
{
- exfat_debug("[fuse_exfat_mkdir] %s", path);
+ exfat_debug("[%s] %s 0%ho", __func__, path, mode);
return exfat_mkdir(&ef, path);
}
static int fuse_exfat_rename(const char* old_path, const char* new_path)
{
- exfat_debug("[fuse_exfat_rename] %s => %s", old_path, new_path);
+ exfat_debug("[%s] %s => %s", __func__, old_path, new_path);
return exfat_rename(&ef, old_path, new_path);
}
struct exfat_node* node;
int rc;
- exfat_debug("[fuse_exfat_utimens] %s", path);
+ exfat_debug("[%s] %s", __func__, path);
rc = exfat_lookup(&ef, &node, path);
if (rc != 0)
return 0;
}
+#ifdef __APPLE__
+static int fuse_exfat_chmod(const char* path, mode_t mode)
+{
+ exfat_debug("[%s] %s 0%ho", __func__, path, mode);
+ /* make OS X utilities happy */
+ return 0;
+}
+#endif
+
static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
{
+ exfat_debug("[%s]", __func__);
+
sfs->f_bsize = CLUSTER_SIZE(*ef.sb);
sfs->f_frsize = CLUSTER_SIZE(*ef.sb);
sfs->f_blocks = le64_to_cpu(ef.sb->sector_count) >> ef.sb->spc_bits;
return 0;
}
+static void* fuse_exfat_init(struct fuse_conn_info* fci)
+{
+ exfat_debug("[%s]", __func__);
+#ifdef FUSE_CAP_BIG_WRITES
+ fci->want |= FUSE_CAP_BIG_WRITES;
+#endif
+ return NULL;
+}
+
static void fuse_exfat_destroy(void* unused)
{
+ exfat_debug("[%s]", __func__);
exfat_unmount(&ef);
}
.mkdir = fuse_exfat_mkdir,
.rename = fuse_exfat_rename,
.utimens = fuse_exfat_utimens,
+#ifdef __APPLE__
+ .chmod = fuse_exfat_chmod,
+#endif
.statfs = fuse_exfat_statfs,
+ .init = fuse_exfat_init,
.destroy = fuse_exfat_destroy,
};
static char* add_fsname_option(char* options, const char* spec)
{
- char spec_abs[PATH_MAX];
+ char* spec_abs = realpath(spec, NULL);
- if (realpath(spec, spec_abs) == NULL)
+ if (spec_abs == NULL)
{
free(options);
exfat_error("failed to get absolute path for `%s'", spec);
return NULL;
}
- return add_option(options, "fsname", spec_abs);
+ options = add_option(options, "fsname", spec_abs);
+ free(spec_abs);
+ return options;
}
static char* add_user_option(char* options)
else if (strcmp(*pp, "-v") == 0)
{
free(mount_options);
- puts("Copyright (C) 2009 Andrew Nayenko");
+ puts("Copyright (C) 2010-2013 Andrew Nayenko");
return 0;
}
else if (spec == NULL)
return 1;
}
- if (ef.ro_fallback)
+ if (ef.ro == -1) /* read-only fallback was used */
{
mount_options = add_option(mount_options, "ro", NULL);
if (mount_options == NULL)
}
/* exit session on HUP, TERM and INT signals and ignore PIPE signal */
- if (fuse_set_signal_handlers(fuse_get_session(fh)))
+ if (fuse_set_signal_handlers(fuse_get_session(fh)) != 0)
{
fuse_unmount(mount_point, fc);
fuse_destroy(fh);
exfat_unmount(&ef);
+ exfat_error("failed to set signal handlers");
return 1;
}
- /* go to background unless "-d" option is passed */
- fuse_daemonize(debug);
-
- /* FUSE main loop */
- fuse_loop(fh);
+ /* go to background (unless "-d" option is passed) and run FUSE
+ main loop */
+ if (fuse_daemonize(debug) == 0)
+ {
+ if (fuse_loop(fh) != 0)
+ exfat_error("FUSE loop failure");
+ }
+ else
+ exfat_error("failed to daemonize");
- /* it's quite illogical but fuse_unmount() must be called BEFORE
- fuse_destroy() */
+ fuse_remove_signal_handlers(fuse_get_session(fh));
+ /* note that fuse_unmount() must be called BEFORE fuse_destroy() */
fuse_unmount(mount_point, fc);
fuse_destroy(fh);
return 0;