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