1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * linux/fs/ext4/symlink.c 4 * 5 * Only fast symlinks left here - the rest is done by generic code. AV, 1999 6 * 7 * Copyright (C) 1992, 1993, 1994, 1995 8 * Remy Card (card@masi.ibp.fr) 9 * Laboratoire MASI - Institut Blaise Pascal 10 * Universite Pierre et Marie Curie (Paris VI) 11 * 12 * from 13 * 14 * linux/fs/minix/symlink.c 15 * 16 * Copyright (C) 1991, 1992 Linus Torvalds 17 * 18 * ext4 symlink handling code 19 */ 20 21 #include <linux/fs.h> 22 #include <linux/namei.h> 23 #include "ext4.h" 24 #include "xattr.h" 25 26 static const char *ext4_encrypted_get_link(struct dentry *dentry, 27 struct inode *inode, 28 struct delayed_call *done) 29 { 30 struct buffer_head *bh = NULL; 31 const void *caddr; 32 unsigned int max_size; 33 const char *paddr; 34 35 if (!dentry) 36 return ERR_PTR(-ECHILD); 37 38 if (ext4_inode_is_fast_symlink(inode)) { 39 caddr = EXT4_I(inode)->i_data; 40 max_size = sizeof(EXT4_I(inode)->i_data); 41 } else { 42 bh = ext4_bread(NULL, inode, 0, 0); 43 if (IS_ERR(bh)) 44 return ERR_CAST(bh); 45 if (!bh) { 46 EXT4_ERROR_INODE(inode, "bad symlink."); 47 return ERR_PTR(-EFSCORRUPTED); 48 } 49 caddr = bh->b_data; 50 max_size = inode->i_sb->s_blocksize; 51 } 52 53 paddr = fscrypt_get_symlink(inode, caddr, max_size, done); 54 brelse(bh); 55 return paddr; 56 } 57 58 static int ext4_encrypted_symlink_getattr(struct mnt_idmap *idmap, 59 const struct path *path, 60 struct kstat *stat, u32 request_mask, 61 unsigned int query_flags) 62 { 63 ext4_getattr(idmap, path, stat, request_mask, query_flags); 64 65 return fscrypt_symlink_getattr(path, stat); 66 } 67 68 static void ext4_free_link(void *bh) 69 { 70 brelse(bh); 71 } 72 73 static const char *ext4_get_link(struct dentry *dentry, struct inode *inode, 74 struct delayed_call *callback) 75 { 76 struct buffer_head *bh; 77 char *inline_link; 78 79 /* 80 * Create a new inlined symlink is not supported, just provide a 81 * method to read the leftovers. 82 */ 83 if (ext4_has_inline_data(inode)) { 84 if (!dentry) 85 return ERR_PTR(-ECHILD); 86 87 inline_link = ext4_read_inline_link(inode); 88 if (!IS_ERR(inline_link)) 89 set_delayed_call(callback, kfree_link, inline_link); 90 return inline_link; 91 } 92 93 if (!dentry) { 94 bh = ext4_getblk(NULL, inode, 0, EXT4_GET_BLOCKS_CACHED_NOWAIT); 95 if (IS_ERR(bh) || !bh) 96 return ERR_PTR(-ECHILD); 97 if (!ext4_buffer_uptodate(bh)) { 98 brelse(bh); 99 return ERR_PTR(-ECHILD); 100 } 101 } else { 102 bh = ext4_bread(NULL, inode, 0, 0); 103 if (IS_ERR(bh)) 104 return ERR_CAST(bh); 105 if (!bh) { 106 EXT4_ERROR_INODE(inode, "bad symlink."); 107 return ERR_PTR(-EFSCORRUPTED); 108 } 109 } 110 111 set_delayed_call(callback, ext4_free_link, bh); 112 nd_terminate_link(bh->b_data, inode->i_size, 113 inode->i_sb->s_blocksize - 1); 114 return bh->b_data; 115 } 116 117 const struct inode_operations ext4_encrypted_symlink_inode_operations = { 118 .get_link = ext4_encrypted_get_link, 119 .setattr = ext4_setattr, 120 .getattr = ext4_encrypted_symlink_getattr, 121 .listxattr = ext4_listxattr, 122 }; 123 124 const struct inode_operations ext4_symlink_inode_operations = { 125 .get_link = ext4_get_link, 126 .setattr = ext4_setattr, 127 .getattr = ext4_getattr, 128 .listxattr = ext4_listxattr, 129 }; 130 131 const struct inode_operations ext4_fast_symlink_inode_operations = { 132 .get_link = simple_get_link, 133 .setattr = ext4_setattr, 134 .getattr = ext4_getattr, 135 .listxattr = ext4_listxattr, 136 }; 137
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.