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> 
  75         #define BuildingMoreFilesXForMacOS9 0 
  79         #define BuildingMoreFilesXForMacOS9 1 
  82 #include "MoreFilesX.h" 
  84 /* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */ 
  85 #ifndef BuildingMoreFilesXForMacOS9 
  86         #define BuildingMoreFilesXForMacOS9 0 
  89 /*****************************************************************************/ 
  91 #pragma mark ----- Local type definitions ----- 
  93 struct FSIterateContainerGlobals
 
  95         IterateContainerFilterProcPtr   iterateFilter
;  /* pointer to IterateFilterProc */ 
  96         FSCatalogInfoBitmap                             whichInfo
;              /* fields of the CatalogInfo to get */ 
  97         FSCatalogInfo                                   catalogInfo
;    /* FSCatalogInfo */ 
  98         FSRef                                                   ref
;                    /* FSRef */ 
  99         FSSpec                                                  spec
;                   /* FSSpec */ 
 100         FSSpec                                                  
*specPtr
;               /* pointer to spec field, or NULL */ 
 101         HFSUniStr255                                    name
;                   /* HFSUniStr255 */ 
 102         HFSUniStr255                                    
*namePtr
;               /* pointer to name field, or NULL */ 
 103         void                                                    *yourDataPtr
;   /* a pointer to caller supplied data the filter may need to access */ 
 104         ItemCount                                               maxLevels
;              /* maximum levels to iterate through */ 
 105         ItemCount                                               currentLevel
;   /* the current level FSIterateContainerLevel is on */ 
 106         Boolean                                                 quitFlag
;               /* set to true if filter wants to kill interation */ 
 107         Boolean                                                 containerChanged
; /* temporary - set to true if the current container changed during iteration */ 
 108         OSErr                                                   result
;                 /* result */ 
 109         ItemCount                                               actualObjects
;  /* number of objects returned */ 
 111 typedef struct FSIterateContainerGlobals FSIterateContainerGlobals
; 
 113 struct FSDeleteContainerGlobals
 
 115         OSErr                                                   result
;                 /* result */ 
 116         ItemCount                                               actualObjects
;  /* number of objects returned */ 
 117         FSCatalogInfo                                   catalogInfo
;    /* FSCatalogInfo */ 
 119 typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals
; 
 121 /*****************************************************************************/ 
 123 #pragma mark ----- Local prototypes ----- 
 127 FSDeleteContainerLevel( 
 128         const FSRef 
*container
, 
 129         FSDeleteContainerGlobals 
*theGlobals
); 
 133 FSIterateContainerLevel( 
 134         FSIterateContainerGlobals 
*theGlobals
); 
 138 GenerateUniqueHFSUniStr( 
 142         HFSUniStr255 
*uniqueName
); 
 144 /*****************************************************************************/ 
 146 #pragma mark ----- File Access Routines ----- 
 148 /*****************************************************************************/ 
 155         ByteCount copyBufferSize
) 
 161         ByteCount       readActualCount
; 
 163         /* check input parameters */ 
 164         require_action((NULL 
!= copyBufferPtr
) && (0 != copyBufferSize
), BadParameter
, result 
= paramErr
); 
 166         /* get source fork size */ 
 167         result 
= FSGetForkSize(srcRefNum
, &forkSize
); 
 168         require_noerr(result
, SourceFSGetForkSizeFailed
); 
 170         /* allocate disk space for destination fork */ 
 171         result 
= FSSetForkSize(dstRefNum
, fsFromStart
, forkSize
); 
 172         require_noerr(result
, DestinationFSSetForkSizeFailed
); 
 174         /* reset source fork's position to 0 */ 
 175         result 
= FSSetForkPosition(srcRefNum
, fsFromStart
, 0); 
 176         require_noerr(result
, SourceFSSetForkPositionFailed
); 
 178         /* reset destination fork's position to 0 */ 
 179         result 
= FSSetForkPosition(dstRefNum
, fsFromStart
, 0); 
 180         require_noerr(result
, DestinationFSSetForkPositionFailed
); 
 182         /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */ 
 183         /* This will make writes on local volumes faster */ 
 184         if ( (copyBufferSize 
>= 0x00001000) && ((copyBufferSize 
& 0x00000fff) != 0) ) 
 186                 copyBufferSize 
&= ~(0x00001000 - 1); 
 189         /* copy source to destination */ 
 190         srcResult 
= dstResult 
= noErr
; 
 191         while ( (noErr 
== srcResult
) && (noErr 
== dstResult
) ) 
 193                 srcResult 
= FSReadFork(srcRefNum
, fsAtMark 
+ noCacheMask
, 0, copyBufferSize
, copyBufferPtr
, &readActualCount
); 
 194                 dstResult 
= FSWriteFork(dstRefNum
, fsAtMark 
+ noCacheMask
, 0, readActualCount
, copyBufferPtr
, NULL
); 
 197         /* make sure there were no errors at the destination */ 
 198         require_noerr_action(dstResult
, DestinationFSWriteForkFailed
, result 
= dstResult
); 
 200         /* make sure the error at the source was eofErr */ 
 201         require_action(eofErr 
== srcResult
, SourceResultNotEofErr
, result 
= srcResult
); 
 203         /* everything went as expected */ 
 206 SourceResultNotEofErr
: 
 207 DestinationFSWriteForkFailed
: 
 208 DestinationFSSetForkPositionFailed
: 
 209 SourceFSSetForkPositionFailed
: 
 210 DestinationFSSetForkSizeFailed
: 
 211 SourceFSGetForkSizeFailed
: 
 217 /*****************************************************************************/ 
 219 #pragma mark ----- Volume Access Routines ----- 
 221 /*****************************************************************************/  
 225         FSVolumeRefNum volRefNum
, 
 227         GetVolParmsInfoBuffer 
*volParmsInfo
, 
 228         UInt32 
*actualInfoSize
) 
 233         /* check parameters */ 
 234         require_action((NULL 
!= volParmsInfo
) && (NULL 
!= actualInfoSize
), 
 235                 BadParameter
, result 
= paramErr
); 
 237         pb
.ioParam
.ioNamePtr 
= NULL
; 
 238         pb
.ioParam
.ioVRefNum 
= volRefNum
; 
 239         pb
.ioParam
.ioBuffer 
= (Ptr
)volParmsInfo
; 
 240         pb
.ioParam
.ioReqCount 
= (SInt32
)bufferSize
; 
 241         result 
= PBHGetVolParmsSync(&pb
); 
 242         require_noerr(result
, PBHGetVolParmsSync
); 
 244         /* return number of bytes the file system returned in volParmsInfo buffer */ 
 245         *actualInfoSize 
= (UInt32
)pb
.ioParam
.ioActCount
; 
 253 /*****************************************************************************/ 
 258         FSVolumeRefNum 
*vRefNum
) 
 261         FSCatalogInfo   catalogInfo
; 
 263         /* check parameters */ 
 264         require_action(NULL 
!= vRefNum
, BadParameter
, result 
= paramErr
); 
 266         /* get the volume refNum from the FSRef */ 
 267         result 
= FSGetCatalogInfo(ref
, kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
, NULL
); 
 268         require_noerr(result
, FSGetCatalogInfo
); 
 270         /* return volume refNum from catalogInfo */ 
 271         *vRefNum 
= catalogInfo
.volume
; 
 279 /*****************************************************************************/ 
 283         FSVolumeRefNum volume
, 
 284         HFSUniStr255 
*volumeName
,       /* can be NULL */ 
 285         UInt64 
*freeBytes
,                      /* can be NULL */ 
 286         UInt64 
*totalBytes
)                     /* can be NULL */ 
 291         /* ask for the volume's sizes only if needed */ 
 292         result 
= FSGetVolumeInfo(volume
, 0, NULL
, 
 293                 (((NULL 
!= freeBytes
) || (NULL 
!= totalBytes
)) ? kFSVolInfoSizes 
: kFSVolInfoNone
), 
 294                 &info
, volumeName
, NULL
); 
 295         require_noerr(result
, FSGetVolumeInfo
); 
 297         if ( NULL 
!= freeBytes 
) 
 299                 *freeBytes 
= info
.freeBytes
; 
 301         if ( NULL 
!= totalBytes 
) 
 303                 *totalBytes 
= info
.totalBytes
; 
 311 /*****************************************************************************/ 
 314 FSGetVolFileSystemID( 
 315         FSVolumeRefNum volume
, 
 316         UInt16 
*fileSystemID
,   /* can be NULL */ 
 317         UInt16 
*signature
)              /* can be NULL */ 
 322         result 
= FSGetVolumeInfo(volume
, 0, NULL
, kFSVolInfoFSInfo
, &info
, NULL
, NULL
); 
 323         require_noerr(result
, FSGetVolumeInfo
); 
 325         if ( NULL 
!= fileSystemID 
) 
 327                 *fileSystemID 
= info
.filesystemID
; 
 329         if ( NULL 
!= signature 
) 
 331                 *signature 
= info
.signature
; 
 339 /*****************************************************************************/ 
 343         FSRef 
***volumeRefsHandle
,      /* pointer to handle of FSRefs */ 
 344         ItemCount 
*numVolumes
) 
 348         ItemCount       volumeIndex
; 
 351         /* check parameters */ 
 352         require_action((NULL 
!= volumeRefsHandle
) && (NULL 
!= numVolumes
), 
 353                 BadParameter
, result 
= paramErr
); 
 358         /* Allocate a handle for the results */ 
 359         *volumeRefsHandle 
= (FSRef 
**)NewHandle(0); 
 360         require_action(NULL 
!= *volumeRefsHandle
, NewHandle
, result 
= memFullErr
); 
 362         /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */ 
 366                 result 
= FSGetVolumeInfo(0, volumeIndex
, NULL
, kFSVolInfoNone
, NULL
, NULL
, &ref
); 
 367                 if ( noErr 
== result 
) 
 369                         /* concatenate the FSRef to the end of the handle */ 
 370                         PtrAndHand(&ref
, (Handle
)*volumeRefsHandle
, sizeof(FSRef
)); 
 371                         memResult 
= MemError(); 
 372                         require_noerr_action(memResult
, MemoryAllocationFailed
, result 
= memResult
); 
 374                         ++(*numVolumes
);        /* increment the volume count */ 
 375                         ++volumeIndex
;          /* and the volumeIndex to get the next volume*/ 
 377         } while ( noErr 
== result 
); 
 379         /* nsvErr is OK -- it just means there are no more volumes */ 
 380         require(nsvErr 
== result
, FSGetVolumeInfo
); 
 384         /**********************/ 
 386 MemoryAllocationFailed
: 
 389         /* dispose of handle if already allocated and clear the outputs */ 
 390         if ( NULL 
!= *volumeRefsHandle 
) 
 392                 DisposeHandle((Handle
)*volumeRefsHandle
); 
 393                 *volumeRefsHandle 
= NULL
; 
 403 /*****************************************************************************/ 
 405 #pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines ----- 
 407 /*****************************************************************************/ 
 416         /* check parameters */ 
 417         require_action(NULL 
!= spec
, BadParameter
, result 
= paramErr
); 
 419         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
); 
 420         require_noerr(result
, FSGetCatalogInfo
); 
 428 /*****************************************************************************/ 
 432         FSVolumeRefNum volRefNum
, 
 434         ConstStr255Param name
, 
 440         /* check parameters */ 
 441         require_action(NULL 
!= ref
, BadParameter
, result 
= paramErr
); 
 443         pb
.ioVRefNum 
= volRefNum
; 
 445         pb
.ioNamePtr 
= (StringPtr
)name
; 
 447         result 
= PBMakeFSRefSync(&pb
); 
 448         require_noerr(result
, PBMakeFSRefSync
); 
 456 /*****************************************************************************/ 
 462         ConstStr255Param name
, 
 469         /* check parameters */ 
 470         require_action(NULL 
!= path
, BadParameter
, result 
= paramErr
); 
 472         /* convert the inputs to an FSRef */ 
 473         result 
= FSMakeFSRef(volRefNum
, dirID
, name
, &ref
); 
 474         require_noerr(result
, FSMakeFSRef
); 
 476         /* and then convert the FSRef to a path */ 
 477         result 
= FSRefMakePath(&ref
, path
, maxPathSize
); 
 478         require_noerr(result
, FSRefMakePath
); 
 487 /*****************************************************************************/ 
 493         Boolean 
*isDirectory
)   /* can be NULL */ 
 498         /* check parameters */ 
 499         require_action(NULL 
!= spec
, BadParameter
, result 
= paramErr
); 
 501         /* convert the POSIX path to an FSRef */ 
 502         result 
= FSPathMakeRef(path
, &ref
, isDirectory
); 
 503         require_noerr(result
, FSPathMakeRef
); 
 505         /* and then convert the FSRef to an FSSpec */ 
 506         result 
= FSGetCatalogInfo(&ref
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
); 
 507         require_noerr(result
, FSGetCatalogInfo
); 
 516 /*****************************************************************************/ 
 519 UnicodeNameGetHFSName( 
 520         UniCharCount nameLength
, 
 522         TextEncoding textEncodingHint
, 
 523         Boolean isVolumeName
, 
 527         ByteCount                       unicodeByteLength
; 
 528         ByteCount                       unicodeBytesConverted
; 
 529         ByteCount                       actualPascalBytes
; 
 530         UnicodeMapping          uMapping
; 
 531         UnicodeToTextInfo       utInfo
; 
 533         /* check parameters */ 
 534         require_action(NULL 
!= hfsName
, BadParameter
, result 
= paramErr
); 
 536         /* make sure output is valid in case we get errors or there's nothing to convert */ 
 539         unicodeByteLength 
= nameLength 
* sizeof(UniChar
); 
 540         if ( 0 == unicodeByteLength 
) 
 547                 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ 
 548                 if ( kTextEncodingUnknown 
== textEncodingHint 
) 
 553                         script 
= (ScriptCode
)GetScriptManagerVariable(smSysScript
); 
 554                         region 
= (RegionCode
)GetScriptManagerVariable(smRegionCode
); 
 555                         result 
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, region
, 
 556                                 NULL
, &textEncodingHint 
); 
 557                         if ( paramErr 
== result 
) 
 559                                 /* ok, ignore the region and try again */ 
 560                                 result 
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, 
 561                                         kTextRegionDontCare
, NULL
, &textEncodingHint 
); 
 563                         if ( noErr 
!= result 
) 
 565                                 /* ok... try something */ 
 566                                 textEncodingHint 
= kTextEncodingMacRoman
; 
 570                 uMapping
.unicodeEncoding 
= CreateTextEncoding(kTextEncodingUnicodeV2_0
, 
 571                         kUnicodeCanonicalDecompVariant
, kUnicode16BitFormat
); 
 572                 uMapping
.otherEncoding 
= GetTextEncodingBase(textEncodingHint
); 
 573                 uMapping
.mappingVersion 
= kUnicodeUseHFSPlusMapping
; 
 575                 result 
= CreateUnicodeToTextInfo(&uMapping
, &utInfo
); 
 576                 require_noerr(result
, CreateUnicodeToTextInfo
); 
 578                 result 
= ConvertFromUnicodeToText(utInfo
, unicodeByteLength
, name
, kUnicodeLooseMappingsMask
, 
 579                         0, NULL
, 0, NULL
,       /* offsetCounts & offsetArrays */ 
 580                         isVolumeName 
? kHFSMaxVolumeNameChars 
: kHFSMaxFileNameChars
, 
 581                         &unicodeBytesConverted
, &actualPascalBytes
, &hfsName
[1]); 
 582                 require_noerr(result
, ConvertFromUnicodeToText
); 
 584                 hfsName
[0] = (unsigned char)actualPascalBytes
;  /* fill in length byte */ 
 586 ConvertFromUnicodeToText
: 
 588                 /* verify the result in debug builds -- there's really not anything you can do if it fails */ 
 589                 verify_noerr(DisposeUnicodeToTextInfo(&utInfo
)); 
 592 CreateUnicodeToTextInfo
:         
 598 /*****************************************************************************/ 
 601 HFSNameGetUnicodeName( 
 602         ConstStr31Param hfsName
, 
 603         TextEncoding textEncodingHint
, 
 604         HFSUniStr255 
*unicodeName
) 
 606         ByteCount                       unicodeByteLength
; 
 608         UnicodeMapping          uMapping
; 
 609         TextToUnicodeInfo       tuInfo
; 
 610         ByteCount                       pascalCharsRead
; 
 612         /* check parameters */ 
 613         require_action(NULL 
!= unicodeName
, BadParameter
, result 
= paramErr
); 
 615         /* make sure output is valid in case we get errors or there's nothing to convert */ 
 616         unicodeName
->length 
= 0; 
 618         if ( 0 == StrLength(hfsName
) ) 
 624                 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ 
 625                 if ( kTextEncodingUnknown 
== textEncodingHint 
) 
 630                         script 
= GetScriptManagerVariable(smSysScript
); 
 631                         region 
= GetScriptManagerVariable(smRegionCode
); 
 632                         result 
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, region
, 
 633                                 NULL
, &textEncodingHint
); 
 634                         if ( paramErr 
== result 
) 
 636                                 /* ok, ignore the region and try again */ 
 637                                 result 
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, 
 638                                         kTextRegionDontCare
, NULL
, &textEncodingHint
); 
 640                         if ( noErr 
!= result 
) 
 642                                 /* ok... try something */ 
 643                                 textEncodingHint 
= kTextEncodingMacRoman
; 
 647                 uMapping
.unicodeEncoding 
= CreateTextEncoding(kTextEncodingUnicodeV2_0
, 
 648                         kUnicodeCanonicalDecompVariant
, kUnicode16BitFormat
); 
 649                 uMapping
.otherEncoding 
= GetTextEncodingBase(textEncodingHint
); 
 650                 uMapping
.mappingVersion 
= kUnicodeUseHFSPlusMapping
; 
 652                 result 
= CreateTextToUnicodeInfo(&uMapping
, &tuInfo
); 
 653                 require_noerr(result
, CreateTextToUnicodeInfo
); 
 655                 result 
= ConvertFromTextToUnicode(tuInfo
, hfsName
[0], &hfsName
[1], 
 656                         0,                                                              /* no control flag bits */ 
 657                         0, NULL
, 0, NULL
,                               /* offsetCounts & offsetArrays */ 
 658                         sizeof(unicodeName
->unicode
),   /* output buffer size in bytes */ 
 659                         &pascalCharsRead
, &unicodeByteLength
, unicodeName
->unicode
); 
 660                 require_noerr(result
, ConvertFromTextToUnicode
); 
 662                 /* convert from byte count to char count */ 
 663                 unicodeName
->length 
= unicodeByteLength 
/ sizeof(UniChar
); 
 665 ConvertFromTextToUnicode
: 
 667                 /* verify the result in debug builds -- there's really not anything you can do if it fails */ 
 668                 verify_noerr(DisposeTextToUnicodeInfo(&tuInfo
)); 
 671 CreateTextToUnicodeInfo
: 
 677 /*****************************************************************************/ 
 679 #pragma mark ----- File/Directory Manipulation Routines ----- 
 681 /*****************************************************************************/ 
 683 Boolean 
FSRefValid(const FSRef 
*ref
) 
 685         return ( noErr 
== FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, NULL
, NULL
) ); 
 688 /*****************************************************************************/ 
 696         FSCatalogInfo   catalogInfo
; 
 698         /* check parameters */ 
 699         require_action(NULL 
!= parentRef
, BadParameter
, result 
= paramErr
); 
 701         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNodeID
, &catalogInfo
, NULL
, NULL
, parentRef
); 
 702         require_noerr(result
, FSGetCatalogInfo
); 
 705          * Note: FSRefs always point to real file system objects. So, there cannot 
 706          * be a FSRef to the parent of volume root directories. Early versions of 
 707          * Mac OS X do not handle this case correctly and incorrectly return a 
 708          * FSRef for the parent of volume root directories instead of returning an 
 709          * invalid FSRef (a cleared FSRef is invalid). The next three lines of code 
 710          * ensure that you won't run into this bug. WW9D! 
 712         if ( fsRtDirID 
== catalogInfo
.nodeID 
) 
 714                 /* clear parentRef and return noErr which is the proper behavior */ 
 715                 memset(parentRef
, 0, sizeof(FSRef
)); 
 724 /*****************************************************************************/ 
 729         HFSUniStr255 
*outName
) 
 733         /* check parameters */ 
 734         require_action(NULL 
!= outName
, BadParameter
, result 
= paramErr
); 
 736         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, outName
, NULL
, NULL
); 
 737         require_noerr(result
, FSGetCatalogInfo
); 
 745 /*****************************************************************************/ 
 750         long *nodeID
,                   /* can be NULL */ 
 751         Boolean 
*isDirectory
)   /* can be NULL */ 
 754         FSCatalogInfo           catalogInfo
; 
 755         FSCatalogInfoBitmap whichInfo
; 
 757         /* determine what catalog information to get */ 
 758         whichInfo 
= kFSCatInfoNone
; /* start with none */ 
 759         if ( NULL 
!= nodeID 
) 
 761                 whichInfo 
|= kFSCatInfoNodeID
; 
 763         if ( NULL 
!= isDirectory 
) 
 765                 whichInfo 
|= kFSCatInfoNodeFlags
; 
 768         result 
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
); 
 769         require_noerr(result
, FSGetCatalogInfo
); 
 771         if ( NULL 
!= nodeID 
) 
 773                 *nodeID 
= catalogInfo
.nodeID
; 
 775         if ( NULL 
!= isDirectory 
) 
 777                 *isDirectory 
= (0 != (kFSNodeIsDirectoryMask 
& catalogInfo
.nodeFlags
)); 
 785 /*****************************************************************************/ 
 788 FSGetUserPrivilegesPermissions( 
 790         UInt8 
*userPrivileges
,          /* can be NULL */ 
 791         UInt32 permissions
[4])          /* can be NULL */ 
 794         FSCatalogInfo   catalogInfo
; 
 795         FSCatalogInfoBitmap whichInfo
; 
 797         /* determine what catalog information to get */ 
 798         whichInfo 
= kFSCatInfoNone
; /* start with none */ 
 799         if ( NULL 
!= userPrivileges 
) 
 801                 whichInfo 
|= kFSCatInfoUserPrivs
; 
 803         if ( NULL 
!= permissions 
) 
 805                 whichInfo 
|= kFSCatInfoPermissions
; 
 808         result 
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
); 
 809         require_noerr(result
, FSGetCatalogInfo
); 
 811         if ( NULL 
!= userPrivileges 
) 
 813                 *userPrivileges 
= catalogInfo
.userPrivileges
; 
 815         if ( NULL 
!= permissions 
) 
 817                 BlockMoveData(&catalogInfo
.permissions
, permissions
, sizeof(UInt32
) * 4); 
 825 /*****************************************************************************/ 
 832         FSCatalogInfo   catalogInfo
; 
 833         FSVolumeInfo    volumeInfo
; 
 835         /* get nodeFlags and vRefNum for container */ 
 836         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags 
+ kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
,NULL
); 
 837         require_noerr(result
, FSGetCatalogInfo
); 
 839         /* is file locked? */ 
 840         if ( 0 != (catalogInfo
.nodeFlags 
& kFSNodeLockedMask
) ) 
 842                 result 
= fLckdErr
;      /* file is locked */ 
 846                 /* file isn't locked, but is volume locked? */ 
 848                 /* get volume flags */ 
 849                 result 
= FSGetVolumeInfo(catalogInfo
.volume
, 0, NULL
, kFSVolInfoFlags
, &volumeInfo
, NULL
, NULL
); 
 850                 require_noerr(result
, FSGetVolumeInfo
); 
 852                 if ( 0 != (volumeInfo
.flags 
& kFSVolFlagHardwareLockedMask
) ) 
 854                         result 
= wPrErr
;        /* volume locked by hardware */ 
 856                 else if ( 0 != (volumeInfo
.flags 
& kFSVolFlagSoftwareLockedMask
) ) 
 858                         result 
= vLckdErr
;      /* volume locked by software */ 
 868 /*****************************************************************************/ 
 873         UInt64 
*dataLogicalSize
,        /* can be NULL */ 
 874         UInt64 
*rsrcLogicalSize
)        /* can be NULL */ 
 877         FSCatalogInfoBitmap whichInfo
; 
 878         FSCatalogInfo           catalogInfo
; 
 880         whichInfo 
= kFSCatInfoNodeFlags
; 
 881         if ( NULL 
!= dataLogicalSize 
) 
 883                 /* get data fork size */ 
 884                 whichInfo 
|= kFSCatInfoDataSizes
; 
 886         if ( NULL 
!= rsrcLogicalSize 
) 
 888                 /* get resource fork size */ 
 889                 whichInfo 
|= kFSCatInfoRsrcSizes
; 
 892         /* get nodeFlags and catalog info */ 
 893         result 
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
,NULL
); 
 894         require_noerr(result
, FSGetCatalogInfo
); 
 896         /* make sure FSRef was to a file */ 
 897         require_action(0 == (catalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
), FSRefNotFile
, result 
= notAFileErr
); 
 899         if ( NULL 
!= dataLogicalSize 
) 
 901                 /* return data fork size */ 
 902                 *dataLogicalSize 
= catalogInfo
.dataLogicalSize
; 
 904         if ( NULL 
!= rsrcLogicalSize 
) 
 906                 /* return resource fork size */ 
 907                 *rsrcLogicalSize 
= catalogInfo
.rsrcLogicalSize
; 
 916 /*****************************************************************************/ 
 921         UInt64 
*totalLogicalSize
,       /* can be NULL */ 
 922         UInt64 
*totalPhysicalSize
,      /* can be NULL */ 
 923         ItemCount 
*forkCount
)           /* can be NULL */ 
 926         CatPositionRec  forkIterator
; 
 929         UInt64                  forkPhysicalSize
; 
 930         UInt64                  
*forkPhysicalSizePtr
; 
 932         /* Determine if forkSize needed */ 
 933         if ( NULL 
!= totalLogicalSize
) 
 935                 *totalLogicalSize 
= 0; 
 936                 forkSizePtr 
= &forkSize
; 
 943         /* Determine if forkPhysicalSize is needed */ 
 944         if ( NULL 
!= totalPhysicalSize 
) 
 946                 *totalPhysicalSize 
= 0; 
 947                 forkPhysicalSizePtr 
= &forkPhysicalSize
; 
 951                 forkPhysicalSizePtr 
= NULL
; 
 954         /* zero fork count if returning it */ 
 955         if ( NULL 
!= forkCount 
) 
 960         /* Iterate through the forks to get the sizes */ 
 961         forkIterator
.initialize 
= 0; 
 964                 result 
= FSIterateForks(ref
, &forkIterator
, NULL
, forkSizePtr
, forkPhysicalSizePtr
); 
 965                 if ( noErr 
== result 
) 
 967                         if ( NULL 
!= totalLogicalSize 
) 
 969                                 *totalLogicalSize 
+= forkSize
; 
 972                         if ( NULL 
!= totalPhysicalSize 
) 
 974                                 *totalPhysicalSize 
+= forkPhysicalSize
; 
 977                         if ( NULL 
!= forkCount 
) 
 982         } while ( noErr 
== result 
); 
 984         /* any error result other than errFSNoMoreItems is serious */ 
 985         require(errFSNoMoreItems 
== result
, FSIterateForks
); 
 995 /*****************************************************************************/ 
1002         FSCatalogInfo   catalogInfo
; 
1003         UTCDateTime             oldDateTime
; 
1004 #if !BuildingMoreFilesXForMacOS9 
1006         Boolean                 notifyParent
; 
1009 #if !BuildingMoreFilesXForMacOS9 
1010         /* Get the node flags, the content modification date and time, and the parent ref */ 
1011         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags 
+ kFSCatInfoContentMod
, &catalogInfo
, NULL
, NULL
, &parentRef
); 
1012         require_noerr(result
, FSGetCatalogInfo
); 
1014         /* Notify the parent if this is a file */ 
1015         notifyParent 
= (0 == (catalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
)); 
1017         /* Get the content modification date and time */ 
1018         result 
= FSGetCatalogInfo(ref
, kFSCatInfoContentMod
, &catalogInfo
, NULL
, NULL
, NULL
); 
1019         require_noerr(result
, FSGetCatalogInfo
); 
1022         oldDateTime 
= catalogInfo
.contentModDate
; 
1024         /* Get the current date and time */ 
1025         result 
= GetUTCDateTime(&catalogInfo
.contentModDate
, kUTCDefaultOptions
); 
1026         require_noerr(result
, GetUTCDateTime
); 
1028         /* if the old date and time is the the same as the current, bump the seconds by one */ 
1029         if ( (catalogInfo
.contentModDate
.fraction 
== oldDateTime
.fraction
) && 
1030                  (catalogInfo
.contentModDate
.lowSeconds 
== oldDateTime
.lowSeconds
) && 
1031                  (catalogInfo
.contentModDate
.highSeconds 
== oldDateTime
.highSeconds
) ) 
1033                 ++catalogInfo
.contentModDate
.lowSeconds
; 
1034                 if ( 0 == catalogInfo
.contentModDate
.lowSeconds 
) 
1036                         ++catalogInfo
.contentModDate
.highSeconds
; 
1040         /* Bump the content modification date and time */ 
1041         result 
= FSSetCatalogInfo(ref
, kFSCatInfoContentMod
, &catalogInfo
); 
1042         require_noerr(result
, FSSetCatalogInfo
); 
1044 #if !BuildingMoreFilesXForMacOS9 
1046          * The problem with FNNotify is that it is not available under Mac OS 9 
1047          * and there's no way to test for that except for looking for the symbol 
1048          * or something. So, I'll just conditionalize this for those who care 
1049          * to send a notification. 
1052         /* Send a notification for the parent of the file, or for the directory */ 
1053         result 
= FNNotify(notifyParent 
? &parentRef 
: ref
, kFNDirectoryModifiedMessage
, kNilOptions
); 
1054         require_noerr(result
, FNNotify
); 
1057         /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */ 
1063         /**********************/ 
1071 /*****************************************************************************/ 
1076         FinderInfo 
*info
,                                       /* can be NULL */ 
1077         ExtendedFinderInfo 
*extendedInfo
,       /* can be NULL */ 
1078         Boolean 
*isDirectory
)                           /* can be NULL */ 
1081         FSCatalogInfo           catalogInfo
; 
1082         FSCatalogInfoBitmap whichInfo
; 
1084         /* determine what catalog information is really needed */ 
1085         whichInfo 
= kFSCatInfoNone
; 
1089                 /* get FinderInfo */ 
1090                 whichInfo 
|= kFSCatInfoFinderInfo
; 
1093         if ( NULL 
!= extendedInfo 
) 
1095                 /* get ExtendedFinderInfo */ 
1096                 whichInfo 
|= kFSCatInfoFinderXInfo
; 
1099         if ( NULL 
!= isDirectory 
) 
1101                 whichInfo 
|= kFSCatInfoNodeFlags
; 
1104         result 
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
); 
1105         require_noerr(result
, FSGetCatalogInfo
); 
1107         /* return FinderInfo if requested */ 
1110                 BlockMoveData(catalogInfo
.finderInfo
, info
, sizeof(FinderInfo
)); 
1113         /* return ExtendedFinderInfo if requested */ 
1114         if ( NULL 
!= extendedInfo
) 
1116                 BlockMoveData(catalogInfo
.extFinderInfo
, extendedInfo
, sizeof(ExtendedFinderInfo
)); 
1119         /* set isDirectory Boolean if requested */ 
1120         if ( NULL 
!= isDirectory
) 
1122                 *isDirectory 
= (0 != (kFSNodeIsDirectoryMask 
& catalogInfo
.nodeFlags
)); 
1130 /*****************************************************************************/ 
1135         const FinderInfo 
*info
, 
1136         const ExtendedFinderInfo 
*extendedInfo
) 
1139         FSCatalogInfo           catalogInfo
; 
1140         FSCatalogInfoBitmap whichInfo
; 
1142         /* determine what catalog information will be set */ 
1143         whichInfo 
= kFSCatInfoNone
; /* start with none */ 
1146                 /* set FinderInfo */ 
1147                 whichInfo 
|= kFSCatInfoFinderInfo
; 
1148                 BlockMoveData(info
, catalogInfo
.finderInfo
, sizeof(FinderInfo
)); 
1150         if ( NULL 
!= extendedInfo 
) 
1152                 /* set ExtendedFinderInfo */ 
1153                 whichInfo 
|= kFSCatInfoFinderXInfo
; 
1154                 BlockMoveData(extendedInfo
, catalogInfo
.extFinderInfo
, sizeof(ExtendedFinderInfo
)); 
1157         result 
= FSSetCatalogInfo(ref
, whichInfo
, &catalogInfo
); 
1158         require_noerr(result
, FSGetCatalogInfo
); 
1165 /*****************************************************************************/ 
1168 FSChangeCreatorType( 
1174         FSCatalogInfo   catalogInfo
; 
1177         /* get nodeFlags, finder info, and parent FSRef */ 
1178         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags 
+ kFSCatInfoFinderInfo
, &catalogInfo 
, NULL
, NULL
, &parentRef
); 
1179         require_noerr(result
, FSGetCatalogInfo
); 
1181         /* make sure FSRef was to a file */ 
1182         require_action(0 == (catalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
), FSRefNotFile
, result 
= notAFileErr
); 
1184         /* If fileType not 0x00000000, change fileType */ 
1185         if ( fileType 
!= (OSType
)0x00000000 ) 
1187                 ((FileInfo 
*)&catalogInfo
.finderInfo
)->fileType 
= fileType
; 
1190         /* If creator not 0x00000000, change creator */ 
1191         if ( fileCreator 
!= (OSType
)0x00000000 ) 
1193                 ((FileInfo 
*)&catalogInfo
.finderInfo
)->fileCreator 
= fileCreator
; 
1196         /* now, save the new information back to disk */ 
1197         result 
= FSSetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
); 
1198         require_noerr(result
, FSSetCatalogInfo
); 
1200         /* and attempt to bump the parent directory's mod date to wake up */ 
1201         /* the Finder to the change we just made (ignore errors from this) */ 
1202         verify_noerr(FSBumpDate(&parentRef
)); 
1211 /*****************************************************************************/ 
1214 FSChangeFinderFlags( 
1220         FSCatalogInfo   catalogInfo
; 
1223         /* get the current finderInfo */ 
1224         result 
= FSGetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
, NULL
, NULL
, &parentRef
); 
1225         require_noerr(result
, FSGetCatalogInfo
); 
1227         /* set or clear the appropriate bits in the finderInfo.finderFlags */ 
1230                 /* OR in the bits */ 
1231                 ((FileInfo 
*)&catalogInfo
.finderInfo
)->finderFlags 
|= flagBits
; 
1235                 /* AND out the bits */ 
1236                 ((FileInfo 
*)&catalogInfo
.finderInfo
)->finderFlags 
&= ~flagBits
; 
1239         /* save the modified finderInfo */ 
1240         result 
= FSSetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
); 
1241         require_noerr(result
, FSSetCatalogInfo
); 
1243         /* and attempt to bump the parent directory's mod date to wake up the Finder */ 
1244         /* to the change we just made (ignore errors from this) */ 
1245         verify_noerr(FSBumpDate(&parentRef
)); 
1253 /*****************************************************************************/ 
1259         return ( FSChangeFinderFlags(ref
, true, kIsInvisible
) ); 
1266         return ( FSChangeFinderFlags(ref
, false, kIsInvisible
) ); 
1269 /*****************************************************************************/ 
1275         return ( FSChangeFinderFlags(ref
, true, kNameLocked
) ); 
1282         return ( FSChangeFinderFlags(ref
, false, kNameLocked
) ); 
1285 /*****************************************************************************/ 
1291         return ( FSChangeFinderFlags(ref
, true, kIsStationery
) ); 
1295 FSClearIsStationery( 
1298         return ( FSChangeFinderFlags(ref
, false, kIsStationery
) ); 
1301 /*****************************************************************************/ 
1307         return ( FSChangeFinderFlags(ref
, true, kHasCustomIcon
) ); 
1311 FSClearHasCustomIcon( 
1314         return ( FSChangeFinderFlags(ref
, false, kHasCustomIcon
) ); 
1317 /*****************************************************************************/ 
1320 FSClearHasBeenInited( 
1323         return ( FSChangeFinderFlags(ref
, false, kHasBeenInited
) ); 
1326 /*****************************************************************************/ 
1329 FSCopyFileMgrAttributes( 
1330         const FSRef 
*sourceRef
, 
1331         const FSRef 
*destinationRef
, 
1332         Boolean copyLockBit
) 
1335         FSCatalogInfo   catalogInfo
; 
1337         /* get the source information */ 
1338         result 
= FSGetCatalogInfo(sourceRef
, kFSCatInfoSettableInfo
, &catalogInfo
, NULL
, NULL
, NULL
); 
1339         require_noerr(result
, FSGetCatalogInfo
); 
1341         /* don't copy the hasBeenInited bit; clear it */ 
1342         ((FileInfo 
*)&catalogInfo
.finderInfo
)->finderFlags 
&= ~kHasBeenInited
; 
1344         /* should the locked bit be copied? */ 
1347                 /* no, make sure the locked bit is clear */ 
1348                 catalogInfo
.nodeFlags 
&= ~kFSNodeLockedMask
; 
1351         /* set the destination information */ 
1352         result 
= FSSetCatalogInfo(destinationRef
, kFSCatInfoSettableInfo
, &catalogInfo
); 
1353         require_noerr(result
, FSSetCatalogInfo
); 
1361 /*****************************************************************************/ 
1364 FSMoveRenameObjectUnicode( 
1366         const FSRef 
*destDirectory
, 
1367         UniCharCount nameLength
, 
1368         const UniChar 
*name
,                    /* can be NULL (no rename during move) */ 
1369         TextEncoding textEncodingHint
, 
1370         FSRef 
*newRef
)                                  /* if function fails along the way, newRef is final location of file */ 
1373         FSVolumeRefNum  vRefNum
; 
1374         FSCatalogInfo   catalogInfo
; 
1375         FSRef                   originalDirectory
; 
1376         TextEncoding    originalTextEncodingHint
; 
1377         HFSUniStr255    originalName
; 
1378         HFSUniStr255    uniqueName
;             /* unique name given to object while moving it to destination */ 
1379         long                    theSeed
;                /* the seed for generating unique names */ 
1381         /* check parameters */ 
1382         require_action(NULL 
!= newRef
, BadParameter
, result 
= paramErr
); 
1384         /* newRef = input to start with */ 
1385         BlockMoveData(ref
, newRef
, sizeof(FSRef
)); 
1387         /* get destDirectory's vRefNum */ 
1388         result 
= FSGetCatalogInfo(destDirectory
, kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
, NULL
); 
1389         require_noerr(result
, DestinationBad
); 
1392         vRefNum 
= catalogInfo
.volume
; 
1394         /* get ref's vRefNum, TextEncoding, name and parent directory*/ 
1395         result 
= FSGetCatalogInfo(ref
, kFSCatInfoTextEncoding 
+ kFSCatInfoVolume
, &catalogInfo
, &originalName
, NULL
, &originalDirectory
); 
1396         require_noerr(result
, SourceBad
); 
1398         /* save TextEncoding */ 
1399         originalTextEncodingHint 
= catalogInfo
.textEncodingHint
; 
1401         /* make sure ref and destDirectory are on same volume */ 
1402         require_action(vRefNum 
== catalogInfo
.volume
, NotSameVolume
, result 
= diffVolErr
); 
1404         /* Skip a few steps if we're not renaming */ 
1407                 /* generate a name that is unique in both directories */ 
1408                 theSeed 
= 0x4a696d4c;   /* a fine unlikely filename */ 
1410                 result 
= GenerateUniqueHFSUniStr(&theSeed
, &originalDirectory
, destDirectory
, &uniqueName
); 
1411                 require_noerr(result
, GenerateUniqueHFSUniStrFailed
); 
1413                 /* Rename the object to uniqueName */ 
1414                 result 
= FSRenameUnicode(ref
, uniqueName
.length
, uniqueName
.unicode
, kTextEncodingUnknown
, newRef
); 
1415                 require_noerr(result
, FSRenameUnicodeBeforeMoveFailed
); 
1417                 /* Move object to its new home */ 
1418                 result 
= FSMoveObject(newRef
, destDirectory
, newRef
); 
1419                 require_noerr(result
, FSMoveObjectAfterRenameFailed
); 
1421                 /* Rename the object to new name */ 
1422                 result 
= FSRenameUnicode(ref
, nameLength
, name
, textEncodingHint
, newRef
); 
1423                 require_noerr(result
, FSRenameUnicodeAfterMoveFailed
); 
1427                 /* Move object to its new home */ 
1428                 result 
= FSMoveObject(newRef
, destDirectory
, newRef
); 
1429                 require_noerr(result
, FSMoveObjectNoRenameFailed
); 
1437  * failure handling code when renaming 
1440 FSRenameUnicodeAfterMoveFailed
: 
1442         /* Error handling: move object back to original location - ignore errors */ 
1443         verify_noerr(FSMoveObject(newRef
, &originalDirectory
, newRef
)); 
1445 FSMoveObjectAfterRenameFailed
: 
1447         /* Error handling: rename object back to original name - ignore errors */ 
1448         verify_noerr(FSRenameUnicode(newRef
, originalName
.length
, originalName
.unicode
, originalTextEncodingHint
, newRef
)); 
1450 FSRenameUnicodeBeforeMoveFailed
: 
1451 GenerateUniqueHFSUniStrFailed
: 
1454  * failure handling code for renaming or not 
1456 FSMoveObjectNoRenameFailed
: 
1465 /*****************************************************************************/ 
1468         The FSDeleteContainerLevel function deletes the contents of a container 
1469         directory. All files and subdirectories in the specified container are 
1470         deleted. If a locked file or directory is encountered, it is unlocked 
1471         and then deleted. If any unexpected errors are encountered, 
1472         FSDeleteContainerLevel quits and returns to the caller. 
1474         container                       --> FSRef to a directory. 
1475         theGlobals                      --> A pointer to a FSDeleteContainerGlobals struct 
1476                                                         which contains the variables that do not need to 
1477                                                         be allocated each time FSDeleteContainerLevel 
1478                                                         recurses. That lets FSDeleteContainerLevel use 
1479                                                         less stack space per recursion level. 
1484 FSDeleteContainerLevel( 
1485         const FSRef 
*container
, 
1486         FSDeleteContainerGlobals 
*theGlobals
) 
1489         FSIterator                                      iterator
; 
1493         /* Open FSIterator for flat access and give delete optimization hint */ 
1494         theGlobals
->result 
= FSOpenIterator(container
, kFSIterateFlat 
+ kFSIterateDelete
, &iterator
); 
1495         require_noerr(theGlobals
->result
, FSOpenIterator
); 
1497         /* delete the contents of the directory */ 
1500                 /* get 1 item to delete */ 
1501                 theGlobals
->result 
= FSGetCatalogInfoBulk(iterator
, 1, &theGlobals
->actualObjects
, 
1502                                                                 NULL
, kFSCatInfoNodeFlags
, &theGlobals
->catalogInfo
, 
1503                                                                 &itemToDelete
, NULL
, NULL
); 
1504                 if ( (noErr 
== theGlobals
->result
) && (1 == theGlobals
->actualObjects
) ) 
1506                         /* save node flags in local in case we have to recurse */ 
1507                         nodeFlags 
= theGlobals
->catalogInfo
.nodeFlags
; 
1509                         /* is it a file or directory? */ 
1510                         if ( 0 != (nodeFlags 
& kFSNodeIsDirectoryMask
) ) 
1512                                 /* it's a directory -- delete its contents before attempting to delete it */ 
1513                                 FSDeleteContainerLevel(&itemToDelete
, theGlobals
); 
1515                         /* are we still OK to delete? */ 
1516                         if ( noErr 
== theGlobals
->result 
) 
1518                                 /* is item locked? */ 
1519                                 if ( 0 != (nodeFlags 
& kFSNodeLockedMask
) ) 
1521                                         /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */ 
1522                                         theGlobals
->catalogInfo
.nodeFlags 
= nodeFlags 
& ~kFSNodeLockedMask
; 
1523                                         (void) FSSetCatalogInfo(&itemToDelete
, kFSCatInfoNodeFlags
, &theGlobals
->catalogInfo
); 
1525                                 /* delete the item */ 
1526                                 theGlobals
->result 
= FSDeleteObject(&itemToDelete
); 
1529         } while ( noErr 
== theGlobals
->result 
); 
1531         /* we found the end of the items normally, so return noErr */ 
1532         if ( errFSNoMoreItems 
== theGlobals
->result 
) 
1534                 theGlobals
->result 
= noErr
; 
1537         /* close the FSIterator (closing an open iterator should never fail) */ 
1538         verify_noerr(FSCloseIterator(iterator
)); 
1545 /*****************************************************************************/ 
1548 FSDeleteContainerContents( 
1549         const FSRef 
*container
) 
1551         FSDeleteContainerGlobals        theGlobals
; 
1553         /* delete container's contents */ 
1554         FSDeleteContainerLevel(container
, &theGlobals
); 
1556         return ( theGlobals
.result 
); 
1559 /*****************************************************************************/ 
1563         const FSRef 
*container
) 
1566         FSCatalogInfo   catalogInfo
; 
1568         /* get nodeFlags for container */ 
1569         result 
= FSGetCatalogInfo(container
, kFSCatInfoNodeFlags
, &catalogInfo
, NULL
, NULL
,NULL
); 
1570         require_noerr(result
, FSGetCatalogInfo
); 
1572         /* make sure container is a directory */ 
1573         require_action(0 != (catalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
), ContainerNotDirectory
, result 
= dirNFErr
); 
1575         /* delete container's contents */ 
1576         result 
= FSDeleteContainerContents(container
); 
1577         require_noerr(result
, FSDeleteContainerContents
); 
1579         /* is container locked? */ 
1580         if ( 0 != (catalogInfo
.nodeFlags 
& kFSNodeLockedMask
) ) 
1582                 /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */ 
1583                 catalogInfo
.nodeFlags 
&= ~kFSNodeLockedMask
; 
1584                 (void) FSSetCatalogInfo(container
, kFSCatInfoNodeFlags
, &catalogInfo
); 
1587         /* delete the container */ 
1588         result 
= FSDeleteObject(container
); 
1590 FSDeleteContainerContents
: 
1591 ContainerNotDirectory
: 
1597 /*****************************************************************************/ 
1600         The FSIterateContainerLevel function iterates the contents of a container 
1601         directory and calls a IterateContainerFilterProc function once for each 
1602         file and directory found. 
1604         theGlobals                      --> A pointer to a FSIterateContainerGlobals struct 
1605                                                         which contains the variables needed globally by 
1606                                                         all recusion levels of FSIterateContainerLevel. 
1607                                                         That makes FSIterateContainer thread safe since 
1608                                                         each call to it uses its own global world. 
1609                                                         It also contains the variables that do not need 
1610                                                         to be allocated each time FSIterateContainerLevel 
1611                                                         recurses. That lets FSIterateContainerLevel use 
1612                                                         less stack space per recursion level. 
1617 FSIterateContainerLevel( 
1618         FSIterateContainerGlobals 
*theGlobals
) 
1620         FSIterator      iterator
; 
1622         /* If maxLevels is zero, we aren't checking levels */ 
1623         /* If currentLevel < maxLevels, look at this level */ 
1624         if ( (theGlobals
->maxLevels 
== 0) || 
1625                  (theGlobals
->currentLevel 
< theGlobals
->maxLevels
) ) 
1627                 /* Open FSIterator for flat access to theGlobals->ref */ 
1628                 theGlobals
->result 
= FSOpenIterator(&theGlobals
->ref
, kFSIterateFlat
, &iterator
); 
1629                 require_noerr(theGlobals
->result
, FSOpenIterator
); 
1631                 ++theGlobals
->currentLevel
; /* Go to next level */ 
1633                 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */ 
1636                         theGlobals
->result 
= FSGetCatalogInfoBulk(iterator
, 1, &theGlobals
->actualObjects
, 
1637                                 &theGlobals
->containerChanged
, theGlobals
->whichInfo
, &theGlobals
->catalogInfo
, 
1638                                 &theGlobals
->ref
, theGlobals
->specPtr
, theGlobals
->namePtr
); 
1639                         if ( (noErr 
== theGlobals
->result 
|| errFSNoMoreItems 
== theGlobals
->result
) && 
1640                                 (0 != theGlobals
->actualObjects
) ) 
1642                                 /* Call the IterateFilterProc */ 
1643                                 theGlobals
->quitFlag 
= CallIterateContainerFilterProc(theGlobals
->iterateFilter
, 
1644                                         theGlobals
->containerChanged
, theGlobals
->currentLevel
, 
1645                                         &theGlobals
->catalogInfo
, &theGlobals
->ref
, 
1646                                         theGlobals
->specPtr
, theGlobals
->namePtr
, theGlobals
->yourDataPtr
); 
1647                                 /* Is it a directory? */ 
1648                                 if ( 0 != (theGlobals
->catalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
) ) 
1651                                         if ( !theGlobals
->quitFlag 
) 
1653                                                 /* Dive again if the IterateFilterProc didn't say "quit" */ 
1654                                                 FSIterateContainerLevel(theGlobals
); 
1658                         /* time to fall back a level? */ 
1659                 } while ( (noErr 
== theGlobals
->result
) && (!theGlobals
->quitFlag
) ); 
1661                 /* errFSNoMoreItems is OK - it only means we hit the end of this level */ 
1662                 /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */ 
1663                 if ( (errFSNoMoreItems 
== theGlobals
->result
) || 
1664                          (afpAccessDenied 
== theGlobals
->result
) ) 
1666                         theGlobals
->result 
= noErr
; 
1669                 --theGlobals
->currentLevel
; /* Return to previous level as we leave */ 
1671                 /* Close the FSIterator (closing an open iterator should never fail) */ 
1672                 verify_noerr(FSCloseIterator(iterator
)); 
1680 /*****************************************************************************/ 
1684         const FSRef 
*container
, 
1685         ItemCount maxLevels
, 
1686         FSCatalogInfoBitmap whichInfo
, 
1689         IterateContainerFilterProcPtr iterateFilter
, 
1693         FSIterateContainerGlobals       theGlobals
; 
1695         /* make sure there is an iterateFilter */ 
1696         require_action(iterateFilter 
!= NULL
, NoIterateFilter
, result 
= paramErr
); 
1699          * set up the globals we need to access from the recursive routine 
1701         theGlobals
.iterateFilter 
= iterateFilter
; 
1702         /* we need the node flags no matter what was requested so we can detect files vs. directories */ 
1703         theGlobals
.whichInfo 
= whichInfo 
| kFSCatInfoNodeFlags
; 
1704         /* start with input container -- the first OpenIterator will ensure it is a directory */ 
1705         theGlobals
.ref 
= *container
; 
1708                 theGlobals
.specPtr 
= &theGlobals
.spec
; 
1712                 theGlobals
.specPtr 
= NULL
; 
1716                 theGlobals
.namePtr 
= &theGlobals
.name
; 
1720                 theGlobals
.namePtr 
= NULL
; 
1722         theGlobals
.yourDataPtr 
= yourDataPtr
; 
1723         theGlobals
.maxLevels 
= maxLevels
; 
1724         theGlobals
.currentLevel 
= 0; 
1725         theGlobals
.quitFlag 
= false; 
1726         theGlobals
.containerChanged 
= false; 
1727         theGlobals
.result 
= noErr
; 
1728         theGlobals
.actualObjects 
= 0; 
1730         /* here we go into recursion land... */ 
1731         FSIterateContainerLevel(&theGlobals
); 
1732         result 
= theGlobals
.result
; 
1733         require_noerr(result
, FSIterateContainerLevel
); 
1735 FSIterateContainerLevel
: 
1741 /*****************************************************************************/ 
1744 FSGetDirectoryItems( 
1745         const FSRef 
*container
, 
1746         FSRef 
***refsHandle
,    /* pointer to handle of FSRefs */ 
1748         Boolean 
*containerChanged
) 
1750         /* Grab items 10 at a time. */ 
1751         enum { kMaxItemsPerBulkCall 
= 10 }; 
1755         FSIterator      iterator
; 
1756         FSRef           refs
[kMaxItemsPerBulkCall
]; 
1757         ItemCount       actualObjects
; 
1760         /* check parameters */ 
1761         require_action((NULL 
!= refsHandle
) && (NULL 
!= numRefs
) && (NULL 
!= containerChanged
), 
1762                 BadParameter
, result 
= paramErr
); 
1765         *containerChanged 
= false; 
1766         *refsHandle 
= (FSRef 
**)NewHandle(0); 
1767         require_action(NULL 
!= *refsHandle
, NewHandle
, result 
= memFullErr
); 
1769         /* open an FSIterator */ 
1770         result 
= FSOpenIterator(container
, kFSIterateFlat
, &iterator
); 
1771         require_noerr(result
, FSOpenIterator
); 
1773         /* Call FSGetCatalogInfoBulk in loop to get all items in the container */ 
1776                 result 
= FSGetCatalogInfoBulk(iterator
, kMaxItemsPerBulkCall
, &actualObjects
, 
1777                                         &changed
, kFSCatInfoNone
,  NULL
,  refs
, NULL
, NULL
); 
1779                 /* if the container changed, set containerChanged for output, but keep going */ 
1782                         *containerChanged 
= changed
; 
1785                 /* any result other than noErr and errFSNoMoreItems is serious */ 
1786                 require((noErr 
== result
) || (errFSNoMoreItems 
== result
), FSGetCatalogInfoBulk
); 
1788                 /* add objects to output array and count */ 
1789                 if ( 0 != actualObjects 
) 
1791                         /* concatenate the FSRefs to the end of the      handle */ 
1792                         PtrAndHand(refs
, (Handle
)*refsHandle
, actualObjects 
* sizeof(FSRef
)); 
1793                         memResult 
= MemError(); 
1794                         require_noerr_action(memResult
, MemoryAllocationFailed
, result 
= memResult
); 
1796                         *numRefs 
+= actualObjects
; 
1798         } while ( noErr 
== result 
); 
1800         verify_noerr(FSCloseIterator(iterator
)); /* closing an open iterator should never fail, but... */ 
1804         /**********************/ 
1806 MemoryAllocationFailed
: 
1807 FSGetCatalogInfoBulk
: 
1809         /* close the iterator */ 
1810         verify_noerr(FSCloseIterator(iterator
)); 
1813         /* dispose of handle if already allocated and clear the outputs */ 
1814         if ( NULL 
!= *refsHandle 
) 
1816                 DisposeHandle((Handle
)*refsHandle
); 
1827 /*****************************************************************************/ 
1830         The GenerateUniqueName function generates a HFSUniStr255 name that is 
1831         unique in both dir1 and dir2. 
1833         startSeed                       -->     A pointer to a long which is used to generate the 
1835                                                 <--     It is modified on output to a value which should 
1836                                                         be used to generate the next unique name. 
1837         dir1                            -->     The first directory. 
1838         dir2                            -->     The second directory. 
1839         uniqueName                      <--     A pointer to a HFSUniStr255 where the unique name 
1845 GenerateUniqueHFSUniStr( 
1849         HFSUniStr255 
*uniqueName
) 
1855         unsigned char   hexStr
[17] = "0123456789ABCDEF"; 
1857         /* set up the parameter block */ 
1858         pb
.name 
= uniqueName
->unicode
; 
1859         pb
.nameLength 
= 8;      /* always 8 characters */ 
1860         pb
.textEncodingHint 
= kTextEncodingUnknown
; 
1861         pb
.newRef 
= &newRef
; 
1863         /* loop until we get fnfErr with a filename in both directories */ 
1865         while ( fnfErr 
!= result 
) 
1867                 /* convert startSeed to 8 character Unicode string */ 
1868                 uniqueName
->length 
= 8; 
1869                 for ( i 
= 0; i 
< 8; ++i 
) 
1871                         uniqueName
->unicode
[i
] = hexStr
[((*startSeed 
>> ((7-i
)*4)) & 0xf)]; 
1876                 result 
= PBMakeFSRefUnicodeSync(&pb
); 
1877                 if ( fnfErr 
== result 
) 
1881                         result 
= PBMakeFSRefUnicodeSync(&pb
); 
1882                         if ( fnfErr 
!= result 
) 
1884                                 /* exit if anything other than noErr or fnfErr */ 
1885                                 require_noerr(result
, Dir2PBMakeFSRefUnicodeSyncFailed
); 
1890                         /* exit if anything other than noErr or fnfErr */ 
1891                         require_noerr(result
, Dir1PBMakeFSRefUnicodeSyncFailed
); 
1894                 /* increment seed for next pass through loop, */ 
1895                 /* or for next call to GenerateUniqueHFSUniStr */ 
1899         /* we have a unique file name which doesn't exist in dir1 or dir2 */ 
1902 Dir2PBMakeFSRefUnicodeSyncFailed
: 
1903 Dir1PBMakeFSRefUnicodeSyncFailed
: 
1908 /*****************************************************************************/ 
1911 FSExchangeObjectsCompat( 
1912         const FSRef 
*sourceRef
, 
1913         const FSRef 
*destRef
, 
1914         FSRef 
*newSourceRef
, 
1919                 /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */ 
1920                 kGetCatInformationMask 
= (kFSCatInfoSettableInfo 
| 
1922                                                                   kFSCatInfoParentDirID
) & 
1923                                                                  ~(kFSCatInfoContentMod 
| kFSCatInfoAttrMod
), 
1924                 /* set everything possible except for mod dates */ 
1925                 kSetCatinformationMask 
= kFSCatInfoSettableInfo 
& 
1926                                                                  ~(kFSCatInfoContentMod 
| kFSCatInfoAttrMod
) 
1930         GetVolParmsInfoBuffer   volParmsInfo
; 
1932         FSCatalogInfo                   sourceCatalogInfo
;      /* source file's catalog information */ 
1933         FSCatalogInfo                   destCatalogInfo
;        /* destination file's catalog information */ 
1934         HFSUniStr255                    sourceName
;                     /* source file's Unicode name */ 
1935         HFSUniStr255                    destName
;                       /* destination file's Unicode name */ 
1936         FSRef                                   sourceCurrentRef
;       /* FSRef to current location of source file throughout this function */ 
1937         FSRef                                   destCurrentRef
;         /* FSRef to current location of destination file throughout this function */ 
1938         FSRef                                   sourceParentRef
;        /* FSRef to parent directory of source file */ 
1939         FSRef                                   destParentRef
;          /* FSRef to parent directory of destination file */ 
1940         HFSUniStr255                    sourceUniqueName
;       /* unique name given to source file while exchanging it with destination */ 
1941         HFSUniStr255                    destUniqueName
;         /* unique name given to destination file while exchanging it with source */ 
1942         long                                    theSeed
;                        /* the seed for generating unique names */ 
1943         Boolean                                 sameParentDirs
;         /* true if source and destinatin parent directory is the same */ 
1945         /* check parameters */ 
1946         require_action((NULL 
!= newSourceRef
) && (NULL 
!= newDestRef
), BadParameter
, result 
= paramErr
); 
1948         /* output refs and current refs = input refs to start with */ 
1949         BlockMoveData(sourceRef
, newSourceRef
, sizeof(FSRef
)); 
1950         BlockMoveData(sourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
1952         BlockMoveData(destRef
, newDestRef
, sizeof(FSRef
)); 
1953         BlockMoveData(destRef
, &destCurrentRef
, sizeof(FSRef
)); 
1955         /* get source volume's vRefNum */ 
1956         result 
= FSGetCatalogInfo(&sourceCurrentRef
, kFSCatInfoVolume
, &sourceCatalogInfo
, NULL
, NULL
, NULL
); 
1957         require_noerr(result
, DetermineSourceVRefNumFailed
); 
1959         /* see if that volume supports FSExchangeObjects */ 
1960         result 
= FSGetVolParms(sourceCatalogInfo
.volume
, sizeof(GetVolParmsInfoBuffer
), 
1961                 &volParmsInfo
, &infoSize
); 
1962         if ( (noErr 
== result
) && VolSupportsFSExchangeObjects(&volParmsInfo
) ) 
1964                 /* yes - use FSExchangeObjects */ 
1965                 result 
= FSExchangeObjects(sourceRef
, destRef
); 
1969                 /* no - emulate FSExchangeObjects */ 
1971                 /* Note: The compatibility case won't work for files with *Btree control blocks. */ 
1972                 /* Right now the only *Btree files are created by the system. */ 
1974                 /* get all catalog information and Unicode names for each file */ 
1975                 result 
= FSGetCatalogInfo(&sourceCurrentRef
, kGetCatInformationMask
, &sourceCatalogInfo
, &sourceName
, NULL
, &sourceParentRef
); 
1976                 require_noerr(result
, SourceFSGetCatalogInfoFailed
); 
1978                 result 
= FSGetCatalogInfo(&destCurrentRef
, kGetCatInformationMask
, &destCatalogInfo
, &destName
, NULL
, &destParentRef
); 
1979                 require_noerr(result
, DestFSGetCatalogInfoFailed
); 
1981                 /* make sure source and destination are on same volume */ 
1982                 require_action(sourceCatalogInfo
.volume 
== destCatalogInfo
.volume
, NotSameVolume
, result 
= diffVolErr
); 
1984                 /* make sure both files are *really* files */ 
1985                 require_action((0 == (sourceCatalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
)) && 
1986                                            (0 == (destCatalogInfo
.nodeFlags 
& kFSNodeIsDirectoryMask
)), NotAFile
, result 
= notAFileErr
); 
1988                 /* generate 2 names that are unique in both directories */ 
1989                 theSeed 
= 0x4a696d4c;   /* a fine unlikely filename */ 
1991                 result 
= GenerateUniqueHFSUniStr(&theSeed
, &sourceParentRef
, &destParentRef
, &sourceUniqueName
); 
1992                 require_noerr(result
, GenerateUniqueHFSUniStr1Failed
); 
1994                 result 
= GenerateUniqueHFSUniStr(&theSeed
, &sourceParentRef
, &destParentRef
, &destUniqueName
); 
1995                 require_noerr(result
, GenerateUniqueHFSUniStr2Failed
); 
1997                 /* rename sourceCurrentRef to sourceUniqueName */ 
1998                 result 
= FSRenameUnicode(&sourceCurrentRef
, sourceUniqueName
.length
, sourceUniqueName
.unicode
, kTextEncodingUnknown
, newSourceRef
); 
1999                 require_noerr(result
, FSRenameUnicode1Failed
); 
2000                 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
2002                 /* rename destCurrentRef to destUniqueName */ 
2003                 result 
= FSRenameUnicode(&destCurrentRef
, destUniqueName
.length
, destUniqueName
.unicode
, kTextEncodingUnknown
, newDestRef
); 
2004                 require_noerr(result
, FSRenameUnicode2Failed
); 
2005                 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
)); 
2007                 /* are the source and destination parent directories the same? */ 
2008                 sameParentDirs 
= ( sourceCatalogInfo
.parentDirID 
== destCatalogInfo
.parentDirID 
); 
2009                 if ( !sameParentDirs 
) 
2011                         /* move source file to dest parent directory */ 
2012                         result 
= FSMoveObject(&sourceCurrentRef
, &destParentRef
, newSourceRef
); 
2013                         require_noerr(result
, FSMoveObject1Failed
); 
2014                         BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
2016                         /* move dest file to source parent directory */ 
2017                         result 
= FSMoveObject(&destCurrentRef
, &sourceParentRef
, newDestRef
); 
2018                         require_noerr(result
, FSMoveObject2Failed
); 
2019                         BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
)); 
2022                 /* At this point, the files are in their new locations (if they were moved). */ 
2023                 /* The source file is named sourceUniqueName and is in the directory referred to */ 
2024                 /* by destParentRef. The destination file is named destUniqueName and is in the */ 
2025                 /* directory referred to by sourceParentRef. */ 
2027                 /* give source file the dest file's catalog information except for mod dates */ 
2028                 result 
= FSSetCatalogInfo(&sourceCurrentRef
, kSetCatinformationMask
, &destCatalogInfo
); 
2029                 require_noerr(result
, FSSetCatalogInfo1Failed
); 
2031                 /* give dest file the source file's catalog information except for mod dates */ 
2032                 result 
= FSSetCatalogInfo(&destCurrentRef
, kSetCatinformationMask
, &sourceCatalogInfo
); 
2033                 require_noerr(result
, FSSetCatalogInfo2Failed
); 
2035                 /* rename source file with dest file's name */ 
2036                 result 
= FSRenameUnicode(&sourceCurrentRef
, destName
.length
, destName
.unicode
, destCatalogInfo
.textEncodingHint
, newSourceRef
); 
2037                 require_noerr(result
, FSRenameUnicode3Failed
); 
2038                 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
2040                 /* rename dest file with source file's name */ 
2041                 result 
= FSRenameUnicode(&destCurrentRef
, sourceName
.length
, sourceName
.unicode
, sourceCatalogInfo
.textEncodingHint
, newDestRef
); 
2042                 require_noerr(result
, FSRenameUnicode4Failed
); 
2044                 /* we're done with no errors, so swap newSourceRef and newDestRef */ 
2045                 BlockMoveData(newDestRef
, newSourceRef
, sizeof(FSRef
)); 
2046                 BlockMoveData(&sourceCurrentRef
, newDestRef
, sizeof(FSRef
)); 
2051         /**********************/ 
2053 /* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */ 
2054 /* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */ 
2055 /* state and location they ended up in so that both files can be found by the calling code. */ 
2057 FSRenameUnicode4Failed
: 
2059         /* attempt to rename source file to sourceUniqueName */ 
2060         if ( noErr 
== FSRenameUnicode(&sourceCurrentRef
, sourceUniqueName
.length
, sourceUniqueName
.unicode
, kTextEncodingUnknown
, newSourceRef
) ) 
2062                 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
2065 FSRenameUnicode3Failed
: 
2067         /* attempt to restore dest file's catalog information */ 
2068         verify_noerr(FSSetCatalogInfo(&destCurrentRef
, kFSCatInfoSettableInfo
, &destCatalogInfo
)); 
2070 FSSetCatalogInfo2Failed
: 
2072         /* attempt to restore source file's catalog information */ 
2073         verify_noerr(FSSetCatalogInfo(&sourceCurrentRef
, kFSCatInfoSettableInfo
, &sourceCatalogInfo
)); 
2075 FSSetCatalogInfo1Failed
: 
2077         if ( !sameParentDirs 
) 
2079                 /* attempt to move dest file back to dest directory */ 
2080                 if ( noErr 
== FSMoveObject(&destCurrentRef
, &destParentRef
, newDestRef
) ) 
2082                         BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
)); 
2086 FSMoveObject2Failed
: 
2088         if ( !sameParentDirs 
) 
2090                 /* attempt to move source file back to source directory */ 
2091                 if ( noErr 
== FSMoveObject(&sourceCurrentRef
, &sourceParentRef
, newSourceRef
) ) 
2093                         BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
)); 
2097 FSMoveObject1Failed
: 
2099         /* attempt to rename dest file to original name */ 
2100         verify_noerr(FSRenameUnicode(&destCurrentRef
, destName
.length
, destName
.unicode
, destCatalogInfo
.textEncodingHint
, newDestRef
)); 
2102 FSRenameUnicode2Failed
: 
2104         /* attempt to rename source file to original name */ 
2105         verify_noerr(FSRenameUnicode(&sourceCurrentRef
, sourceName
.length
, sourceName
.unicode
, sourceCatalogInfo
.textEncodingHint
, newSourceRef
)); 
2107 FSRenameUnicode1Failed
: 
2108 GenerateUniqueHFSUniStr2Failed
: 
2109 GenerateUniqueHFSUniStr1Failed
: 
2112 DestFSGetCatalogInfoFailed
: 
2113 SourceFSGetCatalogInfoFailed
: 
2114 DetermineSourceVRefNumFailed
:    
2120 /*****************************************************************************/ 
2122 #pragma mark ----- Shared Environment Routines ----- 
2124 /*****************************************************************************/ 
2135         pb
.ioParam
.ioRefNum 
= refNum
; 
2136         pb
.ioParam
.ioReqCount 
= rangeLength
; 
2137         pb
.ioParam
.ioPosMode 
= fsFromStart
; 
2138         pb
.ioParam
.ioPosOffset 
= rangeStart
; 
2139         result 
= PBLockRangeSync(&pb
); 
2140         require_noerr(result
, PBLockRangeSync
); 
2147 /*****************************************************************************/ 
2158         pb
.ioParam
.ioRefNum 
= refNum
; 
2159         pb
.ioParam
.ioReqCount 
= rangeLength
; 
2160         pb
.ioParam
.ioPosMode 
= fsFromStart
; 
2161         pb
.ioParam
.ioPosOffset 
= rangeStart
; 
2162         result 
= PBUnlockRangeSync(&pb
); 
2163         require_noerr(result
, PBUnlockRangeSync
); 
2170 /*****************************************************************************/ 
2175         SInt32 
*ownerID
,                /* can be NULL */ 
2176         SInt32 
*groupID
,                /* can be NULL */ 
2177         SInt32 
*accessRights
)   /* can be NULL */ 
2183         /* get FSSpec from FSRef */ 
2184         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
); 
2185         require_noerr(result
, FSGetCatalogInfo
); 
2187         /* get directory access info for FSSpec */ 
2188         pb
.accessParam
.ioNamePtr 
= (StringPtr
)spec
.name
; 
2189         pb
.accessParam
.ioVRefNum 
= spec
.vRefNum
; 
2190         pb
.fileParam
.ioDirID 
= spec
.parID
; 
2191         result 
= PBHGetDirAccessSync(&pb
); 
2192         require_noerr(result
, PBHGetDirAccessSync
); 
2194         /* return the IDs and access rights */ 
2195         if ( NULL 
!= ownerID 
) 
2197                 *ownerID 
= pb
.accessParam
.ioACOwnerID
; 
2199         if ( NULL 
!= groupID 
) 
2201                 *groupID 
= pb
.accessParam
.ioACGroupID
; 
2203         if ( NULL 
!= accessRights 
) 
2205                 *accessRights 
= pb
.accessParam
.ioACAccess
; 
2208 PBHGetDirAccessSync
: 
2214 /*****************************************************************************/ 
2221         SInt32 accessRights
) 
2229                 /* Just the bits that can be set */ 
2230                 kSetDirAccessSettableMask 
= (kioACAccessBlankAccessMask 
+ 
2231                         kioACAccessEveryoneWriteMask 
+ kioACAccessEveryoneReadMask 
+ kioACAccessEveryoneSearchMask 
+ 
2232                         kioACAccessGroupWriteMask 
+ kioACAccessGroupReadMask 
+ kioACAccessGroupSearchMask 
+ 
2233                         kioACAccessOwnerWriteMask 
+ kioACAccessOwnerReadMask 
+ kioACAccessOwnerSearchMask
) 
2236         /* get FSSpec from FSRef */ 
2237         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
); 
2238         require_noerr(result
, FSGetCatalogInfo
); 
2240         /* set directory access info for FSSpec */ 
2241         pb
.accessParam
.ioNamePtr 
= (StringPtr
)spec
.name
; 
2242         pb
.accessParam
.ioVRefNum 
= spec
.vRefNum
; 
2243         pb
.fileParam
.ioDirID 
= spec
.parID
; 
2244         pb
.accessParam
.ioACOwnerID 
= ownerID
; 
2245         pb
.accessParam
.ioACGroupID 
= groupID
; 
2246         pb
.accessParam
.ioACAccess 
= accessRights 
& kSetDirAccessSettableMask
; 
2247         result 
= PBHSetDirAccessSync(&pb
); 
2248         require_noerr(result
, PBHSetDirAccessSync
); 
2250 PBHSetDirAccessSync
: 
2256 /*****************************************************************************/ 
2259 FSGetVolMountInfoSize( 
2260         FSVolumeRefNum volRefNum
, 
2266         /* check parameters */ 
2267         require_action(NULL 
!= size
, BadParameter
, result 
= paramErr
); 
2269         pb
.ioParam
.ioNamePtr 
= NULL
; 
2270         pb
.ioParam
.ioVRefNum 
= volRefNum
; 
2271         pb
.ioParam
.ioBuffer 
= (Ptr
)size
; 
2272         result 
= PBGetVolMountInfoSize(&pb
); 
2273         require_noerr(result
, PBGetVolMountInfoSize
); 
2275 PBGetVolMountInfoSize
: 
2281 /*****************************************************************************/ 
2285         FSVolumeRefNum volRefNum
, 
2291         /* check parameters */ 
2292         require_action(NULL 
!= volMountInfo
, BadParameter
, result 
= paramErr
); 
2294         pb
.ioParam
.ioNamePtr 
= NULL
; 
2295         pb
.ioParam
.ioVRefNum 
= volRefNum
; 
2296         pb
.ioParam
.ioBuffer 
= (Ptr
)volMountInfo
; 
2297         result 
= PBGetVolMountInfo(&pb
); 
2298         require_noerr(result
, PBGetVolMountInfo
); 
2306 /*****************************************************************************/ 
2310         const void *volMountInfo
, 
2311         FSVolumeRefNum 
*volRefNum
) 
2316         /* check parameters */ 
2317         require_action(NULL 
!= volRefNum
, BadParameter
, result 
= paramErr
); 
2319         pb
.ioParam
.ioBuffer 
= (Ptr
)volMountInfo
; 
2320         result 
= PBVolumeMount(&pb
); 
2321         require_noerr(result
, PBVolumeMount
); 
2323         /* return the volume reference number */ 
2324         *volRefNum 
= pb
.ioParam
.ioVRefNum
; 
2332 /*****************************************************************************/ 
2336         FSVolumeRefNum volRefNum
, 
2344         /* check parameters */ 
2345         require_action(NULL 
!= name
, BadParameter
, result 
= paramErr
); 
2347         pb
.objParam
.ioNamePtr 
= NULL
; 
2348         pb
.objParam
.ioVRefNum 
= volRefNum
; 
2349         pb
.objParam
.ioObjType 
= objType
; 
2350         pb
.objParam
.ioObjNamePtr 
= name
; 
2351         pb
.objParam
.ioObjID 
= ugID
; 
2352         result 
= PBHMapIDSync(&pb
); 
2353         require_noerr(result
, PBHMapIDSync
); 
2361 /*****************************************************************************/ 
2365         FSVolumeRefNum volRefNum
, 
2366         ConstStr255Param name
, 
2373         /* check parameters */ 
2374         require_action(NULL 
!= ugID
, BadParameter
, result 
= paramErr
); 
2376         pb
.objParam
.ioNamePtr 
= NULL
; 
2377         pb
.objParam
.ioVRefNum 
= volRefNum
; 
2378         pb
.objParam
.ioObjType 
= objType
; 
2379         pb
.objParam
.ioObjNamePtr 
= (StringPtr
)name
; 
2380         result 
= PBHMapNameSync(&pb
); 
2381         require_noerr(result
, PBHMapNameSync
); 
2383         /* return the user or group ID */ 
2384         *ugID 
= pb
.objParam
.ioObjID
; 
2392 /*****************************************************************************/ 
2396         const FSRef 
*srcFileRef
, 
2397         const FSRef 
*dstDirectoryRef
, 
2398         UniCharCount nameLength
, 
2399         const UniChar 
*copyName
,        /* can be NULL (no rename during copy) */ 
2400         TextEncoding textEncodingHint
, 
2401         FSRef 
*newRef
)                          /* can be NULL */ 
2405         FSCatalogInfo                   catalogInfo
; 
2408         GetVolParmsInfoBuffer   volParmsInfo
; 
2411         /* get source FSSpec from source FSRef */ 
2412         result 
= FSGetCatalogInfo(srcFileRef
, kFSCatInfoNone
, NULL
, NULL
, &srcFileSpec
, NULL
); 
2413         require_noerr(result
, FSGetCatalogInfo_srcFileRef
); 
2415         /* Make sure the volume supports CopyFile */ 
2416         result 
= FSGetVolParms(srcFileSpec
.vRefNum
, sizeof(GetVolParmsInfoBuffer
), 
2417                 &volParmsInfo
, &infoSize
); 
2418         require_action((noErr 
== result
) && VolHasCopyFile(&volParmsInfo
), 
2419                 NoCopyFileSupport
, result 
= paramErr
); 
2421         /* get destination volume reference number and destination directory ID from destination FSRef */ 
2422         result 
= FSGetCatalogInfo(dstDirectoryRef
, kFSCatInfoVolume 
+ kFSCatInfoNodeID
, 
2423                 &catalogInfo
, NULL
, NULL
, NULL
); 
2424         require_noerr(result
, FSGetCatalogInfo_dstDirectoryRef
); 
2426         /* tell the server to copy the object */ 
2427         pb
.copyParam
.ioVRefNum 
= srcFileSpec
.vRefNum
; 
2428         pb
.copyParam
.ioDirID 
= srcFileSpec
.parID
; 
2429         pb
.copyParam
.ioNamePtr 
= (StringPtr
)srcFileSpec
.name
; 
2430         pb
.copyParam
.ioDstVRefNum 
= catalogInfo
.volume
; 
2431         pb
.copyParam
.ioNewDirID 
= (long)catalogInfo
.nodeID
; 
2432         pb
.copyParam
.ioNewName 
= NULL
; 
2433         if ( NULL 
!= copyName 
) 
2435                 result 
= UnicodeNameGetHFSName(nameLength
, copyName
, textEncodingHint
, false, hfsName
); 
2436                 require_noerr(result
, UnicodeNameGetHFSName
); 
2438                 pb
.copyParam
.ioCopyName 
= hfsName
; 
2442                 pb
.copyParam
.ioCopyName 
= NULL
; 
2444         result 
= PBHCopyFileSync(&pb
); 
2445         require_noerr(result
, PBHCopyFileSync
); 
2447         if ( NULL 
!= newRef 
) 
2449                 verify_noerr(FSMakeFSRef(pb
.copyParam
.ioDstVRefNum
, pb
.copyParam
.ioNewDirID
, 
2450                         pb
.copyParam
.ioCopyName
, newRef
)); 
2454 UnicodeNameGetHFSName
: 
2455 FSGetCatalogInfo_dstDirectoryRef
: 
2457 FSGetCatalogInfo_srcFileRef
: 
2462 /*****************************************************************************/ 
2466         const FSRef 
*srcFileRef
, 
2467         const FSRef 
*dstDirectoryRef
, 
2468         UniCharCount nameLength
, 
2469         const UniChar 
*moveName
,        /* can be NULL (no rename during move) */ 
2470         TextEncoding textEncodingHint
, 
2471         FSRef 
*newRef
)                          /* can be NULL */ 
2475         FSCatalogInfo                   catalogInfo
; 
2478         GetVolParmsInfoBuffer   volParmsInfo
; 
2481         /* get source FSSpec from source FSRef */ 
2482         result 
= FSGetCatalogInfo(srcFileRef
, kFSCatInfoNone
, NULL
, NULL
, &srcFileSpec
, NULL
); 
2483         require_noerr(result
, FSGetCatalogInfo_srcFileRef
); 
2485         /* Make sure the volume supports MoveRename */ 
2486         result 
= FSGetVolParms(srcFileSpec
.vRefNum
, sizeof(GetVolParmsInfoBuffer
), 
2487                 &volParmsInfo
, &infoSize
); 
2488         require_action((noErr 
== result
) && VolHasMoveRename(&volParmsInfo
), 
2489                 NoMoveRenameSupport
, result 
= paramErr
); 
2491         /* get destination volume reference number and destination directory ID from destination FSRef */ 
2492         result 
= FSGetCatalogInfo(dstDirectoryRef
, kFSCatInfoVolume 
+ kFSCatInfoNodeID
, 
2493                 &catalogInfo
, NULL
, NULL
, NULL
); 
2494         require_noerr(result
, FSGetCatalogInfo_dstDirectoryRef
); 
2496         /* make sure the source and destination are on the same volume */ 
2497         require_action(srcFileSpec
.vRefNum 
== catalogInfo
.volume
, NotSameVolume
, result 
= diffVolErr
); 
2499         /* tell the server to move and rename the object */ 
2500         pb
.copyParam
.ioVRefNum 
= srcFileSpec
.vRefNum
; 
2501         pb
.copyParam
.ioDirID 
= srcFileSpec
.parID
; 
2502         pb
.copyParam
.ioNamePtr 
= (StringPtr
)srcFileSpec
.name
; 
2503         pb
.copyParam
.ioNewDirID 
= (long)catalogInfo
.nodeID
; 
2504         pb
.copyParam
.ioNewName 
= NULL
; 
2505         if ( NULL 
!= moveName 
) 
2507                 result 
= UnicodeNameGetHFSName(nameLength
, moveName
, textEncodingHint
, false, hfsName
); 
2508                 require_noerr(result
, UnicodeNameGetHFSName
); 
2510                 pb
.copyParam
.ioCopyName 
= hfsName
; 
2514                 pb
.copyParam
.ioCopyName 
= NULL
; 
2516         result 
= PBHMoveRenameSync(&pb
); 
2517         require_noerr(result
, PBHMoveRenameSync
); 
2519         if ( NULL 
!= newRef 
) 
2521                 verify_noerr(FSMakeFSRef(pb
.copyParam
.ioVRefNum
, pb
.copyParam
.ioNewDirID
, 
2522                         pb
.copyParam
.ioCopyName
, newRef
)); 
2526 UnicodeNameGetHFSName
: 
2528 FSGetCatalogInfo_dstDirectoryRef
: 
2529 NoMoveRenameSupport
: 
2530 FSGetCatalogInfo_srcFileRef
: 
2535 /*****************************************************************************/ 
2537 #pragma mark ----- File ID Routines ----- 
2539 /*****************************************************************************/ 
2543         FSVolumeRefNum volRefNum
, 
2551         /* check parameters */ 
2552         require_action(NULL 
!= ref
, BadParameter
, result 
= paramErr
); 
2554         /* resolve the file ID reference */ 
2556         pb
.ioNamePtr 
= tempStr
; 
2557         pb
.ioVRefNum 
= volRefNum
; 
2558         pb
.ioFileID 
= fileID
; 
2559         result 
= PBResolveFileIDRefSync((HParmBlkPtr
)&pb
); 
2560         require_noerr(result
, PBResolveFileIDRefSync
); 
2562         /* and then make an FSRef to the file */ 
2563         result 
= FSMakeFSRef(volRefNum
, pb
.ioSrcDirID
, tempStr
, ref
); 
2564         require_noerr(result
, FSMakeFSRef
); 
2567 PBResolveFileIDRefSync
: 
2573 /*****************************************************************************/ 
2584         /* check parameters */ 
2585         require_action(NULL 
!= fileID
, BadParameter
, result 
= paramErr
); 
2587         /* Get an FSSpec from the FSRef */ 
2588         result 
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
); 
2589         require_noerr(result
, FSGetCatalogInfo
); 
2591         /* Create (or get) the file ID reference using the FSSpec */ 
2592         pb
.ioNamePtr 
= (StringPtr
)spec
.name
; 
2593         pb
.ioVRefNum 
= spec
.vRefNum
; 
2594         pb
.ioSrcDirID 
= spec
.parID
; 
2595         result 
= PBCreateFileIDRefSync((HParmBlkPtr
)&pb
); 
2596         require((noErr 
== result
) || (fidExists 
== result
) || (afpIDExists 
== result
), 
2597                 PBCreateFileIDRefSync
); 
2599         /* return the file ID reference */ 
2600         *fileID 
= pb
.ioFileID
; 
2602 PBCreateFileIDRefSync
: 
2609 /*****************************************************************************/ 
2611 #pragma mark ----- Utility Routines ----- 
2613 /*****************************************************************************/ 
2617         ByteCount buffReqSize
, 
2618         ByteCount 
*buffActSize
) 
2622                 kSlopMemory 
= 0x00008000        /* 32K - Amount of free memory to leave when allocating buffers */ 
2627         /* check parameters */ 
2628         require_action(NULL 
!= buffActSize
, BadParameter
, tempPtr 
= NULL
); 
2630         /* Make request a multiple of 4K bytes */ 
2631         buffReqSize 
= buffReqSize 
& 0xfffff000; 
2633         if ( buffReqSize 
< 0x00001000 ) 
2635                 /* Request was smaller than 4K bytes - make it 4K */ 
2636                 buffReqSize 
= 0x00001000; 
2639         /* Attempt to allocate the memory */ 
2640         tempPtr 
= NewPtr(buffReqSize
); 
2642         /* If request failed, go to backup plan */ 
2643         if ( (tempPtr 
== NULL
) && (buffReqSize 
> 0x00001000) ) 
2646                 **      Try to get largest 4K byte block available 
2647                 **      leaving some slop for the toolbox if possible 
2649                 long freeMemory 
= (FreeMem() - kSlopMemory
) & 0xfffff000; 
2651                 buffReqSize 
= MaxBlock() & 0xfffff000; 
2653                 if ( buffReqSize 
> freeMemory 
) 
2655                         buffReqSize 
= freeMemory
; 
2658                 if ( buffReqSize 
== 0 ) 
2660                         buffReqSize 
= 0x00001000; 
2663                 tempPtr 
= NewPtr(buffReqSize
); 
2666         /* Return bytes allocated */ 
2667         if ( tempPtr 
!= NULL 
) 
2669                 *buffActSize 
= buffReqSize
; 
2681 /*****************************************************************************/ 
2688         return ( FSGetForkCBInfo(refNum
, 0, NULL
, NULL
, NULL
, ref
, NULL
) ); 
2691 /*****************************************************************************/ 
2695         const FSRef 
*newDefault
, 
2699         FSVolumeRefNum  vRefNum
; 
2701         FSCatalogInfo   catalogInfo
; 
2703         /* check parameters */ 
2704         require_action((NULL 
!= newDefault
) && (NULL 
!= oldDefault
), BadParameter
, result 
= paramErr
); 
2706         /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */ 
2707         result 
= FSGetCatalogInfo(newDefault
, 
2708                 kFSCatInfoNodeFlags 
+ kFSCatInfoVolume 
+ kFSCatInfoNodeID
, 
2709                 &catalogInfo
, NULL
, NULL
, NULL
); 
2710         require_noerr(result
, FSGetCatalogInfo
); 
2712         /* Make sure newDefault is a directory */ 
2713         require_action(0 != (kFSNodeIsDirectoryMask 
& catalogInfo
.nodeFlags
), NewDefaultNotDirectory
, 
2716         /* Get the current working directory. */ 
2717         result 
= HGetVol(NULL
, &vRefNum
, &dirID
); 
2718         require_noerr(result
, HGetVol
); 
2720         /* Return the oldDefault FSRef */ 
2721         result 
= FSMakeFSRef(vRefNum
, dirID
, NULL
, oldDefault
); 
2722         require_noerr(result
, FSMakeFSRef
); 
2724         /* Set the new current working directory */ 
2725         result 
= HSetVol(NULL
, catalogInfo
.volume
, catalogInfo
.nodeID
); 
2726         require_noerr(result
, HSetVol
); 
2731 NewDefaultNotDirectory
: 
2738 /*****************************************************************************/ 
2742         const FSRef 
*oldDefault
) 
2745         FSCatalogInfo   catalogInfo
; 
2747         /* check parameters */ 
2748         require_action(NULL 
!= oldDefault
, BadParameter
, result 
= paramErr
); 
2750         /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */ 
2751         result 
= FSGetCatalogInfo(oldDefault
, 
2752                 kFSCatInfoNodeFlags 
+ kFSCatInfoVolume 
+ kFSCatInfoNodeID
, 
2753                 &catalogInfo
, NULL
, NULL
, NULL
); 
2754         require_noerr(result
, FSGetCatalogInfo
); 
2756         /* Make sure oldDefault is a directory */ 
2757         require_action(0 != (kFSNodeIsDirectoryMask 
& catalogInfo
.nodeFlags
), OldDefaultNotDirectory
, 
2760         /* Set the current working directory to oldDefault */ 
2761         result 
= HSetVol(NULL
, catalogInfo
.volume
, catalogInfo
.nodeID
); 
2762         require_noerr(result
, HSetVol
); 
2765 OldDefaultNotDirectory
: 
2772 /*****************************************************************************/