162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * linux/fs/ext4/symlink.c 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Only fast symlinks left here - the rest is done by generic code. AV, 1999 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Copyright (C) 1992, 1993, 1994, 1995 862306a36Sopenharmony_ci * Remy Card (card@masi.ibp.fr) 962306a36Sopenharmony_ci * Laboratoire MASI - Institut Blaise Pascal 1062306a36Sopenharmony_ci * Universite Pierre et Marie Curie (Paris VI) 1162306a36Sopenharmony_ci * 1262306a36Sopenharmony_ci * from 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * linux/fs/minix/symlink.c 1562306a36Sopenharmony_ci * 1662306a36Sopenharmony_ci * Copyright (C) 1991, 1992 Linus Torvalds 1762306a36Sopenharmony_ci * 1862306a36Sopenharmony_ci * ext4 symlink handling code 1962306a36Sopenharmony_ci */ 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci#include <linux/fs.h> 2262306a36Sopenharmony_ci#include <linux/namei.h> 2362306a36Sopenharmony_ci#include "ext4.h" 2462306a36Sopenharmony_ci#include "xattr.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_cistatic const char *ext4_encrypted_get_link(struct dentry *dentry, 2762306a36Sopenharmony_ci struct inode *inode, 2862306a36Sopenharmony_ci struct delayed_call *done) 2962306a36Sopenharmony_ci{ 3062306a36Sopenharmony_ci struct buffer_head *bh = NULL; 3162306a36Sopenharmony_ci const void *caddr; 3262306a36Sopenharmony_ci unsigned int max_size; 3362306a36Sopenharmony_ci const char *paddr; 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci if (!dentry) 3662306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci if (ext4_inode_is_fast_symlink(inode)) { 3962306a36Sopenharmony_ci caddr = EXT4_I(inode)->i_data; 4062306a36Sopenharmony_ci max_size = sizeof(EXT4_I(inode)->i_data); 4162306a36Sopenharmony_ci } else { 4262306a36Sopenharmony_ci bh = ext4_bread(NULL, inode, 0, 0); 4362306a36Sopenharmony_ci if (IS_ERR(bh)) 4462306a36Sopenharmony_ci return ERR_CAST(bh); 4562306a36Sopenharmony_ci if (!bh) { 4662306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "bad symlink."); 4762306a36Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 4862306a36Sopenharmony_ci } 4962306a36Sopenharmony_ci caddr = bh->b_data; 5062306a36Sopenharmony_ci max_size = inode->i_sb->s_blocksize; 5162306a36Sopenharmony_ci } 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci paddr = fscrypt_get_symlink(inode, caddr, max_size, done); 5462306a36Sopenharmony_ci brelse(bh); 5562306a36Sopenharmony_ci return paddr; 5662306a36Sopenharmony_ci} 5762306a36Sopenharmony_ci 5862306a36Sopenharmony_cistatic int ext4_encrypted_symlink_getattr(struct mnt_idmap *idmap, 5962306a36Sopenharmony_ci const struct path *path, 6062306a36Sopenharmony_ci struct kstat *stat, u32 request_mask, 6162306a36Sopenharmony_ci unsigned int query_flags) 6262306a36Sopenharmony_ci{ 6362306a36Sopenharmony_ci ext4_getattr(idmap, path, stat, request_mask, query_flags); 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci return fscrypt_symlink_getattr(path, stat); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_cistatic void ext4_free_link(void *bh) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci brelse(bh); 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_cistatic const char *ext4_get_link(struct dentry *dentry, struct inode *inode, 7462306a36Sopenharmony_ci struct delayed_call *callback) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci struct buffer_head *bh; 7762306a36Sopenharmony_ci char *inline_link; 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci /* 8062306a36Sopenharmony_ci * Create a new inlined symlink is not supported, just provide a 8162306a36Sopenharmony_ci * method to read the leftovers. 8262306a36Sopenharmony_ci */ 8362306a36Sopenharmony_ci if (ext4_has_inline_data(inode)) { 8462306a36Sopenharmony_ci if (!dentry) 8562306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci inline_link = ext4_read_inline_link(inode); 8862306a36Sopenharmony_ci if (!IS_ERR(inline_link)) 8962306a36Sopenharmony_ci set_delayed_call(callback, kfree_link, inline_link); 9062306a36Sopenharmony_ci return inline_link; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci if (!dentry) { 9462306a36Sopenharmony_ci bh = ext4_getblk(NULL, inode, 0, EXT4_GET_BLOCKS_CACHED_NOWAIT); 9562306a36Sopenharmony_ci if (IS_ERR(bh)) 9662306a36Sopenharmony_ci return ERR_CAST(bh); 9762306a36Sopenharmony_ci if (!bh || !ext4_buffer_uptodate(bh)) 9862306a36Sopenharmony_ci return ERR_PTR(-ECHILD); 9962306a36Sopenharmony_ci } else { 10062306a36Sopenharmony_ci bh = ext4_bread(NULL, inode, 0, 0); 10162306a36Sopenharmony_ci if (IS_ERR(bh)) 10262306a36Sopenharmony_ci return ERR_CAST(bh); 10362306a36Sopenharmony_ci if (!bh) { 10462306a36Sopenharmony_ci EXT4_ERROR_INODE(inode, "bad symlink."); 10562306a36Sopenharmony_ci return ERR_PTR(-EFSCORRUPTED); 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci } 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci set_delayed_call(callback, ext4_free_link, bh); 11062306a36Sopenharmony_ci nd_terminate_link(bh->b_data, inode->i_size, 11162306a36Sopenharmony_ci inode->i_sb->s_blocksize - 1); 11262306a36Sopenharmony_ci return bh->b_data; 11362306a36Sopenharmony_ci} 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ciconst struct inode_operations ext4_encrypted_symlink_inode_operations = { 11662306a36Sopenharmony_ci .get_link = ext4_encrypted_get_link, 11762306a36Sopenharmony_ci .setattr = ext4_setattr, 11862306a36Sopenharmony_ci .getattr = ext4_encrypted_symlink_getattr, 11962306a36Sopenharmony_ci .listxattr = ext4_listxattr, 12062306a36Sopenharmony_ci}; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ciconst struct inode_operations ext4_symlink_inode_operations = { 12362306a36Sopenharmony_ci .get_link = ext4_get_link, 12462306a36Sopenharmony_ci .setattr = ext4_setattr, 12562306a36Sopenharmony_ci .getattr = ext4_getattr, 12662306a36Sopenharmony_ci .listxattr = ext4_listxattr, 12762306a36Sopenharmony_ci}; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ciconst struct inode_operations ext4_fast_symlink_inode_operations = { 13062306a36Sopenharmony_ci .get_link = simple_get_link, 13162306a36Sopenharmony_ci .setattr = ext4_setattr, 13262306a36Sopenharmony_ci .getattr = ext4_getattr, 13362306a36Sopenharmony_ci .listxattr = ext4_listxattr, 13462306a36Sopenharmony_ci}; 135