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