1 /* 2 * Copyright (c) 1989 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 * 7 * @(#)ufs_lookup.c 7.52 (Berkeley) 11/14/92 8 */ 9 10 #include <sys/param.h> 11 #include <sys/namei.h> 12 #include <sys/buf.h> 13 #include <sys/file.h> 14 #include <sys/mount.h> 15 #include <sys/vnode.h> 16 17 #include <ufs/ufs/quota.h> 18 #include <ufs/ufs/inode.h> 19 #include <ufs/ufs/dir.h> 20 #include <ufs/ufs/ufsmount.h> 21 #include <ufs/ufs/ufs_extern.h> 22 23 struct nchstats nchstats; 24 #ifdef DIAGNOSTIC 25 int dirchk = 1; 26 #else 27 int dirchk = 0; 28 #endif 29 30 #define FSFMT(vp) ((vp)->v_mount->mnt_maxsymlinklen <= 0) 31 32 /* 33 * Convert a component of a pathname into a pointer to a locked inode. 34 * This is a very central and rather complicated routine. 35 * If the file system is not maintained in a strict tree hierarchy, 36 * this can result in a deadlock situation (see comments in code below). 37 * 38 * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending 39 * on 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, lookup returns both the target and its parent directory locked. 44 * When creating or renaming and LOCKPARENT is specified, the target may 45 * not be ".". When deleting and LOCKPARENT is specified, the target may 46 * be "."., but the caller must check to ensure it does an vrele and vput 47 * instead of two vputs. 48 * 49 * Overall outline of ufs_lookup: 50 * 51 * check accessibility of directory 52 * look for name in cache, if found, then if at end of path 53 * and deleting or creating, drop it, else return name 54 * search for name in directory, to found or notfound 55 * notfound: 56 * if creating, return locked directory, leaving info on available slots 57 * else return error 58 * found: 59 * if at end of path and deleting, return information to allow delete 60 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target 61 * inode and return info to allow rewrite 62 * if not at end, add name to cache; if at end and neither creating 63 * nor deleting, add name to cache 64 * 65 * NOTE: (LOOKUP | LOCKPARENT) currently returns the parent inode unlocked. 66 */ 67 int 68 ufs_lookup(ap) 69 struct vop_lookup_args /* { 70 struct vnode *a_dvp; 71 struct vnode **a_vpp; 72 struct componentname *a_cnp; 73 } */ *ap; 74 { 75 register struct vnode *vdp; /* vnode for directory being searched */ 76 register struct inode *dp; /* inode for directory being searched */ 77 struct buf *bp; /* a buffer of directory entries */ 78 register struct direct *ep; /* the current directory entry */ 79 int entryoffsetinblock; /* offset of ep in bp's buffer */ 80 enum {NONE, COMPACT, FOUND} slotstatus; 81 doff_t slotoffset; /* offset of area with free space */ 82 int slotsize; /* size of area at slotoffset */ 83 int slotfreespace; /* amount of space free in slot */ 84 int slotneeded; /* size of the entry we're seeking */ 85 int numdirpasses; /* strategy for directory search */ 86 doff_t endsearch; /* offset to end directory search */ 87 doff_t prevoff; /* prev entry dp->i_offset */ 88 struct vnode *pdp; /* saved dp during symlink work */ 89 struct vnode *tdp; /* returned by VFS_VGET */ 90 doff_t enduseful; /* pointer past last used dir slot */ 91 u_long bmask; /* block offset mask */ 92 int lockparent; /* 1 => lockparent flag is set */ 93 int wantparent; /* 1 => wantparent or lockparent flag */ 94 int namlen, error; 95 struct vnode **vpp = ap->a_vpp; 96 struct componentname *cnp = ap->a_cnp; 97 struct ucred *cred = cnp->cn_cred; 98 int flags = cnp->cn_flags; 99 int nameiop = cnp->cn_nameiop; 100 101 bp = NULL; 102 slotoffset = -1; 103 *vpp = NULL; 104 vdp = ap->a_dvp; 105 dp = VTOI(vdp); 106 lockparent = flags & LOCKPARENT; 107 wantparent = flags & (LOCKPARENT|WANTPARENT); 108 109 /* 110 * Check accessiblity of directory. 111 */ 112 if ((dp->i_mode & IFMT) != IFDIR) 113 return (ENOTDIR); 114 if (error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) 115 return (error); 116 117 /* 118 * We now have a segment name to search for, and a directory to search. 119 * 120 * Before tediously performing a linear scan of the directory, 121 * check the name cache to see if the directory/name pair 122 * we are looking for is known already. 123 */ 124 if (error = cache_lookup(vdp, vpp, cnp)) { 125 int vpid; /* capability number of vnode */ 126 127 if (error == ENOENT) 128 return (error); 129 /* 130 * Get the next vnode in the path. 131 * See comment below starting `Step through' for 132 * an explaination of the locking protocol. 133 */ 134 pdp = vdp; 135 dp = VTOI(*vpp); 136 vdp = *vpp; 137 vpid = vdp->v_id; 138 if (pdp == vdp) { /* lookup on "." */ 139 VREF(vdp); 140 error = 0; 141 } else if (flags & ISDOTDOT) { 142 VOP_UNLOCK(pdp); 143 error = vget(vdp); 144 if (!error && lockparent && (flags & ISLASTCN)) 145 error = VOP_LOCK(pdp); 146 } else { 147 error = vget(vdp); 148 if (!lockparent || error || !(flags & ISLASTCN)) 149 VOP_UNLOCK(pdp); 150 } 151 /* 152 * Check that the capability number did not change 153 * while we were waiting for the lock. 154 */ 155 if (!error) { 156 if (vpid == vdp->v_id) 157 return (0); 158 vput(vdp); 159 if (lockparent && pdp != vdp && (flags & ISLASTCN)) 160 VOP_UNLOCK(pdp); 161 } 162 if (error = VOP_LOCK(pdp)) 163 return (error); 164 vdp = pdp; 165 dp = VTOI(pdp); 166 *vpp = NULL; 167 } 168 169 /* 170 * Suppress search for slots unless creating 171 * file and at end of pathname, in which case 172 * we watch for a place to put the new file in 173 * case it doesn't already exist. 174 */ 175 slotstatus = FOUND; 176 slotfreespace = slotsize = slotneeded = 0; 177 if ((nameiop == CREATE || nameiop == RENAME) && 178 (flags & ISLASTCN)) { 179 slotstatus = NONE; 180 slotneeded = (sizeof(struct direct) - MAXNAMLEN + 181 cnp->cn_namelen + 3) &~ 3; 182 } 183 184 /* 185 * If there is cached information on a previous search of 186 * this directory, pick up where we last left off. 187 * We cache only lookups as these are the most common 188 * and have the greatest payoff. Caching CREATE has little 189 * benefit as it usually must search the entire directory 190 * to determine that the entry does not exist. Caching the 191 * location of the last DELETE or RENAME has not reduced 192 * profiling time and hence has been removed in the interest 193 * of simplicity. 194 */ 195 bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; 196 if (nameiop != LOOKUP || dp->i_diroff == 0 || 197 dp->i_diroff > dp->i_size) { 198 entryoffsetinblock = 0; 199 dp->i_offset = 0; 200 numdirpasses = 1; 201 } else { 202 dp->i_offset = dp->i_diroff; 203 if ((entryoffsetinblock = dp->i_offset & bmask) && 204 (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp))) 205 return (error); 206 numdirpasses = 2; 207 nchstats.ncs_2passes++; 208 } 209 prevoff = dp->i_offset; 210 endsearch = roundup(dp->i_size, DIRBLKSIZ); 211 enduseful = 0; 212 213 searchloop: 214 while (dp->i_offset < endsearch) { 215 /* 216 * If offset is on a block boundary, read the next directory 217 * block. Release previous if it exists. 218 */ 219 if ((dp->i_offset & bmask) == 0) { 220 if (bp != NULL) 221 brelse(bp); 222 if (error = 223 VOP_BLKATOFF(vdp, (off_t)dp->i_offset, NULL, &bp)) 224 return (error); 225 entryoffsetinblock = 0; 226 } 227 /* 228 * If still looking for a slot, and at a DIRBLKSIZE 229 * boundary, have to start looking for free space again. 230 */ 231 if (slotstatus == NONE && 232 (entryoffsetinblock & (DIRBLKSIZ - 1)) == 0) { 233 slotoffset = -1; 234 slotfreespace = 0; 235 } 236 /* 237 * Get pointer to next entry. 238 * Full validation checks are slow, so we only check 239 * enough to insure forward progress through the 240 * directory. Complete checks can be run by patching 241 * "dirchk" to be true. 242 */ 243 ep = (struct direct *)(bp->b_un.b_addr + entryoffsetinblock); 244 if (ep->d_reclen == 0 || 245 dirchk && ufs_dirbadentry(vdp, ep, entryoffsetinblock)) { 246 int i; 247 248 ufs_dirbad(dp, dp->i_offset, "mangled entry"); 249 i = DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)); 250 dp->i_offset += i; 251 entryoffsetinblock += i; 252 continue; 253 } 254 255 /* 256 * If an appropriate sized slot has not yet been found, 257 * check to see if one is available. Also accumulate space 258 * in the current block so that we can determine if 259 * compaction is viable. 260 */ 261 if (slotstatus != FOUND) { 262 int size = ep->d_reclen; 263 264 if (ep->d_ino != 0) 265 size -= DIRSIZ(FSFMT(vdp), ep); 266 if (size > 0) { 267 if (size >= slotneeded) { 268 slotstatus = FOUND; 269 slotoffset = dp->i_offset; 270 slotsize = ep->d_reclen; 271 } else if (slotstatus == NONE) { 272 slotfreespace += size; 273 if (slotoffset == -1) 274 slotoffset = dp->i_offset; 275 if (slotfreespace >= slotneeded) { 276 slotstatus = COMPACT; 277 slotsize = dp->i_offset + 278 ep->d_reclen - slotoffset; 279 } 280 } 281 } 282 } 283 284 /* 285 * Check for a name match. 286 */ 287 if (ep->d_ino) { 288 # if (BYTE_ORDER == LITTLE_ENDIAN) 289 if (vdp->v_mount->mnt_maxsymlinklen > 0) 290 namlen = ep->d_namlen; 291 else 292 namlen = ep->d_type; 293 # else 294 namlen = ep->d_namlen; 295 # endif 296 if (namlen == cnp->cn_namelen && 297 !bcmp(cnp->cn_nameptr, ep->d_name, 298 (unsigned)namlen)) { 299 /* 300 * Save directory entry's inode number and 301 * reclen in ndp->ni_ufs area, and release 302 * directory buffer. 303 */ 304 dp->i_ino = ep->d_ino; 305 dp->i_reclen = ep->d_reclen; 306 brelse(bp); 307 goto found; 308 } 309 } 310 prevoff = dp->i_offset; 311 dp->i_offset += ep->d_reclen; 312 entryoffsetinblock += ep->d_reclen; 313 if (ep->d_ino) 314 enduseful = dp->i_offset; 315 } 316 /* notfound: */ 317 /* 318 * If we started in the middle of the directory and failed 319 * to find our target, we must check the beginning as well. 320 */ 321 if (numdirpasses == 2) { 322 numdirpasses--; 323 dp->i_offset = 0; 324 endsearch = dp->i_diroff; 325 goto searchloop; 326 } 327 if (bp != NULL) 328 brelse(bp); 329 /* 330 * If creating, and at end of pathname and current 331 * directory has not been removed, then can consider 332 * allowing file to be created. 333 */ 334 if ((nameiop == CREATE || nameiop == RENAME) && 335 (flags & ISLASTCN) && dp->i_nlink != 0) { 336 /* 337 * Access for write is interpreted as allowing 338 * creation of files in the directory. 339 */ 340 if (error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) 341 return (error); 342 /* 343 * Return an indication of where the new directory 344 * entry should be put. If we didn't find a slot, 345 * then set dp->i_count to 0 indicating 346 * that the new slot belongs at the end of the 347 * directory. If we found a slot, then the new entry 348 * can be put in the range from dp->i_offset to 349 * dp->i_offset + dp->i_count. 350 */ 351 if (slotstatus == NONE) { 352 dp->i_offset = roundup(dp->i_size, DIRBLKSIZ); 353 dp->i_count = 0; 354 enduseful = dp->i_offset; 355 } else { 356 dp->i_offset = slotoffset; 357 dp->i_count = slotsize; 358 if (enduseful < slotoffset + slotsize) 359 enduseful = slotoffset + slotsize; 360 } 361 dp->i_endoff = roundup(enduseful, DIRBLKSIZ); 362 dp->i_flag |= IUPD|ICHG; 363 /* 364 * We return with the directory locked, so that 365 * the parameters we set up above will still be 366 * valid if we actually decide to do a direnter(). 367 * We return ni_vp == NULL to indicate that the entry 368 * does not currently exist; we leave a pointer to 369 * the (locked) directory inode in ndp->ni_dvp. 370 * The pathname buffer is saved so that the name 371 * can be obtained later. 372 * 373 * NB - if the directory is unlocked, then this 374 * information cannot be used. 375 */ 376 cnp->cn_flags |= SAVENAME; 377 if (!lockparent) 378 VOP_UNLOCK(vdp); 379 return (EJUSTRETURN); 380 } 381 /* 382 * Insert name into cache (as non-existent) if appropriate. 383 */ 384 if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) 385 cache_enter(vdp, *vpp, cnp); 386 return (ENOENT); 387 388 found: 389 if (numdirpasses == 2) 390 nchstats.ncs_pass2++; 391 /* 392 * Check that directory length properly reflects presence 393 * of this entry. 394 */ 395 if (entryoffsetinblock + DIRSIZ(FSFMT(vdp), ep) > dp->i_size) { 396 ufs_dirbad(dp, dp->i_offset, "i_size too small"); 397 dp->i_size = entryoffsetinblock + DIRSIZ(FSFMT(vdp), ep); 398 dp->i_flag |= IUPD|ICHG; 399 } 400 401 /* 402 * Found component in pathname. 403 * If the final component of path name, save information 404 * in the cache as to where the entry was found. 405 */ 406 if ((flags & ISLASTCN) && nameiop == LOOKUP) 407 dp->i_diroff = dp->i_offset &~ (DIRBLKSIZ - 1); 408 409 /* 410 * If deleting, and at end of pathname, return 411 * parameters which can be used to remove file. 412 * If the wantparent flag isn't set, we return only 413 * the directory (in ndp->ni_dvp), otherwise we go 414 * on and lock the inode, being careful with ".". 415 */ 416 if (nameiop == DELETE && (flags & ISLASTCN)) { 417 /* 418 * Write access to directory required to delete files. 419 */ 420 if (error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) 421 return (error); 422 /* 423 * Return pointer to current entry in dp->i_offset, 424 * and distance past previous entry (if there 425 * is a previous entry in this block) in dp->i_count. 426 * Save directory inode pointer in ndp->ni_dvp for dirremove(). 427 */ 428 if ((dp->i_offset & (DIRBLKSIZ - 1)) == 0) 429 dp->i_count = 0; 430 else 431 dp->i_count = dp->i_offset - prevoff; 432 if (dp->i_number == dp->i_ino) { 433 VREF(vdp); 434 *vpp = vdp; 435 return (0); 436 } 437 if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) 438 return (error); 439 /* 440 * If directory is "sticky", then user must own 441 * the directory, or the file in it, else she 442 * may not delete it (unless she's root). This 443 * implements append-only directories. 444 */ 445 if ((dp->i_mode & ISVTX) && 446 cred->cr_uid != 0 && 447 cred->cr_uid != dp->i_uid && 448 VTOI(tdp)->i_uid != cred->cr_uid) { 449 vput(tdp); 450 return (EPERM); 451 } 452 *vpp = tdp; 453 if (!lockparent) 454 VOP_UNLOCK(vdp); 455 return (0); 456 } 457 458 /* 459 * If rewriting (RENAME), return the inode and the 460 * information required to rewrite the present directory 461 * Must get inode of directory entry to verify it's a 462 * regular file, or empty directory. 463 */ 464 if (nameiop == RENAME && wantparent && 465 (flags & ISLASTCN)) { 466 if (error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) 467 return (error); 468 /* 469 * Careful about locking second inode. 470 * This can only occur if the target is ".". 471 */ 472 if (dp->i_number == dp->i_ino) 473 return (EISDIR); 474 if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) 475 return (error); 476 *vpp = tdp; 477 cnp->cn_flags |= SAVENAME; 478 if (!lockparent) 479 VOP_UNLOCK(vdp); 480 return (0); 481 } 482 483 /* 484 * Step through the translation in the name. We do not `vput' the 485 * directory because we may need it again if a symbolic link 486 * is relative to the current directory. Instead we save it 487 * unlocked as "pdp". We must get the target inode before unlocking 488 * the directory to insure that the inode will not be removed 489 * before we get it. We prevent deadlock by always fetching 490 * inodes from the root, moving down the directory tree. Thus 491 * when following backward pointers ".." we must unlock the 492 * parent directory before getting the requested directory. 493 * There is a potential race condition here if both the current 494 * and parent directories are removed before the `iget' for the 495 * inode associated with ".." returns. We hope that this occurs 496 * infrequently since we cannot avoid this race condition without 497 * implementing a sophisticated deadlock detection algorithm. 498 * Note also that this simple deadlock detection scheme will not 499 * work if the file system has any hard links other than ".." 500 * that point backwards in the directory structure. 501 */ 502 pdp = vdp; 503 if (flags & ISDOTDOT) { 504 VOP_UNLOCK(pdp); /* race to get the inode */ 505 if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) { 506 VOP_LOCK(pdp); 507 return (error); 508 } 509 if (lockparent && (flags & ISLASTCN) && 510 (error = VOP_LOCK(pdp))) { 511 vput(tdp); 512 return (error); 513 } 514 *vpp = tdp; 515 } else if (dp->i_number == dp->i_ino) { 516 VREF(vdp); /* we want ourself, ie "." */ 517 *vpp = vdp; 518 } else { 519 if (error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) 520 return (error); 521 if (!lockparent || !(flags & ISLASTCN)) 522 VOP_UNLOCK(pdp); 523 *vpp = tdp; 524 } 525 526 /* 527 * Insert name into cache if appropriate. 528 */ 529 if (cnp->cn_flags & MAKEENTRY) 530 cache_enter(vdp, *vpp, cnp); 531 return (0); 532 } 533 534 void 535 ufs_dirbad(ip, offset, how) 536 struct inode *ip; 537 doff_t offset; 538 char *how; 539 { 540 struct mount *mp; 541 542 mp = ITOV(ip)->v_mount; 543 (void)printf("%s: bad dir ino %d at offset %d: %s\n", 544 mp->mnt_stat.f_mntonname, ip->i_number, offset, how); 545 if ((mp->mnt_stat.f_flags & MNT_RDONLY) == 0) 546 panic("bad dir"); 547 } 548 549 /* 550 * Do consistency checking on a directory entry: 551 * record length must be multiple of 4 552 * entry must fit in rest of its DIRBLKSIZ block 553 * record must be large enough to contain entry 554 * name is not longer than MAXNAMLEN 555 * name must be as long as advertised, and null terminated 556 */ 557 int 558 ufs_dirbadentry(dp, ep, entryoffsetinblock) 559 struct vnode *dp; 560 register struct direct *ep; 561 int entryoffsetinblock; 562 { 563 register int i; 564 int namlen; 565 566 # if (BYTE_ORDER == LITTLE_ENDIAN) 567 if (dp->v_mount->mnt_maxsymlinklen > 0) 568 namlen = ep->d_namlen; 569 else 570 namlen = ep->d_type; 571 # else 572 namlen = ep->d_namlen; 573 # endif 574 if ((ep->d_reclen & 0x3) != 0 || 575 ep->d_reclen > DIRBLKSIZ - (entryoffsetinblock & (DIRBLKSIZ - 1)) || 576 ep->d_reclen < DIRSIZ(FSFMT(dp), ep) || namlen > MAXNAMLEN) { 577 /*return (1); */ 578 printf("First bad\n"); 579 goto bad; 580 } 581 for (i = 0; i < namlen; i++) 582 if (ep->d_name[i] == '\0') { 583 /*return (1); */ 584 printf("Second bad\n"); 585 goto bad; 586 } 587 if (ep->d_name[i]) 588 goto bad; 589 return (ep->d_name[i]); 590 bad: 591 return(1); 592 } 593 594 /* 595 * Write a directory entry after a call to namei, using the parameters 596 * that it left in nameidata. The argument ip is the inode which the new 597 * directory entry will refer to. Dvp is a pointer to the directory to 598 * be written, which was left locked by namei. Remaining parameters 599 * (dp->i_offset, dp->i_count) indicate how the space for the new 600 * entry is to be obtained. 601 */ 602 int 603 ufs_direnter(ip, dvp, cnp) 604 struct inode *ip; 605 struct vnode *dvp; 606 register struct componentname *cnp; 607 { 608 register struct direct *ep, *nep; 609 register struct inode *dp; 610 struct buf *bp; 611 struct direct newdir; 612 struct iovec aiov; 613 struct uio auio; 614 u_int dsize; 615 int error, loc, newentrysize, spacefree; 616 char *dirbuf; 617 618 #ifdef DIAGNOSTIC 619 if ((cnp->cn_flags & SAVENAME) == 0) 620 panic("direnter: missing name"); 621 #endif 622 dp = VTOI(dvp); 623 newdir.d_ino = ip->i_number; 624 newdir.d_namlen = cnp->cn_namelen; 625 bcopy(cnp->cn_nameptr, newdir.d_name, (unsigned)cnp->cn_namelen + 1); 626 if (dvp->v_mount->mnt_maxsymlinklen > 0) 627 newdir.d_type = IFTODT(ip->i_mode); 628 else { 629 newdir.d_type = 0; 630 # if (BYTE_ORDER == LITTLE_ENDIAN) 631 { u_char tmp = newdir.d_namlen; 632 newdir.d_namlen = newdir.d_type; 633 newdir.d_type = tmp; } 634 # endif 635 } 636 newentrysize = DIRSIZ(FSFMT(dvp), &newdir); 637 if (dp->i_count == 0) { 638 /* 639 * If dp->i_count is 0, then namei could find no 640 * space in the directory. Here, dp->i_offset will 641 * be on a directory block boundary and we will write the 642 * new entry into a fresh block. 643 */ 644 if (dp->i_offset & (DIRBLKSIZ - 1)) 645 panic("wdir: newblk"); 646 auio.uio_offset = dp->i_offset; 647 newdir.d_reclen = DIRBLKSIZ; 648 auio.uio_resid = newentrysize; 649 aiov.iov_len = newentrysize; 650 aiov.iov_base = (caddr_t)&newdir; 651 auio.uio_iov = &aiov; 652 auio.uio_iovcnt = 1; 653 auio.uio_rw = UIO_WRITE; 654 auio.uio_segflg = UIO_SYSSPACE; 655 auio.uio_procp = (struct proc *)0; 656 error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred); 657 if (DIRBLKSIZ > 658 VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) 659 /* XXX should grow with balloc() */ 660 panic("ufs_direnter: frag size"); 661 else if (!error) { 662 dp->i_size = roundup(dp->i_size, DIRBLKSIZ); 663 dp->i_flag |= ICHG; 664 } 665 return (error); 666 } 667 668 /* 669 * If dp->i_count is non-zero, then namei found space 670 * for the new entry in the range dp->i_offset to 671 * dp->i_offset + dp->i_count in the directory. 672 * To use this space, we may have to compact the entries located 673 * there, by copying them together towards the beginning of the 674 * block, leaving the free space in one usable chunk at the end. 675 */ 676 677 /* 678 * Increase size of directory if entry eats into new space. 679 * This should never push the size past a new multiple of 680 * DIRBLKSIZE. 681 * 682 * N.B. - THIS IS AN ARTIFACT OF 4.2 AND SHOULD NEVER HAPPEN. 683 */ 684 if (dp->i_offset + dp->i_count > dp->i_size) 685 dp->i_size = dp->i_offset + dp->i_count; 686 /* 687 * Get the block containing the space for the new directory entry. 688 */ 689 if (error = VOP_BLKATOFF(dvp, (off_t)dp->i_offset, &dirbuf, &bp)) 690 return (error); 691 /* 692 * Find space for the new entry. In the simple case, the entry at 693 * offset base will have the space. If it does not, then namei 694 * arranged that compacting the region dp->i_offset to 695 * dp->i_offset + dp->i_count would yield the 696 * space. 697 */ 698 ep = (struct direct *)dirbuf; 699 dsize = DIRSIZ(FSFMT(dvp), ep); 700 spacefree = ep->d_reclen - dsize; 701 for (loc = ep->d_reclen; loc < dp->i_count; ) { 702 nep = (struct direct *)(dirbuf + loc); 703 if (ep->d_ino) { 704 /* trim the existing slot */ 705 ep->d_reclen = dsize; 706 ep = (struct direct *)((char *)ep + dsize); 707 } else { 708 /* overwrite; nothing there; header is ours */ 709 spacefree += dsize; 710 } 711 dsize = DIRSIZ(FSFMT(dvp), nep); 712 spacefree += nep->d_reclen - dsize; 713 loc += nep->d_reclen; 714 bcopy((caddr_t)nep, (caddr_t)ep, dsize); 715 } 716 /* 717 * Update the pointer fields in the previous entry (if any), 718 * copy in the new entry, and write out the block. 719 */ 720 if (ep->d_ino == 0) { 721 if (spacefree + dsize < newentrysize) 722 panic("wdir: compact1"); 723 newdir.d_reclen = spacefree + dsize; 724 } else { 725 if (spacefree < newentrysize) 726 panic("wdir: compact2"); 727 newdir.d_reclen = spacefree; 728 ep->d_reclen = dsize; 729 ep = (struct direct *)((char *)ep + dsize); 730 } 731 bcopy((caddr_t)&newdir, (caddr_t)ep, (u_int)newentrysize); 732 error = VOP_BWRITE(bp); 733 dp->i_flag |= IUPD|ICHG; 734 if (!error && dp->i_endoff && dp->i_endoff < dp->i_size) 735 error = VOP_TRUNCATE(dvp, (off_t)dp->i_endoff, IO_SYNC, 736 cnp->cn_cred, cnp->cn_proc); 737 return (error); 738 } 739 740 /* 741 * Remove a directory entry after a call to namei, using 742 * the parameters which it left in nameidata. The entry 743 * dp->i_offset contains the offset into the directory of the 744 * entry to be eliminated. The dp->i_count field contains the 745 * size of the previous record in the directory. If this 746 * is 0, the first entry is being deleted, so we need only 747 * zero the inode number to mark the entry as free. If the 748 * entry is not the first in the directory, we must reclaim 749 * the space of the now empty record by adding the record size 750 * to the size of the previous entry. 751 */ 752 int 753 ufs_dirremove(dvp, cnp) 754 struct vnode *dvp; 755 struct componentname *cnp; 756 { 757 register struct inode *dp; 758 struct direct *ep; 759 struct buf *bp; 760 int error; 761 762 dp = VTOI(dvp); 763 if (dp->i_count == 0) { 764 /* 765 * First entry in block: set d_ino to zero. 766 */ 767 if (error = 768 VOP_BLKATOFF(dvp, (off_t)dp->i_offset, (char **)&ep, &bp)) 769 return (error); 770 ep->d_ino = 0; 771 error = VOP_BWRITE(bp); 772 dp->i_flag |= IUPD|ICHG; 773 return (error); 774 } 775 /* 776 * Collapse new free space into previous entry. 777 */ 778 if (error = VOP_BLKATOFF(dvp, (off_t)(dp->i_offset - dp->i_count), 779 (char **)&ep, &bp)) 780 return (error); 781 ep->d_reclen += dp->i_reclen; 782 error = VOP_BWRITE(bp); 783 dp->i_flag |= IUPD|ICHG; 784 return (error); 785 } 786 787 /* 788 * Rewrite an existing directory entry to point at the inode 789 * supplied. The parameters describing the directory entry are 790 * set up by a call to namei. 791 */ 792 int 793 ufs_dirrewrite(dp, ip, cnp) 794 struct inode *dp, *ip; 795 struct componentname *cnp; 796 { 797 struct buf *bp; 798 struct direct *ep; 799 struct vnode *vdp = ITOV(dp); 800 int error; 801 802 if (error = VOP_BLKATOFF(vdp, (off_t)dp->i_offset, (char **)&ep, &bp)) 803 return (error); 804 ep->d_ino = ip->i_number; 805 if (vdp->v_mount->mnt_maxsymlinklen > 0) 806 ep->d_type = IFTODT(ip->i_mode); 807 error = VOP_BWRITE(bp); 808 dp->i_flag |= IUPD|ICHG; 809 return (error); 810 } 811 812 /* 813 * Check if a directory is empty or not. 814 * Inode supplied must be locked. 815 * 816 * Using a struct dirtemplate here is not precisely 817 * what we want, but better than using a struct direct. 818 * 819 * NB: does not handle corrupted directories. 820 */ 821 int 822 ufs_dirempty(ip, parentino, cred) 823 register struct inode *ip; 824 ino_t parentino; 825 struct ucred *cred; 826 { 827 register off_t off; 828 struct dirtemplate dbuf; 829 register struct direct *dp = (struct direct *)&dbuf; 830 int error, count, namlen; 831 #define MINDIRSIZ (sizeof (struct dirtemplate) / 2) 832 833 for (off = 0; off < ip->i_size; off += dp->d_reclen) { 834 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off, 835 UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0); 836 /* 837 * Since we read MINDIRSIZ, residual must 838 * be 0 unless we're at end of file. 839 */ 840 if (error || count != 0) 841 return (0); 842 /* avoid infinite loops */ 843 if (dp->d_reclen == 0) 844 return (0); 845 /* skip empty entries */ 846 if (dp->d_ino == 0) 847 continue; 848 /* accept only "." and ".." */ 849 # if (BYTE_ORDER == LITTLE_ENDIAN) 850 if (ITOV(ip)->v_mount->mnt_maxsymlinklen > 0) 851 namlen = dp->d_namlen; 852 else 853 namlen = dp->d_type; 854 # else 855 namlen = dp->d_namlen; 856 # endif 857 if (namlen > 2) 858 return (0); 859 if (dp->d_name[0] != '.') 860 return (0); 861 /* 862 * At this point namlen must be 1 or 2. 863 * 1 implies ".", 2 implies ".." if second 864 * char is also "." 865 */ 866 if (namlen == 1) 867 continue; 868 if (dp->d_name[1] == '.' && dp->d_ino == parentino) 869 continue; 870 return (0); 871 } 872 return (1); 873 } 874 875 /* 876 * Check if source directory is in the path of the target directory. 877 * Target is supplied locked, source is unlocked. 878 * The target is always vput before returning. 879 */ 880 int 881 ufs_checkpath(source, target, cred) 882 struct inode *source, *target; 883 struct ucred *cred; 884 { 885 struct vnode *vp; 886 int error, rootino, namlen; 887 struct dirtemplate dirbuf; 888 889 vp = ITOV(target); 890 if (target->i_number == source->i_number) { 891 error = EEXIST; 892 goto out; 893 } 894 rootino = ROOTINO; 895 error = 0; 896 if (target->i_number == rootino) 897 goto out; 898 899 for (;;) { 900 if (vp->v_type != VDIR) { 901 error = ENOTDIR; 902 break; 903 } 904 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, 905 sizeof (struct dirtemplate), (off_t)0, UIO_SYSSPACE, 906 IO_NODELOCKED, cred, (int *)0, (struct proc *)0); 907 if (error != 0) 908 break; 909 # if (BYTE_ORDER == LITTLE_ENDIAN) 910 if (vp->v_mount->mnt_maxsymlinklen > 0) 911 namlen = dirbuf.dotdot_namlen; 912 else 913 namlen = dirbuf.dotdot_type; 914 # else 915 namlen = dirbuf.dotdot_namlen; 916 # endif 917 if (namlen != 2 || 918 dirbuf.dotdot_name[0] != '.' || 919 dirbuf.dotdot_name[1] != '.') { 920 error = ENOTDIR; 921 break; 922 } 923 if (dirbuf.dotdot_ino == source->i_number) { 924 error = EINVAL; 925 break; 926 } 927 if (dirbuf.dotdot_ino == rootino) 928 break; 929 vput(vp); 930 if (error = VFS_VGET(vp->v_mount, dirbuf.dotdot_ino, &vp)) { 931 vp = NULL; 932 break; 933 } 934 } 935 936 out: 937 if (error == ENOTDIR) 938 printf("checkpath: .. not a directory\n"); 939 if (vp != NULL) 940 vput(vp); 941 return (error); 942 } 943