VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/xpcom/MoreFiles/MoreFilesX.c@ 589

Last change on this file since 589 was 589, checked in by vboxsync, 18 years ago

Make it build and run on Mac OS X.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette