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