/** * ecryptfs_llseek * @file: File we are seeking in * @offset: The offset to seek to * @origin: 2 - offset from i_size; 1 - offset from f_pos * * Returns the position we have seeked to, or negative on error */ static loff_t ecryptfs_llseek(struct file *file, loff_t offset, int origin) { loff_t rv; loff_t new_end_pos; int rc; int expanding_file = 0; struct inode *inode = file->f_mapping->host; /* If our offset is past the end of our file, we're going to * need to grow it so we have a valid length of 0's */ new_end_pos = offset; switch (origin) { case 2: new_end_pos += i_size_read(inode); expanding_file = 1; break; case 1: new_end_pos += file->f_pos; if (new_end_pos > i_size_read(inode)) { ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) " "> i_size_read(inode)(=[0x%.16x])\n", new_end_pos, i_size_read(inode)); expanding_file = 1; } break; default: if (new_end_pos > i_size_read(inode)) { ecryptfs_printk(KERN_DEBUG, "new_end_pos(=[0x%.16x]) " "> i_size_read(inode)(=[0x%.16x])\n", new_end_pos, i_size_read(inode)); expanding_file = 1; } } ecryptfs_printk(KERN_DEBUG, "new_end_pos = [0x%.16x]\n", new_end_pos); if (expanding_file) { rc = ecryptfs_truncate(file->f_path.dentry, new_end_pos); if (rc) { rv = rc; ecryptfs_printk(KERN_ERR, "Error on attempt to " "truncate to (higher) offset [0x%.16x];" " rc = [%d]\n", new_end_pos, rc); goto out; } } rv = generic_file_llseek(file, offset, origin); out: return rv; }
/** * ecryptfs_readpage * @file: An eCryptfs file * @page: Page from eCryptfs inode mapping into which to stick the read data * * Read in a page, decrypting if necessary. * * Returns zero on success; non-zero on error. */ static int ecryptfs_readpage(struct file *file, struct page *page) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(page->mapping->host)->crypt_stat; #ifdef CONFIG_CRYPTO_DEV_KFIPS struct ecryptfs_page_crypt_req *page_crypt_req = NULL; #endif int rc = 0; if (!crypt_stat || !(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_read_lower_page_segment(page, page->index, 0, PAGE_CACHE_SIZE, page->mapping->host); } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { rc = ecryptfs_copy_up_encrypted_with_header(page, crypt_stat); if (rc) { printk(KERN_ERR "%s: Error attempting to copy " "the encrypted content from the lower " "file whilst inserting the metadata " "from the xattr into the header; rc = " "[%d]\n", __func__, rc); goto out; } } else { rc = ecryptfs_read_lower_page_segment( page, page->index, 0, PAGE_CACHE_SIZE, page->mapping->host); if (rc) { printk(KERN_ERR "Error reading page; rc = " "[%d]\n", rc); goto out; } } } else { #ifndef CONFIG_CRYPTO_DEV_KFIPS rc = ecryptfs_decrypt_page(page); if (rc) { ecryptfs_printk(KERN_ERR, "Error decrypting page; " "rc = [%d]\n", rc); #else page_crypt_req = ecryptfs_alloc_page_crypt_req( page, ecryptfs_readpage_complete); if (!page_crypt_req) { rc = -ENOMEM; ecryptfs_printk(KERN_ERR, "Failed to allocate page crypt request " "for decryption\n"); #endif goto out; } #ifdef CONFIG_CRYPTO_DEV_KFIPS ecryptfs_decrypt_page_async(page_crypt_req); goto out_async_started; #endif } out: #ifndef CONFIG_CRYPTO_DEV_KFIPS if (rc) #else if (unlikely(rc)) #endif ClearPageUptodate(page); else SetPageUptodate(page); ecryptfs_printk(KERN_DEBUG, "Unlocking page with index = [0x%.16lx]\n", page->index); unlock_page(page); #ifdef CONFIG_CRYPTO_DEV_KFIPS out_async_started: #endif return rc; } /** * Called with lower inode mutex held. */ static int fill_zeros_to_end_of_page(struct page *page, unsigned int to) { struct inode *inode = page->mapping->host; int end_byte_in_page; if ((i_size_read(inode) / PAGE_CACHE_SIZE) != page->index) goto out; end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE; if (to > end_byte_in_page) end_byte_in_page = to; zero_user_segment(page, end_byte_in_page, PAGE_CACHE_SIZE); out: return 0; } /** * ecryptfs_write_begin * @file: The eCryptfs file * @mapping: The eCryptfs object * @pos: The file offset at which to start writing * @len: Length of the write * @flags: Various flags * @pagep: Pointer to return the page * @fsdata: Pointer to return fs data (unused) * * This function must zero any hole we create * * Returns zero on success; non-zero otherwise */ static int ecryptfs_write_begin(struct file *file, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) { pgoff_t index = pos >> PAGE_CACHE_SHIFT; struct page *page; loff_t prev_page_end_size; int rc = 0; page = grab_cache_page_write_begin(mapping, index, flags); if (!page) return -ENOMEM; *pagep = page; prev_page_end_size = ((loff_t)index << PAGE_CACHE_SHIFT); if (!PageUptodate(page)) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private(mapping->host)->crypt_stat; if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED)) { rc = ecryptfs_read_lower_page_segment( page, index, 0, PAGE_CACHE_SIZE, mapping->host); if (rc) { printk(KERN_ERR "%s: Error attemping to read " "lower page segment; rc = [%d]\n", __func__, rc); ClearPageUptodate(page); goto out; } else SetPageUptodate(page); } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { rc = ecryptfs_copy_up_encrypted_with_header( page, crypt_stat); if (rc) { printk(KERN_ERR "%s: Error attempting " "to copy the encrypted content " "from the lower file whilst " "inserting the metadata from " "the xattr into the header; rc " "= [%d]\n", __func__, rc); ClearPageUptodate(page); goto out; } SetPageUptodate(page); } else { rc = ecryptfs_read_lower_page_segment( page, index, 0, PAGE_CACHE_SIZE, mapping->host); if (rc) { printk(KERN_ERR "%s: Error reading " "page; rc = [%d]\n", __func__, rc); ClearPageUptodate(page); goto out; } SetPageUptodate(page); } } else { if (prev_page_end_size >= i_size_read(page->mapping->host)) { zero_user(page, 0, PAGE_CACHE_SIZE); } else { rc = ecryptfs_decrypt_page(page); if (rc) { printk(KERN_ERR "%s: Error decrypting " "page at index [%ld]; " "rc = [%d]\n", __func__, page->index, rc); ClearPageUptodate(page); goto out; } } SetPageUptodate(page); } } /* If creating a page or more of holes, zero them out via truncate. * Note, this will increase i_size. */ if (index != 0) { if (prev_page_end_size > i_size_read(page->mapping->host)) { rc = ecryptfs_truncate(file->f_path.dentry, prev_page_end_size); if (rc) { printk(KERN_ERR "%s: Error on attempt to " "truncate to (higher) offset [%lld];" " rc = [%d]\n", __func__, prev_page_end_size, rc); goto out; } } } /* Writing to a new page, and creating a small hole from start * of page? Zero it out. */ if ((i_size_read(mapping->host) == prev_page_end_size) && (pos != 0)) zero_user(page, 0, PAGE_CACHE_SIZE); out: if (unlikely(rc)) { unlock_page(page); page_cache_release(page); *pagep = NULL; } return rc; }
/** * ecryptfs_prepare_write * @file: The eCryptfs file * @page: The eCryptfs page * @from: The start byte from which we will write * @to: The end byte to which we will write * * This function must zero any hole we create * * Returns zero on success; non-zero otherwise */ static int ecryptfs_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to) { loff_t prev_page_end_size; int rc = 0; if (!PageUptodate(page)) { struct ecryptfs_crypt_stat *crypt_stat = &ecryptfs_inode_to_private( file->f_dentry->d_inode)->crypt_stat; if (!(crypt_stat->flags & ECRYPTFS_ENCRYPTED) || (crypt_stat->flags & ECRYPTFS_NEW_FILE)) { rc = ecryptfs_read_lower_page_segment( page, page->index, 0, PAGE_CACHE_SIZE, page->mapping->host); if (rc) { printk(KERN_ERR "%s: Error attemping to read " "lower page segment; rc = [%d]\n", __func__, rc); ClearPageUptodate(page); goto out; } else SetPageUptodate(page); } else if (crypt_stat->flags & ECRYPTFS_VIEW_AS_ENCRYPTED) { if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR) { rc = ecryptfs_copy_up_encrypted_with_header( page, crypt_stat); if (rc) { printk(KERN_ERR "%s: Error attempting " "to copy the encrypted content " "from the lower file whilst " "inserting the metadata from " "the xattr into the header; rc " "= [%d]\n", __func__, rc); ClearPageUptodate(page); goto out; } SetPageUptodate(page); } else { rc = ecryptfs_read_lower_page_segment( page, page->index, 0, PAGE_CACHE_SIZE, page->mapping->host); if (rc) { printk(KERN_ERR "%s: Error reading " "page; rc = [%d]\n", __func__, rc); ClearPageUptodate(page); goto out; } SetPageUptodate(page); } } else { rc = ecryptfs_decrypt_page(page); if (rc) { printk(KERN_ERR "%s: Error decrypting page " "at index [%ld]; rc = [%d]\n", __func__, page->index, rc); ClearPageUptodate(page); goto out; } SetPageUptodate(page); } } prev_page_end_size = ((loff_t)page->index << PAGE_CACHE_SHIFT); /* If creating a page or more of holes, zero them out via truncate. * Note, this will increase i_size. */ if (page->index != 0) { if (prev_page_end_size > i_size_read(page->mapping->host)) { rc = ecryptfs_truncate(file->f_dentry, prev_page_end_size); if (rc) { printk(KERN_ERR "%s: Error on attempt to " "truncate to (higher) offset [%lld];" " rc = [%d]\n", __func__, prev_page_end_size, rc); goto out; } } } /* Writing to a new page, and creating a small hole from start * of page? Zero it out. */ if ((i_size_read(page->mapping->host) == prev_page_end_size) && (from != 0)) zero_user(page, 0, PAGE_CACHE_SIZE); out: return rc; }