#include "../headers/FileMgrInternal.h"
#include "../headers/HFSUnicodeWrappers.h"
#include "../headers/CatalogPrivate.h"
+#include <sys/kernel.h>
+#include <sys/malloc.h>
+#include <libkern/libkern.h>
struct ExtentsRecBuffer {
int16_t numDestExtentBlocks;
OSErr err;
Boolean isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord );
-
+
err = BuildCatalogKeyUTF8(vcb, srcID, srcName, kUndefinedStrLen, &srcKey, NULL);
ReturnIfError(err);
-
+
err = BuildCatalogKeyUTF8(vcb, destID, destName, kUndefinedStrLen, &destKey, NULL);
ReturnIfError(err);
-
+
if ( isHFSPlus )
{
//-- Step 1: Check the catalog nodes for extents
//-- locate the source file, test for extents in extent file, and copy the cat record for later
err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
ReturnIfError( err );
-
+
if ( srcData.recordType != kHFSPlusFileRecord )
return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
-
+
//-- Check if there are any extents in the source file
//\80\80 I am only checling the extents in the low 32 bits, routine will fail if files extents after 2 gig are in overflow
numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.dataFork.extents, srcData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus );
if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents
numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.resourceFork.extents, srcData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus );
-
+
//-- Check if there are any extents in the destination file
err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
ReturnIfError( err );
-
+
if ( destData.recordType != kHFSPlusFileRecord )
return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
-
+
numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.dataFork.extents, destData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus );
if ( numDestExtentBlocks == 0 ) // then check the resource fork extents
numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.resourceFork.extents, destData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus );
-
+
//-- Step 2: Exchange the Extent key in the extent file
//-- Exchange the extents key in the extent file
if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents
{
//-- Change the source extents file ids to our known bogus value
- err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, kHFSBogusExtentFileID, 0, 0, isHFSPlus );
+ err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, kHFSBogusExtentFileID, 0,0, isHFSPlus );
if ( err != noErr )
{
if ( err != dskFulErr )
{
if ( err != dskFulErr )
return( err );
-
- ExUndo2aPlus: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, 0, 0, isHFSPlus );
+
+ExUndo2aPlus: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, 0, 0, isHFSPlus );
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsPlusFile.fileID, 0, 0, isHFSPlus ); // Move the extents back
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
goto ExUndo1a;
}
{
if ( err != dskFulErr )
return( err );
-
+
err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, 0, 0, isHFSPlus );
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, 0, 0, isHFSPlus ); // Move the extents back
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
goto ExUndo2aPlus;
}
{
if ( err != dskFulErr )
return( err );
-
+
err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, 0, 0, isHFSPlus );
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
goto FlushAndReturn;
}
}
{
if ( err != dskFulErr )
return( err );
-
+
err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, 0, 0, isHFSPlus );
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
goto FlushAndReturn;
}
}
-
+
//-- Step 3: Change the data in the catalog nodes
//-- find the source cnode and put dest info in it
err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSPlusCatalogFile), &srcHint );
ReturnIfError( err );
-
+
// find the destination cnode and put source info in it
err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
if ( err != noErr )
return( cmBadNews );
-
+
CopyBigCatalogNodeInfo( &swapData, &destData );
err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSPlusCatalogFile), &destHint );
ReturnIfError( err );
//-- locate the source file, test for extents in extent file, and copy the cat record for later
err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
ReturnIfError( err );
-
+
if ( srcData.recordType != kHFSFileRecord )
return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
-
+
//-- Check if there are any extents in the source file
numSrcExtentBlocks = CheckExtents( srcData.hfsFile.dataExtents, srcData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus );
if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents
//\80\80 Do we save the found source node for later use?
-
+
//-- Check if there are any extents in the destination file
err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
ReturnIfError( err );
-
+
if ( destData.recordType != kHFSFileRecord )
return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
-
+
numDestExtentBlocks = CheckExtents( destData.hfsFile.dataExtents, destData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus );
if ( numDestExtentBlocks == 0 ) // then check the resource fork extents
numDestExtentBlocks = CheckExtents( destData.hfsFile.rsrcExtents, destData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus );
-
+
//\80\80 Do we save the found destination node for later use?
-
-
+
+
//-- Step 2: Exchange the Extent key in the extent file
//-- Exchange the extents key in the extent file
if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents
{
//-- Change the source extents file ids to our known bogus value
- err = MoveExtents( vcb, srcData.hfsFile.fileID, kHFSBogusExtentFileID, 0, 0, isHFSPlus );
+ err = MoveExtents( vcb, srcData.hfsFile.fileID, kHFSBogusExtentFileID, 0, 0, isHFSPlus );
if ( err != noErr )
{
if ( err != dskFulErr )
return( err );
-
- ExUndo1a: err = DeleteExtents( vcb, kHFSBogusExtentFileID, 0, 0, isHFSPlus );
+
+ExUndo1a: err = DeleteExtents( vcb, kHFSBogusExtentFileID, 0, 0, isHFSPlus );
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
err = FlushCatalog( vcb ); // flush the catalog
err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap)
return( dskFulErr );
{
if ( err != dskFulErr )
return( err );
-
- ExUndo2a: err = DeleteExtents( vcb, srcData.hfsFile.fileID, 0, 0, isHFSPlus );
+
+ExUndo2a: err = DeleteExtents( vcb, srcData.hfsFile.fileID, 0, 0, isHFSPlus );
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsFile.fileID, 0, 0, isHFSPlus ); // Move the extents back
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
goto ExUndo1a;
}
{
if ( err != dskFulErr )
return( err );
-
+
err = DeleteExtents( vcb, destData.hfsFile.fileID, 0, 0, isHFSPlus );
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, 0, 0, isHFSPlus ); // Move the extents back
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
goto ExUndo2a;
}
{
if ( err != dskFulErr )
return( err );
-
+
err = DeleteExtents( vcb, srcData.hfsFile.fileID, 0, 0, isHFSPlus );
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
goto FlushAndReturn;
}
}
{
if ( err != dskFulErr )
return( err );
-
+
err = DeleteExtents( vcb, destData.hfsFile.fileID, 0, 0, isHFSPlus );
ReturnIfError( err ); // we are doomed. Just QUIT!
-
+
goto FlushAndReturn;
}
}
-
+
//-- Step 3: Change the data in the catalog nodes
//-- find the source cnode and put dest info in it
err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSCatalogFile), &srcHint );
ReturnIfError( err );
-
+
// find the destination cnode and put source info in it
err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
if ( err != noErr )
return( cmBadNews );
-
+
CopyCatalogNodeInfo( &swapData, &destData );
err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSCatalogFile), &destHint );
ReturnIfError( err );
}
err = noErr;
-
+
//-- Step 4: Error Handling section
-
-
+
+
FlushAndReturn:
err = FlushCatalog( vcb ); // flush the catalog
err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap)
ExtentsRecBuffer extentsBuffer[kNumExtentsToCache];
ExtentKey * extentKeyPtr;
ExtentRecord extentData;
- BTreeIterator btIterator;
+ struct BTreeIterator *btIterator = NULL;
+ struct BTreeIterator *tmpIterator = NULL;
FSBufferDescriptor btRecord;
u_int16_t btKeySize;
u_int16_t btRecordSize;
int16_t i, j;
OSErr err;
-
+ MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+ if (btIterator == NULL) {
+ return memFullErr; // translates to ENOMEM
+ }
+
+
+ MALLOC (tmpIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+ if (tmpIterator == NULL) {
+ FREE (btIterator, M_TEMP);
+ return memFullErr; // translates to ENOMEM
+ }
+
+ bzero(btIterator, sizeof(*btIterator));
+ bzero (tmpIterator, sizeof(*tmpIterator));
+
+
fcb = GetFileControlBlock(vcb->extentsRefNum);
- (void) BTInvalidateHint(&btIterator);
- extentKeyPtr = (ExtentKey*) &btIterator.key;
+ (void) BTInvalidateHint(btIterator);
+ extentKeyPtr = (ExtentKey*) &btIterator->key;
btRecord.bufferAddress = &extentData;
btRecord.itemCount = 1;
-
+
//-- Collect the extent records
-
+
//
// A search on the following key will cause the BTree to be positioned immediately
// before the first extent record for file #srcFileID, but not actually positioned
if (isHFSPlus) {
btRecord.itemSize = sizeof(HFSPlusExtentRecord);
btKeySize = sizeof(HFSPlusExtentKey);
-
+
extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength;
extentKeyPtr->hfsPlus.forkType = forkType;
extentKeyPtr->hfsPlus.pad = 0;
else {
btRecord.itemSize = sizeof(HFSExtentRecord);
btKeySize = sizeof(HFSExtentKey);
-
+
extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength;
extentKeyPtr->hfs.forkType = 0;
extentKeyPtr->hfs.fileID = srcFileID;
// of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record
// we found, so that BTIterateRecord would get the next one (the first we haven't processed).
//
-
- err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator);
+
+ err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator);
// We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
if (err != btNotFound)
if (err == noErr) // If we found such a bogus extent record, then the tree is really messed up
err = cmBadNews; // so return an error that conveys the disk is hosed.
+ FREE (tmpIterator, M_TEMP);
+ FREE (btIterator, M_TEMP);
return err;
}
-
+
do
{
btRecord.bufferAddress = &extentData;
btRecord.itemCount = 1;
-
+
for ( i=0 ; i<kNumExtentsToCache ; i++ )
{
HFSCatalogNodeID foundFileID;
- err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
+ err = BTIterateRecord(fcb, kBTreeNextRecord, btIterator, &btRecord, &btRecordSize);
if ( err == btNotFound ) // Did we run out of extent records in the extents tree?
break; // if xkrFNum(A0) is cleared on this error, then this test is bogus!
- else if ( err != noErr )
+ else if ( err != noErr ) {
+ FREE (btIterator, M_TEMP);
+ FREE (tmpIterator, M_TEMP);
return( err ); // must be ioError
-
+ }
foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
if ( foundFileID == srcFileID ) {
/* Check if we need to quit early. */
}
}
+
+
//-- edit each extent key, and reinsert each extent record in the extent file
if (isHFSPlus)
btRecordSize = sizeof(HFSPlusExtentRecord);
else
btRecordSize = sizeof(HFSExtentRecord);
-
- for ( j=0 ; j<i ; j++ ) {
- BTreeIterator tmpIterator;
-
+
+ for ( j=0 ; j<i ; j++ )
+ {
+
if (isHFSPlus)
extentsBuffer[j].extentKey.hfsPlus.fileID = destFileID; // change only the id in the key to dest ID
else
extentsBuffer[j].extentKey.hfs.fileID = destFileID; // change only the id in the key to dest ID
-
+
// get iterator and buffer descriptor ready...
- (void) BTInvalidateHint(&tmpIterator);
- BlockMoveData(&(extentsBuffer[j].extentKey), &tmpIterator.key, btKeySize);
+ (void) BTInvalidateHint(tmpIterator);
+ BlockMoveData(&(extentsBuffer[j].extentKey), &tmpIterator->key, btKeySize);
btRecord.bufferAddress = &(extentsBuffer[j].extentData);
-
- err = BTInsertRecord(fcb, &tmpIterator, &btRecord, btRecordSize);
- if ( err != noErr )
- { // parse the error
+
+ err = BTInsertRecord(fcb, tmpIterator, &btRecord, btRecordSize);
+ if ( err != noErr ) {
+ /* Parse the error and free iterators */
+ FREE (btIterator, M_TEMP);
+ FREE (tmpIterator, M_TEMP);
if ( err == btExists )
{
- if ( DEBUG_BUILD )
- DebugStr("Can't insert record -- already exists");
+ if ( DEBUG_BUILD ) {
+ DebugStr("Can't insert record -- already exists");
+ }
return( cmBadNews );
}
- else
+ else {
return( err );
+ }
}
}
-
+
//-- okay, done with this buffered batch, go get the next set of extent records
// If our buffer is not full, we must be done, or recieved an error
}
} while ( true );
+ FREE (tmpIterator, M_TEMP);
+ FREE (btIterator, M_TEMP);
+
return( err );
}
}
-
-
//-- Delete all extents in extent file that have the ID given.
static OSErr DeleteExtents( ExtendedVCB *vcb, u_int32_t fileID, int quitEarly, u_int8_t forkType, Boolean isHFSPlus )
{
FCB * fcb;
ExtentKey * extentKeyPtr;
ExtentRecord extentData;
- BTreeIterator btIterator;
+ struct BTreeIterator *btIterator = NULL;
+ struct BTreeIterator *tmpIterator = NULL;
FSBufferDescriptor btRecord;
u_int16_t btRecordSize;
OSErr err;
-
+
+
+ MALLOC (btIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+ if (btIterator == NULL) {
+ return memFullErr; // translates to ENOMEM
+ }
+
+ MALLOC (tmpIterator, struct BTreeIterator*, sizeof(struct BTreeIterator), M_TEMP, M_WAITOK);
+ if (tmpIterator == NULL) {
+ FREE (btIterator, M_TEMP);
+ return memFullErr; // translates to ENOMEM
+ }
+
+ bzero(btIterator, sizeof(*btIterator));
+ bzero (tmpIterator, sizeof(*tmpIterator));
+
fcb = GetFileControlBlock(vcb->extentsRefNum);
-
- (void) BTInvalidateHint(&btIterator);
- extentKeyPtr = (ExtentKey*) &btIterator.key;
+
+ (void) BTInvalidateHint(btIterator);
+ extentKeyPtr = (ExtentKey*) &btIterator->key;
btRecord.bufferAddress = &extentData;
btRecord.itemCount = 1;
-
+
// The algorithm is to position the BTree just before any extent records for fileID.
// Then just keep getting successive records. If the record is still for fileID,
// then delete it.
if (isHFSPlus) {
btRecord.itemSize = sizeof(HFSPlusExtentRecord);
-
+
extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength;
extentKeyPtr->hfsPlus.forkType = forkType;
extentKeyPtr->hfsPlus.pad = 0;
}
else {
btRecord.itemSize = sizeof(HFSExtentRecord);
-
+
extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength;
extentKeyPtr->hfs.forkType = forkType;
extentKeyPtr->hfs.fileID = fileID;
extentKeyPtr->hfs.startBlock = 0;
}
-
- err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator);
+
+ err = BTSearchRecord(fcb, btIterator, &btRecord, &btRecordSize, btIterator);
if ( err != btNotFound )
{
if (err == noErr) { // Did we find a bogus extent record?
return err; // Got some unexpected error, so return it
}
-
+
do
{
- BTreeIterator tmpIterator;
HFSCatalogNodeID foundFileID;
-
- err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
+
+ err = BTIterateRecord(fcb, kBTreeNextRecord, btIterator, &btRecord, &btRecordSize);
if ( err != noErr )
{
if (err == btNotFound) // If we hit the end of the BTree
err = noErr; // then it's OK
-
+
break; // We're done now.
}
}
}
- tmpIterator = btIterator;
- err = BTDeleteRecord( fcb, &tmpIterator );
+ *tmpIterator = *btIterator;
+ err = BTDeleteRecord( fcb, tmpIterator );
if (err != noErr)
break;
} while ( true );
+ FREE (tmpIterator, M_TEMP);
+ FREE (btIterator, M_TEMP);
+
return( err );
}