2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
24 #include "../../hfs_macos_defs.h"
25 #include "../../hfs_format.h"
27 #include "../headers/FileMgrInternal.h"
28 #include "../headers/HFSUnicodeWrappers.h"
29 #include "../headers/CatalogPrivate.h"
32 struct ExtentsRecBuffer
{
34 ExtentRecord extentData
;
36 typedef struct ExtentsRecBuffer ExtentsRecBuffer
;
39 static UInt32
CheckExtents( void *extents
, UInt32 blocks
, Boolean isHFSPlus
);
40 static OSErr
DeleteExtents( ExtendedVCB
*vcb
, UInt32 fileNumber
, Boolean isHFSPlus
);
41 static OSErr
MoveExtents( ExtendedVCB
*vcb
, UInt32 srcFileID
, UInt32 destFileID
, Boolean isHFSPlus
);
42 static void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
43 static void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
44 static void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, UInt16 bufferCount
);
48 OSErr
ExchangeFileIDs( ExtendedVCB
*vcb
, ConstUTF8Param srcName
, ConstUTF8Param destName
, HFSCatalogNodeID srcID
, HFSCatalogNodeID destID
, UInt32 srcHint
, UInt32 destHint
)
50 CatalogKey srcKey
; // 518 bytes
51 CatalogKey destKey
; // 518 bytes
52 CatalogRecord srcData
; // 520 bytes
53 CatalogRecord destData
; // 520 bytes
54 CatalogRecord swapData
; // 520 bytes
55 SInt16 numSrcExtentBlocks
;
56 SInt16 numDestExtentBlocks
;
58 Boolean isHFSPlus
= ( vcb
->vcbSigWord
== kHFSPlusSigWord
);
60 err
= BuildCatalogKeyUTF8(vcb
, srcID
, srcName
, kUndefinedStrLen
, &srcKey
, NULL
);
63 err
= BuildCatalogKeyUTF8(vcb
, destID
, destName
, kUndefinedStrLen
, &destKey
, NULL
);
68 //-- Step 1: Check the catalog nodes for extents
70 //-- locate the source file, test for extents in extent file, and copy the cat record for later
71 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
74 if ( srcData
.recordType
!= kHFSPlusFileRecord
)
75 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
77 //-- Check if there are any extents in the source file
78 //\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
79 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.dataFork
.extents
, srcData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
80 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
81 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.resourceFork
.extents
, srcData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
83 //-- Check if there are any extents in the destination file
84 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
87 if ( destData
.recordType
!= kHFSPlusFileRecord
)
88 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
90 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.dataFork
.extents
, destData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
91 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
92 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.resourceFork
.extents
, destData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
94 //-- Step 2: Exchange the Extent key in the extent file
96 //-- Exchange the extents key in the extent file
97 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
100 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
102 //-- Change the source extents file ids to our known bogus value
103 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, kHFSBogusExtentFileID
, isHFSPlus
);
106 if ( err
!= dskFulErr
)
112 //-- Change the destination extents file id's to the source id's
113 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
116 if ( err
!= dskFulErr
)
119 ExUndo2aPlus
: err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
120 ReturnIfError( err
); // we are doomed. Just QUIT!
122 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
); // Move the extents back
123 ReturnIfError( err
); // we are doomed. Just QUIT!
128 //-- Change the bogus extents file id's to the dest id's
129 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
132 if ( err
!= dskFulErr
)
135 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
136 ReturnIfError( err
); // we are doomed. Just QUIT!
138 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
); // Move the extents back
139 ReturnIfError( err
); // we are doomed. Just QUIT!
145 else if ( numSrcExtentBlocks
) // just the source file has extents
147 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
150 if ( err
!= dskFulErr
)
153 err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
154 ReturnIfError( err
); // we are doomed. Just QUIT!
159 else if ( numDestExtentBlocks
) // just the destination file has extents
161 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
164 if ( err
!= dskFulErr
)
167 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
168 ReturnIfError( err
); // we are doomed. Just QUIT!
174 //-- Step 3: Change the data in the catalog nodes
176 //-- find the source cnode and put dest info in it
177 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
181 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
182 CopyBigCatalogNodeInfo( &destData
, &srcData
);
184 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSPlusCatalogFile
), &srcHint
);
185 ReturnIfError( err
);
187 // find the destination cnode and put source info in it
188 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
192 CopyBigCatalogNodeInfo( &swapData
, &destData
);
193 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSPlusCatalogFile
), &destHint
);
194 ReturnIfError( err
);
198 //-- Step 1: Check the catalog nodes for extents
200 //-- locate the source file, test for extents in extent file, and copy the cat record for later
201 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
202 ReturnIfError( err
);
204 if ( srcData
.recordType
!= kHFSFileRecord
)
205 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
207 //-- Check if there are any extents in the source file
208 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.dataExtents
, srcData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
209 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
210 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.rsrcExtents
, srcData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
213 //\80\80 Do we save the found source node for later use?
216 //-- Check if there are any extents in the destination file
217 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
218 ReturnIfError( err
);
220 if ( destData
.recordType
!= kHFSFileRecord
)
221 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
223 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.dataExtents
, destData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
224 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
225 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.rsrcExtents
, destData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
227 //\80\80 Do we save the found destination node for later use?
230 //-- Step 2: Exchange the Extent key in the extent file
232 //-- Exchange the extents key in the extent file
233 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
234 ReturnIfError( err
);
236 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
238 //-- Change the source extents file ids to our known bogus value
239 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, kHFSBogusExtentFileID
, isHFSPlus
);
242 if ( err
!= dskFulErr
)
245 ExUndo1a
: err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
246 ReturnIfError( err
); // we are doomed. Just QUIT!
248 err
= FlushCatalog( vcb
); // flush the catalog
249 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
253 //-- Change the destination extents file id's to the source id's
254 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, isHFSPlus
);
257 if ( err
!= dskFulErr
)
260 ExUndo2a
: err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, isHFSPlus
);
261 ReturnIfError( err
); // we are doomed. Just QUIT!
263 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsFile
.fileID
, isHFSPlus
); // Move the extents back
264 ReturnIfError( err
); // we are doomed. Just QUIT!
269 //-- Change the bogus extents file id's to the dest id's
270 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsFile
.fileID
, isHFSPlus
);
273 if ( err
!= dskFulErr
)
276 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, isHFSPlus
);
277 ReturnIfError( err
); // we are doomed. Just QUIT!
279 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, isHFSPlus
); // Move the extents back
280 ReturnIfError( err
); // we are doomed. Just QUIT!
286 else if ( numSrcExtentBlocks
) // just the source file has extents
288 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, isHFSPlus
);
291 if ( err
!= dskFulErr
)
294 err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, isHFSPlus
);
295 ReturnIfError( err
); // we are doomed. Just QUIT!
300 else if ( numDestExtentBlocks
) // just the destination file has extents
302 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, isHFSPlus
);
305 if ( err
!= dskFulErr
)
308 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, isHFSPlus
);
309 ReturnIfError( err
); // we are doomed. Just QUIT!
315 //-- Step 3: Change the data in the catalog nodes
317 //-- find the source cnode and put dest info in it
318 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
322 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
323 //\80\80 Asm source copies from the saved dest catalog node
324 CopyCatalogNodeInfo( &destData
, &srcData
);
326 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSCatalogFile
), &srcHint
);
327 ReturnIfError( err
);
330 // find the destination cnode and put source info in it
331 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
335 CopyCatalogNodeInfo( &swapData
, &destData
);
336 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSCatalogFile
), &destHint
);
337 ReturnIfError( err
);
342 //-- Step 4: Error Handling section
346 err
= FlushCatalog( vcb
); // flush the catalog
347 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
352 static void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
354 dest
->hfsFile
.dataLogicalSize
= src
->hfsFile
.dataLogicalSize
;
355 dest
->hfsFile
.dataPhysicalSize
= src
->hfsFile
.dataPhysicalSize
;
356 dest
->hfsFile
.rsrcLogicalSize
= src
->hfsFile
.rsrcLogicalSize
;
357 dest
->hfsFile
.rsrcPhysicalSize
= src
->hfsFile
.rsrcPhysicalSize
;
358 dest
->hfsFile
.modifyDate
= src
->hfsFile
.modifyDate
;
359 BlockMoveData( src
->hfsFile
.dataExtents
, dest
->hfsFile
.dataExtents
, sizeof(HFSExtentRecord
) );
360 BlockMoveData( src
->hfsFile
.rsrcExtents
, dest
->hfsFile
.rsrcExtents
, sizeof(HFSExtentRecord
) );
363 static void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
365 BlockMoveData( &src
->hfsPlusFile
.dataFork
, &dest
->hfsPlusFile
.dataFork
, sizeof(HFSPlusForkData
) );
366 BlockMoveData( &src
->hfsPlusFile
.resourceFork
, &dest
->hfsPlusFile
.resourceFork
, sizeof(HFSPlusForkData
) );
367 dest
->hfsPlusFile
.contentModDate
= src
->hfsPlusFile
.contentModDate
;
371 static OSErr
MoveExtents( ExtendedVCB
*vcb
, UInt32 srcFileID
, UInt32 destFileID
, Boolean isHFSPlus
)
374 ExtentsRecBuffer extentsBuffer
[kNumExtentsToCache
];
375 ExtentKey
* extentKeyPtr
;
376 ExtentRecord extentData
;
377 BTreeIterator btIterator
;
378 FSBufferDescriptor btRecord
;
385 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
387 (void) BTInvalidateHint(&btIterator
);
388 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
389 btRecord
.bufferAddress
= &extentData
;
390 btRecord
.itemCount
= 1;
392 //-- Collect the extent records
395 // A search on the following key will cause the BTree to be positioned immediately
396 // before the first extent record for file #srcFileID, but not actually positioned
397 // on any record. This is because there cannot be an extent record with FABN = 0
398 // (the first extent of the fork, which would be in the catalog entry, not an extent
401 // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
404 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
405 btKeySize
= sizeof(HFSPlusExtentKey
);
407 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
408 extentKeyPtr
->hfsPlus
.forkType
= 0;
409 extentKeyPtr
->hfsPlus
.pad
= 0;
410 extentKeyPtr
->hfsPlus
.fileID
= srcFileID
;
411 extentKeyPtr
->hfsPlus
.startBlock
= 0;
414 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
415 btKeySize
= sizeof(HFSExtentKey
);
417 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
418 extentKeyPtr
->hfs
.forkType
= 0;
419 extentKeyPtr
->hfs
.fileID
= srcFileID
;
420 extentKeyPtr
->hfs
.startBlock
= 0;
424 // We do an initial BTSearchRecord to position the BTree's iterator just before any extent
425 // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found
426 // records, but with destFileID as the file number in the key. Keep doing this sequence of
427 // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are
428 // no more extent records in the tree.
430 // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID
431 // set to destFileID.
433 // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it
434 // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series
435 // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record
436 // we found, so that BTIterateRecord would get the next one (the first we haven't processed).
439 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
441 // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
442 if (err
!= btNotFound
)
445 DebugStr("\pUnexpected error from SearchBTreeRecord");
447 if (err
== noErr
) // If we found such a bogus extent record, then the tree is really messed up
448 err
= cmBadNews
; // so return an error that conveys the disk is hosed.
455 btRecord
.bufferAddress
= &extentData
;
456 btRecord
.itemCount
= 1;
458 for ( i
=0 ; i
<kNumExtentsToCache
; i
++ )
460 HFSCatalogNodeID foundFileID
;
462 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
463 if ( err
== btNotFound
) // Did we run out of extent records in the extents tree?
464 break; // if xkrFNum(A0) is cleared on this error, then this test is bogus!
465 else if ( err
!= noErr
)
466 return( err
); // must be ioError
468 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
469 if ( foundFileID
== srcFileID
)
471 CopyExtentInfo(extentKeyPtr
, &extentData
, extentsBuffer
, i
);
479 //-- edit each extent key, and reinsert each extent record in the extent file
481 btRecordSize
= sizeof(HFSPlusExtentRecord
);
483 btRecordSize
= sizeof(HFSExtentRecord
);
485 for ( j
=0 ; j
<i
; j
++ )
487 BTreeIterator tmpIterator
;
490 extentsBuffer
[j
].extentKey
.hfsPlus
.fileID
= destFileID
; // change only the id in the key to dest ID
492 extentsBuffer
[j
].extentKey
.hfs
.fileID
= destFileID
; // change only the id in the key to dest ID
494 // get iterator and buffer descriptor ready...
495 (void) BTInvalidateHint(&tmpIterator
);
496 BlockMoveData(&(extentsBuffer
[j
].extentKey
), &tmpIterator
.key
, btKeySize
);
497 btRecord
.bufferAddress
= &(extentsBuffer
[j
].extentData
);
499 err
= BTInsertRecord(fcb
, &tmpIterator
, &btRecord
, btRecordSize
);
502 if ( err
== btExists
)
505 DebugStr("\pCan't insert record -- already exists");
513 //-- okay, done with this buffered batch, go get the next set of extent records
514 // If our buffer is not full, we must be done, or recieved an error
516 if ( i
!= kNumExtentsToCache
) // if the buffer is not full, we must be done
518 err
= DeleteExtents( vcb
, srcFileID
, isHFSPlus
); // Now delete all the extent entries with the sourceID
519 if ( DEBUG_BUILD
&& err
!= noErr
)
520 DebugStr("\pError from DeleteExtents");
521 break; // we're done!
529 static void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, UInt16 bufferCount
)
531 BlockMoveData( key
, &(buffer
[bufferCount
].extentKey
), sizeof( ExtentKey
) );
532 BlockMoveData( data
, &(buffer
[bufferCount
].extentData
), sizeof( ExtentRecord
) );
536 //-- Delete all extents in extent file that have the ID given.
537 static OSErr
DeleteExtents( ExtendedVCB
*vcb
, UInt32 fileID
, Boolean isHFSPlus
)
540 ExtentKey
* extentKeyPtr
;
541 ExtentRecord extentData
;
542 BTreeIterator btIterator
;
543 FSBufferDescriptor btRecord
;
547 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
549 (void) BTInvalidateHint(&btIterator
);
550 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
551 btRecord
.bufferAddress
= &extentData
;
552 btRecord
.itemCount
= 1;
554 // The algorithm is to position the BTree just before any extent records for fileID.
555 // Then just keep getting successive records. If the record is still for fileID,
559 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
561 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
562 extentKeyPtr
->hfsPlus
.forkType
= 0;
563 extentKeyPtr
->hfsPlus
.pad
= 0;
564 extentKeyPtr
->hfsPlus
.fileID
= fileID
;
565 extentKeyPtr
->hfsPlus
.startBlock
= 0;
568 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
570 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
571 extentKeyPtr
->hfs
.forkType
= 0;
572 extentKeyPtr
->hfs
.fileID
= fileID
;
573 extentKeyPtr
->hfs
.startBlock
= 0;
576 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
577 if ( err
!= btNotFound
)
579 if (err
== noErr
) { // Did we find a bogus extent record?
580 err
= cmBadNews
; // Yes, so indicate things are messed up.
583 return err
; // Got some unexpected error, so return it
588 BTreeIterator tmpIterator
;
589 HFSCatalogNodeID foundFileID
;
591 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
594 if (err
== btNotFound
) // If we hit the end of the BTree
595 err
= noErr
; // then it's OK
597 break; // We're done now.
600 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
601 if ( foundFileID
!= fileID
)
602 break; // numbers don't match, we must be done
604 tmpIterator
= btIterator
;
605 err
= BTDeleteRecord( fcb
, &tmpIterator
);
614 // Check if there are extents represented in the extents overflow file.
615 static UInt32
CheckExtents( void *extents
, UInt32 totalBlocks
, Boolean isHFSPlus
)
617 UInt32 extentAllocationBlocks
;
621 if ( totalBlocks
== 0 )
624 extentAllocationBlocks
= 0;
628 for ( i
= 0 ; i
< kHFSPlusExtentDensity
; i
++ )
630 extentAllocationBlocks
+= ((HFSPlusExtentDescriptor
*)extents
)[i
].blockCount
;
631 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
637 for ( i
= 0 ; i
< kHFSExtentDensity
; i
++ )
639 extentAllocationBlocks
+= ((HFSExtentDescriptor
*)extents
)[i
].blockCount
;
640 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
645 return( extentAllocationBlocks
);