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