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