|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: File: FileIDServices.c
27:
28: Contains: File ID manipulating routines.
29:
30: Version: HFS Plus 1.0
31:
32: Written by: Deric Horn
33:
34: Copyright: � 1996-1999 by Apple Computer, Inc., all rights reserved.
35:
36: File Ownership:
37:
38: DRI: Deric Horn
39:
40: Other Contact: xxx put other contact here xxx
41:
42: Technology: xxx put technology here xxx
43:
44: Writers:
45:
46: (JL) Jim Luther
47: (msd) Mark Day
48: (djb) Don Brady
49: (DSH) Deric Horn
50:
51: Change History (most recent first):
52: <Rhap> 3/2/98 djb Fix extents corruption bug in MoveExtents (radar #2309434).
53: <Rhap> 11/20/98 djb Add support for UTF-8 names.
54: <Rhap> 4/2/98 djb Switch over to real BTree interface in MoveExtents and DeleteExtents.
55: <Rhap> 3/31/98 djb Sync up with final HFSVolumes.h header file.
56:
57: <CS21> 11/17/97 djb PrepareInputName routine now returns an error.
58: <CS20> 11/13/97 djb Radar #2001699 ResolveFileID needs to use CMNotFound error.
59: <CS19> 10/31/97 JL #2000184 - CreateFileThreadID and ExchangeFiles now return the
60: WDCBRecPtr or NULL for external file systems. ExchangeFiles no
61: longer returns length of FCB table to caller since that wasn't
62: ever needed.
63: <18> 10/23/97 DSH 1685058, Fix ExchangeFiles by invalidating the node cache before
64: switching the files.
65: <CS17> 10/19/97 msd Bug 1684586. GetCatInfo and SetCatInfo use only contentModDate.
66: <CS16> 10/16/97 DSH Return badFidErr in ResolveFileID if LocateCatalogThread fails
67: <CS15> 10/15/97 DSH CreateFileThreadID(), remap btExists to fidExists.
68: <CS14> 9/7/97 djb Turn off some DebugStr calls.
69: <CS13> 9/4/97 msd Remove call to PropertyExchangeObjects.
70: <CS12> 8/14/97 djb Remove hard link support.
71: <CS11> 7/18/97 msd Include LowMemPriv.h.
72: <CS10> 7/16/97 DSH FilesInternal.i renamed FileMgrInternal.i to avoid name
73: collision
74: <CS9> 7/8/97 DSH Loading PrecompiledHeaders from define passed in on C line
75: <CS8> 6/24/97 djb Add hard link support to ResolveFileID and CreateFileIDRef.
76: <CS7> 6/20/97 msd Use contentModDate and attributeModDate fields instead of
77: modifyDate.
78: <CS6> 6/13/97 djb Switch over from PrepareOutputName to ConvertUnicodeToHFSName.
79: PrepareInputName now takes an encoding.
80: <CS5> 5/28/97 msd Move the declaration of FindFileName to FilesInternal.i.
81: <CS4> 5/19/97 djb No longer need to invalidate vcbDirIDM field.
82: <CS3> 5/16/97 msd In ExchangeFiles, change srcNamePtr from char * to StringPtr
83: (fixes warnings).
84: <CS2> 4/28/97 djb (DSH) Added VolumeWritable check back into CreateFileIDThread.
85: <CS1> 4/24/97 djb first checked in
86: <HFS23> 4/11/97 DSH Use extended VCB fields catalogRefNum, and extentsRefNum.
87: <HFS22> 4/9/97 msd Rewrite CreateFileThreadID so that it properly handles
88: pathnames, and doesn't overwrite the ioNamePtr. The data field
89: of FindFileNameGlueRec points to a CatalogNodeData, not
90: CatalogRecord.
91: <HFS21> 4/4/97 djb Get in sync with volume format changes.
92: <HFS20> 3/31/97 djb Change ClearMem to ClearMemory.
93: <HFS19> 3/17/97 DSH C_FlushCache prototype to FilesInternal.h
94: <HFS18> 3/5/97 msd ExchangeFiles needs to call PropertyExchangeObjects.
95: <HFS17> 2/13/97 msd Fix MoveExtents and DeleteExtents to work with HFS+ extent
96: records.
97: <HFS16> 1/31/97 msd In MoveExtents, when a record isn't found and you want the next
98: record in order, use the "next record" offset = 1 instead of
99: "current record" offset = 0. DeleteExtents would always exit
100: without doing anything because it was searching for an invalid
101: key. Removed several DebugStrs that were used as cheap code
102: coverage.
103: <HFS15> 1/15/97 DSH Resolve wasn't passing the name back for HFS
104: <HFS14> 1/13/97 djb LocateCatalogThread now passes back the thread record size.
105: <HFS13> 1/11/97 DSH HFS+, fixed some Unicode/Pascal strings related bugs for use on
106: HFS+ volumes.
107: <HFS12> 1/9/97 DSH Fix ExchangeFiles extents
108: <HFS11> 1/6/97 DSH pass VCB in CloseFile() routine.
109: <HFS10> 1/6/97 djb Fixed ResolveFileID - it was not returning a directory ID!
110: <HFS9> 1/3/97 msd Fix prototype for C_FlushCache. Fix prototype for
111: TrashFileBlocks.
112: <HFS8> 1/3/97 djb Integrate latest HFSVolumesPriv.h changes.
113: <HFS7> 1/2/97 DSH C port of ExchangeFileIDs
114: <HFS6> 12/20/96 djb Fixed bug in CreateFileID.
115: <HFS5> 12/19/96 DSH All refs to VCB are now refs to ExtendedVCB
116: <HFS4> 12/19/96 msd Use kFileThreadExistsMask (from HFSVolumesPriv.h) instead of
117: kFileThreadMask (from FilesInternal.h) since the latter was
118: incorrectly defined and has now been removed.
119: <HFS3> 12/19/96 djb Updated for new B-tree Manager interface.
120: <HFS2> 12/18/96 msd GetFileThreadID was using a bitwise-OR (|) instead of
121: bitwise-AND (&) to test for a bit being set.
122: <HFS1> 12/12/96 DSH first checked in
123:
124: */
125:
126: #if ( PRAGMA_LOAD_SUPPORTED )
127: #pragma load PrecompiledHeaders
128: #else
129: #if TARGET_OS_MAC
130: #include <Types.h>
131: #include <Files.h>
132: #include <LowMemPriv.h>
133: #else
134: #include "../headers/system/MacOSStubs.h"
135: #endif /* TARGET_OS_MAC */
136: #endif /* PRAGMA_LOAD_SUPPORTED */
137:
138: #include "../headers/FileMgrInternal.h"
139: #include "../headers/HFSVolumes.h"
140: #include "../headers/system/HFSUnicodeWrappers.h"
141: #include "../headers/CatalogPrivate.h"
142:
143:
144: struct ExtentsRecBuffer {
145: ExtentKey extentKey;
146: ExtentRecord extentData;
147: };
148: typedef struct ExtentsRecBuffer ExtentsRecBuffer;
149:
150:
151: OSErr CreateFileID( ExtendedVCB *vcb, HFSCatalogNodeID fileID, CatalogName *name, HFSCatalogNodeID *threadID );
152: OSErr GetFileThreadID( ExtendedVCB *vcb, HFSCatalogNodeID id, const CatalogName *name, Boolean isHFSPlus, UInt32 *threadID );
153:
154: UInt32 CheckExtents( void *extents, UInt32 blocks, Boolean isHFSPlus );
155: OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileNumber, Boolean isHFSPlus );
156: OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus );
157: void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest );
158: void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest );
159:
160: void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount );
161: extern void TrashFileBlocks( ExtendedVCB *vcb, UInt32 fileNumber );
162:
163:
164:
165: //�������������������������������������������������������������������������������
166: // Routine: ResolveFileID from Asm : FIDResolveID
167: //
168: // Function: ResolveFileID finds the dirID and CName for a file, given it's thread.
169: //
170: // Output: OSErr err
171: // Str31 name - resolved name
172: // HFSCatalogNodeID parentID - resolved parent ID
173: //�������������������������������������������������������������������������������
174:
175: #if TARGET_OS_MAC
176:
177: OSErr ResolveFileID( ExtendedVCB *vcb, HFSCatalogNodeID fileID, HFSCatalogNodeID *parentID, Str31 name )
178: {
179: OSErr err;
180: CatalogRecord threadData;
181: CatalogKey key;
182: CatalogRecord data;
183: UInt32 threadHint;
184: UInt32 tempHint;
185: UInt16 threadSize;
186: Boolean isHFSPlus;
187:
188:
189: err = CheckVolumeOffLine( vcb );
190: ReturnIfError( err );
191:
192: isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord );
193:
194: //-- if it's not an HFS Plus volume, make sure it's an HFS volume
195: if ( (! isHFSPlus) && (vcb->vcbSigWord != kHFSSigWord) )
196: return( wrgVolTypErr );
197:
198: threadHint = kNoHint;
199:
200: //-- Locate the file thread
201:
202: err = LocateCatalogThread( vcb, fileID, &threadData, &threadSize, &threadHint ); // This call returns nodeName as either Str31 or HFSUniStr255, no need to call PrepareInputName()
203: if ( err != noErr )
204: return( cmNotFound ); // treat it as fidNotFound error
205:
206:
207: if ( (threadData.recordType != kHFSFileThreadRecord) && (threadData.recordType != kHFSPlusFileThreadRecord) )
208: return( cmFThdDirErr );
209:
210:
211: isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord );
212:
213: if ( isHFSPlus )
214: {
215: TextEncoding encoding;
216: ByteCount actualDstLen;
217:
218: //-- Check if the file exists
219:
220: err = LocateCatalogNode( vcb, threadData.hfsPlusThread.parentID, (const CatalogName *) &(threadData.hfsPlusThread.nodeName), kNoHint, &key, &data, &tempHint);
221:
222: //-- We found the file, but is this the file we really want?
223:
224: if ( err || data.hfsPlusFile.fileID != fileID )
225: return( badFidErr );
226:
227: encoding = data.hfsPlusFile.textEncoding; // note: text encoding and fileID is at same offset for folders
228:
229: // Copy the name back for output
230: err = ConvertUnicodeToUTF8( threadData.hfsPlusThread.nodeName.length * sizeof(UniChar),
231: threadData.hfsPlusThread.nodeName.unicode,
232: NAME_MAX+1,
233: &actualDstLen,
234: name);
235: *parentID = threadData.hfsPlusThread.parentID;
236: }
237: else
238: {
239: //-- Check if the file exists
240: // No need to prepare name for in/output, it will stay a Str31 in HFS
241:
242: err = LocateCatalogNode( vcb, threadData.hfsThread.parentID, (const CatalogName *) &(threadData.hfsThread.nodeName), kNoHint, &key, &data, &tempHint );
243:
244: //-- We found the file, but is this the file we really want?
245:
246: if ( err || data.hfsFile.fileID != fileID )
247: return( badFidErr );
248:
249: // Copy the name back for output
250: BlockMoveData( threadData.hfsThread.nodeName, name, StrLength(threadData.hfsThread.nodeName) + 1 );
251: *parentID = threadData.hfsThread.parentID;
252: }
253:
254: return( noErr );
255: }
256:
257: #endif /* TARGET_OS_MAC */
258:
259:
260: //�������������������������������������������������������������������������������
261: // Routine: GetFileThreadID from Asm : FIDGetID
262: //
263: // Function: GetFileThreadID returns a file thread to a file if it exists.
264: //
265: // Input: ExtendedVCB* - VCB pointer
266: // HFSCatalogNodeID - DirID
267: // CatalogName - CName pointer
268: //
269: // Output: OSErr - result code
270: // 0 = ok
271: // CMnotfound = CNode not found
272: // cmFThdGone = File thread not found
273: // cmFThdDirErr = file is a directory, not a file
274: // -n = IO Error
275: // UInt32 - file thread ID
276: //�������������������������������������������������������������������������������
277:
278: #if TARGET_OS_MAC
279:
280: OSErr GetFileThreadID( ExtendedVCB *vcb, HFSCatalogNodeID id, const CatalogName *name, Boolean isHFSPlus, UInt32 *threadID )
281: {
282: OSErr err;
283: CatalogKey key;
284: CatalogRecord data;
285: UInt32 hint;
286:
287:
288: *threadID = 0;
289:
290: //-- Locate the file thread
291:
292: err = LocateCatalogNode( vcb, id, name, kNoHint, &key, &data, &hint );
293: ReturnIfError( err );
294:
295: if ( isHFSPlus )
296: {
297: if ( data.recordType != kHFSPlusFileRecord )
298: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
299:
300: *threadID = data.hfsPlusFile.fileID;
301: }
302: else
303: {
304: if ( data.recordType != kHFSFileRecord )
305: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
306:
307: if ( (data.hfsFile.flags & kHFSThreadExistsMask) != 0 )
308: *threadID = data.hfsFile.fileID;
309: else
310: err = cmFThdGone;
311: }
312:
313: return( err );
314: }
315: #endif /* TARGET_OS_MAC */
316:
317:
318:
319: #if TARGET_OS_MAC
320: OSErr CreateFileThreadID( FIDParam *filePB, WDCBRecPtr *wdcbPtr )
321: {
322: OSErr err;
323: Boolean isHFSPlus;
324: UInt32 fileHint;
325: UInt32 threadHint;
326: Str31 name;
327: FindFileNameGlueRec fileInfo;
328: HFSCatalogKey threadKey;
329: HFSCatalogThread threadData;
330: CatalogKey fileKey;
331: CatalogRecord fileData;
332:
333:
334: err = FindFileName( (ParamBlockRec *) filePB, &fileInfo );
335: *wdcbPtr = fileInfo.wdcb; // return the WDCB pointer to the glue so it can set up A3.
336: if (err != noErr) goto ErrorExit;
337:
338: isHFSPlus = ( fileInfo.vcb->vcbSigWord == kHFSPlusSigWord );
339:
340: //
341: // Make sure we just found a file record.
342: //
343: if (fileInfo.data->nodeType != kCatalogFileNode) {
344: err = notAFileErr;
345: goto ErrorExit;
346: }
347:
348: //
349: // Figure out which FileID this is, and return it.
350: //
351: filePB->ioFileID = fileInfo.data->nodeID;
352:
353: //
354: // If the volume is HFS, see if we need to create the thread record. For HFS Plus, there
355: // is always a thread record.
356: //
357:
358: if (isHFSPlus || fileInfo.data->nodeFlags & kFileThreadExistsMask) {
359: err = fidExists;
360: goto ErrorExit;
361: }
362:
363: err = VolumeWritable( fileInfo.vcb );
364: if ( err != noErr )
365: goto ErrorExit;
366:
367:
368: //
369: // If we get here, we need to create a thread record on an HFS volume.
370: // Start by building finding the original catalog record, so we can get
371: // its key with correct capitalization, etc.
372: //
373: //�� Is there any way to get the actual key back from FindFileName?
374: //
375: name[0] = fileInfo.nameLength;
376: BlockMoveData(fileInfo.nameBuffer, &name[1], fileInfo.nameLength);
377: err = LocateCatalogNode( fileInfo.vcb, fileInfo.id, (CatalogName *) &name, fileInfo.hint, &fileKey, &fileData, &fileHint );
378: if (err != noErr) goto ErrorExit;
379:
380: //
381: // Build the key and data for the thread record.
382: //
383:
384: BuildCatalogKey( filePB->ioFileID, NULL, false, (CatalogKey *) &threadKey );
385:
386: ClearMemory( (Ptr)&threadData, sizeof(HFSCatalogThread) );
387: threadData.recordType = kHFSFileThreadRecord;
388: threadData.parentID = fileKey.hfs.parentID;
389: BlockMoveData(&fileKey.hfs.nodeName[0], &threadData.nodeName[0], fileKey.hfs.nodeName[0]+1);
390:
391: //
392: // Insert the thread record
393: //
394: err = InsertBTreeRecord( fileInfo.vcb->catalogRefNum, &threadKey, &threadData, sizeof(HFSCatalogThread), &threadHint );
395: if (err != noErr)
396: {
397: if ( err == btExists ) err = fidExists; // Remap btExists to fidExists
398: goto ErrorExit;
399: }
400:
401: //
402: // Finally, set the flag in the file record to say this file has a thread record.
403: //
404: fileData.hfsFile.flags |= kFileThreadExistsMask;
405: err = ReplaceBTreeRecord( fileInfo.vcb->catalogRefNum, &fileKey, fileHint, &fileData, sizeof(HFSCatalogFile), &fileHint );
406: if (err != noErr) goto ErrorExit;
407:
408: FlushCatalog( fileInfo.vcb );
409:
410: ErrorExit:
411:
412: return err;
413: }
414: #endif /* TARGET_OS_MAC */
415:
416:
417: //�������������������������������������������������������������������������������
418: // Routine: DeleteFileID from Asm : FIDDeleteID
419: //
420: // Function: DeleteFileID invalidates a file id, by removing the thread from the
421: // from the cat file and by turning off the file CNode link flag.
422: //
423: // Output: OSErr err
424: //�������������������������������������������������������������������������������
425: //
426: // We don't know why anyone would use this routine, so in HFS Plus we want to obsolete it
427: //
428: //�������������������������������������������������������������������������������
429:
430: #if( 0 )
431: OSErr DeleteFileID( ExtendedVCB *vcb, HFSCatalogNodeID fileID )
432: {
433: OSErr err;
434: OSErr btError;
435: Boolean isHFSPlus;
436: CatalogRecord *threadData;
437: CatalogKey key;
438: CatalogRecord record;
439: UInt32 threadHint;
440: UInt16 threadSize;
441: CatalogKey key;
442:
443:
444: //-- Locate the file thread
445:
446: threadHint = kNoHint;
447:
448: err = LocateCatalogThread( vcb, fileID, &threadData, &threadSize, &threadHint );
449:
450: if ( err != noErr )
451: { // translate the error so callee knows it wasn't a fnfErr
452: if ( err != cmNotFound )
453: err = cmFThdGone;
454: return( err );
455: }
456:
457: if ( (threadData->recordType != kHFSFileThreadRecord) && (threadData->recordType != kHFSPlussFileThreadRecord) )
458: return( cmFThdDirErr );
459:
460: //-- Find the file
461:
462: isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord );
463:
464: if ( isHFSPlus )
465: {
466: err = LocateCatalogNode( vcb, threadData->hfsPlusThread.parentID, (const CatalogName *) &(threadData->hfsPlusThread.nodeName), kNoHint, &key, &record, &threadHint );
467:
468: if ( err == noErr )
469: { // Turn off thread flag in file CNode
470: record.hfsPlusFile.flags &= ~kFileThreadExistsMask; // clear the fThreadFlag bit
471: err = ReplaceBTreeRecord( vcb->catalogRefNum, &key, threadHint, &record, sizeof(CatalogThreadRecord), &threadHint); // tell the B-Tree
472: ReturnIfError( err );
473: }
474: }
475: else
476: {
477: err = LocateCatalogNode( vcb, threadData->hfsThread.parentID, (const CatalogName *) &(threadData->hfsThread.nodeName), kNoHint, &key, &record, &threadHint );
478:
479: if ( err == noErr )
480: { // Turn off thread flag in file CNode
481: record.hfsFile.flags &= ~kFileThreadExistsMask; // clear the fThreadFlag bit
482: err = ReplaceBTreeRecord( vcb->catalogRefNum, &key, threadHint, &record, sizeof(CatThdRec), &threadHint); // tell the B-Tree
483: ReturnIfError( err );
484: }
485: }
486:
487: //-- Delete the file thread in the catalog btree
488:
489: BuildCatalogKey( fileID, nil, isHFSPlus, &key );
490:
491: btError = DeleteBTreeRecord( vcb->catalogRefNum, &key );
492: ReturnIfError( btError ); // we know it exists, so must be IOError...
493: // ...Oh well, leave the cnode's fthread flag off.
494: //-- Get it out to disk.
495: (void) FlushCatalog( vcb );
496:
497: return( err );
498: }
499:
500:
501:
502: #if TARGET_OS_MAC
503: OSErr ExchangeFiles( FIDParam *filePB, WDCBRecPtr *wdcbPtr )
504: {
505: FindFileNameGlueRec srcFileInfo;
506: FindFileNameGlueRec destFileInfo;
507: OSErr err;
508: ExtendedVCB *vcb;
509: CatalogName srcName;
510: CatalogName destName;
511: Str31 pSrcName;
512: Str31 pDestName;
513: CatalogKey srcKey;
514: CatalogRecord srcData;
515: CatalogKey destKey;
516: CatalogRecord destData;
517: HFSCatalogNodeID srcFileID;
518: HFSCatalogNodeID destFileID;
519: UInt32 srcHint;
520: UInt32 destHint;
521: UInt32 srcDirID;
522: StringPtr srcNamePtr;
523: Boolean isHFSPlus;
524: Ptr fcbs;
525: UInt16 fcbIndex;
526: FCB *fcb;
527:
528: err = FindFileName( (ParamBlockRec *) filePB, &srcFileInfo );
529: *wdcbPtr = srcFileInfo.wdcb; // return the WDCB pointer to the glue so it can set up A3.
530: ReturnIfError( err );
531:
532: srcNamePtr = filePB->ioNamePtr;
533: srcDirID = filePB->ioSrcDirID;
534:
535: filePB->ioNamePtr = filePB->ioDestNamePtr;
536: filePB->ioSrcDirID = filePB->ioDestDirID;
537:
538: err = FindFileName( (ParamBlockRec *) filePB, &destFileInfo );
539:
540: filePB->ioNamePtr = srcNamePtr;
541: filePB->ioSrcDirID = srcDirID;
542:
543: ReturnIfError( err );
544:
545: if ( srcFileInfo.vcb != destFileInfo.vcb )
546: return( diffVolErr );
547:
548: //-- since the vcb's are the same, let's use a local variable
549: vcb = srcFileInfo.vcb;
550:
551: err = VolumeWritable( vcb );
552: ReturnIfError( err );
553:
554: err = CheckVolumeOffLine( vcb );
555: ReturnIfError( err );
556:
557: isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord );
558:
559: //-- if it's not an HFS Plus volume, make sure it's an HFS volume
560: if ( (! isHFSPlus) && (vcb->vcbSigWord != kHFSSigWord) )
561: return( wrgVolTypErr );
562:
563: //-- Set up the names into pascal strings
564: pDestName[0] = destFileInfo.nameLength;
565: BlockMoveData( destFileInfo.nameBuffer, &(pDestName[1]), pDestName[0] );
566:
567: pSrcName[0] = srcFileInfo.nameLength;
568: BlockMoveData( srcFileInfo.nameBuffer, &(pSrcName[1]), pSrcName[0] );
569:
570: //-- Now prepare the pascal names for input
571: err = PrepareInputName( pSrcName, isHFSPlus, GetTextEncodingFromHint(srcFileInfo.hint), &srcName );
572: if ( err != noErr ) goto ParseError;
573:
574: err = PrepareInputName( pDestName, isHFSPlus, GetTextEncodingFromHint(destFileInfo.hint), &destName );
575: if ( err != noErr ) goto ParseError;
576:
577: //-- locate the source file
578: err = LocateCatalogNode( vcb, srcFileInfo.id, &srcName, srcFileInfo.hint, &srcKey, &srcData, &srcHint );
579: if ( err != noErr ) goto ParseError;
580:
581: //-- locate the dest file
582: err = LocateCatalogNode( vcb, destFileInfo.id, &destName, destFileInfo.hint, &destKey, &destData, &destHint );
583: if ( err != noErr ) goto ParseError;
584:
585: //-- Are we trying to exchange the file with itself?
586: if ( isHFSPlus )
587: {
588: srcFileID = srcData.hfsPlusFile.fileID;
589: destFileID = destData.hfsPlusFile.fileID;
590: }
591: else
592: {
593: srcFileID = srcData.hfsFile.fileID;
594: destFileID = destData.hfsFile.fileID;
595: }
596:
597: if ( srcFileID == destFileID )
598: return( sameFileErr );
599:
600:
601: // Flush any open paths with the files in question! (release cache buffers) <KSCT>
602:
603: // Note: The cache takes fcb refnum as an argument for flushing. The only way to get
604: // this value is to walk the fcb array and find matches of the file number. If a match
605: // is found, that fcb refnum can be used for flushing. BUT, the fcb walk continues, since
606: // there can be more than one open path per file.
607:
608: // FINE TUNING: Flag if either file is open. THEN after FidExchangeFiles, if none, skip fcb walking.
609:
610: Get1stFileControlBlock( &fcbIndex, &fcbs );
611: do
612: {
613: fcb = GetFileControlBlock( fcbIndex );
614: if ( fcb->fcbVPtr == (ExtendedVCB *) vcb ) // make sure we're on the right volume
615: {
616: if ( (fcb->fcbFlNm == srcFileID) || (fcb->fcbFlNm == destFileID) )
617: {
618: //-- Flush and continue
619: LMSetFlushOnly( 0xFF );
620: err = CloseFile( vcb, fcbIndex, fcbs );
621: ReturnIfError( err );
622:
623: LMSetCacheFlag( 0xFF );
624:
625: (void) C_FlushCache( vcb, fcTrashBit, fcbIndex );
626: }
627: }
628: } while ( GetNextFileControlBlock( &fcbIndex, fcbs ) == false ); // while there's still some left
629:
630: // valid buffer in the free queue has a file number tag to it in the header, however,
631: // after FIDExchangeFiles the file number is no longer valid. So we have to call TrashFBlocks
632: // to invalidate all the buffer associated with the files. <16Apr91 #12 ksct>
633:
634: TrashCatalogIterator( vcb, srcFileInfo.id ); // invalidate any iterators for this parentID
635: InvalidateCatalogNodeCache( vcb, srcFileInfo.id ); // invalidate node cache
636: if ( srcFileInfo.id != destFileInfo.id )
637: {
638: TrashCatalogIterator( vcb, destFileInfo.id ); // invalidate any iterators for this parentID
639: InvalidateCatalogNodeCache( vcb, destFileInfo.id ); // invalidate node cache
640: }
641: TrashFileBlocks( vcb, destFileID );
642: TrashFileBlocks( vcb, srcFileID );
643:
644:
645: //-- Do the stuff!
646: err = ExchangeFileIDs( vcb, &srcName, &destName, srcFileInfo.id, destFileInfo.id, srcHint, destHint );
647: if ( DEBUG_BUILD && err != noErr)
648: {
649: DebugStr("\pError from ExchangeFileIDs");
650: }
651:
652: //-- Now get the names ready for output
653: if ( isHFSPlus )
654: {
655: err = ConvertUnicodeToHFSName( &srcName.ustr, srcData.hfsPlusFile.textEncoding, srcData.hfsPlusFile.fileID, pSrcName );
656: if ( err != noErr )
657: goto ParseError;
658:
659: err = ConvertUnicodeToHFSName( &destName.ustr, destData.hfsPlusFile.textEncoding, srcData.hfsPlusFile.fileID, pDestName );
660: }
661: else
662: {
663: BlockMoveData( srcName.pstr, pSrcName, StrLength(srcName.pstr) + 1 );
664: BlockMoveData( destName.pstr, pDestName, StrLength(srcName.pstr) + 1 );
665: }
666:
667: if ( err != noErr )
668: goto ParseError;
669:
670: //-- Exchange fcb info (file number, file name, and file parID only!)
671: Get1stFileControlBlock( &fcbIndex, &fcbs );
672: do
673: {
674: fcb = GetFileControlBlock( fcbIndex );
675: if ( fcb->fcbVPtr == vcb )
676: {
677: if ( fcb->fcbFlNm == srcFileID )
678: {
679: fcb->fcbCatPos = 0;
680: fcb->fcbFlNm = destFileID;
681: fcb->fcbDirID = destFileInfo.id;
682:
683: BlockMoveData( pDestName, fcb->fcbCName, pDestName[0]+1 );
684: }
685: else if ( fcb->fcbFlNm == destFileID )
686: {
687: fcb->fcbCatPos = 0;
688: fcb->fcbFlNm = srcFileID;
689: fcb->fcbDirID = srcFileInfo.id;
690:
691: BlockMoveData( pSrcName, fcb->fcbCName, pSrcName[0]+1 );
692: }
693: }
694: } while ( GetNextFileControlBlock( &fcbIndex, fcbs ) == false ); // while there's still some left
695:
696: return( err );
697:
698: ParseError:
699: if ( err == cmNotFound ) return( fnfErr );
700: else if ( err == cmFThdDirErr ) return( notAFileErr );
701: else return( err );
702: }
703: #endif /* TARGET_OS_MAC */
704: #endif
705:
706:
707: OSErr ExchangeFileIDs( ExtendedVCB *vcb, ConstUTF8Param srcName, ConstUTF8Param destName, HFSCatalogNodeID srcID, HFSCatalogNodeID destID, UInt32 srcHint, UInt32 destHint )
708: {
709: CatalogKey srcKey; // 518 bytes
710: CatalogRecord srcData; // 520 bytes
711: CatalogKey destKey; // 518 bytes
712: CatalogRecord destData; // 520 bytes
713: CatalogRecord swapData; // 520 bytes
714: SInt16 numSrcExtentBlocks;
715: SInt16 numDestExtentBlocks;
716: UInt32 textEncoding;
717: OSErr err;
718: Boolean isHFSPlus = ( vcb->vcbSigWord == kHFSPlusSigWord );
719:
720: TrashCatalogIterator(vcb, srcID); // invalidate any iterators for this parentID
721: TrashCatalogIterator(vcb, destID); // invalidate any iterators for this parentID
722:
723: err = BuildCatalogKeyUTF8(srcID, srcName, isHFSPlus, &srcKey, &textEncoding);
724: ReturnIfError(err);
725:
726: err = BuildCatalogKeyUTF8(destID, destName, isHFSPlus, &destKey, &textEncoding);
727: ReturnIfError(err);
728:
729: if ( isHFSPlus )
730: {
731: //-- Step 1: Check the catalog nodes for extents
732:
733: //-- locate the source file, test for extents in extent file, and copy the cat record for later
734: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
735: ReturnIfError( err );
736:
737: if ( srcData.recordType != kHFSPlusFileRecord )
738: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
739:
740: //-- Check if there are any extents in the source file
741: //�� I am only checling the extents in the low 32 bits, routine will fail if files extents after 2 gig are in overflow
742: numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.dataFork.extents, srcData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus );
743: if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents
744: numSrcExtentBlocks = CheckExtents( srcData.hfsPlusFile.resourceFork.extents, srcData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus );
745:
746: //-- Check if there are any extents in the destination file
747: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
748: ReturnIfError( err );
749:
750: if ( destData.recordType != kHFSPlusFileRecord )
751: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
752:
753: numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.dataFork.extents, destData.hfsPlusFile.dataFork.totalBlocks, isHFSPlus );
754: if ( numDestExtentBlocks == 0 ) // then check the resource fork extents
755: numDestExtentBlocks = CheckExtents( destData.hfsPlusFile.resourceFork.extents, destData.hfsPlusFile.resourceFork.totalBlocks, isHFSPlus );
756:
757: //-- Step 2: Exchange the Extent key in the extent file
758:
759: //-- Exchange the extents key in the extent file
760: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
761: ReturnIfError( err );
762:
763: if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents
764: {
765: //-- Change the source extents file ids to our known bogus value
766: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, kHFSBogusExtentFileID, isHFSPlus );
767: if ( err != noErr )
768: {
769: if ( err != dskFulErr )
770: return( err );
771: else
772: goto ExUndo1a;
773: }
774:
775: //-- Change the destination extents file id's to the source id's
776: err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus );
777: if ( err != noErr )
778: {
779: if ( err != dskFulErr )
780: return( err );
781:
782: ExUndo2aPlus: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus );
783: ReturnIfError( err ); // we are doomed. Just QUIT!
784:
785: err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back
786: ReturnIfError( err ); // we are doomed. Just QUIT!
787:
788: goto ExUndo1a;
789: }
790:
791: //-- Change the bogus extents file id's to the dest id's
792: err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsPlusFile.fileID, isHFSPlus );
793: if ( err != noErr )
794: {
795: if ( err != dskFulErr )
796: return( err );
797:
798: err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus );
799: ReturnIfError( err ); // we are doomed. Just QUIT!
800:
801: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus ); // Move the extents back
802: ReturnIfError( err ); // we are doomed. Just QUIT!
803:
804: goto ExUndo2aPlus;
805: }
806:
807: }
808: else if ( numSrcExtentBlocks ) // just the source file has extents
809: {
810: err = MoveExtents( vcb, srcData.hfsPlusFile.fileID, destData.hfsPlusFile.fileID, isHFSPlus );
811: if ( err != noErr )
812: {
813: if ( err != dskFulErr )
814: return( err );
815:
816: err = DeleteExtents( vcb, srcData.hfsPlusFile.fileID, isHFSPlus );
817: ReturnIfError( err ); // we are doomed. Just QUIT!
818:
819: goto FlushAndReturn;
820: }
821: }
822: else if ( numDestExtentBlocks ) // just the destination file has extents
823: {
824: err = MoveExtents( vcb, destData.hfsPlusFile.fileID, srcData.hfsPlusFile.fileID, isHFSPlus );
825: if ( err != noErr )
826: {
827: if ( err != dskFulErr )
828: return( err );
829:
830: err = DeleteExtents( vcb, destData.hfsPlusFile.fileID, isHFSPlus );
831: ReturnIfError( err ); // we are doomed. Just QUIT!
832:
833: goto FlushAndReturn;
834: }
835: }
836:
837: //-- Step 3: Change the data in the catalog nodes
838:
839: //-- find the source cnode and put dest info in it
840: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
841: if ( err != noErr )
842: return( cmBadNews );
843:
844: BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) );
845: CopyBigCatalogNodeInfo( &destData, &srcData );
846:
847: err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSPlusCatalogFile), &srcHint );
848: ReturnIfError( err );
849:
850: // find the destination cnode and put source info in it
851: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
852: if ( err != noErr )
853: return( cmBadNews );
854:
855: CopyBigCatalogNodeInfo( &swapData, &destData );
856: err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSPlusCatalogFile), &destHint );
857: ReturnIfError( err );
858: }
859: else // HFS //
860: {
861: //-- Step 1: Check the catalog nodes for extents
862:
863: //-- locate the source file, test for extents in extent file, and copy the cat record for later
864: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
865: ReturnIfError( err );
866:
867: if ( srcData.recordType != kHFSFileRecord )
868: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
869:
870: //-- Check if there are any extents in the source file
871: numSrcExtentBlocks = CheckExtents( srcData.hfsFile.dataExtents, srcData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus );
872: if ( numSrcExtentBlocks == 0 ) // then check the resource fork extents
873: numSrcExtentBlocks = CheckExtents( srcData.hfsFile.rsrcExtents, srcData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus );
874:
875:
876: //�� Do we save the found source node for later use?
877:
878:
879: //-- Check if there are any extents in the destination file
880: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
881: ReturnIfError( err );
882:
883: if ( destData.recordType != kHFSFileRecord )
884: return( cmFThdDirErr ); // Error "cmFThdDirErr = it is a directory"
885:
886: numDestExtentBlocks = CheckExtents( destData.hfsFile.dataExtents, destData.hfsFile.dataPhysicalSize / vcb->blockSize, isHFSPlus );
887: if ( numDestExtentBlocks == 0 ) // then check the resource fork extents
888: numDestExtentBlocks = CheckExtents( destData.hfsFile.rsrcExtents, destData.hfsFile.rsrcPhysicalSize / vcb->blockSize, isHFSPlus );
889:
890: //�� Do we save the found destination node for later use?
891:
892:
893: //-- Step 2: Exchange the Extent key in the extent file
894:
895: //-- Exchange the extents key in the extent file
896: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
897: ReturnIfError( err );
898:
899: if ( numSrcExtentBlocks && numDestExtentBlocks ) // if both files have extents
900: {
901: //-- Change the source extents file ids to our known bogus value
902: err = MoveExtents( vcb, srcData.hfsFile.fileID, kHFSBogusExtentFileID, isHFSPlus );
903: if ( err != noErr )
904: {
905: if ( err != dskFulErr )
906: return( err );
907:
908: ExUndo1a: err = DeleteExtents( vcb, kHFSBogusExtentFileID, isHFSPlus );
909: ReturnIfError( err ); // we are doomed. Just QUIT!
910:
911: err = FlushCatalog( vcb ); // flush the catalog
912: err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap)
913: return( dskFulErr );
914: }
915:
916: //-- Change the destination extents file id's to the source id's
917: err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus );
918: if ( err != noErr )
919: {
920: if ( err != dskFulErr )
921: return( err );
922:
923: ExUndo2a: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus );
924: ReturnIfError( err ); // we are doomed. Just QUIT!
925:
926: err = MoveExtents( vcb, kHFSBogusExtentFileID, srcData.hfsFile.fileID, isHFSPlus ); // Move the extents back
927: ReturnIfError( err ); // we are doomed. Just QUIT!
928:
929: goto ExUndo1a;
930: }
931:
932: //-- Change the bogus extents file id's to the dest id's
933: err = MoveExtents( vcb, kHFSBogusExtentFileID, destData.hfsFile.fileID, isHFSPlus );
934: if ( err != noErr )
935: {
936: if ( err != dskFulErr )
937: return( err );
938:
939: err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus );
940: ReturnIfError( err ); // we are doomed. Just QUIT!
941:
942: err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus ); // Move the extents back
943: ReturnIfError( err ); // we are doomed. Just QUIT!
944:
945: goto ExUndo2a;
946: }
947:
948: }
949: else if ( numSrcExtentBlocks ) // just the source file has extents
950: {
951: err = MoveExtents( vcb, srcData.hfsFile.fileID, destData.hfsFile.fileID, isHFSPlus );
952: if ( err != noErr )
953: {
954: if ( err != dskFulErr )
955: return( err );
956:
957: err = DeleteExtents( vcb, srcData.hfsFile.fileID, isHFSPlus );
958: ReturnIfError( err ); // we are doomed. Just QUIT!
959:
960: goto FlushAndReturn;
961: }
962: }
963: else if ( numDestExtentBlocks ) // just the destination file has extents
964: {
965: err = MoveExtents( vcb, destData.hfsFile.fileID, srcData.hfsFile.fileID, isHFSPlus );
966: if ( err != noErr )
967: {
968: if ( err != dskFulErr )
969: return( err );
970:
971: err = DeleteExtents( vcb, destData.hfsFile.fileID, isHFSPlus );
972: ReturnIfError( err ); // we are doomed. Just QUIT!
973:
974: goto FlushAndReturn;
975: }
976: }
977:
978: //-- Step 3: Change the data in the catalog nodes
979:
980: //-- find the source cnode and put dest info in it
981: err = LocateCatalogNodeByKey( vcb, srcHint, &srcKey, &srcData, &srcHint );
982: if ( err != noErr )
983: return( cmBadNews );
984:
985: BlockMoveData( &srcData, &swapData, sizeof(CatalogRecord) );
986: //�� Asm source copies from the saved dest catalog node
987: CopyCatalogNodeInfo( &destData, &srcData );
988:
989: err = ReplaceBTreeRecord( vcb->catalogRefNum, &srcKey, srcHint, &srcData, sizeof(HFSCatalogFile), &srcHint );
990: ReturnIfError( err );
991:
992:
993: // find the destination cnode and put source info in it
994: err = LocateCatalogNodeByKey( vcb, destHint, &destKey, &destData, &destHint );
995: if ( err != noErr )
996: return( cmBadNews );
997:
998: CopyCatalogNodeInfo( &swapData, &destData );
999: err = ReplaceBTreeRecord( vcb->catalogRefNum, &destKey, destHint, &destData, sizeof(HFSCatalogFile), &destHint );
1000: ReturnIfError( err );
1001: }
1002:
1003: err = noErr;
1004:
1005: //-- Step 4: Error Handling section
1006:
1007:
1008: FlushAndReturn:
1009: err = FlushCatalog( vcb ); // flush the catalog
1010: err = FlushExtentFile( vcb ); // flush the extent file (unneeded for common case, but it's cheap)
1011: return( err );
1012: }
1013:
1014:
1015: void CopyCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest )
1016: {
1017: // dest->hfsFile.filStBlk = src->hfsFile.filStBlk;
1018: dest->hfsFile.dataLogicalSize = src->hfsFile.dataLogicalSize;
1019: dest->hfsFile.dataPhysicalSize = src->hfsFile.dataPhysicalSize;
1020: // dest->hfsFile.filRStBlk = src->hfsFile.filRStBlk;
1021: dest->hfsFile.rsrcLogicalSize = src->hfsFile.rsrcLogicalSize;
1022: dest->hfsFile.rsrcPhysicalSize = src->hfsFile.rsrcPhysicalSize;
1023: dest->hfsFile.modifyDate = src->hfsFile.modifyDate;
1024: BlockMoveData( src->hfsFile.dataExtents, dest->hfsFile.dataExtents, sizeof(HFSExtentRecord) );
1025: BlockMoveData( src->hfsFile.rsrcExtents, dest->hfsFile.rsrcExtents, sizeof(HFSExtentRecord) );
1026: }
1027:
1028: void CopyBigCatalogNodeInfo( CatalogRecord *src, CatalogRecord *dest )
1029: {
1030: BlockMoveData( &src->hfsPlusFile.dataFork, &dest->hfsPlusFile.dataFork, sizeof(HFSPlusForkData) );
1031: BlockMoveData( &src->hfsPlusFile.resourceFork, &dest->hfsPlusFile.resourceFork, sizeof(HFSPlusForkData) );
1032: dest->hfsPlusFile.contentModDate = src->hfsPlusFile.contentModDate;
1033: }
1034:
1035:
1036: OSErr MoveExtents( ExtendedVCB *vcb, UInt32 srcFileID, UInt32 destFileID, Boolean isHFSPlus )
1037: {
1038: FCB * fcb;
1039: ExtentsRecBuffer extentsBuffer[kNumExtentsToCache];
1040: ExtentKey * extentKeyPtr;
1041: ExtentRecord extentData;
1042: BTreeIterator btIterator;
1043: FSBufferDescriptor btRecord;
1044: UInt16 btKeySize;
1045: UInt16 btRecordSize;
1046: SInt16 i, j;
1047: OSErr err;
1048:
1049:
1050: fcb = GetFileControlBlock(vcb->extentsRefNum);
1051:
1052: (void) BTInvalidateHint(&btIterator);
1053: extentKeyPtr = (ExtentKey*) &btIterator.key;
1054: btRecord.bufferAddress = &extentData;
1055: btRecord.itemCount = 1;
1056:
1057: //-- Collect the extent records
1058:
1059: //
1060: // A search on the following key will cause the BTree to be positioned immediately
1061: // before the first extent record for file #srcFileID, but not actually positioned
1062: // on any record. This is because there cannot be an extent record with FABN = 0
1063: // (the first extent of the fork, which would be in the catalog entry, not an extent
1064: // record).
1065: //
1066: // Using BTIterateRecord with kBTreeNextRecord will then get that first extent record.
1067: //
1068: if (isHFSPlus) {
1069: btRecord.itemSize = sizeof(HFSPlusExtentRecord);
1070: btKeySize = sizeof(HFSPlusExtentKey);
1071:
1072: extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength;
1073: extentKeyPtr->hfsPlus.forkType = 0;
1074: extentKeyPtr->hfsPlus.pad = 0;
1075: extentKeyPtr->hfsPlus.fileID = srcFileID;
1076: extentKeyPtr->hfsPlus.startBlock = 0;
1077: }
1078: else {
1079: btRecord.itemSize = sizeof(HFSExtentRecord);
1080: btKeySize = sizeof(HFSExtentKey);
1081:
1082: extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength;
1083: extentKeyPtr->hfs.forkType = 0;
1084: extentKeyPtr->hfs.fileID = srcFileID;
1085: extentKeyPtr->hfs.startBlock = 0;
1086: }
1087:
1088: //
1089: // We do an initial BTSearchRecord to position the BTree's iterator just before any extent
1090: // records for srcFileID. We then do a few BTIterateRecord and BTInsertRecord of those found
1091: // records, but with destFileID as the file number in the key. Keep doing this sequence of
1092: // BTIterateRecord and BTInsertRecord until we find an extent for another file, or there are
1093: // no more extent records in the tree.
1094: //
1095: // Basically, we're copying records kNumExtentsToCache at a time. The copies have their file ID
1096: // set to destFileID.
1097: //
1098: // This depends on BTInsertRecord not effecting the iterator used by BTIterateRecord. If it
1099: // _did_ effect the iterator, then we would need to do a BTSearchRecord before each series
1100: // of BTIterateRecord. We'd need to set up the key for BTSearchRecord to find the last record
1101: // we found, so that BTIterateRecord would get the next one (the first we haven't processed).
1102: //
1103:
1104: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
1105:
1106: // We expect a btNotFound here, since there shouldn't be an extent record with FABN = 0.
1107: if (err != btNotFound)
1108: {
1109: if ( DEBUG_BUILD )
1110: DebugStr("\pUnexpected error from SearchBTreeRecord");
1111:
1112: if (err == noErr) // If we found such a bogus extent record, then the tree is really messed up
1113: err = cmBadNews; // so return an error that conveys the disk is hosed.
1114:
1115: return err;
1116: }
1117:
1118: do
1119: {
1120: btRecord.bufferAddress = &extentData;
1121: btRecord.itemCount = 1;
1122:
1123: for ( i=0 ; i<kNumExtentsToCache ; i++ )
1124: {
1125: HFSCatalogNodeID foundFileID;
1126:
1127: err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
1128: if ( err == btNotFound ) // Did we run out of extent records in the extents tree?
1129: break; // if xkrFNum(A0) is cleared on this error, then this test is bogus!
1130: else if ( err != noErr )
1131: return( err ); // must be ioError
1132:
1133: foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
1134: if ( foundFileID == srcFileID )
1135: {
1136: CopyExtentInfo(extentKeyPtr, &extentData, extentsBuffer, i);
1137: }
1138: else
1139: {
1140: break;
1141: }
1142: }
1143:
1144: //-- edit each extent key, and reinsert each extent record in the extent file
1145: if (isHFSPlus)
1146: btRecordSize = sizeof(HFSPlusExtentRecord);
1147: else
1148: btRecordSize = sizeof(HFSExtentRecord);
1149:
1150: for ( j=0 ; j<i ; j++ )
1151: {
1152: BTreeIterator tmpIterator;
1153:
1154: if (isHFSPlus)
1155: extentsBuffer[j].extentKey.hfsPlus.fileID = destFileID; // change only the id in the key to dest ID
1156: else
1157: extentsBuffer[j].extentKey.hfs.fileID = destFileID; // change only the id in the key to dest ID
1158:
1159: // get iterator and buffer descriptor ready...
1160: (void) BTInvalidateHint(&tmpIterator);
1161: BlockMoveData(&(extentsBuffer[j].extentKey), &tmpIterator.key, btKeySize);
1162: btRecord.bufferAddress = &(extentsBuffer[j].extentData);
1163:
1164: err = BTInsertRecord(fcb, &tmpIterator, &btRecord, btRecordSize);
1165: if ( err != noErr )
1166: { // parse the error
1167: if ( err == btExists )
1168: {
1169: if ( DEBUG_BUILD )
1170: DebugStr("\pCan't insert record -- already exists");
1171: return( cmBadNews );
1172: }
1173: else
1174: return( err );
1175: }
1176: }
1177:
1178: //-- okay, done with this buffered batch, go get the next set of extent records
1179: // If our buffer is not full, we must be done, or recieved an error
1180:
1181: if ( i != kNumExtentsToCache ) // if the buffer is not full, we must be done
1182: {
1183: err = DeleteExtents( vcb, srcFileID, isHFSPlus ); // Now delete all the extent entries with the sourceID
1184: if ( DEBUG_BUILD && err != noErr )
1185: DebugStr("\pError from DeleteExtents");
1186: break; // we're done!
1187: }
1188: } while ( true );
1189:
1190: return( err );
1191: }
1192:
1193:
1194: void CopyExtentInfo( ExtentKey *key, ExtentRecord *data, ExtentsRecBuffer *buffer, UInt16 bufferCount )
1195: {
1196: BlockMoveData( key, &(buffer[bufferCount].extentKey), sizeof( ExtentKey ) );
1197: BlockMoveData( data, &(buffer[bufferCount].extentData), sizeof( ExtentRecord ) );
1198: }
1199:
1200:
1201: //-- Delete all extents in extent file that have the ID given.
1202: OSErr DeleteExtents( ExtendedVCB *vcb, UInt32 fileID, Boolean isHFSPlus )
1203: {
1204: FCB * fcb;
1205: ExtentKey * extentKeyPtr;
1206: ExtentRecord extentData;
1207: BTreeIterator btIterator;
1208: FSBufferDescriptor btRecord;
1209: UInt16 btRecordSize;
1210: OSErr err;
1211:
1212: fcb = GetFileControlBlock(vcb->extentsRefNum);
1213:
1214: (void) BTInvalidateHint(&btIterator);
1215: extentKeyPtr = (ExtentKey*) &btIterator.key;
1216: btRecord.bufferAddress = &extentData;
1217: btRecord.itemCount = 1;
1218:
1219: // The algorithm is to position the BTree just before any extent records for fileID.
1220: // Then just keep getting successive records. If the record is still for fileID,
1221: // then delete it.
1222:
1223: if (isHFSPlus) {
1224: btRecord.itemSize = sizeof(HFSPlusExtentRecord);
1225:
1226: extentKeyPtr->hfsPlus.keyLength = kHFSPlusExtentKeyMaximumLength;
1227: extentKeyPtr->hfsPlus.forkType = 0;
1228: extentKeyPtr->hfsPlus.pad = 0;
1229: extentKeyPtr->hfsPlus.fileID = fileID;
1230: extentKeyPtr->hfsPlus.startBlock = 0;
1231: }
1232: else {
1233: btRecord.itemSize = sizeof(HFSExtentRecord);
1234:
1235: extentKeyPtr->hfs.keyLength = kHFSExtentKeyMaximumLength;
1236: extentKeyPtr->hfs.forkType = 0;
1237: extentKeyPtr->hfs.fileID = fileID;
1238: extentKeyPtr->hfs.startBlock = 0;
1239: }
1240:
1241: err = BTSearchRecord(fcb, &btIterator, kInvalidMRUCacheKey, &btRecord, &btRecordSize, &btIterator);
1242: if ( err != btNotFound )
1243: {
1244: if (err == noErr) { // Did we find a bogus extent record?
1245: err = cmBadNews; // Yes, so indicate things are messed up.
1246: }
1247:
1248: return err; // Got some unexpected error, so return it
1249: }
1250:
1251: do
1252: {
1253: BTreeIterator tmpIterator;
1254: HFSCatalogNodeID foundFileID;
1255:
1256: err = BTIterateRecord(fcb, kBTreeNextRecord, &btIterator, &btRecord, &btRecordSize);
1257: if ( err != noErr )
1258: {
1259: if (err == btNotFound) // If we hit the end of the BTree
1260: err = noErr; // then it's OK
1261:
1262: break; // We're done now.
1263: }
1264:
1265: foundFileID = isHFSPlus ? extentKeyPtr->hfsPlus.fileID : extentKeyPtr->hfs.fileID;
1266: if ( foundFileID != fileID )
1267: break; // numbers don't match, we must be done
1268:
1269: tmpIterator = btIterator;
1270: err = BTDeleteRecord( fcb, &tmpIterator );
1271: if (err != noErr)
1272: break;
1273: } while ( true );
1274:
1275: return( err );
1276: }
1277:
1278:
1279: // Check if there are extents represented in the extents overflow file.
1280: UInt32 CheckExtents( void *extents, UInt32 totalBlocks, Boolean isHFSPlus )
1281: {
1282: UInt32 extentAllocationBlocks;
1283: UInt16 i;
1284:
1285:
1286: if ( totalBlocks == 0 )
1287: return( 0 );
1288:
1289: extentAllocationBlocks = 0;
1290:
1291: if ( isHFSPlus )
1292: {
1293: for ( i = 0 ; i < kHFSPlusExtentDensity ; i++ )
1294: {
1295: extentAllocationBlocks += ((HFSPlusExtentDescriptor *)extents)[i].blockCount;
1296: if ( extentAllocationBlocks >= totalBlocks ) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
1297: return( 0 );
1298: }
1299: }
1300: else
1301: {
1302: for ( i = 0 ; i < kHFSExtentDensity ; i++ )
1303: {
1304: extentAllocationBlocks += ((HFSExtentDescriptor *)extents)[i].blockCount;
1305: if ( extentAllocationBlocks >= totalBlocks ) // greater than or equal (extents can add past eof if 'Close" crashes w/o truncating new clump)
1306: return( 0 );
1307: }
1308: }
1309:
1310: return( extentAllocationBlocks );
1311: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.