X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/0b4e3aa066abc0728aacb4bbeb86f53f9737156e..13f56ec4e58bf8687e2a68032c093c0213dd519b:/bsd/hfs/hfscommon/Misc/FileExtentMapping.c?ds=sidebyside diff --git a/bsd/hfs/hfscommon/Misc/FileExtentMapping.c b/bsd/hfs/hfscommon/Misc/FileExtentMapping.c index 3f17d760e..998f97fa9 100644 --- a/bsd/hfs/hfscommon/Misc/FileExtentMapping.c +++ b/bsd/hfs/hfscommon/Misc/FileExtentMapping.c @@ -1,154 +1,30 @@ /* - * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2008 Apple Inc. All rights reserved. * - * @APPLE_LICENSE_HEADER_START@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * - * The contents of this file constitute Original Code as defined in and - * are subject to the Apple Public Source License Version 1.1 (the - * "License"). You may not use this file except in compliance with the - * License. Please obtain a copy of the License at - * http://www.apple.com/publicsource and read it before using this file. + * 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. * - * This Original Code and all software distributed under the License are - * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * 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 OR NON-INFRINGEMENT. Please see the - * License for the specific language governing rights and limitations - * under the License. + * 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_HEADER_END@ + * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ -/* - File: FileExtentMapping.c - - Contains: xxx put contents here xxx - - Version: HFS Plus 1.0 - - Written by: Dave Heller, Mark Day - - Copyright: © 1996-1999 by Apple Computer, Inc., all rights reserved. - - File Ownership: - - DRI: Mark Day - - Other Contact: xxx put other contact here xxx - - Technology: xxx put technology here xxx - - Writers: - - (DSH) Deric Horn - (msd) Mark Day - (djb) Don Brady - - Change History (most recent first): - 9/9/99 djb Fix fcbModifiedMask flag testing logic. - 8/25/98 djb Flush extents b-tree header if dirty (2371088). - 6/30/98 djb Add functions NodesAreContiguous and ExtentsAreIntegral (for radar #2249539). - 6/23/98 djb Changed DeallocFile to DeleteFile which now deletes the catalog record. - Fixed UpdateExtentRecord to pass correct fcb to Btree routines. Fixed - hfs+ bug in CreateExtentRecord (double dereference). - 5/20/98 djb In ExtendFileC don't lie about the peof! (radar #2230094). - 4/17/98 djb Add VCB locking. - 4/2/98 djb Switch over to real BTree interface (no more BTreeWrapper.c). - 3/31/98 djb Sync up with final HFSVolumes.h header file. - - 1/23/98 msd Bug 2208024: AllocContig is actually allocating one extent even - though there is not enough contiguous space. - 12/2/97 DSH GetFCBExtentRecord no longer static so DFA can use it. - 10/20/97 msd When allocating more space for a file, do the clump size - calculations in ExtendFileC, not BlockAllocate. Undo change from - . - 10/17/97 msd Conditionalize DebugStrs. - 10/16/97 msd Simplify the code path for MapFileBlockC (logical to physical - block mapping) in the typical case where the file isn't - fragmented so badly that it has extents in the extents B-tree. - Simplified some of the calculations for all cases. - 10/13/97 DSH FindExtentRecord & DeleteExtentRecord are also being used by DFA - no longer static. - 10/6/97 msd When extending a file, set the physical EOF to include any extra - space allocated due to a file's clump size. - 9/19/97 msd Remove the MapLogicalToPhysical SPI. It was never used and is - not being tested anyway. - 9/5/97 msd In CompareExtentKeys and CompareExtentKeysPlus, use the symbolic - constants for key length. Don't DebugStr unless DEBUG_BUILD is - set. - 7/24/97 djb Add instrumentation to MapFileBlockC - 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name - collision - 7/15/97 DSH AdjEOF() mark the FCB as modified. (1664389) - 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line - 7/3/97 msd Bug #1663518. Remove DebugStr when setting the FCB extent record - for a volume control file. - 6/27/97 msd Moved enum kFirstFileRefnum to FilesInternal. - 6/24/97 djb Include "CatalogPrivate.h" - 6/16/97 msd Finish implementation of CreateLargeFile SPI. - 6/12/97 msd Add stub for CreateLargeFile SPI. - 6/5/97 msd Add MapLogicalToPhysical. - 6/2/97 msd In TruncateFileC, don't update the extent record unless it was - actually changed (prevents extra updates when truncating to the - end of the extent, and it is the last extent of the file.) Added - an AdjustEOF routine called by the assembly AdjEOF routine. It - copies the EOF, physical length, and extent information from one - FCB to all other FCBs for that fork. - 5/20/97 DSH Removed const declaration in MapFileBlocC, const is benign when - passing by value, and SC requires it to match prototype. - 5/15/97 msd Change enum kResourceForkType from -1 to 0xFF since it is now - unsigned. Change all forkType parameters to UInt8. - 5/7/97 msd When checking for an unused extent descriptor, check the length, - not the starting block. - 4/24/97 djb first checked in - 4/11/97 DSH use extended VCB fields catalogRefNum, and extentsRefNum. - 4/4/97 djb Get in sync with volume format changes. - 3/17/97 DSH Casting to compile with SC. - 2/26/97 msd Add instrumentation in ExtendFileC and TruncateFileC. In - CompareExtentKeys and CompareExtentKeysPlus, make sure the key - lengths are correct. - 2/5/97 msd The comparison with fsBTStartOfIterationErr didn't work because - the enum is an unsigned long; it is now casted to an OSErr - before comparing. - 1/31/97 msd In FindExtentRecord, turn an fsBTStartOfIterationErr error into - btNotFound. - 1/28/97 msd Fixed bug in MapFileBlockC where it returned the wrong number of - bytes available at the given block number. This could - potentially cause programs to read or write over other files. - 1/16/97 djb Extent key compare procs now return SInt32. Fixed - UpdateExtentRecord - it was passing a pointer to an ExtentKey - pointer. - 1/10/97 msd Change TruncateFileC to call DellocateFork when the new PEOF is - 0. Fixes a fxRangeErr returned when no extents existed. - 1/6/97 msd Previous change prevents extent records from being removed if - the files new PEOF is in the local (FCB/catalog) extents. - 1/3/97 djb Temp fix in TruncateFileC to prevent unwanted calls to - TruncateExtents. - 12/23/96 msd Previous change to SearchExtentFile didn't set up the outputs - for hint and key when the FCB extent record wasn't full. - 12/20/96 msd In SearchExtentFile, don't bother searching the extents file if - the FCB's extent record wasn't full, or if the FCB was for the - extents file itself. Modified SearchExtentRecord to return a - Boolean to indicate that the record was not full. - 12/19/96 DSH Changed refs from VCB to ExtendedVCB - 12/19/96 djb Updated for new B-tree Manager interface. - 12/12/96 djb Really use new SPI for GetCatalogNode. - 12/12/96 djb Use new Catalog SPI for GetCatalogNode. Added Mark's changes to - MapFileBlockC. - 12/11/96 msd TruncateFileC must always release extents, even if PEOF hasn't - changed (since allocation may have been rounded up due to clump - size). - 12/10/96 msd Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers. - 12/4/96 DSH Precompiled headers - 11/26/96 msd Add an exported routine to grow the parallel FCB table to - accomodate the HFS+ ExtentRecord. - 11/26/96 msd Convert internal routines to use ExtentKey and ExtentRecord - (instead of the raw HFS structures). - 11/21/96 msd Added CompareExtentKeysPlus(). - 11/20/96 msd Finish porting FXM to C. - 11/6/96 DKH first checked in - -*/ #include "../../hfs.h" @@ -157,7 +33,6 @@ #include "../headers/FileMgrInternal.h" #include "../headers/BTreesInternal.h" -#include "../headers/CatalogPrivate.h" // calling a private catalog routine (LocateCatalogNode) #include @@ -165,8 +40,6 @@ ============================================================ Public (Exported) Routines: ============================================================ - DeAllocFile Deallocate all disk space allocated to a specified file. - Both forks are deallocated. ExtendFileC Allocate more space to a given file. @@ -193,21 +66,8 @@ Public (Exported) Routines: FlushExtentFile Flush the extents file for a given volume. - GrowParallelFCBs - Make sure the parallel FCB entries are big enough to support - the HFS+ ExtentRecord. If not, the array is grown and the - pre-existing data copied over. - AdjustEOF - Copy EOF, physical length, and extent records from one FCB - to all other FCBs for that fork. This is used when a file is - grown or shrunk as the result of a Write, SetEOF, or Allocate. - MapLogicalToPhysical - Map some position in a file to a volume block number. Also - returns the number of contiguous bytes that are mapped there. - This is a queued HFSDispatch call that does the equivalent of - MapFileBlockC, using a parameter block. ============================================================ Internal Routines: @@ -237,103 +97,99 @@ Internal Routines: and was in the extents file, then delete the record instead. */ +static const int64_t kTwoGigabytes = 0x80000000LL; + enum { - kTwoGigabytes = (UInt32) 0x80000000, - kDataForkType = 0, kResourceForkType = 0xFF, - kPreviousRecord = -1, - - kSectorSize = 512 // Size of a physical sector + kPreviousRecord = -1 }; -void HFSToHFSPlusExtents( - const HFSExtentRecord oldExtents, - HFSPlusExtentRecord newExtents); -OSErr HFSPlusToHFSExtents( +static OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents); -OSErr FindExtentRecord( +static OSErr FindExtentRecord( const ExtendedVCB *vcb, - UInt8 forkType, - UInt32 fileID, - 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); -OSErr DeleteExtentRecord( +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( - const ExtendedVCB *vcb, + ExtendedVCB *vcb, HFSPlusExtentKey *key, HFSPlusExtentRecord extents, - UInt32 *hint); + u_int32_t *hint); -OSErr GetFCBExtentRecord( +static OSErr GetFCBExtentRecord( const FCB *fcb, HFSPlusExtentRecord extents); static OSErr SearchExtentFile( - const ExtendedVCB *vcb, + ExtendedVCB *vcb, const FCB *fcb, - SInt64 filePosition, + int64_t filePosition, HFSPlusExtentKey *foundExtentKey, HFSPlusExtentRecord foundExtentData, - UInt32 *foundExtentDataIndex, - UInt32 *extentBTreeHint, - UInt32 *endingFABNPlusOne ); + u_int32_t *foundExtentDataIndex, + u_int32_t *extentBTreeHint, + u_int32_t *endingFABNPlusOne ); static OSErr SearchExtentRecord( - const ExtendedVCB *vcb, - UInt32 searchFABN, + ExtendedVCB *vcb, + 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 ( - const ExtendedVCB *vcb, - FCB *fcb, + ExtendedVCB *vcb, + 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); //_________________________________________________________________________________ @@ -358,27 +214,28 @@ static Boolean ExtentsAreIntegral( // fourth entry will be zeroes. // foundHint The BTree hint to find the node again //_________________________________________________________________________________ -OSErr FindExtentRecord( +static OSErr FindExtentRecord( const ExtendedVCB *vcb, - UInt8 forkType, - UInt32 fileID, - 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; FSBufferDescriptor btRecord; OSErr err; - UInt16 btRecordSize; + u_int16_t btRecordSize; err = noErr; - *foundHint = 0; + if (foundHint) + *foundHint = 0; fcb = GetFileControlBlock(vcb->extentsRefNum); - (void) BTInvalidateHint(&btIterator); + bzero(&btIterator, sizeof(btIterator)); if (vcb->vcbSigWord == kHFSSigWord) { HFSExtentKey * extentKeyPtr; @@ -394,7 +251,7 @@ OSErr FindExtentRecord( btRecord.itemSize = sizeof(HFSExtentRecord); btRecord.itemCount = 1; - err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); + err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator); if (err == btNotFound && allowPrevious) { err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize); @@ -412,16 +269,17 @@ OSErr FindExtentRecord( } if (err == noErr) { - UInt16 i; - - // Copy the found key back for the caller - foundKey->keyLength = kHFSPlusExtentKeyMaximumLength; - foundKey->forkType = extentKeyPtr->forkType; - foundKey->pad = 0; - foundKey->fileID = extentKeyPtr->fileID; - foundKey->startBlock = extentKeyPtr->startBlock; + u_int16_t i; - // Copy the found data back for the caller + // Copy the found key back for the caller + if (foundKey) { + foundKey->keyLength = kHFSPlusExtentKeyMaximumLength; + foundKey->forkType = extentKeyPtr->forkType; + foundKey->pad = 0; + foundKey->fileID = extentKeyPtr->fileID; + foundKey->startBlock = extentKeyPtr->startBlock; + } + // Copy the found data back for the caller foundData[0].startBlock = extentData[0].startBlock; foundData[0].blockCount = extentData[0].blockCount; foundData[1].startBlock = extentData[1].startBlock; @@ -451,7 +309,7 @@ OSErr FindExtentRecord( btRecord.itemSize = sizeof(HFSPlusExtentRecord); btRecord.itemCount = 1; - err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator); + err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator); if (err == btNotFound && allowPrevious) { err = BTIterateRecord(fcb, kBTreePrevRecord, &btIterator, &btRecord, &btRecordSize); @@ -469,34 +327,47 @@ OSErr FindExtentRecord( } if (err == noErr) { - // Copy the found key back for the caller - BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey)); - // Copy the found data back for the caller + // Copy the found key back for the caller + if (foundKey) + BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey)); + // Copy the found data back for the caller BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord)); } } - - *foundHint = btIterator.hint.nodeNum; + + if (foundHint) + *foundHint = btIterator.hint.nodeNum; return err; } static OSErr CreateExtentRecord( - const ExtendedVCB *vcb, + ExtendedVCB *vcb, HFSPlusExtentKey *key, HFSPlusExtentRecord extents, - UInt32 *hint) + u_int32_t *hint) { - BTreeIterator btIterator; + BTreeIterator btIterator; FSBufferDescriptor btRecord; - UInt16 btRecordSize; - OSErr err; + u_int16_t btRecordSize; + int lockflags; + OSErr err; err = noErr; *hint = 0; - (void) BTInvalidateHint(&btIterator); - + + bzero(&btIterator, sizeof(btIterator)); + + /* + * The lock taken by callers of ExtendFileC is speculative and + * only occurs when the file already has overflow extents. So + * We need to make sure we have the lock here. The extents + * btree lock can be nested (its recursive) so we always take + * it here. + */ + lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK); + if (vcb->vcbSigWord == kHFSSigWord) { HFSExtentKey * keyPtr; HFSExtentRecord data; @@ -529,21 +400,26 @@ static OSErr CreateExtentRecord( if (err == noErr) *hint = btIterator.hint.nodeNum; + (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum)); + + hfs_systemfile_unlock(vcb, lockflags); + return err; } -OSErr DeleteExtentRecord( +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; + BTreeIterator btIterator; OSErr err; err = noErr; - (void) BTInvalidateHint(&btIterator); + + bzero(&btIterator, sizeof(btIterator)); if (vcb->vcbSigWord == kHFSSigWord) { HFSExtentKey * keyPtr; @@ -566,6 +442,7 @@ OSErr DeleteExtentRecord( } err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator); + (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum)); return err; } @@ -578,20 +455,6 @@ OSErr DeleteExtentRecord( // // Function: Maps a file position into a physical disk address. // -// Input: A2.L - VCB pointer -// (A1,D1.W) - FCB pointer -// D4.L - number of bytes desired -// D5.L - file position (byte address) -// -// Output: D3.L - physical start block -// D6.L - number of contiguous bytes available (up to D4 bytes) -// D0.L - result code <01Oct85> -// 0 = ok -// FXRangeErr = file position beyond mapped range <17Oct85> -// FXOvFlErr = extents file overflow <17Oct85> -// other = error <17Oct85> -// -// Called By: Log2Phys (read/write in place), Cache (map a file block). //_________________________________________________________________________________ OSErr MapFileBlockC ( @@ -599,25 +462,27 @@ OSErr MapFileBlockC ( FCB *fcb, // FCB of file size_t numberOfBytes, // number of contiguous bytes desired off_t offset, // starting offset within file (in bytes) - daddr_t *startSector, // first 512-byte sector (NOT an allocation block) + daddr64_t *startSector, // first sector (NOT an allocation block) size_t *availableBytes) // number of contiguous bytes (up to numberOfBytes) { OSErr err; - UInt32 allocBlockSize; // Size of the volume's allocation block + 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 - daddr_t temp; + 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_logical_block_size; + err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN); if (err == noErr) { startBlock = foundData[foundIndex].startBlock; @@ -632,23 +497,28 @@ OSErr MapFileBlockC ( // // Determine the end of the available space. It will either be the end of the extent, // or the file's PEOF, whichever is smaller. + // - dataEnd = (off_t)((off_t)(nextFABN) * (off_t)(allocBlockSize)); // Assume valid data through end of this extent - if (fcb->fcbPLen < dataEnd) // Is PEOF shorter? - dataEnd = fcb->fcbPLen; // Yes, so only map up to PEOF + dataEnd = (off_t)((off_t)(nextFABN) * (off_t)(allocBlockSize)); // Assume valid data through end of this extent + if (((off_t)fcb->ff_blocks * (off_t)allocBlockSize) < dataEnd) // Is PEOF shorter? + dataEnd = (off_t)fcb->ff_blocks * (off_t)allocBlockSize; // Yes, so only map up to PEOF // Compute the number of sectors in an allocation block - sectorsPerBlock = allocBlockSize / kSectorSize; // sectors per allocation block + sectorsPerBlock = allocBlockSize / sectorSize; // sectors per allocation block // // Compute the absolute sector number that contains the offset of the given file + // offset in sectors from start of the extent + + // offset in sectors from start of allocation block space // - temp = (daddr_t)((offset - (off_t)((off_t)(firstFABN) * (off_t)(allocBlockSize)))/kSectorSize); // offset in sectors from start of the extent - temp += startBlock * sectorsPerBlock; // offset in sectors from start of allocation block space - if (vcb->vcbSigWord == kHFSPlusSigWord) - temp += vcb->hfsPlusIOPosOffset/512; /* offset inside wrapper */ - else - temp += vcb->vcbAlBlSt; /* offset in sectors from start of volume */ + temp = (daddr64_t)((offset - (off_t)((off_t)(firstFABN) * (off_t)(allocBlockSize)))/sectorSize); + temp += (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; @@ -657,11 +527,20 @@ OSErr MapFileBlockC ( // Determine the number of contiguous bytes until the end of the extent // (or the amount they asked for, whichever comes first). // - tmpOff = dataEnd - offset; - if (tmpOff > (off_t)(numberOfBytes)) - *availableBytes = numberOfBytes; // more there than they asked for, so pin the output - else - *availableBytes = tmpOff; + if (availableBytes) + { + tmpOff = dataEnd - offset; + /* + * 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 + *availableBytes = tmpOff; + } return noErr; } @@ -676,11 +555,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; @@ -693,7 +572,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. @@ -704,7 +583,7 @@ static OSErr ReleaseExtents( break; } - err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks ); + err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks , 0); if ( err != noErr ) break; @@ -732,17 +611,27 @@ 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; + + /* + * 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); @@ -761,6 +650,7 @@ static OSErr TruncateExtents( *recordDeleted = true; startBlock += numberExtentsReleased; } + hfs_systemfile_unlock(vcb, lockflags); return err; } @@ -776,12 +666,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 @@ -803,88 +693,28 @@ OSErr FlushExtentFile( ExtendedVCB *vcb ) { FCB * fcb; OSErr err; + int lockflags; fcb = GetFileControlBlock(vcb->extentsRefNum); + + lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK); err = BTFlushPath(fcb); + hfs_systemfile_unlock(vcb, lockflags); + if ( err == noErr ) { // If the FCB for the extent "file" is dirty, mark the VCB as dirty. - if ((fcb->fcbFlags & fcbModifiedMask) != 0) + if (FTOC(fcb)->c_flag & C_MODIFIED) { MarkVCBDirty( vcb ); - err = FlushVolumeControlBlock( vcb ); + // err = FlushVolumeControlBlock( vcb ); } } return( err ); } -//------------------------------------------------------------------------------- -// Routine: DeleteFile -// -// Function: De-allocates all disk space allocated to a specified file -// including the space used by the catalog (ie the catalog record). -// The space occupied by both forks is also deallocated. -// -//------------------------------------------------------------------------------- - -OSErr DeleteFile( ExtendedVCB *vcb, HFSCatalogNodeID parDirID, ConstUTF8Param catalogName, UInt32 catalogHint ) -{ - OSErr err; - OSErr errDF, errRF; - CatalogNodeData catalogData; - Boolean recordDeleted; - - recordDeleted = false; - - INIT_CATALOGDATA(&catalogData, kCatNameNoCopyName); - - // Find catalog data in catalog - err = GetCatalogNode( vcb, parDirID, catalogName, kUndefinedStrLen, catalogHint, &catalogData, &catalogHint); - if( err != noErr ) - goto Exit; - - - // Check to make sure record is for a file - if ( catalogData.cnd_type != kCatalogFileNode ) - { - err = notAFileErr; - goto Exit; - } - - // - // Always delete the Catalog record first (to minimize disk corruption) - // - err = DeleteCatalogNode(vcb, parDirID, catalogName, catalogHint); - if( err != noErr ) - goto Exit; - - // - // Note: we don't report errors from DeallocateFork since the - // file no longer exists (since DeleteCatalogNode succeeded). - // Any errors mean that there are possibly some orphaned disk - // blocks but from the clients perspective the file was deleted. - // - - // Deallocate data fork extents - errDF = DeallocateFork( vcb, catalogData.cnd_nodeID, kDataForkType, - catalogData.cnd_datafork.extents, &recordDeleted ); - - // Deallocate resource fork extents - errRF = DeallocateFork( vcb, catalogData.cnd_nodeID, kResourceForkType, - catalogData.cnd_rsrcfork.extents, &recordDeleted ); - - if (recordDeleted) - err = FlushExtentFile( vcb ); - - CLEAN_CATALOGDATA(&catalogData); - return (errDF ? errDF : (errRF ? errRF : err)); -Exit: - - CLEAN_CATALOGDATA(&catalogData); - return( err ); -} //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ // Routine: CompareExtentKeys @@ -893,15 +723,16 @@ Exit: // an HFS volume. //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey ) +__private_extern__ +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 @@ -956,15 +787,16 @@ SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *tri // an HFS volume. //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ -SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey ) +__private_extern__ +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 @@ -1010,6 +842,71 @@ SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusEx return( result ); } +/* + * Add a file extent to a file. + * + * Used by hfs_extendfs to extend the volume allocation bitmap file. + * + */ +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 { + /* + * Add a new extent into existing record. + */ + foundData[foundIndex].startBlock = startBlock; + foundData[foundIndex].blockCount = blockCount; + error = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint); + } + (void) FlushExtentFile(vcb); + + return (error); +} //_________________________________________________________________________________ @@ -1018,53 +915,38 @@ SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusEx // // Function: Extends the disk space allocated to a file. // -// Input: A2.L - VCB pointer -// A1.L - pointer to FCB array -// D1.W - file refnum -// D3.B - option flags -// kEFContigMask - force contiguous allocation -// kEFAllMask - allocate all requested bytes or none -// NOTE: You may not set both options. -// D4.L - number of additional bytes to allocate -// -// Output: D0.W - result code -// 0 = ok -// -n = IO error -// D6.L - number of bytes allocated -// -// Called by: FileAloc,FileWrite,SetEof -// -// Note: ExtendFile updates the PEOF in the FCB. //_________________________________________________________________________________ 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; - SInt64 previousPEOF; + 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; needsFlush = false; @@ -1072,7 +954,7 @@ OSErr ExtendFileC ( volumeBlockSize = vcb->blockSize; allOrNothing = ((flags & kEFAllMask) != 0); forceContig = ((flags & kEFContigMask) != 0); - previousPEOF = fcb->fcbPLen; + prevblocks = fcb->ff_blocks; if (vcb->vcbSigWord == kHFSPlusSigWord) numExtentsPerRecord = kHFSPlusExtentDensity; @@ -1085,45 +967,86 @@ OSErr ExtendFileC ( if (vcb->vcbSigWord == kHFSSigWord) { if (bytesToAdd >= kTwoGigabytes) goto Overflow; - if ((fcb->fcbPLen + bytesToAdd) >= kTwoGigabytes) + if ((((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) goto Overflow; - } + } // // Determine how many blocks need to be allocated. // Round up the number of desired bytes to add. // - blocksToAdd = FileBytesToBlocks(bytesToAdd, volumeBlockSize); - bytesToAdd = (SInt64)((SInt64)blocksToAdd * (SInt64)volumeBlockSize); - + 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_MOUNT_LOCK(vcb, TRUE); + vcb->loanedBlocks += blocksToAdd; + HFS_MOUNT_UNLOCK(vcb, TRUE); + + fcb->ff_unallocblocks += blocksToAdd; + FTOC(fcb)->c_blocks += blocksToAdd; + fcb->ff_blocks += blocksToAdd; + + FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE; + *actualBytesAdded = bytesToAdd; + return (0); + } + /* + * Give back any unallocated blocks before doing real allocations. + */ + if (fcb->ff_unallocblocks > 0) { + u_int32_t loanedBlocks; + + loanedBlocks = fcb->ff_unallocblocks; + blocksToAdd += loanedBlocks; + bytesToAdd = (int64_t)blocksToAdd * (int64_t)volumeBlockSize; + FTOC(fcb)->c_blocks -= loanedBlocks; + fcb->ff_blocks -= loanedBlocks; + fcb->ff_unallocblocks = 0; + + HFS_MOUNT_LOCK(vcb, TRUE); + vcb->loanedBlocks -= loanedBlocks; + HFS_MOUNT_UNLOCK(vcb, TRUE); + } + // // If the file's clump size is larger than the allocation block size, // then set the maximum number of bytes to the requested number of bytes // rounded up to a multiple of the clump size. // - if (fcb->fcbClmpSize > volumeBlockSize) { - maximumBytes = (SInt64)FileBytesToBlocks(bytesToAdd, fcb->fcbClmpSize); - maximumBytes *= fcb->fcbClmpSize; - } - else { + if ((vcb->vcbClpSiz > (int32_t)volumeBlockSize) + && (bytesToAdd < (int64_t)HFS_MAX_DEFERED_ALLOC) + && (flags & kEFNoClumpMask) == 0) { + maximumBytes = (int64_t)howmany(bytesToAdd, vcb->vcbClpSiz); + maximumBytes *= vcb->vcbClpSiz; + } else { maximumBytes = bytesToAdd; } // // Compute new physical EOF, rounded up to a multiple of a block. // - if ((vcb->vcbSigWord == kHFSSigWord) && ((fcb->fcbPLen + bytesToAdd) >= (SInt64) kTwoGigabytes)) // Too big? + if ( (vcb->vcbSigWord == kHFSSigWord) && // Too big? + ((((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 else { --blocksToAdd; // No, give give 'em one block less bytesToAdd -= volumeBlockSize; } + } // // If allocation is all-or-nothing, make sure there are // enough free blocks on the volume (quick test). // - if (allOrNothing && (blocksToAdd > (SInt64)vcb->freeBlocks)) { + if (allOrNothing && + (blocksToAdd > hfs_freeblks(VCBTOHFS(vcb), flags & kEFReserveMask))) { err = dskFulErr; goto ErrorExit; } @@ -1131,13 +1054,13 @@ OSErr ExtendFileC ( // // See if there are already enough blocks allocated to the file. // - peof = fcb->fcbPLen + 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->fcbPLen = peof; - H_EXTENDSIZE(fcb, bytesToAdd); - fcb->fcbFlags |= fcbModifiedMask; + fcb->ff_blocks = peof / volumeBlockSize; + FTOC(fcb)->c_blocks += (bytesToAdd / volumeBlockSize); + FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE; goto Exit; } if (err != fxRangeErr) // Any real error? @@ -1146,12 +1069,12 @@ OSErr ExtendFileC ( // // Adjust the PEOF to the end of the last extent. // - peof = (SInt64)((SInt64)nextBlock * (SInt64)volumeBlockSize); // currently allocated PEOF - bytesThisExtent = peof - fcb->fcbPLen; + 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->fcbPLen = peof; - H_EXTENDSIZE(fcb, bytesThisExtent); - fcb->fcbFlags |= fcbModifiedMask; + fcb->ff_blocks = nextBlock; + FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize); + FTOC(fcb)->c_flag |= C_MODIFIED; bytesToAdd -= bytesThisExtent; } @@ -1162,15 +1085,82 @@ 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; - vcb->vcbFreeExtCnt = 0; /* For now, force rebuild of free extent list */ + 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; + } + useMetaZone = flags & kEFMetadataMask; do { if (blockHint != 0) startBlock = blockHint; else startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount; - err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, wantContig, &actualStartBlock, &actualNumBlocks); + + 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 { + err = BlockAllocate( + vcb, + startBlock, + howmany(MIN(bytesToAdd, availbytes), volumeBlockSize), + howmany(MIN(maximumBytes, availbytes), volumeBlockSize), + (wantContig ? HFS_ALLOC_FORCECONTIG : 0) | + (useMetaZone ? HFS_ALLOC_METAZONE : 0), + &actualStartBlock, + &actualNumBlocks); + } + } if (err == dskFulErr) { if (forceContig) break; // AllocContig failed because not enough contiguous space @@ -1182,36 +1172,48 @@ 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; + } + // 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? ++foundIndex; // No, so use the next one. if (foundIndex == numExtentsPerRecord) { // This record is full. Need to create a new one. - if (H_FILEID(fcb) == kHFSExtentsFileID) { - (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks); + 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 (fcb->fcbFlags & fcbResourceMask) + if (FORK_IS_RSRC(fcb)) foundKey.forkType = kResourceForkType; else foundKey.forkType = kDataForkType; foundKey.pad = 0; - foundKey.fileID = H_FILEID(fcb); + foundKey.fileID = FTOC(fcb)->c_fileid; foundKey.startBlock = nextBlock; foundData[0].startBlock = actualStartBlock; @@ -1231,7 +1233,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; @@ -1242,7 +1244,7 @@ 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; } } @@ -1251,7 +1253,7 @@ OSErr ExtendFileC ( // 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; } @@ -1259,9 +1261,9 @@ OSErr ExtendFileC ( bytesToAdd -= bytesThisExtent; maximumBytes -= bytesThisExtent; } - fcb->fcbPLen += bytesThisExtent; - H_EXTENDSIZE(fcb, bytesThisExtent); - fcb->fcbFlags |= fcbModifiedMask; + fcb->ff_blocks += (bytesThisExtent / volumeBlockSize); + FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize); + FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE; // If contiguous allocation was requested, then we've already got one contiguous // chunk. If we didn't get all we wanted, then adjust the error to disk full. @@ -1275,7 +1277,21 @@ OSErr ExtendFileC ( ErrorExit: Exit: - *actualBytesAdded = fcb->fcbPLen - previousPEOF; + if (VCBTOHFS(vcb)->hfs_flags & HFS_METADATA_ZONE) { + /* Keep the roving allocator out of the metadata zone. */ + if (vcb->nextAllocation >= VCBTOHFS(vcb)->hfs_metazone_start && + vcb->nextAllocation <= VCBTOHFS(vcb)->hfs_metazone_end) { + HFS_MOUNT_LOCK(vcb, TRUE); + HFS_UPDATE_NEXT_ALLOCATION(vcb, VCBTOHFS(vcb)->hfs_metazone_end + 1); + MarkVCBDirty(vcb); + HFS_MOUNT_UNLOCK(vcb, TRUE); + } + } + if (prevblocks < fcb->ff_blocks) { + *actualBytesAdded = (int64_t)(fcb->ff_blocks - prevblocks) * (int64_t)volumeBlockSize; + } else { + *actualBytesAdded = 0; + } if (needsFlush) (void) FlushExtentFile(vcb); @@ -1298,68 +1314,63 @@ Overflow: // block boundry. If the 'TFTrunExt' option is specified, the file is // truncated to the end of the extent containing the new PEOF. // -// Input: A2.L - VCB pointer -// A1.L - pointer to FCB array -// D1.W - file refnum -// D2.B - option flags -// TFTrunExt - truncate to the extent containing new PEOF -// D3.L - new PEOF -// -// Output: D0.W - result code -// 0 = ok -// -n = IO error -// -// Note: TruncateFile updates the PEOF in the FCB. //_________________________________________________________________________________ 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 (fcb->fcbFlags & fcbResourceMask) + } + + if (rsrc) { forkType = kResourceForkType; - else + } + else { forkType = kDataForkType; - - temp64 = fcb->fcbPLen / (SInt64)vcb->blockSize; // number of allocation blocks currently in file - physNumBlocks = (UInt32)temp64; + } + + 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 = FileBytesToBlocks(peof, vcb->blockSize); // number of allocation blocks to remain in file - peof = (SInt64)((SInt64)nextBlock * (SInt64)vcb->blockSize); // number of bytes in those blocks - if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= (UInt32) kTwoGigabytes)) { + 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 ((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; @@ -1368,10 +1379,25 @@ OSErr TruncateFileC ( // // Update FCB's length // - H_TRUNCSIZE(fcb, fcb->fcbPLen - peof); - fcb->fcbPLen = peof; - fcb->fcbFlags |= fcbModifiedMask; - + /* + * XXX Any errors could cause ff_blocks and c_blocks to get out of sync... + */ + numBlocks = peof / vcb->blockSize; + 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 | C_FORCEUPDATE); + } // // If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate // all storage). @@ -1380,7 +1406,7 @@ OSErr TruncateFileC ( int i; // Deallocate all the extents for this fork - err = DeallocateFork(vcb, H_FILEID(fcb), forkType, fcb->fcbExtents, &recordDeleted); + err = DeallocateFork(vcb, 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) @@ -1414,7 +1440,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; @@ -1438,7 +1464,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; @@ -1456,7 +1482,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; } @@ -1466,11 +1492,10 @@ OSErr TruncateFileC ( // blocks. // if (nextBlock < physNumBlocks) - err = TruncateExtents(vcb, forkType, H_FILEID(fcb), nextBlock, &recordDeleted); + err = TruncateExtents(vcb, forkType, fileid, nextBlock, &recordDeleted); Done: ErrorExit: - if (recordDeleted) (void) FlushExtentFile(vcb); @@ -1478,6 +1503,151 @@ ErrorExit: } +/* + * 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; + 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_FORCEUPDATE; + FTOC(fcb)->c_touch_chgtime = TRUE; + + (void) FlushExtentFile(vcb); + } + +ErrorExit: + return MacToVFSError(error); +} + + //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ // Routine: SearchExtentRecord (was XRSearch) @@ -1502,18 +1672,18 @@ ErrorExit: //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ static OSErr SearchExtentRecord( - const ExtendedVCB *vcb, - UInt32 searchFABN, + ExtendedVCB *vcb, + 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; + u_int32_t numberOfExtents; + u_int32_t numAllocationBlocks; Boolean foundExtent; *endingFABNPlusOne = extentDataStartFABN; @@ -1603,22 +1773,23 @@ static OSErr SearchExtentRecord( //‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ static OSErr SearchExtentFile( - const ExtendedVCB *vcb, + 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)); @@ -1648,8 +1819,11 @@ static OSErr SearchExtentFile( // // Find the desired record, or the previous record if it is the same fork // - err = FindExtentRecord(vcb, (fcb->fcbFlags & fcbResourceMask) ? kResourceForkType : kDataForkType, - H_FILEID(fcb), filePositionBlock, true, foundExtentKey, foundExtentData, extentBTreeHint); + lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK); + + err = FindExtentRecord(vcb, FORK_IS_RSRC(fcb) ? kResourceForkType : kDataForkType, + FTOC(fcb)->c_fileid, filePositionBlock, true, foundExtentKey, foundExtentData, extentBTreeHint); + hfs_systemfile_unlock(vcb, lockflags); if (err == btNotFound) { // @@ -1682,7 +1856,7 @@ Exit: -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ +//============================================================================ // Routine: UpdateExtentRecord // // Function: Write new extent data to an existing extent record with a given key. @@ -1691,6 +1865,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. @@ -1699,31 +1874,44 @@ Exit: // // Result: noErr = ok // (other) = error from BTree -//‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹‹ +//============================================================================ -static OSErr UpdateExtentRecord ( - const 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) { - BTreeIterator btIterator; - FSBufferDescriptor btRecord; - UInt16 btRecordSize; - FCB * btFCB; - OSErr err = noErr; + OSErr err = noErr; if (extentFileKey->keyLength == 0) { // keyLength == 0 means the FCB's extent record BlockMoveData(extentData, fcb->fcbExtents, sizeof(HFSPlusExtentRecord)); - fcb->fcbFlags |= fcbModifiedMask; + if (!deleted) { + FTOC(fcb)->c_flag |= C_MODIFIED; + } } else { + BTreeIterator btIterator; + FSBufferDescriptor btRecord; + u_int16_t btRecordSize; + FCB * btFCB; + int lockflags; + // // Need to find and change a record in Extents BTree // btFCB = GetFileControlBlock(vcb->extentsRefNum); + bzero(&btIterator, sizeof(btIterator)); + + /* + * The lock taken by callers of ExtendFileC/TruncateFileC is + * speculative and only occurs when the file already has + * overflow extents. So we need to make sure we have the lock + * here. The extents btree lock can be nested (its recursive) + * so we always take it here. + */ + lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK); + if (vcb->vcbSigWord == kHFSSigWord) { HFSExtentKey * key; // Actual extent key used on disk in HFS HFSExtentRecord foundData; // The extent data actually found @@ -1741,14 +1929,14 @@ static OSErr UpdateExtentRecord ( btRecord.itemSize = sizeof(HFSExtentRecord); btRecord.itemCount = 1; - err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord, - &btRecordSize, &btIterator); + err = BTSearchRecord(btFCB, &btIterator, &btRecord, &btRecordSize, &btIterator); if (err == noErr) err = HFSPlusToHFSExtents(extentData, (HFSExtentDescriptor *)&foundData); if (err == noErr) err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize); + (void) BTFlushPath(btFCB); } else { // HFS Plus volume HFSPlusExtentRecord foundData; // The extent data actually found @@ -1762,14 +1950,15 @@ static OSErr UpdateExtentRecord ( btRecord.itemSize = sizeof(HFSPlusExtentRecord); btRecord.itemCount = 1; - err = BTSearchRecord(btFCB, &btIterator, kInvalidMRUCacheKey, &btRecord, - &btRecordSize, &btIterator); + err = BTSearchRecord(btFCB, &btIterator, &btRecord, &btRecordSize, &btIterator); if (err == noErr) { BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord)); err = BTReplaceRecord(btFCB, &btIterator, &btRecord, btRecordSize); } + (void) BTFlushPath(btFCB); } + hfs_systemfile_unlock(vcb, lockflags); } return err; @@ -1777,31 +1966,8 @@ static OSErr UpdateExtentRecord ( -void HFSToHFSPlusExtents( - const HFSExtentRecord oldExtents, - HFSPlusExtentRecord newExtents) -{ - UInt32 i; - - // copy the first 3 extents - newExtents[0].startBlock = oldExtents[0].startBlock; - newExtents[0].blockCount = oldExtents[0].blockCount; - newExtents[1].startBlock = oldExtents[1].startBlock; - newExtents[1].blockCount = oldExtents[1].blockCount; - newExtents[2].startBlock = oldExtents[2].startBlock; - newExtents[2].blockCount = oldExtents[2].blockCount; - - // zero out the remaining ones - for (i = 3; i < kHFSPlusExtentDensity; ++i) - { - newExtents[i].startBlock = 0; - newExtents[i].blockCount = 0; - } -} - - -OSErr HFSPlusToHFSExtents( +static OSErr HFSPlusToHFSExtents( const HFSPlusExtentRecord oldExtents, HFSExtentRecord newExtents) { @@ -1819,7 +1985,7 @@ 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 @@ -1830,7 +1996,7 @@ OSErr HFSPlusToHFSExtents( -OSErr GetFCBExtentRecord( +static OSErr GetFCBExtentRecord( const FCB *fcb, HFSPlusExtentRecord extents) { @@ -1851,12 +2017,12 @@ 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; @@ -1892,16 +2058,17 @@ static Boolean ExtentsAreIntegral( 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; Boolean lastExtentReached; + int lockflags; if (vcb->blockSize >= nodeSize) @@ -1914,23 +2081,27 @@ Boolean NodesAreContiguous( if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) ) return FALSE; - if (lastExtentReached || (SInt64)((SInt64)blocksChecked * (SInt64)vcb->blockSize) >= fcb->fcbPLen) + 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, H_FILEID(fcb), startBlock, FALSE, &key, extents, &hint); + result = FindExtentRecord(vcb, kDataForkType, fcb->ff_cp->c_fileid, startBlock, FALSE, &key, extents, &hint); if (result) break; - if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) ) + if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) ) { + hfs_systemfile_unlock(vcb, lockflags); return FALSE; - + } startBlock += blocksChecked; } - + hfs_systemfile_unlock(vcb, lockflags); return TRUE; }