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