4         Contains:       A collection of useful high-level File Manager routines 
   5                                 which use the HFS Plus APIs wherever possible. 
   7         Version:        MoreFilesX 1.0.1 
   9         Copyright:      © 1992-2002 by Apple Computer, Inc., all rights reserved. 
  11         Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc. 
  12                                 ("Apple") in consideration of your agreement to the following terms, and your 
  13                                 use, installation, modification or redistribution of this Apple software 
  14                                 constitutes acceptance of these terms.  If you do not agree with these terms, 
  15                                 please do not use, install, modify or redistribute this Apple software. 
  17                                 In consideration of your agreement to abide by the following terms, and subject 
  18                                 to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs 
  19                                 copyrights in this original Apple software (the "Apple Software"), to use, 
  20                                 reproduce, modify and redistribute the Apple Software, with or without 
  21                                 modifications, in source and/or binary forms; provided that if you redistribute 
  22                                 the Apple Software in its entirety and without modifications, you must retain 
  23                                 this notice and the following text and disclaimers in all such redistributions of 
  24                                 the Apple Software.  Neither the name, trademarks, service marks or logos of 
  25                                 Apple Computer, Inc. may be used to endorse or promote products derived from the 
  26                                 Apple Software without specific prior written permission from Apple.  Except as 
  27                                 expressly stated in this notice, no other rights or licenses, express or implied, 
  28                                 are granted by Apple herein, including but not limited to any patent rights that 
  29                                 may be infringed by your derivative works or by other works in which the Apple 
  30                                 Software may be incorporated. 
  32                                 The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO 
  33                                 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED 
  34                                 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  35                                 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN 
  36                                 COMBINATION WITH YOUR PRODUCTS. 
  38                                 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR 
  39                                 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 
  40                                 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
  41                                 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION 
  42                                 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT 
  43                                 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN 
  44                                 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  48                 DRI:                            Apple Macintosh Developer Technical Support 
  50                 Other Contact:          For bug reports, consult the following page on 
  52                                                                 http://developer.apple.com/bugreporter/ 
  54                 Technology:                     DTS Sample Code 
  60         Change History (most recent first): 
  62                  <4>     8/22/02        JL              [3016251]  Changed FSMoveRenameObjectUnicode to not use 
  63                                                                         the Temporary folder because it isn't available on 
  65                  <3>     4/19/02        JL              [2853905]  Fixed #if test around header includes. 
  66                  <2>     4/19/02        JL              [2850624]  Fixed C++ compile errors and Project Builder 
  68                  <2>     4/19/02        JL              [2853901]  Updated standard disclaimer. 
  69                  <1>     1/25/02        JL              MoreFilesX 1.0 
  73         #include <Carbon/Carbon.h> 
  80 #include "MoreFilesX.h" 
  82 /* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */ 
  83 #ifndef BuildingMoreFilesXForMacOS9 
  84         #define BuildingMoreFilesXForMacOS9 0 
  87 /*****************************************************************************/ 
  89 #pragma mark ----- Local type definitions ----- 
  91 struct FSIterateContainerGlobals
 
  93         IterateContainerFilterProcPtr   iterateFilter
;  /* pointer to IterateFilterProc */ 
  94         FSCatalogInfoBitmap                             whichInfo
;              /* fields of the CatalogInfo to get */ 
  95         FSCatalogInfo                                   catalogInfo
;    /* FSCatalogInfo */ 
  96         FSRef                                                   ref
;                    /* FSRef */ 
  97         FSSpec                                                  spec
;                   /* FSSpec */ 
  98         FSSpec                                                  
*specPtr
;               /* pointer to spec field, or NULL */ 
  99         HFSUniStr255                                    name
;                   /* HFSUniStr255 */ 
 100         HFSUniStr255                                    
*namePtr
;               /* pointer to name field, or NULL */ 
 101         void                                                    *yourDataPtr
;   /* a pointer to caller supplied data the filter may need to access */ 
 102         ItemCount                                               maxLevels
;              /* maximum levels to iterate through */ 
 103         ItemCount                                               currentLevel
;   /* the current level FSIterateContainerLevel is on */ 
 104         Boolean                                                 quitFlag
;               /* set to true if filter wants to kill interation */ 
 105         Boolean                                                 containerChanged
; /* temporary - set to true if the current container changed during iteration */ 
 106         OSErr                                                   result
;                 /* result */ 
 107         ItemCount                                               actualObjects
;  /* number of objects returned */ 
 109 typedef struct FSIterateContainerGlobals FSIterateContainerGlobals
; 
 111 struct FSDeleteContainerGlobals
 
 113         OSErr                                                   result
;                 /* result */ 
 114         ItemCount                                               actualObjects
;  /* number of objects returned */ 
 115         FSCatalogInfo                                   catalogInfo
;    /* FSCatalogInfo */ 
 117 typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals
; 
 119 /*****************************************************************************/ 
 121 #pragma mark ----- Local prototypes ----- 
 125 FSDeleteContainerLevel( 
 126         const FSRef 
*container
, 
 127         FSDeleteContainerGlobals 
*theGlobals
); 
 131 FSIterateContainerLevel( 
 132         FSIterateContainerGlobals 
*theGlobals
); 
 136 GenerateUniqueHFSUniStr( 
 140         HFSUniStr255 
*uniqueName
); 
 142 /*****************************************************************************/ 
 144 #pragma mark ----- File Access Routines ----- 
 146 /*****************************************************************************/ 
 153         ByteCount copyBufferSize
) 
 159         ByteCount       readActualCount
; 
 161         /* check input parameters */ 
 162         require_action((NULL 
!= copyBufferPtr
) && (0 != copyBufferSize
), BadParameter
, result 
= paramErr
); 
 164         /* get source fork size */ 
 165         result 
= FSGetForkSize(srcRefNum
, &forkSize
); 
 166         require_noerr(result
, SourceFSGetForkSizeFailed
); 
 168         /* allocate disk space for destination fork */ 
 169         result 
= FSSetForkSize(dstRefNum
, fsFromStart
, forkSize
); 
 170         require_noerr(result
, DestinationFSSetForkSizeFailed
); 
 172         /* reset source fork's position to 0 */ 
 173         result 
= FSSetForkPosition(srcRefNum
, fsFromStart
, 0); 
 174         require_noerr(result
, SourceFSSetForkPositionFailed
); 
 176         /* reset destination fork's position to 0 */ 
 177         result 
= FSSetForkPosition(dstRefNum
, fsFromStart
, 0); 
 178         require_noerr(result
, DestinationFSSetForkPositionFailed
); 
 180         /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */ 
 181         /* This will make writes on local volumes faster */ 
 182         if ( (copyBufferSize 
>= 0x00001000) && ((copyBufferSize 
& 0x00000fff) != 0) ) 
 184                 copyBufferSize 
&= ~(0x00001000 - 1); 
 187         /* copy source to destination */ 
 188         srcResult 
= dstResult 
= noErr
; 
 189         while ( (noErr 
== srcResult
) && (noErr 
== dstResult
) ) 
 191                 srcResult 
= FSReadFork(srcRefNum
, fsAtMark 
+ noCacheMask
, 0, copyBufferSize
, copyBufferPtr
, &readActualCount
); 
 192                 dstResult 
= FSWriteFork(dstRefNum
, fsAtMark 
+ noCacheMask
, 0, readActualCount
, copyBufferPtr
, NULL
); 
 195         /* make sure there were no errors at the destination */ 
 196         require_noerr_action(dstResult
, DestinationFSWriteForkFailed
, result 
= dstResult
); 
 198         /* make sure the error at the source was eofErr */ 
 199         require_action(eofErr 
== srcResult
, SourceResultNotEofErr
, result 
= srcResult
); 
 201         /* everything went as expected */ 
 204 SourceResultNotEofErr
: 
 205 DestinationFSWriteForkFailed
: 
 206 DestinationFSSetForkPositionFailed
: 
 207 SourceFSSetForkPositionFailed
: 
 208 DestinationFSSetForkSizeFailed
: 
 209 SourceFSGetForkSizeFailed
: 
 215 /*****************************************************************************/ 
 217 #pragma mark ----- Volume Access Routines ----- 
 219 /*****************************************************************************/  
 223         FSVolumeRefNum volRefNum
, 
 225         GetVolParmsInfoBuffer 
*volParmsInfo
, 
 226         UInt32 
*actualInfoSize
) 
 231         /* check parameters */ 
 232         require_action((NULL 
!= volParmsInfo
) && (NULL 
!= actualInfoSize
), 
 233                 BadParameter
, result 
= paramErr
); 
 235         pb
.ioParam
.ioNamePtr 
= NULL
; 
 236         pb
.ioParam
.ioVRefNum 
= volRefNum
; 
 237         pb
.ioParam
.ioBuffer 
= (Ptr
)volParmsInfo
; 
 238         pb
.ioParam
.ioReqCount 
= (SInt32
)bufferSize
; 
 239         result 
= PBHGetVolParmsSync(&pb
); 
 240         require_noerr(result
, PBHGetVolParmsSync
); 
 242         /* return number of bytes the file system returned in volParmsInfo buffer */ 
 243         *actualInfoSize 
= (UInt32
)pb
.ioParam
.ioActCount
; 
 251 /*****************************************************************************/ 
 256         FSVolumeRefNum 
*vRefNum
) 
 259         FSCatalogInfo   catalogInfo
; 
 261         /* check parameters */ 
 262         require_action(NULL 
!= vRefNum
, BadParameter
, result 
= paramErr
); 
 264         /* get the volume refNum from the FSRef */ 
 265         result 
= FSGetCatalogInfo(ref
, kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
, NULL
); 
 266         require_noerr(result
, FSGetCatalogInfo
); 
 268         /* return volume refNum from catalogInfo */ 
 269         *vRefNum 
= catalogInfo
.volume
; 
 277 /*****************************************************************************/ 
 281         FSVolumeRefNum volume
, 
 282         HFSUniStr255 
*volumeName
,       /* can be NULL */ 
 283         UInt64 
*freeBytes
,                      /* can be NULL */ 
 284         UInt64 
*totalBytes
)                     /* can be NULL */ 
 289         /* ask for the volume's sizes only if needed */ 
 290         result 
= FSGetVolumeInfo(volume
, 0, NULL
, 
 291                 (((NULL 
!= freeBytes
) || (NULL 
!= totalBytes
)) ? kFSVolInfoSizes 
: kFSVolInfoNone
), 
 292                 &info
, volumeName
, NULL
); 
 293         require_noerr(result
, FSGetVolumeInfo
); 
 295         if ( NULL 
!= freeBytes 
) 
 297                 *freeBytes 
= info
.freeBytes
; 
 299         if ( NULL 
!= totalBytes 
) 
 301                 *totalBytes 
= info
.totalBytes
; 
 309 /*****************************************************************************/ 
 312 FSGetVolFileSystemID( 
 313         FSVolumeRefNum volume
, 
 314         UInt16 
*fileSystemID
,   /* can be NULL */ 
 315         UInt16 
*signature
)              /* can be NULL */ 
 320         result 
= FSGetVolumeInfo(volume
, 0, NULL
, kFSVolInfoFSInfo
, &info
, NULL
, NULL
); 
 321         require_noerr(result
, FSGetVolumeInfo
); 
 323         if ( NULL 
!= fileSystemID 
) 
 325                 *fileSystemID 
= info
.filesystemID
; 
 327         if ( NULL 
!= signature 
) 
 329                 *signature 
= info
.signature
; 
 337 /*****************************************************************************/ 
 341         FSRef 
***volumeRefsHandle
,      /* pointer to handle of FSRefs */ 
 342         ItemCount 
*numVolumes
) 
 346         ItemCount       volumeIndex
; 
 349         /* check parameters */ 
 350         require_action((NULL 
!= volumeRefsHandle
) && (NULL 
!= numVolumes
), 
 351                 BadParameter
, result 
= paramErr
); 
 356         /* Allocate a handle for the results */ 
 357         *volumeRefsHandle 
= (FSRef 
**)NewHandle(0); 
 358         require_action(NULL 
!= *volumeRefsHandle
, NewHandle
, result 
= memFullErr
); 
 360         /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */ 
 364                 result 
= FSGetVolumeInfo(0, volumeIndex
, NULL
, kFSVolInfoNone
, NULL
, NULL
, &ref
); 
 365                 if ( noErr 
== result 
) 
 367                         /* concatenate the FSRef to the end of the handle */ 
 368                         PtrAndHand(&ref
, (Handle
)*volumeRefsHandle
, sizeof(FSRef
)); 
 369                         memResult 
= MemError(); 
 370                         require_noerr_action(memResult
, MemoryAllocationFailed
, result 
= memResult
); 
 372                         ++(*numVolumes
);        /* increment the volume count */ 
 373                         ++volumeIndex
;          /* and the volumeIndex to get the next volume*/ 
 375         } while ( noErr 
== result 
); 
 377         /* nsvErr is OK -- it just means there are no more volumes */ 
 378         require(nsvErr 
== result
, FSGetVolumeInfo
); 
 382         /**********************/ 
 384 MemoryAllocationFailed
: 
 387         /* dispose of handle if already allocated and clear the outputs */ 
 388         if ( NULL 
!= *volumeRefsHandle 
) 
 390                 DisposeHandle((Handle
)*volumeRefsHandle
); 
 391                 *volumeRefsHandle 
= NULL
; 
 401 /*****************************************************************************/ 
 403 #pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines ----- 
 405 /*****************************************************************************/ 
 414         /* check parameters */ 
 415         require_action(NULL 
!= spec
, BadParameter
, result 
= paramErr
); 
 417         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
); 
 418         require_noerr(result
, FSGetCatalogInfo
); 
 426 /*****************************************************************************/ 
 430         FSVolumeRefNum volRefNum
, 
 432         ConstStr255Param name
, 
 438         /* check parameters */ 
 439         require_action(NULL 
!= ref
, BadParameter
, result 
= paramErr
); 
 441         pb
.ioVRefNum 
= volRefNum
; 
 443         pb
.ioNamePtr 
= (StringPtr
)name
; 
 445         result 
= PBMakeFSRefSync(&pb
); 
 446         require_noerr(result
, PBMakeFSRefSync
); 
 454 /*****************************************************************************/ 
 460         ConstStr255Param name
, 
 467         /* check parameters */ 
 468         require_action(NULL 
!= path
, BadParameter
, result 
= paramErr
); 
 470         /* convert the inputs to an FSRef */ 
 471         result 
= FSMakeFSRef(volRefNum
, dirID
, name
, &ref
); 
 472         require_noerr(result
, FSMakeFSRef
); 
 474         /* and then convert the FSRef to a path */ 
 475         result 
= FSRefMakePath(&ref
, path
, maxPathSize
); 
 476         require_noerr(result
, FSRefMakePath
); 
 485 /*****************************************************************************/ 
 491         Boolean 
*isDirectory
)   /* can be NULL */ 
 496         /* check parameters */ 
 497         require_action(NULL 
!= spec
, BadParameter
, result 
= paramErr
); 
 499         /* convert the POSIX path to an FSRef */ 
 500         result 
= FSPathMakeRef(path
, &ref
, isDirectory
); 
 501         require_noerr(result
, FSPathMakeRef
); 
 503         /* and then convert the FSRef to an FSSpec */ 
 504         result 
= FSGetCatalogInfo(&ref
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
); 
 505         require_noerr(result
, FSGetCatalogInfo
); 
 514 /*****************************************************************************/ 
 517 UnicodeNameGetHFSName( 
 518         UniCharCount nameLength
, 
 520         TextEncoding textEncodingHint
, 
 521         Boolean isVolumeName
, 
 525         ByteCount                       unicodeByteLength
; 
 526         ByteCount                       unicodeBytesConverted
; 
 527         ByteCount                       actualPascalBytes
; 
 528         UnicodeMapping          uMapping
; 
 529         UnicodeToTextInfo       utInfo
; 
 531         /* check parameters */ 
 532         require_action(NULL 
!= hfsName
, BadParameter
, result 
= paramErr
); 
 534         /* make sure output is valid in case we get errors or there's nothing to convert */ 
 537         unicodeByteLength 
= nameLength 
* sizeof(UniChar
); 
 538         if ( 0 == unicodeByteLength 
) 
 545                 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ 
 546                 if ( kTextEncodingUnknown 
== textEncodingHint 
) 
 551                         script 
= (ScriptCode
)GetScriptManagerVariable(smSysScript
); 
 552                         region 
= (RegionCode
)GetScriptManagerVariable(smRegionCode
); 
 553                         result 
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, region
, 
 554                                 NULL
, &textEncodingHint 
); 
 555                         if ( paramErr 
== result 
) 
 557                                 /* ok, ignore the region and try again */ 
 558                                 result 
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, 
 559                                         kTextRegionDontCare
, NULL
, &textEncodingHint 
); 
 561                         if ( noErr 
!= result 
) 
 563                                 /* ok... try something */ 
 564                                 textEncodingHint 
= kTextEncodingMacRoman
; 
 568                 uMapping
.unicodeEncoding 
= CreateTextEncoding(kTextEncodingUnicodeV2_0
, 
 569                         kUnicodeCanonicalDecompVariant
, kUnicode16BitFormat
); 
 570                 uMapping
.otherEncoding 
= GetTextEncodingBase(textEncodingHint
); 
 571                 uMapping
.mappingVersion 
= kUnicodeUseHFSPlusMapping
; 
 573                 result 
= CreateUnicodeToTextInfo(&uMapping
, &utInfo
); 
 574                 require_noerr(result
, CreateUnicodeToTextInfo
); 
 576                 result 
= ConvertFromUnicodeToText(utInfo
, unicodeByteLength
, name
, kUnicodeLooseMappingsMask
, 
 577                         0, NULL
, 0, NULL
,       /* offsetCounts & offsetArrays */ 
 578                         isVolumeName 
? kHFSMaxVolumeNameChars 
: kHFSMaxFileNameChars
, 
 579                         &unicodeBytesConverted
, &actualPascalBytes
, &hfsName
[1]); 
 580                 require_noerr(result
, ConvertFromUnicodeToText
); 
 582                 hfsName
[0] = (unsigned char)actualPascalBytes
;  /* fill in length byte */ 
 584 ConvertFromUnicodeToText
: 
 586                 /* verify the result in debug builds -- there's really not anything you can do if it fails */ 
 587                 verify_noerr(DisposeUnicodeToTextInfo(&utInfo
)); 
 590 CreateUnicodeToTextInfo
:         
 596 /*****************************************************************************/ 
 599 HFSNameGetUnicodeName( 
 600         ConstStr31Param hfsName
, 
 601         TextEncoding textEncodingHint
, 
 602         HFSUniStr255 
*unicodeName
) 
 604         ByteCount                       unicodeByteLength
; 
 606         UnicodeMapping          uMapping
; 
 607         TextToUnicodeInfo       tuInfo
; 
 608         ByteCount                       pascalCharsRead
; 
 610         /* check parameters */ 
 611         require_action(NULL 
!= unicodeName
, BadParameter
, result 
= paramErr
); 
 613         /* make sure output is valid in case we get errors or there's nothing to convert */ 
 614         unicodeName
->length 
= 0; 
 616         if ( 0 == StrLength(hfsName
) ) 
 622                 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ 
 623                 if ( kTextEncodingUnknown 
== textEncodingHint 
) 
 628                         script 
= GetScriptManagerVariable(smSysScript
); 
 629                         region 
= GetScriptManagerVariable(smRegionCode
); 
 630                         result 
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, region
, 
 631                                 NULL
, &textEncodingHint
); 
 632                         if ( paramErr 
== result 
) 
 634                                 /* ok, ignore the region and try again */ 
 635                                 result 
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, 
 636                                         kTextRegionDontCare
, NULL
, &textEncodingHint
); 
 638                         if ( noErr 
!= result 
) 
 640                                 /* ok... try something */ 
 641                                 textEncodingHint 
= kTextEncodingMacRoman
; 
 645                 uMapping
.unicodeEncoding 
= CreateTextEncoding(kTextEncodingUnicodeV2_0
, 
 646                         kUnicodeCanonicalDecompVariant
, kUnicode16BitFormat
); 
 647                 uMapping
.otherEncoding 
= GetTextEncodingBase(textEncodingHint
); 
 648                 uMapping
.mappingVersion 
= kUnicodeUseHFSPlusMapping
; 
 650                 result 
= CreateTextToUnicodeInfo(&uMapping
, &tuInfo
); 
 651                 require_noerr(result
, CreateTextToUnicodeInfo
); 
 653                 result 
= ConvertFromTextToUnicode(tuInfo
, hfsName
[0], &hfsName
[1], 
 654                         0,                                                              /* no control flag bits */ 
 655                         0, NULL
, 0, NULL
,                               /* offsetCounts & offsetArrays */ 
 656                         sizeof(unicodeName
->unicode
),   /* output buffer size in bytes */ 
 657                         &pascalCharsRead
, &unicodeByteLength
, unicodeName
->unicode
); 
 658                 require_noerr(result
, ConvertFromTextToUnicode
); 
 660                 /* convert from byte count to char count */ 
 661                 unicodeName
->length 
= unicodeByteLength 
/ sizeof(UniChar
); 
 663 ConvertFromTextToUnicode
: 
 665                 /* verify the result in debug builds -- there's really not anything you can do if it fails */ 
 666                 verify_noerr(DisposeTextToUnicodeInfo(&tuInfo
)); 
 669 CreateTextToUnicodeInfo
: 
 675 /*****************************************************************************/ 
 677 #pragma mark ----- File/Directory Manipulation Routines ----- 
 679 /*****************************************************************************/ 
 681 Boolean 
FSRefValid(const FSRef 
*ref
) 
 683         return ( noErr 
== FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, NULL
, NULL
) ); 
 686 /*****************************************************************************/ 
 694         FSCatalogInfo   catalogInfo
; 
 696         /* check parameters */ 
 697         require_action(NULL 
!= parentRef
, BadParameter
, result 
= paramErr
); 
 699         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNodeID
, &catalogInfo
, NULL
, NULL
, parentRef
); 
 700         require_noerr(result
, FSGetCatalogInfo
); 
 703          * Note: FSRefs always point to real file system objects. So, there cannot 
 704          * be a FSRef to the parent of volume root directories. Early versions of 
 705          * Mac OS X do not handle this case correctly and incorrectly return a 
 706          * FSRef for the parent of volume root directories instead of returning an 
 707          * invalid FSRef (a cleared FSRef is invalid). The next three lines of code 
 708          * ensure that you won't run into this bug. WW9D! 
 710         if ( fsRtDirID 
== catalogInfo
.nodeID 
) 
 712                 /* clear parentRef and return noErr which is the proper behavior */ 
 713                 memset(parentRef
, 0, sizeof(FSRef
)); 
 722 /*****************************************************************************/ 
 727         HFSUniStr255 
*outName
) 
 731         /* check parameters */ 
 732         require_action(NULL 
!= outName
, BadParameter
, result 
= paramErr
); 
 734         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, outName
, NULL
, NULL
); 
 735         require_noerr(result
, FSGetCatalogInfo
); 
 743 /*****************************************************************************/ 
 748         long *nodeID
,                   /* can be NULL */ 
 749         Boolean 
*isDirectory
)   /* can be NULL */ 
 752         FSCatalogInfo           catalogInfo
; 
 753         FSCatalogInfoBitmap whichInfo
; 
 755         /* determine what catalog information to get */ 
 756         whichInfo 
= kFSCatInfoNone
; /* start with none */ 
 757         if ( NULL 
!= nodeID 
) 
 759                 whichInfo 
|= kFSCatInfoNodeID
; 
 761         if ( NULL 
!= isDirectory 
) 
 763                 whichInfo 
|= kFSCatInfoNodeFlags
; 
 766         result 
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
); 
 767         require_noerr(result
, FSGetCatalogInfo
); 
 769         if ( NULL 
!= nodeID 
) 
 771                 *nodeID 
= catalogInfo
.nodeID
; 
 773         if ( NULL 
!= isDirectory 
) 
 775                 *isDirectory 
= (0 != (kFSNodeIsDirectoryMask 
& catalogInfo
.nodeFlags
)); 
 783 /*****************************************************************************/ 
 786 FSGetUserPrivilegesPermissions( 
 788         UInt8 
*userPrivileges
,          /* can be NULL */ 
 789         UInt32 permissions
[4])          /* can be NULL */ 
 792         FSCatalogInfo   catalogInfo
; 
 793         FSCatalogInfoBitmap whichInfo
; 
 795         /* determine what catalog information to get */ 
 796         whichInfo 
= kFSCatInfoNone
; /* start with none */ 
 797         if ( NULL 
!= userPrivileges 
) 
 799                 whichInfo 
|= kFSCatInfoUserPrivs
; 
 801         if ( NULL 
!= permissions 
) 
 803                 whichInfo 
|= kFSCatInfoPermissions
; 
 806         result 
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
); 
 807         require_noerr(result
, FSGetCatalogInfo
); 
 809         if ( NULL 
!= userPrivileges 
) 
 811                 *userPrivileges 
= catalogInfo
.userPrivileges
; 
 813         if ( NULL 
!= permissions 
) 
 815                 BlockMoveData(&catalogInfo
.permissions
, permissions
, sizeof(UInt32
) * 4); 
 823 /*****************************************************************************/ 
 830         FSCatalogInfo   catalogInfo
; 
 831         FSVolumeInfo    volumeInfo
; 
 833         /* get nodeFlags and vRefNum for container */ 
 834         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags 
+ kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
,NULL
); 
 835         require_noerr(result
, FSGetCatalogInfo
); 
 837         /* is file locked? */ 
 838         if ( 0 != (catalogInfo
.nodeFlags 
& kFSNodeLockedMask
) ) 
 840                 result 
= fLckdErr
;      /* file is locked */ 
 844                 /* file isn't locked, but is volume locked? */ 
 846                 /* get volume flags */ 
 847                 result 
= FSGetVolumeInfo(catalogInfo
.volume
, 0, NULL
, kFSVolInfoFlags
, &volumeInfo
, NULL
, NULL
); 
 848                 require_noerr(result
, FSGetVolumeInfo
); 
 850                 if ( 0 != (volumeInfo
.flags 
& kFSVolFlagHardwareLockedMask
) ) 
 852                         result 
= wPrErr
;        /* volume locked by hardware */ 
 854                 else if ( 0 != (volumeInfo
.flags 
& kFSVolFlagSoftwareLockedMask
) ) 
 856                         result 
= vLckdErr
;      /* volume locked by software */ 
 866 /*****************************************************************************/ 
 871         UInt64 
*dataLogicalSize
,        /* can be NULL */ 
 872         UInt64 
*rsrcLogicalSize
)        /* can be NULL */ 
 875         FSCatalogInfoBitmap whichInfo
; 
 876         FSCatalogInfo           catalogInfo
; 
 878         whichInfo 
= kFSCatInfoNodeFlags
; 
 879         if ( NULL 
!= dataLogicalSize 
) 
 881                 /* get data fork size */ 
 882                 whichInfo 
|= kFSCatInfoDataSizes
; 
 884         if ( NULL 
!= rsrcLogicalSize 
) 
 886                 /* get resource fork size */ 
 887                 whichInfo 
|= kFSCatInfoRsrcSizes
; 
 890         /* get nodeFlags and catalog info */ 
 891         result 
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
,NULL
); 
 892         require_noerr(result
, FSGetCatalogInfo
); 
 894         /* make sure FSRef was to a file */ 
 895         require_action(0 == (catalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
), FSRefNotFile
, result 
= notAFileErr
); 
 897         if ( NULL 
!= dataLogicalSize 
) 
 899                 /* return data fork size */ 
 900                 *dataLogicalSize 
= catalogInfo
.dataLogicalSize
; 
 902         if ( NULL 
!= rsrcLogicalSize 
) 
 904                 /* return resource fork size */ 
 905                 *rsrcLogicalSize 
= catalogInfo
.rsrcLogicalSize
; 
 914 /*****************************************************************************/ 
 919         UInt64 
*totalLogicalSize
,       /* can be NULL */ 
 920         UInt64 
*totalPhysicalSize
,      /* can be NULL */ 
 921         ItemCount 
*forkCount
)           /* can be NULL */ 
 924         CatPositionRec  forkIterator
; 
 927         UInt64                  forkPhysicalSize
; 
 928         UInt64                  
*forkPhysicalSizePtr
; 
 930         /* Determine if forkSize needed */ 
 931         if ( NULL 
!= totalLogicalSize
) 
 933                 *totalLogicalSize 
= 0; 
 934                 forkSizePtr 
= &forkSize
; 
 941         /* Determine if forkPhysicalSize is needed */ 
 942         if ( NULL 
!= totalPhysicalSize 
) 
 944                 *totalPhysicalSize 
= 0; 
 945                 forkPhysicalSizePtr 
= &forkPhysicalSize
; 
 949                 forkPhysicalSizePtr 
= NULL
; 
 952         /* zero fork count if returning it */ 
 953         if ( NULL 
!= forkCount 
) 
 958         /* Iterate through the forks to get the sizes */ 
 959         forkIterator
.initialize 
= 0; 
 962                 result 
= FSIterateForks(ref
, &forkIterator
, NULL
, forkSizePtr
, forkPhysicalSizePtr
); 
 963                 if ( noErr 
== result 
) 
 965                         if ( NULL 
!= totalLogicalSize 
) 
 967                                 *totalLogicalSize 
+= forkSize
; 
 970                         if ( NULL 
!= totalPhysicalSize 
) 
 972                                 *totalPhysicalSize 
+= forkPhysicalSize
; 
 975                         if ( NULL 
!= forkCount 
) 
 980         } while ( noErr 
== result 
); 
 982         /* any error result other than errFSNoMoreItems is serious */ 
 983         require(errFSNoMoreItems 
== result
, FSIterateForks
); 
 993 /*****************************************************************************/ 
1000         FSCatalogInfo   catalogInfo
; 
1001         UTCDateTime             oldDateTime
; 
1002 #if !BuildingMoreFilesXForMacOS9 
1004         Boolean                 notifyParent
; 
1007 #if !BuildingMoreFilesXForMacOS9 
1008         /* Get the node flags, the content modification date and time, and the parent ref */ 
1009         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags 
+ kFSCatInfoContentMod
, &catalogInfo
, NULL
, NULL
, &parentRef
); 
1010         require_noerr(result
, FSGetCatalogInfo
); 
1012         /* Notify the parent if this is a file */ 
1013         notifyParent 
= (0 == (catalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
)); 
1015         /* Get the content modification date and time */ 
1016         result 
= FSGetCatalogInfo(ref
, kFSCatInfoContentMod
, &catalogInfo
, NULL
, NULL
, NULL
); 
1017         require_noerr(result
, FSGetCatalogInfo
); 
1020         oldDateTime 
= catalogInfo
.contentModDate
; 
1022         /* Get the current date and time */ 
1023         result 
= GetUTCDateTime(&catalogInfo
.contentModDate
, kUTCDefaultOptions
); 
1024         require_noerr(result
, GetUTCDateTime
); 
1026         /* if the old date and time is the the same as the current, bump the seconds by one */ 
1027         if ( (catalogInfo
.contentModDate
.fraction 
== oldDateTime
.fraction
) && 
1028                  (catalogInfo
.contentModDate
.lowSeconds 
== oldDateTime
.lowSeconds
) && 
1029                  (catalogInfo
.contentModDate
.highSeconds 
== oldDateTime
.highSeconds
) ) 
1031                 ++catalogInfo
.contentModDate
.lowSeconds
; 
1032                 if ( 0 == catalogInfo
.contentModDate
.lowSeconds 
) 
1034                         ++catalogInfo
.contentModDate
.highSeconds
; 
1038         /* Bump the content modification date and time */ 
1039         result 
= FSSetCatalogInfo(ref
, kFSCatInfoContentMod
, &catalogInfo
); 
1040         require_noerr(result
, FSSetCatalogInfo
); 
1042 #if !BuildingMoreFilesXForMacOS9 
1044          * The problem with FNNotify is that it is not available under Mac OS 9 
1045          * and there's no way to test for that except for looking for the symbol 
1046          * or something. So, I'll just conditionalize this for those who care 
1047          * to send a notification. 
1050         /* Send a notification for the parent of the file, or for the directory */ 
1051         result 
= FNNotify(notifyParent 
? &parentRef 
: ref
, kFNDirectoryModifiedMessage
, kNilOptions
); 
1052         require_noerr(result
, FNNotify
); 
1055         /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */ 
1061         /**********************/ 
1069 /*****************************************************************************/ 
1074         FinderInfo 
*info
,                                       /* can be NULL */ 
1075         ExtendedFinderInfo 
*extendedInfo
,       /* can be NULL */ 
1076         Boolean 
*isDirectory
)                           /* can be NULL */ 
1079         FSCatalogInfo           catalogInfo
; 
1080         FSCatalogInfoBitmap whichInfo
; 
1082         /* determine what catalog information is really needed */ 
1083         whichInfo 
= kFSCatInfoNone
; 
1087                 /* get FinderInfo */ 
1088                 whichInfo 
|= kFSCatInfoFinderInfo
; 
1091         if ( NULL 
!= extendedInfo 
) 
1093                 /* get ExtendedFinderInfo */ 
1094                 whichInfo 
|= kFSCatInfoFinderXInfo
; 
1097         if ( NULL 
!= isDirectory 
) 
1099                 whichInfo 
|= kFSCatInfoNodeFlags
; 
1102         result 
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
); 
1103         require_noerr(result
, FSGetCatalogInfo
); 
1105         /* return FinderInfo if requested */ 
1108                 BlockMoveData(catalogInfo
.finderInfo
, info
, sizeof(FinderInfo
)); 
1111         /* return ExtendedFinderInfo if requested */ 
1112         if ( NULL 
!= extendedInfo
) 
1114                 BlockMoveData(catalogInfo
.extFinderInfo
, extendedInfo
, sizeof(ExtendedFinderInfo
)); 
1117         /* set isDirectory Boolean if requested */ 
1118         if ( NULL 
!= isDirectory
) 
1120                 *isDirectory 
= (0 != (kFSNodeIsDirectoryMask 
& catalogInfo
.nodeFlags
)); 
1128 /*****************************************************************************/ 
1133         const FinderInfo 
*info
, 
1134         const ExtendedFinderInfo 
*extendedInfo
) 
1137         FSCatalogInfo           catalogInfo
; 
1138         FSCatalogInfoBitmap whichInfo
; 
1140         /* determine what catalog information will be set */ 
1141         whichInfo 
= kFSCatInfoNone
; /* start with none */ 
1144                 /* set FinderInfo */ 
1145                 whichInfo 
|= kFSCatInfoFinderInfo
; 
1146                 BlockMoveData(info
, catalogInfo
.finderInfo
, sizeof(FinderInfo
)); 
1148         if ( NULL 
!= extendedInfo 
) 
1150                 /* set ExtendedFinderInfo */ 
1151                 whichInfo 
|= kFSCatInfoFinderXInfo
; 
1152                 BlockMoveData(extendedInfo
, catalogInfo
.extFinderInfo
, sizeof(ExtendedFinderInfo
)); 
1155         result 
= FSSetCatalogInfo(ref
, whichInfo
, &catalogInfo
); 
1156         require_noerr(result
, FSGetCatalogInfo
); 
1163 /*****************************************************************************/ 
1166 FSChangeCreatorType( 
1172         FSCatalogInfo   catalogInfo
; 
1175         /* get nodeFlags, finder info, and parent FSRef */ 
1176         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags 
+ kFSCatInfoFinderInfo
, &catalogInfo 
, NULL
, NULL
, &parentRef
); 
1177         require_noerr(result
, FSGetCatalogInfo
); 
1179         /* make sure FSRef was to a file */ 
1180         require_action(0 == (catalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
), FSRefNotFile
, result 
= notAFileErr
); 
1182         /* If fileType not 0x00000000, change fileType */ 
1183         if ( fileType 
!= (OSType
)0x00000000 ) 
1185                 ((FileInfo 
*)&catalogInfo
.finderInfo
)->fileType 
= fileType
; 
1188         /* If creator not 0x00000000, change creator */ 
1189         if ( fileCreator 
!= (OSType
)0x00000000 ) 
1191                 ((FileInfo 
*)&catalogInfo
.finderInfo
)->fileCreator 
= fileCreator
; 
1194         /* now, save the new information back to disk */ 
1195         result 
= FSSetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
); 
1196         require_noerr(result
, FSSetCatalogInfo
); 
1198         /* and attempt to bump the parent directory's mod date to wake up */ 
1199         /* the Finder to the change we just made (ignore errors from this) */ 
1200         verify_noerr(FSBumpDate(&parentRef
)); 
1209 /*****************************************************************************/ 
1212 FSChangeFinderFlags( 
1218         FSCatalogInfo   catalogInfo
; 
1221         /* get the current finderInfo */ 
1222         result 
= FSGetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
, NULL
, NULL
, &parentRef
); 
1223         require_noerr(result
, FSGetCatalogInfo
); 
1225         /* set or clear the appropriate bits in the finderInfo.finderFlags */ 
1228                 /* OR in the bits */ 
1229                 ((FileInfo 
*)&catalogInfo
.finderInfo
)->finderFlags 
|= flagBits
; 
1233                 /* AND out the bits */ 
1234                 ((FileInfo 
*)&catalogInfo
.finderInfo
)->finderFlags 
&= ~flagBits
; 
1237         /* save the modified finderInfo */ 
1238         result 
= FSSetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
); 
1239         require_noerr(result
, FSSetCatalogInfo
); 
1241         /* and attempt to bump the parent directory's mod date to wake up the Finder */ 
1242         /* to the change we just made (ignore errors from this) */ 
1243         verify_noerr(FSBumpDate(&parentRef
)); 
1251 /*****************************************************************************/ 
1257         return ( FSChangeFinderFlags(ref
, true, kIsInvisible
) ); 
1264         return ( FSChangeFinderFlags(ref
, false, kIsInvisible
) ); 
1267 /*****************************************************************************/ 
1273         return ( FSChangeFinderFlags(ref
, true, kNameLocked
) ); 
1280         return ( FSChangeFinderFlags(ref
, false, kNameLocked
) ); 
1283 /*****************************************************************************/ 
1289         return ( FSChangeFinderFlags(ref
, true, kIsStationery
) ); 
1293 FSClearIsStationery( 
1296         return ( FSChangeFinderFlags(ref
, false, kIsStationery
) ); 
1299 /*****************************************************************************/ 
1305         return ( FSChangeFinderFlags(ref
, true, kHasCustomIcon
) ); 
1309 FSClearHasCustomIcon( 
1312         return ( FSChangeFinderFlags(ref
, false, kHasCustomIcon
) ); 
1315 /*****************************************************************************/ 
1318 FSClearHasBeenInited( 
1321         return ( FSChangeFinderFlags(ref
, false, kHasBeenInited
) ); 
1324 /*****************************************************************************/ 
1327 FSCopyFileMgrAttributes( 
1328         const FSRef 
*sourceRef
, 
1329         const FSRef 
*destinationRef
, 
1330         Boolean copyLockBit
) 
1333         FSCatalogInfo   catalogInfo
; 
1335         /* get the source information */ 
1336         result 
= FSGetCatalogInfo(sourceRef
, kFSCatInfoSettableInfo
, &catalogInfo
, NULL
, NULL
, NULL
); 
1337         require_noerr(result
, FSGetCatalogInfo
); 
1339         /* don't copy the hasBeenInited bit; clear it */ 
1340         ((FileInfo 
*)&catalogInfo
.finderInfo
)->finderFlags 
&= ~kHasBeenInited
; 
1342         /* should the locked bit be copied? */ 
1345                 /* no, make sure the locked bit is clear */ 
1346                 catalogInfo
.nodeFlags 
&= ~kFSNodeLockedMask
; 
1349         /* set the destination information */ 
1350         result 
= FSSetCatalogInfo(destinationRef
, kFSCatInfoSettableInfo
, &catalogInfo
); 
1351         require_noerr(result
, FSSetCatalogInfo
); 
1359 /*****************************************************************************/ 
1362 FSMoveRenameObjectUnicode( 
1364         const FSRef 
*destDirectory
, 
1365         UniCharCount nameLength
, 
1366         const UniChar 
*name
,                    /* can be NULL (no rename during move) */ 
1367         TextEncoding textEncodingHint
, 
1368         FSRef 
*newRef
)                                  /* if function fails along the way, newRef is final location of file */ 
1371         FSVolumeRefNum  vRefNum
; 
1372         FSCatalogInfo   catalogInfo
; 
1373         FSRef                   originalDirectory
; 
1374         TextEncoding    originalTextEncodingHint
; 
1375         HFSUniStr255    originalName
; 
1376         HFSUniStr255    uniqueName
;             /* unique name given to object while moving it to destination */ 
1377         long                    theSeed
;                /* the seed for generating unique names */ 
1379         /* check parameters */ 
1380         require_action(NULL 
!= newRef
, BadParameter
, result 
= paramErr
); 
1382         /* newRef = input to start with */ 
1383         BlockMoveData(ref
, newRef
, sizeof(FSRef
)); 
1385         /* get destDirectory's vRefNum */ 
1386         result 
= FSGetCatalogInfo(destDirectory
, kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
, NULL
); 
1387         require_noerr(result
, DestinationBad
); 
1390         vRefNum 
= catalogInfo
.volume
; 
1392         /* get ref's vRefNum, TextEncoding, name and parent directory*/ 
1393         result 
= FSGetCatalogInfo(ref
, kFSCatInfoTextEncoding 
+ kFSCatInfoVolume
, &catalogInfo
, &originalName
, NULL
, &originalDirectory
); 
1394         require_noerr(result
, SourceBad
); 
1396         /* save TextEncoding */ 
1397         originalTextEncodingHint 
= catalogInfo
.textEncodingHint
; 
1399         /* make sure ref and destDirectory are on same volume */ 
1400         require_action(vRefNum 
== catalogInfo
.volume
, NotSameVolume
, result 
= diffVolErr
); 
1402         /* Skip a few steps if we're not renaming */ 
1405                 /* generate a name that is unique in both directories */ 
1406                 theSeed 
= 0x4a696d4c;   /* a fine unlikely filename */ 
1408                 result 
= GenerateUniqueHFSUniStr(&theSeed
, &originalDirectory
, destDirectory
, &uniqueName
); 
1409                 require_noerr(result
, GenerateUniqueHFSUniStrFailed
); 
1411                 /* Rename the object to uniqueName */ 
1412                 result 
= FSRenameUnicode(ref
, uniqueName
.length
, uniqueName
.unicode
, kTextEncodingUnknown
, newRef
); 
1413                 require_noerr(result
, FSRenameUnicodeBeforeMoveFailed
); 
1415                 /* Move object to its new home */ 
1416                 result 
= FSMoveObject(newRef
, destDirectory
, newRef
); 
1417                 require_noerr(result
, FSMoveObjectAfterRenameFailed
); 
1419                 /* Rename the object to new name */ 
1420                 result 
= FSRenameUnicode(ref
, nameLength
, name
, textEncodingHint
, newRef
); 
1421                 require_noerr(result
, FSRenameUnicodeAfterMoveFailed
); 
1425                 /* Move object to its new home */ 
1426                 result 
= FSMoveObject(newRef
, destDirectory
, newRef
); 
1427                 require_noerr(result
, FSMoveObjectNoRenameFailed
); 
1435  * failure handling code when renaming 
1438 FSRenameUnicodeAfterMoveFailed
: 
1440         /* Error handling: move object back to original location - ignore errors */ 
1441         verify_noerr(FSMoveObject(newRef
, &originalDirectory
, newRef
)); 
1443 FSMoveObjectAfterRenameFailed
: 
1445         /* Error handling: rename object back to original name - ignore errors */ 
1446         verify_noerr(FSRenameUnicode(newRef
, originalName
.length
, originalName
.unicode
, originalTextEncodingHint
, newRef
)); 
1448 FSRenameUnicodeBeforeMoveFailed
: 
1449 GenerateUniqueHFSUniStrFailed
: 
1452  * failure handling code for renaming or not 
1454 FSMoveObjectNoRenameFailed
: 
1463 /*****************************************************************************/ 
1466         The FSDeleteContainerLevel function deletes the contents of a container 
1467         directory. All files and subdirectories in the specified container are 
1468         deleted. If a locked file or directory is encountered, it is unlocked 
1469         and then deleted. If any unexpected errors are encountered, 
1470         FSDeleteContainerLevel quits and returns to the caller. 
1472         container                       --> FSRef to a directory. 
1473         theGlobals                      --> A pointer to a FSDeleteContainerGlobals struct 
1474                                                         which contains the variables that do not need to 
1475                                                         be allocated each time FSDeleteContainerLevel 
1476                                                         recurses. That lets FSDeleteContainerLevel use 
1477                                                         less stack space per recursion level. 
1482 FSDeleteContainerLevel( 
1483         const FSRef 
*container
, 
1484         FSDeleteContainerGlobals 
*theGlobals
) 
1487         FSIterator                                      iterator
; 
1491         /* Open FSIterator for flat access and give delete optimization hint */ 
1492         theGlobals
->result 
= FSOpenIterator(container
, kFSIterateFlat 
+ kFSIterateDelete
, &iterator
); 
1493         require_noerr(theGlobals
->result
, FSOpenIterator
); 
1495         /* delete the contents of the directory */ 
1498                 /* get 1 item to delete */ 
1499                 theGlobals
->result 
= FSGetCatalogInfoBulk(iterator
, 1, &theGlobals
->actualObjects
, 
1500                                                                 NULL
, kFSCatInfoNodeFlags
, &theGlobals
->catalogInfo
, 
1501                                                                 &itemToDelete
, NULL
, NULL
); 
1502                 if ( (noErr 
== theGlobals
->result
) && (1 == theGlobals
->actualObjects
) ) 
1504                         /* save node flags in local in case we have to recurse */ 
1505                         nodeFlags 
= theGlobals
->catalogInfo
.nodeFlags
; 
1507                         /* is it a file or directory? */ 
1508                         if ( 0 != (nodeFlags 
& kFSNodeIsDirectoryMask
) ) 
1510                                 /* it's a directory -- delete its contents before attempting to delete it */ 
1511                                 FSDeleteContainerLevel(&itemToDelete
, theGlobals
); 
1513                         /* are we still OK to delete? */ 
1514                         if ( noErr 
== theGlobals
->result 
) 
1516                                 /* is item locked? */ 
1517                                 if ( 0 != (nodeFlags 
& kFSNodeLockedMask
) ) 
1519                                         /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */ 
1520                                         theGlobals
->catalogInfo
.nodeFlags 
= nodeFlags 
& ~kFSNodeLockedMask
; 
1521                                         (void) FSSetCatalogInfo(&itemToDelete
, kFSCatInfoNodeFlags
, &theGlobals
->catalogInfo
); 
1523                                 /* delete the item */ 
1524                                 theGlobals
->result 
= FSDeleteObject(&itemToDelete
); 
1527         } while ( noErr 
== theGlobals
->result 
); 
1529         /* we found the end of the items normally, so return noErr */ 
1530         if ( errFSNoMoreItems 
== theGlobals
->result 
) 
1532                 theGlobals
->result 
= noErr
; 
1535         /* close the FSIterator (closing an open iterator should never fail) */ 
1536         verify_noerr(FSCloseIterator(iterator
)); 
1543 /*****************************************************************************/ 
1546 FSDeleteContainerContents( 
1547         const FSRef 
*container
) 
1549         FSDeleteContainerGlobals        theGlobals
; 
1551         /* delete container's contents */ 
1552         FSDeleteContainerLevel(container
, &theGlobals
); 
1554         return ( theGlobals
.result 
); 
1557 /*****************************************************************************/ 
1561         const FSRef 
*container
) 
1564         FSCatalogInfo   catalogInfo
; 
1566         /* get nodeFlags for container */ 
1567         result 
= FSGetCatalogInfo(container
, kFSCatInfoNodeFlags
, &catalogInfo
, NULL
, NULL
,NULL
); 
1568         require_noerr(result
, FSGetCatalogInfo
); 
1570         /* make sure container is a directory */ 
1571         require_action(0 != (catalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
), ContainerNotDirectory
, result 
= dirNFErr
); 
1573         /* delete container's contents */ 
1574         result 
= FSDeleteContainerContents(container
); 
1575         require_noerr(result
, FSDeleteContainerContents
); 
1577         /* is container locked? */ 
1578         if ( 0 != (catalogInfo
.nodeFlags 
& kFSNodeLockedMask
) ) 
1580                 /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */ 
1581                 catalogInfo
.nodeFlags 
&= ~kFSNodeLockedMask
; 
1582                 (void) FSSetCatalogInfo(container
, kFSCatInfoNodeFlags
, &catalogInfo
); 
1585         /* delete the container */ 
1586         result 
= FSDeleteObject(container
); 
1588 FSDeleteContainerContents
: 
1589 ContainerNotDirectory
: 
1595 /*****************************************************************************/ 
1598         The FSIterateContainerLevel function iterates the contents of a container 
1599         directory and calls a IterateContainerFilterProc function once for each 
1600         file and directory found. 
1602         theGlobals                      --> A pointer to a FSIterateContainerGlobals struct 
1603                                                         which contains the variables needed globally by 
1604                                                         all recusion levels of FSIterateContainerLevel. 
1605                                                         That makes FSIterateContainer thread safe since 
1606                                                         each call to it uses its own global world. 
1607                                                         It also contains the variables that do not need 
1608                                                         to be allocated each time FSIterateContainerLevel 
1609                                                         recurses. That lets FSIterateContainerLevel use 
1610                                                         less stack space per recursion level. 
1615 FSIterateContainerLevel( 
1616         FSIterateContainerGlobals 
*theGlobals
) 
1618         FSIterator      iterator
; 
1620         /* If maxLevels is zero, we aren't checking levels */ 
1621         /* If currentLevel < maxLevels, look at this level */ 
1622         if ( (theGlobals
->maxLevels 
== 0) || 
1623                  (theGlobals
->currentLevel 
< theGlobals
->maxLevels
) ) 
1625                 /* Open FSIterator for flat access to theGlobals->ref */ 
1626                 theGlobals
->result 
= FSOpenIterator(&theGlobals
->ref
, kFSIterateFlat
, &iterator
); 
1627                 require_noerr(theGlobals
->result
, FSOpenIterator
); 
1629                 ++theGlobals
->currentLevel
; /* Go to next level */ 
1631                 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */ 
1634                         theGlobals
->result 
= FSGetCatalogInfoBulk(iterator
, 1, &theGlobals
->actualObjects
, 
1635                                 &theGlobals
->containerChanged
, theGlobals
->whichInfo
, &theGlobals
->catalogInfo
, 
1636                                 &theGlobals
->ref
, theGlobals
->specPtr
, theGlobals
->namePtr
); 
1637                         if ( (noErr 
== theGlobals
->result 
|| errFSNoMoreItems 
== theGlobals
->result
) && 
1638                                 (0 != theGlobals
->actualObjects
) ) 
1640                                 /* Call the IterateFilterProc */ 
1641                                 theGlobals
->quitFlag 
= CallIterateContainerFilterProc(theGlobals
->iterateFilter
, 
1642                                         theGlobals
->containerChanged
, theGlobals
->currentLevel
, 
1643                                         &theGlobals
->catalogInfo
, &theGlobals
->ref
, 
1644                                         theGlobals
->specPtr
, theGlobals
->namePtr
, theGlobals
->yourDataPtr
); 
1645                                 /* Is it a directory? */ 
1646                                 if ( 0 != (theGlobals
->catalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
) ) 
1649                                         if ( !theGlobals
->quitFlag 
) 
1651                                                 /* Dive again if the IterateFilterProc didn't say "quit" */ 
1652                                                 FSIterateContainerLevel(theGlobals
); 
1656                         /* time to fall back a level? */ 
1657                 } while ( (noErr 
== theGlobals
->result
) && (!theGlobals
->quitFlag
) ); 
1659                 /* errFSNoMoreItems is OK - it only means we hit the end of this level */ 
1660                 /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */ 
1661                 if ( (errFSNoMoreItems 
== theGlobals
->result
) || 
1662                          (afpAccessDenied 
== theGlobals
->result
) ) 
1664                         theGlobals
->result 
= noErr
; 
1667                 --theGlobals
->currentLevel
; /* Return to previous level as we leave */ 
1669                 /* Close the FSIterator (closing an open iterator should never fail) */ 
1670                 verify_noerr(FSCloseIterator(iterator
)); 
1678 /*****************************************************************************/ 
1682         const FSRef 
*container
, 
1683         ItemCount maxLevels
, 
1684         FSCatalogInfoBitmap whichInfo
, 
1687         IterateContainerFilterProcPtr iterateFilter
, 
1691         FSIterateContainerGlobals       theGlobals
; 
1693         /* make sure there is an iterateFilter */ 
1694         require_action(iterateFilter 
!= NULL
, NoIterateFilter
, result 
= paramErr
); 
1697          * set up the globals we need to access from the recursive routine 
1699         theGlobals
.iterateFilter 
= iterateFilter
; 
1700         /* we need the node flags no matter what was requested so we can detect files vs. directories */ 
1701         theGlobals
.whichInfo 
= whichInfo 
| kFSCatInfoNodeFlags
; 
1702         /* start with input container -- the first OpenIterator will ensure it is a directory */ 
1703         theGlobals
.ref 
= *container
; 
1706                 theGlobals
.specPtr 
= &theGlobals
.spec
; 
1710                 theGlobals
.specPtr 
= NULL
; 
1714                 theGlobals
.namePtr 
= &theGlobals
.name
; 
1718                 theGlobals
.namePtr 
= NULL
; 
1720         theGlobals
.yourDataPtr 
= yourDataPtr
; 
1721         theGlobals
.maxLevels 
= maxLevels
; 
1722         theGlobals
.currentLevel 
= 0; 
1723         theGlobals
.quitFlag 
= false; 
1724         theGlobals
.containerChanged 
= false; 
1725         theGlobals
.result 
= noErr
; 
1726         theGlobals
.actualObjects 
= 0; 
1728         /* here we go into recursion land... */ 
1729         FSIterateContainerLevel(&theGlobals
); 
1730         result 
= theGlobals
.result
; 
1731         require_noerr(result
, FSIterateContainerLevel
); 
1733 FSIterateContainerLevel
: 
1739 /*****************************************************************************/ 
1742 FSGetDirectoryItems( 
1743         const FSRef 
*container
, 
1744         FSRef 
***refsHandle
,    /* pointer to handle of FSRefs */ 
1746         Boolean 
*containerChanged
) 
1748         /* Grab items 10 at a time. */ 
1749         enum { kMaxItemsPerBulkCall 
= 10 }; 
1753         FSIterator      iterator
; 
1754         FSRef           refs
[kMaxItemsPerBulkCall
]; 
1755         ItemCount       actualObjects
; 
1758         /* check parameters */ 
1759         require_action((NULL 
!= refsHandle
) && (NULL 
!= numRefs
) && (NULL 
!= containerChanged
), 
1760                 BadParameter
, result 
= paramErr
); 
1763         *containerChanged 
= false; 
1764         *refsHandle 
= (FSRef 
**)NewHandle(0); 
1765         require_action(NULL 
!= *refsHandle
, NewHandle
, result 
= memFullErr
); 
1767         /* open an FSIterator */ 
1768         result 
= FSOpenIterator(container
, kFSIterateFlat
, &iterator
); 
1769         require_noerr(result
, FSOpenIterator
); 
1771         /* Call FSGetCatalogInfoBulk in loop to get all items in the container */ 
1774                 result 
= FSGetCatalogInfoBulk(iterator
, kMaxItemsPerBulkCall
, &actualObjects
, 
1775                                         &changed
, kFSCatInfoNone
,  NULL
,  refs
, NULL
, NULL
); 
1777                 /* if the container changed, set containerChanged for output, but keep going */ 
1780                         *containerChanged 
= changed
; 
1783                 /* any result other than noErr and errFSNoMoreItems is serious */ 
1784                 require((noErr 
== result
) || (errFSNoMoreItems 
== result
), FSGetCatalogInfoBulk
); 
1786                 /* add objects to output array and count */ 
1787                 if ( 0 != actualObjects 
) 
1789                         /* concatenate the FSRefs to the end of the      handle */ 
1790                         PtrAndHand(refs
, (Handle
)*refsHandle
, actualObjects 
* sizeof(FSRef
)); 
1791                         memResult 
= MemError(); 
1792                         require_noerr_action(memResult
, MemoryAllocationFailed
, result 
= memResult
); 
1794                         *numRefs 
+= actualObjects
; 
1796         } while ( noErr 
== result 
); 
1798         verify_noerr(FSCloseIterator(iterator
)); /* closing an open iterator should never fail, but... */ 
1802         /**********************/ 
1804 MemoryAllocationFailed
: 
1805 FSGetCatalogInfoBulk
: 
1807         /* close the iterator */ 
1808         verify_noerr(FSCloseIterator(iterator
)); 
1811         /* dispose of handle if already allocated and clear the outputs */ 
1812         if ( NULL 
!= *refsHandle 
) 
1814                 DisposeHandle((Handle
)*refsHandle
); 
1825 /*****************************************************************************/ 
1828         The GenerateUniqueName function generates a HFSUniStr255 name that is 
1829         unique in both dir1 and dir2. 
1831         startSeed                       -->     A pointer to a long which is used to generate the 
1833                                                 <--     It is modified on output to a value which should 
1834                                                         be used to generate the next unique name. 
1835         dir1                            -->     The first directory. 
1836         dir2                            -->     The second directory. 
1837         uniqueName                      <--     A pointer to a HFSUniStr255 where the unique name 
1843 GenerateUniqueHFSUniStr( 
1847         HFSUniStr255 
*uniqueName
) 
1853         unsigned char   hexStr
[17] = "0123456789ABCDEF"; 
1855         /* set up the parameter block */ 
1856         pb
.name 
= uniqueName
->unicode
; 
1857         pb
.nameLength 
= 8;      /* always 8 characters */ 
1858         pb
.textEncodingHint 
= kTextEncodingUnknown
; 
1859         pb
.newRef 
= &newRef
; 
1861         /* loop until we get fnfErr with a filename in both directories */ 
1863         while ( fnfErr 
!= result 
) 
1865                 /* convert startSeed to 8 character Unicode string */ 
1866                 uniqueName
->length 
= 8; 
1867                 for ( i 
= 0; i 
< 8; ++i 
) 
1869                         uniqueName
->unicode
[i
] = hexStr
[((*startSeed 
>> ((7-i
)*4)) & 0xf)]; 
1874                 result 
= PBMakeFSRefUnicodeSync(&pb
); 
1875                 if ( fnfErr 
== result 
) 
1879                         result 
= PBMakeFSRefUnicodeSync(&pb
); 
1880                         if ( fnfErr 
!= result 
) 
1882                                 /* exit if anything other than noErr or fnfErr */ 
1883                                 require_noerr(result
, Dir2PBMakeFSRefUnicodeSyncFailed
); 
1888                         /* exit if anything other than noErr or fnfErr */ 
1889                         require_noerr(result
, Dir1PBMakeFSRefUnicodeSyncFailed
); 
1892                 /* increment seed for next pass through loop, */ 
1893                 /* or for next call to GenerateUniqueHFSUniStr */ 
1897         /* we have a unique file name which doesn't exist in dir1 or dir2 */ 
1900 Dir2PBMakeFSRefUnicodeSyncFailed
: 
1901 Dir1PBMakeFSRefUnicodeSyncFailed
: 
1906 /*****************************************************************************/ 
1909 FSExchangeObjectsCompat( 
1910         const FSRef 
*sourceRef
, 
1911         const FSRef 
*destRef
, 
1912         FSRef 
*newSourceRef
, 
1917                 /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */ 
1918                 kGetCatInformationMask 
= (kFSCatInfoSettableInfo 
| 
1920                                                                   kFSCatInfoParentDirID
) & 
1921                                                                  ~(kFSCatInfoContentMod 
| kFSCatInfoAttrMod
), 
1922                 /* set everything possible except for mod dates */ 
1923                 kSetCatinformationMask 
= kFSCatInfoSettableInfo 
& 
1924                                                                  ~(kFSCatInfoContentMod 
| kFSCatInfoAttrMod
) 
1928         GetVolParmsInfoBuffer   volParmsInfo
; 
1930         FSCatalogInfo                   sourceCatalogInfo
;      /* source file's catalog information */ 
1931         FSCatalogInfo                   destCatalogInfo
;        /* destination file's catalog information */ 
1932         HFSUniStr255                    sourceName
;                     /* source file's Unicode name */ 
1933         HFSUniStr255                    destName
;                       /* destination file's Unicode name */ 
1934         FSRef                                   sourceCurrentRef
;       /* FSRef to current location of source file throughout this function */ 
1935         FSRef                                   destCurrentRef
;         /* FSRef to current location of destination file throughout this function */ 
1936         FSRef                                   sourceParentRef
;        /* FSRef to parent directory of source file */ 
1937         FSRef                                   destParentRef
;          /* FSRef to parent directory of destination file */ 
1938         HFSUniStr255                    sourceUniqueName
;       /* unique name given to source file while exchanging it with destination */ 
1939         HFSUniStr255                    destUniqueName
;         /* unique name given to destination file while exchanging it with source */ 
1940         long                                    theSeed
;                        /* the seed for generating unique names */ 
1941         Boolean                                 sameParentDirs
;         /* true if source and destinatin parent directory is the same */ 
1943         /* check parameters */ 
1944         require_action((NULL 
!= newSourceRef
) && (NULL 
!= newDestRef
), BadParameter
, result 
= paramErr
); 
1946         /* output refs and current refs = input refs to start with */ 
1947         BlockMoveData(sourceRef
, newSourceRef
, sizeof(FSRef
)); 
1948         BlockMoveData(sourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
1950         BlockMoveData(destRef
, newDestRef
, sizeof(FSRef
)); 
1951         BlockMoveData(destRef
, &destCurrentRef
, sizeof(FSRef
)); 
1953         /* get source volume's vRefNum */ 
1954         result 
= FSGetCatalogInfo(&sourceCurrentRef
, kFSCatInfoVolume
, &sourceCatalogInfo
, NULL
, NULL
, NULL
); 
1955         require_noerr(result
, DetermineSourceVRefNumFailed
); 
1957         /* see if that volume supports FSExchangeObjects */ 
1958         result 
= FSGetVolParms(sourceCatalogInfo
.volume
, sizeof(GetVolParmsInfoBuffer
), 
1959                 &volParmsInfo
, &infoSize
); 
1960         if ( (noErr 
== result
) && VolSupportsFSExchangeObjects(&volParmsInfo
) ) 
1962                 /* yes - use FSExchangeObjects */ 
1963                 result 
= FSExchangeObjects(sourceRef
, destRef
); 
1967                 /* no - emulate FSExchangeObjects */ 
1969                 /* Note: The compatibility case won't work for files with *Btree control blocks. */ 
1970                 /* Right now the only *Btree files are created by the system. */ 
1972                 /* get all catalog information and Unicode names for each file */ 
1973                 result 
= FSGetCatalogInfo(&sourceCurrentRef
, kGetCatInformationMask
, &sourceCatalogInfo
, &sourceName
, NULL
, &sourceParentRef
); 
1974                 require_noerr(result
, SourceFSGetCatalogInfoFailed
); 
1976                 result 
= FSGetCatalogInfo(&destCurrentRef
, kGetCatInformationMask
, &destCatalogInfo
, &destName
, NULL
, &destParentRef
); 
1977                 require_noerr(result
, DestFSGetCatalogInfoFailed
); 
1979                 /* make sure source and destination are on same volume */ 
1980                 require_action(sourceCatalogInfo
.volume 
== destCatalogInfo
.volume
, NotSameVolume
, result 
= diffVolErr
); 
1982                 /* make sure both files are *really* files */ 
1983                 require_action((0 == (sourceCatalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
)) && 
1984                                            (0 == (destCatalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
)), NotAFile
, result 
= notAFileErr
); 
1986                 /* generate 2 names that are unique in both directories */ 
1987                 theSeed 
= 0x4a696d4c;   /* a fine unlikely filename */ 
1989                 result 
= GenerateUniqueHFSUniStr(&theSeed
, &sourceParentRef
, &destParentRef
, &sourceUniqueName
); 
1990                 require_noerr(result
, GenerateUniqueHFSUniStr1Failed
); 
1992                 result 
= GenerateUniqueHFSUniStr(&theSeed
, &sourceParentRef
, &destParentRef
, &destUniqueName
); 
1993                 require_noerr(result
, GenerateUniqueHFSUniStr2Failed
); 
1995                 /* rename sourceCurrentRef to sourceUniqueName */ 
1996                 result 
= FSRenameUnicode(&sourceCurrentRef
, sourceUniqueName
.length
, sourceUniqueName
.unicode
, kTextEncodingUnknown
, newSourceRef
); 
1997                 require_noerr(result
, FSRenameUnicode1Failed
); 
1998                 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
2000                 /* rename destCurrentRef to destUniqueName */ 
2001                 result 
= FSRenameUnicode(&destCurrentRef
, destUniqueName
.length
, destUniqueName
.unicode
, kTextEncodingUnknown
, newDestRef
); 
2002                 require_noerr(result
, FSRenameUnicode2Failed
); 
2003                 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
)); 
2005                 /* are the source and destination parent directories the same? */ 
2006                 sameParentDirs 
= ( sourceCatalogInfo
.parentDirID 
== destCatalogInfo
.parentDirID 
); 
2007                 if ( !sameParentDirs 
) 
2009                         /* move source file to dest parent directory */ 
2010                         result 
= FSMoveObject(&sourceCurrentRef
, &destParentRef
, newSourceRef
); 
2011                         require_noerr(result
, FSMoveObject1Failed
); 
2012                         BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
2014                         /* move dest file to source parent directory */ 
2015                         result 
= FSMoveObject(&destCurrentRef
, &sourceParentRef
, newDestRef
); 
2016                         require_noerr(result
, FSMoveObject2Failed
); 
2017                         BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
)); 
2020                 /* At this point, the files are in their new locations (if they were moved). */ 
2021                 /* The source file is named sourceUniqueName and is in the directory referred to */ 
2022                 /* by destParentRef. The destination file is named destUniqueName and is in the */ 
2023                 /* directory referred to by sourceParentRef. */ 
2025                 /* give source file the dest file's catalog information except for mod dates */ 
2026                 result 
= FSSetCatalogInfo(&sourceCurrentRef
, kSetCatinformationMask
, &destCatalogInfo
); 
2027                 require_noerr(result
, FSSetCatalogInfo1Failed
); 
2029                 /* give dest file the source file's catalog information except for mod dates */ 
2030                 result 
= FSSetCatalogInfo(&destCurrentRef
, kSetCatinformationMask
, &sourceCatalogInfo
); 
2031                 require_noerr(result
, FSSetCatalogInfo2Failed
); 
2033                 /* rename source file with dest file's name */ 
2034                 result 
= FSRenameUnicode(&sourceCurrentRef
, destName
.length
, destName
.unicode
, destCatalogInfo
.textEncodingHint
, newSourceRef
); 
2035                 require_noerr(result
, FSRenameUnicode3Failed
); 
2036                 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
2038                 /* rename dest file with source file's name */ 
2039                 result 
= FSRenameUnicode(&destCurrentRef
, sourceName
.length
, sourceName
.unicode
, sourceCatalogInfo
.textEncodingHint
, newDestRef
); 
2040                 require_noerr(result
, FSRenameUnicode4Failed
); 
2042                 /* we're done with no errors, so swap newSourceRef and newDestRef */ 
2043                 BlockMoveData(newDestRef
, newSourceRef
, sizeof(FSRef
)); 
2044                 BlockMoveData(&sourceCurrentRef
, newDestRef
, sizeof(FSRef
)); 
2049         /**********************/ 
2051 /* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */ 
2052 /* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */ 
2053 /* state and location they ended up in so that both files can be found by the calling code. */ 
2055 FSRenameUnicode4Failed
: 
2057         /* attempt to rename source file to sourceUniqueName */ 
2058         if ( noErr 
== FSRenameUnicode(&sourceCurrentRef
, sourceUniqueName
.length
, sourceUniqueName
.unicode
, kTextEncodingUnknown
, newSourceRef
) ) 
2060                 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
2063 FSRenameUnicode3Failed
: 
2065         /* attempt to restore dest file's catalog information */ 
2066         verify_noerr(FSSetCatalogInfo(&destCurrentRef
, kFSCatInfoSettableInfo
, &destCatalogInfo
)); 
2068 FSSetCatalogInfo2Failed
: 
2070         /* attempt to restore source file's catalog information */ 
2071         verify_noerr(FSSetCatalogInfo(&sourceCurrentRef
, kFSCatInfoSettableInfo
, &sourceCatalogInfo
)); 
2073 FSSetCatalogInfo1Failed
: 
2075         if ( !sameParentDirs 
) 
2077                 /* attempt to move dest file back to dest directory */ 
2078                 if ( noErr 
== FSMoveObject(&destCurrentRef
, &destParentRef
, newDestRef
) ) 
2080                         BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
)); 
2084 FSMoveObject2Failed
: 
2086         if ( !sameParentDirs 
) 
2088                 /* attempt to move source file back to source directory */ 
2089                 if ( noErr 
== FSMoveObject(&sourceCurrentRef
, &sourceParentRef
, newSourceRef
) ) 
2091                         BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
2095 FSMoveObject1Failed
: 
2097         /* attempt to rename dest file to original name */ 
2098         verify_noerr(FSRenameUnicode(&destCurrentRef
, destName
.length
, destName
.unicode
, destCatalogInfo
.textEncodingHint
, newDestRef
)); 
2100 FSRenameUnicode2Failed
: 
2102         /* attempt to rename source file to original name */ 
2103         verify_noerr(FSRenameUnicode(&sourceCurrentRef
, sourceName
.length
, sourceName
.unicode
, sourceCatalogInfo
.textEncodingHint
, newSourceRef
)); 
2105 FSRenameUnicode1Failed
: 
2106 GenerateUniqueHFSUniStr2Failed
: 
2107 GenerateUniqueHFSUniStr1Failed
: 
2110 DestFSGetCatalogInfoFailed
: 
2111 SourceFSGetCatalogInfoFailed
: 
2112 DetermineSourceVRefNumFailed
:    
2118 /*****************************************************************************/ 
2120 #pragma mark ----- Shared Environment Routines ----- 
2122 /*****************************************************************************/ 
2125 FSLockRangeMoreFilesX( 
2133         pb
.ioParam
.ioRefNum 
= refNum
; 
2134         pb
.ioParam
.ioReqCount 
= rangeLength
; 
2135         pb
.ioParam
.ioPosMode 
= fsFromStart
; 
2136         pb
.ioParam
.ioPosOffset 
= rangeStart
; 
2137         result 
= PBLockRangeSync(&pb
); 
2138         require_noerr(result
, PBLockRangeSync
); 
2145 /*****************************************************************************/ 
2148 FSUnlockRangeMoreFilesX( 
2156         pb
.ioParam
.ioRefNum 
= refNum
; 
2157         pb
.ioParam
.ioReqCount 
= rangeLength
; 
2158         pb
.ioParam
.ioPosMode 
= fsFromStart
; 
2159         pb
.ioParam
.ioPosOffset 
= rangeStart
; 
2160         result 
= PBUnlockRangeSync(&pb
); 
2161         require_noerr(result
, PBUnlockRangeSync
); 
2168 /*****************************************************************************/ 
2173         SInt32 
*ownerID
,                /* can be NULL */ 
2174         SInt32 
*groupID
,                /* can be NULL */ 
2175         SInt32 
*accessRights
)   /* can be NULL */ 
2181         /* get FSSpec from FSRef */ 
2182         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
); 
2183         require_noerr(result
, FSGetCatalogInfo
); 
2185         /* get directory access info for FSSpec */ 
2186         pb
.accessParam
.ioNamePtr 
= (StringPtr
)spec
.name
; 
2187         pb
.accessParam
.ioVRefNum 
= spec
.vRefNum
; 
2188         pb
.fileParam
.ioDirID 
= spec
.parID
; 
2189         result 
= PBHGetDirAccessSync(&pb
); 
2190         require_noerr(result
, PBHGetDirAccessSync
); 
2192         /* return the IDs and access rights */ 
2193         if ( NULL 
!= ownerID 
) 
2195                 *ownerID 
= pb
.accessParam
.ioACOwnerID
; 
2197         if ( NULL 
!= groupID 
) 
2199                 *groupID 
= pb
.accessParam
.ioACGroupID
; 
2201         if ( NULL 
!= accessRights 
) 
2203                 *accessRights 
= pb
.accessParam
.ioACAccess
; 
2206 PBHGetDirAccessSync
: 
2212 /*****************************************************************************/ 
2219         SInt32 accessRights
) 
2227                 /* Just the bits that can be set */ 
2228                 kSetDirAccessSettableMask 
= (kioACAccessBlankAccessMask 
+ 
2229                         kioACAccessEveryoneWriteMask 
+ kioACAccessEveryoneReadMask 
+ kioACAccessEveryoneSearchMask 
+ 
2230                         kioACAccessGroupWriteMask 
+ kioACAccessGroupReadMask 
+ kioACAccessGroupSearchMask 
+ 
2231                         kioACAccessOwnerWriteMask 
+ kioACAccessOwnerReadMask 
+ kioACAccessOwnerSearchMask
) 
2234         /* get FSSpec from FSRef */ 
2235         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
); 
2236         require_noerr(result
, FSGetCatalogInfo
); 
2238         /* set directory access info for FSSpec */ 
2239         pb
.accessParam
.ioNamePtr 
= (StringPtr
)spec
.name
; 
2240         pb
.accessParam
.ioVRefNum 
= spec
.vRefNum
; 
2241         pb
.fileParam
.ioDirID 
= spec
.parID
; 
2242         pb
.accessParam
.ioACOwnerID 
= ownerID
; 
2243         pb
.accessParam
.ioACGroupID 
= groupID
; 
2244         pb
.accessParam
.ioACAccess 
= accessRights 
& kSetDirAccessSettableMask
; 
2245         result 
= PBHSetDirAccessSync(&pb
); 
2246         require_noerr(result
, PBHSetDirAccessSync
); 
2248 PBHSetDirAccessSync
: 
2254 /*****************************************************************************/ 
2257 FSGetVolMountInfoSize( 
2258         FSVolumeRefNum volRefNum
, 
2264         /* check parameters */ 
2265         require_action(NULL 
!= size
, BadParameter
, result 
= paramErr
); 
2267         pb
.ioParam
.ioNamePtr 
= NULL
; 
2268         pb
.ioParam
.ioVRefNum 
= volRefNum
; 
2269         pb
.ioParam
.ioBuffer 
= (Ptr
)size
; 
2270         result 
= PBGetVolMountInfoSize(&pb
); 
2271         require_noerr(result
, PBGetVolMountInfoSize
); 
2273 PBGetVolMountInfoSize
: 
2279 /*****************************************************************************/ 
2283         FSVolumeRefNum volRefNum
, 
2289         /* check parameters */ 
2290         require_action(NULL 
!= volMountInfo
, BadParameter
, result 
= paramErr
); 
2292         pb
.ioParam
.ioNamePtr 
= NULL
; 
2293         pb
.ioParam
.ioVRefNum 
= volRefNum
; 
2294         pb
.ioParam
.ioBuffer 
= (Ptr
)volMountInfo
; 
2295         result 
= PBGetVolMountInfo(&pb
); 
2296         require_noerr(result
, PBGetVolMountInfo
); 
2304 /*****************************************************************************/ 
2308         const void *volMountInfo
, 
2309         FSVolumeRefNum 
*volRefNum
) 
2314         /* check parameters */ 
2315         require_action(NULL 
!= volRefNum
, BadParameter
, result 
= paramErr
); 
2317         pb
.ioParam
.ioBuffer 
= (Ptr
)volMountInfo
; 
2318         result 
= PBVolumeMount(&pb
); 
2319         require_noerr(result
, PBVolumeMount
); 
2321         /* return the volume reference number */ 
2322         *volRefNum 
= pb
.ioParam
.ioVRefNum
; 
2330 /*****************************************************************************/ 
2334         FSVolumeRefNum volRefNum
, 
2342         /* check parameters */ 
2343         require_action(NULL 
!= name
, BadParameter
, result 
= paramErr
); 
2345         pb
.objParam
.ioNamePtr 
= NULL
; 
2346         pb
.objParam
.ioVRefNum 
= volRefNum
; 
2347         pb
.objParam
.ioObjType 
= objType
; 
2348         pb
.objParam
.ioObjNamePtr 
= name
; 
2349         pb
.objParam
.ioObjID 
= ugID
; 
2350         result 
= PBHMapIDSync(&pb
); 
2351         require_noerr(result
, PBHMapIDSync
); 
2359 /*****************************************************************************/ 
2363         FSVolumeRefNum volRefNum
, 
2364         ConstStr255Param name
, 
2371         /* check parameters */ 
2372         require_action(NULL 
!= ugID
, BadParameter
, result 
= paramErr
); 
2374         pb
.objParam
.ioNamePtr 
= NULL
; 
2375         pb
.objParam
.ioVRefNum 
= volRefNum
; 
2376         pb
.objParam
.ioObjType 
= objType
; 
2377         pb
.objParam
.ioObjNamePtr 
= (StringPtr
)name
; 
2378         result 
= PBHMapNameSync(&pb
); 
2379         require_noerr(result
, PBHMapNameSync
); 
2381         /* return the user or group ID */ 
2382         *ugID 
= pb
.objParam
.ioObjID
; 
2390 /*****************************************************************************/ 
2394         const FSRef 
*srcFileRef
, 
2395         const FSRef 
*dstDirectoryRef
, 
2396         UniCharCount nameLength
, 
2397         const UniChar 
*copyName
,        /* can be NULL (no rename during copy) */ 
2398         TextEncoding textEncodingHint
, 
2399         FSRef 
*newRef
)                          /* can be NULL */ 
2403         FSCatalogInfo                   catalogInfo
; 
2406         GetVolParmsInfoBuffer   volParmsInfo
; 
2409         /* get source FSSpec from source FSRef */ 
2410         result 
= FSGetCatalogInfo(srcFileRef
, kFSCatInfoNone
, NULL
, NULL
, &srcFileSpec
, NULL
); 
2411         require_noerr(result
, FSGetCatalogInfo_srcFileRef
); 
2413         /* Make sure the volume supports CopyFile */ 
2414         result 
= FSGetVolParms(srcFileSpec
.vRefNum
, sizeof(GetVolParmsInfoBuffer
), 
2415                 &volParmsInfo
, &infoSize
); 
2416         require_action((noErr 
== result
) && VolHasCopyFile(&volParmsInfo
), 
2417                 NoCopyFileSupport
, result 
= paramErr
); 
2419         /* get destination volume reference number and destination directory ID from destination FSRef */ 
2420         result 
= FSGetCatalogInfo(dstDirectoryRef
, kFSCatInfoVolume 
+ kFSCatInfoNodeID
, 
2421                 &catalogInfo
, NULL
, NULL
, NULL
); 
2422         require_noerr(result
, FSGetCatalogInfo_dstDirectoryRef
); 
2424         /* tell the server to copy the object */ 
2425         pb
.copyParam
.ioVRefNum 
= srcFileSpec
.vRefNum
; 
2426         pb
.copyParam
.ioDirID 
= srcFileSpec
.parID
; 
2427         pb
.copyParam
.ioNamePtr 
= (StringPtr
)srcFileSpec
.name
; 
2428         pb
.copyParam
.ioDstVRefNum 
= catalogInfo
.volume
; 
2429         pb
.copyParam
.ioNewDirID 
= (long)catalogInfo
.nodeID
; 
2430         pb
.copyParam
.ioNewName 
= NULL
; 
2431         if ( NULL 
!= copyName 
) 
2433                 result 
= UnicodeNameGetHFSName(nameLength
, copyName
, textEncodingHint
, false, hfsName
); 
2434                 require_noerr(result
, UnicodeNameGetHFSName
); 
2436                 pb
.copyParam
.ioCopyName 
= hfsName
; 
2440                 pb
.copyParam
.ioCopyName 
= NULL
; 
2442         result 
= PBHCopyFileSync(&pb
); 
2443         require_noerr(result
, PBHCopyFileSync
); 
2445         if ( NULL 
!= newRef 
) 
2447                 verify_noerr(FSMakeFSRef(pb
.copyParam
.ioDstVRefNum
, pb
.copyParam
.ioNewDirID
, 
2448                         pb
.copyParam
.ioCopyName
, newRef
)); 
2452 UnicodeNameGetHFSName
: 
2453 FSGetCatalogInfo_dstDirectoryRef
: 
2455 FSGetCatalogInfo_srcFileRef
: 
2460 /*****************************************************************************/ 
2464         const FSRef 
*srcFileRef
, 
2465         const FSRef 
*dstDirectoryRef
, 
2466         UniCharCount nameLength
, 
2467         const UniChar 
*moveName
,        /* can be NULL (no rename during move) */ 
2468         TextEncoding textEncodingHint
, 
2469         FSRef 
*newRef
)                          /* can be NULL */ 
2473         FSCatalogInfo                   catalogInfo
; 
2476         GetVolParmsInfoBuffer   volParmsInfo
; 
2479         /* get source FSSpec from source FSRef */ 
2480         result 
= FSGetCatalogInfo(srcFileRef
, kFSCatInfoNone
, NULL
, NULL
, &srcFileSpec
, NULL
); 
2481         require_noerr(result
, FSGetCatalogInfo_srcFileRef
); 
2483         /* Make sure the volume supports MoveRename */ 
2484         result 
= FSGetVolParms(srcFileSpec
.vRefNum
, sizeof(GetVolParmsInfoBuffer
), 
2485                 &volParmsInfo
, &infoSize
); 
2486         require_action((noErr 
== result
) && VolHasMoveRename(&volParmsInfo
), 
2487                 NoMoveRenameSupport
, result 
= paramErr
); 
2489         /* get destination volume reference number and destination directory ID from destination FSRef */ 
2490         result 
= FSGetCatalogInfo(dstDirectoryRef
, kFSCatInfoVolume 
+ kFSCatInfoNodeID
, 
2491                 &catalogInfo
, NULL
, NULL
, NULL
); 
2492         require_noerr(result
, FSGetCatalogInfo_dstDirectoryRef
); 
2494         /* make sure the source and destination are on the same volume */ 
2495         require_action(srcFileSpec
.vRefNum 
== catalogInfo
.volume
, NotSameVolume
, result 
= diffVolErr
); 
2497         /* tell the server to move and rename the object */ 
2498         pb
.copyParam
.ioVRefNum 
= srcFileSpec
.vRefNum
; 
2499         pb
.copyParam
.ioDirID 
= srcFileSpec
.parID
; 
2500         pb
.copyParam
.ioNamePtr 
= (StringPtr
)srcFileSpec
.name
; 
2501         pb
.copyParam
.ioNewDirID 
= (long)catalogInfo
.nodeID
; 
2502         pb
.copyParam
.ioNewName 
= NULL
; 
2503         if ( NULL 
!= moveName 
) 
2505                 result 
= UnicodeNameGetHFSName(nameLength
, moveName
, textEncodingHint
, false, hfsName
); 
2506                 require_noerr(result
, UnicodeNameGetHFSName
); 
2508                 pb
.copyParam
.ioCopyName 
= hfsName
; 
2512                 pb
.copyParam
.ioCopyName 
= NULL
; 
2514         result 
= PBHMoveRenameSync(&pb
); 
2515         require_noerr(result
, PBHMoveRenameSync
); 
2517         if ( NULL 
!= newRef 
) 
2519                 verify_noerr(FSMakeFSRef(pb
.copyParam
.ioVRefNum
, pb
.copyParam
.ioNewDirID
, 
2520                         pb
.copyParam
.ioCopyName
, newRef
)); 
2524 UnicodeNameGetHFSName
: 
2526 FSGetCatalogInfo_dstDirectoryRef
: 
2527 NoMoveRenameSupport
: 
2528 FSGetCatalogInfo_srcFileRef
: 
2533 /*****************************************************************************/ 
2535 #pragma mark ----- File ID Routines ----- 
2537 /*****************************************************************************/ 
2541         FSVolumeRefNum volRefNum
, 
2549         /* check parameters */ 
2550         require_action(NULL 
!= ref
, BadParameter
, result 
= paramErr
); 
2552         /* resolve the file ID reference */ 
2554         pb
.ioNamePtr 
= tempStr
; 
2555         pb
.ioVRefNum 
= volRefNum
; 
2556         pb
.ioFileID 
= fileID
; 
2557         result 
= PBResolveFileIDRefSync((HParmBlkPtr
)&pb
); 
2558         require_noerr(result
, PBResolveFileIDRefSync
); 
2560         /* and then make an FSRef to the file */ 
2561         result 
= FSMakeFSRef(volRefNum
, pb
.ioSrcDirID
, tempStr
, ref
); 
2562         require_noerr(result
, FSMakeFSRef
); 
2565 PBResolveFileIDRefSync
: 
2571 /*****************************************************************************/ 
2582         /* check parameters */ 
2583         require_action(NULL 
!= fileID
, BadParameter
, result 
= paramErr
); 
2585         /* Get an FSSpec from the FSRef */ 
2586         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
); 
2587         require_noerr(result
, FSGetCatalogInfo
); 
2589         /* Create (or get) the file ID reference using the FSSpec */ 
2590         pb
.ioNamePtr 
= (StringPtr
)spec
.name
; 
2591         pb
.ioVRefNum 
= spec
.vRefNum
; 
2592         pb
.ioSrcDirID 
= spec
.parID
; 
2593         result 
= PBCreateFileIDRefSync((HParmBlkPtr
)&pb
); 
2594         require((noErr 
== result
) || (fidExists 
== result
) || (afpIDExists 
== result
), 
2595                 PBCreateFileIDRefSync
); 
2597         /* return the file ID reference */ 
2598         *fileID 
= pb
.ioFileID
; 
2600 PBCreateFileIDRefSync
: 
2607 /*****************************************************************************/ 
2609 #pragma mark ----- Utility Routines ----- 
2611 /*****************************************************************************/ 
2615         ByteCount buffReqSize
, 
2616         ByteCount 
*buffActSize
) 
2620                 kSlopMemory 
= 0x00008000        /* 32K - Amount of free memory to leave when allocating buffers */ 
2625         /* check parameters */ 
2626         require_action(NULL 
!= buffActSize
, BadParameter
, tempPtr 
= NULL
); 
2628         /* Make request a multiple of 4K bytes */ 
2629         buffReqSize 
= buffReqSize 
& 0xfffff000; 
2631         if ( buffReqSize 
< 0x00001000 ) 
2633                 /* Request was smaller than 4K bytes - make it 4K */ 
2634                 buffReqSize 
= 0x00001000; 
2637         /* Attempt to allocate the memory */ 
2638         tempPtr 
= NewPtr(buffReqSize
); 
2640         /* If request failed, go to backup plan */ 
2641         if ( (tempPtr 
== NULL
) && (buffReqSize 
> 0x00001000) ) 
2644                 **      Try to get largest 4K byte block available 
2645                 **      leaving some slop for the toolbox if possible 
2647                 long freeMemory 
= (FreeMem() - kSlopMemory
) & 0xfffff000; 
2649                 buffReqSize 
= MaxBlock() & 0xfffff000; 
2651                 if ( (long)buffReqSize 
> freeMemory 
) 
2653                         buffReqSize 
= freeMemory
; 
2656                 if ( buffReqSize 
== 0 ) 
2658                         buffReqSize 
= 0x00001000; 
2661                 tempPtr 
= NewPtr(buffReqSize
); 
2664         /* Return bytes allocated */ 
2665         if ( tempPtr 
!= NULL 
) 
2667                 *buffActSize 
= buffReqSize
; 
2679 /*****************************************************************************/ 
2686         return ( FSGetForkCBInfo(refNum
, 0, NULL
, NULL
, NULL
, ref
, NULL
) ); 
2689 /*****************************************************************************/ 
2693         const FSRef 
*newDefault
, 
2697         FSVolumeRefNum  vRefNum
; 
2699         FSCatalogInfo   catalogInfo
; 
2701         /* check parameters */ 
2702         require_action((NULL 
!= newDefault
) && (NULL 
!= oldDefault
), BadParameter
, result 
= paramErr
); 
2704         /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */ 
2705         result 
= FSGetCatalogInfo(newDefault
, 
2706                 kFSCatInfoNodeFlags 
+ kFSCatInfoVolume 
+ kFSCatInfoNodeID
, 
2707                 &catalogInfo
, NULL
, NULL
, NULL
); 
2708         require_noerr(result
, FSGetCatalogInfo
); 
2710         /* Make sure newDefault is a directory */ 
2711         require_action(0 != (kFSNodeIsDirectoryMask 
& catalogInfo
.nodeFlags
), NewDefaultNotDirectory
, 
2714         /* Get the current working directory. */ 
2715         result 
= HGetVol(NULL
, &vRefNum
, &dirID
); 
2716         require_noerr(result
, HGetVol
); 
2718         /* Return the oldDefault FSRef */ 
2719         result 
= FSMakeFSRef(vRefNum
, dirID
, NULL
, oldDefault
); 
2720         require_noerr(result
, FSMakeFSRef
); 
2722         /* Set the new current working directory */ 
2723         result 
= HSetVol(NULL
, catalogInfo
.volume
, catalogInfo
.nodeID
); 
2724         require_noerr(result
, HSetVol
); 
2729 NewDefaultNotDirectory
: 
2736 /*****************************************************************************/ 
2740         const FSRef 
*oldDefault
) 
2743         FSCatalogInfo   catalogInfo
; 
2745         /* check parameters */ 
2746         require_action(NULL 
!= oldDefault
, BadParameter
, result 
= paramErr
); 
2748         /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */ 
2749         result 
= FSGetCatalogInfo(oldDefault
, 
2750                 kFSCatInfoNodeFlags 
+ kFSCatInfoVolume 
+ kFSCatInfoNodeID
, 
2751                 &catalogInfo
, NULL
, NULL
, NULL
); 
2752         require_noerr(result
, FSGetCatalogInfo
); 
2754         /* Make sure oldDefault is a directory */ 
2755         require_action(0 != (kFSNodeIsDirectoryMask 
& catalogInfo
.nodeFlags
), OldDefaultNotDirectory
, 
2758         /* Set the current working directory to oldDefault */ 
2759         result 
= HSetVol(NULL
, catalogInfo
.volume
, catalogInfo
.nodeID
); 
2760         require_noerr(result
, HSetVol
); 
2763 OldDefaultNotDirectory
: 
2770 /*****************************************************************************/