--- /dev/null
+/*
+ File: MoreFilesX.c
+
+ Contains: A collection of useful high-level File Manager routines
+ which use the HFS Plus APIs wherever possible.
+
+ Version: MoreFilesX 1.0.1
+
+ Copyright: © 1992-2002 by Apple Computer, Inc., all rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ File Ownership:
+
+ DRI: Apple Macintosh Developer Technical Support
+
+ Other Contact: For bug reports, consult the following page on
+ the World Wide Web:
+ http://developer.apple.com/bugreporter/
+
+ Technology: DTS Sample Code
+
+ Writers:
+
+ (JL) Jim Luther
+
+ Change History (most recent first):
+
+ <4> 8/22/02 JL [3016251] Changed FSMoveRenameObjectUnicode to not use
+ the Temporary folder because it isn't available on
+ NFS volumes.
+ <3> 4/19/02 JL [2853905] Fixed #if test around header includes.
+ <2> 4/19/02 JL [2850624] Fixed C++ compile errors and Project Builder
+ warnings.
+ <2> 4/19/02 JL [2853901] Updated standard disclaimer.
+ <1> 1/25/02 JL MoreFilesX 1.0
+*/
+
+#if defined(__MACH__)
+ #include <Carbon/Carbon.h>
+ #include <string.h>
+#else
+ #include <Carbon.h>
+ #include <string.h>
+#endif
+
+#include "MoreFilesX.h"
+
+/* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */
+#ifndef BuildingMoreFilesXForMacOS9
+ #define BuildingMoreFilesXForMacOS9 0
+#endif
+
+/*****************************************************************************/
+
+#pragma mark ----- Local type definitions -----
+
+struct FSIterateContainerGlobals
+{
+ IterateContainerFilterProcPtr iterateFilter; /* pointer to IterateFilterProc */
+ FSCatalogInfoBitmap whichInfo; /* fields of the CatalogInfo to get */
+ FSCatalogInfo catalogInfo; /* FSCatalogInfo */
+ FSRef ref; /* FSRef */
+ FSSpec spec; /* FSSpec */
+ FSSpec *specPtr; /* pointer to spec field, or NULL */
+ HFSUniStr255 name; /* HFSUniStr255 */
+ HFSUniStr255 *namePtr; /* pointer to name field, or NULL */
+ void *yourDataPtr; /* a pointer to caller supplied data the filter may need to access */
+ ItemCount maxLevels; /* maximum levels to iterate through */
+ ItemCount currentLevel; /* the current level FSIterateContainerLevel is on */
+ Boolean quitFlag; /* set to true if filter wants to kill interation */
+ Boolean containerChanged; /* temporary - set to true if the current container changed during iteration */
+ OSErr result; /* result */
+ ItemCount actualObjects; /* number of objects returned */
+};
+typedef struct FSIterateContainerGlobals FSIterateContainerGlobals;
+
+struct FSDeleteContainerGlobals
+{
+ OSErr result; /* result */
+ ItemCount actualObjects; /* number of objects returned */
+ FSCatalogInfo catalogInfo; /* FSCatalogInfo */
+};
+typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals;
+
+/*****************************************************************************/
+
+#pragma mark ----- Local prototypes -----
+
+static
+void
+FSDeleteContainerLevel(
+ const FSRef *container,
+ FSDeleteContainerGlobals *theGlobals);
+
+static
+void
+FSIterateContainerLevel(
+ FSIterateContainerGlobals *theGlobals);
+
+static
+OSErr
+GenerateUniqueHFSUniStr(
+ long *startSeed,
+ const FSRef *dir1,
+ const FSRef *dir2,
+ HFSUniStr255 *uniqueName);
+
+/*****************************************************************************/
+
+#pragma mark ----- File Access Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSCopyFork(
+ SInt16 srcRefNum,
+ SInt16 dstRefNum,
+ void *copyBufferPtr,
+ ByteCount copyBufferSize)
+{
+ OSErr srcResult;
+ OSErr dstResult;
+ OSErr result;
+ SInt64 forkSize;
+ ByteCount readActualCount;
+
+ /* check input parameters */
+ require_action((NULL != copyBufferPtr) && (0 != copyBufferSize), BadParameter, result = paramErr);
+
+ /* get source fork size */
+ result = FSGetForkSize(srcRefNum, &forkSize);
+ require_noerr(result, SourceFSGetForkSizeFailed);
+
+ /* allocate disk space for destination fork */
+ result = FSSetForkSize(dstRefNum, fsFromStart, forkSize);
+ require_noerr(result, DestinationFSSetForkSizeFailed);
+
+ /* reset source fork's position to 0 */
+ result = FSSetForkPosition(srcRefNum, fsFromStart, 0);
+ require_noerr(result, SourceFSSetForkPositionFailed);
+
+ /* reset destination fork's position to 0 */
+ result = FSSetForkPosition(dstRefNum, fsFromStart, 0);
+ require_noerr(result, DestinationFSSetForkPositionFailed);
+
+ /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */
+ /* This will make writes on local volumes faster */
+ if ( (copyBufferSize >= 0x00001000) && ((copyBufferSize & 0x00000fff) != 0) )
+ {
+ copyBufferSize &= ~(0x00001000 - 1);
+ }
+
+ /* copy source to destination */
+ srcResult = dstResult = noErr;
+ while ( (noErr == srcResult) && (noErr == dstResult) )
+ {
+ srcResult = FSReadFork(srcRefNum, fsAtMark + noCacheMask, 0, copyBufferSize, copyBufferPtr, &readActualCount);
+ dstResult = FSWriteFork(dstRefNum, fsAtMark + noCacheMask, 0, readActualCount, copyBufferPtr, NULL);
+ }
+
+ /* make sure there were no errors at the destination */
+ require_noerr_action(dstResult, DestinationFSWriteForkFailed, result = dstResult);
+
+ /* make sure the error at the source was eofErr */
+ require_action(eofErr == srcResult, SourceResultNotEofErr, result = srcResult);
+
+ /* everything went as expected */
+ result = noErr;
+
+SourceResultNotEofErr:
+DestinationFSWriteForkFailed:
+DestinationFSSetForkPositionFailed:
+SourceFSSetForkPositionFailed:
+DestinationFSSetForkSizeFailed:
+SourceFSGetForkSizeFailed:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Volume Access Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSGetVolParms(
+ FSVolumeRefNum volRefNum,
+ UInt32 bufferSize,
+ GetVolParmsInfoBuffer *volParmsInfo,
+ UInt32 *actualInfoSize)
+{
+ OSErr result;
+ HParamBlockRec pb;
+
+ /* check parameters */
+ require_action((NULL != volParmsInfo) && (NULL != actualInfoSize),
+ BadParameter, result = paramErr);
+
+ pb.ioParam.ioNamePtr = NULL;
+ pb.ioParam.ioVRefNum = volRefNum;
+ pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
+ pb.ioParam.ioReqCount = (SInt32)bufferSize;
+ result = PBHGetVolParmsSync(&pb);
+ require_noerr(result, PBHGetVolParmsSync);
+
+ /* return number of bytes the file system returned in volParmsInfo buffer */
+ *actualInfoSize = (UInt32)pb.ioParam.ioActCount;
+
+PBHGetVolParmsSync:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVRefNum(
+ const FSRef *ref,
+ FSVolumeRefNum *vRefNum)
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+
+ /* check parameters */
+ require_action(NULL != vRefNum, BadParameter, result = paramErr);
+
+ /* get the volume refNum from the FSRef */
+ result = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* return volume refNum from catalogInfo */
+ *vRefNum = catalogInfo.volume;
+
+FSGetCatalogInfo:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVInfo(
+ FSVolumeRefNum volume,
+ HFSUniStr255 *volumeName, /* can be NULL */
+ UInt64 *freeBytes, /* can be NULL */
+ UInt64 *totalBytes) /* can be NULL */
+{
+ OSErr result;
+ FSVolumeInfo info;
+
+ /* ask for the volume's sizes only if needed */
+ result = FSGetVolumeInfo(volume, 0, NULL,
+ (((NULL != freeBytes) || (NULL != totalBytes)) ? kFSVolInfoSizes : kFSVolInfoNone),
+ &info, volumeName, NULL);
+ require_noerr(result, FSGetVolumeInfo);
+
+ if ( NULL != freeBytes )
+ {
+ *freeBytes = info.freeBytes;
+ }
+ if ( NULL != totalBytes )
+ {
+ *totalBytes = info.totalBytes;
+ }
+
+FSGetVolumeInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVolFileSystemID(
+ FSVolumeRefNum volume,
+ UInt16 *fileSystemID, /* can be NULL */
+ UInt16 *signature) /* can be NULL */
+{
+ OSErr result;
+ FSVolumeInfo info;
+
+ result = FSGetVolumeInfo(volume, 0, NULL, kFSVolInfoFSInfo, &info, NULL, NULL);
+ require_noerr(result, FSGetVolumeInfo);
+
+ if ( NULL != fileSystemID )
+ {
+ *fileSystemID = info.filesystemID;
+ }
+ if ( NULL != signature )
+ {
+ *signature = info.signature;
+ }
+
+FSGetVolumeInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetMountedVolumes(
+ FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */
+ ItemCount *numVolumes)
+{
+ OSErr result;
+ OSErr memResult;
+ ItemCount volumeIndex;
+ FSRef ref;
+
+ /* check parameters */
+ require_action((NULL != volumeRefsHandle) && (NULL != numVolumes),
+ BadParameter, result = paramErr);
+
+ /* No volumes yet */
+ *numVolumes = 0;
+
+ /* Allocate a handle for the results */
+ *volumeRefsHandle = (FSRef **)NewHandle(0);
+ require_action(NULL != *volumeRefsHandle, NewHandle, result = memFullErr);
+
+ /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */
+ volumeIndex = 1;
+ do
+ {
+ result = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoNone, NULL, NULL, &ref);
+ if ( noErr == result )
+ {
+ /* concatenate the FSRef to the end of the handle */
+ PtrAndHand(&ref, (Handle)*volumeRefsHandle, sizeof(FSRef));
+ memResult = MemError();
+ require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
+
+ ++(*numVolumes); /* increment the volume count */
+ ++volumeIndex; /* and the volumeIndex to get the next volume*/
+ }
+ } while ( noErr == result );
+
+ /* nsvErr is OK -- it just means there are no more volumes */
+ require(nsvErr == result, FSGetVolumeInfo);
+
+ return ( noErr );
+
+ /**********************/
+
+MemoryAllocationFailed:
+FSGetVolumeInfo:
+
+ /* dispose of handle if already allocated and clear the outputs */
+ if ( NULL != *volumeRefsHandle )
+ {
+ DisposeHandle((Handle)*volumeRefsHandle);
+ *volumeRefsHandle = NULL;
+ }
+ *numVolumes = 0;
+
+NewHandle:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSRefMakeFSSpec(
+ const FSRef *ref,
+ FSSpec *spec)
+{
+ OSErr result;
+
+ /* check parameters */
+ require_action(NULL != spec, BadParameter, result = paramErr);
+
+ result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+FSGetCatalogInfo:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMakeFSRef(
+ FSVolumeRefNum volRefNum,
+ SInt32 dirID,
+ ConstStr255Param name,
+ FSRef *ref)
+{
+ OSErr result;
+ FSRefParam pb;
+
+ /* check parameters */
+ require_action(NULL != ref, BadParameter, result = paramErr);
+
+ pb.ioVRefNum = volRefNum;
+ pb.ioDirID = dirID;
+ pb.ioNamePtr = (StringPtr)name;
+ pb.newRef = ref;
+ result = PBMakeFSRefSync(&pb);
+ require_noerr(result, PBMakeFSRefSync);
+
+PBMakeFSRefSync:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSStatus
+FSMakePath(
+ SInt16 volRefNum,
+ SInt32 dirID,
+ ConstStr255Param name,
+ UInt8 *path,
+ UInt32 maxPathSize)
+{
+ OSStatus result;
+ FSRef ref;
+
+ /* check parameters */
+ require_action(NULL != path, BadParameter, result = paramErr);
+
+ /* convert the inputs to an FSRef */
+ result = FSMakeFSRef(volRefNum, dirID, name, &ref);
+ require_noerr(result, FSMakeFSRef);
+
+ /* and then convert the FSRef to a path */
+ result = FSRefMakePath(&ref, path, maxPathSize);
+ require_noerr(result, FSRefMakePath);
+
+FSRefMakePath:
+FSMakeFSRef:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSStatus
+FSPathMakeFSSpec(
+ const UInt8 *path,
+ FSSpec *spec,
+ Boolean *isDirectory) /* can be NULL */
+{
+ OSStatus result;
+ FSRef ref;
+
+ /* check parameters */
+ require_action(NULL != spec, BadParameter, result = paramErr);
+
+ /* convert the POSIX path to an FSRef */
+ result = FSPathMakeRef(path, &ref, isDirectory);
+ require_noerr(result, FSPathMakeRef);
+
+ /* and then convert the FSRef to an FSSpec */
+ result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+FSGetCatalogInfo:
+FSPathMakeRef:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+UnicodeNameGetHFSName(
+ UniCharCount nameLength,
+ const UniChar *name,
+ TextEncoding textEncodingHint,
+ Boolean isVolumeName,
+ Str31 hfsName)
+{
+ OSStatus result;
+ ByteCount unicodeByteLength;
+ ByteCount unicodeBytesConverted;
+ ByteCount actualPascalBytes;
+ UnicodeMapping uMapping;
+ UnicodeToTextInfo utInfo;
+
+ /* check parameters */
+ require_action(NULL != hfsName, BadParameter, result = paramErr);
+
+ /* make sure output is valid in case we get errors or there's nothing to convert */
+ hfsName[0] = 0;
+
+ unicodeByteLength = nameLength * sizeof(UniChar);
+ if ( 0 == unicodeByteLength )
+ {
+ /* do nothing */
+ result = noErr;
+ }
+ else
+ {
+ /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
+ if ( kTextEncodingUnknown == textEncodingHint )
+ {
+ ScriptCode script;
+ RegionCode region;
+
+ script = (ScriptCode)GetScriptManagerVariable(smSysScript);
+ region = (RegionCode)GetScriptManagerVariable(smRegionCode);
+ result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
+ NULL, &textEncodingHint );
+ if ( paramErr == result )
+ {
+ /* ok, ignore the region and try again */
+ result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
+ kTextRegionDontCare, NULL, &textEncodingHint );
+ }
+ if ( noErr != result )
+ {
+ /* ok... try something */
+ textEncodingHint = kTextEncodingMacRoman;
+ }
+ }
+
+ uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
+ kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
+ uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
+ uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
+
+ result = CreateUnicodeToTextInfo(&uMapping, &utInfo);
+ require_noerr(result, CreateUnicodeToTextInfo);
+
+ result = ConvertFromUnicodeToText(utInfo, unicodeByteLength, name, kUnicodeLooseMappingsMask,
+ 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */
+ isVolumeName ? kHFSMaxVolumeNameChars : kHFSMaxFileNameChars,
+ &unicodeBytesConverted, &actualPascalBytes, &hfsName[1]);
+ require_noerr(result, ConvertFromUnicodeToText);
+
+ hfsName[0] = (unsigned char)actualPascalBytes; /* fill in length byte */
+
+ConvertFromUnicodeToText:
+
+ /* verify the result in debug builds -- there's really not anything you can do if it fails */
+ verify_noerr(DisposeUnicodeToTextInfo(&utInfo));
+ }
+
+CreateUnicodeToTextInfo:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+HFSNameGetUnicodeName(
+ ConstStr31Param hfsName,
+ TextEncoding textEncodingHint,
+ HFSUniStr255 *unicodeName)
+{
+ ByteCount unicodeByteLength;
+ OSStatus result;
+ UnicodeMapping uMapping;
+ TextToUnicodeInfo tuInfo;
+ ByteCount pascalCharsRead;
+
+ /* check parameters */
+ require_action(NULL != unicodeName, BadParameter, result = paramErr);
+
+ /* make sure output is valid in case we get errors or there's nothing to convert */
+ unicodeName->length = 0;
+
+ if ( 0 == StrLength(hfsName) )
+ {
+ result = noErr;
+ }
+ else
+ {
+ /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
+ if ( kTextEncodingUnknown == textEncodingHint )
+ {
+ ScriptCode script;
+ RegionCode region;
+
+ script = GetScriptManagerVariable(smSysScript);
+ region = GetScriptManagerVariable(smRegionCode);
+ result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
+ NULL, &textEncodingHint);
+ if ( paramErr == result )
+ {
+ /* ok, ignore the region and try again */
+ result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
+ kTextRegionDontCare, NULL, &textEncodingHint);
+ }
+ if ( noErr != result )
+ {
+ /* ok... try something */
+ textEncodingHint = kTextEncodingMacRoman;
+ }
+ }
+
+ uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
+ kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
+ uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
+ uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
+
+ result = CreateTextToUnicodeInfo(&uMapping, &tuInfo);
+ require_noerr(result, CreateTextToUnicodeInfo);
+
+ result = ConvertFromTextToUnicode(tuInfo, hfsName[0], &hfsName[1],
+ 0, /* no control flag bits */
+ 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */
+ sizeof(unicodeName->unicode), /* output buffer size in bytes */
+ &pascalCharsRead, &unicodeByteLength, unicodeName->unicode);
+ require_noerr(result, ConvertFromTextToUnicode);
+
+ /* convert from byte count to char count */
+ unicodeName->length = unicodeByteLength / sizeof(UniChar);
+
+ConvertFromTextToUnicode:
+
+ /* verify the result in debug builds -- there's really not anything you can do if it fails */
+ verify_noerr(DisposeTextToUnicodeInfo(&tuInfo));
+ }
+
+CreateTextToUnicodeInfo:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- File/Directory Manipulation Routines -----
+
+/*****************************************************************************/
+
+Boolean FSRefValid(const FSRef *ref)
+{
+ return ( noErr == FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, NULL, NULL) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetParentRef(
+ const FSRef *ref,
+ FSRef *parentRef)
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+
+ /* check parameters */
+ require_action(NULL != parentRef, BadParameter, result = paramErr);
+
+ result = FSGetCatalogInfo(ref, kFSCatInfoNodeID, &catalogInfo, NULL, NULL, parentRef);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /*
+ * Note: FSRefs always point to real file system objects. So, there cannot
+ * be a FSRef to the parent of volume root directories. Early versions of
+ * Mac OS X do not handle this case correctly and incorrectly return a
+ * FSRef for the parent of volume root directories instead of returning an
+ * invalid FSRef (a cleared FSRef is invalid). The next three lines of code
+ * ensure that you won't run into this bug. WW9D!
+ */
+ if ( fsRtDirID == catalogInfo.nodeID )
+ {
+ /* clear parentRef and return noErr which is the proper behavior */
+ memset(parentRef, 0, sizeof(FSRef));
+ }
+
+FSGetCatalogInfo:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetFileDirName(
+ const FSRef *ref,
+ HFSUniStr255 *outName)
+{
+ OSErr result;
+
+ /* check parameters */
+ require_action(NULL != outName, BadParameter, result = paramErr);
+
+ result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, outName, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+FSGetCatalogInfo:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetNodeID(
+ const FSRef *ref,
+ long *nodeID, /* can be NULL */
+ Boolean *isDirectory) /* can be NULL */
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+ FSCatalogInfoBitmap whichInfo;
+
+ /* determine what catalog information to get */
+ whichInfo = kFSCatInfoNone; /* start with none */
+ if ( NULL != nodeID )
+ {
+ whichInfo |= kFSCatInfoNodeID;
+ }
+ if ( NULL != isDirectory )
+ {
+ whichInfo |= kFSCatInfoNodeFlags;
+ }
+
+ result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ if ( NULL != nodeID )
+ {
+ *nodeID = catalogInfo.nodeID;
+ }
+ if ( NULL != isDirectory )
+ {
+ *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
+ }
+
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetUserPrivilegesPermissions(
+ const FSRef *ref,
+ UInt8 *userPrivileges, /* can be NULL */
+ UInt32 permissions[4]) /* can be NULL */
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+ FSCatalogInfoBitmap whichInfo;
+
+ /* determine what catalog information to get */
+ whichInfo = kFSCatInfoNone; /* start with none */
+ if ( NULL != userPrivileges )
+ {
+ whichInfo |= kFSCatInfoUserPrivs;
+ }
+ if ( NULL != permissions )
+ {
+ whichInfo |= kFSCatInfoPermissions;
+ }
+
+ result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ if ( NULL != userPrivileges )
+ {
+ *userPrivileges = catalogInfo.userPrivileges;
+ }
+ if ( NULL != permissions )
+ {
+ BlockMoveData(&catalogInfo.permissions, permissions, sizeof(UInt32) * 4);
+ }
+
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCheckLock(
+ const FSRef *ref)
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+ FSVolumeInfo volumeInfo;
+
+ /* get nodeFlags and vRefNum for container */
+ result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoVolume, &catalogInfo, NULL, NULL,NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* is file locked? */
+ if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
+ {
+ result = fLckdErr; /* file is locked */
+ }
+ else
+ {
+ /* file isn't locked, but is volume locked? */
+
+ /* get volume flags */
+ result = FSGetVolumeInfo(catalogInfo.volume, 0, NULL, kFSVolInfoFlags, &volumeInfo, NULL, NULL);
+ require_noerr(result, FSGetVolumeInfo);
+
+ if ( 0 != (volumeInfo.flags & kFSVolFlagHardwareLockedMask) )
+ {
+ result = wPrErr; /* volume locked by hardware */
+ }
+ else if ( 0 != (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) )
+ {
+ result = vLckdErr; /* volume locked by software */
+ }
+ }
+
+FSGetVolumeInfo:
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetForkSizes(
+ const FSRef *ref,
+ UInt64 *dataLogicalSize, /* can be NULL */
+ UInt64 *rsrcLogicalSize) /* can be NULL */
+{
+ OSErr result;
+ FSCatalogInfoBitmap whichInfo;
+ FSCatalogInfo catalogInfo;
+
+ whichInfo = kFSCatInfoNodeFlags;
+ if ( NULL != dataLogicalSize )
+ {
+ /* get data fork size */
+ whichInfo |= kFSCatInfoDataSizes;
+ }
+ if ( NULL != rsrcLogicalSize )
+ {
+ /* get resource fork size */
+ whichInfo |= kFSCatInfoRsrcSizes;
+ }
+
+ /* get nodeFlags and catalog info */
+ result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL,NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* make sure FSRef was to a file */
+ require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
+
+ if ( NULL != dataLogicalSize )
+ {
+ /* return data fork size */
+ *dataLogicalSize = catalogInfo.dataLogicalSize;
+ }
+ if ( NULL != rsrcLogicalSize )
+ {
+ /* return resource fork size */
+ *rsrcLogicalSize = catalogInfo.rsrcLogicalSize;
+ }
+
+FSRefNotFile:
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetTotalForkSizes(
+ const FSRef *ref,
+ UInt64 *totalLogicalSize, /* can be NULL */
+ UInt64 *totalPhysicalSize, /* can be NULL */
+ ItemCount *forkCount) /* can be NULL */
+{
+ OSErr result;
+ CatPositionRec forkIterator;
+ SInt64 forkSize;
+ SInt64 *forkSizePtr;
+ UInt64 forkPhysicalSize;
+ UInt64 *forkPhysicalSizePtr;
+
+ /* Determine if forkSize needed */
+ if ( NULL != totalLogicalSize)
+ {
+ *totalLogicalSize = 0;
+ forkSizePtr = &forkSize;
+ }
+ else
+ {
+ forkSizePtr = NULL;
+ }
+
+ /* Determine if forkPhysicalSize is needed */
+ if ( NULL != totalPhysicalSize )
+ {
+ *totalPhysicalSize = 0;
+ forkPhysicalSizePtr = &forkPhysicalSize;
+ }
+ else
+ {
+ forkPhysicalSizePtr = NULL;
+ }
+
+ /* zero fork count if returning it */
+ if ( NULL != forkCount )
+ {
+ *forkCount = 0;
+ }
+
+ /* Iterate through the forks to get the sizes */
+ forkIterator.initialize = 0;
+ do
+ {
+ result = FSIterateForks(ref, &forkIterator, NULL, forkSizePtr, forkPhysicalSizePtr);
+ if ( noErr == result )
+ {
+ if ( NULL != totalLogicalSize )
+ {
+ *totalLogicalSize += forkSize;
+ }
+
+ if ( NULL != totalPhysicalSize )
+ {
+ *totalPhysicalSize += forkPhysicalSize;
+ }
+
+ if ( NULL != forkCount )
+ {
+ ++*forkCount;
+ }
+ }
+ } while ( noErr == result );
+
+ /* any error result other than errFSNoMoreItems is serious */
+ require(errFSNoMoreItems == result, FSIterateForks);
+
+ /* Normal exit */
+ result = noErr;
+
+FSIterateForks:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSBumpDate(
+ const FSRef *ref)
+{
+ OSStatus result;
+ FSCatalogInfo catalogInfo;
+ UTCDateTime oldDateTime;
+#if !BuildingMoreFilesXForMacOS9
+ FSRef parentRef;
+ Boolean notifyParent;
+#endif
+
+#if !BuildingMoreFilesXForMacOS9
+ /* Get the node flags, the content modification date and time, and the parent ref */
+ result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoContentMod, &catalogInfo, NULL, NULL, &parentRef);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* Notify the parent if this is a file */
+ notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask));
+#else
+ /* Get the content modification date and time */
+ result = FSGetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+#endif
+
+ oldDateTime = catalogInfo.contentModDate;
+
+ /* Get the current date and time */
+ result = GetUTCDateTime(&catalogInfo.contentModDate, kUTCDefaultOptions);
+ require_noerr(result, GetUTCDateTime);
+
+ /* if the old date and time is the the same as the current, bump the seconds by one */
+ if ( (catalogInfo.contentModDate.fraction == oldDateTime.fraction) &&
+ (catalogInfo.contentModDate.lowSeconds == oldDateTime.lowSeconds) &&
+ (catalogInfo.contentModDate.highSeconds == oldDateTime.highSeconds) )
+ {
+ ++catalogInfo.contentModDate.lowSeconds;
+ if ( 0 == catalogInfo.contentModDate.lowSeconds )
+ {
+ ++catalogInfo.contentModDate.highSeconds;
+ }
+ }
+
+ /* Bump the content modification date and time */
+ result = FSSetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo);
+ require_noerr(result, FSSetCatalogInfo);
+
+#if !BuildingMoreFilesXForMacOS9
+ /*
+ * The problem with FNNotify is that it is not available under Mac OS 9
+ * and there's no way to test for that except for looking for the symbol
+ * or something. So, I'll just conditionalize this for those who care
+ * to send a notification.
+ */
+
+ /* Send a notification for the parent of the file, or for the directory */
+ result = FNNotify(notifyParent ? &parentRef : ref, kFNDirectoryModifiedMessage, kNilOptions);
+ require_noerr(result, FNNotify);
+#endif
+
+ /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */
+FNNotify:
+FSSetCatalogInfo:
+
+ return ( noErr );
+
+ /**********************/
+
+GetUTCDateTime:
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetFinderInfo(
+ const FSRef *ref,
+ FinderInfo *info, /* can be NULL */
+ ExtendedFinderInfo *extendedInfo, /* can be NULL */
+ Boolean *isDirectory) /* can be NULL */
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+ FSCatalogInfoBitmap whichInfo;
+
+ /* determine what catalog information is really needed */
+ whichInfo = kFSCatInfoNone;
+
+ if ( NULL != info )
+ {
+ /* get FinderInfo */
+ whichInfo |= kFSCatInfoFinderInfo;
+ }
+
+ if ( NULL != extendedInfo )
+ {
+ /* get ExtendedFinderInfo */
+ whichInfo |= kFSCatInfoFinderXInfo;
+ }
+
+ if ( NULL != isDirectory )
+ {
+ whichInfo |= kFSCatInfoNodeFlags;
+ }
+
+ result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* return FinderInfo if requested */
+ if ( NULL != info )
+ {
+ BlockMoveData(catalogInfo.finderInfo, info, sizeof(FinderInfo));
+ }
+
+ /* return ExtendedFinderInfo if requested */
+ if ( NULL != extendedInfo)
+ {
+ BlockMoveData(catalogInfo.extFinderInfo, extendedInfo, sizeof(ExtendedFinderInfo));
+ }
+
+ /* set isDirectory Boolean if requested */
+ if ( NULL != isDirectory)
+ {
+ *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
+ }
+
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetFinderInfo(
+ const FSRef *ref,
+ const FinderInfo *info,
+ const ExtendedFinderInfo *extendedInfo)
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+ FSCatalogInfoBitmap whichInfo;
+
+ /* determine what catalog information will be set */
+ whichInfo = kFSCatInfoNone; /* start with none */
+ if ( NULL != info )
+ {
+ /* set FinderInfo */
+ whichInfo |= kFSCatInfoFinderInfo;
+ BlockMoveData(info, catalogInfo.finderInfo, sizeof(FinderInfo));
+ }
+ if ( NULL != extendedInfo )
+ {
+ /* set ExtendedFinderInfo */
+ whichInfo |= kFSCatInfoFinderXInfo;
+ BlockMoveData(extendedInfo, catalogInfo.extFinderInfo, sizeof(ExtendedFinderInfo));
+ }
+
+ result = FSSetCatalogInfo(ref, whichInfo, &catalogInfo);
+ require_noerr(result, FSGetCatalogInfo);
+
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSChangeCreatorType(
+ const FSRef *ref,
+ OSType fileCreator,
+ OSType fileType)
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+ FSRef parentRef;
+
+ /* get nodeFlags, finder info, and parent FSRef */
+ result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, &catalogInfo , NULL, NULL, &parentRef);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* make sure FSRef was to a file */
+ require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
+
+ /* If fileType not 0x00000000, change fileType */
+ if ( fileType != (OSType)0x00000000 )
+ {
+ ((FileInfo *)&catalogInfo.finderInfo)->fileType = fileType;
+ }
+
+ /* If creator not 0x00000000, change creator */
+ if ( fileCreator != (OSType)0x00000000 )
+ {
+ ((FileInfo *)&catalogInfo.finderInfo)->fileCreator = fileCreator;
+ }
+
+ /* now, save the new information back to disk */
+ result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
+ require_noerr(result, FSSetCatalogInfo);
+
+ /* and attempt to bump the parent directory's mod date to wake up */
+ /* the Finder to the change we just made (ignore errors from this) */
+ verify_noerr(FSBumpDate(&parentRef));
+
+FSSetCatalogInfo:
+FSRefNotFile:
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSChangeFinderFlags(
+ const FSRef *ref,
+ Boolean setBits,
+ UInt16 flagBits)
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+ FSRef parentRef;
+
+ /* get the current finderInfo */
+ result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* set or clear the appropriate bits in the finderInfo.finderFlags */
+ if ( setBits )
+ {
+ /* OR in the bits */
+ ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits;
+ }
+ else
+ {
+ /* AND out the bits */
+ ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits;
+ }
+
+ /* save the modified finderInfo */
+ result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
+ require_noerr(result, FSSetCatalogInfo);
+
+ /* and attempt to bump the parent directory's mod date to wake up the Finder */
+ /* to the change we just made (ignore errors from this) */
+ verify_noerr(FSBumpDate(&parentRef));
+
+FSSetCatalogInfo:
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetInvisible(
+ const FSRef *ref)
+{
+ return ( FSChangeFinderFlags(ref, true, kIsInvisible) );
+}
+
+OSErr
+FSClearInvisible(
+ const FSRef *ref)
+{
+ return ( FSChangeFinderFlags(ref, false, kIsInvisible) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetNameLocked(
+ const FSRef *ref)
+{
+ return ( FSChangeFinderFlags(ref, true, kNameLocked) );
+}
+
+OSErr
+FSClearNameLocked(
+ const FSRef *ref)
+{
+ return ( FSChangeFinderFlags(ref, false, kNameLocked) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetIsStationery(
+ const FSRef *ref)
+{
+ return ( FSChangeFinderFlags(ref, true, kIsStationery) );
+}
+
+OSErr
+FSClearIsStationery(
+ const FSRef *ref)
+{
+ return ( FSChangeFinderFlags(ref, false, kIsStationery) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetHasCustomIcon(
+ const FSRef *ref)
+{
+ return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) );
+}
+
+OSErr
+FSClearHasCustomIcon(
+ const FSRef *ref)
+{
+ return ( FSChangeFinderFlags(ref, false, kHasCustomIcon) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSClearHasBeenInited(
+ const FSRef *ref)
+{
+ return ( FSChangeFinderFlags(ref, false, kHasBeenInited) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCopyFileMgrAttributes(
+ const FSRef *sourceRef,
+ const FSRef *destinationRef,
+ Boolean copyLockBit)
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+
+ /* get the source information */
+ result = FSGetCatalogInfo(sourceRef, kFSCatInfoSettableInfo, &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* don't copy the hasBeenInited bit; clear it */
+ ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~kHasBeenInited;
+
+ /* should the locked bit be copied? */
+ if ( !copyLockBit )
+ {
+ /* no, make sure the locked bit is clear */
+ catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
+ }
+
+ /* set the destination information */
+ result = FSSetCatalogInfo(destinationRef, kFSCatInfoSettableInfo, &catalogInfo);
+ require_noerr(result, FSSetCatalogInfo);
+
+FSSetCatalogInfo:
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMoveRenameObjectUnicode(
+ const FSRef *ref,
+ const FSRef *destDirectory,
+ UniCharCount nameLength,
+ const UniChar *name, /* can be NULL (no rename during move) */
+ TextEncoding textEncodingHint,
+ FSRef *newRef) /* if function fails along the way, newRef is final location of file */
+{
+ OSErr result;
+ FSVolumeRefNum vRefNum;
+ FSCatalogInfo catalogInfo;
+ FSRef originalDirectory;
+ TextEncoding originalTextEncodingHint;
+ HFSUniStr255 originalName;
+ HFSUniStr255 uniqueName; /* unique name given to object while moving it to destination */
+ long theSeed; /* the seed for generating unique names */
+
+ /* check parameters */
+ require_action(NULL != newRef, BadParameter, result = paramErr);
+
+ /* newRef = input to start with */
+ BlockMoveData(ref, newRef, sizeof(FSRef));
+
+ /* get destDirectory's vRefNum */
+ result = FSGetCatalogInfo(destDirectory, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, DestinationBad);
+
+ /* save vRefNum */
+ vRefNum = catalogInfo.volume;
+
+ /* get ref's vRefNum, TextEncoding, name and parent directory*/
+ result = FSGetCatalogInfo(ref, kFSCatInfoTextEncoding + kFSCatInfoVolume, &catalogInfo, &originalName, NULL, &originalDirectory);
+ require_noerr(result, SourceBad);
+
+ /* save TextEncoding */
+ originalTextEncodingHint = catalogInfo.textEncodingHint;
+
+ /* make sure ref and destDirectory are on same volume */
+ require_action(vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
+
+ /* Skip a few steps if we're not renaming */
+ if ( NULL != name )
+ {
+ /* generate a name that is unique in both directories */
+ theSeed = 0x4a696d4c; /* a fine unlikely filename */
+
+ result = GenerateUniqueHFSUniStr(&theSeed, &originalDirectory, destDirectory, &uniqueName);
+ require_noerr(result, GenerateUniqueHFSUniStrFailed);
+
+ /* Rename the object to uniqueName */
+ result = FSRenameUnicode(ref, uniqueName.length, uniqueName.unicode, kTextEncodingUnknown, newRef);
+ require_noerr(result, FSRenameUnicodeBeforeMoveFailed);
+
+ /* Move object to its new home */
+ result = FSMoveObject(newRef, destDirectory, newRef);
+ require_noerr(result, FSMoveObjectAfterRenameFailed);
+
+ /* Rename the object to new name */
+ result = FSRenameUnicode(ref, nameLength, name, textEncodingHint, newRef);
+ require_noerr(result, FSRenameUnicodeAfterMoveFailed);
+ }
+ else
+ {
+ /* Move object to its new home */
+ result = FSMoveObject(newRef, destDirectory, newRef);
+ require_noerr(result, FSMoveObjectNoRenameFailed);
+ }
+
+ return ( result );
+
+ /*************/
+
+/*
+ * failure handling code when renaming
+ */
+
+FSRenameUnicodeAfterMoveFailed:
+
+ /* Error handling: move object back to original location - ignore errors */
+ verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef));
+
+FSMoveObjectAfterRenameFailed:
+
+ /* Error handling: rename object back to original name - ignore errors */
+ verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef));
+
+FSRenameUnicodeBeforeMoveFailed:
+GenerateUniqueHFSUniStrFailed:
+
+/*
+ * failure handling code for renaming or not
+ */
+FSMoveObjectNoRenameFailed:
+NotSameVolume:
+SourceBad:
+DestinationBad:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+ The FSDeleteContainerLevel function deletes the contents of a container
+ directory. All files and subdirectories in the specified container are
+ deleted. If a locked file or directory is encountered, it is unlocked
+ and then deleted. If any unexpected errors are encountered,
+ FSDeleteContainerLevel quits and returns to the caller.
+
+ container --> FSRef to a directory.
+ theGlobals --> A pointer to a FSDeleteContainerGlobals struct
+ which contains the variables that do not need to
+ be allocated each time FSDeleteContainerLevel
+ recurses. That lets FSDeleteContainerLevel use
+ less stack space per recursion level.
+*/
+
+static
+void
+FSDeleteContainerLevel(
+ const FSRef *container,
+ FSDeleteContainerGlobals *theGlobals)
+{
+ /* level locals */
+ FSIterator iterator;
+ FSRef itemToDelete;
+ UInt16 nodeFlags;
+
+ /* Open FSIterator for flat access and give delete optimization hint */
+ theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator);
+ require_noerr(theGlobals->result, FSOpenIterator);
+
+ /* delete the contents of the directory */
+ do
+ {
+ /* get 1 item to delete */
+ theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
+ NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo,
+ &itemToDelete, NULL, NULL);
+ if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) )
+ {
+ /* save node flags in local in case we have to recurse */
+ nodeFlags = theGlobals->catalogInfo.nodeFlags;
+
+ /* is it a file or directory? */
+ if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) )
+ {
+ /* it's a directory -- delete its contents before attempting to delete it */
+ FSDeleteContainerLevel(&itemToDelete, theGlobals);
+ }
+ /* are we still OK to delete? */
+ if ( noErr == theGlobals->result )
+ {
+ /* is item locked? */
+ if ( 0 != (nodeFlags & kFSNodeLockedMask) )
+ {
+ /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
+ theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask;
+ (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo);
+ }
+ /* delete the item */
+ theGlobals->result = FSDeleteObject(&itemToDelete);
+ }
+ }
+ } while ( noErr == theGlobals->result );
+
+ /* we found the end of the items normally, so return noErr */
+ if ( errFSNoMoreItems == theGlobals->result )
+ {
+ theGlobals->result = noErr;
+ }
+
+ /* close the FSIterator (closing an open iterator should never fail) */
+ verify_noerr(FSCloseIterator(iterator));
+
+FSOpenIterator:
+
+ return;
+}
+
+/*****************************************************************************/
+
+OSErr
+FSDeleteContainerContents(
+ const FSRef *container)
+{
+ FSDeleteContainerGlobals theGlobals;
+
+ /* delete container's contents */
+ FSDeleteContainerLevel(container, &theGlobals);
+
+ return ( theGlobals.result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSDeleteContainer(
+ const FSRef *container)
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+
+ /* get nodeFlags for container */
+ result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* make sure container is a directory */
+ require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr);
+
+ /* delete container's contents */
+ result = FSDeleteContainerContents(container);
+ require_noerr(result, FSDeleteContainerContents);
+
+ /* is container locked? */
+ if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
+ {
+ /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
+ catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
+ (void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo);
+ }
+
+ /* delete the container */
+ result = FSDeleteObject(container);
+
+FSDeleteContainerContents:
+ContainerNotDirectory:
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+ The FSIterateContainerLevel function iterates the contents of a container
+ directory and calls a IterateContainerFilterProc function once for each
+ file and directory found.
+
+ theGlobals --> A pointer to a FSIterateContainerGlobals struct
+ which contains the variables needed globally by
+ all recusion levels of FSIterateContainerLevel.
+ That makes FSIterateContainer thread safe since
+ each call to it uses its own global world.
+ It also contains the variables that do not need
+ to be allocated each time FSIterateContainerLevel
+ recurses. That lets FSIterateContainerLevel use
+ less stack space per recursion level.
+*/
+
+static
+void
+FSIterateContainerLevel(
+ FSIterateContainerGlobals *theGlobals)
+{
+ FSIterator iterator;
+
+ /* If maxLevels is zero, we aren't checking levels */
+ /* If currentLevel < maxLevels, look at this level */
+ if ( (theGlobals->maxLevels == 0) ||
+ (theGlobals->currentLevel < theGlobals->maxLevels) )
+ {
+ /* Open FSIterator for flat access to theGlobals->ref */
+ theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator);
+ require_noerr(theGlobals->result, FSOpenIterator);
+
+ ++theGlobals->currentLevel; /* Go to next level */
+
+ /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
+ do
+ {
+ theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
+ &theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo,
+ &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr);
+ if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) &&
+ (0 != theGlobals->actualObjects) )
+ {
+ /* Call the IterateFilterProc */
+ theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter,
+ theGlobals->containerChanged, theGlobals->currentLevel,
+ &theGlobals->catalogInfo, &theGlobals->ref,
+ theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr);
+ /* Is it a directory? */
+ if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) )
+ {
+ /* Keep going? */
+ if ( !theGlobals->quitFlag )
+ {
+ /* Dive again if the IterateFilterProc didn't say "quit" */
+ FSIterateContainerLevel(theGlobals);
+ }
+ }
+ }
+ /* time to fall back a level? */
+ } while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) );
+
+ /* errFSNoMoreItems is OK - it only means we hit the end of this level */
+ /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
+ if ( (errFSNoMoreItems == theGlobals->result) ||
+ (afpAccessDenied == theGlobals->result) )
+ {
+ theGlobals->result = noErr;
+ }
+
+ --theGlobals->currentLevel; /* Return to previous level as we leave */
+
+ /* Close the FSIterator (closing an open iterator should never fail) */
+ verify_noerr(FSCloseIterator(iterator));
+ }
+
+FSOpenIterator:
+
+ return;
+}
+
+/*****************************************************************************/
+
+OSErr
+FSIterateContainer(
+ const FSRef *container,
+ ItemCount maxLevels,
+ FSCatalogInfoBitmap whichInfo,
+ Boolean wantFSSpec,
+ Boolean wantName,
+ IterateContainerFilterProcPtr iterateFilter,
+ void *yourDataPtr)
+{
+ OSErr result;
+ FSIterateContainerGlobals theGlobals;
+
+ /* make sure there is an iterateFilter */
+ require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr);
+
+ /*
+ * set up the globals we need to access from the recursive routine
+ */
+ theGlobals.iterateFilter = iterateFilter;
+ /* we need the node flags no matter what was requested so we can detect files vs. directories */
+ theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags;
+ /* start with input container -- the first OpenIterator will ensure it is a directory */
+ theGlobals.ref = *container;
+ if ( wantFSSpec )
+ {
+ theGlobals.specPtr = &theGlobals.spec;
+ }
+ else
+ {
+ theGlobals.specPtr = NULL;
+ }
+ if ( wantName )
+ {
+ theGlobals.namePtr = &theGlobals.name;
+ }
+ else
+ {
+ theGlobals.namePtr = NULL;
+ }
+ theGlobals.yourDataPtr = yourDataPtr;
+ theGlobals.maxLevels = maxLevels;
+ theGlobals.currentLevel = 0;
+ theGlobals.quitFlag = false;
+ theGlobals.containerChanged = false;
+ theGlobals.result = noErr;
+ theGlobals.actualObjects = 0;
+
+ /* here we go into recursion land... */
+ FSIterateContainerLevel(&theGlobals);
+ result = theGlobals.result;
+ require_noerr(result, FSIterateContainerLevel);
+
+FSIterateContainerLevel:
+NoIterateFilter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetDirectoryItems(
+ const FSRef *container,
+ FSRef ***refsHandle, /* pointer to handle of FSRefs */
+ ItemCount *numRefs,
+ Boolean *containerChanged)
+{
+ /* Grab items 10 at a time. */
+ enum { kMaxItemsPerBulkCall = 10 };
+
+ OSErr result;
+ OSErr memResult;
+ FSIterator iterator;
+ FSRef refs[kMaxItemsPerBulkCall];
+ ItemCount actualObjects;
+ Boolean changed;
+
+ /* check parameters */
+ require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged),
+ BadParameter, result = paramErr);
+
+ *numRefs = 0;
+ *containerChanged = false;
+ *refsHandle = (FSRef **)NewHandle(0);
+ require_action(NULL != *refsHandle, NewHandle, result = memFullErr);
+
+ /* open an FSIterator */
+ result = FSOpenIterator(container, kFSIterateFlat, &iterator);
+ require_noerr(result, FSOpenIterator);
+
+ /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
+ do
+ {
+ result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects,
+ &changed, kFSCatInfoNone, NULL, refs, NULL, NULL);
+
+ /* if the container changed, set containerChanged for output, but keep going */
+ if ( changed )
+ {
+ *containerChanged = changed;
+ }
+
+ /* any result other than noErr and errFSNoMoreItems is serious */
+ require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk);
+
+ /* add objects to output array and count */
+ if ( 0 != actualObjects )
+ {
+ /* concatenate the FSRefs to the end of the handle */
+ PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef));
+ memResult = MemError();
+ require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
+
+ *numRefs += actualObjects;
+ }
+ } while ( noErr == result );
+
+ verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */
+
+ return ( noErr );
+
+ /**********************/
+
+MemoryAllocationFailed:
+FSGetCatalogInfoBulk:
+
+ /* close the iterator */
+ verify_noerr(FSCloseIterator(iterator));
+
+FSOpenIterator:
+ /* dispose of handle if already allocated and clear the outputs */
+ if ( NULL != *refsHandle )
+ {
+ DisposeHandle((Handle)*refsHandle);
+ *refsHandle = NULL;
+ }
+ *numRefs = 0;
+
+NewHandle:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+ The GenerateUniqueName function generates a HFSUniStr255 name that is
+ unique in both dir1 and dir2.
+
+ startSeed --> A pointer to a long which is used to generate the
+ unique name.
+ <-- It is modified on output to a value which should
+ be used to generate the next unique name.
+ dir1 --> The first directory.
+ dir2 --> The second directory.
+ uniqueName <-- A pointer to a HFSUniStr255 where the unique name
+ is to be returned.
+*/
+
+static
+OSErr
+GenerateUniqueHFSUniStr(
+ long *startSeed,
+ const FSRef *dir1,
+ const FSRef *dir2,
+ HFSUniStr255 *uniqueName)
+{
+ OSErr result;
+ long i;
+ FSRefParam pb;
+ FSRef newRef;
+ unsigned char hexStr[17] = "0123456789ABCDEF";
+
+ /* set up the parameter block */
+ pb.name = uniqueName->unicode;
+ pb.nameLength = 8; /* always 8 characters */
+ pb.textEncodingHint = kTextEncodingUnknown;
+ pb.newRef = &newRef;
+
+ /* loop until we get fnfErr with a filename in both directories */
+ result = noErr;
+ while ( fnfErr != result )
+ {
+ /* convert startSeed to 8 character Unicode string */
+ uniqueName->length = 8;
+ for ( i = 0; i < 8; ++i )
+ {
+ uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)];
+ }
+
+ /* try in dir1 */
+ pb.ref = dir1;
+ result = PBMakeFSRefUnicodeSync(&pb);
+ if ( fnfErr == result )
+ {
+ /* try in dir2 */
+ pb.ref = dir2;
+ result = PBMakeFSRefUnicodeSync(&pb);
+ if ( fnfErr != result )
+ {
+ /* exit if anything other than noErr or fnfErr */
+ require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed);
+ }
+ }
+ else
+ {
+ /* exit if anything other than noErr or fnfErr */
+ require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed);
+ }
+
+ /* increment seed for next pass through loop, */
+ /* or for next call to GenerateUniqueHFSUniStr */
+ ++(*startSeed);
+ }
+
+ /* we have a unique file name which doesn't exist in dir1 or dir2 */
+ result = noErr;
+
+Dir2PBMakeFSRefUnicodeSyncFailed:
+Dir1PBMakeFSRefUnicodeSyncFailed:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSExchangeObjectsCompat(
+ const FSRef *sourceRef,
+ const FSRef *destRef,
+ FSRef *newSourceRef,
+ FSRef *newDestRef)
+{
+ enum
+ {
+ /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
+ kGetCatInformationMask = (kFSCatInfoSettableInfo |
+ kFSCatInfoVolume |
+ kFSCatInfoParentDirID) &
+ ~(kFSCatInfoContentMod | kFSCatInfoAttrMod),
+ /* set everything possible except for mod dates */
+ kSetCatinformationMask = kFSCatInfoSettableInfo &
+ ~(kFSCatInfoContentMod | kFSCatInfoAttrMod)
+ };
+
+ OSErr result;
+ GetVolParmsInfoBuffer volParmsInfo;
+ UInt32 infoSize;
+ FSCatalogInfo sourceCatalogInfo; /* source file's catalog information */
+ FSCatalogInfo destCatalogInfo; /* destination file's catalog information */
+ HFSUniStr255 sourceName; /* source file's Unicode name */
+ HFSUniStr255 destName; /* destination file's Unicode name */
+ FSRef sourceCurrentRef; /* FSRef to current location of source file throughout this function */
+ FSRef destCurrentRef; /* FSRef to current location of destination file throughout this function */
+ FSRef sourceParentRef; /* FSRef to parent directory of source file */
+ FSRef destParentRef; /* FSRef to parent directory of destination file */
+ HFSUniStr255 sourceUniqueName; /* unique name given to source file while exchanging it with destination */
+ HFSUniStr255 destUniqueName; /* unique name given to destination file while exchanging it with source */
+ long theSeed; /* the seed for generating unique names */
+ Boolean sameParentDirs; /* true if source and destinatin parent directory is the same */
+
+ /* check parameters */
+ require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr);
+
+ /* output refs and current refs = input refs to start with */
+ BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef));
+ BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef));
+
+ BlockMoveData(destRef, newDestRef, sizeof(FSRef));
+ BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef));
+
+ /* get source volume's vRefNum */
+ result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL);
+ require_noerr(result, DetermineSourceVRefNumFailed);
+
+ /* see if that volume supports FSExchangeObjects */
+ result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer),
+ &volParmsInfo, &infoSize);
+ if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) )
+ {
+ /* yes - use FSExchangeObjects */
+ result = FSExchangeObjects(sourceRef, destRef);
+ }
+ else
+ {
+ /* no - emulate FSExchangeObjects */
+
+ /* Note: The compatibility case won't work for files with *Btree control blocks. */
+ /* Right now the only *Btree files are created by the system. */
+
+ /* get all catalog information and Unicode names for each file */
+ result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef);
+ require_noerr(result, SourceFSGetCatalogInfoFailed);
+
+ result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef);
+ require_noerr(result, DestFSGetCatalogInfoFailed);
+
+ /* make sure source and destination are on same volume */
+ require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr);
+
+ /* make sure both files are *really* files */
+ require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) &&
+ (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr);
+
+ /* generate 2 names that are unique in both directories */
+ theSeed = 0x4a696d4c; /* a fine unlikely filename */
+
+ result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName);
+ require_noerr(result, GenerateUniqueHFSUniStr1Failed);
+
+ result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName);
+ require_noerr(result, GenerateUniqueHFSUniStr2Failed);
+
+ /* rename sourceCurrentRef to sourceUniqueName */
+ result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef);
+ require_noerr(result, FSRenameUnicode1Failed);
+ BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+
+ /* rename destCurrentRef to destUniqueName */
+ result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef);
+ require_noerr(result, FSRenameUnicode2Failed);
+ BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
+
+ /* are the source and destination parent directories the same? */
+ sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID );
+ if ( !sameParentDirs )
+ {
+ /* move source file to dest parent directory */
+ result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef);
+ require_noerr(result, FSMoveObject1Failed);
+ BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+
+ /* move dest file to source parent directory */
+ result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef);
+ require_noerr(result, FSMoveObject2Failed);
+ BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
+ }
+
+ /* At this point, the files are in their new locations (if they were moved). */
+ /* The source file is named sourceUniqueName and is in the directory referred to */
+ /* by destParentRef. The destination file is named destUniqueName and is in the */
+ /* directory referred to by sourceParentRef. */
+
+ /* give source file the dest file's catalog information except for mod dates */
+ result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo);
+ require_noerr(result, FSSetCatalogInfo1Failed);
+
+ /* give dest file the source file's catalog information except for mod dates */
+ result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo);
+ require_noerr(result, FSSetCatalogInfo2Failed);
+
+ /* rename source file with dest file's name */
+ result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef);
+ require_noerr(result, FSRenameUnicode3Failed);
+ BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+
+ /* rename dest file with source file's name */
+ result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef);
+ require_noerr(result, FSRenameUnicode4Failed);
+
+ /* we're done with no errors, so swap newSourceRef and newDestRef */
+ BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef));
+ BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef));
+ }
+
+ return ( result );
+
+ /**********************/
+
+/* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
+/* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
+/* state and location they ended up in so that both files can be found by the calling code. */
+
+FSRenameUnicode4Failed:
+
+ /* attempt to rename source file to sourceUniqueName */
+ if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) )
+ {
+ BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+ }
+
+FSRenameUnicode3Failed:
+
+ /* attempt to restore dest file's catalog information */
+ verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo));
+
+FSSetCatalogInfo2Failed:
+
+ /* attempt to restore source file's catalog information */
+ verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo));
+
+FSSetCatalogInfo1Failed:
+
+ if ( !sameParentDirs )
+ {
+ /* attempt to move dest file back to dest directory */
+ if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) )
+ {
+ BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
+ }
+ }
+
+FSMoveObject2Failed:
+
+ if ( !sameParentDirs )
+ {
+ /* attempt to move source file back to source directory */
+ if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) )
+ {
+ BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
+ }
+ }
+
+FSMoveObject1Failed:
+
+ /* attempt to rename dest file to original name */
+ verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef));
+
+FSRenameUnicode2Failed:
+
+ /* attempt to rename source file to original name */
+ verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef));
+
+FSRenameUnicode1Failed:
+GenerateUniqueHFSUniStr2Failed:
+GenerateUniqueHFSUniStr1Failed:
+NotAFile:
+NotSameVolume:
+DestFSGetCatalogInfoFailed:
+SourceFSGetCatalogInfoFailed:
+DetermineSourceVRefNumFailed:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Shared Environment Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSLockRange(
+ SInt16 refNum,
+ SInt32 rangeLength,
+ SInt32 rangeStart)
+{
+ OSErr result;
+ ParamBlockRec pb;
+
+ pb.ioParam.ioRefNum = refNum;
+ pb.ioParam.ioReqCount = rangeLength;
+ pb.ioParam.ioPosMode = fsFromStart;
+ pb.ioParam.ioPosOffset = rangeStart;
+ result = PBLockRangeSync(&pb);
+ require_noerr(result, PBLockRangeSync);
+
+PBLockRangeSync:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSUnlockRange(
+ SInt16 refNum,
+ SInt32 rangeLength,
+ SInt32 rangeStart)
+{
+ OSErr result;
+ ParamBlockRec pb;
+
+ pb.ioParam.ioRefNum = refNum;
+ pb.ioParam.ioReqCount = rangeLength;
+ pb.ioParam.ioPosMode = fsFromStart;
+ pb.ioParam.ioPosOffset = rangeStart;
+ result = PBUnlockRangeSync(&pb);
+ require_noerr(result, PBUnlockRangeSync);
+
+PBUnlockRangeSync:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetDirAccess(
+ const FSRef *ref,
+ SInt32 *ownerID, /* can be NULL */
+ SInt32 *groupID, /* can be NULL */
+ SInt32 *accessRights) /* can be NULL */
+{
+ OSErr result;
+ FSSpec spec;
+ HParamBlockRec pb;
+
+ /* get FSSpec from FSRef */
+ result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* get directory access info for FSSpec */
+ pb.accessParam.ioNamePtr = (StringPtr)spec.name;
+ pb.accessParam.ioVRefNum = spec.vRefNum;
+ pb.fileParam.ioDirID = spec.parID;
+ result = PBHGetDirAccessSync(&pb);
+ require_noerr(result, PBHGetDirAccessSync);
+
+ /* return the IDs and access rights */
+ if ( NULL != ownerID )
+ {
+ *ownerID = pb.accessParam.ioACOwnerID;
+ }
+ if ( NULL != groupID )
+ {
+ *groupID = pb.accessParam.ioACGroupID;
+ }
+ if ( NULL != accessRights )
+ {
+ *accessRights = pb.accessParam.ioACAccess;
+ }
+
+PBHGetDirAccessSync:
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetDirAccess(
+ const FSRef *ref,
+ SInt32 ownerID,
+ SInt32 groupID,
+ SInt32 accessRights)
+{
+ OSErr result;
+ FSSpec spec;
+ HParamBlockRec pb;
+
+ enum
+ {
+ /* Just the bits that can be set */
+ kSetDirAccessSettableMask = (kioACAccessBlankAccessMask +
+ kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask +
+ kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask +
+ kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask)
+ };
+
+ /* get FSSpec from FSRef */
+ result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* set directory access info for FSSpec */
+ pb.accessParam.ioNamePtr = (StringPtr)spec.name;
+ pb.accessParam.ioVRefNum = spec.vRefNum;
+ pb.fileParam.ioDirID = spec.parID;
+ pb.accessParam.ioACOwnerID = ownerID;
+ pb.accessParam.ioACGroupID = groupID;
+ pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask;
+ result = PBHSetDirAccessSync(&pb);
+ require_noerr(result, PBHSetDirAccessSync);
+
+PBHSetDirAccessSync:
+FSGetCatalogInfo:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVolMountInfoSize(
+ FSVolumeRefNum volRefNum,
+ SInt16 *size)
+{
+ OSErr result;
+ ParamBlockRec pb;
+
+ /* check parameters */
+ require_action(NULL != size, BadParameter, result = paramErr);
+
+ pb.ioParam.ioNamePtr = NULL;
+ pb.ioParam.ioVRefNum = volRefNum;
+ pb.ioParam.ioBuffer = (Ptr)size;
+ result = PBGetVolMountInfoSize(&pb);
+ require_noerr(result, PBGetVolMountInfoSize);
+
+PBGetVolMountInfoSize:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSGetVolMountInfo(
+ FSVolumeRefNum volRefNum,
+ void *volMountInfo)
+{
+ OSErr result;
+ ParamBlockRec pb;
+
+ /* check parameters */
+ require_action(NULL != volMountInfo, BadParameter, result = paramErr);
+
+ pb.ioParam.ioNamePtr = NULL;
+ pb.ioParam.ioVRefNum = volRefNum;
+ pb.ioParam.ioBuffer = (Ptr)volMountInfo;
+ result = PBGetVolMountInfo(&pb);
+ require_noerr(result, PBGetVolMountInfo);
+
+PBGetVolMountInfo:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSVolumeMount(
+ const void *volMountInfo,
+ FSVolumeRefNum *volRefNum)
+{
+ OSErr result;
+ ParamBlockRec pb;
+
+ /* check parameters */
+ require_action(NULL != volRefNum, BadParameter, result = paramErr);
+
+ pb.ioParam.ioBuffer = (Ptr)volMountInfo;
+ result = PBVolumeMount(&pb);
+ require_noerr(result, PBVolumeMount);
+
+ /* return the volume reference number */
+ *volRefNum = pb.ioParam.ioVRefNum;
+
+PBVolumeMount:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMapID(
+ FSVolumeRefNum volRefNum,
+ SInt32 ugID,
+ SInt16 objType,
+ Str31 name)
+{
+ OSErr result;
+ HParamBlockRec pb;
+
+ /* check parameters */
+ require_action(NULL != name, BadParameter, result = paramErr);
+
+ pb.objParam.ioNamePtr = NULL;
+ pb.objParam.ioVRefNum = volRefNum;
+ pb.objParam.ioObjType = objType;
+ pb.objParam.ioObjNamePtr = name;
+ pb.objParam.ioObjID = ugID;
+ result = PBHMapIDSync(&pb);
+ require_noerr(result, PBHMapIDSync);
+
+PBHMapIDSync:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMapName(
+ FSVolumeRefNum volRefNum,
+ ConstStr255Param name,
+ SInt16 objType,
+ SInt32 *ugID)
+{
+ OSErr result;
+ HParamBlockRec pb;
+
+ /* check parameters */
+ require_action(NULL != ugID, BadParameter, result = paramErr);
+
+ pb.objParam.ioNamePtr = NULL;
+ pb.objParam.ioVRefNum = volRefNum;
+ pb.objParam.ioObjType = objType;
+ pb.objParam.ioObjNamePtr = (StringPtr)name;
+ result = PBHMapNameSync(&pb);
+ require_noerr(result, PBHMapNameSync);
+
+ /* return the user or group ID */
+ *ugID = pb.objParam.ioObjID;
+
+PBHMapNameSync:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCopyFile(
+ const FSRef *srcFileRef,
+ const FSRef *dstDirectoryRef,
+ UniCharCount nameLength,
+ const UniChar *copyName, /* can be NULL (no rename during copy) */
+ TextEncoding textEncodingHint,
+ FSRef *newRef) /* can be NULL */
+{
+ OSErr result;
+ FSSpec srcFileSpec;
+ FSCatalogInfo catalogInfo;
+ HParamBlockRec pb;
+ Str31 hfsName;
+ GetVolParmsInfoBuffer volParmsInfo;
+ UInt32 infoSize;
+
+ /* get source FSSpec from source FSRef */
+ result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
+ require_noerr(result, FSGetCatalogInfo_srcFileRef);
+
+ /* Make sure the volume supports CopyFile */
+ result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
+ &volParmsInfo, &infoSize);
+ require_action((noErr == result) && VolHasCopyFile(&volParmsInfo),
+ NoCopyFileSupport, result = paramErr);
+
+ /* get destination volume reference number and destination directory ID from destination FSRef */
+ result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
+ &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
+
+ /* tell the server to copy the object */
+ pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
+ pb.copyParam.ioDirID = srcFileSpec.parID;
+ pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
+ pb.copyParam.ioDstVRefNum = catalogInfo.volume;
+ pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
+ pb.copyParam.ioNewName = NULL;
+ if ( NULL != copyName )
+ {
+ result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName);
+ require_noerr(result, UnicodeNameGetHFSName);
+
+ pb.copyParam.ioCopyName = hfsName;
+ }
+ else
+ {
+ pb.copyParam.ioCopyName = NULL;
+ }
+ result = PBHCopyFileSync(&pb);
+ require_noerr(result, PBHCopyFileSync);
+
+ if ( NULL != newRef )
+ {
+ verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID,
+ pb.copyParam.ioCopyName, newRef));
+ }
+
+PBHCopyFileSync:
+UnicodeNameGetHFSName:
+FSGetCatalogInfo_dstDirectoryRef:
+NoCopyFileSupport:
+FSGetCatalogInfo_srcFileRef:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSMoveRename(
+ const FSRef *srcFileRef,
+ const FSRef *dstDirectoryRef,
+ UniCharCount nameLength,
+ const UniChar *moveName, /* can be NULL (no rename during move) */
+ TextEncoding textEncodingHint,
+ FSRef *newRef) /* can be NULL */
+{
+ OSErr result;
+ FSSpec srcFileSpec;
+ FSCatalogInfo catalogInfo;
+ HParamBlockRec pb;
+ Str31 hfsName;
+ GetVolParmsInfoBuffer volParmsInfo;
+ UInt32 infoSize;
+
+ /* get source FSSpec from source FSRef */
+ result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
+ require_noerr(result, FSGetCatalogInfo_srcFileRef);
+
+ /* Make sure the volume supports MoveRename */
+ result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
+ &volParmsInfo, &infoSize);
+ require_action((noErr == result) && VolHasMoveRename(&volParmsInfo),
+ NoMoveRenameSupport, result = paramErr);
+
+ /* get destination volume reference number and destination directory ID from destination FSRef */
+ result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
+ &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
+
+ /* make sure the source and destination are on the same volume */
+ require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
+
+ /* tell the server to move and rename the object */
+ pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
+ pb.copyParam.ioDirID = srcFileSpec.parID;
+ pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
+ pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
+ pb.copyParam.ioNewName = NULL;
+ if ( NULL != moveName )
+ {
+ result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName);
+ require_noerr(result, UnicodeNameGetHFSName);
+
+ pb.copyParam.ioCopyName = hfsName;
+ }
+ else
+ {
+ pb.copyParam.ioCopyName = NULL;
+ }
+ result = PBHMoveRenameSync(&pb);
+ require_noerr(result, PBHMoveRenameSync);
+
+ if ( NULL != newRef )
+ {
+ verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID,
+ pb.copyParam.ioCopyName, newRef));
+ }
+
+PBHMoveRenameSync:
+UnicodeNameGetHFSName:
+NotSameVolume:
+FSGetCatalogInfo_dstDirectoryRef:
+NoMoveRenameSupport:
+FSGetCatalogInfo_srcFileRef:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- File ID Routines -----
+
+/*****************************************************************************/
+
+OSErr
+FSResolveFileIDRef(
+ FSVolumeRefNum volRefNum,
+ SInt32 fileID,
+ FSRef *ref)
+{
+ OSErr result;
+ FIDParam pb;
+ Str255 tempStr;
+
+ /* check parameters */
+ require_action(NULL != ref, BadParameter, result = paramErr);
+
+ /* resolve the file ID reference */
+ tempStr[0] = 0;
+ pb.ioNamePtr = tempStr;
+ pb.ioVRefNum = volRefNum;
+ pb.ioFileID = fileID;
+ result = PBResolveFileIDRefSync((HParmBlkPtr)&pb);
+ require_noerr(result, PBResolveFileIDRefSync);
+
+ /* and then make an FSRef to the file */
+ result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref);
+ require_noerr(result, FSMakeFSRef);
+
+FSMakeFSRef:
+PBResolveFileIDRefSync:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSCreateFileIDRef(
+ const FSRef *ref,
+ SInt32 *fileID)
+{
+ OSErr result;
+ FSSpec spec;
+ FIDParam pb;
+
+ /* check parameters */
+ require_action(NULL != fileID, BadParameter, result = paramErr);
+
+ /* Get an FSSpec from the FSRef */
+ result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* Create (or get) the file ID reference using the FSSpec */
+ pb.ioNamePtr = (StringPtr)spec.name;
+ pb.ioVRefNum = spec.vRefNum;
+ pb.ioSrcDirID = spec.parID;
+ result = PBCreateFileIDRefSync((HParmBlkPtr)&pb);
+ require((noErr == result) || (fidExists == result) || (afpIDExists == result),
+ PBCreateFileIDRefSync);
+
+ /* return the file ID reference */
+ *fileID = pb.ioFileID;
+
+PBCreateFileIDRefSync:
+FSGetCatalogInfo:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+#pragma mark ----- Utility Routines -----
+
+/*****************************************************************************/
+
+Ptr
+GetTempBuffer(
+ ByteCount buffReqSize,
+ ByteCount *buffActSize)
+{
+ enum
+ {
+ kSlopMemory = 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
+ };
+
+ Ptr tempPtr;
+
+ /* check parameters */
+ require_action(NULL != buffActSize, BadParameter, tempPtr = NULL);
+
+ /* Make request a multiple of 4K bytes */
+ buffReqSize = buffReqSize & 0xfffff000;
+
+ if ( buffReqSize < 0x00001000 )
+ {
+ /* Request was smaller than 4K bytes - make it 4K */
+ buffReqSize = 0x00001000;
+ }
+
+ /* Attempt to allocate the memory */
+ tempPtr = NewPtr(buffReqSize);
+
+ /* If request failed, go to backup plan */
+ if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) )
+ {
+ /*
+ ** Try to get largest 4K byte block available
+ ** leaving some slop for the toolbox if possible
+ */
+ long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000;
+
+ buffReqSize = MaxBlock() & 0xfffff000;
+
+ if ( buffReqSize > freeMemory )
+ {
+ buffReqSize = freeMemory;
+ }
+
+ if ( buffReqSize == 0 )
+ {
+ buffReqSize = 0x00001000;
+ }
+
+ tempPtr = NewPtr(buffReqSize);
+ }
+
+ /* Return bytes allocated */
+ if ( tempPtr != NULL )
+ {
+ *buffActSize = buffReqSize;
+ }
+ else
+ {
+ *buffActSize = 0;
+ }
+
+BadParameter:
+
+ return ( tempPtr );
+}
+
+/*****************************************************************************/
+
+OSErr
+FileRefNumGetFSRef(
+ short refNum,
+ FSRef *ref)
+{
+ return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSSetDefault(
+ const FSRef *newDefault,
+ FSRef *oldDefault)
+{
+ OSErr result;
+ FSVolumeRefNum vRefNum;
+ long dirID;
+ FSCatalogInfo catalogInfo;
+
+ /* check parameters */
+ require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr);
+
+ /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
+ result = FSGetCatalogInfo(newDefault,
+ kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
+ &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* Make sure newDefault is a directory */
+ require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory,
+ result = dirNFErr);
+
+ /* Get the current working directory. */
+ result = HGetVol(NULL, &vRefNum, &dirID);
+ require_noerr(result, HGetVol);
+
+ /* Return the oldDefault FSRef */
+ result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault);
+ require_noerr(result, FSMakeFSRef);
+
+ /* Set the new current working directory */
+ result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
+ require_noerr(result, HSetVol);
+
+HSetVol:
+FSMakeFSRef:
+HGetVol:
+NewDefaultNotDirectory:
+FSGetCatalogInfo:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
+
+OSErr
+FSRestoreDefault(
+ const FSRef *oldDefault)
+{
+ OSErr result;
+ FSCatalogInfo catalogInfo;
+
+ /* check parameters */
+ require_action(NULL != oldDefault, BadParameter, result = paramErr);
+
+ /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
+ result = FSGetCatalogInfo(oldDefault,
+ kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
+ &catalogInfo, NULL, NULL, NULL);
+ require_noerr(result, FSGetCatalogInfo);
+
+ /* Make sure oldDefault is a directory */
+ require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory,
+ result = dirNFErr);
+
+ /* Set the current working directory to oldDefault */
+ result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
+ require_noerr(result, HSetVol);
+
+HSetVol:
+OldDefaultNotDirectory:
+FSGetCatalogInfo:
+BadParameter:
+
+ return ( result );
+}
+
+/*****************************************************************************/
--- /dev/null
+/*
+ File: MoreFilesX.h
+
+ Contains: A collection of useful high-level File Manager routines
+ which use the HFS Plus APIs wherever possible.
+
+ Version: MoreFilesX 1.0.1
+
+ Copyright: © 1992-2002 by Apple Computer, Inc., all rights reserved.
+
+ Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
+ ("Apple") in consideration of your agreement to the following terms, and your
+ use, installation, modification or redistribution of this Apple software
+ constitutes acceptance of these terms. If you do not agree with these terms,
+ please do not use, install, modify or redistribute this Apple software.
+
+ In consideration of your agreement to abide by the following terms, and subject
+ to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
+ copyrights in this original Apple software (the "Apple Software"), to use,
+ reproduce, modify and redistribute the Apple Software, with or without
+ modifications, in source and/or binary forms; provided that if you redistribute
+ the Apple Software in its entirety and without modifications, you must retain
+ this notice and the following text and disclaimers in all such redistributions of
+ the Apple Software. Neither the name, trademarks, service marks or logos of
+ Apple Computer, Inc. may be used to endorse or promote products derived from the
+ Apple Software without specific prior written permission from Apple. Except as
+ expressly stated in this notice, no other rights or licenses, express or implied,
+ are granted by Apple herein, including but not limited to any patent rights that
+ may be infringed by your derivative works or by other works in which the Apple
+ Software may be incorporated.
+
+ The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
+ WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
+ WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
+ COMBINATION WITH YOUR PRODUCTS.
+
+ IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
+ CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
+ OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
+ (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ File Ownership:
+
+ DRI: Apple Macintosh Developer Technical Support
+
+ Other Contact: For bug reports, consult the following page on
+ the World Wide Web:
+ http://developer.apple.com/bugreporter/
+
+ Technology: DTS Sample Code
+
+ Writers:
+
+ (JL) Jim Luther
+
+ Change History (most recent first):
+
+ <3> 4/19/02 JL [2853905] Fixed #if test around header includes.
+ <2> 4/19/02 JL [2853901] Updated standard disclaimer.
+ <1> 1/25/02 JL MoreFilesX 1.0
+
+ Notes:
+ What do those arrows in the documentation for each routine mean?
+
+ --> The parameter is an input
+
+ <-- The parameter is an output. The pointer to the variable
+ where the output will be returned (must not be NULL).
+
+ <** The parameter is an optional output. If it is not a
+ NULL pointer, it points to the variable where the output
+ will be returned. If it is a NULL pointer, the output will
+ not be returned and will possibly let the routine and the
+ File Manager do less work. If you don't need an optional output,
+ don't ask for it.
+ **> The parameter is an optional input. If it is not a
+ NULL pointer, it points to the variable containing the
+ input data. If it is a NULL pointer, the input is not used
+ and will possibly let the routine and the File Manager
+ do less work.
+*/
+
+#ifndef __MOREFILESX__
+#define __MOREFILESX__
+
+#ifndef __CARBON__
+ #if defined(__MACH__)
+ #include <Carbon/Carbon.h>
+ #else
+ #include <Carbon.h>
+ #endif
+#endif
+
+#if PRAGMA_ONCE
+#pragma once
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#if PRAGMA_IMPORT
+#pragma import on
+#endif
+
+#if PRAGMA_STRUCT_ALIGN
+ #pragma options align=mac68k
+#elif PRAGMA_STRUCT_PACKPUSH
+ #pragma pack(push, 2)
+#elif PRAGMA_STRUCT_PACK
+ #pragma pack(2)
+#endif
+
+/*****************************************************************************/
+
+#pragma mark ----- FinderInfo and ExtendedFinderInfo -----
+
+/*
+ * FSGetFinderInfo and FSSetFinderInfo use these unions for Finder information.
+ */
+
+union FinderInfo
+{
+ FileInfo file;
+ FolderInfo folder;
+};
+typedef union FinderInfo FinderInfo;
+
+union ExtendedFinderInfo
+{
+ ExtendedFileInfo file;
+ ExtendedFolderInfo folder;
+};
+typedef union ExtendedFinderInfo ExtendedFinderInfo;
+
+/*****************************************************************************/
+
+#pragma mark ----- GetVolParmsInfoBuffer Macros -----
+
+/*
+ * Macros to get information out of GetVolParmsInfoBuffer.
+ */
+
+/* version 1 field getters */
+#define GetVolParmsInfoVersion(volParms) \
+ ((volParms)->vMVersion)
+#define GetVolParmsInfoAttrib(volParms) \
+ ((volParms)->vMAttrib)
+#define GetVolParmsInfoLocalHand(volParms) \
+ ((volParms)->vMLocalHand)
+#define GetVolParmsInfoServerAdr(volParms) \
+ ((volParms)->vMServerAdr)
+
+/* version 2 field getters (assume zero result if version < 2) */
+#define GetVolParmsInfoVolumeGrade(volParms) \
+ (((volParms)->vMVersion >= 2) ? (volParms)->vMVolumeGrade : 0)
+#define GetVolParmsInfoForeignPrivID(volParms) \
+ (((volParms)->vMVersion >= 2) ? (volParms)->vMForeignPrivID : 0)
+
+/* version 3 field getters (assume zero result if version < 3) */
+#define GetVolParmsInfoExtendedAttributes(volParms) \
+ (((volParms)->vMVersion >= 3) ? (volParms)->vMExtendedAttributes : 0)
+
+/* attribute bits supported by all versions of GetVolParmsInfoBuffer */
+#define VolIsNetworkVolume(volParms) \
+ ((volParms)->vMServerAdr != 0)
+#define VolHasLimitFCBs(volParms) \
+ (((volParms)->vMAttrib & (1L << bLimitFCBs)) != 0)
+#define VolHasLocalWList(volParms) \
+ (((volParms)->vMAttrib & (1L << bLocalWList)) != 0)
+#define VolHasNoMiniFndr(volParms) \
+ (((volParms)->vMAttrib & (1L << bNoMiniFndr)) != 0)
+#define VolHasNoVNEdit(volParms) \
+ (((volParms)->vMAttrib & (1L << bNoVNEdit)) != 0)
+#define VolHasNoLclSync(volParms) \
+ (((volParms)->vMAttrib & (1L << bNoLclSync)) != 0)
+#define VolHasTrshOffLine(volParms) \
+ (((volParms)->vMAttrib & (1L << bTrshOffLine)) != 0)
+#define VolHasNoSwitchTo(volParms) \
+ (((volParms)->vMAttrib & (1L << bNoSwitchTo)) != 0)
+#define VolHasNoDeskItems(volParms) \
+ (((volParms)->vMAttrib & (1L << bNoDeskItems)) != 0)
+#define VolHasNoBootBlks(volParms) \
+ (((volParms)->vMAttrib & (1L << bNoBootBlks)) != 0)
+#define VolHasAccessCntl(volParms) \
+ (((volParms)->vMAttrib & (1L << bAccessCntl)) != 0)
+#define VolHasNoSysDir(volParms) \
+ (((volParms)->vMAttrib & (1L << bNoSysDir)) != 0)
+#define VolHasExtFSVol(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasExtFSVol)) != 0)
+#define VolHasOpenDeny(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasOpenDeny)) != 0)
+#define VolHasCopyFile(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasCopyFile)) != 0)
+#define VolHasMoveRename(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasMoveRename)) != 0)
+#define VolHasDesktopMgr(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasDesktopMgr)) != 0)
+#define VolHasShortName(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasShortName)) != 0)
+#define VolHasFolderLock(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasFolderLock)) != 0)
+#define VolHasPersonalAccessPrivileges(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0)
+#define VolHasUserGroupList(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasUserGroupList)) != 0)
+#define VolHasCatSearch(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasCatSearch)) != 0)
+#define VolHasFileIDs(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasFileIDs)) != 0)
+#define VolHasBTreeMgr(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasBTreeMgr)) != 0)
+#define VolHasBlankAccessPrivileges(volParms) \
+ (((volParms)->vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0)
+#define VolSupportsAsyncRequests(volParms) \
+ (((volParms)->vMAttrib & (1L << bSupportsAsyncRequests)) != 0)
+#define VolSupportsTrashVolumeCache(volParms) \
+ (((volParms)->vMAttrib & (1L << bSupportsTrashVolumeCache)) != 0)
+
+/* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */
+#define VolIsEjectable(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsEjectable)) != 0)
+#define VolSupportsHFSPlusAPIs(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsHFSPlusAPIs)) != 0)
+#define VolSupportsFSCatalogSearch(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSCatalogSearch)) != 0)
+#define VolSupportsFSExchangeObjects(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSExchangeObjects)) != 0)
+#define VolSupports2TBFiles(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupports2TBFiles)) != 0)
+#define VolSupportsLongNames(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsLongNames)) != 0)
+#define VolSupportsMultiScriptNames(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsMultiScriptNames)) != 0)
+#define VolSupportsNamedForks(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsNamedForks)) != 0)
+#define VolSupportsSubtreeIterators(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSubtreeIterators)) != 0)
+#define VolL2PCanMapFileBlocks(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bL2PCanMapFileBlocks)) != 0)
+#define VolParentModDateChanges(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bParentModDateChanges)) != 0)
+#define VolAncestorModDateChanges(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bAncestorModDateChanges)) != 0)
+#define VolSupportsSymbolicLinks(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSymbolicLinks)) != 0)
+#define VolIsAutoMounted(volParms) \
+ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsAutoMounted)) != 0)
+
+/*****************************************************************************/
+
+#pragma mark ----- userPrivileges Bit Masks and Macros -----
+
+/*
+ * Bit masks and macros to get common information out of userPrivileges byte
+ * returned by FSGetCatalogInfo.
+ *
+ * Note: The userPrivileges byte is the same as the ioACUser byte returned
+ * by PBGetCatInfo, and is the 1's complement of the user's privileges
+ * byte returned in ioACAccess by PBHGetDirAccess. That's where the
+ * ioACUser names came from.
+ *
+ * The userPrivileges are user's effective privileges based on the
+ * user ID and the groups that user belongs to, and the owner, group,
+ * and everyone privileges for the given directory.
+ */
+
+enum
+{
+ /* mask for just the access restriction bits */
+ kioACUserAccessMask = (kioACUserNoSeeFolderMask +
+ kioACUserNoSeeFilesMask +
+ kioACUserNoMakeChangesMask),
+ /* common access privilege settings */
+ kioACUserFull = 0x00, /* no access restiction bits on */
+ kioACUserNone = kioACUserAccessMask, /* all access restiction bits on */
+ kioACUserDropBox = (kioACUserNoSeeFolderMask +
+ kioACUserNoSeeFilesMask), /* make changes, but not see files or folders */
+ kioACUserBulletinBoard = kioACUserNoMakeChangesMask /* see files and folders, but not make changes */
+};
+
+
+/* Macros for testing ioACUser bits. */
+
+#define UserIsOwner(userPrivileges) \
+ (((userPrivileges) & kioACUserNotOwnerMask) == 0)
+#define UserHasFullAccess(userPrivileges) \
+ (((userPrivileges) & (kioACUserAccessMask)) == kioACUserFull)
+#define UserHasDropBoxAccess(userPrivileges) \
+ (((userPrivileges) & kioACUserAccessMask) == kioACUserDropBox)
+#define UserHasBulletinBoard(userPrivileges) \
+ (((userPrivileges) & kioACUserAccessMask) == kioACUserBulletinBoard)
+#define UserHasNoAccess(userPrivileges) \
+ (((userPrivileges) & kioACUserAccessMask) == kioACUserNone)
+
+/*****************************************************************************/
+
+#pragma mark ----- File Access Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSCopyFork
+
+OSErr
+FSCopyFork(
+ SInt16 srcRefNum,
+ SInt16 dstRefNum,
+ void *copyBufferPtr,
+ ByteCount copyBufferSize);
+
+/*
+ The FSCopyFork function copies all data from the source fork to the
+ destination fork of open file forks and makes sure the destination EOF
+ is equal to the source EOF.
+
+ srcRefNum --> The source file reference number.
+ dstRefNum --> The destination file reference number.
+ copyBufferPtr --> Pointer to buffer to use during copy. The
+ buffer should be at least 4K-bytes minimum.
+ The larger the buffer, the faster the copy
+ (up to a point).
+ copyBufferSize --> The size of the copy buffer.
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- Volume Access Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSGetVolParms
+
+OSErr
+FSGetVolParms(
+ FSVolumeRefNum volRefNum,
+ UInt32 bufferSize,
+ GetVolParmsInfoBuffer *volParmsInfo,
+ UInt32 *actualInfoSize);
+
+/*
+ The FSGetVolParms function returns information about the characteristics
+ of a volume. A result of paramErr usually just means the volume doesn't
+ support GetVolParms and the feature you were going to check
+ for isn't available.
+
+ volRefNum --> Volume specification.
+ bufferSize --> Size of buffer pointed to by volParmsInfo.
+ volParmsInfo <-- A GetVolParmsInfoBuffer record where the volume
+ attributes information is returned.
+ actualInfoSize <-- The number of bytes actually returned
+ in volParmsInfo.
+
+ __________
+
+ Also see: The GetVolParmsInfoBuffer Macros for checking attribute bits
+ in this file
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetVRefNum
+
+OSErr
+FSGetVRefNum(
+ const FSRef *ref,
+ FSVolumeRefNum *vRefNum);
+
+/*
+ The FSGetVRefNum function determines the volume reference
+ number of a volume from a FSRef.
+
+ ref --> The FSRef.
+ vRefNum <-- The volume reference number.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetVInfo
+
+OSErr
+FSGetVInfo(
+ FSVolumeRefNum volume,
+ HFSUniStr255 *volumeName, /* can be NULL */
+ UInt64 *freeBytes, /* can be NULL */
+ UInt64 *totalBytes); /* can be NULL */
+
+/*
+ The FSGetVInfo function returns the name, available space (in bytes),
+ and total space (in bytes) for the specified volume.
+
+ volume --> The volume reference number.
+ volumeName <** An optional pointer to a HFSUniStr255.
+ If not NULL, the volume name will be returned in
+ the HFSUniStr255.
+ freeBytes <** An optional pointer to a UInt64.
+ If not NULL, the number of free bytes on the
+ volume will be returned in the UInt64.
+ totalBytes <** An optional pointer to a UInt64.
+ If not NULL, the total number of bytes on the
+ volume will be returned in the UInt64.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetVolFileSystemID
+
+OSErr
+FSGetVolFileSystemID(
+ FSVolumeRefNum volume,
+ UInt16 *fileSystemID, /* can be NULL */
+ UInt16 *signature); /* can be NULL */
+
+/*
+ The FSGetVolFileSystemID function returns the file system ID and signature
+ of a mounted volume. The file system ID identifies the file system
+ that handles requests to a particular volume. The signature identifies the
+ volume type of the volume (for example, FSID 0 is Macintosh HFS Plus, HFS
+ or MFS, where a signature of 0x4244 identifies the volume as HFS).
+ Here's a partial list of file system ID numbers (only Apple's file systems
+ are listed):
+ FSID File System
+ ----- -----------------------------------------------------
+ $0000 Macintosh HFS Plus, HFS or MFS
+ $0100 ProDOS File System
+ $0101 PowerTalk Mail Enclosures
+ $4147 ISO 9660 File Access (through Foreign File Access)
+ $4242 High Sierra File Access (through Foreign File Access)
+ $464D QuickTake File System (through Foreign File Access)
+ $4953 Macintosh PC Exchange (MS-DOS)
+ $4A48 Audio CD Access (through Foreign File Access)
+ $4D4B Apple Photo Access (through Foreign File Access)
+ $6173 AppleShare (later versions of AppleShare only)
+
+ See the Technical Note "FL 35 - Determining Which File System
+ Is Active" and the "Guide to the File System Manager" for more
+ information.
+
+ volume --> The volume reference number.
+ fileSystemID <** An optional pointer to a UInt16.
+ If not NULL, the volume's file system ID will
+ be returned in the UInt16.
+ signature <** An optional pointer to a UInt16.
+ If not NULL, the volume's signature will
+ be returned in the UInt16.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetMountedVolumes
+
+OSErr
+FSGetMountedVolumes(
+ FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */
+ ItemCount *numVolumes);
+
+/*
+ The FSGetMountedVolumes function returns the list of volumes currently
+ mounted in an array of FSRef records. The array of FSRef records is
+ returned in a Handle, volumeRefsHandle, which is allocated by
+ FSGetMountedVolumes. The caller is responsible for disposing of
+ volumeRefsHandle if the FSGetMountedVolumes returns noErr.
+
+ volumeRefsHandle <-- Pointer to an FSRef Handle where the array of
+ FSRefs is to be returned.
+ numVolumes <-- The number of volumes returned in the array.
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSRefMakeFSSpec
+
+OSErr
+FSRefMakeFSSpec(
+ const FSRef *ref,
+ FSSpec *spec);
+
+/*
+ The FSRefMakeFSSpec function returns an FSSpec for the file or
+ directory specified by the ref parameter.
+
+ ref --> An FSRef specifying the file or directory.
+ spec <-- The FSSpec.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMakeFSRef
+
+OSErr
+FSMakeFSRef(
+ FSVolumeRefNum volRefNum,
+ SInt32 dirID,
+ ConstStr255Param name,
+ FSRef *ref);
+
+/*
+ The FSMakeFSRef function creates an FSRef from the traditional
+ volume reference number, directory ID and pathname inputs. It is
+ functionally equivalent to FSMakeFSSpec followed by FSpMakeFSRef.
+
+ volRefNum --> Volume specification.
+ dirID --> Directory specification.
+ name --> The file or directory name, or NULL.
+ ref <-- The FSRef.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMakePath
+
+OSStatus
+FSMakePath(
+ SInt16 vRefNum,
+ SInt32 dirID,
+ ConstStr255Param name,
+ UInt8 *path,
+ UInt32 maxPathSize);
+
+/*
+ The FSMakePath function creates a pathname from the traditional volume reference
+ number, directory ID, and pathname inputs. It is functionally equivalent to
+ FSMakeFSSpec, FSpMakeFSRef, FSRefMakePath.
+
+ volRefNum --> Volume specification.
+ dirID --> Directory specification.
+ name --> The file or directory name, or NULL.
+ path <-- A pointer to a buffer which FSMakePath will
+ fill with a C string representing the pathname
+ to the file or directory specified. The format of
+ the pathname returned can be determined with the
+ Gestalt selector gestaltFSAttr's
+ gestaltFSUsesPOSIXPathsForConversion bit.
+ If the gestaltFSUsesPOSIXPathsForConversion bit is
+ clear, the pathname is a Mac OS File Manager full
+ pathname in a C string, and file or directory names
+ in the pathname may be mangled as returned by
+ the File Manager. If the
+ gestaltFSUsesPOSIXPathsForConversion bit is set,
+ the pathname is a UTF8 encoded POSIX absolute
+ pathname in a C string. In either case, the
+ pathname returned can be passed back to
+ FSPathMakeRef to create an FSRef to the file or
+ directory, or FSPathMakeFSSpec to craete an FSSpec
+ to the file or directory.
+ maxPathSize --> The size of the path buffer in bytes. If the path
+ buffer is too small for the pathname string,
+ FSMakePath returns pathTooLongErr or
+ buffersTooSmall.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSPathMakeFSSpec
+
+OSStatus
+FSPathMakeFSSpec(
+ const UInt8 *path,
+ FSSpec *spec,
+ Boolean *isDirectory); /* can be NULL */
+
+/*
+ The FSPathMakeFSSpec function converts a pathname to an FSSpec.
+
+ path --> A pointer to a C String that is the pathname. The
+ format of the pathname you must supply can be
+ determined with the Gestalt selector gestaltFSAttr's
+ gestaltFSUsesPOSIXPathsForConversion bit.
+ If the gestaltFSUsesPOSIXPathsForConversion bit is
+ clear, the pathname must be a Mac OS File Manager
+ full pathname in a C string. If the
+ gestaltFSUsesPOSIXPathsForConversion bit is set,
+ the pathname must be a UTF8 encoded POSIX absolute
+ pathname in a C string.
+ spec <-- The FSSpec.
+ isDirectory <** An optional pointer to a Boolean.
+ If not NULL, true will be returned in the Boolean
+ if the specified path is a directory, or false will
+ be returned in the Boolean if the specified path is
+ a file.
+*/
+
+/*****************************************************************************/
+
+#pragma mark UnicodeNameGetHFSName
+
+OSErr
+UnicodeNameGetHFSName(
+ UniCharCount nameLength,
+ const UniChar *name,
+ TextEncoding textEncodingHint,
+ Boolean isVolumeName,
+ Str31 hfsName);
+
+/*
+ The UnicodeNameGetHFSName function converts a Unicode string
+ to a Pascal Str31 (or Str27) string using an algorithm similar to that used
+ by the File Manager. Note that if the name is too long or cannot be converted
+ using the given text encoding hint, you will get an error instead of the
+ mangled name that the File Manager would return.
+
+ nameLength --> Number of UniChar in name parameter.
+ name --> The Unicode string to convert.
+ textEncodingHint --> The text encoding hint used for the conversion.
+ You can pass kTextEncodingUnknown to use the
+ "default" textEncodingHint.
+ isVolumeName --> If true, the output name will be limited to
+ 27 characters (kHFSMaxVolumeNameChars). If false,
+ the output name will be limited to 31 characters
+ (kHFSMaxFileNameChars).
+ hfsName <-- The hfsName as a Pascal string.
+
+ __________
+
+ Also see: HFSNameGetUnicodeName
+*/
+
+/*****************************************************************************/
+
+#pragma mark HFSNameGetUnicodeName
+
+OSErr
+HFSNameGetUnicodeName(
+ ConstStr31Param hfsName,
+ TextEncoding textEncodingHint,
+ HFSUniStr255 *unicodeName);
+
+/*
+ The HFSNameGetUnicodeName function converts a Pascal Str31 string to an
+ Unicode HFSUniStr255 string using the same routines as the File Manager.
+
+ hfsName --> The Pascal string to convert.
+ textEncodingHint --> The text encoding hint used for the conversion.
+ You can pass kTextEncodingUnknown to use the
+ "default" textEncodingHint.
+ unicodeName <-- The Unicode string.
+
+ __________
+
+ Also see: UnicodeNameGetHFSName
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- File/Directory Manipulation Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSRefValid
+
+Boolean FSRefValid(const FSRef *ref);
+
+/*
+ The FSRefValid function determines if an FSRef is valid. If the result is
+ true, then the FSRef refers to an existing file or directory.
+
+ ref --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetParentRef
+
+OSErr
+FSGetParentRef(
+ const FSRef *ref,
+ FSRef *parentRef);
+
+/*
+ The FSGetParentRef function gets the parent directory FSRef of the
+ specified object.
+
+ Note: FSRefs always point to real file system objects. So, there cannot
+ be a FSRef to the parent of volume root directories. If you call
+ FSGetParentRef with a ref to the root directory of a volume, the
+ function result will be noErr and the parentRef will be invalid (using it
+ for other file system requests will fail).
+
+ ref --> FSRef to a file or directory.
+ parentRef <-- The parent directory's FSRef.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetFileDirName
+
+OSErr
+FSGetFileDirName(
+ const FSRef *ref,
+ HFSUniStr255 *outName);
+
+/*
+ The FSGetFileDirName function gets the name of the file or directory
+ specified.
+
+ ref --> FSRef to a file or directory.
+ outName <-- The file or directory name.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetNodeID
+
+OSErr
+FSGetNodeID(
+ const FSRef *ref,
+ long *nodeID, /* can be NULL */
+ Boolean *isDirectory); /* can be NULL */
+
+/*
+ The GetNodeIDFromFSRef function gets the node ID number of the
+ file or directory specified (note: the node ID is the directory ID
+ for directories).
+
+ ref --> FSRef to a file or directory.
+ nodeID <** An optional pointer to a long.
+ If not NULL, the node ID will be returned in
+ the long.
+ isDirectory <** An optional pointer to a Boolean.
+ If not NULL, true will be returned in the Boolean
+ if the object is a directory, or false will be
+ returned in the Boolean if object is a file.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetUserPrivilegesPermissions
+
+OSErr
+FSGetUserPrivilegesPermissions(
+ const FSRef *ref,
+ UInt8 *userPrivileges, /* can be NULL */
+ UInt32 permissions[4]); /* can be NULL */
+
+/*
+ The FSGetUserPrivilegesPermissions function gets the userPrivileges and/or
+ permissions of the file or directory specified.
+
+ ref --> FSRef to a file or directory.
+ userPrivileges <** An optional pointer to a UInt8.
+ If not NULL, the userPrivileges will be returned
+ in the UInt8.
+ permissions <** An optional pointer to an UInt32[4] array.
+ If not NULL, the permissions will be returned
+ in the UInt32[4] array.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSCheckLock
+
+OSErr
+FSCheckLock(
+ const FSRef *ref);
+
+/*
+ The FSCheckLock function determines if a file or directory is locked.
+ If FSCheckLock returns noErr, then the file or directory is not locked
+ and the volume it is on is not locked either. If FSCheckLock returns
+ fLckdErr, then the file or directory is locked. If FSCheckLock returns
+ wPrErr, then the volume is locked by hardware (i.e., locked tab on
+ removable media). If FSCheckLock returns vLckdErr, then the volume is
+ locked by software.
+
+ ref --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetForkSizes
+
+OSErr
+FSGetForkSizes(
+ const FSRef *ref,
+ UInt64 *dataLogicalSize, /* can be NULL */
+ UInt64 *rsrcLogicalSize); /* can be NULL */
+
+/*
+ The FSGetForkSizes returns the size of the data and/or resource fork for
+ the specified file.
+
+ ref --> FSRef to a file or directory.
+ dataLogicalSize <** An optional pointer to a UInt64.
+ If not NULL, the data fork's size will be
+ returned in the UInt64.
+ rsrcLogicalSize <** An optional pointer to a UInt64.
+ If not NULL, the resource fork's size will be
+ returned in the UInt64.
+
+ __________
+
+ Also see: FSGetTotalForkSizes
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetTotalForkSizes
+
+OSErr
+FSGetTotalForkSizes(
+ const FSRef *ref,
+ UInt64 *totalLogicalSize, /* can be NULL */
+ UInt64 *totalPhysicalSize, /* can be NULL */
+ ItemCount *forkCount); /* can be NULL */
+
+/*
+ The FSGetTotalForkSizes returns the total logical size and/or the total
+ physical size of the specified file (i.e., it adds the sizes of all file
+ forks). It optionally returns the number of file forks.
+
+ ref --> FSRef to a file or directory.
+ totalLogicalSize <** An optional pointer to a UInt64.
+ If not NULL, the sum of all fork logical sizes
+ will be returned in the UInt64.
+ totalPhysicalSize <** An optional pointer to a UInt64.
+ If not NULL, the sum of all fork physical sizes
+ will be returned in the UInt64.
+ forkCount <** An optional pointer to a ItemCount.
+ If not NULL, the number of file forks
+ will be returned in the ItemCount.
+
+ __________
+
+ Also see: FSGetForkSizes
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSBumpDate
+
+OSErr
+FSBumpDate(
+ const FSRef *ref);
+
+/*
+ The FSBumpDate function changes the content modification date of a file
+ or directory to the current date/time. If the content modification date
+ is already equal to the current date/time, then add one second to the
+ content modification date.
+
+ ref --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetFinderInfo
+
+OSErr
+FSGetFinderInfo(
+ const FSRef *ref,
+ FinderInfo *info, /* can be NULL */
+ ExtendedFinderInfo *extendedInfo, /* can be NULL */
+ Boolean *isDirectory); /* can be NULL */
+
+/*
+ The FSGetFinderInfo function gets the finder information for a file or
+ directory.
+
+ ref --> FSRef to a file or directory.
+ info <** An optional pointer to a FinderInfo.
+ If not NULL, the FileInfo (if ref is a file) or
+ the FolderInfo (if ref is a folder) will be
+ returned in the FinderInfo.
+ extendedInfo <** An optional pointer to a ExtendedFinderInfo.
+ If not NULL, the ExtendedFileInfo (if ref is a file)
+ or the ExtendedFolderInfo (if ref is a folder) will
+ be returned in the ExtendedFinderInfo.
+ isDirectory <** An optional pointer to a Boolean.
+ If not NULL, true will be returned in the Boolean
+ if the object is a directory, or false will be
+ returned in the Boolean if object is a file.
+
+ __________
+
+ Also see: FSSetFinderInfo
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetFinderInfo
+
+OSErr
+FSSetFinderInfo(
+ const FSRef *ref,
+ const FinderInfo *info, /* can be NULL */
+ const ExtendedFinderInfo *extendedInfo); /* can be NULL */
+
+/*
+ The FSSetFinderInfo function sets the finder information for a file or
+ directory.
+
+ ref --> FSRef to a file or directory.
+ info **> A pointer to a FinderInfo record with the new
+ FileInfo (if ref is a file) or new FolderInfo
+ (if ref is a folder), or NULL if the FinderInfo
+ is not to be changed.
+ extendedInfo **> A pointer to a FinderInfo record with the new
+ ExtendedFileInfo (if ref is a file) or new
+ ExtendedFolderInfo (if ref is a folder), or NULL
+ if the ExtendedFinderInfo is not to be changed.
+
+ __________
+
+ Also see: FSGetFinderInfo
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSChangeCreatorType
+
+OSErr
+FSChangeCreatorType(
+ const FSRef *ref,
+ OSType fileCreator,
+ OSType fileType);
+
+/*
+ The FSChangeCreatorType function changes the creator and/or file type of a file.
+
+ ref --> FSRef to a file.
+ creator --> The new creator type or 0x00000000 to leave
+ the creator type alone.
+ fileType --> The new file type or 0x00000000 to leave the
+ file type alone.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSChangeFinderFlags
+
+OSErr
+FSChangeFinderFlags(
+ const FSRef *ref,
+ Boolean setBits,
+ UInt16 flagBits);
+
+/*
+ The FSChangeFinderFlags function sets or clears flag bits in
+ the finderFlags field of a file's FileInfo record or a
+ directory's FolderInfo record.
+
+ ref --> FSRef to a file or directory.
+ setBits --> If true, then set the bits specified in flagBits.
+ If false, then clear the bits specified in flagBits.
+ flagBits --> The flagBits parameter specifies which Finder Flag
+ bits to set or clear. If a bit in flagBits is set,
+ then the same bit in fdFlags is either set or
+ cleared depending on the state of the setBits
+ parameter.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetInvisible
+
+OSErr
+FSSetInvisible(
+ const FSRef *ref);
+
+#pragma mark FSClearInvisible
+
+OSErr
+FSClearInvisible(
+ const FSRef *ref);
+
+/*
+ The FSSetInvisible and FSClearInvisible functions set or clear the
+ kIsInvisible bit in the finderFlags field of the specified file or
+ directory's finder information.
+
+ ref --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetNameLocked
+
+OSErr
+FSSetNameLocked(
+ const FSRef *ref);
+
+#pragma mark FSClearNameLocked
+
+OSErr
+FSClearNameLocked(
+ const FSRef *ref);
+
+/*
+ The FSSetNameLocked and FSClearNameLocked functions set or clear the
+ kNameLocked bit bit in the finderFlags field of the specified file or
+ directory's finder information.
+
+ ref --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetIsStationery
+
+OSErr
+FSSetIsStationery(
+ const FSRef *ref);
+
+#pragma mark FSClearIsStationery
+
+OSErr
+FSClearIsStationery(
+ const FSRef *ref);
+
+/*
+ The FSSetIsStationery and FSClearIsStationery functions set or clear the
+ kIsStationery bit bit in the finderFlags field of the specified file or
+ directory's finder information.
+
+ ref --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetHasCustomIcon
+
+OSErr
+FSSetHasCustomIcon(
+ const FSRef *ref);
+
+#pragma mark FSClearHasCustomIcon
+
+OSErr
+FSClearHasCustomIcon(
+ const FSRef *ref);
+
+/*
+ The FSSetHasCustomIcon and FSClearHasCustomIcon functions set or clear the
+ kHasCustomIcon bit bit in the finderFlags field of the specified file or
+ directory's finder information.
+
+ ref --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSClearHasBeenInited
+
+OSErr
+FSClearHasBeenInited(
+ const FSRef *ref);
+
+/*
+ The FSClearHasBeenInited function clears the kHasBeenInited bit in the
+ finderFlags field of the specified file or directory's finder information.
+
+ Note: There is no FSSetHasBeenInited function because ONLY the Finder
+ should set the kHasBeenInited bit.
+
+ ref --> FSRef to a file or directory.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSCopyFileMgrAttributes
+
+OSErr
+FSCopyFileMgrAttributes(
+ const FSRef *sourceRef,
+ const FSRef *destinationRef,
+ Boolean copyLockBit);
+
+/*
+ The CopyFileMgrAttributes function copies all File Manager attributes
+ from the source file or directory to the destination file or directory.
+ If copyLockBit is true, then set the locked state of the destination
+ to match the source.
+
+ sourceRef --> FSRef to a file or directory.
+ destinationRef --> FSRef to a file or directory.
+ copyLockBit --> If true, set the locked state of the destination
+ to match the source.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMoveRenameObjectUnicode
+
+OSErr
+FSMoveRenameObjectUnicode(
+ const FSRef *ref,
+ const FSRef *destDirectory,
+ UniCharCount nameLength,
+ const UniChar *name, /* can be NULL (no rename during move) */
+ TextEncoding textEncodingHint,
+ FSRef *newRef); /* if function fails along the way, newRef is final location of file */
+
+/*
+ The FSMoveRenameObjectUnicode function moves a file or directory and
+ optionally renames it. The source and destination locations must be on
+ the same volume.
+
+ Note: If the input ref parameter is invalid, this call will fail and
+ newRef, like ref, will be invalid.
+
+ ref --> FSRef to a file or directory.
+ destDirectory --> FSRef to the destination directory.
+ nameLength --> Number of UniChar in name parameter.
+ name --> An Unicode string with the new name for the
+ moved object, or NULL if no rename is wanted.
+ textEncodingHint --> The text encoding hint used for the rename.
+ You can pass kTextEncodingUnknown to use the
+ "default" textEncodingHint.
+ newRef <-- The new FSRef of the object moved. Note that if
+ this function fails at any step along the way,
+ newRef is still then final location of the object.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSDeleteContainerContents
+
+OSErr
+FSDeleteContainerContents(
+ const FSRef *container);
+
+/*
+ The FSDeleteContainerContents function deletes the contents of a container
+ directory. All files and subdirectories in the specified container are
+ deleted. If a locked file or directory is encountered, it is unlocked and
+ then deleted. If any unexpected errors are encountered,
+ FSDeleteContainerContents quits and returns to the caller.
+
+ container --> FSRef to a directory.
+
+ __________
+
+ Also see: FSDeleteContainer
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSDeleteContainer
+
+OSErr
+FSDeleteContainer(
+ const FSRef *container);
+
+/*
+ The FSDeleteContainer function deletes a container directory and its contents.
+ All files and subdirectories in the specified container are deleted.
+ If a locked file or directory is encountered, it is unlocked and then
+ deleted. After deleting the container's contents, the container is
+ deleted. If any unexpected errors are encountered, FSDeleteContainer
+ quits and returns to the caller.
+
+ container --> FSRef to a directory.
+
+ __________
+
+ Also see: FSDeleteContainerContents
+*/
+
+/*****************************************************************************/
+
+#pragma mark IterateContainerFilterProcPtr
+
+typedef CALLBACK_API( Boolean , IterateContainerFilterProcPtr ) (
+ Boolean containerChanged,
+ ItemCount currentLevel,
+ const FSCatalogInfo *catalogInfo,
+ const FSRef *ref,
+ const FSSpec *spec,
+ const HFSUniStr255 *name,
+ void *yourDataPtr);
+
+/*
+ This is the prototype for the IterateContainerFilterProc function which
+ is called once for each file and directory found by FSIterateContainer.
+ The IterateContainerFilterProc can use the read-only data it receives for
+ whatever it wants.
+
+ The result of the IterateContainerFilterProc function indicates if
+ iteration should be stopped. To stop iteration, return true; to continue
+ iteration, return false.
+
+ The yourDataPtr parameter can point to whatever data structure you might
+ want to access from within the IterateContainerFilterProc.
+
+ containerChanged --> Set to true if the container's contents changed
+ during iteration.
+ currentLevel --> The current recursion level into the container.
+ 1 = the container, 2 = the container's immediate
+ subdirectories, etc.
+ catalogInfo --> The catalog information for the current object.
+ Only the fields requested by the whichInfo
+ parameter passed to FSIterateContainer are valid.
+ ref --> The FSRef to the current object.
+ spec --> The FSSpec to the current object if the wantFSSpec
+ parameter passed to FSIterateContainer is true.
+ name --> The name of the current object if the wantName
+ parameter passed to FSIterateContainer is true.
+ yourDataPtr --> An optional pointer to whatever data structure you
+ might want to access from within the
+ IterateFilterProc.
+ result <-- To stop iteration, return true; to continue
+ iteration, return false.
+
+ __________
+
+ Also see: FSIterateContainer
+*/
+
+/*****************************************************************************/
+
+#pragma mark CallIterateContainerFilterProc
+
+#define CallIterateContainerFilterProc(userRoutine, containerChanged, currentLevel, catalogInfo, ref, spec, name, yourDataPtr) \
+ (*(userRoutine))((containerChanged), (currentLevel), (catalogInfo), (ref), (spec), (name), (yourDataPtr))
+
+/*****************************************************************************/
+
+#pragma mark FSIterateContainer
+
+OSErr
+FSIterateContainer(
+ const FSRef *container,
+ ItemCount maxLevels,
+ FSCatalogInfoBitmap whichInfo,
+ Boolean wantFSSpec,
+ Boolean wantName,
+ IterateContainerFilterProcPtr iterateFilter,
+ void *yourDataPtr);
+
+/*
+ The FSIterateContainer function performs a recursive iteration (scan) of the
+ specified container directory and calls your IterateContainerFilterProc
+ function once for each file and directory found.
+
+ The maxLevels parameter lets you control how deep the recursion goes.
+ If maxLevels is 1, FSIterateContainer only scans the specified directory;
+ if maxLevels is 2, FSIterateContainer scans the specified directory and
+ one subdirectory below the specified directory; etc. Set maxLevels to
+ zero to scan all levels.
+
+ The yourDataPtr parameter can point to whatever data structure you might
+ want to access from within your IterateContainerFilterProc.
+
+ container --> The FSRef to the container directory to iterate.
+ maxLevels --> Maximum number of directory levels to scan or
+ zero to scan all directory levels.
+ whichInfo --> The fields of the FSCatalogInfo you wish to get.
+ wantFSSpec --> Set to true if you want the FSSpec to each
+ object passed to your IterateContainerFilterProc.
+ wantName --> Set to true if you want the name of each
+ object passed to your IterateContainerFilterProc.
+ iterateFilter --> A pointer to the IterateContainerFilterProc you
+ want called once for each file and directory found
+ by FSIterateContainer.
+ yourDataPtr --> An optional pointer to whatever data structure you
+ might want to access from within the
+ IterateFilterProc.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetDirectoryItems
+
+OSErr
+FSGetDirectoryItems(
+ const FSRef *container,
+ FSRef ***refsHandle, /* pointer to handle of FSRefs */
+ ItemCount *numRefs,
+ Boolean *containerChanged);
+
+/*
+ The FSGetDirectoryItems function returns the list of items in the specified
+ container. The array of FSRef records is returned in a Handle, refsHandle,
+ which is allocated by FSGetDirectoryItems. The caller is responsible for
+ disposing of refsHandle if the FSGetDirectoryItems returns noErr.
+
+ container --> FSRef to a directory.
+ refsHandle <-- Pointer to an FSRef Handle where the array of
+ FSRefs is to be returned.
+ numRefs <-- The number of FSRefs returned in the array.
+ containerChanged <-- Set to true if the container changes while the
+ list of items is being obtained.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSExchangeObjectsCompat
+
+OSErr
+FSExchangeObjectsCompat(
+ const FSRef *sourceRef,
+ const FSRef *destRef,
+ FSRef *newSourceRef,
+ FSRef *newDestRef);
+
+/*
+ The FSExchangeObjectsCompat function exchanges the data between two files.
+
+ The FSExchangeObjectsCompat function is an enhanced version of
+ FSExchangeObjects function. The two enhancements FSExchangeObjectsCompat
+ provides are:
+
+ 1, FSExchangeObjectsCompat will work on volumes which do not support
+ FSExchangeObjects. FSExchangeObjectsCompat does this by emulating
+ FSExchangeObjects through a series of File Manager operations. If
+ there is a failure at any step along the way, FSExchangeObjectsCompat
+ attempts to undo any steps already taken to leave the files in their
+ original state in their original locations.
+
+ 2. FSExchangeObjectsCompat returns new FSRefs to the source and
+ destination files. Note that if this function fails at any step along
+ the way, newSourceRef and newDestRef still give you access to the final
+ locations of the files being exchanged -- even if they are renamed or
+ not in their original locations.
+
+ sourceRef --> FSRef to the source file.
+ destRef --> FSRef to the destination file.
+ newSourceRef <-- The new FSRef to the source file.
+ newDestRef <-- The new FSRef to the destination file.
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- Shared Environment Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSLockRange
+
+OSErr
+FSLockRange(
+ SInt16 refNum,
+ SInt32 rangeLength,
+ SInt32 rangeStart);
+
+/*
+ The LockRange function locks (denies access to) a portion of a file
+ that was opened with shared read/write permission.
+
+ refNum --> The file reference number of an open file.
+ rangeLength --> The number of bytes in the range.
+ rangeStart --> The starting byte in the range to lock.
+
+ __________
+
+ Also see: UnlockRange
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSUnlockRange
+
+OSErr
+FSUnlockRange(
+ SInt16 refNum,
+ SInt32 rangeLength,
+ SInt32 rangeStart);
+
+/*
+ The UnlockRange function unlocks (allows access to) a previously locked
+ portion of a file that was opened with shared read/write permission.
+
+ refNum --> The file reference number of an open file.
+ rangeLength --> The number of bytes in the range.
+ rangeStart --> The starting byte in the range to unlock.
+
+ __________
+
+ Also see: LockRange
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetDirAccess
+
+OSErr
+FSGetDirAccess(
+ const FSRef *ref,
+ SInt32 *ownerID, /* can be NULL */
+ SInt32 *groupID, /* can be NULL */
+ SInt32 *accessRights); /* can be NULL */
+
+/*
+ The FSGetDirAccess function retrieves the directory access control
+ information for a directory on a shared volume.
+
+ ref --> An FSRef specifying the directory.
+ ownerID <** An optional pointer to a SInt32.
+ If not NULL, the directory's owner ID
+ will be returned in the SInt32.
+ groupID <** An optional pointer to a SInt32.
+ If not NULL, the directory's group ID, or 0
+ if no group affiliation, will be returned in
+ the SInt32.
+ accessRights <** An optional pointer to a SInt32.
+ If not NULL, the directory's access rights
+ will be returned in the SInt32.
+
+ __________
+
+ Also see: FSSetDirAccess, FSMapID, FSMapName
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetDirAccess
+
+OSErr
+FSSetDirAccess(
+ const FSRef *ref,
+ SInt32 ownerID,
+ SInt32 groupID,
+ SInt32 accessRights);
+
+/*
+ The FSpSetDirAccess function changes the directory access control
+ information for a directory on a shared volume. You must be the owner of
+ a directory to change its access control information.
+
+ ref --> An FSRef specifying the directory.
+ ownerID --> The directory's owner ID.
+ groupID --> The directory's group ID or 0 if no group affiliation.
+ accessRights --> The directory's access rights.
+
+ __________
+
+ Also see: FSGetDirAccess, FSMapID, FSMapName
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetVolMountInfoSize
+
+OSErr
+FSGetVolMountInfoSize(
+ FSVolumeRefNum volRefNum,
+ SInt16 *size);
+
+/*
+ The FSGetVolMountInfoSize function determines the how much space the
+ program needs to allocate for a volume mounting information record.
+
+ volRefNum --> Volume specification.
+ size <-- The space needed (in bytes) of the volume
+ mounting information record.
+
+ __________
+
+ Also see: FSGetVolMountInfo, VolumeMount
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSGetVolMountInfo
+
+OSErr
+FSGetVolMountInfo(
+ FSVolumeRefNum volRefNum,
+ void *volMountInfo);
+
+/*
+ The FSGetVolMountInfo function retrieves a volume mounting information
+ record containing all the information needed to mount the volume,
+ except for passwords.
+
+ volRefNum --> Volume specification.
+ volMountInfo <-- The volume mounting information.
+
+ __________
+
+ Also see: FSGetVolMountInfoSize, VolumeMount
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSVolumeMount
+
+OSErr
+FSVolumeMount(
+ const void *volMountInfo,
+ FSVolumeRefNum *volRefNum);
+
+/*
+ The VolumeMount function mounts a volume using a volume mounting
+ information record.
+
+ volMountInfo --> A volume mounting information record.
+ volRefNum <-- The volume reference number.
+
+ __________
+
+ Also see: FSGetVolMountInfoSize, FSGetVolMountInfo
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMapID
+
+OSErr
+FSMapID(
+ FSVolumeRefNum volRefNum,
+ SInt32 ugID,
+ SInt16 objType,
+ Str31 name);
+
+/*
+ The FSMapID function determines the name of a user or group if you know
+ the user or group ID.
+
+ volRefNum --> Volume specification.
+ objType --> The mapping function code:
+ kOwnerID2Name to map a user ID to a user name
+ kGroupID2Name to map a group ID to a group name
+ name <** An optional pointer to a buffer (minimum Str31).
+ If not NULL, the user or group name
+ will be returned in the buffer.
+
+ __________
+
+ Also see: FSGetDirAccess, FSSetDirAccess, FSMapName
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMapName
+
+OSErr
+FSMapName(
+ FSVolumeRefNum volRefNum,
+ ConstStr255Param name,
+ SInt16 objType,
+ SInt32 *ugID);
+
+/*
+ The FSMapName function determines the user or group ID if you know the
+ user or group name.
+
+ volRefNum --> Volume specification.
+ name --> The user or group name.
+ objType --> The mapping function code:
+ kOwnerName2ID to map a user name to a user ID
+ kGroupName2ID to map a user name to a group ID
+ ugID <-- The user or group ID.
+
+ __________
+
+ Also see: FSGetDirAccess, FSSetDirAccess, FSMapID
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSCopyFile
+
+OSErr
+FSCopyFile(
+ const FSRef *srcFileRef,
+ const FSRef *dstDirectoryRef,
+ UniCharCount nameLength,
+ const UniChar *copyName, /* can be NULL (no rename during copy) */
+ TextEncoding textEncodingHint,
+ FSRef *newRef); /* can be NULL */
+
+/*
+ The FSCopyFile function duplicates a file and optionally renames it.
+ The source and destination volumes must be on the same file server.
+ This function instructs the server to copy the file.
+
+ srcFileRef --> An FSRef specifying the source file.
+ dstDirectoryRef --> An FSRef specifying the destination directory.
+ nameLength --> Number of UniChar in copyName parameter (ignored
+ if copyName is NULL).
+ copyName --> Points to the new file name if the file is to be
+ renamed, or NULL if the file isn't to be renamed.
+ textEncodingHint --> The text encoding hint used for the rename.
+ You can pass kTextEncodingUnknown to use the
+ "default" textEncodingHint.
+ newRef <** An optional pointer to a FSRef.
+ If not NULL, the FSRef of the duplicated file
+ will be returned in the FSRef.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSMoveRename
+
+OSErr
+FSMoveRename(
+ const FSRef *srcFileRef,
+ const FSRef *dstDirectoryRef,
+ UniCharCount nameLength,
+ const UniChar *moveName, /* can be NULL (no rename during move) */
+ TextEncoding textEncodingHint,
+ FSRef *newRef); /* can be NULL */
+
+/*
+ The FSMoveRename function moves a file or directory (object), and
+ optionally renames it. The source and destination locations must be on
+ the same shared volume.
+
+ srcFileRef --> An FSRef specifying the source file.
+ dstDirectoryRef --> An FSRef specifying the destination directory.
+ nameLength --> Number of UniChar in moveName parameter (ignored
+ if copyName is NULL)
+ moveName --> Points to the new object name if the object is to be
+ renamed, or NULL if the object isn't to be renamed.
+ textEncodingHint --> The text encoding hint used for the rename.
+ You can pass kTextEncodingUnknown to use the
+ "default" textEncodingHint.
+ newRef <** An optional pointer to a FSRef.
+ If not NULL, the FSRef of the moved object
+ will be returned in the FSRef.
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- File ID Routines -----
+
+/*****************************************************************************/
+
+#pragma mark FSResolveFileIDRef
+
+OSErr
+FSResolveFileIDRef(
+ FSVolumeRefNum volRefNum,
+ SInt32 fileID,
+ FSRef *ref);
+
+/*
+ The FSResolveFileIDRef function returns an FSRef for the file with the
+ specified file ID reference.
+
+ volRefNum --> Volume specification.
+ fileID --> The file ID reference.
+ ref <-- The FSRef for the file ID reference.
+
+ __________
+
+ Also see: FSCreateFileIDRef, FSDeleteFileIDRef
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSCreateFileIDRef
+
+OSErr
+FSCreateFileIDRef(
+ const FSRef *ref,
+ SInt32 *fileID);
+
+/*
+ The FSCreateFileIDRef function creates a file ID reference for the
+ specified file, or if a file ID reference already exists, supplies
+ the file ID reference and returns the result code fidExists or afpIDExists.
+
+ ref --> The FSRef for the file.
+ fileID <-- The file ID reference (if result is noErr,
+ fidExists, or afpIDExists).
+
+ __________
+
+ Also see: GetFSRefFromFileIDRef, FSDeleteFileIDRef
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSDeleteFileIDRef
+
+/*
+ Why is there no FSDeleteFileIDRef routine? There are two reasons:
+
+ 1. Since Mac OS 8.1, PBDeleteFileIDRef hasn't deleted file ID references.
+ On HFS volumes, deleting a file ID reference breaks aliases (which
+ use file ID references to track files as they are moved around on a
+ volume) and file ID references are automatically deleted when the file
+ they refer to is deleted. On HFS Plus volumes, file ID references are
+ always created when a file is created, deleted when the file is deleted,
+ and cannot be deleted at any other time.
+
+ 2. PBDeleteFileIDRef causes a memory access fault under Mac OS X 10.0
+ through 10.1.x. While this will be fixed in a future release, the
+ implementation, like the Mac OS 8/9 implementation, does not delete
+ file ID references.
+
+ __________
+
+ Also see: GetFSRefFromFileIDRef, FSCreateFileIDRef
+*/
+
+/*****************************************************************************/
+
+#pragma mark ----- Utility Routines -----
+
+/*****************************************************************************/
+
+#pragma mark GetTempBuffer
+
+Ptr
+GetTempBuffer(
+ ByteCount buffReqSize,
+ ByteCount *buffActSize);
+
+/*
+ The GetTempBuffer function allocates a temporary buffer for file system
+ operations which is at least 4K bytes and a multiple of 4K bytes.
+
+ buffReqSize --> Size you'd like the buffer to be.
+ buffActSize <-- The size of the buffer allocated.
+ function result <-- Pointer to memory allocated, or NULL if no memory
+ was available. The caller is responsible for
+ disposing of this buffer with DisposePtr.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FileRefNumGetFSRef
+
+OSErr
+FileRefNumGetFSRef(
+ short refNum,
+ FSRef *ref);
+
+/*
+ The FileRefNumGetFSRef function gets the FSRef of an open file.
+
+ refNum --> The file reference number of an open file.
+ ref <-- The FSRef to the open file.
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSSetDefault
+
+OSErr
+FSSetDefault(
+ const FSRef *newDefault,
+ FSRef *oldDefault);
+
+/*
+ The FSSetDefault function sets the current working directory to the
+ directory specified by newDefault. The previous current working directory
+ is returned in oldDefault and must be used to restore the current working
+ directory to its previous state with the FSRestoreDefault function.
+ These two functions are designed to be used as a wrapper around
+ Standard I/O routines where the location of the file is implied to be the
+ current working directory. This is how you should use these functions:
+
+ result = FSSetDefault(&newDefault, &oldDefault);
+ if ( noErr == result )
+ {
+ // call the Stdio functions like remove, rename,
+ // fopen, freopen, etc here!
+
+ result = FSRestoreDefault(&oldDefault);
+ }
+
+ newDefault --> An FSRef that specifies the new current working
+ directory.
+ oldDefault <-- The previous current working directory's FSRef.
+
+ __________
+
+ Also see: FSRestoreDefault
+*/
+
+/*****************************************************************************/
+
+#pragma mark FSRestoreDefault
+
+OSErr
+FSRestoreDefault(
+ const FSRef *oldDefault);
+
+/*
+ The FSRestoreDefault function restores the current working directory
+ to the directory specified by oldDefault. The oldDefault parameter was
+ previously obtained from the FSSetDefault function.
+ These two functions are designed to be used as a wrapper around
+ Standard I/O routines where the location of the file is implied to be the
+ current working directory. This is how you should use these functions:
+
+ result = FSSetDefault(&newDefault, &oldDefault);
+ if ( noErr == result )
+ {
+ // call the Stdio functions like remove, rename,
+ // fopen, freopen, etc here!
+
+ result = FSRestoreDefault(&oldDefault);
+ }
+
+ oldDefault --> The FSRef of the location to restore.
+
+ __________
+
+ Also see: FSSetDefault
+*/
+
+/*****************************************************************************/
+
+#if PRAGMA_STRUCT_ALIGN
+ #pragma options align=reset
+#elif PRAGMA_STRUCT_PACKPUSH
+ #pragma pack(pop)
+#elif PRAGMA_STRUCT_PACK
+ #pragma pack()
+#endif
+
+#ifdef PRAGMA_IMPORT_OFF
+#pragma import off
+#elif PRAGMA_IMPORT
+#pragma import reset
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __MOREFILESX__ */
+