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