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