/*
- * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2014 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@
*/
#include "../headers/BTreesInternal.h"
#include <sys/malloc.h>
+#include <sys/vnode_internal.h>
/*
============================================================
FlushExtentFile
Flush the extents file for a given volume.
-
+ SearchExtentFile
+ Search the FCB and extents file for an extent record that
+ contains a given file position (in bytes).
============================================================
============================================================
FindExtentRecord
Search the extents BTree for a particular extent record.
- SearchExtentFile
- Search the FCB and extents file for an extent record that
- contains a given file position (in bytes).
SearchExtentRecord
Search a given extent record to see if it contains a given
file position (in bytes). Used by SearchExtentFile.
and was in the extents file, then delete the record instead.
*/
-static const SInt64 kTwoGigabytes = 0x80000000LL;
+#if CONFIG_HFS_STD
+static const int64_t kTwoGigabytes = 0x80000000LL;
+#endif
enum
{
};
+#if CONFIG_HFS_STD
static OSErr HFSPlusToHFSExtents(
const HFSPlusExtentRecord oldExtents,
HFSExtentRecord newExtents);
+#endif
static OSErr FindExtentRecord(
const ExtendedVCB *vcb,
- UInt8 forkType,
- UInt32 fileID,
- UInt32 startBlock,
+ u_int8_t forkType,
+ u_int32_t fileID,
+ u_int32_t startBlock,
Boolean allowPrevious,
HFSPlusExtentKey *foundKey,
HFSPlusExtentRecord foundData,
- UInt32 *foundHint);
+ u_int32_t *foundHint);
static OSErr DeleteExtentRecord(
const ExtendedVCB *vcb,
- UInt8 forkType,
- UInt32 fileID,
- UInt32 startBlock);
+ u_int8_t forkType,
+ u_int32_t fileID,
+ u_int32_t startBlock);
static OSErr CreateExtentRecord(
ExtendedVCB *vcb,
HFSPlusExtentKey *key,
HFSPlusExtentRecord extents,
- UInt32 *hint);
+ u_int32_t *hint);
static OSErr GetFCBExtentRecord(
const FCB *fcb,
HFSPlusExtentRecord extents);
-static OSErr SearchExtentFile(
- ExtendedVCB *vcb,
- const FCB *fcb,
- SInt64 filePosition,
- HFSPlusExtentKey *foundExtentKey,
- HFSPlusExtentRecord foundExtentData,
- UInt32 *foundExtentDataIndex,
- UInt32 *extentBTreeHint,
- UInt32 *endingFABNPlusOne );
-
static OSErr SearchExtentRecord(
ExtendedVCB *vcb,
- UInt32 searchFABN,
+ u_int32_t searchFABN,
const HFSPlusExtentRecord extentData,
- UInt32 extentDataStartFABN,
- UInt32 *foundExtentDataOffset,
- UInt32 *endingFABNPlusOne,
+ u_int32_t extentDataStartFABN,
+ u_int32_t *foundExtentDataOffset,
+ u_int32_t *endingFABNPlusOne,
Boolean *noMoreExtents);
static OSErr ReleaseExtents(
ExtendedVCB *vcb,
const HFSPlusExtentRecord extentRecord,
- UInt32 *numReleasedAllocationBlocks,
+ u_int32_t *numReleasedAllocationBlocks,
Boolean *releasedLastExtent);
static OSErr DeallocateFork(
ExtendedVCB *vcb,
HFSCatalogNodeID fileID,
- UInt8 forkType,
+ u_int8_t forkType,
HFSPlusExtentRecord catalogExtents,
Boolean * recordDeleted);
static OSErr TruncateExtents(
ExtendedVCB *vcb,
- UInt8 forkType,
- UInt32 fileID,
- UInt32 startBlock,
+ u_int8_t forkType,
+ u_int32_t fileID,
+ u_int32_t startBlock,
Boolean * recordDeleted);
static OSErr UpdateExtentRecord (
ExtendedVCB *vcb,
- FCB *fcb,
+ FCB *fcb,
+ int deleted,
const HFSPlusExtentKey *extentFileKey,
const HFSPlusExtentRecord extentData,
- UInt32 extentBTreeHint);
+ u_int32_t extentBTreeHint);
static Boolean ExtentsAreIntegral(
const HFSPlusExtentRecord extentRecord,
- UInt32 mask,
- UInt32 *blocksChecked,
+ u_int32_t mask,
+ u_int32_t *blocksChecked,
Boolean *checkedLastExtent);
//_________________________________________________________________________________
//_________________________________________________________________________________
static OSErr FindExtentRecord(
const ExtendedVCB *vcb,
- UInt8 forkType,
- UInt32 fileID,
- UInt32 startBlock,
+ u_int8_t forkType,
+ u_int32_t fileID,
+ u_int32_t startBlock,
Boolean allowPrevious,
HFSPlusExtentKey *foundKey,
HFSPlusExtentRecord foundData,
- UInt32 *foundHint)
+ u_int32_t *foundHint)
{
FCB * fcb;
- BTreeIterator *btIterator;
+ struct BTreeIterator *btIterator = NULL;
FSBufferDescriptor btRecord;
OSErr err;
- UInt16 btRecordSize;
+ u_int16_t btRecordSize;
err = noErr;
if (foundHint)
*foundHint = 0;
fcb = GetFileControlBlock(vcb->extentsRefNum);
-
- MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+
+ MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+ if (btIterator == NULL) {
+ return memFullErr; // translates to ENOMEM
+ }
bzero(btIterator, sizeof(*btIterator));
- if (vcb->vcbSigWord == kHFSSigWord) {
- HFSExtentKey * extentKeyPtr;
- HFSExtentRecord extentData;
+ /* HFS Plus / HFSX */
+ if (vcb->vcbSigWord != kHFSSigWord) {
+ HFSPlusExtentKey * extentKeyPtr;
+ HFSPlusExtentRecord extentData;
- extentKeyPtr = (HFSExtentKey*) &btIterator->key;
- extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength;
- extentKeyPtr->forkType = forkType;
- extentKeyPtr->fileID = fileID;
+ extentKeyPtr = (HFSPlusExtentKey*) &btIterator->key;
+ extentKeyPtr->keyLength = kHFSPlusExtentKeyMaximumLength;
+ extentKeyPtr->forkType = forkType;
+ extentKeyPtr->pad = 0;
+ extentKeyPtr->fileID = fileID;
extentKeyPtr->startBlock = startBlock;
btRecord.bufferAddress = &extentData;
- btRecord.itemSize = sizeof(HFSExtentRecord);
+ btRecord.itemSize = sizeof(HFSPlusExtentRecord);
btRecord.itemCount = 1;
err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator);
}
if (err == noErr) {
- UInt16 i;
-
// Copy the found key back for the caller
- if (foundKey) {
- foundKey->keyLength = kHFSPlusExtentKeyMaximumLength;
- foundKey->forkType = extentKeyPtr->forkType;
- foundKey->pad = 0;
- foundKey->fileID = extentKeyPtr->fileID;
- foundKey->startBlock = extentKeyPtr->startBlock;
- }
+ if (foundKey)
+ BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey));
// Copy the found data back for the caller
- foundData[0].startBlock = extentData[0].startBlock;
- foundData[0].blockCount = extentData[0].blockCount;
- foundData[1].startBlock = extentData[1].startBlock;
- foundData[1].blockCount = extentData[1].blockCount;
- foundData[2].startBlock = extentData[2].startBlock;
- foundData[2].blockCount = extentData[2].blockCount;
-
- for (i = 3; i < kHFSPlusExtentDensity; ++i)
- {
- foundData[i].startBlock = 0;
- foundData[i].blockCount = 0;
- }
+ BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord));
}
}
- else { // HFS Plus volume
- HFSPlusExtentKey * extentKeyPtr;
- HFSPlusExtentRecord extentData;
+#if CONFIG_HFS_STD
+ else {
+ HFSExtentKey * extentKeyPtr;
+ HFSExtentRecord extentData;
- extentKeyPtr = (HFSPlusExtentKey*) &btIterator->key;
- extentKeyPtr->keyLength = kHFSPlusExtentKeyMaximumLength;
- extentKeyPtr->forkType = forkType;
- extentKeyPtr->pad = 0;
- extentKeyPtr->fileID = fileID;
+ extentKeyPtr = (HFSExtentKey*) &btIterator->key;
+ extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength;
+ extentKeyPtr->forkType = forkType;
+ extentKeyPtr->fileID = fileID;
extentKeyPtr->startBlock = startBlock;
btRecord.bufferAddress = &extentData;
- btRecord.itemSize = sizeof(HFSPlusExtentRecord);
+ btRecord.itemSize = sizeof(HFSExtentRecord);
btRecord.itemCount = 1;
err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator);
}
if (err == noErr) {
+ u_int16_t i;
+
// Copy the found key back for the caller
- if (foundKey)
- BlockMoveData(extentKeyPtr, foundKey, sizeof(HFSPlusExtentKey));
+ if (foundKey) {
+ foundKey->keyLength = kHFSPlusExtentKeyMaximumLength;
+ foundKey->forkType = extentKeyPtr->forkType;
+ foundKey->pad = 0;
+ foundKey->fileID = extentKeyPtr->fileID;
+ foundKey->startBlock = extentKeyPtr->startBlock;
+ }
// Copy the found data back for the caller
- BlockMoveData(&extentData, foundData, sizeof(HFSPlusExtentRecord));
+ foundData[0].startBlock = extentData[0].startBlock;
+ foundData[0].blockCount = extentData[0].blockCount;
+ foundData[1].startBlock = extentData[1].startBlock;
+ foundData[1].blockCount = extentData[1].blockCount;
+ foundData[2].startBlock = extentData[2].startBlock;
+ foundData[2].blockCount = extentData[2].blockCount;
+
+ for (i = 3; i < kHFSPlusExtentDensity; ++i)
+ {
+ foundData[i].startBlock = 0;
+ foundData[i].blockCount = 0;
+ }
}
}
+#endif
if (foundHint)
*foundHint = btIterator->hint.nodeNum;
- FREE(btIterator, M_TEMP);
+
+ FREE(btIterator, M_TEMP);
return err;
}
ExtendedVCB *vcb,
HFSPlusExtentKey *key,
HFSPlusExtentRecord extents,
- UInt32 *hint)
+ u_int32_t *hint)
{
- BTreeIterator * btIterator;
+ struct BTreeIterator *btIterator = NULL;
FSBufferDescriptor btRecord;
- UInt16 btRecordSize;
+ u_int16_t btRecordSize;
int lockflags;
OSErr err;
err = noErr;
*hint = 0;
- MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+ MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+ if (btIterator == NULL) {
+ return memFullErr; // translates to ENOMEM
+ }
bzero(btIterator, sizeof(*btIterator));
/*
*/
lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
- if (vcb->vcbSigWord == kHFSSigWord) {
+ /* HFS+/HFSX */
+ if (vcb->vcbSigWord != kHFSSigWord) {
+ btRecordSize = sizeof(HFSPlusExtentRecord);
+ btRecord.bufferAddress = extents;
+ btRecord.itemSize = btRecordSize;
+ btRecord.itemCount = 1;
+
+ BlockMoveData(key, &btIterator->key, sizeof(HFSPlusExtentKey));
+ }
+#if CONFIG_HFS_STD
+ else {
+ /* HFS Standard */
HFSExtentKey * keyPtr;
HFSExtentRecord data;
err = HFSPlusToHFSExtents(extents, data);
}
- else { // HFS Plus volume
- btRecordSize = sizeof(HFSPlusExtentRecord);
- btRecord.bufferAddress = extents;
- btRecord.itemSize = btRecordSize;
- btRecord.itemCount = 1;
-
- BlockMoveData(key, &btIterator->key, sizeof(HFSPlusExtentKey));
- }
+#endif
if (err == noErr)
err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator, &btRecord, btRecordSize);
(void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
hfs_systemfile_unlock(vcb, lockflags);
-
- FREE(btIterator, M_TEMP);
+
+ FREE (btIterator, M_TEMP);
return err;
}
static OSErr DeleteExtentRecord(
const ExtendedVCB *vcb,
- UInt8 forkType,
- UInt32 fileID,
- UInt32 startBlock)
+ u_int8_t forkType,
+ u_int32_t fileID,
+ u_int32_t startBlock)
{
- BTreeIterator * btIterator;
+ struct BTreeIterator *btIterator = NULL;
OSErr err;
err = noErr;
- MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+ MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+ if (btIterator == NULL) {
+ return memFullErr; // translates to ENOMEM
+ }
bzero(btIterator, sizeof(*btIterator));
- if (vcb->vcbSigWord == kHFSSigWord) {
- HFSExtentKey * keyPtr;
+ /* HFS+ / HFSX */
+ if (vcb->vcbSigWord != kHFSSigWord) { // HFS Plus volume
+ HFSPlusExtentKey * keyPtr;
- keyPtr = (HFSExtentKey*) &btIterator->key;
- keyPtr->keyLength = kHFSExtentKeyMaximumLength;
+ keyPtr = (HFSPlusExtentKey*) &btIterator->key;
+ keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength;
keyPtr->forkType = forkType;
+ keyPtr->pad = 0;
keyPtr->fileID = fileID;
keyPtr->startBlock = startBlock;
}
- else { // HFS Plus volume
- HFSPlusExtentKey * keyPtr;
+#if CONFIG_HFS_STD
+ else {
+ /* HFS standard */
+ HFSExtentKey * keyPtr;
- keyPtr = (HFSPlusExtentKey*) &btIterator->key;
- keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength;
+ keyPtr = (HFSExtentKey*) &btIterator->key;
+ keyPtr->keyLength = kHFSExtentKeyMaximumLength;
keyPtr->forkType = forkType;
- keyPtr->pad = 0;
keyPtr->fileID = fileID;
keyPtr->startBlock = startBlock;
}
+#endif
err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator);
(void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
- FREE(btIterator, M_TEMP);
+
+ FREE(btIterator, M_TEMP);
return err;
}
//
//_________________________________________________________________________________
-__private_extern__
OSErr MapFileBlockC (
ExtendedVCB *vcb, // volume that file resides on
FCB *fcb, // FCB of file
size_t *availableBytes) // number of contiguous bytes (up to numberOfBytes)
{
OSErr err;
- UInt32 allocBlockSize; // Size of the volume's allocation block
- UInt32 sectorSize;
+ u_int32_t allocBlockSize; // Size of the volume's allocation block
+ u_int32_t sectorSize;
HFSPlusExtentKey foundKey;
HFSPlusExtentRecord foundData;
- UInt32 foundIndex;
- UInt32 hint;
- UInt32 firstFABN; // file allocation block of first block in found extent
- UInt32 nextFABN; // file allocation block of block after end of found extent
+ u_int32_t foundIndex;
+ u_int32_t hint;
+ u_int32_t firstFABN; // file allocation block of first block in found extent
+ u_int32_t nextFABN; // file allocation block of block after end of found extent
off_t dataEnd; // (offset) end of range that is contiguous
- UInt32 sectorsPerBlock; // Number of sectors per allocation block
- UInt32 startBlock; // volume allocation block corresponding to firstFABN
+ u_int32_t sectorsPerBlock; // Number of sectors per allocation block
+ u_int32_t startBlock; // volume allocation block corresponding to firstFABN
daddr64_t temp;
off_t tmpOff;
allocBlockSize = vcb->blockSize;
- sectorSize = VCBTOHFS(vcb)->hfs_phys_block_size;
+ sectorSize = VCBTOHFS(vcb)->hfs_logical_block_size;
err = SearchExtentFile(vcb, fcb, offset, &foundKey, foundData, &foundIndex, &hint, &nextFABN);
if (err == noErr) {
// offset in sectors from start of allocation block space
//
temp = (daddr64_t)((offset - (off_t)((off_t)(firstFABN) * (off_t)(allocBlockSize)))/sectorSize);
- temp += startBlock * sectorsPerBlock;
+ temp += (daddr64_t)startBlock * (daddr64_t)sectorsPerBlock;
/* Add in any volume offsets */
if (vcb->vcbSigWord == kHFSPlusSigWord)
if (availableBytes)
{
tmpOff = dataEnd - offset;
- if (tmpOff > (off_t)(numberOfBytes))
+ /*
+ * Disallow negative runs.
+ */
+ if (tmpOff <= 0) {
+ return EINVAL;
+ }
+
+ if (tmpOff > (off_t)(numberOfBytes)) {
*availableBytes = numberOfBytes; // more there than they asked for, so pin the output
- else
+ }
+ else {
*availableBytes = tmpOff;
+ }
}
return noErr;
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;
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
// Function: Flushes the extent file for a specified volume
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
-__private_extern__
OSErr FlushExtentFile( ExtendedVCB *vcb )
{
FCB * fcb;
}
+#if CONFIG_HFS_STD
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
// Routine: CompareExtentKeys
//
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
__private_extern__
-SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey )
+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
return( result );
}
-
+#endif
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
__private_extern__
-SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey )
+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 );
}
+static int
+should_pin_blocks(hfsmount_t *hfsmp, FCB *fcb)
+{
+ if (!ISSET(hfsmp->hfs_flags, HFS_CS_HOTFILE_PIN)
+ || fcb->ff_cp == NULL || fcb->ff_cp->c_vp == NULL) {
+ return 0;
+ }
+
+ int pin_blocks;
+
+ //
+ // File system metadata should get pinned
+ //
+ if (vnode_issystem(fcb->ff_cp->c_vp)) {
+ return 1;
+ }
+
+ //
+ // If a file is AutoCandidate, we should not pin its blocks because
+ // it was an automatically added file and this function is intended
+ // to pin new blocks being added to user-generated content.
+ //
+ if (fcb->ff_cp->c_attr.ca_recflags & kHFSAutoCandidateMask) {
+ return 0;
+ }
+
+ //
+ // If a file is marked FastDevPinned it is an existing pinned file
+ // or a new file that should be pinned.
+ //
+ // If a file is marked FastDevCandidate it is a new file that is
+ // being written to for the first time so we don't want to pin it
+ // just yet as it may not meet the criteria (i.e. too large).
+ //
+ if ((fcb->ff_cp->c_attr.ca_recflags & (kHFSFastDevPinnedMask)) != 0) {
+ pin_blocks = 1;
+ } else {
+ pin_blocks = 0;
+ }
+
+ return pin_blocks;
+}
+
+
+
+static void
+pin_blocks_if_needed(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockCount)
+{
+ if (!should_pin_blocks(vcb, fcb)) {
+ return;
+ }
+
+ // ask CoreStorage to pin the new blocks being added to this file
+ if (hfs_pin_block_range((struct hfsmount *)vcb, HFS_PIN_IT, startBlock, blockCount, vfs_context_kernel()) == 0) {
+ struct vnode *vp = fcb->ff_cp->c_vp;
+
+ // and make sure to keep our accounting in order
+ hfs_hotfile_adjust_blocks(vp, -blockCount);
+ }
+}
+
+
+
/*
* Add a file extent to a file.
*
* Used by hfs_extendfs to extend the volume allocation bitmap file.
*
*/
-__private_extern__
int
-AddFileExtent(ExtendedVCB *vcb, FCB *fcb, UInt32 startBlock, UInt32 blockCount)
+AddFileExtent(ExtendedVCB *vcb, FCB *fcb, u_int32_t startBlock, u_int32_t blockCount)
{
HFSPlusExtentKey foundKey;
HFSPlusExtentRecord foundData;
- UInt32 foundIndex;
- UInt32 hint;
- UInt32 nextBlock;
- SInt64 peof;
+ u_int32_t foundIndex;
+ u_int32_t hint;
+ u_int32_t nextBlock;
+ int64_t peof;
int i;
int error;
- peof = (SInt64)(fcb->ff_blocks + blockCount) * (SInt64)vcb->blockSize;
+ peof = (int64_t)(fcb->ff_blocks + blockCount) * (int64_t)vcb->blockSize;
error = SearchExtentFile(vcb, fcb, peof-1, &foundKey, foundData, &foundIndex, &hint, &nextBlock);
if (error != fxRangeErr)
foundIndex = 0;
error = CreateExtentRecord(vcb, &foundKey, foundData, &hint);
- if (error == fxOvFlErr)
+ if (error == fxOvFlErr) {
error = dskFulErr;
+ } else if (error == 0) {
+ pin_blocks_if_needed(vcb, fcb, startBlock, blockCount);
+ }
+
} else {
/*
* Add a new extent into existing record.
*/
foundData[foundIndex].startBlock = startBlock;
foundData[foundIndex].blockCount = blockCount;
- error = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
+ error = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint);
+ if (error == 0) {
+ pin_blocks_if_needed(vcb, fcb, startBlock, blockCount);
+ }
}
(void) FlushExtentFile(vcb);
//
//_________________________________________________________________________________
-__private_extern__
OSErr ExtendFileC (
ExtendedVCB *vcb, // volume that file resides on
FCB *fcb, // FCB of file to truncate
- SInt64 bytesToAdd, // number of bytes to allocate
- UInt32 blockHint, // desired starting allocation block
- UInt32 flags, // EFContig and/or EFAll
- SInt64 *actualBytesAdded) // number of bytes actually allocated
+ int64_t bytesToAdd, // number of bytes to allocate
+ u_int32_t blockHint, // desired starting allocation block
+ u_int32_t flags, // EFContig and/or EFAll
+ int64_t *actualBytesAdded) // number of bytes actually allocated
{
OSErr err;
- UInt32 volumeBlockSize;
- SInt64 blocksToAdd;
- SInt64 bytesThisExtent;
+ u_int32_t volumeBlockSize;
+ int64_t blocksToAdd;
+ int64_t bytesThisExtent;
HFSPlusExtentKey foundKey;
HFSPlusExtentRecord foundData;
- UInt32 foundIndex;
- UInt32 hint;
- UInt32 nextBlock;
- UInt32 startBlock;
+ u_int32_t foundIndex;
+ u_int32_t hint;
+ u_int32_t nextBlock;
+ u_int32_t startBlock;
Boolean allOrNothing;
Boolean forceContig;
Boolean wantContig;
Boolean useMetaZone;
Boolean needsFlush;
- UInt32 actualStartBlock;
- UInt32 actualNumBlocks;
- UInt32 numExtentsPerRecord;
- SInt64 maximumBytes;
- SInt64 peof;
- UInt32 prevblocks;
-
-
+ int allowFlushTxns;
+ u_int32_t actualStartBlock;
+ u_int32_t actualNumBlocks;
+ u_int32_t numExtentsPerRecord;
+ int64_t maximumBytes;
+ int64_t availbytes;
+ int64_t peof;
+ u_int32_t prevblocks;
+ uint32_t fastdev = 0;
+
+ struct hfsmount *hfsmp = (struct hfsmount*)vcb;
+ allowFlushTxns = 0;
needsFlush = false;
*actualBytesAdded = 0;
volumeBlockSize = vcb->blockSize;
forceContig = ((flags & kEFContigMask) != 0);
prevblocks = fcb->ff_blocks;
- if (vcb->vcbSigWord == kHFSPlusSigWord)
+ if (vcb->vcbSigWord != kHFSSigWord) {
numExtentsPerRecord = kHFSPlusExtentDensity;
- else
+ }
+#if CONFIG_HFS_STD
+ else {
+ /* HFS Standard */
numExtentsPerRecord = kHFSExtentDensity;
- //
- // Make sure the request and new PEOF are less than 2GB if HFS.
- //
- if (vcb->vcbSigWord == kHFSSigWord) {
+ /* Make sure the request and new PEOF are less than 2GB if HFS std*/
if (bytesToAdd >= kTwoGigabytes)
- goto Overflow;
- if ((((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes)
- goto Overflow;
+ goto HFS_Std_Overflow;
+ if ((((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes)
+ goto HFS_Std_Overflow;
}
+#endif
+
//
// Determine how many blocks need to be allocated.
// Round up the number of desired bytes to add.
//
blocksToAdd = howmany(bytesToAdd, volumeBlockSize);
- bytesToAdd = (SInt64)((SInt64)blocksToAdd * (SInt64)volumeBlockSize);
+ bytesToAdd = (int64_t)((int64_t)blocksToAdd * (int64_t)volumeBlockSize);
/*
* For deferred allocations just reserve the blocks.
*/
if ((flags & kEFDeferMask)
&& (vcb->vcbSigWord == kHFSPlusSigWord)
- && (bytesToAdd < (SInt64)HFS_MAX_DEFERED_ALLOC)
+ && (bytesToAdd < (int64_t)HFS_MAX_DEFERED_ALLOC)
&& (blocksToAdd < hfs_freeblks(VCBTOHFS(vcb), 1))) {
- HFS_MOUNT_LOCK(vcb, TRUE);
+ hfs_lock_mount (hfsmp);
vcb->loanedBlocks += blocksToAdd;
- HFS_MOUNT_UNLOCK(vcb, TRUE);
+ hfs_unlock_mount(hfsmp);
fcb->ff_unallocblocks += blocksToAdd;
FTOC(fcb)->c_blocks += blocksToAdd;
fcb->ff_blocks += blocksToAdd;
- FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
+ /*
+ * We haven't touched the disk here; no blocks have been
+ * allocated and the volume will not be inconsistent if we
+ * don't update the catalog record immediately.
+ */
+ FTOC(fcb)->c_flag |= C_MINOR_MOD;
*actualBytesAdded = bytesToAdd;
return (0);
}
loanedBlocks = fcb->ff_unallocblocks;
blocksToAdd += loanedBlocks;
- bytesToAdd = (SInt64)blocksToAdd * (SInt64)volumeBlockSize;
+ bytesToAdd = (int64_t)blocksToAdd * (int64_t)volumeBlockSize;
FTOC(fcb)->c_blocks -= loanedBlocks;
fcb->ff_blocks -= loanedBlocks;
fcb->ff_unallocblocks = 0;
- HFS_MOUNT_LOCK(vcb, TRUE);
+ hfs_lock_mount(hfsmp);
vcb->loanedBlocks -= loanedBlocks;
- HFS_MOUNT_UNLOCK(vcb, TRUE);
+ hfs_unlock_mount(hfsmp);
}
//
// rounded up to a multiple of the clump size.
//
if ((vcb->vcbClpSiz > (int32_t)volumeBlockSize)
- && (bytesToAdd < (SInt64)HFS_MAX_DEFERED_ALLOC)
+ && (bytesToAdd < (int64_t)HFS_MAX_DEFERED_ALLOC)
&& (flags & kEFNoClumpMask) == 0) {
- maximumBytes = (SInt64)howmany(bytesToAdd, vcb->vcbClpSiz);
+ maximumBytes = (int64_t)howmany(bytesToAdd, vcb->vcbClpSiz);
maximumBytes *= vcb->vcbClpSiz;
} else {
maximumBytes = bytesToAdd;
}
+#if CONFIG_HFS_STD
//
// Compute new physical EOF, rounded up to a multiple of a block.
//
if ( (vcb->vcbSigWord == kHFSSigWord) && // Too big?
- ((((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) ) {
+ ((((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes) ) {
if (allOrNothing) // Yes, must they have it all?
- goto Overflow; // Yes, can't have it
+ goto HFS_Std_Overflow; // Yes, can't have it
else {
--blocksToAdd; // No, give give 'em one block less
bytesToAdd -= volumeBlockSize;
}
}
+#endif
//
// If allocation is all-or-nothing, make sure there are
//
// See if there are already enough blocks allocated to the file.
//
- peof = ((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd; // potential new PEOF
+ peof = ((int64_t)fcb->ff_blocks * (int64_t)volumeBlockSize) + bytesToAdd; // potential new PEOF
err = SearchExtentFile(vcb, fcb, peof-1, &foundKey, foundData, &foundIndex, &hint, &nextBlock);
if (err == noErr) {
// Enough blocks are already allocated. Just update the FCB to reflect the new length.
fcb->ff_blocks = peof / volumeBlockSize;
FTOC(fcb)->c_blocks += (bytesToAdd / volumeBlockSize);
- FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
+ FTOC(fcb)->c_flag |= C_MODIFIED;
goto Exit;
}
if (err != fxRangeErr) // Any real error?
//
// Adjust the PEOF to the end of the last extent.
//
- peof = (SInt64)((SInt64)nextBlock * (SInt64)volumeBlockSize); // currently allocated PEOF
- bytesThisExtent = (SInt64)(nextBlock - fcb->ff_blocks) * (SInt64)volumeBlockSize;
+ peof = (int64_t)((int64_t)nextBlock * (int64_t)volumeBlockSize); // currently allocated PEOF
+ bytesThisExtent = (int64_t)(nextBlock - fcb->ff_blocks) * (int64_t)volumeBlockSize;
if (bytesThisExtent != 0) {
fcb->ff_blocks = nextBlock;
FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize);
// If that fails, get whatever we can.
// If forceContig, then take whatever we got
// else, keep getting bits and pieces (non-contig)
+
+ /*
+ * Note that for sparse devices (like sparse bundle dmgs), we
+ * should only be aggressive with re-using once-allocated pieces
+ * if we're not dealing with system files. If we're trying to operate
+ * on behalf of a system file, we need the maximum contiguous amount
+ * possible. For non-system files we favor locality and fragmentation over
+ * contiguity as it can result in fewer blocks being needed from the underlying
+ * filesystem that the sparse image resides upon.
+ */
err = noErr;
- wantContig = true;
+ if ( (vcb->hfs_flags & HFS_HAS_SPARSE_DEVICE)
+ && (fcb->ff_cp->c_fileid >= kHFSFirstUserCatalogNodeID)
+ && (flags & kEFMetadataMask) == 0) {
+ /*
+ * We want locality over contiguity so by default we set wantContig to
+ * false unless we hit one of the circumstances below.
+ */
+ wantContig = false;
+ if (hfs_isrbtree_active(VCBTOHFS(vcb))) {
+ /*
+ * If the red-black tree is acive, we can always find a suitable contiguous
+ * chunk. So if the user specifically requests contiguous files, we should
+ * honor that no matter what kind of device it is.
+ */
+ if (forceContig) {
+ wantContig = true;
+ }
+ }
+ else {
+ /*
+ * If the red-black tree is not active, then only set wantContig to true
+ * if we have never done a contig scan on the device, which would populate
+ * the free extent cache. Note that the caller may explicitly unset the
+ * DID_CONTIG_SCAN bit in order to force us to vend a contiguous extent here
+ * if the caller wants to get a contiguous chunk.
+ */
+ if ((vcb->hfs_flags & HFS_DID_CONTIG_SCAN) == 0) {
+ vcb->hfs_flags |= HFS_DID_CONTIG_SCAN;
+ wantContig = true;
+ }
+ }
+ }
+ else {
+ wantContig = true;
+ }
+
+ if (should_pin_blocks(hfsmp, fcb))
+ fastdev = HFS_ALLOC_FAST_DEV;
+
useMetaZone = flags & kEFMetadataMask;
- vcb->vcbFreeExtCnt = 0; /* For now, force rebuild of free extent list */
do {
if (blockHint != 0)
startBlock = blockHint;
else
startBlock = foundData[foundIndex].startBlock + foundData[foundIndex].blockCount;
- /* Force reserve checking if requested. */
- if (flags & kEFReserveMask) {
- SInt64 availbytes;
-
- actualNumBlocks = 0;
- actualStartBlock = 0;
+ actualNumBlocks = 0;
+ actualStartBlock = 0;
- availbytes = (SInt64)hfs_freeblks(VCBTOHFS(vcb), 1) *
- (SInt64)volumeBlockSize;
- if (availbytes <= 0) {
+ /* Find number of free blocks based on reserved block flag option */
+ availbytes = (int64_t)hfs_freeblks(VCBTOHFS(vcb), flags & kEFReserveMask) *
+ (int64_t)volumeBlockSize;
+ if (availbytes <= 0) {
+ err = dskFulErr;
+ } else {
+ if (wantContig && (availbytes < bytesToAdd)) {
err = dskFulErr;
- } else {
- if (wantContig && (availbytes < bytesToAdd))
- err = dskFulErr;
- else {
- err = BlockAllocate(
+ }
+ else {
+ uint32_t ba_flags = fastdev;
+
+ if (wantContig) {
+ ba_flags |= HFS_ALLOC_FORCECONTIG;
+ }
+ if (useMetaZone) {
+ ba_flags |= HFS_ALLOC_METAZONE;
+ }
+ if (allowFlushTxns) {
+ ba_flags |= HFS_ALLOC_FLUSHTXN;
+ }
+
+ err = BlockAllocate(
vcb,
startBlock,
howmany(MIN(bytesToAdd, availbytes), volumeBlockSize),
howmany(MIN(maximumBytes, availbytes), volumeBlockSize),
- wantContig,
- useMetaZone,
+ ba_flags,
&actualStartBlock,
&actualNumBlocks);
- }
}
- } else {
- err = BlockAllocate(vcb, startBlock, howmany(bytesToAdd, volumeBlockSize),
- howmany(maximumBytes, volumeBlockSize), wantContig, useMetaZone,
- &actualStartBlock, &actualNumBlocks);
}
if (err == dskFulErr) {
- if (forceContig)
- break; // AllocContig failed because not enough contiguous space
+ if (forceContig) {
+ if (allowFlushTxns == 0) {
+ /* If we're forcing contiguity, re-try but allow plucking from recently freed regions */
+ allowFlushTxns = 1;
+ wantContig = 1;
+ err = noErr;
+ continue;
+ }
+ else {
+ break; // AllocContig failed because not enough contiguous space
+ }
+ }
if (wantContig) {
// Couldn't get one big chunk, so get whatever we can.
err = noErr;
}
if (actualNumBlocks != 0)
err = noErr;
+
if (useMetaZone == 0) {
/* Couldn't get anything so dip into metadat zone */
err = noErr;
useMetaZone = 1;
continue;
}
- }
- if (err == noErr) {
- if (actualNumBlocks != 0) {
- // this catalog entry *must* get forced to disk when
- // hfs_update() is called
- FTOC(fcb)->c_flag |= C_FORCEUPDATE;
+
+ /* If we couldn't find what we needed without flushing the journal, then go ahead and do it now */
+ if (allowFlushTxns == 0) {
+ allowFlushTxns = 1;
+ err = noErr;
+ continue;
}
+ }
+ if (err == noErr) {
// Add the new extent to the existing extent record, or create a new one.
if ((actualStartBlock == startBlock) && (blockHint == 0)) {
// We grew the file's last extent, so just adjust the number of blocks.
foundData[foundIndex].blockCount += actualNumBlocks;
- err = UpdateExtentRecord(vcb, fcb, &foundKey, foundData, hint);
+ err = UpdateExtentRecord(vcb, fcb, 0, &foundKey, foundData, hint);
if (err != noErr) break;
}
else {
- UInt16 i;
+ u_int16_t i;
// Need to add a new extent. See if there is room in the current record.
if (foundData[foundIndex].blockCount != 0) // Is current extent free to use?
if (foundIndex == numExtentsPerRecord) {
// This record is full. Need to create a new one.
if (FTOC(fcb)->c_fileid == kHFSExtentsFileID) {
- (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks);
+ (void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks, 0);
err = dskFulErr; // Oops. Can't extend extents file past first record.
break;
}
// 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;
}
}
-
+
// Figure out how many bytes were actually allocated.
// NOTE: BlockAllocate could have allocated more than we asked for.
// Don't set the PEOF beyond what our client asked for.
nextBlock += actualNumBlocks;
- bytesThisExtent = (SInt64)((SInt64)actualNumBlocks * (SInt64)volumeBlockSize);
+ bytesThisExtent = (int64_t)((int64_t)actualNumBlocks * (int64_t)volumeBlockSize);
if (bytesThisExtent > bytesToAdd) {
bytesToAdd = 0;
}
}
fcb->ff_blocks += (bytesThisExtent / volumeBlockSize);
FTOC(fcb)->c_blocks += (bytesThisExtent / volumeBlockSize);
- FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
+ FTOC(fcb)->c_flag |= C_MODIFIED;
// If contiguous allocation was requested, then we've already got one contiguous
// chunk. If we didn't get all we wanted, then adjust the error to disk full.
/* Keep the roving allocator out of the metadata zone. */
if (vcb->nextAllocation >= VCBTOHFS(vcb)->hfs_metazone_start &&
vcb->nextAllocation <= VCBTOHFS(vcb)->hfs_metazone_end) {
- HFS_MOUNT_LOCK(vcb, TRUE);
- vcb->nextAllocation = VCBTOHFS(vcb)->hfs_metazone_end + 1;
- vcb->vcbFlags |= 0xFF00;
- HFS_MOUNT_UNLOCK(vcb, TRUE);
+ hfs_lock_mount (hfsmp);
+ HFS_UPDATE_NEXT_ALLOCATION(vcb, VCBTOHFS(vcb)->hfs_metazone_end + 1);
+ MarkVCBDirty(vcb);
+ hfs_unlock_mount(hfsmp);
}
}
if (prevblocks < fcb->ff_blocks) {
- *actualBytesAdded = (SInt64)(fcb->ff_blocks - prevblocks) * (SInt64)volumeBlockSize;
+ *actualBytesAdded = (int64_t)(fcb->ff_blocks - prevblocks) * (int64_t)volumeBlockSize;
} else {
*actualBytesAdded = 0;
}
+ if (fastdev) {
+ hfs_hotfile_adjust_blocks(fcb->ff_cp->c_vp,
+ (int64_t)prevblocks - fcb->ff_blocks);
+ }
+
if (needsFlush)
(void) FlushExtentFile(vcb);
return err;
-Overflow:
+#if CONFIG_HFS_STD
+HFS_Std_Overflow:
err = fileBoundsErr;
goto ErrorExit;
+#endif
}
//
//_________________________________________________________________________________
-__private_extern__
OSErr TruncateFileC (
ExtendedVCB *vcb, // volume that file resides on
FCB *fcb, // FCB of file to truncate
- SInt64 peof, // new physical size for file
+ int64_t peof, // new physical size for file
+ int deleted, // if nonzero, the file's catalog record has already been deleted.
+ int rsrc, // does this represent a resource fork or not?
+ uint32_t fileid, // the fileid of the file we're manipulating.
Boolean truncateToExtent) // if true, truncate to end of extent containing newPEOF
+
{
OSErr err;
- UInt32 nextBlock; // next file allocation block to consider
- UInt32 startBlock; // Physical (volume) allocation block number of start of a range
- UInt32 physNumBlocks; // Number of allocation blocks in file (according to PEOF)
- UInt32 numBlocks;
+ u_int32_t nextBlock; // next file allocation block to consider
+ u_int32_t startBlock; // Physical (volume) allocation block number of start of a range
+ u_int32_t physNumBlocks; // Number of allocation blocks in file (according to PEOF)
+ u_int32_t numBlocks;
HFSPlusExtentKey key; // key for current extent record; key->keyLength == 0 if FCB's extent record
- UInt32 hint; // BTree hint corresponding to key
+ u_int32_t hint; // BTree hint corresponding to key
HFSPlusExtentRecord extentRecord;
- UInt32 extentIndex;
- UInt32 extentNextBlock;
- UInt32 numExtentsPerRecord;
- SInt64 temp64;
- UInt8 forkType;
+ u_int32_t extentIndex;
+ u_int32_t extentNextBlock;
+ u_int32_t numExtentsPerRecord;
+ int64_t temp64;
+ u_int8_t forkType;
Boolean extentChanged; // true if we actually changed an extent
Boolean recordDeleted; // true if an extent record got deleted
recordDeleted = false;
- if (vcb->vcbSigWord == kHFSPlusSigWord)
+ if (vcb->vcbSigWord == kHFSPlusSigWord) {
numExtentsPerRecord = kHFSPlusExtentDensity;
- else
+ }
+ else {
numExtentsPerRecord = kHFSExtentDensity;
-
- if (FORK_IS_RSRC(fcb))
+ }
+
+ if (rsrc) {
forkType = kResourceForkType;
- else
+ }
+ else {
forkType = kDataForkType;
-
+ }
+
temp64 = fcb->ff_blocks;
- physNumBlocks = (UInt32)temp64;
+ physNumBlocks = (u_int32_t)temp64;
//
// Round newPEOF up to a multiple of the allocation block size. If new size is
// shouldn't that be an error?).
//
nextBlock = howmany(peof, vcb->blockSize); // number of allocation blocks to remain in file
- peof = (SInt64)((SInt64)nextBlock * (SInt64)vcb->blockSize); // number of bytes in those blocks
+ peof = (int64_t)((int64_t)nextBlock * (int64_t)vcb->blockSize); // number of bytes in those blocks
+
+#if CONFIG_HFS_STD
if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= kTwoGigabytes)) {
#if DEBUG_BUILD
- DebugStr("\pHFS: Trying to truncate a file to 2GB or more");
+ DebugStr("HFS: Trying to truncate a file to 2GB or more");
#endif
err = fileBoundsErr;
goto ErrorExit;
}
+#endif
//
// Update FCB's length
* XXX Any errors could cause ff_blocks and c_blocks to get out of sync...
*/
numBlocks = peof / vcb->blockSize;
- FTOC(fcb)->c_blocks -= (fcb->ff_blocks - numBlocks);
+ if (!deleted) {
+ FTOC(fcb)->c_blocks -= (fcb->ff_blocks - numBlocks);
+ }
fcb->ff_blocks = numBlocks;
-
+
// this catalog entry is modified and *must* get forced
// to disk when hfs_update() is called
- FTOC(fcb)->c_flag |= C_MODIFIED | C_FORCEUPDATE;
-
+ if (!deleted) {
+ /*
+ * If the file is already C_NOEXISTS, then the catalog record
+ * has been removed from disk already. We wouldn't need to force
+ * another update
+ */
+ FTOC(fcb)->c_flag |= C_MODIFIED;
+ }
//
// If the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
// all storage).
int i;
// Deallocate all the extents for this fork
- err = DeallocateFork(vcb, FTOC(fcb)->c_fileid, forkType, fcb->fcbExtents, &recordDeleted);
+ err = DeallocateFork(vcb, fileid, forkType, fcb->fcbExtents, &recordDeleted);
if (err != noErr) goto ErrorExit; // got some error, so return it
// Update the catalog extent record (making sure it's zeroed out)
// 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, FTOC(fcb)->c_fileid, nextBlock, &recordDeleted);
+ err = TruncateExtents(vcb, forkType, fileid, nextBlock, &recordDeleted);
Done:
ErrorExit:
* HFS Plus only
*
*/
-__private_extern__
OSErr HeadTruncateFile (
ExtendedVCB *vcb,
FCB *fcb,
- UInt32 headblks)
+ u_int32_t headblks)
{
HFSPlusExtentRecord extents;
HFSPlusExtentRecord tailExtents;
HFSCatalogNodeID fileID;
- UInt8 forkType;
- UInt32 blkcnt;
- UInt32 startblk;
- UInt32 blksfreed;
+ u_int8_t forkType;
+ u_int32_t blkcnt;
+ u_int32_t startblk;
+ u_int32_t blksfreed;
int i, j;
int error = 0;
int lockflags;
break; /* end of extents */
if (blksfreed < headblks) {
- error = BlockDeallocate(vcb, fcb->fcbExtents[i].startBlock, blkcnt);
+ error = BlockDeallocate(vcb, fcb->fcbExtents[i].startBlock, blkcnt, 0);
/*
* Any errors after the first BlockDeallocate
* must be ignored so we can put the file in
goto ErrorExit; /* uh oh */
else {
error = 0;
- printf("HeadTruncateFile: problems deallocating %s (%d)\n",
- FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error);
+ printf("hfs: HeadTruncateFile: problems deallocating %s (%d)\n",
+ FTOC(fcb)->c_desc.cd_nameptr ? (const char *)FTOC(fcb)->c_desc.cd_nameptr : "", error);
}
}
* Process overflow extents
*/
for (;;) {
- UInt32 extblks;
+ u_int32_t extblks;
error = FindExtentRecord(vcb, forkType, fileID, startblk, false, NULL, extents, NULL);
if (error) {
* a known state.
*/
if (error != btNotFound)
- printf("HeadTruncateFile: problems finding extents %s (%d)\n",
- FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error);
+ printf("hfs: HeadTruncateFile: problems finding extents %s (%d)\n",
+ FTOC(fcb)->c_desc.cd_nameptr ? (const char *)FTOC(fcb)->c_desc.cd_nameptr : "", error);
error = 0;
break;
}
break; /* end of extents */
if (blksfreed < headblks) {
- error = BlockDeallocate(vcb, extents[i].startBlock, blkcnt);
+ error = BlockDeallocate(vcb, extents[i].startBlock, blkcnt, 0);
if (error) {
- printf("HeadTruncateFile: problems deallocating %s (%d)\n",
- FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error);
+ printf("hfs: HeadTruncateFile: problems deallocating %s (%d)\n",
+ FTOC(fcb)->c_desc.cd_nameptr ? (const char *)FTOC(fcb)->c_desc.cd_nameptr : "", error);
error = 0;
}
blksfreed += blkcnt;
error = DeleteExtentRecord(vcb, forkType, fileID, startblk);
if (error) {
- printf("HeadTruncateFile: problems deallocating %s (%d)\n",
- FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error);
+ printf("hfs: HeadTruncateFile: problems deallocating %s (%d)\n",
+ FTOC(fcb)->c_desc.cd_nameptr ? (const char *)FTOC(fcb)->c_desc.cd_nameptr : "", error);
error = 0;
}
if (blksfreed) {
bcopy(tailExtents, fcb->fcbExtents, sizeof(tailExtents));
blkcnt = fcb->ff_blocks - headblks;
- FTOC(fcb)->c_blocks -= blkcnt;
+ FTOC(fcb)->c_blocks -= headblks;
fcb->ff_blocks = blkcnt;
- FTOC(fcb)->c_flag |= C_FORCEUPDATE;
+ FTOC(fcb)->c_flag |= C_MODIFIED;
FTOC(fcb)->c_touch_chgtime = TRUE;
(void) FlushExtentFile(vcb);
static OSErr SearchExtentRecord(
ExtendedVCB *vcb,
- UInt32 searchFABN,
+ u_int32_t searchFABN,
const HFSPlusExtentRecord extentData,
- UInt32 extentDataStartFABN,
- UInt32 *foundExtentIndex,
- UInt32 *endingFABNPlusOne,
+ u_int32_t extentDataStartFABN,
+ u_int32_t *foundExtentIndex,
+ u_int32_t *endingFABNPlusOne,
Boolean *noMoreExtents)
{
OSErr err = noErr;
- UInt32 extentIndex;
- UInt32 numberOfExtents;
- UInt32 numAllocationBlocks;
+ u_int32_t extentIndex;
+ /* Set it to the HFS std value */
+ u_int32_t numberOfExtents = kHFSExtentDensity;
+ u_int32_t numAllocationBlocks;
Boolean foundExtent;
*endingFABNPlusOne = extentDataStartFABN;
*noMoreExtents = false;
foundExtent = false;
- if (vcb->vcbSigWord == kHFSPlusSigWord)
+ /* Override numberOfExtents for HFS+/HFSX */
+ if (vcb->vcbSigWord != kHFSSigWord) {
numberOfExtents = kHFSPlusExtentDensity;
- else
- numberOfExtents = kHFSExtentDensity;
+ }
for( extentIndex = 0; extentIndex < numberOfExtents; ++extentIndex )
{
// (other) (some other internal I/O error)
//\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b\8b
-static OSErr SearchExtentFile(
+OSErr SearchExtentFile(
ExtendedVCB *vcb,
const FCB *fcb,
- SInt64 filePosition,
+ int64_t filePosition,
HFSPlusExtentKey *foundExtentKey,
HFSPlusExtentRecord foundExtentData,
- UInt32 *foundExtentIndex,
- UInt32 *extentBTreeHint,
- UInt32 *endingFABNPlusOne )
+ u_int32_t *foundExtentIndex,
+ u_int32_t *extentBTreeHint,
+ u_int32_t *endingFABNPlusOne )
{
OSErr err;
- UInt32 filePositionBlock;
- SInt64 temp64;
+ u_int32_t filePositionBlock;
+ int64_t temp64;
Boolean noMoreExtents;
int lockflags;
- temp64 = filePosition / (SInt64)vcb->blockSize;
- filePositionBlock = (UInt32)temp64;
+ temp64 = filePosition / (int64_t)vcb->blockSize;
+ filePositionBlock = (u_int32_t)temp64;
bcopy ( fcb->fcbExtents, foundExtentData, sizeof(HFSPlusExtentRecord));
//
// 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.
// (other) = error from BTree
//============================================================================
-static OSErr UpdateExtentRecord (
- ExtendedVCB *vcb,
- FCB *fcb,
- const HFSPlusExtentKey *extentFileKey,
- const HFSPlusExtentRecord extentData,
- UInt32 extentBTreeHint)
+static OSErr UpdateExtentRecord (ExtendedVCB *vcb, FCB *fcb, int deleted,
+ const HFSPlusExtentKey *extentFileKey,
+ const HFSPlusExtentRecord extentData,
+ u_int32_t extentBTreeHint)
{
OSErr err = noErr;
if (extentFileKey->keyLength == 0) { // keyLength == 0 means the FCB's extent record
BlockMoveData(extentData, fcb->fcbExtents, sizeof(HFSPlusExtentRecord));
- FTOC(fcb)->c_flag |= C_MODIFIED;
+ if (!deleted) {
+ FTOC(fcb)->c_flag |= C_MODIFIED;
+ }
}
else {
- BTreeIterator * btIterator;
+ struct BTreeIterator *btIterator = NULL;
FSBufferDescriptor btRecord;
- UInt16 btRecordSize;
+ u_int16_t btRecordSize;
FCB * btFCB;
int lockflags;
// Need to find and change a record in Extents BTree
//
btFCB = GetFileControlBlock(vcb->extentsRefNum);
-
- MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+
+ MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+ if (btIterator == NULL) {
+ return memFullErr; // translates to ENOMEM
+ }
bzero(btIterator, sizeof(*btIterator));
/*
*/
lockflags = hfs_systemfile_lock(vcb, SFL_EXTENTS, HFS_EXCLUSIVE_LOCK);
- if (vcb->vcbSigWord == kHFSSigWord) {
+ /* HFS+/HFSX */
+ if (vcb->vcbSigWord != kHFSSigWord) { // HFS Plus volume
+ HFSPlusExtentRecord foundData; // The extent data actually found
+
+ BlockMoveData(extentFileKey, &btIterator->key, sizeof(HFSPlusExtentKey));
+
+ btIterator->hint.index = 0;
+ btIterator->hint.nodeNum = extentBTreeHint;
+
+ btRecord.bufferAddress = &foundData;
+ btRecord.itemSize = sizeof(HFSPlusExtentRecord);
+ btRecord.itemCount = 1;
+
+ err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator);
+
+ if (err == noErr) {
+ BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord));
+ err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
+ }
+ (void) BTFlushPath(btFCB);
+ }
+#if CONFIG_HFS_STD
+ else {
+ /* HFS Standard */
HFSExtentKey * key; // Actual extent key used on disk in HFS
HFSExtentRecord foundData; // The extent data actually found
btRecord.itemCount = 1;
err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator);
-
+
if (err == noErr)
err = HFSPlusToHFSExtents(extentData, (HFSExtentDescriptor *)&foundData);
if (err == noErr)
err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
(void) BTFlushPath(btFCB);
- }
- else { // HFS Plus volume
- HFSPlusExtentRecord foundData; // The extent data actually found
-
- BlockMoveData(extentFileKey, &btIterator->key, sizeof(HFSPlusExtentKey));
- btIterator->hint.index = 0;
- btIterator->hint.nodeNum = extentBTreeHint;
-
- btRecord.bufferAddress = &foundData;
- btRecord.itemSize = sizeof(HFSPlusExtentRecord);
- btRecord.itemCount = 1;
-
- err = BTSearchRecord(btFCB, btIterator, &btRecord, &btRecordSize, btIterator);
-
- if (err == noErr) {
- BlockMoveData(extentData, &foundData, sizeof(HFSPlusExtentRecord));
- err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
- }
- (void) BTFlushPath(btFCB);
}
+#endif
+
hfs_systemfile_unlock(vcb, lockflags);
- FREE(btIterator, M_TEMP);
+
+ FREE(btIterator, M_TEMP);
}
return err;
-
+#if CONFIG_HFS_STD
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
return err;
}
-
+#endif
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;
// Called by BTOpenPath during volume mount
//_________________________________________________________________________________
-__private_extern__
Boolean NodesAreContiguous(
ExtendedVCB *vcb,
FCB *fcb,
- UInt32 nodeSize)
+ u_int32_t nodeSize)
{
- UInt32 mask;
- UInt32 startBlock;
- UInt32 blocksChecked;
- UInt32 hint;
+ u_int32_t mask;
+ u_int32_t startBlock;
+ u_int32_t blocksChecked;
+ u_int32_t hint;
HFSPlusExtentKey key;
HFSPlusExtentRecord extents;
OSErr result;
return FALSE;
if ( lastExtentReached ||
- (SInt64)((SInt64)blocksChecked * (SInt64)vcb->blockSize) >= (SInt64)fcb->ff_size)
+ (int64_t)((int64_t)blocksChecked * (int64_t)vcb->blockSize) >= (int64_t)fcb->ff_size)
return TRUE;
startBlock = blocksChecked;