|
|
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_fat.c,v 1.3 1993/05/20 03:34:12 cgd Exp ! 19: */ ! 20: ! 21: /* ! 22: * kernel include files. ! 23: */ ! 24: #include "param.h" ! 25: #include "systm.h" ! 26: #include "buf.h" ! 27: #include "file.h" ! 28: #include "namei.h" ! 29: #include "mount.h" /* to define statfs structure */ ! 30: #include "vnode.h" /* to define vattr structure */ ! 31: #include "errno.h" ! 32: ! 33: /* ! 34: * pcfs include files. ! 35: */ ! 36: #include "bpb.h" ! 37: #include "pcfsmount.h" ! 38: #include "direntry.h" ! 39: #include "denode.h" ! 40: #include "fat.h" ! 41: ! 42: /* ! 43: * Fat cache stats. ! 44: */ ! 45: int fc_fileextends; /* # of file extends */ ! 46: int fc_lfcempty; /* # of time last file cluster cache entry ! 47: * was empty */ ! 48: int fc_bmapcalls; /* # of times pcbmap was called */ ! 49: #define LMMAX 20 ! 50: int fc_lmdistance[LMMAX]; /* counters for how far off the last cluster ! 51: * mapped entry was. */ ! 52: int fc_largedistance; /* off by more than LMMAX */ ! 53: ! 54: /* Byte offset in FAT on filesystem pmp, cluster cn */ ! 55: #define FATOFS(pmp, cn) (FAT12(pmp) ? (cn) * 3 / 2 : (cn) * 2) ! 56: ! 57: ! 58: static void fatblock (pmp, ofs, bnp, sizep, bop) ! 59: struct pcfsmount *pmp; ! 60: u_long ofs; ! 61: u_long *bnp; ! 62: u_long *sizep; ! 63: u_long *bop; ! 64: { ! 65: u_long bn, size; ! 66: ! 67: bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec; ! 68: size = min (pmp->pm_fatblocksec, pmp->pm_FATsecs - bn) ! 69: * pmp->pm_BytesPerSec; ! 70: bn += pmp->pm_fatblk; ! 71: if (bnp) ! 72: *bnp = bn; ! 73: if (sizep) ! 74: *sizep = size; ! 75: if (bop) ! 76: *bop = ofs % pmp->pm_fatblocksize; ! 77: } ! 78: ! 79: /* ! 80: * Map the logical cluster number of a file into ! 81: * a physical disk sector that is filesystem relative. ! 82: * dep - address of denode representing the file of interest ! 83: * findcn - file relative cluster whose filesystem relative ! 84: * cluster number and/or block number are/is to be found ! 85: * bnp - address of where to place the file system relative ! 86: * block number. If this pointer is null then don't return ! 87: * this quantity. ! 88: * cnp - address of where to place the file system relative ! 89: * cluster number. If this pointer is null then don't return ! 90: * this quantity. ! 91: * NOTE: ! 92: * Either bnp or cnp must be non-null. ! 93: * This function has one side effect. If the requested ! 94: * file relative cluster is beyond the end of file, then ! 95: * the actual number of clusters in the file is returned ! 96: * in *cnp. This is useful for determining how long a ! 97: * directory is. If cnp is null, nothing is returned. ! 98: */ ! 99: int ! 100: pcbmap(dep, findcn, bnp, cnp) ! 101: struct denode *dep; ! 102: u_long findcn; /* file relative cluster to get */ ! 103: daddr_t *bnp; /* returned filesys relative blk number */ ! 104: u_long *cnp; /* returned cluster number */ ! 105: { ! 106: int error; ! 107: u_long i; ! 108: u_long cn; ! 109: u_long prevcn; ! 110: u_long byteoffset; ! 111: u_long bn; ! 112: u_long bo; ! 113: struct buf *bp = NULL; ! 114: u_long bp_bn = -1; ! 115: struct pcfsmount *pmp = dep->de_pmp; ! 116: u_long bsize; ! 117: int fat12 = FAT12(pmp); /* 12 bit fat */ ! 118: ! 119: fc_bmapcalls++; ! 120: ! 121: /* ! 122: * If they don't give us someplace to return a value ! 123: * then don't bother doing anything. ! 124: */ ! 125: if (bnp == NULL && cnp == NULL) ! 126: return 0; ! 127: ! 128: cn = dep->de_StartCluster; ! 129: /* ! 130: * The "file" that makes up the root directory is contiguous, ! 131: * permanently allocated, of fixed size, and is not made up ! 132: * of clusters. If the cluster number is beyond the end of ! 133: * the root directory, then return the number of clusters in ! 134: * the file. ! 135: */ ! 136: if (cn == PCFSROOT) { ! 137: if (dep->de_Attributes & ATTR_DIRECTORY) { ! 138: if (findcn * pmp->pm_SectPerClust > pmp->pm_rootdirsize) { ! 139: if (cnp) ! 140: *cnp = pmp->pm_rootdirsize / pmp->pm_SectPerClust; ! 141: return E2BIG; ! 142: } ! 143: if (bnp) ! 144: *bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust); ! 145: if (cnp) ! 146: *cnp = PCFSROOT; ! 147: return 0; ! 148: } ! 149: else { /* just an empty file */ ! 150: if (cnp) ! 151: *cnp = 0; ! 152: return E2BIG; ! 153: } ! 154: } ! 155: ! 156: /* ! 157: * Rummage around in the fat cache, maybe we can avoid ! 158: * tromping thru every fat entry for the file. ! 159: * And, keep track of how far off the cache was from ! 160: * where we wanted to be. ! 161: */ ! 162: i = 0; ! 163: fc_lookup(dep, findcn, &i, &cn); ! 164: if ((bn = findcn - i) >= LMMAX) ! 165: fc_largedistance++; ! 166: else ! 167: fc_lmdistance[bn]++; ! 168: ! 169: /* ! 170: * Handle all other files or directories the normal way. ! 171: */ ! 172: for (; i < findcn; i++) { ! 173: if (PCFSEOF(cn)) ! 174: goto hiteof; ! 175: byteoffset = FATOFS(pmp, cn); ! 176: fatblock(pmp, byteoffset, &bn, &bsize, &bo); ! 177: if (bn != bp_bn) { ! 178: if (bp) ! 179: brelse(bp); ! 180: error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); ! 181: if (error) { ! 182: brelse(bp); ! 183: return error; ! 184: } ! 185: bp_bn = bn; ! 186: } ! 187: prevcn = cn; ! 188: cn = getushort(&bp->b_un.b_addr[bo]); ! 189: if (fat12) { ! 190: if (prevcn & 1) ! 191: cn >>= 4; ! 192: cn &= 0x0fff; ! 193: /* ! 194: * Force the special cluster numbers in the range ! 195: * 0x0ff0-0x0fff to be the same as for 16 bit cluster ! 196: * numbers to let the rest of pcfs think it is always ! 197: * dealing with 16 bit fats. ! 198: */ ! 199: if ((cn & 0x0ff0) == 0x0ff0) ! 200: cn |= 0xf000; ! 201: } ! 202: } ! 203: ! 204: if (!PCFSEOF(cn)) { ! 205: if (bp) ! 206: brelse(bp); ! 207: if (bnp) ! 208: *bnp = cntobn(pmp, cn); ! 209: if (cnp) ! 210: *cnp = cn; ! 211: fc_setcache(dep, FC_LASTMAP, i, cn); ! 212: return 0; ! 213: } ! 214: ! 215: hiteof:; ! 216: if (cnp) ! 217: *cnp = i; ! 218: if (bp) ! 219: brelse(bp); ! 220: /* update last file cluster entry in the fat cache */ ! 221: fc_setcache(dep, FC_LASTFC, i-1, prevcn); ! 222: return E2BIG; ! 223: } ! 224: ! 225: /* ! 226: * Find the closest entry in the fat cache to the ! 227: * cluster we are looking for. ! 228: */ ! 229: fc_lookup(dep, findcn, frcnp, fsrcnp) ! 230: struct denode *dep; ! 231: u_long findcn; ! 232: u_long *frcnp; ! 233: u_long *fsrcnp; ! 234: { ! 235: int i; ! 236: u_long cn; ! 237: struct fatcache *closest = 0; ! 238: ! 239: for (i = 0; i < FC_SIZE; i++) { ! 240: cn = dep->de_fc[i].fc_frcn; ! 241: if (cn != FCE_EMPTY && cn <= findcn) { ! 242: if (closest == 0 || cn > closest->fc_frcn) ! 243: closest = &dep->de_fc[i]; ! 244: } ! 245: } ! 246: if (closest) { ! 247: *frcnp = closest->fc_frcn; ! 248: *fsrcnp = closest->fc_fsrcn; ! 249: } ! 250: } ! 251: ! 252: /* ! 253: * Purge the fat cache in denode dep of all entries ! 254: * relating to file relative cluster frcn and beyond. ! 255: */ ! 256: fc_purge(dep, frcn) ! 257: struct denode *dep; ! 258: u_int frcn; ! 259: { ! 260: int i; ! 261: struct fatcache *fcp; ! 262: ! 263: fcp = dep->de_fc; ! 264: for (i = 0; i < FC_SIZE; i++, fcp++) { ! 265: if (fcp->fc_frcn != FCE_EMPTY && fcp->fc_frcn >= frcn) ! 266: fcp->fc_frcn = FCE_EMPTY; ! 267: } ! 268: } ! 269: ! 270: /* ! 271: * Once the first fat is updated the other copies of ! 272: * the fat must also be updated. This function does ! 273: * this. ! 274: * pmp - pcfsmount structure for filesystem to update ! 275: * bp - addr of modified fat block ! 276: * fatbn - block number relative to begin of filesystem ! 277: * of the modified fat block. ! 278: */ ! 279: void ! 280: updateotherfats(pmp, bp, fatbn) ! 281: struct pcfsmount *pmp; ! 282: struct buf *bp; ! 283: u_long fatbn; ! 284: { ! 285: int i; ! 286: struct buf *bpn; ! 287: ! 288: #if defined(PCFSDEBUG) ! 289: printf("updateotherfats(pmp %08x, bp %08x, fatbn %d)\n", ! 290: pmp, bp, fatbn); ! 291: #endif /* defined(PCFSDEBUG) */ ! 292: ! 293: /* ! 294: * Now copy the block(s) of the modified fat to the other ! 295: * copies of the fat and write them out. This is faster ! 296: * than reading in the other fats and then writing them ! 297: * back out. This could tie up the fat for quite a while. ! 298: * Preventing others from accessing it. To prevent us ! 299: * from going after the fat quite so much we use delayed ! 300: * writes, unless they specfied "synchronous" when the ! 301: * filesystem was mounted. If synch is asked for then ! 302: * use bwrite()'s and really slow things down. ! 303: */ ! 304: for (i = 1; i < pmp->pm_FATs; i++) { ! 305: fatbn += pmp->pm_FATsecs; ! 306: /* getblk() never fails */ ! 307: bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount); ! 308: bcopy(bp->b_un.b_addr, bpn->b_un.b_addr, ! 309: bp->b_bcount); ! 310: if (pmp->pm_waitonfat) ! 311: bwrite(bpn); ! 312: else ! 313: bdwrite(bpn); ! 314: } ! 315: } ! 316: ! 317: /* ! 318: * Updating entries in 12 bit fats is a pain in the butt. ! 319: * ! 320: * The following picture shows where nibbles go when ! 321: * moving from a 12 bit cluster number into the appropriate ! 322: * bytes in the FAT. ! 323: * ! 324: * byte m byte m+1 byte m+2 ! 325: * +----+----+ +----+----+ +----+----+ ! 326: * | 0 1 | | 2 3 | | 4 5 | FAT bytes ! 327: * +----+----+ +----+----+ +----+----+ ! 328: * ! 329: * +----+----+----+ +----+----+----+ ! 330: * | 3 0 1 | | 4 5 2 | ! 331: * +----+----+----+ +----+----+----+ ! 332: * cluster n cluster n+1 ! 333: * ! 334: * Where n is even. ! 335: * m = n + (n >> 2) ! 336: * ! 337: * (Function no longer used) ! 338: */ ! 339: ! 340: ! 341: extern inline void ! 342: usemap_alloc (struct pcfsmount *pmp, u_long cn) ! 343: { ! 344: pmp->pm_inusemap[cn / 8] |= 1 << (cn % 8); ! 345: pmp->pm_freeclustercount--; ! 346: /* This assumes that the lowest available cluster was allocated */ ! 347: pmp->pm_lookhere = cn + 1; ! 348: } ! 349: ! 350: extern inline void ! 351: usemap_free (struct pcfsmount *pmp, u_long cn) ! 352: { ! 353: pmp->pm_freeclustercount++; ! 354: pmp->pm_inusemap[cn / 8] &= ~(1 << (cn % 8)); ! 355: if (pmp->pm_lookhere > cn) ! 356: pmp->pm_lookhere = cn; ! 357: } ! 358: ! 359: int ! 360: clusterfree(pmp, cluster, oldcnp) ! 361: struct pcfsmount *pmp; ! 362: u_long cluster; ! 363: u_long *oldcnp; ! 364: { ! 365: int error; ! 366: u_long oldcn; ! 367: ! 368: error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, PCFSFREE); ! 369: if (error == 0) { ! 370: /* ! 371: * If the cluster was successfully marked free, then update the count of ! 372: * free clusters, and turn off the "allocated" bit in the ! 373: * "in use" cluster bit map. ! 374: */ ! 375: usemap_free(pmp, cluster); ! 376: if (oldcnp) ! 377: *oldcnp = oldcn; ! 378: } ! 379: return error; ! 380: } ! 381: ! 382: /* ! 383: * Get or Set or 'Get and Set' the cluster'th entry in the ! 384: * fat. ! 385: * function - whether to get or set a fat entry ! 386: * pmp - address of the pcfsmount structure for the ! 387: * filesystem whose fat is to be manipulated. ! 388: * cluster - which cluster is of interest ! 389: * oldcontents - address of a word that is to receive ! 390: * the contents of the cluster'th entry if this is ! 391: * a get function ! 392: * newcontents - the new value to be written into the ! 393: * cluster'th element of the fat if this is a set ! 394: * function. ! 395: * ! 396: * This function can also be used to free a cluster ! 397: * by setting the fat entry for a cluster to 0. ! 398: * ! 399: * All copies of the fat are updated if this is a set ! 400: * function. ! 401: * NOTE: ! 402: * If fatentry() marks a cluster as free it does not ! 403: * update the inusemap in the pcfsmount structure. ! 404: * This is left to the caller. ! 405: */ ! 406: int ! 407: fatentry(function, pmp, cn, oldcontents, newcontents) ! 408: int function; ! 409: struct pcfsmount *pmp; ! 410: u_long cn; ! 411: u_long *oldcontents; ! 412: u_long newcontents; ! 413: { ! 414: int error; ! 415: u_long readcn; ! 416: u_long bn, bo, bsize, byteoffset; ! 417: struct buf *bp; ! 418: /*printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n", ! 419: function, pmp, cluster, oldcontents, newcontents);*/ ! 420: ! 421: #ifdef DIAGNOSTIC ! 422: /* ! 423: * Be sure they asked us to do something. ! 424: */ ! 425: if ((function & (FAT_SET | FAT_GET)) == 0) { ! 426: printf("fatentry(): function code doesn't specify get or set\n"); ! 427: return EINVAL; ! 428: } ! 429: ! 430: /* ! 431: * If they asked us to return a cluster number ! 432: * but didn't tell us where to put it, give them ! 433: * an error. ! 434: */ ! 435: if ((function & FAT_GET) && oldcontents == NULL) { ! 436: printf("fatentry(): get function with no place to put result\n"); ! 437: return EINVAL; ! 438: } ! 439: #endif ! 440: ! 441: /* ! 442: * Be sure the requested cluster is in the filesystem. ! 443: */ ! 444: if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster) ! 445: return EINVAL; ! 446: ! 447: byteoffset = FATOFS(pmp, cn); ! 448: fatblock(pmp, byteoffset, &bn, &bsize, &bo); ! 449: error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); ! 450: if (error) { ! 451: brelse(bp); ! 452: return error; ! 453: } ! 454: if (function & FAT_GET) { ! 455: readcn = getushort(&bp->b_un.b_addr[bo]); ! 456: if (FAT12(pmp)) { ! 457: if (cn & 1) ! 458: readcn >>= 4; ! 459: readcn &= 0x0fff; ! 460: /* map certain 12 bit fat entries to 16 bit */ ! 461: if ((readcn & 0x0ff0) == 0x0ff0) ! 462: readcn |= 0xf000; ! 463: } ! 464: *oldcontents = readcn; ! 465: } ! 466: if (function & FAT_SET) { ! 467: if (FAT12(pmp)) { ! 468: readcn = getushort(&bp->b_un.b_addr[bo]); ! 469: if (cn & 1) { ! 470: readcn &= 0x000f; ! 471: readcn |= (newcontents << 4); ! 472: } ! 473: else { ! 474: readcn &= 0xf000; ! 475: readcn |= (newcontents << 0); ! 476: } ! 477: putushort(&bp->b_un.b_addr[bo], readcn); ! 478: } ! 479: else ! 480: putushort(&bp->b_un.b_addr[bo], newcontents); ! 481: updateotherfats(pmp, bp, bn); ! 482: /* ! 483: * Write out the first fat last. ! 484: */ ! 485: if (pmp->pm_waitonfat) ! 486: bwrite(bp); ! 487: else ! 488: bdwrite(bp); ! 489: bp = NULL; ! 490: pmp->pm_fmod++; ! 491: } ! 492: if (bp) ! 493: brelse(bp); ! 494: return 0; ! 495: } ! 496: ! 497: /* ! 498: * Allocate a free cluster. ! 499: * pmp - ! 500: * retcluster - put the allocated cluster's number here. ! 501: * fillwith - put this value into the fat entry for the ! 502: * allocated cluster. ! 503: */ ! 504: int ! 505: clusteralloc(pmp, retcluster, fillwith) ! 506: struct pcfsmount *pmp; ! 507: u_long *retcluster; ! 508: u_long fillwith; ! 509: { ! 510: int error; ! 511: u_long cn; ! 512: u_long idx, max_idx, bit, map; ! 513: ! 514: max_idx = pmp->pm_maxcluster / 8; ! 515: for (idx = pmp->pm_lookhere / 8; idx <= max_idx; idx++) { ! 516: map = pmp->pm_inusemap[idx]; ! 517: if (map != 0xff) { ! 518: for (bit = 0; bit < 8; bit++) { ! 519: if ((map & (1 << bit)) == 0) { ! 520: cn = idx * 8 + bit; ! 521: goto found_one; ! 522: } ! 523: } ! 524: } ! 525: } ! 526: return ENOSPC; ! 527: ! 528: found_one:; ! 529: error = fatentry(FAT_SET, pmp, cn, 0, fillwith); ! 530: if (error == 0) { ! 531: usemap_alloc(pmp, cn); ! 532: *retcluster = cn; ! 533: } ! 534: #if defined(PCFSDEBUG) ! 535: printf("clusteralloc(): allocated cluster %d\n", cn); ! 536: #endif /* defined(PCFSDEBUG) */ ! 537: return error; ! 538: } ! 539: ! 540: /* ! 541: * Free a chain of clusters. ! 542: * pmp - address of the pcfs mount structure for the ! 543: * filesystem containing the cluster chain to be freed. ! 544: * startcluster - number of the 1st cluster in the chain ! 545: * of clusters to be freed. ! 546: */ ! 547: int ! 548: freeclusterchain(pmp, startcluster) ! 549: struct pcfsmount *pmp; ! 550: u_long startcluster; ! 551: { ! 552: u_long nextcluster; ! 553: int error = 0; ! 554: ! 555: while (startcluster >= CLUST_FIRST && startcluster <= pmp->pm_maxcluster) { ! 556: error = clusterfree(pmp, startcluster, &nextcluster); ! 557: if (error) { ! 558: printf("freeclusterchain(): free failed, cluster %d\n", ! 559: startcluster); ! 560: break; ! 561: } ! 562: startcluster = nextcluster; ! 563: } ! 564: return error; ! 565: } ! 566: ! 567: /* ! 568: * Read in fat blocks looking for free clusters. ! 569: * For every free cluster found turn off its ! 570: * corresponding bit in the pm_inusemap. ! 571: */ ! 572: int ! 573: fillinusemap(pmp) ! 574: struct pcfsmount *pmp; ! 575: { ! 576: struct buf *bp = NULL; ! 577: u_long cn, readcn; ! 578: int error; ! 579: int fat12 = FAT12(pmp); ! 580: u_long bn, bo, bsize, byteoffset; ! 581: ! 582: /* ! 583: * Mark all clusters in use, we mark the free ones in the ! 584: * fat scan loop further down. ! 585: */ ! 586: for (cn = 0; cn < (pmp->pm_maxcluster >> 3) + 1; cn++) ! 587: pmp->pm_inusemap[cn] = 0xff; ! 588: ! 589: /* ! 590: * Figure how many free clusters are in the filesystem ! 591: * by ripping thougth the fat counting the number of ! 592: * entries whose content is zero. These represent free ! 593: * clusters. ! 594: */ ! 595: pmp->pm_freeclustercount = 0; ! 596: pmp->pm_lookhere = pmp->pm_maxcluster + 1; ! 597: for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) { ! 598: byteoffset = FATOFS(pmp, cn); ! 599: bo = byteoffset % pmp->pm_fatblocksize; ! 600: if (!bo || !bp) { ! 601: /* Read new FAT block */ ! 602: if (bp) ! 603: brelse(bp); ! 604: fatblock(pmp, byteoffset, &bn, &bsize, NULL); ! 605: error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp); ! 606: if (error) { ! 607: brelse(bp); ! 608: return error; ! 609: } ! 610: } ! 611: readcn = getushort(&bp->b_un.b_addr[bo]); ! 612: if (fat12) { ! 613: if (cn & 1) ! 614: readcn >>= 4; ! 615: readcn &= 0x0fff; ! 616: } ! 617: ! 618: if (readcn == 0) ! 619: usemap_free(pmp, cn); ! 620: } ! 621: brelse(bp); ! 622: return 0; ! 623: } ! 624: ! 625: /* ! 626: * Allocate a new cluster and chain it onto the end of the ! 627: * file. ! 628: * dep - the file to extend ! 629: * bpp - where to return the address of the buf header for the ! 630: * new file block ! 631: * ncp - where to put cluster number of the newly allocated file block ! 632: * If this pointer is 0, do not return the cluster number. ! 633: * ! 634: * NOTE: ! 635: * This function is not responsible for turning on the DEUPD ! 636: * bit if the de_flag field of the denode and it does not ! 637: * change the de_FileSize field. This is left for the caller ! 638: * to do. ! 639: */ ! 640: int ! 641: extendfile(dep, bpp, ncp) ! 642: struct denode *dep; ! 643: struct buf **bpp; ! 644: u_int *ncp; ! 645: { ! 646: int error = 0; ! 647: u_long frcn; ! 648: u_long cn; ! 649: struct pcfsmount *pmp = dep->de_pmp; ! 650: ! 651: /* ! 652: * Don't try to extend the root directory ! 653: */ ! 654: if (DETOV(dep)->v_flag & VROOT) { ! 655: printf("extendfile(): attempt to extend root directory\n"); ! 656: return ENOSPC; ! 657: } ! 658: ! 659: /* ! 660: * If the "file's last cluster" cache entry is empty, ! 661: * and the file is not empty, ! 662: * then fill the cache entry by calling pcbmap(). ! 663: */ ! 664: fc_fileextends++; ! 665: if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY && ! 666: dep->de_StartCluster != 0) { ! 667: fc_lfcempty++; ! 668: error = pcbmap(dep, 0xffff, 0, &cn); ! 669: /* we expect it to return E2BIG */ ! 670: if (error != E2BIG) ! 671: return error; ! 672: error = 0; ! 673: } ! 674: ! 675: /* ! 676: * Allocate another cluster and chain onto the end of the file. ! 677: * If the file is empty we make de_StartCluster point to the ! 678: * new block. Note that de_StartCluster being 0 is sufficient ! 679: * to be sure the file is empty since we exclude attempts to ! 680: * extend the root directory above, and the root dir is the ! 681: * only file with a startcluster of 0 that has blocks allocated ! 682: * (sort of). ! 683: */ ! 684: if (error = clusteralloc(pmp, &cn, CLUST_EOFE)) ! 685: return error; ! 686: if (dep->de_StartCluster == 0) { ! 687: dep->de_StartCluster = cn; ! 688: frcn = 0; ! 689: } else { ! 690: error = fatentry(FAT_SET, pmp, dep->de_fc[FC_LASTFC].fc_fsrcn, ! 691: 0, cn); ! 692: if (error) { ! 693: clusterfree(pmp, cn, NULL); ! 694: return error; ! 695: } ! 696: ! 697: frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1; ! 698: } ! 699: ! 700: /* ! 701: * Update the "last cluster of the file" entry in the denode's ! 702: * fat cache. ! 703: */ ! 704: fc_setcache(dep, FC_LASTFC, frcn, cn); ! 705: ! 706: /* ! 707: * Get the buf header for the new block of the file. ! 708: */ ! 709: if (dep->de_Attributes & ATTR_DIRECTORY) ! 710: *bpp = getblk(pmp->pm_devvp, cntobn(pmp, cn), ! 711: pmp->pm_bpcluster); ! 712: else ! 713: *bpp = getblk(DETOV(dep), frcn, pmp->pm_bpcluster); ! 714: clrbuf(*bpp); ! 715: ! 716: if (dep->de_Attributes & ATTR_DIRECTORY) ! 717: /* If we extend a directory, me must record the new size */ ! 718: dep->de_FileSize = (frcn + 1) * pmp->pm_bpcluster; ! 719: ! 720: /* ! 721: * Give them the filesystem relative cluster number ! 722: * if they want it. ! 723: */ ! 724: if (ncp) ! 725: *ncp = cn; ! 726: return 0; ! 727: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.