/*
- * 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):
- <MacOSX> 9/9/99 djb Fix fcbModifiedMask flag testing logic.
- <MacOSX> 8/25/98 djb Flush extents b-tree header if dirty (2371088).
- <MacOSX> 6/30/98 djb Add functions NodesAreContiguous and ExtentsAreIntegral (for radar #2249539).
- <MacOSX> 6/23/98 djb Changed DeallocFile to DeleteFile which now deletes the catalog record.
- Fixed UpdateExtentRecord to pass correct fcb to Btree routines. Fixed
- hfs+ bug in CreateExtentRecord (double dereference).
- <MacOSX> 5/20/98 djb In ExtendFileC don't lie about the peof! (radar #2230094).
- <MacOSX> 4/17/98 djb Add VCB locking.
- <MacOSX> 4/2/98 djb Switch over to real BTree interface (no more BTreeWrapper.c).
- <MacOSX> 3/31/98 djb Sync up with final HFSVolumes.h header file.
-
- <CS24> 1/23/98 msd Bug 2208024: AllocContig is actually allocating one extent even
- though there is not enough contiguous space.
- <CS23> 12/2/97 DSH GetFCBExtentRecord no longer static so DFA can use it.
- <CS22> 10/20/97 msd When allocating more space for a file, do the clump size
- calculations in ExtendFileC, not BlockAllocate. Undo change from
- <CS18>.
- <CS21> 10/17/97 msd Conditionalize DebugStrs.
- <CS20> 10/16/97 msd Simplify the code path for MapFileBlockC (logical to physical
- block mapping) in the typical case where the file isn't
- fragmented so badly that it has extents in the extents B-tree.
- Simplified some of the calculations for all cases.
- <CS19> 10/13/97 DSH FindExtentRecord & DeleteExtentRecord are also being used by DFA
- no longer static.
- <CS18> 10/6/97 msd When extending a file, set the physical EOF to include any extra
- space allocated due to a file's clump size.
- <CS17> 9/19/97 msd Remove the MapLogicalToPhysical SPI. It was never used and is
- not being tested anyway.
- <CS16> 9/5/97 msd In CompareExtentKeys and CompareExtentKeysPlus, use the symbolic
- constants for key length. Don't DebugStr unless DEBUG_BUILD is
- set.
- <CS15> 7/24/97 djb Add instrumentation to MapFileBlockC
- <CS14> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name
- collision
- <CS13> 7/15/97 DSH AdjEOF() mark the FCB as modified. (1664389)
- <CS12> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line
- <CS11> 7/3/97 msd Bug #1663518. Remove DebugStr when setting the FCB extent record
- for a volume control file.
- <CS10> 6/27/97 msd Moved enum kFirstFileRefnum to FilesInternal.
- <CS9> 6/24/97 djb Include "CatalogPrivate.h"
- <CS8> 6/16/97 msd Finish implementation of CreateLargeFile SPI.
- <CS7> 6/12/97 msd Add stub for CreateLargeFile SPI.
- <CS6> 6/5/97 msd Add MapLogicalToPhysical.
- <CS5> 6/2/97 msd In TruncateFileC, don't update the extent record unless it was
- actually changed (prevents extra updates when truncating to the
- end of the extent, and it is the last extent of the file.) Added
- an AdjustEOF routine called by the assembly AdjEOF routine. It
- copies the EOF, physical length, and extent information from one
- FCB to all other FCBs for that fork.
- <CS4> 5/20/97 DSH Removed const declaration in MapFileBlocC, const is benign when
- passing by value, and SC requires it to match prototype.
- <CS3> 5/15/97 msd Change enum kResourceForkType from -1 to 0xFF since it is now
- unsigned. Change all forkType parameters to UInt8.
- <CS2> 5/7/97 msd When checking for an unused extent descriptor, check the length,
- not the starting block.
- <CS1> 4/24/97 djb first checked in
- <HFS25> 4/11/97 DSH use extended VCB fields catalogRefNum, and extentsRefNum.
- <HFS24> 4/4/97 djb Get in sync with volume format changes.
- <HFS23> 3/17/97 DSH Casting to compile with SC.
- <HFS22> 2/26/97 msd Add instrumentation in ExtendFileC and TruncateFileC. In
- CompareExtentKeys and CompareExtentKeysPlus, make sure the key
- lengths are correct.
- <HFS21> 2/5/97 msd The comparison with fsBTStartOfIterationErr didn't work because
- the enum is an unsigned long; it is now casted to an OSErr
- before comparing.
- <HFS20> 1/31/97 msd In FindExtentRecord, turn an fsBTStartOfIterationErr error into
- btNotFound.
- <HFS19> 1/28/97 msd Fixed bug in MapFileBlockC where it returned the wrong number of
- bytes available at the given block number. This could
- potentially cause programs to read or write over other files.
- <HFS18> 1/16/97 djb Extent key compare procs now return SInt32. Fixed
- UpdateExtentRecord - it was passing a pointer to an ExtentKey
- pointer.
- <HFS17> 1/10/97 msd Change TruncateFileC to call DellocateFork when the new PEOF is
- 0. Fixes a fxRangeErr returned when no extents existed.
- <HFS16> 1/6/97 msd Previous change prevents extent records from being removed if
- the files new PEOF is in the local (FCB/catalog) extents.
- <HFS15> 1/3/97 djb Temp fix in TruncateFileC to prevent unwanted calls to
- TruncateExtents.
- <HFS14> 12/23/96 msd Previous change to SearchExtentFile didn't set up the outputs
- for hint and key when the FCB extent record wasn't full.
- <HFS13> 12/20/96 msd In SearchExtentFile, don't bother searching the extents file if
- the FCB's extent record wasn't full, or if the FCB was for the
- extents file itself. Modified SearchExtentRecord to return a
- Boolean to indicate that the record was not full.
- <HFS12> 12/19/96 DSH Changed refs from VCB to ExtendedVCB
- <HFS11> 12/19/96 djb Updated for new B-tree Manager interface.
- <HFS10> 12/12/96 djb Really use new SPI for GetCatalogNode.
- <HFS9> 12/12/96 djb Use new Catalog SPI for GetCatalogNode. Added Mark's changes to
- MapFileBlockC.
- <HFS8> 12/11/96 msd TruncateFileC must always release extents, even if PEOF hasn't
- changed (since allocation may have been rounded up due to clump
- size).
- <HFS7> 12/10/96 msd Check PRAGMA_LOAD_SUPPORTED before loading precompiled headers.
- <HFS6> 12/4/96 DSH Precompiled headers
- <HFS5> 11/26/96 msd Add an exported routine to grow the parallel FCB table to
- accomodate the HFS+ ExtentRecord.
- <HFS4> 11/26/96 msd Convert internal routines to use ExtentKey and ExtentRecord
- (instead of the raw HFS structures).
- <HFS3> 11/21/96 msd Added CompareExtentKeysPlus().
- <HFS2> 11/20/96 msd Finish porting FXM to C.
- <HFS1> 11/6/96 DKH first checked in
-
-*/
#include "../../hfs.h"
#include "../headers/FileMgrInternal.h"
#include "../headers/BTreesInternal.h"
-#include "../headers/CatalogPrivate.h" // calling a private catalog routine (LocateCatalogNode)
-
-#include "../headers/HFSInstrumentation.h"
#include <sys/malloc.h>
============================================================
Public (Exported) Routines:
============================================================
- DeAllocFile Deallocate all disk space allocated to a specified file.
- Both forks are deallocated.
ExtendFileC Allocate more space to a given file.
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:
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);
-
-static OSErr MapFileBlockFromFCB(
- const ExtendedVCB *vcb,
- const FCB *fcb,
- SInt64 offset, // Desired offset in bytes from start of file
- UInt32 *firstFABN, // FABN of first block of found extent
- UInt32 *firstBlock, // Corresponding allocation block number
- UInt32 *nextFABN); // FABN of block after end of extent
+ u_int32_t extentBTreeHint);
static Boolean ExtentsAreIntegral(
const HFSPlusExtentRecord extentRecord,
- UInt32 mask,
- UInt32 *blocksChecked,
+ u_int32_t mask,
+ u_int32_t *blocksChecked,
Boolean *checkedLastExtent);
//_________________________________________________________________________________
// 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;
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);
}
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;
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);
}
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;
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;
}
err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator);
+ (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
return err;
}
//
// 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 (
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;
-
-
- LogStartTime(kTraceMapFileBlock);
allocBlockSize = vcb->blockSize;
-
- err = MapFileBlockFromFCB(vcb, fcb, offset, &firstFABN, &startBlock, &nextFABN);
- if (err != noErr) {
- err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN);
- if (err == noErr) {
- startBlock = foundData[foundIndex].startBlock;
- firstFABN = nextFABN - foundData[foundIndex].blockCount;
- }
+ sectorSize = VCBTOHFS(vcb)->hfs_logical_block_size;
+
+ err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN);
+ if (err == noErr) {
+ startBlock = foundData[foundIndex].startBlock;
+ firstFABN = nextFABN - foundData[foundIndex].blockCount;
}
if (err != noErr)
{
- LogEndTime(kTraceMapFileBlock, err);
-
return err;
}
//
// Determine the end of the available space. It will either be the end of the extent,
// or the file's PEOF, whichever is smaller.
+
//
- dataEnd = (off_t)((off_t)(nextFABN) * (off_t)(allocBlockSize)); // Assume valid data through end of this extent
- if (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;
// Determine the number of contiguous bytes until the end of the extent
// (or the amount they asked for, whichever comes first).
//
- tmpOff = dataEnd - offset;
- if (tmpOff > (off_t)(numberOfBytes))
- *availableBytes = numberOfBytes; // more there than they asked for, so pin the output
- else
- *availableBytes = tmpOff;
- LogEndTime(kTraceMapFileBlock, noErr);
+ if (availableBytes)
+ {
+ tmpOff = dataEnd - offset;
+ /*
+ * 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;
}
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;
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.
break;
}
- err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks );
+ err = BlockDeallocate( vcb, extentRecord[extentIndex].startBlock, numAllocationBlocks , 0);
if ( err != noErr )
break;
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);
*recordDeleted = true;
startBlock += numberExtentsReleased;
}
+ hfs_systemfile_unlock(vcb, lockflags);
return err;
}
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
{
FCB * fcb;
OSErr err;
+ int lockflags;
fcb = GetFileControlBlock(vcb->extentsRefNum);
+
+ lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
err = BTFlushPath(fcb);
+ hfs_systemfile_unlock(vcb, lockflags);
+
if ( err == noErr )
{
// If the FCB for the extent "file" is dirty, mark the VCB as dirty.
- if ((fcb->fcbFlags & fcbModifiedMask) != 0)
+ if (FTOC(fcb)->c_flag & C_MODIFIED)
{
MarkVCBDirty( vcb );
- err = FlushVolumeControlBlock( vcb );
+ // err = FlushVolumeControlBlock( vcb );
}
}
return( err );
}
-//-------------------------------------------------------------------------------
-// Routine: DeleteFile
-//
-// Function: De-allocates all disk space allocated to a specified file
-// including the space used by the catalog (ie the catalog record).
-// The space occupied by both forks is also deallocated.
-//
-//-------------------------------------------------------------------------------
-
-OSErr DeleteFile( ExtendedVCB *vcb, HFSCatalogNodeID parDirID, ConstUTF8Param catalogName, UInt32 catalogHint )
-{
- OSErr err;
- OSErr errDF, errRF;
- CatalogNodeData catalogData;
- Boolean recordDeleted;
-
- recordDeleted = false;
-
- INIT_CATALOGDATA(&catalogData, kCatNameNoCopyName);
-
- // Find catalog data in catalog
- err = GetCatalogNode( vcb, parDirID, catalogName, kUndefinedStrLen, catalogHint, &catalogData, &catalogHint);
- if( err != noErr )
- goto Exit;
-
-
- // Check to make sure record is for a file
- if ( catalogData.cnd_type != kCatalogFileNode )
- {
- err = notAFileErr;
- goto Exit;
- }
-
- //
- // Always delete the Catalog record first (to minimize disk corruption)
- //
- err = DeleteCatalogNode(vcb, parDirID, catalogName, catalogHint);
- if( err != noErr )
- goto Exit;
-
- //
- // Note: we don't report errors from DeallocateFork since the
- // file no longer exists (since DeleteCatalogNode succeeded).
- // Any errors mean that there are possibly some orphaned disk
- // blocks but from the clients perspective the file was deleted.
- //
-
- // Deallocate data fork extents
- errDF = DeallocateFork( vcb, catalogData.cnd_nodeID, kDataForkType,
- catalogData.cnd_datafork.extents, &recordDeleted );
-
- // Deallocate resource fork extents
- errRF = DeallocateFork( vcb, catalogData.cnd_nodeID, kResourceForkType,
- catalogData.cnd_rsrcfork.extents, &recordDeleted );
-
- if (recordDeleted)
- err = FlushExtentFile( vcb );
-
- CLEAN_CATALOGDATA(&catalogData);
- return (errDF ? errDF : (errRF ? errRF : err));
-Exit:
-
- CLEAN_CATALOGDATA(&catalogData);
- return( err );
-}
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
// Routine: CompareExtentKeys
// an HFS volume.
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
-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
// an HFS volume.
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
-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
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);
+}
//_________________________________________________________________________________
//
// 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 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;
-
-
-#if HFSInstrumentation
- InstTraceClassRef trace;
- InstEventTag eventTag;
- InstDataDescriptorRef traceDescriptor;
- FSVarsRec *fsVars = (FSVarsRec *) LMGetFSMVars();
-
- traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
+ 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;
- err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:ExtendFileC", 'hfs+', kInstEnableClassMask, &trace);
- if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
-
- eventTag = InstCreateEventTag();
- InstLogTraceEvent( trace, eventTag, kInstStartEvent);
-#endif
needsFlush = false;
*actualBytesAdded = 0;
volumeBlockSize = vcb->blockSize;
allOrNothing = ((flags & kEFAllMask) != 0);
forceContig = ((flags & kEFContigMask) != 0);
- previousPEOF = fcb->fcbPLen;
+ prevblocks = fcb->ff_blocks;
if (vcb->vcbSigWord == kHFSPlusSigWord)
numExtentsPerRecord = kHFSPlusExtentDensity;
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;
}
//
// 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?
//
// 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;
}
// 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;
+ }
+ useMetaZone = flags & kEFMetadataMask;
do {
- startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount;
- err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, wantContig, &actualStartBlock, &actualNumBlocks);
+ if (blockHint != 0)
+ startBlock = blockHint;
+ else
+ startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount;
+
+ 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
}
if (actualNumBlocks != 0)
err = noErr;
+ if (useMetaZone == 0) {
+ /* Couldn't get anything so dip into metadat zone */
+ err = noErr;
+ useMetaZone = 1;
+ continue;
+ }
}
if (err == noErr) {
-#if HFSInstrumentation
- {
- struct {
- UInt32 fileID;
- UInt32 start;
- UInt32 count;
- UInt32 fabn;
- } x;
-
- x.fileID = H_FILEID(fcb);
- x.start = actualStartBlock;
- x.count = actualNumBlocks;
- x.fabn = nextBlock;
-
- InstLogTraceEventWithDataStructure( trace, eventTag, kInstMiddleEvent, traceDescriptor,
- (UInt8 *) &x, sizeof(x));
+ if (actualNumBlocks != 0) {
+ // this catalog entry *must* get forced to disk when
+ // hfs_update() is called
+ FTOC(fcb)->c_flag |= C_FORCEUPDATE;
}
-#endif
+
// Add the new extent to the existing extent record, or create a new one.
- if (actualStartBlock == startBlock) {
+ if ((actualStartBlock == startBlock) && (blockHint == 0)) {
// We grew the file's last extent, so just adjust the number of blocks.
foundData[foundIndex].blockCount += actualNumBlocks;
- err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
+ 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) {
- err = fxOvFlErr; // Oops. Can't extend extents file (?? really ??)
+ 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;
// 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;
// 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;
}
}
// 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;
}
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.
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);
-#if HFSInstrumentation
- InstLogTraceEvent( trace, eventTag, kInstEndEvent);
-#endif
-
return err;
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
-
-#if HFSInstrumentation
- InstTraceClassRef trace;
- InstEventTag eventTag;
- InstDataDescriptorRef traceDescriptor;
- FSVarsRec *fsVars = (FSVarsRec *) LMGetFSMVars();
-
- traceDescriptor = (InstDataDescriptorRef) fsVars->later[2];
-
- err = InstCreateTraceClass(kInstRootClassRef, "HFS:Extents:TruncateFileC", 'hfs+', kInstEnableClassMask, &trace);
- if (err != noErr) DebugStr("\pError from InstCreateTraceClass");
-
- eventTag = InstCreateEventTag();
- InstLogTraceEvent( trace, eventTag, kInstStartEvent);
-#endif
recordDeleted = false;
- 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;
//
// 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).
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)
// 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;
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;
// 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;
}
// 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);
-#if HFSInstrumentation
- InstLogTraceEvent( trace, eventTag, kInstEndEvent);
-#endif
-
return err;
}
+/*
+ * HFS Plus only
+ *
+ */
+OSErr HeadTruncateFile (
+ ExtendedVCB *vcb,
+ FCB *fcb,
+ u_int32_t headblks)
+{
+ HFSPlusExtentRecord extents;
+ HFSPlusExtentRecord tailExtents;
+ HFSCatalogNodeID fileID;
+ u_int8_t forkType;
+ u_int32_t blkcnt;
+ 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);
+}
+
+
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
// Routine: SearchExtentRecord (was XRSearch)
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
static OSErr SearchExtentRecord(
- const ExtendedVCB *vcb,
- 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;
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
static OSErr SearchExtentFile(
- const ExtendedVCB *vcb,
+ ExtendedVCB *vcb,
const FCB *fcb,
- SInt64 filePosition,
+ 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));
//
// 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) {
//
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
+//============================================================================
// Routine: UpdateExtentRecord
//
// Function: Write new extent data to an existing extent record with a given key.
//
// 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.
//
// Result: noErr = ok
// (other) = error from BTree
-//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
+//============================================================================
-static OSErr UpdateExtentRecord (
- const ExtendedVCB *vcb,
- FCB *fcb,
- const HFSPlusExtentKey *extentFileKey,
- const HFSPlusExtentRecord extentData,
- UInt32 extentBTreeHint)
+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
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
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;
-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)
{
#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
-OSErr GetFCBExtentRecord(
+static OSErr GetFCBExtentRecord(
const FCB *fcb,
HFSPlusExtentRecord extents)
{
}
-
-//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
-// Routine: MapFileBlockFromFCB
-//
-// Function: Determine if the given file offset is within the set of extents
-// stored in the FCB. If so, return the file allocation
-// block number of the start of the extent, volume allocation block number
-// of the start of the extent, and file allocation block number immediately
-// following the extent.
-//
-// Input: vcb - the volume containing the extents
-// fcb - the file that owns the extents
-// offset - desired offset in bytes
-//
-// Output: firstFABN - file alloc block number of start of extent
-// firstBlock - volume alloc block number of start of extent
-// nextFABN - file alloc block number of next extent
-//
-// Result: noErr = ok
-// fxRangeErr = beyond FCB's extents
-//ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
-static OSErr MapFileBlockFromFCB(
- const ExtendedVCB *vcb,
- const FCB *fcb,
- SInt64 offset, // Desired offset in bytes from start of file
- UInt32 *firstFABN, // FABN of first block of found extent
- UInt32 *firstBlock, // Corresponding allocation block number
- UInt32 *nextFABN) // FABN of block after end of extent
-{
- UInt32 index;
- UInt32 offsetBlocks;
- SInt64 temp64;
-
- temp64 = offset / (SInt64)vcb->blockSize;
- offsetBlocks = (UInt32)temp64;
-
- if (vcb->vcbSigWord == kHFSSigWord) {
- /* XXX SER Do we need to test for overflow values ??? */
- UInt16 blockCount;
- UInt16 currentFABN;
-
- currentFABN = 0;
-
- for (index=0; index<kHFSExtentDensity; index++) {
-
- blockCount = fcb->fcbExtents[index].blockCount;
-
- if (blockCount == 0)
- return fxRangeErr; // ran out of extents!
-
- // Is it in this extent?
- if (offsetBlocks < blockCount) {
- *firstFABN = currentFABN;
- *firstBlock = fcb->fcbExtents[index].startBlock;
- currentFABN += blockCount; // faster to add these as UInt16 first, then extend to UInt32
- *nextFABN = currentFABN;
- return noErr; // found the right extent
- }
-
- // Not in current extent, so adjust counters and loop again
- offsetBlocks -= blockCount;
- currentFABN += blockCount;
- }
- }
- else {
- UInt32 blockCount;
- UInt32 currentFABN;
-
- currentFABN = 0;
-
- for (index=0; index<kHFSPlusExtentDensity; index++) {
-
- blockCount = fcb->fcbExtents[index].blockCount;
-
- if (blockCount == 0)
- return fxRangeErr; // ran out of extents!
-
- // Is it in this extent?
- if (offsetBlocks < blockCount) {
- *firstFABN = currentFABN;
- *firstBlock = fcb->fcbExtents[index].startBlock;
- *nextFABN = currentFABN + blockCount;
- return noErr; // found the right extent
- }
-
- // Not in current extent, so adjust counters and loop again
- offsetBlocks -= blockCount;
- currentFABN += blockCount;
- }
- }
-
- // If we fall through here, the extent record was full, but the offset was
- // beyond those extents.
-
- return fxRangeErr;
-}
-
-
//_________________________________________________________________________________
//
// Routine: ExtentsAreIntegral
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;
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)
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;
}