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
75 #include <Carbon/Carbon.h>
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 /*****************************************************************************/
227 FSVolumeRefNum volRefNum
,
229 GetVolParmsInfoBuffer
*volParmsInfo
,
230 UInt32
*actualInfoSize
)
235 /* check parameters */
236 require_action((NULL
!= volParmsInfo
) && (NULL
!= actualInfoSize
),
237 BadParameter
, result
= paramErr
);
239 pb
.ioParam
.ioNamePtr
= NULL
;
240 pb
.ioParam
.ioVRefNum
= volRefNum
;
241 pb
.ioParam
.ioBuffer
= (Ptr
)volParmsInfo
;
242 pb
.ioParam
.ioReqCount
= (SInt32
)bufferSize
;
243 result
= PBHGetVolParmsSync(&pb
);
244 require_noerr(result
, PBHGetVolParmsSync
);
246 /* return number of bytes the file system returned in volParmsInfo buffer */
247 *actualInfoSize
= (UInt32
)pb
.ioParam
.ioActCount
;
257 /*****************************************************************************/
262 FSVolumeRefNum
*vRefNum
)
265 FSCatalogInfo catalogInfo
;
267 /* check parameters */
268 require_action(NULL
!= vRefNum
, BadParameter
, result
= paramErr
);
270 /* get the volume refNum from the FSRef */
271 result
= FSGetCatalogInfo(ref
, kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
, NULL
);
272 require_noerr(result
, FSGetCatalogInfo
);
274 /* return volume refNum from catalogInfo */
275 *vRefNum
= catalogInfo
.volume
;
283 /*****************************************************************************/
287 FSVolumeRefNum volume
,
288 HFSUniStr255
*volumeName
, /* can be NULL */
289 UInt64
*freeBytes
, /* can be NULL */
290 UInt64
*totalBytes
) /* can be NULL */
295 /* ask for the volume's sizes only if needed */
296 result
= FSGetVolumeInfo(volume
, 0, NULL
,
297 (((NULL
!= freeBytes
) || (NULL
!= totalBytes
)) ? kFSVolInfoSizes
: kFSVolInfoNone
),
298 &info
, volumeName
, NULL
);
299 require_noerr(result
, FSGetVolumeInfo
);
301 if ( NULL
!= freeBytes
)
303 *freeBytes
= info
.freeBytes
;
305 if ( NULL
!= totalBytes
)
307 *totalBytes
= info
.totalBytes
;
315 /*****************************************************************************/
318 FSGetVolFileSystemID(
319 FSVolumeRefNum volume
,
320 UInt16
*fileSystemID
, /* can be NULL */
321 UInt16
*signature
) /* can be NULL */
326 result
= FSGetVolumeInfo(volume
, 0, NULL
, kFSVolInfoFSInfo
, &info
, NULL
, NULL
);
327 require_noerr(result
, FSGetVolumeInfo
);
329 if ( NULL
!= fileSystemID
)
331 *fileSystemID
= info
.filesystemID
;
333 if ( NULL
!= signature
)
335 *signature
= info
.signature
;
343 /*****************************************************************************/
347 FSRef
***volumeRefsHandle
, /* pointer to handle of FSRefs */
348 ItemCount
*numVolumes
)
352 ItemCount volumeIndex
;
355 /* check parameters */
356 require_action((NULL
!= volumeRefsHandle
) && (NULL
!= numVolumes
),
357 BadParameter
, result
= paramErr
);
362 /* Allocate a handle for the results */
363 *volumeRefsHandle
= (FSRef
**)NewHandle(0);
364 require_action(NULL
!= *volumeRefsHandle
, NewHandle
, result
= memFullErr
);
366 /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */
370 result
= FSGetVolumeInfo(0, volumeIndex
, NULL
, kFSVolInfoNone
, NULL
, NULL
, &ref
);
371 if ( noErr
== result
)
373 /* concatenate the FSRef to the end of the handle */
374 PtrAndHand(&ref
, (Handle
)*volumeRefsHandle
, sizeof(FSRef
));
375 memResult
= MemError();
376 require_noerr_action(memResult
, MemoryAllocationFailed
, result
= memResult
);
378 ++(*numVolumes
); /* increment the volume count */
379 ++volumeIndex
; /* and the volumeIndex to get the next volume*/
381 } while ( noErr
== result
);
383 /* nsvErr is OK -- it just means there are no more volumes */
384 require(nsvErr
== result
, FSGetVolumeInfo
);
388 /**********************/
390 MemoryAllocationFailed
:
393 /* dispose of handle if already allocated and clear the outputs */
394 if ( NULL
!= *volumeRefsHandle
)
396 DisposeHandle((Handle
)*volumeRefsHandle
);
397 *volumeRefsHandle
= NULL
;
407 /*****************************************************************************/
409 #pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
411 /*****************************************************************************/
420 /* check parameters */
421 require_action(NULL
!= spec
, BadParameter
, result
= paramErr
);
423 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
);
424 require_noerr(result
, FSGetCatalogInfo
);
432 /*****************************************************************************/
436 FSVolumeRefNum volRefNum
,
438 ConstStr255Param name
,
444 /* check parameters */
445 require_action(NULL
!= ref
, BadParameter
, result
= paramErr
);
447 pb
.ioVRefNum
= volRefNum
;
449 pb
.ioNamePtr
= (StringPtr
)name
;
451 result
= PBMakeFSRefSync(&pb
);
452 require_noerr(result
, PBMakeFSRefSync
);
460 /*****************************************************************************/
466 ConstStr255Param name
,
473 /* check parameters */
474 require_action(NULL
!= path
, BadParameter
, result
= paramErr
);
476 /* convert the inputs to an FSRef */
477 result
= FSMakeFSRef(volRefNum
, dirID
, name
, &ref
);
478 require_noerr(result
, FSMakeFSRef
);
480 /* and then convert the FSRef to a path */
481 result
= FSRefMakePath(&ref
, path
, maxPathSize
);
482 require_noerr(result
, FSRefMakePath
);
491 /*****************************************************************************/
497 Boolean
*isDirectory
) /* can be NULL */
502 /* check parameters */
503 require_action(NULL
!= spec
, BadParameter
, result
= paramErr
);
505 /* convert the POSIX path to an FSRef */
506 result
= FSPathMakeRef(path
, &ref
, isDirectory
);
507 require_noerr(result
, FSPathMakeRef
);
509 /* and then convert the FSRef to an FSSpec */
510 result
= FSGetCatalogInfo(&ref
, kFSCatInfoNone
, NULL
, NULL
, spec
, NULL
);
511 require_noerr(result
, FSGetCatalogInfo
);
520 /*****************************************************************************/
523 UnicodeNameGetHFSName(
524 UniCharCount nameLength
,
526 TextEncoding textEncodingHint
,
527 Boolean isVolumeName
,
531 ByteCount unicodeByteLength
;
532 ByteCount unicodeBytesConverted
;
533 ByteCount actualPascalBytes
;
534 UnicodeMapping uMapping
;
535 UnicodeToTextInfo utInfo
;
537 /* check parameters */
538 require_action(NULL
!= hfsName
, BadParameter
, result
= paramErr
);
540 /* make sure output is valid in case we get errors or there's nothing to convert */
543 unicodeByteLength
= nameLength
* sizeof(UniChar
);
544 if ( 0 == unicodeByteLength
)
551 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
552 if ( kTextEncodingUnknown
== textEncodingHint
)
557 script
= (ScriptCode
)GetScriptManagerVariable(smSysScript
);
558 region
= (RegionCode
)GetScriptManagerVariable(smRegionCode
);
559 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, region
,
560 NULL
, &textEncodingHint
);
561 if ( paramErr
== result
)
563 /* ok, ignore the region and try again */
564 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
,
565 kTextRegionDontCare
, NULL
, &textEncodingHint
);
567 if ( noErr
!= result
)
569 /* ok... try something */
570 textEncodingHint
= kTextEncodingMacRoman
;
574 uMapping
.unicodeEncoding
= CreateTextEncoding(kTextEncodingUnicodeV2_0
,
575 kUnicodeCanonicalDecompVariant
, kUnicode16BitFormat
);
576 uMapping
.otherEncoding
= GetTextEncodingBase(textEncodingHint
);
577 uMapping
.mappingVersion
= kUnicodeUseHFSPlusMapping
;
579 result
= CreateUnicodeToTextInfo(&uMapping
, &utInfo
);
580 require_noerr(result
, CreateUnicodeToTextInfo
);
582 result
= ConvertFromUnicodeToText(utInfo
, unicodeByteLength
, name
, kUnicodeLooseMappingsMask
,
583 0, NULL
, 0, NULL
, /* offsetCounts & offsetArrays */
584 isVolumeName
? kHFSMaxVolumeNameChars
: kHFSMaxFileNameChars
,
585 &unicodeBytesConverted
, &actualPascalBytes
, &hfsName
[1]);
586 require_noerr(result
, ConvertFromUnicodeToText
);
588 hfsName
[0] = (unsigned char)actualPascalBytes
; /* fill in length byte */
590 ConvertFromUnicodeToText
:
592 /* verify the result in debug builds -- there's really not anything you can do if it fails */
593 verify_noerr(DisposeUnicodeToTextInfo(&utInfo
));
596 CreateUnicodeToTextInfo
:
602 /*****************************************************************************/
605 HFSNameGetUnicodeName(
606 ConstStr31Param hfsName
,
607 TextEncoding textEncodingHint
,
608 HFSUniStr255
*unicodeName
)
610 ByteCount unicodeByteLength
;
612 UnicodeMapping uMapping
;
613 TextToUnicodeInfo tuInfo
;
614 ByteCount pascalCharsRead
;
616 /* check parameters */
617 require_action(NULL
!= unicodeName
, BadParameter
, result
= paramErr
);
619 /* make sure output is valid in case we get errors or there's nothing to convert */
620 unicodeName
->length
= 0;
622 if ( 0 == StrLength(hfsName
) )
628 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
629 if ( kTextEncodingUnknown
== textEncodingHint
)
634 script
= GetScriptManagerVariable(smSysScript
);
635 region
= GetScriptManagerVariable(smRegionCode
);
636 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
, region
,
637 NULL
, &textEncodingHint
);
638 if ( paramErr
== result
)
640 /* ok, ignore the region and try again */
641 result
= UpgradeScriptInfoToTextEncoding(script
, kTextLanguageDontCare
,
642 kTextRegionDontCare
, NULL
, &textEncodingHint
);
644 if ( noErr
!= result
)
646 /* ok... try something */
647 textEncodingHint
= kTextEncodingMacRoman
;
651 uMapping
.unicodeEncoding
= CreateTextEncoding(kTextEncodingUnicodeV2_0
,
652 kUnicodeCanonicalDecompVariant
, kUnicode16BitFormat
);
653 uMapping
.otherEncoding
= GetTextEncodingBase(textEncodingHint
);
654 uMapping
.mappingVersion
= kUnicodeUseHFSPlusMapping
;
656 result
= CreateTextToUnicodeInfo(&uMapping
, &tuInfo
);
657 require_noerr(result
, CreateTextToUnicodeInfo
);
659 result
= ConvertFromTextToUnicode(tuInfo
, hfsName
[0], &hfsName
[1],
660 0, /* no control flag bits */
661 0, NULL
, 0, NULL
, /* offsetCounts & offsetArrays */
662 sizeof(unicodeName
->unicode
), /* output buffer size in bytes */
663 &pascalCharsRead
, &unicodeByteLength
, unicodeName
->unicode
);
664 require_noerr(result
, ConvertFromTextToUnicode
);
666 /* convert from byte count to char count */
667 unicodeName
->length
= unicodeByteLength
/ sizeof(UniChar
);
669 ConvertFromTextToUnicode
:
671 /* verify the result in debug builds -- there's really not anything you can do if it fails */
672 verify_noerr(DisposeTextToUnicodeInfo(&tuInfo
));
675 CreateTextToUnicodeInfo
:
681 /*****************************************************************************/
683 #pragma mark ----- File/Directory Manipulation Routines -----
685 /*****************************************************************************/
687 Boolean
FSRefValid(const FSRef
*ref
)
689 return ( noErr
== FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, NULL
, NULL
) );
692 /*****************************************************************************/
700 FSCatalogInfo catalogInfo
;
702 /* check parameters */
703 require_action(NULL
!= parentRef
, BadParameter
, result
= paramErr
);
705 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeID
, &catalogInfo
, NULL
, NULL
, parentRef
);
706 require_noerr(result
, FSGetCatalogInfo
);
709 * Note: FSRefs always point to real file system objects. So, there cannot
710 * be a FSRef to the parent of volume root directories. Early versions of
711 * Mac OS X do not handle this case correctly and incorrectly return a
712 * FSRef for the parent of volume root directories instead of returning an
713 * invalid FSRef (a cleared FSRef is invalid). The next three lines of code
714 * ensure that you won't run into this bug. WW9D!
716 if ( fsRtDirID
== catalogInfo
.nodeID
)
718 /* clear parentRef and return noErr which is the proper behavior */
719 memset(parentRef
, 0, sizeof(FSRef
));
728 /*****************************************************************************/
733 HFSUniStr255
*outName
)
737 /* check parameters */
738 require_action(NULL
!= outName
, BadParameter
, result
= paramErr
);
740 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, outName
, NULL
, NULL
);
741 require_noerr(result
, FSGetCatalogInfo
);
749 /*****************************************************************************/
754 long *nodeID
, /* can be NULL */
755 Boolean
*isDirectory
) /* can be NULL */
758 FSCatalogInfo catalogInfo
;
759 FSCatalogInfoBitmap whichInfo
;
761 /* determine what catalog information to get */
762 whichInfo
= kFSCatInfoNone
; /* start with none */
763 if ( NULL
!= nodeID
)
765 whichInfo
|= kFSCatInfoNodeID
;
767 if ( NULL
!= isDirectory
)
769 whichInfo
|= kFSCatInfoNodeFlags
;
772 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
773 require_noerr(result
, FSGetCatalogInfo
);
775 if ( NULL
!= nodeID
)
777 *nodeID
= catalogInfo
.nodeID
;
779 if ( NULL
!= isDirectory
)
781 *isDirectory
= (0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
));
789 /*****************************************************************************/
792 FSGetUserPrivilegesPermissions(
794 UInt8
*userPrivileges
, /* can be NULL */
795 UInt32 permissions
[4]) /* can be NULL */
798 FSCatalogInfo catalogInfo
;
799 FSCatalogInfoBitmap whichInfo
;
801 /* determine what catalog information to get */
802 whichInfo
= kFSCatInfoNone
; /* start with none */
803 if ( NULL
!= userPrivileges
)
805 whichInfo
|= kFSCatInfoUserPrivs
;
807 if ( NULL
!= permissions
)
809 whichInfo
|= kFSCatInfoPermissions
;
812 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
813 require_noerr(result
, FSGetCatalogInfo
);
815 if ( NULL
!= userPrivileges
)
817 *userPrivileges
= catalogInfo
.userPrivileges
;
819 if ( NULL
!= permissions
)
821 BlockMoveData(&catalogInfo
.permissions
, permissions
, sizeof(UInt32
) * 4);
829 /*****************************************************************************/
836 FSCatalogInfo catalogInfo
;
837 FSVolumeInfo volumeInfo
;
839 /* get nodeFlags and vRefNum for container */
840 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags
+ kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
,NULL
);
841 require_noerr(result
, FSGetCatalogInfo
);
843 /* is file locked? */
844 if ( 0 != (catalogInfo
.nodeFlags
& kFSNodeLockedMask
) )
846 result
= fLckdErr
; /* file is locked */
850 /* file isn't locked, but is volume locked? */
852 /* get volume flags */
853 result
= FSGetVolumeInfo(catalogInfo
.volume
, 0, NULL
, kFSVolInfoFlags
, &volumeInfo
, NULL
, NULL
);
854 require_noerr(result
, FSGetVolumeInfo
);
856 if ( 0 != (volumeInfo
.flags
& kFSVolFlagHardwareLockedMask
) )
858 result
= wPrErr
; /* volume locked by hardware */
860 else if ( 0 != (volumeInfo
.flags
& kFSVolFlagSoftwareLockedMask
) )
862 result
= vLckdErr
; /* volume locked by software */
872 /*****************************************************************************/
877 UInt64
*dataLogicalSize
, /* can be NULL */
878 UInt64
*rsrcLogicalSize
) /* can be NULL */
881 FSCatalogInfoBitmap whichInfo
;
882 FSCatalogInfo catalogInfo
;
884 whichInfo
= kFSCatInfoNodeFlags
;
885 if ( NULL
!= dataLogicalSize
)
887 /* get data fork size */
888 whichInfo
|= kFSCatInfoDataSizes
;
890 if ( NULL
!= rsrcLogicalSize
)
892 /* get resource fork size */
893 whichInfo
|= kFSCatInfoRsrcSizes
;
896 /* get nodeFlags and catalog info */
897 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
,NULL
);
898 require_noerr(result
, FSGetCatalogInfo
);
900 /* make sure FSRef was to a file */
901 require_action(0 == (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
), FSRefNotFile
, result
= notAFileErr
);
903 if ( NULL
!= dataLogicalSize
)
905 /* return data fork size */
906 *dataLogicalSize
= catalogInfo
.dataLogicalSize
;
908 if ( NULL
!= rsrcLogicalSize
)
910 /* return resource fork size */
911 *rsrcLogicalSize
= catalogInfo
.rsrcLogicalSize
;
920 /*****************************************************************************/
925 UInt64
*totalLogicalSize
, /* can be NULL */
926 UInt64
*totalPhysicalSize
, /* can be NULL */
927 ItemCount
*forkCount
) /* can be NULL */
930 CatPositionRec forkIterator
;
933 UInt64 forkPhysicalSize
;
934 UInt64
*forkPhysicalSizePtr
;
936 /* Determine if forkSize needed */
937 if ( NULL
!= totalLogicalSize
)
939 *totalLogicalSize
= 0;
940 forkSizePtr
= &forkSize
;
947 /* Determine if forkPhysicalSize is needed */
948 if ( NULL
!= totalPhysicalSize
)
950 *totalPhysicalSize
= 0;
951 forkPhysicalSizePtr
= &forkPhysicalSize
;
955 forkPhysicalSizePtr
= NULL
;
958 /* zero fork count if returning it */
959 if ( NULL
!= forkCount
)
964 /* Iterate through the forks to get the sizes */
965 forkIterator
.initialize
= 0;
968 result
= FSIterateForks(ref
, &forkIterator
, NULL
, forkSizePtr
, forkPhysicalSizePtr
);
969 if ( noErr
== result
)
971 if ( NULL
!= totalLogicalSize
)
973 *totalLogicalSize
+= forkSize
;
976 if ( NULL
!= totalPhysicalSize
)
978 *totalPhysicalSize
+= forkPhysicalSize
;
981 if ( NULL
!= forkCount
)
986 } while ( noErr
== result
);
988 /* any error result other than errFSNoMoreItems is serious */
989 require(errFSNoMoreItems
== result
, FSIterateForks
);
999 /*****************************************************************************/
1006 FSCatalogInfo catalogInfo
;
1007 UTCDateTime oldDateTime
;
1008 #if !BuildingMoreFilesXForMacOS9
1010 Boolean notifyParent
;
1013 #if !BuildingMoreFilesXForMacOS9
1014 /* Get the node flags, the content modification date and time, and the parent ref */
1015 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags
+ kFSCatInfoContentMod
, &catalogInfo
, NULL
, NULL
, &parentRef
);
1016 require_noerr(result
, FSGetCatalogInfo
);
1018 /* Notify the parent if this is a file */
1019 notifyParent
= (0 == (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
));
1021 /* Get the content modification date and time */
1022 result
= FSGetCatalogInfo(ref
, kFSCatInfoContentMod
, &catalogInfo
, NULL
, NULL
, NULL
);
1023 require_noerr(result
, FSGetCatalogInfo
);
1026 oldDateTime
= catalogInfo
.contentModDate
;
1028 /* Get the current date and time */
1029 result
= GetUTCDateTime(&catalogInfo
.contentModDate
, kUTCDefaultOptions
);
1030 require_noerr(result
, GetUTCDateTime
);
1032 /* if the old date and time is the the same as the current, bump the seconds by one */
1033 if ( (catalogInfo
.contentModDate
.fraction
== oldDateTime
.fraction
) &&
1034 (catalogInfo
.contentModDate
.lowSeconds
== oldDateTime
.lowSeconds
) &&
1035 (catalogInfo
.contentModDate
.highSeconds
== oldDateTime
.highSeconds
) )
1037 ++catalogInfo
.contentModDate
.lowSeconds
;
1038 if ( 0 == catalogInfo
.contentModDate
.lowSeconds
)
1040 ++catalogInfo
.contentModDate
.highSeconds
;
1044 /* Bump the content modification date and time */
1045 result
= FSSetCatalogInfo(ref
, kFSCatInfoContentMod
, &catalogInfo
);
1046 require_noerr(result
, FSSetCatalogInfo
);
1048 #if !BuildingMoreFilesXForMacOS9
1050 * The problem with FNNotify is that it is not available under Mac OS 9
1051 * and there's no way to test for that except for looking for the symbol
1052 * or something. So, I'll just conditionalize this for those who care
1053 * to send a notification.
1056 /* Send a notification for the parent of the file, or for the directory */
1057 result
= FNNotify(notifyParent
? &parentRef
: ref
, kFNDirectoryModifiedMessage
, kNilOptions
);
1058 require_noerr(result
, FNNotify
);
1061 /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */
1067 /**********************/
1075 /*****************************************************************************/
1080 FinderInfo
*info
, /* can be NULL */
1081 ExtendedFinderInfo
*extendedInfo
, /* can be NULL */
1082 Boolean
*isDirectory
) /* can be NULL */
1085 FSCatalogInfo catalogInfo
;
1086 FSCatalogInfoBitmap whichInfo
;
1088 /* determine what catalog information is really needed */
1089 whichInfo
= kFSCatInfoNone
;
1093 /* get FinderInfo */
1094 whichInfo
|= kFSCatInfoFinderInfo
;
1097 if ( NULL
!= extendedInfo
)
1099 /* get ExtendedFinderInfo */
1100 whichInfo
|= kFSCatInfoFinderXInfo
;
1103 if ( NULL
!= isDirectory
)
1105 whichInfo
|= kFSCatInfoNodeFlags
;
1108 result
= FSGetCatalogInfo(ref
, whichInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
1109 require_noerr(result
, FSGetCatalogInfo
);
1111 /* return FinderInfo if requested */
1114 BlockMoveData(catalogInfo
.finderInfo
, info
, sizeof(FinderInfo
));
1117 /* return ExtendedFinderInfo if requested */
1118 if ( NULL
!= extendedInfo
)
1120 BlockMoveData(catalogInfo
.extFinderInfo
, extendedInfo
, sizeof(ExtendedFinderInfo
));
1123 /* set isDirectory Boolean if requested */
1124 if ( NULL
!= isDirectory
)
1126 *isDirectory
= (0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
));
1134 /*****************************************************************************/
1139 const FinderInfo
*info
,
1140 const ExtendedFinderInfo
*extendedInfo
)
1143 FSCatalogInfo catalogInfo
;
1144 FSCatalogInfoBitmap whichInfo
;
1146 /* determine what catalog information will be set */
1147 whichInfo
= kFSCatInfoNone
; /* start with none */
1150 /* set FinderInfo */
1151 whichInfo
|= kFSCatInfoFinderInfo
;
1152 BlockMoveData(info
, catalogInfo
.finderInfo
, sizeof(FinderInfo
));
1154 if ( NULL
!= extendedInfo
)
1156 /* set ExtendedFinderInfo */
1157 whichInfo
|= kFSCatInfoFinderXInfo
;
1158 BlockMoveData(extendedInfo
, catalogInfo
.extFinderInfo
, sizeof(ExtendedFinderInfo
));
1161 result
= FSSetCatalogInfo(ref
, whichInfo
, &catalogInfo
);
1162 require_noerr(result
, FSGetCatalogInfo
);
1169 /*****************************************************************************/
1172 FSChangeCreatorType(
1178 FSCatalogInfo catalogInfo
;
1181 /* get nodeFlags, finder info, and parent FSRef */
1182 result
= FSGetCatalogInfo(ref
, kFSCatInfoNodeFlags
+ kFSCatInfoFinderInfo
, &catalogInfo
, NULL
, NULL
, &parentRef
);
1183 require_noerr(result
, FSGetCatalogInfo
);
1185 /* make sure FSRef was to a file */
1186 require_action(0 == (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
), FSRefNotFile
, result
= notAFileErr
);
1188 /* If fileType not 0x00000000, change fileType */
1189 if ( fileType
!= (OSType
)0x00000000 )
1191 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileType
= fileType
;
1194 /* If creator not 0x00000000, change creator */
1195 if ( fileCreator
!= (OSType
)0x00000000 )
1197 ((FileInfo
*)&catalogInfo
.finderInfo
)->fileCreator
= fileCreator
;
1200 /* now, save the new information back to disk */
1201 result
= FSSetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
);
1202 require_noerr(result
, FSSetCatalogInfo
);
1204 /* and attempt to bump the parent directory's mod date to wake up */
1205 /* the Finder to the change we just made (ignore errors from this) */
1206 verify_noerr(FSBumpDate(&parentRef
));
1215 /*****************************************************************************/
1218 FSChangeFinderFlags(
1224 FSCatalogInfo catalogInfo
;
1227 /* get the current finderInfo */
1228 result
= FSGetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
, NULL
, NULL
, &parentRef
);
1229 require_noerr(result
, FSGetCatalogInfo
);
1231 /* set or clear the appropriate bits in the finderInfo.finderFlags */
1234 /* OR in the bits */
1235 ((FileInfo
*)&catalogInfo
.finderInfo
)->finderFlags
|= flagBits
;
1239 /* AND out the bits */
1240 ((FileInfo
*)&catalogInfo
.finderInfo
)->finderFlags
&= ~flagBits
;
1243 /* save the modified finderInfo */
1244 result
= FSSetCatalogInfo(ref
, kFSCatInfoFinderInfo
, &catalogInfo
);
1245 require_noerr(result
, FSSetCatalogInfo
);
1247 /* and attempt to bump the parent directory's mod date to wake up the Finder */
1248 /* to the change we just made (ignore errors from this) */
1249 verify_noerr(FSBumpDate(&parentRef
));
1257 /*****************************************************************************/
1263 return ( FSChangeFinderFlags(ref
, true, kIsInvisible
) );
1270 return ( FSChangeFinderFlags(ref
, false, kIsInvisible
) );
1273 /*****************************************************************************/
1279 return ( FSChangeFinderFlags(ref
, true, kNameLocked
) );
1286 return ( FSChangeFinderFlags(ref
, false, kNameLocked
) );
1289 /*****************************************************************************/
1295 return ( FSChangeFinderFlags(ref
, true, kIsStationery
) );
1299 FSClearIsStationery(
1302 return ( FSChangeFinderFlags(ref
, false, kIsStationery
) );
1305 /*****************************************************************************/
1311 return ( FSChangeFinderFlags(ref
, true, kHasCustomIcon
) );
1315 FSClearHasCustomIcon(
1318 return ( FSChangeFinderFlags(ref
, false, kHasCustomIcon
) );
1321 /*****************************************************************************/
1324 FSClearHasBeenInited(
1327 return ( FSChangeFinderFlags(ref
, false, kHasBeenInited
) );
1330 /*****************************************************************************/
1333 FSCopyFileMgrAttributes(
1334 const FSRef
*sourceRef
,
1335 const FSRef
*destinationRef
,
1336 Boolean copyLockBit
)
1339 FSCatalogInfo catalogInfo
;
1341 /* get the source information */
1342 result
= FSGetCatalogInfo(sourceRef
, kFSCatInfoSettableInfo
, &catalogInfo
, NULL
, NULL
, NULL
);
1343 require_noerr(result
, FSGetCatalogInfo
);
1345 /* don't copy the hasBeenInited bit; clear it */
1346 ((FileInfo
*)&catalogInfo
.finderInfo
)->finderFlags
&= ~kHasBeenInited
;
1348 /* should the locked bit be copied? */
1351 /* no, make sure the locked bit is clear */
1352 catalogInfo
.nodeFlags
&= ~kFSNodeLockedMask
;
1355 /* set the destination information */
1356 result
= FSSetCatalogInfo(destinationRef
, kFSCatInfoSettableInfo
, &catalogInfo
);
1357 require_noerr(result
, FSSetCatalogInfo
);
1365 /*****************************************************************************/
1368 FSMoveRenameObjectUnicode(
1370 const FSRef
*destDirectory
,
1371 UniCharCount nameLength
,
1372 const UniChar
*name
, /* can be NULL (no rename during move) */
1373 TextEncoding textEncodingHint
,
1374 FSRef
*newRef
) /* if function fails along the way, newRef is final location of file */
1377 FSVolumeRefNum vRefNum
;
1378 FSCatalogInfo catalogInfo
;
1379 FSRef originalDirectory
;
1380 TextEncoding originalTextEncodingHint
;
1381 HFSUniStr255 originalName
;
1382 HFSUniStr255 uniqueName
; /* unique name given to object while moving it to destination */
1383 long theSeed
; /* the seed for generating unique names */
1385 /* check parameters */
1386 require_action(NULL
!= newRef
, BadParameter
, result
= paramErr
);
1388 /* newRef = input to start with */
1389 BlockMoveData(ref
, newRef
, sizeof(FSRef
));
1391 /* get destDirectory's vRefNum */
1392 result
= FSGetCatalogInfo(destDirectory
, kFSCatInfoVolume
, &catalogInfo
, NULL
, NULL
, NULL
);
1393 require_noerr(result
, DestinationBad
);
1396 vRefNum
= catalogInfo
.volume
;
1398 /* get ref's vRefNum, TextEncoding, name and parent directory*/
1399 result
= FSGetCatalogInfo(ref
, kFSCatInfoTextEncoding
+ kFSCatInfoVolume
, &catalogInfo
, &originalName
, NULL
, &originalDirectory
);
1400 require_noerr(result
, SourceBad
);
1402 /* save TextEncoding */
1403 originalTextEncodingHint
= catalogInfo
.textEncodingHint
;
1405 /* make sure ref and destDirectory are on same volume */
1406 require_action(vRefNum
== catalogInfo
.volume
, NotSameVolume
, result
= diffVolErr
);
1408 /* Skip a few steps if we're not renaming */
1411 /* generate a name that is unique in both directories */
1412 theSeed
= 0x4a696d4c; /* a fine unlikely filename */
1414 result
= GenerateUniqueHFSUniStr(&theSeed
, &originalDirectory
, destDirectory
, &uniqueName
);
1415 require_noerr(result
, GenerateUniqueHFSUniStrFailed
);
1417 /* Rename the object to uniqueName */
1418 result
= FSRenameUnicode(ref
, uniqueName
.length
, uniqueName
.unicode
, kTextEncodingUnknown
, newRef
);
1419 require_noerr(result
, FSRenameUnicodeBeforeMoveFailed
);
1421 /* Move object to its new home */
1422 result
= FSMoveObject(newRef
, destDirectory
, newRef
);
1423 require_noerr(result
, FSMoveObjectAfterRenameFailed
);
1425 /* Rename the object to new name */
1426 result
= FSRenameUnicode(ref
, nameLength
, name
, textEncodingHint
, newRef
);
1427 require_noerr(result
, FSRenameUnicodeAfterMoveFailed
);
1431 /* Move object to its new home */
1432 result
= FSMoveObject(newRef
, destDirectory
, newRef
);
1433 require_noerr(result
, FSMoveObjectNoRenameFailed
);
1441 * failure handling code when renaming
1444 FSRenameUnicodeAfterMoveFailed
:
1446 /* Error handling: move object back to original location - ignore errors */
1447 verify_noerr(FSMoveObject(newRef
, &originalDirectory
, newRef
));
1449 FSMoveObjectAfterRenameFailed
:
1451 /* Error handling: rename object back to original name - ignore errors */
1452 verify_noerr(FSRenameUnicode(newRef
, originalName
.length
, originalName
.unicode
, originalTextEncodingHint
, newRef
));
1454 FSRenameUnicodeBeforeMoveFailed
:
1455 GenerateUniqueHFSUniStrFailed
:
1458 * failure handling code for renaming or not
1460 FSMoveObjectNoRenameFailed
:
1469 /*****************************************************************************/
1472 The FSDeleteContainerLevel function deletes the contents of a container
1473 directory. All files and subdirectories in the specified container are
1474 deleted. If a locked file or directory is encountered, it is unlocked
1475 and then deleted. If any unexpected errors are encountered,
1476 FSDeleteContainerLevel quits and returns to the caller.
1478 container --> FSRef to a directory.
1479 theGlobals --> A pointer to a FSDeleteContainerGlobals struct
1480 which contains the variables that do not need to
1481 be allocated each time FSDeleteContainerLevel
1482 recurses. That lets FSDeleteContainerLevel use
1483 less stack space per recursion level.
1488 FSDeleteContainerLevel(
1489 const FSRef
*container
,
1490 FSDeleteContainerGlobals
*theGlobals
)
1493 FSIterator iterator
;
1497 /* Open FSIterator for flat access and give delete optimization hint */
1498 theGlobals
->result
= FSOpenIterator(container
, kFSIterateFlat
+ kFSIterateDelete
, &iterator
);
1499 require_noerr(theGlobals
->result
, FSOpenIterator
);
1501 /* delete the contents of the directory */
1504 /* get 1 item to delete */
1505 theGlobals
->result
= FSGetCatalogInfoBulk(iterator
, 1, &theGlobals
->actualObjects
,
1506 NULL
, kFSCatInfoNodeFlags
, &theGlobals
->catalogInfo
,
1507 &itemToDelete
, NULL
, NULL
);
1508 if ( (noErr
== theGlobals
->result
) && (1 == theGlobals
->actualObjects
) )
1510 /* save node flags in local in case we have to recurse */
1511 nodeFlags
= theGlobals
->catalogInfo
.nodeFlags
;
1513 /* is it a file or directory? */
1514 if ( 0 != (nodeFlags
& kFSNodeIsDirectoryMask
) )
1516 /* it's a directory -- delete its contents before attempting to delete it */
1517 FSDeleteContainerLevel(&itemToDelete
, theGlobals
);
1519 /* are we still OK to delete? */
1520 if ( noErr
== theGlobals
->result
)
1522 /* is item locked? */
1523 if ( 0 != (nodeFlags
& kFSNodeLockedMask
) )
1525 /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
1526 theGlobals
->catalogInfo
.nodeFlags
= nodeFlags
& ~kFSNodeLockedMask
;
1527 (void) FSSetCatalogInfo(&itemToDelete
, kFSCatInfoNodeFlags
, &theGlobals
->catalogInfo
);
1529 /* delete the item */
1530 theGlobals
->result
= FSDeleteObject(&itemToDelete
);
1533 } while ( noErr
== theGlobals
->result
);
1535 /* we found the end of the items normally, so return noErr */
1536 if ( errFSNoMoreItems
== theGlobals
->result
)
1538 theGlobals
->result
= noErr
;
1541 /* close the FSIterator (closing an open iterator should never fail) */
1542 verify_noerr(FSCloseIterator(iterator
));
1549 /*****************************************************************************/
1552 FSDeleteContainerContents(
1553 const FSRef
*container
)
1555 FSDeleteContainerGlobals theGlobals
;
1557 /* delete container's contents */
1558 FSDeleteContainerLevel(container
, &theGlobals
);
1560 return ( theGlobals
.result
);
1563 /*****************************************************************************/
1567 const FSRef
*container
)
1570 FSCatalogInfo catalogInfo
;
1572 /* get nodeFlags for container */
1573 result
= FSGetCatalogInfo(container
, kFSCatInfoNodeFlags
, &catalogInfo
, NULL
, NULL
,NULL
);
1574 require_noerr(result
, FSGetCatalogInfo
);
1576 /* make sure container is a directory */
1577 require_action(0 != (catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
), ContainerNotDirectory
, result
= dirNFErr
);
1579 /* delete container's contents */
1580 result
= FSDeleteContainerContents(container
);
1581 require_noerr(result
, FSDeleteContainerContents
);
1583 /* is container locked? */
1584 if ( 0 != (catalogInfo
.nodeFlags
& kFSNodeLockedMask
) )
1586 /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
1587 catalogInfo
.nodeFlags
&= ~kFSNodeLockedMask
;
1588 (void) FSSetCatalogInfo(container
, kFSCatInfoNodeFlags
, &catalogInfo
);
1591 /* delete the container */
1592 result
= FSDeleteObject(container
);
1594 FSDeleteContainerContents
:
1595 ContainerNotDirectory
:
1601 /*****************************************************************************/
1604 The FSIterateContainerLevel function iterates the contents of a container
1605 directory and calls a IterateContainerFilterProc function once for each
1606 file and directory found.
1608 theGlobals --> A pointer to a FSIterateContainerGlobals struct
1609 which contains the variables needed globally by
1610 all recusion levels of FSIterateContainerLevel.
1611 That makes FSIterateContainer thread safe since
1612 each call to it uses its own global world.
1613 It also contains the variables that do not need
1614 to be allocated each time FSIterateContainerLevel
1615 recurses. That lets FSIterateContainerLevel use
1616 less stack space per recursion level.
1621 FSIterateContainerLevel(
1622 FSIterateContainerGlobals
*theGlobals
)
1624 FSIterator iterator
;
1626 /* If maxLevels is zero, we aren't checking levels */
1627 /* If currentLevel < maxLevels, look at this level */
1628 if ( (theGlobals
->maxLevels
== 0) ||
1629 (theGlobals
->currentLevel
< theGlobals
->maxLevels
) )
1631 /* Open FSIterator for flat access to theGlobals->ref */
1632 theGlobals
->result
= FSOpenIterator(&theGlobals
->ref
, kFSIterateFlat
, &iterator
);
1633 require_noerr(theGlobals
->result
, FSOpenIterator
);
1635 ++theGlobals
->currentLevel
; /* Go to next level */
1637 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1640 theGlobals
->result
= FSGetCatalogInfoBulk(iterator
, 1, &theGlobals
->actualObjects
,
1641 &theGlobals
->containerChanged
, theGlobals
->whichInfo
, &theGlobals
->catalogInfo
,
1642 &theGlobals
->ref
, theGlobals
->specPtr
, theGlobals
->namePtr
);
1643 if ( (noErr
== theGlobals
->result
|| errFSNoMoreItems
== theGlobals
->result
) &&
1644 (0 != theGlobals
->actualObjects
) )
1646 /* Call the IterateFilterProc */
1647 theGlobals
->quitFlag
= CallIterateContainerFilterProc(theGlobals
->iterateFilter
,
1648 theGlobals
->containerChanged
, theGlobals
->currentLevel
,
1649 &theGlobals
->catalogInfo
, &theGlobals
->ref
,
1650 theGlobals
->specPtr
, theGlobals
->namePtr
, theGlobals
->yourDataPtr
);
1651 /* Is it a directory? */
1652 if ( 0 != (theGlobals
->catalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
) )
1655 if ( !theGlobals
->quitFlag
)
1657 /* Dive again if the IterateFilterProc didn't say "quit" */
1658 FSIterateContainerLevel(theGlobals
);
1662 /* time to fall back a level? */
1663 } while ( (noErr
== theGlobals
->result
) && (!theGlobals
->quitFlag
) );
1665 /* errFSNoMoreItems is OK - it only means we hit the end of this level */
1666 /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
1667 if ( (errFSNoMoreItems
== theGlobals
->result
) ||
1668 (afpAccessDenied
== theGlobals
->result
) )
1670 theGlobals
->result
= noErr
;
1673 --theGlobals
->currentLevel
; /* Return to previous level as we leave */
1675 /* Close the FSIterator (closing an open iterator should never fail) */
1676 verify_noerr(FSCloseIterator(iterator
));
1684 /*****************************************************************************/
1688 const FSRef
*container
,
1689 ItemCount maxLevels
,
1690 FSCatalogInfoBitmap whichInfo
,
1693 IterateContainerFilterProcPtr iterateFilter
,
1697 FSIterateContainerGlobals theGlobals
;
1699 /* make sure there is an iterateFilter */
1700 require_action(iterateFilter
!= NULL
, NoIterateFilter
, result
= paramErr
);
1703 * set up the globals we need to access from the recursive routine
1705 theGlobals
.iterateFilter
= iterateFilter
;
1706 /* we need the node flags no matter what was requested so we can detect files vs. directories */
1707 theGlobals
.whichInfo
= whichInfo
| kFSCatInfoNodeFlags
;
1708 /* start with input container -- the first OpenIterator will ensure it is a directory */
1709 theGlobals
.ref
= *container
;
1712 theGlobals
.specPtr
= &theGlobals
.spec
;
1716 theGlobals
.specPtr
= NULL
;
1720 theGlobals
.namePtr
= &theGlobals
.name
;
1724 theGlobals
.namePtr
= NULL
;
1726 theGlobals
.yourDataPtr
= yourDataPtr
;
1727 theGlobals
.maxLevels
= maxLevels
;
1728 theGlobals
.currentLevel
= 0;
1729 theGlobals
.quitFlag
= false;
1730 theGlobals
.containerChanged
= false;
1731 theGlobals
.result
= noErr
;
1732 theGlobals
.actualObjects
= 0;
1734 /* here we go into recursion land... */
1735 FSIterateContainerLevel(&theGlobals
);
1736 result
= theGlobals
.result
;
1737 require_noerr(result
, FSIterateContainerLevel
);
1739 FSIterateContainerLevel
:
1745 /*****************************************************************************/
1748 FSGetDirectoryItems(
1749 const FSRef
*container
,
1750 FSRef
***refsHandle
, /* pointer to handle of FSRefs */
1752 Boolean
*containerChanged
)
1754 /* Grab items 10 at a time. */
1755 enum { kMaxItemsPerBulkCall
= 10 };
1759 FSIterator iterator
;
1760 FSRef refs
[kMaxItemsPerBulkCall
];
1761 ItemCount actualObjects
;
1764 /* check parameters */
1765 require_action((NULL
!= refsHandle
) && (NULL
!= numRefs
) && (NULL
!= containerChanged
),
1766 BadParameter
, result
= paramErr
);
1769 *containerChanged
= false;
1770 *refsHandle
= (FSRef
**)NewHandle(0);
1771 require_action(NULL
!= *refsHandle
, NewHandle
, result
= memFullErr
);
1773 /* open an FSIterator */
1774 result
= FSOpenIterator(container
, kFSIterateFlat
, &iterator
);
1775 require_noerr(result
, FSOpenIterator
);
1777 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1780 result
= FSGetCatalogInfoBulk(iterator
, kMaxItemsPerBulkCall
, &actualObjects
,
1781 &changed
, kFSCatInfoNone
, NULL
, refs
, NULL
, NULL
);
1783 /* if the container changed, set containerChanged for output, but keep going */
1786 *containerChanged
= changed
;
1789 /* any result other than noErr and errFSNoMoreItems is serious */
1790 require((noErr
== result
) || (errFSNoMoreItems
== result
), FSGetCatalogInfoBulk
);
1792 /* add objects to output array and count */
1793 if ( 0 != actualObjects
)
1795 /* concatenate the FSRefs to the end of the handle */
1796 PtrAndHand(refs
, (Handle
)*refsHandle
, actualObjects
* sizeof(FSRef
));
1797 memResult
= MemError();
1798 require_noerr_action(memResult
, MemoryAllocationFailed
, result
= memResult
);
1800 *numRefs
+= actualObjects
;
1802 } while ( noErr
== result
);
1804 verify_noerr(FSCloseIterator(iterator
)); /* closing an open iterator should never fail, but... */
1808 /**********************/
1810 MemoryAllocationFailed
:
1811 FSGetCatalogInfoBulk
:
1813 /* close the iterator */
1814 verify_noerr(FSCloseIterator(iterator
));
1817 /* dispose of handle if already allocated and clear the outputs */
1818 if ( NULL
!= *refsHandle
)
1820 DisposeHandle((Handle
)*refsHandle
);
1831 /*****************************************************************************/
1834 The GenerateUniqueName function generates a HFSUniStr255 name that is
1835 unique in both dir1 and dir2.
1837 startSeed --> A pointer to a long which is used to generate the
1839 <-- It is modified on output to a value which should
1840 be used to generate the next unique name.
1841 dir1 --> The first directory.
1842 dir2 --> The second directory.
1843 uniqueName <-- A pointer to a HFSUniStr255 where the unique name
1849 GenerateUniqueHFSUniStr(
1853 HFSUniStr255
*uniqueName
)
1859 unsigned char hexStr
[17] = "0123456789ABCDEF";
1861 /* set up the parameter block */
1862 pb
.name
= uniqueName
->unicode
;
1863 pb
.nameLength
= 8; /* always 8 characters */
1864 pb
.textEncodingHint
= kTextEncodingUnknown
;
1865 pb
.newRef
= &newRef
;
1867 /* loop until we get fnfErr with a filename in both directories */
1869 while ( fnfErr
!= result
)
1871 /* convert startSeed to 8 character Unicode string */
1872 uniqueName
->length
= 8;
1873 for ( i
= 0; i
< 8; ++i
)
1875 uniqueName
->unicode
[i
] = hexStr
[((*startSeed
>> ((7-i
)*4)) & 0xf)];
1880 result
= PBMakeFSRefUnicodeSync(&pb
);
1881 if ( fnfErr
== result
)
1885 result
= PBMakeFSRefUnicodeSync(&pb
);
1886 if ( fnfErr
!= result
)
1888 /* exit if anything other than noErr or fnfErr */
1889 require_noerr(result
, Dir2PBMakeFSRefUnicodeSyncFailed
);
1894 /* exit if anything other than noErr or fnfErr */
1895 require_noerr(result
, Dir1PBMakeFSRefUnicodeSyncFailed
);
1898 /* increment seed for next pass through loop, */
1899 /* or for next call to GenerateUniqueHFSUniStr */
1903 /* we have a unique file name which doesn't exist in dir1 or dir2 */
1906 Dir2PBMakeFSRefUnicodeSyncFailed
:
1907 Dir1PBMakeFSRefUnicodeSyncFailed
:
1912 /*****************************************************************************/
1915 FSExchangeObjectsCompat(
1916 const FSRef
*sourceRef
,
1917 const FSRef
*destRef
,
1918 FSRef
*newSourceRef
,
1923 /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
1924 kGetCatInformationMask
= (kFSCatInfoSettableInfo
|
1926 kFSCatInfoParentDirID
) &
1927 ~(kFSCatInfoContentMod
| kFSCatInfoAttrMod
),
1928 /* set everything possible except for mod dates */
1929 kSetCatinformationMask
= kFSCatInfoSettableInfo
&
1930 ~(kFSCatInfoContentMod
| kFSCatInfoAttrMod
)
1934 GetVolParmsInfoBuffer volParmsInfo
;
1936 FSCatalogInfo sourceCatalogInfo
; /* source file's catalog information */
1937 FSCatalogInfo destCatalogInfo
; /* destination file's catalog information */
1938 HFSUniStr255 sourceName
; /* source file's Unicode name */
1939 HFSUniStr255 destName
; /* destination file's Unicode name */
1940 FSRef sourceCurrentRef
; /* FSRef to current location of source file throughout this function */
1941 FSRef destCurrentRef
; /* FSRef to current location of destination file throughout this function */
1942 FSRef sourceParentRef
; /* FSRef to parent directory of source file */
1943 FSRef destParentRef
; /* FSRef to parent directory of destination file */
1944 HFSUniStr255 sourceUniqueName
; /* unique name given to source file while exchanging it with destination */
1945 HFSUniStr255 destUniqueName
; /* unique name given to destination file while exchanging it with source */
1946 long theSeed
; /* the seed for generating unique names */
1947 Boolean sameParentDirs
; /* true if source and destinatin parent directory is the same */
1949 /* check parameters */
1950 require_action((NULL
!= newSourceRef
) && (NULL
!= newDestRef
), BadParameter
, result
= paramErr
);
1952 /* output refs and current refs = input refs to start with */
1953 BlockMoveData(sourceRef
, newSourceRef
, sizeof(FSRef
));
1954 BlockMoveData(sourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
1956 BlockMoveData(destRef
, newDestRef
, sizeof(FSRef
));
1957 BlockMoveData(destRef
, &destCurrentRef
, sizeof(FSRef
));
1959 /* get source volume's vRefNum */
1960 result
= FSGetCatalogInfo(&sourceCurrentRef
, kFSCatInfoVolume
, &sourceCatalogInfo
, NULL
, NULL
, NULL
);
1961 require_noerr(result
, DetermineSourceVRefNumFailed
);
1963 /* see if that volume supports FSExchangeObjects */
1964 result
= FSGetVolParms(sourceCatalogInfo
.volume
, sizeof(GetVolParmsInfoBuffer
),
1965 &volParmsInfo
, &infoSize
);
1966 if ( (noErr
== result
) && VolSupportsFSExchangeObjects(&volParmsInfo
) )
1968 /* yes - use FSExchangeObjects */
1969 result
= FSExchangeObjects(sourceRef
, destRef
);
1973 /* no - emulate FSExchangeObjects */
1975 /* Note: The compatibility case won't work for files with *Btree control blocks. */
1976 /* Right now the only *Btree files are created by the system. */
1978 /* get all catalog information and Unicode names for each file */
1979 result
= FSGetCatalogInfo(&sourceCurrentRef
, kGetCatInformationMask
, &sourceCatalogInfo
, &sourceName
, NULL
, &sourceParentRef
);
1980 require_noerr(result
, SourceFSGetCatalogInfoFailed
);
1982 result
= FSGetCatalogInfo(&destCurrentRef
, kGetCatInformationMask
, &destCatalogInfo
, &destName
, NULL
, &destParentRef
);
1983 require_noerr(result
, DestFSGetCatalogInfoFailed
);
1985 /* make sure source and destination are on same volume */
1986 require_action(sourceCatalogInfo
.volume
== destCatalogInfo
.volume
, NotSameVolume
, result
= diffVolErr
);
1988 /* make sure both files are *really* files */
1989 require_action((0 == (sourceCatalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
)) &&
1990 (0 == (destCatalogInfo
.nodeFlags
& kFSNodeIsDirectoryMask
)), NotAFile
, result
= notAFileErr
);
1992 /* generate 2 names that are unique in both directories */
1993 theSeed
= 0x4a696d4c; /* a fine unlikely filename */
1995 result
= GenerateUniqueHFSUniStr(&theSeed
, &sourceParentRef
, &destParentRef
, &sourceUniqueName
);
1996 require_noerr(result
, GenerateUniqueHFSUniStr1Failed
);
1998 result
= GenerateUniqueHFSUniStr(&theSeed
, &sourceParentRef
, &destParentRef
, &destUniqueName
);
1999 require_noerr(result
, GenerateUniqueHFSUniStr2Failed
);
2001 /* rename sourceCurrentRef to sourceUniqueName */
2002 result
= FSRenameUnicode(&sourceCurrentRef
, sourceUniqueName
.length
, sourceUniqueName
.unicode
, kTextEncodingUnknown
, newSourceRef
);
2003 require_noerr(result
, FSRenameUnicode1Failed
);
2004 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2006 /* rename destCurrentRef to destUniqueName */
2007 result
= FSRenameUnicode(&destCurrentRef
, destUniqueName
.length
, destUniqueName
.unicode
, kTextEncodingUnknown
, newDestRef
);
2008 require_noerr(result
, FSRenameUnicode2Failed
);
2009 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
));
2011 /* are the source and destination parent directories the same? */
2012 sameParentDirs
= ( sourceCatalogInfo
.parentDirID
== destCatalogInfo
.parentDirID
);
2013 if ( !sameParentDirs
)
2015 /* move source file to dest parent directory */
2016 result
= FSMoveObject(&sourceCurrentRef
, &destParentRef
, newSourceRef
);
2017 require_noerr(result
, FSMoveObject1Failed
);
2018 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2020 /* move dest file to source parent directory */
2021 result
= FSMoveObject(&destCurrentRef
, &sourceParentRef
, newDestRef
);
2022 require_noerr(result
, FSMoveObject2Failed
);
2023 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
));
2026 /* At this point, the files are in their new locations (if they were moved). */
2027 /* The source file is named sourceUniqueName and is in the directory referred to */
2028 /* by destParentRef. The destination file is named destUniqueName and is in the */
2029 /* directory referred to by sourceParentRef. */
2031 /* give source file the dest file's catalog information except for mod dates */
2032 result
= FSSetCatalogInfo(&sourceCurrentRef
, kSetCatinformationMask
, &destCatalogInfo
);
2033 require_noerr(result
, FSSetCatalogInfo1Failed
);
2035 /* give dest file the source file's catalog information except for mod dates */
2036 result
= FSSetCatalogInfo(&destCurrentRef
, kSetCatinformationMask
, &sourceCatalogInfo
);
2037 require_noerr(result
, FSSetCatalogInfo2Failed
);
2039 /* rename source file with dest file's name */
2040 result
= FSRenameUnicode(&sourceCurrentRef
, destName
.length
, destName
.unicode
, destCatalogInfo
.textEncodingHint
, newSourceRef
);
2041 require_noerr(result
, FSRenameUnicode3Failed
);
2042 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2044 /* rename dest file with source file's name */
2045 result
= FSRenameUnicode(&destCurrentRef
, sourceName
.length
, sourceName
.unicode
, sourceCatalogInfo
.textEncodingHint
, newDestRef
);
2046 require_noerr(result
, FSRenameUnicode4Failed
);
2048 /* we're done with no errors, so swap newSourceRef and newDestRef */
2049 BlockMoveData(newDestRef
, newSourceRef
, sizeof(FSRef
));
2050 BlockMoveData(&sourceCurrentRef
, newDestRef
, sizeof(FSRef
));
2055 /**********************/
2057 /* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
2058 /* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
2059 /* state and location they ended up in so that both files can be found by the calling code. */
2061 FSRenameUnicode4Failed
:
2063 /* attempt to rename source file to sourceUniqueName */
2064 if ( noErr
== FSRenameUnicode(&sourceCurrentRef
, sourceUniqueName
.length
, sourceUniqueName
.unicode
, kTextEncodingUnknown
, newSourceRef
) )
2066 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2069 FSRenameUnicode3Failed
:
2071 /* attempt to restore dest file's catalog information */
2072 verify_noerr(FSSetCatalogInfo(&destCurrentRef
, kFSCatInfoSettableInfo
, &destCatalogInfo
));
2074 FSSetCatalogInfo2Failed
:
2076 /* attempt to restore source file's catalog information */
2077 verify_noerr(FSSetCatalogInfo(&sourceCurrentRef
, kFSCatInfoSettableInfo
, &sourceCatalogInfo
));
2079 FSSetCatalogInfo1Failed
:
2081 if ( !sameParentDirs
)
2083 /* attempt to move dest file back to dest directory */
2084 if ( noErr
== FSMoveObject(&destCurrentRef
, &destParentRef
, newDestRef
) )
2086 BlockMoveData(newDestRef
, &destCurrentRef
, sizeof(FSRef
));
2090 FSMoveObject2Failed
:
2092 if ( !sameParentDirs
)
2094 /* attempt to move source file back to source directory */
2095 if ( noErr
== FSMoveObject(&sourceCurrentRef
, &sourceParentRef
, newSourceRef
) )
2097 BlockMoveData(newSourceRef
, &sourceCurrentRef
, sizeof(FSRef
));
2101 FSMoveObject1Failed
:
2103 /* attempt to rename dest file to original name */
2104 verify_noerr(FSRenameUnicode(&destCurrentRef
, destName
.length
, destName
.unicode
, destCatalogInfo
.textEncodingHint
, newDestRef
));
2106 FSRenameUnicode2Failed
:
2108 /* attempt to rename source file to original name */
2109 verify_noerr(FSRenameUnicode(&sourceCurrentRef
, sourceName
.length
, sourceName
.unicode
, sourceCatalogInfo
.textEncodingHint
, newSourceRef
));
2111 FSRenameUnicode1Failed
:
2112 GenerateUniqueHFSUniStr2Failed
:
2113 GenerateUniqueHFSUniStr1Failed
:
2116 DestFSGetCatalogInfoFailed
:
2117 SourceFSGetCatalogInfoFailed
:
2118 DetermineSourceVRefNumFailed
:
2124 /*****************************************************************************/
2126 #pragma mark ----- Shared Environment Routines -----
2128 /*****************************************************************************/
2133 FSLockRangeMoreFilesX(
2141 pb
.ioParam
.ioRefNum
= refNum
;
2142 pb
.ioParam
.ioReqCount
= rangeLength
;
2143 pb
.ioParam
.ioPosMode
= fsFromStart
;
2144 pb
.ioParam
.ioPosOffset
= rangeStart
;
2145 result
= PBLockRangeSync(&pb
);
2146 require_noerr(result
, PBLockRangeSync
);
2153 /*****************************************************************************/
2156 FSUnlockRangeMoreFilesX(
2164 pb
.ioParam
.ioRefNum
= refNum
;
2165 pb
.ioParam
.ioReqCount
= rangeLength
;
2166 pb
.ioParam
.ioPosMode
= fsFromStart
;
2167 pb
.ioParam
.ioPosOffset
= rangeStart
;
2168 result
= PBUnlockRangeSync(&pb
);
2169 require_noerr(result
, PBUnlockRangeSync
);
2176 /*****************************************************************************/
2181 SInt32
*ownerID
, /* can be NULL */
2182 SInt32
*groupID
, /* can be NULL */
2183 SInt32
*accessRights
) /* can be NULL */
2189 /* get FSSpec from FSRef */
2190 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
);
2191 require_noerr(result
, FSGetCatalogInfo
);
2193 /* get directory access info for FSSpec */
2194 pb
.accessParam
.ioNamePtr
= (StringPtr
)spec
.name
;
2195 pb
.accessParam
.ioVRefNum
= spec
.vRefNum
;
2196 pb
.fileParam
.ioDirID
= spec
.parID
;
2197 result
= PBHGetDirAccessSync(&pb
);
2198 require_noerr(result
, PBHGetDirAccessSync
);
2200 /* return the IDs and access rights */
2201 if ( NULL
!= ownerID
)
2203 *ownerID
= pb
.accessParam
.ioACOwnerID
;
2205 if ( NULL
!= groupID
)
2207 *groupID
= pb
.accessParam
.ioACGroupID
;
2209 if ( NULL
!= accessRights
)
2211 *accessRights
= pb
.accessParam
.ioACAccess
;
2214 PBHGetDirAccessSync
:
2220 /*****************************************************************************/
2227 SInt32 accessRights
)
2235 /* Just the bits that can be set */
2236 kSetDirAccessSettableMask
= (kioACAccessBlankAccessMask
+
2237 kioACAccessEveryoneWriteMask
+ kioACAccessEveryoneReadMask
+ kioACAccessEveryoneSearchMask
+
2238 kioACAccessGroupWriteMask
+ kioACAccessGroupReadMask
+ kioACAccessGroupSearchMask
+
2239 kioACAccessOwnerWriteMask
+ kioACAccessOwnerReadMask
+ kioACAccessOwnerSearchMask
)
2242 /* get FSSpec from FSRef */
2243 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
);
2244 require_noerr(result
, FSGetCatalogInfo
);
2246 /* set directory access info for FSSpec */
2247 pb
.accessParam
.ioNamePtr
= (StringPtr
)spec
.name
;
2248 pb
.accessParam
.ioVRefNum
= spec
.vRefNum
;
2249 pb
.fileParam
.ioDirID
= spec
.parID
;
2250 pb
.accessParam
.ioACOwnerID
= ownerID
;
2251 pb
.accessParam
.ioACGroupID
= groupID
;
2252 pb
.accessParam
.ioACAccess
= accessRights
& kSetDirAccessSettableMask
;
2253 result
= PBHSetDirAccessSync(&pb
);
2254 require_noerr(result
, PBHSetDirAccessSync
);
2256 PBHSetDirAccessSync
:
2262 /*****************************************************************************/
2265 FSGetVolMountInfoSize(
2266 FSVolumeRefNum volRefNum
,
2272 /* check parameters */
2273 require_action(NULL
!= size
, BadParameter
, result
= paramErr
);
2275 pb
.ioParam
.ioNamePtr
= NULL
;
2276 pb
.ioParam
.ioVRefNum
= volRefNum
;
2277 pb
.ioParam
.ioBuffer
= (Ptr
)size
;
2278 result
= PBGetVolMountInfoSize(&pb
);
2279 require_noerr(result
, PBGetVolMountInfoSize
);
2281 PBGetVolMountInfoSize
:
2287 /*****************************************************************************/
2291 FSVolumeRefNum volRefNum
,
2297 /* check parameters */
2298 require_action(NULL
!= volMountInfo
, BadParameter
, result
= paramErr
);
2300 pb
.ioParam
.ioNamePtr
= NULL
;
2301 pb
.ioParam
.ioVRefNum
= volRefNum
;
2302 pb
.ioParam
.ioBuffer
= (Ptr
)volMountInfo
;
2303 result
= PBGetVolMountInfo(&pb
);
2304 require_noerr(result
, PBGetVolMountInfo
);
2312 /*****************************************************************************/
2316 const void *volMountInfo
,
2317 FSVolumeRefNum
*volRefNum
)
2322 /* check parameters */
2323 require_action(NULL
!= volRefNum
, BadParameter
, result
= paramErr
);
2325 pb
.ioParam
.ioBuffer
= (Ptr
)volMountInfo
;
2326 result
= PBVolumeMount(&pb
);
2327 require_noerr(result
, PBVolumeMount
);
2329 /* return the volume reference number */
2330 *volRefNum
= pb
.ioParam
.ioVRefNum
;
2338 /*****************************************************************************/
2342 FSVolumeRefNum volRefNum
,
2350 /* check parameters */
2351 require_action(NULL
!= name
, BadParameter
, result
= paramErr
);
2353 pb
.objParam
.ioNamePtr
= NULL
;
2354 pb
.objParam
.ioVRefNum
= volRefNum
;
2355 pb
.objParam
.ioObjType
= objType
;
2356 pb
.objParam
.ioObjNamePtr
= name
;
2357 pb
.objParam
.ioObjID
= ugID
;
2358 result
= PBHMapIDSync(&pb
);
2359 require_noerr(result
, PBHMapIDSync
);
2367 /*****************************************************************************/
2371 FSVolumeRefNum volRefNum
,
2372 ConstStr255Param name
,
2379 /* check parameters */
2380 require_action(NULL
!= ugID
, BadParameter
, result
= paramErr
);
2382 pb
.objParam
.ioNamePtr
= NULL
;
2383 pb
.objParam
.ioVRefNum
= volRefNum
;
2384 pb
.objParam
.ioObjType
= objType
;
2385 pb
.objParam
.ioObjNamePtr
= (StringPtr
)name
;
2386 result
= PBHMapNameSync(&pb
);
2387 require_noerr(result
, PBHMapNameSync
);
2389 /* return the user or group ID */
2390 *ugID
= pb
.objParam
.ioObjID
;
2398 /*****************************************************************************/
2402 const FSRef
*srcFileRef
,
2403 const FSRef
*dstDirectoryRef
,
2404 UniCharCount nameLength
,
2405 const UniChar
*copyName
, /* can be NULL (no rename during copy) */
2406 TextEncoding textEncodingHint
,
2407 FSRef
*newRef
) /* can be NULL */
2411 FSCatalogInfo catalogInfo
;
2414 GetVolParmsInfoBuffer volParmsInfo
;
2417 /* get source FSSpec from source FSRef */
2418 result
= FSGetCatalogInfo(srcFileRef
, kFSCatInfoNone
, NULL
, NULL
, &srcFileSpec
, NULL
);
2419 require_noerr(result
, FSGetCatalogInfo_srcFileRef
);
2421 /* Make sure the volume supports CopyFile */
2422 result
= FSGetVolParms(srcFileSpec
.vRefNum
, sizeof(GetVolParmsInfoBuffer
),
2423 &volParmsInfo
, &infoSize
);
2424 require_action((noErr
== result
) && VolHasCopyFile(&volParmsInfo
),
2425 NoCopyFileSupport
, result
= paramErr
);
2427 /* get destination volume reference number and destination directory ID from destination FSRef */
2428 result
= FSGetCatalogInfo(dstDirectoryRef
, kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2429 &catalogInfo
, NULL
, NULL
, NULL
);
2430 require_noerr(result
, FSGetCatalogInfo_dstDirectoryRef
);
2432 /* tell the server to copy the object */
2433 pb
.copyParam
.ioVRefNum
= srcFileSpec
.vRefNum
;
2434 pb
.copyParam
.ioDirID
= srcFileSpec
.parID
;
2435 pb
.copyParam
.ioNamePtr
= (StringPtr
)srcFileSpec
.name
;
2436 pb
.copyParam
.ioDstVRefNum
= catalogInfo
.volume
;
2437 pb
.copyParam
.ioNewDirID
= (long)catalogInfo
.nodeID
;
2438 pb
.copyParam
.ioNewName
= NULL
;
2439 if ( NULL
!= copyName
)
2441 result
= UnicodeNameGetHFSName(nameLength
, copyName
, textEncodingHint
, false, hfsName
);
2442 require_noerr(result
, UnicodeNameGetHFSName
);
2444 pb
.copyParam
.ioCopyName
= hfsName
;
2448 pb
.copyParam
.ioCopyName
= NULL
;
2450 result
= PBHCopyFileSync(&pb
);
2451 require_noerr(result
, PBHCopyFileSync
);
2453 if ( NULL
!= newRef
)
2455 verify_noerr(FSMakeFSRef(pb
.copyParam
.ioDstVRefNum
, pb
.copyParam
.ioNewDirID
,
2456 pb
.copyParam
.ioCopyName
, newRef
));
2460 UnicodeNameGetHFSName
:
2461 FSGetCatalogInfo_dstDirectoryRef
:
2463 FSGetCatalogInfo_srcFileRef
:
2468 /*****************************************************************************/
2472 const FSRef
*srcFileRef
,
2473 const FSRef
*dstDirectoryRef
,
2474 UniCharCount nameLength
,
2475 const UniChar
*moveName
, /* can be NULL (no rename during move) */
2476 TextEncoding textEncodingHint
,
2477 FSRef
*newRef
) /* can be NULL */
2481 FSCatalogInfo catalogInfo
;
2484 GetVolParmsInfoBuffer volParmsInfo
;
2487 /* get source FSSpec from source FSRef */
2488 result
= FSGetCatalogInfo(srcFileRef
, kFSCatInfoNone
, NULL
, NULL
, &srcFileSpec
, NULL
);
2489 require_noerr(result
, FSGetCatalogInfo_srcFileRef
);
2491 /* Make sure the volume supports MoveRename */
2492 result
= FSGetVolParms(srcFileSpec
.vRefNum
, sizeof(GetVolParmsInfoBuffer
),
2493 &volParmsInfo
, &infoSize
);
2494 require_action((noErr
== result
) && VolHasMoveRename(&volParmsInfo
),
2495 NoMoveRenameSupport
, result
= paramErr
);
2497 /* get destination volume reference number and destination directory ID from destination FSRef */
2498 result
= FSGetCatalogInfo(dstDirectoryRef
, kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2499 &catalogInfo
, NULL
, NULL
, NULL
);
2500 require_noerr(result
, FSGetCatalogInfo_dstDirectoryRef
);
2502 /* make sure the source and destination are on the same volume */
2503 require_action(srcFileSpec
.vRefNum
== catalogInfo
.volume
, NotSameVolume
, result
= diffVolErr
);
2505 /* tell the server to move and rename the object */
2506 pb
.copyParam
.ioVRefNum
= srcFileSpec
.vRefNum
;
2507 pb
.copyParam
.ioDirID
= srcFileSpec
.parID
;
2508 pb
.copyParam
.ioNamePtr
= (StringPtr
)srcFileSpec
.name
;
2509 pb
.copyParam
.ioNewDirID
= (long)catalogInfo
.nodeID
;
2510 pb
.copyParam
.ioNewName
= NULL
;
2511 if ( NULL
!= moveName
)
2513 result
= UnicodeNameGetHFSName(nameLength
, moveName
, textEncodingHint
, false, hfsName
);
2514 require_noerr(result
, UnicodeNameGetHFSName
);
2516 pb
.copyParam
.ioCopyName
= hfsName
;
2520 pb
.copyParam
.ioCopyName
= NULL
;
2522 result
= PBHMoveRenameSync(&pb
);
2523 require_noerr(result
, PBHMoveRenameSync
);
2525 if ( NULL
!= newRef
)
2527 verify_noerr(FSMakeFSRef(pb
.copyParam
.ioVRefNum
, pb
.copyParam
.ioNewDirID
,
2528 pb
.copyParam
.ioCopyName
, newRef
));
2532 UnicodeNameGetHFSName
:
2534 FSGetCatalogInfo_dstDirectoryRef
:
2535 NoMoveRenameSupport
:
2536 FSGetCatalogInfo_srcFileRef
:
2541 /*****************************************************************************/
2543 #pragma mark ----- File ID Routines -----
2545 /*****************************************************************************/
2549 FSVolumeRefNum volRefNum
,
2557 /* check parameters */
2558 require_action(NULL
!= ref
, BadParameter
, result
= paramErr
);
2560 /* resolve the file ID reference */
2562 pb
.ioNamePtr
= tempStr
;
2563 pb
.ioVRefNum
= volRefNum
;
2564 pb
.ioFileID
= fileID
;
2565 result
= PBResolveFileIDRefSync((HParmBlkPtr
)&pb
);
2566 require_noerr(result
, PBResolveFileIDRefSync
);
2568 /* and then make an FSRef to the file */
2569 result
= FSMakeFSRef(volRefNum
, pb
.ioSrcDirID
, tempStr
, ref
);
2570 require_noerr(result
, FSMakeFSRef
);
2573 PBResolveFileIDRefSync
:
2579 /*****************************************************************************/
2590 /* check parameters */
2591 require_action(NULL
!= fileID
, BadParameter
, result
= paramErr
);
2593 /* Get an FSSpec from the FSRef */
2594 result
= FSGetCatalogInfo(ref
, kFSCatInfoNone
, NULL
, NULL
, &spec
, NULL
);
2595 require_noerr(result
, FSGetCatalogInfo
);
2597 /* Create (or get) the file ID reference using the FSSpec */
2598 pb
.ioNamePtr
= (StringPtr
)spec
.name
;
2599 pb
.ioVRefNum
= spec
.vRefNum
;
2600 pb
.ioSrcDirID
= spec
.parID
;
2601 result
= PBCreateFileIDRefSync((HParmBlkPtr
)&pb
);
2602 require((noErr
== result
) || (fidExists
== result
) || (afpIDExists
== result
),
2603 PBCreateFileIDRefSync
);
2605 /* return the file ID reference */
2606 *fileID
= pb
.ioFileID
;
2608 PBCreateFileIDRefSync
:
2617 /*****************************************************************************/
2619 #pragma mark ----- Utility Routines -----
2621 /*****************************************************************************/
2625 ByteCount buffReqSize
,
2626 ByteCount
*buffActSize
)
2630 kSlopMemory
= 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
2635 /* check parameters */
2636 require_action(NULL
!= buffActSize
, BadParameter
, tempPtr
= NULL
);
2638 /* Make request a multiple of 4K bytes */
2639 buffReqSize
= buffReqSize
& 0xfffff000;
2641 if ( buffReqSize
< 0x00001000 )
2643 /* Request was smaller than 4K bytes - make it 4K */
2644 buffReqSize
= 0x00001000;
2647 /* Attempt to allocate the memory */
2648 tempPtr
= NewPtr(buffReqSize
);
2650 /* If request failed, go to backup plan */
2651 if ( (tempPtr
== NULL
) && (buffReqSize
> 0x00001000) )
2654 ** Try to get largest 4K byte block available
2655 ** leaving some slop for the toolbox if possible
2657 long freeMemory
= (FreeMem() - kSlopMemory
) & 0xfffff000;
2659 buffReqSize
= MaxBlock() & 0xfffff000;
2661 if ( (long)buffReqSize
> freeMemory
)
2663 buffReqSize
= freeMemory
;
2666 if ( buffReqSize
== 0 )
2668 buffReqSize
= 0x00001000;
2671 tempPtr
= NewPtr(buffReqSize
);
2674 /* Return bytes allocated */
2675 if ( tempPtr
!= NULL
)
2677 *buffActSize
= buffReqSize
;
2689 /*****************************************************************************/
2696 return ( FSGetForkCBInfo(refNum
, 0, NULL
, NULL
, NULL
, ref
, NULL
) );
2699 /*****************************************************************************/
2703 const FSRef
*newDefault
,
2707 FSVolumeRefNum vRefNum
;
2709 FSCatalogInfo catalogInfo
;
2711 /* check parameters */
2712 require_action((NULL
!= newDefault
) && (NULL
!= oldDefault
), BadParameter
, result
= paramErr
);
2714 /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
2715 result
= FSGetCatalogInfo(newDefault
,
2716 kFSCatInfoNodeFlags
+ kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2717 &catalogInfo
, NULL
, NULL
, NULL
);
2718 require_noerr(result
, FSGetCatalogInfo
);
2720 /* Make sure newDefault is a directory */
2721 require_action(0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
), NewDefaultNotDirectory
,
2724 /* Get the current working directory. */
2725 result
= HGetVol(NULL
, &vRefNum
, &dirID
);
2726 require_noerr(result
, HGetVol
);
2728 /* Return the oldDefault FSRef */
2729 result
= FSMakeFSRef(vRefNum
, dirID
, NULL
, oldDefault
);
2730 require_noerr(result
, FSMakeFSRef
);
2732 /* Set the new current working directory */
2733 result
= HSetVol(NULL
, catalogInfo
.volume
, catalogInfo
.nodeID
);
2734 require_noerr(result
, HSetVol
);
2739 NewDefaultNotDirectory
:
2746 /*****************************************************************************/
2750 const FSRef
*oldDefault
)
2753 FSCatalogInfo catalogInfo
;
2755 /* check parameters */
2756 require_action(NULL
!= oldDefault
, BadParameter
, result
= paramErr
);
2758 /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
2759 result
= FSGetCatalogInfo(oldDefault
,
2760 kFSCatInfoNodeFlags
+ kFSCatInfoVolume
+ kFSCatInfoNodeID
,
2761 &catalogInfo
, NULL
, NULL
, NULL
);
2762 require_noerr(result
, FSGetCatalogInfo
);
2764 /* Make sure oldDefault is a directory */
2765 require_action(0 != (kFSNodeIsDirectoryMask
& catalogInfo
.nodeFlags
), OldDefaultNotDirectory
,
2768 /* Set the current working directory to oldDefault */
2769 result
= HSetVol(NULL
, catalogInfo
.volume
, catalogInfo
.nodeID
);
2770 require_noerr(result
, HSetVol
);
2773 OldDefaultNotDirectory
:
2780 /*****************************************************************************/