OSDN Git Service

Move FUSE arguments construction into a separate function.
[android-x86/external-exfat.git] / fuse / main.c
index 409e503..94fcdc5 100644 (file)
 #include <string.h>
 #include <exfat.h>
 #include <inttypes.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <unistd.h>
 
 #define exfat_debug(format, ...)
 
@@ -33,6 +37,8 @@
        #error FUSE 2.6 or later is required
 #endif
 
+const char* default_options = "allow_other,blkdev";
+
 struct exfat ef;
 
 static struct exfat_node* get_node(const struct fuse_file_info* fi)
@@ -224,12 +230,10 @@ static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
 
 static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
 {
-       const uint64_t block_count = le64_to_cpu(ef.sb->block_count);
-
-       sfs->f_bsize = BLOCK_SIZE(*ef.sb);
+       sfs->f_bsize = CLUSTER_SIZE(*ef.sb);
        sfs->f_frsize = CLUSTER_SIZE(*ef.sb);
-       sfs->f_blocks = block_count;
-       sfs->f_bavail = block_count - ef.sb->allocated_percent * block_count / 100;
+       sfs->f_blocks = le64_to_cpu(ef.sb->block_count) >> ef.sb->bpc_bits;
+       sfs->f_bavail = exfat_count_free_clusters(&ef);
        sfs->f_bfree = sfs->f_bavail;
        sfs->f_namemax = EXFAT_NAME_MAX;
 
@@ -253,7 +257,7 @@ static void fuse_exfat_destroy(void* unused)
 
 static void usage(const char* prog)
 {
-       fprintf(stderr, "Usage: %s <spec> <mountpoint> [-o options]\n", prog);
+       fprintf(stderr, "Usage: %s [-d] [-o options] <device> <dir>\n", prog);
        exit(1);
 }
 
@@ -276,13 +280,95 @@ static struct fuse_operations fuse_exfat_ops =
        .destroy        = fuse_exfat_destroy,
 };
 
+static char* add_option(char* options, const char* name, const char* value)
+{
+       size_t size;
+
+       if (value)
+               size = strlen(options) + strlen(name) + strlen(value) + 3;
+       else
+               size = strlen(options) + strlen(name) + 2;
+
+       options = realloc(options, size);
+       if (options == NULL)
+       {
+               exfat_error("failed to reallocate options string");
+               return NULL;
+       }
+       strcat(options, ",");
+       strcat(options, name);
+       if (value)
+       {
+               strcat(options, "=");
+               strcat(options, value);
+       }
+       return options;
+}
+
+static char* add_fsname_option(char* options, const char* spec)
+{
+       char spec_abs[PATH_MAX];
+
+       if (realpath(spec, spec_abs) == NULL)
+       {
+               free(options);
+               exfat_error("failed to get absolute path for `%s'", spec);
+               return NULL;
+       }
+       return add_option(options, "fsname", spec_abs);
+}
+
+static char* add_user_option(char* options)
+{
+       struct passwd* pw;
+
+       if (getuid() == 0)
+               return options;
+
+       pw = getpwuid(getuid());
+       if (pw == NULL || pw->pw_name == NULL)
+       {
+               free(options);
+               exfat_error("failed to determine username");
+               return NULL;
+       }
+       return add_option(options, "user", pw->pw_name);
+}
+
+static char* add_blksize_option(char* options, long cluster_size)
+{
+       long page_size = sysconf(_SC_PAGESIZE);
+       char blksize[20];
+
+       if (page_size < 1)
+               page_size = 0x1000;
+
+       snprintf(blksize, sizeof(blksize), "%ld", MIN(page_size, cluster_size));
+       return add_option(options, "blksize", blksize);
+}
+
+static char* add_fuse_options(char* options, const char* spec)
+{
+       options = add_fsname_option(options, spec);
+       if (options == NULL)
+               return NULL;
+       options = add_user_option(options);
+       if (options == NULL)
+               return NULL;
+       options = add_blksize_option(options, CLUSTER_SIZE(*ef.sb));
+       if (options == NULL)
+               return NULL;
+
+       return options;
+}
+
 int main(int argc, char* argv[])
 {
        struct fuse_args mount_args = FUSE_ARGS_INIT(0, NULL);
        struct fuse_args newfs_args = FUSE_ARGS_INIT(0, NULL);
        const char* spec = NULL;
        const char* mount_point = NULL;
-       const char* mount_options = "";
+       char* mount_options;
        int debug = 0;
        struct fuse_chan* fc = NULL;
        struct fuse* fh = NULL;
@@ -291,6 +377,13 @@ int main(int argc, char* argv[])
        printf("FUSE exfat %u.%u.%u\n",
                        EXFAT_VERSION_MAJOR, EXFAT_VERSION_MINOR, EXFAT_VERSION_PATCH);
 
+       mount_options = strdup(default_options);
+       if (mount_options == NULL)
+       {
+               exfat_error("failed to allocate options string");
+               return 1;
+       }
+
        for (pp = argv + 1; *pp; pp++)
        {
                if (strcmp(*pp, "-o") == 0)
@@ -298,7 +391,9 @@ int main(int argc, char* argv[])
                        pp++;
                        if (*pp == NULL)
                                usage(argv[0]);
-                       mount_options = *pp;
+                       mount_options = add_option(mount_options, *pp, NULL);
+                       if (mount_options == NULL)
+                               return 1;
                }
                else if (strcmp(*pp, "-d") == 0)
                        debug = 1;
@@ -307,28 +402,57 @@ int main(int argc, char* argv[])
                else if (mount_point == NULL)
                        mount_point = *pp;
                else
+               {
+                       free(mount_options);
                        usage(argv[0]);
+               }
        }
        if (spec == NULL || mount_point == NULL)
+       {
+               free(mount_options);
                usage(argv[0]);
+       }
+
+       if (exfat_mount(&ef, spec, mount_options) != 0)
+       {
+               free(mount_options);
+               return 1;
+       }
+
+       mount_options = add_fuse_options(mount_options, spec);
+       if (mount_options == NULL)
+       {
+               exfat_unmount(&ef);
+               return 1;
+       }
 
        /* create arguments for fuse_mount() */
        if (fuse_opt_add_arg(&mount_args, "exfat") != 0 ||
                fuse_opt_add_arg(&mount_args, "-o") != 0 ||
                fuse_opt_add_arg(&mount_args, mount_options) != 0)
+       {
+               exfat_unmount(&ef);
+               free(mount_options);
                return 1;
+       }
+
+       free(mount_options);
 
        /* create FUSE mount point */
        fc = fuse_mount(mount_point, &mount_args);
        fuse_opt_free_args(&mount_args);
        if (fc == NULL)
+       {
+               exfat_unmount(&ef);
                return 1;
+       }
 
        /* create arguments for fuse_new() */
        if (fuse_opt_add_arg(&newfs_args, "") != 0 ||
                (debug && fuse_opt_add_arg(&newfs_args, "-d") != 0))
        {
                fuse_unmount(mount_point, fc);
+               exfat_unmount(&ef);
                return 1;
        }
 
@@ -339,6 +463,7 @@ int main(int argc, char* argv[])
        if (fh == NULL)
        {
                fuse_unmount(mount_point, fc);
+               exfat_unmount(&ef);
                return 1;
        }
 
@@ -347,13 +472,7 @@ int main(int argc, char* argv[])
        {
                fuse_unmount(mount_point, fc);
                fuse_destroy(fh);
-               return 1;
-       }
-
-       if (exfat_mount(&ef, spec, mount_options) != 0)
-       {
-               fuse_unmount(mount_point, fc);
-               fuse_destroy(fh);
+               exfat_unmount(&ef);
                return 1;
        }