/* * This function moves the overflow extents associated with srcID into the file associated with dstID. * We should have already verified that 'srcID' has overflow extents. So now we move all of the overflow * extent records. */ OSErr MoveData( ExtendedVCB *vcb, HFSCatalogNodeID srcID, HFSCatalogNodeID destID, int rsrc) { OSErr err; /* * Only the source file should have extents, so we just track those. * We operate on the fork represented by the open FD that was used to call into this * function */ if (rsrc) { /* Copy the extent overflow blocks. */ err = MoveExtents( vcb, srcID, destID, 1, (u_int8_t)0xff, 1); if ( err != noErr ) { if ( err != dskFulErr ) { return( err ); } /* * In case of error, we would have probably run into problems * growing the extents b-tree. Since the move is actually a copy + delete * just delete the new entries. Same for below. */ err = DeleteExtents( vcb, destID, 1, (u_int8_t)0xff, 1); ReturnIfError( err ); // we are doomed. Just QUIT! goto FlushAndReturn; } } else { /* Copy the extent overflow blocks. */ err = MoveExtents( vcb, srcID, destID, 1, 0, 1); if ( err != noErr ) { if ( err != dskFulErr ) { return( err ); } err = DeleteExtents( vcb, destID, 1, 0, 1); ReturnIfError( err ); // we are doomed. Just QUIT! goto FlushAndReturn; } } FlushAndReturn: /* Write out the catalog and extent overflow B-Tree changes */ err = FlushCatalog( vcb ); err = FlushExtentFile( vcb ); return( err ); }
OSErr ExchangeFileIDs( ExtendedVCB *vcb, ConstUTF8Param srcName, ConstUTF8Param destName, HFSCatalogNodeID srcID, HFSCatalogNodeID destID, u_int32_t srcHint, u_int32_t destHint ) { CatalogKey srcKey; // 518 bytes CatalogKey destKey; // 518 bytes CatalogRecord srcData; // 520 bytes CatalogRecord destData; // 520 bytes CatalogRecord swapData; // 520 bytes int16_t numSrcExtentBlocks; 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 //€€ 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 err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus ); ReturnIfError( err ); 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, isHFSPlus ); if ( err != noErr ) { if ( err != dskFulErr ) return( err ); else goto ExUndo1a; } //-- Change the destination extents file id's to the source id's err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus ); if ( err != noErr ) { if ( err != dskFulErr ) return( err ); ExUndo2aPlus: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus ); ReturnIfError( err ); // we are doomed. Just QUIT! err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back ReturnIfError( err ); // we are doomed. Just QUIT! goto ExUndo1a; } //-- Change the bogus extents file id's to the dest id's err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsPlusFile.fileID, isHFSPlus ); if ( err != noErr ) { if ( err != dskFulErr ) return( err ); err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus ); ReturnIfError( err ); // we are doomed. Just QUIT! err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back ReturnIfError( err ); // we are doomed. Just QUIT! goto ExUndo2aPlus; } } else if ( numSrcExtentBlocks ) // just the source file has extents { err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus ); if ( err != noErr ) { if ( err != dskFulErr ) return( err ); err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus ); ReturnIfError( err ); // we are doomed. Just QUIT! goto FlushAndReturn; } } else if ( numDestExtentBlocks ) // just the destination file has extents { err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus ); if ( err != noErr ) { if ( err != dskFulErr ) return( err ); err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, 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 = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint ); if ( err != noErr ) return( cmBadNews ); BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) ); CopyBigCatalogNodeInfo( &destData, &srcData ); 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 ); } else // HFS // { //-- 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 != 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 numSrcExtentBlocks = CheckExtents( srcData.hfsFile.rsrcExtents, srcData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus ); //€€ 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 ); //€€ 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 err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus ); ReturnIfError( err ); 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, isHFSPlus ); if ( err != noErr ) { if ( err != dskFulErr ) return( err ); ExUndo1a: err = DeleteExtents( vcb, kHFSBogusExtentFileID, 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 ); } //-- Change the destination extents file id's to the source id's err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus ); if ( err != noErr ) { if ( err != dskFulErr ) return( err ); ExUndo2a: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus ); ReturnIfError( err ); // we are doomed. Just QUIT! err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsFile.fileID, isHFSPlus ); // Move the extents back ReturnIfError( err ); // we are doomed. Just QUIT! goto ExUndo1a; } //-- Change the bogus extents file id's to the dest id's err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsFile.fileID, isHFSPlus ); if ( err != noErr ) { if ( err != dskFulErr ) return( err ); err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus ); ReturnIfError( err ); // we are doomed. Just QUIT! err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus ); // Move the extents back ReturnIfError( err ); // we are doomed. Just QUIT! goto ExUndo2a; } } else if ( numSrcExtentBlocks ) // just the source file has extents { err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus ); if ( err != noErr ) { if ( err != dskFulErr ) return( err ); err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus ); ReturnIfError( err ); // we are doomed. Just QUIT! goto FlushAndReturn; } } else if ( numDestExtentBlocks ) // just the destination file has extents { err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus ); if ( err != noErr ) { if ( err != dskFulErr ) return( err ); err = DeleteExtents( vcb, destData.hfsFile.fileID, 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 = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint ); if ( err != noErr ) return( cmBadNews ); BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) ); //€€ Asm source copies from the saved dest catalog node CopyCatalogNodeInfo( &destData, &srcData ); 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) return( err ); }