2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 #include "../../hfs_macos_defs.h"
27 #include "../../hfs_format.h"
29 #include "../headers/FileMgrInternal.h"
30 #include "../headers/HFSUnicodeWrappers.h"
31 #include "../headers/CatalogPrivate.h"
34 struct ExtentsRecBuffer
{
36 ExtentRecord extentData
;
38 typedef struct ExtentsRecBuffer ExtentsRecBuffer
;
41 UInt32
CheckExtents( void *extents
, UInt32 blocks
, Boolean isHFSPlus
);
42 OSErr
DeleteExtents( ExtendedVCB
*vcb
, UInt32 fileNumber
, Boolean isHFSPlus
);
43 OSErr
MoveExtents( ExtendedVCB
*vcb
, UInt32 srcFileID
, UInt32 destFileID
, Boolean isHFSPlus
);
44 void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
45 void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
46 void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, UInt16 bufferCount
);
50 OSErr
ExchangeFileIDs( ExtendedVCB
*vcb
, ConstUTF8Param srcName
, ConstUTF8Param destName
, HFSCatalogNodeID srcID
, HFSCatalogNodeID destID
, UInt32 srcHint
, UInt32 destHint
)
52 CatalogKey srcKey
; // 518 bytes
53 CatalogKey destKey
; // 518 bytes
54 CatalogRecord srcData
; // 520 bytes
55 CatalogRecord destData
; // 520 bytes
56 CatalogRecord swapData
; // 520 bytes
57 SInt16 numSrcExtentBlocks
;
58 SInt16 numDestExtentBlocks
;
60 Boolean isHFSPlus
= ( vcb
->vcbSigWord
== kHFSPlusSigWord
);
62 TrashCatalogIterator(vcb
, srcID
); // invalidate any iterators for this parentID
63 TrashCatalogIterator(vcb
, destID
); // invalidate any iterators for this parentID
65 err
= BuildCatalogKeyUTF8(vcb
, srcID
, srcName
, kUndefinedStrLen
, &srcKey
, NULL
);
68 err
= BuildCatalogKeyUTF8(vcb
, destID
, destName
, kUndefinedStrLen
, &destKey
, NULL
);
73 //-- Step 1: Check the catalog nodes for extents
75 //-- locate the source file, test for extents in extent file, and copy the cat record for later
76 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
79 if ( srcData
.recordType
!= kHFSPlusFileRecord
)
80 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
82 //-- Check if there are any extents in the source file
83 //\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
84 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.dataFork
.extents
, srcData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
85 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
86 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.resourceFork
.extents
, srcData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
88 //-- Check if there are any extents in the destination file
89 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
92 if ( destData
.recordType
!= kHFSPlusFileRecord
)
93 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
95 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.dataFork
.extents
, destData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
96 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
97 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.resourceFork
.extents
, destData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
99 //-- Step 2: Exchange the Extent key in the extent file
101 //-- Exchange the extents key in the extent file
102 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
103 ReturnIfError( err
);
105 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
107 //-- Change the source extents file ids to our known bogus value
108 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, kHFSBogusExtentFileID
, isHFSPlus
);
111 if ( err
!= dskFulErr
)
117 //-- Change the destination extents file id's to the source id's
118 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
121 if ( err
!= dskFulErr
)
124 ExUndo2aPlus
: err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
125 ReturnIfError( err
); // we are doomed. Just QUIT!
127 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
); // Move the extents back
128 ReturnIfError( err
); // we are doomed. Just QUIT!
133 //-- Change the bogus extents file id's to the dest id's
134 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
137 if ( err
!= dskFulErr
)
140 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
141 ReturnIfError( err
); // we are doomed. Just QUIT!
143 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
); // Move the extents back
144 ReturnIfError( err
); // we are doomed. Just QUIT!
150 else if ( numSrcExtentBlocks
) // just the source file has extents
152 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
155 if ( err
!= dskFulErr
)
158 err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
159 ReturnIfError( err
); // we are doomed. Just QUIT!
164 else if ( numDestExtentBlocks
) // just the destination file has extents
166 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, isHFSPlus
);
169 if ( err
!= dskFulErr
)
172 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, isHFSPlus
);
173 ReturnIfError( err
); // we are doomed. Just QUIT!
179 //-- Step 3: Change the data in the catalog nodes
181 //-- find the source cnode and put dest info in it
182 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
186 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
187 CopyBigCatalogNodeInfo( &destData
, &srcData
);
189 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSPlusCatalogFile
), &srcHint
);
190 ReturnIfError( err
);
192 // find the destination cnode and put source info in it
193 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
197 CopyBigCatalogNodeInfo( &swapData
, &destData
);
198 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSPlusCatalogFile
), &destHint
);
199 ReturnIfError( err
);
203 //-- Step 1: Check the catalog nodes for extents
205 //-- locate the source file, test for extents in extent file, and copy the cat record for later
206 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
207 ReturnIfError( err
);
209 if ( srcData
.recordType
!= kHFSFileRecord
)
210 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
212 //-- Check if there are any extents in the source file
213 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.dataExtents
, srcData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
214 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
215 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.rsrcExtents
, srcData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
218 //\80\80 Do we save the found source node for later use?
221 //-- Check if there are any extents in the destination file
222 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
223 ReturnIfError( err
);
225 if ( destData
.recordType
!= kHFSFileRecord
)
226 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
228 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.dataExtents
, destData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
229 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
230 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.rsrcExtents
, destData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
232 //\80\80 Do we save the found destination node for later use?
235 //-- Step 2: Exchange the Extent key in the extent file
237 //-- Exchange the extents key in the extent file
238 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
239 ReturnIfError( err
);
241 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
243 //-- Change the source extents file ids to our known bogus value
244 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, kHFSBogusExtentFileID
, isHFSPlus
);
247 if ( err
!= dskFulErr
)
250 ExUndo1a
: err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, isHFSPlus
);
251 ReturnIfError( err
); // we are doomed. Just QUIT!
253 err
= FlushCatalog( vcb
); // flush the catalog
254 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
258 //-- Change the destination extents file id's to the source id's
259 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, isHFSPlus
);
262 if ( err
!= dskFulErr
)
265 ExUndo2a
: err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, isHFSPlus
);
266 ReturnIfError( err
); // we are doomed. Just QUIT!
268 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsFile
.fileID
, isHFSPlus
); // Move the extents back
269 ReturnIfError( err
); // we are doomed. Just QUIT!
274 //-- Change the bogus extents file id's to the dest id's
275 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsFile
.fileID
, isHFSPlus
);
278 if ( err
!= dskFulErr
)
281 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, isHFSPlus
);
282 ReturnIfError( err
); // we are doomed. Just QUIT!
284 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, isHFSPlus
); // Move the extents back
285 ReturnIfError( err
); // we are doomed. Just QUIT!
291 else if ( numSrcExtentBlocks
) // just the source file has extents
293 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, isHFSPlus
);
296 if ( err
!= dskFulErr
)
299 err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, isHFSPlus
);
300 ReturnIfError( err
); // we are doomed. Just QUIT!
305 else if ( numDestExtentBlocks
) // just the destination file has extents
307 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, isHFSPlus
);
310 if ( err
!= dskFulErr
)
313 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, isHFSPlus
);
314 ReturnIfError( err
); // we are doomed. Just QUIT!
320 //-- Step 3: Change the data in the catalog nodes
322 //-- find the source cnode and put dest info in it
323 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
327 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
328 //\80\80 Asm source copies from the saved dest catalog node
329 CopyCatalogNodeInfo( &destData
, &srcData
);
331 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSCatalogFile
), &srcHint
);
332 ReturnIfError( err
);
335 // find the destination cnode and put source info in it
336 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
340 CopyCatalogNodeInfo( &swapData
, &destData
);
341 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSCatalogFile
), &destHint
);
342 ReturnIfError( err
);
347 //-- Step 4: Error Handling section
351 err
= FlushCatalog( vcb
); // flush the catalog
352 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
357 void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
359 dest
->hfsFile
.dataLogicalSize
= src
->hfsFile
.dataLogicalSize
;
360 dest
->hfsFile
.dataPhysicalSize
= src
->hfsFile
.dataPhysicalSize
;
361 dest
->hfsFile
.rsrcLogicalSize
= src
->hfsFile
.rsrcLogicalSize
;
362 dest
->hfsFile
.rsrcPhysicalSize
= src
->hfsFile
.rsrcPhysicalSize
;
363 dest
->hfsFile
.modifyDate
= src
->hfsFile
.modifyDate
;
364 BlockMoveData( src
->hfsFile
.dataExtents
, dest
->hfsFile
.dataExtents
, sizeof(HFSExtentRecord
) );
365 BlockMoveData( src
->hfsFile
.rsrcExtents
, dest
->hfsFile
.rsrcExtents
, sizeof(HFSExtentRecord
) );
368 void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
370 BlockMoveData( &src
->hfsPlusFile
.dataFork
, &dest
->hfsPlusFile
.dataFork
, sizeof(HFSPlusForkData
) );
371 BlockMoveData( &src
->hfsPlusFile
.resourceFork
, &dest
->hfsPlusFile
.resourceFork
, sizeof(HFSPlusForkData
) );
372 dest
->hfsPlusFile
.contentModDate
= src
->hfsPlusFile
.contentModDate
;
376 OSErr
MoveExtents( ExtendedVCB
*vcb
, UInt32 srcFileID
, UInt32 destFileID
, Boolean isHFSPlus
)
379 ExtentsRecBuffer extentsBuffer
[kNumExtentsToCache
];
380 ExtentKey
* extentKeyPtr
;
381 ExtentRecord extentData
;
382 BTreeIterator btIterator
;
383 FSBufferDescriptor btRecord
;
390 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
392 (void) BTInvalidateHint(&btIterator
);
393 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
394 btRecord
.bufferAddress
= &extentData
;
395 btRecord
.itemCount
= 1;
397 //-- Collect the extent records
400 // A search on the following key will cause the BTree to be positioned immediately
401 // before the first extent record for file #srcFileID, but not actually positioned
402 // on any record. This is because there cannot be an extent record with FABN = 0
403 // (the first extent of the fork, which would be in the catalog entry, not an extent
406 // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
409 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
410 btKeySize
= sizeof(HFSPlusExtentKey
);
412 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
413 extentKeyPtr
->hfsPlus
.forkType
= 0;
414 extentKeyPtr
->hfsPlus
.pad
= 0;
415 extentKeyPtr
->hfsPlus
.fileID
= srcFileID
;
416 extentKeyPtr
->hfsPlus
.startBlock
= 0;
419 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
420 btKeySize
= sizeof(HFSExtentKey
);
422 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
423 extentKeyPtr
->hfs
.forkType
= 0;
424 extentKeyPtr
->hfs
.fileID
= srcFileID
;
425 extentKeyPtr
->hfs
.startBlock
= 0;
429 // We do an initial BTSearchRecord to position the BTree's iterator just before any extent
430 // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found
431 // records, but with destFileID as the file number in the key. Keep doing this sequence of
432 // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are
433 // no more extent records in the tree.
435 // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID
436 // set to destFileID.
438 // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it
439 // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series
440 // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record
441 // we found, so that BTIterateRecord would get the next one (the first we haven't processed).
444 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
446 // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
447 if (err
!= btNotFound
)
450 DebugStr("\pUnexpected error from SearchBTreeRecord");
452 if (err
== noErr
) // If we found such a bogus extent record, then the tree is really messed up
453 err
= cmBadNews
; // so return an error that conveys the disk is hosed.
460 btRecord
.bufferAddress
= &extentData
;
461 btRecord
.itemCount
= 1;
463 for ( i
=0 ; i
<kNumExtentsToCache
; i
++ )
465 HFSCatalogNodeID foundFileID
;
467 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
468 if ( err
== btNotFound
) // Did we run out of extent records in the extents tree?
469 break; // if xkrFNum(A0) is cleared on this error, then this test is bogus!
470 else if ( err
!= noErr
)
471 return( err
); // must be ioError
473 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
474 if ( foundFileID
== srcFileID
)
476 CopyExtentInfo(extentKeyPtr
, &extentData
, extentsBuffer
, i
);
484 //-- edit each extent key, and reinsert each extent record in the extent file
486 btRecordSize
= sizeof(HFSPlusExtentRecord
);
488 btRecordSize
= sizeof(HFSExtentRecord
);
490 for ( j
=0 ; j
<i
; j
++ )
492 BTreeIterator tmpIterator
;
495 extentsBuffer
[j
].extentKey
.hfsPlus
.fileID
= destFileID
; // change only the id in the key to dest ID
497 extentsBuffer
[j
].extentKey
.hfs
.fileID
= destFileID
; // change only the id in the key to dest ID
499 // get iterator and buffer descriptor ready...
500 (void) BTInvalidateHint(&tmpIterator
);
501 BlockMoveData(&(extentsBuffer
[j
].extentKey
), &tmpIterator
.key
, btKeySize
);
502 btRecord
.bufferAddress
= &(extentsBuffer
[j
].extentData
);
504 err
= BTInsertRecord(fcb
, &tmpIterator
, &btRecord
, btRecordSize
);
507 if ( err
== btExists
)
510 DebugStr("\pCan't insert record -- already exists");
518 //-- okay, done with this buffered batch, go get the next set of extent records
519 // If our buffer is not full, we must be done, or recieved an error
521 if ( i
!= kNumExtentsToCache
) // if the buffer is not full, we must be done
523 err
= DeleteExtents( vcb
, srcFileID
, isHFSPlus
); // Now delete all the extent entries with the sourceID
524 if ( DEBUG_BUILD
&& err
!= noErr
)
525 DebugStr("\pError from DeleteExtents");
526 break; // we're done!
534 void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, UInt16 bufferCount
)
536 BlockMoveData( key
, &(buffer
[bufferCount
].extentKey
), sizeof( ExtentKey
) );
537 BlockMoveData( data
, &(buffer
[bufferCount
].extentData
), sizeof( ExtentRecord
) );
541 //-- Delete all extents in extent file that have the ID given.
542 OSErr
DeleteExtents( ExtendedVCB
*vcb
, UInt32 fileID
, Boolean isHFSPlus
)
545 ExtentKey
* extentKeyPtr
;
546 ExtentRecord extentData
;
547 BTreeIterator btIterator
;
548 FSBufferDescriptor btRecord
;
552 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
554 (void) BTInvalidateHint(&btIterator
);
555 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
556 btRecord
.bufferAddress
= &extentData
;
557 btRecord
.itemCount
= 1;
559 // The algorithm is to position the BTree just before any extent records for fileID.
560 // Then just keep getting successive records. If the record is still for fileID,
564 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
566 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
567 extentKeyPtr
->hfsPlus
.forkType
= 0;
568 extentKeyPtr
->hfsPlus
.pad
= 0;
569 extentKeyPtr
->hfsPlus
.fileID
= fileID
;
570 extentKeyPtr
->hfsPlus
.startBlock
= 0;
573 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
575 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
576 extentKeyPtr
->hfs
.forkType
= 0;
577 extentKeyPtr
->hfs
.fileID
= fileID
;
578 extentKeyPtr
->hfs
.startBlock
= 0;
581 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
582 if ( err
!= btNotFound
)
584 if (err
== noErr
) { // Did we find a bogus extent record?
585 err
= cmBadNews
; // Yes, so indicate things are messed up.
588 return err
; // Got some unexpected error, so return it
593 BTreeIterator tmpIterator
;
594 HFSCatalogNodeID foundFileID
;
596 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
599 if (err
== btNotFound
) // If we hit the end of the BTree
600 err
= noErr
; // then it's OK
602 break; // We're done now.
605 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
606 if ( foundFileID
!= fileID
)
607 break; // numbers don't match, we must be done
609 tmpIterator
= btIterator
;
610 err
= BTDeleteRecord( fcb
, &tmpIterator
);
619 // Check if there are extents represented in the extents overflow file.
620 UInt32
CheckExtents( void *extents
, UInt32 totalBlocks
, Boolean isHFSPlus
)
622 UInt32 extentAllocationBlocks
;
626 if ( totalBlocks
== 0 )
629 extentAllocationBlocks
= 0;
633 for ( i
= 0 ; i
< kHFSPlusExtentDensity
; i
++ )
635 extentAllocationBlocks
+= ((HFSPlusExtentDescriptor
*)extents
)[i
].blockCount
;
636 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
642 for ( i
= 0 ; i
< kHFSExtentDensity
; i
++ )
644 extentAllocationBlocks
+= ((HFSExtentDescriptor
*)extents
)[i
].blockCount
;
645 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
650 return( extentAllocationBlocks
);