diff options
| author | Miklos Szeredi <mszeredi@redhat.com> | 2016-10-04 08:40:45 -0400 |
|---|---|---|
| committer | Miklos Szeredi <mszeredi@redhat.com> | 2016-10-14 05:16:47 -0400 |
| commit | d60874cd58fcb21372f2df698c20f8cf2f78fdcb (patch) | |
| tree | eade1cfdc44321b875a51d1beef4042e9e657165 | |
| parent | 78a3fa4f3249055b472983065b30c02392cf7e2a (diff) | |
vfs: add vfs_get_link() helper
This helper is for filesystems that want to read the symlink and are better
off with the get_link() interface (returning a char *) rather than the
readlink() interface (copy into a userspace buffer).
Also call the LSM hook for readlink (not get_link) since this is for
symlink reading not following.
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
| -rw-r--r-- | fs/namei.c | 25 | ||||
| -rw-r--r-- | include/linux/fs.h | 1 |
2 files changed, 26 insertions, 0 deletions
diff --git a/fs/namei.c b/fs/namei.c index adb04146df09..8a2c2959da08 100644 --- a/fs/namei.c +++ b/fs/namei.c | |||
| @@ -4677,6 +4677,31 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen) | |||
| 4677 | } | 4677 | } |
| 4678 | EXPORT_SYMBOL(generic_readlink); | 4678 | EXPORT_SYMBOL(generic_readlink); |
| 4679 | 4679 | ||
| 4680 | /** | ||
| 4681 | * vfs_get_link - get symlink body | ||
| 4682 | * @dentry: dentry on which to get symbolic link | ||
| 4683 | * @done: caller needs to free returned data with this | ||
| 4684 | * | ||
| 4685 | * Calls security hook and i_op->get_link() on the supplied inode. | ||
| 4686 | * | ||
| 4687 | * It does not touch atime. That's up to the caller if necessary. | ||
| 4688 | * | ||
| 4689 | * Does not work on "special" symlinks like /proc/$$/fd/N | ||
| 4690 | */ | ||
| 4691 | const char *vfs_get_link(struct dentry *dentry, struct delayed_call *done) | ||
| 4692 | { | ||
| 4693 | const char *res = ERR_PTR(-EINVAL); | ||
| 4694 | struct inode *inode = d_inode(dentry); | ||
| 4695 | |||
| 4696 | if (d_is_symlink(dentry)) { | ||
| 4697 | res = ERR_PTR(security_inode_readlink(dentry)); | ||
| 4698 | if (!res) | ||
| 4699 | res = inode->i_op->get_link(dentry, inode, done); | ||
| 4700 | } | ||
| 4701 | return res; | ||
| 4702 | } | ||
| 4703 | EXPORT_SYMBOL(vfs_get_link); | ||
| 4704 | |||
| 4680 | /* get the link contents into pagecache */ | 4705 | /* get the link contents into pagecache */ |
| 4681 | const char *page_get_link(struct dentry *dentry, struct inode *inode, | 4706 | const char *page_get_link(struct dentry *dentry, struct inode *inode, |
| 4682 | struct delayed_call *callback) | 4707 | struct delayed_call *callback) |
diff --git a/include/linux/fs.h b/include/linux/fs.h index 901e25d495cc..bc8ac5108368 100644 --- a/include/linux/fs.h +++ b/include/linux/fs.h | |||
| @@ -2919,6 +2919,7 @@ extern int vfs_stat(const char __user *, struct kstat *); | |||
| 2919 | extern int vfs_lstat(const char __user *, struct kstat *); | 2919 | extern int vfs_lstat(const char __user *, struct kstat *); |
| 2920 | extern int vfs_fstat(unsigned int, struct kstat *); | 2920 | extern int vfs_fstat(unsigned int, struct kstat *); |
| 2921 | extern int vfs_fstatat(int , const char __user *, struct kstat *, int); | 2921 | extern int vfs_fstatat(int , const char __user *, struct kstat *, int); |
| 2922 | extern const char *vfs_get_link(struct dentry *, struct delayed_call *); | ||
| 2922 | 2923 | ||
| 2923 | extern int __generic_block_fiemap(struct inode *inode, | 2924 | extern int __generic_block_fiemap(struct inode *inode, |
| 2924 | struct fiemap_extent_info *fieinfo, | 2925 | struct fiemap_extent_info *fieinfo, |
