diff options
Diffstat (limited to 'fs/nfs/getroot.c')
-rw-r--r-- | fs/nfs/getroot.c | 115 |
1 files changed, 22 insertions, 93 deletions
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c index b35d2a616066..ada369a5647b 100644 --- a/fs/nfs/getroot.c +++ b/fs/nfs/getroot.c | |||
@@ -122,115 +122,44 @@ struct dentry *nfs_get_root(struct super_block *sb, struct nfs_fh *mntfh) | |||
122 | 122 | ||
123 | #ifdef CONFIG_NFS_V4 | 123 | #ifdef CONFIG_NFS_V4 |
124 | 124 | ||
125 | /* | 125 | int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh) |
126 | * Do a simple pathwalk from the root FH of the server to the nominated target | ||
127 | * of the mountpoint | ||
128 | * - give error on symlinks | ||
129 | * - give error on ".." occurring in the path | ||
130 | * - follow traversals | ||
131 | */ | ||
132 | int nfs4_path_walk(struct nfs_server *server, | ||
133 | struct nfs_fh *mntfh, | ||
134 | const char *path) | ||
135 | { | 126 | { |
136 | struct nfs_fsinfo fsinfo; | 127 | struct nfs_fsinfo fsinfo; |
137 | struct nfs_fattr fattr; | 128 | int ret = -ENOMEM; |
138 | struct nfs_fh lastfh; | ||
139 | struct qstr name; | ||
140 | int ret; | ||
141 | 129 | ||
142 | dprintk("--> nfs4_path_walk(,,%s)\n", path); | 130 | dprintk("--> nfs4_get_rootfh()\n"); |
143 | 131 | ||
144 | fsinfo.fattr = &fattr; | 132 | fsinfo.fattr = nfs_alloc_fattr(); |
145 | nfs_fattr_init(&fattr); | 133 | if (fsinfo.fattr == NULL) |
146 | 134 | goto out; | |
147 | /* Eat leading slashes */ | ||
148 | while (*path == '/') | ||
149 | path++; | ||
150 | 135 | ||
151 | /* Start by getting the root filehandle from the server */ | 136 | /* Start by getting the root filehandle from the server */ |
152 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); | 137 | ret = server->nfs_client->rpc_ops->getroot(server, mntfh, &fsinfo); |
153 | if (ret < 0) { | 138 | if (ret < 0) { |
154 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | 139 | dprintk("nfs4_get_rootfh: getroot error = %d\n", -ret); |
155 | return ret; | 140 | goto out; |
156 | } | 141 | } |
157 | 142 | ||
158 | if (!S_ISDIR(fattr.mode)) { | 143 | if (!(fsinfo.fattr->valid & NFS_ATTR_FATTR_MODE) |
159 | printk(KERN_ERR "nfs4_get_root:" | 144 | || !S_ISDIR(fsinfo.fattr->mode)) { |
145 | printk(KERN_ERR "nfs4_get_rootfh:" | ||
160 | " getroot encountered non-directory\n"); | 146 | " getroot encountered non-directory\n"); |
161 | return -ENOTDIR; | 147 | ret = -ENOTDIR; |
148 | goto out; | ||
162 | } | 149 | } |
163 | 150 | ||
164 | /* FIXME: It is quite valid for the server to return a referral here */ | 151 | if (fsinfo.fattr->valid & NFS_ATTR_FATTR_V4_REFERRAL) { |
165 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | 152 | printk(KERN_ERR "nfs4_get_rootfh:" |
166 | printk(KERN_ERR "nfs4_get_root:" | ||
167 | " getroot obtained referral\n"); | 153 | " getroot obtained referral\n"); |
168 | return -EREMOTE; | 154 | ret = -EREMOTE; |
155 | goto out; | ||
169 | } | 156 | } |
170 | 157 | ||
171 | next_component: | 158 | memcpy(&server->fsid, &fsinfo.fattr->fsid, sizeof(server->fsid)); |
172 | dprintk("Next: %s\n", path); | 159 | out: |
173 | 160 | nfs_free_fattr(fsinfo.fattr); | |
174 | /* extract the next bit of the path */ | 161 | dprintk("<-- nfs4_get_rootfh() = %d\n", ret); |
175 | if (!*path) | 162 | return ret; |
176 | goto path_walk_complete; | ||
177 | |||
178 | name.name = path; | ||
179 | while (*path && *path != '/') | ||
180 | path++; | ||
181 | name.len = path - (const char *) name.name; | ||
182 | |||
183 | if (name.len > NFS4_MAXNAMLEN) | ||
184 | return -ENAMETOOLONG; | ||
185 | |||
186 | eat_dot_dir: | ||
187 | while (*path == '/') | ||
188 | path++; | ||
189 | |||
190 | if (path[0] == '.' && (path[1] == '/' || !path[1])) { | ||
191 | path += 2; | ||
192 | goto eat_dot_dir; | ||
193 | } | ||
194 | |||
195 | /* FIXME: Why shouldn't the user be able to use ".." in the path? */ | ||
196 | if (path[0] == '.' && path[1] == '.' && (path[2] == '/' || !path[2]) | ||
197 | ) { | ||
198 | printk(KERN_ERR "nfs4_get_root:" | ||
199 | " Mount path contains reference to \"..\"\n"); | ||
200 | return -EINVAL; | ||
201 | } | ||
202 | |||
203 | /* lookup the next FH in the sequence */ | ||
204 | memcpy(&lastfh, mntfh, sizeof(lastfh)); | ||
205 | |||
206 | dprintk("LookupFH: %*.*s [%s]\n", name.len, name.len, name.name, path); | ||
207 | |||
208 | ret = server->nfs_client->rpc_ops->lookupfh(server, &lastfh, &name, | ||
209 | mntfh, &fattr); | ||
210 | if (ret < 0) { | ||
211 | dprintk("nfs4_get_root: getroot error = %d\n", -ret); | ||
212 | return ret; | ||
213 | } | ||
214 | |||
215 | if (!S_ISDIR(fattr.mode)) { | ||
216 | printk(KERN_ERR "nfs4_get_root:" | ||
217 | " lookupfh encountered non-directory\n"); | ||
218 | return -ENOTDIR; | ||
219 | } | ||
220 | |||
221 | /* FIXME: Referrals are quite valid here too */ | ||
222 | if (fattr.valid & NFS_ATTR_FATTR_V4_REFERRAL) { | ||
223 | printk(KERN_ERR "nfs4_get_root:" | ||
224 | " lookupfh obtained referral\n"); | ||
225 | return -EREMOTE; | ||
226 | } | ||
227 | |||
228 | goto next_component; | ||
229 | |||
230 | path_walk_complete: | ||
231 | memcpy(&server->fsid, &fattr.fsid, sizeof(server->fsid)); | ||
232 | dprintk("<-- nfs4_path_walk() = 0\n"); | ||
233 | return 0; | ||
234 | } | 163 | } |
235 | 164 | ||
236 | /* | 165 | /* |