forked from luck/tmp_suning_uos_patched
680baacbca
a) instead of storing the symlink body (via nd_set_link()) and returning an opaque pointer later passed to ->put_link(), ->follow_link() _stores_ that opaque pointer (into void * passed by address by caller) and returns the symlink body. Returning ERR_PTR() on error, NULL on jump (procfs magic symlinks) and pointer to symlink body for normal symlinks. Stored pointer is ignored in all cases except the last one. Storing NULL for opaque pointer (or not storing it at all) means no call of ->put_link(). b) the body used to be passed to ->put_link() implicitly (via nameidata). Now only the opaque pointer is. In the cases when we used the symlink body to free stuff, ->follow_link() now should store it as opaque pointer in addition to returning it. Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
128 lines
3.2 KiB
C
128 lines
3.2 KiB
C
/*
|
|
* linux/fs/ext4/symlink.c
|
|
*
|
|
* Only fast symlinks left here - the rest is done by generic code. AV, 1999
|
|
*
|
|
* Copyright (C) 1992, 1993, 1994, 1995
|
|
* Remy Card (card@masi.ibp.fr)
|
|
* Laboratoire MASI - Institut Blaise Pascal
|
|
* Universite Pierre et Marie Curie (Paris VI)
|
|
*
|
|
* from
|
|
*
|
|
* linux/fs/minix/symlink.c
|
|
*
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
|
*
|
|
* ext4 symlink handling code
|
|
*/
|
|
|
|
#include <linux/fs.h>
|
|
#include <linux/namei.h>
|
|
#include "ext4.h"
|
|
#include "xattr.h"
|
|
|
|
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
|
static const char *ext4_follow_link(struct dentry *dentry, void **cookie, struct nameidata *nd)
|
|
{
|
|
struct page *cpage = NULL;
|
|
char *caddr, *paddr = NULL;
|
|
struct ext4_str cstr, pstr;
|
|
struct inode *inode = d_inode(dentry);
|
|
struct ext4_fname_crypto_ctx *ctx = NULL;
|
|
struct ext4_encrypted_symlink_data *sd;
|
|
loff_t size = min_t(loff_t, i_size_read(inode), PAGE_SIZE - 1);
|
|
int res;
|
|
u32 plen, max_size = inode->i_sb->s_blocksize;
|
|
|
|
ctx = ext4_get_fname_crypto_ctx(inode, inode->i_sb->s_blocksize);
|
|
if (IS_ERR(ctx))
|
|
return ERR_CAST(ctx);
|
|
|
|
if (ext4_inode_is_fast_symlink(inode)) {
|
|
caddr = (char *) EXT4_I(inode)->i_data;
|
|
max_size = sizeof(EXT4_I(inode)->i_data);
|
|
} else {
|
|
cpage = read_mapping_page(inode->i_mapping, 0, NULL);
|
|
if (IS_ERR(cpage)) {
|
|
ext4_put_fname_crypto_ctx(&ctx);
|
|
return ERR_CAST(cpage);
|
|
}
|
|
caddr = kmap(cpage);
|
|
caddr[size] = 0;
|
|
}
|
|
|
|
/* Symlink is encrypted */
|
|
sd = (struct ext4_encrypted_symlink_data *)caddr;
|
|
cstr.name = sd->encrypted_path;
|
|
cstr.len = le32_to_cpu(sd->len);
|
|
if ((cstr.len +
|
|
sizeof(struct ext4_encrypted_symlink_data) - 1) >
|
|
max_size) {
|
|
/* Symlink data on the disk is corrupted */
|
|
res = -EIO;
|
|
goto errout;
|
|
}
|
|
plen = (cstr.len < EXT4_FNAME_CRYPTO_DIGEST_SIZE*2) ?
|
|
EXT4_FNAME_CRYPTO_DIGEST_SIZE*2 : cstr.len;
|
|
paddr = kmalloc(plen + 1, GFP_NOFS);
|
|
if (!paddr) {
|
|
res = -ENOMEM;
|
|
goto errout;
|
|
}
|
|
pstr.name = paddr;
|
|
res = _ext4_fname_disk_to_usr(ctx, NULL, &cstr, &pstr);
|
|
if (res < 0)
|
|
goto errout;
|
|
/* Null-terminate the name */
|
|
if (res <= plen)
|
|
paddr[res] = '\0';
|
|
ext4_put_fname_crypto_ctx(&ctx);
|
|
if (cpage) {
|
|
kunmap(cpage);
|
|
page_cache_release(cpage);
|
|
}
|
|
return *cookie = paddr;
|
|
errout:
|
|
ext4_put_fname_crypto_ctx(&ctx);
|
|
if (cpage) {
|
|
kunmap(cpage);
|
|
page_cache_release(cpage);
|
|
}
|
|
kfree(paddr);
|
|
return ERR_PTR(res);
|
|
}
|
|
|
|
const struct inode_operations ext4_encrypted_symlink_inode_operations = {
|
|
.readlink = generic_readlink,
|
|
.follow_link = ext4_follow_link,
|
|
.put_link = kfree_put_link,
|
|
.setattr = ext4_setattr,
|
|
.setxattr = generic_setxattr,
|
|
.getxattr = generic_getxattr,
|
|
.listxattr = ext4_listxattr,
|
|
.removexattr = generic_removexattr,
|
|
};
|
|
#endif
|
|
|
|
const struct inode_operations ext4_symlink_inode_operations = {
|
|
.readlink = generic_readlink,
|
|
.follow_link = page_follow_link_light,
|
|
.put_link = page_put_link,
|
|
.setattr = ext4_setattr,
|
|
.setxattr = generic_setxattr,
|
|
.getxattr = generic_getxattr,
|
|
.listxattr = ext4_listxattr,
|
|
.removexattr = generic_removexattr,
|
|
};
|
|
|
|
const struct inode_operations ext4_fast_symlink_inode_operations = {
|
|
.readlink = generic_readlink,
|
|
.follow_link = simple_follow_link,
|
|
.setattr = ext4_setattr,
|
|
.setxattr = generic_setxattr,
|
|
.getxattr = generic_getxattr,
|
|
.listxattr = ext4_listxattr,
|
|
.removexattr = generic_removexattr,
|
|
};
|