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