diff options
author | OGAWA Hirofumi <hirofumi@mail.parknet.co.jp> | 2008-04-28 05:16:26 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-04-28 11:58:47 -0400 |
commit | 1ae43f826b6cb951fc5b0f9c92372a8d5b63c7f9 (patch) | |
tree | aea00f01d74a40e026974182006e8af903b0b241 | |
parent | e97e8de388723f9491514fa0434ddf1fd713a188 (diff) |
fat: Add allow_utime option
Normally utime(2) checks current process is owner of the file, or it
has CAP_FOWNER capability. But FAT filesystem doesn't have uid/gid as
on disk info, so normal check is too unflexible.
With this option you can relax it.
Signed-off-by: OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | Documentation/filesystems/vfat.txt | 15 | ||||
-rw-r--r-- | fs/fat/file.c | 24 | ||||
-rw-r--r-- | fs/fat/inode.c | 18 | ||||
-rw-r--r-- | include/linux/msdos_fs.h | 1 |
4 files changed, 55 insertions, 3 deletions
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt index fcc123ffa252..2d5e1e582e13 100644 --- a/Documentation/filesystems/vfat.txt +++ b/Documentation/filesystems/vfat.txt | |||
@@ -17,6 +17,21 @@ dmask=### -- The permission mask for the directory. | |||
17 | fmask=### -- The permission mask for files. | 17 | fmask=### -- The permission mask for files. |
18 | The default is the umask of current process. | 18 | The default is the umask of current process. |
19 | 19 | ||
20 | allow_utime=### -- This option controls the permission check of mtime/atime. | ||
21 | |||
22 | 20 - If current process is in group of file's group ID, | ||
23 | you can change timestamp. | ||
24 | 2 - Other users can change timestamp. | ||
25 | |||
26 | The default is set from `dmask' option. (If the directory is | ||
27 | writable, utime(2) is also allowed. I.e. ~dmask & 022) | ||
28 | |||
29 | Normally utime(2) checks current process is owner of | ||
30 | the file, or it has CAP_FOWNER capability. But FAT | ||
31 | filesystem doesn't have uid/gid on disk, so normal | ||
32 | check is too unflexible. With this option you can | ||
33 | relax it. | ||
34 | |||
20 | codepage=### -- Sets the codepage number for converting to shortname | 35 | codepage=### -- Sets the codepage number for converting to shortname |
21 | characters on FAT filesystem. | 36 | characters on FAT filesystem. |
22 | By default, FAT_DEFAULT_CODEPAGE setting is used. | 37 | By default, FAT_DEFAULT_CODEPAGE setting is used. |
diff --git a/fs/fat/file.c b/fs/fat/file.c index e73f13a13792..d604bb132422 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -280,11 +280,27 @@ static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode, | |||
280 | return 0; | 280 | return 0; |
281 | } | 281 | } |
282 | 282 | ||
283 | static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) | ||
284 | { | ||
285 | mode_t allow_utime = sbi->options.allow_utime; | ||
286 | |||
287 | if (current->fsuid != inode->i_uid) { | ||
288 | if (in_group_p(inode->i_gid)) | ||
289 | allow_utime >>= 3; | ||
290 | if (allow_utime & MAY_WRITE) | ||
291 | return 1; | ||
292 | } | ||
293 | |||
294 | /* use a default check */ | ||
295 | return 0; | ||
296 | } | ||
297 | |||
283 | int fat_setattr(struct dentry *dentry, struct iattr *attr) | 298 | int fat_setattr(struct dentry *dentry, struct iattr *attr) |
284 | { | 299 | { |
285 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | 300 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); |
286 | struct inode *inode = dentry->d_inode; | 301 | struct inode *inode = dentry->d_inode; |
287 | int mask, error = 0; | 302 | int mask, error = 0; |
303 | unsigned int ia_valid; | ||
288 | 304 | ||
289 | lock_kernel(); | 305 | lock_kernel(); |
290 | 306 | ||
@@ -302,7 +318,15 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
302 | } | 318 | } |
303 | } | 319 | } |
304 | 320 | ||
321 | /* Check for setting the inode time. */ | ||
322 | ia_valid = attr->ia_valid; | ||
323 | if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET)) { | ||
324 | if (fat_allow_set_time(sbi, inode)) | ||
325 | attr->ia_valid &= ~(ATTR_MTIME_SET | ATTR_ATIME_SET); | ||
326 | } | ||
327 | |||
305 | error = inode_change_ok(inode, attr); | 328 | error = inode_change_ok(inode, attr); |
329 | attr->ia_valid = ia_valid; | ||
306 | if (error) { | 330 | if (error) { |
307 | if (sbi->options.quiet) | 331 | if (sbi->options.quiet) |
308 | error = 0; | 332 | error = 0; |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index f22f287e507a..886f6095a378 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -785,6 +785,8 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
785 | seq_printf(m, ",gid=%u", opts->fs_gid); | 785 | seq_printf(m, ",gid=%u", opts->fs_gid); |
786 | seq_printf(m, ",fmask=%04o", opts->fs_fmask); | 786 | seq_printf(m, ",fmask=%04o", opts->fs_fmask); |
787 | seq_printf(m, ",dmask=%04o", opts->fs_dmask); | 787 | seq_printf(m, ",dmask=%04o", opts->fs_dmask); |
788 | if (opts->allow_utime) | ||
789 | seq_printf(m, ",allow_utime=%04o", opts->allow_utime); | ||
788 | if (sbi->nls_disk) | 790 | if (sbi->nls_disk) |
789 | seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); | 791 | seq_printf(m, ",codepage=%s", sbi->nls_disk->charset); |
790 | if (isvfat) { | 792 | if (isvfat) { |
@@ -840,9 +842,9 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
840 | 842 | ||
841 | enum { | 843 | enum { |
842 | Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid, | 844 | Opt_check_n, Opt_check_r, Opt_check_s, Opt_uid, Opt_gid, |
843 | Opt_umask, Opt_dmask, Opt_fmask, Opt_codepage, Opt_usefree, Opt_nocase, | 845 | Opt_umask, Opt_dmask, Opt_fmask, Opt_allow_utime, Opt_codepage, |
844 | Opt_quiet, Opt_showexec, Opt_debug, Opt_immutable, | 846 | Opt_usefree, Opt_nocase, Opt_quiet, Opt_showexec, Opt_debug, |
845 | Opt_dots, Opt_nodots, | 847 | Opt_immutable, Opt_dots, Opt_nodots, |
846 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, | 848 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, |
847 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 849 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
848 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 850 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
@@ -861,6 +863,7 @@ static match_table_t fat_tokens = { | |||
861 | {Opt_umask, "umask=%o"}, | 863 | {Opt_umask, "umask=%o"}, |
862 | {Opt_dmask, "dmask=%o"}, | 864 | {Opt_dmask, "dmask=%o"}, |
863 | {Opt_fmask, "fmask=%o"}, | 865 | {Opt_fmask, "fmask=%o"}, |
866 | {Opt_allow_utime, "allow_utime=%o"}, | ||
864 | {Opt_codepage, "codepage=%u"}, | 867 | {Opt_codepage, "codepage=%u"}, |
865 | {Opt_usefree, "usefree"}, | 868 | {Opt_usefree, "usefree"}, |
866 | {Opt_nocase, "nocase"}, | 869 | {Opt_nocase, "nocase"}, |
@@ -932,6 +935,7 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
932 | opts->fs_uid = current->uid; | 935 | opts->fs_uid = current->uid; |
933 | opts->fs_gid = current->gid; | 936 | opts->fs_gid = current->gid; |
934 | opts->fs_fmask = opts->fs_dmask = current->fs->umask; | 937 | opts->fs_fmask = opts->fs_dmask = current->fs->umask; |
938 | opts->allow_utime = -1; | ||
935 | opts->codepage = fat_default_codepage; | 939 | opts->codepage = fat_default_codepage; |
936 | opts->iocharset = fat_default_iocharset; | 940 | opts->iocharset = fat_default_iocharset; |
937 | if (is_vfat) | 941 | if (is_vfat) |
@@ -1019,6 +1023,11 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
1019 | return 0; | 1023 | return 0; |
1020 | opts->fs_fmask = option; | 1024 | opts->fs_fmask = option; |
1021 | break; | 1025 | break; |
1026 | case Opt_allow_utime: | ||
1027 | if (match_octal(&args[0], &option)) | ||
1028 | return 0; | ||
1029 | opts->allow_utime = option & (S_IWGRP | S_IWOTH); | ||
1030 | break; | ||
1022 | case Opt_codepage: | 1031 | case Opt_codepage: |
1023 | if (match_int(&args[0], &option)) | 1032 | if (match_int(&args[0], &option)) |
1024 | return 0; | 1033 | return 0; |
@@ -1101,6 +1110,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
1101 | " for FAT filesystems, filesystem will be case sensitive!\n"); | 1110 | " for FAT filesystems, filesystem will be case sensitive!\n"); |
1102 | } | 1111 | } |
1103 | 1112 | ||
1113 | /* If user doesn't specify allow_utime, it's initialized from dmask. */ | ||
1114 | if (opts->allow_utime == (unsigned short)-1) | ||
1115 | opts->allow_utime = ~opts->fs_dmask & (S_IWGRP | S_IWOTH); | ||
1104 | if (opts->unicode_xlate) | 1116 | if (opts->unicode_xlate) |
1105 | opts->utf8 = 0; | 1117 | opts->utf8 = 0; |
1106 | 1118 | ||
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index c4bed98bc00b..81fb9bc53220 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h | |||
@@ -195,6 +195,7 @@ struct fat_mount_options { | |||
195 | char *iocharset; /* Charset used for filename input/display */ | 195 | char *iocharset; /* Charset used for filename input/display */ |
196 | unsigned short shortname; /* flags for shortname display/create rule */ | 196 | unsigned short shortname; /* flags for shortname display/create rule */ |
197 | unsigned char name_check; /* r = relaxed, n = normal, s = strict */ | 197 | unsigned char name_check; /* r = relaxed, n = normal, s = strict */ |
198 | unsigned short allow_utime;/* permission for setting the [am]time */ | ||
198 | unsigned quiet:1, /* set = fake successful chmods and chowns */ | 199 | unsigned quiet:1, /* set = fake successful chmods and chowns */ |
199 | showexec:1, /* set = only set x bit for com/exe/bat */ | 200 | showexec:1, /* set = only set x bit for com/exe/bat */ |
200 | sys_immutable:1, /* set = system files are immutable */ | 201 | sys_immutable:1, /* set = system files are immutable */ |