vfs: add vfs_get_link() helper
authorMiklos Szeredi <mszeredi@redhat.com>
Tue, 4 Oct 2016 12:40:45 +0000 (14:40 +0200)
committerMiklos Szeredi <mszeredi@redhat.com>
Fri, 14 Oct 2016 09:16:47 +0000 (11:16 +0200)
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>
fs/namei.c
include/linux/fs.h

index adb04146df09281ff5825382c0f73564024061b9..8a2c2959da08e7e1da25fd735178a2a23cb10540 100644 (file)
@@ -4677,6 +4677,31 @@ int generic_readlink(struct dentry *dentry, char __user *buffer, int buflen)
 }
 EXPORT_SYMBOL(generic_readlink);
 
+/**
+ * vfs_get_link - get symlink body
+ * @dentry: dentry on which to get symbolic link
+ * @done: caller needs to free returned data with this
+ *
+ * Calls security hook and i_op->get_link() on the supplied inode.
+ *
+ * It does not touch atime.  That's up to the caller if necessary.
+ *
+ * Does not work on "special" symlinks like /proc/$$/fd/N
+ */
+const char *vfs_get_link(struct dentry *dentry, struct delayed_call *done)
+{
+       const char *res = ERR_PTR(-EINVAL);
+       struct inode *inode = d_inode(dentry);
+
+       if (d_is_symlink(dentry)) {
+               res = ERR_PTR(security_inode_readlink(dentry));
+               if (!res)
+                       res = inode->i_op->get_link(dentry, inode, done);
+       }
+       return res;
+}
+EXPORT_SYMBOL(vfs_get_link);
+
 /* get the link contents into pagecache */
 const char *page_get_link(struct dentry *dentry, struct inode *inode,
                          struct delayed_call *callback)
index 901e25d495ccfb71d8fc91b158a19cfe4dd9fccf..bc8ac5108368ee9ccbc8335076b4d0508068bd94 100644 (file)
@@ -2919,6 +2919,7 @@ extern int vfs_stat(const char __user *, struct kstat *);
 extern int vfs_lstat(const char __user *, struct kstat *);
 extern int vfs_fstat(unsigned int, struct kstat *);
 extern int vfs_fstatat(int , const char __user *, struct kstat *, int);
+extern const char *vfs_get_link(struct dentry *, struct delayed_call *);
 
 extern int __generic_block_fiemap(struct inode *inode,
                                  struct fiemap_extent_info *fieinfo,