http://prdownloads.sourceforge.net/lufs/lufs-0.9.7.tar.gz?download
[lufs.git] / kernel / Linux / 2.6 / symlink.c
1 /*
2  * symlink.c
3  * Copyright (C) 2002 Florin Malita <mali@go.ro>
4  *
5  * This file is part of LUFS, a free userspace filesystem implementation.
6  * See http://lufs.sourceforge.net/ for updates.
7  *
8  * LUFS is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (at your option) any later version.
12  *
13  * LUFS is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include <linux/version.h>
24 #include <linux/kernel.h>
25 #include <linux/module.h>
26 #include <linux/slab.h>
27 #include <linux/socket.h>
28 #include <linux/smp_lock.h>
29 #include <linux/fs.h>
30
31 #include <asm/uaccess.h>
32 #include <asm/system.h>
33
34
35 #include "lufs.h"
36 #include "proc.h"
37
38 static char failed_link[] = "invalid";
39
40 static int lu_readlink(struct dentry *dentry, char *buffer, int bufflen)
41 {
42     struct server_slot *slot;
43     struct iovec siov, riov;
44     int res;
45     char *cc = failed_link;
46
47     TRACE("in\n");
48
49     if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL)
50         return vfs_readlink(dentry, buffer, bufflen, cc);
51
52     if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){
53         WARN("lu_getname failed!\n");
54         goto out;
55     }
56
57     siov.iov_base = slot->s_buf;
58     siov.iov_len = strlen(slot->s_buf) + 1;
59     riov.iov_base = &slot->s_buf[LU_MAXPATHLEN];
60     riov.iov_len = LU_MAXPATHLEN;
61
62     if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_READLINK, &siov, 1, &riov, 1)) < 0)
63         goto out;
64
65     if(PIS_ERROR(res)){
66         TRACE("read_link failed.\n");
67         res = PERROR(res);
68         goto out;
69     }
70
71     cc = &slot->s_buf[LU_MAXPATHLEN];
72     
73     TRACE("response: %s\n", cc);
74     
75     if(*cc == '/'){
76         if(GET_INFO(dentry->d_sb)->rootlen){
77             if(strncmp(GET_INFO(dentry->d_sb)->root, cc, GET_INFO(dentry->d_sb)->rootlen)){
78                 WARN("symlink outside mounted root!");
79                 cc = failed_link;
80                 goto out;
81             }
82             cc += GET_INFO(dentry->d_sb)->rootlen;
83         }
84
85         lu_xlate_symlink(slot->s_buf, slot->s_buf + LU_MAXPATHLEN, slot->s_buf);
86
87         cc = slot->s_buf;
88
89     }
90
91
92
93   out:
94     res = vfs_readlink(dentry, buffer, bufflen, cc);
95
96     lu_putslot(slot);
97
98     TRACE("out\n");
99     return res;
100 }
101
102 static int lu_followlink(struct dentry *dentry, struct nameidata *nd)
103 {
104     struct server_slot *slot;
105     struct iovec siov, riov;
106     int res;
107     char *cc = failed_link;
108     char *tmp;
109     
110     TRACE("in\n");
111
112     if((slot = lu_getslot(GET_INFO(dentry->d_sb))) == NULL)
113         return vfs_follow_link(nd, cc);
114
115
116     if((res = lu_getname(dentry, slot->s_buf, LU_MAXDATA)) < 0){
117         WARN("lu_getname failed!\n");
118         goto out;
119     }
120
121     siov.iov_base = slot->s_buf;
122     siov.iov_len = strlen(slot->s_buf) + 1;
123     riov.iov_base = &slot->s_buf[LU_MAXPATHLEN];
124     riov.iov_len = LU_MAXPATHLEN;
125
126     if((res = lu_execute(GET_INFO(dentry->d_sb), slot, PTYPE_READLINK, &siov, 1, &riov, 1)) < 0)
127         goto out;
128
129     if(PIS_ERROR(res)){
130         TRACE("read_link failed.\n");
131         res = PERROR(res);
132         goto out;
133     }
134
135     cc = &slot->s_buf[LU_MAXPATHLEN];
136
137     if(*cc == '/'){
138         if(GET_INFO(dentry->d_sb)->rootlen){
139             if(strncmp(GET_INFO(dentry->d_sb)->root, cc, GET_INFO(dentry->d_sb)->rootlen)){
140                 WARN("symlink outside mounted root!");
141                 cc = failed_link;
142                 goto out;
143             }
144             cc += GET_INFO(dentry->d_sb)->rootlen;
145         }
146
147         lu_xlate_symlink(slot->s_buf, slot->s_buf + LU_MAXPATHLEN, slot->s_buf);
148
149         cc = slot->s_buf;
150
151     }
152
153   out:
154
155     /* vfs_follow_link somehow manages to call lookup_validate, so we need to 
156        release the slot, in case it's the only one, otherwise lu_lookup will 
157        fail (avoid a deadlock). bad, bad vfs_follow_link! you break the overall
158        beauty of no kmallocs... */
159
160     if((tmp = kmalloc(strlen(cc) + 1, GFP_KERNEL)) == NULL){
161         WARN("out of mem!\n");
162         tmp = failed_link;
163     }else    
164         strcpy(tmp, cc);
165
166     lu_putslot(slot);
167     res = vfs_follow_link(nd, tmp);
168
169     if(tmp != failed_link)
170         kfree(tmp);
171     
172     TRACE("out\n");
173     return res;
174 }
175
176 struct inode_operations lu_symlink_inode_operations = {
177     .readlink           = lu_readlink,
178     .follow_link        = lu_followlink,
179 };
180
181
182
183
184