]> git.saurik.com Git - apple/hfs.git/blobdiff - core/FileExtentMapping.c
hfs-407.50.6.tar.gz
[apple/hfs.git] / core / FileExtentMapping.c
diff --git a/core/FileExtentMapping.c b/core/FileExtentMapping.c
deleted file mode 100644 (file)
index 1ea93f9..0000000
+++ /dev/null
@@ -1,2249 +0,0 @@
-/*
- * Copyright (c) 2000-2015 Apple Inc. All rights reserved.
- *
- * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
- * 
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. The rights granted to you under the License
- * may not be used to create, or enable the creation or redistribution of,
- * unlawful or unlicensed copies of an Apple operating system, or to
- * circumvent, violate, or enable the circumvention or violation of, any
- * terms of an Apple operating system software license agreement.
- * 
- * Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this file.
- * 
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- * 
- * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
- */
-
-
-#include "hfs.h"
-#include "hfs_format.h"
-#include "hfs_endian.h"
-
-#include "FileMgrInternal.h"
-#include "BTreesInternal.h"
-
-#include <sys/malloc.h>
-/*
-============================================================
-Public (Exported) Routines:
-============================================================
-
-       ExtendFileC             Allocate more space to a given file.
-
-       CompareExtentKeys
-                                       Compare two extents file keys (a search key and a trial
-                                       key).  Used by the BTree manager when searching for,
-                                       adding, or deleting keys in the extents file of an HFS
-                                       volume.
-                                       
-       CompareExtentKeysPlus
-                                       Compare two extents file keys (a search key and a trial
-                                       key).  Used by the BTree manager when searching for,
-                                       adding, or deleting keys in the extents file of an HFS+
-                                       volume.
-                                       
-       MapFileBlockC   Convert (map) an offset within a given file into a
-                                       physical disk address.
-                                       
-       TruncateFileC   Truncates the disk space allocated to a file.  The file
-                                       space is truncated to a specified new physical EOF, rounded
-                                       up to the next allocation block boundry.  There is an option
-                                       to truncate to the end of the extent containing the new EOF.
-       
-       FlushExtentFile
-                                       Flush the extents file for a given volume.
-
-       SearchExtentFile
-                                       Search the FCB and extents file for an extent record that
-                                       contains a given file position (in bytes).
-
-
-============================================================
-Internal Routines:
-============================================================
-       FindExtentRecord
-                                       Search the extents BTree for a particular extent record.
-       SearchExtentRecord
-                                       Search a given extent record to see if it contains a given
-                                       file position (in bytes).  Used by SearchExtentFile.
-       ReleaseExtents
-                                       Deallocate all allocation blocks in all extents of an extent
-                                       data record.
-       TruncateExtents
-                                       Deallocate blocks and delete extent records for all allocation
-                                       blocks beyond a certain point in a file.  The starting point
-                                       must be the first file allocation block for some extent record
-                                       for the file.
-       DeallocateFork
-                                       Deallocate all allocation blocks belonging to a given fork.
-       UpdateExtentRecord
-                                       If the extent record came from the extents file, write out
-                                       the updated record; otherwise, copy the updated record into
-                                       the FCB resident extent record.  If the record has no extents,
-                                       and was in the extents file, then delete the record instead.
-*/
-
-#if CONFIG_HFS_STD
-static const int64_t kTwoGigabytes = 0x80000000LL;
-#endif
-
-enum
-{
-       kDataForkType                   = 0,
-       kResourceForkType               = 0xFF,
-       
-       kPreviousRecord                 = -1
-};
-
-
-#if CONFIG_HFS_STD
-static OSErr HFSPlusToHFSExtents(
-       const HFSPlusExtentRecord       oldExtents,
-       HFSExtentRecord                         newExtents);
-#endif
-
-static OSErr FindExtentRecord(
-       const ExtendedVCB               *vcb,
-       u_int8_t                                forkType,
-       u_int32_t                               fileID,
-       u_int32_t                               startBlock,
-       Boolean                                 allowPrevious,
-       HFSPlusExtentKey                *foundKey,
-       HFSPlusExtentRecord             foundData,
-       u_int32_t                               *foundHint);
-
-static OSErr DeleteExtentRecord(
-       const ExtendedVCB               *vcb,
-       u_int8_t                                forkType,
-       u_int32_t                               fileID,
-       u_int32_t                               startBlock);
-
-static OSErr CreateExtentRecord(
-       ExtendedVCB             *vcb,
-       HFSPlusExtentKey                *key,
-       HFSPlusExtentRecord             extents,
-       u_int32_t                               *hint);
-
-
-static OSErr GetFCBExtentRecord(
-       const FCB                               *fcb,
-       HFSPlusExtentRecord             extents);
-
-static OSErr SearchExtentRecord(
-       ExtendedVCB             *vcb,
-       u_int32_t                               searchFABN,
-       const HFSPlusExtentRecord       extentData,
-       u_int32_t                               extentDataStartFABN,
-       u_int32_t                               *foundExtentDataOffset,
-       u_int32_t                               *endingFABNPlusOne,
-       Boolean                                 *noMoreExtents);
-
-static OSErr ReleaseExtents(
-       ExtendedVCB                             *vcb,
-       const HFSPlusExtentRecord       extentRecord,
-       u_int32_t                               *numReleasedAllocationBlocks,
-       Boolean                                 *releasedLastExtent);
-
-static OSErr DeallocateFork(
-       ExtendedVCB             *vcb,
-       HFSCatalogNodeID        fileID,
-       u_int8_t                        forkType,
-       HFSPlusExtentRecord     catalogExtents,
-       Boolean *               recordDeleted);
-
-static OSErr TruncateExtents(
-       ExtendedVCB                     *vcb,
-       u_int8_t                        forkType,
-       u_int32_t                       fileID,
-       u_int32_t                       startBlock,
-       Boolean *                       recordDeleted);
-
-static OSErr UpdateExtentRecord (
-       ExtendedVCB             *vcb,
-       FCB                             *fcb,
-       int                             deleted,
-       const HFSPlusExtentKey  *extentFileKey,
-       const HFSPlusExtentRecord       extentData,
-       u_int32_t                                       extentBTreeHint);
-
-static Boolean ExtentsAreIntegral(
-       const HFSPlusExtentRecord extentRecord,
-       u_int32_t       mask,
-       u_int32_t       *blocksChecked,
-       Boolean         *checkedLastExtent);
-
-//_________________________________________________________________________________
-//
-//     Routine:        FindExtentRecord
-//
-//     Purpose:        Search the extents BTree for an extent record matching the given
-//                             FileID, fork, and starting file allocation block number.
-//
-//     Inputs:
-//             vcb                             Volume to search
-//             forkType                0 = data fork, -1 = resource fork
-//             fileID                  File's FileID (CatalogNodeID)
-//             startBlock              Starting file allocation block number
-//             allowPrevious   If the desired record isn't found and this flag is set,
-//                                             then see if the previous record belongs to the same fork.
-//                                             If so, then return it.
-//
-//     Outputs:
-//             foundKey        The key data for the record actually found
-//             foundData       The extent record actually found (NOTE: on an HFS volume, the
-//                                     fourth entry will be zeroes.
-//             foundHint       The BTree hint to find the node again
-//_________________________________________________________________________________
-static OSErr FindExtentRecord(
-       const ExtendedVCB       *vcb,
-       u_int8_t                        forkType,
-       u_int32_t                       fileID,
-       u_int32_t                       startBlock,
-       Boolean                         allowPrevious,
-       HFSPlusExtentKey        *foundKey,
-       HFSPlusExtentRecord     foundData,
-       u_int32_t                       *foundHint)
-{
-       FCB *                           fcb;
-       struct BTreeIterator *btIterator = NULL;
-       FSBufferDescriptor      btRecord;
-       OSErr                           err;
-       u_int16_t                       btRecordSize;
-       
-       err = noErr;
-       if (foundHint)
-               *foundHint = 0;
-       fcb = GetFileControlBlock(vcb->extentsRefNum);
-
-       btIterator = hfs_mallocz(sizeof(struct BTreeIterator));
-
-       /* HFS Plus / HFSX */
-       if (vcb->vcbSigWord != kHFSSigWord) {
-               HFSPlusExtentKey *      extentKeyPtr;
-               HFSPlusExtentRecord     extentData;
-
-               extentKeyPtr = (HFSPlusExtentKey*) &btIterator->key;
-               extentKeyPtr->keyLength  = kHFSPlusExtentKeyMaximumLength;
-               extentKeyPtr->forkType   = forkType;
-               extentKeyPtr->pad                = 0;
-               extentKeyPtr->fileID     = fileID;
-               extentKeyPtr->startBlock = startBlock;
-               
-               btRecord.bufferAddress = &extentData;
-               btRecord.itemSize = sizeof(HFSPlusExtentRecord);
-               btRecord.itemCount = 1;
-
-               err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator);
-
-               if (err == btNotFound && allowPrevious) {
-                       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).
-                       if (err == (OSErr) fsBTStartOfIterationErr)             //¥¥ fsBTStartOfIterationErr is type unsigned long
-                               err = btNotFound;
-
-                       if (err == noErr) {
-                               //      Found a previous record.  Does it belong to the same fork of the same file?
-                               if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
-                                       err = btNotFound;
-                       }
-               }
-
-               if (err == noErr) {
-                       // 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));
-               }
-       }
-#if CONFIG_HFS_STD
-       else { 
-               HFSExtentKey *          extentKeyPtr;
-               HFSExtentRecord         extentData;
-
-               extentKeyPtr = (HFSExtentKey*) &btIterator->key;
-               extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength;
-               extentKeyPtr->forkType = forkType;
-               extentKeyPtr->fileID = fileID;
-               extentKeyPtr->startBlock = startBlock;
-               
-               btRecord.bufferAddress = &extentData;
-               btRecord.itemSize = sizeof(HFSExtentRecord);
-               btRecord.itemCount = 1;
-
-               err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator);
-
-               if (err == btNotFound && allowPrevious) {
-                       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).
-                       if (err == (OSErr) fsBTStartOfIterationErr)             //¥¥ fsBTStartOfIterationErr is type unsigned long
-                               err = btNotFound;
-
-                       if (err == noErr) {
-                               //      Found a previous record.  Does it belong to the same fork of the same file?
-                               if (extentKeyPtr->fileID != fileID || extentKeyPtr->forkType != forkType)
-                                       err = btNotFound;
-                       }
-               }
-
-               if (err == noErr) {
-                       u_int16_t       i;
-                       
-                       // 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;
-                       foundData[1].blockCount = extentData[1].blockCount;
-                       foundData[2].startBlock = extentData[2].startBlock;
-                       foundData[2].blockCount = extentData[2].blockCount;
-                       
-                       for (i = 3; i < kHFSPlusExtentDensity; ++i)
-                       {
-                               foundData[i].startBlock = 0;
-                               foundData[i].blockCount = 0;
-                       }
-               }
-       }
-#endif
-
-       if (foundHint)
-               *foundHint = btIterator->hint.nodeNum;
-
-       hfs_free(btIterator, sizeof(*btIterator));
-       return err;
-}
-
-
-
-static OSErr CreateExtentRecord(
-       ExtendedVCB     *vcb,
-       HFSPlusExtentKey        *key,
-       HFSPlusExtentRecord     extents,
-       u_int32_t                       *hint)
-{
-       struct BTreeIterator *btIterator = NULL;
-       FSBufferDescriptor      btRecord;
-       u_int16_t  btRecordSize;
-       int  lockflags;
-       OSErr  err;
-       
-       err = noErr;
-       *hint = 0;
-
-       btIterator = hfs_mallocz(sizeof(struct BTreeIterator));
-
-       /*
-        * 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);
-
-       /* HFS+/HFSX */
-       if (vcb->vcbSigWord != kHFSSigWord) {
-               btRecordSize = sizeof(HFSPlusExtentRecord);
-               btRecord.bufferAddress = extents;
-               btRecord.itemSize = btRecordSize;
-               btRecord.itemCount = 1;
-
-               BlockMoveData(key, &btIterator->key, sizeof(HFSPlusExtentKey));
-       }
-#if CONFIG_HFS_STD
-       else {
-               /* HFS Standard */
-               HFSExtentKey *          keyPtr;
-               HFSExtentRecord         data;
-               
-               btRecordSize = sizeof(HFSExtentRecord);
-               btRecord.bufferAddress = &data;
-               btRecord.itemSize = btRecordSize;
-               btRecord.itemCount = 1;
-
-               keyPtr = (HFSExtentKey*) &btIterator->key;
-               keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
-               keyPtr->forkType        = key->forkType;
-               keyPtr->fileID          = key->fileID;
-               keyPtr->startBlock      = key->startBlock;
-               
-               err = HFSPlusToHFSExtents(extents, data);
-       }
-#endif
-
-       if (err == noErr)
-               err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator, &btRecord, btRecordSize);
-
-       if (err == noErr)
-               *hint = btIterator->hint.nodeNum;
-
-       (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
-       
-       hfs_systemfile_unlock(vcb, lockflags);
-
-       hfs_free(btIterator, sizeof(*btIterator));
-       return err;
-}
-
-
-static OSErr DeleteExtentRecord(
-       const ExtendedVCB       *vcb,
-       u_int8_t                        forkType,
-       u_int32_t                       fileID,
-       u_int32_t                       startBlock)
-{
-       struct BTreeIterator *btIterator = NULL;
-       OSErr                           err;
-       
-       err = noErr;
-
-       btIterator = hfs_mallocz(sizeof(struct BTreeIterator));
-
-       /* HFS+ / HFSX */
-       if (vcb->vcbSigWord != kHFSSigWord) {           //      HFS Plus volume
-               HFSPlusExtentKey *      keyPtr;
-
-               keyPtr = (HFSPlusExtentKey*) &btIterator->key;
-               keyPtr->keyLength       = kHFSPlusExtentKeyMaximumLength;
-               keyPtr->forkType        = forkType;
-               keyPtr->pad                     = 0;
-               keyPtr->fileID          = fileID;
-               keyPtr->startBlock      = startBlock;
-       }
-#if CONFIG_HFS_STD
-       else {
-               /* HFS standard */
-               HFSExtentKey *  keyPtr;
-
-               keyPtr = (HFSExtentKey*) &btIterator->key;
-               keyPtr->keyLength       = kHFSExtentKeyMaximumLength;
-               keyPtr->forkType        = forkType;
-               keyPtr->fileID          = fileID;
-               keyPtr->startBlock      = startBlock;
-       }
-#endif
-
-       err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator);
-       (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
-       
-
-       hfs_free(btIterator, sizeof(*btIterator));
-       return err;
-}
-
-
-
-//_________________________________________________________________________________
-//
-// Routine:            MapFileBlock
-//
-// Function:   Maps a file position into a physical disk address.
-//
-//_________________________________________________________________________________
-
-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)
-       daddr64_t               *startSector,           // first sector (NOT an allocation block)
-       size_t                  *availableBytes)        // number of contiguous bytes (up to numberOfBytes)
-{
-       OSErr                           err;
-       u_int32_t                       allocBlockSize;                 //      Size of the volume's allocation block
-       u_int32_t                       sectorSize;
-       HFSPlusExtentKey        foundKey;
-       HFSPlusExtentRecord     foundData;
-       u_int32_t                       foundIndex;
-       u_int32_t                       hint;
-       u_int32_t                       firstFABN = 0;                  // file allocation block of first block in found extent
-       u_int32_t                       nextFABN;                               // file allocation block of block after end of found extent
-       off_t                           dataEnd;                                // (offset) end of range that is contiguous
-       u_int32_t                       sectorsPerBlock;                // Number of sectors per allocation block
-       u_int32_t                       startBlock = 0;                 // volume allocation block corresponding to firstFABN
-       daddr64_t                       temp;
-       off_t                           tmpOff;
-
-       allocBlockSize = vcb->blockSize;
-       sectorSize = VCBTOHFS(vcb)->hfs_logical_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)
-       {
-               return err;
-       }
-
-       //
-       //      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 (((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 / 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 = (daddr64_t)((offset - (off_t)((off_t)(firstFABN) * (off_t)(allocBlockSize)))/sectorSize);
-       temp += (daddr64_t)startBlock * (daddr64_t)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;
-       
-       //
-       //      Determine the number of contiguous bytes until the end of the extent
-       //      (or the amount they asked for, whichever comes first).
-       //
-       if (availableBytes)
-       {
-               tmpOff = dataEnd - offset;
-               /*
-                * Disallow negative runs.
-                */
-               if (tmpOff <= 0) {
-                       /* This shouldn't happen unless something is corrupt */
-                       hfs_corruption_debug("MapFileBlockC: tmpOff <= 0 (%lld)\n", tmpOff);
-                       return EINVAL;
-               }
-
-               if (tmpOff > (off_t)(numberOfBytes)) {
-                       *availableBytes = numberOfBytes;  // more there than they asked for, so pin the output
-               }
-               else {
-                       *availableBytes = tmpOff;
-               }
-       }
-
-       return noErr;
-}
-
-
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\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:        ReleaseExtents
-//
-//     Function:       Release the extents of a single extent data record.
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\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 ReleaseExtents(
-       ExtendedVCB                     *vcb,
-       const HFSPlusExtentRecord       extentRecord,
-       u_int32_t                               *numReleasedAllocationBlocks,
-       Boolean                                 *releasedLastExtent)
-{
-       u_int32_t       extentIndex;
-       u_int32_t       numberOfExtents;
-       OSErr   err = noErr;
-       
-       *numReleasedAllocationBlocks = 0;
-       *releasedLastExtent = false;
-       
-       if (vcb->vcbSigWord == kHFSPlusSigWord)
-               numberOfExtents = kHFSPlusExtentDensity;
-       else
-               numberOfExtents = kHFSExtentDensity;
-
-       for( extentIndex = 0; extentIndex < numberOfExtents; extentIndex++)
-       {
-               u_int32_t       numAllocationBlocks;
-               
-               // Loop over the extent record and release the blocks associated with each extent.
-               
-               numAllocationBlocks = extentRecord[extentIndex].blockCount;
-               if ( numAllocationBlocks == 0 )
-               {
-                       *releasedLastExtent = true;
-                       break;
-               }
-
-               err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks , 0);
-               if ( err != noErr )
-                       break;
-                                       
-               *numReleasedAllocationBlocks += numAllocationBlocks;            //      bump FABN to beg of next extent
-       }
-
-       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:        TruncateExtents
-//
-//     Purpose:        Delete extent records whose starting file allocation block number
-//                             is greater than or equal to a given starting block number.  The
-//                             allocation blocks represented by the extents are deallocated.
-//
-//     Inputs:
-//             vcb                     Volume to operate on
-//             fileID          Which file to operate on
-//             startBlock      Starting file allocation block number for first extent
-//                                     record to delete.
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\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 TruncateExtents(
-       ExtendedVCB             *vcb,
-       u_int8_t                forkType,
-       u_int32_t               fileID,
-       u_int32_t               startBlock,
-       Boolean *               recordDeleted)
-{
-       OSErr                           err;
-       u_int32_t                       numberExtentsReleased;
-       Boolean                         releasedLastExtent;
-       u_int32_t                       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);
-               if (err != noErr) {
-                       if (err == btNotFound)
-                               err = noErr;
-                       break;
-               }
-               
-               err = ReleaseExtents( vcb, extents, &numberExtentsReleased, &releasedLastExtent );
-               if (err != noErr) break;
-               
-               err = DeleteExtentRecord(vcb, forkType, fileID, startBlock);
-               if (err != noErr) break;
-
-               *recordDeleted = true;
-               startBlock += numberExtentsReleased;
-       }
-       hfs_systemfile_unlock(vcb, lockflags);
-       
-       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:        DeallocateFork
-//
-//     Function:       De-allocates all disk space allocated to a specified fork.
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\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 DeallocateFork(
-       ExtendedVCB             *vcb,
-       HFSCatalogNodeID        fileID,
-       u_int8_t                        forkType,
-       HFSPlusExtentRecord     catalogExtents,
-       Boolean *               recordDeleted) /* true if a record was deleted */
-{
-       OSErr                           err;
-       u_int32_t                       numReleasedAllocationBlocks;
-       Boolean                         releasedLastExtent;
-       
-       //      Release the catalog extents
-       err = ReleaseExtents( vcb, catalogExtents, &numReleasedAllocationBlocks, &releasedLastExtent );
-       // Release the extra extents, if present
-       if (err == noErr && !releasedLastExtent)
-               err = TruncateExtents(vcb, forkType, fileID, numReleasedAllocationBlocks, recordDeleted);
-
-       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:        FlushExtentFile
-//
-//     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
-
-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 (FTOC(fcb)->c_flag & C_MODIFIED)
-               {
-                       MarkVCBDirty( vcb );
-               //      err = FlushVolumeControlBlock( vcb );
-               }
-       }
-       
-       return( err );
-}
-
-
-#if CONFIG_HFS_STD
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\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
-//
-//     Function:       Compares two extent file keys (a search key and a trial key) for
-//                             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
-
-int32_t CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey )
-{
-       int32_t result;         //      ± 1
-       
-       #if DEBUG
-               if (searchKey->keyLength != kHFSExtentKeyMaximumLength)
-                       DebugStr("HFS: search Key is wrong length");
-               if (trialKey->keyLength != kHFSExtentKeyMaximumLength)
-                       DebugStr("HFS: trial Key is wrong length");
-       #endif
-       
-       result = -1;            //      assume searchKey < trialKey
-       
-       if (searchKey->fileID == trialKey->fileID) {
-               //
-               //      FileNum's are equal; compare fork types
-               //
-               if (searchKey->forkType == trialKey->forkType) {
-                       //
-                       //      Fork types are equal; compare allocation block number
-                       //
-                       if (searchKey->startBlock == trialKey->startBlock) {
-                               //
-                               //      Everything is equal
-                               //
-                               result = 0;
-                       }
-                       else {
-                               //
-                               //      Allocation block numbers differ; determine sign
-                               //
-                               if (searchKey->startBlock > trialKey->startBlock)
-                                       result = 1;
-                       }
-               }
-               else {
-                       //
-                       //      Fork types differ; determine sign
-                       //
-                       if (searchKey->forkType > trialKey->forkType)
-                               result = 1;
-               }
-       }
-       else {
-               //
-               //      FileNums differ; determine sign
-               //
-               if (searchKey->fileID > trialKey->fileID)
-                       result = 1;
-       }
-       
-       return( result );
-}
-#endif
-
-
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\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:        CompareExtentKeysPlus
-//
-//     Function:       Compares two extent file keys (a search key and a trial key) for
-//                             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
-
-int32_t CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey )
-{
-       int32_t result;         //      ± 1
-       
-       #if DEBUG
-               if (searchKey->keyLength != kHFSPlusExtentKeyMaximumLength)
-                       DebugStr("HFS: search Key is wrong length");
-               if (trialKey->keyLength != kHFSPlusExtentKeyMaximumLength)
-                       DebugStr("HFS: trial Key is wrong length");
-       #endif
-       
-       result = -1;            //      assume searchKey < trialKey
-       
-       if (searchKey->fileID == trialKey->fileID) {
-               //
-               //      FileNum's are equal; compare fork types
-               //
-               if (searchKey->forkType == trialKey->forkType) {
-                       //
-                       //      Fork types are equal; compare allocation block number
-                       //
-                       if (searchKey->startBlock == trialKey->startBlock) {
-                               //
-                               //      Everything is equal
-                               //
-                               result = 0;
-                       }
-                       else {
-                               //
-                               //      Allocation block numbers differ; determine sign
-                               //
-                               if (searchKey->startBlock > trialKey->startBlock)
-                                       result = 1;
-                       }
-               }
-               else {
-                       //
-                       //      Fork types differ; determine sign
-                       //
-                       if (searchKey->forkType > trialKey->forkType)
-                               result = 1;
-               }
-       }
-       else {
-               //
-               //      FileNums differ; determine sign
-               //
-               if (searchKey->fileID > trialKey->fileID)
-                       result = 1;
-       }
-       
-       return( result );
-}
-
-static int
-should_pin_blocks(hfsmount_t *hfsmp, FCB *fcb)
-{
-       if (!ISSET(hfsmp->hfs_flags, HFS_CS_HOTFILE_PIN)
-               || fcb->ff_cp == NULL || fcb->ff_cp->c_vp == NULL) {
-               return 0;
-       }
-
-       int pin_blocks;
-
-       //
-       // File system metadata should get pinned
-       //
-       if (vnode_issystem(fcb->ff_cp->c_vp)) {
-               return 1;
-       }
-
-       //
-       // If a file is AutoCandidate, we should not pin its blocks because
-       // it was an automatically added file and this function is intended
-       // to pin new blocks being added to user-generated content.
-       //
-       if (fcb->ff_cp->c_attr.ca_recflags & kHFSAutoCandidateMask) {
-               return 0;
-       }
-
-       //
-       // If a file is marked FastDevPinned it is an existing pinned file 
-       // or a new file that should be pinned.
-       //
-       // If a file is marked FastDevCandidate it is a new file that is
-       // being written to for the first time so we don't want to pin it
-       // just yet as it may not meet the criteria (i.e. too large).
-       //
-       if ((fcb->ff_cp->c_attr.ca_recflags & (kHFSFastDevPinnedMask)) != 0) {
-               pin_blocks = 1;
-       } else {
-               pin_blocks = 0;
-       }
-
-       return pin_blocks;
-}
-       
-
-
-static void
-pin_blocks_if_needed(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockCount)   
-{
-       if (!should_pin_blocks(vcb, fcb)) {
-               return;
-       }
-       
-       // ask CoreStorage to pin the new blocks being added to this file
-       if (hfs_pin_block_range((struct hfsmount *)vcb, HFS_PIN_IT, startBlock, blockCount) == 0) {
-               struct vnode *vp = fcb->ff_cp->c_vp;
-               
-               // and make sure to keep our accounting in order
-               hfs_hotfile_adjust_blocks(vp, -blockCount);
-       }
-}
-
-
-
-/*
- * Add a file extent to a file.
- *
- * Used by hfs_extendfs to extend the volume allocation bitmap file.
- *
- */
-int
-AddFileExtent(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockCount)
-{
-       HFSPlusExtentKey foundKey;
-       HFSPlusExtentRecord foundData;
-       u_int32_t foundIndex;
-       u_int32_t hint;
-       u_int32_t nextBlock;
-       int64_t peof;
-       int i;
-       int error;
-
-       peof = (int64_t)(fcb->ff_blocks + blockCount) * (int64_t)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 if (error == 0) {
-                       pin_blocks_if_needed(vcb, fcb, startBlock, blockCount);
-               }
-               
-       } else {
-               /* 
-                * Add a new extent into existing record.
-                */
-               foundData[foundIndex].startBlock = startBlock;
-               foundData[foundIndex].blockCount = blockCount;
-               error = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint);
-               if (error == 0) {
-                       pin_blocks_if_needed(vcb, fcb, startBlock, blockCount);
-               }
-       }
-       (void) FlushExtentFile(vcb);
-
-       return (error);
-}
-
-
-//_________________________________________________________________________________
-//
-// Routine:            Extendfile
-//
-// Function:   Extends the disk space allocated to a file.
-//
-//_________________________________________________________________________________
-
-OSErr ExtendFileC (
-       ExtendedVCB             *vcb,                           // volume that file resides on
-       FCB                             *fcb,                           // FCB of file to truncate
-       int64_t                 bytesToAdd,                     // number of bytes to allocate
-       u_int32_t               blockHint,                      // desired starting allocation block
-       u_int32_t               flags,                          // EFContig and/or EFAll
-       int64_t                 *actualBytesAdded)      // number of bytes actually allocated
-{
-       OSErr                           err;
-       u_int32_t                       volumeBlockSize;
-       int64_t                         blocksToAdd;
-       int64_t                         bytesThisExtent;
-       HFSPlusExtentKey        foundKey;
-       HFSPlusExtentRecord     foundData;
-       u_int32_t                       foundIndex;
-       u_int32_t                       hint;
-       u_int32_t                       nextBlock;
-       u_int32_t                       startBlock;
-       Boolean                         allOrNothing;
-       Boolean                         forceContig;
-       Boolean                         wantContig;
-       Boolean                         useMetaZone;
-       Boolean                         needsFlush;
-       int                                     allowFlushTxns;
-       u_int32_t                       actualStartBlock;
-       u_int32_t                       actualNumBlocks;
-       u_int32_t                       numExtentsPerRecord;
-       int64_t                         maximumBytes;
-       int64_t                         availbytes;
-       int64_t                         peof;
-       u_int32_t                       prevblocks;
-       uint32_t                        fastdev = 0;
-
-       struct hfsmount *hfsmp = (struct hfsmount*)vcb; 
-       allowFlushTxns = 0;
-       needsFlush = false;
-       *actualBytesAdded = 0;
-       volumeBlockSize = vcb->blockSize;
-       allOrNothing = ((flags & kEFAllMask) != 0);
-       forceContig = ((flags & kEFContigMask) != 0);
-       prevblocks = fcb->ff_blocks;
-
-       if (vcb->vcbSigWord != kHFSSigWord) {
-               numExtentsPerRecord = kHFSPlusExtentDensity;
-       }
-#if CONFIG_HFS_STD
-       else {
-               /* HFS Standard */
-               numExtentsPerRecord = kHFSExtentDensity;
-
-               /* Make sure the request and new PEOF are less than 2GB if HFS std*/
-               if (bytesToAdd >=  kTwoGigabytes)
-                       goto HFS_Std_Overflow;
-               if ((((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes)
-                       goto HFS_Std_Overflow;
-       }
-#endif
-
-       //
-       //      Determine how many blocks need to be allocated.
-       //      Round up the number of desired bytes to add.
-       //
-       blocksToAdd = howmany(bytesToAdd, volumeBlockSize);
-       bytesToAdd = (int64_t)((int64_t)blocksToAdd * (int64_t)volumeBlockSize);
-
-       /*
-        * For deferred allocations just reserve the blocks.
-        */
-       if ((flags & kEFDeferMask)
-       &&  (vcb->vcbSigWord == kHFSPlusSigWord)
-       &&  (bytesToAdd < (int64_t)HFS_MAX_DEFERED_ALLOC)
-       &&  (blocksToAdd < hfs_freeblks(VCBTOHFS(vcb), 1))) {
-               hfs_lock_mount (hfsmp);
-               vcb->loanedBlocks += blocksToAdd;
-               hfs_unlock_mount(hfsmp);
-
-               fcb->ff_unallocblocks += blocksToAdd;
-               FTOC(fcb)->c_blocks   += blocksToAdd;
-               fcb->ff_blocks        += blocksToAdd;
-
-               /*
-                * We haven't touched the disk here; no blocks have been
-                * allocated and the volume will not be inconsistent if we
-                * don't update the catalog record immediately.
-                */
-               FTOC(fcb)->c_flag |= C_MINOR_MOD;
-               *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 = (int64_t)blocksToAdd * (int64_t)volumeBlockSize;
-               FTOC(fcb)->c_blocks -= loanedBlocks;
-               fcb->ff_blocks -= loanedBlocks;
-               fcb->ff_unallocblocks  = 0;
-
-               hfs_lock_mount(hfsmp);
-               vcb->loanedBlocks -= loanedBlocks;
-               hfs_unlock_mount(hfsmp);
-       }
-
-       //
-       //      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 ((vcb->vcbClpSiz > (int32_t)volumeBlockSize)
-       &&  (bytesToAdd < (int64_t)HFS_MAX_DEFERED_ALLOC)
-       &&  (flags & kEFNoClumpMask) == 0) {
-               maximumBytes = (int64_t)howmany(bytesToAdd, vcb->vcbClpSiz);
-               maximumBytes *= vcb->vcbClpSiz;
-       } else {
-               maximumBytes = bytesToAdd;
-       }
-       
-#if CONFIG_HFS_STD
-       //
-       //      Compute new physical EOF, rounded up to a multiple of a block.
-       //
-       if ( (vcb->vcbSigWord == kHFSSigWord) &&                //      Too big?
-                ((((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) ) {
-               if (allOrNothing)                                       // Yes, must they have it all?
-                       goto HFS_Std_Overflow;                                          // Yes, can't have it
-               else {
-                       --blocksToAdd;                                          // No, give give 'em one block less
-                       bytesToAdd -= volumeBlockSize;
-               }
-       }
-#endif
-
-       //
-       //      If allocation is all-or-nothing, make sure there are
-       //      enough free blocks on the volume (quick test).
-       //
-       if (allOrNothing &&
-           (blocksToAdd > hfs_freeblks(VCBTOHFS(vcb), flags & kEFReserveMask))) {
-               err = dskFulErr;
-               goto ErrorExit;
-       }
-       
-       //
-       //      See if there are already enough blocks allocated to the file.
-       //
-       peof = ((int64_t)fcb->ff_blocks * (int64_t)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->ff_blocks = peof / volumeBlockSize;
-               FTOC(fcb)->c_blocks += (bytesToAdd / volumeBlockSize);
-               FTOC(fcb)->c_flag |= C_MODIFIED;
-               goto Exit;
-       }
-       if (err != fxRangeErr)          // Any real error?
-               goto ErrorExit;                         // Yes, so exit immediately
-
-       //
-       //      Adjust the PEOF to the end of the last extent.
-       //
-       peof = (int64_t)((int64_t)nextBlock * (int64_t)volumeBlockSize);                        // currently allocated PEOF
-       bytesThisExtent = (int64_t)(nextBlock - fcb->ff_blocks) * (int64_t)volumeBlockSize;
-       if (bytesThisExtent != 0) {
-               fcb->ff_blocks = nextBlock;
-               FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize);
-               FTOC(fcb)->c_flag |= C_MODIFIED;
-               bytesToAdd -= bytesThisExtent;
-       }
-       
-       //
-       //      Allocate some more space.
-       //
-       //      First try a contiguous allocation (of the whole amount).
-       //      If that fails, get whatever we can.
-       //              If forceContig, then take whatever we got
-       //              else, keep getting bits and pieces (non-contig)
-       
-       /*
-        * Note that for sparse devices (like sparse bundle dmgs), we
-        * should only be aggressive with re-using once-allocated pieces
-        * if we're not dealing with system files.  If we're trying to operate
-        * on behalf of a system file, we need the maximum contiguous amount
-        * possible.  For non-system files we favor locality and fragmentation over
-        * contiguity as it can result in fewer blocks being needed from the underlying
-        * filesystem that the sparse image resides upon. 
-        */
-       err = noErr;
-       if (   (vcb->hfs_flags & HFS_HAS_SPARSE_DEVICE)
-                       && (fcb->ff_cp->c_fileid >= kHFSFirstUserCatalogNodeID)
-                       && (flags & kEFMetadataMask) == 0) {
-               /*
-                * We want locality over contiguity so by default we set wantContig to 
-                * false unless we hit one of the circumstances below.
-                */ 
-               wantContig = false;
-               if (hfs_isrbtree_active(VCBTOHFS(vcb))) {
-                       /* 
-                        * If the red-black tree is acive, we can always find a suitable contiguous
-                        * chunk.  So if the user specifically requests contiguous files,  we should 
-                        * honor that no matter what kind of device it is.
-                        */
-                       if (forceContig) {
-                               wantContig = true;
-                       }
-               }
-               else {
-                       /* 
-                        * If the red-black tree is not active, then only set wantContig to true
-                        * if we have never done a contig scan on the device, which would populate
-                        * the free extent cache.  Note that the caller may explicitly unset the 
-                        * DID_CONTIG_SCAN bit in order to force us to vend a contiguous extent here
-                        * if the caller wants to get a contiguous chunk.
-                        */
-                       if ((vcb->hfs_flags & HFS_DID_CONTIG_SCAN) == 0) { 
-                               vcb->hfs_flags |= HFS_DID_CONTIG_SCAN;  
-                               wantContig = true;
-                       }
-               }
-       } 
-       else {
-               wantContig = true;
-       }
-
-       if (should_pin_blocks(hfsmp, fcb))
-               fastdev = HFS_ALLOC_FAST_DEV;
-
-       useMetaZone = flags & kEFMetadataMask;
-       do {
-               if (blockHint != 0)
-                       startBlock = blockHint;
-               else
-                       startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount;
-
-               actualNumBlocks = 0;
-               actualStartBlock = 0;
-                       
-               /* Find number of free blocks based on reserved block flag option */
-               availbytes = (int64_t)hfs_freeblks(VCBTOHFS(vcb), flags & kEFReserveMask) *
-                            (int64_t)volumeBlockSize;
-               if (availbytes <= 0) {
-                       err = dskFulErr;
-               } else {
-                       if (wantContig && (availbytes < bytesToAdd)) {
-                               err = dskFulErr;
-                       }
-                       else {
-                               uint32_t ba_flags = fastdev;
-
-                               if (wantContig) {
-                                       ba_flags |= HFS_ALLOC_FORCECONTIG;      
-                               }
-                               if (useMetaZone) {
-                                       ba_flags |= HFS_ALLOC_METAZONE;
-                               }
-                               if (allowFlushTxns) {
-                                       ba_flags |= HFS_ALLOC_FLUSHTXN;
-                               }
-
-                               err = BlockAllocate(
-                                                 vcb,
-                                                 startBlock,
-                                                 howmany(MIN(bytesToAdd, availbytes), volumeBlockSize),
-                                                 howmany(MIN(maximumBytes, availbytes), volumeBlockSize),
-                                                 ba_flags,
-                                                 &actualStartBlock,
-                                                 &actualNumBlocks);
-                       }
-               }
-               if (err == dskFulErr) {
-                       if (forceContig) {
-                               if (allowFlushTxns == 0) {
-                                       /* If we're forcing contiguity, re-try but allow plucking from recently freed regions */
-                                       allowFlushTxns = 1;
-                                       wantContig = 1;
-                                       err = noErr;
-                                       continue;
-                               }
-                               else {
-                                       break;                  // AllocContig failed because not enough contiguous space
-                               }
-                       }
-                       if (wantContig) {
-                               //      Couldn't get one big chunk, so get whatever we can.
-                               err = noErr;
-                               wantContig = false;
-                               continue;
-                       }
-                       if (actualNumBlocks != 0)
-                               err = noErr;
-
-                       if (useMetaZone == 0) {
-                               /* Couldn't get anything so dip into metadat zone */
-                               err = noErr;
-                               useMetaZone = 1;
-                               continue;
-                       }
-
-                       /* If we couldn't find what we needed without flushing the journal, then go ahead and do it now */
-                       if (allowFlushTxns == 0) {
-                               allowFlushTxns = 1;
-                               err = noErr;
-                               continue;
-                       }
-
-               }
-               if (err == noErr) {
-                       //      Add the new extent to the existing extent record, or create a new one.
-                       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, 0, &foundKey, foundData, hint);
-                               if (err != noErr) break;
-                       }
-                       else {
-                               u_int16_t       i;
-
-                               //      Need to add a new extent.  See if there is room in the current record.
-                               if (foundData[foundIndex].blockCount != 0)      //      Is current extent free to use?
-                                       ++foundIndex;                                                   //      No, so use the next one.
-                               if (foundIndex == numExtentsPerRecord) {
-                                       //      This record is full.  Need to create a new one.
-                                       if (FTOC(fcb)->c_fileid == kHFSExtentsFileID) {
-                                               (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks, 0);
-                                               err = dskFulErr;                // Oops.  Can't extend extents file past first record.
-                                               break;
-                                       }
-                                       
-                                       foundKey.keyLength = kHFSPlusExtentKeyMaximumLength;
-                                       if (FORK_IS_RSRC(fcb))
-                                               foundKey.forkType = kResourceForkType;
-                                       else
-                                               foundKey.forkType = kDataForkType;
-                                       foundKey.pad = 0;
-                                       foundKey.fileID = FTOC(fcb)->c_fileid;
-                                       foundKey.startBlock = nextBlock;
-                                       
-                                       foundData[0].startBlock = actualStartBlock;
-                                       foundData[0].blockCount = actualNumBlocks;
-                                       
-                                       // zero out remaining extents...
-                                       for (i = 1; i < kHFSPlusExtentDensity; ++i)
-                                       {
-                                               foundData[i].startBlock = 0;
-                                               foundData[i].blockCount = 0;
-                                       }
-
-                                       foundIndex = 0;
-                                       
-                                       err = CreateExtentRecord(vcb, &foundKey, foundData, &hint);
-                                       if (err == fxOvFlErr) {
-                                               //      We couldn't create an extent record because extents B-tree
-                                               //      couldn't grow.  Dellocate the extent just allocated and
-                                               //      return a disk full error.
-                                               (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks, 0);
-                                               err = dskFulErr;
-                                       }
-                                       if (err != noErr) break;
-
-                                       needsFlush = true;              //      We need to update the B-tree header
-                               }
-                               else {
-                                       //      Add a new extent into this record and update.
-                                       foundData[foundIndex].startBlock = actualStartBlock;
-                                       foundData[foundIndex].blockCount = actualNumBlocks;
-                                       err = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint);
-                                       if (err != noErr) break;
-                               }
-                       }
-
-                       // Figure out how many bytes were actually allocated.
-                       // NOTE: BlockAllocate could have allocated more than we asked for.
-                       // Don't set the PEOF beyond what our client asked for.
-                       nextBlock += actualNumBlocks;
-                       bytesThisExtent = (int64_t)((int64_t)actualNumBlocks * (int64_t)volumeBlockSize);
-                       if (bytesThisExtent > bytesToAdd) {
-                               bytesToAdd = 0;
-                       }
-                       else {
-                               bytesToAdd -= bytesThisExtent;
-                               maximumBytes -= bytesThisExtent;
-                       }
-                       fcb->ff_blocks += (bytesThisExtent / volumeBlockSize);
-                       FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize);
-                       FTOC(fcb)->c_flag |= C_MODIFIED;
-
-                       //      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.
-                       if (forceContig) {
-                               if (bytesToAdd != 0)
-                                       err = dskFulErr;
-                               break;                  //      We've already got everything that's contiguous
-                       }
-               }
-       } while (err == noErr && bytesToAdd);
-
-ErrorExit:
-Exit:
-       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_lock_mount (hfsmp);
-                       HFS_UPDATE_NEXT_ALLOCATION(vcb, VCBTOHFS(vcb)->hfs_metazone_end + 1);   
-                       MarkVCBDirty(vcb);
-                       hfs_unlock_mount(hfsmp);
-               }
-       }
-       if (prevblocks < fcb->ff_blocks) {
-               *actualBytesAdded = (int64_t)(fcb->ff_blocks - prevblocks) * (int64_t)volumeBlockSize;
-       } else {
-               *actualBytesAdded = 0;
-       }
-
-       if (fastdev) {
-               hfs_hotfile_adjust_blocks(fcb->ff_cp->c_vp, 
-                                         (int64_t)prevblocks - fcb->ff_blocks);
-       }
-
-       if (needsFlush)
-               (void) FlushExtentFile(vcb);
-
-       return err;
-
-#if CONFIG_HFS_STD
-HFS_Std_Overflow:
-       err = fileBoundsErr;
-       goto ErrorExit;
-#endif
-}
-
-
-
-//_________________________________________________________________________________
-//
-// Routine:            TruncateFileC
-//
-// Function:   Truncates the disk space allocated to a file.  The file space is
-//                             truncated to a specified new PEOF rounded up to the next allocation
-//                             block boundry.  If the 'TFTrunExt' option is specified, the file is
-//                             truncated to the end of the extent containing the new PEOF.
-//
-//_________________________________________________________________________________
-
-OSErr TruncateFileC (
-       ExtendedVCB             *vcb,                           // volume that file resides on
-       FCB                             *fcb,                           // FCB of file to truncate
-       int64_t                 peof,                           // new physical size for file
-       int                             deleted,                        // if nonzero, the file's catalog record has already been deleted.
-       int                             rsrc,                           // does this represent a resource fork or not?
-       uint32_t                fileid,                         // the fileid of the file we're manipulating.
-       Boolean                 truncateToExtent)       // if true, truncate to end of extent containing newPEOF
-
-{
-       OSErr                           err;
-       u_int32_t                       nextBlock;              //      next file allocation block to consider
-       u_int32_t                       startBlock;             //      Physical (volume) allocation block number of start of a range
-       u_int32_t                       physNumBlocks;  //      Number of allocation blocks in file (according to PEOF)
-       u_int32_t                       numBlocks;
-       HFSPlusExtentKey        key;                    //      key for current extent record; key->keyLength == 0 if FCB's extent record
-       u_int32_t                       hint;                   //      BTree hint corresponding to key
-       HFSPlusExtentRecord     extentRecord;
-       u_int32_t                       extentIndex;
-       u_int32_t                       extentNextBlock;
-       u_int32_t                       numExtentsPerRecord;
-       int64_t             temp64;
-       u_int8_t                        forkType;
-       Boolean                         extentChanged;  // true if we actually changed an extent
-       Boolean                         recordDeleted;  // true if an extent record got deleted
-
-       recordDeleted = false;
-       
-       if (vcb->vcbSigWord == kHFSPlusSigWord) {
-               numExtentsPerRecord = kHFSPlusExtentDensity;
-       }
-       else {
-               numExtentsPerRecord = kHFSExtentDensity;
-       }
-       
-       if (rsrc) {
-               forkType = kResourceForkType;
-       }
-       else {
-               forkType = kDataForkType;
-       }
-       
-       temp64 = fcb->ff_blocks;
-       physNumBlocks = (u_int32_t)temp64;
-
-       //
-       //      Round newPEOF up to a multiple of the allocation block size.  If new size is
-       //      two gigabytes or more, then round down by one allocation block (??? really?
-       //      shouldn't that be an error?).
-       //
-       nextBlock = howmany(peof, vcb->blockSize);      // number of allocation blocks to remain in file
-       peof = (int64_t)((int64_t)nextBlock * (int64_t)vcb->blockSize);                                 // number of bytes in those blocks
-
-#if CONFIG_HFS_STD
-       if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= kTwoGigabytes)) {
-               #if DEBUG
-                       DebugStr("HFS: Trying to truncate a file to 2GB or more");
-               #endif
-               err = fileBoundsErr;
-               goto ErrorExit;
-       }
-#endif
-
-       //
-       //      Update FCB's length
-       //
-       /*
-        * XXX Any errors could cause ff_blocks and c_blocks to get out of sync...
-        */
-       numBlocks = peof / vcb->blockSize;
-       if (!deleted) {
-               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
-       if (!deleted) {
-               /* 
-                * If the file is already C_NOEXISTS, then the catalog record
-                * has been removed from disk already.  We wouldn't need to force 
-                * another update
-                */
-               FTOC(fcb)->c_flag |= C_MODIFIED;
-       }
-       //
-       //      If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
-       //      all storage).
-       //
-       if (peof == 0) {
-               int i;
-               
-               //      Deallocate all the extents for this fork
-               err = DeallocateFork(vcb, 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)
-               if (err == noErr) {
-                       for (i=0; i < kHFSPlusExtentDensity; i++) {
-                               fcb->fcbExtents[i].startBlock = 0;
-                               fcb->fcbExtents[i].blockCount = 0;
-                       }
-               }
-               goto Done;
-       }
-       
-       //
-       //      Find the extent containing byte (peof-1).  This is the last extent we'll keep.
-       //      (If truncateToExtent is true, we'll keep the whole extent; otherwise, we'll only
-       //      keep up through peof).  The search will tell us how many allocation blocks exist
-       //      in the found extent plus all previous extents.
-       //
-       err = SearchExtentFile(vcb, fcb, peof-1, &key, extentRecord, &extentIndex, &hint, &extentNextBlock);
-       if (err != noErr) goto ErrorExit;
-
-       extentChanged = false;          //      haven't changed the extent yet
-       
-       if (!truncateToExtent) {
-               //
-               //      Shorten this extent.  It may be the case that the entire extent gets
-               //      freed here.
-               //
-               numBlocks = extentNextBlock - nextBlock;        //      How many blocks in this extent to free up
-               if (numBlocks != 0) {
-                       //      Compute first volume allocation block to free
-                       startBlock = extentRecord[extentIndex].startBlock + extentRecord[extentIndex].blockCount - numBlocks;
-                       //      Free the blocks in bitmap
-                       err = BlockDeallocate(vcb, startBlock, numBlocks, 0);
-                       if (err != noErr) goto ErrorExit;
-                       //      Adjust length of this extent
-                       extentRecord[extentIndex].blockCount -= numBlocks;
-                       //      If extent is empty, set start block to 0
-                       if (extentRecord[extentIndex].blockCount == 0)
-                               extentRecord[extentIndex].startBlock = 0;
-                       //      Remember that we changed the extent record
-                       extentChanged = true;
-               }
-       }
-       
-       //
-       //      Now move to the next extent in the record, and set up the file allocation block number
-       //
-       nextBlock = extentNextBlock;            //      Next file allocation block to free
-       ++extentIndex;                                          //      Its index within the extent record
-       
-       //
-       //      Release all following extents in this extent record.  Update the record.
-       //
-       while (extentIndex < numExtentsPerRecord && extentRecord[extentIndex].blockCount != 0) {
-               numBlocks = extentRecord[extentIndex].blockCount;
-               //      Deallocate this extent
-               err = BlockDeallocate(vcb, extentRecord[extentIndex].startBlock, numBlocks, 0);
-               if (err != noErr) goto ErrorExit;
-               //      Update next file allocation block number
-               nextBlock += numBlocks;
-               //      Zero out start and length of this extent to delete it from record
-               extentRecord[extentIndex].startBlock = 0;
-               extentRecord[extentIndex].blockCount = 0;
-               //      Remember that we changed an extent
-               extentChanged = true;
-               //      Move to next extent in record
-               ++extentIndex;
-       }
-       
-       //
-       //      If any of the extents in the current record were changed, then update that
-       //      record (in the FCB, or extents file).
-       //
-       if (extentChanged) {
-               err = UpdateExtentRecord(vcb, fcb, deleted, &key, extentRecord, hint);
-               if (err != noErr) goto ErrorExit;
-       }
-       
-       //
-       //      If there are any following allocation blocks, then we need
-       //      to seach for their extent records and delete those allocation
-       //      blocks.
-       //
-       if (nextBlock < physNumBlocks)
-               err = TruncateExtents(vcb, forkType, fileid, nextBlock, &recordDeleted);
-
-Done:
-ErrorExit:
-       if (recordDeleted)
-               (void) FlushExtentFile(vcb);
-
-       return err;
-}
-
-
-/*
- * HFS Plus only
- *
- */
-OSErr HeadTruncateFile (
-       ExtendedVCB  *vcb,
-       FCB  *fcb,
-       u_int32_t  headblks)
-{
-       HFSPlusExtentRecord  extents;
-       HFSPlusExtentRecord  tailExtents;
-       HFSCatalogNodeID  fileID;
-       u_int8_t  forkType;
-       u_int32_t  blkcnt = 0;
-       u_int32_t  startblk;
-       u_int32_t  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, 0);
-                       /*
-                        * 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("hfs: HeadTruncateFile: problems deallocating %s (%d)\n",
-                                              FTOC(fcb)->c_desc.cd_nameptr ? (const char *)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 (;;) {
-               u_int32_t  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("hfs: HeadTruncateFile: problems finding extents %s (%d)\n",
-                                      FTOC(fcb)->c_desc.cd_nameptr ? (const char *)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, 0);
-                               if (error) {
-                                       printf("hfs: HeadTruncateFile: problems deallocating %s (%d)\n",
-                                              FTOC(fcb)->c_desc.cd_nameptr ? (const char *)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("hfs: HeadTruncateFile: problems deallocating %s (%d)\n",
-                               FTOC(fcb)->c_desc.cd_nameptr ? (const char *)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 -= headblks;
-               fcb->ff_blocks = blkcnt;
-
-               FTOC(fcb)->c_flag |= C_MODIFIED;
-               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)
-//
-//     Function:       Searches extent record for the extent mapping a given file
-//                             allocation block number (FABN).
-//
-//     Input:          searchFABN                      -  desired FABN
-//                             extentData                      -  pointer to extent data record (xdr)
-//                             extentDataStartFABN     -  beginning FABN for extent record
-//
-//     Output:         foundExtentDataOffset  -  offset to extent entry within xdr
-//                                                     result = noErr, offset to extent mapping desired FABN
-//                                                     result = FXRangeErr, offset to last extent in record
-//                             endingFABNPlusOne       -  ending FABN +1
-//                             noMoreExtents           - True if the extent was not found, and the
-//                                                                       extent record was not full (so don't bother
-//                                                                       looking in subsequent records); false otherwise.
-//
-//     Result:         noErr = ok
-//                             FXRangeErr = desired FABN > last mapped FABN in record
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\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(
-       ExtendedVCB             *vcb,
-       u_int32_t                               searchFABN,
-       const HFSPlusExtentRecord       extentData,
-       u_int32_t                               extentDataStartFABN,
-       u_int32_t                               *foundExtentIndex,
-       u_int32_t                               *endingFABNPlusOne,
-       Boolean                                 *noMoreExtents)
-{
-       OSErr   err = noErr;
-       u_int32_t       extentIndex;
-       /* Set it to the HFS std value */
-       u_int32_t       numberOfExtents = kHFSExtentDensity;
-       u_int32_t       numAllocationBlocks;
-       Boolean foundExtent;
-       
-       *endingFABNPlusOne      = extentDataStartFABN;
-       *noMoreExtents          = false;
-       foundExtent                     = false;
-
-       /* Override numberOfExtents for HFS+/HFSX */
-       if (vcb->vcbSigWord != kHFSSigWord) {
-               numberOfExtents = kHFSPlusExtentDensity;
-       }
-       
-       for( extentIndex = 0; extentIndex < numberOfExtents; ++extentIndex )
-       {
-               
-               // Loop over the extent record and find the search FABN.
-               
-               numAllocationBlocks = extentData[extentIndex].blockCount;
-               if ( numAllocationBlocks == 0 )
-               {
-                       break;
-               }
-
-               *endingFABNPlusOne += numAllocationBlocks;
-               
-               if( searchFABN < *endingFABNPlusOne )
-               {
-                       // Found the extent.
-                       foundExtent = true;
-                       break;
-               }
-       }
-       
-       if( foundExtent )
-       {
-               // Found the extent. Note the extent offset
-               *foundExtentIndex = extentIndex;
-       }
-       else
-       {
-               // Did not find the extent. Set foundExtentDataOffset accordingly
-               if( extentIndex > 0 )
-               {
-                       *foundExtentIndex = extentIndex - 1;
-               }
-               else
-               {
-                       *foundExtentIndex = 0;
-               }
-               
-               // If we found an empty extent, then set noMoreExtents.
-               if (extentIndex < numberOfExtents)
-                       *noMoreExtents = true;
-
-               // Finally, return an error to the caller
-               err = fxRangeErr;
-       }
-
-       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:        SearchExtentFile (was XFSearch)
-//
-//     Function:       Searches extent file (including the FCB resident extent record)
-//                             for the extent mapping a given file position.
-//
-//     Input:          vcb                     -  VCB pointer
-//                             fcb                     -  FCB pointer
-//                             filePosition    -  file position (byte address)
-//
-// Output:             foundExtentKey                  -  extent key record (xkr)
-//                                                     If extent was found in the FCB's resident extent record,
-//                                                     then foundExtentKey->keyLength will be set to 0.
-//                             foundExtentData                 -  extent data record(xdr)
-//                             foundExtentIndex        -  index to extent entry in xdr
-//                                                     result =  0, offset to extent mapping desired FABN
-//                                                     result = FXRangeErr, offset to last extent in record
-//                                                                      (i.e., kNumExtentsPerRecord-1)
-//                             extentBTreeHint                 -  BTree hint for extent record
-//                                                     kNoHint = Resident extent record
-//                             endingFABNPlusOne               -  ending FABN +1
-//
-//     Result:
-//             noErr                   Found an extent that contains the given file position
-//             FXRangeErr              Given position is beyond the last allocated extent
-//             (other)                 (some other internal I/O 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
-
-OSErr SearchExtentFile(
-       ExtendedVCB     *vcb,
-       const FCB                       *fcb,
-       int64_t                         filePosition,
-       HFSPlusExtentKey        *foundExtentKey,
-       HFSPlusExtentRecord     foundExtentData,
-       u_int32_t                       *foundExtentIndex,
-       u_int32_t                       *extentBTreeHint,
-       u_int32_t                       *endingFABNPlusOne )
-{
-       OSErr                           err;
-       u_int32_t                       filePositionBlock;
-       int64_t                         temp64;
-       Boolean                         noMoreExtents;
-       int  lockflags;
-       
-       temp64 = filePosition / (int64_t)vcb->blockSize;
-       filePositionBlock = (u_int32_t)temp64;
-
-    bcopy ( fcb->fcbExtents, foundExtentData, sizeof(HFSPlusExtentRecord));
-       
-       //      Search the resident FCB first.
-    err = SearchExtentRecord( vcb, filePositionBlock, foundExtentData, 0,
-                                                                       foundExtentIndex, endingFABNPlusOne, &noMoreExtents );
-
-       if( err == noErr ) {
-               // Found the extent. Set results accordingly
-               *extentBTreeHint = kNoHint;                     // no hint, because not in the BTree
-               foundExtentKey->keyLength = 0;          // 0 = the FCB itself
-               
-               goto Exit;
-       }
-       
-       //      Didn't find extent in FCB.  If FCB's extent record wasn't full, there's no point
-       //      in searching the extents file.  Note that SearchExtentRecord left us pointing at
-       //      the last valid extent (or the first one, if none were valid).  This means we need
-       //      to fill in the hint and key outputs, just like the "if" statement above.
-       if ( noMoreExtents ) {
-               *extentBTreeHint = kNoHint;                     // no hint, because not in the BTree
-               foundExtentKey->keyLength = 0;          // 0 = the FCB itself
-               err = fxRangeErr;               // There are no more extents, so must be beyond PEOF
-               goto Exit;
-       }
-       
-       //
-       //      Find the desired record, or the previous record if it is the same fork
-       //
-       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) {
-               //
-               //      If we get here, the desired position is beyond the extents in the FCB, and there are no extents
-               //      in the extents file.  Return the FCB's extents and a range error.
-               //
-               *extentBTreeHint = kNoHint;
-               foundExtentKey->keyLength = 0;
-               err = GetFCBExtentRecord(fcb, foundExtentData);
-               //      Note: foundExtentIndex and endingFABNPlusOne have already been set as a result of the very
-               //      first SearchExtentRecord call in this function (when searching in the FCB's extents, and
-               //      we got a range error).
-               
-               return fxRangeErr;
-       }
-       
-       //
-       //      If we get here, there was either a BTree error, or we found an appropriate record.
-       //      If we found a record, then search it for the correct index into the extents.
-       //
-       if (err == noErr) {
-               //      Find appropriate index into extent record
-               err = SearchExtentRecord(vcb, filePositionBlock, foundExtentData, foundExtentKey->startBlock,
-                                                                foundExtentIndex, endingFABNPlusOne, &noMoreExtents);
-       }
-
-Exit:
-       return err;
-}
-
-
-
-//============================================================================
-//     Routine:        UpdateExtentRecord
-//
-//     Function:       Write new extent data to an existing extent record with a given key.
-//                             If all of the extents are empty, and the extent record is in the
-//                             extents file, then the record is deleted.
-//
-//     Input:          vcb                                             -       the volume containing the extents
-//                             fcb                                             -       the file that owns the extents
-//                             deleted                                 -       whether or not the file is already deleted
-//                             extentFileKey                   -       pointer to extent key record (xkr)
-//                                             If the key length is 0, then the extents are actually part
-//                                             of the catalog record, stored in the FCB.
-//                             extentData                      -       pointer to extent data record (xdr)
-//                             extentBTreeHint                 -       hint for given key, or kNoHint
-//
-//     Result:         noErr = ok
-//                             (other) = error from BTree
-//============================================================================
-
-static OSErr UpdateExtentRecord (ExtendedVCB *vcb, FCB  *fcb, int deleted,
-                                                                const HFSPlusExtentKey  *extentFileKey,
-                                                                const HFSPlusExtentRecord  extentData,
-                                                                u_int32_t  extentBTreeHint) 
-{
-    OSErr err = noErr;
-       
-       if (extentFileKey->keyLength == 0) {    // keyLength == 0 means the FCB's extent record
-               BlockMoveData(extentData, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
-               if (!deleted) {
-                       FTOC(fcb)->c_flag |= C_MODIFIED;
-               }
-       }
-       else {
-               struct BTreeIterator *btIterator = NULL;
-               FSBufferDescriptor btRecord;
-               u_int16_t btRecordSize;
-               FCB * btFCB;
-               int lockflags;
-
-               //
-               //      Need to find and change a record in Extents BTree
-               //
-               btFCB = GetFileControlBlock(vcb->extentsRefNum);
-               
-               btIterator = hfs_mallocz(sizeof(struct BTreeIterator));
-
-               /*
-                * 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);
-
-               /* HFS+/HFSX */
-               if (vcb->vcbSigWord != kHFSSigWord) {           //      HFS Plus volume
-                       HFSPlusExtentRecord     foundData;              // The extent data actually found
-
-                       BlockMoveData(extentFileKey, &btIterator->key, sizeof(HFSPlusExtentKey));
-
-                       btIterator->hint.index = 0;
-                       btIterator->hint.nodeNum = extentBTreeHint;
-
-                       btRecord.bufferAddress = &foundData;
-                       btRecord.itemSize = sizeof(HFSPlusExtentRecord);
-                       btRecord.itemCount = 1;
-
-                       err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator);
-       
-                       if (err == noErr) {
-                               BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord));
-                               err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
-                       }
-                       (void) BTFlushPath(btFCB);
-               }
-#if CONFIG_HFS_STD
-               else {
-                       /* HFS Standard */
-                       HFSExtentKey *  key;                            // Actual extent key used on disk in HFS
-                       HFSExtentRecord foundData;                      // The extent data actually found
-
-                       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;
-
-                       btRecord.bufferAddress = &foundData;
-                       btRecord.itemSize = sizeof(HFSExtentRecord);
-                       btRecord.itemCount = 1;
-
-                       err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator);
-
-                       if (err == noErr)
-                               err = HFSPlusToHFSExtents(extentData, (HFSExtentDescriptor *)&foundData);
-
-                       if (err == noErr)
-                               err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
-                       (void) BTFlushPath(btFCB);
-
-               }
-#endif
-
-               hfs_systemfile_unlock(vcb, lockflags);
-
-               hfs_free(btIterator, sizeof(*btIterator));
-       }
-       
-       return err;
-}
-
-
-
-#if CONFIG_HFS_STD
-static OSErr HFSPlusToHFSExtents(
-       const HFSPlusExtentRecord       oldExtents,
-       HFSExtentRecord         newExtents)
-{
-       OSErr   err;
-       
-       err = noErr;
-
-       // 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;
-
-       #if DEBUG
-               if (oldExtents[3].startBlock || oldExtents[3].blockCount) {
-                       DebugStr("ExtentRecord with > 3 extents is invalid for HFS");
-                       err = fsDSIntErr;
-               }
-       #endif
-       
-       return err;
-}
-#endif
-
-
-
-static OSErr GetFCBExtentRecord(
-       const FCB                       *fcb,
-       HFSPlusExtentRecord     extents)
-{
-       
-       BlockMoveData(fcb->fcbExtents, extents, sizeof(HFSPlusExtentRecord));
-       
-       return noErr;
-}
-
-
-//_________________________________________________________________________________
-//
-// Routine:            ExtentsAreIntegral
-//
-// Purpose:            Ensure that each extent can hold an integral number of nodes
-//                             Called by the NodesAreContiguous function
-//_________________________________________________________________________________
-
-static Boolean ExtentsAreIntegral(
-       const HFSPlusExtentRecord extentRecord,
-       u_int32_t       mask,
-       u_int32_t       *blocksChecked,
-       Boolean         *checkedLastExtent)
-{
-       u_int32_t       blocks;
-       u_int32_t       extentIndex;
-
-       *blocksChecked = 0;
-       *checkedLastExtent = false;
-       
-       for(extentIndex = 0; extentIndex < kHFSPlusExtentDensity; extentIndex++)
-       {               
-               blocks = extentRecord[extentIndex].blockCount;
-               
-               if ( blocks == 0 )
-               {
-                       *checkedLastExtent = true;
-                       break;
-               }
-
-               *blocksChecked += blocks;
-
-               if (blocks & mask)
-                       return false;
-       }
-       
-       return true;
-}
-
-
-//_________________________________________________________________________________
-//
-// Routine:            NodesAreContiguous
-//
-// Purpose:            Ensure that all b-tree nodes are contiguous on disk
-//                             Called by BTOpenPath during volume mount
-//_________________________________________________________________________________
-
-Boolean NodesAreContiguous(
-       ExtendedVCB     *vcb,
-       FCB                     *fcb,
-       u_int32_t       nodeSize)
-{
-       u_int32_t                       mask;
-       u_int32_t                       startBlock;
-       u_int32_t                       blocksChecked;
-       u_int32_t                       hint;
-       HFSPlusExtentKey        key;
-       HFSPlusExtentRecord     extents;
-       OSErr                           result;
-       Boolean                         lastExtentReached;
-       int  lockflags;
-       
-
-       if (vcb->blockSize >= nodeSize)
-               return TRUE;
-
-       mask = (nodeSize / vcb->blockSize) - 1;
-
-       // check the local extents
-       (void) GetFCBExtentRecord(fcb, extents);
-       if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
-               return FALSE;
-
-       if ( lastExtentReached || 
-                (int64_t)((int64_t)blocksChecked * (int64_t)vcb->blockSize) >= (int64_t)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, fcb->ff_cp->c_fileid, startBlock, FALSE, &key, extents, &hint);
-               if (result) break;
-
-               if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) ) {
-                       hfs_systemfile_unlock(vcb, lockflags);
-                       return FALSE;
-               }
-               startBlock += blocksChecked;
-       }
-       hfs_systemfile_unlock(vcb, lockflags);
-       return TRUE;
-}
-