2 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_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. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 #include "../../hfs_macos_defs.h"
30 #include "../../hfs_format.h"
32 #include "../headers/FileMgrInternal.h"
33 #include "../headers/HFSUnicodeWrappers.h"
34 #include "../headers/CatalogPrivate.h"
37 struct ExtentsRecBuffer
{
39 ExtentRecord extentData
;
41 typedef struct ExtentsRecBuffer ExtentsRecBuffer
;
44 static u_int32_t
CheckExtents( void *extents
, u_int32_t blocks
, Boolean isHFSPlus
);
45 static OSErr
DeleteExtents( ExtendedVCB
*vcb
, u_int32_t fileNumber
, int quitEarly
, u_int8_t forkType
, Boolean isHFSPlus
);
46 static OSErr
MoveExtents( ExtendedVCB
*vcb
, u_int32_t srcFileID
, u_int32_t destFileID
, int quitEarly
, u_int8_t forkType
, Boolean isHFSPlus
);
47 static void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
48 static void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
);
49 static void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, u_int16_t bufferCount
);
52 * This function moves the overflow extents associated with srcID into the file associated with dstID.
53 * We should have already verified that 'srcID' has overflow extents. So now we move all of the overflow
56 OSErr
MoveData( ExtendedVCB
*vcb
, HFSCatalogNodeID srcID
, HFSCatalogNodeID destID
, int rsrc
) {
61 * Only the source file should have extents, so we just track those.
62 * We operate on the fork represented by the open FD that was used to call into this
66 /* Copy the extent overflow blocks. */
67 err
= MoveExtents( vcb
, srcID
, destID
, 1, (u_int8_t
)0xff, 1);
69 if ( err
!= dskFulErr
) {
73 * In case of error, we would have probably run into problems
74 * growing the extents b-tree. Since the move is actually a copy + delete
75 * just delete the new entries. Same for below.
77 err
= DeleteExtents( vcb
, destID
, 1, (u_int8_t
)0xff, 1);
78 ReturnIfError( err
); // we are doomed. Just QUIT!
83 /* Copy the extent overflow blocks. */
84 err
= MoveExtents( vcb
, srcID
, destID
, 1, 0, 1);
86 if ( err
!= dskFulErr
) {
89 err
= DeleteExtents( vcb
, destID
, 1, 0, 1);
90 ReturnIfError( err
); // we are doomed. Just QUIT!
96 /* Write out the catalog and extent overflow B-Tree changes */
97 err
= FlushCatalog( vcb
);
98 err
= FlushExtentFile( vcb
);
104 OSErr
ExchangeFileIDs( ExtendedVCB
*vcb
, ConstUTF8Param srcName
, ConstUTF8Param destName
, HFSCatalogNodeID srcID
, HFSCatalogNodeID destID
, u_int32_t srcHint
, u_int32_t destHint
)
106 CatalogKey srcKey
; // 518 bytes
107 CatalogKey destKey
; // 518 bytes
108 CatalogRecord srcData
; // 520 bytes
109 CatalogRecord destData
; // 520 bytes
110 CatalogRecord swapData
; // 520 bytes
111 int16_t numSrcExtentBlocks
;
112 int16_t numDestExtentBlocks
;
114 Boolean isHFSPlus
= ( vcb
->vcbSigWord
== kHFSPlusSigWord
);
116 err
= BuildCatalogKeyUTF8(vcb
, srcID
, srcName
, kUndefinedStrLen
, &srcKey
, NULL
);
119 err
= BuildCatalogKeyUTF8(vcb
, destID
, destName
, kUndefinedStrLen
, &destKey
, NULL
);
124 //-- Step 1: Check the catalog nodes for extents
126 //-- locate the source file, test for extents in extent file, and copy the cat record for later
127 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
128 ReturnIfError( err
);
130 if ( srcData
.recordType
!= kHFSPlusFileRecord
)
131 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
133 //-- Check if there are any extents in the source file
134 //\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
135 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.dataFork
.extents
, srcData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
136 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
137 numSrcExtentBlocks
= CheckExtents( srcData
.hfsPlusFile
.resourceFork
.extents
, srcData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
139 //-- Check if there are any extents in the destination file
140 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
141 ReturnIfError( err
);
143 if ( destData
.recordType
!= kHFSPlusFileRecord
)
144 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
146 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.dataFork
.extents
, destData
.hfsPlusFile
.dataFork
.totalBlocks
, isHFSPlus
);
147 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
148 numDestExtentBlocks
= CheckExtents( destData
.hfsPlusFile
.resourceFork
.extents
, destData
.hfsPlusFile
.resourceFork
.totalBlocks
, isHFSPlus
);
150 //-- Step 2: Exchange the Extent key in the extent file
152 //-- Exchange the extents key in the extent file
153 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, 0, 0, isHFSPlus
);
154 ReturnIfError( err
);
156 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
158 //-- Change the source extents file ids to our known bogus value
159 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, kHFSBogusExtentFileID
, 0, 0, isHFSPlus
);
162 if ( err
!= dskFulErr
)
168 //-- Change the destination extents file id's to the source id's
169 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, 0, 0, isHFSPlus
);
172 if ( err
!= dskFulErr
)
175 ExUndo2aPlus
: err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, 0, 0, isHFSPlus
);
176 ReturnIfError( err
); // we are doomed. Just QUIT!
178 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsPlusFile
.fileID
, 0, 0, isHFSPlus
); // Move the extents back
179 ReturnIfError( err
); // we are doomed. Just QUIT!
184 //-- Change the bogus extents file id's to the dest id's
185 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsPlusFile
.fileID
, 0, 0, isHFSPlus
);
188 if ( err
!= dskFulErr
)
191 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, 0, 0, isHFSPlus
);
192 ReturnIfError( err
); // we are doomed. Just QUIT!
194 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, 0, 0, isHFSPlus
); // Move the extents back
195 ReturnIfError( err
); // we are doomed. Just QUIT!
201 else if ( numSrcExtentBlocks
) // just the source file has extents
203 err
= MoveExtents( vcb
, srcData
.hfsPlusFile
.fileID
, destData
.hfsPlusFile
.fileID
, 0, 0, isHFSPlus
);
206 if ( err
!= dskFulErr
)
209 err
= DeleteExtents( vcb
, srcData
.hfsPlusFile
.fileID
, 0, 0, isHFSPlus
);
210 ReturnIfError( err
); // we are doomed. Just QUIT!
215 else if ( numDestExtentBlocks
) // just the destination file has extents
217 err
= MoveExtents( vcb
, destData
.hfsPlusFile
.fileID
, srcData
.hfsPlusFile
.fileID
, 0, 0, isHFSPlus
);
220 if ( err
!= dskFulErr
)
223 err
= DeleteExtents( vcb
, destData
.hfsPlusFile
.fileID
, 0, 0, isHFSPlus
);
224 ReturnIfError( err
); // we are doomed. Just QUIT!
230 //-- Step 3: Change the data in the catalog nodes
232 //-- find the source cnode and put dest info in it
233 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
237 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
238 CopyBigCatalogNodeInfo( &destData
, &srcData
);
240 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSPlusCatalogFile
), &srcHint
);
241 ReturnIfError( err
);
243 // find the destination cnode and put source info in it
244 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
248 CopyBigCatalogNodeInfo( &swapData
, &destData
);
249 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSPlusCatalogFile
), &destHint
);
250 ReturnIfError( err
);
254 //-- Step 1: Check the catalog nodes for extents
256 //-- locate the source file, test for extents in extent file, and copy the cat record for later
257 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
258 ReturnIfError( err
);
260 if ( srcData
.recordType
!= kHFSFileRecord
)
261 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
263 //-- Check if there are any extents in the source file
264 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.dataExtents
, srcData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
265 if ( numSrcExtentBlocks
== 0 ) // then check the resource fork extents
266 numSrcExtentBlocks
= CheckExtents( srcData
.hfsFile
.rsrcExtents
, srcData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
269 //\80\80 Do we save the found source node for later use?
272 //-- Check if there are any extents in the destination file
273 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
274 ReturnIfError( err
);
276 if ( destData
.recordType
!= kHFSFileRecord
)
277 return( cmFThdDirErr
); // Error "cmFThdDirErr = it is a directory"
279 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.dataExtents
, destData
.hfsFile
.dataPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
280 if ( numDestExtentBlocks
== 0 ) // then check the resource fork extents
281 numDestExtentBlocks
= CheckExtents( destData
.hfsFile
.rsrcExtents
, destData
.hfsFile
.rsrcPhysicalSize
/ vcb
->blockSize
, isHFSPlus
);
283 //\80\80 Do we save the found destination node for later use?
286 //-- Step 2: Exchange the Extent key in the extent file
288 //-- Exchange the extents key in the extent file
289 err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, 0, 0, isHFSPlus
);
290 ReturnIfError( err
);
292 if ( numSrcExtentBlocks
&& numDestExtentBlocks
) // if both files have extents
294 //-- Change the source extents file ids to our known bogus value
295 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, kHFSBogusExtentFileID
, 0, 0, isHFSPlus
);
298 if ( err
!= dskFulErr
)
301 ExUndo1a
: err
= DeleteExtents( vcb
, kHFSBogusExtentFileID
, 0, 0, isHFSPlus
);
302 ReturnIfError( err
); // we are doomed. Just QUIT!
304 err
= FlushCatalog( vcb
); // flush the catalog
305 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
309 //-- Change the destination extents file id's to the source id's
310 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, 0, 0, isHFSPlus
);
313 if ( err
!= dskFulErr
)
316 ExUndo2a
: err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, 0, 0, isHFSPlus
);
317 ReturnIfError( err
); // we are doomed. Just QUIT!
319 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, srcData
.hfsFile
.fileID
, 0, 0, isHFSPlus
); // Move the extents back
320 ReturnIfError( err
); // we are doomed. Just QUIT!
325 //-- Change the bogus extents file id's to the dest id's
326 err
= MoveExtents( vcb
, kHFSBogusExtentFileID
, destData
.hfsFile
.fileID
, 0, 0, isHFSPlus
);
329 if ( err
!= dskFulErr
)
332 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, 0, 0, isHFSPlus
);
333 ReturnIfError( err
); // we are doomed. Just QUIT!
335 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, 0, 0, isHFSPlus
); // Move the extents back
336 ReturnIfError( err
); // we are doomed. Just QUIT!
342 else if ( numSrcExtentBlocks
) // just the source file has extents
344 err
= MoveExtents( vcb
, srcData
.hfsFile
.fileID
, destData
.hfsFile
.fileID
, 0, 0, isHFSPlus
);
347 if ( err
!= dskFulErr
)
350 err
= DeleteExtents( vcb
, srcData
.hfsFile
.fileID
, 0, 0, isHFSPlus
);
351 ReturnIfError( err
); // we are doomed. Just QUIT!
356 else if ( numDestExtentBlocks
) // just the destination file has extents
358 err
= MoveExtents( vcb
, destData
.hfsFile
.fileID
, srcData
.hfsFile
.fileID
, 0, 0, isHFSPlus
);
361 if ( err
!= dskFulErr
)
364 err
= DeleteExtents( vcb
, destData
.hfsFile
.fileID
, 0, 0, isHFSPlus
);
365 ReturnIfError( err
); // we are doomed. Just QUIT!
371 //-- Step 3: Change the data in the catalog nodes
373 //-- find the source cnode and put dest info in it
374 err
= LocateCatalogNodeByKey( vcb
, srcHint
, &srcKey
, &srcData
, &srcHint
);
378 BlockMoveData( &srcData
, &swapData
, sizeof(CatalogRecord
) );
379 //\80\80 Asm source copies from the saved dest catalog node
380 CopyCatalogNodeInfo( &destData
, &srcData
);
382 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &srcKey
, srcHint
, &srcData
, sizeof(HFSCatalogFile
), &srcHint
);
383 ReturnIfError( err
);
386 // find the destination cnode and put source info in it
387 err
= LocateCatalogNodeByKey( vcb
, destHint
, &destKey
, &destData
, &destHint
);
391 CopyCatalogNodeInfo( &swapData
, &destData
);
392 err
= ReplaceBTreeRecord( vcb
->catalogRefNum
, &destKey
, destHint
, &destData
, sizeof(HFSCatalogFile
), &destHint
);
393 ReturnIfError( err
);
398 //-- Step 4: Error Handling section
402 err
= FlushCatalog( vcb
); // flush the catalog
403 err
= FlushExtentFile( vcb
); // flush the extent file (unneeded for common case, but it's cheap)
408 static void CopyCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
410 dest
->hfsFile
.dataLogicalSize
= src
->hfsFile
.dataLogicalSize
;
411 dest
->hfsFile
.dataPhysicalSize
= src
->hfsFile
.dataPhysicalSize
;
412 dest
->hfsFile
.rsrcLogicalSize
= src
->hfsFile
.rsrcLogicalSize
;
413 dest
->hfsFile
.rsrcPhysicalSize
= src
->hfsFile
.rsrcPhysicalSize
;
414 dest
->hfsFile
.modifyDate
= src
->hfsFile
.modifyDate
;
415 BlockMoveData( src
->hfsFile
.dataExtents
, dest
->hfsFile
.dataExtents
, sizeof(HFSExtentRecord
) );
416 BlockMoveData( src
->hfsFile
.rsrcExtents
, dest
->hfsFile
.rsrcExtents
, sizeof(HFSExtentRecord
) );
419 static void CopyBigCatalogNodeInfo( CatalogRecord
*src
, CatalogRecord
*dest
)
421 BlockMoveData( &src
->hfsPlusFile
.dataFork
, &dest
->hfsPlusFile
.dataFork
, sizeof(HFSPlusForkData
) );
422 BlockMoveData( &src
->hfsPlusFile
.resourceFork
, &dest
->hfsPlusFile
.resourceFork
, sizeof(HFSPlusForkData
) );
423 dest
->hfsPlusFile
.contentModDate
= src
->hfsPlusFile
.contentModDate
;
427 static OSErr
MoveExtents( ExtendedVCB
*vcb
, u_int32_t srcFileID
, u_int32_t destFileID
, int quitEarly
, u_int8_t forkType
, Boolean isHFSPlus
)
430 ExtentsRecBuffer extentsBuffer
[kNumExtentsToCache
];
431 ExtentKey
* extentKeyPtr
;
432 ExtentRecord extentData
;
433 BTreeIterator btIterator
;
434 FSBufferDescriptor btRecord
;
436 u_int16_t btRecordSize
;
441 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
443 (void) BTInvalidateHint(&btIterator
);
444 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
445 btRecord
.bufferAddress
= &extentData
;
446 btRecord
.itemCount
= 1;
448 //-- Collect the extent records
451 // A search on the following key will cause the BTree to be positioned immediately
452 // before the first extent record for file #srcFileID, but not actually positioned
453 // on any record. This is because there cannot be an extent record with FABN = 0
454 // (the first extent of the fork, which would be in the catalog entry, not an extent
457 // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
460 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
461 btKeySize
= sizeof(HFSPlusExtentKey
);
463 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
464 extentKeyPtr
->hfsPlus
.forkType
= forkType
;
465 extentKeyPtr
->hfsPlus
.pad
= 0;
466 extentKeyPtr
->hfsPlus
.fileID
= srcFileID
;
467 extentKeyPtr
->hfsPlus
.startBlock
= 0;
470 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
471 btKeySize
= sizeof(HFSExtentKey
);
473 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
474 extentKeyPtr
->hfs
.forkType
= 0;
475 extentKeyPtr
->hfs
.fileID
= srcFileID
;
476 extentKeyPtr
->hfs
.startBlock
= 0;
480 // We do an initial BTSearchRecord to position the BTree's iterator just before any extent
481 // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found
482 // records, but with destFileID as the file number in the key. Keep doing this sequence of
483 // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are
484 // no more extent records in the tree.
486 // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID
487 // set to destFileID.
489 // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it
490 // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series
491 // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record
492 // we found, so that BTIterateRecord would get the next one (the first we haven't processed).
495 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
497 // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
498 if (err
!= btNotFound
)
501 DebugStr("Unexpected error from SearchBTreeRecord");
503 if (err
== noErr
) // If we found such a bogus extent record, then the tree is really messed up
504 err
= cmBadNews
; // so return an error that conveys the disk is hosed.
511 btRecord
.bufferAddress
= &extentData
;
512 btRecord
.itemCount
= 1;
514 for ( i
=0 ; i
<kNumExtentsToCache
; i
++ )
516 HFSCatalogNodeID foundFileID
;
518 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
519 if ( err
== btNotFound
) // Did we run out of extent records in the extents tree?
520 break; // if xkrFNum(A0) is cleared on this error, then this test is bogus!
521 else if ( err
!= noErr
)
522 return( err
); // must be ioError
524 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
525 if ( foundFileID
== srcFileID
) {
526 /* Check if we need to quit early. */
527 if (quitEarly
&& isHFSPlus
) {
528 if (extentKeyPtr
->hfsPlus
.forkType
!= forkType
) {
532 CopyExtentInfo(extentKeyPtr
, &extentData
, extentsBuffer
, i
);
535 /* The fileID's are of a different file. We're done here. */
540 //-- edit each extent key, and reinsert each extent record in the extent file
542 btRecordSize
= sizeof(HFSPlusExtentRecord
);
544 btRecordSize
= sizeof(HFSExtentRecord
);
546 for ( j
=0 ; j
<i
; j
++ ) {
547 BTreeIterator tmpIterator
;
550 extentsBuffer
[j
].extentKey
.hfsPlus
.fileID
= destFileID
; // change only the id in the key to dest ID
552 extentsBuffer
[j
].extentKey
.hfs
.fileID
= destFileID
; // change only the id in the key to dest ID
554 // get iterator and buffer descriptor ready...
555 (void) BTInvalidateHint(&tmpIterator
);
556 BlockMoveData(&(extentsBuffer
[j
].extentKey
), &tmpIterator
.key
, btKeySize
);
557 btRecord
.bufferAddress
= &(extentsBuffer
[j
].extentData
);
559 err
= BTInsertRecord(fcb
, &tmpIterator
, &btRecord
, btRecordSize
);
562 if ( err
== btExists
)
565 DebugStr("Can't insert record -- already exists");
573 //-- okay, done with this buffered batch, go get the next set of extent records
574 // If our buffer is not full, we must be done, or recieved an error
576 if ( i
!= kNumExtentsToCache
) // if the buffer is not full, we must be done
578 err
= DeleteExtents( vcb
, srcFileID
, forkType
, quitEarly
, isHFSPlus
); // Now delete all the extent entries with the sourceID
579 if ( DEBUG_BUILD
&& err
!= noErr
)
580 DebugStr("Error from DeleteExtents");
581 break; // we're done!
589 static void CopyExtentInfo( ExtentKey
*key
, ExtentRecord
*data
, ExtentsRecBuffer
*buffer
, u_int16_t bufferCount
)
591 BlockMoveData( key
, &(buffer
[bufferCount
].extentKey
), sizeof( ExtentKey
) );
592 BlockMoveData( data
, &(buffer
[bufferCount
].extentData
), sizeof( ExtentRecord
) );
598 //-- Delete all extents in extent file that have the ID given.
599 static OSErr
DeleteExtents( ExtendedVCB
*vcb
, u_int32_t fileID
, int quitEarly
, u_int8_t forkType
, Boolean isHFSPlus
)
602 ExtentKey
* extentKeyPtr
;
603 ExtentRecord extentData
;
604 BTreeIterator btIterator
;
605 FSBufferDescriptor btRecord
;
606 u_int16_t btRecordSize
;
609 fcb
= GetFileControlBlock(vcb
->extentsRefNum
);
611 (void) BTInvalidateHint(&btIterator
);
612 extentKeyPtr
= (ExtentKey
*) &btIterator
.key
;
613 btRecord
.bufferAddress
= &extentData
;
614 btRecord
.itemCount
= 1;
616 // The algorithm is to position the BTree just before any extent records for fileID.
617 // Then just keep getting successive records. If the record is still for fileID,
621 btRecord
.itemSize
= sizeof(HFSPlusExtentRecord
);
623 extentKeyPtr
->hfsPlus
.keyLength
= kHFSPlusExtentKeyMaximumLength
;
624 extentKeyPtr
->hfsPlus
.forkType
= forkType
;
625 extentKeyPtr
->hfsPlus
.pad
= 0;
626 extentKeyPtr
->hfsPlus
.fileID
= fileID
;
627 extentKeyPtr
->hfsPlus
.startBlock
= 0;
630 btRecord
.itemSize
= sizeof(HFSExtentRecord
);
632 extentKeyPtr
->hfs
.keyLength
= kHFSExtentKeyMaximumLength
;
633 extentKeyPtr
->hfs
.forkType
= forkType
;
634 extentKeyPtr
->hfs
.fileID
= fileID
;
635 extentKeyPtr
->hfs
.startBlock
= 0;
638 err
= BTSearchRecord(fcb
, &btIterator
, &btRecord
, &btRecordSize
, &btIterator
);
639 if ( err
!= btNotFound
)
641 if (err
== noErr
) { // Did we find a bogus extent record?
642 err
= cmBadNews
; // Yes, so indicate things are messed up.
645 return err
; // Got some unexpected error, so return it
650 BTreeIterator tmpIterator
;
651 HFSCatalogNodeID foundFileID
;
653 err
= BTIterateRecord(fcb
, kBTreeNextRecord
, &btIterator
, &btRecord
, &btRecordSize
);
656 if (err
== btNotFound
) // If we hit the end of the BTree
657 err
= noErr
; // then it's OK
659 break; // We're done now.
662 foundFileID
= isHFSPlus
? extentKeyPtr
->hfsPlus
.fileID
: extentKeyPtr
->hfs
.fileID
;
663 if ( foundFileID
!= fileID
) {
664 break; // numbers don't match, we must be done
666 if (quitEarly
&& isHFSPlus
) {
667 /* If we're only deleting one type of fork, then quit early if it doesn't match */
668 if (extentKeyPtr
->hfsPlus
.forkType
!= forkType
) {
673 tmpIterator
= btIterator
;
674 err
= BTDeleteRecord( fcb
, &tmpIterator
);
683 // Check if there are extents represented in the extents overflow file.
684 static u_int32_t
CheckExtents( void *extents
, u_int32_t totalBlocks
, Boolean isHFSPlus
)
686 u_int32_t extentAllocationBlocks
;
690 if ( totalBlocks
== 0 )
693 extentAllocationBlocks
= 0;
697 for ( i
= 0 ; i
< kHFSPlusExtentDensity
; i
++ )
699 extentAllocationBlocks
+= ((HFSPlusExtentDescriptor
*)extents
)[i
].blockCount
;
700 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
706 for ( i
= 0 ; i
< kHFSExtentDensity
; i
++ )
708 extentAllocationBlocks
+= ((HFSExtentDescriptor
*)extents
)[i
].blockCount
;
709 if ( extentAllocationBlocks
>= totalBlocks
) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
714 return( extentAllocationBlocks
);