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