2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_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. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
31 #include "../../hfs_macos_defs.h"
32 #include "../../hfs_format.h"
34 #include "../headers/FileMgrInternal.h"
35 #include "../headers/HFSUnicodeWrappers.h"
36 #include "../headers/CatalogPrivate.h"
39 struct ExtentsRecBuffer
{
41 ExtentRecord extentData
;
43 typedef struct ExtentsRecBuffer ExtentsRecBuffer
;
46 static UInt32
CheckExtents( void *extents
, UInt32 blocks
, Boolean isHFSPlus
);
47 static OSErr
DeleteExtents( ExtendedVCB
*vcb
, UInt32 fileNumber
, Boolean isHFSPlus
);
48 static OSErr
MoveExtents( ExtendedVCB
*vcb
, UInt32 srcFileID
, UInt32 destFileID
, Boolean isHFSPlus
);
49 static void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
50 static void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
51 static void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, UInt16 bufferCount
);
55 OSErr
ExchangeFileIDs( ExtendedVCB
*vcb
, ConstUTF8Param srcName
, ConstUTF8Param destName
, HFSCatalogNodeID srcID
, HFSCatalogNodeID destID
, UInt32 srcHint
, UInt32 destHint
)
57 CatalogKey srcKey
; // 518 bytes
58 CatalogKey destKey
; // 518 bytes
59 CatalogRecord srcData
; // 520 bytes
60 CatalogRecord destData
; // 520 bytes
61 CatalogRecord swapData
; // 520 bytes
62 SInt16 numSrcExtentBlocks
;
63 SInt16 numDestExtentBlocks
;
65 Boolean isHFSPlus
= ( vcb
->vcbSigWord
== kHFSPlusSigWord
);
67 err
= BuildCatalogKeyUTF8(vcb
, srcID
, srcName
, kUndefinedStrLen
, &srcKey
, NULL
);
70 err
= BuildCatalogKeyUTF8(vcb
, destID
, destName
, kUndefinedStrLen
, &destKey
, NULL
);
75 //-- Step 1: Check the catalog nodes for extents
77 //-- locate the source file, test for extents in extent file, and copy the cat record for later
78 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
81 if ( srcData
.recordType
!= kHFSPlusFileRecord
)
82 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
84 //-- Check if there are any extents in the source file
85 //\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
86 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.dataFork
.extents
, srcData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
87 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
88 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.resourceFork
.extents
, srcData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
90 //-- Check if there are any extents in the destination file
91 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
94 if ( destData
.recordType
!= kHFSPlusFileRecord
)
95 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
97 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.dataFork
.extents
, destData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
98 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
99 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.resourceFork
.extents
, destData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
101 //-- Step 2: Exchange the Extent key in the extent file
103 //-- Exchange the extents key in the extent file
104 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
105 ReturnIfError( err
);
107 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
109 //-- Change the source extents file ids to our known bogus value
110 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, kHFSBogusExtentFileID
, isHFSPlus
);
113 if ( err
!= dskFulErr
)
119 //-- Change the destination extents file id's to the source id's
120 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
123 if ( err
!= dskFulErr
)
126 ExUndo2aPlus
: err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
127 ReturnIfError( err
); // we are doomed. Just QUIT!
129 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
); // Move the extents back
130 ReturnIfError( err
); // we are doomed. Just QUIT!
135 //-- Change the bogus extents file id's to the dest id's
136 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
139 if ( err
!= dskFulErr
)
142 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
143 ReturnIfError( err
); // we are doomed. Just QUIT!
145 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
); // Move the extents back
146 ReturnIfError( err
); // we are doomed. Just QUIT!
152 else if ( numSrcExtentBlocks
) // just the source file has extents
154 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
157 if ( err
!= dskFulErr
)
160 err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
161 ReturnIfError( err
); // we are doomed. Just QUIT!
166 else if ( numDestExtentBlocks
) // just the destination file has extents
168 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
171 if ( err
!= dskFulErr
)
174 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
175 ReturnIfError( err
); // we are doomed. Just QUIT!
181 //-- Step 3: Change the data in the catalog nodes
183 //-- find the source cnode and put dest info in it
184 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
188 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
189 CopyBigCatalogNodeInfo( &destData
, &srcData
);
191 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSPlusCatalogFile
), &srcHint
);
192 ReturnIfError( err
);
194 // find the destination cnode and put source info in it
195 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
199 CopyBigCatalogNodeInfo( &swapData
, &destData
);
200 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSPlusCatalogFile
), &destHint
);
201 ReturnIfError( err
);
205 //-- Step 1: Check the catalog nodes for extents
207 //-- locate the source file, test for extents in extent file, and copy the cat record for later
208 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
209 ReturnIfError( err
);
211 if ( srcData
.recordType
!= kHFSFileRecord
)
212 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
214 //-- Check if there are any extents in the source file
215 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.dataExtents
, srcData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
216 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
217 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.rsrcExtents
, srcData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
220 //\80\80 Do we save the found source node for later use?
223 //-- Check if there are any extents in the destination file
224 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
225 ReturnIfError( err
);
227 if ( destData
.recordType
!= kHFSFileRecord
)
228 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
230 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.dataExtents
, destData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
231 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
232 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.rsrcExtents
, destData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
234 //\80\80 Do we save the found destination node for later use?
237 //-- Step 2: Exchange the Extent key in the extent file
239 //-- Exchange the extents key in the extent file
240 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
241 ReturnIfError( err
);
243 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
245 //-- Change the source extents file ids to our known bogus value
246 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, kHFSBogusExtentFileID
, isHFSPlus
);
249 if ( err
!= dskFulErr
)
252 ExUndo1a
: err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
253 ReturnIfError( err
); // we are doomed. Just QUIT!
255 err
= FlushCatalog( vcb
); // flush the catalog
256 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
260 //-- Change the destination extents file id's to the source id's
261 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, isHFSPlus
);
264 if ( err
!= dskFulErr
)
267 ExUndo2a
: err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, isHFSPlus
);
268 ReturnIfError( err
); // we are doomed. Just QUIT!
270 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsFile
.fileID
, isHFSPlus
); // Move the extents back
271 ReturnIfError( err
); // we are doomed. Just QUIT!
276 //-- Change the bogus extents file id's to the dest id's
277 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsFile
.fileID
, isHFSPlus
);
280 if ( err
!= dskFulErr
)
283 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, isHFSPlus
);
284 ReturnIfError( err
); // we are doomed. Just QUIT!
286 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, isHFSPlus
); // Move the extents back
287 ReturnIfError( err
); // we are doomed. Just QUIT!
293 else if ( numSrcExtentBlocks
) // just the source file has extents
295 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, isHFSPlus
);
298 if ( err
!= dskFulErr
)
301 err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, isHFSPlus
);
302 ReturnIfError( err
); // we are doomed. Just QUIT!
307 else if ( numDestExtentBlocks
) // just the destination file has extents
309 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, isHFSPlus
);
312 if ( err
!= dskFulErr
)
315 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, isHFSPlus
);
316 ReturnIfError( err
); // we are doomed. Just QUIT!
322 //-- Step 3: Change the data in the catalog nodes
324 //-- find the source cnode and put dest info in it
325 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
329 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
330 //\80\80 Asm source copies from the saved dest catalog node
331 CopyCatalogNodeInfo( &destData
, &srcData
);
333 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSCatalogFile
), &srcHint
);
334 ReturnIfError( err
);
337 // find the destination cnode and put source info in it
338 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
342 CopyCatalogNodeInfo( &swapData
, &destData
);
343 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSCatalogFile
), &destHint
);
344 ReturnIfError( err
);
349 //-- Step 4: Error Handling section
353 err
= FlushCatalog( vcb
); // flush the catalog
354 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
359 static void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
361 dest
->hfsFile
.dataLogicalSize
= src
->hfsFile
.dataLogicalSize
;
362 dest
->hfsFile
.dataPhysicalSize
= src
->hfsFile
.dataPhysicalSize
;
363 dest
->hfsFile
.rsrcLogicalSize
= src
->hfsFile
.rsrcLogicalSize
;
364 dest
->hfsFile
.rsrcPhysicalSize
= src
->hfsFile
.rsrcPhysicalSize
;
365 dest
->hfsFile
.modifyDate
= src
->hfsFile
.modifyDate
;
366 BlockMoveData( src
->hfsFile
.dataExtents
, dest
->hfsFile
.dataExtents
, sizeof(HFSExtentRecord
) );
367 BlockMoveData( src
->hfsFile
.rsrcExtents
, dest
->hfsFile
.rsrcExtents
, sizeof(HFSExtentRecord
) );
370 static void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
372 BlockMoveData( &src
->hfsPlusFile
.dataFork
, &dest
->hfsPlusFile
.dataFork
, sizeof(HFSPlusForkData
) );
373 BlockMoveData( &src
->hfsPlusFile
.resourceFork
, &dest
->hfsPlusFile
.resourceFork
, sizeof(HFSPlusForkData
) );
374 dest
->hfsPlusFile
.contentModDate
= src
->hfsPlusFile
.contentModDate
;
378 static OSErr
MoveExtents( ExtendedVCB
*vcb
, UInt32 srcFileID
, UInt32 destFileID
, Boolean isHFSPlus
)
381 ExtentsRecBuffer extentsBuffer
[kNumExtentsToCache
];
382 ExtentKey
* extentKeyPtr
;
383 ExtentRecord extentData
;
384 BTreeIterator btIterator
;
385 FSBufferDescriptor btRecord
;
392 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
394 (void) BTInvalidateHint(&btIterator
);
395 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
396 btRecord
.bufferAddress
= &extentData
;
397 btRecord
.itemCount
= 1;
399 //-- Collect the extent records
402 // A search on the following key will cause the BTree to be positioned immediately
403 // before the first extent record for file #srcFileID, but not actually positioned
404 // on any record. This is because there cannot be an extent record with FABN = 0
405 // (the first extent of the fork, which would be in the catalog entry, not an extent
408 // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
411 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
412 btKeySize
= sizeof(HFSPlusExtentKey
);
414 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
415 extentKeyPtr
->hfsPlus
.forkType
= 0;
416 extentKeyPtr
->hfsPlus
.pad
= 0;
417 extentKeyPtr
->hfsPlus
.fileID
= srcFileID
;
418 extentKeyPtr
->hfsPlus
.startBlock
= 0;
421 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
422 btKeySize
= sizeof(HFSExtentKey
);
424 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
425 extentKeyPtr
->hfs
.forkType
= 0;
426 extentKeyPtr
->hfs
.fileID
= srcFileID
;
427 extentKeyPtr
->hfs
.startBlock
= 0;
431 // We do an initial BTSearchRecord to position the BTree's iterator just before any extent
432 // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found
433 // records, but with destFileID as the file number in the key. Keep doing this sequence of
434 // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are
435 // no more extent records in the tree.
437 // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID
438 // set to destFileID.
440 // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it
441 // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series
442 // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record
443 // we found, so that BTIterateRecord would get the next one (the first we haven't processed).
446 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
448 // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
449 if (err
!= btNotFound
)
452 DebugStr("\pUnexpected error from SearchBTreeRecord");
454 if (err
== noErr
) // If we found such a bogus extent record, then the tree is really messed up
455 err
= cmBadNews
; // so return an error that conveys the disk is hosed.
462 btRecord
.bufferAddress
= &extentData
;
463 btRecord
.itemCount
= 1;
465 for ( i
=0 ; i
<kNumExtentsToCache
; i
++ )
467 HFSCatalogNodeID foundFileID
;
469 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
470 if ( err
== btNotFound
) // Did we run out of extent records in the extents tree?
471 break; // if xkrFNum(A0) is cleared on this error, then this test is bogus!
472 else if ( err
!= noErr
)
473 return( err
); // must be ioError
475 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
476 if ( foundFileID
== srcFileID
)
478 CopyExtentInfo(extentKeyPtr
, &extentData
, extentsBuffer
, i
);
486 //-- edit each extent key, and reinsert each extent record in the extent file
488 btRecordSize
= sizeof(HFSPlusExtentRecord
);
490 btRecordSize
= sizeof(HFSExtentRecord
);
492 for ( j
=0 ; j
<i
; j
++ )
494 BTreeIterator tmpIterator
;
497 extentsBuffer
[j
].extentKey
.hfsPlus
.fileID
= destFileID
; // change only the id in the key to dest ID
499 extentsBuffer
[j
].extentKey
.hfs
.fileID
= destFileID
; // change only the id in the key to dest ID
501 // get iterator and buffer descriptor ready...
502 (void) BTInvalidateHint(&tmpIterator
);
503 BlockMoveData(&(extentsBuffer
[j
].extentKey
), &tmpIterator
.key
, btKeySize
);
504 btRecord
.bufferAddress
= &(extentsBuffer
[j
].extentData
);
506 err
= BTInsertRecord(fcb
, &tmpIterator
, &btRecord
, btRecordSize
);
509 if ( err
== btExists
)
512 DebugStr("\pCan't insert record -- already exists");
520 //-- okay, done with this buffered batch, go get the next set of extent records
521 // If our buffer is not full, we must be done, or recieved an error
523 if ( i
!= kNumExtentsToCache
) // if the buffer is not full, we must be done
525 err
= DeleteExtents( vcb
, srcFileID
, isHFSPlus
); // Now delete all the extent entries with the sourceID
526 if ( DEBUG_BUILD
&& err
!= noErr
)
527 DebugStr("\pError from DeleteExtents");
528 break; // we're done!
536 static void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, UInt16 bufferCount
)
538 BlockMoveData( key
, &(buffer
[bufferCount
].extentKey
), sizeof( ExtentKey
) );
539 BlockMoveData( data
, &(buffer
[bufferCount
].extentData
), sizeof( ExtentRecord
) );
543 //-- Delete all extents in extent file that have the ID given.
544 static OSErr
DeleteExtents( ExtendedVCB
*vcb
, UInt32 fileID
, Boolean isHFSPlus
)
547 ExtentKey
* extentKeyPtr
;
548 ExtentRecord extentData
;
549 BTreeIterator btIterator
;
550 FSBufferDescriptor btRecord
;
554 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
556 (void) BTInvalidateHint(&btIterator
);
557 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
558 btRecord
.bufferAddress
= &extentData
;
559 btRecord
.itemCount
= 1;
561 // The algorithm is to position the BTree just before any extent records for fileID.
562 // Then just keep getting successive records. If the record is still for fileID,
566 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
568 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
569 extentKeyPtr
->hfsPlus
.forkType
= 0;
570 extentKeyPtr
->hfsPlus
.pad
= 0;
571 extentKeyPtr
->hfsPlus
.fileID
= fileID
;
572 extentKeyPtr
->hfsPlus
.startBlock
= 0;
575 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
577 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
578 extentKeyPtr
->hfs
.forkType
= 0;
579 extentKeyPtr
->hfs
.fileID
= fileID
;
580 extentKeyPtr
->hfs
.startBlock
= 0;
583 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
584 if ( err
!= btNotFound
)
586 if (err
== noErr
) { // Did we find a bogus extent record?
587 err
= cmBadNews
; // Yes, so indicate things are messed up.
590 return err
; // Got some unexpected error, so return it
595 BTreeIterator tmpIterator
;
596 HFSCatalogNodeID foundFileID
;
598 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
601 if (err
== btNotFound
) // If we hit the end of the BTree
602 err
= noErr
; // then it's OK
604 break; // We're done now.
607 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
608 if ( foundFileID
!= fileID
)
609 break; // numbers don't match, we must be done
611 tmpIterator
= btIterator
;
612 err
= BTDeleteRecord( fcb
, &tmpIterator
);
621 // Check if there are extents represented in the extents overflow file.
622 static UInt32
CheckExtents( void *extents
, UInt32 totalBlocks
, Boolean isHFSPlus
)
624 UInt32 extentAllocationBlocks
;
628 if ( totalBlocks
== 0 )
631 extentAllocationBlocks
= 0;
635 for ( i
= 0 ; i
< kHFSPlusExtentDensity
; i
++ )
637 extentAllocationBlocks
+= ((HFSPlusExtentDescriptor
*)extents
)[i
].blockCount
;
638 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
644 for ( i
= 0 ; i
< kHFSExtentDensity
; i
++ )
646 extentAllocationBlocks
+= ((HFSExtentDescriptor
*)extents
)[i
].blockCount
;
647 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
652 return( extentAllocationBlocks
);