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