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