1 /* 2 * Copyright (c) 1982, 1986, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)vfs_lookup.c 8.2 (Berkeley) 09/05/93 8 */ 9 10 #include <sys/param.h> 11 #include <sys/syslimits.h> 12 #include <sys/time.h> 13 #include <sys/namei.h> 14 #include <sys/vnode.h> 15 #include <sys/mount.h> 16 #include <sys/errno.h> 17 #include <sys/malloc.h> 18 #include <sys/filedesc.h> 19 #include <sys/proc.h> 20 21 #ifdef KTRACE 22 #include <sys/ktrace.h> 23 #endif 24 25 /* 26 * Convert a pathname into a pointer to a locked inode. 27 * 28 * The FOLLOW flag is set when symbolic links are to be followed 29 * when they occur at the end of the name translation process. 30 * Symbolic links are always followed for all other pathname 31 * components other than the last. 32 * 33 * The segflg defines whether the name is to be copied from user 34 * space or kernel space. 35 * 36 * Overall outline of namei: 37 * 38 * copy in name 39 * get starting directory 40 * while (!done && !error) { 41 * call lookup to search path. 42 * if symbolic link, massage name in buffer and continue 43 * } 44 */ 45 int 46 namei(ndp) 47 register struct nameidata *ndp; 48 { 49 register struct filedesc *fdp; /* pointer to file descriptor state */ 50 register char *cp; /* pointer into pathname argument */ 51 register struct vnode *dp; /* the directory we are searching */ 52 struct iovec aiov; /* uio for reading symbolic links */ 53 struct uio auio; 54 int error, linklen; 55 struct componentname *cnp = &ndp->ni_cnd; 56 57 ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_proc->p_ucred; 58 #ifdef DIAGNOSTIC 59 if (!cnp->cn_cred || !cnp->cn_proc) 60 panic ("namei: bad cred/proc"); 61 if (cnp->cn_nameiop & (~OPMASK)) 62 panic ("namei: nameiop contaminated with flags"); 63 if (cnp->cn_flags & OPMASK) 64 panic ("namei: flags contaminated with nameiops"); 65 #endif 66 fdp = cnp->cn_proc->p_fd; 67 68 /* 69 * Get a buffer for the name to be translated, and copy the 70 * name into the buffer. 71 */ 72 if ((cnp->cn_flags & HASBUF) == 0) 73 MALLOC(cnp->cn_pnbuf, caddr_t, MAXPATHLEN, M_NAMEI, M_WAITOK); 74 if (ndp->ni_segflg == UIO_SYSSPACE) 75 error = copystr(ndp->ni_dirp, cnp->cn_pnbuf, 76 MAXPATHLEN, &ndp->ni_pathlen); 77 else 78 error = copyinstr(ndp->ni_dirp, cnp->cn_pnbuf, 79 MAXPATHLEN, &ndp->ni_pathlen); 80 if (error) { 81 free(cnp->cn_pnbuf, M_NAMEI); 82 ndp->ni_vp = NULL; 83 return (error); 84 } 85 ndp->ni_loopcnt = 0; 86 #ifdef KTRACE 87 if (KTRPOINT(cnp->cn_proc, KTR_NAMEI)) 88 ktrnamei(cnp->cn_proc->p_tracep, cnp->cn_pnbuf); 89 #endif 90 91 /* 92 * Get starting point for the translation. 93 */ 94 if ((ndp->ni_rootdir = fdp->fd_rdir) == NULL) 95 ndp->ni_rootdir = rootvnode; 96 dp = fdp->fd_cdir; 97 VREF(dp); 98 for (;;) { 99 /* 100 * Check if root directory should replace current directory. 101 * Done at start of translation and after symbolic link. 102 */ 103 cnp->cn_nameptr = cnp->cn_pnbuf; 104 if (*(cnp->cn_nameptr) == '/') { 105 vrele(dp); 106 while (*(cnp->cn_nameptr) == '/') { 107 cnp->cn_nameptr++; 108 ndp->ni_pathlen--; 109 } 110 dp = ndp->ni_rootdir; 111 VREF(dp); 112 } 113 ndp->ni_startdir = dp; 114 if (error = lookup(ndp)) { 115 FREE(cnp->cn_pnbuf, M_NAMEI); 116 return (error); 117 } 118 /* 119 * Check for symbolic link 120 */ 121 if ((cnp->cn_flags & ISSYMLINK) == 0) { 122 if ((cnp->cn_flags & (SAVENAME | SAVESTART)) == 0) 123 FREE(cnp->cn_pnbuf, M_NAMEI); 124 else 125 cnp->cn_flags |= HASBUF; 126 return (0); 127 } 128 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 129 VOP_UNLOCK(ndp->ni_dvp); 130 if (ndp->ni_loopcnt++ >= MAXSYMLINKS) { 131 error = ELOOP; 132 break; 133 } 134 if (ndp->ni_pathlen > 1) 135 MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 136 else 137 cp = cnp->cn_pnbuf; 138 aiov.iov_base = cp; 139 aiov.iov_len = MAXPATHLEN; 140 auio.uio_iov = &aiov; 141 auio.uio_iovcnt = 1; 142 auio.uio_offset = 0; 143 auio.uio_rw = UIO_READ; 144 auio.uio_segflg = UIO_SYSSPACE; 145 auio.uio_procp = (struct proc *)0; 146 auio.uio_resid = MAXPATHLEN; 147 if (error = VOP_READLINK(ndp->ni_vp, &auio, cnp->cn_cred)) { 148 if (ndp->ni_pathlen > 1) 149 free(cp, M_NAMEI); 150 break; 151 } 152 linklen = MAXPATHLEN - auio.uio_resid; 153 if (linklen + ndp->ni_pathlen >= MAXPATHLEN) { 154 if (ndp->ni_pathlen > 1) 155 free(cp, M_NAMEI); 156 error = ENAMETOOLONG; 157 break; 158 } 159 if (ndp->ni_pathlen > 1) { 160 bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen); 161 FREE(cnp->cn_pnbuf, M_NAMEI); 162 cnp->cn_pnbuf = cp; 163 } else 164 cnp->cn_pnbuf[linklen] = '\0'; 165 ndp->ni_pathlen += linklen; 166 vput(ndp->ni_vp); 167 dp = ndp->ni_dvp; 168 } 169 FREE(cnp->cn_pnbuf, M_NAMEI); 170 vrele(ndp->ni_dvp); 171 vput(ndp->ni_vp); 172 ndp->ni_vp = NULL; 173 return (error); 174 } 175 176 /* 177 * Search a pathname. 178 * This is a very central and rather complicated routine. 179 * 180 * The pathname is pointed to by ni_ptr and is of length ni_pathlen. 181 * The starting directory is taken from ni_startdir. The pathname is 182 * descended until done, or a symbolic link is encountered. The variable 183 * ni_more is clear if the path is completed; it is set to one if a 184 * symbolic link needing interpretation is encountered. 185 * 186 * The flag argument is LOOKUP, CREATE, RENAME, or DELETE depending on 187 * whether the name is to be looked up, created, renamed, or deleted. 188 * When CREATE, RENAME, or DELETE is specified, information usable in 189 * creating, renaming, or deleting a directory entry may be calculated. 190 * If flag has LOCKPARENT or'ed into it, the parent directory is returned 191 * locked. If flag has WANTPARENT or'ed into it, the parent directory is 192 * returned unlocked. Otherwise the parent directory is not returned. If 193 * the target of the pathname exists and LOCKLEAF is or'ed into the flag 194 * the target is returned locked, otherwise it is returned unlocked. 195 * When creating or renaming and LOCKPARENT is specified, the target may not 196 * be ".". When deleting and LOCKPARENT is specified, the target may be ".". 197 * 198 * Overall outline of lookup: 199 * 200 * dirloop: 201 * identify next component of name at ndp->ni_ptr 202 * handle degenerate case where name is null string 203 * if .. and crossing mount points and on mounted filesys, find parent 204 * call VOP_LOOKUP routine for next component name 205 * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 206 * component vnode returned in ni_vp (if it exists), locked. 207 * if result vnode is mounted on and crossing mount points, 208 * find mounted on vnode 209 * if more components of name, do next level at dirloop 210 * return the answer in ni_vp, locked if LOCKLEAF set 211 * if LOCKPARENT set, return locked parent in ni_dvp 212 * if WANTPARENT set, return unlocked parent in ni_dvp 213 */ 214 int 215 lookup(ndp) 216 register struct nameidata *ndp; 217 { 218 register char *cp; /* pointer into pathname argument */ 219 register struct vnode *dp = 0; /* the directory we are searching */ 220 struct vnode *tdp; /* saved dp */ 221 struct mount *mp; /* mount table entry */ 222 int docache; /* == 0 do not cache last component */ 223 int wantparent; /* 1 => wantparent or lockparent flag */ 224 int rdonly; /* lookup read-only flag bit */ 225 int error = 0; 226 struct componentname *cnp = &ndp->ni_cnd; 227 228 /* 229 * Setup: break out flag bits into variables. 230 */ 231 wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 232 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 233 if (cnp->cn_nameiop == DELETE || 234 (wantparent && cnp->cn_nameiop != CREATE)) 235 docache = 0; 236 rdonly = cnp->cn_flags & RDONLY; 237 ndp->ni_dvp = NULL; 238 cnp->cn_flags &= ~ISSYMLINK; 239 dp = ndp->ni_startdir; 240 ndp->ni_startdir = NULLVP; 241 VOP_LOCK(dp); 242 243 dirloop: 244 /* 245 * Search a new directory. 246 * 247 * The cn_hash value is for use by vfs_cache. 248 * The last component of the filename is left accessible via 249 * cnp->cn_nameptr for callers that need the name. Callers needing 250 * the name set the SAVENAME flag. When done, they assume 251 * responsibility for freeing the pathname buffer. 252 */ 253 cnp->cn_consume = 0; 254 cnp->cn_hash = 0; 255 for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 256 cnp->cn_hash += (unsigned char)*cp; 257 cnp->cn_namelen = cp - cnp->cn_nameptr; 258 if (cnp->cn_namelen > NAME_MAX) { 259 error = ENAMETOOLONG; 260 goto bad; 261 } 262 #ifdef NAMEI_DIAGNOSTIC 263 { char c = *cp; 264 *cp = '\0'; 265 printf("{%s}: ", cnp->cn_nameptr); 266 *cp = c; } 267 #endif 268 ndp->ni_pathlen -= cnp->cn_namelen; 269 ndp->ni_next = cp; 270 cnp->cn_flags |= MAKEENTRY; 271 if (*cp == '\0' && docache == 0) 272 cnp->cn_flags &= ~MAKEENTRY; 273 if (cnp->cn_namelen == 2 && 274 cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 275 cnp->cn_flags |= ISDOTDOT; 276 else 277 cnp->cn_flags &= ~ISDOTDOT; 278 if (*ndp->ni_next == 0) 279 cnp->cn_flags |= ISLASTCN; 280 else 281 cnp->cn_flags &= ~ISLASTCN; 282 283 284 /* 285 * Check for degenerate name (e.g. / or "") 286 * which is a way of talking about a directory, 287 * e.g. like "/." or ".". 288 */ 289 if (cnp->cn_nameptr[0] == '\0') { 290 if (cnp->cn_nameiop != LOOKUP) { 291 error = EISDIR; 292 goto bad; 293 } 294 if (dp->v_type != VDIR) { 295 error = ENOTDIR; 296 goto bad; 297 } 298 if (wantparent) { 299 ndp->ni_dvp = dp; 300 vref(dp); 301 } 302 ndp->ni_vp = dp; 303 if (!(cnp->cn_flags & (LOCKPARENT | LOCKLEAF))) 304 VOP_UNLOCK(dp); 305 if (cnp->cn_flags & SAVESTART) 306 panic("lookup: SAVESTART"); 307 return (0); 308 } 309 310 /* 311 * Handle "..": two special cases. 312 * 1. If at root directory (e.g. after chroot) 313 * or at absolute root directory 314 * then ignore it so can't get out. 315 * 2. If this vnode is the root of a mounted 316 * filesystem, then replace it with the 317 * vnode which was mounted on so we take the 318 * .. in the other file system. 319 */ 320 if (cnp->cn_flags & ISDOTDOT) { 321 for (;;) { 322 if (dp == ndp->ni_rootdir || dp == rootvnode) { 323 ndp->ni_dvp = dp; 324 ndp->ni_vp = dp; 325 VREF(dp); 326 goto nextname; 327 } 328 if ((dp->v_flag & VROOT) == 0 || 329 (cnp->cn_flags & NOCROSSMOUNT)) 330 break; 331 tdp = dp; 332 dp = dp->v_mount->mnt_vnodecovered; 333 vput(tdp); 334 VREF(dp); 335 VOP_LOCK(dp); 336 } 337 } 338 339 /* 340 * We now have a segment name to search for, and a directory to search. 341 */ 342 unionlookup: 343 ndp->ni_dvp = dp; 344 if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) { 345 #ifdef DIAGNOSTIC 346 if (ndp->ni_vp != NULL) 347 panic("leaf should be empty"); 348 #endif 349 #ifdef NAMEI_DIAGNOSTIC 350 printf("not found\n"); 351 #endif 352 if ((error == ENOENT) && 353 (dp->v_flag & VROOT) && 354 (dp->v_mount->mnt_flag & MNT_UNION)) { 355 tdp = dp; 356 dp = dp->v_mount->mnt_vnodecovered; 357 vput(tdp); 358 VREF(dp); 359 VOP_LOCK(dp); 360 goto unionlookup; 361 } 362 363 if (error != EJUSTRETURN) 364 goto bad; 365 /* 366 * If creating and at end of pathname, then can consider 367 * allowing file to be created. 368 */ 369 if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) { 370 error = EROFS; 371 goto bad; 372 } 373 /* 374 * We return with ni_vp NULL to indicate that the entry 375 * doesn't currently exist, leaving a pointer to the 376 * (possibly locked) directory inode in ndp->ni_dvp. 377 */ 378 if (cnp->cn_flags & SAVESTART) { 379 ndp->ni_startdir = ndp->ni_dvp; 380 VREF(ndp->ni_startdir); 381 } 382 return (0); 383 } 384 #ifdef NAMEI_DIAGNOSTIC 385 printf("found\n"); 386 #endif 387 388 /* 389 * Take into account any additional components consumed by 390 * the underlying filesystem. 391 */ 392 if (cnp->cn_consume > 0) { 393 cnp->cn_nameptr += cnp->cn_consume; 394 ndp->ni_next += cnp->cn_consume; 395 ndp->ni_pathlen -= cnp->cn_consume; 396 cnp->cn_consume = 0; 397 } 398 399 dp = ndp->ni_vp; 400 /* 401 * Check for symbolic link 402 */ 403 if ((dp->v_type == VLNK) && 404 ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) { 405 cnp->cn_flags |= ISSYMLINK; 406 return (0); 407 } 408 409 /* 410 * Check to see if the vnode has been mounted on; 411 * if so find the root of the mounted file system. 412 */ 413 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 414 (cnp->cn_flags & NOCROSSMOUNT) == 0) { 415 if (mp->mnt_flag & MNT_MLOCK) { 416 mp->mnt_flag |= MNT_MWAIT; 417 sleep((caddr_t)mp, PVFS); 418 continue; 419 } 420 if (error = VFS_ROOT(dp->v_mountedhere, &tdp)) 421 goto bad2; 422 vput(dp); 423 ndp->ni_vp = dp = tdp; 424 } 425 426 nextname: 427 /* 428 * Not a symbolic link. If more pathname, 429 * continue at next component, else return. 430 */ 431 if (*ndp->ni_next == '/') { 432 cnp->cn_nameptr = ndp->ni_next; 433 while (*cnp->cn_nameptr == '/') { 434 cnp->cn_nameptr++; 435 ndp->ni_pathlen--; 436 } 437 vrele(ndp->ni_dvp); 438 goto dirloop; 439 } 440 /* 441 * Check for read-only file systems. 442 */ 443 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 444 /* 445 * Disallow directory write attempts on read-only 446 * file systems. 447 */ 448 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 449 (wantparent && 450 (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 451 error = EROFS; 452 goto bad2; 453 } 454 } 455 if (cnp->cn_flags & SAVESTART) { 456 ndp->ni_startdir = ndp->ni_dvp; 457 VREF(ndp->ni_startdir); 458 } 459 if (!wantparent) 460 vrele(ndp->ni_dvp); 461 if ((cnp->cn_flags & LOCKLEAF) == 0) 462 VOP_UNLOCK(dp); 463 return (0); 464 465 bad2: 466 if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') 467 VOP_UNLOCK(ndp->ni_dvp); 468 vrele(ndp->ni_dvp); 469 bad: 470 vput(dp); 471 ndp->ni_vp = NULL; 472 return (error); 473 } 474 475 476