1ac27a0ecSDave Kleikamp /* 2617ba13bSMingming Cao * linux/fs/ext4/symlink.c 3ac27a0ecSDave Kleikamp * 4ac27a0ecSDave Kleikamp * Only fast symlinks left here - the rest is done by generic code. AV, 1999 5ac27a0ecSDave Kleikamp * 6ac27a0ecSDave Kleikamp * Copyright (C) 1992, 1993, 1994, 1995 7ac27a0ecSDave Kleikamp * Remy Card (card@masi.ibp.fr) 8ac27a0ecSDave Kleikamp * Laboratoire MASI - Institut Blaise Pascal 9ac27a0ecSDave Kleikamp * Universite Pierre et Marie Curie (Paris VI) 10ac27a0ecSDave Kleikamp * 11ac27a0ecSDave Kleikamp * from 12ac27a0ecSDave Kleikamp * 13ac27a0ecSDave Kleikamp * linux/fs/minix/symlink.c 14ac27a0ecSDave Kleikamp * 15ac27a0ecSDave Kleikamp * Copyright (C) 1991, 1992 Linus Torvalds 16ac27a0ecSDave Kleikamp * 17617ba13bSMingming Cao * ext4 symlink handling code 18ac27a0ecSDave Kleikamp */ 19ac27a0ecSDave Kleikamp 20ac27a0ecSDave Kleikamp #include <linux/fs.h> 21ac27a0ecSDave Kleikamp #include <linux/namei.h> 223dcf5451SChristoph Hellwig #include "ext4.h" 23ac27a0ecSDave Kleikamp #include "xattr.h" 24ac27a0ecSDave Kleikamp 25f348c252STheodore Ts'o #ifdef CONFIG_EXT4_FS_ENCRYPTION 26617ba13bSMingming Cao static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd) 27ac27a0ecSDave Kleikamp { 28f348c252STheodore Ts'o struct page *cpage = NULL; 29f348c252STheodore Ts'o char *caddr, *paddr = NULL; 30f348c252STheodore Ts'o struct ext4_str cstr, pstr; 31*9ec3a646SLinus Torvalds struct inode *inode = d_inode(dentry); 32f348c252STheodore Ts'o struct ext4_fname_crypto_ctx *ctx = NULL; 33f348c252STheodore Ts'o struct ext4_encrypted_symlink_data *sd; 34f348c252STheodore Ts'o loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1); 35f348c252STheodore Ts'o int res; 36f348c252STheodore Ts'o u32 plen, max_size = inode->i_sb->s_blocksize; 37f348c252STheodore Ts'o 38f348c252STheodore Ts'o if (!ext4_encrypted_inode(inode)) 39f348c252STheodore Ts'o return page_follow_link_light(dentry, nd); 40f348c252STheodore Ts'o 41f348c252STheodore Ts'o ctx = ext4_get_fname_crypto_ctx(inode, inode->i_sb->s_blocksize); 42f348c252STheodore Ts'o if (IS_ERR(ctx)) 43f348c252STheodore Ts'o return ctx; 44f348c252STheodore Ts'o 45f348c252STheodore Ts'o if (ext4_inode_is_fast_symlink(inode)) { 46*9ec3a646SLinus Torvalds caddr = (char *) EXT4_I(inode)->i_data; 47*9ec3a646SLinus Torvalds max_size = sizeof(EXT4_I(inode)->i_data); 48f348c252STheodore Ts'o } else { 49f348c252STheodore Ts'o cpage = read_mapping_page(inode->i_mapping, 0, NULL); 50f348c252STheodore Ts'o if (IS_ERR(cpage)) { 51f348c252STheodore Ts'o ext4_put_fname_crypto_ctx(&ctx); 52f348c252STheodore Ts'o return cpage; 53f348c252STheodore Ts'o } 54f348c252STheodore Ts'o caddr = kmap(cpage); 55f348c252STheodore Ts'o caddr[size] = 0; 56f348c252STheodore Ts'o } 57f348c252STheodore Ts'o 58f348c252STheodore Ts'o /* Symlink is encrypted */ 59f348c252STheodore Ts'o sd = (struct ext4_encrypted_symlink_data *)caddr; 60f348c252STheodore Ts'o cstr.name = sd->encrypted_path; 61f348c252STheodore Ts'o cstr.len = le32_to_cpu(sd->len); 62f348c252STheodore Ts'o if ((cstr.len + 63f348c252STheodore Ts'o sizeof(struct ext4_encrypted_symlink_data) - 1) > 64f348c252STheodore Ts'o max_size) { 65f348c252STheodore Ts'o /* Symlink data on the disk is corrupted */ 66f348c252STheodore Ts'o res = -EIO; 67f348c252STheodore Ts'o goto errout; 68f348c252STheodore Ts'o } 69f348c252STheodore Ts'o plen = (cstr.len < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) ? 70f348c252STheodore Ts'o EXT4_FNAME_CRYPTO_DIGEST_SIZE*2 : cstr.len; 71f348c252STheodore Ts'o paddr = kmalloc(plen + 1, GFP_NOFS); 72f348c252STheodore Ts'o if (!paddr) { 73f348c252STheodore Ts'o res = -ENOMEM; 74f348c252STheodore Ts'o goto errout; 75f348c252STheodore Ts'o } 76f348c252STheodore Ts'o pstr.name = paddr; 77f348c252STheodore Ts'o res = _ext4_fname_disk_to_usr(ctx, &cstr, &pstr); 78f348c252STheodore Ts'o if (res < 0) 79f348c252STheodore Ts'o goto errout; 80f348c252STheodore Ts'o /* Null-terminate the name */ 81f348c252STheodore Ts'o if (res <= plen) 82f348c252STheodore Ts'o paddr[res] = '\0'; 83f348c252STheodore Ts'o nd_set_link(nd, paddr); 84f348c252STheodore Ts'o ext4_put_fname_crypto_ctx(&ctx); 85f348c252STheodore Ts'o if (cpage) { 86f348c252STheodore Ts'o kunmap(cpage); 87f348c252STheodore Ts'o page_cache_release(cpage); 88f348c252STheodore Ts'o } 89f348c252STheodore Ts'o return NULL; 90f348c252STheodore Ts'o errout: 91f348c252STheodore Ts'o ext4_put_fname_crypto_ctx(&ctx); 92f348c252STheodore Ts'o if (cpage) { 93f348c252STheodore Ts'o kunmap(cpage); 94f348c252STheodore Ts'o page_cache_release(cpage); 95f348c252STheodore Ts'o } 96f348c252STheodore Ts'o kfree(paddr); 97f348c252STheodore Ts'o return ERR_PTR(res); 98f348c252STheodore Ts'o } 99f348c252STheodore Ts'o 100f348c252STheodore Ts'o static void ext4_put_link(struct dentry *dentry, struct nameidata *nd, 101f348c252STheodore Ts'o void *cookie) 102f348c252STheodore Ts'o { 103f348c252STheodore Ts'o struct page *page = cookie; 104f348c252STheodore Ts'o 105f348c252STheodore Ts'o if (!page) { 106f348c252STheodore Ts'o kfree(nd_get_link(nd)); 107f348c252STheodore Ts'o } else { 108f348c252STheodore Ts'o kunmap(page); 109f348c252STheodore Ts'o page_cache_release(page); 110f348c252STheodore Ts'o } 111f348c252STheodore Ts'o } 112f348c252STheodore Ts'o #endif 113f348c252STheodore Ts'o 114f348c252STheodore Ts'o static void *ext4_follow_fast_link(struct dentry *dentry, struct nameidata *nd) 115f348c252STheodore Ts'o { 1162b0143b5SDavid Howells struct ext4_inode_info *ei = EXT4_I(d_inode(dentry)); 117ac27a0ecSDave Kleikamp nd_set_link(nd, (char *) ei->i_data); 118ac27a0ecSDave Kleikamp return NULL; 119ac27a0ecSDave Kleikamp } 120ac27a0ecSDave Kleikamp 121754661f1SArjan van de Ven const struct inode_operations ext4_symlink_inode_operations = { 122ac27a0ecSDave Kleikamp .readlink = generic_readlink, 123f348c252STheodore Ts'o #ifdef CONFIG_EXT4_FS_ENCRYPTION 124f348c252STheodore Ts'o .follow_link = ext4_follow_link, 125f348c252STheodore Ts'o .put_link = ext4_put_link, 126f348c252STheodore Ts'o #else 127ac27a0ecSDave Kleikamp .follow_link = page_follow_link_light, 128ac27a0ecSDave Kleikamp .put_link = page_put_link, 129f348c252STheodore Ts'o #endif 130256a4535SDmitry Monakhov .setattr = ext4_setattr, 131ac27a0ecSDave Kleikamp .setxattr = generic_setxattr, 132ac27a0ecSDave Kleikamp .getxattr = generic_getxattr, 133617ba13bSMingming Cao .listxattr = ext4_listxattr, 134ac27a0ecSDave Kleikamp .removexattr = generic_removexattr, 135ac27a0ecSDave Kleikamp }; 136ac27a0ecSDave Kleikamp 137754661f1SArjan van de Ven const struct inode_operations ext4_fast_symlink_inode_operations = { 138ac27a0ecSDave Kleikamp .readlink = generic_readlink, 139f348c252STheodore Ts'o .follow_link = ext4_follow_fast_link, 140256a4535SDmitry Monakhov .setattr = ext4_setattr, 141ac27a0ecSDave Kleikamp .setxattr = generic_setxattr, 142ac27a0ecSDave Kleikamp .getxattr = generic_getxattr, 143617ba13bSMingming Cao .listxattr = ext4_listxattr, 144ac27a0ecSDave Kleikamp .removexattr = generic_removexattr, 145ac27a0ecSDave Kleikamp }; 146