/**1* eCryptfs: Linux filesystem encryption layer2*3* Copyright (C) 2007 International Business Machines Corp.4* Author(s): Michael A. Halcrow <[email protected]>5*6* This program is free software; you can redistribute it and/or7* modify it under the terms of the GNU General Public License as8* published by the Free Software Foundation; either version 2 of the9* License, or (at your option) any later version.10*11* This program is distributed in the hope that it will be useful, but12* WITHOUT ANY WARRANTY; without even the implied warranty of13* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU14* General Public License for more details.15*16* You should have received a copy of the GNU General Public License17* along with this program; if not, write to the Free Software18* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA19* 02111-1307, USA.20*/2122#include <linux/fs.h>23#include <linux/pagemap.h>24#include "ecryptfs_kernel.h"2526/**27* ecryptfs_write_lower28* @ecryptfs_inode: The eCryptfs inode29* @data: Data to write30* @offset: Byte offset in the lower file to which to write the data31* @size: Number of bytes from @data to write at @offset in the lower32* file33*34* Write data to the lower file.35*36* Returns bytes written on success; less than zero on error37*/38int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,39loff_t offset, size_t size)40{41struct ecryptfs_inode_info *inode_info;42mm_segment_t fs_save;43ssize_t rc;4445inode_info = ecryptfs_inode_to_private(ecryptfs_inode);46BUG_ON(!inode_info->lower_file);47fs_save = get_fs();48set_fs(get_ds());49rc = vfs_write(inode_info->lower_file, data, size, &offset);50set_fs(fs_save);51mark_inode_dirty_sync(ecryptfs_inode);52return rc;53}5455/**56* ecryptfs_write_lower_page_segment57* @ecryptfs_inode: The eCryptfs inode58* @page_for_lower: The page containing the data to be written to the59* lower file60* @offset_in_page: The offset in the @page_for_lower from which to61* start writing the data62* @size: The amount of data from @page_for_lower to write to the63* lower file64*65* Determines the byte offset in the file for the given page and66* offset within the page, maps the page, and makes the call to write67* the contents of @page_for_lower to the lower inode.68*69* Returns zero on success; non-zero otherwise70*/71int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,72struct page *page_for_lower,73size_t offset_in_page, size_t size)74{75char *virt;76loff_t offset;77int rc;7879offset = ((((loff_t)page_for_lower->index) << PAGE_CACHE_SHIFT)80+ offset_in_page);81virt = kmap(page_for_lower);82rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);83if (rc > 0)84rc = 0;85kunmap(page_for_lower);86return rc;87}8889/**90* ecryptfs_write91* @ecryptfs_inode: The eCryptfs file into which to write92* @data: Virtual address where data to write is located93* @offset: Offset in the eCryptfs file at which to begin writing the94* data from @data95* @size: The number of bytes to write from @data96*97* Write an arbitrary amount of data to an arbitrary location in the98* eCryptfs inode page cache. This is done on a page-by-page, and then99* by an extent-by-extent, basis; individual extents are encrypted and100* written to the lower page cache (via VFS writes). This function101* takes care of all the address translation to locations in the lower102* filesystem; it also handles truncate events, writing out zeros103* where necessary.104*105* Returns zero on success; non-zero otherwise106*/107int ecryptfs_write(struct inode *ecryptfs_inode, char *data, loff_t offset,108size_t size)109{110struct page *ecryptfs_page;111struct ecryptfs_crypt_stat *crypt_stat;112char *ecryptfs_page_virt;113loff_t ecryptfs_file_size = i_size_read(ecryptfs_inode);114loff_t data_offset = 0;115loff_t pos;116int rc = 0;117118crypt_stat = &ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;119/*120* if we are writing beyond current size, then start pos121* at the current size - we'll fill in zeros from there.122*/123if (offset > ecryptfs_file_size)124pos = ecryptfs_file_size;125else126pos = offset;127while (pos < (offset + size)) {128pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT);129size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK);130size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page);131size_t total_remaining_bytes = ((offset + size) - pos);132133if (num_bytes > total_remaining_bytes)134num_bytes = total_remaining_bytes;135if (pos < offset) {136/* remaining zeros to write, up to destination offset */137size_t total_remaining_zeros = (offset - pos);138139if (num_bytes > total_remaining_zeros)140num_bytes = total_remaining_zeros;141}142ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_inode,143ecryptfs_page_idx);144if (IS_ERR(ecryptfs_page)) {145rc = PTR_ERR(ecryptfs_page);146printk(KERN_ERR "%s: Error getting page at "147"index [%ld] from eCryptfs inode "148"mapping; rc = [%d]\n", __func__,149ecryptfs_page_idx, rc);150goto out;151}152ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0);153154/*155* pos: where we're now writing, offset: where the request was156* If current pos is before request, we are filling zeros157* If we are at or beyond request, we are writing the *data*158* If we're in a fresh page beyond eof, zero it in either case159*/160if (pos < offset || !start_offset_in_page) {161/* We are extending past the previous end of the file.162* Fill in zero values to the end of the page */163memset(((char *)ecryptfs_page_virt164+ start_offset_in_page), 0,165PAGE_CACHE_SIZE - start_offset_in_page);166}167168/* pos >= offset, we are now writing the data request */169if (pos >= offset) {170memcpy(((char *)ecryptfs_page_virt171+ start_offset_in_page),172(data + data_offset), num_bytes);173data_offset += num_bytes;174}175kunmap_atomic(ecryptfs_page_virt, KM_USER0);176flush_dcache_page(ecryptfs_page);177SetPageUptodate(ecryptfs_page);178unlock_page(ecryptfs_page);179if (crypt_stat->flags & ECRYPTFS_ENCRYPTED)180rc = ecryptfs_encrypt_page(ecryptfs_page);181else182rc = ecryptfs_write_lower_page_segment(ecryptfs_inode,183ecryptfs_page,184start_offset_in_page,185data_offset);186page_cache_release(ecryptfs_page);187if (rc) {188printk(KERN_ERR "%s: Error encrypting "189"page; rc = [%d]\n", __func__, rc);190goto out;191}192pos += num_bytes;193}194if ((offset + size) > ecryptfs_file_size) {195i_size_write(ecryptfs_inode, (offset + size));196if (crypt_stat->flags & ECRYPTFS_ENCRYPTED) {197rc = ecryptfs_write_inode_size_to_metadata(198ecryptfs_inode);199if (rc) {200printk(KERN_ERR "Problem with "201"ecryptfs_write_inode_size_to_metadata; "202"rc = [%d]\n", rc);203goto out;204}205}206}207out:208return rc;209}210211/**212* ecryptfs_read_lower213* @data: The read data is stored here by this function214* @offset: Byte offset in the lower file from which to read the data215* @size: Number of bytes to read from @offset of the lower file and216* store into @data217* @ecryptfs_inode: The eCryptfs inode218*219* Read @size bytes of data at byte offset @offset from the lower220* inode into memory location @data.221*222* Returns bytes read on success; 0 on EOF; less than zero on error223*/224int ecryptfs_read_lower(char *data, loff_t offset, size_t size,225struct inode *ecryptfs_inode)226{227struct ecryptfs_inode_info *inode_info =228ecryptfs_inode_to_private(ecryptfs_inode);229mm_segment_t fs_save;230ssize_t rc;231232BUG_ON(!inode_info->lower_file);233fs_save = get_fs();234set_fs(get_ds());235rc = vfs_read(inode_info->lower_file, data, size, &offset);236set_fs(fs_save);237return rc;238}239240/**241* ecryptfs_read_lower_page_segment242* @page_for_ecryptfs: The page into which data for eCryptfs will be243* written244* @offset_in_page: Offset in @page_for_ecryptfs from which to start245* writing246* @size: The number of bytes to write into @page_for_ecryptfs247* @ecryptfs_inode: The eCryptfs inode248*249* Determines the byte offset in the file for the given page and250* offset within the page, maps the page, and makes the call to read251* the contents of @page_for_ecryptfs from the lower inode.252*253* Returns zero on success; non-zero otherwise254*/255int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,256pgoff_t page_index,257size_t offset_in_page, size_t size,258struct inode *ecryptfs_inode)259{260char *virt;261loff_t offset;262int rc;263264offset = ((((loff_t)page_index) << PAGE_CACHE_SHIFT) + offset_in_page);265virt = kmap(page_for_ecryptfs);266rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode);267if (rc > 0)268rc = 0;269kunmap(page_for_ecryptfs);270flush_dcache_page(page_for_ecryptfs);271return rc;272}273274#if 0275/**276* ecryptfs_read277* @data: The virtual address into which to write the data read (and278* possibly decrypted) from the lower file279* @offset: The offset in the decrypted view of the file from which to280* read into @data281* @size: The number of bytes to read into @data282* @ecryptfs_file: The eCryptfs file from which to read283*284* Read an arbitrary amount of data from an arbitrary location in the285* eCryptfs page cache. This is done on an extent-by-extent basis;286* individual extents are decrypted and read from the lower page287* cache (via VFS reads). This function takes care of all the288* address translation to locations in the lower filesystem.289*290* Returns zero on success; non-zero otherwise291*/292int ecryptfs_read(char *data, loff_t offset, size_t size,293struct file *ecryptfs_file)294{295struct inode *ecryptfs_inode = ecryptfs_file->f_dentry->d_inode;296struct page *ecryptfs_page;297char *ecryptfs_page_virt;298loff_t ecryptfs_file_size = i_size_read(ecryptfs_inode);299loff_t data_offset = 0;300loff_t pos;301int rc = 0;302303if ((offset + size) > ecryptfs_file_size) {304rc = -EINVAL;305printk(KERN_ERR "%s: Attempt to read data past the end of the "306"file; offset = [%lld]; size = [%td]; "307"ecryptfs_file_size = [%lld]\n",308__func__, offset, size, ecryptfs_file_size);309goto out;310}311pos = offset;312while (pos < (offset + size)) {313pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT);314size_t start_offset_in_page = (pos & ~PAGE_CACHE_MASK);315size_t num_bytes = (PAGE_CACHE_SIZE - start_offset_in_page);316size_t total_remaining_bytes = ((offset + size) - pos);317318if (num_bytes > total_remaining_bytes)319num_bytes = total_remaining_bytes;320ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_inode,321ecryptfs_page_idx);322if (IS_ERR(ecryptfs_page)) {323rc = PTR_ERR(ecryptfs_page);324printk(KERN_ERR "%s: Error getting page at "325"index [%ld] from eCryptfs inode "326"mapping; rc = [%d]\n", __func__,327ecryptfs_page_idx, rc);328goto out;329}330ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0);331memcpy((data + data_offset),332((char *)ecryptfs_page_virt + start_offset_in_page),333num_bytes);334kunmap_atomic(ecryptfs_page_virt, KM_USER0);335flush_dcache_page(ecryptfs_page);336SetPageUptodate(ecryptfs_page);337unlock_page(ecryptfs_page);338page_cache_release(ecryptfs_page);339pos += num_bytes;340data_offset += num_bytes;341}342out:343return rc;344}345#endif /* 0 */346347348