fat: Update free_clusters even if it is untrusted
[pandora-kernel.git] / fs / fat / inode.c
index f22f287..1604a8a 100644 (file)
@@ -537,7 +537,7 @@ static int fat_statfs(struct dentry *dentry, struct kstatfs *buf)
        struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
 
        /* If the count of free cluster is still unknown, counts it here. */
-       if (sbi->free_clusters == -1) {
+       if (sbi->free_clusters == -1 || !sbi->free_clus_valid) {
                int err = fat_count_free_clusters(dentry->d_sb);
                if (err)
                        return err;
@@ -785,6 +785,8 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
                seq_printf(m, ",gid=%u", opts->fs_gid);
        seq_printf(m, ",fmask=%04o", opts->fs_fmask);
        seq_printf(m, ",dmask=%04o", opts->fs_dmask);
+       if (opts->allow_utime)
+               seq_printf(m, ",allow_utime=%04o", opts->allow_utime);
        if (sbi->nls_disk)
                seq_printf(m, ",codepage=%s", sbi->nls_disk->charset);
        if (isvfat) {
@@ -840,9 +842,9 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt)
 
 enum {
        Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid,
-       Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_usefree, Opt_nocase,
-       Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable,
-       Opt_dots, Opt_nodots,
+       Opt_umask, Opt_dmask, Opt_fmask, Opt_allow_utime, Opt_codepage,
+       Opt_usefree, Opt_nocase, Opt_quiet, Opt_showexec, Opt_debug,
+       Opt_immutable, Opt_dots, Opt_nodots,
        Opt_charset, Opt_shortname_lower, Opt_shortname_win95,
        Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes,
        Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes,
@@ -861,6 +863,7 @@ static match_table_t fat_tokens = {
        {Opt_umask, "umask=%o"},
        {Opt_dmask, "dmask=%o"},
        {Opt_fmask, "fmask=%o"},
+       {Opt_allow_utime, "allow_utime=%o"},
        {Opt_codepage, "codepage=%u"},
        {Opt_usefree, "usefree"},
        {Opt_nocase, "nocase"},
@@ -932,6 +935,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
        opts->fs_uid = current->uid;
        opts->fs_gid = current->gid;
        opts->fs_fmask = opts->fs_dmask = current->fs->umask;
+       opts->allow_utime = -1;
        opts->codepage = fat_default_codepage;
        opts->iocharset = fat_default_iocharset;
        if (is_vfat)
@@ -1019,6 +1023,11 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
                                return 0;
                        opts->fs_fmask = option;
                        break;
+               case Opt_allow_utime:
+                       if (match_octal(&args[0], &option))
+                               return 0;
+                       opts->allow_utime = option & (S_IWGRP | S_IWOTH);
+                       break;
                case Opt_codepage:
                        if (match_int(&args[0], &option))
                                return 0;
@@ -1101,6 +1110,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug,
                       " for FAT filesystems, filesystem will be case sensitive!\n");
        }
 
+       /* If user doesn't specify allow_utime, it's initialized from dmask. */
+       if (opts->allow_utime == (unsigned short)-1)
+               opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH);
        if (opts->unicode_xlate)
                opts->utf8 = 0;
 
@@ -1262,6 +1274,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
        sbi->fat_length = le16_to_cpu(b->fat_length);
        sbi->root_cluster = 0;
        sbi->free_clusters = -1;        /* Don't know yet */
+       sbi->free_clus_valid = 0;
        sbi->prev_free = FAT_START_ENT;
 
        if (!sbi->fat_length && b->fat32_length) {
@@ -1297,8 +1310,8 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
                               sbi->fsinfo_sector);
                } else {
                        if (sbi->options.usefree)
-                               sbi->free_clusters =
-                                       le32_to_cpu(fsinfo->free_clusters);
+                               sbi->free_clus_valid = 1;
+                       sbi->free_clusters = le32_to_cpu(fsinfo->free_clusters);
                        sbi->prev_free = le32_to_cpu(fsinfo->next_cluster);
                }