]> git.jsancho.org Git - lugaru.git/blob - Source/MoreFilesX.c
617f49276826a763ab9edb99decae46b1cb52a51
[lugaru.git] / Source / MoreFilesX.c
1 /*
2         File:           MoreFilesX.c
3
4         Contains:       A collection of useful high-level File Manager routines
5                                 which use the HFS Plus APIs wherever possible.
6
7         Version:        MoreFilesX 1.0.1
8
9         Copyright:      © 1992-2002 by Apple Computer, Inc., all rights reserved.
10
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.
16
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.
31
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.
37
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.
45
46         File Ownership:
47
48                 DRI:                            Apple Macintosh Developer Technical Support
49
50                 Other Contact:          For bug reports, consult the following page on
51                                                         the World Wide Web:
52                                                                 http://developer.apple.com/bugreporter/
53
54                 Technology:                     DTS Sample Code
55
56         Writers:
57
58                 (JL)    Jim Luther
59
60         Change History (most recent first):
61
62                  <4>     8/22/02        JL              [3016251]  Changed FSMoveRenameObjectUnicode to not use
63                                                                         the Temporary folder because it isn't available on
64                                                                         NFS volumes.
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
67                                                                         warnings.
68                  <2>     4/19/02        JL              [2853901]  Updated standard disclaimer.
69                  <1>     1/25/02        JL              MoreFilesX 1.0
70 */
71
72 #if defined(__MACH__)
73         #include <Carbon/Carbon.h>
74         #include <string.h>
75 #else
76         #include <Carbon.h>
77         #include <string.h>
78 #endif
79
80 #include "MoreFilesX.h"
81
82 /* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */
83 #ifndef BuildingMoreFilesXForMacOS9
84         #define BuildingMoreFilesXForMacOS9 0
85 #endif
86
87 /*****************************************************************************/
88
89 #pragma mark ----- Local type definitions -----
90
91 struct FSIterateContainerGlobals
92 {
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 */
108 };
109 typedef struct FSIterateContainerGlobals FSIterateContainerGlobals;
110
111 struct FSDeleteContainerGlobals
112 {
113         OSErr                                                   result;                 /* result */
114         ItemCount                                               actualObjects;  /* number of objects returned */
115         FSCatalogInfo                                   catalogInfo;    /* FSCatalogInfo */
116 };
117 typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals;
118
119 /*****************************************************************************/
120
121 #pragma mark ----- Local prototypes -----
122
123 static
124 void
125 FSDeleteContainerLevel(
126         const FSRef *container,
127         FSDeleteContainerGlobals *theGlobals);
128
129 static
130 void
131 FSIterateContainerLevel(
132         FSIterateContainerGlobals *theGlobals);
133
134 static
135 OSErr
136 GenerateUniqueHFSUniStr(
137         long *startSeed,
138         const FSRef *dir1,
139         const FSRef *dir2,
140         HFSUniStr255 *uniqueName);
141
142 /*****************************************************************************/
143
144 #pragma mark ----- File Access Routines -----
145
146 /*****************************************************************************/
147
148 OSErr
149 FSCopyFork(
150         SInt16 srcRefNum,
151         SInt16 dstRefNum,
152         void *copyBufferPtr,
153         ByteCount copyBufferSize)
154 {
155         OSErr           srcResult;
156         OSErr           dstResult;
157         OSErr           result;
158         SInt64          forkSize;
159         ByteCount       readActualCount;
160         
161         /* check input parameters */
162         require_action((NULL != copyBufferPtr) && (0 != copyBufferSize), BadParameter, result = paramErr);
163         
164         /* get source fork size */
165         result = FSGetForkSize(srcRefNum, &forkSize);
166         require_noerr(result, SourceFSGetForkSizeFailed);
167         
168         /* allocate disk space for destination fork */
169         result = FSSetForkSize(dstRefNum, fsFromStart, forkSize);
170         require_noerr(result, DestinationFSSetForkSizeFailed);
171         
172         /* reset source fork's position to 0 */
173         result = FSSetForkPosition(srcRefNum, fsFromStart, 0);
174         require_noerr(result, SourceFSSetForkPositionFailed);
175         
176         /* reset destination fork's position to 0 */
177         result = FSSetForkPosition(dstRefNum, fsFromStart, 0);
178         require_noerr(result, DestinationFSSetForkPositionFailed);
179
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) )
183         {
184                 copyBufferSize &= ~(0x00001000 - 1);
185         }
186         
187         /* copy source to destination */
188         srcResult = dstResult = noErr;
189         while ( (noErr == srcResult) && (noErr == dstResult) )
190         {
191                 srcResult = FSReadFork(srcRefNum, fsAtMark + noCacheMask, 0, copyBufferSize, copyBufferPtr, &readActualCount);
192                 dstResult = FSWriteFork(dstRefNum, fsAtMark + noCacheMask, 0, readActualCount, copyBufferPtr, NULL);
193         }
194         
195         /* make sure there were no errors at the destination */
196         require_noerr_action(dstResult, DestinationFSWriteForkFailed, result = dstResult);
197         
198         /* make sure the error at the source was eofErr */
199         require_action(eofErr == srcResult, SourceResultNotEofErr, result = srcResult);
200         
201         /* everything went as expected */
202         result = noErr;
203
204 SourceResultNotEofErr:
205 DestinationFSWriteForkFailed:
206 DestinationFSSetForkPositionFailed:
207 SourceFSSetForkPositionFailed:
208 DestinationFSSetForkSizeFailed:
209 SourceFSGetForkSizeFailed:
210 BadParameter:
211
212         return ( result );
213 }
214
215 /*****************************************************************************/
216
217 #pragma mark ----- Volume Access Routines -----
218
219 /*****************************************************************************/ 
220
221 OSErr
222 FSGetVolParms(
223         FSVolumeRefNum volRefNum,
224         UInt32 bufferSize,
225         GetVolParmsInfoBuffer *volParmsInfo,
226         UInt32 *actualInfoSize)
227 {
228         OSErr                   result;
229         HParamBlockRec  pb;
230         
231         /* check parameters */
232         require_action((NULL != volParmsInfo) && (NULL != actualInfoSize),
233                 BadParameter, result = paramErr);
234         
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);
241         
242         /* return number of bytes the file system returned in volParmsInfo buffer */
243         *actualInfoSize = (UInt32)pb.ioParam.ioActCount;
244         
245 PBHGetVolParmsSync:
246 BadParameter:
247
248         return ( result );
249 }
250
251 /*****************************************************************************/
252
253 OSErr
254 FSGetVRefNum(
255         const FSRef *ref,
256         FSVolumeRefNum *vRefNum)
257 {
258         OSErr                   result;
259         FSCatalogInfo   catalogInfo;
260         
261         /* check parameters */
262         require_action(NULL != vRefNum, BadParameter, result = paramErr);
263         
264         /* get the volume refNum from the FSRef */
265         result = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
266         require_noerr(result, FSGetCatalogInfo);
267         
268         /* return volume refNum from catalogInfo */
269         *vRefNum = catalogInfo.volume;
270         
271 FSGetCatalogInfo:
272 BadParameter:
273
274         return ( result );
275 }
276
277 /*****************************************************************************/
278
279 OSErr
280 FSGetVInfo(
281         FSVolumeRefNum volume,
282         HFSUniStr255 *volumeName,       /* can be NULL */
283         UInt64 *freeBytes,                      /* can be NULL */
284         UInt64 *totalBytes)                     /* can be NULL */
285 {
286         OSErr                           result;
287         FSVolumeInfo            info;
288         
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);
294         
295         if ( NULL != freeBytes )
296         {
297                 *freeBytes = info.freeBytes;
298         }
299         if ( NULL != totalBytes )
300         {
301                 *totalBytes = info.totalBytes;
302         }
303         
304 FSGetVolumeInfo:
305
306         return ( result );
307 }
308
309 /*****************************************************************************/
310
311 OSErr
312 FSGetVolFileSystemID(
313         FSVolumeRefNum volume,
314         UInt16 *fileSystemID,   /* can be NULL */
315         UInt16 *signature)              /* can be NULL */
316 {
317         OSErr                   result;
318         FSVolumeInfo    info;
319         
320         result = FSGetVolumeInfo(volume, 0, NULL, kFSVolInfoFSInfo, &info, NULL, NULL);
321         require_noerr(result, FSGetVolumeInfo);
322         
323         if ( NULL != fileSystemID )
324         {
325                 *fileSystemID = info.filesystemID;
326         }
327         if ( NULL != signature )
328         {
329                 *signature = info.signature;
330         }
331         
332 FSGetVolumeInfo:
333
334         return ( result );
335 }
336
337 /*****************************************************************************/
338
339 OSErr
340 FSGetMountedVolumes(
341         FSRef ***volumeRefsHandle,      /* pointer to handle of FSRefs */
342         ItemCount *numVolumes)
343 {
344         OSErr           result;
345         OSErr           memResult;
346         ItemCount       volumeIndex;
347         FSRef           ref;
348         
349         /* check parameters */
350         require_action((NULL != volumeRefsHandle) && (NULL != numVolumes),
351                 BadParameter, result = paramErr);
352         
353         /* No volumes yet */
354         *numVolumes = 0;
355         
356         /* Allocate a handle for the results */
357         *volumeRefsHandle = (FSRef **)NewHandle(0);
358         require_action(NULL != *volumeRefsHandle, NewHandle, result = memFullErr);
359         
360         /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */
361         volumeIndex = 1;
362         do
363         {
364                 result = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoNone, NULL, NULL, &ref);
365                 if ( noErr == result )
366                 {
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);
371                         
372                         ++(*numVolumes);        /* increment the volume count */
373                         ++volumeIndex;          /* and the volumeIndex to get the next volume*/
374                 }
375         } while ( noErr == result );
376         
377         /* nsvErr is OK -- it just means there are no more volumes */
378         require(nsvErr == result, FSGetVolumeInfo);
379                 
380         return ( noErr );
381         
382         /**********************/
383         
384 MemoryAllocationFailed:
385 FSGetVolumeInfo:
386
387         /* dispose of handle if already allocated and clear the outputs */
388         if ( NULL != *volumeRefsHandle )
389         {
390                 DisposeHandle((Handle)*volumeRefsHandle);
391                 *volumeRefsHandle = NULL;
392         }
393         *numVolumes = 0;
394         
395 NewHandle:
396 BadParameter:
397
398         return ( result );
399 }
400
401 /*****************************************************************************/
402
403 #pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
404
405 /*****************************************************************************/
406
407 OSErr
408 FSRefMakeFSSpec(
409         const FSRef *ref,
410         FSSpec *spec)
411 {
412         OSErr   result;
413         
414         /* check parameters */
415         require_action(NULL != spec, BadParameter, result = paramErr);
416         
417         result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
418         require_noerr(result, FSGetCatalogInfo);
419         
420 FSGetCatalogInfo:
421 BadParameter:
422
423         return ( result );
424 }
425
426 /*****************************************************************************/
427
428 OSErr
429 FSMakeFSRef(
430         FSVolumeRefNum volRefNum,
431         SInt32 dirID,
432         ConstStr255Param name,
433         FSRef *ref)
434 {
435         OSErr           result;
436         FSRefParam      pb;
437         
438         /* check parameters */
439         require_action(NULL != ref, BadParameter, result = paramErr);
440         
441         pb.ioVRefNum = volRefNum;
442         pb.ioDirID = dirID;
443         pb.ioNamePtr = (StringPtr)name;
444         pb.newRef = ref;
445         result = PBMakeFSRefSync(&pb);
446         require_noerr(result, PBMakeFSRefSync);
447         
448 PBMakeFSRefSync:
449 BadParameter:
450
451         return ( result );
452 }
453
454 /*****************************************************************************/
455
456 OSStatus
457 FSMakePath(
458         SInt16 volRefNum,
459         SInt32 dirID,
460         ConstStr255Param name,
461         UInt8 *path,
462         UInt32 maxPathSize)
463 {
464         OSStatus        result;
465         FSRef           ref;
466         
467         /* check parameters */
468         require_action(NULL != path, BadParameter, result = paramErr);
469         
470         /* convert the inputs to an FSRef */
471         result = FSMakeFSRef(volRefNum, dirID, name, &ref);
472         require_noerr(result, FSMakeFSRef);
473         
474         /* and then convert the FSRef to a path */
475         result = FSRefMakePath(&ref, path, maxPathSize);
476         require_noerr(result, FSRefMakePath);
477         
478 FSRefMakePath:
479 FSMakeFSRef:
480 BadParameter:
481
482         return ( result );
483 }
484
485 /*****************************************************************************/
486
487 OSStatus
488 FSPathMakeFSSpec(
489         const UInt8 *path,
490         FSSpec *spec,
491         Boolean *isDirectory)   /* can be NULL */
492 {
493         OSStatus        result;
494         FSRef           ref;
495         
496         /* check parameters */
497         require_action(NULL != spec, BadParameter, result = paramErr);
498         
499         /* convert the POSIX path to an FSRef */
500         result = FSPathMakeRef(path, &ref, isDirectory);
501         require_noerr(result, FSPathMakeRef);
502         
503         /* and then convert the FSRef to an FSSpec */
504         result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL);
505         require_noerr(result, FSGetCatalogInfo);
506         
507 FSGetCatalogInfo:
508 FSPathMakeRef:
509 BadParameter:
510
511         return ( result );
512 }
513
514 /*****************************************************************************/
515
516 OSErr
517 UnicodeNameGetHFSName(
518         UniCharCount nameLength,
519         const UniChar *name,
520         TextEncoding textEncodingHint,
521         Boolean isVolumeName,
522         Str31 hfsName)
523 {
524         OSStatus                        result;
525         ByteCount                       unicodeByteLength;
526         ByteCount                       unicodeBytesConverted;
527         ByteCount                       actualPascalBytes;
528         UnicodeMapping          uMapping;
529         UnicodeToTextInfo       utInfo;
530         
531         /* check parameters */
532         require_action(NULL != hfsName, BadParameter, result = paramErr);
533         
534         /* make sure output is valid in case we get errors or there's nothing to convert */
535         hfsName[0] = 0;
536         
537         unicodeByteLength = nameLength * sizeof(UniChar);
538         if ( 0 == unicodeByteLength )
539         {
540                 /* do nothing */
541                 result = noErr;
542         }
543         else
544         {
545                 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
546                 if ( kTextEncodingUnknown == textEncodingHint )
547                 {
548                         ScriptCode                      script;
549                         RegionCode                      region;
550                         
551                         script = (ScriptCode)GetScriptManagerVariable(smSysScript);
552                         region = (RegionCode)GetScriptManagerVariable(smRegionCode);
553                         result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
554                                 NULL, &textEncodingHint );
555                         if ( paramErr == result )
556                         {
557                                 /* ok, ignore the region and try again */
558                                 result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
559                                         kTextRegionDontCare, NULL, &textEncodingHint );
560                         }
561                         if ( noErr != result )
562                         {
563                                 /* ok... try something */
564                                 textEncodingHint = kTextEncodingMacRoman;
565                         }
566                 }
567                 
568                 uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
569                         kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
570                 uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
571                 uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
572         
573                 result = CreateUnicodeToTextInfo(&uMapping, &utInfo);
574                 require_noerr(result, CreateUnicodeToTextInfo);
575                 
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);
581                 
582                 hfsName[0] = (unsigned char)actualPascalBytes;  /* fill in length byte */
583
584 ConvertFromUnicodeToText:
585                 
586                 /* verify the result in debug builds -- there's really not anything you can do if it fails */
587                 verify_noerr(DisposeUnicodeToTextInfo(&utInfo));
588         }
589         
590 CreateUnicodeToTextInfo:        
591 BadParameter:
592
593         return ( result );
594 }
595
596 /*****************************************************************************/
597
598 OSErr
599 HFSNameGetUnicodeName(
600         ConstStr31Param hfsName,
601         TextEncoding textEncodingHint,
602         HFSUniStr255 *unicodeName)
603 {
604         ByteCount                       unicodeByteLength;
605         OSStatus                        result;
606         UnicodeMapping          uMapping;
607         TextToUnicodeInfo       tuInfo;
608         ByteCount                       pascalCharsRead;
609         
610         /* check parameters */
611         require_action(NULL != unicodeName, BadParameter, result = paramErr);
612         
613         /* make sure output is valid in case we get errors or there's nothing to convert */
614         unicodeName->length = 0;
615         
616         if ( 0 == StrLength(hfsName) )
617         {
618                 result = noErr;
619         }
620         else
621         {
622                 /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */
623                 if ( kTextEncodingUnknown == textEncodingHint )
624                 {
625                         ScriptCode                      script;
626                         RegionCode                      region;
627                         
628                         script = GetScriptManagerVariable(smSysScript);
629                         region = GetScriptManagerVariable(smRegionCode);
630                         result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region,
631                                 NULL, &textEncodingHint);
632                         if ( paramErr == result )
633                         {
634                                 /* ok, ignore the region and try again */
635                                 result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare,
636                                         kTextRegionDontCare, NULL, &textEncodingHint);
637                         }
638                         if ( noErr != result )
639                         {
640                                 /* ok... try something */
641                                 textEncodingHint = kTextEncodingMacRoman;
642                         }
643                 }
644                 
645                 uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0,
646                         kUnicodeCanonicalDecompVariant, kUnicode16BitFormat);
647                 uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint);
648                 uMapping.mappingVersion = kUnicodeUseHFSPlusMapping;
649         
650                 result = CreateTextToUnicodeInfo(&uMapping, &tuInfo);
651                 require_noerr(result, CreateTextToUnicodeInfo);
652                         
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);
659                 
660                 /* convert from byte count to char count */
661                 unicodeName->length = unicodeByteLength / sizeof(UniChar);
662
663 ConvertFromTextToUnicode:
664
665                 /* verify the result in debug builds -- there's really not anything you can do if it fails */
666                 verify_noerr(DisposeTextToUnicodeInfo(&tuInfo));
667         }
668         
669 CreateTextToUnicodeInfo:
670 BadParameter:
671
672         return ( result );
673 }
674
675 /*****************************************************************************/
676
677 #pragma mark ----- File/Directory Manipulation Routines -----
678
679 /*****************************************************************************/
680
681 Boolean FSRefValid(const FSRef *ref)
682 {
683         return ( noErr == FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, NULL, NULL) );
684 }
685
686 /*****************************************************************************/
687
688 OSErr
689 FSGetParentRef(
690         const FSRef *ref,
691         FSRef *parentRef)
692 {
693         OSErr   result;
694         FSCatalogInfo   catalogInfo;
695         
696         /* check parameters */
697         require_action(NULL != parentRef, BadParameter, result = paramErr);
698         
699         result = FSGetCatalogInfo(ref, kFSCatInfoNodeID, &catalogInfo, NULL, NULL, parentRef);
700         require_noerr(result, FSGetCatalogInfo);
701         
702         /*
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!
709          */
710         if ( fsRtDirID == catalogInfo.nodeID )
711         {
712                 /* clear parentRef and return noErr which is the proper behavior */
713                 memset(parentRef, 0, sizeof(FSRef));
714         }
715
716 FSGetCatalogInfo:
717 BadParameter:
718
719         return ( result );
720 }
721
722 /*****************************************************************************/
723
724 OSErr
725 FSGetFileDirName(
726         const FSRef *ref,
727         HFSUniStr255 *outName)
728 {
729         OSErr   result;
730         
731         /* check parameters */
732         require_action(NULL != outName, BadParameter, result = paramErr);
733         
734         result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, outName, NULL, NULL);
735         require_noerr(result, FSGetCatalogInfo);
736         
737 FSGetCatalogInfo:
738 BadParameter:
739
740         return ( result );
741 }
742
743 /*****************************************************************************/
744
745 OSErr
746 FSGetNodeID(
747         const FSRef *ref,
748         long *nodeID,                   /* can be NULL */
749         Boolean *isDirectory)   /* can be NULL */
750 {
751         OSErr                           result;
752         FSCatalogInfo           catalogInfo;
753         FSCatalogInfoBitmap whichInfo;
754         
755         /* determine what catalog information to get */
756         whichInfo = kFSCatInfoNone; /* start with none */
757         if ( NULL != nodeID )
758         {
759                 whichInfo |= kFSCatInfoNodeID;
760         }
761         if ( NULL != isDirectory )
762         {
763                 whichInfo |= kFSCatInfoNodeFlags;
764         }
765         
766         result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
767         require_noerr(result, FSGetCatalogInfo);
768         
769         if ( NULL != nodeID )
770         {
771                 *nodeID = catalogInfo.nodeID;
772         }
773         if ( NULL != isDirectory )
774         {
775                 *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
776         }
777         
778 FSGetCatalogInfo:
779
780         return ( result );
781 }
782
783 /*****************************************************************************/
784
785 OSErr
786 FSGetUserPrivilegesPermissions(
787         const FSRef *ref,
788         UInt8 *userPrivileges,          /* can be NULL */
789         UInt32 permissions[4])          /* can be NULL */
790 {
791         OSErr                   result;
792         FSCatalogInfo   catalogInfo;
793         FSCatalogInfoBitmap whichInfo;
794         
795         /* determine what catalog information to get */
796         whichInfo = kFSCatInfoNone; /* start with none */
797         if ( NULL != userPrivileges )
798         {
799                 whichInfo |= kFSCatInfoUserPrivs;
800         }
801         if ( NULL != permissions )
802         {
803                 whichInfo |= kFSCatInfoPermissions;
804         }
805         
806         result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
807         require_noerr(result, FSGetCatalogInfo);
808         
809         if ( NULL != userPrivileges )
810         {
811                 *userPrivileges = catalogInfo.userPrivileges;
812         }
813         if ( NULL != permissions )
814         {
815                 BlockMoveData(&catalogInfo.permissions, permissions, sizeof(UInt32) * 4);
816         }
817         
818 FSGetCatalogInfo:
819
820         return ( result );
821 }
822
823 /*****************************************************************************/
824
825 OSErr
826 FSCheckLock(
827         const FSRef *ref)
828 {
829         OSErr                   result;
830         FSCatalogInfo   catalogInfo;
831         FSVolumeInfo    volumeInfo;
832         
833         /* get nodeFlags and vRefNum for container */
834         result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoVolume, &catalogInfo, NULL, NULL,NULL);
835         require_noerr(result, FSGetCatalogInfo);
836         
837         /* is file locked? */
838         if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
839         {
840                 result = fLckdErr;      /* file is locked */
841         }
842         else
843         {
844                 /* file isn't locked, but is volume locked? */
845                 
846                 /* get volume flags */
847                 result = FSGetVolumeInfo(catalogInfo.volume, 0, NULL, kFSVolInfoFlags, &volumeInfo, NULL, NULL);
848                 require_noerr(result, FSGetVolumeInfo);
849                 
850                 if ( 0 != (volumeInfo.flags & kFSVolFlagHardwareLockedMask) )
851                 {
852                         result = wPrErr;        /* volume locked by hardware */
853                 }
854                 else if ( 0 != (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) )
855                 {
856                         result = vLckdErr;      /* volume locked by software */
857                 }
858         }
859         
860 FSGetVolumeInfo:
861 FSGetCatalogInfo:
862
863         return ( result );
864 }
865
866 /*****************************************************************************/
867
868 OSErr
869 FSGetForkSizes(
870         const FSRef *ref,
871         UInt64 *dataLogicalSize,        /* can be NULL */
872         UInt64 *rsrcLogicalSize)        /* can be NULL */
873 {
874         OSErr                           result;
875         FSCatalogInfoBitmap whichInfo;
876         FSCatalogInfo           catalogInfo;
877         
878         whichInfo = kFSCatInfoNodeFlags;
879         if ( NULL != dataLogicalSize )
880         {
881                 /* get data fork size */
882                 whichInfo |= kFSCatInfoDataSizes;
883         }
884         if ( NULL != rsrcLogicalSize )
885         {
886                 /* get resource fork size */
887                 whichInfo |= kFSCatInfoRsrcSizes;
888         }
889
890         /* get nodeFlags and catalog info */
891         result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL,NULL);
892         require_noerr(result, FSGetCatalogInfo);
893         
894         /* make sure FSRef was to a file */
895         require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
896         
897         if ( NULL != dataLogicalSize )
898         {
899                 /* return data fork size */
900                 *dataLogicalSize = catalogInfo.dataLogicalSize;
901         }
902         if ( NULL != rsrcLogicalSize )
903         {
904                 /* return resource fork size */
905                 *rsrcLogicalSize = catalogInfo.rsrcLogicalSize;
906         }
907         
908 FSRefNotFile:
909 FSGetCatalogInfo:
910
911         return ( result );
912 }
913
914 /*****************************************************************************/
915
916 OSErr
917 FSGetTotalForkSizes(
918         const FSRef *ref,
919         UInt64 *totalLogicalSize,       /* can be NULL */
920         UInt64 *totalPhysicalSize,      /* can be NULL */
921         ItemCount *forkCount)           /* can be NULL */
922 {
923         OSErr                   result;
924         CatPositionRec  forkIterator;
925         SInt64                  forkSize;
926         SInt64                  *forkSizePtr;
927         UInt64                  forkPhysicalSize;
928         UInt64                  *forkPhysicalSizePtr;
929         
930         /* Determine if forkSize needed */
931         if ( NULL != totalLogicalSize)
932         {
933                 *totalLogicalSize = 0;
934                 forkSizePtr = &forkSize;
935         }
936         else
937         {
938                 forkSizePtr = NULL;
939         }
940         
941         /* Determine if forkPhysicalSize is needed */
942         if ( NULL != totalPhysicalSize )
943         {
944                 *totalPhysicalSize = 0;
945                 forkPhysicalSizePtr = &forkPhysicalSize;
946         }
947         else
948         {
949                 forkPhysicalSizePtr = NULL;
950         }
951         
952         /* zero fork count if returning it */
953         if ( NULL != forkCount )
954         {
955                 *forkCount = 0;
956         }
957         
958         /* Iterate through the forks to get the sizes */
959         forkIterator.initialize = 0;
960         do
961         {
962                 result = FSIterateForks(ref, &forkIterator, NULL, forkSizePtr, forkPhysicalSizePtr);
963                 if ( noErr == result )
964                 {
965                         if ( NULL != totalLogicalSize )
966                         {
967                                 *totalLogicalSize += forkSize;
968                         }
969                         
970                         if ( NULL != totalPhysicalSize )
971                         {
972                                 *totalPhysicalSize += forkPhysicalSize;
973                         }
974                         
975                         if ( NULL != forkCount )
976                         {
977                                 ++*forkCount;
978                         }
979                 }
980         } while ( noErr == result );
981         
982         /* any error result other than errFSNoMoreItems is serious */
983         require(errFSNoMoreItems == result, FSIterateForks);
984         
985         /* Normal exit */
986         result = noErr;
987
988 FSIterateForks:
989         
990         return ( result );
991 }
992
993 /*****************************************************************************/
994
995 OSErr
996 FSBumpDate(
997         const FSRef *ref)
998 {
999         OSStatus                result;
1000         FSCatalogInfo   catalogInfo;
1001         UTCDateTime             oldDateTime;
1002 #if !BuildingMoreFilesXForMacOS9
1003         FSRef                   parentRef;
1004         Boolean                 notifyParent;
1005 #endif
1006
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);
1011         
1012         /* Notify the parent if this is a file */
1013         notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask));
1014 #else
1015         /* Get the content modification date and time */
1016         result = FSGetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo, NULL, NULL, NULL);
1017         require_noerr(result, FSGetCatalogInfo);
1018 #endif
1019         
1020         oldDateTime = catalogInfo.contentModDate;
1021
1022         /* Get the current date and time */
1023         result = GetUTCDateTime(&catalogInfo.contentModDate, kUTCDefaultOptions);
1024         require_noerr(result, GetUTCDateTime);
1025         
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) )
1030         {
1031                 ++catalogInfo.contentModDate.lowSeconds;
1032                 if ( 0 == catalogInfo.contentModDate.lowSeconds )
1033                 {
1034                         ++catalogInfo.contentModDate.highSeconds;
1035                 }
1036         }
1037         
1038         /* Bump the content modification date and time */
1039         result = FSSetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo);
1040         require_noerr(result, FSSetCatalogInfo);
1041
1042 #if !BuildingMoreFilesXForMacOS9
1043         /*
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.
1048          */
1049         
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);
1053 #endif
1054
1055         /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */
1056 FNNotify:
1057 FSSetCatalogInfo:
1058         
1059         return ( noErr );
1060         
1061         /**********************/
1062         
1063 GetUTCDateTime:
1064 FSGetCatalogInfo:
1065
1066         return ( result );
1067 }
1068
1069 /*****************************************************************************/
1070
1071 OSErr
1072 FSGetFinderInfo(
1073         const FSRef *ref,
1074         FinderInfo *info,                                       /* can be NULL */
1075         ExtendedFinderInfo *extendedInfo,       /* can be NULL */
1076         Boolean *isDirectory)                           /* can be NULL */
1077 {
1078         OSErr                           result;
1079         FSCatalogInfo           catalogInfo;
1080         FSCatalogInfoBitmap whichInfo;
1081         
1082         /* determine what catalog information is really needed */
1083         whichInfo = kFSCatInfoNone;
1084         
1085         if ( NULL != info )
1086         {
1087                 /* get FinderInfo */
1088                 whichInfo |= kFSCatInfoFinderInfo;
1089         }
1090         
1091         if ( NULL != extendedInfo )
1092         {
1093                 /* get ExtendedFinderInfo */
1094                 whichInfo |= kFSCatInfoFinderXInfo;
1095         }
1096         
1097         if ( NULL != isDirectory )
1098         {
1099                 whichInfo |= kFSCatInfoNodeFlags;
1100         }
1101         
1102         result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL);
1103         require_noerr(result, FSGetCatalogInfo);
1104         
1105         /* return FinderInfo if requested */
1106         if ( NULL != info )
1107         {
1108                 BlockMoveData(catalogInfo.finderInfo, info, sizeof(FinderInfo));
1109         }
1110         
1111         /* return ExtendedFinderInfo if requested */
1112         if ( NULL != extendedInfo)
1113         {
1114                 BlockMoveData(catalogInfo.extFinderInfo, extendedInfo, sizeof(ExtendedFinderInfo));
1115         }
1116         
1117         /* set isDirectory Boolean if requested */
1118         if ( NULL != isDirectory)
1119         {
1120                 *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags));
1121         }
1122         
1123 FSGetCatalogInfo:
1124
1125         return ( result );
1126 }
1127
1128 /*****************************************************************************/
1129
1130 OSErr
1131 FSSetFinderInfo(
1132         const FSRef *ref,
1133         const FinderInfo *info,
1134         const ExtendedFinderInfo *extendedInfo)
1135 {
1136         OSErr                           result;
1137         FSCatalogInfo           catalogInfo;
1138         FSCatalogInfoBitmap whichInfo;
1139         
1140         /* determine what catalog information will be set */
1141         whichInfo = kFSCatInfoNone; /* start with none */
1142         if ( NULL != info )
1143         {
1144                 /* set FinderInfo */
1145                 whichInfo |= kFSCatInfoFinderInfo;
1146                 BlockMoveData(info, catalogInfo.finderInfo, sizeof(FinderInfo));
1147         }
1148         if ( NULL != extendedInfo )
1149         {
1150                 /* set ExtendedFinderInfo */
1151                 whichInfo |= kFSCatInfoFinderXInfo;
1152                 BlockMoveData(extendedInfo, catalogInfo.extFinderInfo, sizeof(ExtendedFinderInfo));
1153         }
1154         
1155         result = FSSetCatalogInfo(ref, whichInfo, &catalogInfo);
1156         require_noerr(result, FSGetCatalogInfo);
1157         
1158 FSGetCatalogInfo:
1159
1160         return ( result );
1161 }
1162
1163 /*****************************************************************************/
1164
1165 OSErr
1166 FSChangeCreatorType(
1167         const FSRef *ref,
1168         OSType fileCreator,
1169         OSType fileType)
1170 {
1171         OSErr                   result;
1172         FSCatalogInfo   catalogInfo;
1173         FSRef                   parentRef;
1174         
1175         /* get nodeFlags, finder info, and parent FSRef */
1176         result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, &catalogInfo , NULL, NULL, &parentRef);
1177         require_noerr(result, FSGetCatalogInfo);
1178         
1179         /* make sure FSRef was to a file */
1180         require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr);
1181         
1182         /* If fileType not 0x00000000, change fileType */
1183         if ( fileType != (OSType)0x00000000 )
1184         {
1185                 ((FileInfo *)&catalogInfo.finderInfo)->fileType = fileType;
1186         }
1187         
1188         /* If creator not 0x00000000, change creator */
1189         if ( fileCreator != (OSType)0x00000000 )
1190         {
1191                 ((FileInfo *)&catalogInfo.finderInfo)->fileCreator = fileCreator;
1192         }
1193         
1194         /* now, save the new information back to disk */
1195         result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
1196         require_noerr(result, FSSetCatalogInfo);
1197         
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));
1201         
1202 FSSetCatalogInfo:
1203 FSRefNotFile:
1204 FSGetCatalogInfo:
1205
1206         return ( result );
1207 }
1208
1209 /*****************************************************************************/
1210
1211 OSErr
1212 FSChangeFinderFlags(
1213         const FSRef *ref,
1214         Boolean setBits,
1215         UInt16 flagBits)
1216 {
1217         OSErr                   result;
1218         FSCatalogInfo   catalogInfo;
1219         FSRef                   parentRef;
1220         
1221         /* get the current finderInfo */
1222         result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef);
1223         require_noerr(result, FSGetCatalogInfo);
1224         
1225         /* set or clear the appropriate bits in the finderInfo.finderFlags */
1226         if ( setBits )
1227         {
1228                 /* OR in the bits */
1229                 ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits;
1230         }
1231         else
1232         {
1233                 /* AND out the bits */
1234                 ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits;
1235         }
1236         
1237         /* save the modified finderInfo */
1238         result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo);
1239         require_noerr(result, FSSetCatalogInfo);
1240         
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));
1244         
1245 FSSetCatalogInfo:
1246 FSGetCatalogInfo:
1247
1248         return ( result );
1249 }
1250
1251 /*****************************************************************************/
1252
1253 OSErr
1254 FSSetInvisible(
1255         const FSRef *ref)
1256 {
1257         return ( FSChangeFinderFlags(ref, true, kIsInvisible) );
1258 }
1259
1260 OSErr
1261 FSClearInvisible(
1262         const FSRef *ref)
1263 {
1264         return ( FSChangeFinderFlags(ref, false, kIsInvisible) );
1265 }
1266
1267 /*****************************************************************************/
1268
1269 OSErr
1270 FSSetNameLocked(
1271         const FSRef *ref)
1272 {
1273         return ( FSChangeFinderFlags(ref, true, kNameLocked) );
1274 }
1275
1276 OSErr
1277 FSClearNameLocked(
1278         const FSRef *ref)
1279 {
1280         return ( FSChangeFinderFlags(ref, false, kNameLocked) );
1281 }
1282
1283 /*****************************************************************************/
1284
1285 OSErr
1286 FSSetIsStationery(
1287         const FSRef *ref)
1288 {
1289         return ( FSChangeFinderFlags(ref, true, kIsStationery) );
1290 }
1291
1292 OSErr
1293 FSClearIsStationery(
1294         const FSRef *ref)
1295 {
1296         return ( FSChangeFinderFlags(ref, false, kIsStationery) );
1297 }
1298
1299 /*****************************************************************************/
1300
1301 OSErr
1302 FSSetHasCustomIcon(
1303         const FSRef *ref)
1304 {
1305         return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) );
1306 }
1307
1308 OSErr
1309 FSClearHasCustomIcon(
1310         const FSRef *ref)
1311 {
1312         return ( FSChangeFinderFlags(ref, false, kHasCustomIcon) );
1313 }
1314
1315 /*****************************************************************************/
1316
1317 OSErr
1318 FSClearHasBeenInited(
1319         const FSRef *ref)
1320 {
1321         return ( FSChangeFinderFlags(ref, false, kHasBeenInited) );
1322 }
1323
1324 /*****************************************************************************/
1325
1326 OSErr
1327 FSCopyFileMgrAttributes(
1328         const FSRef *sourceRef,
1329         const FSRef *destinationRef,
1330         Boolean copyLockBit)
1331 {
1332         OSErr                   result;
1333         FSCatalogInfo   catalogInfo;
1334         
1335         /* get the source information */
1336         result = FSGetCatalogInfo(sourceRef, kFSCatInfoSettableInfo, &catalogInfo, NULL, NULL, NULL);
1337         require_noerr(result, FSGetCatalogInfo);
1338         
1339         /* don't copy the hasBeenInited bit; clear it */
1340         ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~kHasBeenInited;
1341         
1342         /* should the locked bit be copied? */
1343         if ( !copyLockBit )
1344         {
1345                 /* no, make sure the locked bit is clear */
1346                 catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
1347         }
1348                 
1349         /* set the destination information */
1350         result = FSSetCatalogInfo(destinationRef, kFSCatInfoSettableInfo, &catalogInfo);
1351         require_noerr(result, FSSetCatalogInfo);
1352         
1353 FSSetCatalogInfo:
1354 FSGetCatalogInfo:
1355
1356         return ( result );
1357 }
1358
1359 /*****************************************************************************/
1360
1361 OSErr
1362 FSMoveRenameObjectUnicode(
1363         const FSRef *ref,
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 */
1369 {
1370         OSErr                   result;
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 */
1378         
1379         /* check parameters */
1380         require_action(NULL != newRef, BadParameter, result = paramErr);
1381         
1382         /* newRef = input to start with */
1383         BlockMoveData(ref, newRef, sizeof(FSRef));
1384         
1385         /* get destDirectory's vRefNum */
1386         result = FSGetCatalogInfo(destDirectory, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL);
1387         require_noerr(result, DestinationBad);
1388         
1389         /* save vRefNum */
1390         vRefNum = catalogInfo.volume;
1391         
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);
1395         
1396         /* save TextEncoding */
1397         originalTextEncodingHint = catalogInfo.textEncodingHint;
1398         
1399         /* make sure ref and destDirectory are on same volume */
1400         require_action(vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
1401         
1402         /* Skip a few steps if we're not renaming */
1403         if ( NULL != name )
1404         {
1405                 /* generate a name that is unique in both directories */
1406                 theSeed = 0x4a696d4c;   /* a fine unlikely filename */
1407                 
1408                 result = GenerateUniqueHFSUniStr(&theSeed, &originalDirectory, destDirectory, &uniqueName);
1409                 require_noerr(result, GenerateUniqueHFSUniStrFailed);
1410                 
1411                 /* Rename the object to uniqueName */
1412                 result = FSRenameUnicode(ref, uniqueName.length, uniqueName.unicode, kTextEncodingUnknown, newRef);
1413                 require_noerr(result, FSRenameUnicodeBeforeMoveFailed);
1414                 
1415                 /* Move object to its new home */
1416                 result = FSMoveObject(newRef, destDirectory, newRef);
1417                 require_noerr(result, FSMoveObjectAfterRenameFailed);
1418                 
1419                 /* Rename the object to new name */
1420                 result = FSRenameUnicode(ref, nameLength, name, textEncodingHint, newRef);
1421                 require_noerr(result, FSRenameUnicodeAfterMoveFailed);
1422         }
1423         else
1424         {
1425                 /* Move object to its new home */
1426                 result = FSMoveObject(newRef, destDirectory, newRef);
1427                 require_noerr(result, FSMoveObjectNoRenameFailed);
1428         }
1429         
1430         return ( result );
1431         
1432         /*************/
1433
1434 /*
1435  * failure handling code when renaming
1436  */
1437
1438 FSRenameUnicodeAfterMoveFailed:
1439
1440         /* Error handling: move object back to original location - ignore errors */
1441         verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef));
1442         
1443 FSMoveObjectAfterRenameFailed:
1444
1445         /* Error handling: rename object back to original name - ignore errors */
1446         verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef));
1447         
1448 FSRenameUnicodeBeforeMoveFailed:
1449 GenerateUniqueHFSUniStrFailed:
1450
1451 /*
1452  * failure handling code for renaming or not
1453  */
1454 FSMoveObjectNoRenameFailed:
1455 NotSameVolume:
1456 SourceBad:
1457 DestinationBad:
1458 BadParameter:
1459
1460         return ( result );
1461 }
1462
1463 /*****************************************************************************/
1464
1465 /*
1466         The FSDeleteContainerLevel function deletes the contents of a container
1467         directory. All files and subdirectories in the specified container are
1468         deleted. If a locked file or directory is encountered, it is unlocked
1469         and then deleted. If any unexpected errors are encountered,
1470         FSDeleteContainerLevel quits and returns to the caller.
1471         
1472         container                       --> FSRef to a directory.
1473         theGlobals                      --> A pointer to a FSDeleteContainerGlobals struct
1474                                                         which contains the variables that do not need to
1475                                                         be allocated each time FSDeleteContainerLevel
1476                                                         recurses. That lets FSDeleteContainerLevel use
1477                                                         less stack space per recursion level.
1478 */
1479
1480 static
1481 void
1482 FSDeleteContainerLevel(
1483         const FSRef *container,
1484         FSDeleteContainerGlobals *theGlobals)
1485 {
1486         /* level locals */
1487         FSIterator                                      iterator;
1488         FSRef                                           itemToDelete;
1489         UInt16                                          nodeFlags;
1490         
1491         /* Open FSIterator for flat access and give delete optimization hint */
1492         theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator);
1493         require_noerr(theGlobals->result, FSOpenIterator);
1494         
1495         /* delete the contents of the directory */
1496         do
1497         {
1498                 /* get 1 item to delete */
1499                 theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
1500                                                                 NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo,
1501                                                                 &itemToDelete, NULL, NULL);
1502                 if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) )
1503                 {
1504                         /* save node flags in local in case we have to recurse */
1505                         nodeFlags = theGlobals->catalogInfo.nodeFlags;
1506                         
1507                         /* is it a file or directory? */
1508                         if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) )
1509                         {
1510                                 /* it's a directory -- delete its contents before attempting to delete it */
1511                                 FSDeleteContainerLevel(&itemToDelete, theGlobals);
1512                         }
1513                         /* are we still OK to delete? */
1514                         if ( noErr == theGlobals->result )
1515                         {
1516                                 /* is item locked? */
1517                                 if ( 0 != (nodeFlags & kFSNodeLockedMask) )
1518                                 {
1519                                         /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
1520                                         theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask;
1521                                         (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo);
1522                                 }
1523                                 /* delete the item */
1524                                 theGlobals->result = FSDeleteObject(&itemToDelete);
1525                         }
1526                 }
1527         } while ( noErr == theGlobals->result );
1528         
1529         /* we found the end of the items normally, so return noErr */
1530         if ( errFSNoMoreItems == theGlobals->result )
1531         {
1532                 theGlobals->result = noErr;
1533         }
1534         
1535         /* close the FSIterator (closing an open iterator should never fail) */
1536         verify_noerr(FSCloseIterator(iterator));
1537
1538 FSOpenIterator:
1539
1540         return;
1541 }
1542
1543 /*****************************************************************************/
1544
1545 OSErr
1546 FSDeleteContainerContents(
1547         const FSRef *container)
1548 {
1549         FSDeleteContainerGlobals        theGlobals;
1550         
1551         /* delete container's contents */
1552         FSDeleteContainerLevel(container, &theGlobals);
1553         
1554         return ( theGlobals.result );
1555 }
1556
1557 /*****************************************************************************/
1558
1559 OSErr
1560 FSDeleteContainer(
1561         const FSRef *container)
1562 {
1563         OSErr                   result;
1564         FSCatalogInfo   catalogInfo;
1565         
1566         /* get nodeFlags for container */
1567         result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL);
1568         require_noerr(result, FSGetCatalogInfo);
1569         
1570         /* make sure container is a directory */
1571         require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr);
1572         
1573         /* delete container's contents */
1574         result = FSDeleteContainerContents(container);
1575         require_noerr(result, FSDeleteContainerContents);
1576         
1577         /* is container locked? */
1578         if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
1579         {
1580                 /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
1581                 catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
1582                 (void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo);
1583         }
1584         
1585         /* delete the container */
1586         result = FSDeleteObject(container);
1587         
1588 FSDeleteContainerContents:
1589 ContainerNotDirectory:
1590 FSGetCatalogInfo:
1591
1592         return ( result );
1593 }
1594
1595 /*****************************************************************************/
1596
1597 /*
1598         The FSIterateContainerLevel function iterates the contents of a container
1599         directory and calls a IterateContainerFilterProc function once for each
1600         file and directory found.
1601         
1602         theGlobals                      --> A pointer to a FSIterateContainerGlobals struct
1603                                                         which contains the variables needed globally by
1604                                                         all recusion levels of FSIterateContainerLevel.
1605                                                         That makes FSIterateContainer thread safe since
1606                                                         each call to it uses its own global world.
1607                                                         It also contains the variables that do not need
1608                                                         to be allocated each time FSIterateContainerLevel
1609                                                         recurses. That lets FSIterateContainerLevel use
1610                                                         less stack space per recursion level.
1611 */
1612
1613 static
1614 void
1615 FSIterateContainerLevel(
1616         FSIterateContainerGlobals *theGlobals)
1617 {       
1618         FSIterator      iterator;
1619         
1620         /* If maxLevels is zero, we aren't checking levels */
1621         /* If currentLevel < maxLevels, look at this level */
1622         if ( (theGlobals->maxLevels == 0) ||
1623                  (theGlobals->currentLevel < theGlobals->maxLevels) )
1624         {
1625                 /* Open FSIterator for flat access to theGlobals->ref */
1626                 theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator);
1627                 require_noerr(theGlobals->result, FSOpenIterator);
1628                 
1629                 ++theGlobals->currentLevel; /* Go to next level */
1630                 
1631                 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1632                 do
1633                 {
1634                         theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
1635                                 &theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo,
1636                                 &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr);
1637                         if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) &&
1638                                 (0 != theGlobals->actualObjects) )
1639                         {
1640                                 /* Call the IterateFilterProc */
1641                                 theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter,
1642                                         theGlobals->containerChanged, theGlobals->currentLevel,
1643                                         &theGlobals->catalogInfo, &theGlobals->ref,
1644                                         theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr);
1645                                 /* Is it a directory? */
1646                                 if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) )
1647                                 {
1648                                         /* Keep going? */
1649                                         if ( !theGlobals->quitFlag )
1650                                         {
1651                                                 /* Dive again if the IterateFilterProc didn't say "quit" */
1652                                                 FSIterateContainerLevel(theGlobals);
1653                                         }
1654                                 }
1655                         }
1656                         /* time to fall back a level? */
1657                 } while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) );
1658                 
1659                 /* errFSNoMoreItems is OK - it only means we hit the end of this level */
1660                 /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
1661                 if ( (errFSNoMoreItems == theGlobals->result) ||
1662                          (afpAccessDenied == theGlobals->result) )
1663                 {
1664                         theGlobals->result = noErr;
1665                 }
1666                 
1667                 --theGlobals->currentLevel; /* Return to previous level as we leave */
1668                 
1669                 /* Close the FSIterator (closing an open iterator should never fail) */
1670                 verify_noerr(FSCloseIterator(iterator));
1671         }
1672         
1673 FSOpenIterator:
1674
1675         return;
1676 }
1677
1678 /*****************************************************************************/
1679
1680 OSErr
1681 FSIterateContainer(
1682         const FSRef *container,
1683         ItemCount maxLevels,
1684         FSCatalogInfoBitmap whichInfo,
1685         Boolean wantFSSpec,
1686         Boolean wantName,
1687         IterateContainerFilterProcPtr iterateFilter,
1688         void *yourDataPtr)
1689 {
1690         OSErr                                           result;
1691         FSIterateContainerGlobals       theGlobals;
1692         
1693         /* make sure there is an iterateFilter */
1694         require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr);
1695         
1696         /*
1697          * set up the globals we need to access from the recursive routine
1698          */
1699         theGlobals.iterateFilter = iterateFilter;
1700         /* we need the node flags no matter what was requested so we can detect files vs. directories */
1701         theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags;
1702         /* start with input container -- the first OpenIterator will ensure it is a directory */
1703         theGlobals.ref = *container;
1704         if ( wantFSSpec )
1705         {
1706                 theGlobals.specPtr = &theGlobals.spec;
1707         }
1708         else
1709         {
1710                 theGlobals.specPtr = NULL;
1711         }
1712         if ( wantName )
1713         {
1714                 theGlobals.namePtr = &theGlobals.name;
1715         }
1716         else
1717         {
1718                 theGlobals.namePtr = NULL;
1719         }
1720         theGlobals.yourDataPtr = yourDataPtr;
1721         theGlobals.maxLevels = maxLevels;
1722         theGlobals.currentLevel = 0;
1723         theGlobals.quitFlag = false;
1724         theGlobals.containerChanged = false;
1725         theGlobals.result = noErr;
1726         theGlobals.actualObjects = 0;
1727         
1728         /* here we go into recursion land... */
1729         FSIterateContainerLevel(&theGlobals);
1730         result = theGlobals.result;
1731         require_noerr(result, FSIterateContainerLevel);
1732         
1733 FSIterateContainerLevel:
1734 NoIterateFilter:
1735
1736         return ( result );
1737 }
1738
1739 /*****************************************************************************/
1740
1741 OSErr
1742 FSGetDirectoryItems(
1743         const FSRef *container,
1744         FSRef ***refsHandle,    /* pointer to handle of FSRefs */
1745         ItemCount *numRefs,
1746         Boolean *containerChanged)
1747 {
1748         /* Grab items 10 at a time. */
1749         enum { kMaxItemsPerBulkCall = 10 };
1750         
1751         OSErr           result;
1752         OSErr           memResult;
1753         FSIterator      iterator;
1754         FSRef           refs[kMaxItemsPerBulkCall];
1755         ItemCount       actualObjects;
1756         Boolean         changed;
1757         
1758         /* check parameters */
1759         require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged),
1760                 BadParameter, result = paramErr);
1761         
1762         *numRefs = 0;
1763         *containerChanged = false;
1764         *refsHandle = (FSRef **)NewHandle(0);
1765         require_action(NULL != *refsHandle, NewHandle, result = memFullErr);
1766         
1767         /* open an FSIterator */
1768         result = FSOpenIterator(container, kFSIterateFlat, &iterator);
1769         require_noerr(result, FSOpenIterator);
1770         
1771         /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1772         do
1773         {
1774                 result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects,
1775                                         &changed, kFSCatInfoNone,  NULL,  refs, NULL, NULL);
1776                 
1777                 /* if the container changed, set containerChanged for output, but keep going */
1778                 if ( changed )
1779                 {
1780                         *containerChanged = changed;
1781                 }
1782                 
1783                 /* any result other than noErr and errFSNoMoreItems is serious */
1784                 require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk);
1785                 
1786                 /* add objects to output array and count */
1787                 if ( 0 != actualObjects )
1788                 {
1789                         /* concatenate the FSRefs to the end of the      handle */
1790                         PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef));
1791                         memResult = MemError();
1792                         require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
1793                         
1794                         *numRefs += actualObjects;
1795                 }
1796         } while ( noErr == result );
1797         
1798         verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */
1799         
1800         return ( noErr );
1801         
1802         /**********************/
1803         
1804 MemoryAllocationFailed:
1805 FSGetCatalogInfoBulk:
1806
1807         /* close the iterator */
1808         verify_noerr(FSCloseIterator(iterator));
1809
1810 FSOpenIterator:
1811         /* dispose of handle if already allocated and clear the outputs */
1812         if ( NULL != *refsHandle )
1813         {
1814                 DisposeHandle((Handle)*refsHandle);
1815                 *refsHandle = NULL;
1816         }
1817         *numRefs = 0;
1818         
1819 NewHandle:
1820 BadParameter:
1821
1822         return ( result );
1823 }
1824
1825 /*****************************************************************************/
1826
1827 /*
1828         The GenerateUniqueName function generates a HFSUniStr255 name that is
1829         unique in both dir1 and dir2.
1830         
1831         startSeed                       -->     A pointer to a long which is used to generate the
1832                                                         unique name.
1833                                                 <--     It is modified on output to a value which should
1834                                                         be used to generate the next unique name.
1835         dir1                            -->     The first directory.
1836         dir2                            -->     The second directory.
1837         uniqueName                      <--     A pointer to a HFSUniStr255 where the unique name
1838                                                         is to be returned.
1839 */
1840
1841 static
1842 OSErr
1843 GenerateUniqueHFSUniStr(
1844         long *startSeed,
1845         const FSRef *dir1,
1846         const FSRef *dir2,
1847         HFSUniStr255 *uniqueName)
1848 {
1849         OSErr                   result;
1850         long                    i;
1851         FSRefParam              pb;
1852         FSRef                   newRef;
1853         unsigned char   hexStr[17] = "0123456789ABCDEF";
1854         
1855         /* set up the parameter block */
1856         pb.name = uniqueName->unicode;
1857         pb.nameLength = 8;      /* always 8 characters */
1858         pb.textEncodingHint = kTextEncodingUnknown;
1859         pb.newRef = &newRef;
1860
1861         /* loop until we get fnfErr with a filename in both directories */
1862         result = noErr;
1863         while ( fnfErr != result )
1864         {
1865                 /* convert startSeed to 8 character Unicode string */
1866                 uniqueName->length = 8;
1867                 for ( i = 0; i < 8; ++i )
1868                 {
1869                         uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)];
1870                 }
1871                 
1872                 /* try in dir1 */
1873                 pb.ref = dir1;
1874                 result = PBMakeFSRefUnicodeSync(&pb);
1875                 if ( fnfErr == result )
1876                 {
1877                         /* try in dir2 */
1878                         pb.ref = dir2;
1879                         result = PBMakeFSRefUnicodeSync(&pb);
1880                         if ( fnfErr != result )
1881                         {
1882                                 /* exit if anything other than noErr or fnfErr */
1883                                 require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed);
1884                         }
1885                 }
1886                 else
1887                 {
1888                         /* exit if anything other than noErr or fnfErr */
1889                         require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed);
1890                 }
1891                 
1892                 /* increment seed for next pass through loop, */
1893                 /* or for next call to GenerateUniqueHFSUniStr */
1894                 ++(*startSeed);
1895         }
1896         
1897         /* we have a unique file name which doesn't exist in dir1 or dir2 */
1898         result = noErr;
1899         
1900 Dir2PBMakeFSRefUnicodeSyncFailed:
1901 Dir1PBMakeFSRefUnicodeSyncFailed:
1902
1903         return ( result );
1904 }
1905
1906 /*****************************************************************************/
1907
1908 OSErr
1909 FSExchangeObjectsCompat(
1910         const FSRef *sourceRef,
1911         const FSRef *destRef,
1912         FSRef *newSourceRef,
1913         FSRef *newDestRef)
1914 {
1915         enum
1916         {
1917                 /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
1918                 kGetCatInformationMask = (kFSCatInfoSettableInfo |
1919                                                                   kFSCatInfoVolume |
1920                                                                   kFSCatInfoParentDirID) &
1921                                                                  ~(kFSCatInfoContentMod | kFSCatInfoAttrMod),
1922                 /* set everything possible except for mod dates */
1923                 kSetCatinformationMask = kFSCatInfoSettableInfo &
1924                                                                  ~(kFSCatInfoContentMod | kFSCatInfoAttrMod)
1925         };
1926         
1927         OSErr                                   result;
1928         GetVolParmsInfoBuffer   volParmsInfo;
1929         UInt32                                  infoSize;
1930         FSCatalogInfo                   sourceCatalogInfo;      /* source file's catalog information */
1931         FSCatalogInfo                   destCatalogInfo;        /* destination file's catalog information */
1932         HFSUniStr255                    sourceName;                     /* source file's Unicode name */
1933         HFSUniStr255                    destName;                       /* destination file's Unicode name */
1934         FSRef                                   sourceCurrentRef;       /* FSRef to current location of source file throughout this function */
1935         FSRef                                   destCurrentRef;         /* FSRef to current location of destination file throughout this function */
1936         FSRef                                   sourceParentRef;        /* FSRef to parent directory of source file */
1937         FSRef                                   destParentRef;          /* FSRef to parent directory of destination file */
1938         HFSUniStr255                    sourceUniqueName;       /* unique name given to source file while exchanging it with destination */
1939         HFSUniStr255                    destUniqueName;         /* unique name given to destination file while exchanging it with source */
1940         long                                    theSeed;                        /* the seed for generating unique names */
1941         Boolean                                 sameParentDirs;         /* true if source and destinatin parent directory is the same */
1942         
1943         /* check parameters */
1944         require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr);
1945         
1946         /* output refs and current refs = input refs to start with */
1947         BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef));
1948         BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef));
1949         
1950         BlockMoveData(destRef, newDestRef, sizeof(FSRef));
1951         BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef));
1952
1953         /* get source volume's vRefNum */
1954         result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL);
1955         require_noerr(result, DetermineSourceVRefNumFailed);
1956         
1957         /* see if that volume supports FSExchangeObjects */
1958         result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer),
1959                 &volParmsInfo, &infoSize);
1960         if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) )
1961         {
1962                 /* yes - use FSExchangeObjects */
1963                 result = FSExchangeObjects(sourceRef, destRef);
1964         }
1965         else
1966         {
1967                 /* no - emulate FSExchangeObjects */
1968                 
1969                 /* Note: The compatibility case won't work for files with *Btree control blocks. */
1970                 /* Right now the only *Btree files are created by the system. */
1971                 
1972                 /* get all catalog information and Unicode names for each file */
1973                 result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef);
1974                 require_noerr(result, SourceFSGetCatalogInfoFailed);
1975                 
1976                 result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef);
1977                 require_noerr(result, DestFSGetCatalogInfoFailed);
1978                 
1979                 /* make sure source and destination are on same volume */
1980                 require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr);
1981                 
1982                 /* make sure both files are *really* files */
1983                 require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) &&
1984                                            (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr);
1985                 
1986                 /* generate 2 names that are unique in both directories */
1987                 theSeed = 0x4a696d4c;   /* a fine unlikely filename */
1988                 
1989                 result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName);
1990                 require_noerr(result, GenerateUniqueHFSUniStr1Failed);
1991                 
1992                 result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName);
1993                 require_noerr(result, GenerateUniqueHFSUniStr2Failed);
1994
1995                 /* rename sourceCurrentRef to sourceUniqueName */
1996                 result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef);
1997                 require_noerr(result, FSRenameUnicode1Failed);
1998                 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
1999                 
2000                 /* rename destCurrentRef to destUniqueName */
2001                 result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef);
2002                 require_noerr(result, FSRenameUnicode2Failed);
2003                 BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2004                 
2005                 /* are the source and destination parent directories the same? */
2006                 sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID );
2007                 if ( !sameParentDirs )
2008                 {
2009                         /* move source file to dest parent directory */
2010                         result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef);
2011                         require_noerr(result, FSMoveObject1Failed);
2012                         BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2013                         
2014                         /* move dest file to source parent directory */
2015                         result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef);
2016                         require_noerr(result, FSMoveObject2Failed);
2017                         BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2018                 }
2019                 
2020                 /* At this point, the files are in their new locations (if they were moved). */
2021                 /* The source file is named sourceUniqueName and is in the directory referred to */
2022                 /* by destParentRef. The destination file is named destUniqueName and is in the */
2023                 /* directory referred to by sourceParentRef. */
2024                                 
2025                 /* give source file the dest file's catalog information except for mod dates */
2026                 result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo);
2027                 require_noerr(result, FSSetCatalogInfo1Failed);
2028                 
2029                 /* give dest file the source file's catalog information except for mod dates */
2030                 result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo);
2031                 require_noerr(result, FSSetCatalogInfo2Failed);
2032                 
2033                 /* rename source file with dest file's name */
2034                 result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef);
2035                 require_noerr(result, FSRenameUnicode3Failed);
2036                 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2037                 
2038                 /* rename dest file with source file's name */
2039                 result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef);
2040                 require_noerr(result, FSRenameUnicode4Failed);
2041                 
2042                 /* we're done with no errors, so swap newSourceRef and newDestRef */
2043                 BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef));
2044                 BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef));
2045         }
2046         
2047         return ( result );
2048         
2049         /**********************/
2050
2051 /* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
2052 /* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
2053 /* state and location they ended up in so that both files can be found by the calling code. */
2054         
2055 FSRenameUnicode4Failed:
2056
2057         /* attempt to rename source file to sourceUniqueName */
2058         if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) )
2059         {
2060                 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2061         }
2062
2063 FSRenameUnicode3Failed:
2064
2065         /* attempt to restore dest file's catalog information */
2066         verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo));
2067
2068 FSSetCatalogInfo2Failed:
2069
2070         /* attempt to restore source file's catalog information */
2071         verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo));
2072
2073 FSSetCatalogInfo1Failed:
2074
2075         if ( !sameParentDirs )
2076         {
2077                 /* attempt to move dest file back to dest directory */
2078                 if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) )
2079                 {
2080                         BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2081                 }
2082         }
2083
2084 FSMoveObject2Failed:
2085
2086         if ( !sameParentDirs )
2087         {
2088                 /* attempt to move source file back to source directory */
2089                 if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) )
2090                 {
2091                         BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2092                 }
2093         }
2094
2095 FSMoveObject1Failed:
2096
2097         /* attempt to rename dest file to original name */
2098         verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef));
2099
2100 FSRenameUnicode2Failed:
2101
2102         /* attempt to rename source file to original name */
2103         verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef));
2104
2105 FSRenameUnicode1Failed:
2106 GenerateUniqueHFSUniStr2Failed:
2107 GenerateUniqueHFSUniStr1Failed:
2108 NotAFile:
2109 NotSameVolume:
2110 DestFSGetCatalogInfoFailed:
2111 SourceFSGetCatalogInfoFailed:
2112 DetermineSourceVRefNumFailed:   
2113 BadParameter:
2114
2115         return ( result );
2116 }
2117
2118 /*****************************************************************************/
2119
2120 #pragma mark ----- Shared Environment Routines -----
2121
2122 /*****************************************************************************/
2123
2124 OSErr
2125 FSLockRange(
2126         SInt16 refNum,
2127         SInt32 rangeLength,
2128         SInt32 rangeStart)
2129 {
2130         OSErr                   result;
2131         ParamBlockRec   pb;
2132
2133         pb.ioParam.ioRefNum = refNum;
2134         pb.ioParam.ioReqCount = rangeLength;
2135         pb.ioParam.ioPosMode = fsFromStart;
2136         pb.ioParam.ioPosOffset = rangeStart;
2137         result = PBLockRangeSync(&pb);
2138         require_noerr(result, PBLockRangeSync);
2139         
2140 PBLockRangeSync:
2141
2142         return ( result );
2143 }
2144
2145 /*****************************************************************************/
2146
2147 OSErr
2148 FSUnlockRange(
2149         SInt16 refNum,
2150         SInt32 rangeLength,
2151         SInt32 rangeStart)
2152 {
2153         OSErr                   result;
2154         ParamBlockRec   pb;
2155
2156         pb.ioParam.ioRefNum = refNum;
2157         pb.ioParam.ioReqCount = rangeLength;
2158         pb.ioParam.ioPosMode = fsFromStart;
2159         pb.ioParam.ioPosOffset = rangeStart;
2160         result = PBUnlockRangeSync(&pb);
2161         require_noerr(result, PBUnlockRangeSync);
2162         
2163 PBUnlockRangeSync:
2164
2165         return ( result );
2166 }
2167
2168 /*****************************************************************************/
2169
2170 OSErr
2171 FSGetDirAccess(
2172         const FSRef *ref,
2173         SInt32 *ownerID,                /* can be NULL */
2174         SInt32 *groupID,                /* can be NULL */
2175         SInt32 *accessRights)   /* can be NULL */
2176 {
2177         OSErr                   result;
2178         FSSpec                  spec;
2179         HParamBlockRec  pb;
2180         
2181         /* get FSSpec from FSRef */
2182         result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2183         require_noerr(result, FSGetCatalogInfo);
2184         
2185         /* get directory access info for FSSpec */
2186         pb.accessParam.ioNamePtr = (StringPtr)spec.name;
2187         pb.accessParam.ioVRefNum = spec.vRefNum;
2188         pb.fileParam.ioDirID = spec.parID;
2189         result = PBHGetDirAccessSync(&pb);
2190         require_noerr(result, PBHGetDirAccessSync);
2191         
2192         /* return the IDs and access rights */
2193         if ( NULL != ownerID )
2194         {
2195                 *ownerID = pb.accessParam.ioACOwnerID;
2196         }
2197         if ( NULL != groupID )
2198         {
2199                 *groupID = pb.accessParam.ioACGroupID;
2200         }
2201         if ( NULL != accessRights )
2202         {
2203                 *accessRights = pb.accessParam.ioACAccess;
2204         }
2205         
2206 PBHGetDirAccessSync:
2207 FSGetCatalogInfo:
2208
2209         return ( result );
2210 }
2211
2212 /*****************************************************************************/
2213
2214 OSErr
2215 FSSetDirAccess(
2216         const FSRef *ref,
2217         SInt32 ownerID,
2218         SInt32 groupID,
2219         SInt32 accessRights)
2220 {
2221         OSErr                   result;
2222         FSSpec                  spec;
2223         HParamBlockRec  pb;
2224
2225         enum
2226         {
2227                 /* Just the bits that can be set */
2228                 kSetDirAccessSettableMask = (kioACAccessBlankAccessMask +
2229                         kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask +
2230                         kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask +
2231                         kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask)
2232         };
2233         
2234         /* get FSSpec from FSRef */
2235         result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2236         require_noerr(result, FSGetCatalogInfo);
2237         
2238         /* set directory access info for FSSpec */
2239         pb.accessParam.ioNamePtr = (StringPtr)spec.name;
2240         pb.accessParam.ioVRefNum = spec.vRefNum;
2241         pb.fileParam.ioDirID = spec.parID;
2242         pb.accessParam.ioACOwnerID = ownerID;
2243         pb.accessParam.ioACGroupID = groupID;
2244         pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask;
2245         result = PBHSetDirAccessSync(&pb);
2246         require_noerr(result, PBHSetDirAccessSync);
2247         
2248 PBHSetDirAccessSync:
2249 FSGetCatalogInfo:
2250
2251         return ( result );
2252 }
2253
2254 /*****************************************************************************/
2255
2256 OSErr
2257 FSGetVolMountInfoSize(
2258         FSVolumeRefNum volRefNum,
2259         SInt16 *size)
2260 {
2261         OSErr                   result;
2262         ParamBlockRec   pb;
2263
2264         /* check parameters */
2265         require_action(NULL != size, BadParameter, result = paramErr);
2266         
2267         pb.ioParam.ioNamePtr = NULL;
2268         pb.ioParam.ioVRefNum = volRefNum;
2269         pb.ioParam.ioBuffer = (Ptr)size;
2270         result = PBGetVolMountInfoSize(&pb);
2271         require_noerr(result, PBGetVolMountInfoSize);
2272         
2273 PBGetVolMountInfoSize:
2274 BadParameter:
2275
2276         return ( result );
2277 }
2278
2279 /*****************************************************************************/
2280
2281 OSErr
2282 FSGetVolMountInfo(
2283         FSVolumeRefNum volRefNum,
2284         void *volMountInfo)
2285 {
2286         OSErr                   result;
2287         ParamBlockRec   pb;
2288
2289         /* check parameters */
2290         require_action(NULL != volMountInfo, BadParameter, result = paramErr);
2291         
2292         pb.ioParam.ioNamePtr = NULL;
2293         pb.ioParam.ioVRefNum = volRefNum;
2294         pb.ioParam.ioBuffer = (Ptr)volMountInfo;
2295         result = PBGetVolMountInfo(&pb);
2296         require_noerr(result, PBGetVolMountInfo);
2297         
2298 PBGetVolMountInfo:
2299 BadParameter:
2300
2301         return ( result );
2302 }
2303
2304 /*****************************************************************************/
2305
2306 OSErr
2307 FSVolumeMount(
2308         const void *volMountInfo,
2309         FSVolumeRefNum *volRefNum)
2310 {
2311         OSErr                   result;
2312         ParamBlockRec   pb;
2313
2314         /* check parameters */
2315         require_action(NULL != volRefNum, BadParameter, result = paramErr);
2316         
2317         pb.ioParam.ioBuffer = (Ptr)volMountInfo;
2318         result = PBVolumeMount(&pb);
2319         require_noerr(result, PBVolumeMount);
2320         
2321         /* return the volume reference number */
2322         *volRefNum = pb.ioParam.ioVRefNum;
2323
2324 PBVolumeMount:
2325 BadParameter:
2326
2327         return ( result );
2328 }
2329
2330 /*****************************************************************************/
2331
2332 OSErr
2333 FSMapID(
2334         FSVolumeRefNum volRefNum,
2335         SInt32 ugID,
2336         SInt16 objType,
2337         Str31 name)
2338 {
2339         OSErr                   result;
2340         HParamBlockRec  pb;
2341
2342         /* check parameters */
2343         require_action(NULL != name, BadParameter, result = paramErr);
2344         
2345         pb.objParam.ioNamePtr = NULL;
2346         pb.objParam.ioVRefNum = volRefNum;
2347         pb.objParam.ioObjType = objType;
2348         pb.objParam.ioObjNamePtr = name;
2349         pb.objParam.ioObjID = ugID;
2350         result = PBHMapIDSync(&pb);
2351         require_noerr(result, PBHMapIDSync);
2352         
2353 PBHMapIDSync:
2354 BadParameter:
2355
2356         return ( result );
2357 }
2358
2359 /*****************************************************************************/
2360
2361 OSErr
2362 FSMapName(
2363         FSVolumeRefNum volRefNum,
2364         ConstStr255Param name,
2365         SInt16 objType,
2366         SInt32 *ugID)
2367 {
2368         OSErr                   result;
2369         HParamBlockRec  pb;
2370
2371         /* check parameters */
2372         require_action(NULL != ugID, BadParameter, result = paramErr);
2373         
2374         pb.objParam.ioNamePtr = NULL;
2375         pb.objParam.ioVRefNum = volRefNum;
2376         pb.objParam.ioObjType = objType;
2377         pb.objParam.ioObjNamePtr = (StringPtr)name;
2378         result = PBHMapNameSync(&pb);
2379         require_noerr(result, PBHMapNameSync);
2380         
2381         /* return the user or group ID */
2382         *ugID = pb.objParam.ioObjID;
2383         
2384 PBHMapNameSync:
2385 BadParameter:
2386
2387         return ( result );
2388 }
2389
2390 /*****************************************************************************/
2391
2392 OSErr
2393 FSCopyFile(
2394         const FSRef *srcFileRef,
2395         const FSRef *dstDirectoryRef,
2396         UniCharCount nameLength,
2397         const UniChar *copyName,        /* can be NULL (no rename during copy) */
2398         TextEncoding textEncodingHint,
2399         FSRef *newRef)                          /* can be NULL */
2400 {
2401         OSErr                                   result;
2402         FSSpec                                  srcFileSpec;
2403         FSCatalogInfo                   catalogInfo;
2404         HParamBlockRec                  pb;
2405         Str31                                   hfsName;
2406         GetVolParmsInfoBuffer   volParmsInfo;
2407         UInt32                                  infoSize;
2408         
2409         /* get source FSSpec from source FSRef */
2410         result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
2411         require_noerr(result, FSGetCatalogInfo_srcFileRef);
2412         
2413         /* Make sure the volume supports CopyFile */
2414         result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
2415                 &volParmsInfo, &infoSize);
2416         require_action((noErr == result) && VolHasCopyFile(&volParmsInfo),
2417                 NoCopyFileSupport, result = paramErr);
2418
2419         /* get destination volume reference number and destination directory ID from destination FSRef */
2420         result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
2421                 &catalogInfo, NULL, NULL, NULL);
2422         require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
2423         
2424         /* tell the server to copy the object */
2425         pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
2426         pb.copyParam.ioDirID = srcFileSpec.parID;
2427         pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
2428         pb.copyParam.ioDstVRefNum = catalogInfo.volume;
2429         pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
2430         pb.copyParam.ioNewName = NULL;
2431         if ( NULL != copyName )
2432         {
2433                 result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName);
2434                 require_noerr(result, UnicodeNameGetHFSName);
2435                 
2436                 pb.copyParam.ioCopyName = hfsName;
2437         }
2438         else
2439         {
2440                 pb.copyParam.ioCopyName = NULL;
2441         }
2442         result = PBHCopyFileSync(&pb);
2443         require_noerr(result, PBHCopyFileSync);
2444         
2445         if ( NULL != newRef )
2446         {
2447                 verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID,
2448                         pb.copyParam.ioCopyName, newRef));
2449         }
2450                 
2451 PBHCopyFileSync:
2452 UnicodeNameGetHFSName:
2453 FSGetCatalogInfo_dstDirectoryRef:
2454 NoCopyFileSupport:
2455 FSGetCatalogInfo_srcFileRef:
2456
2457         return ( result );
2458 }
2459
2460 /*****************************************************************************/
2461
2462 OSErr
2463 FSMoveRename(
2464         const FSRef *srcFileRef,
2465         const FSRef *dstDirectoryRef,
2466         UniCharCount nameLength,
2467         const UniChar *moveName,        /* can be NULL (no rename during move) */
2468         TextEncoding textEncodingHint,
2469         FSRef *newRef)                          /* can be NULL */
2470 {
2471         OSErr                                   result;
2472         FSSpec                                  srcFileSpec;
2473         FSCatalogInfo                   catalogInfo;
2474         HParamBlockRec                  pb;
2475         Str31                                   hfsName;
2476         GetVolParmsInfoBuffer   volParmsInfo;
2477         UInt32                                  infoSize;
2478         
2479         /* get source FSSpec from source FSRef */
2480         result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
2481         require_noerr(result, FSGetCatalogInfo_srcFileRef);
2482         
2483         /* Make sure the volume supports MoveRename */
2484         result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
2485                 &volParmsInfo, &infoSize);
2486         require_action((noErr == result) && VolHasMoveRename(&volParmsInfo),
2487                 NoMoveRenameSupport, result = paramErr);
2488
2489         /* get destination volume reference number and destination directory ID from destination FSRef */
2490         result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
2491                 &catalogInfo, NULL, NULL, NULL);
2492         require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
2493         
2494         /* make sure the source and destination are on the same volume */
2495         require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
2496         
2497         /* tell the server to move and rename the object */
2498         pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
2499         pb.copyParam.ioDirID = srcFileSpec.parID;
2500         pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
2501         pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
2502         pb.copyParam.ioNewName = NULL;
2503         if ( NULL != moveName )
2504         {
2505                 result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName);
2506                 require_noerr(result, UnicodeNameGetHFSName);
2507                 
2508                 pb.copyParam.ioCopyName = hfsName;
2509         }
2510         else
2511         {
2512                 pb.copyParam.ioCopyName = NULL;
2513         }
2514         result = PBHMoveRenameSync(&pb);
2515         require_noerr(result, PBHMoveRenameSync);
2516         
2517         if ( NULL != newRef )
2518         {
2519                 verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID,
2520                         pb.copyParam.ioCopyName, newRef));
2521         }
2522         
2523 PBHMoveRenameSync:
2524 UnicodeNameGetHFSName:
2525 NotSameVolume:
2526 FSGetCatalogInfo_dstDirectoryRef:
2527 NoMoveRenameSupport:
2528 FSGetCatalogInfo_srcFileRef:
2529
2530         return ( result );
2531 }
2532
2533 /*****************************************************************************/
2534
2535 #pragma mark ----- File ID Routines -----
2536
2537 /*****************************************************************************/
2538
2539 OSErr
2540 FSResolveFileIDRef(
2541         FSVolumeRefNum volRefNum,
2542         SInt32 fileID,
2543         FSRef *ref)
2544 {
2545         OSErr           result;
2546         FIDParam        pb;
2547         Str255          tempStr;
2548         
2549         /* check parameters */
2550         require_action(NULL != ref, BadParameter, result = paramErr);
2551         
2552         /* resolve the file ID reference */
2553         tempStr[0] = 0;
2554         pb.ioNamePtr = tempStr;
2555         pb.ioVRefNum = volRefNum;
2556         pb.ioFileID = fileID;
2557         result = PBResolveFileIDRefSync((HParmBlkPtr)&pb);
2558         require_noerr(result, PBResolveFileIDRefSync);
2559         
2560         /* and then make an FSRef to the file */
2561         result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref);
2562         require_noerr(result, FSMakeFSRef);
2563         
2564 FSMakeFSRef:
2565 PBResolveFileIDRefSync:
2566 BadParameter:
2567
2568         return ( result );
2569 }
2570
2571 /*****************************************************************************/
2572
2573 OSErr
2574 FSCreateFileIDRef(
2575         const FSRef *ref,
2576         SInt32 *fileID)
2577 {
2578         OSErr           result;
2579         FSSpec          spec;
2580         FIDParam        pb;
2581         
2582         /* check parameters */
2583         require_action(NULL != fileID, BadParameter, result = paramErr);
2584         
2585         /* Get an FSSpec from the FSRef */
2586         result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2587         require_noerr(result, FSGetCatalogInfo);
2588         
2589         /* Create (or get) the file ID reference using the FSSpec */
2590         pb.ioNamePtr = (StringPtr)spec.name;
2591         pb.ioVRefNum = spec.vRefNum;
2592         pb.ioSrcDirID = spec.parID;
2593         result = PBCreateFileIDRefSync((HParmBlkPtr)&pb);
2594         require((noErr == result) || (fidExists == result) || (afpIDExists == result),
2595                 PBCreateFileIDRefSync);
2596         
2597         /* return the file ID reference */
2598         *fileID = pb.ioFileID;
2599         
2600 PBCreateFileIDRefSync:
2601 FSGetCatalogInfo:
2602 BadParameter:
2603
2604         return ( result );
2605 }
2606
2607 /*****************************************************************************/
2608
2609 #pragma mark ----- Utility Routines -----
2610
2611 /*****************************************************************************/
2612
2613 Ptr
2614 GetTempBuffer(
2615         ByteCount buffReqSize,
2616         ByteCount *buffActSize)
2617 {
2618         enum
2619         {
2620                 kSlopMemory = 0x00008000        /* 32K - Amount of free memory to leave when allocating buffers */
2621         };
2622         
2623         Ptr tempPtr;
2624         
2625         /* check parameters */
2626         require_action(NULL != buffActSize, BadParameter, tempPtr = NULL);
2627         
2628         /* Make request a multiple of 4K bytes */
2629         buffReqSize = buffReqSize & 0xfffff000;
2630         
2631         if ( buffReqSize < 0x00001000 )
2632         {
2633                 /* Request was smaller than 4K bytes - make it 4K */
2634                 buffReqSize = 0x00001000;
2635         }
2636         
2637         /* Attempt to allocate the memory */
2638         tempPtr = NewPtr(buffReqSize);
2639         
2640         /* If request failed, go to backup plan */
2641         if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) )
2642         {
2643                 /*
2644                 **      Try to get largest 4K byte block available
2645                 **      leaving some slop for the toolbox if possible
2646                 */
2647                 long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000;
2648                 
2649                 buffReqSize = MaxBlock() & 0xfffff000;
2650                 
2651                 if ( buffReqSize > freeMemory )
2652                 {
2653                         buffReqSize = freeMemory;
2654                 }
2655                 
2656                 if ( buffReqSize == 0 )
2657                 {
2658                         buffReqSize = 0x00001000;
2659                 }
2660                 
2661                 tempPtr = NewPtr(buffReqSize);
2662         }
2663         
2664         /* Return bytes allocated */
2665         if ( tempPtr != NULL )
2666         {
2667                 *buffActSize = buffReqSize;
2668         }
2669         else
2670         {
2671                 *buffActSize = 0;
2672         }
2673         
2674 BadParameter:
2675
2676         return ( tempPtr );
2677 }
2678
2679 /*****************************************************************************/
2680
2681 OSErr
2682 FileRefNumGetFSRef(
2683         short refNum,
2684         FSRef *ref)
2685 {
2686         return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) );
2687 }
2688
2689 /*****************************************************************************/
2690
2691 OSErr
2692 FSSetDefault(
2693         const FSRef *newDefault,
2694         FSRef *oldDefault)
2695 {
2696         OSErr                   result;
2697         FSVolumeRefNum  vRefNum;
2698         long                    dirID;
2699         FSCatalogInfo   catalogInfo;
2700         
2701         /* check parameters */
2702         require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr);
2703         
2704         /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
2705         result = FSGetCatalogInfo(newDefault,
2706                 kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
2707                 &catalogInfo, NULL, NULL, NULL);
2708         require_noerr(result, FSGetCatalogInfo);
2709         
2710         /* Make sure newDefault is a directory */
2711         require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory,
2712                 result = dirNFErr);
2713         
2714         /* Get the current working directory. */
2715         result = HGetVol(NULL, &vRefNum, &dirID);
2716         require_noerr(result, HGetVol);
2717         
2718         /* Return the oldDefault FSRef */
2719         result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault);
2720         require_noerr(result, FSMakeFSRef);
2721         
2722         /* Set the new current working directory */
2723         result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
2724         require_noerr(result, HSetVol);
2725
2726 HSetVol:
2727 FSMakeFSRef:
2728 HGetVol:
2729 NewDefaultNotDirectory:
2730 FSGetCatalogInfo:
2731 BadParameter:
2732
2733         return ( result );
2734 }
2735
2736 /*****************************************************************************/
2737
2738 OSErr
2739 FSRestoreDefault(
2740         const FSRef *oldDefault)
2741 {
2742         OSErr                   result;
2743         FSCatalogInfo   catalogInfo;
2744         
2745         /* check parameters */
2746         require_action(NULL != oldDefault, BadParameter, result = paramErr);
2747         
2748         /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
2749         result = FSGetCatalogInfo(oldDefault,
2750                 kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
2751                 &catalogInfo, NULL, NULL, NULL);
2752         require_noerr(result, FSGetCatalogInfo);
2753         
2754         /* Make sure oldDefault is a directory */
2755         require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory,
2756                 result = dirNFErr);
2757         
2758         /* Set the current working directory to oldDefault */
2759         result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
2760         require_noerr(result, HSetVol);
2761
2762 HSetVol:
2763 OldDefaultNotDirectory:
2764 FSGetCatalogInfo:
2765 BadParameter:
2766
2767         return ( result );
2768 }
2769
2770 /*****************************************************************************/