2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
23 #include "../../hfs_macos_defs.h"
24 #include "../../hfs_format.h"
26 #include "../headers/FileMgrInternal.h"
27 #include "../headers/HFSUnicodeWrappers.h"
28 #include "../headers/CatalogPrivate.h"
31 struct ExtentsRecBuffer
{
33 ExtentRecord extentData
;
35 typedef struct ExtentsRecBuffer ExtentsRecBuffer
;
38 UInt32
CheckExtents( void *extents
, UInt32 blocks
, Boolean isHFSPlus
);
39 OSErr
DeleteExtents( ExtendedVCB
*vcb
, UInt32 fileNumber
, Boolean isHFSPlus
);
40 OSErr
MoveExtents( ExtendedVCB
*vcb
, UInt32 srcFileID
, UInt32 destFileID
, Boolean isHFSPlus
);
41 void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
42 void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
43 void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, UInt16 bufferCount
);
47 OSErr
ExchangeFileIDs( ExtendedVCB
*vcb
, ConstUTF8Param srcName
, ConstUTF8Param destName
, HFSCatalogNodeID srcID
, HFSCatalogNodeID destID
, UInt32 srcHint
, UInt32 destHint
)
49 CatalogKey srcKey
; // 518 bytes
50 CatalogKey destKey
; // 518 bytes
51 CatalogRecord srcData
; // 520 bytes
52 CatalogRecord destData
; // 520 bytes
53 CatalogRecord swapData
; // 520 bytes
54 SInt16 numSrcExtentBlocks
;
55 SInt16 numDestExtentBlocks
;
57 Boolean isHFSPlus
= ( vcb
->vcbSigWord
== kHFSPlusSigWord
);
59 TrashCatalogIterator(vcb
, srcID
); // invalidate any iterators for this parentID
60 TrashCatalogIterator(vcb
, destID
); // invalidate any iterators for this parentID
62 err
= BuildCatalogKeyUTF8(vcb
, srcID
, srcName
, kUndefinedStrLen
, &srcKey
, NULL
);
65 err
= BuildCatalogKeyUTF8(vcb
, destID
, destName
, kUndefinedStrLen
, &destKey
, NULL
);
70 //-- Step 1: Check the catalog nodes for extents
72 //-- locate the source file, test for extents in extent file, and copy the cat record for later
73 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
76 if ( srcData
.recordType
!= kHFSPlusFileRecord
)
77 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
79 //-- Check if there are any extents in the source file
80 //\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
81 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.dataFork
.extents
, srcData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
82 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
83 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.resourceFork
.extents
, srcData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
85 //-- Check if there are any extents in the destination file
86 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
89 if ( destData
.recordType
!= kHFSPlusFileRecord
)
90 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
92 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.dataFork
.extents
, destData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
93 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
94 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.resourceFork
.extents
, destData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
96 //-- Step 2: Exchange the Extent key in the extent file
98 //-- Exchange the extents key in the extent file
99 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
100 ReturnIfError( err
);
102 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
104 //-- Change the source extents file ids to our known bogus value
105 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, kHFSBogusExtentFileID
, isHFSPlus
);
108 if ( err
!= dskFulErr
)
114 //-- Change the destination extents file id's to the source id's
115 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
118 if ( err
!= dskFulErr
)
121 ExUndo2aPlus
: err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
122 ReturnIfError( err
); // we are doomed. Just QUIT!
124 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
); // Move the extents back
125 ReturnIfError( err
); // we are doomed. Just QUIT!
130 //-- Change the bogus extents file id's to the dest id's
131 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
134 if ( err
!= dskFulErr
)
137 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
138 ReturnIfError( err
); // we are doomed. Just QUIT!
140 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
); // Move the extents back
141 ReturnIfError( err
); // we are doomed. Just QUIT!
147 else if ( numSrcExtentBlocks
) // just the source file has extents
149 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
152 if ( err
!= dskFulErr
)
155 err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
156 ReturnIfError( err
); // we are doomed. Just QUIT!
161 else if ( numDestExtentBlocks
) // just the destination file has extents
163 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
166 if ( err
!= dskFulErr
)
169 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
170 ReturnIfError( err
); // we are doomed. Just QUIT!
176 //-- Step 3: Change the data in the catalog nodes
178 //-- find the source cnode and put dest info in it
179 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
183 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
184 CopyBigCatalogNodeInfo( &destData
, &srcData
);
186 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSPlusCatalogFile
), &srcHint
);
187 ReturnIfError( err
);
189 // find the destination cnode and put source info in it
190 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
194 CopyBigCatalogNodeInfo( &swapData
, &destData
);
195 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSPlusCatalogFile
), &destHint
);
196 ReturnIfError( err
);
200 //-- Step 1: Check the catalog nodes for extents
202 //-- locate the source file, test for extents in extent file, and copy the cat record for later
203 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
204 ReturnIfError( err
);
206 if ( srcData
.recordType
!= kHFSFileRecord
)
207 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
209 //-- Check if there are any extents in the source file
210 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.dataExtents
, srcData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
211 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
212 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.rsrcExtents
, srcData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
215 //\80\80 Do we save the found source node for later use?
218 //-- Check if there are any extents in the destination file
219 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
220 ReturnIfError( err
);
222 if ( destData
.recordType
!= kHFSFileRecord
)
223 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
225 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.dataExtents
, destData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
226 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
227 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.rsrcExtents
, destData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
229 //\80\80 Do we save the found destination node for later use?
232 //-- Step 2: Exchange the Extent key in the extent file
234 //-- Exchange the extents key in the extent file
235 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
236 ReturnIfError( err
);
238 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
240 //-- Change the source extents file ids to our known bogus value
241 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, kHFSBogusExtentFileID
, isHFSPlus
);
244 if ( err
!= dskFulErr
)
247 ExUndo1a
: err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
248 ReturnIfError( err
); // we are doomed. Just QUIT!
250 err
= FlushCatalog( vcb
); // flush the catalog
251 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
255 //-- Change the destination extents file id's to the source id's
256 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, isHFSPlus
);
259 if ( err
!= dskFulErr
)
262 ExUndo2a
: err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, isHFSPlus
);
263 ReturnIfError( err
); // we are doomed. Just QUIT!
265 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsFile
.fileID
, isHFSPlus
); // Move the extents back
266 ReturnIfError( err
); // we are doomed. Just QUIT!
271 //-- Change the bogus extents file id's to the dest id's
272 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsFile
.fileID
, isHFSPlus
);
275 if ( err
!= dskFulErr
)
278 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, isHFSPlus
);
279 ReturnIfError( err
); // we are doomed. Just QUIT!
281 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, isHFSPlus
); // Move the extents back
282 ReturnIfError( err
); // we are doomed. Just QUIT!
288 else if ( numSrcExtentBlocks
) // just the source file has extents
290 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, isHFSPlus
);
293 if ( err
!= dskFulErr
)
296 err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, isHFSPlus
);
297 ReturnIfError( err
); // we are doomed. Just QUIT!
302 else if ( numDestExtentBlocks
) // just the destination file has extents
304 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, isHFSPlus
);
307 if ( err
!= dskFulErr
)
310 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, isHFSPlus
);
311 ReturnIfError( err
); // we are doomed. Just QUIT!
317 //-- Step 3: Change the data in the catalog nodes
319 //-- find the source cnode and put dest info in it
320 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
324 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
325 //\80\80 Asm source copies from the saved dest catalog node
326 CopyCatalogNodeInfo( &destData
, &srcData
);
328 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSCatalogFile
), &srcHint
);
329 ReturnIfError( err
);
332 // find the destination cnode and put source info in it
333 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
337 CopyCatalogNodeInfo( &swapData
, &destData
);
338 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSCatalogFile
), &destHint
);
339 ReturnIfError( err
);
344 //-- Step 4: Error Handling section
348 err
= FlushCatalog( vcb
); // flush the catalog
349 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
354 void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
356 dest
->hfsFile
.dataLogicalSize
= src
->hfsFile
.dataLogicalSize
;
357 dest
->hfsFile
.dataPhysicalSize
= src
->hfsFile
.dataPhysicalSize
;
358 dest
->hfsFile
.rsrcLogicalSize
= src
->hfsFile
.rsrcLogicalSize
;
359 dest
->hfsFile
.rsrcPhysicalSize
= src
->hfsFile
.rsrcPhysicalSize
;
360 dest
->hfsFile
.modifyDate
= src
->hfsFile
.modifyDate
;
361 BlockMoveData( src
->hfsFile
.dataExtents
, dest
->hfsFile
.dataExtents
, sizeof(HFSExtentRecord
) );
362 BlockMoveData( src
->hfsFile
.rsrcExtents
, dest
->hfsFile
.rsrcExtents
, sizeof(HFSExtentRecord
) );
365 void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
367 BlockMoveData( &src
->hfsPlusFile
.dataFork
, &dest
->hfsPlusFile
.dataFork
, sizeof(HFSPlusForkData
) );
368 BlockMoveData( &src
->hfsPlusFile
.resourceFork
, &dest
->hfsPlusFile
.resourceFork
, sizeof(HFSPlusForkData
) );
369 dest
->hfsPlusFile
.contentModDate
= src
->hfsPlusFile
.contentModDate
;
373 OSErr
MoveExtents( ExtendedVCB
*vcb
, UInt32 srcFileID
, UInt32 destFileID
, Boolean isHFSPlus
)
376 ExtentsRecBuffer extentsBuffer
[kNumExtentsToCache
];
377 ExtentKey
* extentKeyPtr
;
378 ExtentRecord extentData
;
379 BTreeIterator btIterator
;
380 FSBufferDescriptor btRecord
;
387 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
389 (void) BTInvalidateHint(&btIterator
);
390 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
391 btRecord
.bufferAddress
= &extentData
;
392 btRecord
.itemCount
= 1;
394 //-- Collect the extent records
397 // A search on the following key will cause the BTree to be positioned immediately
398 // before the first extent record for file #srcFileID, but not actually positioned
399 // on any record. This is because there cannot be an extent record with FABN = 0
400 // (the first extent of the fork, which would be in the catalog entry, not an extent
403 // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
406 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
407 btKeySize
= sizeof(HFSPlusExtentKey
);
409 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
410 extentKeyPtr
->hfsPlus
.forkType
= 0;
411 extentKeyPtr
->hfsPlus
.pad
= 0;
412 extentKeyPtr
->hfsPlus
.fileID
= srcFileID
;
413 extentKeyPtr
->hfsPlus
.startBlock
= 0;
416 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
417 btKeySize
= sizeof(HFSExtentKey
);
419 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
420 extentKeyPtr
->hfs
.forkType
= 0;
421 extentKeyPtr
->hfs
.fileID
= srcFileID
;
422 extentKeyPtr
->hfs
.startBlock
= 0;
426 // We do an initial BTSearchRecord to position the BTree's iterator just before any extent
427 // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found
428 // records, but with destFileID as the file number in the key. Keep doing this sequence of
429 // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are
430 // no more extent records in the tree.
432 // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID
433 // set to destFileID.
435 // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it
436 // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series
437 // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record
438 // we found, so that BTIterateRecord would get the next one (the first we haven't processed).
441 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
443 // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
444 if (err
!= btNotFound
)
447 DebugStr("\pUnexpected error from SearchBTreeRecord");
449 if (err
== noErr
) // If we found such a bogus extent record, then the tree is really messed up
450 err
= cmBadNews
; // so return an error that conveys the disk is hosed.
457 btRecord
.bufferAddress
= &extentData
;
458 btRecord
.itemCount
= 1;
460 for ( i
=0 ; i
<kNumExtentsToCache
; i
++ )
462 HFSCatalogNodeID foundFileID
;
464 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
465 if ( err
== btNotFound
) // Did we run out of extent records in the extents tree?
466 break; // if xkrFNum(A0) is cleared on this error, then this test is bogus!
467 else if ( err
!= noErr
)
468 return( err
); // must be ioError
470 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
471 if ( foundFileID
== srcFileID
)
473 CopyExtentInfo(extentKeyPtr
, &extentData
, extentsBuffer
, i
);
481 //-- edit each extent key, and reinsert each extent record in the extent file
483 btRecordSize
= sizeof(HFSPlusExtentRecord
);
485 btRecordSize
= sizeof(HFSExtentRecord
);
487 for ( j
=0 ; j
<i
; j
++ )
489 BTreeIterator tmpIterator
;
492 extentsBuffer
[j
].extentKey
.hfsPlus
.fileID
= destFileID
; // change only the id in the key to dest ID
494 extentsBuffer
[j
].extentKey
.hfs
.fileID
= destFileID
; // change only the id in the key to dest ID
496 // get iterator and buffer descriptor ready...
497 (void) BTInvalidateHint(&tmpIterator
);
498 BlockMoveData(&(extentsBuffer
[j
].extentKey
), &tmpIterator
.key
, btKeySize
);
499 btRecord
.bufferAddress
= &(extentsBuffer
[j
].extentData
);
501 err
= BTInsertRecord(fcb
, &tmpIterator
, &btRecord
, btRecordSize
);
504 if ( err
== btExists
)
507 DebugStr("\pCan't insert record -- already exists");
515 //-- okay, done with this buffered batch, go get the next set of extent records
516 // If our buffer is not full, we must be done, or recieved an error
518 if ( i
!= kNumExtentsToCache
) // if the buffer is not full, we must be done
520 err
= DeleteExtents( vcb
, srcFileID
, isHFSPlus
); // Now delete all the extent entries with the sourceID
521 if ( DEBUG_BUILD
&& err
!= noErr
)
522 DebugStr("\pError from DeleteExtents");
523 break; // we're done!
531 void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, UInt16 bufferCount
)
533 BlockMoveData( key
, &(buffer
[bufferCount
].extentKey
), sizeof( ExtentKey
) );
534 BlockMoveData( data
, &(buffer
[bufferCount
].extentData
), sizeof( ExtentRecord
) );
538 //-- Delete all extents in extent file that have the ID given.
539 OSErr
DeleteExtents( ExtendedVCB
*vcb
, UInt32 fileID
, Boolean isHFSPlus
)
542 ExtentKey
* extentKeyPtr
;
543 ExtentRecord extentData
;
544 BTreeIterator btIterator
;
545 FSBufferDescriptor btRecord
;
549 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
551 (void) BTInvalidateHint(&btIterator
);
552 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
553 btRecord
.bufferAddress
= &extentData
;
554 btRecord
.itemCount
= 1;
556 // The algorithm is to position the BTree just before any extent records for fileID.
557 // Then just keep getting successive records. If the record is still for fileID,
561 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
563 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
564 extentKeyPtr
->hfsPlus
.forkType
= 0;
565 extentKeyPtr
->hfsPlus
.pad
= 0;
566 extentKeyPtr
->hfsPlus
.fileID
= fileID
;
567 extentKeyPtr
->hfsPlus
.startBlock
= 0;
570 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
572 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
573 extentKeyPtr
->hfs
.forkType
= 0;
574 extentKeyPtr
->hfs
.fileID
= fileID
;
575 extentKeyPtr
->hfs
.startBlock
= 0;
578 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
579 if ( err
!= btNotFound
)
581 if (err
== noErr
) { // Did we find a bogus extent record?
582 err
= cmBadNews
; // Yes, so indicate things are messed up.
585 return err
; // Got some unexpected error, so return it
590 BTreeIterator tmpIterator
;
591 HFSCatalogNodeID foundFileID
;
593 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
596 if (err
== btNotFound
) // If we hit the end of the BTree
597 err
= noErr
; // then it's OK
599 break; // We're done now.
602 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
603 if ( foundFileID
!= fileID
)
604 break; // numbers don't match, we must be done
606 tmpIterator
= btIterator
;
607 err
= BTDeleteRecord( fcb
, &tmpIterator
);
616 // Check if there are extents represented in the extents overflow file.
617 UInt32
CheckExtents( void *extents
, UInt32 totalBlocks
, Boolean isHFSPlus
)
619 UInt32 extentAllocationBlocks
;
623 if ( totalBlocks
== 0 )
626 extentAllocationBlocks
= 0;
630 for ( i
= 0 ; i
< kHFSPlusExtentDensity
; i
++ )
632 extentAllocationBlocks
+= ((HFSPlusExtentDescriptor
*)extents
)[i
].blockCount
;
633 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
639 for ( i
= 0 ; i
< kHFSExtentDensity
; i
++ )
641 extentAllocationBlocks
+= ((HFSExtentDescriptor
*)extents
)[i
].blockCount
;
642 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
647 return( extentAllocationBlocks
);