|
|
1.1 root 1: /*
2: * Copyright (c) 2000 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: File: FileIDServices.c
24:
25: Contains: File ID manipulating routines.
26:
27: Version: HFS Plus 1.0
28:
29: Written by: Deric Horn
30:
31: Copyright: � 1996-1999 by Apple Computer, Inc., all rights reserved.
32:
33: File Ownership:
34:
35: DRI: Deric Horn
36:
37: Other Contact: xxx put other contact here xxx
38:
39: Technology: xxx put technology here xxx
40:
41: Writers:
42:
43: (JL) Jim Luther
44: (msd) Mark Day
45: (djb) Don Brady
46: (DSH) Deric Horn
47:
48: Change History (most recent first):
49: <MacOSX> 3/2/98 djb Fix extents corruption bug in MoveExtents (radar #2309434).
50: <MacOSX> 11/20/98 djb Add support for UTF-8 names.
51: <MacOSX> 4/2/98 djb Switch over to real BTree interface in MoveExtents and DeleteExtents.
52: <MacOSX> 3/31/98 djb Sync up with final HFSVolumes.h header file.
53:
54: <CS21> 11/17/97 djb PrepareInputName routine now returns an error.
55: <CS20> 11/13/97 djb Radar #2001699 ResolveFileID needs to use CMNotFound error.
56: <CS19> 10/31/97 JL #2000184 - CreateFileThreadID and ExchangeFiles now return the
57: WDCBRecPtr or NULL for external file systems. ExchangeFiles no
58: longer returns length of FCB table to caller since that wasn't
59: ever needed.
60: <18> 10/23/97 DSH 1685058, Fix ExchangeFiles by invalidating the node cache before
61: switching the files.
62: <CS17> 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate.
63: <CS16> 10/16/97 DSH Return badFidErr in ResolveFileID if LocateCatalogThread fails
64: <CS15> 10/15/97 DSH CreateFileThreadID(), remap btExists to fidExists.
65: <CS14> 9/7/97 djb Turn off some DebugStr calls.
66: <CS13> 9/4/97 msd Remove call to PropertyExchangeObjects.
67: <CS12> 8/14/97 djb Remove hard link support.
68: <CS11> 7/18/97 msd Include LowMemPriv.h.
69: <CS10> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name
70: collision
71: <CS9> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line
72: <CS8> 6/24/97 djb Add hard link support to ResolveFileID and CreateFileIDRef.
73: <CS7> 6/20/97 msd Use contentModDate and attributeModDate fields instead of
74: modifyDate.
75: <CS6> 6/13/97 djb Switch over from PrepareOutputName to ConvertUnicodeToHFSName.
76: PrepareInputName now takes an encoding.
77: <CS5> 5/28/97 msd Move the declaration of FindFileName to FilesInternal.i.
78: <CS4> 5/19/97 djb No longer need to invalidate vcbDirIDM field.
79: <CS3> 5/16/97 msd In ExchangeFiles, change srcNamePtr from char * to StringPtr
80: (fixes warnings).
81: <CS2> 4/28/97 djb (DSH) Added VolumeWritable check back into CreateFileIDThread.
82: <CS1> 4/24/97 djb first checked in
83: <HFS23> 4/11/97 DSH Use extended VCB fields catalogRefNum, and extentsRefNum.
84: <HFS22> 4/9/97 msd Rewrite CreateFileThreadID so that it properly handles
85: pathnames, and doesn't overwrite the ioNamePtr. The data field
86: of FindFileNameGlueRec points to a CatalogNodeData, not
87: CatalogRecord.
88: <HFS21> 4/4/97 djb Get in sync with volume format changes.
89: <HFS20> 3/31/97 djb Change ClearMem to ClearMemory.
90: <HFS19> 3/17/97 DSH C_FlushCache prototype to FilesInternal.h
91: <HFS18> 3/5/97 msd ExchangeFiles needs to call PropertyExchangeObjects.
92: <HFS17> 2/13/97 msd Fix MoveExtents and DeleteExtents to work with HFS+ extent
93: records.
94: <HFS16> 1/31/97 msd In MoveExtents, when a record isn't found and you want the next
95: record in order, use the "next record" offset = 1 instead of
96: "current record" offset = 0. DeleteExtents would always exit
97: without doing anything because it was searching for an invalid
98: key. Removed several DebugStrs that were used as cheap code
99: coverage.
100: <HFS15> 1/15/97 DSH Resolve wasn't passing the name back for HFS
101: <HFS14> 1/13/97 djb LocateCatalogThread now passes back the thread record size.
102: <HFS13> 1/11/97 DSH HFS+, fixed some Unicode/Pascal strings related bugs for use on
103: HFS+ volumes.
104: <HFS12> 1/9/97 DSH Fix ExchangeFiles extents
105: <HFS11> 1/6/97 DSH pass VCB in CloseFile() routine.
106: <HFS10> 1/6/97 djb Fixed ResolveFileID - it was not returning a directory ID!
107: <HFS9> 1/3/97 msd Fix prototype for C_FlushCache. Fix prototype for
108: TrashFileBlocks.
109: <HFS8> 1/3/97 djb Integrate latest HFSVolumesPriv.h changes.
110: <HFS7> 1/2/97 DSH C port of ExchangeFileIDs
111: <HFS6> 12/20/96 djb Fixed bug in CreateFileID.
112: <HFS5> 12/19/96 DSH All refs to VCB are now refs to ExtendedVCB
113: <HFS4> 12/19/96 msd Use kFileThreadExistsMask (from HFSVolumesPriv.h) instead of
114: kFileThreadMask (from FilesInternal.h) since the latter was
115: incorrectly defined and has now been removed.
116: <HFS3> 12/19/96 djb Updated for new B-tree Manager interface.
117: <HFS2> 12/18/96 msd GetFileThreadID was using a bitwise-OR (|) instead of
118: bitwise-AND (&) to test for a bit being set.
119: <HFS1> 12/12/96 DSH first checked in
120:
121: */
122:
123: #include "../../hfs_macos_defs.h"
124: #include "../../hfs_format.h"
125:
126: #include "../headers/FileMgrInternal.h"
127: #include "../headers/HFSUnicodeWrappers.h"
128: #include "../headers/CatalogPrivate.h"
129:
130:
131: struct ExtentsRecBuffer {
132: ExtentKey extentKey;
133: ExtentRecord extentData;
134: };
135: typedef struct ExtentsRecBuffer ExtentsRecBuffer;
136:
137:
138: OSErr CreateFileID( ExtendedVCB *vcb, HFSCatalogNodeID fileID, CatalogName *name, HFSCatalogNodeID *threadID );
139: OSErr GetFileThreadID( ExtendedVCB *vcb, HFSCatalogNodeID id, const CatalogName *name, Boolean isHFSPlus, UInt32 *threadID );
140:
141: UInt32 CheckExtents( void *extents, UInt32 blocks, Boolean isHFSPlus );
142: OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileNumber, Boolean isHFSPlus );
143: OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus );
144: void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest );
145: void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest );
146:
147: void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount );
148: extern void TrashFileBlocks( ExtendedVCB *vcb, UInt32 fileNumber );
149:
150:
151:
152: OSErr ExchangeFileIDs( ExtendedVCB *vcb, ConstUTF8Param srcName, ConstUTF8Param destName, HFSCatalogNodeID srcID, HFSCatalogNodeID destID, UInt32 srcHint, UInt32 destHint )
153: {
154: CatalogKey srcKey; // 518 bytes
155: CatalogRecord srcData; // 520 bytes
156: CatalogKey destKey; // 518 bytes
157: CatalogRecord destData; // 520 bytes
158: CatalogRecord swapData; // 520 bytes
159: SInt16 numSrcExtentBlocks;
160: SInt16 numDestExtentBlocks;
161: UInt32 textEncoding;
162: OSErr err;
163: Boolean isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord );
164:
165: TrashCatalogIterator(vcb, srcID); // invalidate any iterators for this parentID
166: TrashCatalogIterator(vcb, destID); // invalidate any iterators for this parentID
167:
168: err = BuildCatalogKeyUTF8(vcb, srcID, srcName, kUndefinedStrLen, &srcKey, &textEncoding);
169: ReturnIfError(err);
170:
171: err = BuildCatalogKeyUTF8(vcb, destID, destName, kUndefinedStrLen, &destKey, &textEncoding);
172: ReturnIfError(err);
173:
174: if ( isHFSPlus )
175: {
176: //-- Step 1: Check the catalog nodes for extents
177:
178: //-- locate the source file, test for extents in extent file, and copy the cat record for later
179: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
180: ReturnIfError( err );
181:
182: if ( srcData.recordType != kHFSPlusFileRecord )
183: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
184:
185: //-- Check if there are any extents in the source file
186: //�� I am only checling the extents in the low 32 bits, routine will fail if files extents after 2 gig are in overflow
187: numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.dataFork.extents, srcData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus );
188: if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents
189: numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.resourceFork.extents, srcData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus );
190:
191: //-- Check if there are any extents in the destination file
192: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
193: ReturnIfError( err );
194:
195: if ( destData.recordType != kHFSPlusFileRecord )
196: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
197:
198: numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.dataFork.extents, destData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus );
199: if ( numDestExtentBlocks == 0 ) // then check the resource fork extents
200: numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.resourceFork.extents, destData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus );
201:
202: //-- Step 2: Exchange the Extent key in the extent file
203:
204: //-- Exchange the extents key in the extent file
205: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
206: ReturnIfError( err );
207:
208: if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents
209: {
210: //-- Change the source extents file ids to our known bogus value
211: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, kHFSBogusExtentFileID, isHFSPlus );
212: if ( err != noErr )
213: {
214: if ( err != dskFulErr )
215: return( err );
216: else
217: goto ExUndo1a;
218: }
219:
220: //-- Change the destination extents file id's to the source id's
221: err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus );
222: if ( err != noErr )
223: {
224: if ( err != dskFulErr )
225: return( err );
226:
227: ExUndo2aPlus: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus );
228: ReturnIfError( err ); // we are doomed. Just QUIT!
229:
230: err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back
231: ReturnIfError( err ); // we are doomed. Just QUIT!
232:
233: goto ExUndo1a;
234: }
235:
236: //-- Change the bogus extents file id's to the dest id's
237: err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsPlusFile.fileID, isHFSPlus );
238: if ( err != noErr )
239: {
240: if ( err != dskFulErr )
241: return( err );
242:
243: err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus );
244: ReturnIfError( err ); // we are doomed. Just QUIT!
245:
246: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back
247: ReturnIfError( err ); // we are doomed. Just QUIT!
248:
249: goto ExUndo2aPlus;
250: }
251:
252: }
253: else if ( numSrcExtentBlocks ) // just the source file has extents
254: {
255: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus );
256: if ( err != noErr )
257: {
258: if ( err != dskFulErr )
259: return( err );
260:
261: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus );
262: ReturnIfError( err ); // we are doomed. Just QUIT!
263:
264: goto FlushAndReturn;
265: }
266: }
267: else if ( numDestExtentBlocks ) // just the destination file has extents
268: {
269: err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus );
270: if ( err != noErr )
271: {
272: if ( err != dskFulErr )
273: return( err );
274:
275: err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus );
276: ReturnIfError( err ); // we are doomed. Just QUIT!
277:
278: goto FlushAndReturn;
279: }
280: }
281:
282: //-- Step 3: Change the data in the catalog nodes
283:
284: //-- find the source cnode and put dest info in it
285: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
286: if ( err != noErr )
287: return( cmBadNews );
288:
289: BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) );
290: CopyBigCatalogNodeInfo( &destData, &srcData );
291:
292: err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSPlusCatalogFile), &srcHint );
293: ReturnIfError( err );
294:
295: // find the destination cnode and put source info in it
296: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
297: if ( err != noErr )
298: return( cmBadNews );
299:
300: CopyBigCatalogNodeInfo( &swapData, &destData );
301: err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSPlusCatalogFile), &destHint );
302: ReturnIfError( err );
303: }
304: else // HFS //
305: {
306: //-- Step 1: Check the catalog nodes for extents
307:
308: //-- locate the source file, test for extents in extent file, and copy the cat record for later
309: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
310: ReturnIfError( err );
311:
312: if ( srcData.recordType != kHFSFileRecord )
313: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
314:
315: //-- Check if there are any extents in the source file
316: numSrcExtentBlocks = CheckExtents( srcData.hfsFile.dataExtents, srcData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus );
317: if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents
318: numSrcExtentBlocks = CheckExtents( srcData.hfsFile.rsrcExtents, srcData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus );
319:
320:
321: //�� Do we save the found source node for later use?
322:
323:
324: //-- Check if there are any extents in the destination file
325: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
326: ReturnIfError( err );
327:
328: if ( destData.recordType != kHFSFileRecord )
329: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
330:
331: numDestExtentBlocks = CheckExtents( destData.hfsFile.dataExtents, destData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus );
332: if ( numDestExtentBlocks == 0 ) // then check the resource fork extents
333: numDestExtentBlocks = CheckExtents( destData.hfsFile.rsrcExtents, destData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus );
334:
335: //�� Do we save the found destination node for later use?
336:
337:
338: //-- Step 2: Exchange the Extent key in the extent file
339:
340: //-- Exchange the extents key in the extent file
341: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
342: ReturnIfError( err );
343:
344: if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents
345: {
346: //-- Change the source extents file ids to our known bogus value
347: err = MoveExtents( vcb, srcData.hfsFile.fileID, kHFSBogusExtentFileID, isHFSPlus );
348: if ( err != noErr )
349: {
350: if ( err != dskFulErr )
351: return( err );
352:
353: ExUndo1a: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
354: ReturnIfError( err ); // we are doomed. Just QUIT!
355:
356: err = FlushCatalog( vcb ); // flush the catalog
357: err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap)
358: return( dskFulErr );
359: }
360:
361: //-- Change the destination extents file id's to the source id's
362: err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus );
363: if ( err != noErr )
364: {
365: if ( err != dskFulErr )
366: return( err );
367:
368: ExUndo2a: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus );
369: ReturnIfError( err ); // we are doomed. Just QUIT!
370:
371: err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsFile.fileID, isHFSPlus ); // Move the extents back
372: ReturnIfError( err ); // we are doomed. Just QUIT!
373:
374: goto ExUndo1a;
375: }
376:
377: //-- Change the bogus extents file id's to the dest id's
378: err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsFile.fileID, isHFSPlus );
379: if ( err != noErr )
380: {
381: if ( err != dskFulErr )
382: return( err );
383:
384: err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus );
385: ReturnIfError( err ); // we are doomed. Just QUIT!
386:
387: err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus ); // Move the extents back
388: ReturnIfError( err ); // we are doomed. Just QUIT!
389:
390: goto ExUndo2a;
391: }
392:
393: }
394: else if ( numSrcExtentBlocks ) // just the source file has extents
395: {
396: err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus );
397: if ( err != noErr )
398: {
399: if ( err != dskFulErr )
400: return( err );
401:
402: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus );
403: ReturnIfError( err ); // we are doomed. Just QUIT!
404:
405: goto FlushAndReturn;
406: }
407: }
408: else if ( numDestExtentBlocks ) // just the destination file has extents
409: {
410: err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus );
411: if ( err != noErr )
412: {
413: if ( err != dskFulErr )
414: return( err );
415:
416: err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus );
417: ReturnIfError( err ); // we are doomed. Just QUIT!
418:
419: goto FlushAndReturn;
420: }
421: }
422:
423: //-- Step 3: Change the data in the catalog nodes
424:
425: //-- find the source cnode and put dest info in it
426: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
427: if ( err != noErr )
428: return( cmBadNews );
429:
430: BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) );
431: //�� Asm source copies from the saved dest catalog node
432: CopyCatalogNodeInfo( &destData, &srcData );
433:
434: err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSCatalogFile), &srcHint );
435: ReturnIfError( err );
436:
437:
438: // find the destination cnode and put source info in it
439: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
440: if ( err != noErr )
441: return( cmBadNews );
442:
443: CopyCatalogNodeInfo( &swapData, &destData );
444: err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSCatalogFile), &destHint );
445: ReturnIfError( err );
446: }
447:
448: err = noErr;
449:
450: //-- Step 4: Error Handling section
451:
452:
453: FlushAndReturn:
454: err = FlushCatalog( vcb ); // flush the catalog
455: err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap)
456: return( err );
457: }
458:
459:
460: void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest )
461: {
462: // dest->hfsFile.filStBlk = src->hfsFile.filStBlk;
463: dest->hfsFile.dataLogicalSize = src->hfsFile.dataLogicalSize;
464: dest->hfsFile.dataPhysicalSize = src->hfsFile.dataPhysicalSize;
465: // dest->hfsFile.filRStBlk = src->hfsFile.filRStBlk;
466: dest->hfsFile.rsrcLogicalSize = src->hfsFile.rsrcLogicalSize;
467: dest->hfsFile.rsrcPhysicalSize = src->hfsFile.rsrcPhysicalSize;
468: dest->hfsFile.modifyDate = src->hfsFile.modifyDate;
469: BlockMoveData( src->hfsFile.dataExtents, dest->hfsFile.dataExtents, sizeof(HFSExtentRecord) );
470: BlockMoveData( src->hfsFile.rsrcExtents, dest->hfsFile.rsrcExtents, sizeof(HFSExtentRecord) );
471: }
472:
473: void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest )
474: {
475: BlockMoveData( &src->hfsPlusFile.dataFork, &dest->hfsPlusFile.dataFork, sizeof(HFSPlusForkData) );
476: BlockMoveData( &src->hfsPlusFile.resourceFork, &dest->hfsPlusFile.resourceFork, sizeof(HFSPlusForkData) );
477: dest->hfsPlusFile.contentModDate = src->hfsPlusFile.contentModDate;
478: }
479:
480:
481: OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus )
482: {
483: FCB * fcb;
484: ExtentsRecBuffer extentsBuffer[kNumExtentsToCache];
485: ExtentKey * extentKeyPtr;
486: ExtentRecord extentData;
487: BTreeIterator btIterator;
488: FSBufferDescriptor btRecord;
489: UInt16 btKeySize;
490: UInt16 btRecordSize;
491: SInt16 i, j;
492: OSErr err;
493:
494:
495: fcb = GetFileControlBlock(vcb->extentsRefNum);
496:
497: (void) BTInvalidateHint(&btIterator);
498: extentKeyPtr = (ExtentKey*) &btIterator.key;
499: btRecord.bufferAddress = &extentData;
500: btRecord.itemCount = 1;
501:
502: //-- Collect the extent records
503:
504: //
505: // A search on the following key will cause the BTree to be positioned immediately
506: // before the first extent record for file #srcFileID, but not actually positioned
507: // on any record. This is because there cannot be an extent record with FABN = 0
508: // (the first extent of the fork, which would be in the catalog entry, not an extent
509: // record).
510: //
511: // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
512: //
513: if (isHFSPlus) {
514: btRecord.itemSize = sizeof(HFSPlusExtentRecord);
515: btKeySize = sizeof(HFSPlusExtentKey);
516:
517: extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength;
518: extentKeyPtr->hfsPlus.forkType = 0;
519: extentKeyPtr->hfsPlus.pad = 0;
520: extentKeyPtr->hfsPlus.fileID = srcFileID;
521: extentKeyPtr->hfsPlus.startBlock = 0;
522: }
523: else {
524: btRecord.itemSize = sizeof(HFSExtentRecord);
525: btKeySize = sizeof(HFSExtentKey);
526:
527: extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength;
528: extentKeyPtr->hfs.forkType = 0;
529: extentKeyPtr->hfs.fileID = srcFileID;
530: extentKeyPtr->hfs.startBlock = 0;
531: }
532:
533: //
534: // We do an initial BTSearchRecord to position the BTree's iterator just before any extent
535: // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found
536: // records, but with destFileID as the file number in the key. Keep doing this sequence of
537: // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are
538: // no more extent records in the tree.
539: //
540: // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID
541: // set to destFileID.
542: //
543: // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it
544: // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series
545: // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record
546: // we found, so that BTIterateRecord would get the next one (the first we haven't processed).
547: //
548:
549: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
550:
551: // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
552: if (err != btNotFound)
553: {
554: if ( DEBUG_BUILD )
555: DebugStr("\pUnexpected error from SearchBTreeRecord");
556:
557: if (err == noErr) // If we found such a bogus extent record, then the tree is really messed up
558: err = cmBadNews; // so return an error that conveys the disk is hosed.
559:
560: return err;
561: }
562:
563: do
564: {
565: btRecord.bufferAddress = &extentData;
566: btRecord.itemCount = 1;
567:
568: for ( i=0 ; i<kNumExtentsToCache ; i++ )
569: {
570: HFSCatalogNodeID foundFileID;
571:
572: err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
573: if ( err == btNotFound ) // Did we run out of extent records in the extents tree?
574: break; // if xkrFNum(A0) is cleared on this error, then this test is bogus!
575: else if ( err != noErr )
576: return( err ); // must be ioError
577:
578: foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
579: if ( foundFileID == srcFileID )
580: {
581: CopyExtentInfo(extentKeyPtr, &extentData, extentsBuffer, i);
582: }
583: else
584: {
585: break;
586: }
587: }
588:
589: //-- edit each extent key, and reinsert each extent record in the extent file
590: if (isHFSPlus)
591: btRecordSize = sizeof(HFSPlusExtentRecord);
592: else
593: btRecordSize = sizeof(HFSExtentRecord);
594:
595: for ( j=0 ; j<i ; j++ )
596: {
597: BTreeIterator tmpIterator;
598:
599: if (isHFSPlus)
600: extentsBuffer[j].extentKey.hfsPlus.fileID = destFileID; // change only the id in the key to dest ID
601: else
602: extentsBuffer[j].extentKey.hfs.fileID = destFileID; // change only the id in the key to dest ID
603:
604: // get iterator and buffer descriptor ready...
605: (void) BTInvalidateHint(&tmpIterator);
606: BlockMoveData(&(extentsBuffer[j].extentKey), &tmpIterator.key, btKeySize);
607: btRecord.bufferAddress = &(extentsBuffer[j].extentData);
608:
609: err = BTInsertRecord(fcb, &tmpIterator, &btRecord, btRecordSize);
610: if ( err != noErr )
611: { // parse the error
612: if ( err == btExists )
613: {
614: if ( DEBUG_BUILD )
615: DebugStr("\pCan't insert record -- already exists");
616: return( cmBadNews );
617: }
618: else
619: return( err );
620: }
621: }
622:
623: //-- okay, done with this buffered batch, go get the next set of extent records
624: // If our buffer is not full, we must be done, or recieved an error
625:
626: if ( i != kNumExtentsToCache ) // if the buffer is not full, we must be done
627: {
628: err = DeleteExtents( vcb, srcFileID, isHFSPlus ); // Now delete all the extent entries with the sourceID
629: if ( DEBUG_BUILD && err != noErr )
630: DebugStr("\pError from DeleteExtents");
631: break; // we're done!
632: }
633: } while ( true );
634:
635: return( err );
636: }
637:
638:
639: void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount )
640: {
641: BlockMoveData( key, &(buffer[bufferCount].extentKey), sizeof( ExtentKey ) );
642: BlockMoveData( data, &(buffer[bufferCount].extentData), sizeof( ExtentRecord ) );
643: }
644:
645:
646: //-- Delete all extents in extent file that have the ID given.
647: OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileID, Boolean isHFSPlus )
648: {
649: FCB * fcb;
650: ExtentKey * extentKeyPtr;
651: ExtentRecord extentData;
652: BTreeIterator btIterator;
653: FSBufferDescriptor btRecord;
654: UInt16 btRecordSize;
655: OSErr err;
656:
657: fcb = GetFileControlBlock(vcb->extentsRefNum);
658:
659: (void) BTInvalidateHint(&btIterator);
660: extentKeyPtr = (ExtentKey*) &btIterator.key;
661: btRecord.bufferAddress = &extentData;
662: btRecord.itemCount = 1;
663:
664: // The algorithm is to position the BTree just before any extent records for fileID.
665: // Then just keep getting successive records. If the record is still for fileID,
666: // then delete it.
667:
668: if (isHFSPlus) {
669: btRecord.itemSize = sizeof(HFSPlusExtentRecord);
670:
671: extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength;
672: extentKeyPtr->hfsPlus.forkType = 0;
673: extentKeyPtr->hfsPlus.pad = 0;
674: extentKeyPtr->hfsPlus.fileID = fileID;
675: extentKeyPtr->hfsPlus.startBlock = 0;
676: }
677: else {
678: btRecord.itemSize = sizeof(HFSExtentRecord);
679:
680: extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength;
681: extentKeyPtr->hfs.forkType = 0;
682: extentKeyPtr->hfs.fileID = fileID;
683: extentKeyPtr->hfs.startBlock = 0;
684: }
685:
686: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
687: if ( err != btNotFound )
688: {
689: if (err == noErr) { // Did we find a bogus extent record?
690: err = cmBadNews; // Yes, so indicate things are messed up.
691: }
692:
693: return err; // Got some unexpected error, so return it
694: }
695:
696: do
697: {
698: BTreeIterator tmpIterator;
699: HFSCatalogNodeID foundFileID;
700:
701: err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
702: if ( err != noErr )
703: {
704: if (err == btNotFound) // If we hit the end of the BTree
705: err = noErr; // then it's OK
706:
707: break; // We're done now.
708: }
709:
710: foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
711: if ( foundFileID != fileID )
712: break; // numbers don't match, we must be done
713:
714: tmpIterator = btIterator;
715: err = BTDeleteRecord( fcb, &tmpIterator );
716: if (err != noErr)
717: break;
718: } while ( true );
719:
720: return( err );
721: }
722:
723:
724: // Check if there are extents represented in the extents overflow file.
725: UInt32 CheckExtents( void *extents, UInt32 totalBlocks, Boolean isHFSPlus )
726: {
727: UInt32 extentAllocationBlocks;
728: UInt16 i;
729:
730:
731: if ( totalBlocks == 0 )
732: return( 0 );
733:
734: extentAllocationBlocks = 0;
735:
736: if ( isHFSPlus )
737: {
738: for ( i = 0 ; i < kHFSPlusExtentDensity ; i++ )
739: {
740: extentAllocationBlocks += ((HFSPlusExtentDescriptor *)extents)[i].blockCount;
741: if ( extentAllocationBlocks >= totalBlocks ) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
742: return( 0 );
743: }
744: }
745: else
746: {
747: for ( i = 0 ; i < kHFSExtentDensity ; i++ )
748: {
749: extentAllocationBlocks += ((HFSExtentDescriptor *)extents)[i].blockCount;
750: if ( extentAllocationBlocks >= totalBlocks ) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
751: return( 0 );
752: }
753: }
754:
755: return( extentAllocationBlocks );
756: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.