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