18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/**
38c2ecf20Sopenharmony_ci * eCryptfs: Linux filesystem encryption layer
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 1997-2004 Erez Zadok
68c2ecf20Sopenharmony_ci * Copyright (C) 2001-2004 Stony Brook University
78c2ecf20Sopenharmony_ci * Copyright (C) 2004-2007 International Business Machines Corp.
88c2ecf20Sopenharmony_ci *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
98c2ecf20Sopenharmony_ci *   		Michael C. Thompson <mcthomps@us.ibm.com>
108c2ecf20Sopenharmony_ci */
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci#include <linux/file.h>
138c2ecf20Sopenharmony_ci#include <linux/poll.h>
148c2ecf20Sopenharmony_ci#include <linux/slab.h>
158c2ecf20Sopenharmony_ci#include <linux/mount.h>
168c2ecf20Sopenharmony_ci#include <linux/pagemap.h>
178c2ecf20Sopenharmony_ci#include <linux/security.h>
188c2ecf20Sopenharmony_ci#include <linux/compat.h>
198c2ecf20Sopenharmony_ci#include <linux/fs_stack.h>
208c2ecf20Sopenharmony_ci#include "ecryptfs_kernel.h"
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci/**
238c2ecf20Sopenharmony_ci * ecryptfs_read_update_atime
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * generic_file_read updates the atime of upper layer inode.  But, it
268c2ecf20Sopenharmony_ci * doesn't give us a chance to update the atime of the lower layer
278c2ecf20Sopenharmony_ci * inode.  This function is a wrapper to generic_file_read.  It
288c2ecf20Sopenharmony_ci * updates the atime of the lower level inode if generic_file_read
298c2ecf20Sopenharmony_ci * returns without any errors. This is to be used only for file reads.
308c2ecf20Sopenharmony_ci * The function to be used for directory reads is ecryptfs_read.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_cistatic ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,
338c2ecf20Sopenharmony_ci				struct iov_iter *to)
348c2ecf20Sopenharmony_ci{
358c2ecf20Sopenharmony_ci	ssize_t rc;
368c2ecf20Sopenharmony_ci	struct path *path;
378c2ecf20Sopenharmony_ci	struct file *file = iocb->ki_filp;
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_ci	rc = generic_file_read_iter(iocb, to);
408c2ecf20Sopenharmony_ci	if (rc >= 0) {
418c2ecf20Sopenharmony_ci		path = ecryptfs_dentry_to_lower_path(file->f_path.dentry);
428c2ecf20Sopenharmony_ci		touch_atime(path);
438c2ecf20Sopenharmony_ci	}
448c2ecf20Sopenharmony_ci	return rc;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistruct ecryptfs_getdents_callback {
488c2ecf20Sopenharmony_ci	struct dir_context ctx;
498c2ecf20Sopenharmony_ci	struct dir_context *caller;
508c2ecf20Sopenharmony_ci	struct super_block *sb;
518c2ecf20Sopenharmony_ci	int filldir_called;
528c2ecf20Sopenharmony_ci	int entries_written;
538c2ecf20Sopenharmony_ci};
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci/* Inspired by generic filldir in fs/readdir.c */
568c2ecf20Sopenharmony_cistatic int
578c2ecf20Sopenharmony_ciecryptfs_filldir(struct dir_context *ctx, const char *lower_name,
588c2ecf20Sopenharmony_ci		 int lower_namelen, loff_t offset, u64 ino, unsigned int d_type)
598c2ecf20Sopenharmony_ci{
608c2ecf20Sopenharmony_ci	struct ecryptfs_getdents_callback *buf =
618c2ecf20Sopenharmony_ci		container_of(ctx, struct ecryptfs_getdents_callback, ctx);
628c2ecf20Sopenharmony_ci	size_t name_size;
638c2ecf20Sopenharmony_ci	char *name;
648c2ecf20Sopenharmony_ci	int rc;
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci	buf->filldir_called++;
678c2ecf20Sopenharmony_ci	rc = ecryptfs_decode_and_decrypt_filename(&name, &name_size,
688c2ecf20Sopenharmony_ci						  buf->sb, lower_name,
698c2ecf20Sopenharmony_ci						  lower_namelen);
708c2ecf20Sopenharmony_ci	if (rc) {
718c2ecf20Sopenharmony_ci		if (rc != -EINVAL) {
728c2ecf20Sopenharmony_ci			ecryptfs_printk(KERN_DEBUG,
738c2ecf20Sopenharmony_ci					"%s: Error attempting to decode and decrypt filename [%s]; rc = [%d]\n",
748c2ecf20Sopenharmony_ci					__func__, lower_name, rc);
758c2ecf20Sopenharmony_ci			return rc;
768c2ecf20Sopenharmony_ci		}
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci		/* Mask -EINVAL errors as these are most likely due a plaintext
798c2ecf20Sopenharmony_ci		 * filename present in the lower filesystem despite filename
808c2ecf20Sopenharmony_ci		 * encryption being enabled. One unavoidable example would be
818c2ecf20Sopenharmony_ci		 * the "lost+found" dentry in the root directory of an Ext4
828c2ecf20Sopenharmony_ci		 * filesystem.
838c2ecf20Sopenharmony_ci		 */
848c2ecf20Sopenharmony_ci		return 0;
858c2ecf20Sopenharmony_ci	}
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci	buf->caller->pos = buf->ctx.pos;
888c2ecf20Sopenharmony_ci	rc = !dir_emit(buf->caller, name, name_size, ino, d_type);
898c2ecf20Sopenharmony_ci	kfree(name);
908c2ecf20Sopenharmony_ci	if (!rc)
918c2ecf20Sopenharmony_ci		buf->entries_written++;
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci	return rc;
948c2ecf20Sopenharmony_ci}
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci/**
978c2ecf20Sopenharmony_ci * ecryptfs_readdir
988c2ecf20Sopenharmony_ci * @file: The eCryptfs directory file
998c2ecf20Sopenharmony_ci * @ctx: The actor to feed the entries to
1008c2ecf20Sopenharmony_ci */
1018c2ecf20Sopenharmony_cistatic int ecryptfs_readdir(struct file *file, struct dir_context *ctx)
1028c2ecf20Sopenharmony_ci{
1038c2ecf20Sopenharmony_ci	int rc;
1048c2ecf20Sopenharmony_ci	struct file *lower_file;
1058c2ecf20Sopenharmony_ci	struct inode *inode = file_inode(file);
1068c2ecf20Sopenharmony_ci	struct ecryptfs_getdents_callback buf = {
1078c2ecf20Sopenharmony_ci		.ctx.actor = ecryptfs_filldir,
1088c2ecf20Sopenharmony_ci		.caller = ctx,
1098c2ecf20Sopenharmony_ci		.sb = inode->i_sb,
1108c2ecf20Sopenharmony_ci	};
1118c2ecf20Sopenharmony_ci	lower_file = ecryptfs_file_to_lower(file);
1128c2ecf20Sopenharmony_ci	rc = iterate_dir(lower_file, &buf.ctx);
1138c2ecf20Sopenharmony_ci	ctx->pos = buf.ctx.pos;
1148c2ecf20Sopenharmony_ci	if (rc < 0)
1158c2ecf20Sopenharmony_ci		goto out;
1168c2ecf20Sopenharmony_ci	if (buf.filldir_called && !buf.entries_written)
1178c2ecf20Sopenharmony_ci		goto out;
1188c2ecf20Sopenharmony_ci	if (rc >= 0)
1198c2ecf20Sopenharmony_ci		fsstack_copy_attr_atime(inode,
1208c2ecf20Sopenharmony_ci					file_inode(lower_file));
1218c2ecf20Sopenharmony_ciout:
1228c2ecf20Sopenharmony_ci	return rc;
1238c2ecf20Sopenharmony_ci}
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_cistruct kmem_cache *ecryptfs_file_info_cache;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic int read_or_initialize_metadata(struct dentry *dentry)
1288c2ecf20Sopenharmony_ci{
1298c2ecf20Sopenharmony_ci	struct inode *inode = d_inode(dentry);
1308c2ecf20Sopenharmony_ci	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;
1318c2ecf20Sopenharmony_ci	struct ecryptfs_crypt_stat *crypt_stat;
1328c2ecf20Sopenharmony_ci	int rc;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
1358c2ecf20Sopenharmony_ci	mount_crypt_stat = &ecryptfs_superblock_to_private(
1368c2ecf20Sopenharmony_ci						inode->i_sb)->mount_crypt_stat;
1378c2ecf20Sopenharmony_ci	mutex_lock(&crypt_stat->cs_mutex);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci	if (crypt_stat->flags & ECRYPTFS_POLICY_APPLIED &&
1408c2ecf20Sopenharmony_ci	    crypt_stat->flags & ECRYPTFS_KEY_VALID) {
1418c2ecf20Sopenharmony_ci		rc = 0;
1428c2ecf20Sopenharmony_ci		goto out;
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	rc = ecryptfs_read_metadata(dentry);
1468c2ecf20Sopenharmony_ci	if (!rc)
1478c2ecf20Sopenharmony_ci		goto out;
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_ci	if (mount_crypt_stat->flags & ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED) {
1508c2ecf20Sopenharmony_ci		crypt_stat->flags &= ~(ECRYPTFS_I_SIZE_INITIALIZED
1518c2ecf20Sopenharmony_ci				       | ECRYPTFS_ENCRYPTED);
1528c2ecf20Sopenharmony_ci		rc = 0;
1538c2ecf20Sopenharmony_ci		goto out;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	if (!(mount_crypt_stat->flags & ECRYPTFS_XATTR_METADATA_ENABLED) &&
1578c2ecf20Sopenharmony_ci	    !i_size_read(ecryptfs_inode_to_lower(inode))) {
1588c2ecf20Sopenharmony_ci		rc = ecryptfs_initialize_file(dentry, inode);
1598c2ecf20Sopenharmony_ci		if (!rc)
1608c2ecf20Sopenharmony_ci			goto out;
1618c2ecf20Sopenharmony_ci	}
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	rc = -EIO;
1648c2ecf20Sopenharmony_ciout:
1658c2ecf20Sopenharmony_ci	mutex_unlock(&crypt_stat->cs_mutex);
1668c2ecf20Sopenharmony_ci	return rc;
1678c2ecf20Sopenharmony_ci}
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_cistatic int ecryptfs_mmap(struct file *file, struct vm_area_struct *vma)
1708c2ecf20Sopenharmony_ci{
1718c2ecf20Sopenharmony_ci	struct file *lower_file = ecryptfs_file_to_lower(file);
1728c2ecf20Sopenharmony_ci	/*
1738c2ecf20Sopenharmony_ci	 * Don't allow mmap on top of file systems that don't support it
1748c2ecf20Sopenharmony_ci	 * natively.  If FILESYSTEM_MAX_STACK_DEPTH > 2 or ecryptfs
1758c2ecf20Sopenharmony_ci	 * allows recursive mounting, this will need to be extended.
1768c2ecf20Sopenharmony_ci	 */
1778c2ecf20Sopenharmony_ci	if (!lower_file->f_op->mmap)
1788c2ecf20Sopenharmony_ci		return -ENODEV;
1798c2ecf20Sopenharmony_ci	return generic_file_mmap(file, vma);
1808c2ecf20Sopenharmony_ci}
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/**
1838c2ecf20Sopenharmony_ci * ecryptfs_open
1848c2ecf20Sopenharmony_ci * @inode: inode specifying file to open
1858c2ecf20Sopenharmony_ci * @file: Structure to return filled in
1868c2ecf20Sopenharmony_ci *
1878c2ecf20Sopenharmony_ci * Opens the file specified by inode.
1888c2ecf20Sopenharmony_ci *
1898c2ecf20Sopenharmony_ci * Returns zero on success; non-zero otherwise
1908c2ecf20Sopenharmony_ci */
1918c2ecf20Sopenharmony_cistatic int ecryptfs_open(struct inode *inode, struct file *file)
1928c2ecf20Sopenharmony_ci{
1938c2ecf20Sopenharmony_ci	int rc = 0;
1948c2ecf20Sopenharmony_ci	struct ecryptfs_crypt_stat *crypt_stat = NULL;
1958c2ecf20Sopenharmony_ci	struct dentry *ecryptfs_dentry = file->f_path.dentry;
1968c2ecf20Sopenharmony_ci	/* Private value of ecryptfs_dentry allocated in
1978c2ecf20Sopenharmony_ci	 * ecryptfs_lookup() */
1988c2ecf20Sopenharmony_ci	struct ecryptfs_file_info *file_info;
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci	/* Released in ecryptfs_release or end of function if failure */
2018c2ecf20Sopenharmony_ci	file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL);
2028c2ecf20Sopenharmony_ci	ecryptfs_set_file_private(file, file_info);
2038c2ecf20Sopenharmony_ci	if (!file_info) {
2048c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR,
2058c2ecf20Sopenharmony_ci				"Error attempting to allocate memory\n");
2068c2ecf20Sopenharmony_ci		rc = -ENOMEM;
2078c2ecf20Sopenharmony_ci		goto out;
2088c2ecf20Sopenharmony_ci	}
2098c2ecf20Sopenharmony_ci	crypt_stat = &ecryptfs_inode_to_private(inode)->crypt_stat;
2108c2ecf20Sopenharmony_ci	mutex_lock(&crypt_stat->cs_mutex);
2118c2ecf20Sopenharmony_ci	if (!(crypt_stat->flags & ECRYPTFS_POLICY_APPLIED)) {
2128c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_DEBUG, "Setting flags for stat...\n");
2138c2ecf20Sopenharmony_ci		/* Policy code enabled in future release */
2148c2ecf20Sopenharmony_ci		crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED
2158c2ecf20Sopenharmony_ci				      | ECRYPTFS_ENCRYPTED);
2168c2ecf20Sopenharmony_ci	}
2178c2ecf20Sopenharmony_ci	mutex_unlock(&crypt_stat->cs_mutex);
2188c2ecf20Sopenharmony_ci	rc = ecryptfs_get_lower_file(ecryptfs_dentry, inode);
2198c2ecf20Sopenharmony_ci	if (rc) {
2208c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error attempting to initialize "
2218c2ecf20Sopenharmony_ci			"the lower file for the dentry with name "
2228c2ecf20Sopenharmony_ci			"[%pd]; rc = [%d]\n", __func__,
2238c2ecf20Sopenharmony_ci			ecryptfs_dentry, rc);
2248c2ecf20Sopenharmony_ci		goto out_free;
2258c2ecf20Sopenharmony_ci	}
2268c2ecf20Sopenharmony_ci	if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags & O_ACCMODE)
2278c2ecf20Sopenharmony_ci	    == O_RDONLY && (file->f_flags & O_ACCMODE) != O_RDONLY) {
2288c2ecf20Sopenharmony_ci		rc = -EPERM;
2298c2ecf20Sopenharmony_ci		printk(KERN_WARNING "%s: Lower file is RO; eCryptfs "
2308c2ecf20Sopenharmony_ci		       "file must hence be opened RO\n", __func__);
2318c2ecf20Sopenharmony_ci		goto out_put;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci	ecryptfs_set_file_lower(
2348c2ecf20Sopenharmony_ci		file, ecryptfs_inode_to_private(inode)->lower_file);
2358c2ecf20Sopenharmony_ci	rc = read_or_initialize_metadata(ecryptfs_dentry);
2368c2ecf20Sopenharmony_ci	if (rc)
2378c2ecf20Sopenharmony_ci		goto out_put;
2388c2ecf20Sopenharmony_ci	ecryptfs_printk(KERN_DEBUG, "inode w/ addr = [0x%p], i_ino = "
2398c2ecf20Sopenharmony_ci			"[0x%.16lx] size: [0x%.16llx]\n", inode, inode->i_ino,
2408c2ecf20Sopenharmony_ci			(unsigned long long)i_size_read(inode));
2418c2ecf20Sopenharmony_ci	goto out;
2428c2ecf20Sopenharmony_ciout_put:
2438c2ecf20Sopenharmony_ci	ecryptfs_put_lower_file(inode);
2448c2ecf20Sopenharmony_ciout_free:
2458c2ecf20Sopenharmony_ci	kmem_cache_free(ecryptfs_file_info_cache,
2468c2ecf20Sopenharmony_ci			ecryptfs_file_to_private(file));
2478c2ecf20Sopenharmony_ciout:
2488c2ecf20Sopenharmony_ci	return rc;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci/**
2528c2ecf20Sopenharmony_ci * ecryptfs_dir_open
2538c2ecf20Sopenharmony_ci * @inode: inode specifying file to open
2548c2ecf20Sopenharmony_ci * @file: Structure to return filled in
2558c2ecf20Sopenharmony_ci *
2568c2ecf20Sopenharmony_ci * Opens the file specified by inode.
2578c2ecf20Sopenharmony_ci *
2588c2ecf20Sopenharmony_ci * Returns zero on success; non-zero otherwise
2598c2ecf20Sopenharmony_ci */
2608c2ecf20Sopenharmony_cistatic int ecryptfs_dir_open(struct inode *inode, struct file *file)
2618c2ecf20Sopenharmony_ci{
2628c2ecf20Sopenharmony_ci	struct dentry *ecryptfs_dentry = file->f_path.dentry;
2638c2ecf20Sopenharmony_ci	/* Private value of ecryptfs_dentry allocated in
2648c2ecf20Sopenharmony_ci	 * ecryptfs_lookup() */
2658c2ecf20Sopenharmony_ci	struct ecryptfs_file_info *file_info;
2668c2ecf20Sopenharmony_ci	struct file *lower_file;
2678c2ecf20Sopenharmony_ci
2688c2ecf20Sopenharmony_ci	/* Released in ecryptfs_release or end of function if failure */
2698c2ecf20Sopenharmony_ci	file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL);
2708c2ecf20Sopenharmony_ci	ecryptfs_set_file_private(file, file_info);
2718c2ecf20Sopenharmony_ci	if (unlikely(!file_info)) {
2728c2ecf20Sopenharmony_ci		ecryptfs_printk(KERN_ERR,
2738c2ecf20Sopenharmony_ci				"Error attempting to allocate memory\n");
2748c2ecf20Sopenharmony_ci		return -ENOMEM;
2758c2ecf20Sopenharmony_ci	}
2768c2ecf20Sopenharmony_ci	lower_file = dentry_open(ecryptfs_dentry_to_lower_path(ecryptfs_dentry),
2778c2ecf20Sopenharmony_ci				 file->f_flags, current_cred());
2788c2ecf20Sopenharmony_ci	if (IS_ERR(lower_file)) {
2798c2ecf20Sopenharmony_ci		printk(KERN_ERR "%s: Error attempting to initialize "
2808c2ecf20Sopenharmony_ci			"the lower file for the dentry with name "
2818c2ecf20Sopenharmony_ci			"[%pd]; rc = [%ld]\n", __func__,
2828c2ecf20Sopenharmony_ci			ecryptfs_dentry, PTR_ERR(lower_file));
2838c2ecf20Sopenharmony_ci		kmem_cache_free(ecryptfs_file_info_cache, file_info);
2848c2ecf20Sopenharmony_ci		return PTR_ERR(lower_file);
2858c2ecf20Sopenharmony_ci	}
2868c2ecf20Sopenharmony_ci	ecryptfs_set_file_lower(file, lower_file);
2878c2ecf20Sopenharmony_ci	return 0;
2888c2ecf20Sopenharmony_ci}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_cistatic int ecryptfs_flush(struct file *file, fl_owner_t td)
2918c2ecf20Sopenharmony_ci{
2928c2ecf20Sopenharmony_ci	struct file *lower_file = ecryptfs_file_to_lower(file);
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	if (lower_file->f_op->flush) {
2958c2ecf20Sopenharmony_ci		filemap_write_and_wait(file->f_mapping);
2968c2ecf20Sopenharmony_ci		return lower_file->f_op->flush(lower_file, td);
2978c2ecf20Sopenharmony_ci	}
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	return 0;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_cistatic int ecryptfs_release(struct inode *inode, struct file *file)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	ecryptfs_put_lower_file(inode);
3058c2ecf20Sopenharmony_ci	kmem_cache_free(ecryptfs_file_info_cache,
3068c2ecf20Sopenharmony_ci			ecryptfs_file_to_private(file));
3078c2ecf20Sopenharmony_ci	return 0;
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_cistatic int ecryptfs_dir_release(struct inode *inode, struct file *file)
3118c2ecf20Sopenharmony_ci{
3128c2ecf20Sopenharmony_ci	fput(ecryptfs_file_to_lower(file));
3138c2ecf20Sopenharmony_ci	kmem_cache_free(ecryptfs_file_info_cache,
3148c2ecf20Sopenharmony_ci			ecryptfs_file_to_private(file));
3158c2ecf20Sopenharmony_ci	return 0;
3168c2ecf20Sopenharmony_ci}
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_cistatic loff_t ecryptfs_dir_llseek(struct file *file, loff_t offset, int whence)
3198c2ecf20Sopenharmony_ci{
3208c2ecf20Sopenharmony_ci	return vfs_llseek(ecryptfs_file_to_lower(file), offset, whence);
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_cistatic int
3248c2ecf20Sopenharmony_ciecryptfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	int rc;
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_ci	rc = file_write_and_wait(file);
3298c2ecf20Sopenharmony_ci	if (rc)
3308c2ecf20Sopenharmony_ci		return rc;
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci	return vfs_fsync(ecryptfs_file_to_lower(file), datasync);
3338c2ecf20Sopenharmony_ci}
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic int ecryptfs_fasync(int fd, struct file *file, int flag)
3368c2ecf20Sopenharmony_ci{
3378c2ecf20Sopenharmony_ci	int rc = 0;
3388c2ecf20Sopenharmony_ci	struct file *lower_file = NULL;
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	lower_file = ecryptfs_file_to_lower(file);
3418c2ecf20Sopenharmony_ci	if (lower_file->f_op->fasync)
3428c2ecf20Sopenharmony_ci		rc = lower_file->f_op->fasync(fd, lower_file, flag);
3438c2ecf20Sopenharmony_ci	return rc;
3448c2ecf20Sopenharmony_ci}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_cistatic long
3478c2ecf20Sopenharmony_ciecryptfs_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
3488c2ecf20Sopenharmony_ci{
3498c2ecf20Sopenharmony_ci	struct file *lower_file = ecryptfs_file_to_lower(file);
3508c2ecf20Sopenharmony_ci	long rc = -ENOTTY;
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	if (!lower_file->f_op->unlocked_ioctl)
3538c2ecf20Sopenharmony_ci		return rc;
3548c2ecf20Sopenharmony_ci
3558c2ecf20Sopenharmony_ci	switch (cmd) {
3568c2ecf20Sopenharmony_ci	case FITRIM:
3578c2ecf20Sopenharmony_ci	case FS_IOC_GETFLAGS:
3588c2ecf20Sopenharmony_ci	case FS_IOC_SETFLAGS:
3598c2ecf20Sopenharmony_ci	case FS_IOC_GETVERSION:
3608c2ecf20Sopenharmony_ci	case FS_IOC_SETVERSION:
3618c2ecf20Sopenharmony_ci		rc = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
3628c2ecf20Sopenharmony_ci		fsstack_copy_attr_all(file_inode(file), file_inode(lower_file));
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci		return rc;
3658c2ecf20Sopenharmony_ci	default:
3668c2ecf20Sopenharmony_ci		return rc;
3678c2ecf20Sopenharmony_ci	}
3688c2ecf20Sopenharmony_ci}
3698c2ecf20Sopenharmony_ci
3708c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
3718c2ecf20Sopenharmony_cistatic long
3728c2ecf20Sopenharmony_ciecryptfs_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
3738c2ecf20Sopenharmony_ci{
3748c2ecf20Sopenharmony_ci	struct file *lower_file = ecryptfs_file_to_lower(file);
3758c2ecf20Sopenharmony_ci	long rc = -ENOIOCTLCMD;
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci	if (!lower_file->f_op->compat_ioctl)
3788c2ecf20Sopenharmony_ci		return rc;
3798c2ecf20Sopenharmony_ci
3808c2ecf20Sopenharmony_ci	switch (cmd) {
3818c2ecf20Sopenharmony_ci	case FITRIM:
3828c2ecf20Sopenharmony_ci	case FS_IOC32_GETFLAGS:
3838c2ecf20Sopenharmony_ci	case FS_IOC32_SETFLAGS:
3848c2ecf20Sopenharmony_ci	case FS_IOC32_GETVERSION:
3858c2ecf20Sopenharmony_ci	case FS_IOC32_SETVERSION:
3868c2ecf20Sopenharmony_ci		rc = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
3878c2ecf20Sopenharmony_ci		fsstack_copy_attr_all(file_inode(file), file_inode(lower_file));
3888c2ecf20Sopenharmony_ci
3898c2ecf20Sopenharmony_ci		return rc;
3908c2ecf20Sopenharmony_ci	default:
3918c2ecf20Sopenharmony_ci		return rc;
3928c2ecf20Sopenharmony_ci	}
3938c2ecf20Sopenharmony_ci}
3948c2ecf20Sopenharmony_ci#endif
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ciconst struct file_operations ecryptfs_dir_fops = {
3978c2ecf20Sopenharmony_ci	.iterate_shared = ecryptfs_readdir,
3988c2ecf20Sopenharmony_ci	.read = generic_read_dir,
3998c2ecf20Sopenharmony_ci	.unlocked_ioctl = ecryptfs_unlocked_ioctl,
4008c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
4018c2ecf20Sopenharmony_ci	.compat_ioctl = ecryptfs_compat_ioctl,
4028c2ecf20Sopenharmony_ci#endif
4038c2ecf20Sopenharmony_ci	.open = ecryptfs_dir_open,
4048c2ecf20Sopenharmony_ci	.release = ecryptfs_dir_release,
4058c2ecf20Sopenharmony_ci	.fsync = ecryptfs_fsync,
4068c2ecf20Sopenharmony_ci	.llseek = ecryptfs_dir_llseek,
4078c2ecf20Sopenharmony_ci};
4088c2ecf20Sopenharmony_ci
4098c2ecf20Sopenharmony_ciconst struct file_operations ecryptfs_main_fops = {
4108c2ecf20Sopenharmony_ci	.llseek = generic_file_llseek,
4118c2ecf20Sopenharmony_ci	.read_iter = ecryptfs_read_update_atime,
4128c2ecf20Sopenharmony_ci	.write_iter = generic_file_write_iter,
4138c2ecf20Sopenharmony_ci	.unlocked_ioctl = ecryptfs_unlocked_ioctl,
4148c2ecf20Sopenharmony_ci#ifdef CONFIG_COMPAT
4158c2ecf20Sopenharmony_ci	.compat_ioctl = ecryptfs_compat_ioctl,
4168c2ecf20Sopenharmony_ci#endif
4178c2ecf20Sopenharmony_ci	.mmap = ecryptfs_mmap,
4188c2ecf20Sopenharmony_ci	.open = ecryptfs_open,
4198c2ecf20Sopenharmony_ci	.flush = ecryptfs_flush,
4208c2ecf20Sopenharmony_ci	.release = ecryptfs_release,
4218c2ecf20Sopenharmony_ci	.fsync = ecryptfs_fsync,
4228c2ecf20Sopenharmony_ci	.fasync = ecryptfs_fasync,
4238c2ecf20Sopenharmony_ci	.splice_read = generic_file_splice_read,
4248c2ecf20Sopenharmony_ci};
425