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
if ( FSCompareFSRefs(destDirectory, &originalDirectory) != noErr )
1417
/* Move object to its new home */
1418
result = FSMoveObject(newRef, destDirectory, newRef);
1419
require_noerr(result, FSMoveObjectAfterRenameFailed);
1422
/* Rename the object to new name */
1423
result = FSRenameUnicode(ref, nameLength, name, textEncodingHint, newRef);
1424
require_noerr(result, FSRenameUnicodeAfterMoveFailed);
1428
/* Move object to its new home */
1429
result = FSMoveObject(newRef, destDirectory, newRef);
1430
require_noerr(result, FSMoveObjectNoRenameFailed);
1438
* failure handling code when renaming
1441
FSRenameUnicodeAfterMoveFailed:
1443
/* Error handling: move object back to original location - ignore errors */
1444
verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef));
1446
FSMoveObjectAfterRenameFailed:
1448
/* Error handling: rename object back to original name - ignore errors */
1449
verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef));
1451
FSRenameUnicodeBeforeMoveFailed:
1452
GenerateUniqueHFSUniStrFailed:
1455
* failure handling code for renaming or not
1457
FSMoveObjectNoRenameFailed:
1466
/*****************************************************************************/
1469
The FSDeleteContainerLevel function deletes the contents of a container
1470
directory. All files and subdirectories in the specified container are
1471
deleted. If a locked file or directory is encountered, it is unlocked
1472
and then deleted. If any unexpected errors are encountered,
1473
FSDeleteContainerLevel quits and returns to the caller.
1475
container --> FSRef to a directory.
1476
theGlobals --> A pointer to a FSDeleteContainerGlobals struct
1477
which contains the variables that do not need to
1478
be allocated each time FSDeleteContainerLevel
1479
recurses. That lets FSDeleteContainerLevel use
1480
less stack space per recursion level.
1485
FSDeleteContainerLevel(
1486
const FSRef *container,
1487
FSDeleteContainerGlobals *theGlobals)
1490
FSIterator iterator;
1494
/* Open FSIterator for flat access and give delete optimization hint */
1495
theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator);
1496
require_noerr(theGlobals->result, FSOpenIterator);
1498
/* delete the contents of the directory */
1501
/* get 1 item to delete */
1502
theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
1503
NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo,
1504
&itemToDelete, NULL, NULL);
1505
if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) )
1507
/* save node flags in local in case we have to recurse */
1508
nodeFlags = theGlobals->catalogInfo.nodeFlags;
1510
/* is it a file or directory? */
1511
if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) )
1513
/* it's a directory -- delete its contents before attempting to delete it */
1514
FSDeleteContainerLevel(&itemToDelete, theGlobals);
1516
/* are we still OK to delete? */
1517
if ( noErr == theGlobals->result )
1519
/* is item locked? */
1520
if ( 0 != (nodeFlags & kFSNodeLockedMask) )
1522
/* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
1523
theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask;
1524
(void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo);
1526
/* delete the item */
1527
theGlobals->result = FSDeleteObject(&itemToDelete);
1530
} while ( noErr == theGlobals->result );
1532
/* we found the end of the items normally, so return noErr */
1533
if ( errFSNoMoreItems == theGlobals->result )
1535
theGlobals->result = noErr;
1538
/* close the FSIterator (closing an open iterator should never fail) */
1539
verify_noerr(FSCloseIterator(iterator));
1546
/*****************************************************************************/
1549
FSDeleteContainerContents(
1550
const FSRef *container)
1552
FSDeleteContainerGlobals theGlobals;
1554
/* delete container's contents */
1555
FSDeleteContainerLevel(container, &theGlobals);
1557
return ( theGlobals.result );
1560
/*****************************************************************************/
1564
const FSRef *container)
1567
FSCatalogInfo catalogInfo;
1569
/* get nodeFlags for container */
1570
result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL);
1571
require_noerr(result, FSGetCatalogInfo);
1573
/* make sure container is a directory */
1574
require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr);
1576
/* delete container's contents */
1577
result = FSDeleteContainerContents(container);
1578
require_noerr(result, FSDeleteContainerContents);
1580
/* is container locked? */
1581
if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
1583
/* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
1584
catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
1585
(void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo);
1588
/* delete the container */
1589
result = FSDeleteObject(container);
1591
FSDeleteContainerContents:
1592
ContainerNotDirectory:
1598
/*****************************************************************************/
1601
The FSIterateContainerLevel function iterates the contents of a container
1602
directory and calls a IterateContainerFilterProc function once for each
1603
file and directory found.
1605
theGlobals --> A pointer to a FSIterateContainerGlobals struct
1606
which contains the variables needed globally by
1607
all recusion levels of FSIterateContainerLevel.
1608
That makes FSIterateContainer thread safe since
1609
each call to it uses its own global world.
1610
It also contains the variables that do not need
1611
to be allocated each time FSIterateContainerLevel
1612
recurses. That lets FSIterateContainerLevel use
1613
less stack space per recursion level.
1618
FSIterateContainerLevel(
1619
FSIterateContainerGlobals *theGlobals)
1621
FSIterator iterator;
1623
/* If maxLevels is zero, we aren't checking levels */
1624
/* If currentLevel < maxLevels, look at this level */
1625
if ( (theGlobals->maxLevels == 0) ||
1626
(theGlobals->currentLevel < theGlobals->maxLevels) )
1628
/* Open FSIterator for flat access to theGlobals->ref */
1629
theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator);
1630
require_noerr(theGlobals->result, FSOpenIterator);
1632
++theGlobals->currentLevel; /* Go to next level */
1634
/* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1637
theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
1638
&theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo,
1639
&theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr);
1640
if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) &&
1641
(0 != theGlobals->actualObjects) )
1643
/* Call the IterateFilterProc */
1644
theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter,
1645
theGlobals->containerChanged, theGlobals->currentLevel,
1646
&theGlobals->catalogInfo, &theGlobals->ref,
1647
theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr);
1648
/* Is it a directory? */
1649
if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) )
1652
if ( !theGlobals->quitFlag )
1654
/* Dive again if the IterateFilterProc didn't say "quit" */
1655
FSIterateContainerLevel(theGlobals);
1659
/* time to fall back a level? */
1660
} while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) );
1662
/* errFSNoMoreItems is OK - it only means we hit the end of this level */
1663
/* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
1664
if ( (errFSNoMoreItems == theGlobals->result) ||
1665
(afpAccessDenied == theGlobals->result) )
1667
theGlobals->result = noErr;
1670
--theGlobals->currentLevel; /* Return to previous level as we leave */
1672
/* Close the FSIterator (closing an open iterator should never fail) */
1673
verify_noerr(FSCloseIterator(iterator));
1681
/*****************************************************************************/
1685
const FSRef *container,
1686
ItemCount maxLevels,
1687
FSCatalogInfoBitmap whichInfo,
1690
IterateContainerFilterProcPtr iterateFilter,
1694
FSIterateContainerGlobals theGlobals;
1696
/* make sure there is an iterateFilter */
1697
require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr);
1700
* set up the globals we need to access from the recursive routine
1702
theGlobals.iterateFilter = iterateFilter;
1703
/* we need the node flags no matter what was requested so we can detect files vs. directories */
1704
theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags;
1705
/* start with input container -- the first OpenIterator will ensure it is a directory */
1706
theGlobals.ref = *container;
1709
theGlobals.specPtr = &theGlobals.spec;
1713
theGlobals.specPtr = NULL;
1717
theGlobals.namePtr = &theGlobals.name;
1721
theGlobals.namePtr = NULL;
1723
theGlobals.yourDataPtr = yourDataPtr;
1724
theGlobals.maxLevels = maxLevels;
1725
theGlobals.currentLevel = 0;
1726
theGlobals.quitFlag = false;
1727
theGlobals.containerChanged = false;
1728
theGlobals.result = noErr;
1729
theGlobals.actualObjects = 0;
1731
/* here we go into recursion land... */
1732
FSIterateContainerLevel(&theGlobals);
1733
result = theGlobals.result;
1734
require_noerr(result, FSIterateContainerLevel);
1736
FSIterateContainerLevel:
1742
/*****************************************************************************/
1745
FSGetDirectoryItems(
1746
const FSRef *container,
1747
FSRef ***refsHandle, /* pointer to handle of FSRefs */
1749
Boolean *containerChanged)
1751
/* Grab items 10 at a time. */
1752
enum { kMaxItemsPerBulkCall = 10 };
1756
FSIterator iterator;
1757
FSRef refs[kMaxItemsPerBulkCall];
1758
ItemCount actualObjects;
1761
/* check parameters */
1762
require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged),
1763
BadParameter, result = paramErr);
1766
*containerChanged = false;
1767
*refsHandle = (FSRef **)NewHandle(0);
1768
require_action(NULL != *refsHandle, NewHandle, result = memFullErr);
1770
/* open an FSIterator */
1771
result = FSOpenIterator(container, kFSIterateFlat, &iterator);
1772
require_noerr(result, FSOpenIterator);
1774
/* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1777
result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects,
1778
&changed, kFSCatInfoNone, NULL, refs, NULL, NULL);
1780
/* if the container changed, set containerChanged for output, but keep going */
1783
*containerChanged = changed;
1786
/* any result other than noErr and errFSNoMoreItems is serious */
1787
require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk);
1789
/* add objects to output array and count */
1790
if ( 0 != actualObjects )
1792
/* concatenate the FSRefs to the end of the handle */
1793
PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef));
1794
memResult = MemError();
1795
require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
1797
*numRefs += actualObjects;
1799
} while ( noErr == result );
1801
verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */
1805
/**********************/
1807
MemoryAllocationFailed:
1808
FSGetCatalogInfoBulk:
1810
/* close the iterator */
1811
verify_noerr(FSCloseIterator(iterator));
1814
/* dispose of handle if already allocated and clear the outputs */
1815
if ( NULL != *refsHandle )
1817
DisposeHandle((Handle)*refsHandle);
1828
/*****************************************************************************/
1831
The GenerateUniqueName function generates a HFSUniStr255 name that is
1832
unique in both dir1 and dir2.
1834
startSeed --> A pointer to a long which is used to generate the
1836
<-- It is modified on output to a value which should
1837
be used to generate the next unique name.
1838
dir1 --> The first directory.
1839
dir2 --> The second directory.
1840
uniqueName <-- A pointer to a HFSUniStr255 where the unique name
1846
GenerateUniqueHFSUniStr(
1850
HFSUniStr255 *uniqueName)
1856
unsigned char hexStr[17] = "0123456789ABCDEF";
1858
/* set up the parameter block */
1859
pb.name = uniqueName->unicode;
1860
pb.nameLength = 8; /* always 8 characters */
1861
pb.textEncodingHint = kTextEncodingUnknown;
1862
pb.newRef = &newRef;
1864
/* loop until we get fnfErr with a filename in both directories */
1866
while ( fnfErr != result )
1868
/* convert startSeed to 8 character Unicode string */
1869
uniqueName->length = 8;
1870
for ( i = 0; i < 8; ++i )
1872
uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)];
1877
result = PBMakeFSRefUnicodeSync(&pb);
1878
if ( fnfErr == result )
1882
result = PBMakeFSRefUnicodeSync(&pb);
1883
if ( fnfErr != result )
1885
/* exit if anything other than noErr or fnfErr */
1886
require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed);
1891
/* exit if anything other than noErr or fnfErr */
1892
require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed);
1895
/* increment seed for next pass through loop, */
1896
/* or for next call to GenerateUniqueHFSUniStr */
1900
/* we have a unique file name which doesn't exist in dir1 or dir2 */
1903
Dir2PBMakeFSRefUnicodeSyncFailed:
1904
Dir1PBMakeFSRefUnicodeSyncFailed:
1909
/*****************************************************************************/
1912
FSExchangeObjectsCompat(
1913
const FSRef *sourceRef,
1914
const FSRef *destRef,
1915
FSRef *newSourceRef,
1920
/* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
1921
kGetCatInformationMask = (kFSCatInfoSettableInfo |
1923
kFSCatInfoParentDirID) &
1924
~(kFSCatInfoContentMod | kFSCatInfoAttrMod),
1925
/* set everything possible except for mod dates */
1926
kSetCatinformationMask = kFSCatInfoSettableInfo &
1927
~(kFSCatInfoContentMod | kFSCatInfoAttrMod)
1931
GetVolParmsInfoBuffer volParmsInfo;
1933
FSCatalogInfo sourceCatalogInfo; /* source file's catalog information */
1934
FSCatalogInfo destCatalogInfo; /* destination file's catalog information */
1935
HFSUniStr255 sourceName; /* source file's Unicode name */
1936
HFSUniStr255 destName; /* destination file's Unicode name */
1937
FSRef sourceCurrentRef; /* FSRef to current location of source file throughout this function */
1938
FSRef destCurrentRef; /* FSRef to current location of destination file throughout this function */
1939
FSRef sourceParentRef; /* FSRef to parent directory of source file */
1940
FSRef destParentRef; /* FSRef to parent directory of destination file */
1941
HFSUniStr255 sourceUniqueName; /* unique name given to source file while exchanging it with destination */
1942
HFSUniStr255 destUniqueName; /* unique name given to destination file while exchanging it with source */
1943
long theSeed; /* the seed for generating unique names */
1944
Boolean sameParentDirs; /* true if source and destinatin parent directory is the same */
1946
/* check parameters */
1947
require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr);
1949
/* output refs and current refs = input refs to start with */
1950
BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef));
1951
BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef));
1953
BlockMoveData(destRef, newDestRef, sizeof(FSRef));
1954
BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef));
1956
/* get source volume's vRefNum */
1957
result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL);
1958
require_noerr(result, DetermineSourceVRefNumFailed);
1960
/* see if that volume supports FSExchangeObjects */
1961
result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer),
1962
&volParmsInfo, &infoSize);
1963
if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) )
1965
/* yes - use FSExchangeObjects */
1966
result = FSExchangeObjects(sourceRef, destRef);
1970
/* no - emulate FSExchangeObjects */
1972
/* Note: The compatibility case won't work for files with *Btree control blocks. */
1973
/* Right now the only *Btree files are created by the system. */
1975
/* get all catalog information and Unicode names for each file */
1976
result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef);
1977
require_noerr(result, SourceFSGetCatalogInfoFailed);
1979
result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef);
1980
require_noerr(result, DestFSGetCatalogInfoFailed);
1982
/* make sure source and destination are on same volume */
1983
require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr);
1985
/* make sure both files are *really* files */
1986
require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) &&
1987
(0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr);
1989
/* generate 2 names that are unique in both directories */
1990
theSeed = 0x4a696d4c; /* a fine unlikely filename */
1992
result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName);
1993
require_noerr(result, GenerateUniqueHFSUniStr1Failed);
1995
result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName);
1996
require_noerr(result, GenerateUniqueHFSUniStr2Failed);
1998
/* rename sourceCurrentRef to sourceUniqueName */
1999
result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef);
2000
require_noerr(result, FSRenameUnicode1Failed);
2001
BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2003
/* rename destCurrentRef to destUniqueName */
2004
result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef);
2005
require_noerr(result, FSRenameUnicode2Failed);
2006
BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2008
/* are the source and destination parent directories the same? */
2009
sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID );
2010
if ( !sameParentDirs )
2012
/* move source file to dest parent directory */
2013
result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef);
2014
require_noerr(result, FSMoveObject1Failed);
2015
BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2017
/* move dest file to source parent directory */
2018
result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef);
2019
require_noerr(result, FSMoveObject2Failed);
2020
BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2023
/* At this point, the files are in their new locations (if they were moved). */
2024
/* The source file is named sourceUniqueName and is in the directory referred to */
2025
/* by destParentRef. The destination file is named destUniqueName and is in the */
2026
/* directory referred to by sourceParentRef. */
2028
/* give source file the dest file's catalog information except for mod dates */
2029
result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo);
2030
require_noerr(result, FSSetCatalogInfo1Failed);
2032
/* give dest file the source file's catalog information except for mod dates */
2033
result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo);
2034
require_noerr(result, FSSetCatalogInfo2Failed);
2036
/* rename source file with dest file's name */
2037
result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef);
2038
require_noerr(result, FSRenameUnicode3Failed);
2039
BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2041
/* rename dest file with source file's name */
2042
result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef);
2043
require_noerr(result, FSRenameUnicode4Failed);
2045
/* we're done with no errors, so swap newSourceRef and newDestRef */
2046
BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef));
2047
BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef));
2052
/**********************/
2054
/* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
2055
/* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
2056
/* state and location they ended up in so that both files can be found by the calling code. */
2058
FSRenameUnicode4Failed:
2060
/* attempt to rename source file to sourceUniqueName */
2061
if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) )
2063
BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2066
FSRenameUnicode3Failed:
2068
/* attempt to restore dest file's catalog information */
2069
verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo));
2071
FSSetCatalogInfo2Failed:
2073
/* attempt to restore source file's catalog information */
2074
verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo));
2076
FSSetCatalogInfo1Failed:
2078
if ( !sameParentDirs )
2080
/* attempt to move dest file back to dest directory */
2081
if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) )
2083
BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2087
FSMoveObject2Failed:
2089
if ( !sameParentDirs )
2091
/* attempt to move source file back to source directory */
2092
if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) )
2094
BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2098
FSMoveObject1Failed:
2100
/* attempt to rename dest file to original name */
2101
verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef));
2103
FSRenameUnicode2Failed:
2105
/* attempt to rename source file to original name */
2106
verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef));
2108
FSRenameUnicode1Failed:
2109
GenerateUniqueHFSUniStr2Failed:
2110
GenerateUniqueHFSUniStr1Failed:
2113
DestFSGetCatalogInfoFailed:
2114
SourceFSGetCatalogInfoFailed:
2115
DetermineSourceVRefNumFailed:
2121
/*****************************************************************************/
2123
#pragma mark ----- Shared Environment Routines -----
2125
/*****************************************************************************/
2136
pb.ioParam.ioRefNum = refNum;
2137
pb.ioParam.ioReqCount = rangeLength;
2138
pb.ioParam.ioPosMode = fsFromStart;
2139
pb.ioParam.ioPosOffset = rangeStart;
2140
result = PBLockRangeSync(&pb);
2141
require_noerr(result, PBLockRangeSync);
2148
/*****************************************************************************/
2159
pb.ioParam.ioRefNum = refNum;
2160
pb.ioParam.ioReqCount = rangeLength;
2161
pb.ioParam.ioPosMode = fsFromStart;
2162
pb.ioParam.ioPosOffset = rangeStart;
2163
result = PBUnlockRangeSync(&pb);
2164
require_noerr(result, PBUnlockRangeSync);
2171
/*****************************************************************************/
2176
SInt32 *ownerID, /* can be NULL */
2177
SInt32 *groupID, /* can be NULL */
2178
SInt32 *accessRights) /* can be NULL */
2184
/* get FSSpec from FSRef */
2185
result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2186
require_noerr(result, FSGetCatalogInfo);
2188
/* get directory access info for FSSpec */
2189
pb.accessParam.ioNamePtr = (StringPtr)spec.name;
2190
pb.accessParam.ioVRefNum = spec.vRefNum;
2191
pb.fileParam.ioDirID = spec.parID;
2192
result = PBHGetDirAccessSync(&pb);
2193
require_noerr(result, PBHGetDirAccessSync);
2195
/* return the IDs and access rights */
2196
if ( NULL != ownerID )
2198
*ownerID = pb.accessParam.ioACOwnerID;
2200
if ( NULL != groupID )
2202
*groupID = pb.accessParam.ioACGroupID;
2204
if ( NULL != accessRights )
2206
*accessRights = pb.accessParam.ioACAccess;
2209
PBHGetDirAccessSync:
2215
/*****************************************************************************/
2222
SInt32 accessRights)
2230
/* Just the bits that can be set */
2231
kSetDirAccessSettableMask = (kioACAccessBlankAccessMask +
2232
kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask +
2233
kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask +
2234
kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask)
2237
/* get FSSpec from FSRef */
2238
result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2239
require_noerr(result, FSGetCatalogInfo);
2241
/* set directory access info for FSSpec */
2242
pb.accessParam.ioNamePtr = (StringPtr)spec.name;
2243
pb.accessParam.ioVRefNum = spec.vRefNum;
2244
pb.fileParam.ioDirID = spec.parID;
2245
pb.accessParam.ioACOwnerID = ownerID;
2246
pb.accessParam.ioACGroupID = groupID;
2247
pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask;
2248
result = PBHSetDirAccessSync(&pb);
2249
require_noerr(result, PBHSetDirAccessSync);
2251
PBHSetDirAccessSync:
2257
/*****************************************************************************/
2260
FSGetVolMountInfoSize(
2261
FSVolumeRefNum volRefNum,
2267
/* check parameters */
2268
require_action(NULL != size, BadParameter, result = paramErr);
2270
pb.ioParam.ioNamePtr = NULL;
2271
pb.ioParam.ioVRefNum = volRefNum;
2272
pb.ioParam.ioBuffer = (Ptr)size;
2273
result = PBGetVolMountInfoSize(&pb);
2274
require_noerr(result, PBGetVolMountInfoSize);
2276
PBGetVolMountInfoSize:
2282
/*****************************************************************************/
2286
FSVolumeRefNum volRefNum,
2292
/* check parameters */
2293
require_action(NULL != volMountInfo, BadParameter, result = paramErr);
2295
pb.ioParam.ioNamePtr = NULL;
2296
pb.ioParam.ioVRefNum = volRefNum;
2297
pb.ioParam.ioBuffer = (Ptr)volMountInfo;
2298
result = PBGetVolMountInfo(&pb);
2299
require_noerr(result, PBGetVolMountInfo);
2307
/*****************************************************************************/
2311
const void *volMountInfo,
2312
FSVolumeRefNum *volRefNum)
2317
/* check parameters */
2318
require_action(NULL != volRefNum, BadParameter, result = paramErr);
2320
pb.ioParam.ioBuffer = (Ptr)volMountInfo;
2321
result = PBVolumeMount(&pb);
2322
require_noerr(result, PBVolumeMount);
2324
/* return the volume reference number */
2325
*volRefNum = pb.ioParam.ioVRefNum;
2333
/*****************************************************************************/
2337
FSVolumeRefNum volRefNum,
2345
/* check parameters */
2346
require_action(NULL != name, BadParameter, result = paramErr);
2348
pb.objParam.ioNamePtr = NULL;
2349
pb.objParam.ioVRefNum = volRefNum;
2350
pb.objParam.ioObjType = objType;
2351
pb.objParam.ioObjNamePtr = name;
2352
pb.objParam.ioObjID = ugID;
2353
result = PBHMapIDSync(&pb);
2354
require_noerr(result, PBHMapIDSync);
2362
/*****************************************************************************/
2366
FSVolumeRefNum volRefNum,
2367
ConstStr255Param name,
2374
/* check parameters */
2375
require_action(NULL != ugID, BadParameter, result = paramErr);
2377
pb.objParam.ioNamePtr = NULL;
2378
pb.objParam.ioVRefNum = volRefNum;
2379
pb.objParam.ioObjType = objType;
2380
pb.objParam.ioObjNamePtr = (StringPtr)name;
2381
result = PBHMapNameSync(&pb);
2382
require_noerr(result, PBHMapNameSync);
2384
/* return the user or group ID */
2385
*ugID = pb.objParam.ioObjID;
2393
/*****************************************************************************/
2397
const FSRef *srcFileRef,
2398
const FSRef *dstDirectoryRef,
2399
UniCharCount nameLength,
2400
const UniChar *copyName, /* can be NULL (no rename during copy) */
2401
TextEncoding textEncodingHint,
2402
FSRef *newRef) /* can be NULL */
2406
FSCatalogInfo catalogInfo;
2409
GetVolParmsInfoBuffer volParmsInfo;
2412
/* get source FSSpec from source FSRef */
2413
result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
2414
require_noerr(result, FSGetCatalogInfo_srcFileRef);
2416
/* Make sure the volume supports CopyFile */
2417
result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
2418
&volParmsInfo, &infoSize);
2419
require_action((noErr == result) && VolHasCopyFile(&volParmsInfo),
2420
NoCopyFileSupport, result = paramErr);
2422
/* get destination volume reference number and destination directory ID from destination FSRef */
2423
result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
2424
&catalogInfo, NULL, NULL, NULL);
2425
require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
2427
/* tell the server to copy the object */
2428
pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
2429
pb.copyParam.ioDirID = srcFileSpec.parID;
2430
pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
2431
pb.copyParam.ioDstVRefNum = catalogInfo.volume;
2432
pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
2433
pb.copyParam.ioNewName = NULL;
2434
if ( NULL != copyName )
2436
result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName);
2437
require_noerr(result, UnicodeNameGetHFSName);
2439
pb.copyParam.ioCopyName = hfsName;
2443
pb.copyParam.ioCopyName = NULL;
2445
result = PBHCopyFileSync(&pb);
2446
require_noerr(result, PBHCopyFileSync);
2448
if ( NULL != newRef )
2450
verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID,
2451
pb.copyParam.ioCopyName, newRef));
2455
UnicodeNameGetHFSName:
2456
FSGetCatalogInfo_dstDirectoryRef:
2458
FSGetCatalogInfo_srcFileRef:
2463
/*****************************************************************************/
2467
const FSRef *srcFileRef,
2468
const FSRef *dstDirectoryRef,
2469
UniCharCount nameLength,
2470
const UniChar *moveName, /* can be NULL (no rename during move) */
2471
TextEncoding textEncodingHint,
2472
FSRef *newRef) /* can be NULL */
2476
FSCatalogInfo catalogInfo;
2479
GetVolParmsInfoBuffer volParmsInfo;
2482
/* get source FSSpec from source FSRef */
2483
result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
2484
require_noerr(result, FSGetCatalogInfo_srcFileRef);
2486
/* Make sure the volume supports MoveRename */
2487
result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
2488
&volParmsInfo, &infoSize);
2489
require_action((noErr == result) && VolHasMoveRename(&volParmsInfo),
2490
NoMoveRenameSupport, result = paramErr);
2492
/* get destination volume reference number and destination directory ID from destination FSRef */
2493
result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
2494
&catalogInfo, NULL, NULL, NULL);
2495
require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
2497
/* make sure the source and destination are on the same volume */
2498
require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
2500
/* tell the server to move and rename the object */
2501
pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
2502
pb.copyParam.ioDirID = srcFileSpec.parID;
2503
pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
2504
pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
2505
pb.copyParam.ioNewName = NULL;
2506
if ( NULL != moveName )
2508
result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName);
2509
require_noerr(result, UnicodeNameGetHFSName);
2511
pb.copyParam.ioCopyName = hfsName;
2515
pb.copyParam.ioCopyName = NULL;
2517
result = PBHMoveRenameSync(&pb);
2518
require_noerr(result, PBHMoveRenameSync);
2520
if ( NULL != newRef )
2522
verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID,
2523
pb.copyParam.ioCopyName, newRef));
2527
UnicodeNameGetHFSName:
2529
FSGetCatalogInfo_dstDirectoryRef:
2530
NoMoveRenameSupport:
2531
FSGetCatalogInfo_srcFileRef:
2536
/*****************************************************************************/
2538
#pragma mark ----- File ID Routines -----
2540
/*****************************************************************************/
2544
FSVolumeRefNum volRefNum,
2552
/* check parameters */
2553
require_action(NULL != ref, BadParameter, result = paramErr);
2555
/* resolve the file ID reference */
2557
pb.ioNamePtr = tempStr;
2558
pb.ioVRefNum = volRefNum;
2559
pb.ioFileID = fileID;
2560
result = PBResolveFileIDRefSync((HParmBlkPtr)&pb);
2561
require_noerr(result, PBResolveFileIDRefSync);
2563
/* and then make an FSRef to the file */
2564
result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref);
2565
require_noerr(result, FSMakeFSRef);
2568
PBResolveFileIDRefSync:
2574
/*****************************************************************************/
2585
/* check parameters */
2586
require_action(NULL != fileID, BadParameter, result = paramErr);
2588
/* Get an FSSpec from the FSRef */
2589
result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2590
require_noerr(result, FSGetCatalogInfo);
2592
/* Create (or get) the file ID reference using the FSSpec */
2593
pb.ioNamePtr = (StringPtr)spec.name;
2594
pb.ioVRefNum = spec.vRefNum;
2595
pb.ioSrcDirID = spec.parID;
2596
result = PBCreateFileIDRefSync((HParmBlkPtr)&pb);
2597
require((noErr == result) || (fidExists == result) || (afpIDExists == result),
2598
PBCreateFileIDRefSync);
2600
/* return the file ID reference */
2601
*fileID = pb.ioFileID;
2603
PBCreateFileIDRefSync:
2610
/*****************************************************************************/
2612
#pragma mark ----- Utility Routines -----
2614
/*****************************************************************************/
2618
ByteCount buffReqSize,
2619
ByteCount *buffActSize)
2623
kSlopMemory = 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
2628
/* check parameters */
2629
require_action(NULL != buffActSize, BadParameter, tempPtr = NULL);
2631
/* Make request a multiple of 4K bytes */
2632
buffReqSize = buffReqSize & 0xfffff000;
2634
if ( buffReqSize < 0x00001000 )
2636
/* Request was smaller than 4K bytes - make it 4K */
2637
buffReqSize = 0x00001000;
2640
/* Attempt to allocate the memory */
2641
tempPtr = NewPtr(buffReqSize);
2643
/* If request failed, go to backup plan */
2644
if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) )
2647
** Try to get largest 4K byte block available
2648
** leaving some slop for the toolbox if possible
2650
long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000;
2652
buffReqSize = MaxBlock() & 0xfffff000;
2654
if ( buffReqSize > freeMemory )
2656
buffReqSize = freeMemory;
2659
if ( buffReqSize == 0 )
2661
buffReqSize = 0x00001000;
2664
tempPtr = NewPtr(buffReqSize);
2667
/* Return bytes allocated */
2668
if ( tempPtr != NULL )
2670
*buffActSize = buffReqSize;
2682
/*****************************************************************************/
2689
return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) );
2692
/*****************************************************************************/
2696
const FSRef *newDefault,
2700
FSVolumeRefNum vRefNum;
2702
FSCatalogInfo catalogInfo;
2704
/* check parameters */
2705
require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr);
2707
/* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
2708
result = FSGetCatalogInfo(newDefault,
2709
kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
2710
&catalogInfo, NULL, NULL, NULL);
2711
require_noerr(result, FSGetCatalogInfo);
2713
/* Make sure newDefault is a directory */
2714
require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory,
2717
/* Get the current working directory. */
2718
result = HGetVol(NULL, &vRefNum, &dirID);
2719
require_noerr(result, HGetVol);
2721
/* Return the oldDefault FSRef */
2722
result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault);
2723
require_noerr(result, FSMakeFSRef);
2725
/* Set the new current working directory */
2726
result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
2727
require_noerr(result, HSetVol);
2732
NewDefaultNotDirectory:
2739
/*****************************************************************************/
2743
const FSRef *oldDefault)
2746
FSCatalogInfo catalogInfo;
2748
/* check parameters */
2749
require_action(NULL != oldDefault, BadParameter, result = paramErr);
2751
/* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
2752
result = FSGetCatalogInfo(oldDefault,
2753
kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
2754
&catalogInfo, NULL, NULL, NULL);
2755
require_noerr(result, FSGetCatalogInfo);
2757
/* Make sure oldDefault is a directory */
2758
require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory,
2761
/* Set the current working directory to oldDefault */
2762
result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
2763
require_noerr(result, HSetVol);
2766
OldDefaultNotDirectory:
2773
/*****************************************************************************/