2 * This Cplant(TM) source code is the property of Sandia National
5 * This Cplant(TM) source code is copyrighted by Sandia National
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)
12 * Cplant(TM) Copyright 1998-2006 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
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.
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.
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
34 * Questions or comments about this library should be sent to:
37 * Sandia National Laboratories, New Mexico
39 * Albuquerque, NM 87185-1110
49 #include <sys/param.h>
50 #include <sys/types.h>
52 #include <sys/queue.h>
59 * Parse next component in path.
61 #ifndef AUTOMOUNT_FILE_NAME
65 _sysio_next_component(const char *path, struct qstr *name)
67 while (*path == PATH_SEPARATOR)
72 while (*path && *path != PATH_SEPARATOR) {
74 37 * name->hashval + *path++;
80 * Given parent, look up component.
83 lookup(struct pnode *parent,
88 int check_permissions)
93 if (!parent->p_base->pb_ino)
97 * Sometimes we don't want to check permissions. At initialization
100 if (check_permissions) {
101 err = _sysio_permitted(parent, X_OK);
107 * Short-circuit `.' and `..'; We don't cache those.
110 if (name->len == 1 && name->name[0] == '.')
112 else if (name->len == 2 && name->name[0] == '.' && name->name[1] == '.')
113 pno = parent->p_parent;
118 * Get cache entry then.
120 err = _sysio_p_find_alias(parent, name, &pno);
126 * While covered, move to the covering node.
128 while (pno->p_cover && pno->p_cover != pno) {
131 cover = pno->p_cover;
140 * (Re)validate the pnode.
142 err = _sysio_p_validate(pno, intnt, path);
150 * The meat. Walk an absolute or relative path, looking up each
151 * component. Various flags in the nameidata argument govern actions
152 * and return values/state. They are:
154 * ND_NOFOLLOW symbolic links are not followed
155 * ND_NEGOK if terminal/leaf does not exist, return
156 * path node (alias) anyway.
157 * ND_NOPERMCHECK do not check permissions
160 _sysio_path_walk(struct pnode *parent, struct nameidata *nd)
164 struct qstr this, next;
182 if (*nd->nd_path == PATH_SEPARATOR) {
184 * Make parent the root of the name space.
186 parent = nd->nd_root;
189 #ifdef DEFER_INIT_CWD
193 if (!_sysio_init_cwd && !nd->nd_root)
197 * Finally have to set the current working directory. We can
198 * not tolerate errors here or else risk leaving the process
199 * in a very unexpected location. We abort then unless all goes
202 icwd = _sysio_init_cwd;
203 _sysio_init_cwd = NULL;
204 parent = nd->nd_root;
207 (void )_sysio_namei(nd->nd_root, icwd, 0, NULL, &parent);
208 if (_sysio_p_chdir(parent) != 0)
214 * (Re)Validate the parent.
216 err = _sysio_p_validate(parent, NULL, NULL);
221 * Prime everything for the loop. Will need another reference to the
222 * initial directory. It'll be dropped later.
226 _sysio_next_component(nd->nd_path, &next);
232 * Derecurse the path tree-walk.
235 ino = nd->nd_pno->p_base->pb_ino;
236 if (S_ISLNK(ino->i_stbuf.st_mode) &&
237 (next.len || !(nd->nd_flags & ND_NOFOLLOW))) {
240 struct nameidata nameidata;
242 if (nd->nd_slicnt >= MAX_SYMLINK) {
248 * Follow symbolic link.
250 lpath = malloc(MAXPATHLEN + 1);
256 ino->i_ops.inop_readlink(nd->nd_pno,
264 lpath[cc] = '\0'; /* NUL term */
266 * Handle symbolic links with recursion. Yuck!
267 * Pass the NULL intent for recursive symlink
268 * except the last component.
274 !next.len ? nd->nd_intent : NULL);
275 nameidata.nd_slicnt = nd->nd_slicnt + 1;
277 _sysio_path_walk(nd->nd_pno->p_parent, &nameidata);
282 nd->nd_pno = nameidata.nd_pno;
283 ino = nd->nd_pno->p_base->pb_ino;
285 #ifdef AUTOMOUNT_FILE_NAME
287 S_ISDIR(ino->i_stbuf.st_mode) &&
288 (nd->nd_pno->p_mount->mnt_flags & MOUNT_F_AUTO) &&
289 nd->nd_amcnt < MAX_MOUNT_DEPTH &&
290 ino->i_stbuf.st_mode & S_ISUID) {
294 * We're committed to a lookup. It's time to see if
295 * we're going to do it in an automount-point and
296 * arrange the mount if so.
298 assert(!nd->nd_pno->p_cover);
301 &_sysio_mount_file_name,
308 if (!err && _sysio_automount(pno) == 0) {
312 * All went well. Need to switch
313 * parent pno and ino to the
314 * root of the newly mounted sub-tree.
317 * We don't recurseively retry these
318 * things. It's OK to have the new root
319 * be an automount-point but it's going
320 * to take another lookup to accomplish it.
321 * The alternative could get us into an
324 root = nd->nd_pno->p_cover;
331 ino = nd->nd_pno->p_base->pb_ino;
335 * Must send the intent-path again.
341 * Must go back top and retry with this
342 * new pnode as parent.
346 err = 0; /* it never happened */
351 * Set up for next component.
360 * Should only be here if final component was
361 * target of a symlink.
363 nd->nd_path = this.name + this.len;
367 nd->nd_path = this.name + this.len;
368 _sysio_next_component(nd->nd_path, &next);
373 * Parent must be a directory.
375 if (ino && !S_ISDIR(ino->i_stbuf.st_mode)) {
381 * The extra path arg is passed only on the first lookup in the
382 * walk as we cross into each file system, anew. The intent is
383 * passed both on the first lookup and when trying to look up
384 * the final component -- Of the original path, not on the
387 * Confused? Me too and I came up with this weirdness. It's
388 * hints to the file system drivers. Read on.
390 * The first lookup will give everything one needs to ready
391 * everything for the entire operation before the path is
392 * walked. The file system driver knows it's the first lookup
393 * in the walk because it has both the path and the intent.
395 * Alternatively, one could split the duties; The first lookup
396 * can be used to prime the file system inode cache with the
397 * interior nodes we'll want in the path-walk. Then, when
398 * looking up the last component, ready everything for the
399 * operations(s) to come. The file system driver knows it's
400 * the last lookup in the walk because it has the intent,
401 * again, but without the path.
403 * One special case; If we were asked to look up a single
404 * component, we treat it as the last component. The file
405 * system driver never sees the extra path argument. It should
406 * be noted that the driver always has the fully qualified
407 * path, on the target file system, available to it for any
408 * node it is looking up, including the last, via the base
409 * path node and it's ancestor chain.
418 (path && next.len) ? path : NULL,
419 !(nd->nd_flags & ND_NOPERMCHECK));
421 if (err == -ENOENT &&
423 (nd->nd_flags & ND_NEGOK))
427 path = NULL; /* Stop that! */
428 if ((parent->p_mount->mnt_fs !=
429 nd->nd_pno->p_mount->mnt_fs)) {
431 * Crossed into a new fs. We'll want the next lookup
432 * to include the path again.
438 * Release the parent.
445 * Trailing separators cause us to break from the loop with
446 * a parent set but no pnode. Check for that.
452 * Make sure the last processed component was a directory. The
453 * trailing slashes are illegal behind anything else.
456 S_ISDIR(nd->nd_pno->p_base->pb_ino->i_stbuf.st_mode)))
461 * Drop reference to parent if set. Either we have a dup of the original
462 * parent or an intermediate reference.
468 * On error, we will want to drop our reference to the current
469 * path node if at end.
471 if (err && nd->nd_pno) {
481 * for backward compatibility w/protocol switch
482 * remove everything up to the first ':'
483 * fortran libs prepend cwd to path, so not much choice
485 #define STRIP_PREFIX(p) strchr(p,':') ? strchr(p,':')+1 : p
487 #define STRIP_PREFIX(p) p
491 * Expanded form of the path-walk routine, with the common arguments, builds
492 * the nameidata bundle and calls path-walk.
495 _sysio_namei(struct pnode *parent,
498 struct intent *intnt,
501 struct nameidata nameidata;
504 ND_INIT(&nameidata, flags, STRIP_PREFIX(path), _sysio_root, intnt);
505 err = _sysio_path_walk(parent, &nameidata);
507 *pnop = nameidata.nd_pno;