]> git.saurik.com Git - wxWidgets.git/commitdiff
no message
authorStefan Csomor <csomor@advancedconcepts.ch>
Sun, 18 May 2003 12:08:49 +0000 (12:08 +0000)
committerStefan Csomor <csomor@advancedconcepts.ch>
Sun, 18 May 2003 12:08:49 +0000 (12:08 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20657 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

src/mac/morefilex/MoreFilesX.cpp [new file with mode: 0755]

diff --git a/src/mac/morefilex/MoreFilesX.cpp b/src/mac/morefilex/MoreFilesX.cpp
new file mode 100755 (executable)
index 0000000..617f492
--- /dev/null
@@ -0,0 +1,2770 @@
+/*
+       File:           MoreFilesX.c
+
+       Contains:       A collection of useful high-level File Manager routines
+                               which use the HFS Plus APIs wherever possible.
+
+       Version:        MoreFilesX 1.0.1
+
+       Copyright:      © 1992-2002 by Apple Computer, Inc., all rights reserved.
+
+       Disclaimer:     IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
+                               ("Apple") in consideration of your agreement to the following terms, and your
+                               use, installation, modification or redistribution of this Apple software
+                               constitutes acceptance of these terms.  If you do not agree with these terms,
+                               please do not use, install, modify or redistribute this Apple software.
+
+                               In consideration of your agreement to abide by the following terms, and subject
+                               to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+                               copyrights in this original Apple software (the "Apple Software"), to use,
+                               reproduce, modify and redistribute the Apple Software, with or without
+                               modifications, in source and/or binary forms; provided that if you redistribute
+                               the Apple Software in its entirety and without modifications, you must retain
+                               this notice and the following text and disclaimers in all such redistributions of
+                               the Apple Software.  Neither the name, trademarks, service marks or logos of
+                               Apple Computer, Inc. may be used to endorse or promote products derived from the
+                               Apple Software without specific prior written permission from Apple.  Except as
+                               expressly stated in this notice, no other rights or licenses, express or implied,
+                               are granted by Apple herein, including but not limited to any patent rights that
+                               may be infringed by your derivative works or by other works in which the Apple
+                               Software may be incorporated.
+
+                               The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
+                               WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+                               WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+                               PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+                               COMBINATION WITH YOUR PRODUCTS.
+
+                               IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+                               CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+                               GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+                               ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+                               OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+                               (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+                               ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+       File Ownership:
+
+               DRI:                            Apple Macintosh Developer Technical Support
+
+               Other Contact:          For bug reports, consult the following page on
+                                                       the World Wide Web:
+                                                               http://developer.apple.com/bugreporter/
+
+               Technology:                     DTS Sample Code
+
+       Writers:
+
+               (JL)    Jim Luther
+
+       Change History (most recent first):
+
+                <4>     8/22/02        JL              [3016251]  Changed FSMoveRenameObjectUnicode to not use
+                                                                       the Temporary folder because it isn't available on
+                                                                       NFS volumes.
+                <3>     4/19/02        JL              [2853905]  Fixed #if test around header includes.
+                <2>     4/19/02        JL              [2850624]  Fixed C++ compile errors and Project Builder
+                                                                       warnings.
+                <2>     4/19/02        JL              [2853901]  Updated standard disclaimer.
+                <1>     1/25/02        JL              MoreFilesX 1.0
+*/
+
+#if defined(__MACH__)
+       #include <Carbon/Carbon.h>
+       #include <string.h>
+#else
+       #include <Carbon.h>
+       #include <string.h>
+#endif
+
+#include "MoreFilesX.h"
+
+/* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */
+#ifndef BuildingMoreFilesXForMacOS9
+       #define BuildingMoreFilesXForMacOS9 0
+#endif
+
+/*****************************************************************************/
+
+#pragma mark ----- Local type definitions -----
+
+struct FSIterateContainerGlobals
+{
+       IterateContainerFilterProcPtr   iterateFilter;  /* pointer to IterateFilterProc */
+       FSCatalogInfoBitmap                             whichInfo;              /* fields of the CatalogInfo to get */
+       FSCatalogInfo                                   catalogInfo;    /* FSCatalogInfo */
+       FSRef                                                   ref;                    /* FSRef */
+       FSSpec                                                  spec;                   /* FSSpec */
+       FSSpec                                                  *specPtr;               /* pointer to spec field, or NULL */
+       HFSUniStr255                                    name;                   /* HFSUniStr255 */
+       HFSUniStr255                                    *namePtr;               /* pointer to name field, or NULL */
+       void                                                    *yourDataPtr;   /* a pointer to caller supplied data the filter may need to access */
+       ItemCount                                               maxLevels;              /* maximum levels to iterate through */
+       ItemCount                                               currentLevel;   /* the current level FSIterateContainerLevel is on */
+       Boolean                                                 quitFlag;               /* set to true if filter wants to kill interation */
+       Boolean                                                 containerChanged; /* temporary - set to true if the current container changed during iteration */
+       OSErr                                                   result;                 /* result */
+       ItemCount                                               actualObjects;  /* number of objects returned */
+};
+typedef struct FSIterateContainerGlobals FSIterateContainerGlobals;
+
+struct FSDeleteContainerGlobals
+{
+       OSErr                                                   result;                 /* result */
+       ItemCount                                               actualObjects;  /* number of objects returned */
+       FSCatalogInfo                                   catalogInfo;    /* FSCatalogInfo */
+};
+typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals;
+
+/*****************************************************************************/
+
+#pragma mark ----- Local prototypes -----
+
+static
+void
+FSDeleteContainerLevel(
+       const FSRef *container,
+       FSDeleteContainerGlobals *theGlobals);
+
+static
+void
+FSIterateContainerLevel(
+       FSIterateContainerGlobals *theGlobals);
+
+static
+OSErr
+GenerateUniqueHFSUniStr(
+       long *startSeed,
+       const FSRef *dir1,
+       const FSRef *dir2,
+       HFSUniStr255 *uniqueName);
+
+/*****************************************************************************/
+
+#pragma mark ----- File Access Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSCopyFork(
+       SInt16 srcRefNum,
+       SInt16 dstRefNum,
+       void *copyBufferPtr,
+       ByteCount copyBufferSize)
+{
+       OSErr           srcResult;
+       OSErr           dstResult;
+       OSErr           result;
+       SInt64          forkSize;
+       ByteCount       readActualCount;
+       
+       /* check input parameters */
+       require_action((NULL != copyBufferPtr) && (0 != copyBufferSize), BadParameter, result = paramErr);
+       
+       /* get source fork size */
+       result = FSGetForkSize(srcRefNum, &forkSize);
+       require_noerr(result, SourceFSGetForkSizeFailed);
+       
+       /* allocate disk space for destination fork */
+       result = FSSetForkSize(dstRefNum, fsFromStart, forkSize);
+       require_noerr(result, DestinationFSSetForkSizeFailed);
+       
+       /* reset source fork's position to 0 */
+       result = FSSetForkPosition(srcRefNum, fsFromStart, 0);
+       require_noerr(result, SourceFSSetForkPositionFailed);
+       
+       /* reset destination fork's position to 0 */
+       result = FSSetForkPosition(dstRefNum, fsFromStart, 0);
+       require_noerr(result, DestinationFSSetForkPositionFailed);
+
+       /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */
+       /* This will make writes on local volumes faster */
+       if ( (copyBufferSize >= 0x00001000) && ((copyBufferSize & 0x00000fff) != 0) )
+       {
+               copyBufferSize &= ~(0x00001000 - 1);
+       }
+       
+       /* copy source to destination */
+       srcResult = dstResult = noErr;
+       while ( (noErr == srcResult) && (noErr == dstResult) )
+       {
+               srcResult = FSReadFork(srcRefNum, fsAtMark + noCacheMask, 0, copyBufferSize, copyBufferPtr, &readActualCount);
+               dstResult = FSWriteFork(dstRefNum, fsAtMark + noCacheMask, 0, readActualCount, copyBufferPtr, NULL);
+       }
+       
+       /* make sure there were no errors at the destination */
+       require_noerr_action(dstResult, DestinationFSWriteForkFailed, result = dstResult);
+       
+       /* make sure the error at the source was eofErr */
+       require_action(eofErr == srcResult, SourceResultNotEofErr, result = srcResult);
+       
+       /* everything went as expected */
+       result = noErr;
+
+SourceResultNotEofErr:
+DestinationFSWriteForkFailed:
+DestinationFSSetForkPositionFailed:
+SourceFSSetForkPositionFailed:
+DestinationFSSetForkSizeFailed:
+SourceFSGetForkSizeFailed:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Volume Access Routines -----
+
+/*****************************************************************************/ 
+
+OSErr
+FSGetVolParms(
+       FSVolumeRefNum volRefNum,
+       UInt32 bufferSize,
+       GetVolParmsInfoBuffer *volParmsInfo,
+       UInt32 *actualInfoSize)
+{
+       OSErr                   result;
+       HParamBlockRec  pb;
+       
+       /* check parameters */
+       require_action((NULL != volParmsInfo) && (NULL != actualInfoSize),
+               BadParameter, result = paramErr);
+       
+       pb.ioParam.ioNamePtr = NULL;
+       pb.ioParam.ioVRefNum = volRefNum;
+       pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
+       pb.ioParam.ioReqCount = (SInt32)bufferSize;
+       result = PBHGetVolParmsSync(&pb);
+       require_noerr(result, PBHGetVolParmsSync);
+       
+       /* return number of bytes the file system returned in volParmsInfo buffer */
+       *actualInfoSize = (UInt32)pb.ioParam.ioActCount;
+       
+PBHGetVolParmsSync:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVRefNum(
+       const FSRef *ref,
+       FSVolumeRefNum *vRefNum)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       
+       /* check parameters */
+       require_action(NULL != vRefNum, BadParameter, result = paramErr);
+       
+       /* get the volume refNum from the FSRef */
+       result = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* return volume refNum from catalogInfo */
+       *vRefNum = catalogInfo.volume;
+       
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVInfo(
+       FSVolumeRefNum volume,
+       HFSUniStr255 *volumeName,       /* can be NULL */
+       UInt64 *freeBytes,                      /* can be NULL */
+       UInt64 *totalBytes)                     /* can be NULL */
+{
+       OSErr                           result;
+       FSVolumeInfo            info;
+       
+       /* ask for the volume's sizes only if needed */
+       result = FSGetVolumeInfo(volume, 0, NULL,
+               (((NULL != freeBytes) || (NULL != totalBytes)) ? kFSVolInfoSizes : kFSVolInfoNone),
+               &info, volumeName, NULL);
+       require_noerr(result, FSGetVolumeInfo);
+       
+       if ( NULL != freeBytes )
+       {
+               *freeBytes = info.freeBytes;
+       }
+       if ( NULL != totalBytes )
+       {
+               *totalBytes = info.totalBytes;
+       }
+       
+FSGetVolumeInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVolFileSystemID(
+       FSVolumeRefNum volume,
+       UInt16 *fileSystemID,   /* can be NULL */
+       UInt16 *signature)              /* can be NULL */
+{
+       OSErr                   result;
+       FSVolumeInfo    info;
+       
+       result = FSGetVolumeInfo(volume, 0, NULL, kFSVolInfoFSInfo, &info, NULL, NULL);
+       require_noerr(result, FSGetVolumeInfo);
+       
+       if ( NULL != fileSystemID )
+       {
+               *fileSystemID = info.filesystemID;
+       }
+       if ( NULL != signature )
+       {
+               *signature = info.signature;
+       }
+       
+FSGetVolumeInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetMountedVolumes(
+       FSRef ***volumeRefsHandle,      /* pointer to handle of FSRefs */
+       ItemCount *numVolumes)
+{
+       OSErr           result;
+       OSErr           memResult;
+       ItemCount       volumeIndex;
+       FSRef           ref;
+       
+       /* check parameters */
+       require_action((NULL != volumeRefsHandle) && (NULL != numVolumes),
+               BadParameter, result = paramErr);
+       
+       /* No volumes yet */
+       *numVolumes = 0;
+       
+       /* Allocate a handle for the results */
+       *volumeRefsHandle = (FSRef **)NewHandle(0);
+       require_action(NULL != *volumeRefsHandle, NewHandle, result = memFullErr);
+       
+       /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */
+       volumeIndex = 1;
+       do
+       {
+               result = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoNone, NULL, NULL, &ref);
+               if ( noErr == result )
+               {
+                       /* concatenate the FSRef to the end of the handle */
+                       PtrAndHand(&ref, (Handle)*volumeRefsHandle, sizeof(FSRef));
+                       memResult = MemError();
+                       require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
+                       
+                       ++(*numVolumes);        /* increment the volume count */
+                       ++volumeIndex;          /* and the volumeIndex to get the next volume*/
+               }
+       } while ( noErr == result );
+       
+       /* nsvErr is OK -- it just means there are no more volumes */
+       require(nsvErr == result, FSGetVolumeInfo);
+               
+       return ( noErr );
+       
+       /**********************/
+       
+MemoryAllocationFailed:
+FSGetVolumeInfo:
+
+       /* dispose of handle if already allocated and clear the outputs */
+       if ( NULL != *volumeRefsHandle )
+       {
+               DisposeHandle((Handle)*volumeRefsHandle);
+               *volumeRefsHandle = NULL;
+       }
+       *numVolumes = 0;
+       
+NewHandle:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSRefMakeFSSpec(
+       const FSRef *ref,
+       FSSpec *spec)
+{
+       OSErr   result;
+       
+       /* check parameters */
+       require_action(NULL != spec, BadParameter, result = paramErr);
+       
+       result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMakeFSRef(
+       FSVolumeRefNum volRefNum,
+       SInt32 dirID,
+       ConstStr255Param name,
+       FSRef *ref)
+{
+       OSErr           result;
+       FSRefParam      pb;
+       
+       /* check parameters */
+       require_action(NULL != ref, BadParameter, result = paramErr);
+       
+       pb.ioVRefNum = volRefNum;
+       pb.ioDirID = dirID;
+       pb.ioNamePtr = (StringPtr)name;
+       pb.newRef = ref;
+       result = PBMakeFSRefSync(&pb);
+       require_noerr(result, PBMakeFSRefSync);
+       
+PBMakeFSRefSync:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSStatus
+FSMakePath(
+       SInt16 volRefNum,
+       SInt32 dirID,
+       ConstStr255Param name,
+       UInt8 *path,
+       UInt32 maxPathSize)
+{
+       OSStatus        result;
+       FSRef           ref;
+       
+       /* check parameters */
+       require_action(NULL != path, BadParameter, result = paramErr);
+       
+       /* convert the inputs to an FSRef */
+       result = FSMakeFSRef(volRefNum, dirID, name, &ref);
+       require_noerr(result, FSMakeFSRef);
+       
+       /* and then convert the FSRef to a path */
+       result = FSRefMakePath(&ref, path, maxPathSize);
+       require_noerr(result, FSRefMakePath);
+       
+FSRefMakePath:
+FSMakeFSRef:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSStatus
+FSPathMakeFSSpec(
+       const UInt8 *path,
+       FSSpec *spec,
+       Boolean *isDirectory)   /* can be NULL */
+{
+       OSStatus        result;
+       FSRef           ref;
+       
+       /* check parameters */
+       require_action(NULL != spec, BadParameter, result = paramErr);
+       
+       /* convert the POSIX path to an FSRef */
+       result = FSPathMakeRef(path, &ref, isDirectory);
+       require_noerr(result, FSPathMakeRef);
+       
+       /* and then convert the FSRef to an FSSpec */
+       result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+FSGetCatalogInfo:
+FSPathMakeRef:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+UnicodeNameGetHFSName(
+       UniCharCount nameLength,
+       const UniChar *name,
+       TextEncoding textEncodingHint,
+       Boolean isVolumeName,
+       Str31 hfsName)
+{
+       OSStatus                        result;
+       ByteCount                       unicodeByteLength;
+       ByteCount                       unicodeBytesConverted;
+       ByteCount                       actualPascalBytes;
+       UnicodeMapping          uMapping;
+       UnicodeToTextInfo       utInfo;
+       
+       /* check parameters */
+       require_action(NULL != hfsName, BadParameter, result = paramErr);
+       
+       /* make sure output is valid in case we get errors or there's nothing to convert */
+       hfsName[0] = 0;
+       
+       unicodeByteLength = nameLength * sizeof(UniChar);
+       if ( 0 == unicodeByteLength )
+       {
+               /* do nothing */
+               result = noErr;
+       }
+       else
+       {
+               /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
+               if ( kTextEncodingUnknown == textEncodingHint )
+               {
+                       ScriptCode                      script;
+                       RegionCode                      region;
+                       
+                       script = (ScriptCode)GetScriptManagerVariable(smSysScript);
+                       region = (RegionCode)GetScriptManagerVariable(smRegionCode);
+                       result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
+                               NULL, &textEncodingHint );
+                       if ( paramErr == result )
+                       {
+                               /* ok, ignore the region and try again */
+                               result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
+                                       kTextRegionDontCare, NULL, &textEncodingHint );
+                       }
+                       if ( noErr != result )
+                       {
+                               /* ok... try something */
+                               textEncodingHint = kTextEncodingMacRoman;
+                       }
+               }
+               
+               uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
+                       kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
+               uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
+               uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
+       
+               result = CreateUnicodeToTextInfo(&uMapping, &utInfo);
+               require_noerr(result, CreateUnicodeToTextInfo);
+               
+               result = ConvertFromUnicodeToText(utInfo, unicodeByteLength, name, kUnicodeLooseMappingsMask,
+                       0, NULL, 0, NULL,       /* offsetCounts & offsetArrays */
+                       isVolumeName ? kHFSMaxVolumeNameChars : kHFSMaxFileNameChars,
+                       &unicodeBytesConverted, &actualPascalBytes, &hfsName[1]);
+               require_noerr(result, ConvertFromUnicodeToText);
+               
+               hfsName[0] = (unsigned char)actualPascalBytes;  /* fill in length byte */
+
+ConvertFromUnicodeToText:
+               
+               /* verify the result in debug builds -- there's really not anything you can do if it fails */
+               verify_noerr(DisposeUnicodeToTextInfo(&utInfo));
+       }
+       
+CreateUnicodeToTextInfo:       
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+HFSNameGetUnicodeName(
+       ConstStr31Param hfsName,
+       TextEncoding textEncodingHint,
+       HFSUniStr255 *unicodeName)
+{
+       ByteCount                       unicodeByteLength;
+       OSStatus                        result;
+       UnicodeMapping          uMapping;
+       TextToUnicodeInfo       tuInfo;
+       ByteCount                       pascalCharsRead;
+       
+       /* check parameters */
+       require_action(NULL != unicodeName, BadParameter, result = paramErr);
+       
+       /* make sure output is valid in case we get errors or there's nothing to convert */
+       unicodeName->length = 0;
+       
+       if ( 0 == StrLength(hfsName) )
+       {
+               result = noErr;
+       }
+       else
+       {
+               /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
+               if ( kTextEncodingUnknown == textEncodingHint )
+               {
+                       ScriptCode                      script;
+                       RegionCode                      region;
+                       
+                       script = GetScriptManagerVariable(smSysScript);
+                       region = GetScriptManagerVariable(smRegionCode);
+                       result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
+                               NULL, &textEncodingHint);
+                       if ( paramErr == result )
+                       {
+                               /* ok, ignore the region and try again */
+                               result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
+                                       kTextRegionDontCare, NULL, &textEncodingHint);
+                       }
+                       if ( noErr != result )
+                       {
+                               /* ok... try something */
+                               textEncodingHint = kTextEncodingMacRoman;
+                       }
+               }
+               
+               uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
+                       kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
+               uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
+               uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
+       
+               result = CreateTextToUnicodeInfo(&uMapping, &tuInfo);
+               require_noerr(result, CreateTextToUnicodeInfo);
+                       
+               result = ConvertFromTextToUnicode(tuInfo, hfsName[0], &hfsName[1],
+                       0,                                                              /* no control flag bits */
+                       0, NULL, 0, NULL,                               /* offsetCounts & offsetArrays */
+                       sizeof(unicodeName->unicode),   /* output buffer size in bytes */
+                       &pascalCharsRead, &unicodeByteLength, unicodeName->unicode);
+               require_noerr(result, ConvertFromTextToUnicode);
+               
+               /* convert from byte count to char count */
+               unicodeName->length = unicodeByteLength / sizeof(UniChar);
+
+ConvertFromTextToUnicode:
+
+               /* verify the result in debug builds -- there's really not anything you can do if it fails */
+               verify_noerr(DisposeTextToUnicodeInfo(&tuInfo));
+       }
+       
+CreateTextToUnicodeInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- File/Directory Manipulation Routines -----
+
+/*****************************************************************************/
+
+Boolean FSRefValid(const FSRef *ref)
+{
+       return ( noErr == FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, NULL, NULL) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetParentRef(
+       const FSRef *ref,
+       FSRef *parentRef)
+{
+       OSErr   result;
+       FSCatalogInfo   catalogInfo;
+       
+       /* check parameters */
+       require_action(NULL != parentRef, BadParameter, result = paramErr);
+       
+       result = FSGetCatalogInfo(ref, kFSCatInfoNodeID, &catalogInfo, NULL, NULL, parentRef);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /*
+        * Note: FSRefs always point to real file system objects. So, there cannot
+        * be a FSRef to the parent of volume root directories. Early versions of
+        * Mac OS X do not handle this case correctly and incorrectly return a
+        * FSRef for the parent of volume root directories instead of returning an
+        * invalid FSRef (a cleared FSRef is invalid). The next three lines of code
+        * ensure that you won't run into this bug. WW9D!
+        */
+       if ( fsRtDirID == catalogInfo.nodeID )
+       {
+               /* clear parentRef and return noErr which is the proper behavior */
+               memset(parentRef, 0, sizeof(FSRef));
+       }
+
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetFileDirName(
+       const FSRef *ref,
+       HFSUniStr255 *outName)
+{
+       OSErr   result;
+       
+       /* check parameters */
+       require_action(NULL != outName, BadParameter, result = paramErr);
+       
+       result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, outName, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetNodeID(
+       const FSRef *ref,
+       long *nodeID,                   /* can be NULL */
+       Boolean *isDirectory)   /* can be NULL */
+{
+       OSErr                           result;
+       FSCatalogInfo           catalogInfo;
+       FSCatalogInfoBitmap whichInfo;
+       
+       /* determine what catalog information to get */
+       whichInfo = kFSCatInfoNone; /* start with none */
+       if ( NULL != nodeID )
+       {
+               whichInfo |= kFSCatInfoNodeID;
+       }
+       if ( NULL != isDirectory )
+       {
+               whichInfo |= kFSCatInfoNodeFlags;
+       }
+       
+       result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       if ( NULL != nodeID )
+       {
+               *nodeID = catalogInfo.nodeID;
+       }
+       if ( NULL != isDirectory )
+       {
+               *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
+       }
+       
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetUserPrivilegesPermissions(
+       const FSRef *ref,
+       UInt8 *userPrivileges,          /* can be NULL */
+       UInt32 permissions[4])          /* can be NULL */
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       FSCatalogInfoBitmap whichInfo;
+       
+       /* determine what catalog information to get */
+       whichInfo = kFSCatInfoNone; /* start with none */
+       if ( NULL != userPrivileges )
+       {
+               whichInfo |= kFSCatInfoUserPrivs;
+       }
+       if ( NULL != permissions )
+       {
+               whichInfo |= kFSCatInfoPermissions;
+       }
+       
+       result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       if ( NULL != userPrivileges )
+       {
+               *userPrivileges = catalogInfo.userPrivileges;
+       }
+       if ( NULL != permissions )
+       {
+               BlockMoveData(&catalogInfo.permissions, permissions, sizeof(UInt32) * 4);
+       }
+       
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCheckLock(
+       const FSRef *ref)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       FSVolumeInfo    volumeInfo;
+       
+       /* get nodeFlags and vRefNum for container */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoVolume, &catalogInfo, NULL, NULL,NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* is file locked? */
+       if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
+       {
+               result = fLckdErr;      /* file is locked */
+       }
+       else
+       {
+               /* file isn't locked, but is volume locked? */
+               
+               /* get volume flags */
+               result = FSGetVolumeInfo(catalogInfo.volume, 0, NULL, kFSVolInfoFlags, &volumeInfo, NULL, NULL);
+               require_noerr(result, FSGetVolumeInfo);
+               
+               if ( 0 != (volumeInfo.flags & kFSVolFlagHardwareLockedMask) )
+               {
+                       result = wPrErr;        /* volume locked by hardware */
+               }
+               else if ( 0 != (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) )
+               {
+                       result = vLckdErr;      /* volume locked by software */
+               }
+       }
+       
+FSGetVolumeInfo:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetForkSizes(
+       const FSRef *ref,
+       UInt64 *dataLogicalSize,        /* can be NULL */
+       UInt64 *rsrcLogicalSize)        /* can be NULL */
+{
+       OSErr                           result;
+       FSCatalogInfoBitmap whichInfo;
+       FSCatalogInfo           catalogInfo;
+       
+       whichInfo = kFSCatInfoNodeFlags;
+       if ( NULL != dataLogicalSize )
+       {
+               /* get data fork size */
+               whichInfo |= kFSCatInfoDataSizes;
+       }
+       if ( NULL != rsrcLogicalSize )
+       {
+               /* get resource fork size */
+               whichInfo |= kFSCatInfoRsrcSizes;
+       }
+
+       /* get nodeFlags and catalog info */
+       result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL,NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* make sure FSRef was to a file */
+       require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
+       
+       if ( NULL != dataLogicalSize )
+       {
+               /* return data fork size */
+               *dataLogicalSize = catalogInfo.dataLogicalSize;
+       }
+       if ( NULL != rsrcLogicalSize )
+       {
+               /* return resource fork size */
+               *rsrcLogicalSize = catalogInfo.rsrcLogicalSize;
+       }
+       
+FSRefNotFile:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetTotalForkSizes(
+       const FSRef *ref,
+       UInt64 *totalLogicalSize,       /* can be NULL */
+       UInt64 *totalPhysicalSize,      /* can be NULL */
+       ItemCount *forkCount)           /* can be NULL */
+{
+       OSErr                   result;
+       CatPositionRec  forkIterator;
+       SInt64                  forkSize;
+       SInt64                  *forkSizePtr;
+       UInt64                  forkPhysicalSize;
+       UInt64                  *forkPhysicalSizePtr;
+       
+       /* Determine if forkSize needed */
+       if ( NULL != totalLogicalSize)
+       {
+               *totalLogicalSize = 0;
+               forkSizePtr = &forkSize;
+       }
+       else
+       {
+               forkSizePtr = NULL;
+       }
+       
+       /* Determine if forkPhysicalSize is needed */
+       if ( NULL != totalPhysicalSize )
+       {
+               *totalPhysicalSize = 0;
+               forkPhysicalSizePtr = &forkPhysicalSize;
+       }
+       else
+       {
+               forkPhysicalSizePtr = NULL;
+       }
+       
+       /* zero fork count if returning it */
+       if ( NULL != forkCount )
+       {
+               *forkCount = 0;
+       }
+       
+       /* Iterate through the forks to get the sizes */
+       forkIterator.initialize = 0;
+       do
+       {
+               result = FSIterateForks(ref, &forkIterator, NULL, forkSizePtr, forkPhysicalSizePtr);
+               if ( noErr == result )
+               {
+                       if ( NULL != totalLogicalSize )
+                       {
+                               *totalLogicalSize += forkSize;
+                       }
+                       
+                       if ( NULL != totalPhysicalSize )
+                       {
+                               *totalPhysicalSize += forkPhysicalSize;
+                       }
+                       
+                       if ( NULL != forkCount )
+                       {
+                               ++*forkCount;
+                       }
+               }
+       } while ( noErr == result );
+       
+       /* any error result other than errFSNoMoreItems is serious */
+       require(errFSNoMoreItems == result, FSIterateForks);
+       
+       /* Normal exit */
+       result = noErr;
+
+FSIterateForks:
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSBumpDate(
+       const FSRef *ref)
+{
+       OSStatus                result;
+       FSCatalogInfo   catalogInfo;
+       UTCDateTime             oldDateTime;
+#if !BuildingMoreFilesXForMacOS9
+       FSRef                   parentRef;
+       Boolean                 notifyParent;
+#endif
+
+#if !BuildingMoreFilesXForMacOS9
+       /* Get the node flags, the content modification date and time, and the parent ref */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoContentMod, &catalogInfo, NULL, NULL, &parentRef);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* Notify the parent if this is a file */
+       notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask));
+#else
+       /* Get the content modification date and time */
+       result = FSGetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+#endif
+       
+       oldDateTime = catalogInfo.contentModDate;
+
+       /* Get the current date and time */
+       result = GetUTCDateTime(&catalogInfo.contentModDate, kUTCDefaultOptions);
+       require_noerr(result, GetUTCDateTime);
+       
+       /* if the old date and time is the the same as the current, bump the seconds by one */
+       if ( (catalogInfo.contentModDate.fraction == oldDateTime.fraction) &&
+                (catalogInfo.contentModDate.lowSeconds == oldDateTime.lowSeconds) &&
+                (catalogInfo.contentModDate.highSeconds == oldDateTime.highSeconds) )
+       {
+               ++catalogInfo.contentModDate.lowSeconds;
+               if ( 0 == catalogInfo.contentModDate.lowSeconds )
+               {
+                       ++catalogInfo.contentModDate.highSeconds;
+               }
+       }
+       
+       /* Bump the content modification date and time */
+       result = FSSetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo);
+       require_noerr(result, FSSetCatalogInfo);
+
+#if !BuildingMoreFilesXForMacOS9
+       /*
+        * The problem with FNNotify is that it is not available under Mac OS 9
+        * and there's no way to test for that except for looking for the symbol
+        * or something. So, I'll just conditionalize this for those who care
+        * to send a notification.
+        */
+       
+       /* Send a notification for the parent of the file, or for the directory */
+       result = FNNotify(notifyParent ? &parentRef : ref, kFNDirectoryModifiedMessage, kNilOptions);
+       require_noerr(result, FNNotify);
+#endif
+
+       /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */
+FNNotify:
+FSSetCatalogInfo:
+       
+       return ( noErr );
+       
+       /**********************/
+       
+GetUTCDateTime:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetFinderInfo(
+       const FSRef *ref,
+       FinderInfo *info,                                       /* can be NULL */
+       ExtendedFinderInfo *extendedInfo,       /* can be NULL */
+       Boolean *isDirectory)                           /* can be NULL */
+{
+       OSErr                           result;
+       FSCatalogInfo           catalogInfo;
+       FSCatalogInfoBitmap whichInfo;
+       
+       /* determine what catalog information is really needed */
+       whichInfo = kFSCatInfoNone;
+       
+       if ( NULL != info )
+       {
+               /* get FinderInfo */
+               whichInfo |= kFSCatInfoFinderInfo;
+       }
+       
+       if ( NULL != extendedInfo )
+       {
+               /* get ExtendedFinderInfo */
+               whichInfo |= kFSCatInfoFinderXInfo;
+       }
+       
+       if ( NULL != isDirectory )
+       {
+               whichInfo |= kFSCatInfoNodeFlags;
+       }
+       
+       result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* return FinderInfo if requested */
+       if ( NULL != info )
+       {
+               BlockMoveData(catalogInfo.finderInfo, info, sizeof(FinderInfo));
+       }
+       
+       /* return ExtendedFinderInfo if requested */
+       if ( NULL != extendedInfo)
+       {
+               BlockMoveData(catalogInfo.extFinderInfo, extendedInfo, sizeof(ExtendedFinderInfo));
+       }
+       
+       /* set isDirectory Boolean if requested */
+       if ( NULL != isDirectory)
+       {
+               *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
+       }
+       
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetFinderInfo(
+       const FSRef *ref,
+       const FinderInfo *info,
+       const ExtendedFinderInfo *extendedInfo)
+{
+       OSErr                           result;
+       FSCatalogInfo           catalogInfo;
+       FSCatalogInfoBitmap whichInfo;
+       
+       /* determine what catalog information will be set */
+       whichInfo = kFSCatInfoNone; /* start with none */
+       if ( NULL != info )
+       {
+               /* set FinderInfo */
+               whichInfo |= kFSCatInfoFinderInfo;
+               BlockMoveData(info, catalogInfo.finderInfo, sizeof(FinderInfo));
+       }
+       if ( NULL != extendedInfo )
+       {
+               /* set ExtendedFinderInfo */
+               whichInfo |= kFSCatInfoFinderXInfo;
+               BlockMoveData(extendedInfo, catalogInfo.extFinderInfo, sizeof(ExtendedFinderInfo));
+       }
+       
+       result = FSSetCatalogInfo(ref, whichInfo, &catalogInfo);
+       require_noerr(result, FSGetCatalogInfo);
+       
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSChangeCreatorType(
+       const FSRef *ref,
+       OSType fileCreator,
+       OSType fileType)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       FSRef                   parentRef;
+       
+       /* get nodeFlags, finder info, and parent FSRef */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, &catalogInfo , NULL, NULL, &parentRef);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* make sure FSRef was to a file */
+       require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
+       
+       /* If fileType not 0x00000000, change fileType */
+       if ( fileType != (OSType)0x00000000 )
+       {
+               ((FileInfo *)&catalogInfo.finderInfo)->fileType = fileType;
+       }
+       
+       /* If creator not 0x00000000, change creator */
+       if ( fileCreator != (OSType)0x00000000 )
+       {
+               ((FileInfo *)&catalogInfo.finderInfo)->fileCreator = fileCreator;
+       }
+       
+       /* now, save the new information back to disk */
+       result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
+       require_noerr(result, FSSetCatalogInfo);
+       
+       /* and attempt to bump the parent directory's mod date to wake up */
+       /* the Finder to the change we just made (ignore errors from this) */
+       verify_noerr(FSBumpDate(&parentRef));
+       
+FSSetCatalogInfo:
+FSRefNotFile:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSChangeFinderFlags(
+       const FSRef *ref,
+       Boolean setBits,
+       UInt16 flagBits)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       FSRef                   parentRef;
+       
+       /* get the current finderInfo */
+       result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* set or clear the appropriate bits in the finderInfo.finderFlags */
+       if ( setBits )
+       {
+               /* OR in the bits */
+               ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits;
+       }
+       else
+       {
+               /* AND out the bits */
+               ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits;
+       }
+       
+       /* save the modified finderInfo */
+       result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
+       require_noerr(result, FSSetCatalogInfo);
+       
+       /* and attempt to bump the parent directory's mod date to wake up the Finder */
+       /* to the change we just made (ignore errors from this) */
+       verify_noerr(FSBumpDate(&parentRef));
+       
+FSSetCatalogInfo:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetInvisible(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, true, kIsInvisible) );
+}
+
+OSErr
+FSClearInvisible(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, false, kIsInvisible) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetNameLocked(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, true, kNameLocked) );
+}
+
+OSErr
+FSClearNameLocked(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, false, kNameLocked) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetIsStationery(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, true, kIsStationery) );
+}
+
+OSErr
+FSClearIsStationery(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, false, kIsStationery) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetHasCustomIcon(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) );
+}
+
+OSErr
+FSClearHasCustomIcon(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, false, kHasCustomIcon) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSClearHasBeenInited(
+       const FSRef *ref)
+{
+       return ( FSChangeFinderFlags(ref, false, kHasBeenInited) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCopyFileMgrAttributes(
+       const FSRef *sourceRef,
+       const FSRef *destinationRef,
+       Boolean copyLockBit)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       
+       /* get the source information */
+       result = FSGetCatalogInfo(sourceRef, kFSCatInfoSettableInfo, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* don't copy the hasBeenInited bit; clear it */
+       ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~kHasBeenInited;
+       
+       /* should the locked bit be copied? */
+       if ( !copyLockBit )
+       {
+               /* no, make sure the locked bit is clear */
+               catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
+       }
+               
+       /* set the destination information */
+       result = FSSetCatalogInfo(destinationRef, kFSCatInfoSettableInfo, &catalogInfo);
+       require_noerr(result, FSSetCatalogInfo);
+       
+FSSetCatalogInfo:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMoveRenameObjectUnicode(
+       const FSRef *ref,
+       const FSRef *destDirectory,
+       UniCharCount nameLength,
+       const UniChar *name,                    /* can be NULL (no rename during move) */
+       TextEncoding textEncodingHint,
+       FSRef *newRef)                                  /* if function fails along the way, newRef is final location of file */
+{
+       OSErr                   result;
+       FSVolumeRefNum  vRefNum;
+       FSCatalogInfo   catalogInfo;
+       FSRef                   originalDirectory;
+       TextEncoding    originalTextEncodingHint;
+       HFSUniStr255    originalName;
+       HFSUniStr255    uniqueName;             /* unique name given to object while moving it to destination */
+       long                    theSeed;                /* the seed for generating unique names */
+       
+       /* check parameters */
+       require_action(NULL != newRef, BadParameter, result = paramErr);
+       
+       /* newRef = input to start with */
+       BlockMoveData(ref, newRef, sizeof(FSRef));
+       
+       /* get destDirectory's vRefNum */
+       result = FSGetCatalogInfo(destDirectory, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, DestinationBad);
+       
+       /* save vRefNum */
+       vRefNum = catalogInfo.volume;
+       
+       /* get ref's vRefNum, TextEncoding, name and parent directory*/
+       result = FSGetCatalogInfo(ref, kFSCatInfoTextEncoding + kFSCatInfoVolume, &catalogInfo, &originalName, NULL, &originalDirectory);
+       require_noerr(result, SourceBad);
+       
+       /* save TextEncoding */
+       originalTextEncodingHint = catalogInfo.textEncodingHint;
+       
+       /* make sure ref and destDirectory are on same volume */
+       require_action(vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
+       
+       /* Skip a few steps if we're not renaming */
+       if ( NULL != name )
+       {
+               /* generate a name that is unique in both directories */
+               theSeed = 0x4a696d4c;   /* a fine unlikely filename */
+               
+               result = GenerateUniqueHFSUniStr(&theSeed, &originalDirectory, destDirectory, &uniqueName);
+               require_noerr(result, GenerateUniqueHFSUniStrFailed);
+               
+               /* Rename the object to uniqueName */
+               result = FSRenameUnicode(ref, uniqueName.length, uniqueName.unicode, kTextEncodingUnknown, newRef);
+               require_noerr(result, FSRenameUnicodeBeforeMoveFailed);
+               
+               /* Move object to its new home */
+               result = FSMoveObject(newRef, destDirectory, newRef);
+               require_noerr(result, FSMoveObjectAfterRenameFailed);
+               
+               /* Rename the object to new name */
+               result = FSRenameUnicode(ref, nameLength, name, textEncodingHint, newRef);
+               require_noerr(result, FSRenameUnicodeAfterMoveFailed);
+       }
+       else
+       {
+               /* Move object to its new home */
+               result = FSMoveObject(newRef, destDirectory, newRef);
+               require_noerr(result, FSMoveObjectNoRenameFailed);
+       }
+       
+       return ( result );
+       
+       /*************/
+
+/*
+ * failure handling code when renaming
+ */
+
+FSRenameUnicodeAfterMoveFailed:
+
+       /* Error handling: move object back to original location - ignore errors */
+       verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef));
+       
+FSMoveObjectAfterRenameFailed:
+
+       /* Error handling: rename object back to original name - ignore errors */
+       verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef));
+       
+FSRenameUnicodeBeforeMoveFailed:
+GenerateUniqueHFSUniStrFailed:
+
+/*
+ * failure handling code for renaming or not
+ */
+FSMoveObjectNoRenameFailed:
+NotSameVolume:
+SourceBad:
+DestinationBad:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+       The FSDeleteContainerLevel function deletes the contents of a container
+       directory. All files and subdirectories in the specified container are
+       deleted. If a locked file or directory is encountered, it is unlocked
+       and then deleted. If any unexpected errors are encountered,
+       FSDeleteContainerLevel quits and returns to the caller.
+       
+       container                       --> FSRef to a directory.
+       theGlobals                      --> A pointer to a FSDeleteContainerGlobals struct
+                                                       which contains the variables that do not need to
+                                                       be allocated each time FSDeleteContainerLevel
+                                                       recurses. That lets FSDeleteContainerLevel use
+                                                       less stack space per recursion level.
+*/
+
+static
+void
+FSDeleteContainerLevel(
+       const FSRef *container,
+       FSDeleteContainerGlobals *theGlobals)
+{
+       /* level locals */
+       FSIterator                                      iterator;
+       FSRef                                           itemToDelete;
+       UInt16                                          nodeFlags;
+       
+       /* Open FSIterator for flat access and give delete optimization hint */
+       theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator);
+       require_noerr(theGlobals->result, FSOpenIterator);
+       
+       /* delete the contents of the directory */
+       do
+       {
+               /* get 1 item to delete */
+               theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
+                                                               NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo,
+                                                               &itemToDelete, NULL, NULL);
+               if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) )
+               {
+                       /* save node flags in local in case we have to recurse */
+                       nodeFlags = theGlobals->catalogInfo.nodeFlags;
+                       
+                       /* is it a file or directory? */
+                       if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) )
+                       {
+                               /* it's a directory -- delete its contents before attempting to delete it */
+                               FSDeleteContainerLevel(&itemToDelete, theGlobals);
+                       }
+                       /* are we still OK to delete? */
+                       if ( noErr == theGlobals->result )
+                       {
+                               /* is item locked? */
+                               if ( 0 != (nodeFlags & kFSNodeLockedMask) )
+                               {
+                                       /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
+                                       theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask;
+                                       (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo);
+                               }
+                               /* delete the item */
+                               theGlobals->result = FSDeleteObject(&itemToDelete);
+                       }
+               }
+       } while ( noErr == theGlobals->result );
+       
+       /* we found the end of the items normally, so return noErr */
+       if ( errFSNoMoreItems == theGlobals->result )
+       {
+               theGlobals->result = noErr;
+       }
+       
+       /* close the FSIterator (closing an open iterator should never fail) */
+       verify_noerr(FSCloseIterator(iterator));
+
+FSOpenIterator:
+
+       return;
+}
+
+/*****************************************************************************/
+
+OSErr
+FSDeleteContainerContents(
+       const FSRef *container)
+{
+       FSDeleteContainerGlobals        theGlobals;
+       
+       /* delete container's contents */
+       FSDeleteContainerLevel(container, &theGlobals);
+       
+       return ( theGlobals.result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSDeleteContainer(
+       const FSRef *container)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       
+       /* get nodeFlags for container */
+       result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* make sure container is a directory */
+       require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr);
+       
+       /* delete container's contents */
+       result = FSDeleteContainerContents(container);
+       require_noerr(result, FSDeleteContainerContents);
+       
+       /* is container locked? */
+       if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
+       {
+               /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
+               catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
+               (void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo);
+       }
+       
+       /* delete the container */
+       result = FSDeleteObject(container);
+       
+FSDeleteContainerContents:
+ContainerNotDirectory:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+       The FSIterateContainerLevel function iterates the contents of a container
+       directory and calls a IterateContainerFilterProc function once for each
+       file and directory found.
+       
+       theGlobals                      --> A pointer to a FSIterateContainerGlobals struct
+                                                       which contains the variables needed globally by
+                                                       all recusion levels of FSIterateContainerLevel.
+                                                       That makes FSIterateContainer thread safe since
+                                                       each call to it uses its own global world.
+                                                       It also contains the variables that do not need
+                                                       to be allocated each time FSIterateContainerLevel
+                                                       recurses. That lets FSIterateContainerLevel use
+                                                       less stack space per recursion level.
+*/
+
+static
+void
+FSIterateContainerLevel(
+       FSIterateContainerGlobals *theGlobals)
+{      
+       FSIterator      iterator;
+       
+       /* If maxLevels is zero, we aren't checking levels */
+       /* If currentLevel < maxLevels, look at this level */
+       if ( (theGlobals->maxLevels == 0) ||
+                (theGlobals->currentLevel < theGlobals->maxLevels) )
+       {
+               /* Open FSIterator for flat access to theGlobals->ref */
+               theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator);
+               require_noerr(theGlobals->result, FSOpenIterator);
+               
+               ++theGlobals->currentLevel; /* Go to next level */
+               
+               /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
+               do
+               {
+                       theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
+                               &theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo,
+                               &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr);
+                       if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) &&
+                               (0 != theGlobals->actualObjects) )
+                       {
+                               /* Call the IterateFilterProc */
+                               theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter,
+                                       theGlobals->containerChanged, theGlobals->currentLevel,
+                                       &theGlobals->catalogInfo, &theGlobals->ref,
+                                       theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr);
+                               /* Is it a directory? */
+                               if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) )
+                               {
+                                       /* Keep going? */
+                                       if ( !theGlobals->quitFlag )
+                                       {
+                                               /* Dive again if the IterateFilterProc didn't say "quit" */
+                                               FSIterateContainerLevel(theGlobals);
+                                       }
+                               }
+                       }
+                       /* time to fall back a level? */
+               } while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) );
+               
+               /* errFSNoMoreItems is OK - it only means we hit the end of this level */
+               /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
+               if ( (errFSNoMoreItems == theGlobals->result) ||
+                        (afpAccessDenied == theGlobals->result) )
+               {
+                       theGlobals->result = noErr;
+               }
+               
+               --theGlobals->currentLevel; /* Return to previous level as we leave */
+               
+               /* Close the FSIterator (closing an open iterator should never fail) */
+               verify_noerr(FSCloseIterator(iterator));
+       }
+       
+FSOpenIterator:
+
+       return;
+}
+
+/*****************************************************************************/
+
+OSErr
+FSIterateContainer(
+       const FSRef *container,
+       ItemCount maxLevels,
+       FSCatalogInfoBitmap whichInfo,
+       Boolean wantFSSpec,
+       Boolean wantName,
+       IterateContainerFilterProcPtr iterateFilter,
+       void *yourDataPtr)
+{
+       OSErr                                           result;
+       FSIterateContainerGlobals       theGlobals;
+       
+       /* make sure there is an iterateFilter */
+       require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr);
+       
+       /*
+        * set up the globals we need to access from the recursive routine
+        */
+       theGlobals.iterateFilter = iterateFilter;
+       /* we need the node flags no matter what was requested so we can detect files vs. directories */
+       theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags;
+       /* start with input container -- the first OpenIterator will ensure it is a directory */
+       theGlobals.ref = *container;
+       if ( wantFSSpec )
+       {
+               theGlobals.specPtr = &theGlobals.spec;
+       }
+       else
+       {
+               theGlobals.specPtr = NULL;
+       }
+       if ( wantName )
+       {
+               theGlobals.namePtr = &theGlobals.name;
+       }
+       else
+       {
+               theGlobals.namePtr = NULL;
+       }
+       theGlobals.yourDataPtr = yourDataPtr;
+       theGlobals.maxLevels = maxLevels;
+       theGlobals.currentLevel = 0;
+       theGlobals.quitFlag = false;
+       theGlobals.containerChanged = false;
+       theGlobals.result = noErr;
+       theGlobals.actualObjects = 0;
+       
+       /* here we go into recursion land... */
+       FSIterateContainerLevel(&theGlobals);
+       result = theGlobals.result;
+       require_noerr(result, FSIterateContainerLevel);
+       
+FSIterateContainerLevel:
+NoIterateFilter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetDirectoryItems(
+       const FSRef *container,
+       FSRef ***refsHandle,    /* pointer to handle of FSRefs */
+       ItemCount *numRefs,
+       Boolean *containerChanged)
+{
+       /* Grab items 10 at a time. */
+       enum { kMaxItemsPerBulkCall = 10 };
+       
+       OSErr           result;
+       OSErr           memResult;
+       FSIterator      iterator;
+       FSRef           refs[kMaxItemsPerBulkCall];
+       ItemCount       actualObjects;
+       Boolean         changed;
+       
+       /* check parameters */
+       require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged),
+               BadParameter, result = paramErr);
+       
+       *numRefs = 0;
+       *containerChanged = false;
+       *refsHandle = (FSRef **)NewHandle(0);
+       require_action(NULL != *refsHandle, NewHandle, result = memFullErr);
+       
+       /* open an FSIterator */
+       result = FSOpenIterator(container, kFSIterateFlat, &iterator);
+       require_noerr(result, FSOpenIterator);
+       
+       /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
+       do
+       {
+               result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects,
+                                       &changed, kFSCatInfoNone,  NULL,  refs, NULL, NULL);
+               
+               /* if the container changed, set containerChanged for output, but keep going */
+               if ( changed )
+               {
+                       *containerChanged = changed;
+               }
+               
+               /* any result other than noErr and errFSNoMoreItems is serious */
+               require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk);
+               
+               /* add objects to output array and count */
+               if ( 0 != actualObjects )
+               {
+                       /* concatenate the FSRefs to the end of the      handle */
+                       PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef));
+                       memResult = MemError();
+                       require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
+                       
+                       *numRefs += actualObjects;
+               }
+       } while ( noErr == result );
+       
+       verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */
+       
+       return ( noErr );
+       
+       /**********************/
+       
+MemoryAllocationFailed:
+FSGetCatalogInfoBulk:
+
+       /* close the iterator */
+       verify_noerr(FSCloseIterator(iterator));
+
+FSOpenIterator:
+       /* dispose of handle if already allocated and clear the outputs */
+       if ( NULL != *refsHandle )
+       {
+               DisposeHandle((Handle)*refsHandle);
+               *refsHandle = NULL;
+       }
+       *numRefs = 0;
+       
+NewHandle:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+       The GenerateUniqueName function generates a HFSUniStr255 name that is
+       unique in both dir1 and dir2.
+       
+       startSeed                       -->     A pointer to a long which is used to generate the
+                                                       unique name.
+                                               <--     It is modified on output to a value which should
+                                                       be used to generate the next unique name.
+       dir1                            -->     The first directory.
+       dir2                            -->     The second directory.
+       uniqueName                      <--     A pointer to a HFSUniStr255 where the unique name
+                                                       is to be returned.
+*/
+
+static
+OSErr
+GenerateUniqueHFSUniStr(
+       long *startSeed,
+       const FSRef *dir1,
+       const FSRef *dir2,
+       HFSUniStr255 *uniqueName)
+{
+       OSErr                   result;
+       long                    i;
+       FSRefParam              pb;
+       FSRef                   newRef;
+       unsigned char   hexStr[17] = "0123456789ABCDEF";
+       
+       /* set up the parameter block */
+       pb.name = uniqueName->unicode;
+       pb.nameLength = 8;      /* always 8 characters */
+       pb.textEncodingHint = kTextEncodingUnknown;
+       pb.newRef = &newRef;
+
+       /* loop until we get fnfErr with a filename in both directories */
+       result = noErr;
+       while ( fnfErr != result )
+       {
+               /* convert startSeed to 8 character Unicode string */
+               uniqueName->length = 8;
+               for ( i = 0; i < 8; ++i )
+               {
+                       uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)];
+               }
+               
+               /* try in dir1 */
+               pb.ref = dir1;
+               result = PBMakeFSRefUnicodeSync(&pb);
+               if ( fnfErr == result )
+               {
+                       /* try in dir2 */
+                       pb.ref = dir2;
+                       result = PBMakeFSRefUnicodeSync(&pb);
+                       if ( fnfErr != result )
+                       {
+                               /* exit if anything other than noErr or fnfErr */
+                               require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed);
+                       }
+               }
+               else
+               {
+                       /* exit if anything other than noErr or fnfErr */
+                       require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed);
+               }
+               
+               /* increment seed for next pass through loop, */
+               /* or for next call to GenerateUniqueHFSUniStr */
+               ++(*startSeed);
+       }
+       
+       /* we have a unique file name which doesn't exist in dir1 or dir2 */
+       result = noErr;
+       
+Dir2PBMakeFSRefUnicodeSyncFailed:
+Dir1PBMakeFSRefUnicodeSyncFailed:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSExchangeObjectsCompat(
+       const FSRef *sourceRef,
+       const FSRef *destRef,
+       FSRef *newSourceRef,
+       FSRef *newDestRef)
+{
+       enum
+       {
+               /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
+               kGetCatInformationMask = (kFSCatInfoSettableInfo |
+                                                                 kFSCatInfoVolume |
+                                                                 kFSCatInfoParentDirID) &
+                                                                ~(kFSCatInfoContentMod | kFSCatInfoAttrMod),
+               /* set everything possible except for mod dates */
+               kSetCatinformationMask = kFSCatInfoSettableInfo &
+                                                                ~(kFSCatInfoContentMod | kFSCatInfoAttrMod)
+       };
+       
+       OSErr                                   result;
+       GetVolParmsInfoBuffer   volParmsInfo;
+       UInt32                                  infoSize;
+       FSCatalogInfo                   sourceCatalogInfo;      /* source file's catalog information */
+       FSCatalogInfo                   destCatalogInfo;        /* destination file's catalog information */
+       HFSUniStr255                    sourceName;                     /* source file's Unicode name */
+       HFSUniStr255                    destName;                       /* destination file's Unicode name */
+       FSRef                                   sourceCurrentRef;       /* FSRef to current location of source file throughout this function */
+       FSRef                                   destCurrentRef;         /* FSRef to current location of destination file throughout this function */
+       FSRef                                   sourceParentRef;        /* FSRef to parent directory of source file */
+       FSRef                                   destParentRef;          /* FSRef to parent directory of destination file */
+       HFSUniStr255                    sourceUniqueName;       /* unique name given to source file while exchanging it with destination */
+       HFSUniStr255                    destUniqueName;         /* unique name given to destination file while exchanging it with source */
+       long                                    theSeed;                        /* the seed for generating unique names */
+       Boolean                                 sameParentDirs;         /* true if source and destinatin parent directory is the same */
+       
+       /* check parameters */
+       require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr);
+       
+       /* output refs and current refs = input refs to start with */
+       BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef));
+       BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef));
+       
+       BlockMoveData(destRef, newDestRef, sizeof(FSRef));
+       BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef));
+
+       /* get source volume's vRefNum */
+       result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL);
+       require_noerr(result, DetermineSourceVRefNumFailed);
+       
+       /* see if that volume supports FSExchangeObjects */
+       result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer),
+               &volParmsInfo, &infoSize);
+       if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) )
+       {
+               /* yes - use FSExchangeObjects */
+               result = FSExchangeObjects(sourceRef, destRef);
+       }
+       else
+       {
+               /* no - emulate FSExchangeObjects */
+               
+               /* Note: The compatibility case won't work for files with *Btree control blocks. */
+               /* Right now the only *Btree files are created by the system. */
+               
+               /* get all catalog information and Unicode names for each file */
+               result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef);
+               require_noerr(result, SourceFSGetCatalogInfoFailed);
+               
+               result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef);
+               require_noerr(result, DestFSGetCatalogInfoFailed);
+               
+               /* make sure source and destination are on same volume */
+               require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr);
+               
+               /* make sure both files are *really* files */
+               require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) &&
+                                          (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr);
+               
+               /* generate 2 names that are unique in both directories */
+               theSeed = 0x4a696d4c;   /* a fine unlikely filename */
+               
+               result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName);
+               require_noerr(result, GenerateUniqueHFSUniStr1Failed);
+               
+               result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName);
+               require_noerr(result, GenerateUniqueHFSUniStr2Failed);
+
+               /* rename sourceCurrentRef to sourceUniqueName */
+               result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef);
+               require_noerr(result, FSRenameUnicode1Failed);
+               BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+               
+               /* rename destCurrentRef to destUniqueName */
+               result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef);
+               require_noerr(result, FSRenameUnicode2Failed);
+               BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
+               
+               /* are the source and destination parent directories the same? */
+               sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID );
+               if ( !sameParentDirs )
+               {
+                       /* move source file to dest parent directory */
+                       result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef);
+                       require_noerr(result, FSMoveObject1Failed);
+                       BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+                       
+                       /* move dest file to source parent directory */
+                       result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef);
+                       require_noerr(result, FSMoveObject2Failed);
+                       BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
+               }
+               
+               /* At this point, the files are in their new locations (if they were moved). */
+               /* The source file is named sourceUniqueName and is in the directory referred to */
+               /* by destParentRef. The destination file is named destUniqueName and is in the */
+               /* directory referred to by sourceParentRef. */
+                               
+               /* give source file the dest file's catalog information except for mod dates */
+               result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo);
+               require_noerr(result, FSSetCatalogInfo1Failed);
+               
+               /* give dest file the source file's catalog information except for mod dates */
+               result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo);
+               require_noerr(result, FSSetCatalogInfo2Failed);
+               
+               /* rename source file with dest file's name */
+               result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef);
+               require_noerr(result, FSRenameUnicode3Failed);
+               BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+               
+               /* rename dest file with source file's name */
+               result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef);
+               require_noerr(result, FSRenameUnicode4Failed);
+               
+               /* we're done with no errors, so swap newSourceRef and newDestRef */
+               BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef));
+               BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef));
+       }
+       
+       return ( result );
+       
+       /**********************/
+
+/* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
+/* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
+/* state and location they ended up in so that both files can be found by the calling code. */
+       
+FSRenameUnicode4Failed:
+
+       /* attempt to rename source file to sourceUniqueName */
+       if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) )
+       {
+               BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+       }
+
+FSRenameUnicode3Failed:
+
+       /* attempt to restore dest file's catalog information */
+       verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo));
+
+FSSetCatalogInfo2Failed:
+
+       /* attempt to restore source file's catalog information */
+       verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo));
+
+FSSetCatalogInfo1Failed:
+
+       if ( !sameParentDirs )
+       {
+               /* attempt to move dest file back to dest directory */
+               if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) )
+               {
+                       BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
+               }
+       }
+
+FSMoveObject2Failed:
+
+       if ( !sameParentDirs )
+       {
+               /* attempt to move source file back to source directory */
+               if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) )
+               {
+                       BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+               }
+       }
+
+FSMoveObject1Failed:
+
+       /* attempt to rename dest file to original name */
+       verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef));
+
+FSRenameUnicode2Failed:
+
+       /* attempt to rename source file to original name */
+       verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef));
+
+FSRenameUnicode1Failed:
+GenerateUniqueHFSUniStr2Failed:
+GenerateUniqueHFSUniStr1Failed:
+NotAFile:
+NotSameVolume:
+DestFSGetCatalogInfoFailed:
+SourceFSGetCatalogInfoFailed:
+DetermineSourceVRefNumFailed:  
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Shared Environment Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSLockRange(
+       SInt16 refNum,
+       SInt32 rangeLength,
+       SInt32 rangeStart)
+{
+       OSErr                   result;
+       ParamBlockRec   pb;
+
+       pb.ioParam.ioRefNum = refNum;
+       pb.ioParam.ioReqCount = rangeLength;
+       pb.ioParam.ioPosMode = fsFromStart;
+       pb.ioParam.ioPosOffset = rangeStart;
+       result = PBLockRangeSync(&pb);
+       require_noerr(result, PBLockRangeSync);
+       
+PBLockRangeSync:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSUnlockRange(
+       SInt16 refNum,
+       SInt32 rangeLength,
+       SInt32 rangeStart)
+{
+       OSErr                   result;
+       ParamBlockRec   pb;
+
+       pb.ioParam.ioRefNum = refNum;
+       pb.ioParam.ioReqCount = rangeLength;
+       pb.ioParam.ioPosMode = fsFromStart;
+       pb.ioParam.ioPosOffset = rangeStart;
+       result = PBUnlockRangeSync(&pb);
+       require_noerr(result, PBUnlockRangeSync);
+       
+PBUnlockRangeSync:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetDirAccess(
+       const FSRef *ref,
+       SInt32 *ownerID,                /* can be NULL */
+       SInt32 *groupID,                /* can be NULL */
+       SInt32 *accessRights)   /* can be NULL */
+{
+       OSErr                   result;
+       FSSpec                  spec;
+       HParamBlockRec  pb;
+       
+       /* get FSSpec from FSRef */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* get directory access info for FSSpec */
+       pb.accessParam.ioNamePtr = (StringPtr)spec.name;
+       pb.accessParam.ioVRefNum = spec.vRefNum;
+       pb.fileParam.ioDirID = spec.parID;
+       result = PBHGetDirAccessSync(&pb);
+       require_noerr(result, PBHGetDirAccessSync);
+       
+       /* return the IDs and access rights */
+       if ( NULL != ownerID )
+       {
+               *ownerID = pb.accessParam.ioACOwnerID;
+       }
+       if ( NULL != groupID )
+       {
+               *groupID = pb.accessParam.ioACGroupID;
+       }
+       if ( NULL != accessRights )
+       {
+               *accessRights = pb.accessParam.ioACAccess;
+       }
+       
+PBHGetDirAccessSync:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetDirAccess(
+       const FSRef *ref,
+       SInt32 ownerID,
+       SInt32 groupID,
+       SInt32 accessRights)
+{
+       OSErr                   result;
+       FSSpec                  spec;
+       HParamBlockRec  pb;
+
+       enum
+       {
+               /* Just the bits that can be set */
+               kSetDirAccessSettableMask = (kioACAccessBlankAccessMask +
+                       kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask +
+                       kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask +
+                       kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask)
+       };
+       
+       /* get FSSpec from FSRef */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* set directory access info for FSSpec */
+       pb.accessParam.ioNamePtr = (StringPtr)spec.name;
+       pb.accessParam.ioVRefNum = spec.vRefNum;
+       pb.fileParam.ioDirID = spec.parID;
+       pb.accessParam.ioACOwnerID = ownerID;
+       pb.accessParam.ioACGroupID = groupID;
+       pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask;
+       result = PBHSetDirAccessSync(&pb);
+       require_noerr(result, PBHSetDirAccessSync);
+       
+PBHSetDirAccessSync:
+FSGetCatalogInfo:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVolMountInfoSize(
+       FSVolumeRefNum volRefNum,
+       SInt16 *size)
+{
+       OSErr                   result;
+       ParamBlockRec   pb;
+
+       /* check parameters */
+       require_action(NULL != size, BadParameter, result = paramErr);
+       
+       pb.ioParam.ioNamePtr = NULL;
+       pb.ioParam.ioVRefNum = volRefNum;
+       pb.ioParam.ioBuffer = (Ptr)size;
+       result = PBGetVolMountInfoSize(&pb);
+       require_noerr(result, PBGetVolMountInfoSize);
+       
+PBGetVolMountInfoSize:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVolMountInfo(
+       FSVolumeRefNum volRefNum,
+       void *volMountInfo)
+{
+       OSErr                   result;
+       ParamBlockRec   pb;
+
+       /* check parameters */
+       require_action(NULL != volMountInfo, BadParameter, result = paramErr);
+       
+       pb.ioParam.ioNamePtr = NULL;
+       pb.ioParam.ioVRefNum = volRefNum;
+       pb.ioParam.ioBuffer = (Ptr)volMountInfo;
+       result = PBGetVolMountInfo(&pb);
+       require_noerr(result, PBGetVolMountInfo);
+       
+PBGetVolMountInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSVolumeMount(
+       const void *volMountInfo,
+       FSVolumeRefNum *volRefNum)
+{
+       OSErr                   result;
+       ParamBlockRec   pb;
+
+       /* check parameters */
+       require_action(NULL != volRefNum, BadParameter, result = paramErr);
+       
+       pb.ioParam.ioBuffer = (Ptr)volMountInfo;
+       result = PBVolumeMount(&pb);
+       require_noerr(result, PBVolumeMount);
+       
+       /* return the volume reference number */
+       *volRefNum = pb.ioParam.ioVRefNum;
+
+PBVolumeMount:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMapID(
+       FSVolumeRefNum volRefNum,
+       SInt32 ugID,
+       SInt16 objType,
+       Str31 name)
+{
+       OSErr                   result;
+       HParamBlockRec  pb;
+
+       /* check parameters */
+       require_action(NULL != name, BadParameter, result = paramErr);
+       
+       pb.objParam.ioNamePtr = NULL;
+       pb.objParam.ioVRefNum = volRefNum;
+       pb.objParam.ioObjType = objType;
+       pb.objParam.ioObjNamePtr = name;
+       pb.objParam.ioObjID = ugID;
+       result = PBHMapIDSync(&pb);
+       require_noerr(result, PBHMapIDSync);
+       
+PBHMapIDSync:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMapName(
+       FSVolumeRefNum volRefNum,
+       ConstStr255Param name,
+       SInt16 objType,
+       SInt32 *ugID)
+{
+       OSErr                   result;
+       HParamBlockRec  pb;
+
+       /* check parameters */
+       require_action(NULL != ugID, BadParameter, result = paramErr);
+       
+       pb.objParam.ioNamePtr = NULL;
+       pb.objParam.ioVRefNum = volRefNum;
+       pb.objParam.ioObjType = objType;
+       pb.objParam.ioObjNamePtr = (StringPtr)name;
+       result = PBHMapNameSync(&pb);
+       require_noerr(result, PBHMapNameSync);
+       
+       /* return the user or group ID */
+       *ugID = pb.objParam.ioObjID;
+       
+PBHMapNameSync:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCopyFile(
+       const FSRef *srcFileRef,
+       const FSRef *dstDirectoryRef,
+       UniCharCount nameLength,
+       const UniChar *copyName,        /* can be NULL (no rename during copy) */
+       TextEncoding textEncodingHint,
+       FSRef *newRef)                          /* can be NULL */
+{
+       OSErr                                   result;
+       FSSpec                                  srcFileSpec;
+       FSCatalogInfo                   catalogInfo;
+       HParamBlockRec                  pb;
+       Str31                                   hfsName;
+       GetVolParmsInfoBuffer   volParmsInfo;
+       UInt32                                  infoSize;
+       
+       /* get source FSSpec from source FSRef */
+       result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
+       require_noerr(result, FSGetCatalogInfo_srcFileRef);
+       
+       /* Make sure the volume supports CopyFile */
+       result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
+               &volParmsInfo, &infoSize);
+       require_action((noErr == result) && VolHasCopyFile(&volParmsInfo),
+               NoCopyFileSupport, result = paramErr);
+
+       /* get destination volume reference number and destination directory ID from destination FSRef */
+       result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
+               &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
+       
+       /* tell the server to copy the object */
+       pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
+       pb.copyParam.ioDirID = srcFileSpec.parID;
+       pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
+       pb.copyParam.ioDstVRefNum = catalogInfo.volume;
+       pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
+       pb.copyParam.ioNewName = NULL;
+       if ( NULL != copyName )
+       {
+               result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName);
+               require_noerr(result, UnicodeNameGetHFSName);
+               
+               pb.copyParam.ioCopyName = hfsName;
+       }
+       else
+       {
+               pb.copyParam.ioCopyName = NULL;
+       }
+       result = PBHCopyFileSync(&pb);
+       require_noerr(result, PBHCopyFileSync);
+       
+       if ( NULL != newRef )
+       {
+               verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID,
+                       pb.copyParam.ioCopyName, newRef));
+       }
+               
+PBHCopyFileSync:
+UnicodeNameGetHFSName:
+FSGetCatalogInfo_dstDirectoryRef:
+NoCopyFileSupport:
+FSGetCatalogInfo_srcFileRef:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMoveRename(
+       const FSRef *srcFileRef,
+       const FSRef *dstDirectoryRef,
+       UniCharCount nameLength,
+       const UniChar *moveName,        /* can be NULL (no rename during move) */
+       TextEncoding textEncodingHint,
+       FSRef *newRef)                          /* can be NULL */
+{
+       OSErr                                   result;
+       FSSpec                                  srcFileSpec;
+       FSCatalogInfo                   catalogInfo;
+       HParamBlockRec                  pb;
+       Str31                                   hfsName;
+       GetVolParmsInfoBuffer   volParmsInfo;
+       UInt32                                  infoSize;
+       
+       /* get source FSSpec from source FSRef */
+       result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
+       require_noerr(result, FSGetCatalogInfo_srcFileRef);
+       
+       /* Make sure the volume supports MoveRename */
+       result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
+               &volParmsInfo, &infoSize);
+       require_action((noErr == result) && VolHasMoveRename(&volParmsInfo),
+               NoMoveRenameSupport, result = paramErr);
+
+       /* get destination volume reference number and destination directory ID from destination FSRef */
+       result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
+               &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
+       
+       /* make sure the source and destination are on the same volume */
+       require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
+       
+       /* tell the server to move and rename the object */
+       pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
+       pb.copyParam.ioDirID = srcFileSpec.parID;
+       pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
+       pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
+       pb.copyParam.ioNewName = NULL;
+       if ( NULL != moveName )
+       {
+               result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName);
+               require_noerr(result, UnicodeNameGetHFSName);
+               
+               pb.copyParam.ioCopyName = hfsName;
+       }
+       else
+       {
+               pb.copyParam.ioCopyName = NULL;
+       }
+       result = PBHMoveRenameSync(&pb);
+       require_noerr(result, PBHMoveRenameSync);
+       
+       if ( NULL != newRef )
+       {
+               verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID,
+                       pb.copyParam.ioCopyName, newRef));
+       }
+       
+PBHMoveRenameSync:
+UnicodeNameGetHFSName:
+NotSameVolume:
+FSGetCatalogInfo_dstDirectoryRef:
+NoMoveRenameSupport:
+FSGetCatalogInfo_srcFileRef:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- File ID Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSResolveFileIDRef(
+       FSVolumeRefNum volRefNum,
+       SInt32 fileID,
+       FSRef *ref)
+{
+       OSErr           result;
+       FIDParam        pb;
+       Str255          tempStr;
+       
+       /* check parameters */
+       require_action(NULL != ref, BadParameter, result = paramErr);
+       
+       /* resolve the file ID reference */
+       tempStr[0] = 0;
+       pb.ioNamePtr = tempStr;
+       pb.ioVRefNum = volRefNum;
+       pb.ioFileID = fileID;
+       result = PBResolveFileIDRefSync((HParmBlkPtr)&pb);
+       require_noerr(result, PBResolveFileIDRefSync);
+       
+       /* and then make an FSRef to the file */
+       result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref);
+       require_noerr(result, FSMakeFSRef);
+       
+FSMakeFSRef:
+PBResolveFileIDRefSync:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCreateFileIDRef(
+       const FSRef *ref,
+       SInt32 *fileID)
+{
+       OSErr           result;
+       FSSpec          spec;
+       FIDParam        pb;
+       
+       /* check parameters */
+       require_action(NULL != fileID, BadParameter, result = paramErr);
+       
+       /* Get an FSSpec from the FSRef */
+       result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* Create (or get) the file ID reference using the FSSpec */
+       pb.ioNamePtr = (StringPtr)spec.name;
+       pb.ioVRefNum = spec.vRefNum;
+       pb.ioSrcDirID = spec.parID;
+       result = PBCreateFileIDRefSync((HParmBlkPtr)&pb);
+       require((noErr == result) || (fidExists == result) || (afpIDExists == result),
+               PBCreateFileIDRefSync);
+       
+       /* return the file ID reference */
+       *fileID = pb.ioFileID;
+       
+PBCreateFileIDRefSync:
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Utility Routines -----
+
+/*****************************************************************************/
+
+Ptr
+GetTempBuffer(
+       ByteCount buffReqSize,
+       ByteCount *buffActSize)
+{
+       enum
+       {
+               kSlopMemory = 0x00008000        /* 32K - Amount of free memory to leave when allocating buffers */
+       };
+       
+       Ptr tempPtr;
+       
+       /* check parameters */
+       require_action(NULL != buffActSize, BadParameter, tempPtr = NULL);
+       
+       /* Make request a multiple of 4K bytes */
+       buffReqSize = buffReqSize & 0xfffff000;
+       
+       if ( buffReqSize < 0x00001000 )
+       {
+               /* Request was smaller than 4K bytes - make it 4K */
+               buffReqSize = 0x00001000;
+       }
+       
+       /* Attempt to allocate the memory */
+       tempPtr = NewPtr(buffReqSize);
+       
+       /* If request failed, go to backup plan */
+       if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) )
+       {
+               /*
+               **      Try to get largest 4K byte block available
+               **      leaving some slop for the toolbox if possible
+               */
+               long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000;
+               
+               buffReqSize = MaxBlock() & 0xfffff000;
+               
+               if ( buffReqSize > freeMemory )
+               {
+                       buffReqSize = freeMemory;
+               }
+               
+               if ( buffReqSize == 0 )
+               {
+                       buffReqSize = 0x00001000;
+               }
+               
+               tempPtr = NewPtr(buffReqSize);
+       }
+       
+       /* Return bytes allocated */
+       if ( tempPtr != NULL )
+       {
+               *buffActSize = buffReqSize;
+       }
+       else
+       {
+               *buffActSize = 0;
+       }
+       
+BadParameter:
+
+       return ( tempPtr );
+}
+
+/*****************************************************************************/
+
+OSErr
+FileRefNumGetFSRef(
+       short refNum,
+       FSRef *ref)
+{
+       return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetDefault(
+       const FSRef *newDefault,
+       FSRef *oldDefault)
+{
+       OSErr                   result;
+       FSVolumeRefNum  vRefNum;
+       long                    dirID;
+       FSCatalogInfo   catalogInfo;
+       
+       /* check parameters */
+       require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr);
+       
+       /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
+       result = FSGetCatalogInfo(newDefault,
+               kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
+               &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* Make sure newDefault is a directory */
+       require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory,
+               result = dirNFErr);
+       
+       /* Get the current working directory. */
+       result = HGetVol(NULL, &vRefNum, &dirID);
+       require_noerr(result, HGetVol);
+       
+       /* Return the oldDefault FSRef */
+       result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault);
+       require_noerr(result, FSMakeFSRef);
+       
+       /* Set the new current working directory */
+       result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
+       require_noerr(result, HSetVol);
+
+HSetVol:
+FSMakeFSRef:
+HGetVol:
+NewDefaultNotDirectory:
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSRestoreDefault(
+       const FSRef *oldDefault)
+{
+       OSErr                   result;
+       FSCatalogInfo   catalogInfo;
+       
+       /* check parameters */
+       require_action(NULL != oldDefault, BadParameter, result = paramErr);
+       
+       /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
+       result = FSGetCatalogInfo(oldDefault,
+               kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
+               &catalogInfo, NULL, NULL, NULL);
+       require_noerr(result, FSGetCatalogInfo);
+       
+       /* Make sure oldDefault is a directory */
+       require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory,
+               result = dirNFErr);
+       
+       /* Set the current working directory to oldDefault */
+       result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
+       require_noerr(result, HSetVol);
+
+HSetVol:
+OldDefaultNotDirectory:
+FSGetCatalogInfo:
+BadParameter:
+
+       return ( result );
+}
+
+/*****************************************************************************/