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