]> git.saurik.com Git - apple/xnu.git/blob - bsd/hfs/hfscommon/Catalog/FileIDsServices.c
xnu-792.6.56.tar.gz
[apple/xnu.git] / bsd / hfs / hfscommon / Catalog / FileIDsServices.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24 #include "../../hfs_macos_defs.h"
25 #include "../../hfs_format.h"
26
27 #include "../headers/FileMgrInternal.h"
28 #include "../headers/HFSUnicodeWrappers.h"
29 #include "../headers/CatalogPrivate.h"
30
31
32 struct ExtentsRecBuffer {
33 ExtentKey extentKey;
34 ExtentRecord extentData;
35 };
36 typedef struct ExtentsRecBuffer ExtentsRecBuffer;
37
38
39 static UInt32 CheckExtents( void *extents, UInt32 blocks, Boolean isHFSPlus );
40 static OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileNumber, Boolean isHFSPlus );
41 static OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus );
42 static void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest );
43 static void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest );
44 static void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount );
45
46
47
48 OSErr ExchangeFileIDs( ExtendedVCB *vcb, ConstUTF8Param srcName, ConstUTF8Param destName, HFSCatalogNodeID srcID, HFSCatalogNodeID destID, UInt32 srcHint, UInt32 destHint )
49 {
50 CatalogKey srcKey; // 518 bytes
51 CatalogKey destKey; // 518 bytes
52 CatalogRecord srcData; // 520 bytes
53 CatalogRecord destData; // 520 bytes
54 CatalogRecord swapData; // 520 bytes
55 SInt16 numSrcExtentBlocks;
56 SInt16 numDestExtentBlocks;
57 OSErr err;
58 Boolean isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord );
59
60 err = BuildCatalogKeyUTF8(vcb, srcID, srcName, kUndefinedStrLen, &srcKey, NULL);
61 ReturnIfError(err);
62
63 err = BuildCatalogKeyUTF8(vcb, destID, destName, kUndefinedStrLen, &destKey, NULL);
64 ReturnIfError(err);
65
66 if ( isHFSPlus )
67 {
68 //-- Step 1: Check the catalog nodes for extents
69
70 //-- locate the source file, test for extents in extent file, and copy the cat record for later
71 err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
72 ReturnIfError( err );
73
74 if ( srcData.recordType != kHFSPlusFileRecord )
75 return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
76
77 //-- Check if there are any extents in the source file
78 //\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
79 numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.dataFork.extents, srcData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus );
80 if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents
81 numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.resourceFork.extents, srcData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus );
82
83 //-- Check if there are any extents in the destination file
84 err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
85 ReturnIfError( err );
86
87 if ( destData.recordType != kHFSPlusFileRecord )
88 return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
89
90 numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.dataFork.extents, destData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus );
91 if ( numDestExtentBlocks == 0 ) // then check the resource fork extents
92 numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.resourceFork.extents, destData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus );
93
94 //-- Step 2: Exchange the Extent key in the extent file
95
96 //-- Exchange the extents key in the extent file
97 err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
98 ReturnIfError( err );
99
100 if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents
101 {
102 //-- Change the source extents file ids to our known bogus value
103 err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, kHFSBogusExtentFileID, isHFSPlus );
104 if ( err != noErr )
105 {
106 if ( err != dskFulErr )
107 return( err );
108 else
109 goto ExUndo1a;
110 }
111
112 //-- Change the destination extents file id's to the source id's
113 err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus );
114 if ( err != noErr )
115 {
116 if ( err != dskFulErr )
117 return( err );
118
119 ExUndo2aPlus: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus );
120 ReturnIfError( err ); // we are doomed. Just QUIT!
121
122 err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back
123 ReturnIfError( err ); // we are doomed. Just QUIT!
124
125 goto ExUndo1a;
126 }
127
128 //-- Change the bogus extents file id's to the dest id's
129 err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsPlusFile.fileID, isHFSPlus );
130 if ( err != noErr )
131 {
132 if ( err != dskFulErr )
133 return( err );
134
135 err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus );
136 ReturnIfError( err ); // we are doomed. Just QUIT!
137
138 err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back
139 ReturnIfError( err ); // we are doomed. Just QUIT!
140
141 goto ExUndo2aPlus;
142 }
143
144 }
145 else if ( numSrcExtentBlocks ) // just the source file has extents
146 {
147 err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus );
148 if ( err != noErr )
149 {
150 if ( err != dskFulErr )
151 return( err );
152
153 err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus );
154 ReturnIfError( err ); // we are doomed. Just QUIT!
155
156 goto FlushAndReturn;
157 }
158 }
159 else if ( numDestExtentBlocks ) // just the destination file has extents
160 {
161 err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus );
162 if ( err != noErr )
163 {
164 if ( err != dskFulErr )
165 return( err );
166
167 err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus );
168 ReturnIfError( err ); // we are doomed. Just QUIT!
169
170 goto FlushAndReturn;
171 }
172 }
173
174 //-- Step 3: Change the data in the catalog nodes
175
176 //-- find the source cnode and put dest info in it
177 err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
178 if ( err != noErr )
179 return( cmBadNews );
180
181 BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) );
182 CopyBigCatalogNodeInfo( &destData, &srcData );
183
184 err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSPlusCatalogFile), &srcHint );
185 ReturnIfError( err );
186
187 // find the destination cnode and put source info in it
188 err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
189 if ( err != noErr )
190 return( cmBadNews );
191
192 CopyBigCatalogNodeInfo( &swapData, &destData );
193 err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSPlusCatalogFile), &destHint );
194 ReturnIfError( err );
195 }
196 else // HFS //
197 {
198 //-- Step 1: Check the catalog nodes for extents
199
200 //-- locate the source file, test for extents in extent file, and copy the cat record for later
201 err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
202 ReturnIfError( err );
203
204 if ( srcData.recordType != kHFSFileRecord )
205 return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
206
207 //-- Check if there are any extents in the source file
208 numSrcExtentBlocks = CheckExtents( srcData.hfsFile.dataExtents, srcData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus );
209 if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents
210 numSrcExtentBlocks = CheckExtents( srcData.hfsFile.rsrcExtents, srcData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus );
211
212
213 //\80\80 Do we save the found source node for later use?
214
215
216 //-- Check if there are any extents in the destination file
217 err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
218 ReturnIfError( err );
219
220 if ( destData.recordType != kHFSFileRecord )
221 return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
222
223 numDestExtentBlocks = CheckExtents( destData.hfsFile.dataExtents, destData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus );
224 if ( numDestExtentBlocks == 0 ) // then check the resource fork extents
225 numDestExtentBlocks = CheckExtents( destData.hfsFile.rsrcExtents, destData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus );
226
227 //\80\80 Do we save the found destination node for later use?
228
229
230 //-- Step 2: Exchange the Extent key in the extent file
231
232 //-- Exchange the extents key in the extent file
233 err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
234 ReturnIfError( err );
235
236 if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents
237 {
238 //-- Change the source extents file ids to our known bogus value
239 err = MoveExtents( vcb, srcData.hfsFile.fileID, kHFSBogusExtentFileID, isHFSPlus );
240 if ( err != noErr )
241 {
242 if ( err != dskFulErr )
243 return( err );
244
245 ExUndo1a: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
246 ReturnIfError( err ); // we are doomed. Just QUIT!
247
248 err = FlushCatalog( vcb ); // flush the catalog
249 err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap)
250 return( dskFulErr );
251 }
252
253 //-- Change the destination extents file id's to the source id's
254 err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus );
255 if ( err != noErr )
256 {
257 if ( err != dskFulErr )
258 return( err );
259
260 ExUndo2a: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus );
261 ReturnIfError( err ); // we are doomed. Just QUIT!
262
263 err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsFile.fileID, isHFSPlus ); // Move the extents back
264 ReturnIfError( err ); // we are doomed. Just QUIT!
265
266 goto ExUndo1a;
267 }
268
269 //-- Change the bogus extents file id's to the dest id's
270 err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsFile.fileID, isHFSPlus );
271 if ( err != noErr )
272 {
273 if ( err != dskFulErr )
274 return( err );
275
276 err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus );
277 ReturnIfError( err ); // we are doomed. Just QUIT!
278
279 err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus ); // Move the extents back
280 ReturnIfError( err ); // we are doomed. Just QUIT!
281
282 goto ExUndo2a;
283 }
284
285 }
286 else if ( numSrcExtentBlocks ) // just the source file has extents
287 {
288 err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus );
289 if ( err != noErr )
290 {
291 if ( err != dskFulErr )
292 return( err );
293
294 err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus );
295 ReturnIfError( err ); // we are doomed. Just QUIT!
296
297 goto FlushAndReturn;
298 }
299 }
300 else if ( numDestExtentBlocks ) // just the destination file has extents
301 {
302 err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus );
303 if ( err != noErr )
304 {
305 if ( err != dskFulErr )
306 return( err );
307
308 err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus );
309 ReturnIfError( err ); // we are doomed. Just QUIT!
310
311 goto FlushAndReturn;
312 }
313 }
314
315 //-- Step 3: Change the data in the catalog nodes
316
317 //-- find the source cnode and put dest info in it
318 err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
319 if ( err != noErr )
320 return( cmBadNews );
321
322 BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) );
323 //\80\80 Asm source copies from the saved dest catalog node
324 CopyCatalogNodeInfo( &destData, &srcData );
325
326 err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSCatalogFile), &srcHint );
327 ReturnIfError( err );
328
329
330 // find the destination cnode and put source info in it
331 err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
332 if ( err != noErr )
333 return( cmBadNews );
334
335 CopyCatalogNodeInfo( &swapData, &destData );
336 err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSCatalogFile), &destHint );
337 ReturnIfError( err );
338 }
339
340 err = noErr;
341
342 //-- Step 4: Error Handling section
343
344
345 FlushAndReturn:
346 err = FlushCatalog( vcb ); // flush the catalog
347 err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap)
348 return( err );
349 }
350
351
352 static void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest )
353 {
354 dest->hfsFile.dataLogicalSize = src->hfsFile.dataLogicalSize;
355 dest->hfsFile.dataPhysicalSize = src->hfsFile.dataPhysicalSize;
356 dest->hfsFile.rsrcLogicalSize = src->hfsFile.rsrcLogicalSize;
357 dest->hfsFile.rsrcPhysicalSize = src->hfsFile.rsrcPhysicalSize;
358 dest->hfsFile.modifyDate = src->hfsFile.modifyDate;
359 BlockMoveData( src->hfsFile.dataExtents, dest->hfsFile.dataExtents, sizeof(HFSExtentRecord) );
360 BlockMoveData( src->hfsFile.rsrcExtents, dest->hfsFile.rsrcExtents, sizeof(HFSExtentRecord) );
361 }
362
363 static void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest )
364 {
365 BlockMoveData( &src->hfsPlusFile.dataFork, &dest->hfsPlusFile.dataFork, sizeof(HFSPlusForkData) );
366 BlockMoveData( &src->hfsPlusFile.resourceFork, &dest->hfsPlusFile.resourceFork, sizeof(HFSPlusForkData) );
367 dest->hfsPlusFile.contentModDate = src->hfsPlusFile.contentModDate;
368 }
369
370
371 static OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus )
372 {
373 FCB * fcb;
374 ExtentsRecBuffer extentsBuffer[kNumExtentsToCache];
375 ExtentKey * extentKeyPtr;
376 ExtentRecord extentData;
377 BTreeIterator btIterator;
378 FSBufferDescriptor btRecord;
379 UInt16 btKeySize;
380 UInt16 btRecordSize;
381 SInt16 i, j;
382 OSErr err;
383
384
385 fcb = GetFileControlBlock(vcb->extentsRefNum);
386
387 (void) BTInvalidateHint(&btIterator);
388 extentKeyPtr = (ExtentKey*) &btIterator.key;
389 btRecord.bufferAddress = &extentData;
390 btRecord.itemCount = 1;
391
392 //-- Collect the extent records
393
394 //
395 // A search on the following key will cause the BTree to be positioned immediately
396 // before the first extent record for file #srcFileID, but not actually positioned
397 // on any record. This is because there cannot be an extent record with FABN = 0
398 // (the first extent of the fork, which would be in the catalog entry, not an extent
399 // record).
400 //
401 // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
402 //
403 if (isHFSPlus) {
404 btRecord.itemSize = sizeof(HFSPlusExtentRecord);
405 btKeySize = sizeof(HFSPlusExtentKey);
406
407 extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength;
408 extentKeyPtr->hfsPlus.forkType = 0;
409 extentKeyPtr->hfsPlus.pad = 0;
410 extentKeyPtr->hfsPlus.fileID = srcFileID;
411 extentKeyPtr->hfsPlus.startBlock = 0;
412 }
413 else {
414 btRecord.itemSize = sizeof(HFSExtentRecord);
415 btKeySize = sizeof(HFSExtentKey);
416
417 extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength;
418 extentKeyPtr->hfs.forkType = 0;
419 extentKeyPtr->hfs.fileID = srcFileID;
420 extentKeyPtr->hfs.startBlock = 0;
421 }
422
423 //
424 // We do an initial BTSearchRecord to position the BTree's iterator just before any extent
425 // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found
426 // records, but with destFileID as the file number in the key. Keep doing this sequence of
427 // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are
428 // no more extent records in the tree.
429 //
430 // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID
431 // set to destFileID.
432 //
433 // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it
434 // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series
435 // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record
436 // we found, so that BTIterateRecord would get the next one (the first we haven't processed).
437 //
438
439 err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator);
440
441 // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
442 if (err != btNotFound)
443 {
444 if ( DEBUG_BUILD )
445 DebugStr("\pUnexpected error from SearchBTreeRecord");
446
447 if (err == noErr) // If we found such a bogus extent record, then the tree is really messed up
448 err = cmBadNews; // so return an error that conveys the disk is hosed.
449
450 return err;
451 }
452
453 do
454 {
455 btRecord.bufferAddress = &extentData;
456 btRecord.itemCount = 1;
457
458 for ( i=0 ; i<kNumExtentsToCache ; i++ )
459 {
460 HFSCatalogNodeID foundFileID;
461
462 err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
463 if ( err == btNotFound ) // Did we run out of extent records in the extents tree?
464 break; // if xkrFNum(A0) is cleared on this error, then this test is bogus!
465 else if ( err != noErr )
466 return( err ); // must be ioError
467
468 foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
469 if ( foundFileID == srcFileID )
470 {
471 CopyExtentInfo(extentKeyPtr, &extentData, extentsBuffer, i);
472 }
473 else
474 {
475 break;
476 }
477 }
478
479 //-- edit each extent key, and reinsert each extent record in the extent file
480 if (isHFSPlus)
481 btRecordSize = sizeof(HFSPlusExtentRecord);
482 else
483 btRecordSize = sizeof(HFSExtentRecord);
484
485 for ( j=0 ; j<i ; j++ )
486 {
487 BTreeIterator tmpIterator;
488
489 if (isHFSPlus)
490 extentsBuffer[j].extentKey.hfsPlus.fileID = destFileID; // change only the id in the key to dest ID
491 else
492 extentsBuffer[j].extentKey.hfs.fileID = destFileID; // change only the id in the key to dest ID
493
494 // get iterator and buffer descriptor ready...
495 (void) BTInvalidateHint(&tmpIterator);
496 BlockMoveData(&(extentsBuffer[j].extentKey), &tmpIterator.key, btKeySize);
497 btRecord.bufferAddress = &(extentsBuffer[j].extentData);
498
499 err = BTInsertRecord(fcb, &tmpIterator, &btRecord, btRecordSize);
500 if ( err != noErr )
501 { // parse the error
502 if ( err == btExists )
503 {
504 if ( DEBUG_BUILD )
505 DebugStr("\pCan't insert record -- already exists");
506 return( cmBadNews );
507 }
508 else
509 return( err );
510 }
511 }
512
513 //-- okay, done with this buffered batch, go get the next set of extent records
514 // If our buffer is not full, we must be done, or recieved an error
515
516 if ( i != kNumExtentsToCache ) // if the buffer is not full, we must be done
517 {
518 err = DeleteExtents( vcb, srcFileID, isHFSPlus ); // Now delete all the extent entries with the sourceID
519 if ( DEBUG_BUILD && err != noErr )
520 DebugStr("\pError from DeleteExtents");
521 break; // we're done!
522 }
523 } while ( true );
524
525 return( err );
526 }
527
528
529 static void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount )
530 {
531 BlockMoveData( key, &(buffer[bufferCount].extentKey), sizeof( ExtentKey ) );
532 BlockMoveData( data, &(buffer[bufferCount].extentData), sizeof( ExtentRecord ) );
533 }
534
535
536 //-- Delete all extents in extent file that have the ID given.
537 static OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileID, Boolean isHFSPlus )
538 {
539 FCB * fcb;
540 ExtentKey * extentKeyPtr;
541 ExtentRecord extentData;
542 BTreeIterator btIterator;
543 FSBufferDescriptor btRecord;
544 UInt16 btRecordSize;
545 OSErr err;
546
547 fcb = GetFileControlBlock(vcb->extentsRefNum);
548
549 (void) BTInvalidateHint(&btIterator);
550 extentKeyPtr = (ExtentKey*) &btIterator.key;
551 btRecord.bufferAddress = &extentData;
552 btRecord.itemCount = 1;
553
554 // The algorithm is to position the BTree just before any extent records for fileID.
555 // Then just keep getting successive records. If the record is still for fileID,
556 // then delete it.
557
558 if (isHFSPlus) {
559 btRecord.itemSize = sizeof(HFSPlusExtentRecord);
560
561 extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength;
562 extentKeyPtr->hfsPlus.forkType = 0;
563 extentKeyPtr->hfsPlus.pad = 0;
564 extentKeyPtr->hfsPlus.fileID = fileID;
565 extentKeyPtr->hfsPlus.startBlock = 0;
566 }
567 else {
568 btRecord.itemSize = sizeof(HFSExtentRecord);
569
570 extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength;
571 extentKeyPtr->hfs.forkType = 0;
572 extentKeyPtr->hfs.fileID = fileID;
573 extentKeyPtr->hfs.startBlock = 0;
574 }
575
576 err = BTSearchRecord(fcb, &btIterator, &btRecord, &btRecordSize, &btIterator);
577 if ( err != btNotFound )
578 {
579 if (err == noErr) { // Did we find a bogus extent record?
580 err = cmBadNews; // Yes, so indicate things are messed up.
581 }
582
583 return err; // Got some unexpected error, so return it
584 }
585
586 do
587 {
588 BTreeIterator tmpIterator;
589 HFSCatalogNodeID foundFileID;
590
591 err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
592 if ( err != noErr )
593 {
594 if (err == btNotFound) // If we hit the end of the BTree
595 err = noErr; // then it's OK
596
597 break; // We're done now.
598 }
599
600 foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
601 if ( foundFileID != fileID )
602 break; // numbers don't match, we must be done
603
604 tmpIterator = btIterator;
605 err = BTDeleteRecord( fcb, &tmpIterator );
606 if (err != noErr)
607 break;
608 } while ( true );
609
610 return( err );
611 }
612
613
614 // Check if there are extents represented in the extents overflow file.
615 static UInt32 CheckExtents( void *extents, UInt32 totalBlocks, Boolean isHFSPlus )
616 {
617 UInt32 extentAllocationBlocks;
618 UInt16 i;
619
620
621 if ( totalBlocks == 0 )
622 return( 0 );
623
624 extentAllocationBlocks = 0;
625
626 if ( isHFSPlus )
627 {
628 for ( i = 0 ; i < kHFSPlusExtentDensity ; i++ )
629 {
630 extentAllocationBlocks += ((HFSPlusExtentDescriptor *)extents)[i].blockCount;
631 if ( extentAllocationBlocks >= totalBlocks ) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
632 return( 0 );
633 }
634 }
635 else
636 {
637 for ( i = 0 ; i < kHFSExtentDensity ; i++ )
638 {
639 extentAllocationBlocks += ((HFSExtentDescriptor *)extents)[i].blockCount;
640 if ( extentAllocationBlocks >= totalBlocks ) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
641 return( 0 );
642 }
643 }
644
645 return( extentAllocationBlocks );
646 }