Back to index

lightning-sunbird  0.9+nobinonly
MoreFilesX.c
Go to the documentation of this file.
00001 /*
00002        File:         MoreFilesX.c
00003 
00004        Contains:     A collection of useful high-level File Manager routines
00005                             which use the HFS Plus APIs wherever possible.
00006 
00007        Version:      MoreFilesX 1.0.1
00008 
00009        Copyright:    © 1992-2002 by Apple Computer, Inc., all rights reserved.
00010 
00011        Disclaimer:   IMPORTANT:  This Apple software is supplied to you by Apple Computer, Inc.
00012                             ("Apple") in consideration of your agreement to the following terms, and your
00013                             use, installation, modification or redistribution of this Apple software
00014                             constitutes acceptance of these terms.  If you do not agree with these terms,
00015                             please do not use, install, modify or redistribute this Apple software.
00016 
00017                             In consideration of your agreement to abide by the following terms, and subject
00018                             to these terms, Apple grants you a personal, non-exclusive license, under Apple’s
00019                             copyrights in this original Apple software (the "Apple Software"), to use,
00020                             reproduce, modify and redistribute the Apple Software, with or without
00021                             modifications, in source and/or binary forms; provided that if you redistribute
00022                             the Apple Software in its entirety and without modifications, you must retain
00023                             this notice and the following text and disclaimers in all such redistributions of
00024                             the Apple Software.  Neither the name, trademarks, service marks or logos of
00025                             Apple Computer, Inc. may be used to endorse or promote products derived from the
00026                             Apple Software without specific prior written permission from Apple.  Except as
00027                             expressly stated in this notice, no other rights or licenses, express or implied,
00028                             are granted by Apple herein, including but not limited to any patent rights that
00029                             may be infringed by your derivative works or by other works in which the Apple
00030                             Software may be incorporated.
00031 
00032                             The Apple Software is provided by Apple on an "AS IS" basis.  APPLE MAKES NO
00033                             WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
00034                             WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00035                             PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
00036                             COMBINATION WITH YOUR PRODUCTS.
00037 
00038                             IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
00039                             CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
00040                             GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
00041                             ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
00042                             OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
00043                             (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
00044                             ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00045 
00046        File Ownership:
00047 
00048               DRI:                        Apple Macintosh Developer Technical Support
00049 
00050               Other Contact:              For bug reports, consult the following page on
00051                                                  the World Wide Web:
00052                                                         http://developer.apple.com/bugreporter/
00053 
00054               Technology:                 DTS Sample Code
00055 
00056        Writers:
00057 
00058               (JL)   Jim Luther
00059 
00060        Change History (most recent first):
00061 
00062                <4>    8/22/02      JL            [3016251]  Changed FSMoveRenameObjectUnicode to not use
00063                                                                the Temporary folder because it isn't available on
00064                                                                NFS volumes.
00065                <3>    4/19/02      JL            [2853905]  Fixed #if test around header includes.
00066                <2>    4/19/02      JL            [2850624]  Fixed C++ compile errors and Project Builder
00067                                                                warnings.
00068                <2>    4/19/02      JL            [2853901]  Updated standard disclaimer.
00069                <1>    1/25/02      JL            MoreFilesX 1.0
00070 */
00071 
00072 #if defined(__MACH__)
00073        #include <Carbon/Carbon.h>
00074        #include <string.h>
00075 #else
00076        #include <Carbon.h>
00077        #include <string.h>
00078 #endif
00079 
00080 #include "MoreFilesX.h"
00081 
00082 /* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */
00083 #ifndef BuildingMoreFilesXForMacOS9
00084        #define BuildingMoreFilesXForMacOS9 0
00085 #endif
00086 
00087 /*****************************************************************************/
00088 
00089 #pragma mark ----- Local type definitions -----
00090 
00091 struct FSIterateContainerGlobals
00092 {
00093        IterateContainerFilterProcPtr      iterateFilter;       /* pointer to IterateFilterProc */
00094        FSCatalogInfoBitmap                       whichInfo;           /* fields of the CatalogInfo to get */
00095        FSCatalogInfo                             catalogInfo;  /* FSCatalogInfo */
00096        FSRef                                            ref;                 /* FSRef */
00097        FSSpec                                           spec;                /* FSSpec */
00098        FSSpec                                           *specPtr;            /* pointer to spec field, or NULL */
00099        HFSUniStr255                              name;                /* HFSUniStr255 */
00100        HFSUniStr255                              *namePtr;            /* pointer to name field, or NULL */
00101        void                                             *yourDataPtr; /* a pointer to caller supplied data the filter may need to access */
00102        ItemCount                                        maxLevels;           /* maximum levels to iterate through */
00103        ItemCount                                        currentLevel; /* the current level FSIterateContainerLevel is on */
00104        Boolean                                                 quitFlag;            /* set to true if filter wants to kill interation */
00105        Boolean                                                 containerChanged; /* temporary - set to true if the current container changed during iteration */
00106        OSErr                                            result;                     /* result */
00107        ItemCount                                        actualObjects;       /* number of objects returned */
00108 };
00109 typedef struct FSIterateContainerGlobals FSIterateContainerGlobals;
00110 
00111 struct FSDeleteContainerGlobals
00112 {
00113        OSErr                                            result;                     /* result */
00114        ItemCount                                        actualObjects;       /* number of objects returned */
00115        FSCatalogInfo                             catalogInfo;  /* FSCatalogInfo */
00116 };
00117 typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals;
00118 
00119 /*****************************************************************************/
00120 
00121 #pragma mark ----- Local prototypes -----
00122 
00123 static
00124 void
00125 FSDeleteContainerLevel(
00126        const FSRef *container,
00127        FSDeleteContainerGlobals *theGlobals);
00128 
00129 static
00130 void
00131 FSIterateContainerLevel(
00132        FSIterateContainerGlobals *theGlobals);
00133 
00134 static
00135 OSErr
00136 GenerateUniqueHFSUniStr(
00137        long *startSeed,
00138        const FSRef *dir1,
00139        const FSRef *dir2,
00140        HFSUniStr255 *uniqueName);
00141 
00142 /*****************************************************************************/
00143 
00144 #pragma mark ----- File Access Routines -----
00145 
00146 /*****************************************************************************/
00147 
00148 OSErr
00149 FSCopyFork(
00150        SInt16 srcRefNum,
00151        SInt16 dstRefNum,
00152        void *copyBufferPtr,
00153        ByteCount copyBufferSize)
00154 {
00155        OSErr         srcResult;
00156        OSErr         dstResult;
00157        OSErr         result;
00158        SInt64        forkSize;
00159        ByteCount     readActualCount;
00160        
00161        /* check input parameters */
00162        require_action((NULL != copyBufferPtr) && (0 != copyBufferSize), BadParameter, result = paramErr);
00163        
00164        /* get source fork size */
00165        result = FSGetForkSize(srcRefNum, &forkSize);
00166        require_noerr(result, SourceFSGetForkSizeFailed);
00167        
00168        /* allocate disk space for destination fork */
00169        result = FSSetForkSize(dstRefNum, fsFromStart, forkSize);
00170        require_noerr(result, DestinationFSSetForkSizeFailed);
00171        
00172        /* reset source fork's position to 0 */
00173        result = FSSetForkPosition(srcRefNum, fsFromStart, 0);
00174        require_noerr(result, SourceFSSetForkPositionFailed);
00175        
00176        /* reset destination fork's position to 0 */
00177        result = FSSetForkPosition(dstRefNum, fsFromStart, 0);
00178        require_noerr(result, DestinationFSSetForkPositionFailed);
00179 
00180        /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */
00181        /* This will make writes on local volumes faster */
00182        if ( (copyBufferSize >= 0x00001000) && ((copyBufferSize & 0x00000fff) != 0) )
00183        {
00184               copyBufferSize &= ~(0x00001000 - 1);
00185        }
00186        
00187        /* copy source to destination */
00188        srcResult = dstResult = noErr;
00189        while ( (noErr == srcResult) && (noErr == dstResult) )
00190        {
00191               srcResult = FSReadFork(srcRefNum, fsAtMark + noCacheMask, 0, copyBufferSize, copyBufferPtr, &readActualCount);
00192               dstResult = FSWriteFork(dstRefNum, fsAtMark + noCacheMask, 0, readActualCount, copyBufferPtr, NULL);
00193        }
00194        
00195        /* make sure there were no errors at the destination */
00196        require_noerr_action(dstResult, DestinationFSWriteForkFailed, result = dstResult);
00197        
00198        /* make sure the error at the source was eofErr */
00199        require_action(eofErr == srcResult, SourceResultNotEofErr, result = srcResult);
00200        
00201        /* everything went as expected */
00202        result = noErr;
00203 
00204 SourceResultNotEofErr:
00205 DestinationFSWriteForkFailed:
00206 DestinationFSSetForkPositionFailed:
00207 SourceFSSetForkPositionFailed:
00208 DestinationFSSetForkSizeFailed:
00209 SourceFSGetForkSizeFailed:
00210 BadParameter:
00211 
00212        return ( result );
00213 }
00214 
00215 /*****************************************************************************/
00216 
00217 #pragma mark ----- Volume Access Routines -----
00218 
00219 /*****************************************************************************/ 
00220 
00221 OSErr
00222 FSGetVolParms(
00223        FSVolumeRefNum volRefNum,
00224        UInt32 bufferSize,
00225        GetVolParmsInfoBuffer *volParmsInfo,
00226        UInt32 *actualInfoSize)
00227 {
00228        OSErr                result;
00229        HParamBlockRec       pb;
00230        
00231        /* check parameters */
00232        require_action((NULL != volParmsInfo) && (NULL != actualInfoSize),
00233               BadParameter, result = paramErr);
00234        
00235        pb.ioParam.ioNamePtr = NULL;
00236        pb.ioParam.ioVRefNum = volRefNum;
00237        pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
00238        pb.ioParam.ioReqCount = (SInt32)bufferSize;
00239        result = PBHGetVolParmsSync(&pb);
00240        require_noerr(result, PBHGetVolParmsSync);
00241        
00242        /* return number of bytes the file system returned in volParmsInfo buffer */
00243        *actualInfoSize = (UInt32)pb.ioParam.ioActCount;
00244        
00245 PBHGetVolParmsSync:
00246 BadParameter:
00247 
00248        return ( result );
00249 }
00250 
00251 /*****************************************************************************/
00252 
00253 OSErr
00254 FSGetVRefNum(
00255        const FSRef *ref,
00256        FSVolumeRefNum *vRefNum)
00257 {
00258        OSErr                result;
00259        FSCatalogInfo catalogInfo;
00260        
00261        /* check parameters */
00262        require_action(NULL != vRefNum, BadParameter, result = paramErr);
00263        
00264        /* get the volume refNum from the FSRef */
00265        result = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
00266        require_noerr(result, FSGetCatalogInfo);
00267        
00268        /* return volume refNum from catalogInfo */
00269        *vRefNum = catalogInfo.volume;
00270        
00271 FSGetCatalogInfo:
00272 BadParameter:
00273 
00274        return ( result );
00275 }
00276 
00277 /*****************************************************************************/
00278 
00279 OSErr
00280 FSGetVInfo(
00281        FSVolumeRefNum volume,
00282        HFSUniStr255 *volumeName,   /* can be NULL */
00283        UInt64 *freeBytes,                 /* can be NULL */
00284        UInt64 *totalBytes)                /* can be NULL */
00285 {
00286        OSErr                       result;
00287        FSVolumeInfo         info;
00288        
00289        /* ask for the volume's sizes only if needed */
00290        result = FSGetVolumeInfo(volume, 0, NULL,
00291               (((NULL != freeBytes) || (NULL != totalBytes)) ? kFSVolInfoSizes : kFSVolInfoNone),
00292               &info, volumeName, NULL);
00293        require_noerr(result, FSGetVolumeInfo);
00294        
00295        if ( NULL != freeBytes )
00296        {
00297               *freeBytes = info.freeBytes;
00298        }
00299        if ( NULL != totalBytes )
00300        {
00301               *totalBytes = info.totalBytes;
00302        }
00303        
00304 FSGetVolumeInfo:
00305 
00306        return ( result );
00307 }
00308 
00309 /*****************************************************************************/
00310 
00311 OSErr
00312 FSGetVolFileSystemID(
00313        FSVolumeRefNum volume,
00314        UInt16 *fileSystemID,       /* can be NULL */
00315        UInt16 *signature)          /* can be NULL */
00316 {
00317        OSErr                result;
00318        FSVolumeInfo  info;
00319        
00320        result = FSGetVolumeInfo(volume, 0, NULL, kFSVolInfoFSInfo, &info, NULL, NULL);
00321        require_noerr(result, FSGetVolumeInfo);
00322        
00323        if ( NULL != fileSystemID )
00324        {
00325               *fileSystemID = info.filesystemID;
00326        }
00327        if ( NULL != signature )
00328        {
00329               *signature = info.signature;
00330        }
00331        
00332 FSGetVolumeInfo:
00333 
00334        return ( result );
00335 }
00336 
00337 /*****************************************************************************/
00338 
00339 OSErr
00340 FSGetMountedVolumes(
00341        FSRef ***volumeRefsHandle,  /* pointer to handle of FSRefs */
00342        ItemCount *numVolumes)
00343 {
00344        OSErr         result;
00345        OSErr         memResult;
00346        ItemCount     volumeIndex;
00347        FSRef         ref;
00348        
00349        /* check parameters */
00350        require_action((NULL != volumeRefsHandle) && (NULL != numVolumes),
00351               BadParameter, result = paramErr);
00352        
00353        /* No volumes yet */
00354        *numVolumes = 0;
00355        
00356        /* Allocate a handle for the results */
00357        *volumeRefsHandle = (FSRef **)NewHandle(0);
00358        require_action(NULL != *volumeRefsHandle, NewHandle, result = memFullErr);
00359        
00360        /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */
00361        volumeIndex = 1;
00362        do
00363        {
00364               result = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoNone, NULL, NULL, &ref);
00365               if ( noErr == result )
00366               {
00367                      /* concatenate the FSRef to the end of the handle */
00368                      PtrAndHand(&ref, (Handle)*volumeRefsHandle, sizeof(FSRef));
00369                      memResult = MemError();
00370                      require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
00371                      
00372                      ++(*numVolumes);     /* increment the volume count */
00373                      ++volumeIndex;              /* and the volumeIndex to get the next volume*/
00374               }
00375        } while ( noErr == result );
00376        
00377        /* nsvErr is OK -- it just means there are no more volumes */
00378        require(nsvErr == result, FSGetVolumeInfo);
00379               
00380        return ( noErr );
00381        
00382        /**********************/
00383        
00384 MemoryAllocationFailed:
00385 FSGetVolumeInfo:
00386 
00387        /* dispose of handle if already allocated and clear the outputs */
00388        if ( NULL != *volumeRefsHandle )
00389        {
00390               DisposeHandle((Handle)*volumeRefsHandle);
00391               *volumeRefsHandle = NULL;
00392        }
00393        *numVolumes = 0;
00394        
00395 NewHandle:
00396 BadParameter:
00397 
00398        return ( result );
00399 }
00400 
00401 /*****************************************************************************/
00402 
00403 #pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
00404 
00405 /*****************************************************************************/
00406 
00407 OSErr
00408 FSRefMakeFSSpec(
00409        const FSRef *ref,
00410        FSSpec *spec)
00411 {
00412        OSErr  result;
00413        
00414        /* check parameters */
00415        require_action(NULL != spec, BadParameter, result = paramErr);
00416        
00417        result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
00418        require_noerr(result, FSGetCatalogInfo);
00419        
00420 FSGetCatalogInfo:
00421 BadParameter:
00422 
00423        return ( result );
00424 }
00425 
00426 /*****************************************************************************/
00427 
00428 OSErr
00429 FSMakeFSRef(
00430        FSVolumeRefNum volRefNum,
00431        SInt32 dirID,
00432        ConstStr255Param name,
00433        FSRef *ref)
00434 {
00435        OSErr         result;
00436        FSRefParam    pb;
00437        
00438        /* check parameters */
00439        require_action(NULL != ref, BadParameter, result = paramErr);
00440        
00441        pb.ioVRefNum = volRefNum;
00442        pb.ioDirID = dirID;
00443        pb.ioNamePtr = (StringPtr)name;
00444        pb.newRef = ref;
00445        result = PBMakeFSRefSync(&pb);
00446        require_noerr(result, PBMakeFSRefSync);
00447        
00448 PBMakeFSRefSync:
00449 BadParameter:
00450 
00451        return ( result );
00452 }
00453 
00454 /*****************************************************************************/
00455 
00456 OSStatus
00457 FSMakePath(
00458        SInt16 volRefNum,
00459        SInt32 dirID,
00460        ConstStr255Param name,
00461        UInt8 *path,
00462        UInt32 maxPathSize)
00463 {
00464        OSStatus      result;
00465        FSRef         ref;
00466        
00467        /* check parameters */
00468        require_action(NULL != path, BadParameter, result = paramErr);
00469        
00470        /* convert the inputs to an FSRef */
00471        result = FSMakeFSRef(volRefNum, dirID, name, &ref);
00472        require_noerr(result, FSMakeFSRef);
00473        
00474        /* and then convert the FSRef to a path */
00475        result = FSRefMakePath(&ref, path, maxPathSize);
00476        require_noerr(result, FSRefMakePath);
00477        
00478 FSRefMakePath:
00479 FSMakeFSRef:
00480 BadParameter:
00481 
00482        return ( result );
00483 }
00484 
00485 /*****************************************************************************/
00486 
00487 OSStatus
00488 FSPathMakeFSSpec(
00489        const UInt8 *path,
00490        FSSpec *spec,
00491        Boolean *isDirectory)       /* can be NULL */
00492 {
00493        OSStatus      result;
00494        FSRef         ref;
00495        
00496        /* check parameters */
00497        require_action(NULL != spec, BadParameter, result = paramErr);
00498        
00499        /* convert the POSIX path to an FSRef */
00500        result = FSPathMakeRef(path, &ref, isDirectory);
00501        require_noerr(result, FSPathMakeRef);
00502        
00503        /* and then convert the FSRef to an FSSpec */
00504        result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
00505        require_noerr(result, FSGetCatalogInfo);
00506        
00507 FSGetCatalogInfo:
00508 FSPathMakeRef:
00509 BadParameter:
00510 
00511        return ( result );
00512 }
00513 
00514 /*****************************************************************************/
00515 
00516 OSErr
00517 UnicodeNameGetHFSName(
00518        UniCharCount nameLength,
00519        const UniChar *name,
00520        TextEncoding textEncodingHint,
00521        Boolean isVolumeName,
00522        Str31 hfsName)
00523 {
00524        OSStatus                    result;
00525        ByteCount                   unicodeByteLength;
00526        ByteCount                   unicodeBytesConverted;
00527        ByteCount                   actualPascalBytes;
00528        UnicodeMapping              uMapping;
00529        UnicodeToTextInfo    utInfo;
00530        
00531        /* check parameters */
00532        require_action(NULL != hfsName, BadParameter, result = paramErr);
00533        
00534        /* make sure output is valid in case we get errors or there's nothing to convert */
00535        hfsName[0] = 0;
00536        
00537        unicodeByteLength = nameLength * sizeof(UniChar);
00538        if ( 0 == unicodeByteLength )
00539        {
00540               /* do nothing */
00541               result = noErr;
00542        }
00543        else
00544        {
00545               /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
00546               if ( kTextEncodingUnknown == textEncodingHint )
00547               {
00548                      ScriptCode                  script;
00549                      RegionCode                  region;
00550                      
00551                      script = (ScriptCode)GetScriptManagerVariable(smSysScript);
00552                      region = (RegionCode)GetScriptManagerVariable(smRegionCode);
00553                      result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
00554                             NULL, &textEncodingHint );
00555                      if ( paramErr == result )
00556                      {
00557                             /* ok, ignore the region and try again */
00558                             result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
00559                                    kTextRegionDontCare, NULL, &textEncodingHint );
00560                      }
00561                      if ( noErr != result )
00562                      {
00563                             /* ok... try something */
00564                             textEncodingHint = kTextEncodingMacRoman;
00565                      }
00566               }
00567               
00568               uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
00569                      kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
00570               uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
00571               uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
00572        
00573               result = CreateUnicodeToTextInfo(&uMapping, &utInfo);
00574               require_noerr(result, CreateUnicodeToTextInfo);
00575               
00576               result = ConvertFromUnicodeToText(utInfo, unicodeByteLength, name, kUnicodeLooseMappingsMask,
00577                      0, NULL, 0, NULL,    /* offsetCounts & offsetArrays */
00578                      isVolumeName ? kHFSMaxVolumeNameChars : kHFSMaxFileNameChars,
00579                      &unicodeBytesConverted, &actualPascalBytes, &hfsName[1]);
00580               require_noerr(result, ConvertFromUnicodeToText);
00581               
00582               hfsName[0] = (unsigned char)actualPascalBytes;   /* fill in length byte */
00583 
00584 ConvertFromUnicodeToText:
00585               
00586               /* verify the result in debug builds -- there's really not anything you can do if it fails */
00587               verify_noerr(DisposeUnicodeToTextInfo(&utInfo));
00588        }
00589        
00590 CreateUnicodeToTextInfo:    
00591 BadParameter:
00592 
00593        return ( result );
00594 }
00595 
00596 /*****************************************************************************/
00597 
00598 OSErr
00599 HFSNameGetUnicodeName(
00600        ConstStr31Param hfsName,
00601        TextEncoding textEncodingHint,
00602        HFSUniStr255 *unicodeName)
00603 {
00604        ByteCount                   unicodeByteLength;
00605        OSStatus                    result;
00606        UnicodeMapping              uMapping;
00607        TextToUnicodeInfo    tuInfo;
00608        ByteCount                   pascalCharsRead;
00609        
00610        /* check parameters */
00611        require_action(NULL != unicodeName, BadParameter, result = paramErr);
00612        
00613        /* make sure output is valid in case we get errors or there's nothing to convert */
00614        unicodeName->length = 0;
00615        
00616        if ( 0 == StrLength(hfsName) )
00617        {
00618               result = noErr;
00619        }
00620        else
00621        {
00622               /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
00623               if ( kTextEncodingUnknown == textEncodingHint )
00624               {
00625                      ScriptCode                  script;
00626                      RegionCode                  region;
00627                      
00628                      script = GetScriptManagerVariable(smSysScript);
00629                      region = GetScriptManagerVariable(smRegionCode);
00630                      result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
00631                             NULL, &textEncodingHint);
00632                      if ( paramErr == result )
00633                      {
00634                             /* ok, ignore the region and try again */
00635                             result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
00636                                    kTextRegionDontCare, NULL, &textEncodingHint);
00637                      }
00638                      if ( noErr != result )
00639                      {
00640                             /* ok... try something */
00641                             textEncodingHint = kTextEncodingMacRoman;
00642                      }
00643               }
00644               
00645               uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
00646                      kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
00647               uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
00648               uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
00649        
00650               result = CreateTextToUnicodeInfo(&uMapping, &tuInfo);
00651               require_noerr(result, CreateTextToUnicodeInfo);
00652                      
00653               result = ConvertFromTextToUnicode(tuInfo, hfsName[0], &hfsName[1],
00654                      0,                                                      /* no control flag bits */
00655                      0, NULL, 0, NULL,                         /* offsetCounts & offsetArrays */
00656                      sizeof(unicodeName->unicode),      /* output buffer size in bytes */
00657                      &pascalCharsRead, &unicodeByteLength, unicodeName->unicode);
00658               require_noerr(result, ConvertFromTextToUnicode);
00659               
00660               /* convert from byte count to char count */
00661               unicodeName->length = unicodeByteLength / sizeof(UniChar);
00662 
00663 ConvertFromTextToUnicode:
00664 
00665               /* verify the result in debug builds -- there's really not anything you can do if it fails */
00666               verify_noerr(DisposeTextToUnicodeInfo(&tuInfo));
00667        }
00668        
00669 CreateTextToUnicodeInfo:
00670 BadParameter:
00671 
00672        return ( result );
00673 }
00674 
00675 /*****************************************************************************/
00676 
00677 #pragma mark ----- File/Directory Manipulation Routines -----
00678 
00679 /*****************************************************************************/
00680 
00681 Boolean FSRefValid(const FSRef *ref)
00682 {
00683        return ( noErr == FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, NULL, NULL) );
00684 }
00685 
00686 /*****************************************************************************/
00687 
00688 OSErr
00689 FSGetParentRef(
00690        const FSRef *ref,
00691        FSRef *parentRef)
00692 {
00693        OSErr  result;
00694        FSCatalogInfo catalogInfo;
00695        
00696        /* check parameters */
00697        require_action(NULL != parentRef, BadParameter, result = paramErr);
00698        
00699        result = FSGetCatalogInfo(ref, kFSCatInfoNodeID, &catalogInfo, NULL, NULL, parentRef);
00700        require_noerr(result, FSGetCatalogInfo);
00701        
00702        /*
00703         * Note: FSRefs always point to real file system objects. So, there cannot
00704         * be a FSRef to the parent of volume root directories. Early versions of
00705         * Mac OS X do not handle this case correctly and incorrectly return a
00706         * FSRef for the parent of volume root directories instead of returning an
00707         * invalid FSRef (a cleared FSRef is invalid). The next three lines of code
00708         * ensure that you won't run into this bug. WW9D!
00709         */
00710        if ( fsRtDirID == catalogInfo.nodeID )
00711        {
00712               /* clear parentRef and return noErr which is the proper behavior */
00713               memset(parentRef, 0, sizeof(FSRef));
00714        }
00715 
00716 FSGetCatalogInfo:
00717 BadParameter:
00718 
00719        return ( result );
00720 }
00721 
00722 /*****************************************************************************/
00723 
00724 OSErr
00725 FSGetFileDirName(
00726        const FSRef *ref,
00727        HFSUniStr255 *outName)
00728 {
00729        OSErr  result;
00730        
00731        /* check parameters */
00732        require_action(NULL != outName, BadParameter, result = paramErr);
00733        
00734        result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, outName, NULL, NULL);
00735        require_noerr(result, FSGetCatalogInfo);
00736        
00737 FSGetCatalogInfo:
00738 BadParameter:
00739 
00740        return ( result );
00741 }
00742 
00743 /*****************************************************************************/
00744 
00745 OSErr
00746 FSGetNodeID(
00747        const FSRef *ref,
00748        long *nodeID,               /* can be NULL */
00749        Boolean *isDirectory)       /* can be NULL */
00750 {
00751        OSErr                       result;
00752        FSCatalogInfo        catalogInfo;
00753        FSCatalogInfoBitmap whichInfo;
00754        
00755        /* determine what catalog information to get */
00756        whichInfo = kFSCatInfoNone; /* start with none */
00757        if ( NULL != nodeID )
00758        {
00759               whichInfo |= kFSCatInfoNodeID;
00760        }
00761        if ( NULL != isDirectory )
00762        {
00763               whichInfo |= kFSCatInfoNodeFlags;
00764        }
00765        
00766        result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
00767        require_noerr(result, FSGetCatalogInfo);
00768        
00769        if ( NULL != nodeID )
00770        {
00771               *nodeID = catalogInfo.nodeID;
00772        }
00773        if ( NULL != isDirectory )
00774        {
00775               *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
00776        }
00777        
00778 FSGetCatalogInfo:
00779 
00780        return ( result );
00781 }
00782 
00783 /*****************************************************************************/
00784 
00785 OSErr
00786 FSGetUserPrivilegesPermissions(
00787        const FSRef *ref,
00788        UInt8 *userPrivileges,             /* can be NULL */
00789        UInt32 permissions[4])             /* can be NULL */
00790 {
00791        OSErr                result;
00792        FSCatalogInfo catalogInfo;
00793        FSCatalogInfoBitmap whichInfo;
00794        
00795        /* determine what catalog information to get */
00796        whichInfo = kFSCatInfoNone; /* start with none */
00797        if ( NULL != userPrivileges )
00798        {
00799               whichInfo |= kFSCatInfoUserPrivs;
00800        }
00801        if ( NULL != permissions )
00802        {
00803               whichInfo |= kFSCatInfoPermissions;
00804        }
00805        
00806        result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
00807        require_noerr(result, FSGetCatalogInfo);
00808        
00809        if ( NULL != userPrivileges )
00810        {
00811               *userPrivileges = catalogInfo.userPrivileges;
00812        }
00813        if ( NULL != permissions )
00814        {
00815               BlockMoveData(&catalogInfo.permissions, permissions, sizeof(UInt32) * 4);
00816        }
00817        
00818 FSGetCatalogInfo:
00819 
00820        return ( result );
00821 }
00822 
00823 /*****************************************************************************/
00824 
00825 OSErr
00826 FSCheckLock(
00827        const FSRef *ref)
00828 {
00829        OSErr                result;
00830        FSCatalogInfo catalogInfo;
00831        FSVolumeInfo  volumeInfo;
00832        
00833        /* get nodeFlags and vRefNum for container */
00834        result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoVolume, &catalogInfo, NULL, NULL,NULL);
00835        require_noerr(result, FSGetCatalogInfo);
00836        
00837        /* is file locked? */
00838        if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
00839        {
00840               result = fLckdErr;   /* file is locked */
00841        }
00842        else
00843        {
00844               /* file isn't locked, but is volume locked? */
00845               
00846               /* get volume flags */
00847               result = FSGetVolumeInfo(catalogInfo.volume, 0, NULL, kFSVolInfoFlags, &volumeInfo, NULL, NULL);
00848               require_noerr(result, FSGetVolumeInfo);
00849               
00850               if ( 0 != (volumeInfo.flags & kFSVolFlagHardwareLockedMask) )
00851               {
00852                      result = wPrErr;     /* volume locked by hardware */
00853               }
00854               else if ( 0 != (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) )
00855               {
00856                      result = vLckdErr;   /* volume locked by software */
00857               }
00858        }
00859        
00860 FSGetVolumeInfo:
00861 FSGetCatalogInfo:
00862 
00863        return ( result );
00864 }
00865 
00866 /*****************************************************************************/
00867 
00868 OSErr
00869 FSGetForkSizes(
00870        const FSRef *ref,
00871        UInt64 *dataLogicalSize,    /* can be NULL */
00872        UInt64 *rsrcLogicalSize)    /* can be NULL */
00873 {
00874        OSErr                       result;
00875        FSCatalogInfoBitmap whichInfo;
00876        FSCatalogInfo        catalogInfo;
00877        
00878        whichInfo = kFSCatInfoNodeFlags;
00879        if ( NULL != dataLogicalSize )
00880        {
00881               /* get data fork size */
00882               whichInfo |= kFSCatInfoDataSizes;
00883        }
00884        if ( NULL != rsrcLogicalSize )
00885        {
00886               /* get resource fork size */
00887               whichInfo |= kFSCatInfoRsrcSizes;
00888        }
00889 
00890        /* get nodeFlags and catalog info */
00891        result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL,NULL);
00892        require_noerr(result, FSGetCatalogInfo);
00893        
00894        /* make sure FSRef was to a file */
00895        require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
00896        
00897        if ( NULL != dataLogicalSize )
00898        {
00899               /* return data fork size */
00900               *dataLogicalSize = catalogInfo.dataLogicalSize;
00901        }
00902        if ( NULL != rsrcLogicalSize )
00903        {
00904               /* return resource fork size */
00905               *rsrcLogicalSize = catalogInfo.rsrcLogicalSize;
00906        }
00907        
00908 FSRefNotFile:
00909 FSGetCatalogInfo:
00910 
00911        return ( result );
00912 }
00913 
00914 /*****************************************************************************/
00915 
00916 OSErr
00917 FSGetTotalForkSizes(
00918        const FSRef *ref,
00919        UInt64 *totalLogicalSize,   /* can be NULL */
00920        UInt64 *totalPhysicalSize,  /* can be NULL */
00921        ItemCount *forkCount)              /* can be NULL */
00922 {
00923        OSErr                result;
00924        CatPositionRec       forkIterator;
00925        SInt64               forkSize;
00926        SInt64               *forkSizePtr;
00927        UInt64               forkPhysicalSize;
00928        UInt64               *forkPhysicalSizePtr;
00929        
00930        /* Determine if forkSize needed */
00931        if ( NULL != totalLogicalSize)
00932        {
00933               *totalLogicalSize = 0;
00934               forkSizePtr = &forkSize;
00935        }
00936        else
00937        {
00938               forkSizePtr = NULL;
00939        }
00940        
00941        /* Determine if forkPhysicalSize is needed */
00942        if ( NULL != totalPhysicalSize )
00943        {
00944               *totalPhysicalSize = 0;
00945               forkPhysicalSizePtr = &forkPhysicalSize;
00946        }
00947        else
00948        {
00949               forkPhysicalSizePtr = NULL;
00950        }
00951        
00952        /* zero fork count if returning it */
00953        if ( NULL != forkCount )
00954        {
00955               *forkCount = 0;
00956        }
00957        
00958        /* Iterate through the forks to get the sizes */
00959        forkIterator.initialize = 0;
00960        do
00961        {
00962               result = FSIterateForks(ref, &forkIterator, NULL, forkSizePtr, forkPhysicalSizePtr);
00963               if ( noErr == result )
00964               {
00965                      if ( NULL != totalLogicalSize )
00966                      {
00967                             *totalLogicalSize += forkSize;
00968                      }
00969                      
00970                      if ( NULL != totalPhysicalSize )
00971                      {
00972                             *totalPhysicalSize += forkPhysicalSize;
00973                      }
00974                      
00975                      if ( NULL != forkCount )
00976                      {
00977                             ++*forkCount;
00978                      }
00979               }
00980        } while ( noErr == result );
00981        
00982        /* any error result other than errFSNoMoreItems is serious */
00983        require(errFSNoMoreItems == result, FSIterateForks);
00984        
00985        /* Normal exit */
00986        result = noErr;
00987 
00988 FSIterateForks:
00989        
00990        return ( result );
00991 }
00992 
00993 /*****************************************************************************/
00994 
00995 OSErr
00996 FSBumpDate(
00997        const FSRef *ref)
00998 {
00999        OSStatus             result;
01000        FSCatalogInfo catalogInfo;
01001        UTCDateTime          oldDateTime;
01002 #if !BuildingMoreFilesXForMacOS9
01003        FSRef                parentRef;
01004        Boolean                     notifyParent;
01005 #endif
01006 
01007 #if !BuildingMoreFilesXForMacOS9
01008        /* Get the node flags, the content modification date and time, and the parent ref */
01009        result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoContentMod, &catalogInfo, NULL, NULL, &parentRef);
01010        require_noerr(result, FSGetCatalogInfo);
01011        
01012        /* Notify the parent if this is a file */
01013        notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask));
01014 #else
01015        /* Get the content modification date and time */
01016        result = FSGetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo, NULL, NULL, NULL);
01017        require_noerr(result, FSGetCatalogInfo);
01018 #endif
01019        
01020        oldDateTime = catalogInfo.contentModDate;
01021 
01022        /* Get the current date and time */
01023        result = GetUTCDateTime(&catalogInfo.contentModDate, kUTCDefaultOptions);
01024        require_noerr(result, GetUTCDateTime);
01025        
01026        /* if the old date and time is the the same as the current, bump the seconds by one */
01027        if ( (catalogInfo.contentModDate.fraction == oldDateTime.fraction) &&
01028                (catalogInfo.contentModDate.lowSeconds == oldDateTime.lowSeconds) &&
01029                (catalogInfo.contentModDate.highSeconds == oldDateTime.highSeconds) )
01030        {
01031               ++catalogInfo.contentModDate.lowSeconds;
01032               if ( 0 == catalogInfo.contentModDate.lowSeconds )
01033               {
01034                      ++catalogInfo.contentModDate.highSeconds;
01035               }
01036        }
01037        
01038        /* Bump the content modification date and time */
01039        result = FSSetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo);
01040        require_noerr(result, FSSetCatalogInfo);
01041 
01042 #if !BuildingMoreFilesXForMacOS9
01043        /*
01044         * The problem with FNNotify is that it is not available under Mac OS 9
01045         * and there's no way to test for that except for looking for the symbol
01046         * or something. So, I'll just conditionalize this for those who care
01047         * to send a notification.
01048         */
01049        
01050        /* Send a notification for the parent of the file, or for the directory */
01051        result = FNNotify(notifyParent ? &parentRef : ref, kFNDirectoryModifiedMessage, kNilOptions);
01052        require_noerr(result, FNNotify);
01053 #endif
01054 
01055        /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */
01056 FNNotify:
01057 FSSetCatalogInfo:
01058        
01059        return ( noErr );
01060        
01061        /**********************/
01062        
01063 GetUTCDateTime:
01064 FSGetCatalogInfo:
01065 
01066        return ( result );
01067 }
01068 
01069 /*****************************************************************************/
01070 
01071 OSErr
01072 FSGetFinderInfo(
01073        const FSRef *ref,
01074        FinderInfo *info,                                /* can be NULL */
01075        ExtendedFinderInfo *extendedInfo,  /* can be NULL */
01076        Boolean *isDirectory)                            /* can be NULL */
01077 {
01078        OSErr                       result;
01079        FSCatalogInfo        catalogInfo;
01080        FSCatalogInfoBitmap whichInfo;
01081        
01082        /* determine what catalog information is really needed */
01083        whichInfo = kFSCatInfoNone;
01084        
01085        if ( NULL != info )
01086        {
01087               /* get FinderInfo */
01088               whichInfo |= kFSCatInfoFinderInfo;
01089        }
01090        
01091        if ( NULL != extendedInfo )
01092        {
01093               /* get ExtendedFinderInfo */
01094               whichInfo |= kFSCatInfoFinderXInfo;
01095        }
01096        
01097        if ( NULL != isDirectory )
01098        {
01099               whichInfo |= kFSCatInfoNodeFlags;
01100        }
01101        
01102        result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
01103        require_noerr(result, FSGetCatalogInfo);
01104        
01105        /* return FinderInfo if requested */
01106        if ( NULL != info )
01107        {
01108               BlockMoveData(catalogInfo.finderInfo, info, sizeof(FinderInfo));
01109        }
01110        
01111        /* return ExtendedFinderInfo if requested */
01112        if ( NULL != extendedInfo)
01113        {
01114               BlockMoveData(catalogInfo.extFinderInfo, extendedInfo, sizeof(ExtendedFinderInfo));
01115        }
01116        
01117        /* set isDirectory Boolean if requested */
01118        if ( NULL != isDirectory)
01119        {
01120               *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
01121        }
01122        
01123 FSGetCatalogInfo:
01124 
01125        return ( result );
01126 }
01127 
01128 /*****************************************************************************/
01129 
01130 OSErr
01131 FSSetFinderInfo(
01132        const FSRef *ref,
01133        const FinderInfo *info,
01134        const ExtendedFinderInfo *extendedInfo)
01135 {
01136        OSErr                       result;
01137        FSCatalogInfo        catalogInfo;
01138        FSCatalogInfoBitmap whichInfo;
01139        
01140        /* determine what catalog information will be set */
01141        whichInfo = kFSCatInfoNone; /* start with none */
01142        if ( NULL != info )
01143        {
01144               /* set FinderInfo */
01145               whichInfo |= kFSCatInfoFinderInfo;
01146               BlockMoveData(info, catalogInfo.finderInfo, sizeof(FinderInfo));
01147        }
01148        if ( NULL != extendedInfo )
01149        {
01150               /* set ExtendedFinderInfo */
01151               whichInfo |= kFSCatInfoFinderXInfo;
01152               BlockMoveData(extendedInfo, catalogInfo.extFinderInfo, sizeof(ExtendedFinderInfo));
01153        }
01154        
01155        result = FSSetCatalogInfo(ref, whichInfo, &catalogInfo);
01156        require_noerr(result, FSGetCatalogInfo);
01157        
01158 FSGetCatalogInfo:
01159 
01160        return ( result );
01161 }
01162 
01163 /*****************************************************************************/
01164 
01165 OSErr
01166 FSChangeCreatorType(
01167        const FSRef *ref,
01168        OSType fileCreator,
01169        OSType fileType)
01170 {
01171        OSErr                result;
01172        FSCatalogInfo catalogInfo;
01173        FSRef                parentRef;
01174        
01175        /* get nodeFlags, finder info, and parent FSRef */
01176        result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, &catalogInfo , NULL, NULL, &parentRef);
01177        require_noerr(result, FSGetCatalogInfo);
01178        
01179        /* make sure FSRef was to a file */
01180        require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
01181        
01182        /* If fileType not 0x00000000, change fileType */
01183        if ( fileType != (OSType)0x00000000 )
01184        {
01185               ((FileInfo *)&catalogInfo.finderInfo)->fileType = fileType;
01186        }
01187        
01188        /* If creator not 0x00000000, change creator */
01189        if ( fileCreator != (OSType)0x00000000 )
01190        {
01191               ((FileInfo *)&catalogInfo.finderInfo)->fileCreator = fileCreator;
01192        }
01193        
01194        /* now, save the new information back to disk */
01195        result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
01196        require_noerr(result, FSSetCatalogInfo);
01197        
01198        /* and attempt to bump the parent directory's mod date to wake up */
01199        /* the Finder to the change we just made (ignore errors from this) */
01200        verify_noerr(FSBumpDate(&parentRef));
01201        
01202 FSSetCatalogInfo:
01203 FSRefNotFile:
01204 FSGetCatalogInfo:
01205 
01206        return ( result );
01207 }
01208 
01209 /*****************************************************************************/
01210 
01211 OSErr
01212 FSChangeFinderFlags(
01213        const FSRef *ref,
01214        Boolean setBits,
01215        UInt16 flagBits)
01216 {
01217        OSErr                result;
01218        FSCatalogInfo catalogInfo;
01219        FSRef                parentRef;
01220        
01221        /* get the current finderInfo */
01222        result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef);
01223        require_noerr(result, FSGetCatalogInfo);
01224        
01225        /* set or clear the appropriate bits in the finderInfo.finderFlags */
01226        if ( setBits )
01227        {
01228               /* OR in the bits */
01229               ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits;
01230        }
01231        else
01232        {
01233               /* AND out the bits */
01234               ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits;
01235        }
01236        
01237        /* save the modified finderInfo */
01238        result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
01239        require_noerr(result, FSSetCatalogInfo);
01240        
01241        /* and attempt to bump the parent directory's mod date to wake up the Finder */
01242        /* to the change we just made (ignore errors from this) */
01243        verify_noerr(FSBumpDate(&parentRef));
01244        
01245 FSSetCatalogInfo:
01246 FSGetCatalogInfo:
01247 
01248        return ( result );
01249 }
01250 
01251 /*****************************************************************************/
01252 
01253 OSErr
01254 FSSetInvisible(
01255        const FSRef *ref)
01256 {
01257        return ( FSChangeFinderFlags(ref, true, kIsInvisible) );
01258 }
01259 
01260 OSErr
01261 FSClearInvisible(
01262        const FSRef *ref)
01263 {
01264        return ( FSChangeFinderFlags(ref, false, kIsInvisible) );
01265 }
01266 
01267 /*****************************************************************************/
01268 
01269 OSErr
01270 FSSetNameLocked(
01271        const FSRef *ref)
01272 {
01273        return ( FSChangeFinderFlags(ref, true, kNameLocked) );
01274 }
01275 
01276 OSErr
01277 FSClearNameLocked(
01278        const FSRef *ref)
01279 {
01280        return ( FSChangeFinderFlags(ref, false, kNameLocked) );
01281 }
01282 
01283 /*****************************************************************************/
01284 
01285 OSErr
01286 FSSetIsStationery(
01287        const FSRef *ref)
01288 {
01289        return ( FSChangeFinderFlags(ref, true, kIsStationery) );
01290 }
01291 
01292 OSErr
01293 FSClearIsStationery(
01294        const FSRef *ref)
01295 {
01296        return ( FSChangeFinderFlags(ref, false, kIsStationery) );
01297 }
01298 
01299 /*****************************************************************************/
01300 
01301 OSErr
01302 FSSetHasCustomIcon(
01303        const FSRef *ref)
01304 {
01305        return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) );
01306 }
01307 
01308 OSErr
01309 FSClearHasCustomIcon(
01310        const FSRef *ref)
01311 {
01312        return ( FSChangeFinderFlags(ref, false, kHasCustomIcon) );
01313 }
01314 
01315 /*****************************************************************************/
01316 
01317 OSErr
01318 FSClearHasBeenInited(
01319        const FSRef *ref)
01320 {
01321        return ( FSChangeFinderFlags(ref, false, kHasBeenInited) );
01322 }
01323 
01324 /*****************************************************************************/
01325 
01326 OSErr
01327 FSCopyFileMgrAttributes(
01328        const FSRef *sourceRef,
01329        const FSRef *destinationRef,
01330        Boolean copyLockBit)
01331 {
01332        OSErr                result;
01333        FSCatalogInfo catalogInfo;
01334        
01335        /* get the source information */
01336        result = FSGetCatalogInfo(sourceRef, kFSCatInfoSettableInfo, &catalogInfo, NULL, NULL, NULL);
01337        require_noerr(result, FSGetCatalogInfo);
01338        
01339        /* don't copy the hasBeenInited bit; clear it */
01340        ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~kHasBeenInited;
01341        
01342        /* should the locked bit be copied? */
01343        if ( !copyLockBit )
01344        {
01345               /* no, make sure the locked bit is clear */
01346               catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
01347        }
01348               
01349        /* set the destination information */
01350        result = FSSetCatalogInfo(destinationRef, kFSCatInfoSettableInfo, &catalogInfo);
01351        require_noerr(result, FSSetCatalogInfo);
01352        
01353 FSSetCatalogInfo:
01354 FSGetCatalogInfo:
01355 
01356        return ( result );
01357 }
01358 
01359 /*****************************************************************************/
01360 
01361 OSErr
01362 FSMoveRenameObjectUnicode(
01363        const FSRef *ref,
01364        const FSRef *destDirectory,
01365        UniCharCount nameLength,
01366        const UniChar *name,               /* can be NULL (no rename during move) */
01367        TextEncoding textEncodingHint,
01368        FSRef *newRef)                                   /* if function fails along the way, newRef is final location of file */
01369 {
01370        OSErr                result;
01371        FSVolumeRefNum       vRefNum;
01372        FSCatalogInfo catalogInfo;
01373        FSRef                originalDirectory;
01374        TextEncoding  originalTextEncodingHint;
01375        HFSUniStr255  originalName;
01376        HFSUniStr255  uniqueName;          /* unique name given to object while moving it to destination */
01377        long                 theSeed;             /* the seed for generating unique names */
01378        
01379        /* check parameters */
01380        require_action(NULL != newRef, BadParameter, result = paramErr);
01381        
01382        /* newRef = input to start with */
01383        BlockMoveData(ref, newRef, sizeof(FSRef));
01384        
01385        /* get destDirectory's vRefNum */
01386        result = FSGetCatalogInfo(destDirectory, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
01387        require_noerr(result, DestinationBad);
01388        
01389        /* save vRefNum */
01390        vRefNum = catalogInfo.volume;
01391        
01392        /* get ref's vRefNum, TextEncoding, name and parent directory*/
01393        result = FSGetCatalogInfo(ref, kFSCatInfoTextEncoding + kFSCatInfoVolume, &catalogInfo, &originalName, NULL, &originalDirectory);
01394        require_noerr(result, SourceBad);
01395        
01396        /* save TextEncoding */
01397        originalTextEncodingHint = catalogInfo.textEncodingHint;
01398        
01399        /* make sure ref and destDirectory are on same volume */
01400        require_action(vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
01401        
01402        /* Skip a few steps if we're not renaming */
01403        if ( NULL != name )
01404        {
01405               /* generate a name that is unique in both directories */
01406               theSeed = 0x4a696d4c;       /* a fine unlikely filename */
01407               
01408               result = GenerateUniqueHFSUniStr(&theSeed, &originalDirectory, destDirectory, &uniqueName);
01409               require_noerr(result, GenerateUniqueHFSUniStrFailed);
01410               
01411               /* Rename the object to uniqueName */
01412               result = FSRenameUnicode(ref, uniqueName.length, uniqueName.unicode, kTextEncodingUnknown, newRef);
01413               require_noerr(result, FSRenameUnicodeBeforeMoveFailed);
01414               
01415               if ( FSCompareFSRefs(destDirectory, &originalDirectory) != noErr )
01416               {
01417                 /* Move object to its new home */
01418                 result = FSMoveObject(newRef, destDirectory, newRef);
01419                 require_noerr(result, FSMoveObjectAfterRenameFailed);
01420               }
01421               
01422               /* Rename the object to new name */
01423               result = FSRenameUnicode(ref, nameLength, name, textEncodingHint, newRef);
01424               require_noerr(result, FSRenameUnicodeAfterMoveFailed);
01425        }
01426        else
01427        {
01428               /* Move object to its new home */
01429               result = FSMoveObject(newRef, destDirectory, newRef);
01430               require_noerr(result, FSMoveObjectNoRenameFailed);
01431        }
01432        
01433        return ( result );
01434        
01435        /*************/
01436 
01437 /*
01438  * failure handling code when renaming
01439  */
01440 
01441 FSRenameUnicodeAfterMoveFailed:
01442 
01443        /* Error handling: move object back to original location - ignore errors */
01444        verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef));
01445        
01446 FSMoveObjectAfterRenameFailed:
01447 
01448        /* Error handling: rename object back to original name - ignore errors */
01449        verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef));
01450        
01451 FSRenameUnicodeBeforeMoveFailed:
01452 GenerateUniqueHFSUniStrFailed:
01453 
01454 /*
01455  * failure handling code for renaming or not
01456  */
01457 FSMoveObjectNoRenameFailed:
01458 NotSameVolume:
01459 SourceBad:
01460 DestinationBad:
01461 BadParameter:
01462 
01463        return ( result );
01464 }
01465 
01466 /*****************************************************************************/
01467 
01468 /*
01469        The FSDeleteContainerLevel function deletes the contents of a container
01470        directory. All files and subdirectories in the specified container are
01471        deleted. If a locked file or directory is encountered, it is unlocked
01472        and then deleted. If any unexpected errors are encountered,
01473        FSDeleteContainerLevel quits and returns to the caller.
01474        
01475        container                   --> FSRef to a directory.
01476        theGlobals                  --> A pointer to a FSDeleteContainerGlobals struct
01477                                                  which contains the variables that do not need to
01478                                                  be allocated each time FSDeleteContainerLevel
01479                                                  recurses. That lets FSDeleteContainerLevel use
01480                                                  less stack space per recursion level.
01481 */
01482 
01483 static
01484 void
01485 FSDeleteContainerLevel(
01486        const FSRef *container,
01487        FSDeleteContainerGlobals *theGlobals)
01488 {
01489        /* level locals */
01490        FSIterator                                iterator;
01491        FSRef                                     itemToDelete;
01492        UInt16                                    nodeFlags;
01493        
01494        /* Open FSIterator for flat access and give delete optimization hint */
01495        theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator);
01496        require_noerr(theGlobals->result, FSOpenIterator);
01497        
01498        /* delete the contents of the directory */
01499        do
01500        {
01501               /* get 1 item to delete */
01502               theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
01503                                                         NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo,
01504                                                         &itemToDelete, NULL, NULL);
01505               if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) )
01506               {
01507                      /* save node flags in local in case we have to recurse */
01508                      nodeFlags = theGlobals->catalogInfo.nodeFlags;
01509                      
01510                      /* is it a file or directory? */
01511                      if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) )
01512                      {
01513                             /* it's a directory -- delete its contents before attempting to delete it */
01514                             FSDeleteContainerLevel(&itemToDelete, theGlobals);
01515                      }
01516                      /* are we still OK to delete? */
01517                      if ( noErr == theGlobals->result )
01518                      {
01519                             /* is item locked? */
01520                             if ( 0 != (nodeFlags & kFSNodeLockedMask) )
01521                             {
01522                                    /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
01523                                    theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask;
01524                                    (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo);
01525                             }
01526                             /* delete the item */
01527                             theGlobals->result = FSDeleteObject(&itemToDelete);
01528                      }
01529               }
01530        } while ( noErr == theGlobals->result );
01531        
01532        /* we found the end of the items normally, so return noErr */
01533        if ( errFSNoMoreItems == theGlobals->result )
01534        {
01535               theGlobals->result = noErr;
01536        }
01537        
01538        /* close the FSIterator (closing an open iterator should never fail) */
01539        verify_noerr(FSCloseIterator(iterator));
01540 
01541 FSOpenIterator:
01542 
01543        return;
01544 }
01545 
01546 /*****************************************************************************/
01547 
01548 OSErr
01549 FSDeleteContainerContents(
01550        const FSRef *container)
01551 {
01552        FSDeleteContainerGlobals    theGlobals;
01553        
01554        /* delete container's contents */
01555        FSDeleteContainerLevel(container, &theGlobals);
01556        
01557        return ( theGlobals.result );
01558 }
01559 
01560 /*****************************************************************************/
01561 
01562 OSErr
01563 FSDeleteContainer(
01564        const FSRef *container)
01565 {
01566        OSErr                result;
01567        FSCatalogInfo catalogInfo;
01568        
01569        /* get nodeFlags for container */
01570        result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL);
01571        require_noerr(result, FSGetCatalogInfo);
01572        
01573        /* make sure container is a directory */
01574        require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr);
01575        
01576        /* delete container's contents */
01577        result = FSDeleteContainerContents(container);
01578        require_noerr(result, FSDeleteContainerContents);
01579        
01580        /* is container locked? */
01581        if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
01582        {
01583               /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
01584               catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
01585               (void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo);
01586        }
01587        
01588        /* delete the container */
01589        result = FSDeleteObject(container);
01590        
01591 FSDeleteContainerContents:
01592 ContainerNotDirectory:
01593 FSGetCatalogInfo:
01594 
01595        return ( result );
01596 }
01597 
01598 /*****************************************************************************/
01599 
01600 /*
01601        The FSIterateContainerLevel function iterates the contents of a container
01602        directory and calls a IterateContainerFilterProc function once for each
01603        file and directory found.
01604        
01605        theGlobals                  --> A pointer to a FSIterateContainerGlobals struct
01606                                                  which contains the variables needed globally by
01607                                                  all recusion levels of FSIterateContainerLevel.
01608                                                  That makes FSIterateContainer thread safe since
01609                                                  each call to it uses its own global world.
01610                                                  It also contains the variables that do not need
01611                                                  to be allocated each time FSIterateContainerLevel
01612                                                  recurses. That lets FSIterateContainerLevel use
01613                                                  less stack space per recursion level.
01614 */
01615 
01616 static
01617 void
01618 FSIterateContainerLevel(
01619        FSIterateContainerGlobals *theGlobals)
01620 {      
01621        FSIterator    iterator;
01622        
01623        /* If maxLevels is zero, we aren't checking levels */
01624        /* If currentLevel < maxLevels, look at this level */
01625        if ( (theGlobals->maxLevels == 0) ||
01626                (theGlobals->currentLevel < theGlobals->maxLevels) )
01627        {
01628               /* Open FSIterator for flat access to theGlobals->ref */
01629               theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator);
01630               require_noerr(theGlobals->result, FSOpenIterator);
01631               
01632               ++theGlobals->currentLevel; /* Go to next level */
01633               
01634               /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
01635               do
01636               {
01637                      theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
01638                             &theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo,
01639                             &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr);
01640                      if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) &&
01641                             (0 != theGlobals->actualObjects) )
01642                      {
01643                             /* Call the IterateFilterProc */
01644                             theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter,
01645                                    theGlobals->containerChanged, theGlobals->currentLevel,
01646                                    &theGlobals->catalogInfo, &theGlobals->ref,
01647                                    theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr);
01648                             /* Is it a directory? */
01649                             if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) )
01650                             {
01651                                    /* Keep going? */
01652                                    if ( !theGlobals->quitFlag )
01653                                    {
01654                                           /* Dive again if the IterateFilterProc didn't say "quit" */
01655                                           FSIterateContainerLevel(theGlobals);
01656                                    }
01657                             }
01658                      }
01659                      /* time to fall back a level? */
01660               } while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) );
01661               
01662               /* errFSNoMoreItems is OK - it only means we hit the end of this level */
01663               /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
01664               if ( (errFSNoMoreItems == theGlobals->result) ||
01665                       (afpAccessDenied == theGlobals->result) )
01666               {
01667                      theGlobals->result = noErr;
01668               }
01669               
01670               --theGlobals->currentLevel; /* Return to previous level as we leave */
01671               
01672               /* Close the FSIterator (closing an open iterator should never fail) */
01673               verify_noerr(FSCloseIterator(iterator));
01674        }
01675        
01676 FSOpenIterator:
01677 
01678        return;
01679 }
01680 
01681 /*****************************************************************************/
01682 
01683 OSErr
01684 FSIterateContainer(
01685        const FSRef *container,
01686        ItemCount maxLevels,
01687        FSCatalogInfoBitmap whichInfo,
01688        Boolean wantFSSpec,
01689        Boolean wantName,
01690        IterateContainerFilterProcPtr iterateFilter,
01691        void *yourDataPtr)
01692 {
01693        OSErr                                     result;
01694        FSIterateContainerGlobals   theGlobals;
01695        
01696        /* make sure there is an iterateFilter */
01697        require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr);
01698        
01699        /*
01700         * set up the globals we need to access from the recursive routine
01701         */
01702        theGlobals.iterateFilter = iterateFilter;
01703        /* we need the node flags no matter what was requested so we can detect files vs. directories */
01704        theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags;
01705        /* start with input container -- the first OpenIterator will ensure it is a directory */
01706        theGlobals.ref = *container;
01707        if ( wantFSSpec )
01708        {
01709               theGlobals.specPtr = &theGlobals.spec;
01710        }
01711        else
01712        {
01713               theGlobals.specPtr = NULL;
01714        }
01715        if ( wantName )
01716        {
01717               theGlobals.namePtr = &theGlobals.name;
01718        }
01719        else
01720        {
01721               theGlobals.namePtr = NULL;
01722        }
01723        theGlobals.yourDataPtr = yourDataPtr;
01724        theGlobals.maxLevels = maxLevels;
01725        theGlobals.currentLevel = 0;
01726        theGlobals.quitFlag = false;
01727        theGlobals.containerChanged = false;
01728        theGlobals.result = noErr;
01729        theGlobals.actualObjects = 0;
01730        
01731        /* here we go into recursion land... */
01732        FSIterateContainerLevel(&theGlobals);
01733        result = theGlobals.result;
01734        require_noerr(result, FSIterateContainerLevel);
01735        
01736 FSIterateContainerLevel:
01737 NoIterateFilter:
01738 
01739        return ( result );
01740 }
01741 
01742 /*****************************************************************************/
01743 
01744 OSErr
01745 FSGetDirectoryItems(
01746        const FSRef *container,
01747        FSRef ***refsHandle, /* pointer to handle of FSRefs */
01748        ItemCount *numRefs,
01749        Boolean *containerChanged)
01750 {
01751        /* Grab items 10 at a time. */
01752        enum { kMaxItemsPerBulkCall = 10 };
01753        
01754        OSErr         result;
01755        OSErr         memResult;
01756        FSIterator    iterator;
01757        FSRef         refs[kMaxItemsPerBulkCall];
01758        ItemCount     actualObjects;
01759        Boolean              changed;
01760        
01761        /* check parameters */
01762        require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged),
01763               BadParameter, result = paramErr);
01764        
01765        *numRefs = 0;
01766        *containerChanged = false;
01767        *refsHandle = (FSRef **)NewHandle(0);
01768        require_action(NULL != *refsHandle, NewHandle, result = memFullErr);
01769        
01770        /* open an FSIterator */
01771        result = FSOpenIterator(container, kFSIterateFlat, &iterator);
01772        require_noerr(result, FSOpenIterator);
01773        
01774        /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
01775        do
01776        {
01777               result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects,
01778                                    &changed, kFSCatInfoNone,  NULL,  refs, NULL, NULL);
01779               
01780               /* if the container changed, set containerChanged for output, but keep going */
01781               if ( changed )
01782               {
01783                      *containerChanged = changed;
01784               }
01785               
01786               /* any result other than noErr and errFSNoMoreItems is serious */
01787               require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk);
01788               
01789               /* add objects to output array and count */
01790               if ( 0 != actualObjects )
01791               {
01792                      /* concatenate the FSRefs to the end of the       handle */
01793                      PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef));
01794                      memResult = MemError();
01795                      require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
01796                      
01797                      *numRefs += actualObjects;
01798               }
01799        } while ( noErr == result );
01800        
01801        verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */
01802        
01803        return ( noErr );
01804        
01805        /**********************/
01806        
01807 MemoryAllocationFailed:
01808 FSGetCatalogInfoBulk:
01809 
01810        /* close the iterator */
01811        verify_noerr(FSCloseIterator(iterator));
01812 
01813 FSOpenIterator:
01814        /* dispose of handle if already allocated and clear the outputs */
01815        if ( NULL != *refsHandle )
01816        {
01817               DisposeHandle((Handle)*refsHandle);
01818               *refsHandle = NULL;
01819        }
01820        *numRefs = 0;
01821        
01822 NewHandle:
01823 BadParameter:
01824 
01825        return ( result );
01826 }
01827 
01828 /*****************************************************************************/
01829 
01830 /*
01831        The GenerateUniqueName function generates a HFSUniStr255 name that is
01832        unique in both dir1 and dir2.
01833        
01834        startSeed                   -->    A pointer to a long which is used to generate the
01835                                                  unique name.
01836                                           <--    It is modified on output to a value which should
01837                                                  be used to generate the next unique name.
01838        dir1                        -->    The first directory.
01839        dir2                        -->    The second directory.
01840        uniqueName                  <--    A pointer to a HFSUniStr255 where the unique name
01841                                                  is to be returned.
01842 */
01843 
01844 static
01845 OSErr
01846 GenerateUniqueHFSUniStr(
01847        long *startSeed,
01848        const FSRef *dir1,
01849        const FSRef *dir2,
01850        HFSUniStr255 *uniqueName)
01851 {
01852        OSErr                result;
01853        long                 i;
01854        FSRefParam           pb;
01855        FSRef                newRef;
01856        unsigned char hexStr[17] = "0123456789ABCDEF";
01857        
01858        /* set up the parameter block */
01859        pb.name = uniqueName->unicode;
01860        pb.nameLength = 8;   /* always 8 characters */
01861        pb.textEncodingHint = kTextEncodingUnknown;
01862        pb.newRef = &newRef;
01863 
01864        /* loop until we get fnfErr with a filename in both directories */
01865        result = noErr;
01866        while ( fnfErr != result )
01867        {
01868               /* convert startSeed to 8 character Unicode string */
01869               uniqueName->length = 8;
01870               for ( i = 0; i < 8; ++i )
01871               {
01872                      uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)];
01873               }
01874               
01875               /* try in dir1 */
01876               pb.ref = dir1;
01877               result = PBMakeFSRefUnicodeSync(&pb);
01878               if ( fnfErr == result )
01879               {
01880                      /* try in dir2 */
01881                      pb.ref = dir2;
01882                      result = PBMakeFSRefUnicodeSync(&pb);
01883                      if ( fnfErr != result )
01884                      {
01885                             /* exit if anything other than noErr or fnfErr */
01886                             require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed);
01887                      }
01888               }
01889               else
01890               {
01891                      /* exit if anything other than noErr or fnfErr */
01892                      require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed);
01893               }
01894               
01895               /* increment seed for next pass through loop, */
01896               /* or for next call to GenerateUniqueHFSUniStr */
01897               ++(*startSeed);
01898        }
01899        
01900        /* we have a unique file name which doesn't exist in dir1 or dir2 */
01901        result = noErr;
01902        
01903 Dir2PBMakeFSRefUnicodeSyncFailed:
01904 Dir1PBMakeFSRefUnicodeSyncFailed:
01905 
01906        return ( result );
01907 }
01908 
01909 /*****************************************************************************/
01910 
01911 OSErr
01912 FSExchangeObjectsCompat(
01913        const FSRef *sourceRef,
01914        const FSRef *destRef,
01915        FSRef *newSourceRef,
01916        FSRef *newDestRef)
01917 {
01918        enum
01919        {
01920               /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
01921               kGetCatInformationMask = (kFSCatInfoSettableInfo |
01922                                                           kFSCatInfoVolume |
01923                                                           kFSCatInfoParentDirID) &
01924                                                          ~(kFSCatInfoContentMod | kFSCatInfoAttrMod),
01925               /* set everything possible except for mod dates */
01926               kSetCatinformationMask = kFSCatInfoSettableInfo &
01927                                                          ~(kFSCatInfoContentMod | kFSCatInfoAttrMod)
01928        };
01929        
01930        OSErr                              result;
01931        GetVolParmsInfoBuffer       volParmsInfo;
01932        UInt32                             infoSize;
01933        FSCatalogInfo               sourceCatalogInfo;   /* source file's catalog information */
01934        FSCatalogInfo               destCatalogInfo;     /* destination file's catalog information */
01935        HFSUniStr255                sourceName;                 /* source file's Unicode name */
01936        HFSUniStr255                destName;                   /* destination file's Unicode name */
01937        FSRef                              sourceCurrentRef;    /* FSRef to current location of source file throughout this function */
01938        FSRef                              destCurrentRef;             /* FSRef to current location of destination file throughout this function */
01939        FSRef                              sourceParentRef;     /* FSRef to parent directory of source file */
01940        FSRef                              destParentRef;              /* FSRef to parent directory of destination file */
01941        HFSUniStr255                sourceUniqueName;    /* unique name given to source file while exchanging it with destination */
01942        HFSUniStr255                destUniqueName;             /* unique name given to destination file while exchanging it with source */
01943        long                               theSeed;                    /* the seed for generating unique names */
01944        Boolean                                   sameParentDirs;             /* true if source and destinatin parent directory is the same */
01945        
01946        /* check parameters */
01947        require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr);
01948        
01949        /* output refs and current refs = input refs to start with */
01950        BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef));
01951        BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef));
01952        
01953        BlockMoveData(destRef, newDestRef, sizeof(FSRef));
01954        BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef));
01955 
01956        /* get source volume's vRefNum */
01957        result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL);
01958        require_noerr(result, DetermineSourceVRefNumFailed);
01959        
01960        /* see if that volume supports FSExchangeObjects */
01961        result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer),
01962               &volParmsInfo, &infoSize);
01963        if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) )
01964        {
01965               /* yes - use FSExchangeObjects */
01966               result = FSExchangeObjects(sourceRef, destRef);
01967        }
01968        else
01969        {
01970               /* no - emulate FSExchangeObjects */
01971               
01972               /* Note: The compatibility case won't work for files with *Btree control blocks. */
01973               /* Right now the only *Btree files are created by the system. */
01974               
01975               /* get all catalog information and Unicode names for each file */
01976               result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef);
01977               require_noerr(result, SourceFSGetCatalogInfoFailed);
01978               
01979               result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef);
01980               require_noerr(result, DestFSGetCatalogInfoFailed);
01981               
01982               /* make sure source and destination are on same volume */
01983               require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr);
01984               
01985               /* make sure both files are *really* files */
01986               require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) &&
01987                                       (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr);
01988               
01989               /* generate 2 names that are unique in both directories */
01990               theSeed = 0x4a696d4c;       /* a fine unlikely filename */
01991               
01992               result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName);
01993               require_noerr(result, GenerateUniqueHFSUniStr1Failed);
01994               
01995               result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName);
01996               require_noerr(result, GenerateUniqueHFSUniStr2Failed);
01997 
01998               /* rename sourceCurrentRef to sourceUniqueName */
01999               result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef);
02000               require_noerr(result, FSRenameUnicode1Failed);
02001               BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
02002               
02003               /* rename destCurrentRef to destUniqueName */
02004               result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef);
02005               require_noerr(result, FSRenameUnicode2Failed);
02006               BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
02007               
02008               /* are the source and destination parent directories the same? */
02009               sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID );
02010               if ( !sameParentDirs )
02011               {
02012                      /* move source file to dest parent directory */
02013                      result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef);
02014                      require_noerr(result, FSMoveObject1Failed);
02015                      BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
02016                      
02017                      /* move dest file to source parent directory */
02018                      result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef);
02019                      require_noerr(result, FSMoveObject2Failed);
02020                      BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
02021               }
02022               
02023               /* At this point, the files are in their new locations (if they were moved). */
02024               /* The source file is named sourceUniqueName and is in the directory referred to */
02025               /* by destParentRef. The destination file is named destUniqueName and is in the */
02026               /* directory referred to by sourceParentRef. */
02027                             
02028               /* give source file the dest file's catalog information except for mod dates */
02029               result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo);
02030               require_noerr(result, FSSetCatalogInfo1Failed);
02031               
02032               /* give dest file the source file's catalog information except for mod dates */
02033               result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo);
02034               require_noerr(result, FSSetCatalogInfo2Failed);
02035               
02036               /* rename source file with dest file's name */
02037               result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef);
02038               require_noerr(result, FSRenameUnicode3Failed);
02039               BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
02040               
02041               /* rename dest file with source file's name */
02042               result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef);
02043               require_noerr(result, FSRenameUnicode4Failed);
02044               
02045               /* we're done with no errors, so swap newSourceRef and newDestRef */
02046               BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef));
02047               BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef));
02048        }
02049        
02050        return ( result );
02051        
02052        /**********************/
02053 
02054 /* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
02055 /* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
02056 /* state and location they ended up in so that both files can be found by the calling code. */
02057        
02058 FSRenameUnicode4Failed:
02059 
02060        /* attempt to rename source file to sourceUniqueName */
02061        if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) )
02062        {
02063               BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
02064        }
02065 
02066 FSRenameUnicode3Failed:
02067 
02068        /* attempt to restore dest file's catalog information */
02069        verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo));
02070 
02071 FSSetCatalogInfo2Failed:
02072 
02073        /* attempt to restore source file's catalog information */
02074        verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo));
02075 
02076 FSSetCatalogInfo1Failed:
02077 
02078        if ( !sameParentDirs )
02079        {
02080               /* attempt to move dest file back to dest directory */
02081               if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) )
02082               {
02083                      BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
02084               }
02085        }
02086 
02087 FSMoveObject2Failed:
02088 
02089        if ( !sameParentDirs )
02090        {
02091               /* attempt to move source file back to source directory */
02092               if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) )
02093               {
02094                      BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
02095               }
02096        }
02097 
02098 FSMoveObject1Failed:
02099 
02100        /* attempt to rename dest file to original name */
02101        verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef));
02102 
02103 FSRenameUnicode2Failed:
02104 
02105        /* attempt to rename source file to original name */
02106        verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef));
02107 
02108 FSRenameUnicode1Failed:
02109 GenerateUniqueHFSUniStr2Failed:
02110 GenerateUniqueHFSUniStr1Failed:
02111 NotAFile:
02112 NotSameVolume:
02113 DestFSGetCatalogInfoFailed:
02114 SourceFSGetCatalogInfoFailed:
02115 DetermineSourceVRefNumFailed:      
02116 BadParameter:
02117 
02118        return ( result );
02119 }
02120 
02121 /*****************************************************************************/
02122 
02123 #pragma mark ----- Shared Environment Routines -----
02124 
02125 /*****************************************************************************/
02126 
02127 /* Renamed from FSLockRange to MFX_FSLockRange to avoid a conflict with
02128  * the FSLockRange function present in the system library since Mac OS X
02129  * 10.4. */
02130 
02131 OSErr
02132 MFX_FSLockRange(
02133        SInt16 refNum,
02134        SInt32 rangeLength,
02135        SInt32 rangeStart)
02136 {
02137        OSErr                result;
02138        ParamBlockRec pb;
02139 
02140        pb.ioParam.ioRefNum = refNum;
02141        pb.ioParam.ioReqCount = rangeLength;
02142        pb.ioParam.ioPosMode = fsFromStart;
02143        pb.ioParam.ioPosOffset = rangeStart;
02144        result = PBLockRangeSync(&pb);
02145        require_noerr(result, PBLockRangeSync);
02146        
02147 PBLockRangeSync:
02148 
02149        return ( result );
02150 }
02151 
02152 /*****************************************************************************/
02153 
02154 /* Renamed from FSUnlockRange to MFX_FSUnlockRange to avoid a conflict with
02155  * the FSUnlockRange function present in the system library since Mac OS X
02156  * 10.4. */
02157 
02158 OSErr
02159 MFX_FSUnlockRange(
02160        SInt16 refNum,
02161        SInt32 rangeLength,
02162        SInt32 rangeStart)
02163 {
02164        OSErr                result;
02165        ParamBlockRec pb;
02166 
02167        pb.ioParam.ioRefNum = refNum;
02168        pb.ioParam.ioReqCount = rangeLength;
02169        pb.ioParam.ioPosMode = fsFromStart;
02170        pb.ioParam.ioPosOffset = rangeStart;
02171        result = PBUnlockRangeSync(&pb);
02172        require_noerr(result, PBUnlockRangeSync);
02173        
02174 PBUnlockRangeSync:
02175 
02176        return ( result );
02177 }
02178 
02179 /*****************************************************************************/
02180 
02181 OSErr
02182 FSGetDirAccess(
02183        const FSRef *ref,
02184        SInt32 *ownerID,            /* can be NULL */
02185        SInt32 *groupID,            /* can be NULL */
02186        SInt32 *accessRights)       /* can be NULL */
02187 {
02188        OSErr                result;
02189        FSSpec               spec;
02190        HParamBlockRec       pb;
02191        
02192        /* get FSSpec from FSRef */
02193        result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
02194        require_noerr(result, FSGetCatalogInfo);
02195        
02196        /* get directory access info for FSSpec */
02197        pb.accessParam.ioNamePtr = (StringPtr)spec.name;
02198        pb.accessParam.ioVRefNum = spec.vRefNum;
02199        pb.fileParam.ioDirID = spec.parID;
02200        result = PBHGetDirAccessSync(&pb);
02201        require_noerr(result, PBHGetDirAccessSync);
02202        
02203        /* return the IDs and access rights */
02204        if ( NULL != ownerID )
02205        {
02206               *ownerID = pb.accessParam.ioACOwnerID;
02207        }
02208        if ( NULL != groupID )
02209        {
02210               *groupID = pb.accessParam.ioACGroupID;
02211        }
02212        if ( NULL != accessRights )
02213        {
02214               *accessRights = pb.accessParam.ioACAccess;
02215        }
02216        
02217 PBHGetDirAccessSync:
02218 FSGetCatalogInfo:
02219 
02220        return ( result );
02221 }
02222 
02223 /*****************************************************************************/
02224 
02225 OSErr
02226 FSSetDirAccess(
02227        const FSRef *ref,
02228        SInt32 ownerID,
02229        SInt32 groupID,
02230        SInt32 accessRights)
02231 {
02232        OSErr                result;
02233        FSSpec               spec;
02234        HParamBlockRec       pb;
02235 
02236        enum
02237        {
02238               /* Just the bits that can be set */
02239               kSetDirAccessSettableMask = (kioACAccessBlankAccessMask +
02240                      kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask +
02241                      kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask +
02242                      kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask)
02243        };
02244        
02245        /* get FSSpec from FSRef */
02246        result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
02247        require_noerr(result, FSGetCatalogInfo);
02248        
02249        /* set directory access info for FSSpec */
02250        pb.accessParam.ioNamePtr = (StringPtr)spec.name;
02251        pb.accessParam.ioVRefNum = spec.vRefNum;
02252        pb.fileParam.ioDirID = spec.parID;
02253        pb.accessParam.ioACOwnerID = ownerID;
02254        pb.accessParam.ioACGroupID = groupID;
02255        pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask;
02256        result = PBHSetDirAccessSync(&pb);
02257        require_noerr(result, PBHSetDirAccessSync);
02258        
02259 PBHSetDirAccessSync:
02260 FSGetCatalogInfo:
02261 
02262        return ( result );
02263 }
02264 
02265 /*****************************************************************************/
02266 
02267 OSErr
02268 FSGetVolMountInfoSize(
02269        FSVolumeRefNum volRefNum,
02270        SInt16 *size)
02271 {
02272        OSErr                result;
02273        ParamBlockRec pb;
02274 
02275        /* check parameters */
02276        require_action(NULL != size, BadParameter, result = paramErr);
02277        
02278        pb.ioParam.ioNamePtr = NULL;
02279        pb.ioParam.ioVRefNum = volRefNum;
02280        pb.ioParam.ioBuffer = (Ptr)size;
02281        result = PBGetVolMountInfoSize(&pb);
02282        require_noerr(result, PBGetVolMountInfoSize);
02283        
02284 PBGetVolMountInfoSize:
02285 BadParameter:
02286 
02287        return ( result );
02288 }
02289 
02290 /*****************************************************************************/
02291 
02292 OSErr
02293 FSGetVolMountInfo(
02294        FSVolumeRefNum volRefNum,
02295        void *volMountInfo)
02296 {
02297        OSErr                result;
02298        ParamBlockRec pb;
02299 
02300        /* check parameters */
02301        require_action(NULL != volMountInfo, BadParameter, result = paramErr);
02302        
02303        pb.ioParam.ioNamePtr = NULL;
02304        pb.ioParam.ioVRefNum = volRefNum;
02305        pb.ioParam.ioBuffer = (Ptr)volMountInfo;
02306        result = PBGetVolMountInfo(&pb);
02307        require_noerr(result, PBGetVolMountInfo);
02308        
02309 PBGetVolMountInfo:
02310 BadParameter:
02311 
02312        return ( result );
02313 }
02314 
02315 /*****************************************************************************/
02316 
02317 OSErr
02318 MFX_FSVolumeMount(
02319        const void *volMountInfo,
02320        FSVolumeRefNum *volRefNum)
02321 {
02322        OSErr                result;
02323        ParamBlockRec pb;
02324 
02325        /* check parameters */
02326        require_action(NULL != volRefNum, BadParameter, result = paramErr);
02327        
02328        pb.ioParam.ioBuffer = (Ptr)volMountInfo;
02329        result = PBVolumeMount(&pb);
02330        require_noerr(result, PBVolumeMount);
02331        
02332        /* return the volume reference number */
02333        *volRefNum = pb.ioParam.ioVRefNum;
02334 
02335 PBVolumeMount:
02336 BadParameter:
02337 
02338        return ( result );
02339 }
02340 
02341 /*****************************************************************************/
02342 
02343 OSErr
02344 FSMapID(
02345        FSVolumeRefNum volRefNum,
02346        SInt32 ugID,
02347        SInt16 objType,
02348        Str31 name)
02349 {
02350        OSErr                result;
02351        HParamBlockRec       pb;
02352 
02353        /* check parameters */
02354        require_action(NULL != name, BadParameter, result = paramErr);
02355        
02356        pb.objParam.ioNamePtr = NULL;
02357        pb.objParam.ioVRefNum = volRefNum;
02358        pb.objParam.ioObjType = objType;
02359        pb.objParam.ioObjNamePtr = name;
02360        pb.objParam.ioObjID = ugID;
02361        result = PBHMapIDSync(&pb);
02362        require_noerr(result, PBHMapIDSync);
02363        
02364 PBHMapIDSync:
02365 BadParameter:
02366 
02367        return ( result );
02368 }
02369 
02370 /*****************************************************************************/
02371 
02372 OSErr
02373 FSMapName(
02374        FSVolumeRefNum volRefNum,
02375        ConstStr255Param name,
02376        SInt16 objType,
02377        SInt32 *ugID)
02378 {
02379        OSErr                result;
02380        HParamBlockRec       pb;
02381 
02382        /* check parameters */
02383        require_action(NULL != ugID, BadParameter, result = paramErr);
02384        
02385        pb.objParam.ioNamePtr = NULL;
02386        pb.objParam.ioVRefNum = volRefNum;
02387        pb.objParam.ioObjType = objType;
02388        pb.objParam.ioObjNamePtr = (StringPtr)name;
02389        result = PBHMapNameSync(&pb);
02390        require_noerr(result, PBHMapNameSync);
02391        
02392        /* return the user or group ID */
02393        *ugID = pb.objParam.ioObjID;
02394        
02395 PBHMapNameSync:
02396 BadParameter:
02397 
02398        return ( result );
02399 }
02400 
02401 /*****************************************************************************/
02402 
02403 OSErr
02404 FSCopyFile(
02405        const FSRef *srcFileRef,
02406        const FSRef *dstDirectoryRef,
02407        UniCharCount nameLength,
02408        const UniChar *copyName,    /* can be NULL (no rename during copy) */
02409        TextEncoding textEncodingHint,
02410        FSRef *newRef)                            /* can be NULL */
02411 {
02412        OSErr                              result;
02413        FSSpec                             srcFileSpec;
02414        FSCatalogInfo               catalogInfo;
02415        HParamBlockRec                     pb;
02416        Str31                              hfsName;
02417        GetVolParmsInfoBuffer       volParmsInfo;
02418        UInt32                             infoSize;
02419        
02420        /* get source FSSpec from source FSRef */
02421        result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
02422        require_noerr(result, FSGetCatalogInfo_srcFileRef);
02423        
02424        /* Make sure the volume supports CopyFile */
02425        result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
02426               &volParmsInfo, &infoSize);
02427        require_action((noErr == result) && VolHasCopyFile(&volParmsInfo),
02428               NoCopyFileSupport, result = paramErr);
02429 
02430        /* get destination volume reference number and destination directory ID from destination FSRef */
02431        result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
02432               &catalogInfo, NULL, NULL, NULL);
02433        require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
02434        
02435        /* tell the server to copy the object */
02436        pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
02437        pb.copyParam.ioDirID = srcFileSpec.parID;
02438        pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
02439        pb.copyParam.ioDstVRefNum = catalogInfo.volume;
02440        pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
02441        pb.copyParam.ioNewName = NULL;
02442        if ( NULL != copyName )
02443        {
02444               result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName);
02445               require_noerr(result, UnicodeNameGetHFSName);
02446               
02447               pb.copyParam.ioCopyName = hfsName;
02448        }
02449        else
02450        {
02451               pb.copyParam.ioCopyName = NULL;
02452        }
02453        result = PBHCopyFileSync(&pb);
02454        require_noerr(result, PBHCopyFileSync);
02455        
02456        if ( NULL != newRef )
02457        {
02458               verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID,
02459                      pb.copyParam.ioCopyName, newRef));
02460        }
02461               
02462 PBHCopyFileSync:
02463 UnicodeNameGetHFSName:
02464 FSGetCatalogInfo_dstDirectoryRef:
02465 NoCopyFileSupport:
02466 FSGetCatalogInfo_srcFileRef:
02467 
02468        return ( result );
02469 }
02470 
02471 /*****************************************************************************/
02472 
02473 OSErr
02474 FSMoveRename(
02475        const FSRef *srcFileRef,
02476        const FSRef *dstDirectoryRef,
02477        UniCharCount nameLength,
02478        const UniChar *moveName,    /* can be NULL (no rename during move) */
02479        TextEncoding textEncodingHint,
02480        FSRef *newRef)                            /* can be NULL */
02481 {
02482        OSErr                              result;
02483        FSSpec                             srcFileSpec;
02484        FSCatalogInfo               catalogInfo;
02485        HParamBlockRec                     pb;
02486        Str31                              hfsName;
02487        GetVolParmsInfoBuffer       volParmsInfo;
02488        UInt32                             infoSize;
02489        
02490        /* get source FSSpec from source FSRef */
02491        result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
02492        require_noerr(result, FSGetCatalogInfo_srcFileRef);
02493        
02494        /* Make sure the volume supports MoveRename */
02495        result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
02496               &volParmsInfo, &infoSize);
02497        require_action((noErr == result) && VolHasMoveRename(&volParmsInfo),
02498               NoMoveRenameSupport, result = paramErr);
02499 
02500        /* get destination volume reference number and destination directory ID from destination FSRef */
02501        result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
02502               &catalogInfo, NULL, NULL, NULL);
02503        require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
02504        
02505        /* make sure the source and destination are on the same volume */
02506        require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
02507        
02508        /* tell the server to move and rename the object */
02509        pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
02510        pb.copyParam.ioDirID = srcFileSpec.parID;
02511        pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
02512        pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
02513        pb.copyParam.ioNewName = NULL;
02514        if ( NULL != moveName )
02515        {
02516               result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName);
02517               require_noerr(result, UnicodeNameGetHFSName);
02518               
02519               pb.copyParam.ioCopyName = hfsName;
02520        }
02521        else
02522        {
02523               pb.copyParam.ioCopyName = NULL;
02524        }
02525        result = PBHMoveRenameSync(&pb);
02526        require_noerr(result, PBHMoveRenameSync);
02527        
02528        if ( NULL != newRef )
02529        {
02530               verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID,
02531                      pb.copyParam.ioCopyName, newRef));
02532        }
02533        
02534 PBHMoveRenameSync:
02535 UnicodeNameGetHFSName:
02536 NotSameVolume:
02537 FSGetCatalogInfo_dstDirectoryRef:
02538 NoMoveRenameSupport:
02539 FSGetCatalogInfo_srcFileRef:
02540 
02541        return ( result );
02542 }
02543 
02544 /*****************************************************************************/
02545 
02546 #pragma mark ----- File ID Routines -----
02547 
02548 /*****************************************************************************/
02549 
02550 OSErr
02551 FSResolveFileIDRef(
02552        FSVolumeRefNum volRefNum,
02553        SInt32 fileID,
02554        FSRef *ref)
02555 {
02556        OSErr         result;
02557        FIDParam      pb;
02558        Str255        tempStr;
02559        
02560        /* check parameters */
02561        require_action(NULL != ref, BadParameter, result = paramErr);
02562        
02563        /* resolve the file ID reference */
02564        tempStr[0] = 0;
02565        pb.ioNamePtr = tempStr;
02566        pb.ioVRefNum = volRefNum;
02567        pb.ioFileID = fileID;
02568        result = PBResolveFileIDRefSync((HParmBlkPtr)&pb);
02569        require_noerr(result, PBResolveFileIDRefSync);
02570        
02571        /* and then make an FSRef to the file */
02572        result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref);
02573        require_noerr(result, FSMakeFSRef);
02574        
02575 FSMakeFSRef:
02576 PBResolveFileIDRefSync:
02577 BadParameter:
02578 
02579        return ( result );
02580 }
02581 
02582 /*****************************************************************************/
02583 
02584 OSErr
02585 FSCreateFileIDRef(
02586        const FSRef *ref,
02587        SInt32 *fileID)
02588 {
02589        OSErr         result;
02590        FSSpec        spec;
02591        FIDParam      pb;
02592        
02593        /* check parameters */
02594        require_action(NULL != fileID, BadParameter, result = paramErr);
02595        
02596        /* Get an FSSpec from the FSRef */
02597        result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
02598        require_noerr(result, FSGetCatalogInfo);
02599        
02600        /* Create (or get) the file ID reference using the FSSpec */
02601        pb.ioNamePtr = (StringPtr)spec.name;
02602        pb.ioVRefNum = spec.vRefNum;
02603        pb.ioSrcDirID = spec.parID;
02604        result = PBCreateFileIDRefSync((HParmBlkPtr)&pb);
02605        require((noErr == result) || (fidExists == result) || (afpIDExists == result),
02606               PBCreateFileIDRefSync);
02607        
02608        /* return the file ID reference */
02609        *fileID = pb.ioFileID;
02610        
02611 PBCreateFileIDRefSync:
02612 FSGetCatalogInfo:
02613 BadParameter:
02614 
02615        return ( result );
02616 }
02617 
02618 /*****************************************************************************/
02619 
02620 #pragma mark ----- Utility Routines -----
02621 
02622 /*****************************************************************************/
02623 
02624 Ptr
02625 GetTempBuffer(
02626        ByteCount buffReqSize,
02627        ByteCount *buffActSize)
02628 {
02629        enum
02630        {
02631               kSlopMemory = 0x00008000    /* 32K - Amount of free memory to leave when allocating buffers */
02632        };
02633        
02634        Ptr tempPtr;
02635        
02636        /* check parameters */
02637        require_action(NULL != buffActSize, BadParameter, tempPtr = NULL);
02638        
02639        /* Make request a multiple of 4K bytes */
02640        buffReqSize = buffReqSize & 0xfffff000;
02641        
02642        if ( buffReqSize < 0x00001000 )
02643        {
02644               /* Request was smaller than 4K bytes - make it 4K */
02645               buffReqSize = 0x00001000;
02646        }
02647        
02648        /* Attempt to allocate the memory */
02649        tempPtr = NewPtr(buffReqSize);
02650        
02651        /* If request failed, go to backup plan */
02652        if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) )
02653        {
02654               /*
02655               **     Try to get largest 4K byte block available
02656               **     leaving some slop for the toolbox if possible
02657               */
02658               long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000;
02659               
02660               buffReqSize = MaxBlock() & 0xfffff000;
02661               
02662               if ( buffReqSize > freeMemory )
02663               {
02664                      buffReqSize = freeMemory;
02665               }
02666               
02667               if ( buffReqSize == 0 )
02668               {
02669                      buffReqSize = 0x00001000;
02670               }
02671               
02672               tempPtr = NewPtr(buffReqSize);
02673        }
02674        
02675        /* Return bytes allocated */
02676        if ( tempPtr != NULL )
02677        {
02678               *buffActSize = buffReqSize;
02679        }
02680        else
02681        {
02682               *buffActSize = 0;
02683        }
02684        
02685 BadParameter:
02686 
02687        return ( tempPtr );
02688 }
02689 
02690 /*****************************************************************************/
02691 
02692 OSErr
02693 FileRefNumGetFSRef(
02694        short refNum,
02695        FSRef *ref)
02696 {
02697        return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) );
02698 }
02699 
02700 /*****************************************************************************/
02701 
02702 OSErr
02703 FSSetDefault(
02704        const FSRef *newDefault,
02705        FSRef *oldDefault)
02706 {
02707        OSErr                result;
02708        FSVolumeRefNum       vRefNum;
02709        long                 dirID;
02710        FSCatalogInfo catalogInfo;
02711        
02712        /* check parameters */
02713        require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr);
02714        
02715        /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
02716        result = FSGetCatalogInfo(newDefault,
02717               kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
02718               &catalogInfo, NULL, NULL, NULL);
02719        require_noerr(result, FSGetCatalogInfo);
02720        
02721        /* Make sure newDefault is a directory */
02722        require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory,
02723               result = dirNFErr);
02724        
02725        /* Get the current working directory. */
02726        result = HGetVol(NULL, &vRefNum, &dirID);
02727        require_noerr(result, HGetVol);
02728        
02729        /* Return the oldDefault FSRef */
02730        result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault);
02731        require_noerr(result, FSMakeFSRef);
02732        
02733        /* Set the new current working directory */
02734        result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
02735        require_noerr(result, HSetVol);
02736 
02737 HSetVol:
02738 FSMakeFSRef:
02739 HGetVol:
02740 NewDefaultNotDirectory:
02741 FSGetCatalogInfo:
02742 BadParameter:
02743 
02744        return ( result );
02745 }
02746 
02747 /*****************************************************************************/
02748 
02749 OSErr
02750 FSRestoreDefault(
02751        const FSRef *oldDefault)
02752 {
02753        OSErr                result;
02754        FSCatalogInfo catalogInfo;
02755        
02756        /* check parameters */
02757        require_action(NULL != oldDefault, BadParameter, result = paramErr);
02758        
02759        /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
02760        result = FSGetCatalogInfo(oldDefault,
02761               kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
02762               &catalogInfo, NULL, NULL, NULL);
02763        require_noerr(result, FSGetCatalogInfo);
02764        
02765        /* Make sure oldDefault is a directory */
02766        require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory,
02767               result = dirNFErr);
02768        
02769        /* Set the current working directory to oldDefault */
02770        result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
02771        require_noerr(result, HSetVol);
02772 
02773 HSetVol:
02774 OldDefaultNotDirectory:
02775 FSGetCatalogInfo:
02776 BadParameter:
02777 
02778        return ( result );
02779 }
02780 
02781 /*****************************************************************************/