ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / fs / sysfs / symlink.c
1 /*
2  * symlink.c - operations for sysfs symlinks.
3  */
4
5 #include <linux/fs.h>
6 #include <linux/module.h>
7 #include <linux/kobject.h>
8
9 #include "sysfs.h"
10
11
12 static int init_symlink(struct inode * inode)
13 {
14         inode->i_op = &page_symlink_inode_operations;
15         return 0;
16 }
17
18 static int sysfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname)
19 {
20         int error;
21
22         error = sysfs_create(dentry, S_IFLNK|S_IRWXUGO, init_symlink);
23         if (!error) {
24                 int l = strlen(symname)+1;
25                 error = page_symlink(dentry->d_inode, symname, l);
26                 if (error)
27                         iput(dentry->d_inode);
28         }
29         return error;
30 }
31
32 static int object_depth(struct kobject * kobj)
33 {
34         struct kobject * p = kobj;
35         int depth = 0;
36         do { depth++; } while ((p = p->parent));
37         return depth;
38 }
39
40 static int object_path_length(struct kobject * kobj)
41 {
42         struct kobject * p = kobj;
43         int length = 1;
44         do {
45                 length += strlen(kobject_name(p)) + 1;
46                 p = p->parent;
47         } while (p);
48         return length;
49 }
50
51 static void fill_object_path(struct kobject * kobj, char * buffer, int length)
52 {
53         struct kobject * p;
54
55         --length;
56         for (p = kobj; p; p = p->parent) {
57                 int cur = strlen(kobject_name(p));
58
59                 /* back up enough to print this bus id with '/' */
60                 length -= cur;
61                 strncpy(buffer + length,kobject_name(p),cur);
62                 *(buffer + --length) = '/';
63         }
64 }
65
66 /**
67  *      sysfs_create_link - create symlink between two objects.
68  *      @kobj:  object whose directory we're creating the link in.
69  *      @target:        object we're pointing to.
70  *      @name:          name of the symlink.
71  */
72 int sysfs_create_link(struct kobject * kobj, struct kobject * target, char * name)
73 {
74         struct dentry * dentry = kobj->dentry;
75         struct dentry * d;
76         int error = 0;
77         int size;
78         int depth;
79         char * path;
80         char * s;
81
82         depth = object_depth(kobj);
83         size = object_path_length(target) + depth * 3 - 1;
84         if (size > PATH_MAX)
85                 return -ENAMETOOLONG;
86         pr_debug("%s: depth = %d, size = %d\n",__FUNCTION__,depth,size);
87
88         path = kmalloc(size,GFP_KERNEL);
89         if (!path)
90                 return -ENOMEM;
91         memset(path,0,size);
92
93         for (s = path; depth--; s += 3)
94                 strcpy(s,"../");
95
96         fill_object_path(target,path,size);
97         pr_debug("%s: path = '%s'\n",__FUNCTION__,path);
98
99         down(&dentry->d_inode->i_sem);
100         d = sysfs_get_dentry(dentry,name);
101         if (!IS_ERR(d))
102                 error = sysfs_symlink(dentry->d_inode,d,path);
103         else
104                 error = PTR_ERR(d);
105         dput(d);
106         up(&dentry->d_inode->i_sem);
107         kfree(path);
108         return error;
109 }
110
111
112 /**
113  *      sysfs_remove_link - remove symlink in object's directory.
114  *      @kobj:  object we're acting for.
115  *      @name:  name of the symlink to remove.
116  */
117
118 void sysfs_remove_link(struct kobject * kobj, char * name)
119 {
120         sysfs_hash_and_remove(kobj->dentry,name);
121 }
122
123
124 EXPORT_SYMBOL(sysfs_create_link);
125 EXPORT_SYMBOL(sysfs_remove_link);
126