2 Copyright (C) 2003, 2010 - Wolfire Games
4 This file is part of Lugaru.
6 Lugaru is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
15 See the GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 Contains: A collection of useful high-level File Manager routines
26 which use the HFS Plus APIs wherever possible.
28 Version: MoreFilesX 1.0.1
30 Copyright: © 1992-2002 by Apple Computer, Inc., all rights reserved.
32 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
33 ("Apple") in consideration of your agreement to the following terms, and your
34 use, installation, modification or redistribution of this Apple software
35 constitutes acceptance of these terms. If you do not agree with these terms,
36 please do not use, install, modify or redistribute this Apple software.
38 In consideration of your agreement to abide by the following terms, and subject
39 to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
40 copyrights in this original Apple software (the "Apple Software"), to use,
41 reproduce, modify and redistribute the Apple Software, with or without
42 modifications, in source and/or binary forms; provided that if you redistribute
43 the Apple Software in its entirety and without modifications, you must retain
44 this notice and the following text and disclaimers in all such redistributions of
45 the Apple Software. Neither the name, trademarks, service marks or logos of
46 Apple Computer, Inc. may be used to endorse or promote products derived from the
47 Apple Software without specific prior written permission from Apple. Except as
48 expressly stated in this notice, no other rights or licenses, express or implied,
49 are granted by Apple herein, including but not limited to any patent rights that
50 may be infringed by your derivative works or by other works in which the Apple
51 Software may be incorporated.
53 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
54 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
55 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
56 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
57 COMBINATION WITH YOUR PRODUCTS.
59 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
60 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
61 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
62 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
63 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
64 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
65 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
69 DRI: Apple Macintosh Developer Technical Support
71 Other Contact: For bug reports, consult the following page on
73 http://developer.apple.com/bugreporter/
75 Technology: DTS Sample Code
81 Change History (most recent first):
83 <4> 8/22/02 JL [3016251] Changed FSMoveRenameObjectUnicode to not use
84 the Temporary folder because it isn't available on
86 <3> 4/19/02 JL [2853905] Fixed #if test around header includes.
87 <2> 4/19/02 JL [2850624] Fixed C++ compile errors and Project Builder
89 <2> 4/19/02 JL [2853901] Updated standard disclaimer.
90 <1> 1/25/02 JL MoreFilesX 1.0
94 #include <Carbon/Carbon.h>
101 #include "MoreFilesX.h"
103 /* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */
104 #ifndef BuildingMoreFilesXForMacOS9
105 #define BuildingMoreFilesXForMacOS9 0
108 /*****************************************************************************/
110 #pragma mark ----- Local type definitions -----
112 struct FSIterateContainerGlobals
114 IterateContainerFilterProcPtr iterateFilter; /* pointer to IterateFilterProc */
115 FSCatalogInfoBitmap whichInfo; /* fields of the CatalogInfo to get */
116 FSCatalogInfo catalogInfo; /* FSCatalogInfo */
117 FSRef ref; /* FSRef */
118 FSSpec spec; /* FSSpec */
119 FSSpec *specPtr; /* pointer to spec field, or NULL */
120 HFSUniStr255 name; /* HFSUniStr255 */
121 HFSUniStr255 *namePtr; /* pointer to name field, or NULL */
122 void *yourDataPtr; /* a pointer to caller supplied data the filter may need to access */
123 ItemCount maxLevels; /* maximum levels to iterate through */
124 ItemCount currentLevel; /* the current level FSIterateContainerLevel is on */
125 Boolean quitFlag; /* set to true if filter wants to kill interation */
126 Boolean containerChanged; /* temporary - set to true if the current container changed during iteration */
127 OSErr result; /* result */
128 ItemCount actualObjects; /* number of objects returned */
130 typedef struct FSIterateContainerGlobals FSIterateContainerGlobals;
132 struct FSDeleteContainerGlobals
134 OSErr result; /* result */
135 ItemCount actualObjects; /* number of objects returned */
136 FSCatalogInfo catalogInfo; /* FSCatalogInfo */
138 typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals;
140 /*****************************************************************************/
142 #pragma mark ----- Local prototypes -----
146 FSDeleteContainerLevel(
147 const FSRef *container,
148 FSDeleteContainerGlobals *theGlobals);
152 FSIterateContainerLevel(
153 FSIterateContainerGlobals *theGlobals);
157 GenerateUniqueHFSUniStr(
161 HFSUniStr255 *uniqueName);
163 /*****************************************************************************/
165 #pragma mark ----- File Access Routines -----
167 /*****************************************************************************/
174 ByteCount copyBufferSize)
180 ByteCount readActualCount;
182 /* check input parameters */
183 require_action((NULL != copyBufferPtr) && (0 != copyBufferSize), BadParameter, result = paramErr);
185 /* get source fork size */
186 result = FSGetForkSize(srcRefNum, &forkSize);
187 require_noerr(result, SourceFSGetForkSizeFailed);
189 /* allocate disk space for destination fork */
190 result = FSSetForkSize(dstRefNum, fsFromStart, forkSize);
191 require_noerr(result, DestinationFSSetForkSizeFailed);
193 /* reset source fork's position to 0 */
194 result = FSSetForkPosition(srcRefNum, fsFromStart, 0);
195 require_noerr(result, SourceFSSetForkPositionFailed);
197 /* reset destination fork's position to 0 */
198 result = FSSetForkPosition(dstRefNum, fsFromStart, 0);
199 require_noerr(result, DestinationFSSetForkPositionFailed);
201 /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */
202 /* This will make writes on local volumes faster */
203 if ( (copyBufferSize >= 0x00001000) && ((copyBufferSize & 0x00000fff) != 0) )
205 copyBufferSize &= ~(0x00001000 - 1);
208 /* copy source to destination */
209 srcResult = dstResult = noErr;
210 while ( (noErr == srcResult) && (noErr == dstResult) )
212 srcResult = FSReadFork(srcRefNum, fsAtMark + noCacheMask, 0, copyBufferSize, copyBufferPtr, &readActualCount);
213 dstResult = FSWriteFork(dstRefNum, fsAtMark + noCacheMask, 0, readActualCount, copyBufferPtr, NULL);
216 /* make sure there were no errors at the destination */
217 require_noerr_action(dstResult, DestinationFSWriteForkFailed, result = dstResult);
219 /* make sure the error at the source was eofErr */
220 require_action(eofErr == srcResult, SourceResultNotEofErr, result = srcResult);
222 /* everything went as expected */
225 SourceResultNotEofErr:
226 DestinationFSWriteForkFailed:
227 DestinationFSSetForkPositionFailed:
228 SourceFSSetForkPositionFailed:
229 DestinationFSSetForkSizeFailed:
230 SourceFSGetForkSizeFailed:
236 /*****************************************************************************/
238 #pragma mark ----- Volume Access Routines -----
240 /*****************************************************************************/
244 FSVolumeRefNum volRefNum,
246 GetVolParmsInfoBuffer *volParmsInfo,
247 UInt32 *actualInfoSize)
252 /* check parameters */
253 require_action((NULL != volParmsInfo) && (NULL != actualInfoSize),
254 BadParameter, result = paramErr);
256 pb.ioParam.ioNamePtr = NULL;
257 pb.ioParam.ioVRefNum = volRefNum;
258 pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
259 pb.ioParam.ioReqCount = (SInt32)bufferSize;
260 result = PBHGetVolParmsSync(&pb);
261 require_noerr(result, PBHGetVolParmsSync);
263 /* return number of bytes the file system returned in volParmsInfo buffer */
264 *actualInfoSize = (UInt32)pb.ioParam.ioActCount;
272 /*****************************************************************************/
277 FSVolumeRefNum *vRefNum)
280 FSCatalogInfo catalogInfo;
282 /* check parameters */
283 require_action(NULL != vRefNum, BadParameter, result = paramErr);
285 /* get the volume refNum from the FSRef */
286 result = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
287 require_noerr(result, FSGetCatalogInfo);
289 /* return volume refNum from catalogInfo */
290 *vRefNum = catalogInfo.volume;
298 /*****************************************************************************/
302 FSVolumeRefNum volume,
303 HFSUniStr255 *volumeName, /* can be NULL */
304 UInt64 *freeBytes, /* can be NULL */
305 UInt64 *totalBytes) /* can be NULL */
310 /* ask for the volume's sizes only if needed */
311 result = FSGetVolumeInfo(volume, 0, NULL,
312 (((NULL != freeBytes) || (NULL != totalBytes)) ? kFSVolInfoSizes : kFSVolInfoNone),
313 &info, volumeName, NULL);
314 require_noerr(result, FSGetVolumeInfo);
316 if ( NULL != freeBytes )
318 *freeBytes = info.freeBytes;
320 if ( NULL != totalBytes )
322 *totalBytes = info.totalBytes;
330 /*****************************************************************************/
333 FSGetVolFileSystemID(
334 FSVolumeRefNum volume,
335 UInt16 *fileSystemID, /* can be NULL */
336 UInt16 *signature) /* can be NULL */
341 result = FSGetVolumeInfo(volume, 0, NULL, kFSVolInfoFSInfo, &info, NULL, NULL);
342 require_noerr(result, FSGetVolumeInfo);
344 if ( NULL != fileSystemID )
346 *fileSystemID = info.filesystemID;
348 if ( NULL != signature )
350 *signature = info.signature;
358 /*****************************************************************************/
362 FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */
363 ItemCount *numVolumes)
367 ItemCount volumeIndex;
370 /* check parameters */
371 require_action((NULL != volumeRefsHandle) && (NULL != numVolumes),
372 BadParameter, result = paramErr);
377 /* Allocate a handle for the results */
378 *volumeRefsHandle = (FSRef **)NewHandle(0);
379 require_action(NULL != *volumeRefsHandle, NewHandle, result = memFullErr);
381 /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */
385 result = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoNone, NULL, NULL, &ref);
386 if ( noErr == result )
388 /* concatenate the FSRef to the end of the handle */
389 PtrAndHand(&ref, (Handle)*volumeRefsHandle, sizeof(FSRef));
390 memResult = MemError();
391 require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
393 ++(*numVolumes); /* increment the volume count */
394 ++volumeIndex; /* and the volumeIndex to get the next volume*/
396 } while ( noErr == result );
398 /* nsvErr is OK -- it just means there are no more volumes */
399 require(nsvErr == result, FSGetVolumeInfo);
403 /**********************/
405 MemoryAllocationFailed:
408 /* dispose of handle if already allocated and clear the outputs */
409 if ( NULL != *volumeRefsHandle )
411 DisposeHandle((Handle)*volumeRefsHandle);
412 *volumeRefsHandle = NULL;
422 /*****************************************************************************/
424 #pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
426 /*****************************************************************************/
435 /* check parameters */
436 require_action(NULL != spec, BadParameter, result = paramErr);
438 result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
439 require_noerr(result, FSGetCatalogInfo);
447 /*****************************************************************************/
451 FSVolumeRefNum volRefNum,
453 ConstStr255Param name,
459 /* check parameters */
460 require_action(NULL != ref, BadParameter, result = paramErr);
462 pb.ioVRefNum = volRefNum;
464 pb.ioNamePtr = (StringPtr)name;
466 result = PBMakeFSRefSync(&pb);
467 require_noerr(result, PBMakeFSRefSync);
475 /*****************************************************************************/
481 ConstStr255Param name,
488 /* check parameters */
489 require_action(NULL != path, BadParameter, result = paramErr);
491 /* convert the inputs to an FSRef */
492 result = FSMakeFSRef(volRefNum, dirID, name, &ref);
493 require_noerr(result, FSMakeFSRef);
495 /* and then convert the FSRef to a path */
496 result = FSRefMakePath(&ref, path, maxPathSize);
497 require_noerr(result, FSRefMakePath);
506 /*****************************************************************************/
512 Boolean *isDirectory) /* can be NULL */
517 /* check parameters */
518 require_action(NULL != spec, BadParameter, result = paramErr);
520 /* convert the POSIX path to an FSRef */
521 result = FSPathMakeRef(path, &ref, isDirectory);
522 require_noerr(result, FSPathMakeRef);
524 /* and then convert the FSRef to an FSSpec */
525 result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
526 require_noerr(result, FSGetCatalogInfo);
535 /*****************************************************************************/
538 UnicodeNameGetHFSName(
539 UniCharCount nameLength,
541 TextEncoding textEncodingHint,
542 Boolean isVolumeName,
546 ByteCount unicodeByteLength;
547 ByteCount unicodeBytesConverted;
548 ByteCount actualPascalBytes;
549 UnicodeMapping uMapping;
550 UnicodeToTextInfo utInfo;
552 /* check parameters */
553 require_action(NULL != hfsName, BadParameter, result = paramErr);
555 /* make sure output is valid in case we get errors or there's nothing to convert */
558 unicodeByteLength = nameLength * sizeof(UniChar);
559 if ( 0 == unicodeByteLength )
566 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
567 if ( kTextEncodingUnknown == textEncodingHint )
572 script = (ScriptCode)GetScriptManagerVariable(smSysScript);
573 region = (RegionCode)GetScriptManagerVariable(smRegionCode);
574 result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
575 NULL, &textEncodingHint );
576 if ( paramErr == result )
578 /* ok, ignore the region and try again */
579 result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
580 kTextRegionDontCare, NULL, &textEncodingHint );
582 if ( noErr != result )
584 /* ok... try something */
585 textEncodingHint = kTextEncodingMacRoman;
589 uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
590 kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
591 uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
592 uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
594 result = CreateUnicodeToTextInfo(&uMapping, &utInfo);
595 require_noerr(result, CreateUnicodeToTextInfo);
597 result = ConvertFromUnicodeToText(utInfo, unicodeByteLength, name, kUnicodeLooseMappingsMask,
598 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */
599 isVolumeName ? kHFSMaxVolumeNameChars : kHFSMaxFileNameChars,
600 &unicodeBytesConverted, &actualPascalBytes, &hfsName[1]);
601 require_noerr(result, ConvertFromUnicodeToText);
603 hfsName[0] = (unsigned char)actualPascalBytes; /* fill in length byte */
605 ConvertFromUnicodeToText:
607 /* verify the result in debug builds -- there's really not anything you can do if it fails */
608 verify_noerr(DisposeUnicodeToTextInfo(&utInfo));
611 CreateUnicodeToTextInfo:
617 /*****************************************************************************/
620 HFSNameGetUnicodeName(
621 ConstStr31Param hfsName,
622 TextEncoding textEncodingHint,
623 HFSUniStr255 *unicodeName)
625 ByteCount unicodeByteLength;
627 UnicodeMapping uMapping;
628 TextToUnicodeInfo tuInfo;
629 ByteCount pascalCharsRead;
631 /* check parameters */
632 require_action(NULL != unicodeName, BadParameter, result = paramErr);
634 /* make sure output is valid in case we get errors or there's nothing to convert */
635 unicodeName->length = 0;
637 if ( 0 == StrLength(hfsName) )
643 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
644 if ( kTextEncodingUnknown == textEncodingHint )
649 script = GetScriptManagerVariable(smSysScript);
650 region = GetScriptManagerVariable(smRegionCode);
651 result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
652 NULL, &textEncodingHint);
653 if ( paramErr == result )
655 /* ok, ignore the region and try again */
656 result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
657 kTextRegionDontCare, NULL, &textEncodingHint);
659 if ( noErr != result )
661 /* ok... try something */
662 textEncodingHint = kTextEncodingMacRoman;
666 uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
667 kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
668 uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
669 uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
671 result = CreateTextToUnicodeInfo(&uMapping, &tuInfo);
672 require_noerr(result, CreateTextToUnicodeInfo);
674 result = ConvertFromTextToUnicode(tuInfo, hfsName[0], &hfsName[1],
675 0, /* no control flag bits */
676 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */
677 sizeof(unicodeName->unicode), /* output buffer size in bytes */
678 &pascalCharsRead, &unicodeByteLength, unicodeName->unicode);
679 require_noerr(result, ConvertFromTextToUnicode);
681 /* convert from byte count to char count */
682 unicodeName->length = unicodeByteLength / sizeof(UniChar);
684 ConvertFromTextToUnicode:
686 /* verify the result in debug builds -- there's really not anything you can do if it fails */
687 verify_noerr(DisposeTextToUnicodeInfo(&tuInfo));
690 CreateTextToUnicodeInfo:
696 /*****************************************************************************/
698 #pragma mark ----- File/Directory Manipulation Routines -----
700 /*****************************************************************************/
702 Boolean FSRefValid(const FSRef *ref)
704 return ( noErr == FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, NULL, NULL) );
707 /*****************************************************************************/
715 FSCatalogInfo catalogInfo;
717 /* check parameters */
718 require_action(NULL != parentRef, BadParameter, result = paramErr);
720 result = FSGetCatalogInfo(ref, kFSCatInfoNodeID, &catalogInfo, NULL, NULL, parentRef);
721 require_noerr(result, FSGetCatalogInfo);
724 * Note: FSRefs always point to real file system objects. So, there cannot
725 * be a FSRef to the parent of volume root directories. Early versions of
726 * Mac OS X do not handle this case correctly and incorrectly return a
727 * FSRef for the parent of volume root directories instead of returning an
728 * invalid FSRef (a cleared FSRef is invalid). The next three lines of code
729 * ensure that you won't run into this bug. WW9D!
731 if ( fsRtDirID == catalogInfo.nodeID )
733 /* clear parentRef and return noErr which is the proper behavior */
734 memset(parentRef, 0, sizeof(FSRef));
743 /*****************************************************************************/
748 HFSUniStr255 *outName)
752 /* check parameters */
753 require_action(NULL != outName, BadParameter, result = paramErr);
755 result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, outName, NULL, NULL);
756 require_noerr(result, FSGetCatalogInfo);
764 /*****************************************************************************/
769 long *nodeID, /* can be NULL */
770 Boolean *isDirectory) /* can be NULL */
773 FSCatalogInfo catalogInfo;
774 FSCatalogInfoBitmap whichInfo;
776 /* determine what catalog information to get */
777 whichInfo = kFSCatInfoNone; /* start with none */
778 if ( NULL != nodeID )
780 whichInfo |= kFSCatInfoNodeID;
782 if ( NULL != isDirectory )
784 whichInfo |= kFSCatInfoNodeFlags;
787 result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
788 require_noerr(result, FSGetCatalogInfo);
790 if ( NULL != nodeID )
792 *nodeID = catalogInfo.nodeID;
794 if ( NULL != isDirectory )
796 *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
804 /*****************************************************************************/
807 FSGetUserPrivilegesPermissions(
809 UInt8 *userPrivileges, /* can be NULL */
810 UInt32 permissions[4]) /* can be NULL */
813 FSCatalogInfo catalogInfo;
814 FSCatalogInfoBitmap whichInfo;
816 /* determine what catalog information to get */
817 whichInfo = kFSCatInfoNone; /* start with none */
818 if ( NULL != userPrivileges )
820 whichInfo |= kFSCatInfoUserPrivs;
822 if ( NULL != permissions )
824 whichInfo |= kFSCatInfoPermissions;
827 result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
828 require_noerr(result, FSGetCatalogInfo);
830 if ( NULL != userPrivileges )
832 *userPrivileges = catalogInfo.userPrivileges;
834 if ( NULL != permissions )
836 BlockMoveData(&catalogInfo.permissions, permissions, sizeof(UInt32) * 4);
844 /*****************************************************************************/
851 FSCatalogInfo catalogInfo;
852 FSVolumeInfo volumeInfo;
854 /* get nodeFlags and vRefNum for container */
855 result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoVolume, &catalogInfo, NULL, NULL,NULL);
856 require_noerr(result, FSGetCatalogInfo);
858 /* is file locked? */
859 if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
861 result = fLckdErr; /* file is locked */
865 /* file isn't locked, but is volume locked? */
867 /* get volume flags */
868 result = FSGetVolumeInfo(catalogInfo.volume, 0, NULL, kFSVolInfoFlags, &volumeInfo, NULL, NULL);
869 require_noerr(result, FSGetVolumeInfo);
871 if ( 0 != (volumeInfo.flags & kFSVolFlagHardwareLockedMask) )
873 result = wPrErr; /* volume locked by hardware */
875 else if ( 0 != (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) )
877 result = vLckdErr; /* volume locked by software */
887 /*****************************************************************************/
892 UInt64 *dataLogicalSize, /* can be NULL */
893 UInt64 *rsrcLogicalSize) /* can be NULL */
896 FSCatalogInfoBitmap whichInfo;
897 FSCatalogInfo catalogInfo;
899 whichInfo = kFSCatInfoNodeFlags;
900 if ( NULL != dataLogicalSize )
902 /* get data fork size */
903 whichInfo |= kFSCatInfoDataSizes;
905 if ( NULL != rsrcLogicalSize )
907 /* get resource fork size */
908 whichInfo |= kFSCatInfoRsrcSizes;
911 /* get nodeFlags and catalog info */
912 result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL,NULL);
913 require_noerr(result, FSGetCatalogInfo);
915 /* make sure FSRef was to a file */
916 require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
918 if ( NULL != dataLogicalSize )
920 /* return data fork size */
921 *dataLogicalSize = catalogInfo.dataLogicalSize;
923 if ( NULL != rsrcLogicalSize )
925 /* return resource fork size */
926 *rsrcLogicalSize = catalogInfo.rsrcLogicalSize;
935 /*****************************************************************************/
940 UInt64 *totalLogicalSize, /* can be NULL */
941 UInt64 *totalPhysicalSize, /* can be NULL */
942 ItemCount *forkCount) /* can be NULL */
945 CatPositionRec forkIterator;
948 UInt64 forkPhysicalSize;
949 UInt64 *forkPhysicalSizePtr;
951 /* Determine if forkSize needed */
952 if ( NULL != totalLogicalSize)
954 *totalLogicalSize = 0;
955 forkSizePtr = &forkSize;
962 /* Determine if forkPhysicalSize is needed */
963 if ( NULL != totalPhysicalSize )
965 *totalPhysicalSize = 0;
966 forkPhysicalSizePtr = &forkPhysicalSize;
970 forkPhysicalSizePtr = NULL;
973 /* zero fork count if returning it */
974 if ( NULL != forkCount )
979 /* Iterate through the forks to get the sizes */
980 forkIterator.initialize = 0;
983 result = FSIterateForks(ref, &forkIterator, NULL, forkSizePtr, forkPhysicalSizePtr);
984 if ( noErr == result )
986 if ( NULL != totalLogicalSize )
988 *totalLogicalSize += forkSize;
991 if ( NULL != totalPhysicalSize )
993 *totalPhysicalSize += forkPhysicalSize;
996 if ( NULL != forkCount )
1001 } while ( noErr == result );
1003 /* any error result other than errFSNoMoreItems is serious */
1004 require(errFSNoMoreItems == result, FSIterateForks);
1014 /*****************************************************************************/
1021 FSCatalogInfo catalogInfo;
1022 UTCDateTime oldDateTime;
1023 #if !BuildingMoreFilesXForMacOS9
1025 Boolean notifyParent;
1028 #if !BuildingMoreFilesXForMacOS9
1029 /* Get the node flags, the content modification date and time, and the parent ref */
1030 result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoContentMod, &catalogInfo, NULL, NULL, &parentRef);
1031 require_noerr(result, FSGetCatalogInfo);
1033 /* Notify the parent if this is a file */
1034 notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask));
1036 /* Get the content modification date and time */
1037 result = FSGetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo, NULL, NULL, NULL);
1038 require_noerr(result, FSGetCatalogInfo);
1041 oldDateTime = catalogInfo.contentModDate;
1043 /* Get the current date and time */
1044 result = GetUTCDateTime(&catalogInfo.contentModDate, kUTCDefaultOptions);
1045 require_noerr(result, GetUTCDateTime);
1047 /* if the old date and time is the the same as the current, bump the seconds by one */
1048 if ( (catalogInfo.contentModDate.fraction == oldDateTime.fraction) &&
1049 (catalogInfo.contentModDate.lowSeconds == oldDateTime.lowSeconds) &&
1050 (catalogInfo.contentModDate.highSeconds == oldDateTime.highSeconds) )
1052 ++catalogInfo.contentModDate.lowSeconds;
1053 if ( 0 == catalogInfo.contentModDate.lowSeconds )
1055 ++catalogInfo.contentModDate.highSeconds;
1059 /* Bump the content modification date and time */
1060 result = FSSetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo);
1061 require_noerr(result, FSSetCatalogInfo);
1063 #if !BuildingMoreFilesXForMacOS9
1065 * The problem with FNNotify is that it is not available under Mac OS 9
1066 * and there's no way to test for that except for looking for the symbol
1067 * or something. So, I'll just conditionalize this for those who care
1068 * to send a notification.
1071 /* Send a notification for the parent of the file, or for the directory */
1072 result = FNNotify(notifyParent ? &parentRef : ref, kFNDirectoryModifiedMessage, kNilOptions);
1073 require_noerr(result, FNNotify);
1076 /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */
1082 /**********************/
1090 /*****************************************************************************/
1095 FinderInfo *info, /* can be NULL */
1096 ExtendedFinderInfo *extendedInfo, /* can be NULL */
1097 Boolean *isDirectory) /* can be NULL */
1100 FSCatalogInfo catalogInfo;
1101 FSCatalogInfoBitmap whichInfo;
1103 /* determine what catalog information is really needed */
1104 whichInfo = kFSCatInfoNone;
1108 /* get FinderInfo */
1109 whichInfo |= kFSCatInfoFinderInfo;
1112 if ( NULL != extendedInfo )
1114 /* get ExtendedFinderInfo */
1115 whichInfo |= kFSCatInfoFinderXInfo;
1118 if ( NULL != isDirectory )
1120 whichInfo |= kFSCatInfoNodeFlags;
1123 result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
1124 require_noerr(result, FSGetCatalogInfo);
1126 /* return FinderInfo if requested */
1129 BlockMoveData(catalogInfo.finderInfo, info, sizeof(FinderInfo));
1132 /* return ExtendedFinderInfo if requested */
1133 if ( NULL != extendedInfo)
1135 BlockMoveData(catalogInfo.extFinderInfo, extendedInfo, sizeof(ExtendedFinderInfo));
1138 /* set isDirectory Boolean if requested */
1139 if ( NULL != isDirectory)
1141 *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
1149 /*****************************************************************************/
1154 const FinderInfo *info,
1155 const ExtendedFinderInfo *extendedInfo)
1158 FSCatalogInfo catalogInfo;
1159 FSCatalogInfoBitmap whichInfo;
1161 /* determine what catalog information will be set */
1162 whichInfo = kFSCatInfoNone; /* start with none */
1165 /* set FinderInfo */
1166 whichInfo |= kFSCatInfoFinderInfo;
1167 BlockMoveData(info, catalogInfo.finderInfo, sizeof(FinderInfo));
1169 if ( NULL != extendedInfo )
1171 /* set ExtendedFinderInfo */
1172 whichInfo |= kFSCatInfoFinderXInfo;
1173 BlockMoveData(extendedInfo, catalogInfo.extFinderInfo, sizeof(ExtendedFinderInfo));
1176 result = FSSetCatalogInfo(ref, whichInfo, &catalogInfo);
1177 require_noerr(result, FSGetCatalogInfo);
1184 /*****************************************************************************/
1187 FSChangeCreatorType(
1193 FSCatalogInfo catalogInfo;
1196 /* get nodeFlags, finder info, and parent FSRef */
1197 result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, &catalogInfo , NULL, NULL, &parentRef);
1198 require_noerr(result, FSGetCatalogInfo);
1200 /* make sure FSRef was to a file */
1201 require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
1203 /* If fileType not 0x00000000, change fileType */
1204 if ( fileType != (OSType)0x00000000 )
1206 ((FileInfo *)&catalogInfo.finderInfo)->fileType = fileType;
1209 /* If creator not 0x00000000, change creator */
1210 if ( fileCreator != (OSType)0x00000000 )
1212 ((FileInfo *)&catalogInfo.finderInfo)->fileCreator = fileCreator;
1215 /* now, save the new information back to disk */
1216 result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
1217 require_noerr(result, FSSetCatalogInfo);
1219 /* and attempt to bump the parent directory's mod date to wake up */
1220 /* the Finder to the change we just made (ignore errors from this) */
1221 verify_noerr(FSBumpDate(&parentRef));
1230 /*****************************************************************************/
1233 FSChangeFinderFlags(
1239 FSCatalogInfo catalogInfo;
1242 /* get the current finderInfo */
1243 result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef);
1244 require_noerr(result, FSGetCatalogInfo);
1246 /* set or clear the appropriate bits in the finderInfo.finderFlags */
1249 /* OR in the bits */
1250 ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits;
1254 /* AND out the bits */
1255 ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits;
1258 /* save the modified finderInfo */
1259 result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
1260 require_noerr(result, FSSetCatalogInfo);
1262 /* and attempt to bump the parent directory's mod date to wake up the Finder */
1263 /* to the change we just made (ignore errors from this) */
1264 verify_noerr(FSBumpDate(&parentRef));
1272 /*****************************************************************************/
1278 return ( FSChangeFinderFlags(ref, true, kIsInvisible) );
1285 return ( FSChangeFinderFlags(ref, false, kIsInvisible) );
1288 /*****************************************************************************/
1294 return ( FSChangeFinderFlags(ref, true, kNameLocked) );
1301 return ( FSChangeFinderFlags(ref, false, kNameLocked) );
1304 /*****************************************************************************/
1310 return ( FSChangeFinderFlags(ref, true, kIsStationery) );
1314 FSClearIsStationery(
1317 return ( FSChangeFinderFlags(ref, false, kIsStationery) );
1320 /*****************************************************************************/
1326 return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) );
1330 FSClearHasCustomIcon(
1333 return ( FSChangeFinderFlags(ref, false, kHasCustomIcon) );
1336 /*****************************************************************************/
1339 FSClearHasBeenInited(
1342 return ( FSChangeFinderFlags(ref, false, kHasBeenInited) );
1345 /*****************************************************************************/
1348 FSCopyFileMgrAttributes(
1349 const FSRef *sourceRef,
1350 const FSRef *destinationRef,
1351 Boolean copyLockBit)
1354 FSCatalogInfo catalogInfo;
1356 /* get the source information */
1357 result = FSGetCatalogInfo(sourceRef, kFSCatInfoSettableInfo, &catalogInfo, NULL, NULL, NULL);
1358 require_noerr(result, FSGetCatalogInfo);
1360 /* don't copy the hasBeenInited bit; clear it */
1361 ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~kHasBeenInited;
1363 /* should the locked bit be copied? */
1366 /* no, make sure the locked bit is clear */
1367 catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
1370 /* set the destination information */
1371 result = FSSetCatalogInfo(destinationRef, kFSCatInfoSettableInfo, &catalogInfo);
1372 require_noerr(result, FSSetCatalogInfo);
1380 /*****************************************************************************/
1383 FSMoveRenameObjectUnicode(
1385 const FSRef *destDirectory,
1386 UniCharCount nameLength,
1387 const UniChar *name, /* can be NULL (no rename during move) */
1388 TextEncoding textEncodingHint,
1389 FSRef *newRef) /* if function fails along the way, newRef is final location of file */
1392 FSVolumeRefNum vRefNum;
1393 FSCatalogInfo catalogInfo;
1394 FSRef originalDirectory;
1395 TextEncoding originalTextEncodingHint;
1396 HFSUniStr255 originalName;
1397 HFSUniStr255 uniqueName; /* unique name given to object while moving it to destination */
1398 long theSeed; /* the seed for generating unique names */
1400 /* check parameters */
1401 require_action(NULL != newRef, BadParameter, result = paramErr);
1403 /* newRef = input to start with */
1404 BlockMoveData(ref, newRef, sizeof(FSRef));
1406 /* get destDirectory's vRefNum */
1407 result = FSGetCatalogInfo(destDirectory, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
1408 require_noerr(result, DestinationBad);
1411 vRefNum = catalogInfo.volume;
1413 /* get ref's vRefNum, TextEncoding, name and parent directory*/
1414 result = FSGetCatalogInfo(ref, kFSCatInfoTextEncoding + kFSCatInfoVolume, &catalogInfo, &originalName, NULL, &originalDirectory);
1415 require_noerr(result, SourceBad);
1417 /* save TextEncoding */
1418 originalTextEncodingHint = catalogInfo.textEncodingHint;
1420 /* make sure ref and destDirectory are on same volume */
1421 require_action(vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
1423 /* Skip a few steps if we're not renaming */
1426 /* generate a name that is unique in both directories */
1427 theSeed = 0x4a696d4c; /* a fine unlikely filename */
1429 result = GenerateUniqueHFSUniStr(&theSeed, &originalDirectory, destDirectory, &uniqueName);
1430 require_noerr(result, GenerateUniqueHFSUniStrFailed);
1432 /* Rename the object to uniqueName */
1433 result = FSRenameUnicode(ref, uniqueName.length, uniqueName.unicode, kTextEncodingUnknown, newRef);
1434 require_noerr(result, FSRenameUnicodeBeforeMoveFailed);
1436 /* Move object to its new home */
1437 result = FSMoveObject(newRef, destDirectory, newRef);
1438 require_noerr(result, FSMoveObjectAfterRenameFailed);
1440 /* Rename the object to new name */
1441 result = FSRenameUnicode(ref, nameLength, name, textEncodingHint, newRef);
1442 require_noerr(result, FSRenameUnicodeAfterMoveFailed);
1446 /* Move object to its new home */
1447 result = FSMoveObject(newRef, destDirectory, newRef);
1448 require_noerr(result, FSMoveObjectNoRenameFailed);
1456 * failure handling code when renaming
1459 FSRenameUnicodeAfterMoveFailed:
1461 /* Error handling: move object back to original location - ignore errors */
1462 verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef));
1464 FSMoveObjectAfterRenameFailed:
1466 /* Error handling: rename object back to original name - ignore errors */
1467 verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef));
1469 FSRenameUnicodeBeforeMoveFailed:
1470 GenerateUniqueHFSUniStrFailed:
1473 * failure handling code for renaming or not
1475 FSMoveObjectNoRenameFailed:
1484 /*****************************************************************************/
1487 The FSDeleteContainerLevel function deletes the contents of a container
1488 directory. All files and subdirectories in the specified container are
1489 deleted. If a locked file or directory is encountered, it is unlocked
1490 and then deleted. If any unexpected errors are encountered,
1491 FSDeleteContainerLevel quits and returns to the caller.
1493 container --> FSRef to a directory.
1494 theGlobals --> A pointer to a FSDeleteContainerGlobals struct
1495 which contains the variables that do not need to
1496 be allocated each time FSDeleteContainerLevel
1497 recurses. That lets FSDeleteContainerLevel use
1498 less stack space per recursion level.
1503 FSDeleteContainerLevel(
1504 const FSRef *container,
1505 FSDeleteContainerGlobals *theGlobals)
1508 FSIterator iterator;
1512 /* Open FSIterator for flat access and give delete optimization hint */
1513 theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator);
1514 require_noerr(theGlobals->result, FSOpenIterator);
1516 /* delete the contents of the directory */
1519 /* get 1 item to delete */
1520 theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
1521 NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo,
1522 &itemToDelete, NULL, NULL);
1523 if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) )
1525 /* save node flags in local in case we have to recurse */
1526 nodeFlags = theGlobals->catalogInfo.nodeFlags;
1528 /* is it a file or directory? */
1529 if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) )
1531 /* it's a directory -- delete its contents before attempting to delete it */
1532 FSDeleteContainerLevel(&itemToDelete, theGlobals);
1534 /* are we still OK to delete? */
1535 if ( noErr == theGlobals->result )
1537 /* is item locked? */
1538 if ( 0 != (nodeFlags & kFSNodeLockedMask) )
1540 /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
1541 theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask;
1542 (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo);
1544 /* delete the item */
1545 theGlobals->result = FSDeleteObject(&itemToDelete);
1548 } while ( noErr == theGlobals->result );
1550 /* we found the end of the items normally, so return noErr */
1551 if ( errFSNoMoreItems == theGlobals->result )
1553 theGlobals->result = noErr;
1556 /* close the FSIterator (closing an open iterator should never fail) */
1557 verify_noerr(FSCloseIterator(iterator));
1564 /*****************************************************************************/
1567 FSDeleteContainerContents(
1568 const FSRef *container)
1570 FSDeleteContainerGlobals theGlobals;
1572 /* delete container's contents */
1573 FSDeleteContainerLevel(container, &theGlobals);
1575 return ( theGlobals.result );
1578 /*****************************************************************************/
1582 const FSRef *container)
1585 FSCatalogInfo catalogInfo;
1587 /* get nodeFlags for container */
1588 result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL);
1589 require_noerr(result, FSGetCatalogInfo);
1591 /* make sure container is a directory */
1592 require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr);
1594 /* delete container's contents */
1595 result = FSDeleteContainerContents(container);
1596 require_noerr(result, FSDeleteContainerContents);
1598 /* is container locked? */
1599 if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
1601 /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
1602 catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
1603 (void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo);
1606 /* delete the container */
1607 result = FSDeleteObject(container);
1609 FSDeleteContainerContents:
1610 ContainerNotDirectory:
1616 /*****************************************************************************/
1619 The FSIterateContainerLevel function iterates the contents of a container
1620 directory and calls a IterateContainerFilterProc function once for each
1621 file and directory found.
1623 theGlobals --> A pointer to a FSIterateContainerGlobals struct
1624 which contains the variables needed globally by
1625 all recusion levels of FSIterateContainerLevel.
1626 That makes FSIterateContainer thread safe since
1627 each call to it uses its own global world.
1628 It also contains the variables that do not need
1629 to be allocated each time FSIterateContainerLevel
1630 recurses. That lets FSIterateContainerLevel use
1631 less stack space per recursion level.
1636 FSIterateContainerLevel(
1637 FSIterateContainerGlobals *theGlobals)
1639 FSIterator iterator;
1641 /* If maxLevels is zero, we aren't checking levels */
1642 /* If currentLevel < maxLevels, look at this level */
1643 if ( (theGlobals->maxLevels == 0) ||
1644 (theGlobals->currentLevel < theGlobals->maxLevels) )
1646 /* Open FSIterator for flat access to theGlobals->ref */
1647 theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator);
1648 require_noerr(theGlobals->result, FSOpenIterator);
1650 ++theGlobals->currentLevel; /* Go to next level */
1652 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1655 theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
1656 &theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo,
1657 &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr);
1658 if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) &&
1659 (0 != theGlobals->actualObjects) )
1661 /* Call the IterateFilterProc */
1662 theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter,
1663 theGlobals->containerChanged, theGlobals->currentLevel,
1664 &theGlobals->catalogInfo, &theGlobals->ref,
1665 theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr);
1666 /* Is it a directory? */
1667 if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) )
1670 if ( !theGlobals->quitFlag )
1672 /* Dive again if the IterateFilterProc didn't say "quit" */
1673 FSIterateContainerLevel(theGlobals);
1677 /* time to fall back a level? */
1678 } while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) );
1680 /* errFSNoMoreItems is OK - it only means we hit the end of this level */
1681 /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
1682 if ( (errFSNoMoreItems == theGlobals->result) ||
1683 (afpAccessDenied == theGlobals->result) )
1685 theGlobals->result = noErr;
1688 --theGlobals->currentLevel; /* Return to previous level as we leave */
1690 /* Close the FSIterator (closing an open iterator should never fail) */
1691 verify_noerr(FSCloseIterator(iterator));
1699 /*****************************************************************************/
1703 const FSRef *container,
1704 ItemCount maxLevels,
1705 FSCatalogInfoBitmap whichInfo,
1708 IterateContainerFilterProcPtr iterateFilter,
1712 FSIterateContainerGlobals theGlobals;
1714 /* make sure there is an iterateFilter */
1715 require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr);
1718 * set up the globals we need to access from the recursive routine
1720 theGlobals.iterateFilter = iterateFilter;
1721 /* we need the node flags no matter what was requested so we can detect files vs. directories */
1722 theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags;
1723 /* start with input container -- the first OpenIterator will ensure it is a directory */
1724 theGlobals.ref = *container;
1727 theGlobals.specPtr = &theGlobals.spec;
1731 theGlobals.specPtr = NULL;
1735 theGlobals.namePtr = &theGlobals.name;
1739 theGlobals.namePtr = NULL;
1741 theGlobals.yourDataPtr = yourDataPtr;
1742 theGlobals.maxLevels = maxLevels;
1743 theGlobals.currentLevel = 0;
1744 theGlobals.quitFlag = false;
1745 theGlobals.containerChanged = false;
1746 theGlobals.result = noErr;
1747 theGlobals.actualObjects = 0;
1749 /* here we go into recursion land... */
1750 FSIterateContainerLevel(&theGlobals);
1751 result = theGlobals.result;
1752 require_noerr(result, FSIterateContainerLevel);
1754 FSIterateContainerLevel:
1760 /*****************************************************************************/
1763 FSGetDirectoryItems(
1764 const FSRef *container,
1765 FSRef ***refsHandle, /* pointer to handle of FSRefs */
1767 Boolean *containerChanged)
1769 /* Grab items 10 at a time. */
1770 enum { kMaxItemsPerBulkCall = 10 };
1774 FSIterator iterator;
1775 FSRef refs[kMaxItemsPerBulkCall];
1776 ItemCount actualObjects;
1779 /* check parameters */
1780 require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged),
1781 BadParameter, result = paramErr);
1784 *containerChanged = false;
1785 *refsHandle = (FSRef **)NewHandle(0);
1786 require_action(NULL != *refsHandle, NewHandle, result = memFullErr);
1788 /* open an FSIterator */
1789 result = FSOpenIterator(container, kFSIterateFlat, &iterator);
1790 require_noerr(result, FSOpenIterator);
1792 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1795 result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects,
1796 &changed, kFSCatInfoNone, NULL, refs, NULL, NULL);
1798 /* if the container changed, set containerChanged for output, but keep going */
1801 *containerChanged = changed;
1804 /* any result other than noErr and errFSNoMoreItems is serious */
1805 require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk);
1807 /* add objects to output array and count */
1808 if ( 0 != actualObjects )
1810 /* concatenate the FSRefs to the end of the handle */
1811 PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef));
1812 memResult = MemError();
1813 require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
1815 *numRefs += actualObjects;
1817 } while ( noErr == result );
1819 verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */
1823 /**********************/
1825 MemoryAllocationFailed:
1826 FSGetCatalogInfoBulk:
1828 /* close the iterator */
1829 verify_noerr(FSCloseIterator(iterator));
1832 /* dispose of handle if already allocated and clear the outputs */
1833 if ( NULL != *refsHandle )
1835 DisposeHandle((Handle)*refsHandle);
1846 /*****************************************************************************/
1849 The GenerateUniqueName function generates a HFSUniStr255 name that is
1850 unique in both dir1 and dir2.
1852 startSeed --> A pointer to a long which is used to generate the
1854 <-- It is modified on output to a value which should
1855 be used to generate the next unique name.
1856 dir1 --> The first directory.
1857 dir2 --> The second directory.
1858 uniqueName <-- A pointer to a HFSUniStr255 where the unique name
1864 GenerateUniqueHFSUniStr(
1868 HFSUniStr255 *uniqueName)
1874 unsigned char hexStr[17] = "0123456789ABCDEF";
1876 /* set up the parameter block */
1877 pb.name = uniqueName->unicode;
1878 pb.nameLength = 8; /* always 8 characters */
1879 pb.textEncodingHint = kTextEncodingUnknown;
1880 pb.newRef = &newRef;
1882 /* loop until we get fnfErr with a filename in both directories */
1884 while ( fnfErr != result )
1886 /* convert startSeed to 8 character Unicode string */
1887 uniqueName->length = 8;
1888 for ( i = 0; i < 8; ++i )
1890 uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)];
1895 result = PBMakeFSRefUnicodeSync(&pb);
1896 if ( fnfErr == result )
1900 result = PBMakeFSRefUnicodeSync(&pb);
1901 if ( fnfErr != result )
1903 /* exit if anything other than noErr or fnfErr */
1904 require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed);
1909 /* exit if anything other than noErr or fnfErr */
1910 require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed);
1913 /* increment seed for next pass through loop, */
1914 /* or for next call to GenerateUniqueHFSUniStr */
1918 /* we have a unique file name which doesn't exist in dir1 or dir2 */
1921 Dir2PBMakeFSRefUnicodeSyncFailed:
1922 Dir1PBMakeFSRefUnicodeSyncFailed:
1927 /*****************************************************************************/
1930 FSExchangeObjectsCompat(
1931 const FSRef *sourceRef,
1932 const FSRef *destRef,
1933 FSRef *newSourceRef,
1938 /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
1939 kGetCatInformationMask = (kFSCatInfoSettableInfo |
1941 kFSCatInfoParentDirID) &
1942 ~(kFSCatInfoContentMod | kFSCatInfoAttrMod),
1943 /* set everything possible except for mod dates */
1944 kSetCatinformationMask = kFSCatInfoSettableInfo &
1945 ~(kFSCatInfoContentMod | kFSCatInfoAttrMod)
1949 GetVolParmsInfoBuffer volParmsInfo;
1951 FSCatalogInfo sourceCatalogInfo; /* source file's catalog information */
1952 FSCatalogInfo destCatalogInfo; /* destination file's catalog information */
1953 HFSUniStr255 sourceName; /* source file's Unicode name */
1954 HFSUniStr255 destName; /* destination file's Unicode name */
1955 FSRef sourceCurrentRef; /* FSRef to current location of source file throughout this function */
1956 FSRef destCurrentRef; /* FSRef to current location of destination file throughout this function */
1957 FSRef sourceParentRef; /* FSRef to parent directory of source file */
1958 FSRef destParentRef; /* FSRef to parent directory of destination file */
1959 HFSUniStr255 sourceUniqueName; /* unique name given to source file while exchanging it with destination */
1960 HFSUniStr255 destUniqueName; /* unique name given to destination file while exchanging it with source */
1961 long theSeed; /* the seed for generating unique names */
1962 Boolean sameParentDirs; /* true if source and destinatin parent directory is the same */
1964 /* check parameters */
1965 require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr);
1967 /* output refs and current refs = input refs to start with */
1968 BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef));
1969 BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef));
1971 BlockMoveData(destRef, newDestRef, sizeof(FSRef));
1972 BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef));
1974 /* get source volume's vRefNum */
1975 result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL);
1976 require_noerr(result, DetermineSourceVRefNumFailed);
1978 /* see if that volume supports FSExchangeObjects */
1979 result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer),
1980 &volParmsInfo, &infoSize);
1981 if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) )
1983 /* yes - use FSExchangeObjects */
1984 result = FSExchangeObjects(sourceRef, destRef);
1988 /* no - emulate FSExchangeObjects */
1990 /* Note: The compatibility case won't work for files with *Btree control blocks. */
1991 /* Right now the only *Btree files are created by the system. */
1993 /* get all catalog information and Unicode names for each file */
1994 result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef);
1995 require_noerr(result, SourceFSGetCatalogInfoFailed);
1997 result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef);
1998 require_noerr(result, DestFSGetCatalogInfoFailed);
2000 /* make sure source and destination are on same volume */
2001 require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr);
2003 /* make sure both files are *really* files */
2004 require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) &&
2005 (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr);
2007 /* generate 2 names that are unique in both directories */
2008 theSeed = 0x4a696d4c; /* a fine unlikely filename */
2010 result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName);
2011 require_noerr(result, GenerateUniqueHFSUniStr1Failed);
2013 result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName);
2014 require_noerr(result, GenerateUniqueHFSUniStr2Failed);
2016 /* rename sourceCurrentRef to sourceUniqueName */
2017 result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef);
2018 require_noerr(result, FSRenameUnicode1Failed);
2019 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2021 /* rename destCurrentRef to destUniqueName */
2022 result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef);
2023 require_noerr(result, FSRenameUnicode2Failed);
2024 BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2026 /* are the source and destination parent directories the same? */
2027 sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID );
2028 if ( !sameParentDirs )
2030 /* move source file to dest parent directory */
2031 result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef);
2032 require_noerr(result, FSMoveObject1Failed);
2033 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2035 /* move dest file to source parent directory */
2036 result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef);
2037 require_noerr(result, FSMoveObject2Failed);
2038 BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2041 /* At this point, the files are in their new locations (if they were moved). */
2042 /* The source file is named sourceUniqueName and is in the directory referred to */
2043 /* by destParentRef. The destination file is named destUniqueName and is in the */
2044 /* directory referred to by sourceParentRef. */
2046 /* give source file the dest file's catalog information except for mod dates */
2047 result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo);
2048 require_noerr(result, FSSetCatalogInfo1Failed);
2050 /* give dest file the source file's catalog information except for mod dates */
2051 result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo);
2052 require_noerr(result, FSSetCatalogInfo2Failed);
2054 /* rename source file with dest file's name */
2055 result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef);
2056 require_noerr(result, FSRenameUnicode3Failed);
2057 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2059 /* rename dest file with source file's name */
2060 result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef);
2061 require_noerr(result, FSRenameUnicode4Failed);
2063 /* we're done with no errors, so swap newSourceRef and newDestRef */
2064 BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef));
2065 BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef));
2070 /**********************/
2072 /* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
2073 /* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
2074 /* state and location they ended up in so that both files can be found by the calling code. */
2076 FSRenameUnicode4Failed:
2078 /* attempt to rename source file to sourceUniqueName */
2079 if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) )
2081 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2084 FSRenameUnicode3Failed:
2086 /* attempt to restore dest file's catalog information */
2087 verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo));
2089 FSSetCatalogInfo2Failed:
2091 /* attempt to restore source file's catalog information */
2092 verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo));
2094 FSSetCatalogInfo1Failed:
2096 if ( !sameParentDirs )
2098 /* attempt to move dest file back to dest directory */
2099 if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) )
2101 BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2105 FSMoveObject2Failed:
2107 if ( !sameParentDirs )
2109 /* attempt to move source file back to source directory */
2110 if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) )
2112 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2116 FSMoveObject1Failed:
2118 /* attempt to rename dest file to original name */
2119 verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef));
2121 FSRenameUnicode2Failed:
2123 /* attempt to rename source file to original name */
2124 verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef));
2126 FSRenameUnicode1Failed:
2127 GenerateUniqueHFSUniStr2Failed:
2128 GenerateUniqueHFSUniStr1Failed:
2131 DestFSGetCatalogInfoFailed:
2132 SourceFSGetCatalogInfoFailed:
2133 DetermineSourceVRefNumFailed:
2139 /*****************************************************************************/
2141 #pragma mark ----- Shared Environment Routines -----
2143 /*****************************************************************************/
2154 pb.ioParam.ioRefNum = refNum;
2155 pb.ioParam.ioReqCount = rangeLength;
2156 pb.ioParam.ioPosMode = fsFromStart;
2157 pb.ioParam.ioPosOffset = rangeStart;
2158 result = PBLockRangeSync(&pb);
2159 require_noerr(result, PBLockRangeSync);
2166 /*****************************************************************************/
2177 pb.ioParam.ioRefNum = refNum;
2178 pb.ioParam.ioReqCount = rangeLength;
2179 pb.ioParam.ioPosMode = fsFromStart;
2180 pb.ioParam.ioPosOffset = rangeStart;
2181 result = PBUnlockRangeSync(&pb);
2182 require_noerr(result, PBUnlockRangeSync);
2189 /*****************************************************************************/
2194 SInt32 *ownerID, /* can be NULL */
2195 SInt32 *groupID, /* can be NULL */
2196 SInt32 *accessRights) /* can be NULL */
2202 /* get FSSpec from FSRef */
2203 result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2204 require_noerr(result, FSGetCatalogInfo);
2206 /* get directory access info for FSSpec */
2207 pb.accessParam.ioNamePtr = (StringPtr)spec.name;
2208 pb.accessParam.ioVRefNum = spec.vRefNum;
2209 pb.fileParam.ioDirID = spec.parID;
2210 result = PBHGetDirAccessSync(&pb);
2211 require_noerr(result, PBHGetDirAccessSync);
2213 /* return the IDs and access rights */
2214 if ( NULL != ownerID )
2216 *ownerID = pb.accessParam.ioACOwnerID;
2218 if ( NULL != groupID )
2220 *groupID = pb.accessParam.ioACGroupID;
2222 if ( NULL != accessRights )
2224 *accessRights = pb.accessParam.ioACAccess;
2227 PBHGetDirAccessSync:
2233 /*****************************************************************************/
2240 SInt32 accessRights)
2248 /* Just the bits that can be set */
2249 kSetDirAccessSettableMask = (kioACAccessBlankAccessMask +
2250 kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask +
2251 kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask +
2252 kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask)
2255 /* get FSSpec from FSRef */
2256 result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2257 require_noerr(result, FSGetCatalogInfo);
2259 /* set directory access info for FSSpec */
2260 pb.accessParam.ioNamePtr = (StringPtr)spec.name;
2261 pb.accessParam.ioVRefNum = spec.vRefNum;
2262 pb.fileParam.ioDirID = spec.parID;
2263 pb.accessParam.ioACOwnerID = ownerID;
2264 pb.accessParam.ioACGroupID = groupID;
2265 pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask;
2266 result = PBHSetDirAccessSync(&pb);
2267 require_noerr(result, PBHSetDirAccessSync);
2269 PBHSetDirAccessSync:
2275 /*****************************************************************************/
2278 FSGetVolMountInfoSize(
2279 FSVolumeRefNum volRefNum,
2285 /* check parameters */
2286 require_action(NULL != size, BadParameter, result = paramErr);
2288 pb.ioParam.ioNamePtr = NULL;
2289 pb.ioParam.ioVRefNum = volRefNum;
2290 pb.ioParam.ioBuffer = (Ptr)size;
2291 result = PBGetVolMountInfoSize(&pb);
2292 require_noerr(result, PBGetVolMountInfoSize);
2294 PBGetVolMountInfoSize:
2300 /*****************************************************************************/
2304 FSVolumeRefNum volRefNum,
2310 /* check parameters */
2311 require_action(NULL != volMountInfo, BadParameter, result = paramErr);
2313 pb.ioParam.ioNamePtr = NULL;
2314 pb.ioParam.ioVRefNum = volRefNum;
2315 pb.ioParam.ioBuffer = (Ptr)volMountInfo;
2316 result = PBGetVolMountInfo(&pb);
2317 require_noerr(result, PBGetVolMountInfo);
2325 /*****************************************************************************/
2329 const void *volMountInfo,
2330 FSVolumeRefNum *volRefNum)
2335 /* check parameters */
2336 require_action(NULL != volRefNum, BadParameter, result = paramErr);
2338 pb.ioParam.ioBuffer = (Ptr)volMountInfo;
2339 result = PBVolumeMount(&pb);
2340 require_noerr(result, PBVolumeMount);
2342 /* return the volume reference number */
2343 *volRefNum = pb.ioParam.ioVRefNum;
2351 /*****************************************************************************/
2355 FSVolumeRefNum volRefNum,
2363 /* check parameters */
2364 require_action(NULL != name, BadParameter, result = paramErr);
2366 pb.objParam.ioNamePtr = NULL;
2367 pb.objParam.ioVRefNum = volRefNum;
2368 pb.objParam.ioObjType = objType;
2369 pb.objParam.ioObjNamePtr = name;
2370 pb.objParam.ioObjID = ugID;
2371 result = PBHMapIDSync(&pb);
2372 require_noerr(result, PBHMapIDSync);
2380 /*****************************************************************************/
2384 FSVolumeRefNum volRefNum,
2385 ConstStr255Param name,
2392 /* check parameters */
2393 require_action(NULL != ugID, BadParameter, result = paramErr);
2395 pb.objParam.ioNamePtr = NULL;
2396 pb.objParam.ioVRefNum = volRefNum;
2397 pb.objParam.ioObjType = objType;
2398 pb.objParam.ioObjNamePtr = (StringPtr)name;
2399 result = PBHMapNameSync(&pb);
2400 require_noerr(result, PBHMapNameSync);
2402 /* return the user or group ID */
2403 *ugID = pb.objParam.ioObjID;
2411 /*****************************************************************************/
2415 const FSRef *srcFileRef,
2416 const FSRef *dstDirectoryRef,
2417 UniCharCount nameLength,
2418 const UniChar *copyName, /* can be NULL (no rename during copy) */
2419 TextEncoding textEncodingHint,
2420 FSRef *newRef) /* can be NULL */
2424 FSCatalogInfo catalogInfo;
2427 GetVolParmsInfoBuffer volParmsInfo;
2430 /* get source FSSpec from source FSRef */
2431 result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
2432 require_noerr(result, FSGetCatalogInfo_srcFileRef);
2434 /* Make sure the volume supports CopyFile */
2435 result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
2436 &volParmsInfo, &infoSize);
2437 require_action((noErr == result) && VolHasCopyFile(&volParmsInfo),
2438 NoCopyFileSupport, result = paramErr);
2440 /* get destination volume reference number and destination directory ID from destination FSRef */
2441 result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
2442 &catalogInfo, NULL, NULL, NULL);
2443 require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
2445 /* tell the server to copy the object */
2446 pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
2447 pb.copyParam.ioDirID = srcFileSpec.parID;
2448 pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
2449 pb.copyParam.ioDstVRefNum = catalogInfo.volume;
2450 pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
2451 pb.copyParam.ioNewName = NULL;
2452 if ( NULL != copyName )
2454 result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName);
2455 require_noerr(result, UnicodeNameGetHFSName);
2457 pb.copyParam.ioCopyName = hfsName;
2461 pb.copyParam.ioCopyName = NULL;
2463 result = PBHCopyFileSync(&pb);
2464 require_noerr(result, PBHCopyFileSync);
2466 if ( NULL != newRef )
2468 verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID,
2469 pb.copyParam.ioCopyName, newRef));
2473 UnicodeNameGetHFSName:
2474 FSGetCatalogInfo_dstDirectoryRef:
2476 FSGetCatalogInfo_srcFileRef:
2481 /*****************************************************************************/
2485 const FSRef *srcFileRef,
2486 const FSRef *dstDirectoryRef,
2487 UniCharCount nameLength,
2488 const UniChar *moveName, /* can be NULL (no rename during move) */
2489 TextEncoding textEncodingHint,
2490 FSRef *newRef) /* can be NULL */
2494 FSCatalogInfo catalogInfo;
2497 GetVolParmsInfoBuffer volParmsInfo;
2500 /* get source FSSpec from source FSRef */
2501 result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
2502 require_noerr(result, FSGetCatalogInfo_srcFileRef);
2504 /* Make sure the volume supports MoveRename */
2505 result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
2506 &volParmsInfo, &infoSize);
2507 require_action((noErr == result) && VolHasMoveRename(&volParmsInfo),
2508 NoMoveRenameSupport, result = paramErr);
2510 /* get destination volume reference number and destination directory ID from destination FSRef */
2511 result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
2512 &catalogInfo, NULL, NULL, NULL);
2513 require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
2515 /* make sure the source and destination are on the same volume */
2516 require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
2518 /* tell the server to move and rename the object */
2519 pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
2520 pb.copyParam.ioDirID = srcFileSpec.parID;
2521 pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
2522 pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
2523 pb.copyParam.ioNewName = NULL;
2524 if ( NULL != moveName )
2526 result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName);
2527 require_noerr(result, UnicodeNameGetHFSName);
2529 pb.copyParam.ioCopyName = hfsName;
2533 pb.copyParam.ioCopyName = NULL;
2535 result = PBHMoveRenameSync(&pb);
2536 require_noerr(result, PBHMoveRenameSync);
2538 if ( NULL != newRef )
2540 verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID,
2541 pb.copyParam.ioCopyName, newRef));
2545 UnicodeNameGetHFSName:
2547 FSGetCatalogInfo_dstDirectoryRef:
2548 NoMoveRenameSupport:
2549 FSGetCatalogInfo_srcFileRef:
2554 /*****************************************************************************/
2556 #pragma mark ----- File ID Routines -----
2558 /*****************************************************************************/
2562 FSVolumeRefNum volRefNum,
2570 /* check parameters */
2571 require_action(NULL != ref, BadParameter, result = paramErr);
2573 /* resolve the file ID reference */
2575 pb.ioNamePtr = tempStr;
2576 pb.ioVRefNum = volRefNum;
2577 pb.ioFileID = fileID;
2578 result = PBResolveFileIDRefSync((HParmBlkPtr)&pb);
2579 require_noerr(result, PBResolveFileIDRefSync);
2581 /* and then make an FSRef to the file */
2582 result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref);
2583 require_noerr(result, FSMakeFSRef);
2586 PBResolveFileIDRefSync:
2592 /*****************************************************************************/
2603 /* check parameters */
2604 require_action(NULL != fileID, BadParameter, result = paramErr);
2606 /* Get an FSSpec from the FSRef */
2607 result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2608 require_noerr(result, FSGetCatalogInfo);
2610 /* Create (or get) the file ID reference using the FSSpec */
2611 pb.ioNamePtr = (StringPtr)spec.name;
2612 pb.ioVRefNum = spec.vRefNum;
2613 pb.ioSrcDirID = spec.parID;
2614 result = PBCreateFileIDRefSync((HParmBlkPtr)&pb);
2615 require((noErr == result) || (fidExists == result) || (afpIDExists == result),
2616 PBCreateFileIDRefSync);
2618 /* return the file ID reference */
2619 *fileID = pb.ioFileID;
2621 PBCreateFileIDRefSync:
2628 /*****************************************************************************/
2630 #pragma mark ----- Utility Routines -----
2632 /*****************************************************************************/
2636 ByteCount buffReqSize,
2637 ByteCount *buffActSize)
2641 kSlopMemory = 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
2646 /* check parameters */
2647 require_action(NULL != buffActSize, BadParameter, tempPtr = NULL);
2649 /* Make request a multiple of 4K bytes */
2650 buffReqSize = buffReqSize & 0xfffff000;
2652 if ( buffReqSize < 0x00001000 )
2654 /* Request was smaller than 4K bytes - make it 4K */
2655 buffReqSize = 0x00001000;
2658 /* Attempt to allocate the memory */
2659 tempPtr = NewPtr(buffReqSize);
2661 /* If request failed, go to backup plan */
2662 if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) )
2665 ** Try to get largest 4K byte block available
2666 ** leaving some slop for the toolbox if possible
2668 long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000;
2670 buffReqSize = MaxBlock() & 0xfffff000;
2672 if ( buffReqSize > freeMemory )
2674 buffReqSize = freeMemory;
2677 if ( buffReqSize == 0 )
2679 buffReqSize = 0x00001000;
2682 tempPtr = NewPtr(buffReqSize);
2685 /* Return bytes allocated */
2686 if ( tempPtr != NULL )
2688 *buffActSize = buffReqSize;
2700 /*****************************************************************************/
2707 return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) );
2710 /*****************************************************************************/
2714 const FSRef *newDefault,
2718 FSVolumeRefNum vRefNum;
2720 FSCatalogInfo catalogInfo;
2722 /* check parameters */
2723 require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr);
2725 /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
2726 result = FSGetCatalogInfo(newDefault,
2727 kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
2728 &catalogInfo, NULL, NULL, NULL);
2729 require_noerr(result, FSGetCatalogInfo);
2731 /* Make sure newDefault is a directory */
2732 require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory,
2735 /* Get the current working directory. */
2736 result = HGetVol(NULL, &vRefNum, &dirID);
2737 require_noerr(result, HGetVol);
2739 /* Return the oldDefault FSRef */
2740 result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault);
2741 require_noerr(result, FSMakeFSRef);
2743 /* Set the new current working directory */
2744 result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
2745 require_noerr(result, HSetVol);
2750 NewDefaultNotDirectory:
2757 /*****************************************************************************/
2761 const FSRef *oldDefault)
2764 FSCatalogInfo catalogInfo;
2766 /* check parameters */
2767 require_action(NULL != oldDefault, BadParameter, result = paramErr);
2769 /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
2770 result = FSGetCatalogInfo(oldDefault,
2771 kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
2772 &catalogInfo, NULL, NULL, NULL);
2773 require_noerr(result, FSGetCatalogInfo);
2775 /* Make sure oldDefault is a directory */
2776 require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory,
2779 /* Set the current working directory to oldDefault */
2780 result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
2781 require_noerr(result, HSetVol);
2784 OldDefaultNotDirectory:
2791 /*****************************************************************************/