1 /* 2 * Copyright (c) 1982, 1986, 1989 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)vfs_lookup.c 7.46 (Berkeley) 01/22/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 = rootdir; 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 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent vnode unlocked. 198 * 199 * Overall outline of lookup: 200 * 201 * dirloop: 202 * identify next component of name at ndp->ni_ptr 203 * handle degenerate case where name is null string 204 * if .. and crossing mount points and on mounted filesys, find parent 205 * call VOP_LOOKUP routine for next component name 206 * directory vnode returned in ni_dvp, unlocked unless LOCKPARENT set 207 * component vnode returned in ni_vp (if it exists), locked. 208 * if result vnode is mounted on and crossing mount points, 209 * find mounted on vnode 210 * if more components of name, do next level at dirloop 211 * return the answer in ni_vp, locked if LOCKLEAF set 212 * if LOCKPARENT set, return locked parent in ni_dvp 213 * if WANTPARENT set, return unlocked parent in ni_dvp 214 */ 215 int 216 lookup(ndp) 217 register struct nameidata *ndp; 218 { 219 register char *cp; /* pointer into pathname argument */ 220 register struct vnode *dp = 0; /* the directory we are searching */ 221 struct vnode *tdp; /* saved dp */ 222 struct mount *mp; /* mount table entry */ 223 int docache; /* == 0 do not cache last component */ 224 int wantparent; /* 1 => wantparent or lockparent flag */ 225 int rdonly; /* lookup read-only flag bit */ 226 int error = 0; 227 struct componentname *cnp = &ndp->ni_cnd; 228 229 /* 230 * Setup: break out flag bits into variables. 231 */ 232 wantparent = cnp->cn_flags & (LOCKPARENT | WANTPARENT); 233 docache = (cnp->cn_flags & NOCACHE) ^ NOCACHE; 234 if (cnp->cn_nameiop == DELETE || 235 (wantparent && cnp->cn_nameiop != CREATE)) 236 docache = 0; 237 rdonly = cnp->cn_flags & RDONLY; 238 ndp->ni_dvp = NULL; 239 cnp->cn_flags &= ~ISSYMLINK; 240 dp = ndp->ni_startdir; 241 ndp->ni_startdir = NULLVP; 242 VOP_LOCK(dp); 243 244 dirloop: 245 /* 246 * Search a new directory. 247 * 248 * The cn_hash value is for use by vfs_cache. 249 * The last component of the filename is left accessible via 250 * cnp->cn_nameptr for callers that need the name. Callers needing 251 * the name set the SAVENAME flag. When done, they assume 252 * responsibility for freeing the pathname buffer. 253 */ 254 cnp->cn_consume = 0; 255 cnp->cn_hash = 0; 256 for (cp = cnp->cn_nameptr; *cp != 0 && *cp != '/'; cp++) 257 cnp->cn_hash += (unsigned char)*cp; 258 cnp->cn_namelen = cp - cnp->cn_nameptr; 259 if (cnp->cn_namelen > NAME_MAX) { 260 error = ENAMETOOLONG; 261 goto bad; 262 } 263 #ifdef NAMEI_DIAGNOSTIC 264 { char c = *cp; 265 *cp = '\0'; 266 printf("{%s}: ", cnp->cn_nameptr); 267 *cp = c; } 268 #endif 269 ndp->ni_pathlen -= cnp->cn_namelen; 270 ndp->ni_next = cp; 271 cnp->cn_flags |= MAKEENTRY; 272 if (*cp == '\0' && docache == 0) 273 cnp->cn_flags &= ~MAKEENTRY; 274 if (cnp->cn_namelen == 2 && 275 cnp->cn_nameptr[1] == '.' && cnp->cn_nameptr[0] == '.') 276 cnp->cn_flags |= ISDOTDOT; 277 else 278 cnp->cn_flags &= ~ISDOTDOT; 279 if (*ndp->ni_next == 0) 280 cnp->cn_flags |= ISLASTCN; 281 else 282 cnp->cn_flags &= ~ISLASTCN; 283 284 285 /* 286 * Check for degenerate name (e.g. / or "") 287 * which is a way of talking about a directory, 288 * e.g. like "/." or ".". 289 */ 290 if (cnp->cn_nameptr[0] == '\0') { 291 if (cnp->cn_nameiop != LOOKUP || wantparent) { 292 error = EISDIR; 293 goto bad; 294 } 295 if (dp->v_type != VDIR) { 296 error = ENOTDIR; 297 goto bad; 298 } 299 if (!(cnp->cn_flags & LOCKLEAF)) 300 VOP_UNLOCK(dp); 301 ndp->ni_vp = dp; 302 if (cnp->cn_flags & SAVESTART) 303 panic("lookup: SAVESTART"); 304 return (0); 305 } 306 307 /* 308 * Handle "..": two special cases. 309 * 1. If at root directory (e.g. after chroot) 310 * or at absolute root directory 311 * then ignore it so can't get out. 312 * 2. If this vnode is the root of a mounted 313 * filesystem, then replace it with the 314 * vnode which was mounted on so we take the 315 * .. in the other file system. 316 */ 317 if (cnp->cn_flags & ISDOTDOT) { 318 for (;;) { 319 if (dp == ndp->ni_rootdir || dp == rootdir) { 320 ndp->ni_dvp = dp; 321 ndp->ni_vp = dp; 322 VREF(dp); 323 goto nextname; 324 } 325 if ((dp->v_flag & VROOT) == 0 || 326 (cnp->cn_flags & NOCROSSMOUNT)) 327 break; 328 tdp = dp; 329 dp = dp->v_mount->mnt_vnodecovered; 330 vput(tdp); 331 VREF(dp); 332 VOP_LOCK(dp); 333 } 334 } 335 336 /* 337 * We now have a segment name to search for, and a directory to search. 338 */ 339 unionlookup: 340 ndp->ni_dvp = dp; 341 if (error = VOP_LOOKUP(dp, &ndp->ni_vp, cnp)) { 342 #ifdef DIAGNOSTIC 343 if (ndp->ni_vp != NULL) 344 panic("leaf should be empty"); 345 #endif 346 #ifdef NAMEI_DIAGNOSTIC 347 printf("not found\n"); 348 #endif 349 if ((error == ENOENT) && 350 (dp->v_flag & VROOT) && 351 (dp->v_mount->mnt_flag & MNT_UNION)) { 352 tdp = dp; 353 dp = dp->v_mount->mnt_vnodecovered; 354 vput(tdp); 355 VREF(dp); 356 VOP_LOCK(dp); 357 goto unionlookup; 358 } 359 360 if (error != EJUSTRETURN) 361 goto bad; 362 /* 363 * If creating and at end of pathname, then can consider 364 * allowing file to be created. 365 */ 366 if (rdonly || (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY)) { 367 error = EROFS; 368 goto bad; 369 } 370 /* 371 * We return with ni_vp NULL to indicate that the entry 372 * doesn't currently exist, leaving a pointer to the 373 * (possibly locked) directory inode in ndp->ni_dvp. 374 */ 375 if (cnp->cn_flags & SAVESTART) { 376 ndp->ni_startdir = ndp->ni_dvp; 377 VREF(ndp->ni_startdir); 378 } 379 return (0); 380 } 381 #ifdef NAMEI_DIAGNOSTIC 382 printf("found\n"); 383 #endif 384 385 /* 386 * Take into account any additional components consumed by 387 * the underlying filesystem. 388 */ 389 if (cnp->cn_consume > 0) { 390 cnp->cn_nameptr += cnp->cn_consume; 391 ndp->ni_next += cnp->cn_consume; 392 ndp->ni_pathlen -= cnp->cn_consume; 393 cnp->cn_consume = 0; 394 } 395 396 dp = ndp->ni_vp; 397 /* 398 * Check for symbolic link 399 */ 400 if ((dp->v_type == VLNK) && 401 ((cnp->cn_flags & FOLLOW) || *ndp->ni_next == '/')) { 402 cnp->cn_flags |= ISSYMLINK; 403 return (0); 404 } 405 406 /* 407 * Check to see if the vnode has been mounted on; 408 * if so find the root of the mounted file system. 409 */ 410 while (dp->v_type == VDIR && (mp = dp->v_mountedhere) && 411 (cnp->cn_flags & NOCROSSMOUNT) == 0) { 412 if (mp->mnt_flag & MNT_MLOCK) { 413 mp->mnt_flag |= MNT_MWAIT; 414 sleep((caddr_t)mp, PVFS); 415 continue; 416 } 417 if (error = VFS_ROOT(dp->v_mountedhere, &tdp)) 418 goto bad2; 419 vput(dp); 420 ndp->ni_vp = dp = tdp; 421 } 422 423 nextname: 424 /* 425 * Not a symbolic link. If more pathname, 426 * continue at next component, else return. 427 */ 428 if (*ndp->ni_next == '/') { 429 cnp->cn_nameptr = ndp->ni_next; 430 while (*cnp->cn_nameptr == '/') { 431 cnp->cn_nameptr++; 432 ndp->ni_pathlen--; 433 } 434 vrele(ndp->ni_dvp); 435 goto dirloop; 436 } 437 /* 438 * Check for read-only file systems. 439 */ 440 if (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME) { 441 /* 442 * Disallow directory write attempts on read-only 443 * file systems. 444 */ 445 if (rdonly || (dp->v_mount->mnt_flag & MNT_RDONLY) || 446 (wantparent && 447 (ndp->ni_dvp->v_mount->mnt_flag & MNT_RDONLY))) { 448 error = EROFS; 449 goto bad2; 450 } 451 } 452 if (cnp->cn_flags & SAVESTART) { 453 ndp->ni_startdir = ndp->ni_dvp; 454 VREF(ndp->ni_startdir); 455 } 456 if (!wantparent) 457 vrele(ndp->ni_dvp); 458 if ((cnp->cn_flags & LOCKLEAF) == 0) 459 VOP_UNLOCK(dp); 460 return (0); 461 462 bad2: 463 if ((cnp->cn_flags & LOCKPARENT) && *ndp->ni_next == '\0') 464 VOP_UNLOCK(ndp->ni_dvp); 465 vrele(ndp->ni_dvp); 466 bad: 467 vput(dp); 468 ndp->ni_vp = NULL; 469 return (error); 470 } 471 472 473