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