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