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