1 /* 2 * linux/fs/ext4/symlink.c 3 * 4 * Only fast symlinks left here - the rest is done by generic code. AV, 1999 5 * 6 * Copyright (C) 1992, 1993, 1994, 1995 7 * Remy Card (card@masi.ibp.fr) 8 * Laboratoire MASI - Institut Blaise Pascal 9 * Universite Pierre et Marie Curie (Paris VI) 10 * 11 * from 12 * 13 * linux/fs/minix/symlink.c 14 * 15 * Copyright (C) 1991, 1992 Linus Torvalds 16 * 17 * ext4 symlink handling code 18 */ 19 20 #include <linux/fs.h> 21 #include <linux/namei.h> 22 #include "ext4.h" 23 #include "xattr.h" 24 25 #ifdef CONFIG_EXT4_FS_ENCRYPTION 26 static const char *ext4_encrypted_get_link(struct dentry *dentry, 27 struct inode *inode, void **cookie) 28 { 29 struct page *cpage = NULL; 30 char *caddr, *paddr = NULL; 31 struct ext4_str cstr, pstr; 32 struct ext4_encrypted_symlink_data *sd; 33 loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1); 34 int res; 35 u32 plen, max_size = inode->i_sb->s_blocksize; 36 37 if (!dentry) 38 return ERR_PTR(-ECHILD); 39 40 res = ext4_get_encryption_info(inode); 41 if (res) 42 return ERR_PTR(res); 43 44 if (ext4_inode_is_fast_symlink(inode)) { 45 caddr = (char *) EXT4_I(inode)->i_data; 46 max_size = sizeof(EXT4_I(inode)->i_data); 47 } else { 48 cpage = read_mapping_page(inode->i_mapping, 0, NULL); 49 if (IS_ERR(cpage)) 50 return ERR_CAST(cpage); 51 caddr = page_address(cpage); 52 caddr[size] = 0; 53 } 54 55 /* Symlink is encrypted */ 56 sd = (struct ext4_encrypted_symlink_data *)caddr; 57 cstr.name = sd->encrypted_path; 58 cstr.len = le32_to_cpu(sd->len); 59 if ((cstr.len + 60 sizeof(struct ext4_encrypted_symlink_data) - 1) > 61 max_size) { 62 /* Symlink data on the disk is corrupted */ 63 res = -EFSCORRUPTED; 64 goto errout; 65 } 66 plen = (cstr.len < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) ? 67 EXT4_FNAME_CRYPTO_DIGEST_SIZE*2 : cstr.len; 68 paddr = kmalloc(plen + 1, GFP_NOFS); 69 if (!paddr) { 70 res = -ENOMEM; 71 goto errout; 72 } 73 pstr.name = paddr; 74 pstr.len = plen; 75 res = _ext4_fname_disk_to_usr(inode, NULL, &cstr, &pstr); 76 if (res < 0) 77 goto errout; 78 /* Null-terminate the name */ 79 if (res <= plen) 80 paddr[res] = '\0'; 81 if (cpage) 82 page_cache_release(cpage); 83 return *cookie = paddr; 84 errout: 85 if (cpage) 86 page_cache_release(cpage); 87 kfree(paddr); 88 return ERR_PTR(res); 89 } 90 91 const struct inode_operations ext4_encrypted_symlink_inode_operations = { 92 .readlink = generic_readlink, 93 .get_link = ext4_encrypted_get_link, 94 .put_link = kfree_put_link, 95 .setattr = ext4_setattr, 96 .setxattr = generic_setxattr, 97 .getxattr = generic_getxattr, 98 .listxattr = ext4_listxattr, 99 .removexattr = generic_removexattr, 100 }; 101 #endif 102 103 const struct inode_operations ext4_symlink_inode_operations = { 104 .readlink = generic_readlink, 105 .get_link = page_get_link, 106 .put_link = page_put_link, 107 .setattr = ext4_setattr, 108 .setxattr = generic_setxattr, 109 .getxattr = generic_getxattr, 110 .listxattr = ext4_listxattr, 111 .removexattr = generic_removexattr, 112 }; 113 114 const struct inode_operations ext4_fast_symlink_inode_operations = { 115 .readlink = generic_readlink, 116 .get_link = simple_get_link, 117 .setattr = ext4_setattr, 118 .setxattr = generic_setxattr, 119 .getxattr = generic_getxattr, 120 .listxattr = ext4_listxattr, 121 .removexattr = generic_removexattr, 122 }; 123