root/kern/vfs/vfslookup.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. change_bootfs
  2. vfs_setbootfs
  3. vfs_clearbootfs
  4. getdevice
  5. vfs_lookparent
  6. vfs_lookup

   1 /*
   2  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
   3  *      The President and Fellows of Harvard College.
   4  *
   5  * Redistribution and use in source and binary forms, with or without
   6  * modification, are permitted provided that the following conditions
   7  * are met:
   8  * 1. Redistributions of source code must retain the above copyright
   9  *    notice, this list of conditions and the following disclaimer.
  10  * 2. Redistributions in binary form must reproduce the above copyright
  11  *    notice, this list of conditions and the following disclaimer in the
  12  *    documentation and/or other materials provided with the distribution.
  13  * 3. Neither the name of the University nor the names of its contributors
  14  *    may be used to endorse or promote products derived from this software
  15  *    without specific prior written permission.
  16  *
  17  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
  18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
  21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  27  * SUCH DAMAGE.
  28  */
  29 
  30 /*
  31  * VFS operations relating to pathname translation
  32  */
  33 
  34 #include <types.h>
  35 #include <kern/errno.h>
  36 #include <limits.h>
  37 #include <lib.h>
  38 #include <synch.h>
  39 #include <vfs.h>
  40 #include <fs.h>
  41 #include <vnode.h>
  42 
  43 static struct vnode *bootfs_vnode = NULL;
  44 
  45 /*
  46  * Helper function for actually changing bootfs_vnode.
  47  */
  48 static
  49 void
  50 change_bootfs(struct vnode *newvn)
  51 {
  52         struct vnode *oldvn;
  53 
  54         oldvn = bootfs_vnode;
  55         bootfs_vnode = newvn;
  56 
  57         if (oldvn != NULL) {
  58                 VOP_DECREF(oldvn);
  59         }
  60 }
  61 
  62 /*
  63  * Set bootfs_vnode.
  64  *
  65  * Bootfs_vnode is the vnode used for beginning path translation of
  66  * pathnames starting with /.
  67  *
  68  * It is also incidentally the system's first current directory.
  69  */
  70 int
  71 vfs_setbootfs(const char *fsname)
  72 {
  73         char tmp[NAME_MAX+1];
  74         char *s;
  75         int result;
  76         struct vnode *newguy;
  77 
  78         vfs_biglock_acquire();
  79 
  80         snprintf(tmp, sizeof(tmp)-1, "%s", fsname);
  81         s = strchr(tmp, ':');
  82         if (s) {
  83                 /* If there's a colon, it must be at the end */
  84                 if (strlen(s)>0) {
  85                         vfs_biglock_release();
  86                         return EINVAL;
  87                 }
  88         }
  89         else {
  90                 strcat(tmp, ":");
  91         }
  92 
  93         result = vfs_chdir(tmp);
  94         if (result) {
  95                 vfs_biglock_release();
  96                 return result;
  97         }
  98 
  99         result = vfs_getcurdir(&newguy);
 100         if (result) {
 101                 vfs_biglock_release();
 102                 return result;
 103         }
 104 
 105         change_bootfs(newguy);
 106 
 107         vfs_biglock_release();
 108         return 0;
 109 }
 110 
 111 /*
 112  * Clear the bootfs vnode (preparatory to system shutdown).
 113  */
 114 void
 115 vfs_clearbootfs(void)
 116 {
 117         vfs_biglock_acquire();
 118         change_bootfs(NULL);
 119         vfs_biglock_release();
 120 }
 121 
 122 
 123 /*
 124  * Common code to pull the device name, if any, off the front of a
 125  * path and choose the vnode to begin the name lookup relative to.
 126  */
 127 
 128 static
 129 int
 130 getdevice(char *path, char **subpath, struct vnode **startvn)
 131 {
 132         int slash=-1, colon=-1, i;
 133         struct vnode *vn;
 134         int result;
 135 
 136         KASSERT(vfs_biglock_do_i_hold());
 137 
 138         /*
 139          * Locate the first colon or slash.
 140          */
 141 
 142         for (i=0; path[i]; i++) {
 143                 if (path[i]==':') {
 144                         colon = i;
 145                         break;
 146                 }
 147                 if (path[i]=='/') {
 148                         slash = i;
 149                         break;
 150                 }
 151         }
 152 
 153         if (colon < 0 && slash != 0) {
 154                 /*
 155                  * No colon before a slash, so no device name
 156                  * specified, and the slash isn't leading or is also
 157                  * absent, so this is a relative path or just a bare
 158                  * filename. Start from the current directory, and
 159                  * use the whole thing as the subpath.
 160                  */
 161                 *subpath = path;
 162                 return vfs_getcurdir(startvn);
 163         }
 164 
 165         if (colon>0) {
 166                 /* device:path - get root of device's filesystem */
 167                 path[colon]=0;
 168                 while (path[colon+1]=='/') {
 169                         /* device:/path - skip slash, treat as device:path */
 170                         colon++;
 171                 }
 172                 *subpath = &path[colon+1];
 173                 
 174                 result = vfs_getroot(path, startvn);
 175                 if (result) {
 176                         return result;
 177                 }
 178 
 179                 return 0;
 180         }
 181 
 182         /*
 183          * We have either /path or :path.
 184          *
 185          * /path is a path relative to the root of the "boot filesystem".
 186          * :path is a path relative to the root of the current filesystem.
 187          */
 188         KASSERT(colon==0 || slash==0);
 189 
 190         if (path[0]=='/') {
 191                 if (bootfs_vnode==NULL) {
 192                         return ENOENT;
 193                 }
 194                 VOP_INCREF(bootfs_vnode);
 195                 *startvn = bootfs_vnode;
 196         }
 197         else {
 198                 KASSERT(path[0]==':');
 199 
 200                 result = vfs_getcurdir(&vn);
 201                 if (result) {
 202                         return result;
 203                 }
 204 
 205                 /*
 206                  * The current directory may not be a device, so it
 207                  * must have a fs.
 208                  */
 209                 KASSERT(vn->vn_fs!=NULL);
 210 
 211                 *startvn = FSOP_GETROOT(vn->vn_fs);
 212 
 213                 VOP_DECREF(vn);
 214         }
 215 
 216         while (path[1]=='/') {
 217                 /* ///... or :/... */
 218                 path++;
 219         }
 220 
 221         *subpath = path+1;
 222 
 223         return 0;
 224 }
 225 
 226 /*
 227  * Name-to-vnode translation.
 228  * (In BSD, both of these are subsumed by namei().)
 229  */
 230 
 231 int
 232 vfs_lookparent(char *path, struct vnode **retval,
 233                char *buf, size_t buflen)
 234 {
 235         struct vnode *startvn;
 236         int result;
 237 
 238         vfs_biglock_acquire();
 239 
 240         result = getdevice(path, &path, &startvn);
 241         if (result) {
 242                 vfs_biglock_release();
 243                 return result;
 244         }
 245 
 246         if (strlen(path)==0) {
 247                 /*
 248                  * It does not make sense to use just a device name in
 249                  * a context where "lookparent" is the desired
 250                  * operation.
 251                  */
 252                 result = EINVAL;
 253         }
 254         else {
 255                 result = VOP_LOOKPARENT(startvn, path, retval, buf, buflen);
 256         }
 257 
 258         VOP_DECREF(startvn);
 259 
 260         vfs_biglock_release();
 261         return result;
 262 }
 263 
 264 int
 265 vfs_lookup(char *path, struct vnode **retval)
 266 {
 267         struct vnode *startvn;
 268         int result;
 269 
 270         vfs_biglock_acquire();
 271 
 272         result = getdevice(path, &path, &startvn);
 273         if (result) {
 274                 vfs_biglock_release();
 275                 return result;
 276         }
 277 
 278         if (strlen(path)==0) {
 279                 *retval = startvn;
 280                 vfs_biglock_release();
 281                 return 0;
 282         }
 283 
 284         result = VOP_LOOKUP(startvn, path, retval);
 285 
 286         VOP_DECREF(startvn);
 287         vfs_biglock_release();
 288         return result;
 289 }

/* [<][>][^][v][top][bottom][index][help] */