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