MoreFilesX.c

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

Generated on Wed May 31 18:19:56 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6