/*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
and was in the extents file, then delete the record instead.
*/
+static const SInt64 kTwoGigabytes = 0x80000000LL;
+
enum
{
- kTwoGigabytes = (UInt32) 0x80000000,
-
kDataForkType = 0,
kResourceForkType = 0xFF,
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,
HFSPlusExtentRecord foundData,
UInt32 *foundHint);
-OSErr DeleteExtentRecord(
+static OSErr DeleteExtentRecord(
const ExtendedVCB *vcb,
UInt8 forkType,
UInt32 fileID,
UInt32 *hint);
-OSErr GetFCBExtentRecord(
+static OSErr GetFCBExtentRecord(
const FCB *fcb,
HFSPlusExtentRecord extents);
// 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 *foundHint)
{
FCB * fcb;
- BTreeIterator btIterator;
+ BTreeIterator *btIterator;
FSBufferDescriptor btRecord;
OSErr err;
UInt16 btRecordSize;
err = noErr;
- *foundHint = 0;
+ if (foundHint)
+ *foundHint = 0;
fcb = GetFileControlBlock(vcb->extentsRefNum);
- (void) BTInvalidateHint(&btIterator);
+ MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+ bzero(btIterator, sizeof(*btIterator));
if (vcb->vcbSigWord == kHFSSigWord) {
HFSExtentKey * extentKeyPtr;
HFSExtentRecord extentData;
- extentKeyPtr = (HFSExtentKey*) &btIterator.key;
+ extentKeyPtr = (HFSExtentKey*) &btIterator->key;
extentKeyPtr->keyLength = kHFSExtentKeyMaximumLength;
extentKeyPtr->forkType = forkType;
extentKeyPtr->fileID = fileID;
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);
+ err = BTIterateRecord(fcb, kBTreePrevRecord, btIterator, &btRecord, &btRecordSize);
// A previous record may not exist, so just return btNotFound (like we would if
// it was for the wrong file/fork).
if (err == 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;
-
- // 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;
HFSPlusExtentKey * extentKeyPtr;
HFSPlusExtentRecord extentData;
- extentKeyPtr = (HFSPlusExtentKey*) &btIterator.key;
+ extentKeyPtr = (HFSPlusExtentKey*) &btIterator->key;
extentKeyPtr->keyLength = kHFSPlusExtentKeyMaximumLength;
extentKeyPtr->forkType = forkType;
extentKeyPtr->pad = 0;
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);
+ err = BTIterateRecord(fcb, kBTreePrevRecord, btIterator, &btRecord, &btRecordSize);
// A previous record may not exist, so just return btNotFound (like we would if
// it was for the wrong file/fork).
}
if (err == 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;
+ FREE(btIterator, M_TEMP);
return err;
}
HFSPlusExtentRecord extents,
UInt32 *hint)
{
- BTreeIterator btIterator;
+ BTreeIterator * btIterator;
FSBufferDescriptor btRecord;
UInt16 btRecordSize;
OSErr err;
err = noErr;
*hint = 0;
- (void) BTInvalidateHint(&btIterator);
+
+ MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+ bzero(btIterator, sizeof(*btIterator));
if (vcb->vcbSigWord == kHFSSigWord) {
HFSExtentKey * keyPtr;
btRecord.itemSize = btRecordSize;
btRecord.itemCount = 1;
- keyPtr = (HFSExtentKey*) &btIterator.key;
+ keyPtr = (HFSExtentKey*) &btIterator->key;
keyPtr->keyLength = kHFSExtentKeyMaximumLength;
keyPtr->forkType = key->forkType;
keyPtr->fileID = key->fileID;
btRecord.itemSize = btRecordSize;
btRecord.itemCount = 1;
- BlockMoveData(key, &btIterator.key, sizeof(HFSPlusExtentKey));
+ BlockMoveData(key, &btIterator->key, sizeof(HFSPlusExtentKey));
}
if (err == noErr)
- err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator, &btRecord, btRecordSize);
+ err = BTInsertRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator, &btRecord, btRecordSize);
if (err == noErr)
- *hint = btIterator.hint.nodeNum;
+ *hint = btIterator->hint.nodeNum;
+ (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
+
+ FREE(btIterator, M_TEMP);
return err;
}
-OSErr DeleteExtentRecord(
+static OSErr DeleteExtentRecord(
const ExtendedVCB *vcb,
UInt8 forkType,
UInt32 fileID,
UInt32 startBlock)
{
- BTreeIterator btIterator;
+ BTreeIterator * btIterator;
OSErr err;
err = noErr;
- (void) BTInvalidateHint(&btIterator);
+
+ MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+ bzero(btIterator, sizeof(*btIterator));
if (vcb->vcbSigWord == kHFSSigWord) {
HFSExtentKey * keyPtr;
- keyPtr = (HFSExtentKey*) &btIterator.key;
+ keyPtr = (HFSExtentKey*) &btIterator->key;
keyPtr->keyLength = kHFSExtentKeyMaximumLength;
keyPtr->forkType = forkType;
keyPtr->fileID = fileID;
else { // HFS Plus volume
HFSPlusExtentKey * keyPtr;
- keyPtr = (HFSPlusExtentKey*) &btIterator.key;
+ keyPtr = (HFSPlusExtentKey*) &btIterator->key;
keyPtr->keyLength = kHFSPlusExtentKeyMaximumLength;
keyPtr->forkType = forkType;
keyPtr->pad = 0;
keyPtr->startBlock = startBlock;
}
- err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), &btIterator);
+ err = BTDeleteRecord(GetFileControlBlock(vcb->extentsRefNum), btIterator);
+ (void) BTFlushPath(GetFileControlBlock(vcb->extentsRefNum));
+ FREE(btIterator, M_TEMP);
return err;
}
// Called By: Log2Phys (read/write in place), Cache (map a file block).
//_________________________________________________________________________________
+__private_extern__
OSErr MapFileBlockC (
ExtendedVCB *vcb, // volume that file resides on
FCB *fcb, // FCB of file
// 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 / 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
//
-
- // offset in sectors from start of the extent
temp = (daddr_t)((offset - (off_t)((off_t)(firstFABN) * (off_t)(allocBlockSize)))/sectorSize);
- // offset in sectors from start of allocation block space
- temp += startBlock * sectorsPerBlock; // offset in sectors from start of allocation block space
+ temp += startBlock * sectorsPerBlock;
+
+ /* Add in any volume offsets */
if (vcb->vcbSigWord == kHFSPlusSigWord)
- temp += vcb->hfsPlusIOPosOffset / sectorSize; /* offset inside wrapper */
+ temp += vcb->hfsPlusIOPosOffset / sectorSize;
else
- temp += vcb->vcbAlBlSt; /* offset in sectors from start of volume */
+ 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;
-
+ if (availableBytes)
+ {
+ tmpOff = dataEnd - offset;
+ if (tmpOff > (off_t)(numberOfBytes))
+ *availableBytes = numberOfBytes; // more there than they asked for, so pin the output
+ else
+ *availableBytes = tmpOff;
+ }
return noErr;
}
// 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 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
+__private_extern__
SInt32 CompareExtentKeys( const HFSExtentKey *searchKey, const HFSExtentKey *trialKey )
{
SInt32 result; // ± 1
// 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
+__private_extern__
SInt32 CompareExtentKeysPlus( const HFSPlusExtentKey *searchKey, const HFSPlusExtentKey *trialKey )
{
SInt32 result; // ± 1
return( result );
}
+/*
+ * 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)
+{
+ HFSPlusExtentKey foundKey;
+ HFSPlusExtentRecord foundData;
+ UInt32 foundIndex;
+ UInt32 hint;
+ UInt32 nextBlock;
+ SInt64 peof;
+ int i;
+ int error;
+
+ peof = (SInt64)(fcb->ff_blocks + blockCount) * (SInt64)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, &foundKey, foundData, hint);
+ }
+ (void) FlushExtentFile(vcb);
+
+ return (error);
+}
//_________________________________________________________________________________
// Note: ExtendFile updates the PEOF in the FCB.
//_________________________________________________________________________________
+__private_extern__
OSErr ExtendFileC (
ExtendedVCB *vcb, // volume that file resides on
FCB *fcb, // FCB of file to truncate
Boolean allOrNothing;
Boolean forceContig;
Boolean wantContig;
+ Boolean useMetaZone;
Boolean needsFlush;
UInt32 actualStartBlock;
UInt32 actualNumBlocks;
UInt32 numExtentsPerRecord;
SInt64 maximumBytes;
SInt64 peof;
- SInt64 previousPEOF;
+ UInt32 prevblocks;
needsFlush = false;
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 ((((SInt64)fcb->ff_blocks * (SInt64)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);
+ blocksToAdd = howmany(bytesToAdd, volumeBlockSize);
bytesToAdd = (SInt64)((SInt64)blocksToAdd * (SInt64)volumeBlockSize);
-
+
+ /*
+ * For deferred allocations just reserve the blocks.
+ */
+ if ((flags & kEFDeferMask)
+ && (vcb->vcbSigWord == kHFSPlusSigWord)
+ && (bytesToAdd < (SInt64)HFS_MAX_DEFERED_ALLOC)
+ && (blocksToAdd < hfs_freeblks(VCBTOHFS(vcb), 1))) {
+ fcb->ff_unallocblocks += blocksToAdd;
+ vcb->loanedBlocks += 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) {
+ blocksToAdd += fcb->ff_unallocblocks;
+ bytesToAdd = (SInt64)blocksToAdd * (SInt64)volumeBlockSize;
+
+ vcb->loanedBlocks -= fcb->ff_unallocblocks;
+ FTOC(fcb)->c_blocks -= fcb->ff_unallocblocks;
+ fcb->ff_blocks -= fcb->ff_unallocblocks;
+ fcb->ff_unallocblocks = 0;
+ }
+
//
// 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 > volumeBlockSize)
+ && (bytesToAdd < (SInt64)HFS_MAX_DEFERED_ALLOC)
+ && (flags & kEFNoClumpMask) == 0) {
+ maximumBytes = (SInt64)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) && ((((SInt64)fcb->ff_blocks * (SInt64)volumeBlockSize) + bytesToAdd) >= kTwoGigabytes)) // Too big?
if (allOrNothing) // Yes, must they have it all?
goto Overflow; // Yes, can't have it
else {
// 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 = ((SInt64)fcb->ff_blocks * (SInt64)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;
+ bytesThisExtent = (SInt64)(nextBlock - fcb->ff_blocks) * (SInt64)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;
}
// else, keep getting bits and pieces (non-contig)
err = noErr;
wantContig = true;
+ 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;
- err = BlockAllocate(vcb, startBlock, bytesToAdd, maximumBytes, wantContig, &actualStartBlock, &actualNumBlocks);
+
+ /* Force reserve checking if requested. */
+ if (flags & kEFReserveMask) {
+ SInt64 availbytes;
+
+ actualNumBlocks = 0;
+ actualStartBlock = 0;
+
+ availbytes = (SInt64)hfs_freeblks(VCBTOHFS(vcb), 1) *
+ (SInt64)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,
+ useMetaZone,
+ &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 (actualNumBlocks != 0)
err = noErr;
+ if (useMetaZone == 0) {
+ /* Couldn't get anything so dip into metadat zone */
+ err = noErr;
+ useMetaZone = 1;
+ continue;
+ }
}
if (err == noErr) {
+ if (actualNumBlocks != 0) {
+ // this catalog entry *must* get forced to disk when
+ // hfs_update() is called
+ FTOC(fcb)->c_flag |= C_FORCEUPDATE;
+ }
+
// Add the new extent to the existing extent record, or create a new one.
if ((actualStartBlock == startBlock) && (blockHint == 0)) {
// We grew the file's last extent, so just adjust the number of blocks.
++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) {
+ if (FTOC(fcb)->c_fileid == kHFSExtentsFileID) {
(void) BlockDeallocate(vcb, actualStartBlock, actualNumBlocks);
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;
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) {
+ vcb->nextAllocation = VCBTOHFS(vcb)->hfs_metazone_end + 1;
+ }
+ }
+ *actualBytesAdded = (SInt64)(fcb->ff_blocks - prevblocks) * (SInt64)volumeBlockSize;
if (needsFlush)
(void) FlushExtentFile(vcb);
// Note: TruncateFile updates the PEOF in the FCB.
//_________________________________________________________________________________
+__private_extern__
OSErr TruncateFileC (
ExtendedVCB *vcb, // volume that file resides on
FCB *fcb, // FCB of file to truncate
else
numExtentsPerRecord = kHFSExtentDensity;
- if (fcb->fcbFlags & fcbResourceMask)
+ if (FORK_IS_RSRC(fcb))
forkType = kResourceForkType;
else
forkType = kDataForkType;
- temp64 = fcb->fcbPLen / (SInt64)vcb->blockSize; // number of allocation blocks currently in file
+ temp64 = fcb->ff_blocks;
physNumBlocks = (UInt32)temp64;
//
// 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
+ 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
- if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= (UInt32) kTwoGigabytes)) {
+ if ((vcb->vcbSigWord == kHFSSigWord) && (peof >= kTwoGigabytes)) {
#if DEBUG_BUILD
DebugStr("\pHFS: Trying to truncate a file to 2GB or more");
#endif
//
// 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;
+ 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 the new PEOF is 0, then truncateToExtent has no meaning (we should always deallocate
int i;
// Deallocate all the extents for this fork
- err = DeallocateFork(vcb, H_FILEID(fcb), forkType, fcb->fcbExtents, &recordDeleted);
+ err = DeallocateFork(vcb, FTOC(fcb)->c_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)
// blocks.
//
if (nextBlock < physNumBlocks)
- err = TruncateExtents(vcb, forkType, H_FILEID(fcb), nextBlock, &recordDeleted);
+ err = TruncateExtents(vcb, forkType, FTOC(fcb)->c_fileid, nextBlock, &recordDeleted);
Done:
ErrorExit:
}
+/*
+ * HFS Plus only
+ *
+ */
+__private_extern__
+OSErr HeadTruncateFile (
+ ExtendedVCB *vcb,
+ FCB *fcb,
+ UInt32 headblks)
+{
+ HFSPlusExtentRecord extents;
+ HFSPlusExtentRecord tailExtents;
+ HFSCatalogNodeID fileID;
+ UInt8 forkType;
+ UInt32 blkcnt;
+ UInt32 startblk;
+ UInt32 blksfreed;
+ int i, j;
+ int error;
+
+
+ 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);
+ /*
+ * 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("HeadTruncateFile: problems deallocating %s (%d)\n",
+ FTOC(fcb)->c_desc.cd_nameptr ? 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;
+
+ /*
+ * Process overflow extents
+ */
+ for (;;) {
+ UInt32 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("HeadTruncateFile: problems finding extents %s (%d)\n",
+ FTOC(fcb)->c_desc.cd_nameptr ? 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);
+ if (error) {
+ printf("HeadTruncateFile: problems deallocating %s (%d)\n",
+ FTOC(fcb)->c_desc.cd_nameptr ? 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("HeadTruncateFile: problems deallocating %s (%d)\n",
+ FTOC(fcb)->c_desc.cd_nameptr ? FTOC(fcb)->c_desc.cd_nameptr : "", error);
+ error = 0;
+ }
+
+ if (blkcnt == 0)
+ break; /* all done */
+
+ startblk += extblks;
+ }
+
+CopyExtents:
+ if (blksfreed) {
+ bcopy(tailExtents, fcb->fcbExtents, sizeof(tailExtents));
+ blkcnt = fcb->ff_blocks - headblks;
+ FTOC(fcb)->c_blocks -= blkcnt;
+ fcb->ff_blocks = blkcnt;
+
+ FTOC(fcb)->c_flag |= C_CHANGE | C_FORCEUPDATE;
+
+ (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)
//
// 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);
+ err = FindExtentRecord(vcb, FORK_IS_RSRC(fcb) ? kResourceForkType : kDataForkType,
+ FTOC(fcb)->c_fileid, filePositionBlock, true, foundExtentKey, foundExtentData, extentBTreeHint);
if (err == btNotFound) {
//
const HFSPlusExtentRecord extentData,
UInt32 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;
+ FTOC(fcb)->c_flag |= C_MODIFIED;
}
else {
+ BTreeIterator * btIterator;
+ FSBufferDescriptor btRecord;
+ UInt16 btRecordSize;
+ FCB * btFCB;
+
//
// Need to find and change a record in Extents BTree
//
btFCB = GetFileControlBlock(vcb->extentsRefNum);
+ MALLOC(btIterator, BTreeIterator *, sizeof(*btIterator), M_TEMP, M_WAITOK);
+ bzero(btIterator, sizeof(*btIterator));
+
if (vcb->vcbSigWord == kHFSSigWord) {
HFSExtentKey * key; // Actual extent key used on disk in HFS
HFSExtentRecord foundData; // The extent data actually found
- key = (HFSExtentKey*) &btIterator.key;
+ key = (HFSExtentKey*) &btIterator->key;
key->keyLength = kHFSExtentKeyMaximumLength;
key->forkType = extentFileKey->forkType;
key->fileID = extentFileKey->fileID;
key->startBlock = extentFileKey->startBlock;
- btIterator.hint.index = 0;
- btIterator.hint.nodeNum = extentBTreeHint;
+ btIterator->hint.index = 0;
+ btIterator->hint.nodeNum = extentBTreeHint;
btRecord.bufferAddress = &foundData;
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);
+ 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));
+ BlockMoveData(extentFileKey, &btIterator->key, sizeof(HFSPlusExtentKey));
- btIterator.hint.index = 0;
- btIterator.hint.nodeNum = extentBTreeHint;
+ btIterator->hint.index = 0;
+ btIterator->hint.nodeNum = extentBTreeHint;
btRecord.bufferAddress = &foundData;
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);
+ err = BTReplaceRecord(btFCB, btIterator, &btRecord, btRecordSize);
}
+ (void) BTFlushPath(btFCB);
}
+ FREE(btIterator, M_TEMP);
}
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)
{
-OSErr GetFCBExtentRecord(
+static OSErr GetFCBExtentRecord(
const FCB *fcb,
HFSPlusExtentRecord extents)
{
// Called by BTOpenPath during volume mount
//_________________________________________________________________________________
+__private_extern__
Boolean NodesAreContiguous(
ExtendedVCB *vcb,
FCB *fcb,
if ( !ExtentsAreIntegral(extents, mask, &blocksChecked, &lastExtentReached) )
return FALSE;
- if (lastExtentReached || (SInt64)((SInt64)blocksChecked * (SInt64)vcb->blockSize) >= fcb->fcbPLen)
+ if (lastExtentReached || (SInt64)((SInt64)blocksChecked * (SInt64)vcb->blockSize) >= fcb->ff_size)
return TRUE;
startBlock = blocksChecked;
// 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) )