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