Blame view
fs/fat/file.c
11 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 6 7 |
/* * linux/fs/fat/file.c * * Written 1992,1993 by Werner Almesberger * * regular file handling primitives for fat-based filesystems */ |
16f7e0fe2 [PATCH] capable/c... |
8 |
#include <linux/capability.h> |
1da177e4c Linux-2.6.12-rc2 |
9 |
#include <linux/module.h> |
7845bc3e1 fat: convert to u... |
10 |
#include <linux/compat.h> |
42a74f206 [PATCH] r/o bind ... |
11 |
#include <linux/mount.h> |
1da177e4c Linux-2.6.12-rc2 |
12 |
#include <linux/time.h> |
1da177e4c Linux-2.6.12-rc2 |
13 |
#include <linux/buffer_head.h> |
05eb0b51f [PATCH] fat: supp... |
14 |
#include <linux/writeback.h> |
3fcfab16c [PATCH] separate ... |
15 |
#include <linux/backing-dev.h> |
ae78bf9c4 [PATCH] add -o fl... |
16 |
#include <linux/blkdev.h> |
b1da47e29 [patch 3/4] fat: ... |
17 18 |
#include <linux/fsnotify.h> #include <linux/security.h> |
9e975dae2 fat: split includ... |
19 |
#include "fat.h" |
1da177e4c Linux-2.6.12-rc2 |
20 |
|
21bea4959 fat: split fat_ge... |
21 22 23 24 25 26 27 28 29 30 31 32 |
static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr) { u32 attr; mutex_lock(&inode->i_mutex); attr = fat_make_attrs(inode); mutex_unlock(&inode->i_mutex); return put_user(attr, user_attr); } static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr) |
1da177e4c Linux-2.6.12-rc2 |
33 |
{ |
21bea4959 fat: split fat_ge... |
34 |
struct inode *inode = file->f_path.dentry->d_inode; |
1da177e4c Linux-2.6.12-rc2 |
35 |
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
21bea4959 fat: split fat_ge... |
36 37 38 39 |
int is_dir = S_ISDIR(inode->i_mode); u32 attr, oldattr; struct iattr ia; int err; |
1da177e4c Linux-2.6.12-rc2 |
40 |
|
21bea4959 fat: split fat_ge... |
41 42 43 |
err = get_user(attr, user_attr); if (err) goto out; |
1da177e4c Linux-2.6.12-rc2 |
44 |
|
21bea4959 fat: split fat_ge... |
45 |
mutex_lock(&inode->i_mutex); |
a561be710 switch a bunch of... |
46 |
err = mnt_want_write_file(file); |
21bea4959 fat: split fat_ge... |
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
if (err) goto out_unlock_inode; /* * ATTR_VOLUME and ATTR_DIR cannot be changed; this also * prevents the user from turning us into a VFAT * longname entry. Also, we obviously can't set * any of the NTFS attributes in the high 24 bits. */ attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR); /* Merge in ATTR_VOLUME and ATTR_DIR */ attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) | (is_dir ? ATTR_DIR : 0); oldattr = fat_make_attrs(inode); /* Equivalent to a chmod() */ ia.ia_valid = ATTR_MODE | ATTR_CTIME; ia.ia_ctime = current_fs_time(inode->i_sb); if (is_dir) ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO); else { ia.ia_mode = fat_make_mode(sbi, attr, S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO)); } |
1da177e4c Linux-2.6.12-rc2 |
71 |
|
21bea4959 fat: split fat_ge... |
72 73 74 75 |
/* The root directory has no attributes */ if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) { err = -EINVAL; goto out_drop_write; |
1da177e4c Linux-2.6.12-rc2 |
76 |
} |
1da177e4c Linux-2.6.12-rc2 |
77 |
|
21bea4959 fat: split fat_ge... |
78 79 80 81 82 83 |
if (sbi->options.sys_immutable && ((attr | oldattr) & ATTR_SYS) && !capable(CAP_LINUX_IMMUTABLE)) { err = -EPERM; goto out_drop_write; } |
1da177e4c Linux-2.6.12-rc2 |
84 |
|
21bea4959 fat: split fat_ge... |
85 86 87 88 89 90 91 92 |
/* * The security check is questionable... We single * out the RO attribute for checking by the security * module, just because it maps to a file mode. */ err = security_inode_setattr(file->f_path.dentry, &ia); if (err) goto out_drop_write; |
1da177e4c Linux-2.6.12-rc2 |
93 |
|
21bea4959 fat: split fat_ge... |
94 95 96 97 98 99 100 101 102 103 |
/* This MUST be done before doing anything irreversible... */ err = fat_setattr(file->f_path.dentry, &ia); if (err) goto out_drop_write; fsnotify_change(file->f_path.dentry, ia.ia_valid); if (sbi->options.sys_immutable) { if (attr & ATTR_SYS) inode->i_flags |= S_IMMUTABLE; else |
1adffbae2 fat: Fix corrupt ... |
104 |
inode->i_flags &= ~S_IMMUTABLE; |
21bea4959 fat: split fat_ge... |
105 |
} |
1da177e4c Linux-2.6.12-rc2 |
106 |
|
21bea4959 fat: split fat_ge... |
107 108 109 |
fat_save_attrs(inode, attr); mark_inode_dirty(inode); out_drop_write: |
2a79f17e4 vfs: mnt_drop_wri... |
110 |
mnt_drop_write_file(file); |
21bea4959 fat: split fat_ge... |
111 112 113 114 115 |
out_unlock_inode: mutex_unlock(&inode->i_mutex); out: return err; } |
1da177e4c Linux-2.6.12-rc2 |
116 |
|
7845bc3e1 fat: convert to u... |
117 |
long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) |
1da177e4c Linux-2.6.12-rc2 |
118 |
{ |
7845bc3e1 fat: convert to u... |
119 |
struct inode *inode = filp->f_path.dentry->d_inode; |
1da177e4c Linux-2.6.12-rc2 |
120 |
u32 __user *user_attr = (u32 __user *)arg; |
1da177e4c Linux-2.6.12-rc2 |
121 |
|
1da177e4c Linux-2.6.12-rc2 |
122 123 |
switch (cmd) { case FAT_IOCTL_GET_ATTRIBUTES: |
21bea4959 fat: split fat_ge... |
124 |
return fat_ioctl_get_attributes(inode, user_attr); |
1da177e4c Linux-2.6.12-rc2 |
125 |
case FAT_IOCTL_SET_ATTRIBUTES: |
21bea4959 fat: split fat_ge... |
126 |
return fat_ioctl_set_attributes(filp, user_attr); |
1da177e4c Linux-2.6.12-rc2 |
127 128 129 130 |
default: return -ENOTTY; /* Inappropriate ioctl for device */ } } |
7845bc3e1 fat: convert to u... |
131 132 133 134 135 136 137 138 |
#ifdef CONFIG_COMPAT static long fat_generic_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { return fat_generic_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); } #endif |
ae78bf9c4 [PATCH] add -o fl... |
139 140 141 142 143 |
static int fat_file_release(struct inode *inode, struct file *filp) { if ((filp->f_mode & FMODE_WRITE) && MSDOS_SB(inode->i_sb)->options.flush) { fat_flush_inodes(inode->i_sb, inode, NULL); |
8aa7e847d Fix congestion_wa... |
144 |
congestion_wait(BLK_RW_ASYNC, HZ/10); |
ae78bf9c4 [PATCH] add -o fl... |
145 146 147 |
} return 0; } |
02c24a821 fs: push i_mutex ... |
148 |
int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync) |
b522412ae Sanitize ->fsync(... |
149 |
{ |
7ea808591 drop unused dentr... |
150 |
struct inode *inode = filp->f_mapping->host; |
b522412ae Sanitize ->fsync(... |
151 |
int res, err; |
02c24a821 fs: push i_mutex ... |
152 |
res = generic_file_fsync(filp, start, end, datasync); |
b522412ae Sanitize ->fsync(... |
153 154 155 156 |
err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping); return res ? res : err; } |
4b6f5d20b [PATCH] Make most... |
157 |
const struct file_operations fat_file_operations = { |
1da177e4c Linux-2.6.12-rc2 |
158 159 160 |
.llseek = generic_file_llseek, .read = do_sync_read, .write = do_sync_write, |
1da177e4c Linux-2.6.12-rc2 |
161 |
.aio_read = generic_file_aio_read, |
ef402268f [PATCH] FAT: miss... |
162 |
.aio_write = generic_file_aio_write, |
1da177e4c Linux-2.6.12-rc2 |
163 |
.mmap = generic_file_mmap, |
ae78bf9c4 [PATCH] add -o fl... |
164 |
.release = fat_file_release, |
7845bc3e1 fat: convert to u... |
165 166 167 168 |
.unlocked_ioctl = fat_generic_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = fat_generic_compat_ioctl, #endif |
b522412ae Sanitize ->fsync(... |
169 |
.fsync = fat_file_fsync, |
5ffc4ef45 sendfile: remove ... |
170 |
.splice_read = generic_file_splice_read, |
1da177e4c Linux-2.6.12-rc2 |
171 |
}; |
05eb0b51f [PATCH] fat: supp... |
172 173 174 175 176 177 178 179 180 181 182 183 |
static int fat_cont_expand(struct inode *inode, loff_t size) { struct address_space *mapping = inode->i_mapping; loff_t start = inode->i_size, count = size - inode->i_size; int err; err = generic_cont_expand_simple(inode, size); if (err) goto out; inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; mark_inode_dirty(inode); |
2f3d675bc fat: Opencode syn... |
184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 |
if (IS_SYNC(inode)) { int err2; /* * Opencode syncing since we don't have a file open to use * standard fsync path. */ err = filemap_fdatawrite_range(mapping, start, start + count - 1); err2 = sync_mapping_buffers(mapping); if (!err) err = err2; err2 = write_inode_now(inode, 1); if (!err) err = err2; if (!err) { err = filemap_fdatawait_range(mapping, start, start + count - 1); } } |
05eb0b51f [PATCH] fat: supp... |
204 205 206 |
out: return err; } |
1da177e4c Linux-2.6.12-rc2 |
207 208 209 210 211 212 213 214 |
/* Free all clusters after the skip'th cluster. */ static int fat_free(struct inode *inode, int skip) { struct super_block *sb = inode->i_sb; int err, wait, free_start, i_start, i_logstart; if (MSDOS_I(inode)->i_start == 0) return 0; |
3b641407a [PATCH] fat: Fix ... |
215 |
fat_cache_inval_inode(inode); |
1da177e4c Linux-2.6.12-rc2 |
216 |
wait = IS_DIRSYNC(inode); |
3b641407a [PATCH] fat: Fix ... |
217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 |
i_start = free_start = MSDOS_I(inode)->i_start; i_logstart = MSDOS_I(inode)->i_logstart; /* First, we write the new file size. */ if (!skip) { MSDOS_I(inode)->i_start = 0; MSDOS_I(inode)->i_logstart = 0; } MSDOS_I(inode)->i_attrs |= ATTR_ARCH; inode->i_ctime = inode->i_mtime = CURRENT_TIME_SEC; if (wait) { err = fat_sync_inode(inode); if (err) { MSDOS_I(inode)->i_start = i_start; MSDOS_I(inode)->i_logstart = i_logstart; return err; } } else mark_inode_dirty(inode); /* Write a new EOF, and get the remaining cluster chain for freeing. */ |
1da177e4c Linux-2.6.12-rc2 |
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
if (skip) { struct fat_entry fatent; int ret, fclus, dclus; ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus); if (ret < 0) return ret; else if (ret == FAT_ENT_EOF) return 0; fatent_init(&fatent); ret = fat_ent_read(inode, &fatent, dclus); if (ret == FAT_ENT_EOF) { fatent_brelse(&fatent); return 0; } else if (ret == FAT_ENT_FREE) { |
85c785919 FAT: add 'errors'... |
254 |
fat_fs_error(sb, |
1da177e4c Linux-2.6.12-rc2 |
255 |
"%s: invalid cluster chain (i_pos %lld)", |
8e24eea72 fs: replace remai... |
256 |
__func__, MSDOS_I(inode)->i_pos); |
1da177e4c Linux-2.6.12-rc2 |
257 258 259 260 261 262 263 264 265 266 267 |
ret = -EIO; } else if (ret > 0) { err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait); if (err) ret = err; } fatent_brelse(&fatent); if (ret < 0) return ret; free_start = ret; |
1da177e4c Linux-2.6.12-rc2 |
268 |
} |
1da177e4c Linux-2.6.12-rc2 |
269 270 271 272 |
inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9); /* Freeing the remained cluster chain */ return fat_free_clusters(inode, free_start); |
1da177e4c Linux-2.6.12-rc2 |
273 |
} |
459f6ed3b fat: convert to u... |
274 |
void fat_truncate_blocks(struct inode *inode, loff_t offset) |
1da177e4c Linux-2.6.12-rc2 |
275 |
{ |
9c20616c3 Make FAT users ha... |
276 |
struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb); |
1da177e4c Linux-2.6.12-rc2 |
277 278 279 280 281 282 283 |
const unsigned int cluster_size = sbi->cluster_size; int nr_clusters; /* * This protects against truncating a file bigger than it was then * trying to write into the hole. */ |
459f6ed3b fat: convert to u... |
284 285 |
if (MSDOS_I(inode)->mmu_private > offset) MSDOS_I(inode)->mmu_private = offset; |
1da177e4c Linux-2.6.12-rc2 |
286 |
|
459f6ed3b fat: convert to u... |
287 |
nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits; |
1da177e4c Linux-2.6.12-rc2 |
288 |
|
1da177e4c Linux-2.6.12-rc2 |
289 |
fat_free(inode, nr_clusters); |
ae78bf9c4 [PATCH] add -o fl... |
290 |
fat_flush_inodes(inode->i_sb, inode, NULL); |
1da177e4c Linux-2.6.12-rc2 |
291 |
} |
da63fc7ce [PATCH] fat: add ... |
292 293 294 295 296 297 298 299 |
int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) { struct inode *inode = dentry->d_inode; generic_fillattr(inode, stat); stat->blksize = MSDOS_SB(inode->i_sb)->cluster_size; return 0; } EXPORT_SYMBOL_GPL(fat_getattr); |
2d518f84e fat: relax the pe... |
300 301 |
static int fat_sanitize_mode(const struct msdos_sb_info *sbi, struct inode *inode, umode_t *mode_ptr) |
1278fdd34 fat: fat_notify_c... |
302 |
{ |
dacd0e7b3 fat: propagate um... |
303 |
umode_t mask, perm; |
1278fdd34 fat: fat_notify_c... |
304 |
|
2d518f84e fat: relax the pe... |
305 306 |
/* * Note, the basic check is already done by a caller of |
9c0aa1b87 fat: Cleanup FAT ... |
307 |
* (attr->ia_mode & ~FAT_VALID_MODE) |
2d518f84e fat: relax the pe... |
308 309 310 |
*/ if (S_ISREG(inode->i_mode)) |
1278fdd34 fat: fat_notify_c... |
311 312 313 |
mask = sbi->options.fs_fmask; else mask = sbi->options.fs_dmask; |
2d518f84e fat: relax the pe... |
314 |
perm = *mode_ptr & ~(S_IFMT | mask); |
1278fdd34 fat: fat_notify_c... |
315 316 317 |
/* * Of the r and x bits, all (subject to umask) must be present. Of the * w bits, either all (subject to umask) or none must be present. |
dfc209c00 fat: Fix ATTR_RO ... |
318 319 |
* * If fat_mode_can_hold_ro(inode) is false, can't change w bits. |
1278fdd34 fat: fat_notify_c... |
320 |
*/ |
2d518f84e fat: relax the pe... |
321 |
if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) |
1278fdd34 fat: fat_notify_c... |
322 |
return -EPERM; |
dfc209c00 fat: Fix ATTR_RO ... |
323 324 325 326 327 328 329 |
if (fat_mode_can_hold_ro(inode)) { if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) return -EPERM; } else { if ((perm & S_IWUGO) != (S_IWUGO & ~mask)) return -EPERM; } |
1278fdd34 fat: fat_notify_c... |
330 |
|
2d518f84e fat: relax the pe... |
331 |
*mode_ptr &= S_IFMT | perm; |
1278fdd34 fat: fat_notify_c... |
332 333 |
return 0; } |
1ae43f826 fat: Add allow_ut... |
334 335 |
static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode) { |
dacd0e7b3 fat: propagate um... |
336 |
umode_t allow_utime = sbi->options.allow_utime; |
1ae43f826 fat: Add allow_ut... |
337 |
|
f0ce7ee3a CRED: Wrap task c... |
338 |
if (current_fsuid() != inode->i_uid) { |
1ae43f826 fat: Add allow_ut... |
339 340 341 342 343 344 345 346 347 |
if (in_group_p(inode->i_gid)) allow_utime >>= 3; if (allow_utime & MAY_WRITE) return 1; } /* use a default check */ return 0; } |
17263849c fat: Fix allow_ut... |
348 |
#define TIMES_SET_FLAGS (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET) |
9c0aa1b87 fat: Cleanup FAT ... |
349 350 |
/* valid file mode bits */ #define FAT_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXUGO) |
17263849c fat: Fix allow_ut... |
351 |
|
1278fdd34 fat: fat_notify_c... |
352 353 354 355 |
int fat_setattr(struct dentry *dentry, struct iattr *attr) { struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); struct inode *inode = dentry->d_inode; |
1ae43f826 fat: Add allow_ut... |
356 |
unsigned int ia_valid; |
dfc209c00 fat: Fix ATTR_RO ... |
357 |
int error; |
1278fdd34 fat: fat_notify_c... |
358 |
|
1ae43f826 fat: Add allow_ut... |
359 360 |
/* Check for setting the inode time. */ ia_valid = attr->ia_valid; |
17263849c fat: Fix allow_ut... |
361 |
if (ia_valid & TIMES_SET_FLAGS) { |
1ae43f826 fat: Add allow_ut... |
362 |
if (fat_allow_set_time(sbi, inode)) |
17263849c fat: Fix allow_ut... |
363 |
attr->ia_valid &= ~TIMES_SET_FLAGS; |
1ae43f826 fat: Add allow_ut... |
364 |
} |
1278fdd34 fat: fat_notify_c... |
365 |
error = inode_change_ok(inode, attr); |
1ae43f826 fat: Add allow_ut... |
366 |
attr->ia_valid = ia_valid; |
1278fdd34 fat: fat_notify_c... |
367 368 369 370 371 |
if (error) { if (sbi->options.quiet) error = 0; goto out; } |
2d518f84e fat: relax the pe... |
372 |
|
db78b877f always call inode... |
373 374 375 376 377 378 379 |
/* * Expand the file. Since inode_setattr() updates ->i_size * before calling the ->truncate(), but FAT needs to fill the * hole before it. XXX: this is no longer true with new truncate * sequence. */ if (attr->ia_valid & ATTR_SIZE) { |
562c72aa5 fs: move inode_di... |
380 |
inode_dio_wait(inode); |
db78b877f always call inode... |
381 382 383 384 385 386 387 |
if (attr->ia_size > inode->i_size) { error = fat_cont_expand(inode, attr->ia_size); if (error || attr->ia_valid == ATTR_SIZE) goto out; attr->ia_valid &= ~ATTR_SIZE; } } |
1278fdd34 fat: fat_notify_c... |
388 389 390 |
if (((attr->ia_valid & ATTR_UID) && (attr->ia_uid != sbi->options.fs_uid)) || ((attr->ia_valid & ATTR_GID) && |
e97e8de38 fat: fat_setattr(... |
391 392 |
(attr->ia_gid != sbi->options.fs_gid)) || ((attr->ia_valid & ATTR_MODE) && |
9c0aa1b87 fat: Cleanup FAT ... |
393 |
(attr->ia_mode & ~FAT_VALID_MODE))) |
1278fdd34 fat: fat_notify_c... |
394 395 396 397 398 399 400 |
error = -EPERM; if (error) { if (sbi->options.quiet) error = 0; goto out; } |
2d518f84e fat: relax the pe... |
401 402 403 404 405 406 407 408 |
/* * We don't return -EPERM here. Yes, strange, but this is too * old behavior. */ if (attr->ia_valid & ATTR_MODE) { if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) attr->ia_valid &= ~ATTR_MODE; } |
1278fdd34 fat: fat_notify_c... |
409 |
|
459f6ed3b fat: convert to u... |
410 |
if (attr->ia_valid & ATTR_SIZE) { |
582686915 fat: remove i_all... |
411 |
down_write(&MSDOS_I(inode)->truncate_lock); |
2c27c65ed check ATTR_SIZE c... |
412 413 |
truncate_setsize(inode, attr->ia_size); fat_truncate_blocks(inode, attr->ia_size); |
582686915 fat: remove i_all... |
414 |
up_write(&MSDOS_I(inode)->truncate_lock); |
459f6ed3b fat: convert to u... |
415 |
} |
6a1a90ad1 rename generic_se... |
416 |
setattr_copy(inode, attr); |
459f6ed3b fat: convert to u... |
417 |
mark_inode_dirty(inode); |
1278fdd34 fat: fat_notify_c... |
418 |
out: |
1278fdd34 fat: fat_notify_c... |
419 420 421 |
return error; } EXPORT_SYMBOL_GPL(fat_setattr); |
754661f14 [PATCH] mark stru... |
422 |
const struct inode_operations fat_file_inode_operations = { |
1278fdd34 fat: fat_notify_c... |
423 |
.setattr = fat_setattr, |
da63fc7ce [PATCH] fat: add ... |
424 |
.getattr = fat_getattr, |
1da177e4c Linux-2.6.12-rc2 |
425 |
}; |