file.c 11.0 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8
/*
 *  linux/fs/fat/file.c
 *
 *  Written 1992,1993 by Werner Almesberger
 *
 *  regular file handling primitives for fat-based filesystems
 */

9
#include <linux/capability.h>
L
Linus Torvalds 已提交
10
#include <linux/module.h>
A
Arnd Bergmann 已提交
11
#include <linux/compat.h>
12
#include <linux/mount.h>
L
Linus Torvalds 已提交
13 14
#include <linux/time.h>
#include <linux/buffer_head.h>
15
#include <linux/writeback.h>
16
#include <linux/backing-dev.h>
C
Chris Mason 已提交
17
#include <linux/blkdev.h>
18 19
#include <linux/fsnotify.h>
#include <linux/security.h>
O
OGAWA Hirofumi 已提交
20
#include "fat.h"
L
Linus Torvalds 已提交
21

C
Christoph Hellwig 已提交
22 23 24 25 26 27 28 29 30 31 32 33
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)
L
Linus Torvalds 已提交
34
{
C
Christoph Hellwig 已提交
35
	struct inode *inode = file->f_path.dentry->d_inode;
L
Linus Torvalds 已提交
36
	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
C
Christoph Hellwig 已提交
37 38 39 40
	int is_dir = S_ISDIR(inode->i_mode);
	u32 attr, oldattr;
	struct iattr ia;
	int err;
L
Linus Torvalds 已提交
41

C
Christoph Hellwig 已提交
42 43 44
	err = get_user(attr, user_attr);
	if (err)
		goto out;
L
Linus Torvalds 已提交
45

C
Christoph Hellwig 已提交
46
	mutex_lock(&inode->i_mutex);
47
	err = mnt_want_write_file(file);
C
Christoph Hellwig 已提交
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71
	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));
	}
L
Linus Torvalds 已提交
72

C
Christoph Hellwig 已提交
73 74 75 76
	/* The root directory has no attributes */
	if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {
		err = -EINVAL;
		goto out_drop_write;
L
Linus Torvalds 已提交
77 78
	}

C
Christoph Hellwig 已提交
79 80 81 82 83 84
	if (sbi->options.sys_immutable &&
	    ((attr | oldattr) & ATTR_SYS) &&
	    !capable(CAP_LINUX_IMMUTABLE)) {
		err = -EPERM;
		goto out_drop_write;
	}
L
Linus Torvalds 已提交
85

C
Christoph Hellwig 已提交
86 87 88 89 90 91 92 93
	/*
	 * 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;
L
Linus Torvalds 已提交
94

C
Christoph Hellwig 已提交
95 96 97 98 99 100 101 102 103 104
	/* 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
105
			inode->i_flags &= ~S_IMMUTABLE;
C
Christoph Hellwig 已提交
106
	}
L
Linus Torvalds 已提交
107

C
Christoph Hellwig 已提交
108 109 110 111 112 113 114 115 116
	fat_save_attrs(inode, attr);
	mark_inode_dirty(inode);
out_drop_write:
	mnt_drop_write(file->f_path.mnt);
out_unlock_inode:
	mutex_unlock(&inode->i_mutex);
out:
	return err;
}
L
Linus Torvalds 已提交
117

A
Arnd Bergmann 已提交
118
long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
L
Linus Torvalds 已提交
119
{
A
Arnd Bergmann 已提交
120
	struct inode *inode = filp->f_path.dentry->d_inode;
L
Linus Torvalds 已提交
121 122 123 124
	u32 __user *user_attr = (u32 __user *)arg;

	switch (cmd) {
	case FAT_IOCTL_GET_ATTRIBUTES:
C
Christoph Hellwig 已提交
125
		return fat_ioctl_get_attributes(inode, user_attr);
L
Linus Torvalds 已提交
126
	case FAT_IOCTL_SET_ATTRIBUTES:
C
Christoph Hellwig 已提交
127
		return fat_ioctl_set_attributes(filp, user_attr);
L
Linus Torvalds 已提交
128 129 130 131 132
	default:
		return -ENOTTY;	/* Inappropriate ioctl for device */
	}
}

A
Arnd Bergmann 已提交
133 134 135 136 137 138 139 140 141
#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

C
Chris Mason 已提交
142 143 144 145 146
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);
147
		congestion_wait(BLK_RW_ASYNC, HZ/10);
C
Chris Mason 已提交
148 149 150 151
	}
	return 0;
}

152
int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)
A
Al Viro 已提交
153
{
154
	struct inode *inode = filp->f_mapping->host;
A
Al Viro 已提交
155 156
	int res, err;

157
	res = generic_file_fsync(filp, start, end, datasync);
A
Al Viro 已提交
158 159 160 161 162 163
	err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping);

	return res ? res : err;
}


164
const struct file_operations fat_file_operations = {
L
Linus Torvalds 已提交
165 166 167 168
	.llseek		= generic_file_llseek,
	.read		= do_sync_read,
	.write		= do_sync_write,
	.aio_read	= generic_file_aio_read,
169
	.aio_write	= generic_file_aio_write,
L
Linus Torvalds 已提交
170
	.mmap		= generic_file_mmap,
C
Chris Mason 已提交
171
	.release	= fat_file_release,
A
Arnd Bergmann 已提交
172 173 174 175
	.unlocked_ioctl	= fat_generic_ioctl,
#ifdef CONFIG_COMPAT
	.compat_ioctl	= fat_generic_compat_ioctl,
#endif
A
Al Viro 已提交
176
	.fsync		= fat_file_fsync,
177
	.splice_read	= generic_file_splice_read,
L
Linus Torvalds 已提交
178 179
};

180 181 182 183 184 185 186 187 188 189 190 191
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);
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211
	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);
		}
	}
212 213 214 215
out:
	return err;
}

L
Linus Torvalds 已提交
216 217 218 219 220 221 222 223 224
/* 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;

225 226
	fat_cache_inval_inode(inode);

L
Linus Torvalds 已提交
227
	wait = IS_DIRSYNC(inode);
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248
	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. */
L
Linus Torvalds 已提交
249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264
	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) {
D
Denis Karpov 已提交
265
			fat_fs_error(sb,
L
Linus Torvalds 已提交
266
				     "%s: invalid cluster chain (i_pos %lld)",
267
				     __func__, MSDOS_I(inode)->i_pos);
L
Linus Torvalds 已提交
268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
			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;
	}
	inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);

	/* Freeing the remained cluster chain */
	return fat_free_clusters(inode, free_start);
}

286
void fat_truncate_blocks(struct inode *inode, loff_t offset)
L
Linus Torvalds 已提交
287
{
288
	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);
L
Linus Torvalds 已提交
289 290 291 292 293 294 295
	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.
	 */
296 297
	if (MSDOS_I(inode)->mmu_private > offset)
		MSDOS_I(inode)->mmu_private = offset;
L
Linus Torvalds 已提交
298

299
	nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits;
L
Linus Torvalds 已提交
300 301

	fat_free(inode, nr_clusters);
C
Chris Mason 已提交
302
	fat_flush_inodes(inode->i_sb, inode, NULL);
L
Linus Torvalds 已提交
303 304
}

O
OGAWA Hirofumi 已提交
305 306 307 308 309 310 311 312 313
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);

314 315
static int fat_sanitize_mode(const struct msdos_sb_info *sbi,
			     struct inode *inode, umode_t *mode_ptr)
316
{
317
	mode_t mask, perm;
318

319 320
	/*
	 * Note, the basic check is already done by a caller of
O
OGAWA Hirofumi 已提交
321
	 * (attr->ia_mode & ~FAT_VALID_MODE)
322 323 324
	 */

	if (S_ISREG(inode->i_mode))
325 326 327 328
		mask = sbi->options.fs_fmask;
	else
		mask = sbi->options.fs_dmask;

329 330
	perm = *mode_ptr & ~(S_IFMT | mask);

331 332 333
	/*
	 * 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.
O
OGAWA Hirofumi 已提交
334 335
	 *
	 * If fat_mode_can_hold_ro(inode) is false, can't change w bits.
336
	 */
337
	if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
338
		return -EPERM;
O
OGAWA Hirofumi 已提交
339 340 341 342 343 344 345
	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;
	}
346

347 348
	*mode_ptr &= S_IFMT | perm;

349 350 351
	return 0;
}

O
OGAWA Hirofumi 已提交
352 353 354 355
static int fat_allow_set_time(struct msdos_sb_info *sbi, struct inode *inode)
{
	mode_t allow_utime = sbi->options.allow_utime;

356
	if (current_fsuid() != inode->i_uid) {
O
OGAWA Hirofumi 已提交
357 358 359 360 361 362 363 364 365 366
		if (in_group_p(inode->i_gid))
			allow_utime >>= 3;
		if (allow_utime & MAY_WRITE)
			return 1;
	}

	/* use a default check */
	return 0;
}

O
OGAWA Hirofumi 已提交
367
#define TIMES_SET_FLAGS	(ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)
O
OGAWA Hirofumi 已提交
368 369
/* valid file mode bits */
#define FAT_VALID_MODE	(S_IFREG | S_IFDIR | S_IRWXUGO)
O
OGAWA Hirofumi 已提交
370

371 372 373 374
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;
O
OGAWA Hirofumi 已提交
375
	unsigned int ia_valid;
O
OGAWA Hirofumi 已提交
376
	int error;
377

O
OGAWA Hirofumi 已提交
378 379
	/* Check for setting the inode time. */
	ia_valid = attr->ia_valid;
O
OGAWA Hirofumi 已提交
380
	if (ia_valid & TIMES_SET_FLAGS) {
O
OGAWA Hirofumi 已提交
381
		if (fat_allow_set_time(sbi, inode))
O
OGAWA Hirofumi 已提交
382
			attr->ia_valid &= ~TIMES_SET_FLAGS;
O
OGAWA Hirofumi 已提交
383 384
	}

385
	error = inode_change_ok(inode, attr);
O
OGAWA Hirofumi 已提交
386
	attr->ia_valid = ia_valid;
387 388 389 390 391
	if (error) {
		if (sbi->options.quiet)
			error = 0;
		goto out;
	}
392

393 394 395 396 397 398 399
	/*
	 * 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) {
400 401
		inode_dio_wait(inode);

402 403 404 405 406 407 408 409
		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;
		}
	}

410 411 412
	if (((attr->ia_valid & ATTR_UID) &&
	     (attr->ia_uid != sbi->options.fs_uid)) ||
	    ((attr->ia_valid & ATTR_GID) &&
O
OGAWA Hirofumi 已提交
413 414
	     (attr->ia_gid != sbi->options.fs_gid)) ||
	    ((attr->ia_valid & ATTR_MODE) &&
O
OGAWA Hirofumi 已提交
415
	     (attr->ia_mode & ~FAT_VALID_MODE)))
416 417 418 419 420 421 422 423
		error = -EPERM;

	if (error) {
		if (sbi->options.quiet)
			error = 0;
		goto out;
	}

424 425 426 427 428 429 430 431
	/*
	 * 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;
	}
432

433
	if (attr->ia_valid & ATTR_SIZE) {
434
		down_write(&MSDOS_I(inode)->truncate_lock);
435 436
		truncate_setsize(inode, attr->ia_size);
		fat_truncate_blocks(inode, attr->ia_size);
437
		up_write(&MSDOS_I(inode)->truncate_lock);
438 439
	}

C
Christoph Hellwig 已提交
440
	setattr_copy(inode, attr);
441
	mark_inode_dirty(inode);
442 443 444 445 446
out:
	return error;
}
EXPORT_SYMBOL_GPL(fat_setattr);

447
const struct inode_operations fat_file_inode_operations = {
448
	.setattr	= fat_setattr,
O
OGAWA Hirofumi 已提交
449
	.getattr	= fat_getattr,
L
Linus Torvalds 已提交
450
};