exfat: fix appending discontinuous clusters to empty file
[linux-block.git] / fs / exfat / file.c
index d25a96a148af4cdb966c5d20f720aa944cab10c2..cc00f1a7a1e18082af9e0e8ff28f5995de75f1ba 100644 (file)
@@ -35,13 +35,18 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
        if (new_num_clusters == num_clusters)
                goto out;
 
-       exfat_chain_set(&clu, ei->start_clu, num_clusters, ei->flags);
-       ret = exfat_find_last_cluster(sb, &clu, &last_clu);
-       if (ret)
-               return ret;
+       if (num_clusters) {
+               exfat_chain_set(&clu, ei->start_clu, num_clusters, ei->flags);
+               ret = exfat_find_last_cluster(sb, &clu, &last_clu);
+               if (ret)
+                       return ret;
+
+               clu.dir = last_clu + 1;
+       } else {
+               last_clu = EXFAT_EOF_CLUSTER;
+               clu.dir = EXFAT_EOF_CLUSTER;
+       }
 
-       clu.dir = (last_clu == EXFAT_EOF_CLUSTER) ?
-                       EXFAT_EOF_CLUSTER : last_clu + 1;
        clu.size = 0;
        clu.flags = ei->flags;
 
@@ -51,17 +56,19 @@ static int exfat_cont_expand(struct inode *inode, loff_t size)
                return ret;
 
        /* Append new clusters to chain */
-       if (clu.flags != ei->flags) {
-               exfat_chain_cont_cluster(sb, ei->start_clu, num_clusters);
-               ei->flags = ALLOC_FAT_CHAIN;
-       }
-       if (clu.flags == ALLOC_FAT_CHAIN)
-               if (exfat_ent_set(sb, last_clu, clu.dir))
-                       goto free_clu;
-
-       if (num_clusters == 0)
+       if (num_clusters) {
+               if (clu.flags != ei->flags)
+                       if (exfat_chain_cont_cluster(sb, ei->start_clu, num_clusters))
+                               goto free_clu;
+
+               if (clu.flags == ALLOC_FAT_CHAIN)
+                       if (exfat_ent_set(sb, last_clu, clu.dir))
+                               goto free_clu;
+       } else
                ei->start_clu = clu.dir;
 
+       ei->flags = clu.flags;
+
 out:
        inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
        /* Expanded range not zeroed, do not update valid_size */