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