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