]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Catalog/FileIDsServices.c
xnu-517.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Catalog / FileIDsServices.c
1 /*
2 * Copyright (c) 2000-2003 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25
26 #include "../../hfs_macos_defs.h"
27 #include "../../hfs_format.h"
28
29 #include "../headers/FileMgrInternal.h"
30 #include "../headers/HFSUnicodeWrappers.h"
31 #include "../headers/CatalogPrivate.h"
32
33
34 struct ExtentsRecBuffer {
35 ExtentKey extentKey;
36 ExtentRecord extentData;
37 };
38 typedef struct ExtentsRecBuffer ExtentsRecBuffer;
39
40
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 );
47
48
49
50 OSErr ExchangeFileIDs( ExtendedVCB *vcb, ConstUTF8Param srcName, ConstUTF8Param destName, HFSCatalogNodeID srcID, HFSCatalogNodeID destID, UInt32 srcHint, UInt32 destHint )
51 {
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;
59 OSErr err;
60 Boolean isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord );
61
62 TrashCatalogIterator(vcb, srcID); // invalidate any iterators for this parentID
63 TrashCatalogIterator(vcb, destID); // invalidate any iterators for this parentID
64
65 err = BuildCatalogKeyUTF8(vcb, srcID, srcName, kUndefinedStrLen, &srcKey, NULL);
66 ReturnIfError(err);
67
68 err = BuildCatalogKeyUTF8(vcb, destID, destName, kUndefinedStrLen, &destKey, NULL);
69 ReturnIfError(err);
70
71 if ( isHFSPlus )
72 {
73 //-- Step 1: Check the catalog nodes for extents
74
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 );
77 ReturnIfError( err );
78
79 if ( srcData.recordType != kHFSPlusFileRecord )
80 return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
81
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 );
87
88 //-- Check if there are any extents in the destination file
89 err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
90 ReturnIfError( err );
91
92 if ( destData.recordType != kHFSPlusFileRecord )
93 return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
94
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 );
98
99 //-- Step 2: Exchange the Extent key in the extent file
100
101 //-- Exchange the extents key in the extent file
102 err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
103 ReturnIfError( err );
104
105 if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents
106 {
107 //-- Change the source extents file ids to our known bogus value
108 err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, kHFSBogusExtentFileID, isHFSPlus );
109 if ( err != noErr )
110 {
111 if ( err != dskFulErr )
112 return( err );
113 else
114 goto ExUndo1a;
115 }
116
117 //-- Change the destination extents file id's to the source id's
118 err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus );
119 if ( err != noErr )
120 {
121 if ( err != dskFulErr )
122 return( err );
123
124 ExUndo2aPlus: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus );
125 ReturnIfError( err ); // we are doomed. Just QUIT!
126
127 err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back
128 ReturnIfError( err ); // we are doomed. Just QUIT!
129
130 goto ExUndo1a;
131 }
132
133 //-- Change the bogus extents file id's to the dest id's
134 err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsPlusFile.fileID, isHFSPlus );
135 if ( err != noErr )
136 {
137 if ( err != dskFulErr )
138 return( err );
139
140 err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus );
141 ReturnIfError( err ); // we are doomed. Just QUIT!
142
143 err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back
144 ReturnIfError( err ); // we are doomed. Just QUIT!
145
146 goto ExUndo2aPlus;
147 }
148
149 }
150 else if ( numSrcExtentBlocks ) // just the source file has extents
151 {
152 err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus );
153 if ( err != noErr )
154 {
155 if ( err != dskFulErr )
156 return( err );
157
158 err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus );
159 ReturnIfError( err ); // we are doomed. Just QUIT!
160
161 goto FlushAndReturn;
162 }
163 }
164 else if ( numDestExtentBlocks ) // just the destination file has extents
165 {
166 err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus );
167 if ( err != noErr )
168 {
169 if ( err != dskFulErr )
170 return( err );
171
172 err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus );
173 ReturnIfError( err ); // we are doomed. Just QUIT!
174
175 goto FlushAndReturn;
176 }
177 }
178
179 //-- Step 3: Change the data in the catalog nodes
180
181 //-- find the source cnode and put dest info in it
182 err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
183 if ( err != noErr )
184 return( cmBadNews );
185
186 BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) );
187 CopyBigCatalogNodeInfo( &destData, &srcData );
188
189 err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSPlusCatalogFile), &srcHint );
190 ReturnIfError( err );
191
192 // find the destination cnode and put source info in it
193 err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
194 if ( err != noErr )
195 return( cmBadNews );
196
197 CopyBigCatalogNodeInfo( &swapData, &destData );
198 err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSPlusCatalogFile), &destHint );
199 ReturnIfError( err );
200 }
201 else // HFS //
202 {
203 //-- Step 1: Check the catalog nodes for extents
204
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 );
208
209 if ( srcData.recordType != kHFSFileRecord )
210 return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
211
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 );
216
217
218 //\80\80 Do we save the found source node for later use?
219
220
221 //-- Check if there are any extents in the destination file
222 err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
223 ReturnIfError( err );
224
225 if ( destData.recordType != kHFSFileRecord )
226 return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
227
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 );
231
232 //\80\80 Do we save the found destination node for later use?
233
234
235 //-- Step 2: Exchange the Extent key in the extent file
236
237 //-- Exchange the extents key in the extent file
238 err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
239 ReturnIfError( err );
240
241 if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents
242 {
243 //-- Change the source extents file ids to our known bogus value
244 err = MoveExtents( vcb, srcData.hfsFile.fileID, kHFSBogusExtentFileID, isHFSPlus );
245 if ( err != noErr )
246 {
247 if ( err != dskFulErr )
248 return( err );
249
250 ExUndo1a: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
251 ReturnIfError( err ); // we are doomed. Just QUIT!
252
253 err = FlushCatalog( vcb ); // flush the catalog
254 err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap)
255 return( dskFulErr );
256 }
257
258 //-- Change the destination extents file id's to the source id's
259 err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus );
260 if ( err != noErr )
261 {
262 if ( err != dskFulErr )
263 return( err );
264
265 ExUndo2a: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus );
266 ReturnIfError( err ); // we are doomed. Just QUIT!
267
268 err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsFile.fileID, isHFSPlus ); // Move the extents back
269 ReturnIfError( err ); // we are doomed. Just QUIT!
270
271 goto ExUndo1a;
272 }
273
274 //-- Change the bogus extents file id's to the dest id's
275 err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsFile.fileID, isHFSPlus );
276 if ( err != noErr )
277 {
278 if ( err != dskFulErr )
279 return( err );
280
281 err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus );
282 ReturnIfError( err ); // we are doomed. Just QUIT!
283
284 err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus ); // Move the extents back
285 ReturnIfError( err ); // we are doomed. Just QUIT!
286
287 goto ExUndo2a;
288 }
289
290 }
291 else if ( numSrcExtentBlocks ) // just the source file has extents
292 {
293 err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus );
294 if ( err != noErr )
295 {
296 if ( err != dskFulErr )
297 return( err );
298
299 err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus );
300 ReturnIfError( err ); // we are doomed. Just QUIT!
301
302 goto FlushAndReturn;
303 }
304 }
305 else if ( numDestExtentBlocks ) // just the destination file has extents
306 {
307 err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus );
308 if ( err != noErr )
309 {
310 if ( err != dskFulErr )
311 return( err );
312
313 err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus );
314 ReturnIfError( err ); // we are doomed. Just QUIT!
315
316 goto FlushAndReturn;
317 }
318 }
319
320 //-- Step 3: Change the data in the catalog nodes
321
322 //-- find the source cnode and put dest info in it
323 err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
324 if ( err != noErr )
325 return( cmBadNews );
326
327 BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) );
328 //\80\80 Asm source copies from the saved dest catalog node
329 CopyCatalogNodeInfo( &destData, &srcData );
330
331 err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSCatalogFile), &srcHint );
332 ReturnIfError( err );
333
334
335 // find the destination cnode and put source info in it
336 err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
337 if ( err != noErr )
338 return( cmBadNews );
339
340 CopyCatalogNodeInfo( &swapData, &destData );
341 err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSCatalogFile), &destHint );
342 ReturnIfError( err );
343 }
344
345 err = noErr;
346
347 //-- Step 4: Error Handling section
348
349
350 FlushAndReturn:
351 err = FlushCatalog( vcb ); // flush the catalog
352 err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap)
353 return( err );
354 }
355
356
357 void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest )
358 {
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) );
366 }
367
368 void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest )
369 {
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;
373 }
374
375
376 OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus )
377 {
378 FCB * fcb;
379 ExtentsRecBuffer extentsBuffer[kNumExtentsToCache];
380 ExtentKey * extentKeyPtr;
381 ExtentRecord extentData;
382 BTreeIterator btIterator;
383 FSBufferDescriptor btRecord;
384 UInt16 btKeySize;
385 UInt16 btRecordSize;
386 SInt16 i, j;
387 OSErr err;
388
389
390 fcb = GetFileControlBlock(vcb->extentsRefNum);
391
392 (void) BTInvalidateHint(&btIterator);
393 extentKeyPtr = (ExtentKey*) &btIterator.key;
394 btRecord.bufferAddress = &extentData;
395 btRecord.itemCount = 1;
396
397 //-- Collect the extent records
398
399 //
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
404 // record).
405 //
406 // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
407 //
408 if (isHFSPlus) {
409 btRecord.itemSize = sizeof(HFSPlusExtentRecord);
410 btKeySize = sizeof(HFSPlusExtentKey);
411
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;
417 }
418 else {
419 btRecord.itemSize = sizeof(HFSExtentRecord);
420 btKeySize = sizeof(HFSExtentKey);
421
422 extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength;
423 extentKeyPtr->hfs.forkType = 0;
424 extentKeyPtr->hfs.fileID = srcFileID;
425 extentKeyPtr->hfs.startBlock = 0;
426 }
427
428 //
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.
434 //
435 // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID
436 // set to destFileID.
437 //
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).
442 //
443
444 err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator);
445
446 // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
447 if (err != btNotFound)
448 {
449 if ( DEBUG_BUILD )
450 DebugStr("\pUnexpected error from SearchBTreeRecord");
451
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.
454
455 return err;
456 }
457
458 do
459 {
460 btRecord.bufferAddress = &extentData;
461 btRecord.itemCount = 1;
462
463 for ( i=0 ; i<kNumExtentsToCache ; i++ )
464 {
465 HFSCatalogNodeID foundFileID;
466
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
472
473 foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
474 if ( foundFileID == srcFileID )
475 {
476 CopyExtentInfo(extentKeyPtr, &extentData, extentsBuffer, i);
477 }
478 else
479 {
480 break;
481 }
482 }
483
484 //-- edit each extent key, and reinsert each extent record in the extent file
485 if (isHFSPlus)
486 btRecordSize = sizeof(HFSPlusExtentRecord);
487 else
488 btRecordSize = sizeof(HFSExtentRecord);
489
490 for ( j=0 ; j<i ; j++ )
491 {
492 BTreeIterator tmpIterator;
493
494 if (isHFSPlus)
495 extentsBuffer[j].extentKey.hfsPlus.fileID = destFileID; // change only the id in the key to dest ID
496 else
497 extentsBuffer[j].extentKey.hfs.fileID = destFileID; // change only the id in the key to dest ID
498
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);
503
504 err = BTInsertRecord(fcb, &tmpIterator, &btRecord, btRecordSize);
505 if ( err != noErr )
506 { // parse the error
507 if ( err == btExists )
508 {
509 if ( DEBUG_BUILD )
510 DebugStr("\pCan't insert record -- already exists");
511 return( cmBadNews );
512 }
513 else
514 return( err );
515 }
516 }
517
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
520
521 if ( i != kNumExtentsToCache ) // if the buffer is not full, we must be done
522 {
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!
527 }
528 } while ( true );
529
530 return( err );
531 }
532
533
534 void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount )
535 {
536 BlockMoveData( key, &(buffer[bufferCount].extentKey), sizeof( ExtentKey ) );
537 BlockMoveData( data, &(buffer[bufferCount].extentData), sizeof( ExtentRecord ) );
538 }
539
540
541 //-- Delete all extents in extent file that have the ID given.
542 OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileID, Boolean isHFSPlus )
543 {
544 FCB * fcb;
545 ExtentKey * extentKeyPtr;
546 ExtentRecord extentData;
547 BTreeIterator btIterator;
548 FSBufferDescriptor btRecord;
549 UInt16 btRecordSize;
550 OSErr err;
551
552 fcb = GetFileControlBlock(vcb->extentsRefNum);
553
554 (void) BTInvalidateHint(&btIterator);
555 extentKeyPtr = (ExtentKey*) &btIterator.key;
556 btRecord.bufferAddress = &extentData;
557 btRecord.itemCount = 1;
558
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,
561 // then delete it.
562
563 if (isHFSPlus) {
564 btRecord.itemSize = sizeof(HFSPlusExtentRecord);
565
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;
571 }
572 else {
573 btRecord.itemSize = sizeof(HFSExtentRecord);
574
575 extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength;
576 extentKeyPtr->hfs.forkType = 0;
577 extentKeyPtr->hfs.fileID = fileID;
578 extentKeyPtr->hfs.startBlock = 0;
579 }
580
581 err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator);
582 if ( err != btNotFound )
583 {
584 if (err == noErr) { // Did we find a bogus extent record?
585 err = cmBadNews; // Yes, so indicate things are messed up.
586 }
587
588 return err; // Got some unexpected error, so return it
589 }
590
591 do
592 {
593 BTreeIterator tmpIterator;
594 HFSCatalogNodeID foundFileID;
595
596 err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
597 if ( err != noErr )
598 {
599 if (err == btNotFound) // If we hit the end of the BTree
600 err = noErr; // then it's OK
601
602 break; // We're done now.
603 }
604
605 foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
606 if ( foundFileID != fileID )
607 break; // numbers don't match, we must be done
608
609 tmpIterator = btIterator;
610 err = BTDeleteRecord( fcb, &tmpIterator );
611 if (err != noErr)
612 break;
613 } while ( true );
614
615 return( err );
616 }
617
618
619 // Check if there are extents represented in the extents overflow file.
620 UInt32 CheckExtents( void *extents, UInt32 totalBlocks, Boolean isHFSPlus )
621 {
622 UInt32 extentAllocationBlocks;
623 UInt16 i;
624
625
626 if ( totalBlocks == 0 )
627 return( 0 );
628
629 extentAllocationBlocks = 0;
630
631 if ( isHFSPlus )
632 {
633 for ( i = 0 ; i < kHFSPlusExtentDensity ; i++ )
634 {
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)
637 return( 0 );
638 }
639 }
640 else
641 {
642 for ( i = 0 ; i < kHFSExtentDensity ; i++ )
643 {
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)
646 return( 0 );
647 }
648 }
649
650 return( extentAllocationBlocks );
651 }