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>
80 #include "MoreFilesX.h"
82 /* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */
83 #ifndef BuildingMoreFilesXForMacOS9
84 #define BuildingMoreFilesXForMacOS9 0
87 /*****************************************************************************/
89 #pragma mark ----- Local type definitions -----
91 struct FSIterateContainerGlobals
93 IterateContainerFilterProcPtr iterateFilter
; /* pointer to IterateFilterProc */
94 FSCatalogInfoBitmap whichInfo
; /* fields of the CatalogInfo to get */
95 FSCatalogInfo catalogInfo
; /* FSCatalogInfo */
96 FSRef ref
; /* FSRef */
97 FSSpec spec
; /* FSSpec */
98 FSSpec
*specPtr
; /* pointer to spec field, or NULL */
99 HFSUniStr255 name
; /* HFSUniStr255 */
100 HFSUniStr255
*namePtr
; /* pointer to name field, or NULL */
101 void *yourDataPtr
; /* a pointer to caller supplied data the filter may need to access */
102 ItemCount maxLevels
; /* maximum levels to iterate through */
103 ItemCount currentLevel
; /* the current level FSIterateContainerLevel is on */
104 Boolean quitFlag
; /* set to true if filter wants to kill interation */
105 Boolean containerChanged
; /* temporary - set to true if the current container changed during iteration */
106 OSErr result
; /* result */
107 ItemCount actualObjects
; /* number of objects returned */
109 typedef struct FSIterateContainerGlobals FSIterateContainerGlobals
;
111 struct FSDeleteContainerGlobals
113 OSErr result
; /* result */
114 ItemCount actualObjects
; /* number of objects returned */
115 FSCatalogInfo catalogInfo
; /* FSCatalogInfo */
117 typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals
;
119 /*****************************************************************************/
121 #pragma mark ----- Local prototypes -----
125 FSDeleteContainerLevel(
126 const FSRef
*container
,
127 FSDeleteContainerGlobals
*theGlobals
);
131 FSIterateContainerLevel(
132 FSIterateContainerGlobals
*theGlobals
);
136 GenerateUniqueHFSUniStr(
140 HFSUniStr255
*uniqueName
);
142 /*****************************************************************************/
144 #pragma mark ----- File Access Routines -----
146 /*****************************************************************************/
153 ByteCount copyBufferSize
)
159 ByteCount readActualCount
;
161 /* check input parameters */
162 require_action((NULL
!= copyBufferPtr
) && (0 != copyBufferSize
), BadParameter
, result
= paramErr
);
164 /* get source fork size */
165 result
= FSGetForkSize(srcRefNum
, &forkSize
);
166 require_noerr(result
, SourceFSGetForkSizeFailed
);
168 /* allocate disk space for destination fork */
169 result
= FSSetForkSize(dstRefNum
, fsFromStart
, forkSize
);
170 require_noerr(result
, DestinationFSSetForkSizeFailed
);
172 /* reset source fork's position to 0 */
173 result
= FSSetForkPosition(srcRefNum
, fsFromStart
, 0);
174 require_noerr(result
, SourceFSSetForkPositionFailed
);
176 /* reset destination fork's position to 0 */
177 result
= FSSetForkPosition(dstRefNum
, fsFromStart
, 0);
178 require_noerr(result
, DestinationFSSetForkPositionFailed
);
180 /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */
181 /* This will make writes on local volumes faster */
182 if ( (copyBufferSize
>= 0x00001000) && ((copyBufferSize
& 0x00000fff) != 0) )
184 copyBufferSize
&= ~(0x00001000 - 1);
187 /* copy source to destination */
188 srcResult
= dstResult
= noErr
;
189 while ( (noErr
== srcResult
) && (noErr
== dstResult
) )
191 srcResult
= FSReadFork(srcRefNum
, fsAtMark
+ noCacheMask
, 0, copyBufferSize
, copyBufferPtr
, &readActualCount
);
192 dstResult
= FSWriteFork(dstRefNum
, fsAtMark
+ noCacheMask
, 0, readActualCount
, copyBufferPtr
, NULL
);
195 /* make sure there were no errors at the destination */
196 require_noerr_action(dstResult
, DestinationFSWriteForkFailed
, result
= dstResult
);
198 /* make sure the error at the source was eofErr */
199 require_action(eofErr
== srcResult
, SourceResultNotEofErr
, result
= srcResult
);
201 /* everything went as expected */
204 SourceResultNotEofErr
:
205 DestinationFSWriteForkFailed
:
206 DestinationFSSetForkPositionFailed
:
207 SourceFSSetForkPositionFailed
:
208 DestinationFSSetForkSizeFailed
:
209 SourceFSGetForkSizeFailed
:
215 /*****************************************************************************/
217 #pragma mark ----- Volume Access Routines -----
219 /*****************************************************************************/
223 FSVolumeRefNum volRefNum
,
225 GetVolParmsInfoBuffer
*volParmsInfo
,
226 UInt32
*actualInfoSize
)
231 /* check parameters */
232 require_action((NULL
!= volParmsInfo
) && (NULL
!= actualInfoSize
),
233 BadParameter
, result
= paramErr
);
235 pb
.ioParam
.ioNamePtr
= NULL
;
236 pb
.ioParam
.ioVRefNum
= volRefNum
;
237 pb
.ioParam
.ioBuffer
= (Ptr
)volParmsInfo
;
238 pb
.ioParam
.ioReqCount
= (SInt32
)bufferSize
;
239 result
= PBHGetVolParmsSync(&pb
);
240 require_noerr(result
, PBHGetVolParmsSync
);
242 /* return number of bytes the file system returned in volParmsInfo buffer */
243 *actualInfoSize
= (UInt32
)pb
.ioParam
.ioActCount
;
251 /*****************************************************************************/
256 FSVolumeRefNum
*vRefNum
)
259 FSCatalogInfo catalogInfo
;
261 /* check parameters */
262 require_action(NULL
!= vRefNum
, BadParameter
, result
= paramErr
);
264 /* get the volume refNum from the FSRef */
265 result
= FSGetCatalogInfo(ref
, kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
, NULL
);
266 require_noerr(result
, FSGetCatalogInfo
);
268 /* return volume refNum from catalogInfo */
269 *vRefNum
= catalogInfo
.volume
;
277 /*****************************************************************************/
281 FSVolumeRefNum volume
,
282 HFSUniStr255
*volumeName
, /* can be NULL */
283 UInt64
*freeBytes
, /* can be NULL */
284 UInt64
*totalBytes
) /* can be NULL */
289 /* ask for the volume's sizes only if needed */
290 result
= FSGetVolumeInfo(volume
, 0, NULL
,
291 (((NULL
!= freeBytes
) || (NULL
!= totalBytes
)) ? kFSVolInfoSizes
: kFSVolInfoNone
),
292 &info
, volumeName
, NULL
);
293 require_noerr(result
, FSGetVolumeInfo
);
295 if ( NULL
!= freeBytes
)
297 *freeBytes
= info
.freeBytes
;
299 if ( NULL
!= totalBytes
)
301 *totalBytes
= info
.totalBytes
;
309 /*****************************************************************************/
312 FSGetVolFileSystemID(
313 FSVolumeRefNum volume
,
314 UInt16
*fileSystemID
, /* can be NULL */
315 UInt16
*signature
) /* can be NULL */
320 result
= FSGetVolumeInfo(volume
, 0, NULL
, kFSVolInfoFSInfo
, &info
, NULL
, NULL
);
321 require_noerr(result
, FSGetVolumeInfo
);
323 if ( NULL
!= fileSystemID
)
325 *fileSystemID
= info
.filesystemID
;
327 if ( NULL
!= signature
)
329 *signature
= info
.signature
;
337 /*****************************************************************************/
341 FSRef
***volumeRefsHandle
, /* pointer to handle of FSRefs */
342 ItemCount
*numVolumes
)
346 ItemCount volumeIndex
;
349 /* check parameters */
350 require_action((NULL
!= volumeRefsHandle
) && (NULL
!= numVolumes
),
351 BadParameter
, result
= paramErr
);
356 /* Allocate a handle for the results */
357 *volumeRefsHandle
= (FSRef
**)NewHandle(0);
358 require_action(NULL
!= *volumeRefsHandle
, NewHandle
, result
= memFullErr
);
360 /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */
364 result
= FSGetVolumeInfo(0, volumeIndex
, NULL
, kFSVolInfoNone
, NULL
, NULL
, &ref
);
365 if ( noErr
== result
)
367 /* concatenate the FSRef to the end of the handle */
368 PtrAndHand(&ref
, (Handle
)*volumeRefsHandle
, sizeof(FSRef
));
369 memResult
= MemError();
370 require_noerr_action(memResult
, MemoryAllocationFailed
, result
= memResult
);
372 ++(*numVolumes
); /* increment the volume count */
373 ++volumeIndex
; /* and the volumeIndex to get the next volume*/
375 } while ( noErr
== result
);
377 /* nsvErr is OK -- it just means there are no more volumes */
378 require(nsvErr
== result
, FSGetVolumeInfo
);
382 /**********************/
384 MemoryAllocationFailed
:
387 /* dispose of handle if already allocated and clear the outputs */
388 if ( NULL
!= *volumeRefsHandle
)
390 DisposeHandle((Handle
)*volumeRefsHandle
);
391 *volumeRefsHandle
= NULL
;
401 /*****************************************************************************/
403 #pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
405 /*****************************************************************************/
414 /* check parameters */
415 require_action(NULL
!= spec
, BadParameter
, result
= paramErr
);
417 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
);
418 require_noerr(result
, FSGetCatalogInfo
);
426 /*****************************************************************************/
430 FSVolumeRefNum volRefNum
,
432 ConstStr255Param name
,
438 /* check parameters */
439 require_action(NULL
!= ref
, BadParameter
, result
= paramErr
);
441 pb
.ioVRefNum
= volRefNum
;
443 pb
.ioNamePtr
= (StringPtr
)name
;
445 result
= PBMakeFSRefSync(&pb
);
446 require_noerr(result
, PBMakeFSRefSync
);
454 /*****************************************************************************/
460 ConstStr255Param name
,
467 /* check parameters */
468 require_action(NULL
!= path
, BadParameter
, result
= paramErr
);
470 /* convert the inputs to an FSRef */
471 result
= FSMakeFSRef(volRefNum
, dirID
, name
, &ref
);
472 require_noerr(result
, FSMakeFSRef
);
474 /* and then convert the FSRef to a path */
475 result
= FSRefMakePath(&ref
, path
, maxPathSize
);
476 require_noerr(result
, FSRefMakePath
);
485 /*****************************************************************************/
491 Boolean
*isDirectory
) /* can be NULL */
496 /* check parameters */
497 require_action(NULL
!= spec
, BadParameter
, result
= paramErr
);
499 /* convert the POSIX path to an FSRef */
500 result
= FSPathMakeRef(path
, &ref
, isDirectory
);
501 require_noerr(result
, FSPathMakeRef
);
503 /* and then convert the FSRef to an FSSpec */
504 result
= FSGetCatalogInfo(&ref
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
);
505 require_noerr(result
, FSGetCatalogInfo
);
514 /*****************************************************************************/
517 UnicodeNameGetHFSName(
518 UniCharCount nameLength
,
520 TextEncoding textEncodingHint
,
521 Boolean isVolumeName
,
525 ByteCount unicodeByteLength
;
526 ByteCount unicodeBytesConverted
;
527 ByteCount actualPascalBytes
;
528 UnicodeMapping uMapping
;
529 UnicodeToTextInfo utInfo
;
531 /* check parameters */
532 require_action(NULL
!= hfsName
, BadParameter
, result
= paramErr
);
534 /* make sure output is valid in case we get errors or there's nothing to convert */
537 unicodeByteLength
= nameLength
* sizeof(UniChar
);
538 if ( 0 == unicodeByteLength
)
545 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
546 if ( kTextEncodingUnknown
== textEncodingHint
)
551 script
= (ScriptCode
)GetScriptManagerVariable(smSysScript
);
552 region
= (RegionCode
)GetScriptManagerVariable(smRegionCode
);
553 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, region
,
554 NULL
, &textEncodingHint
);
555 if ( paramErr
== result
)
557 /* ok, ignore the region and try again */
558 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
,
559 kTextRegionDontCare
, NULL
, &textEncodingHint
);
561 if ( noErr
!= result
)
563 /* ok... try something */
564 textEncodingHint
= kTextEncodingMacRoman
;
568 uMapping
.unicodeEncoding
= CreateTextEncoding(kTextEncodingUnicodeV2_0
,
569 kUnicodeCanonicalDecompVariant
, kUnicode16BitFormat
);
570 uMapping
.otherEncoding
= GetTextEncodingBase(textEncodingHint
);
571 uMapping
.mappingVersion
= kUnicodeUseHFSPlusMapping
;
573 result
= CreateUnicodeToTextInfo(&uMapping
, &utInfo
);
574 require_noerr(result
, CreateUnicodeToTextInfo
);
576 result
= ConvertFromUnicodeToText(utInfo
, unicodeByteLength
, name
, kUnicodeLooseMappingsMask
,
577 0, NULL
, 0, NULL
, /* offsetCounts & offsetArrays */
578 isVolumeName
? kHFSMaxVolumeNameChars
: kHFSMaxFileNameChars
,
579 &unicodeBytesConverted
, &actualPascalBytes
, &hfsName
[1]);
580 require_noerr(result
, ConvertFromUnicodeToText
);
582 hfsName
[0] = (unsigned char)actualPascalBytes
; /* fill in length byte */
584 ConvertFromUnicodeToText
:
586 /* verify the result in debug builds -- there's really not anything you can do if it fails */
587 verify_noerr(DisposeUnicodeToTextInfo(&utInfo
));
590 CreateUnicodeToTextInfo
:
596 /*****************************************************************************/
599 HFSNameGetUnicodeName(
600 ConstStr31Param hfsName
,
601 TextEncoding textEncodingHint
,
602 HFSUniStr255
*unicodeName
)
604 ByteCount unicodeByteLength
;
606 UnicodeMapping uMapping
;
607 TextToUnicodeInfo tuInfo
;
608 ByteCount pascalCharsRead
;
610 /* check parameters */
611 require_action(NULL
!= unicodeName
, BadParameter
, result
= paramErr
);
613 /* make sure output is valid in case we get errors or there's nothing to convert */
614 unicodeName
->length
= 0;
616 if ( 0 == StrLength(hfsName
) )
622 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
623 if ( kTextEncodingUnknown
== textEncodingHint
)
628 script
= GetScriptManagerVariable(smSysScript
);
629 region
= GetScriptManagerVariable(smRegionCode
);
630 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, region
,
631 NULL
, &textEncodingHint
);
632 if ( paramErr
== result
)
634 /* ok, ignore the region and try again */
635 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
,
636 kTextRegionDontCare
, NULL
, &textEncodingHint
);
638 if ( noErr
!= result
)
640 /* ok... try something */
641 textEncodingHint
= kTextEncodingMacRoman
;
645 uMapping
.unicodeEncoding
= CreateTextEncoding(kTextEncodingUnicodeV2_0
,
646 kUnicodeCanonicalDecompVariant
, kUnicode16BitFormat
);
647 uMapping
.otherEncoding
= GetTextEncodingBase(textEncodingHint
);
648 uMapping
.mappingVersion
= kUnicodeUseHFSPlusMapping
;
650 result
= CreateTextToUnicodeInfo(&uMapping
, &tuInfo
);
651 require_noerr(result
, CreateTextToUnicodeInfo
);
653 result
= ConvertFromTextToUnicode(tuInfo
, hfsName
[0], &hfsName
[1],
654 0, /* no control flag bits */
655 0, NULL
, 0, NULL
, /* offsetCounts & offsetArrays */
656 sizeof(unicodeName
->unicode
), /* output buffer size in bytes */
657 &pascalCharsRead
, &unicodeByteLength
, unicodeName
->unicode
);
658 require_noerr(result
, ConvertFromTextToUnicode
);
660 /* convert from byte count to char count */
661 unicodeName
->length
= unicodeByteLength
/ sizeof(UniChar
);
663 ConvertFromTextToUnicode
:
665 /* verify the result in debug builds -- there's really not anything you can do if it fails */
666 verify_noerr(DisposeTextToUnicodeInfo(&tuInfo
));
669 CreateTextToUnicodeInfo
:
675 /*****************************************************************************/
677 #pragma mark ----- File/Directory Manipulation Routines -----
679 /*****************************************************************************/
681 Boolean
FSRefValid(const FSRef
*ref
)
683 return ( noErr
== FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, NULL
, NULL
) );
686 /*****************************************************************************/
694 FSCatalogInfo catalogInfo
;
696 /* check parameters */
697 require_action(NULL
!= parentRef
, BadParameter
, result
= paramErr
);
699 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeID
, &catalogInfo
, NULL
, NULL
, parentRef
);
700 require_noerr(result
, FSGetCatalogInfo
);
703 * Note: FSRefs always point to real file system objects. So, there cannot
704 * be a FSRef to the parent of volume root directories. Early versions of
705 * Mac OS X do not handle this case correctly and incorrectly return a
706 * FSRef for the parent of volume root directories instead of returning an
707 * invalid FSRef (a cleared FSRef is invalid). The next three lines of code
708 * ensure that you won't run into this bug. WW9D!
710 if ( fsRtDirID
== catalogInfo
.nodeID
)
712 /* clear parentRef and return noErr which is the proper behavior */
713 memset(parentRef
, 0, sizeof(FSRef
));
722 /*****************************************************************************/
727 HFSUniStr255
*outName
)
731 /* check parameters */
732 require_action(NULL
!= outName
, BadParameter
, result
= paramErr
);
734 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, outName
, NULL
, NULL
);
735 require_noerr(result
, FSGetCatalogInfo
);
743 /*****************************************************************************/
748 long *nodeID
, /* can be NULL */
749 Boolean
*isDirectory
) /* can be NULL */
752 FSCatalogInfo catalogInfo
;
753 FSCatalogInfoBitmap whichInfo
;
755 /* determine what catalog information to get */
756 whichInfo
= kFSCatInfoNone
; /* start with none */
757 if ( NULL
!= nodeID
)
759 whichInfo
|= kFSCatInfoNodeID
;
761 if ( NULL
!= isDirectory
)
763 whichInfo
|= kFSCatInfoNodeFlags
;
766 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
767 require_noerr(result
, FSGetCatalogInfo
);
769 if ( NULL
!= nodeID
)
771 *nodeID
= catalogInfo
.nodeID
;
773 if ( NULL
!= isDirectory
)
775 *isDirectory
= (0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
));
783 /*****************************************************************************/
786 FSGetUserPrivilegesPermissions(
788 UInt8
*userPrivileges
, /* can be NULL */
789 UInt32 permissions
[4]) /* can be NULL */
792 FSCatalogInfo catalogInfo
;
793 FSCatalogInfoBitmap whichInfo
;
795 /* determine what catalog information to get */
796 whichInfo
= kFSCatInfoNone
; /* start with none */
797 if ( NULL
!= userPrivileges
)
799 whichInfo
|= kFSCatInfoUserPrivs
;
801 if ( NULL
!= permissions
)
803 whichInfo
|= kFSCatInfoPermissions
;
806 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
807 require_noerr(result
, FSGetCatalogInfo
);
809 if ( NULL
!= userPrivileges
)
811 *userPrivileges
= catalogInfo
.userPrivileges
;
813 if ( NULL
!= permissions
)
815 BlockMoveData(&catalogInfo
.permissions
, permissions
, sizeof(UInt32
) * 4);
823 /*****************************************************************************/
830 FSCatalogInfo catalogInfo
;
831 FSVolumeInfo volumeInfo
;
833 /* get nodeFlags and vRefNum for container */
834 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags
+ kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
,NULL
);
835 require_noerr(result
, FSGetCatalogInfo
);
837 /* is file locked? */
838 if ( 0 != (catalogInfo
.nodeFlags
& kFSNodeLockedMask
) )
840 result
= fLckdErr
; /* file is locked */
844 /* file isn't locked, but is volume locked? */
846 /* get volume flags */
847 result
= FSGetVolumeInfo(catalogInfo
.volume
, 0, NULL
, kFSVolInfoFlags
, &volumeInfo
, NULL
, NULL
);
848 require_noerr(result
, FSGetVolumeInfo
);
850 if ( 0 != (volumeInfo
.flags
& kFSVolFlagHardwareLockedMask
) )
852 result
= wPrErr
; /* volume locked by hardware */
854 else if ( 0 != (volumeInfo
.flags
& kFSVolFlagSoftwareLockedMask
) )
856 result
= vLckdErr
; /* volume locked by software */
866 /*****************************************************************************/
871 UInt64
*dataLogicalSize
, /* can be NULL */
872 UInt64
*rsrcLogicalSize
) /* can be NULL */
875 FSCatalogInfoBitmap whichInfo
;
876 FSCatalogInfo catalogInfo
;
878 whichInfo
= kFSCatInfoNodeFlags
;
879 if ( NULL
!= dataLogicalSize
)
881 /* get data fork size */
882 whichInfo
|= kFSCatInfoDataSizes
;
884 if ( NULL
!= rsrcLogicalSize
)
886 /* get resource fork size */
887 whichInfo
|= kFSCatInfoRsrcSizes
;
890 /* get nodeFlags and catalog info */
891 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
,NULL
);
892 require_noerr(result
, FSGetCatalogInfo
);
894 /* make sure FSRef was to a file */
895 require_action(0 == (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
), FSRefNotFile
, result
= notAFileErr
);
897 if ( NULL
!= dataLogicalSize
)
899 /* return data fork size */
900 *dataLogicalSize
= catalogInfo
.dataLogicalSize
;
902 if ( NULL
!= rsrcLogicalSize
)
904 /* return resource fork size */
905 *rsrcLogicalSize
= catalogInfo
.rsrcLogicalSize
;
914 /*****************************************************************************/
919 UInt64
*totalLogicalSize
, /* can be NULL */
920 UInt64
*totalPhysicalSize
, /* can be NULL */
921 ItemCount
*forkCount
) /* can be NULL */
924 CatPositionRec forkIterator
;
927 UInt64 forkPhysicalSize
;
928 UInt64
*forkPhysicalSizePtr
;
930 /* Determine if forkSize needed */
931 if ( NULL
!= totalLogicalSize
)
933 *totalLogicalSize
= 0;
934 forkSizePtr
= &forkSize
;
941 /* Determine if forkPhysicalSize is needed */
942 if ( NULL
!= totalPhysicalSize
)
944 *totalPhysicalSize
= 0;
945 forkPhysicalSizePtr
= &forkPhysicalSize
;
949 forkPhysicalSizePtr
= NULL
;
952 /* zero fork count if returning it */
953 if ( NULL
!= forkCount
)
958 /* Iterate through the forks to get the sizes */
959 forkIterator
.initialize
= 0;
962 result
= FSIterateForks(ref
, &forkIterator
, NULL
, forkSizePtr
, forkPhysicalSizePtr
);
963 if ( noErr
== result
)
965 if ( NULL
!= totalLogicalSize
)
967 *totalLogicalSize
+= forkSize
;
970 if ( NULL
!= totalPhysicalSize
)
972 *totalPhysicalSize
+= forkPhysicalSize
;
975 if ( NULL
!= forkCount
)
980 } while ( noErr
== result
);
982 /* any error result other than errFSNoMoreItems is serious */
983 require(errFSNoMoreItems
== result
, FSIterateForks
);
993 /*****************************************************************************/
1000 FSCatalogInfo catalogInfo
;
1001 UTCDateTime oldDateTime
;
1002 #if !BuildingMoreFilesXForMacOS9
1004 Boolean notifyParent
;
1007 #if !BuildingMoreFilesXForMacOS9
1008 /* Get the node flags, the content modification date and time, and the parent ref */
1009 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags
+ kFSCatInfoContentMod
, &catalogInfo
, NULL
, NULL
, &parentRef
);
1010 require_noerr(result
, FSGetCatalogInfo
);
1012 /* Notify the parent if this is a file */
1013 notifyParent
= (0 == (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
));
1015 /* Get the content modification date and time */
1016 result
= FSGetCatalogInfo(ref
, kFSCatInfoContentMod
, &catalogInfo
, NULL
, NULL
, NULL
);
1017 require_noerr(result
, FSGetCatalogInfo
);
1020 oldDateTime
= catalogInfo
.contentModDate
;
1022 /* Get the current date and time */
1023 result
= GetUTCDateTime(&catalogInfo
.contentModDate
, kUTCDefaultOptions
);
1024 require_noerr(result
, GetUTCDateTime
);
1026 /* if the old date and time is the the same as the current, bump the seconds by one */
1027 if ( (catalogInfo
.contentModDate
.fraction
== oldDateTime
.fraction
) &&
1028 (catalogInfo
.contentModDate
.lowSeconds
== oldDateTime
.lowSeconds
) &&
1029 (catalogInfo
.contentModDate
.highSeconds
== oldDateTime
.highSeconds
) )
1031 ++catalogInfo
.contentModDate
.lowSeconds
;
1032 if ( 0 == catalogInfo
.contentModDate
.lowSeconds
)
1034 ++catalogInfo
.contentModDate
.highSeconds
;
1038 /* Bump the content modification date and time */
1039 result
= FSSetCatalogInfo(ref
, kFSCatInfoContentMod
, &catalogInfo
);
1040 require_noerr(result
, FSSetCatalogInfo
);
1042 #if !BuildingMoreFilesXForMacOS9
1044 * The problem with FNNotify is that it is not available under Mac OS 9
1045 * and there's no way to test for that except for looking for the symbol
1046 * or something. So, I'll just conditionalize this for those who care
1047 * to send a notification.
1050 /* Send a notification for the parent of the file, or for the directory */
1051 result
= FNNotify(notifyParent
? &parentRef
: ref
, kFNDirectoryModifiedMessage
, kNilOptions
);
1052 require_noerr(result
, FNNotify
);
1055 /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */
1061 /**********************/
1069 /*****************************************************************************/
1074 FinderInfo
*info
, /* can be NULL */
1075 ExtendedFinderInfo
*extendedInfo
, /* can be NULL */
1076 Boolean
*isDirectory
) /* can be NULL */
1079 FSCatalogInfo catalogInfo
;
1080 FSCatalogInfoBitmap whichInfo
;
1082 /* determine what catalog information is really needed */
1083 whichInfo
= kFSCatInfoNone
;
1087 /* get FinderInfo */
1088 whichInfo
|= kFSCatInfoFinderInfo
;
1091 if ( NULL
!= extendedInfo
)
1093 /* get ExtendedFinderInfo */
1094 whichInfo
|= kFSCatInfoFinderXInfo
;
1097 if ( NULL
!= isDirectory
)
1099 whichInfo
|= kFSCatInfoNodeFlags
;
1102 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
1103 require_noerr(result
, FSGetCatalogInfo
);
1105 /* return FinderInfo if requested */
1108 BlockMoveData(catalogInfo
.finderInfo
, info
, sizeof(FinderInfo
));
1111 /* return ExtendedFinderInfo if requested */
1112 if ( NULL
!= extendedInfo
)
1114 BlockMoveData(catalogInfo
.extFinderInfo
, extendedInfo
, sizeof(ExtendedFinderInfo
));
1117 /* set isDirectory Boolean if requested */
1118 if ( NULL
!= isDirectory
)
1120 *isDirectory
= (0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
));
1128 /*****************************************************************************/
1133 const FinderInfo
*info
,
1134 const ExtendedFinderInfo
*extendedInfo
)
1137 FSCatalogInfo catalogInfo
;
1138 FSCatalogInfoBitmap whichInfo
;
1140 /* determine what catalog information will be set */
1141 whichInfo
= kFSCatInfoNone
; /* start with none */
1144 /* set FinderInfo */
1145 whichInfo
|= kFSCatInfoFinderInfo
;
1146 BlockMoveData(info
, catalogInfo
.finderInfo
, sizeof(FinderInfo
));
1148 if ( NULL
!= extendedInfo
)
1150 /* set ExtendedFinderInfo */
1151 whichInfo
|= kFSCatInfoFinderXInfo
;
1152 BlockMoveData(extendedInfo
, catalogInfo
.extFinderInfo
, sizeof(ExtendedFinderInfo
));
1155 result
= FSSetCatalogInfo(ref
, whichInfo
, &catalogInfo
);
1156 require_noerr(result
, FSGetCatalogInfo
);
1163 /*****************************************************************************/
1166 FSChangeCreatorType(
1172 FSCatalogInfo catalogInfo
;
1175 /* get nodeFlags, finder info, and parent FSRef */
1176 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags
+ kFSCatInfoFinderInfo
, &catalogInfo
, NULL
, NULL
, &parentRef
);
1177 require_noerr(result
, FSGetCatalogInfo
);
1179 /* make sure FSRef was to a file */
1180 require_action(0 == (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
), FSRefNotFile
, result
= notAFileErr
);
1182 /* If fileType not 0x00000000, change fileType */
1183 if ( fileType
!= (OSType
)0x00000000 )
1185 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
= fileType
;
1188 /* If creator not 0x00000000, change creator */
1189 if ( fileCreator
!= (OSType
)0x00000000 )
1191 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
= fileCreator
;
1194 /* now, save the new information back to disk */
1195 result
= FSSetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
);
1196 require_noerr(result
, FSSetCatalogInfo
);
1198 /* and attempt to bump the parent directory's mod date to wake up */
1199 /* the Finder to the change we just made (ignore errors from this) */
1200 verify_noerr(FSBumpDate(&parentRef
));
1209 /*****************************************************************************/
1212 FSChangeFinderFlags(
1218 FSCatalogInfo catalogInfo
;
1221 /* get the current finderInfo */
1222 result
= FSGetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
, NULL
, NULL
, &parentRef
);
1223 require_noerr(result
, FSGetCatalogInfo
);
1225 /* set or clear the appropriate bits in the finderInfo.finderFlags */
1228 /* OR in the bits */
1229 ((FileInfo
*)&catalogInfo
.finderInfo
)->finderFlags
|= flagBits
;
1233 /* AND out the bits */
1234 ((FileInfo
*)&catalogInfo
.finderInfo
)->finderFlags
&= ~flagBits
;
1237 /* save the modified finderInfo */
1238 result
= FSSetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
);
1239 require_noerr(result
, FSSetCatalogInfo
);
1241 /* and attempt to bump the parent directory's mod date to wake up the Finder */
1242 /* to the change we just made (ignore errors from this) */
1243 verify_noerr(FSBumpDate(&parentRef
));
1251 /*****************************************************************************/
1257 return ( FSChangeFinderFlags(ref
, true, kIsInvisible
) );
1264 return ( FSChangeFinderFlags(ref
, false, kIsInvisible
) );
1267 /*****************************************************************************/
1273 return ( FSChangeFinderFlags(ref
, true, kNameLocked
) );
1280 return ( FSChangeFinderFlags(ref
, false, kNameLocked
) );
1283 /*****************************************************************************/
1289 return ( FSChangeFinderFlags(ref
, true, kIsStationery
) );
1293 FSClearIsStationery(
1296 return ( FSChangeFinderFlags(ref
, false, kIsStationery
) );
1299 /*****************************************************************************/
1305 return ( FSChangeFinderFlags(ref
, true, kHasCustomIcon
) );
1309 FSClearHasCustomIcon(
1312 return ( FSChangeFinderFlags(ref
, false, kHasCustomIcon
) );
1315 /*****************************************************************************/
1318 FSClearHasBeenInited(
1321 return ( FSChangeFinderFlags(ref
, false, kHasBeenInited
) );
1324 /*****************************************************************************/
1327 FSCopyFileMgrAttributes(
1328 const FSRef
*sourceRef
,
1329 const FSRef
*destinationRef
,
1330 Boolean copyLockBit
)
1333 FSCatalogInfo catalogInfo
;
1335 /* get the source information */
1336 result
= FSGetCatalogInfo(sourceRef
, kFSCatInfoSettableInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
1337 require_noerr(result
, FSGetCatalogInfo
);
1339 /* don't copy the hasBeenInited bit; clear it */
1340 ((FileInfo
*)&catalogInfo
.finderInfo
)->finderFlags
&= ~kHasBeenInited
;
1342 /* should the locked bit be copied? */
1345 /* no, make sure the locked bit is clear */
1346 catalogInfo
.nodeFlags
&= ~kFSNodeLockedMask
;
1349 /* set the destination information */
1350 result
= FSSetCatalogInfo(destinationRef
, kFSCatInfoSettableInfo
, &catalogInfo
);
1351 require_noerr(result
, FSSetCatalogInfo
);
1359 /*****************************************************************************/
1362 FSMoveRenameObjectUnicode(
1364 const FSRef
*destDirectory
,
1365 UniCharCount nameLength
,
1366 const UniChar
*name
, /* can be NULL (no rename during move) */
1367 TextEncoding textEncodingHint
,
1368 FSRef
*newRef
) /* if function fails along the way, newRef is final location of file */
1371 FSVolumeRefNum vRefNum
;
1372 FSCatalogInfo catalogInfo
;
1373 FSRef originalDirectory
;
1374 TextEncoding originalTextEncodingHint
;
1375 HFSUniStr255 originalName
;
1376 HFSUniStr255 uniqueName
; /* unique name given to object while moving it to destination */
1377 long theSeed
; /* the seed for generating unique names */
1379 /* check parameters */
1380 require_action(NULL
!= newRef
, BadParameter
, result
= paramErr
);
1382 /* newRef = input to start with */
1383 BlockMoveData(ref
, newRef
, sizeof(FSRef
));
1385 /* get destDirectory's vRefNum */
1386 result
= FSGetCatalogInfo(destDirectory
, kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
, NULL
);
1387 require_noerr(result
, DestinationBad
);
1390 vRefNum
= catalogInfo
.volume
;
1392 /* get ref's vRefNum, TextEncoding, name and parent directory*/
1393 result
= FSGetCatalogInfo(ref
, kFSCatInfoTextEncoding
+ kFSCatInfoVolume
, &catalogInfo
, &originalName
, NULL
, &originalDirectory
);
1394 require_noerr(result
, SourceBad
);
1396 /* save TextEncoding */
1397 originalTextEncodingHint
= catalogInfo
.textEncodingHint
;
1399 /* make sure ref and destDirectory are on same volume */
1400 require_action(vRefNum
== catalogInfo
.volume
, NotSameVolume
, result
= diffVolErr
);
1402 /* Skip a few steps if we're not renaming */
1405 /* generate a name that is unique in both directories */
1406 theSeed
= 0x4a696d4c; /* a fine unlikely filename */
1408 result
= GenerateUniqueHFSUniStr(&theSeed
, &originalDirectory
, destDirectory
, &uniqueName
);
1409 require_noerr(result
, GenerateUniqueHFSUniStrFailed
);
1411 /* Rename the object to uniqueName */
1412 result
= FSRenameUnicode(ref
, uniqueName
.length
, uniqueName
.unicode
, kTextEncodingUnknown
, newRef
);
1413 require_noerr(result
, FSRenameUnicodeBeforeMoveFailed
);
1415 /* Move object to its new home */
1416 result
= FSMoveObject(newRef
, destDirectory
, newRef
);
1417 require_noerr(result
, FSMoveObjectAfterRenameFailed
);
1419 /* Rename the object to new name */
1420 result
= FSRenameUnicode(ref
, nameLength
, name
, textEncodingHint
, newRef
);
1421 require_noerr(result
, FSRenameUnicodeAfterMoveFailed
);
1425 /* Move object to its new home */
1426 result
= FSMoveObject(newRef
, destDirectory
, newRef
);
1427 require_noerr(result
, FSMoveObjectNoRenameFailed
);
1435 * failure handling code when renaming
1438 FSRenameUnicodeAfterMoveFailed
:
1440 /* Error handling: move object back to original location - ignore errors */
1441 verify_noerr(FSMoveObject(newRef
, &originalDirectory
, newRef
));
1443 FSMoveObjectAfterRenameFailed
:
1445 /* Error handling: rename object back to original name - ignore errors */
1446 verify_noerr(FSRenameUnicode(newRef
, originalName
.length
, originalName
.unicode
, originalTextEncodingHint
, newRef
));
1448 FSRenameUnicodeBeforeMoveFailed
:
1449 GenerateUniqueHFSUniStrFailed
:
1452 * failure handling code for renaming or not
1454 FSMoveObjectNoRenameFailed
:
1463 /*****************************************************************************/
1466 The FSDeleteContainerLevel function deletes the contents of a container
1467 directory. All files and subdirectories in the specified container are
1468 deleted. If a locked file or directory is encountered, it is unlocked
1469 and then deleted. If any unexpected errors are encountered,
1470 FSDeleteContainerLevel quits and returns to the caller.
1472 container --> FSRef to a directory.
1473 theGlobals --> A pointer to a FSDeleteContainerGlobals struct
1474 which contains the variables that do not need to
1475 be allocated each time FSDeleteContainerLevel
1476 recurses. That lets FSDeleteContainerLevel use
1477 less stack space per recursion level.
1482 FSDeleteContainerLevel(
1483 const FSRef
*container
,
1484 FSDeleteContainerGlobals
*theGlobals
)
1487 FSIterator iterator
;
1491 /* Open FSIterator for flat access and give delete optimization hint */
1492 theGlobals
->result
= FSOpenIterator(container
, kFSIterateFlat
+ kFSIterateDelete
, &iterator
);
1493 require_noerr(theGlobals
->result
, FSOpenIterator
);
1495 /* delete the contents of the directory */
1498 /* get 1 item to delete */
1499 theGlobals
->result
= FSGetCatalogInfoBulk(iterator
, 1, &theGlobals
->actualObjects
,
1500 NULL
, kFSCatInfoNodeFlags
, &theGlobals
->catalogInfo
,
1501 &itemToDelete
, NULL
, NULL
);
1502 if ( (noErr
== theGlobals
->result
) && (1 == theGlobals
->actualObjects
) )
1504 /* save node flags in local in case we have to recurse */
1505 nodeFlags
= theGlobals
->catalogInfo
.nodeFlags
;
1507 /* is it a file or directory? */
1508 if ( 0 != (nodeFlags
& kFSNodeIsDirectoryMask
) )
1510 /* it's a directory -- delete its contents before attempting to delete it */
1511 FSDeleteContainerLevel(&itemToDelete
, theGlobals
);
1513 /* are we still OK to delete? */
1514 if ( noErr
== theGlobals
->result
)
1516 /* is item locked? */
1517 if ( 0 != (nodeFlags
& kFSNodeLockedMask
) )
1519 /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
1520 theGlobals
->catalogInfo
.nodeFlags
= nodeFlags
& ~kFSNodeLockedMask
;
1521 (void) FSSetCatalogInfo(&itemToDelete
, kFSCatInfoNodeFlags
, &theGlobals
->catalogInfo
);
1523 /* delete the item */
1524 theGlobals
->result
= FSDeleteObject(&itemToDelete
);
1527 } while ( noErr
== theGlobals
->result
);
1529 /* we found the end of the items normally, so return noErr */
1530 if ( errFSNoMoreItems
== theGlobals
->result
)
1532 theGlobals
->result
= noErr
;
1535 /* close the FSIterator (closing an open iterator should never fail) */
1536 verify_noerr(FSCloseIterator(iterator
));
1543 /*****************************************************************************/
1546 FSDeleteContainerContents(
1547 const FSRef
*container
)
1549 FSDeleteContainerGlobals theGlobals
;
1551 /* delete container's contents */
1552 FSDeleteContainerLevel(container
, &theGlobals
);
1554 return ( theGlobals
.result
);
1557 /*****************************************************************************/
1561 const FSRef
*container
)
1564 FSCatalogInfo catalogInfo
;
1566 /* get nodeFlags for container */
1567 result
= FSGetCatalogInfo(container
, kFSCatInfoNodeFlags
, &catalogInfo
, NULL
, NULL
,NULL
);
1568 require_noerr(result
, FSGetCatalogInfo
);
1570 /* make sure container is a directory */
1571 require_action(0 != (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
), ContainerNotDirectory
, result
= dirNFErr
);
1573 /* delete container's contents */
1574 result
= FSDeleteContainerContents(container
);
1575 require_noerr(result
, FSDeleteContainerContents
);
1577 /* is container locked? */
1578 if ( 0 != (catalogInfo
.nodeFlags
& kFSNodeLockedMask
) )
1580 /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
1581 catalogInfo
.nodeFlags
&= ~kFSNodeLockedMask
;
1582 (void) FSSetCatalogInfo(container
, kFSCatInfoNodeFlags
, &catalogInfo
);
1585 /* delete the container */
1586 result
= FSDeleteObject(container
);
1588 FSDeleteContainerContents
:
1589 ContainerNotDirectory
:
1595 /*****************************************************************************/
1598 The FSIterateContainerLevel function iterates the contents of a container
1599 directory and calls a IterateContainerFilterProc function once for each
1600 file and directory found.
1602 theGlobals --> A pointer to a FSIterateContainerGlobals struct
1603 which contains the variables needed globally by
1604 all recusion levels of FSIterateContainerLevel.
1605 That makes FSIterateContainer thread safe since
1606 each call to it uses its own global world.
1607 It also contains the variables that do not need
1608 to be allocated each time FSIterateContainerLevel
1609 recurses. That lets FSIterateContainerLevel use
1610 less stack space per recursion level.
1615 FSIterateContainerLevel(
1616 FSIterateContainerGlobals
*theGlobals
)
1618 FSIterator iterator
;
1620 /* If maxLevels is zero, we aren't checking levels */
1621 /* If currentLevel < maxLevels, look at this level */
1622 if ( (theGlobals
->maxLevels
== 0) ||
1623 (theGlobals
->currentLevel
< theGlobals
->maxLevels
) )
1625 /* Open FSIterator for flat access to theGlobals->ref */
1626 theGlobals
->result
= FSOpenIterator(&theGlobals
->ref
, kFSIterateFlat
, &iterator
);
1627 require_noerr(theGlobals
->result
, FSOpenIterator
);
1629 ++theGlobals
->currentLevel
; /* Go to next level */
1631 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1634 theGlobals
->result
= FSGetCatalogInfoBulk(iterator
, 1, &theGlobals
->actualObjects
,
1635 &theGlobals
->containerChanged
, theGlobals
->whichInfo
, &theGlobals
->catalogInfo
,
1636 &theGlobals
->ref
, theGlobals
->specPtr
, theGlobals
->namePtr
);
1637 if ( (noErr
== theGlobals
->result
|| errFSNoMoreItems
== theGlobals
->result
) &&
1638 (0 != theGlobals
->actualObjects
) )
1640 /* Call the IterateFilterProc */
1641 theGlobals
->quitFlag
= CallIterateContainerFilterProc(theGlobals
->iterateFilter
,
1642 theGlobals
->containerChanged
, theGlobals
->currentLevel
,
1643 &theGlobals
->catalogInfo
, &theGlobals
->ref
,
1644 theGlobals
->specPtr
, theGlobals
->namePtr
, theGlobals
->yourDataPtr
);
1645 /* Is it a directory? */
1646 if ( 0 != (theGlobals
->catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
) )
1649 if ( !theGlobals
->quitFlag
)
1651 /* Dive again if the IterateFilterProc didn't say "quit" */
1652 FSIterateContainerLevel(theGlobals
);
1656 /* time to fall back a level? */
1657 } while ( (noErr
== theGlobals
->result
) && (!theGlobals
->quitFlag
) );
1659 /* errFSNoMoreItems is OK - it only means we hit the end of this level */
1660 /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
1661 if ( (errFSNoMoreItems
== theGlobals
->result
) ||
1662 (afpAccessDenied
== theGlobals
->result
) )
1664 theGlobals
->result
= noErr
;
1667 --theGlobals
->currentLevel
; /* Return to previous level as we leave */
1669 /* Close the FSIterator (closing an open iterator should never fail) */
1670 verify_noerr(FSCloseIterator(iterator
));
1678 /*****************************************************************************/
1682 const FSRef
*container
,
1683 ItemCount maxLevels
,
1684 FSCatalogInfoBitmap whichInfo
,
1687 IterateContainerFilterProcPtr iterateFilter
,
1691 FSIterateContainerGlobals theGlobals
;
1693 /* make sure there is an iterateFilter */
1694 require_action(iterateFilter
!= NULL
, NoIterateFilter
, result
= paramErr
);
1697 * set up the globals we need to access from the recursive routine
1699 theGlobals
.iterateFilter
= iterateFilter
;
1700 /* we need the node flags no matter what was requested so we can detect files vs. directories */
1701 theGlobals
.whichInfo
= whichInfo
| kFSCatInfoNodeFlags
;
1702 /* start with input container -- the first OpenIterator will ensure it is a directory */
1703 theGlobals
.ref
= *container
;
1706 theGlobals
.specPtr
= &theGlobals
.spec
;
1710 theGlobals
.specPtr
= NULL
;
1714 theGlobals
.namePtr
= &theGlobals
.name
;
1718 theGlobals
.namePtr
= NULL
;
1720 theGlobals
.yourDataPtr
= yourDataPtr
;
1721 theGlobals
.maxLevels
= maxLevels
;
1722 theGlobals
.currentLevel
= 0;
1723 theGlobals
.quitFlag
= false;
1724 theGlobals
.containerChanged
= false;
1725 theGlobals
.result
= noErr
;
1726 theGlobals
.actualObjects
= 0;
1728 /* here we go into recursion land... */
1729 FSIterateContainerLevel(&theGlobals
);
1730 result
= theGlobals
.result
;
1731 require_noerr(result
, FSIterateContainerLevel
);
1733 FSIterateContainerLevel
:
1739 /*****************************************************************************/
1742 FSGetDirectoryItems(
1743 const FSRef
*container
,
1744 FSRef
***refsHandle
, /* pointer to handle of FSRefs */
1746 Boolean
*containerChanged
)
1748 /* Grab items 10 at a time. */
1749 enum { kMaxItemsPerBulkCall
= 10 };
1753 FSIterator iterator
;
1754 FSRef refs
[kMaxItemsPerBulkCall
];
1755 ItemCount actualObjects
;
1758 /* check parameters */
1759 require_action((NULL
!= refsHandle
) && (NULL
!= numRefs
) && (NULL
!= containerChanged
),
1760 BadParameter
, result
= paramErr
);
1763 *containerChanged
= false;
1764 *refsHandle
= (FSRef
**)NewHandle(0);
1765 require_action(NULL
!= *refsHandle
, NewHandle
, result
= memFullErr
);
1767 /* open an FSIterator */
1768 result
= FSOpenIterator(container
, kFSIterateFlat
, &iterator
);
1769 require_noerr(result
, FSOpenIterator
);
1771 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1774 result
= FSGetCatalogInfoBulk(iterator
, kMaxItemsPerBulkCall
, &actualObjects
,
1775 &changed
, kFSCatInfoNone
, NULL
, refs
, NULL
, NULL
);
1777 /* if the container changed, set containerChanged for output, but keep going */
1780 *containerChanged
= changed
;
1783 /* any result other than noErr and errFSNoMoreItems is serious */
1784 require((noErr
== result
) || (errFSNoMoreItems
== result
), FSGetCatalogInfoBulk
);
1786 /* add objects to output array and count */
1787 if ( 0 != actualObjects
)
1789 /* concatenate the FSRefs to the end of the handle */
1790 PtrAndHand(refs
, (Handle
)*refsHandle
, actualObjects
* sizeof(FSRef
));
1791 memResult
= MemError();
1792 require_noerr_action(memResult
, MemoryAllocationFailed
, result
= memResult
);
1794 *numRefs
+= actualObjects
;
1796 } while ( noErr
== result
);
1798 verify_noerr(FSCloseIterator(iterator
)); /* closing an open iterator should never fail, but... */
1802 /**********************/
1804 MemoryAllocationFailed
:
1805 FSGetCatalogInfoBulk
:
1807 /* close the iterator */
1808 verify_noerr(FSCloseIterator(iterator
));
1811 /* dispose of handle if already allocated and clear the outputs */
1812 if ( NULL
!= *refsHandle
)
1814 DisposeHandle((Handle
)*refsHandle
);
1825 /*****************************************************************************/
1828 The GenerateUniqueName function generates a HFSUniStr255 name that is
1829 unique in both dir1 and dir2.
1831 startSeed --> A pointer to a long which is used to generate the
1833 <-- It is modified on output to a value which should
1834 be used to generate the next unique name.
1835 dir1 --> The first directory.
1836 dir2 --> The second directory.
1837 uniqueName <-- A pointer to a HFSUniStr255 where the unique name
1843 GenerateUniqueHFSUniStr(
1847 HFSUniStr255
*uniqueName
)
1853 unsigned char hexStr
[17] = "0123456789ABCDEF";
1855 /* set up the parameter block */
1856 pb
.name
= uniqueName
->unicode
;
1857 pb
.nameLength
= 8; /* always 8 characters */
1858 pb
.textEncodingHint
= kTextEncodingUnknown
;
1859 pb
.newRef
= &newRef
;
1861 /* loop until we get fnfErr with a filename in both directories */
1863 while ( fnfErr
!= result
)
1865 /* convert startSeed to 8 character Unicode string */
1866 uniqueName
->length
= 8;
1867 for ( i
= 0; i
< 8; ++i
)
1869 uniqueName
->unicode
[i
] = hexStr
[((*startSeed
>> ((7-i
)*4)) & 0xf)];
1874 result
= PBMakeFSRefUnicodeSync(&pb
);
1875 if ( fnfErr
== result
)
1879 result
= PBMakeFSRefUnicodeSync(&pb
);
1880 if ( fnfErr
!= result
)
1882 /* exit if anything other than noErr or fnfErr */
1883 require_noerr(result
, Dir2PBMakeFSRefUnicodeSyncFailed
);
1888 /* exit if anything other than noErr or fnfErr */
1889 require_noerr(result
, Dir1PBMakeFSRefUnicodeSyncFailed
);
1892 /* increment seed for next pass through loop, */
1893 /* or for next call to GenerateUniqueHFSUniStr */
1897 /* we have a unique file name which doesn't exist in dir1 or dir2 */
1900 Dir2PBMakeFSRefUnicodeSyncFailed
:
1901 Dir1PBMakeFSRefUnicodeSyncFailed
:
1906 /*****************************************************************************/
1909 FSExchangeObjectsCompat(
1910 const FSRef
*sourceRef
,
1911 const FSRef
*destRef
,
1912 FSRef
*newSourceRef
,
1917 /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
1918 kGetCatInformationMask
= (kFSCatInfoSettableInfo
|
1920 kFSCatInfoParentDirID
) &
1921 ~(kFSCatInfoContentMod
| kFSCatInfoAttrMod
),
1922 /* set everything possible except for mod dates */
1923 kSetCatinformationMask
= kFSCatInfoSettableInfo
&
1924 ~(kFSCatInfoContentMod
| kFSCatInfoAttrMod
)
1928 GetVolParmsInfoBuffer volParmsInfo
;
1930 FSCatalogInfo sourceCatalogInfo
; /* source file's catalog information */
1931 FSCatalogInfo destCatalogInfo
; /* destination file's catalog information */
1932 HFSUniStr255 sourceName
; /* source file's Unicode name */
1933 HFSUniStr255 destName
; /* destination file's Unicode name */
1934 FSRef sourceCurrentRef
; /* FSRef to current location of source file throughout this function */
1935 FSRef destCurrentRef
; /* FSRef to current location of destination file throughout this function */
1936 FSRef sourceParentRef
; /* FSRef to parent directory of source file */
1937 FSRef destParentRef
; /* FSRef to parent directory of destination file */
1938 HFSUniStr255 sourceUniqueName
; /* unique name given to source file while exchanging it with destination */
1939 HFSUniStr255 destUniqueName
; /* unique name given to destination file while exchanging it with source */
1940 long theSeed
; /* the seed for generating unique names */
1941 Boolean sameParentDirs
; /* true if source and destinatin parent directory is the same */
1943 /* check parameters */
1944 require_action((NULL
!= newSourceRef
) && (NULL
!= newDestRef
), BadParameter
, result
= paramErr
);
1946 /* output refs and current refs = input refs to start with */
1947 BlockMoveData(sourceRef
, newSourceRef
, sizeof(FSRef
));
1948 BlockMoveData(sourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
1950 BlockMoveData(destRef
, newDestRef
, sizeof(FSRef
));
1951 BlockMoveData(destRef
, &destCurrentRef
, sizeof(FSRef
));
1953 /* get source volume's vRefNum */
1954 result
= FSGetCatalogInfo(&sourceCurrentRef
, kFSCatInfoVolume
, &sourceCatalogInfo
, NULL
, NULL
, NULL
);
1955 require_noerr(result
, DetermineSourceVRefNumFailed
);
1957 /* see if that volume supports FSExchangeObjects */
1958 result
= FSGetVolParms(sourceCatalogInfo
.volume
, sizeof(GetVolParmsInfoBuffer
),
1959 &volParmsInfo
, &infoSize
);
1960 if ( (noErr
== result
) && VolSupportsFSExchangeObjects(&volParmsInfo
) )
1962 /* yes - use FSExchangeObjects */
1963 result
= FSExchangeObjects(sourceRef
, destRef
);
1967 /* no - emulate FSExchangeObjects */
1969 /* Note: The compatibility case won't work for files with *Btree control blocks. */
1970 /* Right now the only *Btree files are created by the system. */
1972 /* get all catalog information and Unicode names for each file */
1973 result
= FSGetCatalogInfo(&sourceCurrentRef
, kGetCatInformationMask
, &sourceCatalogInfo
, &sourceName
, NULL
, &sourceParentRef
);
1974 require_noerr(result
, SourceFSGetCatalogInfoFailed
);
1976 result
= FSGetCatalogInfo(&destCurrentRef
, kGetCatInformationMask
, &destCatalogInfo
, &destName
, NULL
, &destParentRef
);
1977 require_noerr(result
, DestFSGetCatalogInfoFailed
);
1979 /* make sure source and destination are on same volume */
1980 require_action(sourceCatalogInfo
.volume
== destCatalogInfo
.volume
, NotSameVolume
, result
= diffVolErr
);
1982 /* make sure both files are *really* files */
1983 require_action((0 == (sourceCatalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
)) &&
1984 (0 == (destCatalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
)), NotAFile
, result
= notAFileErr
);
1986 /* generate 2 names that are unique in both directories */
1987 theSeed
= 0x4a696d4c; /* a fine unlikely filename */
1989 result
= GenerateUniqueHFSUniStr(&theSeed
, &sourceParentRef
, &destParentRef
, &sourceUniqueName
);
1990 require_noerr(result
, GenerateUniqueHFSUniStr1Failed
);
1992 result
= GenerateUniqueHFSUniStr(&theSeed
, &sourceParentRef
, &destParentRef
, &destUniqueName
);
1993 require_noerr(result
, GenerateUniqueHFSUniStr2Failed
);
1995 /* rename sourceCurrentRef to sourceUniqueName */
1996 result
= FSRenameUnicode(&sourceCurrentRef
, sourceUniqueName
.length
, sourceUniqueName
.unicode
, kTextEncodingUnknown
, newSourceRef
);
1997 require_noerr(result
, FSRenameUnicode1Failed
);
1998 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2000 /* rename destCurrentRef to destUniqueName */
2001 result
= FSRenameUnicode(&destCurrentRef
, destUniqueName
.length
, destUniqueName
.unicode
, kTextEncodingUnknown
, newDestRef
);
2002 require_noerr(result
, FSRenameUnicode2Failed
);
2003 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
));
2005 /* are the source and destination parent directories the same? */
2006 sameParentDirs
= ( sourceCatalogInfo
.parentDirID
== destCatalogInfo
.parentDirID
);
2007 if ( !sameParentDirs
)
2009 /* move source file to dest parent directory */
2010 result
= FSMoveObject(&sourceCurrentRef
, &destParentRef
, newSourceRef
);
2011 require_noerr(result
, FSMoveObject1Failed
);
2012 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2014 /* move dest file to source parent directory */
2015 result
= FSMoveObject(&destCurrentRef
, &sourceParentRef
, newDestRef
);
2016 require_noerr(result
, FSMoveObject2Failed
);
2017 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
));
2020 /* At this point, the files are in their new locations (if they were moved). */
2021 /* The source file is named sourceUniqueName and is in the directory referred to */
2022 /* by destParentRef. The destination file is named destUniqueName and is in the */
2023 /* directory referred to by sourceParentRef. */
2025 /* give source file the dest file's catalog information except for mod dates */
2026 result
= FSSetCatalogInfo(&sourceCurrentRef
, kSetCatinformationMask
, &destCatalogInfo
);
2027 require_noerr(result
, FSSetCatalogInfo1Failed
);
2029 /* give dest file the source file's catalog information except for mod dates */
2030 result
= FSSetCatalogInfo(&destCurrentRef
, kSetCatinformationMask
, &sourceCatalogInfo
);
2031 require_noerr(result
, FSSetCatalogInfo2Failed
);
2033 /* rename source file with dest file's name */
2034 result
= FSRenameUnicode(&sourceCurrentRef
, destName
.length
, destName
.unicode
, destCatalogInfo
.textEncodingHint
, newSourceRef
);
2035 require_noerr(result
, FSRenameUnicode3Failed
);
2036 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2038 /* rename dest file with source file's name */
2039 result
= FSRenameUnicode(&destCurrentRef
, sourceName
.length
, sourceName
.unicode
, sourceCatalogInfo
.textEncodingHint
, newDestRef
);
2040 require_noerr(result
, FSRenameUnicode4Failed
);
2042 /* we're done with no errors, so swap newSourceRef and newDestRef */
2043 BlockMoveData(newDestRef
, newSourceRef
, sizeof(FSRef
));
2044 BlockMoveData(&sourceCurrentRef
, newDestRef
, sizeof(FSRef
));
2049 /**********************/
2051 /* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
2052 /* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
2053 /* state and location they ended up in so that both files can be found by the calling code. */
2055 FSRenameUnicode4Failed
:
2057 /* attempt to rename source file to sourceUniqueName */
2058 if ( noErr
== FSRenameUnicode(&sourceCurrentRef
, sourceUniqueName
.length
, sourceUniqueName
.unicode
, kTextEncodingUnknown
, newSourceRef
) )
2060 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2063 FSRenameUnicode3Failed
:
2065 /* attempt to restore dest file's catalog information */
2066 verify_noerr(FSSetCatalogInfo(&destCurrentRef
, kFSCatInfoSettableInfo
, &destCatalogInfo
));
2068 FSSetCatalogInfo2Failed
:
2070 /* attempt to restore source file's catalog information */
2071 verify_noerr(FSSetCatalogInfo(&sourceCurrentRef
, kFSCatInfoSettableInfo
, &sourceCatalogInfo
));
2073 FSSetCatalogInfo1Failed
:
2075 if ( !sameParentDirs
)
2077 /* attempt to move dest file back to dest directory */
2078 if ( noErr
== FSMoveObject(&destCurrentRef
, &destParentRef
, newDestRef
) )
2080 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
));
2084 FSMoveObject2Failed
:
2086 if ( !sameParentDirs
)
2088 /* attempt to move source file back to source directory */
2089 if ( noErr
== FSMoveObject(&sourceCurrentRef
, &sourceParentRef
, newSourceRef
) )
2091 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2095 FSMoveObject1Failed
:
2097 /* attempt to rename dest file to original name */
2098 verify_noerr(FSRenameUnicode(&destCurrentRef
, destName
.length
, destName
.unicode
, destCatalogInfo
.textEncodingHint
, newDestRef
));
2100 FSRenameUnicode2Failed
:
2102 /* attempt to rename source file to original name */
2103 verify_noerr(FSRenameUnicode(&sourceCurrentRef
, sourceName
.length
, sourceName
.unicode
, sourceCatalogInfo
.textEncodingHint
, newSourceRef
));
2105 FSRenameUnicode1Failed
:
2106 GenerateUniqueHFSUniStr2Failed
:
2107 GenerateUniqueHFSUniStr1Failed
:
2110 DestFSGetCatalogInfoFailed
:
2111 SourceFSGetCatalogInfoFailed
:
2112 DetermineSourceVRefNumFailed
:
2118 /*****************************************************************************/
2120 #pragma mark ----- Shared Environment Routines -----
2122 /*****************************************************************************/
2133 pb
.ioParam
.ioRefNum
= refNum
;
2134 pb
.ioParam
.ioReqCount
= rangeLength
;
2135 pb
.ioParam
.ioPosMode
= fsFromStart
;
2136 pb
.ioParam
.ioPosOffset
= rangeStart
;
2137 result
= PBLockRangeSync(&pb
);
2138 require_noerr(result
, PBLockRangeSync
);
2145 /*****************************************************************************/
2156 pb
.ioParam
.ioRefNum
= refNum
;
2157 pb
.ioParam
.ioReqCount
= rangeLength
;
2158 pb
.ioParam
.ioPosMode
= fsFromStart
;
2159 pb
.ioParam
.ioPosOffset
= rangeStart
;
2160 result
= PBUnlockRangeSync(&pb
);
2161 require_noerr(result
, PBUnlockRangeSync
);
2168 /*****************************************************************************/
2173 SInt32
*ownerID
, /* can be NULL */
2174 SInt32
*groupID
, /* can be NULL */
2175 SInt32
*accessRights
) /* can be NULL */
2181 /* get FSSpec from FSRef */
2182 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
);
2183 require_noerr(result
, FSGetCatalogInfo
);
2185 /* get directory access info for FSSpec */
2186 pb
.accessParam
.ioNamePtr
= (StringPtr
)spec
.name
;
2187 pb
.accessParam
.ioVRefNum
= spec
.vRefNum
;
2188 pb
.fileParam
.ioDirID
= spec
.parID
;
2189 result
= PBHGetDirAccessSync(&pb
);
2190 require_noerr(result
, PBHGetDirAccessSync
);
2192 /* return the IDs and access rights */
2193 if ( NULL
!= ownerID
)
2195 *ownerID
= pb
.accessParam
.ioACOwnerID
;
2197 if ( NULL
!= groupID
)
2199 *groupID
= pb
.accessParam
.ioACGroupID
;
2201 if ( NULL
!= accessRights
)
2203 *accessRights
= pb
.accessParam
.ioACAccess
;
2206 PBHGetDirAccessSync
:
2212 /*****************************************************************************/
2219 SInt32 accessRights
)
2227 /* Just the bits that can be set */
2228 kSetDirAccessSettableMask
= (kioACAccessBlankAccessMask
+
2229 kioACAccessEveryoneWriteMask
+ kioACAccessEveryoneReadMask
+ kioACAccessEveryoneSearchMask
+
2230 kioACAccessGroupWriteMask
+ kioACAccessGroupReadMask
+ kioACAccessGroupSearchMask
+
2231 kioACAccessOwnerWriteMask
+ kioACAccessOwnerReadMask
+ kioACAccessOwnerSearchMask
)
2234 /* get FSSpec from FSRef */
2235 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
);
2236 require_noerr(result
, FSGetCatalogInfo
);
2238 /* set directory access info for FSSpec */
2239 pb
.accessParam
.ioNamePtr
= (StringPtr
)spec
.name
;
2240 pb
.accessParam
.ioVRefNum
= spec
.vRefNum
;
2241 pb
.fileParam
.ioDirID
= spec
.parID
;
2242 pb
.accessParam
.ioACOwnerID
= ownerID
;
2243 pb
.accessParam
.ioACGroupID
= groupID
;
2244 pb
.accessParam
.ioACAccess
= accessRights
& kSetDirAccessSettableMask
;
2245 result
= PBHSetDirAccessSync(&pb
);
2246 require_noerr(result
, PBHSetDirAccessSync
);
2248 PBHSetDirAccessSync
:
2254 /*****************************************************************************/
2257 FSGetVolMountInfoSize(
2258 FSVolumeRefNum volRefNum
,
2264 /* check parameters */
2265 require_action(NULL
!= size
, BadParameter
, result
= paramErr
);
2267 pb
.ioParam
.ioNamePtr
= NULL
;
2268 pb
.ioParam
.ioVRefNum
= volRefNum
;
2269 pb
.ioParam
.ioBuffer
= (Ptr
)size
;
2270 result
= PBGetVolMountInfoSize(&pb
);
2271 require_noerr(result
, PBGetVolMountInfoSize
);
2273 PBGetVolMountInfoSize
:
2279 /*****************************************************************************/
2283 FSVolumeRefNum volRefNum
,
2289 /* check parameters */
2290 require_action(NULL
!= volMountInfo
, BadParameter
, result
= paramErr
);
2292 pb
.ioParam
.ioNamePtr
= NULL
;
2293 pb
.ioParam
.ioVRefNum
= volRefNum
;
2294 pb
.ioParam
.ioBuffer
= (Ptr
)volMountInfo
;
2295 result
= PBGetVolMountInfo(&pb
);
2296 require_noerr(result
, PBGetVolMountInfo
);
2304 /*****************************************************************************/
2308 const void *volMountInfo
,
2309 FSVolumeRefNum
*volRefNum
)
2314 /* check parameters */
2315 require_action(NULL
!= volRefNum
, BadParameter
, result
= paramErr
);
2317 pb
.ioParam
.ioBuffer
= (Ptr
)volMountInfo
;
2318 result
= PBVolumeMount(&pb
);
2319 require_noerr(result
, PBVolumeMount
);
2321 /* return the volume reference number */
2322 *volRefNum
= pb
.ioParam
.ioVRefNum
;
2330 /*****************************************************************************/
2334 FSVolumeRefNum volRefNum
,
2342 /* check parameters */
2343 require_action(NULL
!= name
, BadParameter
, result
= paramErr
);
2345 pb
.objParam
.ioNamePtr
= NULL
;
2346 pb
.objParam
.ioVRefNum
= volRefNum
;
2347 pb
.objParam
.ioObjType
= objType
;
2348 pb
.objParam
.ioObjNamePtr
= name
;
2349 pb
.objParam
.ioObjID
= ugID
;
2350 result
= PBHMapIDSync(&pb
);
2351 require_noerr(result
, PBHMapIDSync
);
2359 /*****************************************************************************/
2363 FSVolumeRefNum volRefNum
,
2364 ConstStr255Param name
,
2371 /* check parameters */
2372 require_action(NULL
!= ugID
, BadParameter
, result
= paramErr
);
2374 pb
.objParam
.ioNamePtr
= NULL
;
2375 pb
.objParam
.ioVRefNum
= volRefNum
;
2376 pb
.objParam
.ioObjType
= objType
;
2377 pb
.objParam
.ioObjNamePtr
= (StringPtr
)name
;
2378 result
= PBHMapNameSync(&pb
);
2379 require_noerr(result
, PBHMapNameSync
);
2381 /* return the user or group ID */
2382 *ugID
= pb
.objParam
.ioObjID
;
2390 /*****************************************************************************/
2394 const FSRef
*srcFileRef
,
2395 const FSRef
*dstDirectoryRef
,
2396 UniCharCount nameLength
,
2397 const UniChar
*copyName
, /* can be NULL (no rename during copy) */
2398 TextEncoding textEncodingHint
,
2399 FSRef
*newRef
) /* can be NULL */
2403 FSCatalogInfo catalogInfo
;
2406 GetVolParmsInfoBuffer volParmsInfo
;
2409 /* get source FSSpec from source FSRef */
2410 result
= FSGetCatalogInfo(srcFileRef
, kFSCatInfoNone
, NULL
, NULL
, &srcFileSpec
, NULL
);
2411 require_noerr(result
, FSGetCatalogInfo_srcFileRef
);
2413 /* Make sure the volume supports CopyFile */
2414 result
= FSGetVolParms(srcFileSpec
.vRefNum
, sizeof(GetVolParmsInfoBuffer
),
2415 &volParmsInfo
, &infoSize
);
2416 require_action((noErr
== result
) && VolHasCopyFile(&volParmsInfo
),
2417 NoCopyFileSupport
, result
= paramErr
);
2419 /* get destination volume reference number and destination directory ID from destination FSRef */
2420 result
= FSGetCatalogInfo(dstDirectoryRef
, kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2421 &catalogInfo
, NULL
, NULL
, NULL
);
2422 require_noerr(result
, FSGetCatalogInfo_dstDirectoryRef
);
2424 /* tell the server to copy the object */
2425 pb
.copyParam
.ioVRefNum
= srcFileSpec
.vRefNum
;
2426 pb
.copyParam
.ioDirID
= srcFileSpec
.parID
;
2427 pb
.copyParam
.ioNamePtr
= (StringPtr
)srcFileSpec
.name
;
2428 pb
.copyParam
.ioDstVRefNum
= catalogInfo
.volume
;
2429 pb
.copyParam
.ioNewDirID
= (long)catalogInfo
.nodeID
;
2430 pb
.copyParam
.ioNewName
= NULL
;
2431 if ( NULL
!= copyName
)
2433 result
= UnicodeNameGetHFSName(nameLength
, copyName
, textEncodingHint
, false, hfsName
);
2434 require_noerr(result
, UnicodeNameGetHFSName
);
2436 pb
.copyParam
.ioCopyName
= hfsName
;
2440 pb
.copyParam
.ioCopyName
= NULL
;
2442 result
= PBHCopyFileSync(&pb
);
2443 require_noerr(result
, PBHCopyFileSync
);
2445 if ( NULL
!= newRef
)
2447 verify_noerr(FSMakeFSRef(pb
.copyParam
.ioDstVRefNum
, pb
.copyParam
.ioNewDirID
,
2448 pb
.copyParam
.ioCopyName
, newRef
));
2452 UnicodeNameGetHFSName
:
2453 FSGetCatalogInfo_dstDirectoryRef
:
2455 FSGetCatalogInfo_srcFileRef
:
2460 /*****************************************************************************/
2464 const FSRef
*srcFileRef
,
2465 const FSRef
*dstDirectoryRef
,
2466 UniCharCount nameLength
,
2467 const UniChar
*moveName
, /* can be NULL (no rename during move) */
2468 TextEncoding textEncodingHint
,
2469 FSRef
*newRef
) /* can be NULL */
2473 FSCatalogInfo catalogInfo
;
2476 GetVolParmsInfoBuffer volParmsInfo
;
2479 /* get source FSSpec from source FSRef */
2480 result
= FSGetCatalogInfo(srcFileRef
, kFSCatInfoNone
, NULL
, NULL
, &srcFileSpec
, NULL
);
2481 require_noerr(result
, FSGetCatalogInfo_srcFileRef
);
2483 /* Make sure the volume supports MoveRename */
2484 result
= FSGetVolParms(srcFileSpec
.vRefNum
, sizeof(GetVolParmsInfoBuffer
),
2485 &volParmsInfo
, &infoSize
);
2486 require_action((noErr
== result
) && VolHasMoveRename(&volParmsInfo
),
2487 NoMoveRenameSupport
, result
= paramErr
);
2489 /* get destination volume reference number and destination directory ID from destination FSRef */
2490 result
= FSGetCatalogInfo(dstDirectoryRef
, kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2491 &catalogInfo
, NULL
, NULL
, NULL
);
2492 require_noerr(result
, FSGetCatalogInfo_dstDirectoryRef
);
2494 /* make sure the source and destination are on the same volume */
2495 require_action(srcFileSpec
.vRefNum
== catalogInfo
.volume
, NotSameVolume
, result
= diffVolErr
);
2497 /* tell the server to move and rename the object */
2498 pb
.copyParam
.ioVRefNum
= srcFileSpec
.vRefNum
;
2499 pb
.copyParam
.ioDirID
= srcFileSpec
.parID
;
2500 pb
.copyParam
.ioNamePtr
= (StringPtr
)srcFileSpec
.name
;
2501 pb
.copyParam
.ioNewDirID
= (long)catalogInfo
.nodeID
;
2502 pb
.copyParam
.ioNewName
= NULL
;
2503 if ( NULL
!= moveName
)
2505 result
= UnicodeNameGetHFSName(nameLength
, moveName
, textEncodingHint
, false, hfsName
);
2506 require_noerr(result
, UnicodeNameGetHFSName
);
2508 pb
.copyParam
.ioCopyName
= hfsName
;
2512 pb
.copyParam
.ioCopyName
= NULL
;
2514 result
= PBHMoveRenameSync(&pb
);
2515 require_noerr(result
, PBHMoveRenameSync
);
2517 if ( NULL
!= newRef
)
2519 verify_noerr(FSMakeFSRef(pb
.copyParam
.ioVRefNum
, pb
.copyParam
.ioNewDirID
,
2520 pb
.copyParam
.ioCopyName
, newRef
));
2524 UnicodeNameGetHFSName
:
2526 FSGetCatalogInfo_dstDirectoryRef
:
2527 NoMoveRenameSupport
:
2528 FSGetCatalogInfo_srcFileRef
:
2533 /*****************************************************************************/
2535 #pragma mark ----- File ID Routines -----
2537 /*****************************************************************************/
2541 FSVolumeRefNum volRefNum
,
2549 /* check parameters */
2550 require_action(NULL
!= ref
, BadParameter
, result
= paramErr
);
2552 /* resolve the file ID reference */
2554 pb
.ioNamePtr
= tempStr
;
2555 pb
.ioVRefNum
= volRefNum
;
2556 pb
.ioFileID
= fileID
;
2557 result
= PBResolveFileIDRefSync((HParmBlkPtr
)&pb
);
2558 require_noerr(result
, PBResolveFileIDRefSync
);
2560 /* and then make an FSRef to the file */
2561 result
= FSMakeFSRef(volRefNum
, pb
.ioSrcDirID
, tempStr
, ref
);
2562 require_noerr(result
, FSMakeFSRef
);
2565 PBResolveFileIDRefSync
:
2571 /*****************************************************************************/
2582 /* check parameters */
2583 require_action(NULL
!= fileID
, BadParameter
, result
= paramErr
);
2585 /* Get an FSSpec from the FSRef */
2586 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
);
2587 require_noerr(result
, FSGetCatalogInfo
);
2589 /* Create (or get) the file ID reference using the FSSpec */
2590 pb
.ioNamePtr
= (StringPtr
)spec
.name
;
2591 pb
.ioVRefNum
= spec
.vRefNum
;
2592 pb
.ioSrcDirID
= spec
.parID
;
2593 result
= PBCreateFileIDRefSync((HParmBlkPtr
)&pb
);
2594 require((noErr
== result
) || (fidExists
== result
) || (afpIDExists
== result
),
2595 PBCreateFileIDRefSync
);
2597 /* return the file ID reference */
2598 *fileID
= pb
.ioFileID
;
2600 PBCreateFileIDRefSync
:
2607 /*****************************************************************************/
2609 #pragma mark ----- Utility Routines -----
2611 /*****************************************************************************/
2615 ByteCount buffReqSize
,
2616 ByteCount
*buffActSize
)
2620 kSlopMemory
= 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
2625 /* check parameters */
2626 require_action(NULL
!= buffActSize
, BadParameter
, tempPtr
= NULL
);
2628 /* Make request a multiple of 4K bytes */
2629 buffReqSize
= buffReqSize
& 0xfffff000;
2631 if ( buffReqSize
< 0x00001000 )
2633 /* Request was smaller than 4K bytes - make it 4K */
2634 buffReqSize
= 0x00001000;
2637 /* Attempt to allocate the memory */
2638 tempPtr
= NewPtr(buffReqSize
);
2640 /* If request failed, go to backup plan */
2641 if ( (tempPtr
== NULL
) && (buffReqSize
> 0x00001000) )
2644 ** Try to get largest 4K byte block available
2645 ** leaving some slop for the toolbox if possible
2647 long freeMemory
= (FreeMem() - kSlopMemory
) & 0xfffff000;
2649 buffReqSize
= MaxBlock() & 0xfffff000;
2651 if ( buffReqSize
> freeMemory
)
2653 buffReqSize
= freeMemory
;
2656 if ( buffReqSize
== 0 )
2658 buffReqSize
= 0x00001000;
2661 tempPtr
= NewPtr(buffReqSize
);
2664 /* Return bytes allocated */
2665 if ( tempPtr
!= NULL
)
2667 *buffActSize
= buffReqSize
;
2679 /*****************************************************************************/
2686 return ( FSGetForkCBInfo(refNum
, 0, NULL
, NULL
, NULL
, ref
, NULL
) );
2689 /*****************************************************************************/
2693 const FSRef
*newDefault
,
2697 FSVolumeRefNum vRefNum
;
2699 FSCatalogInfo catalogInfo
;
2701 /* check parameters */
2702 require_action((NULL
!= newDefault
) && (NULL
!= oldDefault
), BadParameter
, result
= paramErr
);
2704 /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
2705 result
= FSGetCatalogInfo(newDefault
,
2706 kFSCatInfoNodeFlags
+ kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2707 &catalogInfo
, NULL
, NULL
, NULL
);
2708 require_noerr(result
, FSGetCatalogInfo
);
2710 /* Make sure newDefault is a directory */
2711 require_action(0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
), NewDefaultNotDirectory
,
2714 /* Get the current working directory. */
2715 result
= HGetVol(NULL
, &vRefNum
, &dirID
);
2716 require_noerr(result
, HGetVol
);
2718 /* Return the oldDefault FSRef */
2719 result
= FSMakeFSRef(vRefNum
, dirID
, NULL
, oldDefault
);
2720 require_noerr(result
, FSMakeFSRef
);
2722 /* Set the new current working directory */
2723 result
= HSetVol(NULL
, catalogInfo
.volume
, catalogInfo
.nodeID
);
2724 require_noerr(result
, HSetVol
);
2729 NewDefaultNotDirectory
:
2736 /*****************************************************************************/
2740 const FSRef
*oldDefault
)
2743 FSCatalogInfo catalogInfo
;
2745 /* check parameters */
2746 require_action(NULL
!= oldDefault
, BadParameter
, result
= paramErr
);
2748 /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
2749 result
= FSGetCatalogInfo(oldDefault
,
2750 kFSCatInfoNodeFlags
+ kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2751 &catalogInfo
, NULL
, NULL
, NULL
);
2752 require_noerr(result
, FSGetCatalogInfo
);
2754 /* Make sure oldDefault is a directory */
2755 require_action(0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
), OldDefaultNotDirectory
,
2758 /* Set the current working directory to oldDefault */
2759 result
= HSetVol(NULL
, catalogInfo
.volume
, catalogInfo
.nodeID
);
2760 require_noerr(result
, HSetVol
);
2763 OldDefaultNotDirectory
:
2770 /*****************************************************************************/