4 Contains: A collection of useful high-level File Manager routines
5 which use the HFS Plus APIs wherever possible.
7 Version: MoreFilesX 1.0.1
9 Copyright: © 1992-2002 by Apple Computer, Inc., all rights reserved.
11 Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc.
12 ("Apple") in consideration of your agreement to the following terms, and your
13 use, installation, modification or redistribution of this Apple software
14 constitutes acceptance of these terms. If you do not agree with these terms,
15 please do not use, install, modify or redistribute this Apple software.
17 In consideration of your agreement to abide by the following terms, and subject
18 to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs
19 copyrights in this original Apple software (the "Apple Software"), to use,
20 reproduce, modify and redistribute the Apple Software, with or without
21 modifications, in source and/or binary forms; provided that if you redistribute
22 the Apple Software in its entirety and without modifications, you must retain
23 this notice and the following text and disclaimers in all such redistributions of
24 the Apple Software. Neither the name, trademarks, service marks or logos of
25 Apple Computer, Inc. may be used to endorse or promote products derived from the
26 Apple Software without specific prior written permission from Apple. Except as
27 expressly stated in this notice, no other rights or licenses, express or implied,
28 are granted by Apple herein, including but not limited to any patent rights that
29 may be infringed by your derivative works or by other works in which the Apple
30 Software may be incorporated.
32 The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO
33 WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED
34 WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
35 PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN
36 COMBINATION WITH YOUR PRODUCTS.
38 IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR
39 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
40 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION
42 OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT
43 (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN
44 ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48 DRI: Apple Macintosh Developer Technical Support
50 Other Contact: For bug reports, consult the following page on
52 http://developer.apple.com/bugreporter/
54 Technology: DTS Sample Code
60 Change History (most recent first):
62 <4> 8/22/02 JL [3016251] Changed FSMoveRenameObjectUnicode to not use
63 the Temporary folder because it isn't available on
65 <3> 4/19/02 JL [2853905] Fixed #if test around header includes.
66 <2> 4/19/02 JL [2850624] Fixed C++ compile errors and Project Builder
68 <2> 4/19/02 JL [2853901] Updated standard disclaimer.
69 <1> 1/25/02 JL MoreFilesX 1.0
73 #include <Carbon/Carbon.h>
75 #define BuildingMoreFilesXForMacOS9 0
79 #define BuildingMoreFilesXForMacOS9 1
82 #include "MoreFilesX.h"
84 /* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */
85 #ifndef BuildingMoreFilesXForMacOS9
86 #define BuildingMoreFilesXForMacOS9 0
89 /*****************************************************************************/
91 #pragma mark ----- Local type definitions -----
93 struct FSIterateContainerGlobals
95 IterateContainerFilterProcPtr iterateFilter
; /* pointer to IterateFilterProc */
96 FSCatalogInfoBitmap whichInfo
; /* fields of the CatalogInfo to get */
97 FSCatalogInfo catalogInfo
; /* FSCatalogInfo */
98 FSRef ref
; /* FSRef */
99 FSSpec spec
; /* FSSpec */
100 FSSpec
*specPtr
; /* pointer to spec field, or NULL */
101 HFSUniStr255 name
; /* HFSUniStr255 */
102 HFSUniStr255
*namePtr
; /* pointer to name field, or NULL */
103 void *yourDataPtr
; /* a pointer to caller supplied data the filter may need to access */
104 ItemCount maxLevels
; /* maximum levels to iterate through */
105 ItemCount currentLevel
; /* the current level FSIterateContainerLevel is on */
106 Boolean quitFlag
; /* set to true if filter wants to kill interation */
107 Boolean containerChanged
; /* temporary - set to true if the current container changed during iteration */
108 OSErr result
; /* result */
109 ItemCount actualObjects
; /* number of objects returned */
111 typedef struct FSIterateContainerGlobals FSIterateContainerGlobals
;
113 struct FSDeleteContainerGlobals
115 OSErr result
; /* result */
116 ItemCount actualObjects
; /* number of objects returned */
117 FSCatalogInfo catalogInfo
; /* FSCatalogInfo */
119 typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals
;
121 /*****************************************************************************/
123 #pragma mark ----- Local prototypes -----
127 FSDeleteContainerLevel(
128 const FSRef
*container
,
129 FSDeleteContainerGlobals
*theGlobals
);
133 FSIterateContainerLevel(
134 FSIterateContainerGlobals
*theGlobals
);
138 GenerateUniqueHFSUniStr(
142 HFSUniStr255
*uniqueName
);
144 /*****************************************************************************/
146 #pragma mark ----- File Access Routines -----
148 /*****************************************************************************/
155 ByteCount copyBufferSize
)
161 ByteCount readActualCount
;
163 /* check input parameters */
164 require_action((NULL
!= copyBufferPtr
) && (0 != copyBufferSize
), BadParameter
, result
= paramErr
);
166 /* get source fork size */
167 result
= FSGetForkSize(srcRefNum
, &forkSize
);
168 require_noerr(result
, SourceFSGetForkSizeFailed
);
170 /* allocate disk space for destination fork */
171 result
= FSSetForkSize(dstRefNum
, fsFromStart
, forkSize
);
172 require_noerr(result
, DestinationFSSetForkSizeFailed
);
174 /* reset source fork's position to 0 */
175 result
= FSSetForkPosition(srcRefNum
, fsFromStart
, 0);
176 require_noerr(result
, SourceFSSetForkPositionFailed
);
178 /* reset destination fork's position to 0 */
179 result
= FSSetForkPosition(dstRefNum
, fsFromStart
, 0);
180 require_noerr(result
, DestinationFSSetForkPositionFailed
);
182 /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */
183 /* This will make writes on local volumes faster */
184 if ( (copyBufferSize
>= 0x00001000) && ((copyBufferSize
& 0x00000fff) != 0) )
186 copyBufferSize
&= ~(0x00001000 - 1);
189 /* copy source to destination */
190 srcResult
= dstResult
= noErr
;
191 while ( (noErr
== srcResult
) && (noErr
== dstResult
) )
193 srcResult
= FSReadFork(srcRefNum
, fsAtMark
+ noCacheMask
, 0, copyBufferSize
, copyBufferPtr
, &readActualCount
);
194 dstResult
= FSWriteFork(dstRefNum
, fsAtMark
+ noCacheMask
, 0, readActualCount
, copyBufferPtr
, NULL
);
197 /* make sure there were no errors at the destination */
198 require_noerr_action(dstResult
, DestinationFSWriteForkFailed
, result
= dstResult
);
200 /* make sure the error at the source was eofErr */
201 require_action(eofErr
== srcResult
, SourceResultNotEofErr
, result
= srcResult
);
203 /* everything went as expected */
206 SourceResultNotEofErr
:
207 DestinationFSWriteForkFailed
:
208 DestinationFSSetForkPositionFailed
:
209 SourceFSSetForkPositionFailed
:
210 DestinationFSSetForkSizeFailed
:
211 SourceFSGetForkSizeFailed
:
217 /*****************************************************************************/
219 #pragma mark ----- Volume Access Routines -----
221 /*****************************************************************************/
225 FSVolumeRefNum volRefNum
,
227 GetVolParmsInfoBuffer
*volParmsInfo
,
228 UInt32
*actualInfoSize
)
233 /* check parameters */
234 require_action((NULL
!= volParmsInfo
) && (NULL
!= actualInfoSize
),
235 BadParameter
, result
= paramErr
);
237 pb
.ioParam
.ioNamePtr
= NULL
;
238 pb
.ioParam
.ioVRefNum
= volRefNum
;
239 pb
.ioParam
.ioBuffer
= (Ptr
)volParmsInfo
;
240 pb
.ioParam
.ioReqCount
= (SInt32
)bufferSize
;
241 result
= PBHGetVolParmsSync(&pb
);
242 require_noerr(result
, PBHGetVolParmsSync
);
244 /* return number of bytes the file system returned in volParmsInfo buffer */
245 *actualInfoSize
= (UInt32
)pb
.ioParam
.ioActCount
;
253 /*****************************************************************************/
258 FSVolumeRefNum
*vRefNum
)
261 FSCatalogInfo catalogInfo
;
263 /* check parameters */
264 require_action(NULL
!= vRefNum
, BadParameter
, result
= paramErr
);
266 /* get the volume refNum from the FSRef */
267 result
= FSGetCatalogInfo(ref
, kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
, NULL
);
268 require_noerr(result
, FSGetCatalogInfo
);
270 /* return volume refNum from catalogInfo */
271 *vRefNum
= catalogInfo
.volume
;
279 /*****************************************************************************/
283 FSVolumeRefNum volume
,
284 HFSUniStr255
*volumeName
, /* can be NULL */
285 UInt64
*freeBytes
, /* can be NULL */
286 UInt64
*totalBytes
) /* can be NULL */
291 /* ask for the volume's sizes only if needed */
292 result
= FSGetVolumeInfo(volume
, 0, NULL
,
293 (((NULL
!= freeBytes
) || (NULL
!= totalBytes
)) ? kFSVolInfoSizes
: kFSVolInfoNone
),
294 &info
, volumeName
, NULL
);
295 require_noerr(result
, FSGetVolumeInfo
);
297 if ( NULL
!= freeBytes
)
299 *freeBytes
= info
.freeBytes
;
301 if ( NULL
!= totalBytes
)
303 *totalBytes
= info
.totalBytes
;
311 /*****************************************************************************/
314 FSGetVolFileSystemID(
315 FSVolumeRefNum volume
,
316 UInt16
*fileSystemID
, /* can be NULL */
317 UInt16
*signature
) /* can be NULL */
322 result
= FSGetVolumeInfo(volume
, 0, NULL
, kFSVolInfoFSInfo
, &info
, NULL
, NULL
);
323 require_noerr(result
, FSGetVolumeInfo
);
325 if ( NULL
!= fileSystemID
)
327 *fileSystemID
= info
.filesystemID
;
329 if ( NULL
!= signature
)
331 *signature
= info
.signature
;
339 /*****************************************************************************/
343 FSRef
***volumeRefsHandle
, /* pointer to handle of FSRefs */
344 ItemCount
*numVolumes
)
348 ItemCount volumeIndex
;
351 /* check parameters */
352 require_action((NULL
!= volumeRefsHandle
) && (NULL
!= numVolumes
),
353 BadParameter
, result
= paramErr
);
358 /* Allocate a handle for the results */
359 *volumeRefsHandle
= (FSRef
**)NewHandle(0);
360 require_action(NULL
!= *volumeRefsHandle
, NewHandle
, result
= memFullErr
);
362 /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */
366 result
= FSGetVolumeInfo(0, volumeIndex
, NULL
, kFSVolInfoNone
, NULL
, NULL
, &ref
);
367 if ( noErr
== result
)
369 /* concatenate the FSRef to the end of the handle */
370 PtrAndHand(&ref
, (Handle
)*volumeRefsHandle
, sizeof(FSRef
));
371 memResult
= MemError();
372 require_noerr_action(memResult
, MemoryAllocationFailed
, result
= memResult
);
374 ++(*numVolumes
); /* increment the volume count */
375 ++volumeIndex
; /* and the volumeIndex to get the next volume*/
377 } while ( noErr
== result
);
379 /* nsvErr is OK -- it just means there are no more volumes */
380 require(nsvErr
== result
, FSGetVolumeInfo
);
384 /**********************/
386 MemoryAllocationFailed
:
389 /* dispose of handle if already allocated and clear the outputs */
390 if ( NULL
!= *volumeRefsHandle
)
392 DisposeHandle((Handle
)*volumeRefsHandle
);
393 *volumeRefsHandle
= NULL
;
403 /*****************************************************************************/
405 #pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
407 /*****************************************************************************/
416 /* check parameters */
417 require_action(NULL
!= spec
, BadParameter
, result
= paramErr
);
419 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
);
420 require_noerr(result
, FSGetCatalogInfo
);
428 /*****************************************************************************/
432 FSVolumeRefNum volRefNum
,
434 ConstStr255Param name
,
440 /* check parameters */
441 require_action(NULL
!= ref
, BadParameter
, result
= paramErr
);
443 pb
.ioVRefNum
= volRefNum
;
445 pb
.ioNamePtr
= (StringPtr
)name
;
447 result
= PBMakeFSRefSync(&pb
);
448 require_noerr(result
, PBMakeFSRefSync
);
456 /*****************************************************************************/
462 ConstStr255Param name
,
469 /* check parameters */
470 require_action(NULL
!= path
, BadParameter
, result
= paramErr
);
472 /* convert the inputs to an FSRef */
473 result
= FSMakeFSRef(volRefNum
, dirID
, name
, &ref
);
474 require_noerr(result
, FSMakeFSRef
);
476 /* and then convert the FSRef to a path */
477 result
= FSRefMakePath(&ref
, path
, maxPathSize
);
478 require_noerr(result
, FSRefMakePath
);
487 /*****************************************************************************/
493 Boolean
*isDirectory
) /* can be NULL */
498 /* check parameters */
499 require_action(NULL
!= spec
, BadParameter
, result
= paramErr
);
501 /* convert the POSIX path to an FSRef */
502 result
= FSPathMakeRef(path
, &ref
, isDirectory
);
503 require_noerr(result
, FSPathMakeRef
);
505 /* and then convert the FSRef to an FSSpec */
506 result
= FSGetCatalogInfo(&ref
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
);
507 require_noerr(result
, FSGetCatalogInfo
);
516 /*****************************************************************************/
519 UnicodeNameGetHFSName(
520 UniCharCount nameLength
,
522 TextEncoding textEncodingHint
,
523 Boolean isVolumeName
,
527 ByteCount unicodeByteLength
;
528 ByteCount unicodeBytesConverted
;
529 ByteCount actualPascalBytes
;
530 UnicodeMapping uMapping
;
531 UnicodeToTextInfo utInfo
;
533 /* check parameters */
534 require_action(NULL
!= hfsName
, BadParameter
, result
= paramErr
);
536 /* make sure output is valid in case we get errors or there's nothing to convert */
539 unicodeByteLength
= nameLength
* sizeof(UniChar
);
540 if ( 0 == unicodeByteLength
)
547 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
548 if ( kTextEncodingUnknown
== textEncodingHint
)
553 script
= (ScriptCode
)GetScriptManagerVariable(smSysScript
);
554 region
= (RegionCode
)GetScriptManagerVariable(smRegionCode
);
555 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, region
,
556 NULL
, &textEncodingHint
);
557 if ( paramErr
== result
)
559 /* ok, ignore the region and try again */
560 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
,
561 kTextRegionDontCare
, NULL
, &textEncodingHint
);
563 if ( noErr
!= result
)
565 /* ok... try something */
566 textEncodingHint
= kTextEncodingMacRoman
;
570 uMapping
.unicodeEncoding
= CreateTextEncoding(kTextEncodingUnicodeV2_0
,
571 kUnicodeCanonicalDecompVariant
, kUnicode16BitFormat
);
572 uMapping
.otherEncoding
= GetTextEncodingBase(textEncodingHint
);
573 uMapping
.mappingVersion
= kUnicodeUseHFSPlusMapping
;
575 result
= CreateUnicodeToTextInfo(&uMapping
, &utInfo
);
576 require_noerr(result
, CreateUnicodeToTextInfo
);
578 result
= ConvertFromUnicodeToText(utInfo
, unicodeByteLength
, name
, kUnicodeLooseMappingsMask
,
579 0, NULL
, 0, NULL
, /* offsetCounts & offsetArrays */
580 isVolumeName
? kHFSMaxVolumeNameChars
: kHFSMaxFileNameChars
,
581 &unicodeBytesConverted
, &actualPascalBytes
, &hfsName
[1]);
582 require_noerr(result
, ConvertFromUnicodeToText
);
584 hfsName
[0] = (unsigned char)actualPascalBytes
; /* fill in length byte */
586 ConvertFromUnicodeToText
:
588 /* verify the result in debug builds -- there's really not anything you can do if it fails */
589 verify_noerr(DisposeUnicodeToTextInfo(&utInfo
));
592 CreateUnicodeToTextInfo
:
598 /*****************************************************************************/
601 HFSNameGetUnicodeName(
602 ConstStr31Param hfsName
,
603 TextEncoding textEncodingHint
,
604 HFSUniStr255
*unicodeName
)
606 ByteCount unicodeByteLength
;
608 UnicodeMapping uMapping
;
609 TextToUnicodeInfo tuInfo
;
610 ByteCount pascalCharsRead
;
612 /* check parameters */
613 require_action(NULL
!= unicodeName
, BadParameter
, result
= paramErr
);
615 /* make sure output is valid in case we get errors or there's nothing to convert */
616 unicodeName
->length
= 0;
618 if ( 0 == StrLength(hfsName
) )
624 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
625 if ( kTextEncodingUnknown
== textEncodingHint
)
630 script
= GetScriptManagerVariable(smSysScript
);
631 region
= GetScriptManagerVariable(smRegionCode
);
632 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, region
,
633 NULL
, &textEncodingHint
);
634 if ( paramErr
== result
)
636 /* ok, ignore the region and try again */
637 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
,
638 kTextRegionDontCare
, NULL
, &textEncodingHint
);
640 if ( noErr
!= result
)
642 /* ok... try something */
643 textEncodingHint
= kTextEncodingMacRoman
;
647 uMapping
.unicodeEncoding
= CreateTextEncoding(kTextEncodingUnicodeV2_0
,
648 kUnicodeCanonicalDecompVariant
, kUnicode16BitFormat
);
649 uMapping
.otherEncoding
= GetTextEncodingBase(textEncodingHint
);
650 uMapping
.mappingVersion
= kUnicodeUseHFSPlusMapping
;
652 result
= CreateTextToUnicodeInfo(&uMapping
, &tuInfo
);
653 require_noerr(result
, CreateTextToUnicodeInfo
);
655 result
= ConvertFromTextToUnicode(tuInfo
, hfsName
[0], &hfsName
[1],
656 0, /* no control flag bits */
657 0, NULL
, 0, NULL
, /* offsetCounts & offsetArrays */
658 sizeof(unicodeName
->unicode
), /* output buffer size in bytes */
659 &pascalCharsRead
, &unicodeByteLength
, unicodeName
->unicode
);
660 require_noerr(result
, ConvertFromTextToUnicode
);
662 /* convert from byte count to char count */
663 unicodeName
->length
= unicodeByteLength
/ sizeof(UniChar
);
665 ConvertFromTextToUnicode
:
667 /* verify the result in debug builds -- there's really not anything you can do if it fails */
668 verify_noerr(DisposeTextToUnicodeInfo(&tuInfo
));
671 CreateTextToUnicodeInfo
:
677 /*****************************************************************************/
679 #pragma mark ----- File/Directory Manipulation Routines -----
681 /*****************************************************************************/
683 Boolean
FSRefValid(const FSRef
*ref
)
685 return ( noErr
== FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, NULL
, NULL
) );
688 /*****************************************************************************/
696 FSCatalogInfo catalogInfo
;
698 /* check parameters */
699 require_action(NULL
!= parentRef
, BadParameter
, result
= paramErr
);
701 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeID
, &catalogInfo
, NULL
, NULL
, parentRef
);
702 require_noerr(result
, FSGetCatalogInfo
);
705 * Note: FSRefs always point to real file system objects. So, there cannot
706 * be a FSRef to the parent of volume root directories. Early versions of
707 * Mac OS X do not handle this case correctly and incorrectly return a
708 * FSRef for the parent of volume root directories instead of returning an
709 * invalid FSRef (a cleared FSRef is invalid). The next three lines of code
710 * ensure that you won't run into this bug. WW9D!
712 if ( fsRtDirID
== catalogInfo
.nodeID
)
714 /* clear parentRef and return noErr which is the proper behavior */
715 memset(parentRef
, 0, sizeof(FSRef
));
724 /*****************************************************************************/
729 HFSUniStr255
*outName
)
733 /* check parameters */
734 require_action(NULL
!= outName
, BadParameter
, result
= paramErr
);
736 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, outName
, NULL
, NULL
);
737 require_noerr(result
, FSGetCatalogInfo
);
745 /*****************************************************************************/
750 long *nodeID
, /* can be NULL */
751 Boolean
*isDirectory
) /* can be NULL */
754 FSCatalogInfo catalogInfo
;
755 FSCatalogInfoBitmap whichInfo
;
757 /* determine what catalog information to get */
758 whichInfo
= kFSCatInfoNone
; /* start with none */
759 if ( NULL
!= nodeID
)
761 whichInfo
|= kFSCatInfoNodeID
;
763 if ( NULL
!= isDirectory
)
765 whichInfo
|= kFSCatInfoNodeFlags
;
768 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
769 require_noerr(result
, FSGetCatalogInfo
);
771 if ( NULL
!= nodeID
)
773 *nodeID
= catalogInfo
.nodeID
;
775 if ( NULL
!= isDirectory
)
777 *isDirectory
= (0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
));
785 /*****************************************************************************/
788 FSGetUserPrivilegesPermissions(
790 UInt8
*userPrivileges
, /* can be NULL */
791 UInt32 permissions
[4]) /* can be NULL */
794 FSCatalogInfo catalogInfo
;
795 FSCatalogInfoBitmap whichInfo
;
797 /* determine what catalog information to get */
798 whichInfo
= kFSCatInfoNone
; /* start with none */
799 if ( NULL
!= userPrivileges
)
801 whichInfo
|= kFSCatInfoUserPrivs
;
803 if ( NULL
!= permissions
)
805 whichInfo
|= kFSCatInfoPermissions
;
808 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
809 require_noerr(result
, FSGetCatalogInfo
);
811 if ( NULL
!= userPrivileges
)
813 *userPrivileges
= catalogInfo
.userPrivileges
;
815 if ( NULL
!= permissions
)
817 BlockMoveData(&catalogInfo
.permissions
, permissions
, sizeof(UInt32
) * 4);
825 /*****************************************************************************/
832 FSCatalogInfo catalogInfo
;
833 FSVolumeInfo volumeInfo
;
835 /* get nodeFlags and vRefNum for container */
836 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags
+ kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
,NULL
);
837 require_noerr(result
, FSGetCatalogInfo
);
839 /* is file locked? */
840 if ( 0 != (catalogInfo
.nodeFlags
& kFSNodeLockedMask
) )
842 result
= fLckdErr
; /* file is locked */
846 /* file isn't locked, but is volume locked? */
848 /* get volume flags */
849 result
= FSGetVolumeInfo(catalogInfo
.volume
, 0, NULL
, kFSVolInfoFlags
, &volumeInfo
, NULL
, NULL
);
850 require_noerr(result
, FSGetVolumeInfo
);
852 if ( 0 != (volumeInfo
.flags
& kFSVolFlagHardwareLockedMask
) )
854 result
= wPrErr
; /* volume locked by hardware */
856 else if ( 0 != (volumeInfo
.flags
& kFSVolFlagSoftwareLockedMask
) )
858 result
= vLckdErr
; /* volume locked by software */
868 /*****************************************************************************/
873 UInt64
*dataLogicalSize
, /* can be NULL */
874 UInt64
*rsrcLogicalSize
) /* can be NULL */
877 FSCatalogInfoBitmap whichInfo
;
878 FSCatalogInfo catalogInfo
;
880 whichInfo
= kFSCatInfoNodeFlags
;
881 if ( NULL
!= dataLogicalSize
)
883 /* get data fork size */
884 whichInfo
|= kFSCatInfoDataSizes
;
886 if ( NULL
!= rsrcLogicalSize
)
888 /* get resource fork size */
889 whichInfo
|= kFSCatInfoRsrcSizes
;
892 /* get nodeFlags and catalog info */
893 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
,NULL
);
894 require_noerr(result
, FSGetCatalogInfo
);
896 /* make sure FSRef was to a file */
897 require_action(0 == (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
), FSRefNotFile
, result
= notAFileErr
);
899 if ( NULL
!= dataLogicalSize
)
901 /* return data fork size */
902 *dataLogicalSize
= catalogInfo
.dataLogicalSize
;
904 if ( NULL
!= rsrcLogicalSize
)
906 /* return resource fork size */
907 *rsrcLogicalSize
= catalogInfo
.rsrcLogicalSize
;
916 /*****************************************************************************/
921 UInt64
*totalLogicalSize
, /* can be NULL */
922 UInt64
*totalPhysicalSize
, /* can be NULL */
923 ItemCount
*forkCount
) /* can be NULL */
926 CatPositionRec forkIterator
;
929 UInt64 forkPhysicalSize
;
930 UInt64
*forkPhysicalSizePtr
;
932 /* Determine if forkSize needed */
933 if ( NULL
!= totalLogicalSize
)
935 *totalLogicalSize
= 0;
936 forkSizePtr
= &forkSize
;
943 /* Determine if forkPhysicalSize is needed */
944 if ( NULL
!= totalPhysicalSize
)
946 *totalPhysicalSize
= 0;
947 forkPhysicalSizePtr
= &forkPhysicalSize
;
951 forkPhysicalSizePtr
= NULL
;
954 /* zero fork count if returning it */
955 if ( NULL
!= forkCount
)
960 /* Iterate through the forks to get the sizes */
961 forkIterator
.initialize
= 0;
964 result
= FSIterateForks(ref
, &forkIterator
, NULL
, forkSizePtr
, forkPhysicalSizePtr
);
965 if ( noErr
== result
)
967 if ( NULL
!= totalLogicalSize
)
969 *totalLogicalSize
+= forkSize
;
972 if ( NULL
!= totalPhysicalSize
)
974 *totalPhysicalSize
+= forkPhysicalSize
;
977 if ( NULL
!= forkCount
)
982 } while ( noErr
== result
);
984 /* any error result other than errFSNoMoreItems is serious */
985 require(errFSNoMoreItems
== result
, FSIterateForks
);
995 /*****************************************************************************/
1002 FSCatalogInfo catalogInfo
;
1003 UTCDateTime oldDateTime
;
1004 #if !BuildingMoreFilesXForMacOS9
1006 Boolean notifyParent
;
1009 #if !BuildingMoreFilesXForMacOS9
1010 /* Get the node flags, the content modification date and time, and the parent ref */
1011 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags
+ kFSCatInfoContentMod
, &catalogInfo
, NULL
, NULL
, &parentRef
);
1012 require_noerr(result
, FSGetCatalogInfo
);
1014 /* Notify the parent if this is a file */
1015 notifyParent
= (0 == (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
));
1017 /* Get the content modification date and time */
1018 result
= FSGetCatalogInfo(ref
, kFSCatInfoContentMod
, &catalogInfo
, NULL
, NULL
, NULL
);
1019 require_noerr(result
, FSGetCatalogInfo
);
1022 oldDateTime
= catalogInfo
.contentModDate
;
1024 /* Get the current date and time */
1025 result
= GetUTCDateTime(&catalogInfo
.contentModDate
, kUTCDefaultOptions
);
1026 require_noerr(result
, GetUTCDateTime
);
1028 /* if the old date and time is the the same as the current, bump the seconds by one */
1029 if ( (catalogInfo
.contentModDate
.fraction
== oldDateTime
.fraction
) &&
1030 (catalogInfo
.contentModDate
.lowSeconds
== oldDateTime
.lowSeconds
) &&
1031 (catalogInfo
.contentModDate
.highSeconds
== oldDateTime
.highSeconds
) )
1033 ++catalogInfo
.contentModDate
.lowSeconds
;
1034 if ( 0 == catalogInfo
.contentModDate
.lowSeconds
)
1036 ++catalogInfo
.contentModDate
.highSeconds
;
1040 /* Bump the content modification date and time */
1041 result
= FSSetCatalogInfo(ref
, kFSCatInfoContentMod
, &catalogInfo
);
1042 require_noerr(result
, FSSetCatalogInfo
);
1044 #if !BuildingMoreFilesXForMacOS9
1046 * The problem with FNNotify is that it is not available under Mac OS 9
1047 * and there's no way to test for that except for looking for the symbol
1048 * or something. So, I'll just conditionalize this for those who care
1049 * to send a notification.
1052 /* Send a notification for the parent of the file, or for the directory */
1053 result
= FNNotify(notifyParent
? &parentRef
: ref
, kFNDirectoryModifiedMessage
, kNilOptions
);
1054 require_noerr(result
, FNNotify
);
1057 /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */
1063 /**********************/
1071 /*****************************************************************************/
1076 FinderInfo
*info
, /* can be NULL */
1077 ExtendedFinderInfo
*extendedInfo
, /* can be NULL */
1078 Boolean
*isDirectory
) /* can be NULL */
1081 FSCatalogInfo catalogInfo
;
1082 FSCatalogInfoBitmap whichInfo
;
1084 /* determine what catalog information is really needed */
1085 whichInfo
= kFSCatInfoNone
;
1089 /* get FinderInfo */
1090 whichInfo
|= kFSCatInfoFinderInfo
;
1093 if ( NULL
!= extendedInfo
)
1095 /* get ExtendedFinderInfo */
1096 whichInfo
|= kFSCatInfoFinderXInfo
;
1099 if ( NULL
!= isDirectory
)
1101 whichInfo
|= kFSCatInfoNodeFlags
;
1104 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
1105 require_noerr(result
, FSGetCatalogInfo
);
1107 /* return FinderInfo if requested */
1110 BlockMoveData(catalogInfo
.finderInfo
, info
, sizeof(FinderInfo
));
1113 /* return ExtendedFinderInfo if requested */
1114 if ( NULL
!= extendedInfo
)
1116 BlockMoveData(catalogInfo
.extFinderInfo
, extendedInfo
, sizeof(ExtendedFinderInfo
));
1119 /* set isDirectory Boolean if requested */
1120 if ( NULL
!= isDirectory
)
1122 *isDirectory
= (0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
));
1130 /*****************************************************************************/
1135 const FinderInfo
*info
,
1136 const ExtendedFinderInfo
*extendedInfo
)
1139 FSCatalogInfo catalogInfo
;
1140 FSCatalogInfoBitmap whichInfo
;
1142 /* determine what catalog information will be set */
1143 whichInfo
= kFSCatInfoNone
; /* start with none */
1146 /* set FinderInfo */
1147 whichInfo
|= kFSCatInfoFinderInfo
;
1148 BlockMoveData(info
, catalogInfo
.finderInfo
, sizeof(FinderInfo
));
1150 if ( NULL
!= extendedInfo
)
1152 /* set ExtendedFinderInfo */
1153 whichInfo
|= kFSCatInfoFinderXInfo
;
1154 BlockMoveData(extendedInfo
, catalogInfo
.extFinderInfo
, sizeof(ExtendedFinderInfo
));
1157 result
= FSSetCatalogInfo(ref
, whichInfo
, &catalogInfo
);
1158 require_noerr(result
, FSGetCatalogInfo
);
1165 /*****************************************************************************/
1168 FSChangeCreatorType(
1174 FSCatalogInfo catalogInfo
;
1177 /* get nodeFlags, finder info, and parent FSRef */
1178 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags
+ kFSCatInfoFinderInfo
, &catalogInfo
, NULL
, NULL
, &parentRef
);
1179 require_noerr(result
, FSGetCatalogInfo
);
1181 /* make sure FSRef was to a file */
1182 require_action(0 == (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
), FSRefNotFile
, result
= notAFileErr
);
1184 /* If fileType not 0x00000000, change fileType */
1185 if ( fileType
!= (OSType
)0x00000000 )
1187 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
= fileType
;
1190 /* If creator not 0x00000000, change creator */
1191 if ( fileCreator
!= (OSType
)0x00000000 )
1193 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
= fileCreator
;
1196 /* now, save the new information back to disk */
1197 result
= FSSetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
);
1198 require_noerr(result
, FSSetCatalogInfo
);
1200 /* and attempt to bump the parent directory's mod date to wake up */
1201 /* the Finder to the change we just made (ignore errors from this) */
1202 verify_noerr(FSBumpDate(&parentRef
));
1211 /*****************************************************************************/
1214 FSChangeFinderFlags(
1220 FSCatalogInfo catalogInfo
;
1223 /* get the current finderInfo */
1224 result
= FSGetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
, NULL
, NULL
, &parentRef
);
1225 require_noerr(result
, FSGetCatalogInfo
);
1227 /* set or clear the appropriate bits in the finderInfo.finderFlags */
1230 /* OR in the bits */
1231 ((FileInfo
*)&catalogInfo
.finderInfo
)->finderFlags
|= flagBits
;
1235 /* AND out the bits */
1236 ((FileInfo
*)&catalogInfo
.finderInfo
)->finderFlags
&= ~flagBits
;
1239 /* save the modified finderInfo */
1240 result
= FSSetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
);
1241 require_noerr(result
, FSSetCatalogInfo
);
1243 /* and attempt to bump the parent directory's mod date to wake up the Finder */
1244 /* to the change we just made (ignore errors from this) */
1245 verify_noerr(FSBumpDate(&parentRef
));
1253 /*****************************************************************************/
1259 return ( FSChangeFinderFlags(ref
, true, kIsInvisible
) );
1266 return ( FSChangeFinderFlags(ref
, false, kIsInvisible
) );
1269 /*****************************************************************************/
1275 return ( FSChangeFinderFlags(ref
, true, kNameLocked
) );
1282 return ( FSChangeFinderFlags(ref
, false, kNameLocked
) );
1285 /*****************************************************************************/
1291 return ( FSChangeFinderFlags(ref
, true, kIsStationery
) );
1295 FSClearIsStationery(
1298 return ( FSChangeFinderFlags(ref
, false, kIsStationery
) );
1301 /*****************************************************************************/
1307 return ( FSChangeFinderFlags(ref
, true, kHasCustomIcon
) );
1311 FSClearHasCustomIcon(
1314 return ( FSChangeFinderFlags(ref
, false, kHasCustomIcon
) );
1317 /*****************************************************************************/
1320 FSClearHasBeenInited(
1323 return ( FSChangeFinderFlags(ref
, false, kHasBeenInited
) );
1326 /*****************************************************************************/
1329 FSCopyFileMgrAttributes(
1330 const FSRef
*sourceRef
,
1331 const FSRef
*destinationRef
,
1332 Boolean copyLockBit
)
1335 FSCatalogInfo catalogInfo
;
1337 /* get the source information */
1338 result
= FSGetCatalogInfo(sourceRef
, kFSCatInfoSettableInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
1339 require_noerr(result
, FSGetCatalogInfo
);
1341 /* don't copy the hasBeenInited bit; clear it */
1342 ((FileInfo
*)&catalogInfo
.finderInfo
)->finderFlags
&= ~kHasBeenInited
;
1344 /* should the locked bit be copied? */
1347 /* no, make sure the locked bit is clear */
1348 catalogInfo
.nodeFlags
&= ~kFSNodeLockedMask
;
1351 /* set the destination information */
1352 result
= FSSetCatalogInfo(destinationRef
, kFSCatInfoSettableInfo
, &catalogInfo
);
1353 require_noerr(result
, FSSetCatalogInfo
);
1361 /*****************************************************************************/
1364 FSMoveRenameObjectUnicode(
1366 const FSRef
*destDirectory
,
1367 UniCharCount nameLength
,
1368 const UniChar
*name
, /* can be NULL (no rename during move) */
1369 TextEncoding textEncodingHint
,
1370 FSRef
*newRef
) /* if function fails along the way, newRef is final location of file */
1373 FSVolumeRefNum vRefNum
;
1374 FSCatalogInfo catalogInfo
;
1375 FSRef originalDirectory
;
1376 TextEncoding originalTextEncodingHint
;
1377 HFSUniStr255 originalName
;
1378 HFSUniStr255 uniqueName
; /* unique name given to object while moving it to destination */
1379 long theSeed
; /* the seed for generating unique names */
1381 /* check parameters */
1382 require_action(NULL
!= newRef
, BadParameter
, result
= paramErr
);
1384 /* newRef = input to start with */
1385 BlockMoveData(ref
, newRef
, sizeof(FSRef
));
1387 /* get destDirectory's vRefNum */
1388 result
= FSGetCatalogInfo(destDirectory
, kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
, NULL
);
1389 require_noerr(result
, DestinationBad
);
1392 vRefNum
= catalogInfo
.volume
;
1394 /* get ref's vRefNum, TextEncoding, name and parent directory*/
1395 result
= FSGetCatalogInfo(ref
, kFSCatInfoTextEncoding
+ kFSCatInfoVolume
, &catalogInfo
, &originalName
, NULL
, &originalDirectory
);
1396 require_noerr(result
, SourceBad
);
1398 /* save TextEncoding */
1399 originalTextEncodingHint
= catalogInfo
.textEncodingHint
;
1401 /* make sure ref and destDirectory are on same volume */
1402 require_action(vRefNum
== catalogInfo
.volume
, NotSameVolume
, result
= diffVolErr
);
1404 /* Skip a few steps if we're not renaming */
1407 /* generate a name that is unique in both directories */
1408 theSeed
= 0x4a696d4c; /* a fine unlikely filename */
1410 result
= GenerateUniqueHFSUniStr(&theSeed
, &originalDirectory
, destDirectory
, &uniqueName
);
1411 require_noerr(result
, GenerateUniqueHFSUniStrFailed
);
1413 /* Rename the object to uniqueName */
1414 result
= FSRenameUnicode(ref
, uniqueName
.length
, uniqueName
.unicode
, kTextEncodingUnknown
, newRef
);
1415 require_noerr(result
, FSRenameUnicodeBeforeMoveFailed
);
1417 /* Move object to its new home */
1418 result
= FSMoveObject(newRef
, destDirectory
, newRef
);
1419 require_noerr(result
, FSMoveObjectAfterRenameFailed
);
1421 /* Rename the object to new name */
1422 result
= FSRenameUnicode(ref
, nameLength
, name
, textEncodingHint
, newRef
);
1423 require_noerr(result
, FSRenameUnicodeAfterMoveFailed
);
1427 /* Move object to its new home */
1428 result
= FSMoveObject(newRef
, destDirectory
, newRef
);
1429 require_noerr(result
, FSMoveObjectNoRenameFailed
);
1437 * failure handling code when renaming
1440 FSRenameUnicodeAfterMoveFailed
:
1442 /* Error handling: move object back to original location - ignore errors */
1443 verify_noerr(FSMoveObject(newRef
, &originalDirectory
, newRef
));
1445 FSMoveObjectAfterRenameFailed
:
1447 /* Error handling: rename object back to original name - ignore errors */
1448 verify_noerr(FSRenameUnicode(newRef
, originalName
.length
, originalName
.unicode
, originalTextEncodingHint
, newRef
));
1450 FSRenameUnicodeBeforeMoveFailed
:
1451 GenerateUniqueHFSUniStrFailed
:
1454 * failure handling code for renaming or not
1456 FSMoveObjectNoRenameFailed
:
1465 /*****************************************************************************/
1468 The FSDeleteContainerLevel function deletes the contents of a container
1469 directory. All files and subdirectories in the specified container are
1470 deleted. If a locked file or directory is encountered, it is unlocked
1471 and then deleted. If any unexpected errors are encountered,
1472 FSDeleteContainerLevel quits and returns to the caller.
1474 container --> FSRef to a directory.
1475 theGlobals --> A pointer to a FSDeleteContainerGlobals struct
1476 which contains the variables that do not need to
1477 be allocated each time FSDeleteContainerLevel
1478 recurses. That lets FSDeleteContainerLevel use
1479 less stack space per recursion level.
1484 FSDeleteContainerLevel(
1485 const FSRef
*container
,
1486 FSDeleteContainerGlobals
*theGlobals
)
1489 FSIterator iterator
;
1493 /* Open FSIterator for flat access and give delete optimization hint */
1494 theGlobals
->result
= FSOpenIterator(container
, kFSIterateFlat
+ kFSIterateDelete
, &iterator
);
1495 require_noerr(theGlobals
->result
, FSOpenIterator
);
1497 /* delete the contents of the directory */
1500 /* get 1 item to delete */
1501 theGlobals
->result
= FSGetCatalogInfoBulk(iterator
, 1, &theGlobals
->actualObjects
,
1502 NULL
, kFSCatInfoNodeFlags
, &theGlobals
->catalogInfo
,
1503 &itemToDelete
, NULL
, NULL
);
1504 if ( (noErr
== theGlobals
->result
) && (1 == theGlobals
->actualObjects
) )
1506 /* save node flags in local in case we have to recurse */
1507 nodeFlags
= theGlobals
->catalogInfo
.nodeFlags
;
1509 /* is it a file or directory? */
1510 if ( 0 != (nodeFlags
& kFSNodeIsDirectoryMask
) )
1512 /* it's a directory -- delete its contents before attempting to delete it */
1513 FSDeleteContainerLevel(&itemToDelete
, theGlobals
);
1515 /* are we still OK to delete? */
1516 if ( noErr
== theGlobals
->result
)
1518 /* is item locked? */
1519 if ( 0 != (nodeFlags
& kFSNodeLockedMask
) )
1521 /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
1522 theGlobals
->catalogInfo
.nodeFlags
= nodeFlags
& ~kFSNodeLockedMask
;
1523 (void) FSSetCatalogInfo(&itemToDelete
, kFSCatInfoNodeFlags
, &theGlobals
->catalogInfo
);
1525 /* delete the item */
1526 theGlobals
->result
= FSDeleteObject(&itemToDelete
);
1529 } while ( noErr
== theGlobals
->result
);
1531 /* we found the end of the items normally, so return noErr */
1532 if ( errFSNoMoreItems
== theGlobals
->result
)
1534 theGlobals
->result
= noErr
;
1537 /* close the FSIterator (closing an open iterator should never fail) */
1538 verify_noerr(FSCloseIterator(iterator
));
1545 /*****************************************************************************/
1548 FSDeleteContainerContents(
1549 const FSRef
*container
)
1551 FSDeleteContainerGlobals theGlobals
;
1553 /* delete container's contents */
1554 FSDeleteContainerLevel(container
, &theGlobals
);
1556 return ( theGlobals
.result
);
1559 /*****************************************************************************/
1563 const FSRef
*container
)
1566 FSCatalogInfo catalogInfo
;
1568 /* get nodeFlags for container */
1569 result
= FSGetCatalogInfo(container
, kFSCatInfoNodeFlags
, &catalogInfo
, NULL
, NULL
,NULL
);
1570 require_noerr(result
, FSGetCatalogInfo
);
1572 /* make sure container is a directory */
1573 require_action(0 != (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
), ContainerNotDirectory
, result
= dirNFErr
);
1575 /* delete container's contents */
1576 result
= FSDeleteContainerContents(container
);
1577 require_noerr(result
, FSDeleteContainerContents
);
1579 /* is container locked? */
1580 if ( 0 != (catalogInfo
.nodeFlags
& kFSNodeLockedMask
) )
1582 /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
1583 catalogInfo
.nodeFlags
&= ~kFSNodeLockedMask
;
1584 (void) FSSetCatalogInfo(container
, kFSCatInfoNodeFlags
, &catalogInfo
);
1587 /* delete the container */
1588 result
= FSDeleteObject(container
);
1590 FSDeleteContainerContents
:
1591 ContainerNotDirectory
:
1597 /*****************************************************************************/
1600 The FSIterateContainerLevel function iterates the contents of a container
1601 directory and calls a IterateContainerFilterProc function once for each
1602 file and directory found.
1604 theGlobals --> A pointer to a FSIterateContainerGlobals struct
1605 which contains the variables needed globally by
1606 all recusion levels of FSIterateContainerLevel.
1607 That makes FSIterateContainer thread safe since
1608 each call to it uses its own global world.
1609 It also contains the variables that do not need
1610 to be allocated each time FSIterateContainerLevel
1611 recurses. That lets FSIterateContainerLevel use
1612 less stack space per recursion level.
1617 FSIterateContainerLevel(
1618 FSIterateContainerGlobals
*theGlobals
)
1620 FSIterator iterator
;
1622 /* If maxLevels is zero, we aren't checking levels */
1623 /* If currentLevel < maxLevels, look at this level */
1624 if ( (theGlobals
->maxLevels
== 0) ||
1625 (theGlobals
->currentLevel
< theGlobals
->maxLevels
) )
1627 /* Open FSIterator for flat access to theGlobals->ref */
1628 theGlobals
->result
= FSOpenIterator(&theGlobals
->ref
, kFSIterateFlat
, &iterator
);
1629 require_noerr(theGlobals
->result
, FSOpenIterator
);
1631 ++theGlobals
->currentLevel
; /* Go to next level */
1633 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1636 theGlobals
->result
= FSGetCatalogInfoBulk(iterator
, 1, &theGlobals
->actualObjects
,
1637 &theGlobals
->containerChanged
, theGlobals
->whichInfo
, &theGlobals
->catalogInfo
,
1638 &theGlobals
->ref
, theGlobals
->specPtr
, theGlobals
->namePtr
);
1639 if ( (noErr
== theGlobals
->result
|| errFSNoMoreItems
== theGlobals
->result
) &&
1640 (0 != theGlobals
->actualObjects
) )
1642 /* Call the IterateFilterProc */
1643 theGlobals
->quitFlag
= CallIterateContainerFilterProc(theGlobals
->iterateFilter
,
1644 theGlobals
->containerChanged
, theGlobals
->currentLevel
,
1645 &theGlobals
->catalogInfo
, &theGlobals
->ref
,
1646 theGlobals
->specPtr
, theGlobals
->namePtr
, theGlobals
->yourDataPtr
);
1647 /* Is it a directory? */
1648 if ( 0 != (theGlobals
->catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
) )
1651 if ( !theGlobals
->quitFlag
)
1653 /* Dive again if the IterateFilterProc didn't say "quit" */
1654 FSIterateContainerLevel(theGlobals
);
1658 /* time to fall back a level? */
1659 } while ( (noErr
== theGlobals
->result
) && (!theGlobals
->quitFlag
) );
1661 /* errFSNoMoreItems is OK - it only means we hit the end of this level */
1662 /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
1663 if ( (errFSNoMoreItems
== theGlobals
->result
) ||
1664 (afpAccessDenied
== theGlobals
->result
) )
1666 theGlobals
->result
= noErr
;
1669 --theGlobals
->currentLevel
; /* Return to previous level as we leave */
1671 /* Close the FSIterator (closing an open iterator should never fail) */
1672 verify_noerr(FSCloseIterator(iterator
));
1680 /*****************************************************************************/
1684 const FSRef
*container
,
1685 ItemCount maxLevels
,
1686 FSCatalogInfoBitmap whichInfo
,
1689 IterateContainerFilterProcPtr iterateFilter
,
1693 FSIterateContainerGlobals theGlobals
;
1695 /* make sure there is an iterateFilter */
1696 require_action(iterateFilter
!= NULL
, NoIterateFilter
, result
= paramErr
);
1699 * set up the globals we need to access from the recursive routine
1701 theGlobals
.iterateFilter
= iterateFilter
;
1702 /* we need the node flags no matter what was requested so we can detect files vs. directories */
1703 theGlobals
.whichInfo
= whichInfo
| kFSCatInfoNodeFlags
;
1704 /* start with input container -- the first OpenIterator will ensure it is a directory */
1705 theGlobals
.ref
= *container
;
1708 theGlobals
.specPtr
= &theGlobals
.spec
;
1712 theGlobals
.specPtr
= NULL
;
1716 theGlobals
.namePtr
= &theGlobals
.name
;
1720 theGlobals
.namePtr
= NULL
;
1722 theGlobals
.yourDataPtr
= yourDataPtr
;
1723 theGlobals
.maxLevels
= maxLevels
;
1724 theGlobals
.currentLevel
= 0;
1725 theGlobals
.quitFlag
= false;
1726 theGlobals
.containerChanged
= false;
1727 theGlobals
.result
= noErr
;
1728 theGlobals
.actualObjects
= 0;
1730 /* here we go into recursion land... */
1731 FSIterateContainerLevel(&theGlobals
);
1732 result
= theGlobals
.result
;
1733 require_noerr(result
, FSIterateContainerLevel
);
1735 FSIterateContainerLevel
:
1741 /*****************************************************************************/
1744 FSGetDirectoryItems(
1745 const FSRef
*container
,
1746 FSRef
***refsHandle
, /* pointer to handle of FSRefs */
1748 Boolean
*containerChanged
)
1750 /* Grab items 10 at a time. */
1751 enum { kMaxItemsPerBulkCall
= 10 };
1755 FSIterator iterator
;
1756 FSRef refs
[kMaxItemsPerBulkCall
];
1757 ItemCount actualObjects
;
1760 /* check parameters */
1761 require_action((NULL
!= refsHandle
) && (NULL
!= numRefs
) && (NULL
!= containerChanged
),
1762 BadParameter
, result
= paramErr
);
1765 *containerChanged
= false;
1766 *refsHandle
= (FSRef
**)NewHandle(0);
1767 require_action(NULL
!= *refsHandle
, NewHandle
, result
= memFullErr
);
1769 /* open an FSIterator */
1770 result
= FSOpenIterator(container
, kFSIterateFlat
, &iterator
);
1771 require_noerr(result
, FSOpenIterator
);
1773 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1776 result
= FSGetCatalogInfoBulk(iterator
, kMaxItemsPerBulkCall
, &actualObjects
,
1777 &changed
, kFSCatInfoNone
, NULL
, refs
, NULL
, NULL
);
1779 /* if the container changed, set containerChanged for output, but keep going */
1782 *containerChanged
= changed
;
1785 /* any result other than noErr and errFSNoMoreItems is serious */
1786 require((noErr
== result
) || (errFSNoMoreItems
== result
), FSGetCatalogInfoBulk
);
1788 /* add objects to output array and count */
1789 if ( 0 != actualObjects
)
1791 /* concatenate the FSRefs to the end of the handle */
1792 PtrAndHand(refs
, (Handle
)*refsHandle
, actualObjects
* sizeof(FSRef
));
1793 memResult
= MemError();
1794 require_noerr_action(memResult
, MemoryAllocationFailed
, result
= memResult
);
1796 *numRefs
+= actualObjects
;
1798 } while ( noErr
== result
);
1800 verify_noerr(FSCloseIterator(iterator
)); /* closing an open iterator should never fail, but... */
1804 /**********************/
1806 MemoryAllocationFailed
:
1807 FSGetCatalogInfoBulk
:
1809 /* close the iterator */
1810 verify_noerr(FSCloseIterator(iterator
));
1813 /* dispose of handle if already allocated and clear the outputs */
1814 if ( NULL
!= *refsHandle
)
1816 DisposeHandle((Handle
)*refsHandle
);
1827 /*****************************************************************************/
1830 The GenerateUniqueName function generates a HFSUniStr255 name that is
1831 unique in both dir1 and dir2.
1833 startSeed --> A pointer to a long which is used to generate the
1835 <-- It is modified on output to a value which should
1836 be used to generate the next unique name.
1837 dir1 --> The first directory.
1838 dir2 --> The second directory.
1839 uniqueName <-- A pointer to a HFSUniStr255 where the unique name
1845 GenerateUniqueHFSUniStr(
1849 HFSUniStr255
*uniqueName
)
1855 unsigned char hexStr
[17] = "0123456789ABCDEF";
1857 /* set up the parameter block */
1858 pb
.name
= uniqueName
->unicode
;
1859 pb
.nameLength
= 8; /* always 8 characters */
1860 pb
.textEncodingHint
= kTextEncodingUnknown
;
1861 pb
.newRef
= &newRef
;
1863 /* loop until we get fnfErr with a filename in both directories */
1865 while ( fnfErr
!= result
)
1867 /* convert startSeed to 8 character Unicode string */
1868 uniqueName
->length
= 8;
1869 for ( i
= 0; i
< 8; ++i
)
1871 uniqueName
->unicode
[i
] = hexStr
[((*startSeed
>> ((7-i
)*4)) & 0xf)];
1876 result
= PBMakeFSRefUnicodeSync(&pb
);
1877 if ( fnfErr
== result
)
1881 result
= PBMakeFSRefUnicodeSync(&pb
);
1882 if ( fnfErr
!= result
)
1884 /* exit if anything other than noErr or fnfErr */
1885 require_noerr(result
, Dir2PBMakeFSRefUnicodeSyncFailed
);
1890 /* exit if anything other than noErr or fnfErr */
1891 require_noerr(result
, Dir1PBMakeFSRefUnicodeSyncFailed
);
1894 /* increment seed for next pass through loop, */
1895 /* or for next call to GenerateUniqueHFSUniStr */
1899 /* we have a unique file name which doesn't exist in dir1 or dir2 */
1902 Dir2PBMakeFSRefUnicodeSyncFailed
:
1903 Dir1PBMakeFSRefUnicodeSyncFailed
:
1908 /*****************************************************************************/
1911 FSExchangeObjectsCompat(
1912 const FSRef
*sourceRef
,
1913 const FSRef
*destRef
,
1914 FSRef
*newSourceRef
,
1919 /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
1920 kGetCatInformationMask
= (kFSCatInfoSettableInfo
|
1922 kFSCatInfoParentDirID
) &
1923 ~(kFSCatInfoContentMod
| kFSCatInfoAttrMod
),
1924 /* set everything possible except for mod dates */
1925 kSetCatinformationMask
= kFSCatInfoSettableInfo
&
1926 ~(kFSCatInfoContentMod
| kFSCatInfoAttrMod
)
1930 GetVolParmsInfoBuffer volParmsInfo
;
1932 FSCatalogInfo sourceCatalogInfo
; /* source file's catalog information */
1933 FSCatalogInfo destCatalogInfo
; /* destination file's catalog information */
1934 HFSUniStr255 sourceName
; /* source file's Unicode name */
1935 HFSUniStr255 destName
; /* destination file's Unicode name */
1936 FSRef sourceCurrentRef
; /* FSRef to current location of source file throughout this function */
1937 FSRef destCurrentRef
; /* FSRef to current location of destination file throughout this function */
1938 FSRef sourceParentRef
; /* FSRef to parent directory of source file */
1939 FSRef destParentRef
; /* FSRef to parent directory of destination file */
1940 HFSUniStr255 sourceUniqueName
; /* unique name given to source file while exchanging it with destination */
1941 HFSUniStr255 destUniqueName
; /* unique name given to destination file while exchanging it with source */
1942 long theSeed
; /* the seed for generating unique names */
1943 Boolean sameParentDirs
; /* true if source and destinatin parent directory is the same */
1945 /* check parameters */
1946 require_action((NULL
!= newSourceRef
) && (NULL
!= newDestRef
), BadParameter
, result
= paramErr
);
1948 /* output refs and current refs = input refs to start with */
1949 BlockMoveData(sourceRef
, newSourceRef
, sizeof(FSRef
));
1950 BlockMoveData(sourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
1952 BlockMoveData(destRef
, newDestRef
, sizeof(FSRef
));
1953 BlockMoveData(destRef
, &destCurrentRef
, sizeof(FSRef
));
1955 /* get source volume's vRefNum */
1956 result
= FSGetCatalogInfo(&sourceCurrentRef
, kFSCatInfoVolume
, &sourceCatalogInfo
, NULL
, NULL
, NULL
);
1957 require_noerr(result
, DetermineSourceVRefNumFailed
);
1959 /* see if that volume supports FSExchangeObjects */
1960 result
= FSGetVolParms(sourceCatalogInfo
.volume
, sizeof(GetVolParmsInfoBuffer
),
1961 &volParmsInfo
, &infoSize
);
1962 if ( (noErr
== result
) && VolSupportsFSExchangeObjects(&volParmsInfo
) )
1964 /* yes - use FSExchangeObjects */
1965 result
= FSExchangeObjects(sourceRef
, destRef
);
1969 /* no - emulate FSExchangeObjects */
1971 /* Note: The compatibility case won't work for files with *Btree control blocks. */
1972 /* Right now the only *Btree files are created by the system. */
1974 /* get all catalog information and Unicode names for each file */
1975 result
= FSGetCatalogInfo(&sourceCurrentRef
, kGetCatInformationMask
, &sourceCatalogInfo
, &sourceName
, NULL
, &sourceParentRef
);
1976 require_noerr(result
, SourceFSGetCatalogInfoFailed
);
1978 result
= FSGetCatalogInfo(&destCurrentRef
, kGetCatInformationMask
, &destCatalogInfo
, &destName
, NULL
, &destParentRef
);
1979 require_noerr(result
, DestFSGetCatalogInfoFailed
);
1981 /* make sure source and destination are on same volume */
1982 require_action(sourceCatalogInfo
.volume
== destCatalogInfo
.volume
, NotSameVolume
, result
= diffVolErr
);
1984 /* make sure both files are *really* files */
1985 require_action((0 == (sourceCatalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
)) &&
1986 (0 == (destCatalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
)), NotAFile
, result
= notAFileErr
);
1988 /* generate 2 names that are unique in both directories */
1989 theSeed
= 0x4a696d4c; /* a fine unlikely filename */
1991 result
= GenerateUniqueHFSUniStr(&theSeed
, &sourceParentRef
, &destParentRef
, &sourceUniqueName
);
1992 require_noerr(result
, GenerateUniqueHFSUniStr1Failed
);
1994 result
= GenerateUniqueHFSUniStr(&theSeed
, &sourceParentRef
, &destParentRef
, &destUniqueName
);
1995 require_noerr(result
, GenerateUniqueHFSUniStr2Failed
);
1997 /* rename sourceCurrentRef to sourceUniqueName */
1998 result
= FSRenameUnicode(&sourceCurrentRef
, sourceUniqueName
.length
, sourceUniqueName
.unicode
, kTextEncodingUnknown
, newSourceRef
);
1999 require_noerr(result
, FSRenameUnicode1Failed
);
2000 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2002 /* rename destCurrentRef to destUniqueName */
2003 result
= FSRenameUnicode(&destCurrentRef
, destUniqueName
.length
, destUniqueName
.unicode
, kTextEncodingUnknown
, newDestRef
);
2004 require_noerr(result
, FSRenameUnicode2Failed
);
2005 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
));
2007 /* are the source and destination parent directories the same? */
2008 sameParentDirs
= ( sourceCatalogInfo
.parentDirID
== destCatalogInfo
.parentDirID
);
2009 if ( !sameParentDirs
)
2011 /* move source file to dest parent directory */
2012 result
= FSMoveObject(&sourceCurrentRef
, &destParentRef
, newSourceRef
);
2013 require_noerr(result
, FSMoveObject1Failed
);
2014 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2016 /* move dest file to source parent directory */
2017 result
= FSMoveObject(&destCurrentRef
, &sourceParentRef
, newDestRef
);
2018 require_noerr(result
, FSMoveObject2Failed
);
2019 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
));
2022 /* At this point, the files are in their new locations (if they were moved). */
2023 /* The source file is named sourceUniqueName and is in the directory referred to */
2024 /* by destParentRef. The destination file is named destUniqueName and is in the */
2025 /* directory referred to by sourceParentRef. */
2027 /* give source file the dest file's catalog information except for mod dates */
2028 result
= FSSetCatalogInfo(&sourceCurrentRef
, kSetCatinformationMask
, &destCatalogInfo
);
2029 require_noerr(result
, FSSetCatalogInfo1Failed
);
2031 /* give dest file the source file's catalog information except for mod dates */
2032 result
= FSSetCatalogInfo(&destCurrentRef
, kSetCatinformationMask
, &sourceCatalogInfo
);
2033 require_noerr(result
, FSSetCatalogInfo2Failed
);
2035 /* rename source file with dest file's name */
2036 result
= FSRenameUnicode(&sourceCurrentRef
, destName
.length
, destName
.unicode
, destCatalogInfo
.textEncodingHint
, newSourceRef
);
2037 require_noerr(result
, FSRenameUnicode3Failed
);
2038 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2040 /* rename dest file with source file's name */
2041 result
= FSRenameUnicode(&destCurrentRef
, sourceName
.length
, sourceName
.unicode
, sourceCatalogInfo
.textEncodingHint
, newDestRef
);
2042 require_noerr(result
, FSRenameUnicode4Failed
);
2044 /* we're done with no errors, so swap newSourceRef and newDestRef */
2045 BlockMoveData(newDestRef
, newSourceRef
, sizeof(FSRef
));
2046 BlockMoveData(&sourceCurrentRef
, newDestRef
, sizeof(FSRef
));
2051 /**********************/
2053 /* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
2054 /* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
2055 /* state and location they ended up in so that both files can be found by the calling code. */
2057 FSRenameUnicode4Failed
:
2059 /* attempt to rename source file to sourceUniqueName */
2060 if ( noErr
== FSRenameUnicode(&sourceCurrentRef
, sourceUniqueName
.length
, sourceUniqueName
.unicode
, kTextEncodingUnknown
, newSourceRef
) )
2062 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2065 FSRenameUnicode3Failed
:
2067 /* attempt to restore dest file's catalog information */
2068 verify_noerr(FSSetCatalogInfo(&destCurrentRef
, kFSCatInfoSettableInfo
, &destCatalogInfo
));
2070 FSSetCatalogInfo2Failed
:
2072 /* attempt to restore source file's catalog information */
2073 verify_noerr(FSSetCatalogInfo(&sourceCurrentRef
, kFSCatInfoSettableInfo
, &sourceCatalogInfo
));
2075 FSSetCatalogInfo1Failed
:
2077 if ( !sameParentDirs
)
2079 /* attempt to move dest file back to dest directory */
2080 if ( noErr
== FSMoveObject(&destCurrentRef
, &destParentRef
, newDestRef
) )
2082 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
));
2086 FSMoveObject2Failed
:
2088 if ( !sameParentDirs
)
2090 /* attempt to move source file back to source directory */
2091 if ( noErr
== FSMoveObject(&sourceCurrentRef
, &sourceParentRef
, newSourceRef
) )
2093 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2097 FSMoveObject1Failed
:
2099 /* attempt to rename dest file to original name */
2100 verify_noerr(FSRenameUnicode(&destCurrentRef
, destName
.length
, destName
.unicode
, destCatalogInfo
.textEncodingHint
, newDestRef
));
2102 FSRenameUnicode2Failed
:
2104 /* attempt to rename source file to original name */
2105 verify_noerr(FSRenameUnicode(&sourceCurrentRef
, sourceName
.length
, sourceName
.unicode
, sourceCatalogInfo
.textEncodingHint
, newSourceRef
));
2107 FSRenameUnicode1Failed
:
2108 GenerateUniqueHFSUniStr2Failed
:
2109 GenerateUniqueHFSUniStr1Failed
:
2112 DestFSGetCatalogInfoFailed
:
2113 SourceFSGetCatalogInfoFailed
:
2114 DetermineSourceVRefNumFailed
:
2120 /*****************************************************************************/
2122 #pragma mark ----- Shared Environment Routines -----
2124 /*****************************************************************************/
2135 pb
.ioParam
.ioRefNum
= refNum
;
2136 pb
.ioParam
.ioReqCount
= rangeLength
;
2137 pb
.ioParam
.ioPosMode
= fsFromStart
;
2138 pb
.ioParam
.ioPosOffset
= rangeStart
;
2139 result
= PBLockRangeSync(&pb
);
2140 require_noerr(result
, PBLockRangeSync
);
2147 /*****************************************************************************/
2158 pb
.ioParam
.ioRefNum
= refNum
;
2159 pb
.ioParam
.ioReqCount
= rangeLength
;
2160 pb
.ioParam
.ioPosMode
= fsFromStart
;
2161 pb
.ioParam
.ioPosOffset
= rangeStart
;
2162 result
= PBUnlockRangeSync(&pb
);
2163 require_noerr(result
, PBUnlockRangeSync
);
2170 /*****************************************************************************/
2175 SInt32
*ownerID
, /* can be NULL */
2176 SInt32
*groupID
, /* can be NULL */
2177 SInt32
*accessRights
) /* can be NULL */
2183 /* get FSSpec from FSRef */
2184 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
);
2185 require_noerr(result
, FSGetCatalogInfo
);
2187 /* get directory access info for FSSpec */
2188 pb
.accessParam
.ioNamePtr
= (StringPtr
)spec
.name
;
2189 pb
.accessParam
.ioVRefNum
= spec
.vRefNum
;
2190 pb
.fileParam
.ioDirID
= spec
.parID
;
2191 result
= PBHGetDirAccessSync(&pb
);
2192 require_noerr(result
, PBHGetDirAccessSync
);
2194 /* return the IDs and access rights */
2195 if ( NULL
!= ownerID
)
2197 *ownerID
= pb
.accessParam
.ioACOwnerID
;
2199 if ( NULL
!= groupID
)
2201 *groupID
= pb
.accessParam
.ioACGroupID
;
2203 if ( NULL
!= accessRights
)
2205 *accessRights
= pb
.accessParam
.ioACAccess
;
2208 PBHGetDirAccessSync
:
2214 /*****************************************************************************/
2221 SInt32 accessRights
)
2229 /* Just the bits that can be set */
2230 kSetDirAccessSettableMask
= (kioACAccessBlankAccessMask
+
2231 kioACAccessEveryoneWriteMask
+ kioACAccessEveryoneReadMask
+ kioACAccessEveryoneSearchMask
+
2232 kioACAccessGroupWriteMask
+ kioACAccessGroupReadMask
+ kioACAccessGroupSearchMask
+
2233 kioACAccessOwnerWriteMask
+ kioACAccessOwnerReadMask
+ kioACAccessOwnerSearchMask
)
2236 /* get FSSpec from FSRef */
2237 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
);
2238 require_noerr(result
, FSGetCatalogInfo
);
2240 /* set directory access info for FSSpec */
2241 pb
.accessParam
.ioNamePtr
= (StringPtr
)spec
.name
;
2242 pb
.accessParam
.ioVRefNum
= spec
.vRefNum
;
2243 pb
.fileParam
.ioDirID
= spec
.parID
;
2244 pb
.accessParam
.ioACOwnerID
= ownerID
;
2245 pb
.accessParam
.ioACGroupID
= groupID
;
2246 pb
.accessParam
.ioACAccess
= accessRights
& kSetDirAccessSettableMask
;
2247 result
= PBHSetDirAccessSync(&pb
);
2248 require_noerr(result
, PBHSetDirAccessSync
);
2250 PBHSetDirAccessSync
:
2256 /*****************************************************************************/
2259 FSGetVolMountInfoSize(
2260 FSVolumeRefNum volRefNum
,
2266 /* check parameters */
2267 require_action(NULL
!= size
, BadParameter
, result
= paramErr
);
2269 pb
.ioParam
.ioNamePtr
= NULL
;
2270 pb
.ioParam
.ioVRefNum
= volRefNum
;
2271 pb
.ioParam
.ioBuffer
= (Ptr
)size
;
2272 result
= PBGetVolMountInfoSize(&pb
);
2273 require_noerr(result
, PBGetVolMountInfoSize
);
2275 PBGetVolMountInfoSize
:
2281 /*****************************************************************************/
2285 FSVolumeRefNum volRefNum
,
2291 /* check parameters */
2292 require_action(NULL
!= volMountInfo
, BadParameter
, result
= paramErr
);
2294 pb
.ioParam
.ioNamePtr
= NULL
;
2295 pb
.ioParam
.ioVRefNum
= volRefNum
;
2296 pb
.ioParam
.ioBuffer
= (Ptr
)volMountInfo
;
2297 result
= PBGetVolMountInfo(&pb
);
2298 require_noerr(result
, PBGetVolMountInfo
);
2306 /*****************************************************************************/
2310 const void *volMountInfo
,
2311 FSVolumeRefNum
*volRefNum
)
2316 /* check parameters */
2317 require_action(NULL
!= volRefNum
, BadParameter
, result
= paramErr
);
2319 pb
.ioParam
.ioBuffer
= (Ptr
)volMountInfo
;
2320 result
= PBVolumeMount(&pb
);
2321 require_noerr(result
, PBVolumeMount
);
2323 /* return the volume reference number */
2324 *volRefNum
= pb
.ioParam
.ioVRefNum
;
2332 /*****************************************************************************/
2336 FSVolumeRefNum volRefNum
,
2344 /* check parameters */
2345 require_action(NULL
!= name
, BadParameter
, result
= paramErr
);
2347 pb
.objParam
.ioNamePtr
= NULL
;
2348 pb
.objParam
.ioVRefNum
= volRefNum
;
2349 pb
.objParam
.ioObjType
= objType
;
2350 pb
.objParam
.ioObjNamePtr
= name
;
2351 pb
.objParam
.ioObjID
= ugID
;
2352 result
= PBHMapIDSync(&pb
);
2353 require_noerr(result
, PBHMapIDSync
);
2361 /*****************************************************************************/
2365 FSVolumeRefNum volRefNum
,
2366 ConstStr255Param name
,
2373 /* check parameters */
2374 require_action(NULL
!= ugID
, BadParameter
, result
= paramErr
);
2376 pb
.objParam
.ioNamePtr
= NULL
;
2377 pb
.objParam
.ioVRefNum
= volRefNum
;
2378 pb
.objParam
.ioObjType
= objType
;
2379 pb
.objParam
.ioObjNamePtr
= (StringPtr
)name
;
2380 result
= PBHMapNameSync(&pb
);
2381 require_noerr(result
, PBHMapNameSync
);
2383 /* return the user or group ID */
2384 *ugID
= pb
.objParam
.ioObjID
;
2392 /*****************************************************************************/
2396 const FSRef
*srcFileRef
,
2397 const FSRef
*dstDirectoryRef
,
2398 UniCharCount nameLength
,
2399 const UniChar
*copyName
, /* can be NULL (no rename during copy) */
2400 TextEncoding textEncodingHint
,
2401 FSRef
*newRef
) /* can be NULL */
2405 FSCatalogInfo catalogInfo
;
2408 GetVolParmsInfoBuffer volParmsInfo
;
2411 /* get source FSSpec from source FSRef */
2412 result
= FSGetCatalogInfo(srcFileRef
, kFSCatInfoNone
, NULL
, NULL
, &srcFileSpec
, NULL
);
2413 require_noerr(result
, FSGetCatalogInfo_srcFileRef
);
2415 /* Make sure the volume supports CopyFile */
2416 result
= FSGetVolParms(srcFileSpec
.vRefNum
, sizeof(GetVolParmsInfoBuffer
),
2417 &volParmsInfo
, &infoSize
);
2418 require_action((noErr
== result
) && VolHasCopyFile(&volParmsInfo
),
2419 NoCopyFileSupport
, result
= paramErr
);
2421 /* get destination volume reference number and destination directory ID from destination FSRef */
2422 result
= FSGetCatalogInfo(dstDirectoryRef
, kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2423 &catalogInfo
, NULL
, NULL
, NULL
);
2424 require_noerr(result
, FSGetCatalogInfo_dstDirectoryRef
);
2426 /* tell the server to copy the object */
2427 pb
.copyParam
.ioVRefNum
= srcFileSpec
.vRefNum
;
2428 pb
.copyParam
.ioDirID
= srcFileSpec
.parID
;
2429 pb
.copyParam
.ioNamePtr
= (StringPtr
)srcFileSpec
.name
;
2430 pb
.copyParam
.ioDstVRefNum
= catalogInfo
.volume
;
2431 pb
.copyParam
.ioNewDirID
= (long)catalogInfo
.nodeID
;
2432 pb
.copyParam
.ioNewName
= NULL
;
2433 if ( NULL
!= copyName
)
2435 result
= UnicodeNameGetHFSName(nameLength
, copyName
, textEncodingHint
, false, hfsName
);
2436 require_noerr(result
, UnicodeNameGetHFSName
);
2438 pb
.copyParam
.ioCopyName
= hfsName
;
2442 pb
.copyParam
.ioCopyName
= NULL
;
2444 result
= PBHCopyFileSync(&pb
);
2445 require_noerr(result
, PBHCopyFileSync
);
2447 if ( NULL
!= newRef
)
2449 verify_noerr(FSMakeFSRef(pb
.copyParam
.ioDstVRefNum
, pb
.copyParam
.ioNewDirID
,
2450 pb
.copyParam
.ioCopyName
, newRef
));
2454 UnicodeNameGetHFSName
:
2455 FSGetCatalogInfo_dstDirectoryRef
:
2457 FSGetCatalogInfo_srcFileRef
:
2462 /*****************************************************************************/
2466 const FSRef
*srcFileRef
,
2467 const FSRef
*dstDirectoryRef
,
2468 UniCharCount nameLength
,
2469 const UniChar
*moveName
, /* can be NULL (no rename during move) */
2470 TextEncoding textEncodingHint
,
2471 FSRef
*newRef
) /* can be NULL */
2475 FSCatalogInfo catalogInfo
;
2478 GetVolParmsInfoBuffer volParmsInfo
;
2481 /* get source FSSpec from source FSRef */
2482 result
= FSGetCatalogInfo(srcFileRef
, kFSCatInfoNone
, NULL
, NULL
, &srcFileSpec
, NULL
);
2483 require_noerr(result
, FSGetCatalogInfo_srcFileRef
);
2485 /* Make sure the volume supports MoveRename */
2486 result
= FSGetVolParms(srcFileSpec
.vRefNum
, sizeof(GetVolParmsInfoBuffer
),
2487 &volParmsInfo
, &infoSize
);
2488 require_action((noErr
== result
) && VolHasMoveRename(&volParmsInfo
),
2489 NoMoveRenameSupport
, result
= paramErr
);
2491 /* get destination volume reference number and destination directory ID from destination FSRef */
2492 result
= FSGetCatalogInfo(dstDirectoryRef
, kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2493 &catalogInfo
, NULL
, NULL
, NULL
);
2494 require_noerr(result
, FSGetCatalogInfo_dstDirectoryRef
);
2496 /* make sure the source and destination are on the same volume */
2497 require_action(srcFileSpec
.vRefNum
== catalogInfo
.volume
, NotSameVolume
, result
= diffVolErr
);
2499 /* tell the server to move and rename the object */
2500 pb
.copyParam
.ioVRefNum
= srcFileSpec
.vRefNum
;
2501 pb
.copyParam
.ioDirID
= srcFileSpec
.parID
;
2502 pb
.copyParam
.ioNamePtr
= (StringPtr
)srcFileSpec
.name
;
2503 pb
.copyParam
.ioNewDirID
= (long)catalogInfo
.nodeID
;
2504 pb
.copyParam
.ioNewName
= NULL
;
2505 if ( NULL
!= moveName
)
2507 result
= UnicodeNameGetHFSName(nameLength
, moveName
, textEncodingHint
, false, hfsName
);
2508 require_noerr(result
, UnicodeNameGetHFSName
);
2510 pb
.copyParam
.ioCopyName
= hfsName
;
2514 pb
.copyParam
.ioCopyName
= NULL
;
2516 result
= PBHMoveRenameSync(&pb
);
2517 require_noerr(result
, PBHMoveRenameSync
);
2519 if ( NULL
!= newRef
)
2521 verify_noerr(FSMakeFSRef(pb
.copyParam
.ioVRefNum
, pb
.copyParam
.ioNewDirID
,
2522 pb
.copyParam
.ioCopyName
, newRef
));
2526 UnicodeNameGetHFSName
:
2528 FSGetCatalogInfo_dstDirectoryRef
:
2529 NoMoveRenameSupport
:
2530 FSGetCatalogInfo_srcFileRef
:
2535 /*****************************************************************************/
2537 #pragma mark ----- File ID Routines -----
2539 /*****************************************************************************/
2543 FSVolumeRefNum volRefNum
,
2551 /* check parameters */
2552 require_action(NULL
!= ref
, BadParameter
, result
= paramErr
);
2554 /* resolve the file ID reference */
2556 pb
.ioNamePtr
= tempStr
;
2557 pb
.ioVRefNum
= volRefNum
;
2558 pb
.ioFileID
= fileID
;
2559 result
= PBResolveFileIDRefSync((HParmBlkPtr
)&pb
);
2560 require_noerr(result
, PBResolveFileIDRefSync
);
2562 /* and then make an FSRef to the file */
2563 result
= FSMakeFSRef(volRefNum
, pb
.ioSrcDirID
, tempStr
, ref
);
2564 require_noerr(result
, FSMakeFSRef
);
2567 PBResolveFileIDRefSync
:
2573 /*****************************************************************************/
2584 /* check parameters */
2585 require_action(NULL
!= fileID
, BadParameter
, result
= paramErr
);
2587 /* Get an FSSpec from the FSRef */
2588 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
);
2589 require_noerr(result
, FSGetCatalogInfo
);
2591 /* Create (or get) the file ID reference using the FSSpec */
2592 pb
.ioNamePtr
= (StringPtr
)spec
.name
;
2593 pb
.ioVRefNum
= spec
.vRefNum
;
2594 pb
.ioSrcDirID
= spec
.parID
;
2595 result
= PBCreateFileIDRefSync((HParmBlkPtr
)&pb
);
2596 require((noErr
== result
) || (fidExists
== result
) || (afpIDExists
== result
),
2597 PBCreateFileIDRefSync
);
2599 /* return the file ID reference */
2600 *fileID
= pb
.ioFileID
;
2602 PBCreateFileIDRefSync
:
2609 /*****************************************************************************/
2611 #pragma mark ----- Utility Routines -----
2613 /*****************************************************************************/
2617 ByteCount buffReqSize
,
2618 ByteCount
*buffActSize
)
2622 kSlopMemory
= 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
2627 /* check parameters */
2628 require_action(NULL
!= buffActSize
, BadParameter
, tempPtr
= NULL
);
2630 /* Make request a multiple of 4K bytes */
2631 buffReqSize
= buffReqSize
& 0xfffff000;
2633 if ( buffReqSize
< 0x00001000 )
2635 /* Request was smaller than 4K bytes - make it 4K */
2636 buffReqSize
= 0x00001000;
2639 /* Attempt to allocate the memory */
2640 tempPtr
= NewPtr(buffReqSize
);
2642 /* If request failed, go to backup plan */
2643 if ( (tempPtr
== NULL
) && (buffReqSize
> 0x00001000) )
2646 ** Try to get largest 4K byte block available
2647 ** leaving some slop for the toolbox if possible
2649 long freeMemory
= (FreeMem() - kSlopMemory
) & 0xfffff000;
2651 buffReqSize
= MaxBlock() & 0xfffff000;
2653 if ( buffReqSize
> freeMemory
)
2655 buffReqSize
= freeMemory
;
2658 if ( buffReqSize
== 0 )
2660 buffReqSize
= 0x00001000;
2663 tempPtr
= NewPtr(buffReqSize
);
2666 /* Return bytes allocated */
2667 if ( tempPtr
!= NULL
)
2669 *buffActSize
= buffReqSize
;
2681 /*****************************************************************************/
2688 return ( FSGetForkCBInfo(refNum
, 0, NULL
, NULL
, NULL
, ref
, NULL
) );
2691 /*****************************************************************************/
2695 const FSRef
*newDefault
,
2699 FSVolumeRefNum vRefNum
;
2701 FSCatalogInfo catalogInfo
;
2703 /* check parameters */
2704 require_action((NULL
!= newDefault
) && (NULL
!= oldDefault
), BadParameter
, result
= paramErr
);
2706 /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
2707 result
= FSGetCatalogInfo(newDefault
,
2708 kFSCatInfoNodeFlags
+ kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2709 &catalogInfo
, NULL
, NULL
, NULL
);
2710 require_noerr(result
, FSGetCatalogInfo
);
2712 /* Make sure newDefault is a directory */
2713 require_action(0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
), NewDefaultNotDirectory
,
2716 /* Get the current working directory. */
2717 result
= HGetVol(NULL
, &vRefNum
, &dirID
);
2718 require_noerr(result
, HGetVol
);
2720 /* Return the oldDefault FSRef */
2721 result
= FSMakeFSRef(vRefNum
, dirID
, NULL
, oldDefault
);
2722 require_noerr(result
, FSMakeFSRef
);
2724 /* Set the new current working directory */
2725 result
= HSetVol(NULL
, catalogInfo
.volume
, catalogInfo
.nodeID
);
2726 require_noerr(result
, HSetVol
);
2731 NewDefaultNotDirectory
:
2738 /*****************************************************************************/
2742 const FSRef
*oldDefault
)
2745 FSCatalogInfo catalogInfo
;
2747 /* check parameters */
2748 require_action(NULL
!= oldDefault
, BadParameter
, result
= paramErr
);
2750 /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
2751 result
= FSGetCatalogInfo(oldDefault
,
2752 kFSCatInfoNodeFlags
+ kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2753 &catalogInfo
, NULL
, NULL
, NULL
);
2754 require_noerr(result
, FSGetCatalogInfo
);
2756 /* Make sure oldDefault is a directory */
2757 require_action(0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
), OldDefaultNotDirectory
,
2760 /* Set the current working directory to oldDefault */
2761 result
= HSetVol(NULL
, catalogInfo
.volume
, catalogInfo
.nodeID
);
2762 require_noerr(result
, HSetVol
);
2765 OldDefaultNotDirectory
:
2772 /*****************************************************************************/