Blame view
fs/kernfs/symlink.c
3.31 KB
55716d264 treewide: Replace... |
1 |
// SPDX-License-Identifier: GPL-2.0-only |
b8441ed27 sysfs, kernfs: ad... |
2 3 4 5 6 7 |
/* * fs/kernfs/symlink.c - kernfs symlink implementation * * Copyright (c) 2001-3 Patrick Mochel * Copyright (c) 2007 SUSE Linux Products GmbH * Copyright (c) 2007, 2013 Tejun Heo <tj@kernel.org> |
b8441ed27 sysfs, kernfs: ad... |
8 |
*/ |
2072f1afd sysfs, kernfs: mo... |
9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <linux/fs.h> #include <linux/gfp.h> #include <linux/namei.h> #include "kernfs-internal.h" /** * kernfs_create_link - create a symlink * @parent: directory to create the symlink in * @name: name of the symlink * @target: target node for the symlink to point to * * Returns the created node on success, ERR_PTR() value on error. |
488dee96b kernfs: allow cre... |
23 |
* Ownership of the link matches ownership of the target. |
2072f1afd sysfs, kernfs: mo... |
24 |
*/ |
324a56e16 kernfs: s/sysfs_d... |
25 26 27 |
struct kernfs_node *kernfs_create_link(struct kernfs_node *parent, const char *name, struct kernfs_node *target) |
2072f1afd sysfs, kernfs: mo... |
28 |
{ |
324a56e16 kernfs: s/sysfs_d... |
29 |
struct kernfs_node *kn; |
2072f1afd sysfs, kernfs: mo... |
30 |
int error; |
488dee96b kernfs: allow cre... |
31 32 |
kuid_t uid = GLOBAL_ROOT_UID; kgid_t gid = GLOBAL_ROOT_GID; |
2072f1afd sysfs, kernfs: mo... |
33 |
|
488dee96b kernfs: allow cre... |
34 |
if (target->iattr) { |
058952196 kernfs: clean up ... |
35 36 |
uid = target->iattr->ia_uid; gid = target->iattr->ia_gid; |
488dee96b kernfs: allow cre... |
37 38 39 40 |
} kn = kernfs_new_node(parent, name, S_IFLNK|S_IRWXUGO, uid, gid, KERNFS_LINK); |
324a56e16 kernfs: s/sysfs_d... |
41 |
if (!kn) |
2072f1afd sysfs, kernfs: mo... |
42 |
return ERR_PTR(-ENOMEM); |
ac9bba031 sysfs, kernfs: im... |
43 |
if (kernfs_ns_enabled(parent)) |
adc5e8b58 kernfs: drop s_ p... |
44 45 |
kn->ns = target->ns; kn->symlink.target_kn = target; |
2072f1afd sysfs, kernfs: mo... |
46 |
kernfs_get(target); /* ref owned by symlink */ |
988cd7afb kernfs: remove ke... |
47 |
error = kernfs_add_one(kn); |
2072f1afd sysfs, kernfs: mo... |
48 |
if (!error) |
324a56e16 kernfs: s/sysfs_d... |
49 |
return kn; |
2072f1afd sysfs, kernfs: mo... |
50 |
|
324a56e16 kernfs: s/sysfs_d... |
51 |
kernfs_put(kn); |
2072f1afd sysfs, kernfs: mo... |
52 53 |
return ERR_PTR(error); } |
c637b8acb kernfs: s/sysfs/k... |
54 55 |
static int kernfs_get_target_path(struct kernfs_node *parent, struct kernfs_node *target, char *path) |
2072f1afd sysfs, kernfs: mo... |
56 |
{ |
324a56e16 kernfs: s/sysfs_d... |
57 |
struct kernfs_node *base, *kn; |
2072f1afd sysfs, kernfs: mo... |
58 59 60 61 |
char *s = path; int len = 0; /* go up to the root, stop at the base */ |
324a56e16 kernfs: s/sysfs_d... |
62 |
base = parent; |
adc5e8b58 kernfs: drop s_ p... |
63 64 65 66 |
while (base->parent) { kn = target->parent; while (kn->parent && base != kn) kn = kn->parent; |
2072f1afd sysfs, kernfs: mo... |
67 |
|
324a56e16 kernfs: s/sysfs_d... |
68 |
if (base == kn) |
2072f1afd sysfs, kernfs: mo... |
69 |
break; |
a75e78f21 kernfs: Fix range... |
70 71 |
if ((s - path) + 3 >= PATH_MAX) return -ENAMETOOLONG; |
2072f1afd sysfs, kernfs: mo... |
72 73 |
strcpy(s, "../"); s += 3; |
adc5e8b58 kernfs: drop s_ p... |
74 |
base = base->parent; |
2072f1afd sysfs, kernfs: mo... |
75 76 77 |
} /* determine end of target string for reverse fillup */ |
324a56e16 kernfs: s/sysfs_d... |
78 |
kn = target; |
adc5e8b58 kernfs: drop s_ p... |
79 80 81 |
while (kn->parent && kn != base) { len += strlen(kn->name) + 1; kn = kn->parent; |
2072f1afd sysfs, kernfs: mo... |
82 83 84 85 86 87 |
} /* check limits */ if (len < 2) return -EINVAL; len--; |
a75e78f21 kernfs: Fix range... |
88 |
if ((s - path) + len >= PATH_MAX) |
2072f1afd sysfs, kernfs: mo... |
89 90 91 |
return -ENAMETOOLONG; /* reverse fillup of target string from target to base */ |
324a56e16 kernfs: s/sysfs_d... |
92 |
kn = target; |
adc5e8b58 kernfs: drop s_ p... |
93 94 |
while (kn->parent && kn != base) { int slen = strlen(kn->name); |
2072f1afd sysfs, kernfs: mo... |
95 96 |
len -= slen; |
166126c1e kernfs: Replace s... |
97 |
memcpy(s + len, kn->name, slen); |
2072f1afd sysfs, kernfs: mo... |
98 99 |
if (len) s[--len] = '/'; |
adc5e8b58 kernfs: drop s_ p... |
100 |
kn = kn->parent; |
2072f1afd sysfs, kernfs: mo... |
101 102 103 104 |
} return 0; } |
319ba91d3 kernfs: don't set... |
105 |
static int kernfs_getlink(struct inode *inode, char *path) |
2072f1afd sysfs, kernfs: mo... |
106 |
{ |
319ba91d3 kernfs: don't set... |
107 |
struct kernfs_node *kn = inode->i_private; |
adc5e8b58 kernfs: drop s_ p... |
108 109 |
struct kernfs_node *parent = kn->parent; struct kernfs_node *target = kn->symlink.target_kn; |
2072f1afd sysfs, kernfs: mo... |
110 |
int error; |
a797bfc30 kernfs: s/sysfs/k... |
111 |
mutex_lock(&kernfs_mutex); |
c637b8acb kernfs: s/sysfs/k... |
112 |
error = kernfs_get_target_path(parent, target, path); |
a797bfc30 kernfs: s/sysfs/k... |
113 |
mutex_unlock(&kernfs_mutex); |
2072f1afd sysfs, kernfs: mo... |
114 115 116 |
return error; } |
6b2553918 replace ->follow_... |
117 |
static const char *kernfs_iop_get_link(struct dentry *dentry, |
fceef393a switch ->get_link... |
118 119 |
struct inode *inode, struct delayed_call *done) |
2072f1afd sysfs, kernfs: mo... |
120 |
{ |
fceef393a switch ->get_link... |
121 122 |
char *body; int error; |
6b2553918 replace ->follow_... |
123 124 125 |
if (!dentry) return ERR_PTR(-ECHILD); |
fceef393a switch ->get_link... |
126 127 |
body = kzalloc(PAGE_SIZE, GFP_KERNEL); if (!body) |
680baacbc new ->follow_link... |
128 |
return ERR_PTR(-ENOMEM); |
319ba91d3 kernfs: don't set... |
129 |
error = kernfs_getlink(inode, body); |
680baacbc new ->follow_link... |
130 |
if (unlikely(error < 0)) { |
fceef393a switch ->get_link... |
131 |
kfree(body); |
680baacbc new ->follow_link... |
132 |
return ERR_PTR(error); |
2072f1afd sysfs, kernfs: mo... |
133 |
} |
fceef393a switch ->get_link... |
134 135 |
set_delayed_call(done, kfree_link, body); return body; |
2072f1afd sysfs, kernfs: mo... |
136 |
} |
a797bfc30 kernfs: s/sysfs/k... |
137 |
const struct inode_operations kernfs_symlink_iops = { |
c637b8acb kernfs: s/sysfs/k... |
138 |
.listxattr = kernfs_iop_listxattr, |
6b2553918 replace ->follow_... |
139 |
.get_link = kernfs_iop_get_link, |
c637b8acb kernfs: s/sysfs/k... |
140 141 142 |
.setattr = kernfs_iop_setattr, .getattr = kernfs_iop_getattr, .permission = kernfs_iop_permission, |
2072f1afd sysfs, kernfs: mo... |
143 |
}; |