os161-1.99
 All Data Structures
vfslookup.c
00001 /*
00002  * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2008, 2009
00003  *      The President and Fellows of Harvard College.
00004  *
00005  * Redistribution and use in source and binary forms, with or without
00006  * modification, are permitted provided that the following conditions
00007  * are met:
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the University nor the names of its contributors
00014  *    may be used to endorse or promote products derived from this software
00015  *    without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE UNIVERSITY AND CONTRIBUTORS ``AS IS'' AND
00018  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00019  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00020  * ARE DISCLAIMED.  IN NO EVENT SHALL THE UNIVERSITY OR CONTRIBUTORS BE LIABLE
00021  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
00022  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
00023  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00024  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
00025  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
00026  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00027  * SUCH DAMAGE.
00028  */
00029 
00030 /*
00031  * VFS operations relating to pathname translation
00032  */
00033 
00034 #include <types.h>
00035 #include <kern/errno.h>
00036 #include <limits.h>
00037 #include <lib.h>
00038 #include <synch.h>
00039 #include <vfs.h>
00040 #include <fs.h>
00041 #include <vnode.h>
00042 
00043 static struct vnode *bootfs_vnode = NULL;
00044 
00045 /*
00046  * Helper function for actually changing bootfs_vnode.
00047  */
00048 static
00049 void
00050 change_bootfs(struct vnode *newvn)
00051 {
00052         struct vnode *oldvn;
00053 
00054         oldvn = bootfs_vnode;
00055         bootfs_vnode = newvn;
00056 
00057         if (oldvn != NULL) {
00058                 VOP_DECREF(oldvn);
00059         }
00060 }
00061 
00062 /*
00063  * Set bootfs_vnode.
00064  *
00065  * Bootfs_vnode is the vnode used for beginning path translation of
00066  * pathnames starting with /.
00067  *
00068  * It is also incidentally the system's first current directory.
00069  */
00070 int
00071 vfs_setbootfs(const char *fsname)
00072 {
00073         char tmp[NAME_MAX+1];
00074         char *s;
00075         int result;
00076         struct vnode *newguy;
00077 
00078         vfs_biglock_acquire();
00079 
00080         snprintf(tmp, sizeof(tmp)-1, "%s", fsname);
00081         s = strchr(tmp, ':');
00082         if (s) {
00083                 /* If there's a colon, it must be at the end */
00084                 if (strlen(s)>0) {
00085                         vfs_biglock_release();
00086                         return EINVAL;
00087                 }
00088         }
00089         else {
00090                 strcat(tmp, ":");
00091         }
00092 
00093         result = vfs_chdir(tmp);
00094         if (result) {
00095                 vfs_biglock_release();
00096                 return result;
00097         }
00098 
00099         result = vfs_getcurdir(&newguy);
00100         if (result) {
00101                 vfs_biglock_release();
00102                 return result;
00103         }
00104 
00105         change_bootfs(newguy);
00106 
00107         vfs_biglock_release();
00108         return 0;
00109 }
00110 
00111 /*
00112  * Clear the bootfs vnode (preparatory to system shutdown).
00113  */
00114 void
00115 vfs_clearbootfs(void)
00116 {
00117         vfs_biglock_acquire();
00118         change_bootfs(NULL);
00119         vfs_biglock_release();
00120 }
00121 
00122 
00123 /*
00124  * Common code to pull the device name, if any, off the front of a
00125  * path and choose the vnode to begin the name lookup relative to.
00126  */
00127 
00128 static
00129 int
00130 getdevice(char *path, char **subpath, struct vnode **startvn)
00131 {
00132         int slash=-1, colon=-1, i;
00133         struct vnode *vn;
00134         int result;
00135 
00136         KASSERT(vfs_biglock_do_i_hold());
00137 
00138         /*
00139          * Locate the first colon or slash.
00140          */
00141 
00142         for (i=0; path[i]; i++) {
00143                 if (path[i]==':') {
00144                         colon = i;
00145                         break;
00146                 }
00147                 if (path[i]=='/') {
00148                         slash = i;
00149                         break;
00150                 }
00151         }
00152 
00153         if (colon < 0 && slash != 0) {
00154                 /*
00155                  * No colon before a slash, so no device name
00156                  * specified, and the slash isn't leading or is also
00157                  * absent, so this is a relative path or just a bare
00158                  * filename. Start from the current directory, and
00159                  * use the whole thing as the subpath.
00160                  */
00161                 *subpath = path;
00162                 return vfs_getcurdir(startvn);
00163         }
00164 
00165         if (colon>0) {
00166                 /* device:path - get root of device's filesystem */
00167                 path[colon]=0;
00168                 while (path[colon+1]=='/') {
00169                         /* device:/path - skip slash, treat as device:path */
00170                         colon++;
00171                 }
00172                 *subpath = &path[colon+1];
00173                 
00174                 result = vfs_getroot(path, startvn);
00175                 if (result) {
00176                         return result;
00177                 }
00178 
00179                 return 0;
00180         }
00181 
00182         /*
00183          * We have either /path or :path.
00184          *
00185          * /path is a path relative to the root of the "boot filesystem".
00186          * :path is a path relative to the root of the current filesystem.
00187          */
00188         KASSERT(colon==0 || slash==0);
00189 
00190         if (path[0]=='/') {
00191                 if (bootfs_vnode==NULL) {
00192                         return ENOENT;
00193                 }
00194                 VOP_INCREF(bootfs_vnode);
00195                 *startvn = bootfs_vnode;
00196         }
00197         else {
00198                 KASSERT(path[0]==':');
00199 
00200                 result = vfs_getcurdir(&vn);
00201                 if (result) {
00202                         return result;
00203                 }
00204 
00205                 /*
00206                  * The current directory may not be a device, so it
00207                  * must have a fs.
00208                  */
00209                 KASSERT(vn->vn_fs!=NULL);
00210 
00211                 *startvn = FSOP_GETROOT(vn->vn_fs);
00212 
00213                 VOP_DECREF(vn);
00214         }
00215 
00216         while (path[1]=='/') {
00217                 /* ///... or :/... */
00218                 path++;
00219         }
00220 
00221         *subpath = path+1;
00222 
00223         return 0;
00224 }
00225 
00226 /*
00227  * Name-to-vnode translation.
00228  * (In BSD, both of these are subsumed by namei().)
00229  */
00230 
00231 int
00232 vfs_lookparent(char *path, struct vnode **retval,
00233                char *buf, size_t buflen)
00234 {
00235         struct vnode *startvn;
00236         int result;
00237 
00238         vfs_biglock_acquire();
00239 
00240         result = getdevice(path, &path, &startvn);
00241         if (result) {
00242                 vfs_biglock_release();
00243                 return result;
00244         }
00245 
00246         if (strlen(path)==0) {
00247                 /*
00248                  * It does not make sense to use just a device name in
00249                  * a context where "lookparent" is the desired
00250                  * operation.
00251                  */
00252                 result = EINVAL;
00253         }
00254         else {
00255                 result = VOP_LOOKPARENT(startvn, path, retval, buf, buflen);
00256         }
00257 
00258         VOP_DECREF(startvn);
00259 
00260         vfs_biglock_release();
00261         return result;
00262 }
00263 
00264 int
00265 vfs_lookup(char *path, struct vnode **retval)
00266 {
00267         struct vnode *startvn;
00268         int result;
00269 
00270         vfs_biglock_acquire();
00271 
00272         result = getdevice(path, &path, &startvn);
00273         if (result) {
00274                 vfs_biglock_release();
00275                 return result;
00276         }
00277 
00278         if (strlen(path)==0) {
00279                 *retval = startvn;
00280                 vfs_biglock_release();
00281                 return 0;
00282         }
00283 
00284         result = VOP_LOOKUP(startvn, path, retval);
00285 
00286         VOP_DECREF(startvn);
00287         vfs_biglock_release();
00288         return result;
00289 }
 All Data Structures