OSDN Git Service

Fix memory leak on realloc() failure.
[android-x86/external-exfat.git] / fuse / main.c
index 333c2c4..2f157c4 100644 (file)
@@ -83,6 +83,13 @@ static int fuse_exfat_truncate(const char* path, off_t size)
                return rc;
 
        rc = exfat_truncate(&ef, node, size, true);
+       if (rc != 0)
+       {
+               exfat_flush_node(&ef, node);    /* ignore return code */
+               exfat_put_node(&ef, node);
+               return rc;
+       }
+       rc = exfat_flush_node(&ef, node);
        exfat_put_node(&ef, node);
        return rc;
 }
@@ -149,9 +156,28 @@ static int fuse_exfat_open(const char* path, struct fuse_file_info* fi)
 
 static int fuse_exfat_release(const char* path, struct fuse_file_info* fi)
 {
+       /*
+          This handler is called by FUSE on close() syscall. If the FUSE
+          implementation does not call flush handler, we will flush node here.
+          But in this case we will not be able to return an error to the caller.
+          See fuse_exfat_flush() below.
+       */
        exfat_debug("[%s] %s", __func__, path);
+       exfat_flush_node(&ef, get_node(fi));
        exfat_put_node(&ef, get_node(fi));
-       return 0;
+       return 0; /* FUSE ignores this return value */
+}
+
+static int fuse_exfat_flush(const char* path, struct fuse_file_info* fi)
+{
+       /*
+          This handler may be called by FUSE on close() syscall. FUSE also deals
+          with removals of open files, so we don't free clusters on close but
+          only on rmdir and unlink. If the FUSE implementation does not call this
+          handler we will flush node on release. See fuse_exfat_relase() above.
+       */
+       exfat_debug("[%s] %s", __func__, path);
+       return exfat_flush_node(&ef, get_node(fi));
 }
 
 static int fuse_exfat_fsync(const char* path, int datasync,
@@ -160,10 +186,9 @@ static int fuse_exfat_fsync(const char* path, int datasync,
        int rc;
 
        exfat_debug("[%s] %s", __func__, path);
-       rc = exfat_flush_node(&ef, get_node(fi));
+       rc = exfat_flush(&ef);
        if (rc != 0)
                return rc;
-       exfat_flush(&ef);
        return exfat_fsync(ef.dev);
 }
 
@@ -204,7 +229,9 @@ static int fuse_exfat_unlink(const char* path)
 
        rc = exfat_unlink(&ef, node);
        exfat_put_node(&ef, node);
-       return rc;
+       if (rc != 0)
+               return rc;
+       return exfat_cleanup_node(&ef, node);
 }
 
 static int fuse_exfat_rmdir(const char* path)
@@ -220,7 +247,9 @@ static int fuse_exfat_rmdir(const char* path)
 
        rc = exfat_rmdir(&ef, node);
        exfat_put_node(&ef, node);
-       return rc;
+       if (rc != 0)
+               return rc;
+       return exfat_cleanup_node(&ef, node);
 }
 
 static int fuse_exfat_mknod(const char* path, mode_t mode, dev_t dev)
@@ -253,8 +282,9 @@ static int fuse_exfat_utimens(const char* path, const struct timespec tv[2])
                return rc;
 
        exfat_utimes(node, tv);
+       rc = exfat_flush_node(&ef, node);
        exfat_put_node(&ef, node);
-       return 0;
+       return rc;
 }
 
 static int fuse_exfat_chmod(const char* path, mode_t mode)
@@ -293,7 +323,7 @@ static int fuse_exfat_statfs(const char* path, struct statvfs* sfs)
           b) no such thing as inode;
           So here we assume that inode = cluster.
        */
-       sfs->f_files = (sfs->f_blocks - sfs->f_bfree) >> ef.sb->spc_bits;
+       sfs->f_files = le32_to_cpu(ef.sb->cluster_count);
        sfs->f_favail = sfs->f_bfree >> ef.sb->spc_bits;
        sfs->f_ffree = sfs->f_bavail;
 
@@ -328,6 +358,7 @@ static struct fuse_operations fuse_exfat_ops =
        .readdir        = fuse_exfat_readdir,
        .open           = fuse_exfat_open,
        .release        = fuse_exfat_release,
+       .flush          = fuse_exfat_flush,
        .fsync          = fuse_exfat_fsync,
        .fsyncdir       = fuse_exfat_fsync,
        .read           = fuse_exfat_read,
@@ -348,6 +379,7 @@ static struct fuse_operations fuse_exfat_ops =
 static char* add_option(char* options, const char* name, const char* value)
 {
        size_t size;
+       char* optionsf = options;
 
        if (value)
                size = strlen(options) + strlen(name) + strlen(value) + 3;
@@ -357,6 +389,7 @@ static char* add_option(char* options, const char* name, const char* value)
        options = realloc(options, size);
        if (options == NULL)
        {
+               free(optionsf);
                exfat_error("failed to reallocate options string");
                return NULL;
        }