X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/5d5c5d0d5b79ade9a973d55186ffda2638ba2b6e..2dced7af2b695f87fe26496a3e73c219b7880cbc:/bsd/hfs/hfscommon/Misc/FileExtentMapping.c diff --git a/bsd/hfs/hfscommon/Misc/FileExtentMapping.c b/bsd/hfs/hfscommon/Misc/FileExtentMapping.c index 2a03dee2c..31249e05b 100644 --- a/bsd/hfs/hfscommon/Misc/FileExtentMapping.c +++ b/bsd/hfs/hfscommon/Misc/FileExtentMapping.c @@ -1,31 +1,29 @@ /* - * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2014 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_OSREFERENCE_HEADER_START@ + * @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 + * 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_LICENSE_OSREFERENCE_HEADER_END@ + * + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ @@ -37,6 +35,7 @@ #include "../headers/BTreesInternal.h" #include +#include /* ============================================================ @@ -68,7 +67,9 @@ Public (Exported) Routines: 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). ============================================================ @@ -76,9 +77,6 @@ Internal Routines: ============================================================ FindExtentRecord Search the extents BTree for a particular extent record. - SearchExtentFile - Search the FCB and extents file for an extent record that - contains a given file position (in bytes). SearchExtentRecord Search a given extent record to see if it contains a given file position (in bytes). Used by SearchExtentFile. @@ -99,7 +97,9 @@ Internal Routines: and was in the extents file, then delete the record instead. */ -static const SInt64 kTwoGigabytes = 0x80000000LL; +#if CONFIG_HFS_STD +static const int64_t kTwoGigabytes = 0x80000000LL; +#endif enum { @@ -110,87 +110,80 @@ enum }; +#if CONFIG_HFS_STD static OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents); +#endif static OSErr FindExtentRecord( const ExtendedVCB *vcb, - UInt8 forkType, - UInt32 fileID, - UInt32 startBlock, + u_int8_t forkType, + u_int32_t fileID, + u_int32_t startBlock, Boolean allowPrevious, HFSPlusExtentKey *foundKey, HFSPlusExtentRecord foundData, - UInt32 *foundHint); + u_int32_t *foundHint); static OSErr DeleteExtentRecord( const ExtendedVCB *vcb, - UInt8 forkType, - UInt32 fileID, - UInt32 startBlock); + u_int8_t forkType, + u_int32_t fileID, + u_int32_t startBlock); static OSErr CreateExtentRecord( ExtendedVCB *vcb, HFSPlusExtentKey *key, HFSPlusExtentRecord extents, - UInt32 *hint); + u_int32_t *hint); static OSErr GetFCBExtentRecord( const FCB *fcb, HFSPlusExtentRecord extents); -static OSErr SearchExtentFile( - ExtendedVCB *vcb, - const FCB *fcb, - SInt64 filePosition, - HFSPlusExtentKey *foundExtentKey, - HFSPlusExtentRecord foundExtentData, - UInt32 *foundExtentDataIndex, - UInt32 *extentBTreeHint, - UInt32 *endingFABNPlusOne ); - static OSErr SearchExtentRecord( ExtendedVCB *vcb, - UInt32 searchFABN, + u_int32_t searchFABN, const HFSPlusExtentRecord extentData, - UInt32 extentDataStartFABN, - UInt32 *foundExtentDataOffset, - UInt32 *endingFABNPlusOne, + u_int32_t extentDataStartFABN, + u_int32_t *foundExtentDataOffset, + u_int32_t *endingFABNPlusOne, Boolean *noMoreExtents); static OSErr ReleaseExtents( ExtendedVCB *vcb, const HFSPlusExtentRecord extentRecord, - UInt32 *numReleasedAllocationBlocks, + u_int32_t *numReleasedAllocationBlocks, Boolean *releasedLastExtent); static OSErr DeallocateFork( ExtendedVCB *vcb, HFSCatalogNodeID fileID, - UInt8 forkType, + u_int8_t forkType, HFSPlusExtentRecord catalogExtents, Boolean * recordDeleted); static OSErr TruncateExtents( ExtendedVCB *vcb, - UInt8 forkType, - UInt32 fileID, - UInt32 startBlock, + u_int8_t forkType, + u_int32_t fileID, + u_int32_t startBlock, Boolean * recordDeleted); static OSErr UpdateExtentRecord ( ExtendedVCB *vcb, - FCB *fcb, + FCB *fcb, + int deleted, const HFSPlusExtentKey *extentFileKey, const HFSPlusExtentRecord extentData, - UInt32 extentBTreeHint); + u_int32_t extentBTreeHint); static Boolean ExtentsAreIntegral( const HFSPlusExtentRecord extentRecord, - UInt32 mask, - UInt32 *blocksChecked, + u_int32_t mask, + u_int32_t *blocksChecked, Boolean *checkedLastExtent); //_________________________________________________________________________________ @@ -217,40 +210,45 @@ static Boolean ExtentsAreIntegral( //_________________________________________________________________________________ static OSErr FindExtentRecord( const ExtendedVCB *vcb, - UInt8 forkType, - UInt32 fileID, - UInt32 startBlock, + u_int8_t forkType, + u_int32_t fileID, + u_int32_t startBlock, Boolean allowPrevious, HFSPlusExtentKey *foundKey, HFSPlusExtentRecord foundData, - UInt32 *foundHint) + u_int32_t *foundHint) { FCB * fcb; - BTreeIterator *btIterator; + struct BTreeIterator *btIterator = NULL; FSBufferDescriptor btRecord; OSErr err; - UInt16 btRecordSize; + u_int16_t btRecordSize; err = noErr; if (foundHint) *foundHint = 0; fcb = GetFileControlBlock(vcb->extentsRefNum); - - MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK); + + MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK); + if (btIterator == NULL) { + return memFullErr; // translates to ENOMEM + } bzero(btIterator, sizeof(*btIterator)); - if (vcb->vcbSigWord == kHFSSigWord) { - HFSExtentKey * extentKeyPtr; - HFSExtentRecord extentData; + /* HFS Plus / HFSX */ + if (vcb->vcbSigWord != kHFSSigWord) { + HFSPlusExtentKey * extentKeyPtr; + HFSPlusExtentRecord extentData; - extentKeyPtr = (HFSExtentKey*) &btIterator->key; - extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength; - extentKeyPtr->forkType = forkType; - extentKeyPtr->fileID = fileID; + 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(HFSExtentRecord); + btRecord.itemSize = sizeof(HFSPlusExtentRecord); btRecord.itemCount = 1; err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator); @@ -271,44 +269,26 @@ static OSErr FindExtentRecord( } if (err == noErr) { - UInt16 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; - } + if (foundKey) + BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey)); // 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; - } + BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord)); } } - else { // HFS Plus volume - HFSPlusExtentKey * extentKeyPtr; - HFSPlusExtentRecord extentData; +#if CONFIG_HFS_STD + else { + HFSExtentKey * extentKeyPtr; + HFSExtentRecord extentData; - extentKeyPtr = (HFSPlusExtentKey*) &btIterator->key; - extentKeyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; - extentKeyPtr->forkType = forkType; - extentKeyPtr->pad = 0; - extentKeyPtr->fileID = fileID; + extentKeyPtr = (HFSExtentKey*) &btIterator->key; + extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength; + extentKeyPtr->forkType = forkType; + extentKeyPtr->fileID = fileID; extentKeyPtr->startBlock = startBlock; btRecord.bufferAddress = &extentData; - btRecord.itemSize = sizeof(HFSPlusExtentRecord); + btRecord.itemSize = sizeof(HFSExtentRecord); btRecord.itemCount = 1; err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator); @@ -329,17 +309,37 @@ static OSErr FindExtentRecord( } if (err == noErr) { + u_int16_t i; + // Copy the found key back for the caller - if (foundKey) - BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey)); + 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 - BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord)); + 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; - FREE(btIterator, M_TEMP); + + FREE(btIterator, M_TEMP); return err; } @@ -349,18 +349,21 @@ static OSErr CreateExtentRecord( ExtendedVCB *vcb, HFSPlusExtentKey *key, HFSPlusExtentRecord extents, - UInt32 *hint) + u_int32_t *hint) { - BTreeIterator * btIterator; + struct BTreeIterator *btIterator = NULL; FSBufferDescriptor btRecord; - UInt16 btRecordSize; + u_int16_t btRecordSize; int lockflags; OSErr err; err = noErr; *hint = 0; - MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK); + MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK); + if (btIterator == NULL) { + return memFullErr; // translates to ENOMEM + } bzero(btIterator, sizeof(*btIterator)); /* @@ -372,7 +375,18 @@ static OSErr CreateExtentRecord( */ lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK); - if (vcb->vcbSigWord == kHFSSigWord) { + /* 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; @@ -389,14 +403,7 @@ static OSErr CreateExtentRecord( err = HFSPlusToHFSExtents(extents, data); } - else { // HFS Plus volume - btRecordSize = sizeof(HFSPlusExtentRecord); - btRecord.bufferAddress = extents; - btRecord.itemSize = btRecordSize; - btRecord.itemCount = 1; - - BlockMoveData(key, &btIterator->key, sizeof(HFSPlusExtentKey)); - } +#endif if (err == noErr) err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator, &btRecord, btRecordSize); @@ -407,50 +414,58 @@ static OSErr CreateExtentRecord( (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum)); hfs_systemfile_unlock(vcb, lockflags); - - FREE(btIterator, M_TEMP); + + FREE (btIterator, M_TEMP); return err; } static OSErr DeleteExtentRecord( const ExtendedVCB *vcb, - UInt8 forkType, - UInt32 fileID, - UInt32 startBlock) + u_int8_t forkType, + u_int32_t fileID, + u_int32_t startBlock) { - BTreeIterator * btIterator; + struct BTreeIterator *btIterator = NULL; OSErr err; err = noErr; - MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK); + MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK); + if (btIterator == NULL) { + return memFullErr; // translates to ENOMEM + } bzero(btIterator, sizeof(*btIterator)); - if (vcb->vcbSigWord == kHFSSigWord) { - HFSExtentKey * keyPtr; + /* HFS+ / HFSX */ + if (vcb->vcbSigWord != kHFSSigWord) { // HFS Plus volume + HFSPlusExtentKey * keyPtr; - keyPtr = (HFSExtentKey*) &btIterator->key; - keyPtr->keyLength = kHFSExtentKeyMaximumLength; + keyPtr = (HFSPlusExtentKey*) &btIterator->key; + keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; keyPtr->forkType = forkType; + keyPtr->pad = 0; keyPtr->fileID = fileID; keyPtr->startBlock = startBlock; } - else { // HFS Plus volume - HFSPlusExtentKey * keyPtr; +#if CONFIG_HFS_STD + else { + /* HFS standard */ + HFSExtentKey * keyPtr; - keyPtr = (HFSPlusExtentKey*) &btIterator->key; - keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength; + keyPtr = (HFSExtentKey*) &btIterator->key; + keyPtr->keyLength = kHFSExtentKeyMaximumLength; keyPtr->forkType = forkType; - keyPtr->pad = 0; keyPtr->fileID = fileID; keyPtr->startBlock = startBlock; } +#endif err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator); (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum)); - FREE(btIterator, M_TEMP); + + FREE(btIterator, M_TEMP); return err; } @@ -464,7 +479,6 @@ static OSErr DeleteExtentRecord( // //_________________________________________________________________________________ -__private_extern__ OSErr MapFileBlockC ( ExtendedVCB *vcb, // volume that file resides on FCB *fcb, // FCB of file @@ -474,22 +488,22 @@ OSErr MapFileBlockC ( size_t *availableBytes) // number of contiguous bytes (up to numberOfBytes) { OSErr err; - UInt32 allocBlockSize; // Size of the volume's allocation block - UInt32 sectorSize; + u_int32_t allocBlockSize; // Size of the volume's allocation block + u_int32_t sectorSize; HFSPlusExtentKey foundKey; HFSPlusExtentRecord foundData; - UInt32 foundIndex; - UInt32 hint; - UInt32 firstFABN; // file allocation block of first block in found extent - UInt32 nextFABN; // file allocation block of block after end of found extent + u_int32_t foundIndex; + u_int32_t hint; + u_int32_t firstFABN; // 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 - UInt32 sectorsPerBlock; // Number of sectors per allocation block - UInt32 startBlock; // volume allocation block corresponding to firstFABN + u_int32_t sectorsPerBlock; // Number of sectors per allocation block + u_int32_t startBlock; // volume allocation block corresponding to firstFABN daddr64_t temp; off_t tmpOff; allocBlockSize = vcb->blockSize; - sectorSize = VCBTOHFS(vcb)->hfs_phys_block_size; + sectorSize = VCBTOHFS(vcb)->hfs_logical_block_size; err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN); if (err == noErr) { @@ -519,7 +533,7 @@ OSErr MapFileBlockC ( // offset in sectors from start of allocation block space // temp = (daddr64_t)((offset - (off_t)((off_t)(firstFABN) * (off_t)(allocBlockSize)))/sectorSize); - temp += startBlock * sectorsPerBlock; + temp += (daddr64_t)startBlock * (daddr64_t)sectorsPerBlock; /* Add in any volume offsets */ if (vcb->vcbSigWord == kHFSPlusSigWord) @@ -537,10 +551,19 @@ OSErr MapFileBlockC ( if (availableBytes) { tmpOff = dataEnd - offset; - if (tmpOff > (off_t)(numberOfBytes)) + /* + * Disallow negative runs. + */ + if (tmpOff <= 0) { + return EINVAL; + } + + if (tmpOff > (off_t)(numberOfBytes)) { *availableBytes = numberOfBytes; // more there than they asked for, so pin the output - else + } + else { *availableBytes = tmpOff; + } } return noErr; @@ -556,11 +579,11 @@ OSErr MapFileBlockC ( static OSErr ReleaseExtents( ExtendedVCB *vcb, const HFSPlusExtentRecord extentRecord, - UInt32 *numReleasedAllocationBlocks, + u_int32_t *numReleasedAllocationBlocks, Boolean *releasedLastExtent) { - UInt32 extentIndex; - UInt32 numberOfExtents; + u_int32_t extentIndex; + u_int32_t numberOfExtents; OSErr err = noErr; *numReleasedAllocationBlocks = 0; @@ -573,7 +596,7 @@ static OSErr ReleaseExtents( for( extentIndex = 0; extentIndex < numberOfExtents; extentIndex++) { - UInt32 numAllocationBlocks; + u_int32_t numAllocationBlocks; // Loop over the extent record and release the blocks associated with each extent. @@ -584,7 +607,7 @@ static OSErr ReleaseExtents( break; } - err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks ); + err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks , 0); if ( err != noErr ) break; @@ -612,15 +635,15 @@ static OSErr ReleaseExtents( static OSErr TruncateExtents( ExtendedVCB *vcb, - UInt8 forkType, - UInt32 fileID, - UInt32 startBlock, + u_int8_t forkType, + u_int32_t fileID, + u_int32_t startBlock, Boolean * recordDeleted) { OSErr err; - UInt32 numberExtentsReleased; + u_int32_t numberExtentsReleased; Boolean releasedLastExtent; - UInt32 hint; + u_int32_t hint; HFSPlusExtentKey key; HFSPlusExtentRecord extents; int lockflags; @@ -667,12 +690,12 @@ static OSErr TruncateExtents( static OSErr DeallocateFork( ExtendedVCB *vcb, HFSCatalogNodeID fileID, - UInt8 forkType, + u_int8_t forkType, HFSPlusExtentRecord catalogExtents, Boolean * recordDeleted) /* true if a record was deleted */ { OSErr err; - UInt32 numReleasedAllocationBlocks; + u_int32_t numReleasedAllocationBlocks; Boolean releasedLastExtent; // Release the catalog extents @@ -690,7 +713,6 @@ static OSErr DeallocateFork( // Function: Flushes the extent file for a specified volume //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -__private_extern__ OSErr FlushExtentFile( ExtendedVCB *vcb ) { FCB * fcb; @@ -718,6 +740,7 @@ OSErr FlushExtentFile( ExtendedVCB *vcb ) } +#if CONFIG_HFS_STD //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ // Routine: CompareExtentKeys // @@ -726,15 +749,15 @@ OSErr FlushExtentFile( ExtendedVCB *vcb ) //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ __private_extern__ -SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey ) +int32_t CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey ) { - SInt32 result; // ± 1 + int32_t result; // ± 1 #if DEBUG_BUILD if (searchKey->keyLength != kHFSExtentKeyMaximumLength) - DebugStr("\pHFS: search Key is wrong length"); + DebugStr("HFS: search Key is wrong length"); if (trialKey->keyLength != kHFSExtentKeyMaximumLength) - DebugStr("\pHFS: trial Key is wrong length"); + DebugStr("HFS: trial Key is wrong length"); #endif result = -1; // assume searchKey < trialKey @@ -779,7 +802,7 @@ SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *tri return( result ); } - +#endif //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ @@ -790,15 +813,15 @@ SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *tri //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ __private_extern__ -SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey ) +int32_t CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey ) { - SInt32 result; // ± 1 + int32_t result; // ± 1 #if DEBUG_BUILD if (searchKey->keyLength != kHFSPlusExtentKeyMaximumLength) - DebugStr("\pHFS: search Key is wrong length"); + DebugStr("HFS: search Key is wrong length"); if (trialKey->keyLength != kHFSPlusExtentKeyMaximumLength) - DebugStr("\pHFS: trial Key is wrong length"); + DebugStr("HFS: trial Key is wrong length"); #endif result = -1; // assume searchKey < trialKey @@ -844,26 +867,88 @@ SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusEx 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, vfs_context_kernel()) == 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. * */ -__private_extern__ int -AddFileExtent(ExtendedVCB *vcb, FCB *fcb, UInt32 startBlock, UInt32 blockCount) +AddFileExtent(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockCount) { HFSPlusExtentKey foundKey; HFSPlusExtentRecord foundData; - UInt32 foundIndex; - UInt32 hint; - UInt32 nextBlock; - SInt64 peof; + u_int32_t foundIndex; + u_int32_t hint; + u_int32_t nextBlock; + int64_t peof; int i; int error; - peof = (SInt64)(fcb->ff_blocks + blockCount) * (SInt64)vcb->blockSize; + 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) @@ -896,15 +981,22 @@ AddFileExtent(ExtendedVCB *vcb, FCB *fcb, UInt32 startBlock, UInt32 blockCount) foundIndex = 0; error = CreateExtentRecord(vcb, &foundKey, foundData, &hint); - if (error == fxOvFlErr) + 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, &foundKey, foundData, hint); + error = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint); + if (error == 0) { + pin_blocks_if_needed(vcb, fcb, startBlock, blockCount); + } } (void) FlushExtentFile(vcb); @@ -920,38 +1012,41 @@ AddFileExtent(ExtendedVCB *vcb, FCB *fcb, UInt32 startBlock, UInt32 blockCount) // //_________________________________________________________________________________ -__private_extern__ OSErr ExtendFileC ( ExtendedVCB *vcb, // volume that file resides on FCB *fcb, // FCB of file to truncate - SInt64 bytesToAdd, // number of bytes to allocate - UInt32 blockHint, // desired starting allocation block - UInt32 flags, // EFContig and/or EFAll - SInt64 *actualBytesAdded) // number of bytes actually allocated + 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; - UInt32 volumeBlockSize; - SInt64 blocksToAdd; - SInt64 bytesThisExtent; + u_int32_t volumeBlockSize; + int64_t blocksToAdd; + int64_t bytesThisExtent; HFSPlusExtentKey foundKey; HFSPlusExtentRecord foundData; - UInt32 foundIndex; - UInt32 hint; - UInt32 nextBlock; - UInt32 startBlock; + 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; - UInt32 actualStartBlock; - UInt32 actualNumBlocks; - UInt32 numExtentsPerRecord; - SInt64 maximumBytes; - SInt64 peof; - UInt32 prevblocks; - - + 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; @@ -959,43 +1054,50 @@ OSErr ExtendFileC ( forceContig = ((flags & kEFContigMask) != 0); prevblocks = fcb->ff_blocks; - if (vcb->vcbSigWord == kHFSPlusSigWord) + if (vcb->vcbSigWord != kHFSSigWord) { numExtentsPerRecord = kHFSPlusExtentDensity; - else + } +#if CONFIG_HFS_STD + else { + /* HFS Standard */ numExtentsPerRecord = kHFSExtentDensity; - // - // Make sure the request and new PEOF are less than 2GB if HFS. - // - if (vcb->vcbSigWord == kHFSSigWord) { + /* Make sure the request and new PEOF are less than 2GB if HFS std*/ if (bytesToAdd >= kTwoGigabytes) - goto Overflow; - if ((((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) - goto Overflow; + 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 = (SInt64)((SInt64)blocksToAdd * (SInt64)volumeBlockSize); + bytesToAdd = (int64_t)((int64_t)blocksToAdd * (int64_t)volumeBlockSize); /* * For deferred allocations just reserve the blocks. */ if ((flags & kEFDeferMask) && (vcb->vcbSigWord == kHFSPlusSigWord) - && (bytesToAdd < (SInt64)HFS_MAX_DEFERED_ALLOC) + && (bytesToAdd < (int64_t)HFS_MAX_DEFERED_ALLOC) && (blocksToAdd < hfs_freeblks(VCBTOHFS(vcb), 1))) { - HFS_MOUNT_LOCK(vcb, TRUE); + hfs_lock_mount (hfsmp); vcb->loanedBlocks += blocksToAdd; - HFS_MOUNT_UNLOCK(vcb, TRUE); + hfs_unlock_mount(hfsmp); fcb->ff_unallocblocks += blocksToAdd; FTOC(fcb)->c_blocks += blocksToAdd; fcb->ff_blocks += blocksToAdd; - FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE; + /* + * 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); } @@ -1007,14 +1109,14 @@ OSErr ExtendFileC ( loanedBlocks = fcb->ff_unallocblocks; blocksToAdd += loanedBlocks; - bytesToAdd = (SInt64)blocksToAdd * (SInt64)volumeBlockSize; + bytesToAdd = (int64_t)blocksToAdd * (int64_t)volumeBlockSize; FTOC(fcb)->c_blocks -= loanedBlocks; fcb->ff_blocks -= loanedBlocks; fcb->ff_unallocblocks = 0; - HFS_MOUNT_LOCK(vcb, TRUE); + hfs_lock_mount(hfsmp); vcb->loanedBlocks -= loanedBlocks; - HFS_MOUNT_UNLOCK(vcb, TRUE); + hfs_unlock_mount(hfsmp); } // @@ -1023,26 +1125,28 @@ OSErr ExtendFileC ( // rounded up to a multiple of the clump size. // if ((vcb->vcbClpSiz > (int32_t)volumeBlockSize) - && (bytesToAdd < (SInt64)HFS_MAX_DEFERED_ALLOC) + && (bytesToAdd < (int64_t)HFS_MAX_DEFERED_ALLOC) && (flags & kEFNoClumpMask) == 0) { - maximumBytes = (SInt64)howmany(bytesToAdd, vcb->vcbClpSiz); + 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? - ((((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) ) { + ((((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) ) { if (allOrNothing) // Yes, must they have it all? - goto Overflow; // Yes, can't have it + 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 @@ -1057,13 +1161,13 @@ OSErr ExtendFileC ( // // See if there are already enough blocks allocated to the file. // - peof = ((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd; // potential new PEOF + 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 | C_FORCEUPDATE; + FTOC(fcb)->c_flag |= C_MODIFIED; goto Exit; } if (err != fxRangeErr) // Any real error? @@ -1072,8 +1176,8 @@ OSErr ExtendFileC ( // // Adjust the PEOF to the end of the last extent. // - peof = (SInt64)((SInt64)nextBlock * (SInt64)volumeBlockSize); // currently allocated PEOF - bytesThisExtent = (SInt64)(nextBlock - fcb->ff_blocks) * (SInt64)volumeBlockSize; + 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); @@ -1088,50 +1192,111 @@ OSErr ExtendFileC ( // 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; - wantContig = true; + 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; - vcb->vcbFreeExtCnt = 0; /* For now, force rebuild of free extent list */ do { if (blockHint != 0) startBlock = blockHint; else startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount; - /* Force reserve checking if requested. */ - if (flags & kEFReserveMask) { - SInt64 availbytes; - - actualNumBlocks = 0; - actualStartBlock = 0; + actualNumBlocks = 0; + actualStartBlock = 0; - availbytes = (SInt64)hfs_freeblks(VCBTOHFS(vcb), 1) * - (SInt64)volumeBlockSize; - if (availbytes <= 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 { - if (wantContig && (availbytes < bytesToAdd)) - err = dskFulErr; - else { - err = BlockAllocate( + } + 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), - wantContig, - useMetaZone, + ba_flags, &actualStartBlock, &actualNumBlocks); - } } - } else { - err = BlockAllocate(vcb, startBlock, howmany(bytesToAdd, volumeBlockSize), - howmany(maximumBytes, volumeBlockSize), wantContig, useMetaZone, - &actualStartBlock, &actualNumBlocks); } if (err == dskFulErr) { - if (forceContig) - break; // AllocContig failed because not enough contiguous space + 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; @@ -1140,29 +1305,32 @@ OSErr ExtendFileC ( } if (actualNumBlocks != 0) err = noErr; + if (useMetaZone == 0) { /* Couldn't get anything so dip into metadat zone */ err = noErr; useMetaZone = 1; continue; } - } - if (err == noErr) { - if (actualNumBlocks != 0) { - // this catalog entry *must* get forced to disk when - // hfs_update() is called - FTOC(fcb)->c_flag |= C_FORCEUPDATE; + + /* 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, &foundKey, foundData, hint); + err = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint); if (err != noErr) break; } else { - UInt16 i; + 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? @@ -1170,7 +1338,7 @@ OSErr ExtendFileC ( if (foundIndex == numExtentsPerRecord) { // This record is full. Need to create a new one. if (FTOC(fcb)->c_fileid == kHFSExtentsFileID) { - (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks); + (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks, 0); err = dskFulErr; // Oops. Can't extend extents file past first record. break; } @@ -1201,7 +1369,7 @@ OSErr ExtendFileC ( // 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); + (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks, 0); err = dskFulErr; } if (err != noErr) break; @@ -1212,16 +1380,16 @@ OSErr ExtendFileC ( // Add a new extent into this record and update. foundData[foundIndex].startBlock = actualStartBlock; foundData[foundIndex].blockCount = actualNumBlocks; - err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint); + 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 = (SInt64)((SInt64)actualNumBlocks * (SInt64)volumeBlockSize); + bytesThisExtent = (int64_t)((int64_t)actualNumBlocks * (int64_t)volumeBlockSize); if (bytesThisExtent > bytesToAdd) { bytesToAdd = 0; } @@ -1231,7 +1399,7 @@ OSErr ExtendFileC ( } fcb->ff_blocks += (bytesThisExtent / volumeBlockSize); FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize); - FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE; + 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. @@ -1249,26 +1417,33 @@ Exit: /* Keep the roving allocator out of the metadata zone. */ if (vcb->nextAllocation >= VCBTOHFS(vcb)->hfs_metazone_start && vcb->nextAllocation <= VCBTOHFS(vcb)->hfs_metazone_end) { - HFS_MOUNT_LOCK(vcb, TRUE); - vcb->nextAllocation = VCBTOHFS(vcb)->hfs_metazone_end + 1; - vcb->vcbFlags |= 0xFF00; - HFS_MOUNT_UNLOCK(vcb, TRUE); + 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 = (SInt64)(fcb->ff_blocks - prevblocks) * (SInt64)volumeBlockSize; + *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; -Overflow: +#if CONFIG_HFS_STD +HFS_Std_Overflow: err = fileBoundsErr; goto ErrorExit; +#endif } @@ -1284,43 +1459,50 @@ Overflow: // //_________________________________________________________________________________ -__private_extern__ OSErr TruncateFileC ( ExtendedVCB *vcb, // volume that file resides on FCB *fcb, // FCB of file to truncate - SInt64 peof, // new physical size for file + 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; - UInt32 nextBlock; // next file allocation block to consider - UInt32 startBlock; // Physical (volume) allocation block number of start of a range - UInt32 physNumBlocks; // Number of allocation blocks in file (according to PEOF) - UInt32 numBlocks; + 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 - UInt32 hint; // BTree hint corresponding to key + u_int32_t hint; // BTree hint corresponding to key HFSPlusExtentRecord extentRecord; - UInt32 extentIndex; - UInt32 extentNextBlock; - UInt32 numExtentsPerRecord; - SInt64 temp64; - UInt8 forkType; + 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) + if (vcb->vcbSigWord == kHFSPlusSigWord) { numExtentsPerRecord = kHFSPlusExtentDensity; - else + } + else { numExtentsPerRecord = kHFSExtentDensity; - - if (FORK_IS_RSRC(fcb)) + } + + if (rsrc) { forkType = kResourceForkType; - else + } + else { forkType = kDataForkType; - + } + temp64 = fcb->ff_blocks; - physNumBlocks = (UInt32)temp64; + physNumBlocks = (u_int32_t)temp64; // // Round newPEOF up to a multiple of the allocation block size. If new size is @@ -1328,14 +1510,17 @@ OSErr TruncateFileC ( // shouldn't that be an error?). // nextBlock = howmany(peof, vcb->blockSize); // number of allocation blocks to remain in file - peof = (SInt64)((SInt64)nextBlock * (SInt64)vcb->blockSize); // number of bytes in those blocks + 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_BUILD - DebugStr("\pHFS: Trying to truncate a file to 2GB or more"); + DebugStr("HFS: Trying to truncate a file to 2GB or more"); #endif err = fileBoundsErr; goto ErrorExit; } +#endif // // Update FCB's length @@ -1344,13 +1529,21 @@ OSErr TruncateFileC ( * XXX Any errors could cause ff_blocks and c_blocks to get out of sync... */ numBlocks = peof / vcb->blockSize; - FTOC(fcb)->c_blocks -= (fcb->ff_blocks - numBlocks); + 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 - FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE; - + 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). @@ -1359,7 +1552,7 @@ OSErr TruncateFileC ( int i; // Deallocate all the extents for this fork - err = DeallocateFork(vcb, FTOC(fcb)->c_fileid, forkType, fcb->fcbExtents, &recordDeleted); + 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) @@ -1393,7 +1586,7 @@ OSErr TruncateFileC ( // 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); + err = BlockDeallocate(vcb, startBlock, numBlocks, 0); if (err != noErr) goto ErrorExit; // Adjust length of this extent extentRecord[extentIndex].blockCount -= numBlocks; @@ -1417,7 +1610,7 @@ OSErr TruncateFileC ( while (extentIndex < numExtentsPerRecord && extentRecord[extentIndex].blockCount != 0) { numBlocks = extentRecord[extentIndex].blockCount; // Deallocate this extent - err = BlockDeallocate(vcb, extentRecord[extentIndex].startBlock, numBlocks); + err = BlockDeallocate(vcb, extentRecord[extentIndex].startBlock, numBlocks, 0); if (err != noErr) goto ErrorExit; // Update next file allocation block number nextBlock += numBlocks; @@ -1435,7 +1628,7 @@ OSErr TruncateFileC ( // record (in the FCB, or extents file). // if (extentChanged) { - err = UpdateExtentRecord(vcb, fcb, &key, extentRecord, hint); + err = UpdateExtentRecord(vcb, fcb, deleted, &key, extentRecord, hint); if (err != noErr) goto ErrorExit; } @@ -1445,7 +1638,7 @@ OSErr TruncateFileC ( // blocks. // if (nextBlock < physNumBlocks) - err = TruncateExtents(vcb, forkType, FTOC(fcb)->c_fileid, nextBlock, &recordDeleted); + err = TruncateExtents(vcb, forkType, fileid, nextBlock, &recordDeleted); Done: ErrorExit: @@ -1460,19 +1653,18 @@ ErrorExit: * HFS Plus only * */ -__private_extern__ OSErr HeadTruncateFile ( ExtendedVCB *vcb, FCB *fcb, - UInt32 headblks) + u_int32_t headblks) { HFSPlusExtentRecord extents; HFSPlusExtentRecord tailExtents; HFSCatalogNodeID fileID; - UInt8 forkType; - UInt32 blkcnt; - UInt32 startblk; - UInt32 blksfreed; + u_int8_t forkType; + u_int32_t blkcnt; + u_int32_t startblk; + u_int32_t blksfreed; int i, j; int error = 0; int lockflags; @@ -1497,7 +1689,7 @@ OSErr HeadTruncateFile ( break; /* end of extents */ if (blksfreed < headblks) { - error = BlockDeallocate(vcb, fcb->fcbExtents[i].startBlock, blkcnt); + 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 @@ -1508,8 +1700,8 @@ OSErr HeadTruncateFile ( goto ErrorExit; /* uh oh */ else { error = 0; - printf("HeadTruncateFile: problems deallocating %s (%d)\n", - FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error); + printf("hfs: HeadTruncateFile: problems deallocating %s (%d)\n", + FTOC(fcb)->c_desc.cd_nameptr ? (const char *)FTOC(fcb)->c_desc.cd_nameptr : "", error); } } @@ -1533,7 +1725,7 @@ OSErr HeadTruncateFile ( * Process overflow extents */ for (;;) { - UInt32 extblks; + u_int32_t extblks; error = FindExtentRecord(vcb, forkType, fileID, startblk, false, NULL, extents, NULL); if (error) { @@ -1543,8 +1735,8 @@ OSErr HeadTruncateFile ( * a known state. */ if (error != btNotFound) - printf("HeadTruncateFile: problems finding extents %s (%d)\n", - FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error); + 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; } @@ -1555,10 +1747,10 @@ OSErr HeadTruncateFile ( break; /* end of extents */ if (blksfreed < headblks) { - error = BlockDeallocate(vcb, extents[i].startBlock, blkcnt); + error = BlockDeallocate(vcb, extents[i].startBlock, blkcnt, 0); if (error) { - printf("HeadTruncateFile: problems deallocating %s (%d)\n", - FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", 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; @@ -1572,8 +1764,8 @@ OSErr HeadTruncateFile ( error = DeleteExtentRecord(vcb, forkType, fileID, startblk); if (error) { - printf("HeadTruncateFile: problems deallocating %s (%d)\n", - FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error); + 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; } @@ -1588,10 +1780,10 @@ CopyExtents: if (blksfreed) { bcopy(tailExtents, fcb->fcbExtents, sizeof(tailExtents)); blkcnt = fcb->ff_blocks - headblks; - FTOC(fcb)->c_blocks -= blkcnt; + FTOC(fcb)->c_blocks -= headblks; fcb->ff_blocks = blkcnt; - FTOC(fcb)->c_flag |= C_FORCEUPDATE; + FTOC(fcb)->c_flag |= C_MODIFIED; FTOC(fcb)->c_touch_chgtime = TRUE; (void) FlushExtentFile(vcb); @@ -1627,27 +1819,28 @@ ErrorExit: static OSErr SearchExtentRecord( ExtendedVCB *vcb, - UInt32 searchFABN, + u_int32_t searchFABN, const HFSPlusExtentRecord extentData, - UInt32 extentDataStartFABN, - UInt32 *foundExtentIndex, - UInt32 *endingFABNPlusOne, + u_int32_t extentDataStartFABN, + u_int32_t *foundExtentIndex, + u_int32_t *endingFABNPlusOne, Boolean *noMoreExtents) { OSErr err = noErr; - UInt32 extentIndex; - UInt32 numberOfExtents; - UInt32 numAllocationBlocks; + 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; - if (vcb->vcbSigWord == kHFSPlusSigWord) + /* Override numberOfExtents for HFS+/HFSX */ + if (vcb->vcbSigWord != kHFSSigWord) { numberOfExtents = kHFSPlusExtentDensity; - else - numberOfExtents = kHFSExtentDensity; + } for( extentIndex = 0; extentIndex < numberOfExtents; ++extentIndex ) { @@ -1726,24 +1919,24 @@ static OSErr SearchExtentRecord( // (other) (some other internal I/O error) //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -static OSErr SearchExtentFile( +OSErr SearchExtentFile( ExtendedVCB *vcb, const FCB *fcb, - SInt64 filePosition, + int64_t filePosition, HFSPlusExtentKey *foundExtentKey, HFSPlusExtentRecord foundExtentData, - UInt32 *foundExtentIndex, - UInt32 *extentBTreeHint, - UInt32 *endingFABNPlusOne ) + u_int32_t *foundExtentIndex, + u_int32_t *extentBTreeHint, + u_int32_t *endingFABNPlusOne ) { OSErr err; - UInt32 filePositionBlock; - SInt64 temp64; + u_int32_t filePositionBlock; + int64_t temp64; Boolean noMoreExtents; int lockflags; - temp64 = filePosition / (SInt64)vcb->blockSize; - filePositionBlock = (UInt32)temp64; + temp64 = filePosition / (int64_t)vcb->blockSize; + filePositionBlock = (u_int32_t)temp64; bcopy ( fcb->fcbExtents, foundExtentData, sizeof(HFSPlusExtentRecord)); @@ -1819,6 +2012,7 @@ Exit: // // 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. @@ -1829,23 +2023,23 @@ Exit: // (other) = error from BTree //============================================================================ -static OSErr UpdateExtentRecord ( - ExtendedVCB *vcb, - FCB *fcb, - const HFSPlusExtentKey *extentFileKey, - const HFSPlusExtentRecord extentData, - UInt32 extentBTreeHint) +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)); - FTOC(fcb)->c_flag |= C_MODIFIED; + if (!deleted) { + FTOC(fcb)->c_flag |= C_MODIFIED; + } } else { - BTreeIterator * btIterator; + struct BTreeIterator *btIterator = NULL; FSBufferDescriptor btRecord; - UInt16 btRecordSize; + u_int16_t btRecordSize; FCB * btFCB; int lockflags; @@ -1853,8 +2047,11 @@ static OSErr UpdateExtentRecord ( // Need to find and change a record in Extents BTree // btFCB = GetFileControlBlock(vcb->extentsRefNum); - - MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK); + + MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK); + if (btIterator == NULL) { + return memFullErr; // translates to ENOMEM + } bzero(btIterator, sizeof(*btIterator)); /* @@ -1866,7 +2063,30 @@ static OSErr UpdateExtentRecord ( */ lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK); - if (vcb->vcbSigWord == kHFSSigWord) { + /* 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 @@ -1884,36 +2104,20 @@ static OSErr UpdateExtentRecord ( 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); - } - else { // 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); } +#endif + hfs_systemfile_unlock(vcb, lockflags); - FREE(btIterator, M_TEMP); + + FREE(btIterator, M_TEMP); } return err; @@ -1921,7 +2125,7 @@ static OSErr UpdateExtentRecord ( - +#if CONFIG_HFS_STD static OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents) @@ -1940,14 +2144,14 @@ static OSErr HFSPlusToHFSExtents( #if DEBUG_BUILD if (oldExtents[3].startBlock || oldExtents[3].blockCount) { - DebugStr("\pExtentRecord with > 3 extents is invalid for HFS"); + DebugStr("ExtentRecord with > 3 extents is invalid for HFS"); err = fsDSIntErr; } #endif return err; } - +#endif @@ -1972,12 +2176,12 @@ static OSErr GetFCBExtentRecord( static Boolean ExtentsAreIntegral( const HFSPlusExtentRecord extentRecord, - UInt32 mask, - UInt32 *blocksChecked, + u_int32_t mask, + u_int32_t *blocksChecked, Boolean *checkedLastExtent) { - UInt32 blocks; - UInt32 extentIndex; + u_int32_t blocks; + u_int32_t extentIndex; *blocksChecked = 0; *checkedLastExtent = false; @@ -2010,16 +2214,15 @@ static Boolean ExtentsAreIntegral( // Called by BTOpenPath during volume mount //_________________________________________________________________________________ -__private_extern__ Boolean NodesAreContiguous( ExtendedVCB *vcb, FCB *fcb, - UInt32 nodeSize) + u_int32_t nodeSize) { - UInt32 mask; - UInt32 startBlock; - UInt32 blocksChecked; - UInt32 hint; + u_int32_t mask; + u_int32_t startBlock; + u_int32_t blocksChecked; + u_int32_t hint; HFSPlusExtentKey key; HFSPlusExtentRecord extents; OSErr result; @@ -2038,7 +2241,7 @@ Boolean NodesAreContiguous( return FALSE; if ( lastExtentReached || - (SInt64)((SInt64)blocksChecked * (SInt64)vcb->blockSize) >= (SInt64)fcb->ff_size) + (int64_t)((int64_t)blocksChecked * (int64_t)vcb->blockSize) >= (int64_t)fcb->ff_size) return TRUE; startBlock = blocksChecked;