STDMETHODIMP CCoderMixer2MT::Code(ISequentialInStream **inStreams, const UInt64 ** /* inSizes */, UInt32 numInStreams, ISequentialOutStream **outStreams, const UInt64 ** /* outSizes */, UInt32 numOutStreams, ICompressProgressInfo *progress) { if (numInStreams != (UInt32)_bindInfo.InStreams.Size() || numOutStreams != (UInt32)_bindInfo.OutStreams.Size()) return E_INVALIDARG; Init(inStreams, outStreams); int i; for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) { RINOK(_coders[i].Create()); } for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) _coders[i].Start(); _coders[_progressCoderIndex].Code(progress); for (i = 0; i < _coders.Size(); i++) if (i != _progressCoderIndex) _coders[i].WaitFinish(); RINOK(ReturnIfError(E_ABORT)); RINOK(ReturnIfError(E_OUTOFMEMORY)); for (i = 0; i < _coders.Size(); i++) { HRESULT result = _coders[i].Result; if (result != S_OK && result != E_FAIL && result != S_FALSE) return result; } RINOK(ReturnIfError(S_FALSE)); for (i = 0; i < _coders.Size(); i++) { HRESULT result = _coders[i].Result; if (result != S_OK) return result; } return S_OK; }
/* * 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 LocateCatalogNode(const ExtendedVCB *volume, HFSCatalogNodeID folderID, const CatalogName *name, u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint) { OSErr result; CatalogName *nodeName = NULL; /* To ward off uninitialized use warnings from compiler */ HFSCatalogNodeID threadParentID; result = LocateCatalogRecord(volume, folderID, name, hint, keyPtr, dataPtr, newHint); ReturnIfError(result); // if we got a thread record, then go look up real record switch ( dataPtr->recordType ) { case kHFSFileThreadRecord: case kHFSFolderThreadRecord: threadParentID = dataPtr->hfsThread.parentID; nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName; break; case kHFSPlusFileThreadRecord: case kHFSPlusFolderThreadRecord: threadParentID = dataPtr->hfsPlusThread.parentID; nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName; break; default: threadParentID = 0; break; } if ( threadParentID ) // found a thread result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint); return result; }
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 ); }
OSErr LocateCatalogNodeByKey(const ExtendedVCB *volume, u_int32_t hint, CatalogKey *keyPtr, CatalogRecord *dataPtr, u_int32_t *newHint) { OSErr result; CatalogName *nodeName = NULL; HFSCatalogNodeID threadParentID; u_int16_t tempSize; FSBufferDescriptor btRecord; BTreeIterator searchIterator; FCB *fcb; bzero(&searchIterator, sizeof(searchIterator)); fcb = GetFileControlBlock(volume->catalogRefNum); btRecord.bufferAddress = dataPtr; btRecord.itemCount = 1; btRecord.itemSize = sizeof(CatalogRecord); searchIterator.hint.nodeNum = hint; bcopy(keyPtr, &searchIterator.key, sizeof(CatalogKey)); result = BTSearchRecord( fcb, &searchIterator, &btRecord, &tempSize, &searchIterator ); if (result == noErr) { *newHint = searchIterator.hint.nodeNum; BlockMoveData(&searchIterator.key, keyPtr, sizeof(CatalogKey)); } if (result == btNotFound) result = cmNotFound; ReturnIfError(result); // if we got a thread record, then go look up real record switch ( dataPtr->recordType ) { case kHFSFileThreadRecord: case kHFSFolderThreadRecord: threadParentID = dataPtr->hfsThread.parentID; nodeName = (CatalogName *) &dataPtr->hfsThread.nodeName; break; case kHFSPlusFileThreadRecord: case kHFSPlusFolderThreadRecord: threadParentID = dataPtr->hfsPlusThread.parentID; nodeName = (CatalogName *) &dataPtr->hfsPlusThread.nodeName; break; default: threadParentID = 0; break; } if ( threadParentID ) // found a thread result = LocateCatalogRecord(volume, threadParentID, nodeName, kNoHint, keyPtr, dataPtr, newHint); return result; }