2 * Copyright (c) 2000-2004 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 static UInt32
CheckExtents( void *extents
, UInt32 blocks
, Boolean isHFSPlus
);
39 static OSErr
DeleteExtents( ExtendedVCB
*vcb
, UInt32 fileNumber
, Boolean isHFSPlus
);
40 static OSErr
MoveExtents( ExtendedVCB
*vcb
, UInt32 srcFileID
, UInt32 destFileID
, Boolean isHFSPlus
);
41 static void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
42 static void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
43 static 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 err
= BuildCatalogKeyUTF8(vcb
, srcID
, srcName
, kUndefinedStrLen
, &srcKey
, NULL
);
62 err
= BuildCatalogKeyUTF8(vcb
, destID
, destName
, kUndefinedStrLen
, &destKey
, NULL
);
67 //-- Step 1: Check the catalog nodes for extents
69 //-- locate the source file, test for extents in extent file, and copy the cat record for later
70 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
73 if ( srcData
.recordType
!= kHFSPlusFileRecord
)
74 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
76 //-- Check if there are any extents in the source file
77 //\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
78 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.dataFork
.extents
, srcData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
79 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
80 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.resourceFork
.extents
, srcData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
82 //-- Check if there are any extents in the destination file
83 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
86 if ( destData
.recordType
!= kHFSPlusFileRecord
)
87 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
89 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.dataFork
.extents
, destData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
90 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
91 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.resourceFork
.extents
, destData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
93 //-- Step 2: Exchange the Extent key in the extent file
95 //-- Exchange the extents key in the extent file
96 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
99 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
101 //-- Change the source extents file ids to our known bogus value
102 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, kHFSBogusExtentFileID
, isHFSPlus
);
105 if ( err
!= dskFulErr
)
111 //-- Change the destination extents file id's to the source id's
112 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
115 if ( err
!= dskFulErr
)
118 ExUndo2aPlus
: err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
119 ReturnIfError( err
); // we are doomed. Just QUIT!
121 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
); // Move the extents back
122 ReturnIfError( err
); // we are doomed. Just QUIT!
127 //-- Change the bogus extents file id's to the dest id's
128 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
131 if ( err
!= dskFulErr
)
134 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
135 ReturnIfError( err
); // we are doomed. Just QUIT!
137 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
); // Move the extents back
138 ReturnIfError( err
); // we are doomed. Just QUIT!
144 else if ( numSrcExtentBlocks
) // just the source file has extents
146 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
149 if ( err
!= dskFulErr
)
152 err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
153 ReturnIfError( err
); // we are doomed. Just QUIT!
158 else if ( numDestExtentBlocks
) // just the destination file has extents
160 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
163 if ( err
!= dskFulErr
)
166 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
167 ReturnIfError( err
); // we are doomed. Just QUIT!
173 //-- Step 3: Change the data in the catalog nodes
175 //-- find the source cnode and put dest info in it
176 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
180 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
181 CopyBigCatalogNodeInfo( &destData
, &srcData
);
183 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSPlusCatalogFile
), &srcHint
);
184 ReturnIfError( err
);
186 // find the destination cnode and put source info in it
187 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
191 CopyBigCatalogNodeInfo( &swapData
, &destData
);
192 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSPlusCatalogFile
), &destHint
);
193 ReturnIfError( err
);
197 //-- Step 1: Check the catalog nodes for extents
199 //-- locate the source file, test for extents in extent file, and copy the cat record for later
200 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
201 ReturnIfError( err
);
203 if ( srcData
.recordType
!= kHFSFileRecord
)
204 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
206 //-- Check if there are any extents in the source file
207 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.dataExtents
, srcData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
208 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
209 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.rsrcExtents
, srcData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
212 //\80\80 Do we save the found source node for later use?
215 //-- Check if there are any extents in the destination file
216 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
217 ReturnIfError( err
);
219 if ( destData
.recordType
!= kHFSFileRecord
)
220 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
222 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.dataExtents
, destData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
223 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
224 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.rsrcExtents
, destData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
226 //\80\80 Do we save the found destination node for later use?
229 //-- Step 2: Exchange the Extent key in the extent file
231 //-- Exchange the extents key in the extent file
232 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
233 ReturnIfError( err
);
235 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
237 //-- Change the source extents file ids to our known bogus value
238 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, kHFSBogusExtentFileID
, isHFSPlus
);
241 if ( err
!= dskFulErr
)
244 ExUndo1a
: err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
245 ReturnIfError( err
); // we are doomed. Just QUIT!
247 err
= FlushCatalog( vcb
); // flush the catalog
248 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
252 //-- Change the destination extents file id's to the source id's
253 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, isHFSPlus
);
256 if ( err
!= dskFulErr
)
259 ExUndo2a
: err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, isHFSPlus
);
260 ReturnIfError( err
); // we are doomed. Just QUIT!
262 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsFile
.fileID
, isHFSPlus
); // Move the extents back
263 ReturnIfError( err
); // we are doomed. Just QUIT!
268 //-- Change the bogus extents file id's to the dest id's
269 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsFile
.fileID
, isHFSPlus
);
272 if ( err
!= dskFulErr
)
275 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, isHFSPlus
);
276 ReturnIfError( err
); // we are doomed. Just QUIT!
278 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, isHFSPlus
); // Move the extents back
279 ReturnIfError( err
); // we are doomed. Just QUIT!
285 else if ( numSrcExtentBlocks
) // just the source file has extents
287 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, isHFSPlus
);
290 if ( err
!= dskFulErr
)
293 err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, isHFSPlus
);
294 ReturnIfError( err
); // we are doomed. Just QUIT!
299 else if ( numDestExtentBlocks
) // just the destination file has extents
301 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, isHFSPlus
);
304 if ( err
!= dskFulErr
)
307 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, isHFSPlus
);
308 ReturnIfError( err
); // we are doomed. Just QUIT!
314 //-- Step 3: Change the data in the catalog nodes
316 //-- find the source cnode and put dest info in it
317 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
321 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
322 //\80\80 Asm source copies from the saved dest catalog node
323 CopyCatalogNodeInfo( &destData
, &srcData
);
325 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSCatalogFile
), &srcHint
);
326 ReturnIfError( err
);
329 // find the destination cnode and put source info in it
330 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
334 CopyCatalogNodeInfo( &swapData
, &destData
);
335 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSCatalogFile
), &destHint
);
336 ReturnIfError( err
);
341 //-- Step 4: Error Handling section
345 err
= FlushCatalog( vcb
); // flush the catalog
346 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
351 static void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
353 dest
->hfsFile
.dataLogicalSize
= src
->hfsFile
.dataLogicalSize
;
354 dest
->hfsFile
.dataPhysicalSize
= src
->hfsFile
.dataPhysicalSize
;
355 dest
->hfsFile
.rsrcLogicalSize
= src
->hfsFile
.rsrcLogicalSize
;
356 dest
->hfsFile
.rsrcPhysicalSize
= src
->hfsFile
.rsrcPhysicalSize
;
357 dest
->hfsFile
.modifyDate
= src
->hfsFile
.modifyDate
;
358 BlockMoveData( src
->hfsFile
.dataExtents
, dest
->hfsFile
.dataExtents
, sizeof(HFSExtentRecord
) );
359 BlockMoveData( src
->hfsFile
.rsrcExtents
, dest
->hfsFile
.rsrcExtents
, sizeof(HFSExtentRecord
) );
362 static void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
364 BlockMoveData( &src
->hfsPlusFile
.dataFork
, &dest
->hfsPlusFile
.dataFork
, sizeof(HFSPlusForkData
) );
365 BlockMoveData( &src
->hfsPlusFile
.resourceFork
, &dest
->hfsPlusFile
.resourceFork
, sizeof(HFSPlusForkData
) );
366 dest
->hfsPlusFile
.contentModDate
= src
->hfsPlusFile
.contentModDate
;
370 static OSErr
MoveExtents( ExtendedVCB
*vcb
, UInt32 srcFileID
, UInt32 destFileID
, Boolean isHFSPlus
)
373 ExtentsRecBuffer extentsBuffer
[kNumExtentsToCache
];
374 ExtentKey
* extentKeyPtr
;
375 ExtentRecord extentData
;
376 BTreeIterator btIterator
;
377 FSBufferDescriptor btRecord
;
384 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
386 (void) BTInvalidateHint(&btIterator
);
387 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
388 btRecord
.bufferAddress
= &extentData
;
389 btRecord
.itemCount
= 1;
391 //-- Collect the extent records
394 // A search on the following key will cause the BTree to be positioned immediately
395 // before the first extent record for file #srcFileID, but not actually positioned
396 // on any record. This is because there cannot be an extent record with FABN = 0
397 // (the first extent of the fork, which would be in the catalog entry, not an extent
400 // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
403 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
404 btKeySize
= sizeof(HFSPlusExtentKey
);
406 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
407 extentKeyPtr
->hfsPlus
.forkType
= 0;
408 extentKeyPtr
->hfsPlus
.pad
= 0;
409 extentKeyPtr
->hfsPlus
.fileID
= srcFileID
;
410 extentKeyPtr
->hfsPlus
.startBlock
= 0;
413 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
414 btKeySize
= sizeof(HFSExtentKey
);
416 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
417 extentKeyPtr
->hfs
.forkType
= 0;
418 extentKeyPtr
->hfs
.fileID
= srcFileID
;
419 extentKeyPtr
->hfs
.startBlock
= 0;
423 // We do an initial BTSearchRecord to position the BTree's iterator just before any extent
424 // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found
425 // records, but with destFileID as the file number in the key. Keep doing this sequence of
426 // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are
427 // no more extent records in the tree.
429 // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID
430 // set to destFileID.
432 // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it
433 // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series
434 // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record
435 // we found, so that BTIterateRecord would get the next one (the first we haven't processed).
438 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
440 // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
441 if (err
!= btNotFound
)
444 DebugStr("\pUnexpected error from SearchBTreeRecord");
446 if (err
== noErr
) // If we found such a bogus extent record, then the tree is really messed up
447 err
= cmBadNews
; // so return an error that conveys the disk is hosed.
454 btRecord
.bufferAddress
= &extentData
;
455 btRecord
.itemCount
= 1;
457 for ( i
=0 ; i
<kNumExtentsToCache
; i
++ )
459 HFSCatalogNodeID foundFileID
;
461 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
462 if ( err
== btNotFound
) // Did we run out of extent records in the extents tree?
463 break; // if xkrFNum(A0) is cleared on this error, then this test is bogus!
464 else if ( err
!= noErr
)
465 return( err
); // must be ioError
467 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
468 if ( foundFileID
== srcFileID
)
470 CopyExtentInfo(extentKeyPtr
, &extentData
, extentsBuffer
, i
);
478 //-- edit each extent key, and reinsert each extent record in the extent file
480 btRecordSize
= sizeof(HFSPlusExtentRecord
);
482 btRecordSize
= sizeof(HFSExtentRecord
);
484 for ( j
=0 ; j
<i
; j
++ )
486 BTreeIterator tmpIterator
;
489 extentsBuffer
[j
].extentKey
.hfsPlus
.fileID
= destFileID
; // change only the id in the key to dest ID
491 extentsBuffer
[j
].extentKey
.hfs
.fileID
= destFileID
; // change only the id in the key to dest ID
493 // get iterator and buffer descriptor ready...
494 (void) BTInvalidateHint(&tmpIterator
);
495 BlockMoveData(&(extentsBuffer
[j
].extentKey
), &tmpIterator
.key
, btKeySize
);
496 btRecord
.bufferAddress
= &(extentsBuffer
[j
].extentData
);
498 err
= BTInsertRecord(fcb
, &tmpIterator
, &btRecord
, btRecordSize
);
501 if ( err
== btExists
)
504 DebugStr("\pCan't insert record -- already exists");
512 //-- okay, done with this buffered batch, go get the next set of extent records
513 // If our buffer is not full, we must be done, or recieved an error
515 if ( i
!= kNumExtentsToCache
) // if the buffer is not full, we must be done
517 err
= DeleteExtents( vcb
, srcFileID
, isHFSPlus
); // Now delete all the extent entries with the sourceID
518 if ( DEBUG_BUILD
&& err
!= noErr
)
519 DebugStr("\pError from DeleteExtents");
520 break; // we're done!
528 static void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, UInt16 bufferCount
)
530 BlockMoveData( key
, &(buffer
[bufferCount
].extentKey
), sizeof( ExtentKey
) );
531 BlockMoveData( data
, &(buffer
[bufferCount
].extentData
), sizeof( ExtentRecord
) );
535 //-- Delete all extents in extent file that have the ID given.
536 static OSErr
DeleteExtents( ExtendedVCB
*vcb
, UInt32 fileID
, Boolean isHFSPlus
)
539 ExtentKey
* extentKeyPtr
;
540 ExtentRecord extentData
;
541 BTreeIterator btIterator
;
542 FSBufferDescriptor btRecord
;
546 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
548 (void) BTInvalidateHint(&btIterator
);
549 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
550 btRecord
.bufferAddress
= &extentData
;
551 btRecord
.itemCount
= 1;
553 // The algorithm is to position the BTree just before any extent records for fileID.
554 // Then just keep getting successive records. If the record is still for fileID,
558 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
560 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
561 extentKeyPtr
->hfsPlus
.forkType
= 0;
562 extentKeyPtr
->hfsPlus
.pad
= 0;
563 extentKeyPtr
->hfsPlus
.fileID
= fileID
;
564 extentKeyPtr
->hfsPlus
.startBlock
= 0;
567 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
569 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
570 extentKeyPtr
->hfs
.forkType
= 0;
571 extentKeyPtr
->hfs
.fileID
= fileID
;
572 extentKeyPtr
->hfs
.startBlock
= 0;
575 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
576 if ( err
!= btNotFound
)
578 if (err
== noErr
) { // Did we find a bogus extent record?
579 err
= cmBadNews
; // Yes, so indicate things are messed up.
582 return err
; // Got some unexpected error, so return it
587 BTreeIterator tmpIterator
;
588 HFSCatalogNodeID foundFileID
;
590 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
593 if (err
== btNotFound
) // If we hit the end of the BTree
594 err
= noErr
; // then it's OK
596 break; // We're done now.
599 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
600 if ( foundFileID
!= fileID
)
601 break; // numbers don't match, we must be done
603 tmpIterator
= btIterator
;
604 err
= BTDeleteRecord( fcb
, &tmpIterator
);
613 // Check if there are extents represented in the extents overflow file.
614 static UInt32
CheckExtents( void *extents
, UInt32 totalBlocks
, Boolean isHFSPlus
)
616 UInt32 extentAllocationBlocks
;
620 if ( totalBlocks
== 0 )
623 extentAllocationBlocks
= 0;
627 for ( i
= 0 ; i
< kHFSPlusExtentDensity
; i
++ )
629 extentAllocationBlocks
+= ((HFSPlusExtentDescriptor
*)extents
)[i
].blockCount
;
630 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
636 for ( i
= 0 ; i
< kHFSExtentDensity
; i
++ )
638 extentAllocationBlocks
+= ((HFSExtentDescriptor
*)extents
)[i
].blockCount
;
639 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
644 return( extentAllocationBlocks
);