ext2fs_lookup.c revision 1.16
1/* $OpenBSD: ext2fs_lookup.c,v 1.16 2003/06/02 23:28:22 millert 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/extattr.h> 62#include <ufs/ufs/quota.h> 63#include <ufs/ufs/inode.h> 64#include <ufs/ufs/ufsmount.h> 65#include <ufs/ufs/ufs_extern.h> 66 67#include <ufs/ext2fs/ext2fs_extern.h> 68#include <ufs/ext2fs/ext2fs_dir.h> 69#include <ufs/ext2fs/ext2fs.h> 70 71extern int dirchk; 72 73static void ext2fs_dirconv2ffs(struct ext2fs_direct *e2dir, 74 struct dirent *ffsdir); 75static int ext2fs_dirbadentry(struct vnode *dp, 76 struct ext2fs_direct *de, 77 int entryoffsetinblock); 78 79/* 80 * the problem that is tackled below is the fact that FFS 81 * includes the terminating zero on disk while EXT2FS doesn't 82 * this implies that we need to introduce some padding. 83 * For instance, a filename "sbin" has normally a reclen 12 84 * in EXT2, but 16 in FFS. 85 * This reminds me of that Pepsi commercial: 'Kid saved a lousy nine cents...' 86 * If it wasn't for that, the complete ufs code for directories would 87 * have worked w/o changes (except for the difference in DIRBLKSIZ) 88 */ 89static void 90ext2fs_dirconv2ffs( e2dir, ffsdir) 91 struct ext2fs_direct *e2dir; 92 struct dirent *ffsdir; 93{ 94 memset(ffsdir, 0, sizeof(struct dirent)); 95 ffsdir->d_fileno = fs2h32(e2dir->e2d_ino); 96 ffsdir->d_namlen = e2dir->e2d_namlen; 97 98 ffsdir->d_type = DT_UNKNOWN; /* don't know more here */ 99#ifdef DIAGNOSTIC 100 /* 101 * XXX Rigth now this can't happen, but if one day 102 * MAXNAMLEN != E2FS_MAXNAMLEN we should handle this more gracefully ! 103 */ 104 if (e2dir->e2d_namlen > MAXNAMLEN) 105 panic("ext2fs: e2dir->e2d_namlen"); 106#endif 107 strncpy(ffsdir->d_name, e2dir->e2d_name, ffsdir->d_namlen); 108 109 /* Godmar thinks: since e2dir->e2d_reclen can be big and means 110 nothing anyway, we compute our own reclen according to what 111 we think is right 112 */ 113 ffsdir->d_reclen = DIRENT_SIZE(ffsdir); 114} 115 116/* 117 * Vnode op for reading directories. 118 * 119 * Convert the on-disk entries to <sys/dirent.h> entries. 120 * the problem is that the conversion will blow up some entries by four bytes, 121 * so it can't be done in place. This is too bad. Right now the conversion is 122 * done entry by entry, the converted entry is sent via uiomove. 123 * 124 * XXX allocate a buffer, convert as many entries as possible, then send 125 * the whole buffer to uiomove 126 */ 127int 128ext2fs_readdir(v) 129 void *v; 130{ 131 struct vop_readdir_args /* { 132 struct vnode *a_vp; 133 struct uio *a_uio; 134 struct ucred *a_cred; 135 int **a_eofflag; 136 off_t **a_cookies; 137 int ncookies; 138 } */ *ap = v; 139 struct uio *uio = ap->a_uio; 140 int error; 141 size_t e2fs_count, readcnt; 142 struct vnode *vp = ap->a_vp; 143 struct m_ext2fs *fs = VTOI(vp)->i_e2fs; 144 145 struct ext2fs_direct *dp; 146 struct dirent dstd; 147 struct uio auio; 148 struct iovec aiov; 149 caddr_t dirbuf; 150 off_t off = uio->uio_offset; 151 u_long *cookies = NULL; 152 int nc = 0, ncookies = 0; 153 int e2d_reclen; 154 155 if (vp->v_type != VDIR) 156 return (ENOTDIR); 157 158 e2fs_count = uio->uio_resid; 159 /* Make sure we don't return partial entries. */ 160 e2fs_count -= (uio->uio_offset + e2fs_count) & (fs->e2fs_bsize -1); 161 if (e2fs_count <= 0) 162 return (EINVAL); 163 164 auio = *uio; 165 auio.uio_iov = &aiov; 166 auio.uio_iovcnt = 1; 167 auio.uio_segflg = UIO_SYSSPACE; 168 aiov.iov_len = e2fs_count; 169 auio.uio_resid = e2fs_count; 170 MALLOC(dirbuf, caddr_t, e2fs_count, M_TEMP, M_WAITOK); 171 if (ap->a_ncookies) { 172 nc = ncookies = e2fs_count / 16; 173 cookies = malloc(sizeof (off_t) * ncookies, M_TEMP, M_WAITOK); 174 *ap->a_cookies = cookies; 175 } 176 memset(dirbuf, 0, e2fs_count); 177 aiov.iov_base = dirbuf; 178 179 error = VOP_READ(ap->a_vp, &auio, 0, ap->a_cred); 180 if (error == 0) { 181 readcnt = e2fs_count - auio.uio_resid; 182 for (dp = (struct ext2fs_direct *)dirbuf; 183 (char *)dp < (char *)dirbuf + readcnt; ) { 184 e2d_reclen = fs2h16(dp->e2d_reclen); 185 if (e2d_reclen == 0) { 186 error = EIO; 187 break; 188 } 189 ext2fs_dirconv2ffs(dp, &dstd); 190 if(dstd.d_reclen > uio->uio_resid) { 191 break; 192 } 193 if ((error = uiomove((caddr_t)&dstd, dstd.d_reclen, uio)) != 0) { 194 break; 195 } 196 off = off + e2d_reclen; 197 if (cookies != NULL) { 198 *cookies++ = off; 199 if (--ncookies <= 0){ 200 break; /* out of cookies */ 201 } 202 } 203 /* advance dp */ 204 dp = (struct ext2fs_direct *) ((char *)dp + e2d_reclen); 205 } 206 /* we need to correct uio_offset */ 207 uio->uio_offset = off; 208 } 209 FREE(dirbuf, M_TEMP); 210 *ap->a_eofflag = VTOI(ap->a_vp)->i_e2fs_size <= uio->uio_offset; 211 if (ap->a_ncookies) { 212 if (error) { 213 free(*ap->a_cookies, M_TEMP); 214 *ap->a_ncookies = 0; 215 *ap->a_cookies = NULL; 216 } else 217 *ap->a_ncookies = nc - ncookies; 218 } 219 return (error); 220} 221 222/* 223 * Convert a component of a pathname into a pointer to a locked inode. 224 * This is a very central and rather complicated routine. 225 * If the file system is not maintained in a strict tree hierarchy, 226 * this can result in a deadlock situation (see comments in code below). 227 * 228 * The cnp->cn_nameiop argument is LOOKUP, CREATE, RENAME, or DELETE depending 229 * on whether the name is to be looked up, created, renamed, or deleted. 230 * When CREATE, RENAME, or DELETE is specified, information usable in 231 * creating, renaming, or deleting a directory entry may be calculated. 232 * If flag has LOCKPARENT or'ed into it and the target of the pathname 233 * exists, lookup returns both the target and its parent directory locked. 234 * When creating or renaming and LOCKPARENT is specified, the target may 235 * not be ".". When deleting and LOCKPARENT is specified, the target may 236 * be "."., but the caller must check to ensure it does an vrele and vput 237 * instead of two vputs. 238 * 239 * Overall outline of ext2fs_lookup: 240 * 241 * check accessibility of directory 242 * look for name in cache, if found, then if at end of path 243 * and deleting or creating, drop it, else return name 244 * search for name in directory, to found or notfound 245 * notfound: 246 * if creating, return locked directory, leaving info on available slots 247 * else return error 248 * found: 249 * if at end of path and deleting, return information to allow delete 250 * if at end of path and rewriting (RENAME and LOCKPARENT), lock target 251 * inode and return info to allow rewrite 252 * if not at end, add name to cache; if at end and neither creating 253 * nor deleting, add name to cache 254 */ 255int 256ext2fs_lookup(v) 257 void *v; 258{ 259 struct vop_lookup_args /* { 260 struct vnode *a_dvp; 261 struct vnode **a_vpp; 262 struct componentname *a_cnp; 263 } */ *ap = v; 264 struct vnode *vdp; /* vnode for directory being searched */ 265 struct inode *dp; /* inode for directory being searched */ 266 struct buf *bp; /* a buffer of directory entries */ 267 struct ext2fs_direct *ep; /* the current directory entry */ 268 int entryoffsetinblock; /* offset of ep in bp's buffer */ 269 enum {NONE, COMPACT, FOUND} slotstatus; 270 doff_t slotoffset; /* offset of area with free space */ 271 int slotsize; /* size of area at slotoffset */ 272 int slotfreespace; /* amount of space free in slot */ 273 int slotneeded; /* size of the entry we're seeking */ 274 int numdirpasses; /* strategy for directory search */ 275 doff_t endsearch; /* offset to end directory search */ 276 doff_t prevoff; /* prev entry dp->i_offset */ 277 struct vnode *pdp; /* saved dp during symlink work */ 278 struct vnode *tdp; /* returned by VFS_VGET */ 279 doff_t enduseful; /* pointer past last used dir slot */ 280 u_long bmask; /* block offset mask */ 281 int lockparent; /* 1 => lockparent flag is set */ 282 int wantparent; /* 1 => wantparent or lockparent flag */ 283 int namlen, error; 284 struct vnode **vpp = ap->a_vpp; 285 struct componentname *cnp = ap->a_cnp; 286 struct ucred *cred = cnp->cn_cred; 287 int flags = cnp->cn_flags; 288 int nameiop = cnp->cn_nameiop; 289 struct proc *p = cnp->cn_proc; 290 int dirblksize = VTOI(ap->a_dvp)->i_e2fs->e2fs_bsize; 291 292 bp = NULL; 293 slotoffset = -1; 294 *vpp = NULL; 295 vdp = ap->a_dvp; 296 dp = VTOI(vdp); 297 lockparent = flags & LOCKPARENT; 298 wantparent = flags & (LOCKPARENT|WANTPARENT); 299 /* 300 * Check accessiblity of directory. 301 */ 302 if ((error = VOP_ACCESS(vdp, VEXEC, cred, cnp->cn_proc)) != 0) 303 return (error); 304 305 if ((flags & ISLASTCN) && (vdp->v_mount->mnt_flag & MNT_RDONLY) && 306 (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME)) 307 return (EROFS); 308 309 /* 310 * We now have a segment name to search for, and a directory to search. 311 * 312 * Before tediously performing a linear scan of the directory, 313 * check the name cache to see if the directory/name pair 314 * we are looking for is known already. 315 */ 316 if ((error = cache_lookup(vdp, vpp, cnp)) >= 0) 317 return (error); 318 319 /* 320 * Suppress search for slots unless creating 321 * file and at end of pathname, in which case 322 * we watch for a place to put the new file in 323 * case it doesn't already exist. 324 */ 325 slotstatus = FOUND; 326 slotfreespace = slotsize = slotneeded = 0; 327 if ((nameiop == CREATE || nameiop == RENAME) && 328 (flags & ISLASTCN)) { 329 slotstatus = NONE; 330 slotneeded = EXT2FS_DIRSIZ(cnp->cn_namelen); 331 } 332 333 /* 334 * If there is cached information on a previous search of 335 * this directory, pick up where we last left off. 336 * We cache only lookups as these are the most common 337 * and have the greatest payoff. Caching CREATE has little 338 * benefit as it usually must search the entire directory 339 * to determine that the entry does not exist. Caching the 340 * location of the last DELETE or RENAME has not reduced 341 * profiling time and hence has been removed in the interest 342 * of simplicity. 343 */ 344 bmask = VFSTOUFS(vdp->v_mount)->um_mountp->mnt_stat.f_iosize - 1; 345 if (nameiop != LOOKUP || dp->i_diroff == 0 || 346 dp->i_diroff > dp->i_e2fs_size) { 347 entryoffsetinblock = 0; 348 dp->i_offset = 0; 349 numdirpasses = 1; 350 } else { 351 dp->i_offset = dp->i_diroff; 352 if ((entryoffsetinblock = dp->i_offset & bmask) && 353 (error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, 354 NULL, &bp))) 355 return (error); 356 numdirpasses = 2; 357 } 358 prevoff = dp->i_offset; 359 endsearch = roundup(dp->i_e2fs_size, dirblksize); 360 enduseful = 0; 361 362searchloop: 363 while (dp->i_offset < endsearch) { 364 /* 365 * If necessary, get the next directory block. 366 */ 367 if ((dp->i_offset & bmask) == 0) { 368 if (bp != NULL) 369 brelse(bp); 370 error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, 371 NULL, &bp); 372 if (error != 0) 373 return (error); 374 entryoffsetinblock = 0; 375 } 376 /* 377 * If still looking for a slot, and at a dirblksize 378 * boundary, have to start looking for free space again. 379 */ 380 if (slotstatus == NONE && 381 (entryoffsetinblock & (dirblksize - 1)) == 0) { 382 slotoffset = -1; 383 slotfreespace = 0; 384 } 385 /* 386 * Get pointer to next entry. 387 * Full validation checks are slow, so we only check 388 * enough to insure forward progress through the 389 * directory. Complete checks can be run by patching 390 * "dirchk" to be true. 391 */ 392 ep = (struct ext2fs_direct *) 393 ((char *)bp->b_data + entryoffsetinblock); 394 if (ep->e2d_reclen == 0 || 395 (dirchk && 396 ext2fs_dirbadentry(vdp, ep, entryoffsetinblock))) { 397 int i; 398 ufs_dirbad(dp, dp->i_offset, "mangled entry"); 399 i = dirblksize - 400 (entryoffsetinblock & (dirblksize - 1)); 401 dp->i_offset += i; 402 entryoffsetinblock += i; 403 continue; 404 } 405 406 /* 407 * If an appropriate sized slot has not yet been found, 408 * check to see if one is available. Also accumulate space 409 * in the current block so that we can determine if 410 * compaction is viable. 411 */ 412 if (slotstatus != FOUND) { 413 int size = fs2h16(ep->e2d_reclen); 414 415 if (ep->e2d_ino != 0) 416 size -= EXT2FS_DIRSIZ(ep->e2d_namlen); 417 if (size > 0) { 418 if (size >= slotneeded) { 419 slotstatus = FOUND; 420 slotoffset = dp->i_offset; 421 slotsize = fs2h16(ep->e2d_reclen); 422 } else if (slotstatus == NONE) { 423 slotfreespace += size; 424 if (slotoffset == -1) 425 slotoffset = dp->i_offset; 426 if (slotfreespace >= slotneeded) { 427 slotstatus = COMPACT; 428 slotsize = dp->i_offset + 429 fs2h16(ep->e2d_reclen) - slotoffset; 430 } 431 } 432 } 433 } 434 435 /* 436 * Check for a name match. 437 */ 438 if (ep->e2d_ino) { 439 namlen = ep->e2d_namlen; 440 if (namlen == cnp->cn_namelen && 441 !memcmp(cnp->cn_nameptr, ep->e2d_name, 442 (unsigned)namlen)) { 443 /* 444 * Save directory entry's inode number and 445 * reclen in ndp->ni_ufs area, and release 446 * directory buffer. 447 */ 448 dp->i_ino = fs2h32(ep->e2d_ino); 449 dp->i_reclen = fs2h16(ep->e2d_reclen); 450 brelse(bp); 451 goto found; 452 } 453 } 454 prevoff = dp->i_offset; 455 dp->i_offset += fs2h16(ep->e2d_reclen); 456 entryoffsetinblock += fs2h16(ep->e2d_reclen); 457 if (ep->e2d_ino) 458 enduseful = dp->i_offset; 459 } 460/* notfound: */ 461 /* 462 * If we started in the middle of the directory and failed 463 * to find our target, we must check the beginning as well. 464 */ 465 if (numdirpasses == 2) { 466 numdirpasses--; 467 dp->i_offset = 0; 468 endsearch = dp->i_diroff; 469 goto searchloop; 470 } 471 if (bp != NULL) 472 brelse(bp); 473 /* 474 * If creating, and at end of pathname and current 475 * directory has not been removed, then can consider 476 * allowing file to be created. 477 */ 478 if ((nameiop == CREATE || nameiop == RENAME) && 479 (flags & ISLASTCN) && dp->i_e2fs_nlink != 0) { 480 /* 481 * Creation of files on a read-only mounted file system 482 * is pointless, so don't proceed any further. 483 */ 484 if (vdp->v_mount->mnt_flag & MNT_RDONLY) 485 return (EROFS); 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, p); 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 540found: 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 == dp->i_ino) { 585 VREF(vdp); 586 *vpp = vdp; 587 return (0); 588 } 589 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &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, p); 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 if ((error = VOP_ACCESS(vdp, VWRITE, cred, cnp->cn_proc)) != 0) 621 return (error); 622 /* 623 * Careful about locking second inode. 624 * This can only occur if the target is ".". 625 */ 626 if (dp->i_number == dp->i_ino) 627 return (EISDIR); 628 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) 629 return (error); 630 *vpp = tdp; 631 cnp->cn_flags |= SAVENAME; 632 if (!lockparent) { 633 VOP_UNLOCK(vdp, 0, p); 634 cnp->cn_flags |= PDIRUNLOCK; 635 } 636 return (0); 637 } 638 639 /* 640 * Step through the translation in the name. We do not `vput' the 641 * directory because we may need it again if a symbolic link 642 * is relative to the current directory. Instead we save it 643 * unlocked as "pdp". We must get the target inode before unlocking 644 * the directory to insure that the inode will not be removed 645 * before we get it. We prevent deadlock by always fetching 646 * inodes from the root, moving down the directory tree. Thus 647 * when following backward pointers ".." we must unlock the 648 * parent directory before getting the requested directory. 649 * There is a potential race condition here if both the current 650 * and parent directories are removed before the VFS_VGET for the 651 * inode associated with ".." returns. We hope that this occurs 652 * infrequently since we cannot avoid this race condition without 653 * implementing a sophisticated deadlock detection algorithm. 654 * Note also that this simple deadlock detection scheme will not 655 * work if the file system has any hard links other than ".." 656 * that point backwards in the directory structure. 657 */ 658 pdp = vdp; 659 if (flags & ISDOTDOT) { 660 VOP_UNLOCK(pdp, 0, p); /* race to get the inode */ 661 cnp->cn_flags |= PDIRUNLOCK; 662 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) { 663 if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0) 664 cnp->cn_flags &= ~PDIRUNLOCK; 665 return (error); 666 } 667 if (lockparent && (flags & ISLASTCN)) { 668 if ((error = vn_lock(pdp, LK_EXCLUSIVE, p)) != 0) { 669 vput(tdp); 670 return (error); 671 } 672 cnp->cn_flags &= ~PDIRUNLOCK; 673 } 674 *vpp = tdp; 675 } else if (dp->i_number == dp->i_ino) { 676 VREF(vdp); /* we want ourself, ie "." */ 677 *vpp = vdp; 678 } else { 679 if ((error = VFS_VGET(vdp->v_mount, dp->i_ino, &tdp)) != 0) 680 return (error); 681 if (!lockparent || !(flags & ISLASTCN)) { 682 VOP_UNLOCK(pdp, 0, p); 683 cnp->cn_flags |= PDIRUNLOCK; 684 } 685 *vpp = tdp; 686 } 687 688 /* 689 * Insert name into cache if appropriate. 690 */ 691 if (cnp->cn_flags & MAKEENTRY) 692 cache_enter(vdp, *vpp, cnp); 693 return (0); 694} 695 696/* 697 * Do consistency checking on a directory entry: 698 * record length must be multiple of 4 699 * entry must fit in rest of its dirblksize block 700 * record must be large enough to contain entry 701 * name is not longer than MAXNAMLEN 702 * name must be as long as advertised, and null terminated 703 */ 704/* 705 * changed so that it confirms to ext2fs_check_dir_entry 706 */ 707static int 708ext2fs_dirbadentry(dp, de, entryoffsetinblock) 709 struct vnode *dp; 710 struct ext2fs_direct *de; 711 int entryoffsetinblock; 712{ 713 int dirblksize = VTOI(dp)->i_e2fs->e2fs_bsize; 714 715 char * error_msg = NULL; 716 int reclen = fs2h16(de->e2d_reclen); 717 int namlen = de->e2d_namlen; 718 719 if (reclen < EXT2FS_DIRSIZ(1)) /* e2d_namlen = 1 */ 720 error_msg = "rec_len is smaller than minimal"; 721 else if (reclen % 4 != 0) 722 error_msg = "rec_len % 4 != 0"; 723 else if (reclen < EXT2FS_DIRSIZ(namlen)) 724 error_msg = "reclen is too small for name_len"; 725 else if (entryoffsetinblock + reclen > dirblksize) 726 error_msg = "directory entry across blocks"; 727 else if (fs2h32(de->e2d_ino) > 728 VTOI(dp)->i_e2fs->e2fs.e2fs_icount) 729 error_msg = "inode out of bounds"; 730 731 if (error_msg != NULL) { 732 printf( "bad directory entry: %s\n" 733 "offset=%d, inode=%lu, rec_len=%d, name_len=%d \n", 734 error_msg, entryoffsetinblock, 735 (unsigned long) fs2h32(de->e2d_ino), 736 reclen, namlen); 737 panic("ext2fs_dirbadentry"); 738 } 739 return error_msg == NULL ? 0 : 1; 740} 741 742/* 743 * Write a directory entry after a call to namei, using the parameters 744 * that it left in nameidata. The argument ip is the inode which the new 745 * directory entry will refer to. Dvp is a pointer to the directory to 746 * be written, which was left locked by namei. Remaining parameters 747 * (dp->i_offset, dp->i_count) indicate how the space for the new 748 * entry is to be obtained. 749 */ 750int 751ext2fs_direnter(ip, dvp, cnp) 752 struct inode *ip; 753 struct vnode *dvp; 754 struct componentname *cnp; 755{ 756 struct ext2fs_direct *ep, *nep; 757 struct inode *dp; 758 struct buf *bp; 759 struct ext2fs_direct newdir; 760 struct iovec aiov; 761 struct uio auio; 762 u_int dsize; 763 int error, loc, newentrysize, spacefree; 764 char *dirbuf; 765 int dirblksize = ip->i_e2fs->e2fs_bsize; 766 767 768#ifdef DIAGNOSTIC 769 if ((cnp->cn_flags & SAVENAME) == 0) 770 panic("direnter: missing name"); 771#endif 772 dp = VTOI(dvp); 773 newdir.e2d_ino = h2fs32(ip->i_number); 774 newdir.e2d_namlen = cnp->cn_namelen; 775 if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 && 776 (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) { 777 newdir.e2d_type = inot2ext2dt(IFTODT(ip->i_ffs_mode)); 778 } else { 779 newdir.e2d_type = 0; 780 }; 781 memcpy(newdir.e2d_name, cnp->cn_nameptr, (unsigned)cnp->cn_namelen + 1); 782 newentrysize = EXT2FS_DIRSIZ(cnp->cn_namelen); 783 if (dp->i_count == 0) { 784 /* 785 * If dp->i_count is 0, then namei could find no 786 * space in the directory. Here, dp->i_offset will 787 * be on a directory block boundary and we will write the 788 * new entry into a fresh block. 789 */ 790 if (dp->i_offset & (dirblksize - 1)) 791 panic("ext2fs_direnter: newblk"); 792 auio.uio_offset = dp->i_offset; 793 newdir.e2d_reclen = h2fs16(dirblksize); 794 auio.uio_resid = newentrysize; 795 aiov.iov_len = newentrysize; 796 aiov.iov_base = (caddr_t)&newdir; 797 auio.uio_iov = &aiov; 798 auio.uio_iovcnt = 1; 799 auio.uio_rw = UIO_WRITE; 800 auio.uio_segflg = UIO_SYSSPACE; 801 auio.uio_procp = (struct proc *)0; 802 error = VOP_WRITE(dvp, &auio, IO_SYNC, cnp->cn_cred); 803 if (dirblksize > 804 VFSTOUFS(dvp->v_mount)->um_mountp->mnt_stat.f_bsize) 805 /* XXX should grow with balloc() */ 806 panic("ext2fs_direnter: frag size"); 807 else if (!error) { 808 dp->i_e2fs_size = roundup(dp->i_e2fs_size, dirblksize); 809 dp->i_flag |= IN_CHANGE; 810 } 811 return (error); 812 } 813 814 /* 815 * If dp->i_count is non-zero, then namei found space 816 * for the new entry in the range dp->i_offset to 817 * dp->i_offset + dp->i_count in the directory. 818 * To use this space, we may have to compact the entries located 819 * there, by copying them together towards the beginning of the 820 * block, leaving the free space in one usable chunk at the end. 821 */ 822 823 /* 824 * Get the block containing the space for the new directory entry. 825 */ 826 if ((error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, &dirbuf, &bp)) 827 != 0) 828 return (error); 829 /* 830 * Find space for the new entry. In the simple case, the entry at 831 * offset base will have the space. If it does not, then namei 832 * arranged that compacting the region dp->i_offset to 833 * dp->i_offset + dp->i_count would yield the 834 * space. 835 */ 836 ep = (struct ext2fs_direct *)dirbuf; 837 dsize = EXT2FS_DIRSIZ(ep->e2d_namlen); 838 spacefree = fs2h16(ep->e2d_reclen) - dsize; 839 for (loc = fs2h16(ep->e2d_reclen); loc < dp->i_count; ) { 840 nep = (struct ext2fs_direct *)(dirbuf + loc); 841 if (ep->e2d_ino) { 842 /* trim the existing slot */ 843 ep->e2d_reclen = h2fs16(dsize); 844 ep = (struct ext2fs_direct *)((char *)ep + dsize); 845 } else { 846 /* overwrite; nothing there; header is ours */ 847 spacefree += dsize; 848 } 849 dsize = EXT2FS_DIRSIZ(nep->e2d_namlen); 850 spacefree += fs2h16(nep->e2d_reclen) - dsize; 851 loc += fs2h16(nep->e2d_reclen); 852 memcpy((caddr_t)ep, (caddr_t)nep, dsize); 853 } 854 /* 855 * Update the pointer fields in the previous entry (if any), 856 * copy in the new entry, and write out the block. 857 */ 858 if (ep->e2d_ino == 0) { 859#ifdef DIAGNOSTIC 860 if (spacefree + dsize < newentrysize) 861 panic("ext2fs_direnter: compact1"); 862#endif 863 newdir.e2d_reclen = h2fs16(spacefree + dsize); 864 } else { 865#ifdef DIAGNOSTIC 866 if (spacefree < newentrysize) { 867 printf("ext2fs_direnter: compact2 %u %u", 868 (u_int)spacefree, (u_int)newentrysize); 869 panic("ext2fs_direnter: compact2"); 870 } 871#endif 872 newdir.e2d_reclen = h2fs16(spacefree); 873 ep->e2d_reclen = h2fs16(dsize); 874 ep = (struct ext2fs_direct *)((char *)ep + dsize); 875 } 876 memcpy((caddr_t)ep, (caddr_t)&newdir, (u_int)newentrysize); 877 error = VOP_BWRITE(bp); 878 dp->i_flag |= IN_CHANGE | IN_UPDATE; 879 if (!error && dp->i_endoff && dp->i_endoff < dp->i_e2fs_size) 880 error = ext2fs_truncate(dp, (off_t)dp->i_endoff, IO_SYNC, 881 cnp->cn_cred); 882 return (error); 883} 884 885/* 886 * Remove a directory entry after a call to namei, using 887 * the parameters which it left in nameidata. The entry 888 * dp->i_offset contains the offset into the directory of the 889 * entry to be eliminated. The dp->i_count field contains the 890 * size of the previous record in the directory. If this 891 * is 0, the first entry is being deleted, so we need only 892 * zero the inode number to mark the entry as free. If the 893 * entry is not the first in the directory, we must reclaim 894 * the space of the now empty record by adding the record size 895 * to the size of the previous entry. 896 */ 897int 898ext2fs_dirremove(dvp, cnp) 899 struct vnode *dvp; 900 struct componentname *cnp; 901{ 902 struct inode *dp; 903 struct ext2fs_direct *ep; 904 struct buf *bp; 905 int error; 906 907 dp = VTOI(dvp); 908 if (dp->i_count == 0) { 909 /* 910 * First entry in block: set d_ino to zero. 911 */ 912 error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, (char **)&ep, 913 &bp); 914 if (error != 0) 915 return (error); 916 ep->e2d_ino = 0; 917 error = VOP_BWRITE(bp); 918 dp->i_flag |= IN_CHANGE | IN_UPDATE; 919 return (error); 920 } 921 /* 922 * Collapse new free space into previous entry. 923 */ 924 error = ext2fs_bufatoff(dp, (off_t)(dp->i_offset - dp->i_count), 925 (char **)&ep, &bp); 926 if (error != 0) 927 return (error); 928 ep->e2d_reclen = h2fs16(fs2h16(ep->e2d_reclen) + dp->i_reclen); 929 error = VOP_BWRITE(bp); 930 dp->i_flag |= IN_CHANGE | IN_UPDATE; 931 return (error); 932} 933 934/* 935 * Rewrite an existing directory entry to point at the inode 936 * supplied. The parameters describing the directory entry are 937 * set up by a call to namei. 938 */ 939int 940ext2fs_dirrewrite(dp, ip, cnp) 941 struct inode *dp, *ip; 942 struct componentname *cnp; 943{ 944 struct buf *bp; 945 struct ext2fs_direct *ep; 946 int error; 947 948 error = ext2fs_bufatoff(dp, (off_t)dp->i_offset, (char **)&ep, &bp); 949 if (error != 0) 950 return (error); 951 ep->e2d_ino = h2fs32(ip->i_number); 952 if (ip->i_e2fs->e2fs.e2fs_rev > E2FS_REV0 && 953 (ip->i_e2fs->e2fs.e2fs_features_incompat & EXT2F_INCOMPAT_FTYPE)) { 954 ep->e2d_type = inot2ext2dt(IFTODT(ip->i_ffs_mode)); 955 } else { 956 ep->e2d_type = 0; 957 } 958 error = VOP_BWRITE(bp); 959 dp->i_flag |= IN_CHANGE | IN_UPDATE; 960 return (error); 961} 962 963/* 964 * Check if a directory is empty or not. 965 * Inode supplied must be locked. 966 * 967 * Using a struct dirtemplate here is not precisely 968 * what we want, but better than using a struct ext2fs_direct. 969 * 970 * NB: does not handle corrupted directories. 971 */ 972int 973ext2fs_dirempty(ip, parentino, cred) 974 struct inode *ip; 975 ino_t parentino; 976 struct ucred *cred; 977{ 978 off_t off; 979 struct ext2fs_dirtemplate dbuf; 980 struct ext2fs_direct *dp = (struct ext2fs_direct *)&dbuf; 981 int error, namlen; 982 size_t count; 983 984#define MINDIRSIZ (sizeof (struct ext2fs_dirtemplate) / 2) 985 986 for (off = 0; off < ip->i_e2fs_size; off += fs2h16(dp->e2d_reclen)) { 987 error = vn_rdwr(UIO_READ, ITOV(ip), (caddr_t)dp, MINDIRSIZ, off, 988 UIO_SYSSPACE, IO_NODELOCKED, cred, &count, (struct proc *)0); 989 /* 990 * Since we read MINDIRSIZ, residual must 991 * be 0 unless we're at end of file. 992 */ 993 if (error || count != 0) 994 return (0); 995 /* avoid infinite loops */ 996 if (dp->e2d_reclen == 0) 997 return (0); 998 /* skip empty entries */ 999 if (dp->e2d_ino == 0) 1000 continue; 1001 /* accept only "." and ".." */ 1002 namlen = dp->e2d_namlen; 1003 if (namlen > 2) 1004 return (0); 1005 if (dp->e2d_name[0] != '.') 1006 return (0); 1007 /* 1008 * At this point namlen must be 1 or 2. 1009 * 1 implies ".", 2 implies ".." if second 1010 * char is also "." 1011 */ 1012 if (namlen == 1) 1013 continue; 1014 if (dp->e2d_name[1] == '.' && fs2h32(dp->e2d_ino) == parentino) 1015 continue; 1016 return (0); 1017 } 1018 return (1); 1019} 1020 1021/* 1022 * Check if source directory is in the path of the target directory. 1023 * Target is supplied locked, source is unlocked. 1024 * The target is always vput before returning. 1025 */ 1026int 1027ext2fs_checkpath(source, target, cred) 1028 struct inode *source, *target; 1029 struct ucred *cred; 1030{ 1031 struct vnode *vp; 1032 int error, rootino, namlen; 1033 struct ext2fs_dirtemplate dirbuf; 1034 u_int32_t ino; 1035 1036 vp = ITOV(target); 1037 if (target->i_number == source->i_number) { 1038 error = EEXIST; 1039 goto out; 1040 } 1041 rootino = ROOTINO; 1042 error = 0; 1043 if (target->i_number == rootino) 1044 goto out; 1045 1046 for (;;) { 1047 if (vp->v_type != VDIR) { 1048 error = ENOTDIR; 1049 break; 1050 } 1051 error = vn_rdwr(UIO_READ, vp, (caddr_t)&dirbuf, 1052 sizeof (struct ext2fs_dirtemplate), (off_t)0, 1053 UIO_SYSSPACE, IO_NODELOCKED, cred, (size_t *)0, 1054 (struct proc *)0); 1055 if (error != 0) 1056 break; 1057 namlen = dirbuf.dotdot_namlen; 1058 if (namlen != 2 || 1059 dirbuf.dotdot_name[0] != '.' || 1060 dirbuf.dotdot_name[1] != '.') { 1061 error = ENOTDIR; 1062 break; 1063 } 1064 ino = fs2h32(dirbuf.dotdot_ino); 1065 if (ino == source->i_number) { 1066 error = EINVAL; 1067 break; 1068 } 1069 if (ino == rootino) 1070 break; 1071 vput(vp); 1072 error = VFS_VGET(vp->v_mount, ino, &vp); 1073 if (error != 0) { 1074 vp = NULL; 1075 break; 1076 } 1077 } 1078 1079out: 1080 if (error == ENOTDIR) { 1081 printf("checkpath: .. not a directory\n"); 1082 panic("checkpath"); 1083 } 1084 if (vp != NULL) 1085 vput(vp); 1086 return (error); 1087} 1088