1 /* $Id: msdosfs_lookup.c,v 1.1 1994/09/19 15:41:44 dfr Exp $ */ 2 /* $NetBSD: msdosfs_lookup.c,v 1.14 1994/08/21 18:44:07 ws Exp $ */ 3 4 /*- 5 * Copyright (C) 1994 Wolfgang Solfrank. 6 * Copyright (C) 1994 TooLs GmbH. 7 * All rights reserved. 8 * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by TooLs GmbH. 21 * 4. The name of TooLs GmbH may not be used to endorse or promote products 22 * derived from this software without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 25 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27 * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 30 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 33 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34 */ 35 /* 36 * Written by Paul Popelka (paulp@uts.amdahl.com) 37 * 38 * You can do anything you want with this software, just don't say you wrote 39 * it, and don't remove this notice. 40 * 41 * This software is provided "as is". 42 * 43 * The author supplies this software to be publicly redistributed on the 44 * understanding that the author is not responsible for the correct 45 * functioning of this software in any circumstances and is not liable for 46 * any damages caused by this software. 47 * 48 * October 1992 49 */ 50 51 #include <sys/param.h> 52 #include <sys/namei.h> 53 #include <sys/buf.h> 54 #include <sys/vnode.h> 55 #include <sys/mount.h> 56 #include <sys/systm.h> 57 58 #include <msdosfs/bpb.h> 59 #include <msdosfs/direntry.h> 60 #include <msdosfs/denode.h> 61 #include <msdosfs/msdosfsmount.h> 62 #include <msdosfs/fat.h> 63 64 /* 65 * When we search a directory the blocks containing directory entries are 66 * read and examined. The directory entries contain information that would 67 * normally be in the inode of a unix filesystem. This means that some of 68 * a directory's contents may also be in memory resident denodes (sort of 69 * an inode). This can cause problems if we are searching while some other 70 * process is modifying a directory. To prevent one process from accessing 71 * incompletely modified directory information we depend upon being the 72 * soul owner of a directory block. bread/brelse provide this service. 73 * This being the case, when a process modifies a directory it must first 74 * acquire the disk block that contains the directory entry to be modified. 75 * Then update the disk block and the denode, and then write the disk block 76 * out to disk. This way disk blocks containing directory entries and in 77 * memory denode's will be in synch. 78 */ 79 int 80 msdosfs_lookup(ap) 81 struct vop_lookup_args /* { 82 struct vnode *a_dvp; 83 struct vnode **a_vpp; 84 struct componentname *a_cnp; 85 } */ *ap; 86 { 87 struct vnode *vdp = ap->a_dvp; 88 struct vnode **vpp = ap->a_vpp; 89 struct componentname *cnp = ap->a_cnp; 90 daddr_t bn; 91 int error; 92 int lockparent; 93 int wantparent; 94 int slotstatus; 95 96 #define NONE 0 97 #define FOUND 1 98 int slotoffset = -1; 99 int slotcluster = -1; 100 int frcn; 101 u_long cluster; 102 int rootreloff; 103 int diroff; 104 int isadir; /* ~0 if found direntry is a directory */ 105 u_long scn; /* starting cluster number */ 106 struct vnode *pdp; 107 struct denode *dp; 108 struct denode *tdp; 109 struct msdosfsmount *pmp; 110 struct buf *bp = 0; 111 struct direntry *dep = NULL; 112 u_char dosfilename[12]; 113 int flags = cnp->cn_flags; 114 int nameiop = cnp->cn_nameiop; 115 116 #ifdef MSDOSFS_DEBUG 117 printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr); 118 #endif 119 dp = VTODE(vdp); 120 pmp = dp->de_pmp; 121 *vpp = NULL; 122 lockparent = flags & LOCKPARENT; 123 wantparent = flags & (LOCKPARENT | WANTPARENT); 124 #ifdef MSDOSFS_DEBUG 125 printf("msdosfs_lookup(): vdp %08x, dp %08x, Attr %02x\n", 126 vdp, dp, dp->de_Attributes); 127 #endif 128 129 /* 130 * Be sure vdp is a directory. Since dos filesystems don't have 131 * the concept of execute permission anybody can search a 132 * directory. 133 */ 134 if ((dp->de_Attributes & ATTR_DIRECTORY) == 0) 135 return ENOTDIR; 136 137 /* 138 * See if the component of the pathname we are looking for is in 139 * the directory cache. If so then do a few things and return. 140 */ 141 error = cache_lookup(vdp, vpp, cnp); 142 if (error) { 143 int vpid; 144 145 if (error == ENOENT) 146 return error; 147 pdp = vdp; 148 vdp = *vpp; 149 dp = VTODE(vdp); 150 vpid = vdp->v_id; 151 if (pdp == vdp) { 152 VREF(vdp); 153 error = 0; 154 } else if (flags & ISDOTDOT) { 155 VOP_UNLOCK(pdp); 156 error = vget(vdp, 1); 157 if (!error && lockparent && (flags & ISLASTCN)) 158 error = VOP_LOCK(pdp); 159 } else { 160 error = vget(vdp, 1); 161 if (!lockparent || error || !(flags & ISLASTCN)) 162 VOP_UNLOCK(pdp); 163 } 164 165 if (!error) { 166 if (vpid == vdp->v_id) { 167 #ifdef MSDOSFS_DEBUG 168 printf("msdosfs_lookup(): cache hit, vnode %08x, file %s\n", 169 vdp, dp->de_Name); 170 #endif 171 return 0; 172 } 173 vput(vdp); 174 if (lockparent && pdp != vdp && (flags & ISLASTCN)) 175 VOP_UNLOCK(pdp); 176 } 177 error = VOP_LOCK(pdp); 178 if (error) 179 return error; 180 vdp = pdp; 181 dp = VTODE(vdp); 182 *vpp = NULL; 183 } 184 185 /* 186 * If they are going after the . or .. entry in the root directory, 187 * they won't find it. DOS filesystems don't have them in the root 188 * directory. So, we fake it. deget() is in on this scam too. 189 */ 190 if ((vdp->v_flag & VROOT) && cnp->cn_nameptr[0] == '.' && 191 (cnp->cn_namelen == 1 || 192 (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) { 193 isadir = ATTR_DIRECTORY; 194 scn = MSDOSFSROOT; 195 #ifdef MSDOSFS_DEBUG 196 printf("msdosfs_lookup(): looking for . or .. in root directory\n"); 197 #endif 198 cluster = MSDOSFSROOT; 199 diroff = MSDOSFSROOT_OFS; 200 goto foundroot; 201 } 202 203 /* 204 * Don't search for free slots unless we are creating a filename 205 * and we are at the end of the pathname. 206 */ 207 slotstatus = FOUND; 208 if ((nameiop == CREATE || nameiop == RENAME) && (flags & ISLASTCN)) { 209 slotstatus = NONE; 210 slotoffset = -1; 211 } 212 213 unix2dosfn((u_char *) cnp->cn_nameptr, dosfilename, cnp->cn_namelen); 214 dosfilename[11] = 0; 215 #ifdef MSDOSFS_DEBUG 216 printf("msdosfs_lookup(): dos version of filename %s, length %d\n", 217 dosfilename, cnp->cn_namelen); 218 #endif 219 /* 220 * Search the directory pointed at by vdp for the name pointed at 221 * by cnp->cn_nameptr. 222 */ 223 tdp = NULL; 224 /* 225 * The outer loop ranges over the clusters that make up the 226 * directory. Note that the root directory is different from all 227 * other directories. It has a fixed number of blocks that are not 228 * part of the pool of allocatable clusters. So, we treat it a 229 * little differently. The root directory starts at "cluster" 0. 230 */ 231 rootreloff = 0; 232 for (frcn = 0;; frcn++) { 233 error = pcbmap(dp, frcn, &bn, &cluster); 234 if (error) { 235 if (error == E2BIG) 236 break; 237 return error; 238 } 239 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,NOCRED,&bp); 240 if (error) 241 return error; 242 for (diroff = 0; diroff < pmp->pm_depclust; diroff++) { 243 dep = (struct direntry *) bp->b_data + diroff; 244 245 /* 246 * If the slot is empty and we are still looking 247 * for an empty then remember this one. If the 248 * slot is not empty then check to see if it 249 * matches what we are looking for. If the slot 250 * has never been filled with anything, then the 251 * remainder of the directory has never been used, 252 * so there is no point in searching it. 253 */ 254 if (dep->deName[0] == SLOT_EMPTY || 255 dep->deName[0] == SLOT_DELETED) { 256 if (slotstatus != FOUND) { 257 slotstatus = FOUND; 258 if (cluster == MSDOSFSROOT) 259 slotoffset = rootreloff; 260 else 261 slotoffset = diroff; 262 slotcluster = cluster; 263 } 264 if (dep->deName[0] == SLOT_EMPTY) { 265 brelse(bp); 266 goto notfound; 267 } 268 } else { 269 /* 270 * Ignore volume labels (anywhere, not just 271 * the root directory). 272 */ 273 if ((dep->deAttributes & ATTR_VOLUME) == 0 && 274 bcmp(dosfilename, dep->deName, 11) == 0) { 275 #ifdef MSDOSFS_DEBUG 276 printf("msdosfs_lookup(): match diroff %d, rootreloff %d\n", 277 diroff, rootreloff); 278 #endif 279 /* 280 * Remember where this directory 281 * entry came from for whoever did 282 * this lookup. If this is the root 283 * directory we are interested in 284 * the offset relative to the 285 * beginning of the directory (not 286 * the beginning of the cluster). 287 */ 288 if (cluster == MSDOSFSROOT) 289 diroff = rootreloff; 290 dp->de_fndoffset = diroff; 291 dp->de_fndclust = cluster; 292 goto found; 293 } 294 } 295 rootreloff++; 296 } /* for (diroff = 0; .... */ 297 /* 298 * Release the buffer holding the directory cluster just 299 * searched. 300 */ 301 brelse(bp); 302 } /* for (frcn = 0; ; frcn++) */ 303 notfound:; 304 /* 305 * We hold no disk buffers at this point. 306 */ 307 308 /* 309 * If we get here we didn't find the entry we were looking for. But 310 * that's ok if we are creating or renaming and are at the end of 311 * the pathname and the directory hasn't been removed. 312 */ 313 #ifdef MSDOSFS_DEBUG 314 printf("msdosfs_lookup(): op %d, refcnt %d, slotstatus %d\n", 315 nameiop, dp->de_refcnt, slotstatus); 316 printf(" slotoffset %d, slotcluster %d\n", 317 slotoffset, slotcluster); 318 #endif 319 if ((nameiop == CREATE || nameiop == RENAME) && 320 (flags & ISLASTCN) && dp->de_refcnt != 0) { 321 if (slotstatus == NONE) { 322 dp->de_fndoffset = (u_long)-1; 323 dp->de_fndclust = (u_long)-1; 324 } else { 325 #ifdef MSDOSFS_DEBUG 326 printf("msdosfs_lookup(): saving empty slot location\n"); 327 #endif 328 dp->de_fndoffset = slotoffset; 329 dp->de_fndclust = slotcluster; 330 } 331 /* dp->de_flag |= DE_UPDATE; never update dos directories */ 332 cnp->cn_flags |= SAVENAME; 333 if (!lockparent)/* leave searched dir locked? */ 334 VOP_UNLOCK(vdp); 335 return EJUSTRETURN; 336 } 337 /* 338 * Insert name in cache as non-existant if not trying to create it. 339 */ 340 if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE) 341 cache_enter(vdp, *vpp, cnp); 342 return ENOENT; 343 344 found: ; 345 /* 346 * NOTE: We still have the buffer with matched directory entry at 347 * this point. 348 */ 349 isadir = dep->deAttributes & ATTR_DIRECTORY; 350 scn = getushort(dep->deStartCluster); 351 352 foundroot:; 353 /* 354 * If we entered at foundroot, then we are looking for the . or .. 355 * entry of the filesystems root directory. isadir and scn were 356 * setup before jumping here. And, bp is null. There is no buf 357 * header. 358 */ 359 360 /* 361 * If deleting and at the end of the path, then if we matched on 362 * "." then don't deget() we would probably panic(). Otherwise 363 * deget() the directory entry. 364 */ 365 if (nameiop == DELETE && (flags & ISLASTCN)) { 366 if (dp->de_StartCluster == scn && isadir) { /* "." */ 367 VREF(vdp); 368 *vpp = vdp; 369 if (bp) 370 brelse(bp); 371 return 0; 372 } 373 error = deget(pmp, cluster, diroff, dep, &tdp); 374 if (error) { 375 if (bp) 376 brelse(bp); 377 return error; 378 } 379 *vpp = DETOV(tdp); 380 if (!lockparent) 381 VOP_UNLOCK(vdp); 382 if (bp) 383 brelse(bp); 384 return 0; 385 } 386 387 /* 388 * If renaming. 389 */ 390 if (nameiop == RENAME && wantparent && (flags & ISLASTCN)) { 391 if (dp->de_StartCluster == scn && isadir) { 392 if (bp) 393 brelse(bp); 394 return EISDIR; 395 } 396 error = deget(pmp, cluster, diroff, dep, &tdp); 397 if (error) { 398 if (bp) 399 brelse(bp); 400 return error; 401 } 402 *vpp = DETOV(tdp); 403 cnp->cn_flags |= SAVENAME; 404 if (!lockparent) 405 VOP_UNLOCK(vdp); 406 if (bp) 407 brelse(bp); 408 return 0; 409 } 410 411 /* 412 * ? 413 */ 414 pdp = vdp; 415 if (flags & ISDOTDOT) { 416 VOP_UNLOCK(pdp); 417 error = deget(pmp, cluster, diroff, dep, &tdp); 418 if (error) { 419 VOP_LOCK(pdp); 420 if (bp) 421 brelse(bp); 422 return error; 423 } 424 if (lockparent && (flags & ISLASTCN) 425 && (error = VOP_LOCK(pdp))) { 426 vput(DETOV(tdp)); 427 return error; 428 } 429 *vpp = DETOV(tdp); 430 } else if (dp->de_StartCluster == scn && isadir) { /* "." */ 431 VREF(vdp); 432 *vpp = vdp; 433 } else { 434 error = deget(pmp, cluster, diroff, dep, &tdp); 435 if (error) { 436 if (bp) 437 brelse(bp); 438 return error; 439 } 440 if (!lockparent || !(flags & ISLASTCN)) 441 VOP_UNLOCK(pdp); 442 *vpp = DETOV(tdp); 443 } 444 if (bp) 445 brelse(bp); 446 447 /* 448 * Insert name in cache if wanted. 449 */ 450 if (cnp->cn_flags & MAKEENTRY) 451 cache_enter(vdp, *vpp, cnp); 452 return 0; 453 } 454 455 /* 456 * dep - directory entry to copy into the directory 457 * ddep - directory to add to 458 * depp - return the address of the denode for the created directory entry 459 * if depp != 0 460 */ 461 int 462 createde(dep, ddep, depp) 463 struct denode *dep; 464 struct denode *ddep; 465 struct denode **depp; 466 { 467 int error; 468 u_long dirclust, diroffset; 469 struct direntry *ndep; 470 struct msdosfsmount *pmp = ddep->de_pmp; 471 struct buf *bp; 472 473 #ifdef MSDOSFS_DEBUG 474 printf("createde(dep %08x, ddep %08x, depp %08x)\n", dep, ddep, depp); 475 #endif 476 477 /* 478 * If no space left in the directory then allocate another cluster 479 * and chain it onto the end of the file. There is one exception 480 * to this. That is, if the root directory has no more space it 481 * can NOT be expanded. extendfile() checks for and fails attempts 482 * to extend the root directory. We just return an error in that 483 * case. 484 */ 485 if (ddep->de_fndclust == (u_long)-1) { 486 error = extendfile(ddep, 1, &bp, &dirclust, DE_CLEAR); 487 if (error) 488 return error; 489 ndep = (struct direntry *) bp->b_data; 490 /* 491 * Let caller know where we put the directory entry. 492 */ 493 ddep->de_fndclust = dirclust; 494 ddep->de_fndoffset = diroffset = 0; 495 /* 496 * Update the size of the directory 497 */ 498 ddep->de_FileSize += pmp->pm_bpcluster; 499 } else { 500 /* 501 * There is space in the existing directory. So, we just 502 * read in the cluster with space. Copy the new directory 503 * entry in. Then write it to disk. NOTE: DOS directories 504 * do not get smaller as clusters are emptied. 505 */ 506 dirclust = ddep->de_fndclust; 507 diroffset = ddep->de_fndoffset; 508 509 error = readep(pmp, dirclust, diroffset, &bp, &ndep); 510 if (error) 511 return error; 512 } 513 DE_EXTERNALIZE(ndep, dep); 514 515 /* 516 * If they want us to return with the denode gotten. 517 */ 518 if (depp) { 519 error = deget(pmp, dirclust, diroffset, ndep, depp); 520 if (error) 521 return error; 522 } 523 error = bwrite(bp); 524 if (error) { 525 vput(DETOV(*depp)); /* free the vnode we got on error */ 526 return error; 527 } 528 return 0; 529 } 530 531 /* 532 * Read in a directory entry and mark it as being deleted. 533 */ 534 int 535 markdeleted(pmp, dirclust, diroffset) 536 struct msdosfsmount *pmp; 537 u_long dirclust; 538 u_long diroffset; 539 { 540 int error; 541 struct direntry *ep; 542 struct buf *bp; 543 544 error = readep(pmp, dirclust, diroffset, &bp, &ep); 545 if (error) 546 return error; 547 ep->deName[0] = SLOT_DELETED; 548 return bwrite(bp); 549 } 550 551 /* 552 * Remove a directory entry. At this point the file represented by the 553 * directory entry to be removed is still full length until no one has it 554 * open. When the file no longer being used msdosfs_inactive() is called 555 * and will truncate the file to 0 length. When the vnode containing the 556 * denode is needed for some other purpose by VFS it will call 557 * msdosfs_reclaim() which will remove the denode from the denode cache. 558 */ 559 int 560 removede(pdep,dep) 561 struct denode *pdep; /* directory where the entry is removed */ 562 struct denode *dep; /* file to be removed */ 563 { 564 struct msdosfsmount *pmp = pdep->de_pmp; 565 int error; 566 567 #ifdef MSDOSFS_DEBUG 568 printf("removede(): filename %s\n", dep->de_Name); 569 printf("removede(): dep %08x, ndpcluster %d, ndpoffset %d\n", 570 dep, pdep->de_fndclust, pdep->de_fndoffset); 571 #endif 572 573 /* 574 * Read the directory block containing the directory entry we are 575 * to make free. The nameidata structure holds the cluster number 576 * and directory entry index number of the entry to free. 577 */ 578 error = markdeleted(pmp, pdep->de_fndclust, pdep->de_fndoffset); 579 580 if (error == 0) 581 dep->de_refcnt--; 582 return error; 583 } 584 585 /* 586 * Be sure a directory is empty except for "." and "..". Return 1 if empty, 587 * return 0 if not empty or error. 588 */ 589 int 590 dosdirempty(dep) 591 struct denode *dep; 592 { 593 int dei; 594 int error; 595 u_long cn; 596 daddr_t bn; 597 struct buf *bp; 598 struct msdosfsmount *pmp = dep->de_pmp; 599 struct direntry *dentp; 600 601 /* 602 * Since the filesize field in directory entries for a directory is 603 * zero, we just have to feel our way through the directory until 604 * we hit end of file. 605 */ 606 for (cn = 0;; cn++) { 607 error = pcbmap(dep, cn, &bn, 0); 608 if (error == E2BIG) 609 return 1; /* it's empty */ 610 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, 611 &bp); 612 if (error) 613 return error; 614 dentp = (struct direntry *) bp->b_data; 615 for (dei = 0; dei < pmp->pm_depclust; dei++) { 616 if (dentp->deName[0] != SLOT_DELETED) { 617 /* 618 * In dos directories an entry whose name 619 * starts with SLOT_EMPTY (0) starts the 620 * beginning of the unused part of the 621 * directory, so we can just return that it 622 * is empty. 623 */ 624 if (dentp->deName[0] == SLOT_EMPTY) { 625 brelse(bp); 626 return 1; 627 } 628 /* 629 * Any names other than "." and ".." in a 630 * directory mean it is not empty. 631 */ 632 if (bcmp(dentp->deName, ". ", 11) && 633 bcmp(dentp->deName, ".. ", 11)) { 634 brelse(bp); 635 #ifdef MSDOSFS_DEBUG 636 printf("dosdirempty(): entry %d found %02x, %02x\n", 637 dei, dentp->deName[0], dentp->deName[1]); 638 #endif 639 return 0; /* not empty */ 640 } 641 } 642 dentp++; 643 } 644 brelse(bp); 645 } 646 /* NOTREACHED */ 647 } 648 649 /* 650 * Check to see if the directory described by target is in some 651 * subdirectory of source. This prevents something like the following from 652 * succeeding and leaving a bunch or files and directories orphaned. mv 653 * /a/b/c /a/b/c/d/e/f Where c and f are directories. 654 * 655 * source - the inode for /a/b/c 656 * target - the inode for /a/b/c/d/e/f 657 * 658 * Returns 0 if target is NOT a subdirectory of source. 659 * Otherwise returns a non-zero error number. 660 * The target inode is always unlocked on return. 661 */ 662 int 663 doscheckpath(source, target) 664 struct denode *source; 665 struct denode *target; 666 { 667 daddr_t scn; 668 struct msdosfsmount *pmp; 669 struct direntry *ep; 670 struct denode *dep; 671 struct buf *bp = NULL; 672 int error = 0; 673 674 dep = target; 675 if ((target->de_Attributes & ATTR_DIRECTORY) == 0 || 676 (source->de_Attributes & ATTR_DIRECTORY) == 0) { 677 error = ENOTDIR; 678 goto out; 679 } 680 if (dep->de_StartCluster == source->de_StartCluster) { 681 error = EEXIST; 682 goto out; 683 } 684 if (dep->de_StartCluster == MSDOSFSROOT) 685 goto out; 686 for (;;) { 687 if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) { 688 error = ENOTDIR; 689 goto out; 690 } 691 pmp = dep->de_pmp; 692 scn = dep->de_StartCluster; 693 error = bread(pmp->pm_devvp, cntobn(pmp, scn), 694 pmp->pm_bpcluster, NOCRED, &bp); 695 if (error) { 696 break; 697 } 698 ep = (struct direntry *) bp->b_data + 1; 699 if ((ep->deAttributes & ATTR_DIRECTORY) == 0 || 700 bcmp(ep->deName, ".. ", 11) != 0) { 701 error = ENOTDIR; 702 break; 703 } 704 scn = getushort(ep->deStartCluster); 705 if (scn == source->de_StartCluster) { 706 error = EINVAL; 707 break; 708 } 709 if (scn == MSDOSFSROOT) 710 break; 711 vput(DETOV(dep)); 712 /* NOTE: deget() clears dep on error */ 713 error = deget(pmp, scn, 0, ep, &dep); 714 brelse(bp); 715 bp = NULL; 716 if (error) 717 break; 718 } 719 out: ; 720 if (bp) 721 brelse(bp); 722 if (error == ENOTDIR) 723 printf("doscheckpath(): .. not a directory?\n"); 724 if (dep != NULL) 725 vput(DETOV(dep)); 726 return error; 727 } 728 729 /* 730 * Read in the disk block containing the directory entry (dirclu, dirofs) 731 * and return the address of the buf header, and the address of the 732 * directory entry within the block. 733 */ 734 int 735 readep(pmp, dirclu, dirofs, bpp, epp) 736 struct msdosfsmount *pmp; 737 u_long dirclu, dirofs; 738 struct buf **bpp; 739 struct direntry **epp; 740 { 741 int error; 742 daddr_t bn; 743 744 bn = detobn(pmp, dirclu, dirofs); 745 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, bpp); 746 if (error) { 747 *bpp = NULL; 748 return error; 749 } 750 if (epp) 751 *epp = bptoep(pmp, *bpp, dirofs); 752 return 0; 753 } 754 755 756 /* 757 * Read in the disk block containing the directory entry dep came from and 758 * return the address of the buf header, and the address of the directory 759 * entry within the block. 760 */ 761 int 762 readde(dep, bpp, epp) 763 struct denode *dep; 764 struct buf **bpp; 765 struct direntry **epp; 766 { 767 return readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset, 768 bpp, epp); 769 } 770