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