Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * fs/kernfs/symlink.c - kernfs symlink implementation
0004  *
0005  * Copyright (c) 2001-3 Patrick Mochel
0006  * Copyright (c) 2007 SUSE Linux Products GmbH
0007  * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org>
0008  */
0009 
0010 #include <linux/fs.h>
0011 #include <linux/gfp.h>
0012 #include <linux/namei.h>
0013 
0014 #include "kernfs-internal.h"
0015 
0016 /**
0017  * kernfs_create_link - create a symlink
0018  * @parent: directory to create the symlink in
0019  * @name: name of the symlink
0020  * @target: target node for the symlink to point to
0021  *
0022  * Returns the created node on success, ERR_PTR() value on error.
0023  * Ownership of the link matches ownership of the target.
0024  */
0025 struct kernfs_node *kernfs_create_link(struct kernfs_node *parent,
0026                        const char *name,
0027                        struct kernfs_node *target)
0028 {
0029     struct kernfs_node *kn;
0030     int error;
0031     kuid_t uid = GLOBAL_ROOT_UID;
0032     kgid_t gid = GLOBAL_ROOT_GID;
0033 
0034     if (target->iattr) {
0035         uid = target->iattr->ia_uid;
0036         gid = target->iattr->ia_gid;
0037     }
0038 
0039     kn = kernfs_new_node(parent, name, S_IFLNK|0777, uid, gid, KERNFS_LINK);
0040     if (!kn)
0041         return ERR_PTR(-ENOMEM);
0042 
0043     if (kernfs_ns_enabled(parent))
0044         kn->ns = target->ns;
0045     kn->symlink.target_kn = target;
0046     kernfs_get(target); /* ref owned by symlink */
0047 
0048     error = kernfs_add_one(kn);
0049     if (!error)
0050         return kn;
0051 
0052     kernfs_put(kn);
0053     return ERR_PTR(error);
0054 }
0055 
0056 static int kernfs_get_target_path(struct kernfs_node *parent,
0057                   struct kernfs_node *target, char *path)
0058 {
0059     struct kernfs_node *base, *kn;
0060     char *s = path;
0061     int len = 0;
0062 
0063     /* go up to the root, stop at the base */
0064     base = parent;
0065     while (base->parent) {
0066         kn = target->parent;
0067         while (kn->parent && base != kn)
0068             kn = kn->parent;
0069 
0070         if (base == kn)
0071             break;
0072 
0073         if ((s - path) + 3 >= PATH_MAX)
0074             return -ENAMETOOLONG;
0075 
0076         strcpy(s, "../");
0077         s += 3;
0078         base = base->parent;
0079     }
0080 
0081     /* determine end of target string for reverse fillup */
0082     kn = target;
0083     while (kn->parent && kn != base) {
0084         len += strlen(kn->name) + 1;
0085         kn = kn->parent;
0086     }
0087 
0088     /* check limits */
0089     if (len < 2)
0090         return -EINVAL;
0091     len--;
0092     if ((s - path) + len >= PATH_MAX)
0093         return -ENAMETOOLONG;
0094 
0095     /* reverse fillup of target string from target to base */
0096     kn = target;
0097     while (kn->parent && kn != base) {
0098         int slen = strlen(kn->name);
0099 
0100         len -= slen;
0101         memcpy(s + len, kn->name, slen);
0102         if (len)
0103             s[--len] = '/';
0104 
0105         kn = kn->parent;
0106     }
0107 
0108     return 0;
0109 }
0110 
0111 static int kernfs_getlink(struct inode *inode, char *path)
0112 {
0113     struct kernfs_node *kn = inode->i_private;
0114     struct kernfs_node *parent = kn->parent;
0115     struct kernfs_node *target = kn->symlink.target_kn;
0116     struct kernfs_root *root = kernfs_root(parent);
0117     int error;
0118 
0119     down_read(&root->kernfs_rwsem);
0120     error = kernfs_get_target_path(parent, target, path);
0121     up_read(&root->kernfs_rwsem);
0122 
0123     return error;
0124 }
0125 
0126 static const char *kernfs_iop_get_link(struct dentry *dentry,
0127                        struct inode *inode,
0128                        struct delayed_call *done)
0129 {
0130     char *body;
0131     int error;
0132 
0133     if (!dentry)
0134         return ERR_PTR(-ECHILD);
0135     body = kzalloc(PAGE_SIZE, GFP_KERNEL);
0136     if (!body)
0137         return ERR_PTR(-ENOMEM);
0138     error = kernfs_getlink(inode, body);
0139     if (unlikely(error < 0)) {
0140         kfree(body);
0141         return ERR_PTR(error);
0142     }
0143     set_delayed_call(done, kfree_link, body);
0144     return body;
0145 }
0146 
0147 const struct inode_operations kernfs_symlink_iops = {
0148     .listxattr  = kernfs_iop_listxattr,
0149     .get_link   = kernfs_iop_get_link,
0150     .setattr    = kernfs_iop_setattr,
0151     .getattr    = kernfs_iop_getattr,
0152     .permission = kernfs_iop_permission,
0153 };