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