Blame view

fs/fat/file.c 11 KB
1da177e4c   Linus Torvalds   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   Randy Dunlap   [PATCH] capable/c...
8
  #include <linux/capability.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
9
  #include <linux/module.h>
7845bc3e1   Arnd Bergmann   fat: convert to u...
10
  #include <linux/compat.h>
42a74f206   Dave Hansen   [PATCH] r/o bind ...
11
  #include <linux/mount.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
12
  #include <linux/time.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
13
  #include <linux/buffer_head.h>
05eb0b51f   OGAWA Hirofumi   [PATCH] fat: supp...
14
  #include <linux/writeback.h>
3fcfab16c   Andrew Morton   [PATCH] separate ...
15
  #include <linux/backing-dev.h>
ae78bf9c4   Chris Mason   [PATCH] add -o fl...
16
  #include <linux/blkdev.h>
b1da47e29   Miklos Szeredi   [patch 3/4] fat: ...
17
18
  #include <linux/fsnotify.h>
  #include <linux/security.h>
9e975dae2   OGAWA Hirofumi   fat: split includ...
19
  #include "fat.h"
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
20

21bea4959   Christoph Hellwig   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   Linus Torvalds   Linux-2.6.12-rc2
33
  {
21bea4959   Christoph Hellwig   fat: split fat_ge...
34
  	struct inode *inode = file->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
35
  	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
21bea4959   Christoph Hellwig   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   Linus Torvalds   Linux-2.6.12-rc2
40

21bea4959   Christoph Hellwig   fat: split fat_ge...
41
42
43
  	err = get_user(attr, user_attr);
  	if (err)
  		goto out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44

21bea4959   Christoph Hellwig   fat: split fat_ge...
45
  	mutex_lock(&inode->i_mutex);
a561be710   Al Viro   switch a bunch of...
46
  	err = mnt_want_write_file(file);
21bea4959   Christoph Hellwig   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   Linus Torvalds   Linux-2.6.12-rc2
71

21bea4959   Christoph Hellwig   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   Linus Torvalds   Linux-2.6.12-rc2
76
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
77

21bea4959   Christoph Hellwig   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   Linus Torvalds   Linux-2.6.12-rc2
84

21bea4959   Christoph Hellwig   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   Linus Torvalds   Linux-2.6.12-rc2
93

21bea4959   Christoph Hellwig   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   OGAWA Hirofumi   fat: Fix corrupt ...
104
  			inode->i_flags &= ~S_IMMUTABLE;
21bea4959   Christoph Hellwig   fat: split fat_ge...
105
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106

21bea4959   Christoph Hellwig   fat: split fat_ge...
107
108
109
  	fat_save_attrs(inode, attr);
  	mark_inode_dirty(inode);
  out_drop_write:
2a79f17e4   Al Viro   vfs: mnt_drop_wri...
110
  	mnt_drop_write_file(file);
21bea4959   Christoph Hellwig   fat: split fat_ge...
111
112
113
114
115
  out_unlock_inode:
  	mutex_unlock(&inode->i_mutex);
  out:
  	return err;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
116

7845bc3e1   Arnd Bergmann   fat: convert to u...
117
  long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  {
7845bc3e1   Arnd Bergmann   fat: convert to u...
119
  	struct inode *inode = filp->f_path.dentry->d_inode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  	u32 __user *user_attr = (u32 __user *)arg;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
121

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
  	switch (cmd) {
  	case FAT_IOCTL_GET_ATTRIBUTES:
21bea4959   Christoph Hellwig   fat: split fat_ge...
124
  		return fat_ioctl_get_attributes(inode, user_attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  	case FAT_IOCTL_SET_ATTRIBUTES:
21bea4959   Christoph Hellwig   fat: split fat_ge...
126
  		return fat_ioctl_set_attributes(filp, user_attr);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
  	default:
  		return -ENOTTY;	/* Inappropriate ioctl for device */
  	}
  }
7845bc3e1   Arnd Bergmann   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   Chris Mason   [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   Jens Axboe   Fix congestion_wa...
144
  		congestion_wait(BLK_RW_ASYNC, HZ/10);
ae78bf9c4   Chris Mason   [PATCH] add -o fl...
145
146
147
  	}
  	return 0;
  }
02c24a821   Josef Bacik   fs: push i_mutex ...
148
  int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
b522412ae   Al Viro   Sanitize ->fsync(...
149
  {
7ea808591   Christoph Hellwig   drop unused dentr...
150
  	struct inode *inode = filp->f_mapping->host;
b522412ae   Al Viro   Sanitize ->fsync(...
151
  	int res, err;
02c24a821   Josef Bacik   fs: push i_mutex ...
152
  	res = generic_file_fsync(filp, start, end, datasync);
b522412ae   Al Viro   Sanitize ->fsync(...
153
154
155
156
  	err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping);
  
  	return res ? res : err;
  }
4b6f5d20b   Arjan van de Ven   [PATCH] Make most...
157
  const struct file_operations fat_file_operations = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
158
159
160
  	.llseek		= generic_file_llseek,
  	.read		= do_sync_read,
  	.write		= do_sync_write,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
161
  	.aio_read	= generic_file_aio_read,
ef402268f   OGAWA Hirofumi   [PATCH] FAT: miss...
162
  	.aio_write	= generic_file_aio_write,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
163
  	.mmap		= generic_file_mmap,
ae78bf9c4   Chris Mason   [PATCH] add -o fl...
164
  	.release	= fat_file_release,
7845bc3e1   Arnd Bergmann   fat: convert to u...
165
166
167
168
  	.unlocked_ioctl	= fat_generic_ioctl,
  #ifdef CONFIG_COMPAT
  	.compat_ioctl	= fat_generic_compat_ioctl,
  #endif
b522412ae   Al Viro   Sanitize ->fsync(...
169
  	.fsync		= fat_file_fsync,
5ffc4ef45   Jens Axboe   sendfile: remove ...
170
  	.splice_read	= generic_file_splice_read,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  };
05eb0b51f   OGAWA Hirofumi   [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   Jan Kara   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   OGAWA Hirofumi   [PATCH] fat: supp...
204
205
206
  out:
  	return err;
  }
1da177e4c   Linus Torvalds   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   OGAWA Hirofumi   [PATCH] fat: Fix ...
215
  	fat_cache_inval_inode(inode);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  	wait = IS_DIRSYNC(inode);
3b641407a   OGAWA Hirofumi   [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   Linus Torvalds   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   Denis Karpov   FAT: add 'errors'...
254
  			fat_fs_error(sb,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
255
  				     "%s: invalid cluster chain (i_pos %lld)",
8e24eea72   Harvey Harrison   fs: replace remai...
256
  				     __func__, MSDOS_I(inode)->i_pos);
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
268
  	}
1da177e4c   Linus Torvalds   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   Linus Torvalds   Linux-2.6.12-rc2
273
  }
459f6ed3b   npiggin@suse.de   fat: convert to u...
274
  void fat_truncate_blocks(struct inode *inode, loff_t offset)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
  {
9c20616c3   Jonathan Corbet   Make FAT users ha...
276
  	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
1da177e4c   Linus Torvalds   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   npiggin@suse.de   fat: convert to u...
284
285
  	if (MSDOS_I(inode)->mmu_private > offset)
  		MSDOS_I(inode)->mmu_private = offset;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
286

459f6ed3b   npiggin@suse.de   fat: convert to u...
287
  	nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
289
  	fat_free(inode, nr_clusters);
ae78bf9c4   Chris Mason   [PATCH] add -o fl...
290
  	fat_flush_inodes(inode->i_sb, inode, NULL);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  }
da63fc7ce   OGAWA Hirofumi   [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   OGAWA Hirofumi   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   OGAWA Hirofumi   fat: fat_notify_c...
302
  {
dacd0e7b3   Al Viro   fat: propagate um...
303
  	umode_t mask, perm;
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
304

2d518f84e   OGAWA Hirofumi   fat: relax the pe...
305
306
  	/*
  	 * Note, the basic check is already done by a caller of
9c0aa1b87   OGAWA Hirofumi   fat: Cleanup FAT ...
307
  	 * (attr->ia_mode & ~FAT_VALID_MODE)
2d518f84e   OGAWA Hirofumi   fat: relax the pe...
308
309
310
  	 */
  
  	if (S_ISREG(inode->i_mode))
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
311
312
313
  		mask = sbi->options.fs_fmask;
  	else
  		mask = sbi->options.fs_dmask;
2d518f84e   OGAWA Hirofumi   fat: relax the pe...
314
  	perm = *mode_ptr & ~(S_IFMT | mask);
1278fdd34   OGAWA Hirofumi   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   OGAWA Hirofumi   fat: Fix ATTR_RO ...
318
319
  	 *
  	 * If fat_mode_can_hold_ro(inode) is false, can't change w bits.
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
320
  	 */
2d518f84e   OGAWA Hirofumi   fat: relax the pe...
321
  	if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
322
  		return -EPERM;
dfc209c00   OGAWA Hirofumi   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   OGAWA Hirofumi   fat: fat_notify_c...
330

2d518f84e   OGAWA Hirofumi   fat: relax the pe...
331
  	*mode_ptr &= S_IFMT | perm;
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
332
333
  	return 0;
  }
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
334
335
  static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
  {
dacd0e7b3   Al Viro   fat: propagate um...
336
  	umode_t allow_utime = sbi->options.allow_utime;
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
337

f0ce7ee3a   David Howells   CRED: Wrap task c...
338
  	if (current_fsuid() != inode->i_uid) {
1ae43f826   OGAWA Hirofumi   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   OGAWA Hirofumi   fat: Fix allow_ut...
348
  #define TIMES_SET_FLAGS	(ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)
9c0aa1b87   OGAWA Hirofumi   fat: Cleanup FAT ...
349
350
  /* valid file mode bits */
  #define FAT_VALID_MODE	(S_IFREG | S_IFDIR | S_IRWXUGO)
17263849c   OGAWA Hirofumi   fat: Fix allow_ut...
351

1278fdd34   OGAWA Hirofumi   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   OGAWA Hirofumi   fat: Add allow_ut...
356
  	unsigned int ia_valid;
dfc209c00   OGAWA Hirofumi   fat: Fix ATTR_RO ...
357
  	int error;
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
358

1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
359
360
  	/* Check for setting the inode time. */
  	ia_valid = attr->ia_valid;
17263849c   OGAWA Hirofumi   fat: Fix allow_ut...
361
  	if (ia_valid & TIMES_SET_FLAGS) {
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
362
  		if (fat_allow_set_time(sbi, inode))
17263849c   OGAWA Hirofumi   fat: Fix allow_ut...
363
  			attr->ia_valid &= ~TIMES_SET_FLAGS;
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
364
  	}
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
365
  	error = inode_change_ok(inode, attr);
1ae43f826   OGAWA Hirofumi   fat: Add allow_ut...
366
  	attr->ia_valid = ia_valid;
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
367
368
369
370
371
  	if (error) {
  		if (sbi->options.quiet)
  			error = 0;
  		goto out;
  	}
2d518f84e   OGAWA Hirofumi   fat: relax the pe...
372

db78b877f   Christoph Hellwig   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   Christoph Hellwig   fs: move inode_di...
380
  		inode_dio_wait(inode);
db78b877f   Christoph Hellwig   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   OGAWA Hirofumi   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   OGAWA Hirofumi   fat: fat_setattr(...
391
392
  	     (attr->ia_gid != sbi->options.fs_gid)) ||
  	    ((attr->ia_valid & ATTR_MODE) &&
9c0aa1b87   OGAWA Hirofumi   fat: Cleanup FAT ...
393
  	     (attr->ia_mode & ~FAT_VALID_MODE)))
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
394
395
396
397
398
399
400
  		error = -EPERM;
  
  	if (error) {
  		if (sbi->options.quiet)
  			error = 0;
  		goto out;
  	}
2d518f84e   OGAWA Hirofumi   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   OGAWA Hirofumi   fat: fat_notify_c...
409

459f6ed3b   npiggin@suse.de   fat: convert to u...
410
  	if (attr->ia_valid & ATTR_SIZE) {
582686915   Christoph Hellwig   fat: remove i_all...
411
  		down_write(&MSDOS_I(inode)->truncate_lock);
2c27c65ed   Christoph Hellwig   check ATTR_SIZE c...
412
413
  		truncate_setsize(inode, attr->ia_size);
  		fat_truncate_blocks(inode, attr->ia_size);
582686915   Christoph Hellwig   fat: remove i_all...
414
  		up_write(&MSDOS_I(inode)->truncate_lock);
459f6ed3b   npiggin@suse.de   fat: convert to u...
415
  	}
6a1a90ad1   Christoph Hellwig   rename generic_se...
416
  	setattr_copy(inode, attr);
459f6ed3b   npiggin@suse.de   fat: convert to u...
417
  	mark_inode_dirty(inode);
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
418
  out:
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
419
420
421
  	return error;
  }
  EXPORT_SYMBOL_GPL(fat_setattr);
754661f14   Arjan van de Ven   [PATCH] mark stru...
422
  const struct inode_operations fat_file_inode_operations = {
1278fdd34   OGAWA Hirofumi   fat: fat_notify_c...
423
  	.setattr	= fat_setattr,
da63fc7ce   OGAWA Hirofumi   [PATCH] fat: add ...
424
  	.getattr	= fat_getattr,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
425
  };