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