diff options
| -rw-r--r-- | fs/fat/file.c | 183 | ||||
| -rw-r--r-- | fs/msdos/namei.c | 2 | ||||
| -rw-r--r-- | fs/vfat/namei.c | 2 | ||||
| -rw-r--r-- | include/linux/msdos_fs.h | 2 |
4 files changed, 87 insertions, 102 deletions
diff --git a/fs/fat/file.c b/fs/fat/file.c index 2a3bed967041..b61a98f5398a 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
| @@ -157,104 +157,6 @@ out: | |||
| 157 | return err; | 157 | return err; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | static int check_mode(const struct msdos_sb_info *sbi, mode_t mode) | ||
| 161 | { | ||
| 162 | mode_t req = mode & ~S_IFMT; | ||
| 163 | |||
| 164 | /* | ||
| 165 | * Of the r and x bits, all (subject to umask) must be present. Of the | ||
| 166 | * w bits, either all (subject to umask) or none must be present. | ||
| 167 | */ | ||
| 168 | |||
| 169 | if (S_ISREG(mode)) { | ||
| 170 | req &= ~sbi->options.fs_fmask; | ||
| 171 | |||
| 172 | if ((req & (S_IRUGO | S_IXUGO)) != | ||
| 173 | ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask)) | ||
| 174 | return -EPERM; | ||
| 175 | |||
| 176 | if ((req & S_IWUGO) != 0 && | ||
| 177 | (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask)) | ||
| 178 | return -EPERM; | ||
| 179 | } else if (S_ISDIR(mode)) { | ||
| 180 | req &= ~sbi->options.fs_dmask; | ||
| 181 | |||
| 182 | if ((req & (S_IRUGO | S_IXUGO)) != | ||
| 183 | ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask)) | ||
| 184 | return -EPERM; | ||
| 185 | |||
| 186 | if ((req & S_IWUGO) != 0 && | ||
| 187 | (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask)) | ||
| 188 | return -EPERM; | ||
| 189 | } else { | ||
| 190 | return -EPERM; | ||
| 191 | } | ||
| 192 | |||
| 193 | return 0; | ||
| 194 | } | ||
| 195 | |||
| 196 | int fat_notify_change(struct dentry *dentry, struct iattr *attr) | ||
| 197 | { | ||
| 198 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | ||
| 199 | struct inode *inode = dentry->d_inode; | ||
| 200 | int mask, error = 0; | ||
| 201 | |||
| 202 | lock_kernel(); | ||
| 203 | |||
| 204 | /* | ||
| 205 | * Expand the file. Since inode_setattr() updates ->i_size | ||
| 206 | * before calling the ->truncate(), but FAT needs to fill the | ||
| 207 | * hole before it. | ||
| 208 | */ | ||
| 209 | if (attr->ia_valid & ATTR_SIZE) { | ||
| 210 | if (attr->ia_size > inode->i_size) { | ||
| 211 | error = fat_cont_expand(inode, attr->ia_size); | ||
| 212 | if (error || attr->ia_valid == ATTR_SIZE) | ||
| 213 | goto out; | ||
| 214 | attr->ia_valid &= ~ATTR_SIZE; | ||
| 215 | } | ||
| 216 | } | ||
| 217 | |||
| 218 | error = inode_change_ok(inode, attr); | ||
| 219 | if (error) { | ||
| 220 | if (sbi->options.quiet) | ||
| 221 | error = 0; | ||
| 222 | goto out; | ||
| 223 | } | ||
| 224 | if (((attr->ia_valid & ATTR_UID) && | ||
| 225 | (attr->ia_uid != sbi->options.fs_uid)) || | ||
| 226 | ((attr->ia_valid & ATTR_GID) && | ||
| 227 | (attr->ia_gid != sbi->options.fs_gid))) | ||
| 228 | error = -EPERM; | ||
| 229 | |||
| 230 | if (error) { | ||
| 231 | if (sbi->options.quiet) | ||
| 232 | error = 0; | ||
| 233 | goto out; | ||
| 234 | } | ||
| 235 | |||
| 236 | if (attr->ia_valid & ATTR_MODE) { | ||
| 237 | error = check_mode(sbi, attr->ia_mode); | ||
| 238 | if (error != 0 && !sbi->options.quiet) | ||
| 239 | goto out; | ||
| 240 | } | ||
| 241 | |||
| 242 | error = inode_setattr(inode, attr); | ||
| 243 | if (error) | ||
| 244 | goto out; | ||
| 245 | |||
| 246 | if (S_ISDIR(inode->i_mode)) | ||
| 247 | mask = sbi->options.fs_dmask; | ||
| 248 | else | ||
| 249 | mask = sbi->options.fs_fmask; | ||
| 250 | inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask); | ||
| 251 | out: | ||
| 252 | unlock_kernel(); | ||
| 253 | return error; | ||
| 254 | } | ||
| 255 | |||
| 256 | EXPORT_SYMBOL_GPL(fat_notify_change); | ||
| 257 | |||
| 258 | /* Free all clusters after the skip'th cluster. */ | 160 | /* Free all clusters after the skip'th cluster. */ |
| 259 | static int fat_free(struct inode *inode, int skip) | 161 | static int fat_free(struct inode *inode, int skip) |
| 260 | { | 162 | { |
| @@ -355,8 +257,91 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
| 355 | } | 257 | } |
| 356 | EXPORT_SYMBOL_GPL(fat_getattr); | 258 | EXPORT_SYMBOL_GPL(fat_getattr); |
| 357 | 259 | ||
| 260 | static int fat_check_mode(const struct msdos_sb_info *sbi, mode_t mode) | ||
| 261 | { | ||
| 262 | mode_t mask, req = mode & ~S_IFMT; | ||
| 263 | |||
| 264 | if (S_ISREG(mode)) | ||
| 265 | mask = sbi->options.fs_fmask; | ||
| 266 | else | ||
| 267 | mask = sbi->options.fs_dmask; | ||
| 268 | |||
| 269 | /* | ||
| 270 | * Of the r and x bits, all (subject to umask) must be present. Of the | ||
| 271 | * w bits, either all (subject to umask) or none must be present. | ||
| 272 | */ | ||
| 273 | req &= ~mask; | ||
| 274 | if ((req & (S_IRUGO | S_IXUGO)) != ((S_IRUGO | S_IXUGO) & ~mask)) | ||
| 275 | return -EPERM; | ||
| 276 | if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask))) | ||
| 277 | return -EPERM; | ||
| 278 | |||
| 279 | return 0; | ||
| 280 | } | ||
| 281 | |||
| 282 | int fat_setattr(struct dentry *dentry, struct iattr *attr) | ||
| 283 | { | ||
| 284 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | ||
| 285 | struct inode *inode = dentry->d_inode; | ||
| 286 | int mask, error = 0; | ||
| 287 | |||
| 288 | lock_kernel(); | ||
| 289 | |||
| 290 | /* | ||
| 291 | * Expand the file. Since inode_setattr() updates ->i_size | ||
| 292 | * before calling the ->truncate(), but FAT needs to fill the | ||
| 293 | * hole before it. | ||
| 294 | */ | ||
| 295 | if (attr->ia_valid & ATTR_SIZE) { | ||
| 296 | if (attr->ia_size > inode->i_size) { | ||
| 297 | error = fat_cont_expand(inode, attr->ia_size); | ||
| 298 | if (error || attr->ia_valid == ATTR_SIZE) | ||
| 299 | goto out; | ||
| 300 | attr->ia_valid &= ~ATTR_SIZE; | ||
| 301 | } | ||
| 302 | } | ||
| 303 | |||
| 304 | error = inode_change_ok(inode, attr); | ||
| 305 | if (error) { | ||
| 306 | if (sbi->options.quiet) | ||
| 307 | error = 0; | ||
| 308 | goto out; | ||
| 309 | } | ||
| 310 | if (((attr->ia_valid & ATTR_UID) && | ||
| 311 | (attr->ia_uid != sbi->options.fs_uid)) || | ||
| 312 | ((attr->ia_valid & ATTR_GID) && | ||
| 313 | (attr->ia_gid != sbi->options.fs_gid))) | ||
| 314 | error = -EPERM; | ||
| 315 | |||
| 316 | if (error) { | ||
| 317 | if (sbi->options.quiet) | ||
| 318 | error = 0; | ||
| 319 | goto out; | ||
| 320 | } | ||
| 321 | |||
| 322 | if (attr->ia_valid & ATTR_MODE) { | ||
| 323 | error = fat_check_mode(sbi, attr->ia_mode); | ||
| 324 | if (error != 0 && !sbi->options.quiet) | ||
| 325 | goto out; | ||
| 326 | } | ||
| 327 | |||
| 328 | error = inode_setattr(inode, attr); | ||
| 329 | if (error) | ||
| 330 | goto out; | ||
| 331 | |||
| 332 | if (S_ISDIR(inode->i_mode)) | ||
| 333 | mask = sbi->options.fs_dmask; | ||
| 334 | else | ||
| 335 | mask = sbi->options.fs_fmask; | ||
| 336 | inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask); | ||
| 337 | out: | ||
| 338 | unlock_kernel(); | ||
| 339 | return error; | ||
| 340 | } | ||
| 341 | EXPORT_SYMBOL_GPL(fat_setattr); | ||
| 342 | |||
| 358 | const struct inode_operations fat_file_inode_operations = { | 343 | const struct inode_operations fat_file_inode_operations = { |
| 359 | .truncate = fat_truncate, | 344 | .truncate = fat_truncate, |
| 360 | .setattr = fat_notify_change, | 345 | .setattr = fat_setattr, |
| 361 | .getattr = fat_getattr, | 346 | .getattr = fat_getattr, |
| 362 | }; | 347 | }; |
diff --git a/fs/msdos/namei.c b/fs/msdos/namei.c index 30f7d0ae2215..2d4358c59f68 100644 --- a/fs/msdos/namei.c +++ b/fs/msdos/namei.c | |||
| @@ -653,7 +653,7 @@ static const struct inode_operations msdos_dir_inode_operations = { | |||
| 653 | .mkdir = msdos_mkdir, | 653 | .mkdir = msdos_mkdir, |
| 654 | .rmdir = msdos_rmdir, | 654 | .rmdir = msdos_rmdir, |
| 655 | .rename = msdos_rename, | 655 | .rename = msdos_rename, |
| 656 | .setattr = fat_notify_change, | 656 | .setattr = fat_setattr, |
| 657 | .getattr = fat_getattr, | 657 | .getattr = fat_getattr, |
| 658 | }; | 658 | }; |
| 659 | 659 | ||
diff --git a/fs/vfat/namei.c b/fs/vfat/namei.c index cd450bea9f1a..efc70576e4b4 100644 --- a/fs/vfat/namei.c +++ b/fs/vfat/namei.c | |||
| @@ -1003,7 +1003,7 @@ static const struct inode_operations vfat_dir_inode_operations = { | |||
| 1003 | .mkdir = vfat_mkdir, | 1003 | .mkdir = vfat_mkdir, |
| 1004 | .rmdir = vfat_rmdir, | 1004 | .rmdir = vfat_rmdir, |
| 1005 | .rename = vfat_rename, | 1005 | .rename = vfat_rename, |
| 1006 | .setattr = fat_notify_change, | 1006 | .setattr = fat_setattr, |
| 1007 | .getattr = fat_getattr, | 1007 | .getattr = fat_getattr, |
| 1008 | }; | 1008 | }; |
| 1009 | 1009 | ||
diff --git a/include/linux/msdos_fs.h b/include/linux/msdos_fs.h index f950921523f5..c4bed98bc00b 100644 --- a/include/linux/msdos_fs.h +++ b/include/linux/msdos_fs.h | |||
| @@ -401,7 +401,7 @@ extern int fat_generic_ioctl(struct inode *inode, struct file *filp, | |||
| 401 | unsigned int cmd, unsigned long arg); | 401 | unsigned int cmd, unsigned long arg); |
| 402 | extern const struct file_operations fat_file_operations; | 402 | extern const struct file_operations fat_file_operations; |
| 403 | extern const struct inode_operations fat_file_inode_operations; | 403 | extern const struct inode_operations fat_file_inode_operations; |
| 404 | extern int fat_notify_change(struct dentry * dentry, struct iattr * attr); | 404 | extern int fat_setattr(struct dentry * dentry, struct iattr * attr); |
| 405 | extern void fat_truncate(struct inode *inode); | 405 | extern void fat_truncate(struct inode *inode); |
| 406 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, | 406 | extern int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, |
| 407 | struct kstat *stat); | 407 | struct kstat *stat); |
