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