1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms are permitted 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 * 17 * @(#)vfs_lookup.c 7.21 (Berkeley) 05/04/90 18 */ 19 20 #include "param.h" 21 #include "time.h" 22 #include "namei.h" 23 #include "vnode.h" 24 #include "mount.h" 25 #include "errno.h" 26 #include "malloc.h" 27 28 #ifdef KTRACE 29 #include "user.h" 30 #include "proc.h" 31 #include "ktrace.h" 32 #endif 33 34 /* 35 * Convert a pathname into a pointer to a locked inode. 36 * This is a very central and rather complicated routine. 37 * 38 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 39 * whether the name is to be looked up, created, renamed, or deleted. 40 * When CREATE, RENAME, or DELETE is specified, information usable in 41 * creating, renaming, or deleting a directory entry may be calculated. 42 * If flag has LOCKPARENT or'ed into it and the target of the pathname 43 * exists, namei returns both the target and its parent directory locked. 44 * When creating or renaming and LOCKPARENT is specified, the target may not 45 * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 46 * 47 * The FOLLOW flag is set when symbolic links are to be followed 48 * when they occur at the end of the name translation process. 49 * Symbolic links are always followed for all other pathname 50 * components other than the last. 51 * 52 * The segflg defines whether the name is to be copied from user 53 * space or kernel space. 54 * 55 * Overall outline of namei: 56 * 57 * copy in name 58 * get starting directory 59 * dirloop: 60 * copy next component of name to ndp->ni_dent 61 * handle degenerate case where name is null string 62 * if .. and on mounted filesys, find parent 63 * call lookup routine for next component name 64 * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 65 * component vnode returned in ni_vp (if it exists), locked. 66 * if symbolic link, massage name in buffer and continue at dirloop 67 * if result inode is mounted on, find mounted on vnode 68 * if more components of name, do next level at dirloop 69 * return the answer in ni_vp as locked vnode; 70 * if LOCKPARENT set, return locked parent in ni_dvp 71 * 72 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked. 73 */ 74 namei(ndp) 75 register struct nameidata *ndp; 76 { 77 register char *cp; /* pointer into pathname argument */ 78 register struct vnode *dp = 0; /* the directory we are searching */ 79 register int i; /* Temp counter */ 80 struct vnode *tdp; /* saved dp */ 81 struct mount *mp; /* mount table entry */ 82 int docache; /* == 0 do not cache last component */ 83 int flag; /* LOOKUP, CREATE, RENAME or DELETE */ 84 int wantparent; /* 1 => wantparent or lockparent flag */ 85 int lockparent; /* 1 => lockparent flag */ 86 int getbuf; /* 1 => Malloc a pathname buffer */ 87 int rdonly; /* mounted read-only flag bit(s) */ 88 int error = 0; 89 90 /* 91 * Setup: break out flag bits into variables. 92 */ 93 ndp->ni_dvp = NULL; 94 flag = ndp->ni_nameiop & OPFLAG; 95 wantparent = ndp->ni_nameiop & (LOCKPARENT|WANTPARENT); 96 lockparent = ndp->ni_nameiop & LOCKPARENT; 97 docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; 98 getbuf = (ndp->ni_nameiop & HASBUF) ^ HASBUF; 99 if (flag == DELETE || wantparent) 100 docache = 0; 101 rdonly = MNT_RDONLY; 102 if (ndp->ni_nameiop & REMOTE) 103 rdonly |= MNT_EXRDONLY; 104 /* 105 * Get a buffer for the name to be translated, and copy the 106 * name into the buffer. 107 */ 108 if (getbuf) { 109 MALLOC(ndp->ni_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 110 if (ndp->ni_segflg == UIO_SYSSPACE) 111 error = copystr(ndp->ni_dirp, ndp->ni_pnbuf, 112 MAXPATHLEN, &ndp->ni_pathlen); 113 else 114 error = copyinstr(ndp->ni_dirp, ndp->ni_pnbuf, 115 MAXPATHLEN, &ndp->ni_pathlen); 116 if (error) { 117 free(ndp->ni_pnbuf, M_NAMEI); 118 ndp->ni_vp = NULL; 119 return (error); 120 } 121 ndp->ni_ptr = ndp->ni_pnbuf; 122 } 123 ndp->ni_loopcnt = 0; 124 dp = ndp->ni_cdir; 125 VREF(dp); 126 #ifdef KTRACE 127 if (KTRPOINT(u.u_procp, KTR_NAMEI)) 128 ktrnamei(u.u_procp->p_tracep, ndp->ni_pnbuf); 129 #endif 130 131 start: 132 /* 133 * Get starting directory. 134 * Done at start of translation and after symbolic link. 135 */ 136 if (*ndp->ni_ptr == '/') { 137 vrele(dp); 138 while (*ndp->ni_ptr == '/') { 139 ndp->ni_ptr++; 140 ndp->ni_pathlen--; 141 } 142 if ((dp = ndp->ni_rdir) == NULL) 143 dp = rootdir; 144 VREF(dp); 145 } 146 VOP_LOCK(dp); 147 ndp->ni_endoff = 0; 148 149 /* 150 * We come to dirloop to search a new directory. 151 */ 152 dirloop: 153 /* 154 * Copy next component of name to ndp->ni_dent. 155 * XXX kern_exec looks at d_name 156 * ??? The ni_hash value may be useful for vfs_cache 157 * XXX There must be the last component of the filename left 158 * somewhere accessible via. ndp for NFS (and any other stateless file 159 * systems) in case they are doing a CREATE. The "Towards a..." noted 160 * that ni_ptr would be left pointing to the last component, but since 161 * the ni_pnbuf gets free'd, that is not a good idea. 162 */ 163 if (getbuf) { 164 ndp->ni_hash = 0; 165 for (cp = ndp->ni_ptr, i = 0; *cp != 0 && *cp != '/'; cp++) { 166 if (i >= MAXNAMLEN) { 167 error = ENAMETOOLONG; 168 goto bad; 169 } 170 if (*cp & 0200) 171 if ((*cp&0377) == ('/'|0200) || 172 flag != DELETE) { 173 error = EINVAL; 174 goto bad; 175 } 176 ndp->ni_dent.d_name[i++] = *cp; 177 ndp->ni_hash += (unsigned char)*cp * i; 178 } 179 ndp->ni_namelen = i; 180 ndp->ni_dent.d_namlen = i; 181 ndp->ni_dent.d_name[i] = '\0'; 182 ndp->ni_pathlen -= i; 183 ndp->ni_next = cp; 184 #ifdef NAMEI_DIAGNOSTIC 185 printf("{%s}: ", ndp->ni_dent.d_name); 186 #endif 187 } 188 cp = ndp->ni_next; 189 ndp->ni_makeentry = 1; 190 if (*cp == '\0' && docache == 0) 191 ndp->ni_makeentry = 0; 192 ndp->ni_isdotdot = (ndp->ni_namelen == 2 && 193 ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.'); 194 195 /* 196 * Check for degenerate name (e.g. / or "") 197 * which is a way of talking about a directory, 198 * e.g. like "/." or ".". 199 */ 200 if (ndp->ni_ptr[0] == '\0') { 201 if (flag != LOOKUP || wantparent) { 202 error = EISDIR; 203 goto bad; 204 } 205 if (getbuf) 206 free(ndp->ni_pnbuf, M_NAMEI); 207 if (!(ndp->ni_nameiop & LOCKLEAF)) 208 VOP_UNLOCK(dp); 209 ndp->ni_vp = dp; 210 return (0); 211 } 212 213 /* 214 * Handle "..": two special cases. 215 * 1. If at root directory (e.g. after chroot) 216 * then ignore it so can't get out. 217 * 2. If this vnode is the root of a mounted 218 * file system, then replace it with the 219 * vnode which was mounted on so we take the 220 * .. in the other file system. 221 */ 222 if (ndp->ni_isdotdot) { 223 for (;;) { 224 if (dp == ndp->ni_rdir || dp == rootdir) { 225 ndp->ni_dvp = dp; 226 ndp->ni_vp = dp; 227 VREF(dp); 228 goto nextname; 229 } 230 if ((dp->v_flag & VROOT) == 0 || 231 (ndp->ni_nameiop & NOCROSSMOUNT)) 232 break; 233 tdp = dp; 234 dp = dp->v_mount->mnt_vnodecovered; 235 vput(tdp); 236 VREF(dp); 237 VOP_LOCK(dp); 238 } 239 } 240 241 /* 242 * We now have a segment name to search for, and a directory to search. 243 */ 244 if (error = VOP_LOOKUP(dp, ndp)) { 245 if (ndp->ni_vp != NULL) 246 panic("leaf should be empty"); 247 #ifdef NAMEI_DIAGNOSTIC 248 printf("not found\n"); 249 #endif 250 if (flag == LOOKUP || flag == DELETE || 251 error != ENOENT || *cp != 0) 252 goto bad; 253 /* 254 * If creating and at end of pathname, then can consider 255 * allowing file to be created. 256 */ 257 if (ndp->ni_dvp->v_mount->mnt_flag & rdonly) { 258 error = EROFS; 259 goto bad; 260 } 261 /* 262 * We return with ni_vp NULL to indicate that the entry 263 * doesn't currently exist, leaving a pointer to the 264 * (possibly locked) directory inode in ndp->ni_dvp. 265 */ 266 if (getbuf) 267 FREE(ndp->ni_pnbuf, M_NAMEI); 268 return (0); /* should this be ENOENT? */ 269 } 270 #ifdef NAMEI_DIAGNOSTIC 271 printf("found\n"); 272 #endif 273 274 /* 275 * Check for symbolic link 276 */ 277 dp = ndp->ni_vp; 278 if ((dp->v_type == VLNK) && 279 ((ndp->ni_nameiop & FOLLOW) || *ndp->ni_next == '/')) { 280 struct iovec aiov; 281 struct uio auio; 282 int linklen; 283 284 if (!getbuf) 285 panic("namei: unexpected symlink"); 286 if (++ndp->ni_loopcnt > MAXSYMLINKS) { 287 error = ELOOP; 288 goto bad2; 289 } 290 if (ndp->ni_pathlen > 1) 291 MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 292 else 293 cp = ndp->ni_pnbuf; 294 aiov.iov_base = cp; 295 aiov.iov_len = MAXPATHLEN; 296 auio.uio_iov = &aiov; 297 auio.uio_iovcnt = 1; 298 auio.uio_offset = 0; 299 auio.uio_rw = UIO_READ; 300 auio.uio_segflg = UIO_SYSSPACE; 301 auio.uio_resid = MAXPATHLEN; 302 if (error = VOP_READLINK(dp, &auio, ndp->ni_cred)) { 303 if (ndp->ni_pathlen > 1) 304 free(cp, M_NAMEI); 305 goto bad2; 306 } 307 linklen = MAXPATHLEN - auio.uio_resid; 308 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 309 if (ndp->ni_pathlen > 1) 310 free(cp, M_NAMEI); 311 error = ENAMETOOLONG; 312 goto bad2; 313 } 314 if (ndp->ni_pathlen > 1) { 315 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 316 FREE(ndp->ni_pnbuf, M_NAMEI); 317 ndp->ni_pnbuf = cp; 318 } else 319 ndp->ni_pnbuf[linklen] = '\0'; 320 ndp->ni_ptr = cp; 321 vput(dp); 322 dp = ndp->ni_dvp; 323 if (lockparent && ndp->ni_pathlen == 1) 324 VOP_UNLOCK(dp); 325 ndp->ni_pathlen += linklen; 326 goto start; 327 } 328 329 /* 330 * Check to see if the vnode has been mounted on; 331 * if so find the root of the mounted file system. 332 */ 333 mntloop: 334 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 335 (ndp->ni_nameiop & NOCROSSMOUNT) == 0) { 336 while(mp->mnt_flag & MNT_MLOCK) { 337 mp->mnt_flag |= MNT_MWAIT; 338 sleep((caddr_t)mp, PVFS); 339 goto mntloop; 340 } 341 error = VFS_ROOT(dp->v_mountedhere, &tdp); 342 if (error) 343 goto bad2; 344 vput(dp); 345 ndp->ni_vp = dp = tdp; 346 } 347 348 nextname: 349 /* 350 * Not a symbolic link. If more pathname, 351 * continue at next component, else return. 352 */ 353 ndp->ni_ptr = ndp->ni_next; 354 if (*ndp->ni_ptr == '/') { 355 while (*ndp->ni_ptr == '/') { 356 ndp->ni_ptr++; 357 ndp->ni_pathlen--; 358 } 359 vrele(ndp->ni_dvp); 360 goto dirloop; 361 } 362 /* 363 * Check for read-only file systems. 364 */ 365 if (flag == DELETE || flag == RENAME) { 366 /* 367 * Disallow directory write attempts on read-only 368 * file systems. 369 */ 370 if ((dp->v_mount->mnt_flag & rdonly) || 371 (wantparent && (ndp->ni_dvp->v_mount->mnt_flag & rdonly))) { 372 error = EROFS; 373 goto bad2; 374 } 375 } 376 if (!wantparent) 377 vrele(ndp->ni_dvp); 378 if ((ndp->ni_nameiop & LOCKLEAF) == 0) 379 VOP_UNLOCK(dp); 380 if (getbuf) 381 FREE(ndp->ni_pnbuf, M_NAMEI); 382 return (0); 383 384 bad2: 385 if (lockparent && *ndp->ni_next == '\0') 386 VOP_UNLOCK(ndp->ni_dvp); 387 vrele(ndp->ni_dvp); 388 bad: 389 vput(dp); 390 ndp->ni_vp = NULL; 391 if (getbuf) 392 FREE(ndp->ni_pnbuf, M_NAMEI); 393 return (error); 394 } 395