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