]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/hfs/hfscommon/Misc/FileExtentMapping.c
xnu-792.24.17.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Misc / FileExtentMapping.c
index 92ae16ad6fb38034e3f6b557b3c35dc2da2e4a46..76c6a407acc48fef35bded000795c49dcef233e2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  * 
  * 
  * @APPLE_LICENSE_HEADER_END@
  */
-/*
-       File:           FileExtentMapping.c
-
-       Contains:       xxx put contents here xxx
-
-       Version:        HFS Plus 1.0
-
-       Written by:     Dave Heller, Mark Day
-
-       Copyright:      © 1996-1999 by Apple Computer, Inc., all rights reserved.
-
-       File Ownership:
-
-               DRI:                            Mark Day
-
-               Other Contact:          xxx put other contact here xxx
-
-               Technology:                     xxx put technology here xxx
-
-       Writers:
-
-               (DSH)   Deric Horn
-               (msd)   Mark Day
-               (djb)   Don Brady
-
-       Change History (most recent first):
-         <MacOSX>        9/9/99        djb             Fix fcbModifiedMask flag testing logic.
-         <MacOSX>       8/25/98        djb             Flush extents b-tree header if dirty (2371088).
-         <MacOSX>       6/30/98        djb             Add functions NodesAreContiguous and ExtentsAreIntegral (for radar #2249539).
-         <MacOSX>       6/23/98        djb             Changed DeallocFile to DeleteFile which now deletes the catalog record.
-                                                                       Fixed UpdateExtentRecord to pass correct fcb to Btree routines. Fixed
-                                                                       hfs+ bug in CreateExtentRecord (double dereference).
-         <MacOSX>       5/20/98        djb             In ExtendFileC don't lie about the peof! (radar #2230094).
-         <MacOSX>       4/17/98        djb             Add VCB locking.
-         <MacOSX>        4/2/98        djb             Switch over to real BTree interface (no more BTreeWrapper.c).
-         <MacOSX>       3/31/98        djb             Sync up with final HFSVolumes.h header file.
-
-         <CS24>         1/23/98        msd             Bug 2208024: AllocContig is actually allocating one extent even
-                                                                       though there is not enough contiguous space.
-         <CS23>         12/2/97        DSH             GetFCBExtentRecord no longer static so DFA can use it.
-         <CS22>        10/20/97        msd             When allocating more space for a file, do the clump size
-                                                                       calculations in ExtendFileC, not BlockAllocate. Undo change from
-                                                                       <CS18>.
-         <CS21>        10/17/97        msd             Conditionalize DebugStrs.
-         <CS20>        10/16/97        msd             Simplify the code path for MapFileBlockC (logical to physical
-                                                                       block mapping) in the typical case where the file isn't
-                                                                       fragmented so badly that it has extents in the extents B-tree.
-                                                                       Simplified some of the calculations for all cases.
-         <CS19>        10/13/97        DSH             FindExtentRecord & DeleteExtentRecord are also being used by DFA
-                                                                       no longer static.
-         <CS18>         10/6/97        msd             When extending a file, set the physical EOF to include any extra
-                                                                       space allocated due to a file's clump size.
-         <CS17>         9/19/97        msd             Remove the MapLogicalToPhysical SPI. It was never used and is
-                                                                       not being tested anyway.
-         <CS16>          9/5/97        msd             In CompareExtentKeys and CompareExtentKeysPlus, use the symbolic
-                                                                       constants for key length. Don't DebugStr unless DEBUG_BUILD is
-                                                                       set.
-         <CS15>         7/24/97        djb             Add instrumentation to MapFileBlockC
-         <CS14>         7/16/97        DSH             FilesInternal.i renamed FileMgrInternal.i to avoid name
-                                                                       collision
-         <CS13>         7/15/97        DSH             AdjEOF() mark the FCB as modified. (1664389)
-         <CS12>          7/8/97        DSH             Loading PrecompiledHeaders from define passed in on C line
-         <CS11>          7/3/97        msd             Bug #1663518. Remove DebugStr when setting the FCB extent record
-                                                                       for a volume control file.
-         <CS10>         6/27/97        msd             Moved enum kFirstFileRefnum to FilesInternal.
-          <CS9>         6/24/97        djb             Include "CatalogPrivate.h"
-          <CS8>         6/16/97        msd             Finish implementation of CreateLargeFile SPI.
-          <CS7>         6/12/97        msd             Add stub for CreateLargeFile SPI.
-          <CS6>          6/5/97        msd             Add MapLogicalToPhysical.
-          <CS5>          6/2/97        msd             In TruncateFileC, don't update the extent record unless it was
-                                                                       actually changed (prevents extra updates when truncating to the
-                                                                       end of the extent, and it is the last extent of the file.) Added
-                                                                       an AdjustEOF routine called by the assembly AdjEOF routine. It
-                                                                       copies the EOF, physical length, and extent information from one
-                                                                       FCB to all other FCBs for that fork.
-          <CS4>         5/20/97        DSH             Removed const declaration in MapFileBlocC, const is benign when
-                                                                       passing by value, and SC requires it to match prototype.
-          <CS3>         5/15/97        msd             Change enum kResourceForkType from -1 to 0xFF since it is now
-                                                                       unsigned. Change all forkType parameters to UInt8.
-          <CS2>          5/7/97        msd             When checking for an unused extent descriptor, check the length,
-                                                                       not the starting block.
-          <CS1>         4/24/97        djb             first checked in
-        <HFS25>         4/11/97        DSH             use extended VCB fields catalogRefNum, and extentsRefNum.
-        <HFS24>          4/4/97        djb             Get in sync with volume format changes.
-        <HFS23>         3/17/97        DSH             Casting to compile with SC.
-        <HFS22>         2/26/97        msd             Add instrumentation in ExtendFileC and TruncateFileC. In
-                                                                       CompareExtentKeys and CompareExtentKeysPlus, make sure the key
-                                                                       lengths are correct.
-        <HFS21>          2/5/97        msd             The comparison with fsBTStartOfIterationErr didn't work because
-                                                                       the enum is an unsigned long; it is now casted to an OSErr
-                                                                       before comparing.
-        <HFS20>         1/31/97        msd             In FindExtentRecord, turn an fsBTStartOfIterationErr error into
-                                                                       btNotFound.
-        <HFS19>         1/28/97        msd             Fixed bug in MapFileBlockC where it returned the wrong number of
-                                                                       bytes available at the given block number.  This could
-                                                                       potentially cause programs to read or write over other files.
-        <HFS18>         1/16/97        djb             Extent key compare procs now return SInt32. Fixed
-                                                                       UpdateExtentRecord - it was passing a pointer to an ExtentKey
-                                                                       pointer.
-        <HFS17>         1/10/97        msd             Change TruncateFileC to call DellocateFork when the new PEOF is
-                                                                       0. Fixes a fxRangeErr returned when no extents existed.
-        <HFS16>          1/6/97        msd             Previous change prevents extent records from being removed if
-                                                                       the files new PEOF is in the local (FCB/catalog) extents.
-        <HFS15>          1/3/97        djb             Temp fix in TruncateFileC to prevent unwanted calls to
-                                                                       TruncateExtents.
-        <HFS14>        12/23/96        msd             Previous change to SearchExtentFile didn't set up the outputs
-                                                                       for hint and key when the FCB extent record wasn't full.
-        <HFS13>        12/20/96        msd             In SearchExtentFile, don't bother searching the extents file if
-                                                                       the FCB's extent record wasn't full, or if the FCB was for the
-                                                                       extents file itself. Modified SearchExtentRecord to return a
-                                                                       Boolean to indicate that the record was not full.
-        <HFS12>        12/19/96        DSH             Changed refs from VCB to ExtendedVCB
-        <HFS11>        12/19/96        djb             Updated for new B-tree Manager interface.
-        <HFS10>        12/12/96        djb             Really use new SPI for GetCatalogNode.
-         <HFS9>        12/12/96        djb             Use new Catalog SPI for GetCatalogNode. Added Mark's changes to
-                                                                       MapFileBlockC.
-         <HFS8>        12/11/96        msd             TruncateFileC must always release extents, even if PEOF hasn't
-                                                                       changed (since allocation may have been rounded up due to clump
-                                                                       size).
-         <HFS7>        12/10/96        msd             Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
-         <HFS6>         12/4/96        DSH             Precompiled headers
-         <HFS5>        11/26/96        msd             Add an exported routine to grow the parallel FCB table to
-                                                                       accomodate the HFS+ ExtentRecord.
-         <HFS4>        11/26/96        msd             Convert internal routines to use ExtentKey and ExtentRecord
-                                                                       (instead of the raw HFS structures).
-         <HFS3>        11/21/96        msd             Added CompareExtentKeysPlus().
-         <HFS2>        11/20/96        msd             Finish porting FXM to C.
-         <HFS1>         11/6/96        DKH             first checked in
-
-*/
 
 
 #include "../../hfs.h"
 
 #include "../headers/FileMgrInternal.h"
 #include "../headers/BTreesInternal.h"
-#include "../headers/CatalogPrivate.h"         // calling a private catalog routine (LocateCatalogNode)
-
-#include "../headers/HFSInstrumentation.h"
 
 #include <sys/malloc.h>
  
 ============================================================
 Public (Exported) Routines:
 ============================================================
-       DeAllocFile             Deallocate all disk space allocated to a specified file.
-                                       Both forks are deallocated.
 
        ExtendFileC             Allocate more space to a given file.
 
@@ -195,21 +60,8 @@ Public (Exported) Routines:
        FlushExtentFile
                                        Flush the extents file for a given volume.
 
-       GrowParallelFCBs
-                                       Make sure the parallel FCB entries are big enough to support
-                                       the HFS+ ExtentRecord.  If not, the array is grown and the
-                                       pre-existing data copied over.
 
-       AdjustEOF
-                                       Copy EOF, physical length, and extent records from one FCB
-                                       to all other FCBs for that fork.  This is used when a file is
-                                       grown or shrunk as the result of a Write, SetEOF, or Allocate.
 
-       MapLogicalToPhysical
-                                       Map some position in a file to a volume block number.  Also
-                                       returns the number of contiguous bytes that are mapped there.
-                                       This is a queued HFSDispatch call that does the equivalent of
-                                       MapFileBlockC, using a parameter block.
 
 ============================================================
 Internal Routines:
@@ -239,27 +91,22 @@ Internal Routines:
                                        and was in the extents file, then delete the record instead.
 */
 
+static const SInt64 kTwoGigabytes = 0x80000000LL;
+
 enum
 {
-       kTwoGigabytes                   = (UInt32) 0x80000000,
-       
        kDataForkType                   = 0,
        kResourceForkType               = 0xFF,
        
-       kPreviousRecord                 = -1,
-       
-       kSectorSize                             = 512           // Size of a physical sector
+       kPreviousRecord                 = -1
 };
 
-void HFSToHFSPlusExtents(
-       const HFSExtentRecord   oldExtents,
-       HFSPlusExtentRecord             newExtents);
 
-OSErr HFSPlusToHFSExtents(
+static OSErr HFSPlusToHFSExtents(
        const HFSPlusExtentRecord       oldExtents,
        HFSExtentRecord                         newExtents);
 
-OSErr FindExtentRecord(
+static OSErr FindExtentRecord(
        const ExtendedVCB               *vcb,
        UInt8                                   forkType,
        UInt32                                  fileID,
@@ -269,25 +116,25 @@ OSErr FindExtentRecord(
        HFSPlusExtentRecord             foundData,
        UInt32                                  *foundHint);
 
-OSErr DeleteExtentRecord(
+static OSErr DeleteExtentRecord(
        const ExtendedVCB               *vcb,
        UInt8                                   forkType,
        UInt32                                  fileID,
        UInt32                                  startBlock);
 
 static OSErr CreateExtentRecord(
-       const ExtendedVCB               *vcb,
+       ExtendedVCB             *vcb,
        HFSPlusExtentKey                *key,
        HFSPlusExtentRecord             extents,
        UInt32                                  *hint);
 
 
-OSErr GetFCBExtentRecord(
+static OSErr GetFCBExtentRecord(
        const FCB                               *fcb,
        HFSPlusExtentRecord             extents);
 
 static OSErr SearchExtentFile(
-       const ExtendedVCB               *vcb,
+       ExtendedVCB             *vcb,
        const FCB                               *fcb,
        SInt64                                  filePosition,
        HFSPlusExtentKey                *foundExtentKey,
@@ -297,7 +144,7 @@ static OSErr SearchExtentFile(
        UInt32                                  *endingFABNPlusOne );
 
 static OSErr SearchExtentRecord(
-       const ExtendedVCB               *vcb,
+       ExtendedVCB             *vcb,
        UInt32                                  searchFABN,
        const HFSPlusExtentRecord       extentData,
        UInt32                                  extentDataStartFABN,
@@ -326,20 +173,12 @@ static OSErr TruncateExtents(
        Boolean *                       recordDeleted);
 
 static OSErr UpdateExtentRecord (
-       const ExtendedVCB               *vcb,
+       ExtendedVCB             *vcb,
        FCB                                             *fcb,
        const HFSPlusExtentKey  *extentFileKey,
        const HFSPlusExtentRecord       extentData,
        UInt32                                  extentBTreeHint);
 
-static OSErr MapFileBlockFromFCB(
-       const ExtendedVCB               *vcb,
-       const FCB                               *fcb,
-       SInt64                                  offset,                 // Desired offset in bytes from start of file
-       UInt32                                  *firstFABN,             // FABN of first block of found extent
-       UInt32                                  *firstBlock,    // Corresponding allocation block number
-       UInt32                                  *nextFABN);             // FABN of block after end of extent
-
 static Boolean ExtentsAreIntegral(
        const HFSPlusExtentRecord extentRecord,
        UInt32          mask,
@@ -368,7 +207,7 @@ static Boolean ExtentsAreIntegral(
 //                                     fourth entry will be zeroes.
 //             foundHint       The BTree hint to find the node again
 //_________________________________________________________________________________
-OSErr FindExtentRecord(
+static OSErr FindExtentRecord(
        const ExtendedVCB       *vcb,
        UInt8                           forkType,
        UInt32                          fileID,
@@ -379,22 +218,24 @@ OSErr FindExtentRecord(
        UInt32                          *foundHint)
 {
        FCB *                           fcb;
-       BTreeIterator           btIterator;
+       BTreeIterator           *btIterator;
        FSBufferDescriptor      btRecord;
        OSErr                           err;
        UInt16                          btRecordSize;
        
        err = noErr;
-       *foundHint = 0;
+       if (foundHint)
+               *foundHint = 0;
        fcb = GetFileControlBlock(vcb->extentsRefNum);
        
-       (void) BTInvalidateHint(&btIterator);
+       MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+       bzero(btIterator, sizeof(*btIterator));
 
        if (vcb->vcbSigWord == kHFSSigWord) {
                HFSExtentKey *          extentKeyPtr;
                HFSExtentRecord         extentData;
 
-               extentKeyPtr = (HFSExtentKey*) &btIterator.key;
+               extentKeyPtr = (HFSExtentKey*) &btIterator->key;
                extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength;
                extentKeyPtr->forkType = forkType;
                extentKeyPtr->fileID = fileID;
@@ -404,10 +245,10 @@ OSErr FindExtentRecord(
                btRecord.itemSize = sizeof(HFSExtentRecord);
                btRecord.itemCount = 1;
 
-               err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
+               err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator);
 
                if (err == btNotFound && allowPrevious) {
-                       err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
+                       err = BTIterateRecord(fcb, kBTreePrevRecord, btIterator, &btRecord, &btRecordSize);
 
                        //      A previous record may not exist, so just return btNotFound (like we would if
                        //      it was for the wrong file/fork).
@@ -424,14 +265,15 @@ OSErr FindExtentRecord(
                if (err == noErr) {
                        UInt16  i;
                        
-                       //      Copy the found key back for the caller
-                       foundKey->keyLength     = kHFSPlusExtentKeyMaximumLength;
-                       foundKey->forkType              = extentKeyPtr->forkType;
-                       foundKey->pad                   = 0;
-                       foundKey->fileID                = extentKeyPtr->fileID;
-                       foundKey->startBlock    = extentKeyPtr->startBlock;
-                       
-                       //      Copy the found data back for the caller
+                       // Copy the found key back for the caller
+                       if (foundKey) {
+                               foundKey->keyLength  = kHFSPlusExtentKeyMaximumLength;
+                               foundKey->forkType   = extentKeyPtr->forkType;
+                               foundKey->pad        = 0;
+                               foundKey->fileID     = extentKeyPtr->fileID;
+                               foundKey->startBlock = extentKeyPtr->startBlock;
+                       }
+                       // Copy the found data back for the caller
                        foundData[0].startBlock = extentData[0].startBlock;
                        foundData[0].blockCount = extentData[0].blockCount;
                        foundData[1].startBlock = extentData[1].startBlock;
@@ -450,7 +292,7 @@ OSErr FindExtentRecord(
                HFSPlusExtentKey *      extentKeyPtr;
                HFSPlusExtentRecord     extentData;
 
-               extentKeyPtr = (HFSPlusExtentKey*) &btIterator.key;
+               extentKeyPtr = (HFSPlusExtentKey*) &btIterator->key;
                extentKeyPtr->keyLength  = kHFSPlusExtentKeyMaximumLength;
                extentKeyPtr->forkType   = forkType;
                extentKeyPtr->pad                = 0;
@@ -461,10 +303,10 @@ OSErr FindExtentRecord(
                btRecord.itemSize = sizeof(HFSPlusExtentRecord);
                btRecord.itemCount = 1;
 
-               err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
+               err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator);
 
                if (err == btNotFound && allowPrevious) {
-                       err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize);
+                       err = BTIterateRecord(fcb, kBTreePrevRecord, btIterator, &btRecord, &btRecordSize);
 
                        //      A previous record may not exist, so just return btNotFound (like we would if
                        //      it was for the wrong file/fork).
@@ -479,34 +321,49 @@ OSErr FindExtentRecord(
                }
 
                if (err == noErr) {
-                       //      Copy the found key back for the caller
-                       BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey));
-                       //      Copy the found data back for the caller
+                       // Copy the found key back for the caller
+                       if (foundKey)
+                               BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey));
+                       // Copy the found data back for the caller
                        BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord));
                }
        }
-       
-       *foundHint = btIterator.hint.nodeNum;
+
+       if (foundHint)
+               *foundHint = btIterator->hint.nodeNum;
+       FREE(btIterator, M_TEMP);       
        return err;
 }
 
 
 
 static OSErr CreateExtentRecord(
-       const ExtendedVCB       *vcb,
+       ExtendedVCB     *vcb,
        HFSPlusExtentKey        *key,
        HFSPlusExtentRecord     extents,
        UInt32                          *hint)
 {
-       BTreeIterator           btIterator;
+       BTreeIterator * btIterator;
        FSBufferDescriptor      btRecord;
-       UInt16                          btRecordSize;
-       OSErr                           err;
+       UInt16  btRecordSize;
+       int  lockflags;
+       OSErr  err;
        
        err = noErr;
        *hint = 0;
-       (void) BTInvalidateHint(&btIterator);
-       
+
+       MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+       bzero(btIterator, sizeof(*btIterator));
+
+       /*
+        * The lock taken by callers of ExtendFileC is speculative and
+        * only occurs when the file already has overflow extents. So
+        * We need to make sure we have the lock here.  The extents
+        * btree lock can be nested (its recursive) so we always take
+        * it here.
+        */
+       lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
+
        if (vcb->vcbSigWord == kHFSSigWord) {
                HFSExtentKey *          keyPtr;
                HFSExtentRecord         data;
@@ -516,7 +373,7 @@ static OSErr CreateExtentRecord(
                btRecord.itemSize = btRecordSize;
                btRecord.itemCount = 1;
 
-               keyPtr = (HFSExtentKey*) &btIterator.key;
+               keyPtr = (HFSExtentKey*) &btIterator->key;
                keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
                keyPtr->forkType        = key->forkType;
                keyPtr->fileID          = key->fileID;
@@ -530,35 +387,42 @@ static OSErr CreateExtentRecord(
                btRecord.itemSize = btRecordSize;
                btRecord.itemCount = 1;
 
-               BlockMoveData(key, &btIterator.key, sizeof(HFSPlusExtentKey));
+               BlockMoveData(key, &btIterator->key, sizeof(HFSPlusExtentKey));
        }
 
        if (err == noErr)
-               err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator, &btRecord, btRecordSize);
+               err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator, &btRecord, btRecordSize);
 
        if (err == noErr)
-               *hint = btIterator.hint.nodeNum;
+               *hint = btIterator->hint.nodeNum;
 
+       (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
+       
+       hfs_systemfile_unlock(vcb, lockflags);
+       
+       FREE(btIterator, M_TEMP);       
        return err;
 }
 
 
-OSErr DeleteExtentRecord(
+static OSErr DeleteExtentRecord(
        const ExtendedVCB       *vcb,
        UInt8                           forkType,
        UInt32                          fileID,
        UInt32                          startBlock)
 {
-       BTreeIterator           btIterator;
+       BTreeIterator * btIterator;
        OSErr                           err;
        
        err = noErr;
-       (void) BTInvalidateHint(&btIterator);
+
+       MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+       bzero(btIterator, sizeof(*btIterator));
        
        if (vcb->vcbSigWord == kHFSSigWord) {
                HFSExtentKey *  keyPtr;
 
-               keyPtr = (HFSExtentKey*) &btIterator.key;
+               keyPtr = (HFSExtentKey*) &btIterator->key;
                keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
                keyPtr->forkType        = forkType;
                keyPtr->fileID          = fileID;
@@ -567,7 +431,7 @@ OSErr DeleteExtentRecord(
        else {          //      HFS Plus volume
                HFSPlusExtentKey *      keyPtr;
 
-               keyPtr = (HFSPlusExtentKey*) &btIterator.key;
+               keyPtr = (HFSPlusExtentKey*) &btIterator->key;
                keyPtr->keyLength       = kHFSPlusExtentKeyMaximumLength;
                keyPtr->forkType        = forkType;
                keyPtr->pad                     = 0;
@@ -575,8 +439,10 @@ OSErr DeleteExtentRecord(
                keyPtr->startBlock      = startBlock;
        }
 
-       err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator);
+       err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator);
+       (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
        
+       FREE(btIterator, M_TEMP);       
        return err;
 }
 
@@ -588,32 +454,20 @@ OSErr DeleteExtentRecord(
 //
 // Function:   Maps a file position into a physical disk address.
 //
-// Input:              A2.L  -  VCB pointer
-//                             (A1,D1.W)  -  FCB pointer
-//                             D4.L  -  number of bytes desired
-//                             D5.L  -  file position (byte address)
-//
-// Output:             D3.L  -  physical start block
-//                             D6.L  -  number of contiguous bytes available (up to D4 bytes)
-//                             D0.L  -  result code                                                                                            <01Oct85>
-//                                                0 = ok
-//                                                FXRangeErr = file position beyond mapped range                       <17Oct85>
-//                                                FXOvFlErr = extents file overflow                                            <17Oct85>
-//                                                other = error                                                                                        <17Oct85>
-//
-// Called By:  Log2Phys (read/write in place), Cache (map a file block).
 //_________________________________________________________________________________
 
+__private_extern__
 OSErr MapFileBlockC (
        ExtendedVCB             *vcb,                           // volume that file resides on
        FCB                             *fcb,                           // FCB of file
        size_t                  numberOfBytes,          // number of contiguous bytes desired
        off_t                   offset,                         // starting offset within file (in bytes)
-       daddr_t                 *startSector,           // first 512-byte sector (NOT an allocation block)
+       daddr64_t               *startSector,           // first sector (NOT an allocation block)
        size_t                  *availableBytes)        // number of contiguous bytes (up to numberOfBytes)
 {
        OSErr                           err;
        UInt32                          allocBlockSize;                 //      Size of the volume's allocation block
+       UInt32                  sectorSize;
        HFSPlusExtentKey        foundKey;
        HFSPlusExtentRecord     foundData;
        UInt32                          foundIndex;
@@ -623,27 +477,20 @@ OSErr MapFileBlockC (
        off_t                           dataEnd;                                // (offset) end of range that is contiguous
        UInt32                          sectorsPerBlock;                // Number of sectors per allocation block
        UInt32                          startBlock;                             // volume allocation block corresponding to firstFABN
-       daddr_t                         temp;
+       daddr64_t                       temp;
        off_t                           tmpOff;
-       
-       
-       LogStartTime(kTraceMapFileBlock);
 
        allocBlockSize = vcb->blockSize;
-       
-       err = MapFileBlockFromFCB(vcb, fcb, offset, &firstFABN, &startBlock, &nextFABN);
-       if (err != noErr) {
-               err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN);
-               if (err == noErr) {
-                       startBlock = foundData[foundIndex].startBlock;
-                       firstFABN = nextFABN - foundData[foundIndex].blockCount;
-               }
+       sectorSize = VCBTOHFS(vcb)->hfs_phys_block_size;
+
+       err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN);
+       if (err == noErr) {
+               startBlock = foundData[foundIndex].startBlock;
+               firstFABN = nextFABN - foundData[foundIndex].blockCount;
        }
        
        if (err != noErr)
        {
-               LogEndTime(kTraceMapFileBlock, err);
-
                return err;
        }
 
@@ -651,22 +498,26 @@ OSErr MapFileBlockC (
        //      Determine the end of the available space.  It will either be the end of the extent,
        //      or the file's PEOF, whichever is smaller.
        //
-       dataEnd = (off_t)((off_t)(nextFABN) * (off_t)(allocBlockSize));         // Assume valid data through end of this extent
-       if (fcb->fcbPLen < dataEnd)                                     // Is PEOF shorter?
-               dataEnd = fcb->fcbPLen;                                 // Yes, so only map up to PEOF
+       dataEnd = (off_t)((off_t)(nextFABN) * (off_t)(allocBlockSize));   // Assume valid data through end of this extent
+       if (((off_t)fcb->ff_blocks * (off_t)allocBlockSize) < dataEnd)    // Is PEOF shorter?
+               dataEnd = (off_t)fcb->ff_blocks * (off_t)allocBlockSize;  // Yes, so only map up to PEOF
        
        //      Compute the number of sectors in an allocation block
-       sectorsPerBlock = allocBlockSize / kSectorSize; // sectors per allocation block
+       sectorsPerBlock = allocBlockSize / sectorSize;  // sectors per allocation block
        
        //
        //      Compute the absolute sector number that contains the offset of the given file
+       //      offset in sectors from start of the extent +
+       //      offset in sectors from start of allocation block space
        //
-       temp = (daddr_t)((offset - (off_t)((off_t)(firstFABN) * (off_t)(allocBlockSize)))/kSectorSize); // offset in sectors from start of the extent
-       temp += startBlock * sectorsPerBlock;                   // offset in sectors from start of allocation block space
-    if (vcb->vcbSigWord == kHFSPlusSigWord)
-        temp += vcb->hfsPlusIOPosOffset/512;  /* offset inside wrapper */
-    else
-        temp += vcb->vcbAlBlSt;                /* offset in sectors from start of volume */
+       temp = (daddr64_t)((offset - (off_t)((off_t)(firstFABN) * (off_t)(allocBlockSize)))/sectorSize);
+       temp += startBlock * sectorsPerBlock;
+
+       /* Add in any volume offsets */
+       if (vcb->vcbSigWord == kHFSPlusSigWord)
+               temp += vcb->hfsPlusIOPosOffset / sectorSize;
+       else
+               temp += vcb->vcbAlBlSt;
        
        //      Return the desired sector for file position "offset"
        *startSector = temp;
@@ -675,12 +526,14 @@ OSErr MapFileBlockC (
        //      Determine the number of contiguous bytes until the end of the extent
        //      (or the amount they asked for, whichever comes first).
        //
-       tmpOff = dataEnd - offset;
-       if (tmpOff > (off_t)(numberOfBytes))
-               *availableBytes = numberOfBytes;        // more there than they asked for, so pin the output
-       else
-               *availableBytes = tmpOff;
-       LogEndTime(kTraceMapFileBlock, noErr);
+       if (availableBytes)
+       {
+               tmpOff = dataEnd - offset;
+               if (tmpOff > (off_t)(numberOfBytes))
+                       *availableBytes = numberOfBytes;  // more there than they asked for, so pin the output
+               else
+                       *availableBytes = tmpOff;
+       }
 
        return noErr;
 }
@@ -762,6 +615,16 @@ static OSErr TruncateExtents(
        UInt32                          hint;
        HFSPlusExtentKey        key;
        HFSPlusExtentRecord     extents;
+       int  lockflags;
+
+       /*
+        * The lock taken by callers of TruncateFileC is speculative and
+        * only occurs when the file already has overflow extents. So
+        * We need to make sure we have the lock here.  The extents
+        * btree lock can be nested (its recursive) so we always take
+        * it here.
+        */
+       lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
 
        while (true) {
                err = FindExtentRecord(vcb, forkType, fileID, startBlock, false, &key, extents, &hint);
@@ -780,6 +643,7 @@ static OSErr TruncateExtents(
                *recordDeleted = true;
                startBlock += numberExtentsReleased;
        }
+       hfs_systemfile_unlock(vcb, lockflags);
        
        return err;
 }
@@ -818,92 +682,33 @@ static OSErr DeallocateFork(
 //     Function:       Flushes the extent file for a specified volume
 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
 
+__private_extern__
 OSErr FlushExtentFile( ExtendedVCB *vcb )
 {
        FCB *   fcb;
        OSErr   err;
+       int  lockflags;
        
        fcb = GetFileControlBlock(vcb->extentsRefNum);
+
+       lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
        err = BTFlushPath(fcb);
+       hfs_systemfile_unlock(vcb, lockflags);
+
        if ( err == noErr )
        {
                // If the FCB for the extent "file" is dirty, mark the VCB as dirty.
                
-        if ((fcb->fcbFlags & fcbModifiedMask) != 0)
+        if (FTOC(fcb)->c_flag & C_MODIFIED)
                {
                        MarkVCBDirty( vcb );
-                       err = FlushVolumeControlBlock( vcb );
+               //      err = FlushVolumeControlBlock( vcb );
                }
        }
        
        return( err );
 }
 
-//-------------------------------------------------------------------------------
-//     Routine:        DeleteFile
-//
-//     Function:       De-allocates all disk space allocated to a specified file 
-//                             including the space used by the catalog (ie the catalog record).
-//                             The space occupied by both forks is also deallocated.
-//
-//-------------------------------------------------------------------------------
-
-OSErr DeleteFile( ExtendedVCB *vcb, HFSCatalogNodeID parDirID, ConstUTF8Param catalogName, UInt32 catalogHint )
-{
-       OSErr                   err;
-       OSErr                   errDF, errRF;
-       CatalogNodeData catalogData;
-       Boolean                 recordDeleted;
-       
-       recordDeleted = false;
-       
-       INIT_CATALOGDATA(&catalogData, kCatNameNoCopyName);
-       
-       // Find catalog data in catalog
-    err = GetCatalogNode( vcb, parDirID, catalogName, kUndefinedStrLen, catalogHint, &catalogData, &catalogHint);
-       if( err != noErr )
-               goto Exit;
-
-       
-       // Check to make sure record is for a file
-       if ( catalogData.cnd_type != kCatalogFileNode )
-       {
-               err = notAFileErr;
-               goto Exit;
-       }
-       
-       //
-       // Always delete the Catalog record first (to minimize disk corruption)
-       //
-       err = DeleteCatalogNode(vcb, parDirID, catalogName, catalogHint);
-       if( err != noErr )
-               goto Exit;
-
-       //
-       // Note: we don't report errors from DeallocateFork since the
-       // file no longer exists (since DeleteCatalogNode succeeded).
-       // Any errors mean that there are possibly some orphaned disk
-       // blocks but from the clients perspective the file was deleted.
-       //
-
-       // Deallocate data fork extents
-       errDF = DeallocateFork( vcb, catalogData.cnd_nodeID, kDataForkType,
-                   catalogData.cnd_datafork.extents, &recordDeleted );
-
-       // Deallocate resource fork extents
-       errRF = DeallocateFork( vcb, catalogData.cnd_nodeID, kResourceForkType,
-                   catalogData.cnd_rsrcfork.extents, &recordDeleted );
-
-       if (recordDeleted)
-               err = FlushExtentFile( vcb );
-
-       CLEAN_CATALOGDATA(&catalogData);
-       return (errDF ? errDF : (errRF ? errRF : err));
-Exit:
-       
-       CLEAN_CATALOGDATA(&catalogData);
-       return( err );
-}
 
 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
 //     Routine:        CompareExtentKeys
@@ -912,6 +717,7 @@ Exit:
 //                             an HFS volume.
 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
 
+__private_extern__
 SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey )
 {
        SInt32  result;         //      ± 1
@@ -975,6 +781,7 @@ SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *tri
 //                             an HFS volume.
 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
 
+__private_extern__
 SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey )
 {
        SInt32  result;         //      ± 1
@@ -1029,6 +836,72 @@ SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusEx
        return( result );
 }
 
+/*
+ * Add a file extent to a file.
+ *
+ * Used by hfs_extendfs to extend the volume allocation bitmap file.
+ *
+ */
+__private_extern__
+int
+AddFileExtent(ExtendedVCB *vcb, FCB *fcb, UInt32 startBlock, UInt32 blockCount)
+{
+       HFSPlusExtentKey foundKey;
+       HFSPlusExtentRecord foundData;
+       UInt32 foundIndex;
+       UInt32 hint;
+       UInt32 nextBlock;
+       SInt64 peof;
+       int i;
+       int error;
+
+       peof = (SInt64)(fcb->ff_blocks + blockCount) * (SInt64)vcb->blockSize;
+
+       error = SearchExtentFile(vcb, fcb, peof-1, &foundKey, foundData, &foundIndex, &hint, &nextBlock);
+       if (error != fxRangeErr)
+               return (EBUSY);
+
+       /*
+        * Add new extent.  See if there is room in the current record.
+        */
+       if (foundData[foundIndex].blockCount != 0)
+               ++foundIndex;
+       if (foundIndex == kHFSPlusExtentDensity) {
+               /*
+                * Existing record is full so create a new one.
+                */
+               foundKey.keyLength = kHFSPlusExtentKeyMaximumLength;
+               foundKey.forkType = kDataForkType;
+               foundKey.pad = 0;
+               foundKey.fileID = FTOC(fcb)->c_fileid;
+               foundKey.startBlock = nextBlock;
+               
+               foundData[0].startBlock = startBlock;
+               foundData[0].blockCount = blockCount;
+               
+               /* zero out remaining extents. */
+               for (i = 1; i < kHFSPlusExtentDensity; ++i) {
+                       foundData[i].startBlock = 0;
+                       foundData[i].blockCount = 0;
+               }
+
+               foundIndex = 0;
+
+               error = CreateExtentRecord(vcb, &foundKey, foundData, &hint);
+               if (error == fxOvFlErr)
+                       error = dskFulErr;
+       } else {
+               /* 
+                * Add a new extent into existing record.
+                */
+               foundData[foundIndex].startBlock = startBlock;
+               foundData[foundIndex].blockCount = blockCount;
+               error = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
+       }
+       (void) FlushExtentFile(vcb);
+
+       return (error);
+}
 
 
 //_________________________________________________________________________________
@@ -1037,29 +910,14 @@ SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusEx
 //
 // Function:   Extends the disk space allocated to a file.
 //
-// Input:              A2.L  -  VCB pointer
-//                             A1.L  -  pointer to FCB array
-//                             D1.W  -  file refnum
-//                             D3.B  -  option flags
-//                                                     kEFContigMask - force contiguous allocation
-//                                                     kEFAllMask - allocate all requested bytes or none
-//                                                     NOTE: You may not set both options.
-//                             D4.L  -  number of additional bytes to allocate
-//
-// Output:             D0.W  -  result code
-//                                                      0 = ok
-//                                                      -n = IO error
-//                             D6.L  -  number of bytes allocated
-//
-// Called by:  FileAloc,FileWrite,SetEof
-//
-// Note:               ExtendFile updates the PEOF in the FCB.
 //_________________________________________________________________________________
 
+__private_extern__
 OSErr ExtendFileC (
        ExtendedVCB             *vcb,                           // volume that file resides on
        FCB                             *fcb,                           // FCB of file to truncate
        SInt64                  bytesToAdd,                     // number of bytes to allocate
+       UInt32                  blockHint,                      // desired starting allocation block
        UInt32                  flags,                          // EFContig and/or EFAll
        SInt64                  *actualBytesAdded)      // number of bytes actually allocated
 {
@@ -1076,36 +934,22 @@ OSErr ExtendFileC (
        Boolean                         allOrNothing;
        Boolean                         forceContig;
        Boolean                         wantContig;
+       Boolean                         useMetaZone;
        Boolean                         needsFlush;
        UInt32                          actualStartBlock;
        UInt32                          actualNumBlocks;
        UInt32                          numExtentsPerRecord;
        SInt64                          maximumBytes;
        SInt64                          peof;
-       SInt64                          previousPEOF;
+       UInt32                          prevblocks;
        
 
-#if HFSInstrumentation
-       InstTraceClassRef       trace;
-       InstEventTag            eventTag;
-       InstDataDescriptorRef   traceDescriptor;
-       FSVarsRec                       *fsVars = (FSVarsRec *) LMGetFSMVars();
-
-       traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
-       
-       err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:ExtendFileC", 'hfs+', kInstEnableClassMask, &trace);
-       if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
-
-       eventTag = InstCreateEventTag();
-       InstLogTraceEvent( trace, eventTag, kInstStartEvent);
-#endif
-
        needsFlush = false;
        *actualBytesAdded = 0;
        volumeBlockSize = vcb->blockSize;
        allOrNothing = ((flags & kEFAllMask) != 0);
        forceContig = ((flags & kEFContigMask) != 0);
-       previousPEOF = fcb->fcbPLen;
+       prevblocks = fcb->ff_blocks;
 
        if (vcb->vcbSigWord == kHFSPlusSigWord)
                numExtentsPerRecord = kHFSPlusExtentDensity;
@@ -1118,45 +962,86 @@ OSErr ExtendFileC (
        if (vcb->vcbSigWord == kHFSSigWord) {
                if (bytesToAdd >=  kTwoGigabytes)
                        goto Overflow;
-               if ((fcb->fcbPLen + bytesToAdd) >= kTwoGigabytes)
+               if ((((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes)
                        goto Overflow;
-               }
+       }
        //
        //      Determine how many blocks need to be allocated.
        //      Round up the number of desired bytes to add.
        //
-       blocksToAdd = FileBytesToBlocks(bytesToAdd, volumeBlockSize);
+       blocksToAdd = howmany(bytesToAdd, volumeBlockSize);
        bytesToAdd = (SInt64)((SInt64)blocksToAdd * (SInt64)volumeBlockSize);
-       
+
+       /*
+        * For deferred allocations just reserve the blocks.
+        */
+       if ((flags & kEFDeferMask)
+       &&  (vcb->vcbSigWord == kHFSPlusSigWord)
+       &&  (bytesToAdd < (SInt64)HFS_MAX_DEFERED_ALLOC)
+       &&  (blocksToAdd < hfs_freeblks(VCBTOHFS(vcb), 1))) {
+               HFS_MOUNT_LOCK(vcb, TRUE);
+               vcb->loanedBlocks += blocksToAdd;
+               HFS_MOUNT_UNLOCK(vcb, TRUE);
+
+               fcb->ff_unallocblocks += blocksToAdd;
+               FTOC(fcb)->c_blocks   += blocksToAdd;
+               fcb->ff_blocks        += blocksToAdd;
+
+               FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
+               *actualBytesAdded = bytesToAdd;
+               return (0);
+       }
+       /* 
+        * Give back any unallocated blocks before doing real allocations.
+        */
+       if (fcb->ff_unallocblocks > 0) {
+               u_int32_t loanedBlocks;
+
+               loanedBlocks = fcb->ff_unallocblocks;
+               blocksToAdd += loanedBlocks;
+               bytesToAdd = (SInt64)blocksToAdd * (SInt64)volumeBlockSize;
+               FTOC(fcb)->c_blocks -= loanedBlocks;
+               fcb->ff_blocks -= loanedBlocks;
+               fcb->ff_unallocblocks  = 0;
+
+               HFS_MOUNT_LOCK(vcb, TRUE);
+               vcb->loanedBlocks -= loanedBlocks;
+               HFS_MOUNT_UNLOCK(vcb, TRUE);
+       }
+
        //
        //      If the file's clump size is larger than the allocation block size,
        //      then set the maximum number of bytes to the requested number of bytes
        //      rounded up to a multiple of the clump size.
        //
-       if (fcb->fcbClmpSize > volumeBlockSize) {
-               maximumBytes = (SInt64)FileBytesToBlocks(bytesToAdd, fcb->fcbClmpSize);
-               maximumBytes *= fcb->fcbClmpSize;
-       }
-       else {
+       if ((vcb->vcbClpSiz > (int32_t)volumeBlockSize)
+       &&  (bytesToAdd < (SInt64)HFS_MAX_DEFERED_ALLOC)
+       &&  (flags & kEFNoClumpMask) == 0) {
+               maximumBytes = (SInt64)howmany(bytesToAdd, vcb->vcbClpSiz);
+               maximumBytes *= vcb->vcbClpSiz;
+       } else {
                maximumBytes = bytesToAdd;
        }
        
        //
        //      Compute new physical EOF, rounded up to a multiple of a block.
        //
-       if ((vcb->vcbSigWord == kHFSSigWord) && ((fcb->fcbPLen + bytesToAdd) >= (SInt64) kTwoGigabytes))        //      Too big?
+       if ( (vcb->vcbSigWord == kHFSSigWord) &&                //      Too big?
+                ((((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) ) {
                if (allOrNothing)                                       // Yes, must they have it all?
                        goto Overflow;                                          // Yes, can't have it
                else {
                        --blocksToAdd;                                          // No, give give 'em one block less
                        bytesToAdd -= volumeBlockSize;
                }
+       }
 
        //
        //      If allocation is all-or-nothing, make sure there are
        //      enough free blocks on the volume (quick test).
        //
-       if (allOrNothing && (blocksToAdd > (SInt64)vcb->freeBlocks)) {
+       if (allOrNothing &&
+           (blocksToAdd > hfs_freeblks(VCBTOHFS(vcb), flags & kEFReserveMask))) {
                err = dskFulErr;
                goto ErrorExit;
        }
@@ -1164,13 +1049,13 @@ OSErr ExtendFileC (
        //
        //      See if there are already enough blocks allocated to the file.
        //
-       peof = fcb->fcbPLen + bytesToAdd;                       // potential new PEOF
+       peof = ((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd;  // potential new PEOF
        err = SearchExtentFile(vcb, fcb, peof-1, &foundKey, foundData, &foundIndex, &hint, &nextBlock);
        if (err == noErr) {
                //      Enough blocks are already allocated.  Just update the FCB to reflect the new length.
-               fcb->fcbPLen = peof;
-               H_EXTENDSIZE(fcb, bytesToAdd);
-               fcb->fcbFlags |= fcbModifiedMask;
+               fcb->ff_blocks = peof / volumeBlockSize;
+               FTOC(fcb)->c_blocks += (bytesToAdd / volumeBlockSize);
+               FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
                goto Exit;
        }
        if (err != fxRangeErr)          // Any real error?
@@ -1180,11 +1065,11 @@ OSErr ExtendFileC (
        //      Adjust the PEOF to the end of the last extent.
        //
        peof = (SInt64)((SInt64)nextBlock * (SInt64)volumeBlockSize);                   // currently allocated PEOF
-       bytesThisExtent = peof - fcb->fcbPLen;
+       bytesThisExtent = (SInt64)(nextBlock - fcb->ff_blocks) * (SInt64)volumeBlockSize;
        if (bytesThisExtent != 0) {
-               fcb->fcbPLen = peof;
-               H_EXTENDSIZE(fcb, bytesThisExtent);
-               fcb->fcbFlags |= fcbModifiedMask;
+               fcb->ff_blocks = nextBlock;
+               FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize);
+               FTOC(fcb)->c_flag |= C_MODIFIED;
                bytesToAdd -= bytesThisExtent;
        }
        
@@ -1197,9 +1082,45 @@ OSErr ExtendFileC (
        //              else, keep getting bits and pieces (non-contig)
        err = noErr;
        wantContig = true;
+       useMetaZone = flags & kEFMetadataMask;
+       vcb->vcbFreeExtCnt = 0; /* For now, force rebuild of free extent list */
        do {
-               startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount;
-               err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, wantContig, &actualStartBlock, &actualNumBlocks);
+               if (blockHint != 0)
+                       startBlock = blockHint;
+               else
+                       startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount;
+
+               /* Force reserve checking if requested. */
+               if (flags & kEFReserveMask) {
+                       SInt64 availbytes;
+
+                       actualNumBlocks = 0;
+                       actualStartBlock = 0;
+                       
+                       availbytes = (SInt64)hfs_freeblks(VCBTOHFS(vcb), 1) *
+                                    (SInt64)volumeBlockSize;
+                       if (availbytes <= 0) {
+                               err = dskFulErr;
+                       } else {
+                               if (wantContig && (availbytes < bytesToAdd))
+                                       err = dskFulErr;
+                               else {
+                                       err = BlockAllocate(
+                                                 vcb,
+                                                 startBlock,
+                                                 howmany(MIN(bytesToAdd, availbytes), volumeBlockSize),
+                                                 howmany(MIN(maximumBytes, availbytes), volumeBlockSize),
+                                                 wantContig,
+                                                 useMetaZone,
+                                                 &actualStartBlock,
+                                                 &actualNumBlocks);
+                               }
+                       }
+               } else {
+                       err = BlockAllocate(vcb, startBlock, howmany(bytesToAdd, volumeBlockSize),
+                                           howmany(maximumBytes, volumeBlockSize), wantContig, useMetaZone,
+                                           &actualStartBlock, &actualNumBlocks);
+               }
                if (err == dskFulErr) {
                        if (forceContig)
                                break;                  // AllocContig failed because not enough contiguous space
@@ -1211,28 +1132,22 @@ OSErr ExtendFileC (
                        }
                        if (actualNumBlocks != 0)
                                err = noErr;
+                       if (useMetaZone == 0) {
+                               /* Couldn't get anything so dip into metadat zone */
+                               err = noErr;
+                               useMetaZone = 1;
+                               continue;
+                       }
                }
                if (err == noErr) {
-#if HFSInstrumentation
-                       {
-                               struct {
-                                       UInt32  fileID;
-                                       UInt32  start;
-                                       UInt32  count;
-                                       UInt32  fabn;
-                               } x;
-                               
-                               x.fileID = H_FILEID(fcb);
-                               x.start = actualStartBlock;
-                               x.count = actualNumBlocks;
-                               x.fabn = nextBlock;
-                               
-                               InstLogTraceEventWithDataStructure( trace, eventTag, kInstMiddleEvent, traceDescriptor,
-                                                                                                       (UInt8 *) &x, sizeof(x));
+                   if (actualNumBlocks != 0) {
+                               // this catalog entry *must* get forced to disk when
+                               // hfs_update() is called
+                               FTOC(fcb)->c_flag |= C_FORCEUPDATE;
                        }
-#endif
+
                        //      Add the new extent to the existing extent record, or create a new one.
-                       if (actualStartBlock == startBlock) {
+                       if ((actualStartBlock == startBlock) && (blockHint == 0)) {
                                //      We grew the file's last extent, so just adjust the number of blocks.
                                foundData[foundIndex].blockCount += actualNumBlocks;
                                err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
@@ -1246,18 +1161,19 @@ OSErr ExtendFileC (
                                        ++foundIndex;                                                   //      No, so use the next one.
                                if (foundIndex == numExtentsPerRecord) {
                                        //      This record is full.  Need to create a new one.
-                                       if (H_FILEID(fcb) == kHFSExtentsFileID) {
-                                               err = fxOvFlErr;                // Oops.  Can't extend extents file (?? really ??)
+                                       if (FTOC(fcb)->c_fileid == kHFSExtentsFileID) {
+                                               (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks);
+                                               err = dskFulErr;                // Oops.  Can't extend extents file past first record.
                                                break;
                                        }
                                        
                                        foundKey.keyLength = kHFSPlusExtentKeyMaximumLength;
-                                       if (fcb->fcbFlags & fcbResourceMask)
+                                       if (FORK_IS_RSRC(fcb))
                                                foundKey.forkType = kResourceForkType;
                                        else
                                                foundKey.forkType = kDataForkType;
                                        foundKey.pad = 0;
-                                       foundKey.fileID = H_FILEID(fcb);
+                                       foundKey.fileID = FTOC(fcb)->c_fileid;
                                        foundKey.startBlock = nextBlock;
                                        
                                        foundData[0].startBlock = actualStartBlock;
@@ -1305,9 +1221,9 @@ OSErr ExtendFileC (
                                bytesToAdd -= bytesThisExtent;
                                maximumBytes -= bytesThisExtent;
                        }
-            fcb->fcbPLen += bytesThisExtent;
-            H_EXTENDSIZE(fcb, bytesThisExtent);
-                       fcb->fcbFlags |= fcbModifiedMask;
+                       fcb->ff_blocks += (bytesThisExtent / volumeBlockSize);
+                       FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize);
+                       FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
 
                        //      If contiguous allocation was requested, then we've already got one contiguous
                        //      chunk.  If we didn't get all we wanted, then adjust the error to disk full.
@@ -1321,15 +1237,25 @@ OSErr ExtendFileC (
 
 ErrorExit:
 Exit:
-       *actualBytesAdded = fcb->fcbPLen - previousPEOF;
+       if (VCBTOHFS(vcb)->hfs_flags & HFS_METADATA_ZONE) {
+               /* Keep the roving allocator out of the metadata zone. */
+               if (vcb->nextAllocation >= VCBTOHFS(vcb)->hfs_metazone_start &&
+                   vcb->nextAllocation <= VCBTOHFS(vcb)->hfs_metazone_end) {
+                       HFS_MOUNT_LOCK(vcb, TRUE);
+                       vcb->nextAllocation = VCBTOHFS(vcb)->hfs_metazone_end + 1;
+                       vcb->vcbFlags |= 0xFF00;
+                       HFS_MOUNT_UNLOCK(vcb, TRUE);
+               }
+       }
+       if (prevblocks < fcb->ff_blocks) {
+               *actualBytesAdded = (SInt64)(fcb->ff_blocks - prevblocks) * (SInt64)volumeBlockSize;
+       } else {
+               *actualBytesAdded = 0;
+       }
 
        if (needsFlush)
                (void) FlushExtentFile(vcb);
 
-#if HFSInstrumentation
-       InstLogTraceEvent( trace, eventTag, kInstEndEvent);
-#endif
-
        return err;
 
 Overflow:
@@ -1348,20 +1274,9 @@ Overflow:
 //                             block boundry.  If the 'TFTrunExt' option is specified, the file is
 //                             truncated to the end of the extent containing the new PEOF.
 //
-// Input:              A2.L  -  VCB pointer
-//                             A1.L  -  pointer to FCB array
-//                             D1.W  -  file refnum
-//                             D2.B  -  option flags
-//                                                TFTrunExt - truncate to the extent containing new PEOF
-//                             D3.L  -  new PEOF
-//
-// Output:             D0.W  -  result code
-//                                                      0 = ok
-//                                                      -n = IO error
-//
-// Note:               TruncateFile updates the PEOF in the FCB.
 //_________________________________________________________________________________
 
+__private_extern__
 OSErr TruncateFileC (
        ExtendedVCB             *vcb,                           // volume that file resides on
        FCB                             *fcb,                           // FCB of file to truncate
@@ -1383,21 +1298,6 @@ OSErr TruncateFileC (
        UInt8                           forkType;
        Boolean                         extentChanged;  // true if we actually changed an extent
        Boolean                         recordDeleted;  // true if an extent record got deleted
-       
-#if HFSInstrumentation
-       InstTraceClassRef       trace;
-       InstEventTag            eventTag;
-       InstDataDescriptorRef   traceDescriptor;
-       FSVarsRec                       *fsVars = (FSVarsRec *) LMGetFSMVars();
-
-       traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
-       
-       err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:TruncateFileC", 'hfs+', kInstEnableClassMask, &trace);
-       if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
-
-       eventTag = InstCreateEventTag();
-       InstLogTraceEvent( trace, eventTag, kInstStartEvent);
-#endif
 
        recordDeleted = false;
        
@@ -1406,12 +1306,12 @@ OSErr TruncateFileC (
        else
                numExtentsPerRecord = kHFSExtentDensity;
 
-       if (fcb->fcbFlags & fcbResourceMask)
+       if (FORK_IS_RSRC(fcb))
                forkType = kResourceForkType;
        else
                forkType = kDataForkType;
 
-       temp64 = fcb->fcbPLen / (SInt64)vcb->blockSize;         // number of allocation blocks currently in file
+       temp64 = fcb->ff_blocks;
        physNumBlocks = (UInt32)temp64;
 
        //
@@ -1419,9 +1319,9 @@ OSErr TruncateFileC (
        //      two gigabytes or more, then round down by one allocation block (??? really?
        //      shouldn't that be an error?).
        //
-       nextBlock = FileBytesToBlocks(peof, vcb->blockSize);    // number of allocation blocks to remain in file
+       nextBlock = howmany(peof, vcb->blockSize);      // number of allocation blocks to remain in file
        peof = (SInt64)((SInt64)nextBlock * (SInt64)vcb->blockSize);                                    // number of bytes in those blocks
-       if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= (UInt32) kTwoGigabytes)) {
+       if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= kTwoGigabytes)) {
                #if DEBUG_BUILD
                        DebugStr("\pHFS: Trying to truncate a file to 2GB or more");
                #endif
@@ -1432,9 +1332,16 @@ OSErr TruncateFileC (
        //
        //      Update FCB's length
        //
-       H_TRUNCSIZE(fcb, fcb->fcbPLen - peof);
-       fcb->fcbPLen = peof;
-       fcb->fcbFlags |= fcbModifiedMask;
+       /*
+        * XXX Any errors could cause ff_blocks and c_blocks to get out of sync...
+        */
+       numBlocks = peof / vcb->blockSize;
+       FTOC(fcb)->c_blocks -= (fcb->ff_blocks - numBlocks);
+       fcb->ff_blocks = numBlocks;
+
+       // this catalog entry is modified and *must* get forced 
+       // to disk when hfs_update() is called
+       FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
        
        //
        //      If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
@@ -1444,7 +1351,7 @@ OSErr TruncateFileC (
                int i;
                
                //      Deallocate all the extents for this fork
-               err = DeallocateFork(vcb, H_FILEID(fcb), forkType, fcb->fcbExtents, &recordDeleted);
+               err = DeallocateFork(vcb, FTOC(fcb)->c_fileid, forkType, fcb->fcbExtents, &recordDeleted);
                if (err != noErr) goto ErrorExit;       //      got some error, so return it
                
                //      Update the catalog extent record (making sure it's zeroed out)
@@ -1530,22 +1437,163 @@ OSErr TruncateFileC (
        //      blocks.
        //
        if (nextBlock < physNumBlocks)
-               err = TruncateExtents(vcb, forkType, H_FILEID(fcb), nextBlock, &recordDeleted);
+               err = TruncateExtents(vcb, forkType, FTOC(fcb)->c_fileid, nextBlock, &recordDeleted);
 
 Done:
 ErrorExit:
-
        if (recordDeleted)
                (void) FlushExtentFile(vcb);
 
-#if HFSInstrumentation
-       InstLogTraceEvent( trace, eventTag, kInstEndEvent);
-#endif
-
        return err;
 }
 
 
+/*
+ * HFS Plus only
+ *
+ */
+__private_extern__
+OSErr HeadTruncateFile (
+       ExtendedVCB  *vcb,
+       FCB  *fcb,
+       UInt32  headblks)
+{
+       HFSPlusExtentRecord  extents;
+       HFSPlusExtentRecord  tailExtents;
+       HFSCatalogNodeID  fileID;
+       UInt8  forkType;
+       UInt32  blkcnt;
+       UInt32  startblk;
+       UInt32  blksfreed;
+       int  i, j;
+       int  error = 0;
+       int  lockflags;
+
+
+       if (vcb->vcbSigWord != kHFSPlusSigWord)
+               return (-1);
+
+       forkType = FORK_IS_RSRC(fcb) ? kResourceForkType : kDataForkType;
+       fileID = FTOC(fcb)->c_fileid;
+       bzero(tailExtents, sizeof(tailExtents));
+
+       blksfreed = 0;
+       startblk = 0;
+
+       /*
+        * Process catalog resident extents
+        */
+       for (i = 0, j = 0; i < kHFSPlusExtentDensity; ++i) {
+               blkcnt = fcb->fcbExtents[i].blockCount;
+               if (blkcnt == 0)
+                       break;  /* end of extents */
+
+               if (blksfreed < headblks) {
+                       error = BlockDeallocate(vcb, fcb->fcbExtents[i].startBlock, blkcnt);
+                       /*
+                        * Any errors after the first BlockDeallocate
+                        * must be ignored so we can put the file in
+                        * a known state.
+                        */
+                       if (error ) {
+                               if (i == 0)
+                                       goto ErrorExit;  /* uh oh */
+                               else {
+                                       error = 0;
+                                       printf("HeadTruncateFile: problems deallocating %s (%d)\n",
+                                              FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error);
+                               }
+                       }
+
+                       blksfreed += blkcnt;
+                       fcb->fcbExtents[i].startBlock = 0;
+                       fcb->fcbExtents[i].blockCount = 0;
+               } else {
+                       tailExtents[j].startBlock = fcb->fcbExtents[i].startBlock;
+                       tailExtents[j].blockCount = blkcnt;
+                       ++j;
+               }
+               startblk += blkcnt;     
+       }
+       
+       if (blkcnt == 0)
+               goto CopyExtents;
+
+       lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
+
+       /* 
+        * Process overflow extents
+        */
+       for (;;) {
+               UInt32  extblks;
+
+               error = FindExtentRecord(vcb, forkType, fileID, startblk, false, NULL, extents, NULL);
+               if (error) {
+                       /*
+                        * Any errors after the first BlockDeallocate
+                        * must be ignored so we can put the file in
+                        * a known state.
+                        */
+                       if (error != btNotFound)
+                               printf("HeadTruncateFile: problems finding extents %s (%d)\n",
+                                      FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error);
+                       error = 0;
+                       break;
+               }
+
+               for(i = 0, extblks = 0; i < kHFSPlusExtentDensity; ++i) {
+                       blkcnt = extents[i].blockCount;
+                       if (blkcnt == 0)
+                               break;  /* end of extents */
+
+                       if (blksfreed < headblks) {
+                               error = BlockDeallocate(vcb, extents[i].startBlock, blkcnt);
+                               if (error) {
+                                       printf("HeadTruncateFile: problems deallocating %s (%d)\n",
+                                              FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error);
+                                       error = 0;
+                               }
+                               blksfreed += blkcnt;
+                       } else {
+                               tailExtents[j].startBlock = extents[i].startBlock;
+                               tailExtents[j].blockCount = blkcnt;
+                               ++j;
+                       }
+                       extblks += blkcnt;              
+               }
+               
+               error = DeleteExtentRecord(vcb, forkType, fileID, startblk);
+               if (error) {
+                       printf("HeadTruncateFile: problems deallocating %s (%d)\n",
+                               FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error);
+                       error = 0;
+               }
+               
+               if (blkcnt == 0)
+                       break;  /* all done */
+
+               startblk += extblks;
+       }
+       hfs_systemfile_unlock(vcb, lockflags);
+
+CopyExtents:
+       if (blksfreed) {
+               bcopy(tailExtents, fcb->fcbExtents, sizeof(tailExtents));
+               blkcnt = fcb->ff_blocks - headblks;
+               FTOC(fcb)->c_blocks -= blkcnt;
+               fcb->ff_blocks = blkcnt;
+
+               FTOC(fcb)->c_flag |= C_FORCEUPDATE;
+               FTOC(fcb)->c_touch_chgtime = TRUE;
+
+               (void) FlushExtentFile(vcb);
+       }
+
+ErrorExit:     
+       return MacToVFSError(error);
+}
+
+
 
 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
 //     Routine:        SearchExtentRecord (was XRSearch)
@@ -1570,7 +1618,7 @@ ErrorExit:
 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
 
 static OSErr SearchExtentRecord(
-       const ExtendedVCB               *vcb,
+       ExtendedVCB             *vcb,
        UInt32                                  searchFABN,
        const HFSPlusExtentRecord       extentData,
        UInt32                                  extentDataStartFABN,
@@ -1671,7 +1719,7 @@ static OSErr SearchExtentRecord(
 //\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
 
 static OSErr SearchExtentFile(
-       const ExtendedVCB       *vcb,
+       ExtendedVCB     *vcb,
        const FCB                       *fcb,
        SInt64                          filePosition,
        HFSPlusExtentKey        *foundExtentKey,
@@ -1684,6 +1732,7 @@ static OSErr SearchExtentFile(
        UInt32                          filePositionBlock;
        SInt64                          temp64;
        Boolean                         noMoreExtents;
+       int  lockflags;
        
        temp64 = filePosition / (SInt64)vcb->blockSize;
        filePositionBlock = (UInt32)temp64;
@@ -1716,8 +1765,11 @@ static OSErr SearchExtentFile(
        //
        //      Find the desired record, or the previous record if it is the same fork
        //
-       err = FindExtentRecord(vcb, (fcb->fcbFlags & fcbResourceMask) ? kResourceForkType : kDataForkType,
-                                                  H_FILEID(fcb), filePositionBlock, true, foundExtentKey, foundExtentData, extentBTreeHint);
+       lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
+
+       err = FindExtentRecord(vcb, FORK_IS_RSRC(fcb) ? kResourceForkType : kDataForkType,
+                                                  FTOC(fcb)->c_fileid, filePositionBlock, true, foundExtentKey, foundExtentData, extentBTreeHint);
+       hfs_systemfile_unlock(vcb, lockflags);
 
        if (err == btNotFound) {
                //
@@ -1750,7 +1802,7 @@ Exit:
 
 
 
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
+//============================================================================
 //     Routine:        UpdateExtentRecord
 //
 //     Function:       Write new extent data to an existing extent record with a given key.
@@ -1767,77 +1819,93 @@ Exit:
 //
 //     Result:         noErr = ok
 //                             (other) = error from BTree
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
+//============================================================================
 
 static OSErr UpdateExtentRecord (
-       const ExtendedVCB               *vcb,
-       FCB                                             *fcb,
-       const HFSPlusExtentKey  *extentFileKey,
-       const HFSPlusExtentRecord       extentData,
-       UInt32                                  extentBTreeHint)
+       ExtendedVCB  *vcb,
+       FCB  *fcb,
+       const HFSPlusExtentKey  *extentFileKey,
+       const HFSPlusExtentRecord  extentData,
+       UInt32  extentBTreeHint)
 {
-       BTreeIterator           btIterator;
-       FSBufferDescriptor      btRecord;
-       UInt16                          btRecordSize;
-       FCB *                           btFCB;
-    OSErr                              err = noErr;
+    OSErr err = noErr;
        
        if (extentFileKey->keyLength == 0) {    // keyLength == 0 means the FCB's extent record
                BlockMoveData(extentData, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
-               fcb->fcbFlags |= fcbModifiedMask;
+               FTOC(fcb)->c_flag |= C_MODIFIED;
        }
        else {
+               BTreeIterator * btIterator;
+               FSBufferDescriptor btRecord;
+               UInt16 btRecordSize;
+               FCB * btFCB;
+               int lockflags;
+
                //
                //      Need to find and change a record in Extents BTree
                //
                btFCB = GetFileControlBlock(vcb->extentsRefNum);
 
+               MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+               bzero(btIterator, sizeof(*btIterator));
+
+               /*
+                * The lock taken by callers of ExtendFileC/TruncateFileC is
+                * speculative and only occurs when the file already has
+                * overflow extents. So we need to make sure we have the lock
+                * here.  The extents btree lock can be nested (its recursive)
+                * so we always take it here.
+                */
+               lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
+
                if (vcb->vcbSigWord == kHFSSigWord) {
                        HFSExtentKey *  key;                            // Actual extent key used on disk in HFS
                        HFSExtentRecord foundData;                      // The extent data actually found
 
-                       key = (HFSExtentKey*) &btIterator.key;
+                       key = (HFSExtentKey*) &btIterator->key;
                        key->keyLength  = kHFSExtentKeyMaximumLength;
                        key->forkType   = extentFileKey->forkType;
                        key->fileID             = extentFileKey->fileID;
                        key->startBlock = extentFileKey->startBlock;
 
-                       btIterator.hint.index = 0;
-                       btIterator.hint.nodeNum = extentBTreeHint;
+                       btIterator->hint.index = 0;
+                       btIterator->hint.nodeNum = extentBTreeHint;
 
                        btRecord.bufferAddress = &foundData;
                        btRecord.itemSize = sizeof(HFSExtentRecord);
                        btRecord.itemCount = 1;
 
-                       err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord,
-                                                                &btRecordSize, &btIterator);
+                       err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator);
                        
                        if (err == noErr)
                                err = HFSPlusToHFSExtents(extentData, (HFSExtentDescriptor *)&foundData);
 
                        if (err == noErr)
-                               err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize);
+                               err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
+                       (void) BTFlushPath(btFCB);
                }
                else {          //      HFS Plus volume
                        HFSPlusExtentRecord     foundData;              // The extent data actually found
 
-                       BlockMoveData(extentFileKey, &btIterator.key, sizeof(HFSPlusExtentKey));
+                       BlockMoveData(extentFileKey, &btIterator->key, sizeof(HFSPlusExtentKey));
 
-                       btIterator.hint.index = 0;
-                       btIterator.hint.nodeNum = extentBTreeHint;
+                       btIterator->hint.index = 0;
+                       btIterator->hint.nodeNum = extentBTreeHint;
 
                        btRecord.bufferAddress = &foundData;
                        btRecord.itemSize = sizeof(HFSPlusExtentRecord);
                        btRecord.itemCount = 1;
 
-                       err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord,
-                                                                &btRecordSize, &btIterator);
+                       err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator);
        
                        if (err == noErr) {
                                BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord));
-                               err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize);
+                               err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
                        }
+                       (void) BTFlushPath(btFCB);
                }
+               hfs_systemfile_unlock(vcb, lockflags);
+               FREE(btIterator, M_TEMP);       
        }
        
        return err;
@@ -1845,31 +1913,8 @@ static OSErr UpdateExtentRecord (
 
 
 
-void HFSToHFSPlusExtents(
-       const HFSExtentRecord   oldExtents,
-       HFSPlusExtentRecord             newExtents)
-{
-       UInt32  i;
-
-       // copy the first 3 extents
-       newExtents[0].startBlock = oldExtents[0].startBlock;
-       newExtents[0].blockCount = oldExtents[0].blockCount;
-       newExtents[1].startBlock = oldExtents[1].startBlock;
-       newExtents[1].blockCount = oldExtents[1].blockCount;
-       newExtents[2].startBlock = oldExtents[2].startBlock;
-       newExtents[2].blockCount = oldExtents[2].blockCount;
-
-       // zero out the remaining ones
-       for (i = 3; i < kHFSPlusExtentDensity; ++i)
-       {
-               newExtents[i].startBlock = 0;
-               newExtents[i].blockCount = 0;
-       }
-}
-
-
 
-OSErr HFSPlusToHFSExtents(
+static OSErr HFSPlusToHFSExtents(
        const HFSPlusExtentRecord       oldExtents,
        HFSExtentRecord         newExtents)
 {
@@ -1898,7 +1943,7 @@ OSErr HFSPlusToHFSExtents(
 
 
 
-OSErr GetFCBExtentRecord(
+static OSErr GetFCBExtentRecord(
        const FCB                       *fcb,
        HFSPlusExtentRecord     extents)
 {
@@ -1909,104 +1954,6 @@ OSErr GetFCBExtentRecord(
 }
 
 
-
-//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
-//     Routine:        MapFileBlockFromFCB
-//
-//     Function:       Determine if the given file offset is within the set of extents
-//                             stored in the FCB.  If so, return the file allocation
-//                             block number of the start of the extent, volume allocation block number
-//                             of the start of the extent, and file allocation block number immediately
-//                             following the extent.
-//
-//     Input:          vcb                                             -       the volume containing the extents
-//                             fcb                                             -       the file that owns the extents
-//                             offset                                  -       desired offset in bytes
-//
-//     Output:         firstFABN                               -       file alloc block number of start of extent
-//                             firstBlock                              -       volume alloc block number of start of extent
-//                             nextFABN                                -       file alloc block number of next extent
-//
-//     Result:         noErr           = ok
-//                             fxRangeErr      = beyond FCB's extents
-//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
-static OSErr MapFileBlockFromFCB(
-       const ExtendedVCB               *vcb,
-       const FCB                               *fcb,
-       SInt64                                  offset,                 // Desired offset in bytes from start of file
-       UInt32                                  *firstFABN,             // FABN of first block of found extent
-       UInt32                                  *firstBlock,    // Corresponding allocation block number
-       UInt32                                  *nextFABN)              // FABN of block after end of extent
-{
-       UInt32  index;
-       UInt32  offsetBlocks;
-       SInt64  temp64;
-       
-       temp64 = offset / (SInt64)vcb->blockSize;
-       offsetBlocks = (UInt32)temp64;
-
-       if (vcb->vcbSigWord == kHFSSigWord) {
-               /* XXX SER Do we need to test for overflow values ??? */
-               UInt16  blockCount;
-               UInt16  currentFABN;
-               
-               currentFABN = 0;
-               
-               for (index=0; index<kHFSExtentDensity; index++) {
-
-                       blockCount = fcb->fcbExtents[index].blockCount;
-
-                       if (blockCount == 0)
-                               return fxRangeErr;                              //      ran out of extents!
-
-                       //      Is it in this extent?
-                       if (offsetBlocks < blockCount) {
-                               *firstFABN      = currentFABN;
-                               *firstBlock     = fcb->fcbExtents[index].startBlock;
-                               currentFABN += blockCount;              //      faster to add these as UInt16 first, then extend to UInt32
-                               *nextFABN       = currentFABN;
-                               return noErr;                                   //      found the right extent
-                       }
-
-                       //      Not in current extent, so adjust counters and loop again
-                       offsetBlocks -= blockCount;
-                       currentFABN += blockCount;
-               }
-       }
-       else {
-               UInt32  blockCount;
-               UInt32  currentFABN;
-               
-               currentFABN = 0;
-               
-               for (index=0; index<kHFSPlusExtentDensity; index++) {
-
-                       blockCount = fcb->fcbExtents[index].blockCount;
-
-                       if (blockCount == 0)
-                               return fxRangeErr;                              //      ran out of extents!
-
-                       //      Is it in this extent?
-                       if (offsetBlocks < blockCount) {
-                               *firstFABN      = currentFABN;
-                               *firstBlock     = fcb->fcbExtents[index].startBlock;
-                               *nextFABN       = currentFABN + blockCount;
-                               return noErr;                                   //      found the right extent
-                       }
-
-                       //      Not in current extent, so adjust counters and loop again
-                       offsetBlocks -= blockCount;
-                       currentFABN += blockCount;
-               }
-       }
-       
-       //      If we fall through here, the extent record was full, but the offset was
-       //      beyond those extents.
-       
-       return fxRangeErr;
-}
-
-
 //_________________________________________________________________________________
 //
 // Routine:            ExtentsAreIntegral
@@ -2055,6 +2002,7 @@ static Boolean ExtentsAreIntegral(
 //                             Called by BTOpenPath during volume mount
 //_________________________________________________________________________________
 
+__private_extern__
 Boolean NodesAreContiguous(
        ExtendedVCB     *vcb,
        FCB                     *fcb,
@@ -2068,6 +2016,7 @@ Boolean NodesAreContiguous(
        HFSPlusExtentRecord     extents;
        OSErr                           result;
        Boolean                         lastExtentReached;
+       int  lockflags;
        
 
        if (vcb->blockSize >= nodeSize)
@@ -2080,23 +2029,27 @@ Boolean NodesAreContiguous(
        if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
                return FALSE;
 
-       if (lastExtentReached || (SInt64)((SInt64)blocksChecked * (SInt64)vcb->blockSize) >= fcb->fcbPLen)
+       if ( lastExtentReached || 
+                (SInt64)((SInt64)blocksChecked * (SInt64)vcb->blockSize) >= (SInt64)fcb->ff_size)
                return TRUE;
 
        startBlock = blocksChecked;
 
+       lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
+
        // check the overflow extents (if any)
        while ( !lastExtentReached )
        {
-               result = FindExtentRecord(vcb, kDataForkType, H_FILEID(fcb), startBlock, FALSE, &key, extents, &hint);
+               result = FindExtentRecord(vcb, kDataForkType, fcb->ff_cp->c_fileid, startBlock, FALSE, &key, extents, &hint);
                if (result) break;
 
-               if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
+               if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) ) {
+                       hfs_systemfile_unlock(vcb, lockflags);
                        return FALSE;
-
+               }
                startBlock += blocksChecked;
        }
-
+       hfs_systemfile_unlock(vcb, lockflags);
        return TRUE;
 }