Whamcloud - gitweb
2d2e905e3243e2dbd4e4a337d64f3b5b387958ae
[fs/lustre-release.git] / libsysio / src / namei.c
1 /*
2  *    This Cplant(TM) source code is the property of Sandia National
3  *    Laboratories.
4  *
5  *    This Cplant(TM) source code is copyrighted by Sandia National
6  *    Laboratories.
7  *
8  *    The redistribution of this Cplant(TM) source code is subject to the
9  *    terms of the GNU Lesser General Public License
10  *    (see cit/LGPL or http://www.gnu.org/licenses/lgpl.html)
11  *
12  *    Cplant(TM) Copyright 1998-2003 Sandia Corporation. 
13  *    Under the terms of Contract DE-AC04-94AL85000, there is a non-exclusive
14  *    license for use of this work by or on behalf of the US Government.
15  *    Export of this program may require a license from the United States
16  *    Government.
17  */
18
19 /*
20  * This library is free software; you can redistribute it and/or
21  * modify it under the terms of the GNU Lesser General Public
22  * License as published by the Free Software Foundation; either
23  * version 2.1 of the License, or (at your option) any later version.
24  * 
25  * This library is distributed in the hope that it will be useful,
26  * but WITHOUT ANY WARRANTY; without even the implied warranty of
27  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
28  * Lesser General Public License for more details.
29  * 
30  * You should have received a copy of the GNU Lesser General Public
31  * License along with this library; if not, write to the Free Software
32  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33  *
34  * Questions or comments about this library should be sent to:
35  *
36  * Lee Ward
37  * Sandia National Laboratories, New Mexico
38  * P.O. Box 5800
39  * Albuquerque, NM 87185-1110
40  *
41  * lee@sandia.gov
42  */
43
44 #if defined(AUTOMOUNT_FILE_NAME) && defined(__linux__)
45 #define _BSD_SOURCE
46 #endif
47
48 #include <stdlib.h>
49 #include <string.h>
50 #include <errno.h>
51 #include <assert.h>
52 #include <sys/param.h>
53 #include <sys/queue.h>
54 #include <sys/types.h>
55 #include <sys/stat.h>
56
57 #include "sysio.h"
58 #include "mount.h"
59 #include "inode.h"
60
61 /*
62  * Parse next component in path.
63  */
64 #ifndef AUTOMOUNT_FILE_NAME
65 static
66 #endif
67 void
68 _sysio_next_component(const char *path, struct qstr *name)
69 {
70         while (*path == PATH_SEPARATOR)
71                 path++;
72         name->name = path;
73         name->len = 0;
74         name->hashval = 0;
75         while (*path && *path != PATH_SEPARATOR) {
76                 name->hashval =
77                     37 * name->hashval + *path++;
78                 name->len++;
79         }
80 }
81
82 /*
83  * Given parent, look up component.
84  */
85 static int
86 lookup(struct pnode *parent,
87        struct qstr *name,
88        struct pnode **pnop,
89        struct intent *intnt,
90        const char *path)
91 {
92         struct pnode *pno;
93         int     err;
94
95         if (!parent->p_base->pb_ino)
96                 return -ENOTDIR;
97
98         /*
99          * Short-circuit `.' and `..'; We don't cache those.
100          */
101         pno = NULL;
102         if (name->len == 1 && name->name[0] == '.')
103                 pno = parent;
104         else if (name->len == 2 && name->name[0] == '.' && name->name[1] == '.')
105                 pno = parent->p_parent;
106         if (pno)
107                 P_REF(pno);
108         else {
109                 /*
110                  * Get cache entry then.
111                  */
112                 err = _sysio_p_find_alias(parent, name, &pno);
113                 if (err)
114                         return err;
115         }
116
117         /*
118          * While covered, move to the covering node.
119          */
120         while (pno->p_cover && pno->p_cover != pno) {
121                 struct pnode *cover;
122
123                 cover = pno->p_cover;
124                 P_REF(cover);
125                 P_RELE(pno);
126                 pno = cover;
127         }
128
129         *pnop = pno;
130
131         /*
132          * (Re)validate the pnode.
133          */
134         err = _sysio_p_validate(pno, intnt, path);
135         if (err)
136                 return err;
137
138         return 0;
139 }
140
141 /*
142  * The meat. Walk an absolute or relative path, looking up each
143  * component. Various flags in the nameidata argument govern actions
144  * and return values/state. They are:
145  *
146  * ND_NOFOLLOW          symbolic links are not followed
147  * ND_NEGOK             if terminal/leaf does not exist, return
148  *                       path node (alias) anyway.
149  */
150 int
151 _sysio_path_walk(struct pnode *parent, struct nameidata *nd)
152 {
153         int     err;
154         const char *path;
155         struct qstr this, next;
156         struct inode *ino;
157
158         /*
159          * NULL path?
160          */
161         if (!nd->nd_path)
162                 return -EFAULT;
163
164         /*
165          * Empty path?
166          */
167         if (!*nd->nd_path)
168                 return -ENOENT;
169
170         /*
171          * Leading slash?
172          */
173         if (*nd->nd_path == PATH_SEPARATOR) {
174                 /*
175                  * Make parent the root of the name space.
176                  */
177                 parent = nd->nd_root;
178         }
179
180         /*
181          * (Re)Validate the parent.
182          */
183         err = _sysio_p_validate(parent, NULL, NULL);
184         if (err)
185                 return err;
186
187         /*
188          * Prime everything for the loop. Will need another reference to the
189          * initial directory. It'll be dropped later.
190          */
191         nd->nd_pno = parent;
192         P_REF(nd->nd_pno);
193         _sysio_next_component(nd->nd_path, &next);
194         path = next.name;
195         parent = NULL;
196         err = 0;
197
198         /*
199          * Derecurse the path tree-walk.
200          */
201         for (;;) {
202                 ino = nd->nd_pno->p_base->pb_ino;
203                 if (S_ISLNK(ino->i_mode) &&
204                     (next.len || !(nd->nd_flags & ND_NOFOLLOW))) {
205                         char    *lpath;
206                         ssize_t cc;
207                         struct nameidata nameidata;
208
209                         if (nd->nd_slicnt >= MAX_SYMLINK) {
210                                 err = -ELOOP;
211                                 break;
212                         }
213
214                         /*
215                          * Follow symbolic link.
216                          */
217                         lpath = malloc(MAXPATHLEN + 1);
218                         if (!lpath) {
219                                 err = -ENOMEM;
220                                 break;
221                         }
222                         cc =
223                             ino->i_ops.inop_readlink(nd->nd_pno,
224                                                      lpath,
225                                                      MAXPATHLEN);
226                         if (cc < 0) {
227                                 free(lpath);
228                                 err = (int )cc;
229                                 break;
230                         }
231                         lpath[cc] = '\0';                       /* NUL term */
232                         /*
233                          * Handle symbolic links with recursion. Yuck!
234                          */
235                         ND_INIT(&nameidata,
236                                 (nd->nd_flags | ND_NEGOK),
237                                 lpath,
238                                 nd->nd_root,
239                                 nd->nd_intent);
240                         nameidata.nd_slicnt = nd->nd_slicnt + 1;
241                         err =
242                             _sysio_path_walk(nd->nd_pno->p_parent, &nameidata);
243                         free(lpath);
244                         if (err)
245                                 break;
246                         P_RELE(nd->nd_pno);
247                         nd->nd_pno = nameidata.nd_pno;
248                         ino = nd->nd_pno->p_base->pb_ino;
249                 }
250 #ifdef AUTOMOUNT_FILE_NAME
251                 else if (ino &&
252                          S_ISDIR(ino->i_mode) &&
253                          (nd->nd_pno->p_mount->mnt_flags & MOUNT_F_AUTO) &&
254                          nd->nd_amcnt < MAX_MOUNT_DEPTH &&
255                          ino->i_mode & S_ISUID) {
256                         struct pnode *pno;
257
258                         /*
259                          * We're committed to a lookup. It's time to see if
260                          * we're going to do it in an automount-point and
261                          * arrange the mount if so.
262                          */
263                         assert(!nd->nd_pno->p_cover);
264                         err =
265                             lookup(nd->nd_pno,
266                                    &_sysio_mount_file_name,
267                                    &pno,
268                                    NULL,
269                                    NULL);
270                         if (pno)
271                                 P_RELE(pno);
272                         if (!err && _sysio_automount(pno) == 0) {
273                                 struct pnode *root;
274
275                                 /*
276                                  * All went well. Need to switch
277                                  * parent pno and ino to the
278                                  * root of the newly mounted sub-tree.
279                                  *
280                                  * NB:
281                                  * We don't recurseively retry these
282                                  * things. It's OK to have the new root
283                                  * be an automount-point but it's going
284                                  * to take another lookup to accomplish it.
285                                  * The alternative could get us into an
286                                  * infinite loop.
287                                  */
288                                 root = nd->nd_pno->p_cover;
289                                 assert(root);
290                                 P_RELE(nd->nd_pno);
291                                 nd->nd_pno = root;
292 #if 0
293                                 P_REF(nd->nd_pno);
294 #endif
295                                 ino = nd->nd_pno->p_base->pb_ino;
296                                 assert(ino);
297
298                                 /*
299                                  * Must send the intent-path again.
300                                  */
301                                 path = nd->nd_path;
302                                 nd->nd_amcnt++;
303
304                                 /*
305                                  * Must go back top and retry with this
306                                  * new pnode as parent.
307                                  */
308                                 continue;
309                         }
310                         err = 0;                        /* it never happened */
311                 }
312 #endif
313
314                 /*
315                  * Set up for next component.
316                  */
317                 this = next;
318                 if (path)
319                         path = this.name;
320                 if (!this.len)
321                         break;
322                 if (!ino) {
323                         /*
324                          * Should only be here if final component was
325                          * target of a symlink.
326                          */
327                         nd->nd_path = this.name + this.len;
328                         err = -ENOENT;
329                         break;
330                 }
331                 nd->nd_path = this.name + this.len;
332                 _sysio_next_component(nd->nd_path, &next);
333                 parent = nd->nd_pno;
334                 nd->nd_pno = NULL;
335
336                 /*
337                  * Parent must be a directory.
338                  */
339                 if (ino && !S_ISDIR(ino->i_mode)) {
340                         err = -ENOTDIR;
341                         break;
342                 }
343
344                 /*
345                  * The extra path arg is passed only on the first lookup in the
346                  * walk as we cross into each file system, anew. The intent is
347                  * passed both on the first lookup and when trying to look up
348                  * the final component -- Of the original path, not on the
349                  * file system.
350                  *
351                  * Confused? Me too and I came up with this weirdness. It's
352                  * hints to the file system drivers. Read on.
353                  *
354                  * The first lookup will give everything one needs to ready
355                  * everything for the entire operation before the path is
356                  * walked. The file system driver knows it's the first lookup
357                  * in the walk because it has both the path and the intent.
358                  *
359                  * Alternatively, one could split the duties; The first lookup
360                  * can be used to prime the file system inode cache with the
361                  * interior nodes we'll want in the path-walk. Then, when
362                  * looking up the last component, ready everything for the
363                  * operations(s) to come. The file system driver knows it's
364                  * the last lookup in the walk because it has the intent,
365                  * again, but without the path.
366                  *
367                  * One special case; If we were asked to look up a single
368                  * component, we treat it as the last component. The file
369                  * system driver never sees the extra path argument. It should
370                  * be noted that the driver always has the fully qualified
371                  * path, on the target file system, available to it for any
372                  * node it is looking up, including the last, via the base
373                  * path node and it's ancestor chain.
374                  */
375                 err =
376                     lookup(parent,
377                            &this,
378                            &nd->nd_pno,
379                            (path || !next.len)
380                              ? nd->nd_intent
381                              : NULL,
382                            (path && next.len) ? path : NULL);
383                 if (err) {
384                         if (err == -ENOENT &&
385                             !next.len &&
386                             (nd->nd_flags & ND_NEGOK))
387                                 err = 0;
388                         break;
389                 }
390                 path = NULL;                            /* Stop that! */
391                 if ((parent->p_mount->mnt_fs !=
392                      nd->nd_pno->p_mount->mnt_fs)) {
393                         /*
394                          * Crossed into a new fs. We'll want the next lookup
395                          * to include the path again.
396                          */
397                         path = nd->nd_path;
398                 }
399
400                 /*
401                  * Release the parent.
402                  */
403                 P_RELE(parent);
404                 parent = NULL;
405         }
406
407         /*
408          * Trailing separators cause us to break from the loop with
409          * a parent set but no pnode. Check for that.
410          */
411         if (!nd->nd_pno) {
412                 nd->nd_pno = parent;
413                 parent = NULL;
414                 /*
415                  * Make sure the last processed component was a directory. The
416                  * trailing slashes are illegal behind anything else.
417                  */
418                 if (!(err || S_ISDIR(nd->nd_pno->p_base->pb_ino->i_mode)))
419                         err = -ENOTDIR;
420         }
421
422         /*
423          * Drop reference to parent if set. Either we have a dup of the original
424          * parent or an intermediate reference.
425          */
426         if (parent)
427                 P_RELE(parent);
428
429         /*
430          * On error, we will want to drop our reference to the current
431          * path node if at end.
432          */
433         if (err && nd->nd_pno) {
434                 P_RELE(nd->nd_pno);
435                 nd->nd_pno = NULL;
436         }
437
438         return err;
439 }
440
441 #ifdef CPLANT_YOD
442 /* 
443  * for backward compatibility w/protocol switch
444  * remove everything up to the first ':'
445  * fortran libs prepend cwd to path, so not much choice
446  */
447 #define STRIP_PREFIX(p) strchr(p,':') ? strchr(p,':')+1 : p
448 #else
449 #define STRIP_PREFIX(p) p
450 #endif
451
452 /*
453  * Expanded form of the path-walk routine, with the common arguments, builds
454  * the nameidata bundle and calls path-walk.
455  */
456 int
457 _sysio_namei(struct pnode *parent,
458              const char *path,
459              unsigned flags,
460              struct intent *intnt,
461              struct pnode **pnop)
462 {
463         struct nameidata nameidata;
464         int     err;
465
466         ND_INIT(&nameidata, flags, STRIP_PREFIX(path), _sysio_root, intnt);
467         err = _sysio_path_walk(parent, &nameidata);
468         if (!err)
469                 *pnop = nameidata.nd_pno;
470         return err;
471 }