diff options
-rw-r--r-- | Documentation/filesystems/vfat.txt | 8 | ||||
-rw-r--r-- | fs/fat/fat.h | 14 | ||||
-rw-r--r-- | fs/fat/file.c | 16 | ||||
-rw-r--r-- | fs/fat/inode.c | 17 |
4 files changed, 43 insertions, 12 deletions
diff --git a/Documentation/filesystems/vfat.txt b/Documentation/filesystems/vfat.txt index dc9dc73d7d38..3a5ddc96901a 100644 --- a/Documentation/filesystems/vfat.txt +++ b/Documentation/filesystems/vfat.txt | |||
@@ -124,6 +124,14 @@ sys_immutable -- If set, ATTR_SYS attribute on FAT is handled as | |||
124 | flush -- If set, the filesystem will try to flush to disk more | 124 | flush -- If set, the filesystem will try to flush to disk more |
125 | early than normal. Not set by default. | 125 | early than normal. Not set by default. |
126 | 126 | ||
127 | rodir -- FAT has the ATTR_RO (read-only) attribute. But on Windows, | ||
128 | the ATTR_RO of the directory will be just ignored actually, | ||
129 | and is used by only applications as flag. E.g. it's setted | ||
130 | for the customized folder. | ||
131 | |||
132 | If you want to use ATTR_RO as read-only flag even for | ||
133 | the directory, set this option. | ||
134 | |||
127 | <bool>: 0,1,yes,no,true,false | 135 | <bool>: 0,1,yes,no,true,false |
128 | 136 | ||
129 | TODO | 137 | TODO |
diff --git a/fs/fat/fat.h b/fs/fat/fat.h index 313b645b8126..e9dce5d8e7a7 100644 --- a/fs/fat/fat.h +++ b/fs/fat/fat.h | |||
@@ -38,7 +38,8 @@ struct fat_mount_options { | |||
38 | flush:1, /* write things quickly */ | 38 | flush:1, /* write things quickly */ |
39 | nocase:1, /* Does this need case conversion? 0=need case conversion*/ | 39 | nocase:1, /* Does this need case conversion? 0=need case conversion*/ |
40 | usefree:1, /* Use free_clusters for FAT32 */ | 40 | usefree:1, /* Use free_clusters for FAT32 */ |
41 | tz_utc:1; /* Filesystem timestamps are in UTC */ | 41 | tz_utc:1, /* Filesystem timestamps are in UTC */ |
42 | rodir:1; /* allow ATTR_RO for directory */ | ||
42 | }; | 43 | }; |
43 | 44 | ||
44 | #define FAT_HASH_BITS 8 | 45 | #define FAT_HASH_BITS 8 |
@@ -120,15 +121,20 @@ static inline struct msdos_inode_info *MSDOS_I(struct inode *inode) | |||
120 | /* | 121 | /* |
121 | * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to | 122 | * If ->i_mode can't hold S_IWUGO (i.e. ATTR_RO), we use ->i_attrs to |
122 | * save ATTR_RO instead of ->i_mode. | 123 | * save ATTR_RO instead of ->i_mode. |
124 | * | ||
125 | * If it's directory and !sbi->options.rodir, ATTR_RO isn't read-only | ||
126 | * bit, it's just used as flag for app. | ||
123 | */ | 127 | */ |
124 | static inline int fat_mode_can_hold_ro(struct inode *inode) | 128 | static inline int fat_mode_can_hold_ro(struct inode *inode) |
125 | { | 129 | { |
126 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); | 130 | struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
127 | mode_t mask; | 131 | mode_t mask; |
128 | 132 | ||
129 | if (S_ISDIR(inode->i_mode)) | 133 | if (S_ISDIR(inode->i_mode)) { |
134 | if (!sbi->options.rodir) | ||
135 | return 0; | ||
130 | mask = ~sbi->options.fs_dmask; | 136 | mask = ~sbi->options.fs_dmask; |
131 | else | 137 | } else |
132 | mask = ~sbi->options.fs_fmask; | 138 | mask = ~sbi->options.fs_fmask; |
133 | 139 | ||
134 | if (!(mask & S_IWUGO)) | 140 | if (!(mask & S_IWUGO)) |
@@ -140,7 +146,7 @@ static inline int fat_mode_can_hold_ro(struct inode *inode) | |||
140 | static inline mode_t fat_make_mode(struct msdos_sb_info *sbi, | 146 | static inline mode_t fat_make_mode(struct msdos_sb_info *sbi, |
141 | u8 attrs, mode_t mode) | 147 | u8 attrs, mode_t mode) |
142 | { | 148 | { |
143 | if (attrs & ATTR_RO) | 149 | if (attrs & ATTR_RO && !((attrs & ATTR_DIR) && !sbi->options.rodir)) |
144 | mode &= ~S_IWUGO; | 150 | mode &= ~S_IWUGO; |
145 | 151 | ||
146 | if (attrs & ATTR_DIR) | 152 | if (attrs & ATTR_DIR) |
diff --git a/fs/fat/file.c b/fs/fat/file.c index 81b15c623803..f06a4e525ece 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
@@ -282,11 +282,18 @@ static int fat_sanitize_mode(const struct msdos_sb_info *sbi, | |||
282 | /* | 282 | /* |
283 | * Of the r and x bits, all (subject to umask) must be present. Of the | 283 | * Of the r and x bits, all (subject to umask) must be present. Of the |
284 | * w bits, either all (subject to umask) or none must be present. | 284 | * w bits, either all (subject to umask) or none must be present. |
285 | * | ||
286 | * If fat_mode_can_hold_ro(inode) is false, can't change w bits. | ||
285 | */ | 287 | */ |
286 | if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) | 288 | if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) |
287 | return -EPERM; | 289 | return -EPERM; |
288 | if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) | 290 | if (fat_mode_can_hold_ro(inode)) { |
289 | return -EPERM; | 291 | if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) |
292 | return -EPERM; | ||
293 | } else { | ||
294 | if ((perm & S_IWUGO) != (S_IWUGO & ~mask)) | ||
295 | return -EPERM; | ||
296 | } | ||
290 | 297 | ||
291 | *mode_ptr &= S_IFMT | perm; | 298 | *mode_ptr &= S_IFMT | perm; |
292 | 299 | ||
@@ -316,8 +323,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
316 | { | 323 | { |
317 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | 324 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); |
318 | struct inode *inode = dentry->d_inode; | 325 | struct inode *inode = dentry->d_inode; |
319 | int error = 0; | ||
320 | unsigned int ia_valid; | 326 | unsigned int ia_valid; |
327 | int error; | ||
321 | 328 | ||
322 | /* | 329 | /* |
323 | * Expand the file. Since inode_setattr() updates ->i_size | 330 | * Expand the file. Since inode_setattr() updates ->i_size |
@@ -371,7 +378,8 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
371 | attr->ia_valid &= ~ATTR_MODE; | 378 | attr->ia_valid &= ~ATTR_MODE; |
372 | } | 379 | } |
373 | 380 | ||
374 | error = inode_setattr(inode, attr); | 381 | if (attr->ia_valid) |
382 | error = inode_setattr(inode, attr); | ||
375 | out: | 383 | out: |
376 | return error; | 384 | return error; |
377 | } | 385 | } |
diff --git a/fs/fat/inode.c b/fs/fat/inode.c index 7aaa21cf019a..0da04e6d1e34 100644 --- a/fs/fat/inode.c +++ b/fs/fat/inode.c | |||
@@ -797,8 +797,10 @@ static int fat_show_options(struct seq_file *m, struct vfsmount *mnt) | |||
797 | seq_puts(m, ",uni_xlate"); | 797 | seq_puts(m, ",uni_xlate"); |
798 | if (!opts->numtail) | 798 | if (!opts->numtail) |
799 | seq_puts(m, ",nonumtail"); | 799 | seq_puts(m, ",nonumtail"); |
800 | if (opts->rodir) | ||
801 | seq_puts(m, ",rodir"); | ||
800 | } | 802 | } |
801 | if (sbi->options.flush) | 803 | if (opts->flush) |
802 | seq_puts(m, ",flush"); | 804 | seq_puts(m, ",flush"); |
803 | if (opts->tz_utc) | 805 | if (opts->tz_utc) |
804 | seq_puts(m, ",tz=UTC"); | 806 | seq_puts(m, ",tz=UTC"); |
@@ -814,7 +816,7 @@ enum { | |||
814 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, | 816 | Opt_charset, Opt_shortname_lower, Opt_shortname_win95, |
815 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, | 817 | Opt_shortname_winnt, Opt_shortname_mixed, Opt_utf8_no, Opt_utf8_yes, |
816 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, | 818 | Opt_uni_xl_no, Opt_uni_xl_yes, Opt_nonumtail_no, Opt_nonumtail_yes, |
817 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_err, | 819 | Opt_obsolate, Opt_flush, Opt_tz_utc, Opt_rodir, Opt_err, |
818 | }; | 820 | }; |
819 | 821 | ||
820 | static const match_table_t fat_tokens = { | 822 | static const match_table_t fat_tokens = { |
@@ -886,6 +888,7 @@ static const match_table_t vfat_tokens = { | |||
886 | {Opt_nonumtail_yes, "nonumtail=yes"}, | 888 | {Opt_nonumtail_yes, "nonumtail=yes"}, |
887 | {Opt_nonumtail_yes, "nonumtail=true"}, | 889 | {Opt_nonumtail_yes, "nonumtail=true"}, |
888 | {Opt_nonumtail_yes, "nonumtail"}, | 890 | {Opt_nonumtail_yes, "nonumtail"}, |
891 | {Opt_rodir, "rodir"}, | ||
889 | {Opt_err, NULL} | 892 | {Opt_err, NULL} |
890 | }; | 893 | }; |
891 | 894 | ||
@@ -905,10 +908,13 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
905 | opts->allow_utime = -1; | 908 | opts->allow_utime = -1; |
906 | opts->codepage = fat_default_codepage; | 909 | opts->codepage = fat_default_codepage; |
907 | opts->iocharset = fat_default_iocharset; | 910 | opts->iocharset = fat_default_iocharset; |
908 | if (is_vfat) | 911 | if (is_vfat) { |
909 | opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95; | 912 | opts->shortname = VFAT_SFN_DISPLAY_LOWER|VFAT_SFN_CREATE_WIN95; |
910 | else | 913 | opts->rodir = 0; |
914 | } else { | ||
911 | opts->shortname = 0; | 915 | opts->shortname = 0; |
916 | opts->rodir = 1; | ||
917 | } | ||
912 | opts->name_check = 'n'; | 918 | opts->name_check = 'n'; |
913 | opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0; | 919 | opts->quiet = opts->showexec = opts->sys_immutable = opts->dotsOK = 0; |
914 | opts->utf8 = opts->unicode_xlate = 0; | 920 | opts->utf8 = opts->unicode_xlate = 0; |
@@ -1059,6 +1065,9 @@ static int parse_options(char *options, int is_vfat, int silent, int *debug, | |||
1059 | case Opt_nonumtail_yes: /* empty or 1 or yes or true */ | 1065 | case Opt_nonumtail_yes: /* empty or 1 or yes or true */ |
1060 | opts->numtail = 0; /* negated option */ | 1066 | opts->numtail = 0; /* negated option */ |
1061 | break; | 1067 | break; |
1068 | case Opt_rodir: | ||
1069 | opts->rodir = 1; | ||
1070 | break; | ||
1062 | 1071 | ||
1063 | /* obsolete mount options */ | 1072 | /* obsolete mount options */ |
1064 | case Opt_obsolate: | 1073 | case Opt_obsolate: |