00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048 #include "FSCopyObject.h"
00049 #include "GenLinkedList.h"
00050 #if !TARGET_API_MAC_OSX
00051 #include <UnicodeConverter.h>
00052 #endif
00053 #include <stddef.h>
00054 #include <string.h>
00055
00056 #pragma mark ----- Tunable Parameters -----
00057
00058
00059
00060 enum {
00061
00062 kDefaultCopyBufferSize = 256L * 1024,
00063 kMaximumCopyBufferSize = 2L * 1024 * 1024,
00064 kMinimumCopyBufferSize = 1024
00065 };
00066
00067 enum {
00068 errFSDestInsideSource = -1234
00069 };
00070
00071 enum {
00072
00073 kPrivilegesMask = kioACAccessUserWriteMask | kioACAccessUserReadMask | kioACAccessUserSearchMask,
00074
00075
00076
00077
00078
00079
00080
00081 kRWXUserAccessMask = 0x01C0,
00082 kReadAccessUser = 0x0100,
00083 kWriteAccessUser = 0x0080,
00084 kExecuteAccessUser = 0x0040,
00085
00086 kRWXGroupAccessMask = 0x0038,
00087 kReadAccessGroup = 0x0020,
00088 kWriteAccessGroup = 0x0010,
00089 kExecuteAccessGroup = 0x0008,
00090
00091 kRWXOtherAccessMask = 0x0007,
00092 kReadAccessOther = 0x0004,
00093 kWriteAccessOther = 0x0002,
00094 kExecuteAccessOther = 0x0001,
00095
00096 kDropFolderValue = kWriteAccessOther | kExecuteAccessOther
00097 };
00098
00099 #define kNumObjects 80
00100
00101 #define VolHasCopyFile(volParms) (((volParms)->vMAttrib & (1L << bHasCopyFile)) != 0)
00102
00103 #pragma mark ----- Struct Definitions -----
00104
00105
00106
00107
00108 struct CopyParams {
00109 void *copyBuffer;
00110 ByteCount copyBufferSize;
00111 Boolean copyingToDropFolder;
00112 Boolean copyingToLocalVolume;
00113 Boolean volHasCopyFile;
00114 DupeAction dupeAction;
00115 };
00116 typedef struct CopyParams CopyParams;
00117
00118
00119
00120
00121 struct FilterParams {
00122 FSCatalogInfoBitmap whichInfo;
00123 CopyObjectFilterProcPtr filterProcPtr;
00124 Boolean containerChanged;
00125 Boolean wantSpec;
00126 Boolean wantName;
00127 void *yourDataPtr;
00128 };
00129 typedef struct FilterParams FilterParams;
00130
00131
00132
00133
00134
00135
00136
00137 struct ForkTracker {
00138 HFSUniStr255 forkName;
00139 SInt64 forkSize;
00140 SInt16 forkDestRefNum;
00141 };
00142 typedef struct ForkTracker ForkTracker;
00143 typedef ForkTracker *ForkTrackerPtr;
00144
00145
00146
00147
00148 struct FolderListData
00149 {
00150 FSRef sourceDirRef;
00151 FSRef destDirRef;
00152 UInt32 level;
00153 };
00154 typedef struct FolderListData FolderListData;
00155
00156
00157
00158 struct FSCopyFolderGlobals
00159 {
00160 FSRef *sourceDirRef;
00161 FSRef *destDirRef;
00162
00163 FSCatalogInfo *catInfoList;
00164 FSRef *srcRefList;
00165 HFSUniStr255 *nameList;
00166
00167 GenLinkedList folderList;
00168 GenIteratorPtr folderListIter;
00169
00170 CopyParams *copyParams;
00171 FilterParams *filterParams;
00172 Boolean containerChanged;
00173
00174 ItemCount maxLevels;
00175 ItemCount currentLevel;
00176 };
00177 typedef struct FSCopyFolderGlobals FSCopyFolderGlobals;
00178
00179
00180
00181 struct FSDeleteObjectGlobals
00182 {
00183 FSCatalogInfo catalogInfo;
00184 ItemCount actualObjects;
00185 OSErr result;
00186 };
00187 typedef struct FSDeleteObjectGlobals FSDeleteObjectGlobals;
00188
00189 #pragma mark ----- Local Prototypes -----
00190
00191 static OSErr FSCopyObjectPreflight ( const FSRef *source,
00192 const FSRef *destDir,
00193 const DupeAction dupeAction,
00194 FSCatalogInfo *sourceCatInfo,
00195 CopyParams *copyParams,
00196 HFSUniStr255 *newObjectName,
00197 FSRef *deleteMeRef,
00198 Boolean *isReplacing,
00199 Boolean *isDirectory );
00200
00201 static OSErr FSCopyFile ( const FSRef *source,
00202 const FSRef *destDir,
00203 const FSCatalogInfo *sourceCatInfo,
00204 const HFSUniStr255 *newFileName,
00205 CopyParams *copyParams,
00206 FilterParams *filterParams,
00207 FSRef *newFileRef,
00208 FSSpec *newFileSpec );
00209
00210 static OSErr CopyFile ( const FSRef *source,
00211 FSCatalogInfo *sourceCatInfo,
00212 const FSRef *destDir,
00213 const HFSUniStr255 *destName,
00214 CopyParams *copyParams,
00215 FSRef *newRef,
00216 FSSpec *newSpec );
00217
00218 static OSErr FSUsePBHCopyFile ( const FSRef *srcFileRef,
00219 const FSRef *dstDirectoryRef,
00220 const HFSUniStr255 *destName,
00221 TextEncoding textEncodingHint,
00222 FSRef *newRef,
00223 FSSpec *newSpec );
00224
00225 static OSErr DoCopyFile ( const FSRef *source,
00226 FSCatalogInfo *sourceCatInfo,
00227 const FSRef *destDir,
00228 const HFSUniStr255 *destName,
00229 CopyParams *params,
00230 FSRef *newRef,
00231 FSSpec *newSpec );
00232
00233 static OSErr FSCopyFolder ( const FSRef *source,
00234 const FSRef *destDir,
00235 const FSCatalogInfo *sourceCatInfo,
00236 const HFSUniStr255 *newFoldName,
00237 CopyParams *copyParams,
00238 FilterParams *filterParams,
00239 ItemCount maxLevels,
00240 FSRef *outDirRef,
00241 FSSpec *outDirSpec );
00242
00243 static OSErr ProcessFolderList ( FSCopyFolderGlobals *folderGlobals );
00244
00245 static OSErr CopyFolder ( FSCopyFolderGlobals *folderGlobals );
00246
00247 static OSErr CheckForDestInsideSrc ( const FSRef *source,
00248 const FSRef *destDir );
00249
00250 static OSErr CopyForks ( const FSRef *source,
00251 const FSRef *dest,
00252 CopyParams *params );
00253
00254 static OSErr CopyForksToDisk ( const FSRef *source,
00255 const FSRef *dest,
00256 CopyParams *params );
00257
00258 static OSErr CopyForksToDropBox ( const FSRef *source,
00259 const FSRef *dest,
00260 CopyParams *params );
00261
00262 static OSErr OpenAllForks ( const FSRef *dest,
00263 GenLinkedList *forkList );
00264
00265 static OSErr WriteFork ( const SInt16 srcRefNum,
00266 const SInt16 destRefNum,
00267 const CopyParams *params,
00268 const SInt64 forkSize );
00269
00270 static UInt32 CalcBufferSizeForVol ( const GetVolParmsInfoBuffer *volParms,
00271 UInt32 volParmsSize );
00272
00273 static UInt32 BufferSizeForVolSpeed ( UInt32 volumeBytesPerSecond );
00274
00275 static OSErr FSDeleteFolder ( const FSRef *container );
00276
00277 static void FSDeleteFolderLevel ( const FSRef *container,
00278 FSDeleteObjectGlobals *theGlobals );
00279
00280 static OSErr IsDropBox ( const FSRef *source,
00281 Boolean *isDropBox );
00282
00283 static OSErr GetMagicBusyCreateDate( UTCDateTime *date );
00284
00285 static OSErr FSGetVRefNum ( const FSRef *ref,
00286 FSVolumeRefNum *vRefNum );
00287
00288 static OSErr FSGetVolParms ( FSVolumeRefNum volRefNum,
00289 UInt32 bufferSize,
00290 GetVolParmsInfoBuffer*volParmsInfo,
00291 UInt32 *actualInfoSize );
00292
00293 static OSErr UniStrToPStr ( const HFSUniStr255 *uniStr,
00294 TextEncoding textEncodingHint,
00295 Boolean isVolumeName,
00296 Str255 pStr );
00297
00298 static OSErr FSMakeFSRef ( FSVolumeRefNum volRefNum,
00299 SInt32 dirID,
00300 ConstStr255Param name,
00301 FSRef *ref );
00302
00303 static OSErr SetupDestination ( const FSRef *destDir,
00304 const DupeAction dupeAction,
00305 HFSUniStr255 *sourceName,
00306 FSRef *deleteMeRef,
00307 Boolean *isReplacing);
00308
00309 static OSErr GetUniqueName ( const FSRef *destDir,
00310 HFSUniStr255 *sourceName );
00311
00312 static OSErr GetObjectName ( const FSRef *sourceRef,
00313 HFSUniStr255 *sourceName,
00314 TextEncoding *sourceEncoding );
00315
00316 static OSErr CreateFolder ( const FSRef *sourceRef,
00317 const FSRef *destDirRef,
00318 const FSCatalogInfo *catalogInfo,
00319 const HFSUniStr255 *folderName,
00320 CopyParams *params,
00321 FSRef *newFSRefPtr,
00322 FSSpec *newFSSpecPtr );
00323
00324 static OSErr DoCreateFolder ( const FSRef *sourceRef,
00325 const FSRef *destDirRef,
00326 const FSCatalogInfo *catalogInfo,
00327 const HFSUniStr255 *folderName,
00328 CopyParams *params,
00329 FSRef *newFSRefPtr,
00330 FSSpec *newFSSpecPtr);
00331
00332 static pascal void MyDisposeDataProc ( void *pData );
00333
00334 static pascal void MyCloseForkProc ( void *pData );
00335
00336
00337
00338
00339
00340 #pragma mark ----- Copy Objects -----
00341
00342
00343 OSErr FSCopyObject( const FSRef *source,
00344 const FSRef *destDir,
00345 ItemCount maxLevels,
00346 FSCatalogInfoBitmap whichInfo,
00347 DupeAction dupeAction,
00348 const HFSUniStr255 *newObjectName,
00349 Boolean wantFSSpec,
00350 Boolean wantName,
00351 CopyObjectFilterProcPtr filterProcPtr,
00352 void *yourDataPtr,
00353 FSRef *newObjectRef,
00354 FSSpec *newObjectSpec)
00355 {
00356 CopyParams copyParams;
00357 FilterParams filterParams;
00358 FSCatalogInfo sourceCatInfo;
00359 HFSUniStr255 sourceName,
00360 tmpObjectName;
00361 FSRef tmpObjectRef,
00362 deleteMeRef;
00363 Boolean isDirectory = false,
00364 isReplacing = false;
00365 OSErr err = ( source != NULL && destDir != NULL ) ? noErr : paramErr;
00366
00367
00368
00369 BlockZero( &deleteMeRef, sizeof( FSRef ) );
00370 BlockZero( &tmpObjectRef, sizeof( FSRef ) );
00371
00372
00373 filterParams.whichInfo = whichInfo;
00374 filterParams.filterProcPtr = filterProcPtr;
00375 filterParams.wantSpec = ( filterProcPtr && wantFSSpec );
00376 filterParams.wantName = ( filterProcPtr && wantName );
00377 filterParams.yourDataPtr = yourDataPtr;
00378
00379
00380
00381 if( err == noErr )
00382 err = GetObjectName( source, &sourceName, NULL );
00383 if( err == noErr )
00384 tmpObjectName = (newObjectName != NULL) ? *newObjectName : sourceName;
00385
00386 if( err == noErr )
00387 err = FSCopyObjectPreflight( source, destDir, dupeAction, &sourceCatInfo, ©Params, &tmpObjectName, &deleteMeRef, &isReplacing, &isDirectory );
00388
00389
00390 if( err == noErr )
00391 {
00392 dwarning(( "%s -- err: %d, maxLevels: %u, whichInfo: %08x,\n", __FUNCTION__, err, (unsigned int)maxLevels, (int)whichInfo ));
00393 dwarning(( "\t\t\t\tdupeAction: %s, wantSpec: %s, wantName: %s,\n", ((dupeAction == kDupeActionReplace) ? "replace" : ((dupeAction == kDupeActionRename) ? "rename" : "standard")), (filterParams.wantSpec)?"yes":"no", (filterParams.wantName)?"yes":"no" ));
00394 dwarning(( "\t\t\t\tfilterProcPtr: 0x%08x, yourDataPtr: 0x%08x,\n", (unsigned int)filterProcPtr, (unsigned int)yourDataPtr ));
00395 dwarning(( "\t\t\t\tnewObjectRef: 0x%08x, newObjectSpec: 0x%08x,\n", (unsigned int)newObjectRef, (unsigned int)newObjectSpec ));
00396 dwarning(( "\t\t\t\tcopyBufferSize: %dkB, isDirectory: %s, isLocal: %s,\n", (int)copyParams.copyBufferSize/1024, (isDirectory)?"yes":"no", (copyParams.copyingToLocalVolume)?"yes":"no" ));
00397 dwarning(( "\t\t\t\tisDropBox: %s, PBHCopyFileSync supported: %s\n\n", (copyParams.copyingToDropFolder)?"yes":"no", (copyParams.volHasCopyFile)?"yes":"no" ));
00398 }
00399
00400 if( err == noErr )
00401 {
00402 if ( isDirectory )
00403 {
00404 err = CheckForDestInsideSrc(source, destDir);
00405 if( err == noErr )
00406 err = FSCopyFolder( source, destDir, &sourceCatInfo, &tmpObjectName, ©Params, &filterParams, maxLevels, &tmpObjectRef, newObjectSpec );
00407 }
00408 else
00409 err = FSCopyFile(source, destDir, &sourceCatInfo, &tmpObjectName, ©Params, &filterParams, &tmpObjectRef, newObjectSpec);
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421 if( copyParams.dupeAction == kDupeActionReplace && isReplacing == true )
00422 {
00423 dwarning(("%s -- Cleaning up, this might take a moment. err : %d\n", __FUNCTION__, err));
00424
00425 if( err == noErr )
00426 err = FSDeleteObjects( &deleteMeRef );
00427 else
00428 {
00429
00430
00431
00432
00433
00434 myverify_noerr( FSDeleteObjects( &tmpObjectRef ) );
00435 myverify_noerr( FSRenameUnicode( &deleteMeRef, sourceName.length, sourceName.unicode, sourceCatInfo.textEncodingHint, NULL ) );
00436 }
00437 }
00438
00439 if( err == noErr && newObjectRef != NULL )
00440 *newObjectRef = tmpObjectRef;
00441
00442
00443 if( copyParams.copyBuffer != NULL )
00444 DisposePtr((char*)copyParams.copyBuffer);
00445
00446 mycheck_noerr( err );
00447
00448 return err;
00449 }
00450
00451
00452
00453
00454
00455 static OSErr FSCopyObjectPreflight( const FSRef *source,
00456 const FSRef *destDir,
00457 const DupeAction dupeAction,
00458 FSCatalogInfo *sourceCatInfo,
00459 CopyParams *copyParams,
00460 HFSUniStr255 *newObjectName,
00461 FSRef *deleteMeRef,
00462 Boolean *isReplacing,
00463 Boolean *isDirectory)
00464 {
00465 GetVolParmsInfoBuffer srcVolParms,
00466 destVolParms;
00467 UInt32 srcVolParmsSize = 0,
00468 destVolParmsSize = 0;
00469 FSVolumeRefNum srcVRefNum = 0,
00470 destVRefNum = 0;
00471 OSErr err = ( source != NULL && destDir != NULL &&
00472 sourceCatInfo != NULL && copyParams != NULL &&
00473 newObjectName != NULL && deleteMeRef != NULL &&
00474 isDirectory != NULL ) ? noErr : paramErr;
00475
00476 BlockZero( copyParams, sizeof( CopyParams ) );
00477
00478 copyParams->dupeAction = dupeAction;
00479
00480 if( err == noErr )
00481 err = FSGetCatalogInfo( source, kFSCatInfoSettableInfo, sourceCatInfo, NULL, NULL, NULL );
00482 if( err == noErr )
00483 err = FSGetVRefNum( source, &srcVRefNum );
00484 if( err == noErr )
00485 err = FSGetVolParms( srcVRefNum, sizeof(GetVolParmsInfoBuffer), &srcVolParms, &srcVolParmsSize );
00486 if( err == noErr )
00487 err = FSGetVRefNum( destDir, &destVRefNum );
00488 if( err == noErr )
00489 {
00490
00491 copyParams->copyBufferSize = CalcBufferSizeForVol( &srcVolParms, srcVolParmsSize );
00492
00493
00494
00495
00496 if( srcVRefNum != destVRefNum )
00497 {
00498 err = FSGetVolParms( destVRefNum, sizeof(GetVolParmsInfoBuffer), &destVolParms, &destVolParmsSize );
00499 if( err == noErr )
00500 {
00501 ByteCount tmpBufferSize = CalcBufferSizeForVol( &destVolParms, destVolParmsSize );
00502 if( tmpBufferSize < copyParams->copyBufferSize )
00503 copyParams->copyBufferSize = tmpBufferSize;
00504 }
00505 }
00506 else
00507 destVolParms = srcVolParms;
00508 }
00509 if( err == noErr )
00510 err = ((copyParams->copyBuffer = NewPtr( copyParams->copyBufferSize )) != NULL ) ? noErr : MemError();
00511
00512
00513
00514
00515
00516
00517 if( err == noErr )
00518 err = IsDropBox( destDir, ©Params->copyingToDropFolder );
00519 if( err == noErr )
00520 {
00521
00522 *isDirectory = ((sourceCatInfo->nodeFlags & kFSNodeIsDirectoryMask) != 0);
00523
00524 copyParams->copyingToLocalVolume = (destVolParms.vMServerAdr == 0);
00525 if( !copyParams->copyingToLocalVolume )
00526 {
00527
00528
00529
00530
00531
00532 copyParams->volHasCopyFile = ( err == noErr && destVolParms.vMServerAdr == srcVolParms.vMServerAdr ) ?
00533 VolHasCopyFile(&srcVolParms) : false;
00534 }
00535 }
00536
00537 if( err == noErr )
00538 err = SetupDestination( destDir, copyParams->dupeAction, newObjectName, deleteMeRef, isReplacing );
00539
00540 return err;
00541 }
00542
00543 #pragma mark ----- Copy Files -----
00544
00545
00546
00547 static OSErr FSCopyFile( const FSRef *source,
00548 const FSRef *destDir,
00549 const FSCatalogInfo *sourceCatInfo,
00550 const HFSUniStr255 *newFileName,
00551 CopyParams *copyParams,
00552 FilterParams *filterParams,
00553 FSRef *outFileRef,
00554 FSSpec *outFileSpec )
00555 {
00556 FSCatalogInfo catInfo = *sourceCatInfo;
00557 FSRef newFileRef;
00558 FSSpec newFileSpec;
00559 OSErr err = ( source != NULL && destDir != NULL &&
00560 copyParams != NULL && filterParams != NULL ) ? noErr : paramErr;
00561
00562
00563
00564
00565 if( err == noErr )
00566 err = CopyFile( source, &catInfo, destDir, newFileName, copyParams, &newFileRef, (filterParams->wantSpec || outFileSpec) ? &newFileSpec : NULL );
00567
00568
00569
00570 if( filterParams->filterProcPtr != NULL )
00571 {
00572
00573 if( err == noErr && (filterParams->whichInfo & ~kFSCatInfoSettableInfo) != kFSCatInfoNone )
00574 err = FSGetCatalogInfo( &newFileRef, filterParams->whichInfo & ~kFSCatInfoSettableInfo, &catInfo, NULL, NULL, NULL );
00575
00576 err = CallCopyObjectFilterProc( filterParams->filterProcPtr, false, 0, err, &catInfo, &newFileRef,
00577 (filterParams->wantSpec) ? &newFileSpec : NULL,
00578 (filterParams->wantName) ? newFileName : NULL,
00579 filterParams->yourDataPtr);
00580 }
00581
00582 if( err == noErr )
00583 {
00584 if( outFileRef != NULL )
00585 *outFileRef = newFileRef;
00586 if( outFileSpec != NULL )
00587 *outFileSpec = newFileSpec;
00588 }
00589
00590 mycheck_noerr(err);
00591
00592 return err;
00593 }
00594
00595
00596
00597 static OSErr CopyFile( const FSRef *source,
00598 FSCatalogInfo *sourceCatInfo,
00599 const FSRef *destDir,
00600 const HFSUniStr255 *destName,
00601 CopyParams *params,
00602 FSRef *newFile,
00603 FSSpec *newSpec )
00604 {
00605 OSErr err = paramErr;
00606
00607
00608 ((FInfo *)(sourceCatInfo->finderInfo))->fdFlags &= ~kHasBeenInited;
00609
00610
00611 if( params->volHasCopyFile == true )
00612 err = FSUsePBHCopyFile( source, destDir, destName, kTextEncodingUnknown, newFile, newSpec );
00613
00614
00615 if( err != noErr )
00616 err = DoCopyFile( source, sourceCatInfo, destDir, destName, params, newFile, newSpec );
00617
00618 mycheck_noerr(err);
00619
00620 return err;
00621 }
00622
00623
00624
00625
00626 static OSErr FSUsePBHCopyFile( const FSRef *srcFileRef,
00627 const FSRef *dstDirectoryRef,
00628 const HFSUniStr255 *destName,
00629 TextEncoding textEncodingHint,
00630 FSRef *newRef,
00631 FSSpec *newSpec)
00632 {
00633 FSSpec srcFileSpec;
00634 FSCatalogInfo catalogInfo;
00635 HParamBlockRec pb;
00636 Str255 hfsName;
00637 OSErr err = ( srcFileRef != NULL && dstDirectoryRef != NULL ) ? noErr : paramErr;
00638
00639 if( err == noErr )
00640 err = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
00641 if( err == noErr )
00642 err = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume | kFSCatInfoNodeID, &catalogInfo, NULL, NULL, NULL);
00643 if( err == noErr )
00644 {
00645 pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
00646 pb.copyParam.ioDirID = srcFileSpec.parID;
00647 pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
00648 pb.copyParam.ioDstVRefNum = catalogInfo.volume;
00649 pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
00650 pb.copyParam.ioNewName = NULL;
00651 if( destName != NULL )
00652 err = UniStrToPStr( destName, textEncodingHint, false, hfsName );
00653 pb.copyParam.ioCopyName = ( destName != NULL && err == noErr ) ? hfsName : NULL;
00654 }
00655 if( err == noErr )
00656 err = PBHCopyFileSync(&pb);
00657
00658 if( err == noErr )
00659 {
00660 if( newSpec != NULL )
00661 myverify_noerr(FSMakeFSSpec( pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID, pb.copyParam.ioCopyName, newSpec));
00662 if( newRef != NULL )
00663 myverify_noerr(FSMakeFSRef( pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID, pb.copyParam.ioCopyName, newRef));
00664 }
00665
00666 if( err != paramErr )
00667 mycheck_noerr(err);
00668
00669 return err;
00670 }
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681 static OSErr DoCopyFile(const FSRef *source,
00682 FSCatalogInfo *sourceCatInfo,
00683 const FSRef *destDir,
00684 const HFSUniStr255 *destName,
00685 CopyParams *params,
00686 FSRef *newRef,
00687 FSSpec *newSpec )
00688 {
00689 FSRef dest;
00690 FSSpec tmpSpec;
00691 FSPermissionInfo originalPermissions;
00692 OSType originalFileType = 'xxxx';
00693 UInt16 originalNodeFlags = kFSCatInfoNone;
00694 Boolean getSpec;
00695 OSErr err = noErr;
00696
00697
00698
00699
00700
00701 if (!params->copyingToDropFolder)
00702 {
00703
00704
00705 originalFileType = ((FInfo *) &sourceCatInfo->finderInfo)->fdType;
00706 ((FInfo *) &sourceCatInfo->finderInfo)->fdType = kFirstMagicBusyFiletype;
00707
00708
00709
00710 originalNodeFlags = sourceCatInfo->nodeFlags;
00711 }
00712 sourceCatInfo->nodeFlags &= ~kFSNodeLockedMask;
00713
00714
00715
00716 getSpec = ( ( newSpec != NULL ) || ( !params->copyingToDropFolder && originalFileType == 'slnk' && ((FInfo *) &sourceCatInfo->finderInfo)->fdCreator == 'rhap' ) );
00717
00718
00719
00720
00721
00722 originalPermissions = *((FSPermissionInfo*)sourceCatInfo->permissions);
00723 ((FSPermissionInfo*)sourceCatInfo->permissions)->mode |= kRWXUserAccessMask;
00724
00725
00726
00727 if( err == noErr )
00728 err = FSCreateFileUnicode(destDir, destName->length, destName->unicode, kFSCatInfoSettableInfo, sourceCatInfo, &dest, ( getSpec ) ? &tmpSpec : NULL );
00729 if( err == noErr )
00730 err = CopyForks(source, &dest, params);
00731
00732
00733
00734
00735
00736
00737 if (err == noErr && !params->copyingToDropFolder)
00738 {
00739 ((FInfo *) &sourceCatInfo->finderInfo)->fdType = originalFileType;
00740 sourceCatInfo->nodeFlags = originalNodeFlags;
00741 *((FSPermissionInfo*)sourceCatInfo->permissions) = originalPermissions;
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754 if ((originalFileType == 'slnk') && (((FInfo *) &sourceCatInfo->finderInfo)->fdCreator == 'rhap'))
00755 {
00756
00757 err = FSSetCatalogInfo(&dest, kFSCatInfoNodeFlags | kFSCatInfoPermissions, sourceCatInfo);
00758 if ( err == noErr )
00759 err = FSpSetFInfo( &tmpSpec, ((FInfo *) &sourceCatInfo->finderInfo) );
00760 }
00761 else
00762 err = FSSetCatalogInfo(&dest, kFSCatInfoNodeFlags | kFSCatInfoFinderInfo | kFSCatInfoPermissions, sourceCatInfo);
00763 }
00764
00765
00766
00767
00768
00769
00770
00771 if( err == noErr || err == dupFNErr )
00772 {
00773 if( newRef != NULL )
00774 *newRef = dest;
00775 if( newSpec != NULL )
00776 *newSpec = tmpSpec;
00777 }
00778 else
00779 myverify_noerr( FSDeleteObjects(&dest) );
00780
00781 mycheck_noerr(err);
00782
00783 return err;
00784 }
00785
00786
00787
00788 #pragma mark ----- Copy Folders -----
00789
00790 static OSErr FSCopyFolder( const FSRef *source,
00791 const FSRef *destDir,
00792 const FSCatalogInfo *sourceCatInfo,
00793 const HFSUniStr255 *newObjectName,
00794 CopyParams *copyParams,
00795 FilterParams *filterParams,
00796 ItemCount maxLevels,
00797 FSRef *outDirRef,
00798 FSSpec *outDirSpec )
00799 {
00800 FSCopyFolderGlobals folderGlobals;
00801 FolderListData *tmpListData = NULL;
00802 FSCatalogInfo catInfo = *sourceCatInfo;
00803 FSRef newDirRef;
00804 FSSpec newDirSpec;
00805 OSErr err;
00806
00807
00808 folderGlobals.catInfoList = (FSCatalogInfo*) NewPtr( sizeof( FSCatalogInfo ) * kNumObjects );
00809 folderGlobals.srcRefList = (FSRef*) NewPtr( sizeof( FSRef ) * kNumObjects );
00810 folderGlobals.nameList = (HFSUniStr255*) NewPtr( sizeof( HFSUniStr255 ) * kNumObjects );
00811 folderGlobals.folderListIter = NULL;
00812 folderGlobals.copyParams = copyParams;
00813 folderGlobals.filterParams = filterParams;
00814 folderGlobals.maxLevels = maxLevels;
00815 folderGlobals.currentLevel = 0;
00816
00817
00818 err = ( folderGlobals.catInfoList != NULL &&
00819 folderGlobals.srcRefList != NULL &&
00820 folderGlobals.nameList != NULL ) ? noErr : memFullErr;
00821
00822
00823 InitLinkedList( &folderGlobals.folderList, MyDisposeDataProc );
00824
00825 if( err == noErr && !copyParams->copyingToDropFolder )
00826 err = GetMagicBusyCreateDate( &catInfo.createDate );
00827 if( err == noErr )
00828 err = DoCreateFolder( source, destDir, &catInfo, newObjectName, folderGlobals.copyParams, &newDirRef, (filterParams->wantSpec || outDirSpec ) ? &newDirSpec : NULL );
00829
00830
00831 if( filterParams->filterProcPtr != NULL )
00832 {
00833
00834 if( err == noErr && (filterParams->whichInfo & ~kFSCatInfoSettableInfo) != kFSCatInfoNone )
00835 err = FSGetCatalogInfo(&newDirRef, filterParams->whichInfo & ~kFSCatInfoSettableInfo, &catInfo, NULL, NULL, NULL);
00836
00837 err = CallCopyObjectFilterProc(filterParams->filterProcPtr, false, folderGlobals.currentLevel,
00838 err, &catInfo, &newDirRef,
00839 ( filterParams->wantSpec ) ? &newDirSpec : NULL,
00840 ( filterParams->wantName ) ? newObjectName : NULL,
00841 filterParams->yourDataPtr);
00842 }
00843 if( err == noErr )
00844 err = ( ( tmpListData = (FolderListData*) NewPtr( sizeof( FolderListData ) ) ) != NULL ) ? noErr : MemError();
00845 if( err == noErr )
00846 {
00847 tmpListData->sourceDirRef = *source;
00848 tmpListData->destDirRef = newDirRef;
00849 tmpListData->level = folderGlobals.currentLevel;
00850
00851 err = AddToTail( &folderGlobals.folderList, tmpListData );
00852 if( err == noErr )
00853 err = ProcessFolderList( &folderGlobals );
00854 else
00855 DisposePtr( (char*) tmpListData );
00856 }
00857
00858 dwarning(("\n%s -- %u folders were found\n", __FUNCTION__, (unsigned int)GetNumberOfItems( &folderGlobals.folderList ) ));
00859
00860
00861 DestroyList( &folderGlobals.folderList );
00862
00863
00864
00865
00866
00867 if( err == noErr && !folderGlobals.copyParams->copyingToDropFolder )
00868 err = FSSetCatalogInfo( &newDirRef, kFSCatInfoCreateDate | kFSCatInfoPermissions, sourceCatInfo );
00869
00870
00871 if( err == noErr )
00872 {
00873 if( outDirRef != NULL)
00874 *outDirRef = newDirRef;
00875 if( outDirSpec != NULL )
00876 *outDirSpec = newDirSpec;
00877 }
00878
00879
00880 if( folderGlobals.catInfoList )
00881 DisposePtr( (char*) folderGlobals.catInfoList );
00882 if( folderGlobals.srcRefList )
00883 DisposePtr( (char*) folderGlobals.srcRefList );
00884 if( folderGlobals.nameList )
00885 DisposePtr( (char*) folderGlobals.nameList );
00886
00887 mycheck_noerr(err);
00888
00889 return ( err );
00890 }
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902 static OSErr ProcessFolderList( FSCopyFolderGlobals *folderGlobals )
00903 {
00904 FolderListData *folderListData;
00905 OSErr err = noErr;
00906
00907
00908 for( InitIterator( &folderGlobals->folderList, &folderGlobals->folderListIter ); folderGlobals->folderListIter != NULL && err == noErr; Next( &folderGlobals->folderListIter ) )
00909 {
00910
00911 folderListData = (FolderListData*) GetData( folderGlobals->folderListIter );
00912 if( folderListData != NULL )
00913 {
00914 #if DEBUG && !TARGET_API_MAC_OS8
00915 {
00916 char path[1024];
00917 myverify_noerr(FSRefMakePath( &(folderListData->sourceDirRef), (unsigned char*)path, 1024 ));
00918 dwarning(("\n\n%s -- Copying contents of\n\t%s\n", __FUNCTION__, path));
00919 myverify_noerr(FSRefMakePath( &(folderListData->destDirRef), (unsigned char*)path, 1024 ));
00920 dwarning(("\t\tto\n\t%s\n", path));
00921 }
00922 #endif
00923
00924
00925 folderGlobals->sourceDirRef = &(folderListData->sourceDirRef);
00926 folderGlobals->destDirRef = &(folderListData->destDirRef);
00927 folderGlobals->currentLevel = folderListData->level;
00928
00929
00930
00931 err = CopyFolder( folderGlobals );
00932 }
00933 }
00934
00935 return err;
00936 }
00937
00938
00939
00940
00941
00942
00943
00944
00945 static OSErr CopyFolder( FSCopyFolderGlobals *folderGlobals )
00946 {
00947 GenLinkedList tmpList;
00948 FolderListData *tmpListData = NULL;
00949 FilterParams *filterPtr = folderGlobals->filterParams;
00950 FSIterator iterator;
00951 FSRef newRef;
00952 FSSpec newSpec;
00953 UInt32 actualObjects;
00954 OSErr err,
00955 junkErr;
00956 int i;
00957
00958
00959 InitLinkedList( &tmpList, MyDisposeDataProc);
00960
00961 err = FSOpenIterator( folderGlobals->sourceDirRef, kFSIterateFlat, &iterator );
00962 if( err == noErr )
00963 {
00964 do
00965 {
00966
00967 err = FSGetCatalogInfoBulk( iterator, kNumObjects, &actualObjects, &filterPtr->containerChanged,
00968 kFSCatInfoSettableInfo, folderGlobals->catInfoList, folderGlobals->srcRefList,
00969 NULL, folderGlobals->nameList );
00970 if( ( err == noErr || err == errFSNoMoreItems ) &&
00971 ( actualObjects != 0 ) )
00972 {
00973 dwarning(("%s -- actualObjects retrieved from FSGetCatalogInfoBulk: %u\n",__FUNCTION__, (unsigned int)actualObjects ));
00974
00975
00976 for( i = 0; i < actualObjects; i++ )
00977 {
00978
00979
00980
00981
00982
00983
00984
00985 if( ( folderGlobals->catInfoList[i].nodeFlags & kFSNodeIsDirectoryMask ) != 0 )
00986 {
00987 junkErr = CreateFolder( &folderGlobals->srcRefList[i], folderGlobals->destDirRef,
00988 &folderGlobals->catInfoList[i], &folderGlobals->nameList[i],
00989 folderGlobals->copyParams, &newRef, (filterPtr->wantSpec) ? &newSpec : NULL );
00990
00991
00992 if( folderGlobals->maxLevels == 0 || (folderGlobals->currentLevel + 1) < folderGlobals->maxLevels )
00993 {
00994 if( junkErr == noErr )
00995 junkErr = ( ( tmpListData = (FolderListData*) NewPtr( sizeof( FolderListData ) ) ) != NULL ) ? noErr : MemError();
00996 if( junkErr == noErr )
00997 {
00998 tmpListData->sourceDirRef = folderGlobals->srcRefList[i];
00999 tmpListData->destDirRef = newRef;
01000 tmpListData->level = folderGlobals->currentLevel + 1;
01001
01002
01003 junkErr = AddToTail( &tmpList, tmpListData );
01004 }
01005
01006
01007 if( junkErr != noErr && tmpListData != NULL )
01008 DisposePtr( (char*) tmpListData );
01009 }
01010 }
01011 else
01012 {
01013 junkErr = CopyFile( &folderGlobals->srcRefList[i], &folderGlobals->catInfoList[i],
01014 folderGlobals->destDirRef, &folderGlobals->nameList[i],
01015 folderGlobals->copyParams, &newRef, ( filterPtr->wantSpec ) ? &newSpec : NULL );
01016 }
01017
01018
01019 if( filterPtr->filterProcPtr != NULL )
01020 {
01021 if( junkErr == noErr && (filterPtr->whichInfo & ~kFSCatInfoSettableInfo) != kFSCatInfoNone )
01022 junkErr = FSGetCatalogInfo( &newRef, filterPtr->whichInfo & ~kFSCatInfoSettableInfo, &folderGlobals->catInfoList[i], NULL, NULL, NULL );
01023
01024 err = CallCopyObjectFilterProc( filterPtr->filterProcPtr, filterPtr->containerChanged,
01025 folderGlobals->currentLevel, junkErr,
01026 &folderGlobals->catInfoList[i], &newRef,
01027 ( filterPtr->wantSpec ) ? &newSpec : NULL,
01028 ( filterPtr->wantName ) ? &folderGlobals->nameList[i] : NULL,
01029 filterPtr->yourDataPtr);
01030 }
01031 }
01032 }
01033 }while( err == noErr );
01034
01035
01036
01037 if( err == errFSNoMoreItems || err == afpAccessDenied )
01038 err = noErr;
01039
01040
01041
01042
01043
01044
01045 InsertList( &folderGlobals->folderList, &tmpList, folderGlobals->folderListIter );
01046
01047
01048 (void) FSCloseIterator(iterator);
01049 }
01050
01051 mycheck_noerr( err );
01052
01053 return err;
01054 }
01055
01056
01057
01058
01059
01060
01061
01062
01063 static OSErr CheckForDestInsideSrc( const FSRef *source,
01064 const FSRef *destDir)
01065 {
01066 FSRef thisDir = *destDir;
01067 FSCatalogInfo thisDirInfo;
01068 Boolean done = false;
01069 OSErr err;
01070
01071 do
01072 {
01073 err = FSCompareFSRefs(source, &thisDir);
01074 if (err == noErr)
01075 err = errFSDestInsideSource;
01076 else if (err == diffVolErr)
01077 {
01078 err = noErr;
01079 done = true;
01080 }
01081 else if (err == errFSRefsDifferent)
01082 {
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092 err = FSGetCatalogInfo(&thisDir, kFSCatInfoParentDirID, &thisDirInfo, NULL, NULL, &thisDir);
01093 if( ( err == noErr ) && ( thisDirInfo.parentDirID == fsRtParID ) )
01094 done = true;
01095 }
01096 } while ( err == noErr && ! done );
01097
01098 mycheck_noerr( err );
01099
01100 return err;
01101 }
01102
01103
01104
01105 #pragma mark ----- Copy Forks -----
01106
01107
01108
01109
01110
01111 static OSErr CopyForks( const FSRef *source,
01112 const FSRef *dest,
01113 CopyParams *params)
01114 {
01115 OSErr err;
01116
01117 err = ( !params->copyingToDropFolder ) ? CopyForksToDisk ( source, dest, params ) :
01118 CopyForksToDropBox ( source, dest, params );
01119
01120 mycheck_noerr( err );
01121
01122 return err;
01123 }
01124
01125
01126 static OSErr CopyForksToDisk( const FSRef *source,
01127 const FSRef *dest,
01128 CopyParams *params )
01129 {
01130 HFSUniStr255 forkName;
01131 CatPositionRec iterator;
01132 SInt64 forkSize;
01133 SInt16 srcRefNum,
01134 destRefNum;
01135 OSErr err;
01136
01137
01138 iterator.initialize = 0;
01139
01140 do
01141 {
01142 err = FSIterateForks( source, &iterator, &forkName, &forkSize, NULL );
01143
01144
01145
01146
01147
01148 if( err == noErr )
01149 err = FSCreateFork( dest, forkName.length, forkName.unicode );
01150
01151
01152
01153
01154
01155 if( err == errFSForkExists && !params->copyingToLocalVolume )
01156 err = noErr;
01157
01158
01159
01160
01161 if( err == noErr && forkSize > 0 )
01162 {
01163 destRefNum = srcRefNum = 0;
01164
01165
01166 err = FSOpenFork(dest, forkName.length, forkName.unicode, fsWrPerm, &destRefNum);
01167 if( err == noErr )
01168 err = FSOpenFork(source, forkName.length, forkName.unicode, fsRdPerm, &srcRefNum);
01169 if( err == noErr )
01170 err = WriteFork( srcRefNum, destRefNum, params, forkSize );
01171
01172 if( destRefNum != 0 )
01173 myverify_noerr( FSCloseFork( destRefNum ) );
01174 if( srcRefNum != 0 )
01175 myverify_noerr( FSCloseFork( srcRefNum ) );
01176 }
01177 }
01178 while( err == noErr );
01179
01180 if( err == errFSNoMoreItems )
01181 err = noErr;
01182
01183 mycheck_noerr( err );
01184
01185 return err;
01186 }
01187
01188
01189
01190 static OSErr CopyForksToDropBox( const FSRef *source,
01191 const FSRef *dest,
01192 CopyParams *params )
01193 {
01194 GenLinkedList forkList;
01195 GenIteratorPtr pIter;
01196 ForkTrackerPtr forkPtr;
01197 SInt16 srcRefNum;
01198 OSErr err;
01199
01200 InitLinkedList( &forkList, MyCloseForkProc );
01201
01202
01203
01204
01205 err = OpenAllForks( dest, &forkList );
01206
01207
01208 for( InitIterator( &forkList, &pIter ); pIter != NULL && err == noErr; Next( &pIter ) )
01209 {
01210 srcRefNum = 0;
01211 forkPtr = GetData( pIter );
01212
01213 err = FSOpenFork(source, forkPtr->forkName.length, forkPtr->forkName.unicode, fsRdPerm, &srcRefNum);
01214 if( err == noErr )
01215 err = WriteFork( srcRefNum, forkPtr->forkDestRefNum, params, forkPtr->forkSize );
01216
01217 if( srcRefNum != 0 )
01218 myverify_noerr( FSCloseFork( srcRefNum ) );
01219 }
01220
01221
01222 DestroyList( &forkList );
01223
01224 mycheck_noerr( err );
01225
01226 return err;
01227 }
01228
01229
01230
01231
01232
01233
01234
01235
01236
01237
01238 static OSErr OpenAllForks( const FSRef *dest,
01239 GenLinkedList *forkList )
01240 {
01241 ForkTrackerPtr forkPtr;
01242 HFSUniStr255 forkName;
01243 CatPositionRec iterator;
01244 SInt64 forkSize;
01245 OSErr err = ( dest != NULL && forkList != NULL ) ? noErr : paramErr;
01246
01247
01248 iterator.initialize = 0;
01249
01250
01251 while( err == noErr )
01252 {
01253 forkPtr = NULL;
01254
01255 err = FSIterateForks( dest, &iterator, &forkName, &forkSize, NULL );
01256 if( err == noErr )
01257 err = ( forkPtr = (ForkTrackerPtr) NewPtr( sizeof( ForkTracker ) ) ) != NULL ? noErr : MemError();
01258 if( err == noErr )
01259 {
01260 forkPtr->forkName = forkName;
01261 forkPtr->forkSize = forkSize;
01262 forkPtr->forkDestRefNum = 0;
01263
01264
01265
01266
01267
01268 err = FSCreateFork( dest, forkName.length, forkName.unicode );
01269
01270
01271
01272
01273
01274
01275
01276
01277
01278
01279 if( err == afpAccessDenied )
01280 err = noErr;
01281
01282
01283 if( err == noErr && forkPtr->forkSize > 0 )
01284 err = FSOpenFork( dest, forkPtr->forkName.length, forkPtr->forkName.unicode, fsWrPerm, &forkPtr->forkDestRefNum );
01285
01286
01287 if( err == noErr )
01288 err = AddToTail( forkList, forkPtr );
01289 }
01290
01291 if( err != noErr && forkPtr != NULL )
01292 DisposePtr( (char*) forkPtr );
01293 }
01294
01295 if( err == errFSNoMoreItems )
01296 err = noErr;
01297
01298 mycheck_noerr( err );
01299
01300 return err;
01301 }
01302
01303
01304
01305
01306
01307 static OSErr WriteFork( const SInt16 srcRefNum,
01308 const SInt16 destRefNum,
01309 const CopyParams *params,
01310 const SInt64 forkSize )
01311 {
01312 UInt64 bytesRemaining;
01313 UInt64 bytesToReadThisTime;
01314 UInt64 bytesToWriteThisTime;
01315 OSErr err;
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326 err = FSAllocateFork(destRefNum, kFSAllocNoRoundUpMask, fsFromStart, 0, forkSize, NULL);
01327
01328
01329
01330
01331
01332
01333
01334
01335
01336
01337
01338
01339
01340
01341
01342
01343
01344
01345
01346
01347 bytesRemaining = forkSize;
01348 while( err == noErr && bytesRemaining != 0 )
01349 {
01350 if( bytesRemaining > params->copyBufferSize )
01351 {
01352 bytesToReadThisTime = params->copyBufferSize;
01353 bytesToWriteThisTime = bytesToReadThisTime;
01354 }
01355 else
01356 {
01357 bytesToReadThisTime = bytesRemaining;
01358 bytesToWriteThisTime = ( params->copyingToLocalVolume ) ?
01359 ( (bytesRemaining + 0x01FF ) & ~0x01FF ) : bytesRemaining;
01360 }
01361
01362 err = FSReadFork( srcRefNum, fsAtMark + noCacheMask, 0, bytesToReadThisTime, params->copyBuffer, NULL );
01363 if( err == noErr )
01364 err = FSWriteFork( destRefNum, fsAtMark + noCacheMask, 0, bytesToWriteThisTime, params->copyBuffer, NULL );
01365 if( err == noErr )
01366 bytesRemaining -= bytesToReadThisTime;
01367 }
01368
01369 if (err == noErr && params->copyingToLocalVolume && ( forkSize & 0x01FF ) != 0 )
01370 err = FSSetForkSize( destRefNum, fsFromStart, forkSize );
01371
01372 return err;
01373 }
01374
01375
01376
01377 #pragma mark ----- Calculate Buffer Size -----
01378
01379
01380
01381
01382 static UInt32 CalcBufferSizeForVol(const GetVolParmsInfoBuffer *volParms, UInt32 volParmsSize)
01383 {
01384 UInt32 volumeBytesPerSecond = 0;
01385
01386
01387
01388
01389
01390
01391 mycheck(volParmsSize >= offsetof(GetVolParmsInfoBuffer, vMVolumeGrade));
01392
01393
01394
01395
01396
01397 if( ( volParmsSize >= offsetof(GetVolParmsInfoBuffer, vMForeignPrivID) ) &&
01398 ( volParms->vMVolumeGrade <= 0 ) )
01399 {
01400 volumeBytesPerSecond = -volParms->vMVolumeGrade;
01401 }
01402
01403 return BufferSizeForVolSpeed(volumeBytesPerSecond);
01404 }
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418 static UInt32 BufferSizeForVolSpeed(UInt32 volumeBytesPerSecond)
01419 {
01420 ByteCount bufferSize;
01421
01422 if (volumeBytesPerSecond == 0)
01423 bufferSize = kDefaultCopyBufferSize;
01424 else
01425 {
01426
01427 bufferSize = volumeBytesPerSecond / 4;
01428 }
01429
01430
01431 bufferSize &= ~0x01FF;
01432
01433
01434 if (bufferSize < kMinimumCopyBufferSize)
01435 bufferSize = kMinimumCopyBufferSize;
01436 else if (bufferSize > kMaximumCopyBufferSize)
01437 bufferSize = kMaximumCopyBufferSize;
01438
01439 return bufferSize;
01440 }
01441
01442
01443
01444 #pragma mark ----- Delete Objects -----
01445
01446 OSErr FSDeleteObjects( const FSRef *source )
01447 {
01448 FSCatalogInfo catalogInfo;
01449 OSErr err = ( source != NULL ) ? noErr : paramErr;
01450
01451 #if DEBUG && !TARGET_API_MAC_OS8
01452 if( err == noErr )
01453 {
01454 char path[1024];
01455 myverify_noerr(FSRefMakePath( source, (unsigned char*)path, 1024 ));
01456 dwarning(("\n%s -- Deleting %s\n", __FUNCTION__, path));
01457 }
01458 #endif
01459
01460
01461 if( err == noErr )
01462 err = FSGetCatalogInfo(source, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL);
01463 if( err == noErr && (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0 )
01464 {
01465 err = FSDeleteFolder(source);
01466 }
01467 if( err == noErr && (catalogInfo.nodeFlags & kFSNodeLockedMask) != 0 )
01468 {
01469 catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
01470 (void) FSSetCatalogInfo(source, kFSCatInfoNodeFlags, &catalogInfo);
01471 }
01472 if( err == noErr )
01473 err = FSDeleteObject(source);
01474
01475 mycheck_noerr( err );
01476
01477 return ( err );
01478 }
01479
01480
01481
01482 #pragma mark ----- Delete Folders -----
01483
01484 static OSErr FSDeleteFolder( const FSRef *container )
01485 {
01486 FSDeleteObjectGlobals theGlobals;
01487
01488 theGlobals.result = ( container != NULL ) ? noErr : paramErr;
01489
01490
01491 if( theGlobals.result == noErr )
01492 FSDeleteFolderLevel(container, &theGlobals);
01493
01494 mycheck_noerr( theGlobals.result );
01495
01496 return ( theGlobals.result );
01497 }
01498
01499
01500
01501 static void FSDeleteFolderLevel(const FSRef *container,
01502 FSDeleteObjectGlobals *theGlobals )
01503 {
01504 FSIterator iterator;
01505 FSRef itemToDelete;
01506 UInt16 nodeFlags;
01507
01508
01509 theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator);
01510 if ( theGlobals->result == noErr )
01511 {
01512 do
01513 {
01514
01515 theGlobals->result = FSGetCatalogInfoBulk( iterator, 1, &theGlobals->actualObjects,
01516 NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo,
01517 &itemToDelete, NULL, NULL);
01518 if ( (theGlobals->result == noErr) && (theGlobals->actualObjects == 1) )
01519 {
01520
01521 nodeFlags = theGlobals->catalogInfo.nodeFlags;
01522
01523
01524 if ( (nodeFlags & kFSNodeIsDirectoryMask) != 0 )
01525 {
01526 FSDeleteFolderLevel(&itemToDelete, theGlobals);
01527 }
01528 if ( theGlobals->result == noErr)
01529 {
01530 if ( (nodeFlags & kFSNodeLockedMask) != 0 )
01531 {
01532 theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask;
01533 (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo);
01534 }
01535
01536 theGlobals->result = FSDeleteObject(&itemToDelete);
01537 }
01538 }
01539 } while ( theGlobals->result == noErr );
01540
01541
01542 if ( theGlobals->result == errFSNoMoreItems )
01543 theGlobals->result = noErr;
01544
01545
01546 myverify_noerr(FSCloseIterator(iterator));
01547 }
01548
01549 mycheck_noerr( theGlobals->result );
01550
01551 return;
01552 }
01553
01554
01555
01556 #pragma mark ----- Utilities -----
01557
01558
01559
01560 static OSErr IsDropBox( const FSRef* source,
01561 Boolean *isDropBox )
01562 {
01563 FSCatalogInfo tmpCatInfo;
01564 FSSpec sourceSpec;
01565 Boolean isDrop = false;
01566 OSErr err;
01567
01568
01569 err = FSGetCatalogInfo(source, kFSCatInfoNodeFlags | kFSCatInfoPermissions, &tmpCatInfo, NULL, &sourceSpec, NULL);
01570 if( err == noErr )
01571 err = ((tmpCatInfo.nodeFlags & kFSNodeIsDirectoryMask) != 0) ? noErr : errFSNotAFolder;
01572 if( err == noErr )
01573 {
01574 HParamBlockRec hPB;
01575
01576 BlockZero( &hPB, sizeof( HParamBlockRec ) );
01577
01578 hPB.accessParam.ioNamePtr = sourceSpec.name;
01579 hPB.accessParam.ioVRefNum = sourceSpec.vRefNum;
01580 hPB.accessParam.ioDirID = sourceSpec.parID;
01581
01582
01583
01584 err = PBHGetDirAccessSync(&hPB);
01585 if( err == noErr )
01586 isDrop = (hPB.accessParam.ioACAccess & kPrivilegesMask) == kioACAccessUserWriteMask;
01587 else if ( err == paramErr )
01588 {
01589
01590
01591
01592
01593
01594
01595 FSPermissionInfo *tmpPerm = (FSPermissionInfo *)tmpCatInfo.permissions;
01596 isDrop = ((tmpPerm->mode & kRWXOtherAccessMask) == kDropFolderValue);
01597 err = noErr;
01598 }
01599 }
01600
01601 *isDropBox = isDrop;
01602
01603 mycheck_noerr( err );
01604
01605 return err;
01606 }
01607
01608
01609
01610
01611
01612
01613
01614
01615
01616
01617
01618
01619
01620
01621 static OSErr GetMagicBusyCreateDate( UTCDateTime *date )
01622 {
01623 static UTCDateTime magicDate = { 0, 0xDEADBEEF, 0 };
01624 OSErr err = ( date != NULL ) ? noErr : paramErr;
01625
01626 if( err == noErr && magicDate.lowSeconds == 0xDEADBEEF )
01627 err = ConvertLocalTimeToUTC( kMagicBusyCreationDate, &magicDate.lowSeconds );
01628 if( err == noErr )
01629 *date = magicDate;
01630
01631 mycheck_noerr( err );
01632
01633 return err;
01634 }
01635
01636
01637
01638 static OSErr FSGetVRefNum( const FSRef *ref,
01639 FSVolumeRefNum *vRefNum)
01640 {
01641 FSCatalogInfo catalogInfo;
01642 OSErr err = ( ref != NULL && vRefNum != NULL ) ? noErr : paramErr;
01643
01644 if( err == noErr )
01645 err = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
01646 if( err == noErr )
01647 *vRefNum = catalogInfo.volume;
01648
01649 mycheck_noerr( err );
01650
01651 return err;
01652 }
01653
01654
01655
01656 static OSErr FSGetVolParms( FSVolumeRefNum volRefNum,
01657 UInt32 bufferSize,
01658 GetVolParmsInfoBuffer *volParmsInfo,
01659 UInt32 *actualInfoSize)
01660 {
01661 HParamBlockRec pb;
01662 OSErr err = ( volParmsInfo != NULL ) ? noErr : paramErr;
01663
01664 if( err == noErr )
01665 {
01666 pb.ioParam.ioNamePtr = NULL;
01667 pb.ioParam.ioVRefNum = volRefNum;
01668 pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
01669 pb.ioParam.ioReqCount = (SInt32)bufferSize;
01670 err = PBHGetVolParmsSync(&pb);
01671 }
01672
01673 if( err == noErr && actualInfoSize != NULL)
01674 *actualInfoSize = (UInt32)pb.ioParam.ioActCount;
01675
01676 mycheck_noerr( err );
01677
01678 return ( err );
01679 }
01680
01681
01682
01683
01684
01685
01686
01687 static OSErr UniStrToPStr( const HFSUniStr255 *uniStr,
01688 TextEncoding textEncodingHint,
01689 Boolean isVolumeName,
01690 Str255 pStr )
01691 {
01692 UnicodeMapping uMapping;
01693 UnicodeToTextInfo utInfo;
01694 ByteCount unicodeByteLength = 0;
01695 ByteCount unicodeBytesConverted;
01696 ByteCount actualPascalBytes;
01697 OSErr err = (uniStr != NULL && pStr != NULL) ? noErr : paramErr;
01698
01699
01700 pStr[0] = 0;
01701
01702 if( err == noErr )
01703 unicodeByteLength = uniStr->length * sizeof(UniChar);
01704 if( err == noErr && unicodeByteLength != 0 )
01705 {
01706
01707 if ( kTextEncodingUnknown == textEncodingHint )
01708 {
01709 ScriptCode script;
01710 RegionCode region;
01711
01712 script = (ScriptCode)GetScriptManagerVariable(smSysScript);
01713 region = (RegionCode)GetScriptManagerVariable(smRegionCode);
01714 err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
01715 region, NULL, &textEncodingHint );
01716 if ( err == paramErr )
01717 {
01718 err = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
01719 kTextRegionDontCare, NULL,
01720 &textEncodingHint );
01721 }
01722 if ( err != noErr )
01723 textEncodingHint = kTextEncodingMacRoman;
01724 }
01725
01726 uMapping.unicodeEncoding = CreateTextEncoding( kTextEncodingUnicodeV2_0,
01727 kUnicodeCanonicalDecompVariant,
01728 kUnicode16BitFormat);
01729 uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
01730 uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
01731
01732 err = CreateUnicodeToTextInfo(&uMapping, &utInfo);
01733 if( err == noErr )
01734 {
01735 err = ConvertFromUnicodeToText( utInfo, unicodeByteLength, uniStr->unicode, kUnicodeLooseMappingsMask,
01736 0, NULL, 0, NULL,
01737 isVolumeName ? kHFSMaxVolumeNameChars : kHFSPlusMaxFileNameChars,
01738 &unicodeBytesConverted, &actualPascalBytes, &pStr[1]);
01739 }
01740 if( err == noErr )
01741 pStr[0] = actualPascalBytes;
01742
01743
01744 myverify_noerr(DisposeUnicodeToTextInfo(&utInfo));
01745 }
01746
01747 mycheck_noerr( err );
01748
01749 return ( err );
01750 }
01751
01752
01753
01754
01755
01756
01757 static OSErr FSMakeFSRef( FSVolumeRefNum volRefNum,
01758 SInt32 dirID,
01759 ConstStr255Param name,
01760 FSRef *ref )
01761 {
01762 FSRefParam pb;
01763 OSErr err = ( ref != NULL ) ? noErr : paramErr;
01764
01765 if( err == noErr )
01766 {
01767 pb.ioVRefNum = volRefNum;
01768 pb.ioDirID = dirID;
01769 pb.ioNamePtr = (StringPtr)name;
01770 pb.newRef = ref;
01771 err = PBMakeFSRefSync(&pb);
01772 }
01773
01774 mycheck_noerr( err );
01775
01776 return ( err );
01777 }
01778
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794 static OSErr SetupDestination( const FSRef *destDir,
01795 const DupeAction dupeAction,
01796 HFSUniStr255 *sourceName,
01797 FSRef *deleteMeRef,
01798 Boolean *isReplacing )
01799 {
01800 FSRef tmpRef;
01801 OSErr err;
01802
01803
01804 err = FSMakeFSRefUnicode( destDir, sourceName->length, sourceName->unicode, kTextEncodingUnknown, &tmpRef );
01805 if( err == noErr )
01806 {
01807
01808 if( dupeAction == kDupeActionReplace )
01809 {
01810 err = FSRenameUnicode( &tmpRef, 9, (UniChar*)"\0.\0D\0e\0l\0e\0t\0e\0M\0e", kTextEncodingMacRoman, deleteMeRef );
01811 *isReplacing = ( err == noErr ) ? true : false;
01812 }
01813 else if( dupeAction == kDupeActionRename )
01814 err = GetUniqueName( destDir, sourceName );
01815 }
01816 else if ( err == fnfErr )
01817 err = noErr;
01818
01819 return err;
01820 }
01821
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832 static OSErr GetUniqueName( const FSRef *destDir,
01833 HFSUniStr255 *sourceName )
01834 {
01835 HFSUniStr255 tmpName = *sourceName;
01836 FSRef tmpRef;
01837 unsigned char hexStr[17] = "123456789";
01838 long count = 0;
01839 int index;
01840 OSErr err;
01841
01842
01843 for( index = tmpName.length; index >= 0 && tmpName.unicode[index] != (UniChar) '.'; index-- ) { }
01844
01845 if( index <= 0)
01846 index = tmpName.length;
01847 else
01848 BlockMoveData( tmpName.unicode + index, tmpName.unicode + index + 2, (tmpName.length - index) * 2 );
01849
01850
01851 tmpName.unicode[ index ] = (UniChar)' ';
01852
01853 tmpName.length += 2;
01854
01855 do {
01856 tmpName.unicode[ index + 1 ] = hexStr[count];
01857
01858 err = FSMakeFSRefUnicode( destDir, tmpName.length, tmpName.unicode, kTextEncodingUnknown, &tmpRef );
01859 count++;
01860 } while( err == noErr && count < 10 );
01861
01862 if( err == fnfErr )
01863 {
01864 err = noErr;
01865 *sourceName = tmpName;
01866 }
01867
01868 return err;
01869 }
01870
01871
01872
01873 static OSErr GetObjectName( const FSRef *sourceRef,
01874 HFSUniStr255 *sourceName,
01875 TextEncoding *sourceEncoding )
01876 {
01877 FSCatalogInfo catInfo;
01878 FSCatalogInfoBitmap whichInfo = (sourceEncoding != NULL) ? kFSCatInfoTextEncoding : kFSCatInfoNone;
01879 OSErr err;
01880
01881 err = FSGetCatalogInfo( sourceRef, whichInfo, &catInfo, sourceName, NULL, NULL );
01882 if( err == noErr && sourceEncoding != NULL )
01883 *sourceEncoding = catInfo.textEncodingHint;
01884
01885 return err;
01886 }
01887
01888
01889
01890 static OSErr CreateFolder( const FSRef *sourceRef,
01891 const FSRef *destDirRef,
01892 const FSCatalogInfo *catalogInfo,
01893 const HFSUniStr255 *folderName,
01894 CopyParams *params,
01895 FSRef *newFSRefPtr,
01896 FSSpec *newFSSpecPtr )
01897 {
01898 FSCatalogInfo tmpCatInfo;
01899 FSPermissionInfo origPermissions;
01900 OSErr err = ( sourceRef != NULL && destDirRef != NULL && catalogInfo != NULL &&
01901 folderName != NULL && newFSRefPtr != NULL ) ? noErr : paramErr;
01902
01903 if( err == noErr )
01904 {
01905 tmpCatInfo = *catalogInfo;
01906 origPermissions = *((FSPermissionInfo*)catalogInfo->permissions);
01907 }
01908 if( err == noErr )
01909 err = DoCreateFolder( sourceRef, destDirRef, &tmpCatInfo, folderName, params, newFSRefPtr, newFSSpecPtr );
01910 if( err == noErr && !params->copyingToDropFolder )
01911 {
01912 *((FSPermissionInfo*)tmpCatInfo.permissions) = origPermissions;
01913 err = FSSetCatalogInfo( newFSRefPtr, kFSCatInfoPermissions, &tmpCatInfo );
01914 }
01915
01916 mycheck_noerr( err );
01917
01918 return err;
01919 }
01920
01921
01922
01923 static OSErr DoCreateFolder(const FSRef *sourceRef,
01924 const FSRef *destDirRef,
01925 const FSCatalogInfo *catalogInfo,
01926 const HFSUniStr255 *folderName,
01927 CopyParams *params,
01928 FSRef *newFSRefPtr,
01929 FSSpec *newFSSpecPtr)
01930 {
01931 FSCatalogInfo catInfo = *catalogInfo;
01932 OSErr err;
01933
01934
01935 ((FInfo *)(catInfo.finderInfo))->fdFlags &= ~kHasBeenInited;
01936
01937
01938
01939
01940 ((FSPermissionInfo*) catInfo.permissions)->mode |= kRWXUserAccessMask;
01941
01942 err = FSCreateDirectoryUnicode( destDirRef, folderName->length,
01943 folderName->unicode, kFSCatInfoSettableInfo,
01944 &catInfo, newFSRefPtr,
01945 newFSSpecPtr, NULL);
01946
01947
01948
01949
01950
01951
01952 if( err == noErr )
01953 err = CopyForks( sourceRef, newFSRefPtr, params );
01954
01955 mycheck_noerr( err );
01956
01957 return err;
01958 }
01959
01960
01961
01962
01963
01964 static pascal void MyDisposeDataProc( void *pData )
01965 {
01966 if( pData != NULL )
01967 DisposePtr( (char*) pData );
01968 }
01969
01970
01971
01972
01973
01974 static pascal void MyCloseForkProc( void *pData )
01975 {
01976 SInt16 refNum;
01977
01978 if( pData == NULL )
01979 return;
01980
01981 refNum = ((ForkTrackerPtr)pData)->forkDestRefNum;
01982 if( refNum != 0 )
01983 myverify_noerr( FSCloseFork( refNum ) );
01984
01985 DisposePtr( (char*) pData );
01986 }