MoreFilesX.c

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

Generated on Thu Jul 1 06:09:56 2010 for Second Life Viewer by  doxygen 1.4.7