brintos

brintos / linux-shallow public Read only

0
0
Text · 14.6 KiB · e887e9a Raw
579 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 *  linux/fs/fat/file.c4 *5 *  Written 1992,1993 by Werner Almesberger6 *7 *  regular file handling primitives for fat-based filesystems8 */9 10#include <linux/capability.h>11#include <linux/module.h>12#include <linux/compat.h>13#include <linux/mount.h>14#include <linux/blkdev.h>15#include <linux/backing-dev.h>16#include <linux/fsnotify.h>17#include <linux/security.h>18#include <linux/falloc.h>19#include "fat.h"20 21static long fat_fallocate(struct file *file, int mode,22			  loff_t offset, loff_t len);23 24static int fat_ioctl_get_attributes(struct inode *inode, u32 __user *user_attr)25{26	u32 attr;27 28	inode_lock_shared(inode);29	attr = fat_make_attrs(inode);30	inode_unlock_shared(inode);31 32	return put_user(attr, user_attr);33}34 35static int fat_ioctl_set_attributes(struct file *file, u32 __user *user_attr)36{37	struct inode *inode = file_inode(file);38	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);39	int is_dir = S_ISDIR(inode->i_mode);40	u32 attr, oldattr;41	struct iattr ia;42	int err;43 44	err = get_user(attr, user_attr);45	if (err)46		goto out;47 48	err = mnt_want_write_file(file);49	if (err)50		goto out;51	inode_lock(inode);52 53	/*54	 * ATTR_VOLUME and ATTR_DIR cannot be changed; this also55	 * prevents the user from turning us into a VFAT56	 * longname entry.  Also, we obviously can't set57	 * any of the NTFS attributes in the high 24 bits.58	 */59	attr &= 0xff & ~(ATTR_VOLUME | ATTR_DIR);60	/* Merge in ATTR_VOLUME and ATTR_DIR */61	attr |= (MSDOS_I(inode)->i_attrs & ATTR_VOLUME) |62		(is_dir ? ATTR_DIR : 0);63	oldattr = fat_make_attrs(inode);64 65	/* Equivalent to a chmod() */66	ia.ia_valid = ATTR_MODE | ATTR_CTIME;67	ia.ia_ctime = current_time(inode);68	if (is_dir)69		ia.ia_mode = fat_make_mode(sbi, attr, S_IRWXUGO);70	else {71		ia.ia_mode = fat_make_mode(sbi, attr,72			S_IRUGO | S_IWUGO | (inode->i_mode & S_IXUGO));73	}74 75	/* The root directory has no attributes */76	if (inode->i_ino == MSDOS_ROOT_INO && attr != ATTR_DIR) {77		err = -EINVAL;78		goto out_unlock_inode;79	}80 81	if (sbi->options.sys_immutable &&82	    ((attr | oldattr) & ATTR_SYS) &&83	    !capable(CAP_LINUX_IMMUTABLE)) {84		err = -EPERM;85		goto out_unlock_inode;86	}87 88	/*89	 * The security check is questionable...  We single90	 * out the RO attribute for checking by the security91	 * module, just because it maps to a file mode.92	 */93	err = security_inode_setattr(file_mnt_idmap(file),94				     file->f_path.dentry, &ia);95	if (err)96		goto out_unlock_inode;97 98	/* This MUST be done before doing anything irreversible... */99	err = fat_setattr(file_mnt_idmap(file), file->f_path.dentry, &ia);100	if (err)101		goto out_unlock_inode;102 103	fsnotify_change(file->f_path.dentry, ia.ia_valid);104	if (sbi->options.sys_immutable) {105		if (attr & ATTR_SYS)106			inode->i_flags |= S_IMMUTABLE;107		else108			inode->i_flags &= ~S_IMMUTABLE;109	}110 111	fat_save_attrs(inode, attr);112	mark_inode_dirty(inode);113out_unlock_inode:114	inode_unlock(inode);115	mnt_drop_write_file(file);116out:117	return err;118}119 120static int fat_ioctl_get_volume_id(struct inode *inode, u32 __user *user_attr)121{122	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);123	return put_user(sbi->vol_id, user_attr);124}125 126static int fat_ioctl_fitrim(struct inode *inode, unsigned long arg)127{128	struct super_block *sb = inode->i_sb;129	struct fstrim_range __user *user_range;130	struct fstrim_range range;131	int err;132 133	if (!capable(CAP_SYS_ADMIN))134		return -EPERM;135 136	if (!bdev_max_discard_sectors(sb->s_bdev))137		return -EOPNOTSUPP;138 139	user_range = (struct fstrim_range __user *)arg;140	if (copy_from_user(&range, user_range, sizeof(range)))141		return -EFAULT;142 143	range.minlen = max_t(unsigned int, range.minlen,144			     bdev_discard_granularity(sb->s_bdev));145 146	err = fat_trim_fs(inode, &range);147	if (err < 0)148		return err;149 150	if (copy_to_user(user_range, &range, sizeof(range)))151		return -EFAULT;152 153	return 0;154}155 156long fat_generic_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)157{158	struct inode *inode = file_inode(filp);159	u32 __user *user_attr = (u32 __user *)arg;160 161	switch (cmd) {162	case FAT_IOCTL_GET_ATTRIBUTES:163		return fat_ioctl_get_attributes(inode, user_attr);164	case FAT_IOCTL_SET_ATTRIBUTES:165		return fat_ioctl_set_attributes(filp, user_attr);166	case FAT_IOCTL_GET_VOLUME_ID:167		return fat_ioctl_get_volume_id(inode, user_attr);168	case FITRIM:169		return fat_ioctl_fitrim(inode, arg);170	default:171		return -ENOTTY;	/* Inappropriate ioctl for device */172	}173}174 175static int fat_file_release(struct inode *inode, struct file *filp)176{177	if ((filp->f_mode & FMODE_WRITE) &&178	    MSDOS_SB(inode->i_sb)->options.flush) {179		fat_flush_inodes(inode->i_sb, inode, NULL);180		set_current_state(TASK_UNINTERRUPTIBLE);181		io_schedule_timeout(HZ/10);182	}183	return 0;184}185 186int fat_file_fsync(struct file *filp, loff_t start, loff_t end, int datasync)187{188	struct inode *inode = filp->f_mapping->host;189	int err;190 191	err = __generic_file_fsync(filp, start, end, datasync);192	if (err)193		return err;194 195	err = sync_mapping_buffers(MSDOS_SB(inode->i_sb)->fat_inode->i_mapping);196	if (err)197		return err;198 199	return blkdev_issue_flush(inode->i_sb->s_bdev);200}201 202 203const struct file_operations fat_file_operations = {204	.llseek		= generic_file_llseek,205	.read_iter	= generic_file_read_iter,206	.write_iter	= generic_file_write_iter,207	.mmap		= generic_file_mmap,208	.release	= fat_file_release,209	.unlocked_ioctl	= fat_generic_ioctl,210	.compat_ioctl	= compat_ptr_ioctl,211	.fsync		= fat_file_fsync,212	.splice_read	= filemap_splice_read,213	.splice_write	= iter_file_splice_write,214	.fallocate	= fat_fallocate,215};216 217static int fat_cont_expand(struct inode *inode, loff_t size)218{219	struct address_space *mapping = inode->i_mapping;220	loff_t start = inode->i_size, count = size - inode->i_size;221	int err;222 223	err = generic_cont_expand_simple(inode, size);224	if (err)225		goto out;226 227	fat_truncate_time(inode, NULL, S_CTIME|S_MTIME);228	mark_inode_dirty(inode);229	if (IS_SYNC(inode)) {230		int err2;231 232		/*233		 * Opencode syncing since we don't have a file open to use234		 * standard fsync path.235		 */236		err = filemap_fdatawrite_range(mapping, start,237					       start + count - 1);238		err2 = sync_mapping_buffers(mapping);239		if (!err)240			err = err2;241		err2 = write_inode_now(inode, 1);242		if (!err)243			err = err2;244		if (!err) {245			err =  filemap_fdatawait_range(mapping, start,246						       start + count - 1);247		}248	}249out:250	return err;251}252 253/*254 * Preallocate space for a file. This implements fat's fallocate file255 * operation, which gets called from sys_fallocate system call. User256 * space requests len bytes at offset. If FALLOC_FL_KEEP_SIZE is set257 * we just allocate clusters without zeroing them out. Otherwise we258 * allocate and zero out clusters via an expanding truncate.259 */260static long fat_fallocate(struct file *file, int mode,261			  loff_t offset, loff_t len)262{263	int nr_cluster; /* Number of clusters to be allocated */264	loff_t mm_bytes; /* Number of bytes to be allocated for file */265	loff_t ondisksize; /* block aligned on-disk size in bytes*/266	struct inode *inode = file->f_mapping->host;267	struct super_block *sb = inode->i_sb;268	struct msdos_sb_info *sbi = MSDOS_SB(sb);269	int err = 0;270 271	/* No support for hole punch or other fallocate flags. */272	if (mode & ~FALLOC_FL_KEEP_SIZE)273		return -EOPNOTSUPP;274 275	/* No support for dir */276	if (!S_ISREG(inode->i_mode))277		return -EOPNOTSUPP;278 279	inode_lock(inode);280	if (mode & FALLOC_FL_KEEP_SIZE) {281		ondisksize = inode->i_blocks << 9;282		if ((offset + len) <= ondisksize)283			goto error;284 285		/* First compute the number of clusters to be allocated */286		mm_bytes = offset + len - ondisksize;287		nr_cluster = (mm_bytes + (sbi->cluster_size - 1)) >>288			sbi->cluster_bits;289 290		/* Start the allocation.We are not zeroing out the clusters */291		while (nr_cluster-- > 0) {292			err = fat_add_cluster(inode);293			if (err)294				goto error;295		}296	} else {297		if ((offset + len) <= i_size_read(inode))298			goto error;299 300		/* This is just an expanding truncate */301		err = fat_cont_expand(inode, (offset + len));302	}303 304error:305	inode_unlock(inode);306	return err;307}308 309/* Free all clusters after the skip'th cluster. */310static int fat_free(struct inode *inode, int skip)311{312	struct super_block *sb = inode->i_sb;313	int err, wait, free_start, i_start, i_logstart;314 315	if (MSDOS_I(inode)->i_start == 0)316		return 0;317 318	fat_cache_inval_inode(inode);319 320	wait = IS_DIRSYNC(inode);321	i_start = free_start = MSDOS_I(inode)->i_start;322	i_logstart = MSDOS_I(inode)->i_logstart;323 324	/* First, we write the new file size. */325	if (!skip) {326		MSDOS_I(inode)->i_start = 0;327		MSDOS_I(inode)->i_logstart = 0;328	}329	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;330	fat_truncate_time(inode, NULL, S_CTIME|S_MTIME);331	if (wait) {332		err = fat_sync_inode(inode);333		if (err) {334			MSDOS_I(inode)->i_start = i_start;335			MSDOS_I(inode)->i_logstart = i_logstart;336			return err;337		}338	} else339		mark_inode_dirty(inode);340 341	/* Write a new EOF, and get the remaining cluster chain for freeing. */342	if (skip) {343		struct fat_entry fatent;344		int ret, fclus, dclus;345 346		ret = fat_get_cluster(inode, skip - 1, &fclus, &dclus);347		if (ret < 0)348			return ret;349		else if (ret == FAT_ENT_EOF)350			return 0;351 352		fatent_init(&fatent);353		ret = fat_ent_read(inode, &fatent, dclus);354		if (ret == FAT_ENT_EOF) {355			fatent_brelse(&fatent);356			return 0;357		} else if (ret == FAT_ENT_FREE) {358			fat_fs_error(sb,359				     "%s: invalid cluster chain (i_pos %lld)",360				     __func__, MSDOS_I(inode)->i_pos);361			ret = -EIO;362		} else if (ret > 0) {363			err = fat_ent_write(inode, &fatent, FAT_ENT_EOF, wait);364			if (err)365				ret = err;366		}367		fatent_brelse(&fatent);368		if (ret < 0)369			return ret;370 371		free_start = ret;372	}373	inode->i_blocks = skip << (MSDOS_SB(sb)->cluster_bits - 9);374 375	/* Freeing the remained cluster chain */376	return fat_free_clusters(inode, free_start);377}378 379void fat_truncate_blocks(struct inode *inode, loff_t offset)380{381	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);382	const unsigned int cluster_size = sbi->cluster_size;383	int nr_clusters;384 385	/*386	 * This protects against truncating a file bigger than it was then387	 * trying to write into the hole.388	 */389	if (MSDOS_I(inode)->mmu_private > offset)390		MSDOS_I(inode)->mmu_private = offset;391 392	nr_clusters = (offset + (cluster_size - 1)) >> sbi->cluster_bits;393 394	fat_free(inode, nr_clusters);395	fat_flush_inodes(inode->i_sb, inode, NULL);396}397 398int fat_getattr(struct mnt_idmap *idmap, const struct path *path,399		struct kstat *stat, u32 request_mask, unsigned int flags)400{401	struct inode *inode = d_inode(path->dentry);402	struct msdos_sb_info *sbi = MSDOS_SB(inode->i_sb);403 404	generic_fillattr(idmap, request_mask, inode, stat);405	stat->blksize = sbi->cluster_size;406 407	if (sbi->options.nfs == FAT_NFS_NOSTALE_RO) {408		/* Use i_pos for ino. This is used as fileid of nfs. */409		stat->ino = fat_i_pos_read(sbi, inode);410	}411 412	if (sbi->options.isvfat && request_mask & STATX_BTIME) {413		stat->result_mask |= STATX_BTIME;414		stat->btime = MSDOS_I(inode)->i_crtime;415	}416 417	return 0;418}419EXPORT_SYMBOL_GPL(fat_getattr);420 421static int fat_sanitize_mode(const struct msdos_sb_info *sbi,422			     struct inode *inode, umode_t *mode_ptr)423{424	umode_t mask, perm;425 426	/*427	 * Note, the basic check is already done by a caller of428	 * (attr->ia_mode & ~FAT_VALID_MODE)429	 */430 431	if (S_ISREG(inode->i_mode))432		mask = sbi->options.fs_fmask;433	else434		mask = sbi->options.fs_dmask;435 436	perm = *mode_ptr & ~(S_IFMT | mask);437 438	/*439	 * Of the r and x bits, all (subject to umask) must be present. Of the440	 * w bits, either all (subject to umask) or none must be present.441	 *442	 * If fat_mode_can_hold_ro(inode) is false, can't change w bits.443	 */444	if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))445		return -EPERM;446	if (fat_mode_can_hold_ro(inode)) {447		if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask)))448			return -EPERM;449	} else {450		if ((perm & S_IWUGO) != (S_IWUGO & ~mask))451			return -EPERM;452	}453 454	*mode_ptr &= S_IFMT | perm;455 456	return 0;457}458 459static int fat_allow_set_time(struct mnt_idmap *idmap,460			      struct msdos_sb_info *sbi, struct inode *inode)461{462	umode_t allow_utime = sbi->options.allow_utime;463 464	if (!vfsuid_eq_kuid(i_uid_into_vfsuid(idmap, inode),465			    current_fsuid())) {466		if (vfsgid_in_group_p(i_gid_into_vfsgid(idmap, inode)))467			allow_utime >>= 3;468		if (allow_utime & MAY_WRITE)469			return 1;470	}471 472	/* use a default check */473	return 0;474}475 476#define TIMES_SET_FLAGS	(ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)477/* valid file mode bits */478#define FAT_VALID_MODE	(S_IFREG | S_IFDIR | S_IRWXUGO)479 480int fat_setattr(struct mnt_idmap *idmap, struct dentry *dentry,481		struct iattr *attr)482{483	struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);484	struct inode *inode = d_inode(dentry);485	unsigned int ia_valid;486	int error;487 488	/* Check for setting the inode time. */489	ia_valid = attr->ia_valid;490	if (ia_valid & TIMES_SET_FLAGS) {491		if (fat_allow_set_time(idmap, sbi, inode))492			attr->ia_valid &= ~TIMES_SET_FLAGS;493	}494 495	error = setattr_prepare(idmap, dentry, attr);496	attr->ia_valid = ia_valid;497	if (error) {498		if (sbi->options.quiet)499			error = 0;500		goto out;501	}502 503	/*504	 * Expand the file. Since inode_setattr() updates ->i_size505	 * before calling the ->truncate(), but FAT needs to fill the506	 * hole before it. XXX: this is no longer true with new truncate507	 * sequence.508	 */509	if (attr->ia_valid & ATTR_SIZE) {510		inode_dio_wait(inode);511 512		if (attr->ia_size > inode->i_size) {513			error = fat_cont_expand(inode, attr->ia_size);514			if (error || attr->ia_valid == ATTR_SIZE)515				goto out;516			attr->ia_valid &= ~ATTR_SIZE;517		}518	}519 520	if (((attr->ia_valid & ATTR_UID) &&521	     (!uid_eq(from_vfsuid(idmap, i_user_ns(inode), attr->ia_vfsuid),522		      sbi->options.fs_uid))) ||523	    ((attr->ia_valid & ATTR_GID) &&524	     (!gid_eq(from_vfsgid(idmap, i_user_ns(inode), attr->ia_vfsgid),525		      sbi->options.fs_gid))) ||526	    ((attr->ia_valid & ATTR_MODE) &&527	     (attr->ia_mode & ~FAT_VALID_MODE)))528		error = -EPERM;529 530	if (error) {531		if (sbi->options.quiet)532			error = 0;533		goto out;534	}535 536	/*537	 * We don't return -EPERM here. Yes, strange, but this is too538	 * old behavior.539	 */540	if (attr->ia_valid & ATTR_MODE) {541		if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0)542			attr->ia_valid &= ~ATTR_MODE;543	}544 545	if (attr->ia_valid & ATTR_SIZE) {546		error = fat_block_truncate_page(inode, attr->ia_size);547		if (error)548			goto out;549		down_write(&MSDOS_I(inode)->truncate_lock);550		truncate_setsize(inode, attr->ia_size);551		fat_truncate_blocks(inode, attr->ia_size);552		up_write(&MSDOS_I(inode)->truncate_lock);553	}554 555	/*556	 * setattr_copy can't truncate these appropriately, so we'll557	 * copy them ourselves558	 */559	if (attr->ia_valid & ATTR_ATIME)560		fat_truncate_time(inode, &attr->ia_atime, S_ATIME);561	if (attr->ia_valid & ATTR_CTIME)562		fat_truncate_time(inode, &attr->ia_ctime, S_CTIME);563	if (attr->ia_valid & ATTR_MTIME)564		fat_truncate_time(inode, &attr->ia_mtime, S_MTIME);565	attr->ia_valid &= ~(ATTR_ATIME|ATTR_CTIME|ATTR_MTIME);566 567	setattr_copy(idmap, inode, attr);568	mark_inode_dirty(inode);569out:570	return error;571}572EXPORT_SYMBOL_GPL(fat_setattr);573 574const struct inode_operations fat_file_inode_operations = {575	.setattr	= fat_setattr,576	.getattr	= fat_getattr,577	.update_time	= fat_update_time,578};579