VirtualBox

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

Last change on this file since 549 was 1, checked in by vboxsync, 55 years ago

import

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 76.4 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#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
91struct 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};
109typedef struct FSIterateContainerGlobals FSIterateContainerGlobals;
110
111struct FSDeleteContainerGlobals
112{
113 OSErr result; /* result */
114 ItemCount actualObjects; /* number of objects returned */
115 FSCatalogInfo catalogInfo; /* FSCatalogInfo */
116};
117typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals;
118
119/*****************************************************************************/
120
121#pragma mark ----- Local prototypes -----
122
123static
124void
125FSDeleteContainerLevel(
126 const FSRef *container,
127 FSDeleteContainerGlobals *theGlobals);
128
129static
130void
131FSIterateContainerLevel(
132 FSIterateContainerGlobals *theGlobals);
133
134static
135OSErr
136GenerateUniqueHFSUniStr(
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
148OSErr
149FSCopyFork(
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
204SourceResultNotEofErr:
205DestinationFSWriteForkFailed:
206DestinationFSSetForkPositionFailed:
207SourceFSSetForkPositionFailed:
208DestinationFSSetForkSizeFailed:
209SourceFSGetForkSizeFailed:
210BadParameter:
211
212 return ( result );
213}
214
215/*****************************************************************************/
216
217#pragma mark ----- Volume Access Routines -----
218
219/*****************************************************************************/
220
221OSErr
222FSGetVolParms(
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
245PBHGetVolParmsSync:
246BadParameter:
247
248 return ( result );
249}
250
251/*****************************************************************************/
252
253OSErr
254FSGetVRefNum(
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
271FSGetCatalogInfo:
272BadParameter:
273
274 return ( result );
275}
276
277/*****************************************************************************/
278
279OSErr
280FSGetVInfo(
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
304FSGetVolumeInfo:
305
306 return ( result );
307}
308
309/*****************************************************************************/
310
311OSErr
312FSGetVolFileSystemID(
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
332FSGetVolumeInfo:
333
334 return ( result );
335}
336
337/*****************************************************************************/
338
339OSErr
340FSGetMountedVolumes(
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
384MemoryAllocationFailed:
385FSGetVolumeInfo:
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
395NewHandle:
396BadParameter:
397
398 return ( result );
399}
400
401/*****************************************************************************/
402
403#pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines -----
404
405/*****************************************************************************/
406
407OSErr
408FSRefMakeFSSpec(
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
420FSGetCatalogInfo:
421BadParameter:
422
423 return ( result );
424}
425
426/*****************************************************************************/
427
428OSErr
429FSMakeFSRef(
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
448PBMakeFSRefSync:
449BadParameter:
450
451 return ( result );
452}
453
454/*****************************************************************************/
455
456OSStatus
457FSMakePath(
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
478FSRefMakePath:
479FSMakeFSRef:
480BadParameter:
481
482 return ( result );
483}
484
485/*****************************************************************************/
486
487OSStatus
488FSPathMakeFSSpec(
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
507FSGetCatalogInfo:
508FSPathMakeRef:
509BadParameter:
510
511 return ( result );
512}
513
514/*****************************************************************************/
515
516OSErr
517UnicodeNameGetHFSName(
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
584ConvertFromUnicodeToText:
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
590CreateUnicodeToTextInfo:
591BadParameter:
592
593 return ( result );
594}
595
596/*****************************************************************************/
597
598OSErr
599HFSNameGetUnicodeName(
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
663ConvertFromTextToUnicode:
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
669CreateTextToUnicodeInfo:
670BadParameter:
671
672 return ( result );
673}
674
675/*****************************************************************************/
676
677#pragma mark ----- File/Directory Manipulation Routines -----
678
679/*****************************************************************************/
680
681Boolean FSRefValid(const FSRef *ref)
682{
683 return ( noErr == FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, NULL, NULL) );
684}
685
686/*****************************************************************************/
687
688OSErr
689FSGetParentRef(
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
716FSGetCatalogInfo:
717BadParameter:
718
719 return ( result );
720}
721
722/*****************************************************************************/
723
724OSErr
725FSGetFileDirName(
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
737FSGetCatalogInfo:
738BadParameter:
739
740 return ( result );
741}
742
743/*****************************************************************************/
744
745OSErr
746FSGetNodeID(
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
778FSGetCatalogInfo:
779
780 return ( result );
781}
782
783/*****************************************************************************/
784
785OSErr
786FSGetUserPrivilegesPermissions(
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
818FSGetCatalogInfo:
819
820 return ( result );
821}
822
823/*****************************************************************************/
824
825OSErr
826FSCheckLock(
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
860FSGetVolumeInfo:
861FSGetCatalogInfo:
862
863 return ( result );
864}
865
866/*****************************************************************************/
867
868OSErr
869FSGetForkSizes(
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
908FSRefNotFile:
909FSGetCatalogInfo:
910
911 return ( result );
912}
913
914/*****************************************************************************/
915
916OSErr
917FSGetTotalForkSizes(
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
988FSIterateForks:
989
990 return ( result );
991}
992
993/*****************************************************************************/
994
995OSErr
996FSBumpDate(
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 */
1056FNNotify:
1057FSSetCatalogInfo:
1058
1059 return ( noErr );
1060
1061 /**********************/
1062
1063GetUTCDateTime:
1064FSGetCatalogInfo:
1065
1066 return ( result );
1067}
1068
1069/*****************************************************************************/
1070
1071OSErr
1072FSGetFinderInfo(
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
1123FSGetCatalogInfo:
1124
1125 return ( result );
1126}
1127
1128/*****************************************************************************/
1129
1130OSErr
1131FSSetFinderInfo(
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
1158FSGetCatalogInfo:
1159
1160 return ( result );
1161}
1162
1163/*****************************************************************************/
1164
1165OSErr
1166FSChangeCreatorType(
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
1202FSSetCatalogInfo:
1203FSRefNotFile:
1204FSGetCatalogInfo:
1205
1206 return ( result );
1207}
1208
1209/*****************************************************************************/
1210
1211OSErr
1212FSChangeFinderFlags(
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
1245FSSetCatalogInfo:
1246FSGetCatalogInfo:
1247
1248 return ( result );
1249}
1250
1251/*****************************************************************************/
1252
1253OSErr
1254FSSetInvisible(
1255 const FSRef *ref)
1256{
1257 return ( FSChangeFinderFlags(ref, true, kIsInvisible) );
1258}
1259
1260OSErr
1261FSClearInvisible(
1262 const FSRef *ref)
1263{
1264 return ( FSChangeFinderFlags(ref, false, kIsInvisible) );
1265}
1266
1267/*****************************************************************************/
1268
1269OSErr
1270FSSetNameLocked(
1271 const FSRef *ref)
1272{
1273 return ( FSChangeFinderFlags(ref, true, kNameLocked) );
1274}
1275
1276OSErr
1277FSClearNameLocked(
1278 const FSRef *ref)
1279{
1280 return ( FSChangeFinderFlags(ref, false, kNameLocked) );
1281}
1282
1283/*****************************************************************************/
1284
1285OSErr
1286FSSetIsStationery(
1287 const FSRef *ref)
1288{
1289 return ( FSChangeFinderFlags(ref, true, kIsStationery) );
1290}
1291
1292OSErr
1293FSClearIsStationery(
1294 const FSRef *ref)
1295{
1296 return ( FSChangeFinderFlags(ref, false, kIsStationery) );
1297}
1298
1299/*****************************************************************************/
1300
1301OSErr
1302FSSetHasCustomIcon(
1303 const FSRef *ref)
1304{
1305 return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) );
1306}
1307
1308OSErr
1309FSClearHasCustomIcon(
1310 const FSRef *ref)
1311{
1312 return ( FSChangeFinderFlags(ref, false, kHasCustomIcon) );
1313}
1314
1315/*****************************************************************************/
1316
1317OSErr
1318FSClearHasBeenInited(
1319 const FSRef *ref)
1320{
1321 return ( FSChangeFinderFlags(ref, false, kHasBeenInited) );
1322}
1323
1324/*****************************************************************************/
1325
1326OSErr
1327FSCopyFileMgrAttributes(
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
1353FSSetCatalogInfo:
1354FSGetCatalogInfo:
1355
1356 return ( result );
1357}
1358
1359/*****************************************************************************/
1360
1361OSErr
1362FSMoveRenameObjectUnicode(
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 if ( FSCompareFSRefs(destDirectory, &originalDirectory) != noErr )
1416 {
1417 /* Move object to its new home */
1418 result = FSMoveObject(newRef, destDirectory, newRef);
1419 require_noerr(result, FSMoveObjectAfterRenameFailed);
1420 }
1421
1422 /* Rename the object to new name */
1423 result = FSRenameUnicode(ref, nameLength, name, textEncodingHint, newRef);
1424 require_noerr(result, FSRenameUnicodeAfterMoveFailed);
1425 }
1426 else
1427 {
1428 /* Move object to its new home */
1429 result = FSMoveObject(newRef, destDirectory, newRef);
1430 require_noerr(result, FSMoveObjectNoRenameFailed);
1431 }
1432
1433 return ( result );
1434
1435 /*************/
1436
1437/*
1438 * failure handling code when renaming
1439 */
1440
1441FSRenameUnicodeAfterMoveFailed:
1442
1443 /* Error handling: move object back to original location - ignore errors */
1444 verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef));
1445
1446FSMoveObjectAfterRenameFailed:
1447
1448 /* Error handling: rename object back to original name - ignore errors */
1449 verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef));
1450
1451FSRenameUnicodeBeforeMoveFailed:
1452GenerateUniqueHFSUniStrFailed:
1453
1454/*
1455 * failure handling code for renaming or not
1456 */
1457FSMoveObjectNoRenameFailed:
1458NotSameVolume:
1459SourceBad:
1460DestinationBad:
1461BadParameter:
1462
1463 return ( result );
1464}
1465
1466/*****************************************************************************/
1467
1468/*
1469 The FSDeleteContainerLevel function deletes the contents of a container
1470 directory. All files and subdirectories in the specified container are
1471 deleted. If a locked file or directory is encountered, it is unlocked
1472 and then deleted. If any unexpected errors are encountered,
1473 FSDeleteContainerLevel quits and returns to the caller.
1474
1475 container --> FSRef to a directory.
1476 theGlobals --> A pointer to a FSDeleteContainerGlobals struct
1477 which contains the variables that do not need to
1478 be allocated each time FSDeleteContainerLevel
1479 recurses. That lets FSDeleteContainerLevel use
1480 less stack space per recursion level.
1481*/
1482
1483static
1484void
1485FSDeleteContainerLevel(
1486 const FSRef *container,
1487 FSDeleteContainerGlobals *theGlobals)
1488{
1489 /* level locals */
1490 FSIterator iterator;
1491 FSRef itemToDelete;
1492 UInt16 nodeFlags;
1493
1494 /* Open FSIterator for flat access and give delete optimization hint */
1495 theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator);
1496 require_noerr(theGlobals->result, FSOpenIterator);
1497
1498 /* delete the contents of the directory */
1499 do
1500 {
1501 /* get 1 item to delete */
1502 theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
1503 NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo,
1504 &itemToDelete, NULL, NULL);
1505 if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) )
1506 {
1507 /* save node flags in local in case we have to recurse */
1508 nodeFlags = theGlobals->catalogInfo.nodeFlags;
1509
1510 /* is it a file or directory? */
1511 if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) )
1512 {
1513 /* it's a directory -- delete its contents before attempting to delete it */
1514 FSDeleteContainerLevel(&itemToDelete, theGlobals);
1515 }
1516 /* are we still OK to delete? */
1517 if ( noErr == theGlobals->result )
1518 {
1519 /* is item locked? */
1520 if ( 0 != (nodeFlags & kFSNodeLockedMask) )
1521 {
1522 /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */
1523 theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask;
1524 (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo);
1525 }
1526 /* delete the item */
1527 theGlobals->result = FSDeleteObject(&itemToDelete);
1528 }
1529 }
1530 } while ( noErr == theGlobals->result );
1531
1532 /* we found the end of the items normally, so return noErr */
1533 if ( errFSNoMoreItems == theGlobals->result )
1534 {
1535 theGlobals->result = noErr;
1536 }
1537
1538 /* close the FSIterator (closing an open iterator should never fail) */
1539 verify_noerr(FSCloseIterator(iterator));
1540
1541FSOpenIterator:
1542
1543 return;
1544}
1545
1546/*****************************************************************************/
1547
1548OSErr
1549FSDeleteContainerContents(
1550 const FSRef *container)
1551{
1552 FSDeleteContainerGlobals theGlobals;
1553
1554 /* delete container's contents */
1555 FSDeleteContainerLevel(container, &theGlobals);
1556
1557 return ( theGlobals.result );
1558}
1559
1560/*****************************************************************************/
1561
1562OSErr
1563FSDeleteContainer(
1564 const FSRef *container)
1565{
1566 OSErr result;
1567 FSCatalogInfo catalogInfo;
1568
1569 /* get nodeFlags for container */
1570 result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL);
1571 require_noerr(result, FSGetCatalogInfo);
1572
1573 /* make sure container is a directory */
1574 require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr);
1575
1576 /* delete container's contents */
1577 result = FSDeleteContainerContents(container);
1578 require_noerr(result, FSDeleteContainerContents);
1579
1580 /* is container locked? */
1581 if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) )
1582 {
1583 /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */
1584 catalogInfo.nodeFlags &= ~kFSNodeLockedMask;
1585 (void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo);
1586 }
1587
1588 /* delete the container */
1589 result = FSDeleteObject(container);
1590
1591FSDeleteContainerContents:
1592ContainerNotDirectory:
1593FSGetCatalogInfo:
1594
1595 return ( result );
1596}
1597
1598/*****************************************************************************/
1599
1600/*
1601 The FSIterateContainerLevel function iterates the contents of a container
1602 directory and calls a IterateContainerFilterProc function once for each
1603 file and directory found.
1604
1605 theGlobals --> A pointer to a FSIterateContainerGlobals struct
1606 which contains the variables needed globally by
1607 all recusion levels of FSIterateContainerLevel.
1608 That makes FSIterateContainer thread safe since
1609 each call to it uses its own global world.
1610 It also contains the variables that do not need
1611 to be allocated each time FSIterateContainerLevel
1612 recurses. That lets FSIterateContainerLevel use
1613 less stack space per recursion level.
1614*/
1615
1616static
1617void
1618FSIterateContainerLevel(
1619 FSIterateContainerGlobals *theGlobals)
1620{
1621 FSIterator iterator;
1622
1623 /* If maxLevels is zero, we aren't checking levels */
1624 /* If currentLevel < maxLevels, look at this level */
1625 if ( (theGlobals->maxLevels == 0) ||
1626 (theGlobals->currentLevel < theGlobals->maxLevels) )
1627 {
1628 /* Open FSIterator for flat access to theGlobals->ref */
1629 theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator);
1630 require_noerr(theGlobals->result, FSOpenIterator);
1631
1632 ++theGlobals->currentLevel; /* Go to next level */
1633
1634 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1635 do
1636 {
1637 theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects,
1638 &theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo,
1639 &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr);
1640 if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) &&
1641 (0 != theGlobals->actualObjects) )
1642 {
1643 /* Call the IterateFilterProc */
1644 theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter,
1645 theGlobals->containerChanged, theGlobals->currentLevel,
1646 &theGlobals->catalogInfo, &theGlobals->ref,
1647 theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr);
1648 /* Is it a directory? */
1649 if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) )
1650 {
1651 /* Keep going? */
1652 if ( !theGlobals->quitFlag )
1653 {
1654 /* Dive again if the IterateFilterProc didn't say "quit" */
1655 FSIterateContainerLevel(theGlobals);
1656 }
1657 }
1658 }
1659 /* time to fall back a level? */
1660 } while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) );
1661
1662 /* errFSNoMoreItems is OK - it only means we hit the end of this level */
1663 /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
1664 if ( (errFSNoMoreItems == theGlobals->result) ||
1665 (afpAccessDenied == theGlobals->result) )
1666 {
1667 theGlobals->result = noErr;
1668 }
1669
1670 --theGlobals->currentLevel; /* Return to previous level as we leave */
1671
1672 /* Close the FSIterator (closing an open iterator should never fail) */
1673 verify_noerr(FSCloseIterator(iterator));
1674 }
1675
1676FSOpenIterator:
1677
1678 return;
1679}
1680
1681/*****************************************************************************/
1682
1683OSErr
1684FSIterateContainer(
1685 const FSRef *container,
1686 ItemCount maxLevels,
1687 FSCatalogInfoBitmap whichInfo,
1688 Boolean wantFSSpec,
1689 Boolean wantName,
1690 IterateContainerFilterProcPtr iterateFilter,
1691 void *yourDataPtr)
1692{
1693 OSErr result;
1694 FSIterateContainerGlobals theGlobals;
1695
1696 /* make sure there is an iterateFilter */
1697 require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr);
1698
1699 /*
1700 * set up the globals we need to access from the recursive routine
1701 */
1702 theGlobals.iterateFilter = iterateFilter;
1703 /* we need the node flags no matter what was requested so we can detect files vs. directories */
1704 theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags;
1705 /* start with input container -- the first OpenIterator will ensure it is a directory */
1706 theGlobals.ref = *container;
1707 if ( wantFSSpec )
1708 {
1709 theGlobals.specPtr = &theGlobals.spec;
1710 }
1711 else
1712 {
1713 theGlobals.specPtr = NULL;
1714 }
1715 if ( wantName )
1716 {
1717 theGlobals.namePtr = &theGlobals.name;
1718 }
1719 else
1720 {
1721 theGlobals.namePtr = NULL;
1722 }
1723 theGlobals.yourDataPtr = yourDataPtr;
1724 theGlobals.maxLevels = maxLevels;
1725 theGlobals.currentLevel = 0;
1726 theGlobals.quitFlag = false;
1727 theGlobals.containerChanged = false;
1728 theGlobals.result = noErr;
1729 theGlobals.actualObjects = 0;
1730
1731 /* here we go into recursion land... */
1732 FSIterateContainerLevel(&theGlobals);
1733 result = theGlobals.result;
1734 require_noerr(result, FSIterateContainerLevel);
1735
1736FSIterateContainerLevel:
1737NoIterateFilter:
1738
1739 return ( result );
1740}
1741
1742/*****************************************************************************/
1743
1744OSErr
1745FSGetDirectoryItems(
1746 const FSRef *container,
1747 FSRef ***refsHandle, /* pointer to handle of FSRefs */
1748 ItemCount *numRefs,
1749 Boolean *containerChanged)
1750{
1751 /* Grab items 10 at a time. */
1752 enum { kMaxItemsPerBulkCall = 10 };
1753
1754 OSErr result;
1755 OSErr memResult;
1756 FSIterator iterator;
1757 FSRef refs[kMaxItemsPerBulkCall];
1758 ItemCount actualObjects;
1759 Boolean changed;
1760
1761 /* check parameters */
1762 require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged),
1763 BadParameter, result = paramErr);
1764
1765 *numRefs = 0;
1766 *containerChanged = false;
1767 *refsHandle = (FSRef **)NewHandle(0);
1768 require_action(NULL != *refsHandle, NewHandle, result = memFullErr);
1769
1770 /* open an FSIterator */
1771 result = FSOpenIterator(container, kFSIterateFlat, &iterator);
1772 require_noerr(result, FSOpenIterator);
1773
1774 /* Call FSGetCatalogInfoBulk in loop to get all items in the container */
1775 do
1776 {
1777 result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects,
1778 &changed, kFSCatInfoNone, NULL, refs, NULL, NULL);
1779
1780 /* if the container changed, set containerChanged for output, but keep going */
1781 if ( changed )
1782 {
1783 *containerChanged = changed;
1784 }
1785
1786 /* any result other than noErr and errFSNoMoreItems is serious */
1787 require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk);
1788
1789 /* add objects to output array and count */
1790 if ( 0 != actualObjects )
1791 {
1792 /* concatenate the FSRefs to the end of the handle */
1793 PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef));
1794 memResult = MemError();
1795 require_noerr_action(memResult, MemoryAllocationFailed, result = memResult);
1796
1797 *numRefs += actualObjects;
1798 }
1799 } while ( noErr == result );
1800
1801 verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */
1802
1803 return ( noErr );
1804
1805 /**********************/
1806
1807MemoryAllocationFailed:
1808FSGetCatalogInfoBulk:
1809
1810 /* close the iterator */
1811 verify_noerr(FSCloseIterator(iterator));
1812
1813FSOpenIterator:
1814 /* dispose of handle if already allocated and clear the outputs */
1815 if ( NULL != *refsHandle )
1816 {
1817 DisposeHandle((Handle)*refsHandle);
1818 *refsHandle = NULL;
1819 }
1820 *numRefs = 0;
1821
1822NewHandle:
1823BadParameter:
1824
1825 return ( result );
1826}
1827
1828/*****************************************************************************/
1829
1830/*
1831 The GenerateUniqueName function generates a HFSUniStr255 name that is
1832 unique in both dir1 and dir2.
1833
1834 startSeed --> A pointer to a long which is used to generate the
1835 unique name.
1836 <-- It is modified on output to a value which should
1837 be used to generate the next unique name.
1838 dir1 --> The first directory.
1839 dir2 --> The second directory.
1840 uniqueName <-- A pointer to a HFSUniStr255 where the unique name
1841 is to be returned.
1842*/
1843
1844static
1845OSErr
1846GenerateUniqueHFSUniStr(
1847 long *startSeed,
1848 const FSRef *dir1,
1849 const FSRef *dir2,
1850 HFSUniStr255 *uniqueName)
1851{
1852 OSErr result;
1853 long i;
1854 FSRefParam pb;
1855 FSRef newRef;
1856 unsigned char hexStr[17] = "0123456789ABCDEF";
1857
1858 /* set up the parameter block */
1859 pb.name = uniqueName->unicode;
1860 pb.nameLength = 8; /* always 8 characters */
1861 pb.textEncodingHint = kTextEncodingUnknown;
1862 pb.newRef = &newRef;
1863
1864 /* loop until we get fnfErr with a filename in both directories */
1865 result = noErr;
1866 while ( fnfErr != result )
1867 {
1868 /* convert startSeed to 8 character Unicode string */
1869 uniqueName->length = 8;
1870 for ( i = 0; i < 8; ++i )
1871 {
1872 uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)];
1873 }
1874
1875 /* try in dir1 */
1876 pb.ref = dir1;
1877 result = PBMakeFSRefUnicodeSync(&pb);
1878 if ( fnfErr == result )
1879 {
1880 /* try in dir2 */
1881 pb.ref = dir2;
1882 result = PBMakeFSRefUnicodeSync(&pb);
1883 if ( fnfErr != result )
1884 {
1885 /* exit if anything other than noErr or fnfErr */
1886 require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed);
1887 }
1888 }
1889 else
1890 {
1891 /* exit if anything other than noErr or fnfErr */
1892 require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed);
1893 }
1894
1895 /* increment seed for next pass through loop, */
1896 /* or for next call to GenerateUniqueHFSUniStr */
1897 ++(*startSeed);
1898 }
1899
1900 /* we have a unique file name which doesn't exist in dir1 or dir2 */
1901 result = noErr;
1902
1903Dir2PBMakeFSRefUnicodeSyncFailed:
1904Dir1PBMakeFSRefUnicodeSyncFailed:
1905
1906 return ( result );
1907}
1908
1909/*****************************************************************************/
1910
1911OSErr
1912FSExchangeObjectsCompat(
1913 const FSRef *sourceRef,
1914 const FSRef *destRef,
1915 FSRef *newSourceRef,
1916 FSRef *newDestRef)
1917{
1918 enum
1919 {
1920 /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */
1921 kGetCatInformationMask = (kFSCatInfoSettableInfo |
1922 kFSCatInfoVolume |
1923 kFSCatInfoParentDirID) &
1924 ~(kFSCatInfoContentMod | kFSCatInfoAttrMod),
1925 /* set everything possible except for mod dates */
1926 kSetCatinformationMask = kFSCatInfoSettableInfo &
1927 ~(kFSCatInfoContentMod | kFSCatInfoAttrMod)
1928 };
1929
1930 OSErr result;
1931 GetVolParmsInfoBuffer volParmsInfo;
1932 UInt32 infoSize;
1933 FSCatalogInfo sourceCatalogInfo; /* source file's catalog information */
1934 FSCatalogInfo destCatalogInfo; /* destination file's catalog information */
1935 HFSUniStr255 sourceName; /* source file's Unicode name */
1936 HFSUniStr255 destName; /* destination file's Unicode name */
1937 FSRef sourceCurrentRef; /* FSRef to current location of source file throughout this function */
1938 FSRef destCurrentRef; /* FSRef to current location of destination file throughout this function */
1939 FSRef sourceParentRef; /* FSRef to parent directory of source file */
1940 FSRef destParentRef; /* FSRef to parent directory of destination file */
1941 HFSUniStr255 sourceUniqueName; /* unique name given to source file while exchanging it with destination */
1942 HFSUniStr255 destUniqueName; /* unique name given to destination file while exchanging it with source */
1943 long theSeed; /* the seed for generating unique names */
1944 Boolean sameParentDirs; /* true if source and destinatin parent directory is the same */
1945
1946 /* check parameters */
1947 require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr);
1948
1949 /* output refs and current refs = input refs to start with */
1950 BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef));
1951 BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef));
1952
1953 BlockMoveData(destRef, newDestRef, sizeof(FSRef));
1954 BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef));
1955
1956 /* get source volume's vRefNum */
1957 result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL);
1958 require_noerr(result, DetermineSourceVRefNumFailed);
1959
1960 /* see if that volume supports FSExchangeObjects */
1961 result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer),
1962 &volParmsInfo, &infoSize);
1963 if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) )
1964 {
1965 /* yes - use FSExchangeObjects */
1966 result = FSExchangeObjects(sourceRef, destRef);
1967 }
1968 else
1969 {
1970 /* no - emulate FSExchangeObjects */
1971
1972 /* Note: The compatibility case won't work for files with *Btree control blocks. */
1973 /* Right now the only *Btree files are created by the system. */
1974
1975 /* get all catalog information and Unicode names for each file */
1976 result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef);
1977 require_noerr(result, SourceFSGetCatalogInfoFailed);
1978
1979 result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef);
1980 require_noerr(result, DestFSGetCatalogInfoFailed);
1981
1982 /* make sure source and destination are on same volume */
1983 require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr);
1984
1985 /* make sure both files are *really* files */
1986 require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) &&
1987 (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr);
1988
1989 /* generate 2 names that are unique in both directories */
1990 theSeed = 0x4a696d4c; /* a fine unlikely filename */
1991
1992 result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName);
1993 require_noerr(result, GenerateUniqueHFSUniStr1Failed);
1994
1995 result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName);
1996 require_noerr(result, GenerateUniqueHFSUniStr2Failed);
1997
1998 /* rename sourceCurrentRef to sourceUniqueName */
1999 result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef);
2000 require_noerr(result, FSRenameUnicode1Failed);
2001 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2002
2003 /* rename destCurrentRef to destUniqueName */
2004 result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef);
2005 require_noerr(result, FSRenameUnicode2Failed);
2006 BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2007
2008 /* are the source and destination parent directories the same? */
2009 sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID );
2010 if ( !sameParentDirs )
2011 {
2012 /* move source file to dest parent directory */
2013 result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef);
2014 require_noerr(result, FSMoveObject1Failed);
2015 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2016
2017 /* move dest file to source parent directory */
2018 result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef);
2019 require_noerr(result, FSMoveObject2Failed);
2020 BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2021 }
2022
2023 /* At this point, the files are in their new locations (if they were moved). */
2024 /* The source file is named sourceUniqueName and is in the directory referred to */
2025 /* by destParentRef. The destination file is named destUniqueName and is in the */
2026 /* directory referred to by sourceParentRef. */
2027
2028 /* give source file the dest file's catalog information except for mod dates */
2029 result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo);
2030 require_noerr(result, FSSetCatalogInfo1Failed);
2031
2032 /* give dest file the source file's catalog information except for mod dates */
2033 result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo);
2034 require_noerr(result, FSSetCatalogInfo2Failed);
2035
2036 /* rename source file with dest file's name */
2037 result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef);
2038 require_noerr(result, FSRenameUnicode3Failed);
2039 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2040
2041 /* rename dest file with source file's name */
2042 result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef);
2043 require_noerr(result, FSRenameUnicode4Failed);
2044
2045 /* we're done with no errors, so swap newSourceRef and newDestRef */
2046 BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef));
2047 BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef));
2048 }
2049
2050 return ( result );
2051
2052 /**********************/
2053
2054/* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */
2055/* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */
2056/* state and location they ended up in so that both files can be found by the calling code. */
2057
2058FSRenameUnicode4Failed:
2059
2060 /* attempt to rename source file to sourceUniqueName */
2061 if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) )
2062 {
2063 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2064 }
2065
2066FSRenameUnicode3Failed:
2067
2068 /* attempt to restore dest file's catalog information */
2069 verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo));
2070
2071FSSetCatalogInfo2Failed:
2072
2073 /* attempt to restore source file's catalog information */
2074 verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo));
2075
2076FSSetCatalogInfo1Failed:
2077
2078 if ( !sameParentDirs )
2079 {
2080 /* attempt to move dest file back to dest directory */
2081 if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) )
2082 {
2083 BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef));
2084 }
2085 }
2086
2087FSMoveObject2Failed:
2088
2089 if ( !sameParentDirs )
2090 {
2091 /* attempt to move source file back to source directory */
2092 if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) )
2093 {
2094 BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef));
2095 }
2096 }
2097
2098FSMoveObject1Failed:
2099
2100 /* attempt to rename dest file to original name */
2101 verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef));
2102
2103FSRenameUnicode2Failed:
2104
2105 /* attempt to rename source file to original name */
2106 verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef));
2107
2108FSRenameUnicode1Failed:
2109GenerateUniqueHFSUniStr2Failed:
2110GenerateUniqueHFSUniStr1Failed:
2111NotAFile:
2112NotSameVolume:
2113DestFSGetCatalogInfoFailed:
2114SourceFSGetCatalogInfoFailed:
2115DetermineSourceVRefNumFailed:
2116BadParameter:
2117
2118 return ( result );
2119}
2120
2121/*****************************************************************************/
2122
2123#pragma mark ----- Shared Environment Routines -----
2124
2125/*****************************************************************************/
2126
2127OSErr
2128FSLockRange(
2129 SInt16 refNum,
2130 SInt32 rangeLength,
2131 SInt32 rangeStart)
2132{
2133 OSErr result;
2134 ParamBlockRec pb;
2135
2136 pb.ioParam.ioRefNum = refNum;
2137 pb.ioParam.ioReqCount = rangeLength;
2138 pb.ioParam.ioPosMode = fsFromStart;
2139 pb.ioParam.ioPosOffset = rangeStart;
2140 result = PBLockRangeSync(&pb);
2141 require_noerr(result, PBLockRangeSync);
2142
2143PBLockRangeSync:
2144
2145 return ( result );
2146}
2147
2148/*****************************************************************************/
2149
2150OSErr
2151FSUnlockRange(
2152 SInt16 refNum,
2153 SInt32 rangeLength,
2154 SInt32 rangeStart)
2155{
2156 OSErr result;
2157 ParamBlockRec pb;
2158
2159 pb.ioParam.ioRefNum = refNum;
2160 pb.ioParam.ioReqCount = rangeLength;
2161 pb.ioParam.ioPosMode = fsFromStart;
2162 pb.ioParam.ioPosOffset = rangeStart;
2163 result = PBUnlockRangeSync(&pb);
2164 require_noerr(result, PBUnlockRangeSync);
2165
2166PBUnlockRangeSync:
2167
2168 return ( result );
2169}
2170
2171/*****************************************************************************/
2172
2173OSErr
2174FSGetDirAccess(
2175 const FSRef *ref,
2176 SInt32 *ownerID, /* can be NULL */
2177 SInt32 *groupID, /* can be NULL */
2178 SInt32 *accessRights) /* can be NULL */
2179{
2180 OSErr result;
2181 FSSpec spec;
2182 HParamBlockRec pb;
2183
2184 /* get FSSpec from FSRef */
2185 result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2186 require_noerr(result, FSGetCatalogInfo);
2187
2188 /* get directory access info for FSSpec */
2189 pb.accessParam.ioNamePtr = (StringPtr)spec.name;
2190 pb.accessParam.ioVRefNum = spec.vRefNum;
2191 pb.fileParam.ioDirID = spec.parID;
2192 result = PBHGetDirAccessSync(&pb);
2193 require_noerr(result, PBHGetDirAccessSync);
2194
2195 /* return the IDs and access rights */
2196 if ( NULL != ownerID )
2197 {
2198 *ownerID = pb.accessParam.ioACOwnerID;
2199 }
2200 if ( NULL != groupID )
2201 {
2202 *groupID = pb.accessParam.ioACGroupID;
2203 }
2204 if ( NULL != accessRights )
2205 {
2206 *accessRights = pb.accessParam.ioACAccess;
2207 }
2208
2209PBHGetDirAccessSync:
2210FSGetCatalogInfo:
2211
2212 return ( result );
2213}
2214
2215/*****************************************************************************/
2216
2217OSErr
2218FSSetDirAccess(
2219 const FSRef *ref,
2220 SInt32 ownerID,
2221 SInt32 groupID,
2222 SInt32 accessRights)
2223{
2224 OSErr result;
2225 FSSpec spec;
2226 HParamBlockRec pb;
2227
2228 enum
2229 {
2230 /* Just the bits that can be set */
2231 kSetDirAccessSettableMask = (kioACAccessBlankAccessMask +
2232 kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask +
2233 kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask +
2234 kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask)
2235 };
2236
2237 /* get FSSpec from FSRef */
2238 result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2239 require_noerr(result, FSGetCatalogInfo);
2240
2241 /* set directory access info for FSSpec */
2242 pb.accessParam.ioNamePtr = (StringPtr)spec.name;
2243 pb.accessParam.ioVRefNum = spec.vRefNum;
2244 pb.fileParam.ioDirID = spec.parID;
2245 pb.accessParam.ioACOwnerID = ownerID;
2246 pb.accessParam.ioACGroupID = groupID;
2247 pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask;
2248 result = PBHSetDirAccessSync(&pb);
2249 require_noerr(result, PBHSetDirAccessSync);
2250
2251PBHSetDirAccessSync:
2252FSGetCatalogInfo:
2253
2254 return ( result );
2255}
2256
2257/*****************************************************************************/
2258
2259OSErr
2260FSGetVolMountInfoSize(
2261 FSVolumeRefNum volRefNum,
2262 SInt16 *size)
2263{
2264 OSErr result;
2265 ParamBlockRec pb;
2266
2267 /* check parameters */
2268 require_action(NULL != size, BadParameter, result = paramErr);
2269
2270 pb.ioParam.ioNamePtr = NULL;
2271 pb.ioParam.ioVRefNum = volRefNum;
2272 pb.ioParam.ioBuffer = (Ptr)size;
2273 result = PBGetVolMountInfoSize(&pb);
2274 require_noerr(result, PBGetVolMountInfoSize);
2275
2276PBGetVolMountInfoSize:
2277BadParameter:
2278
2279 return ( result );
2280}
2281
2282/*****************************************************************************/
2283
2284OSErr
2285FSGetVolMountInfo(
2286 FSVolumeRefNum volRefNum,
2287 void *volMountInfo)
2288{
2289 OSErr result;
2290 ParamBlockRec pb;
2291
2292 /* check parameters */
2293 require_action(NULL != volMountInfo, BadParameter, result = paramErr);
2294
2295 pb.ioParam.ioNamePtr = NULL;
2296 pb.ioParam.ioVRefNum = volRefNum;
2297 pb.ioParam.ioBuffer = (Ptr)volMountInfo;
2298 result = PBGetVolMountInfo(&pb);
2299 require_noerr(result, PBGetVolMountInfo);
2300
2301PBGetVolMountInfo:
2302BadParameter:
2303
2304 return ( result );
2305}
2306
2307/*****************************************************************************/
2308
2309OSErr
2310FSVolumeMount(
2311 const void *volMountInfo,
2312 FSVolumeRefNum *volRefNum)
2313{
2314 OSErr result;
2315 ParamBlockRec pb;
2316
2317 /* check parameters */
2318 require_action(NULL != volRefNum, BadParameter, result = paramErr);
2319
2320 pb.ioParam.ioBuffer = (Ptr)volMountInfo;
2321 result = PBVolumeMount(&pb);
2322 require_noerr(result, PBVolumeMount);
2323
2324 /* return the volume reference number */
2325 *volRefNum = pb.ioParam.ioVRefNum;
2326
2327PBVolumeMount:
2328BadParameter:
2329
2330 return ( result );
2331}
2332
2333/*****************************************************************************/
2334
2335OSErr
2336FSMapID(
2337 FSVolumeRefNum volRefNum,
2338 SInt32 ugID,
2339 SInt16 objType,
2340 Str31 name)
2341{
2342 OSErr result;
2343 HParamBlockRec pb;
2344
2345 /* check parameters */
2346 require_action(NULL != name, BadParameter, result = paramErr);
2347
2348 pb.objParam.ioNamePtr = NULL;
2349 pb.objParam.ioVRefNum = volRefNum;
2350 pb.objParam.ioObjType = objType;
2351 pb.objParam.ioObjNamePtr = name;
2352 pb.objParam.ioObjID = ugID;
2353 result = PBHMapIDSync(&pb);
2354 require_noerr(result, PBHMapIDSync);
2355
2356PBHMapIDSync:
2357BadParameter:
2358
2359 return ( result );
2360}
2361
2362/*****************************************************************************/
2363
2364OSErr
2365FSMapName(
2366 FSVolumeRefNum volRefNum,
2367 ConstStr255Param name,
2368 SInt16 objType,
2369 SInt32 *ugID)
2370{
2371 OSErr result;
2372 HParamBlockRec pb;
2373
2374 /* check parameters */
2375 require_action(NULL != ugID, BadParameter, result = paramErr);
2376
2377 pb.objParam.ioNamePtr = NULL;
2378 pb.objParam.ioVRefNum = volRefNum;
2379 pb.objParam.ioObjType = objType;
2380 pb.objParam.ioObjNamePtr = (StringPtr)name;
2381 result = PBHMapNameSync(&pb);
2382 require_noerr(result, PBHMapNameSync);
2383
2384 /* return the user or group ID */
2385 *ugID = pb.objParam.ioObjID;
2386
2387PBHMapNameSync:
2388BadParameter:
2389
2390 return ( result );
2391}
2392
2393/*****************************************************************************/
2394
2395OSErr
2396FSCopyFile(
2397 const FSRef *srcFileRef,
2398 const FSRef *dstDirectoryRef,
2399 UniCharCount nameLength,
2400 const UniChar *copyName, /* can be NULL (no rename during copy) */
2401 TextEncoding textEncodingHint,
2402 FSRef *newRef) /* can be NULL */
2403{
2404 OSErr result;
2405 FSSpec srcFileSpec;
2406 FSCatalogInfo catalogInfo;
2407 HParamBlockRec pb;
2408 Str31 hfsName;
2409 GetVolParmsInfoBuffer volParmsInfo;
2410 UInt32 infoSize;
2411
2412 /* get source FSSpec from source FSRef */
2413 result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
2414 require_noerr(result, FSGetCatalogInfo_srcFileRef);
2415
2416 /* Make sure the volume supports CopyFile */
2417 result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
2418 &volParmsInfo, &infoSize);
2419 require_action((noErr == result) && VolHasCopyFile(&volParmsInfo),
2420 NoCopyFileSupport, result = paramErr);
2421
2422 /* get destination volume reference number and destination directory ID from destination FSRef */
2423 result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
2424 &catalogInfo, NULL, NULL, NULL);
2425 require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
2426
2427 /* tell the server to copy the object */
2428 pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
2429 pb.copyParam.ioDirID = srcFileSpec.parID;
2430 pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
2431 pb.copyParam.ioDstVRefNum = catalogInfo.volume;
2432 pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
2433 pb.copyParam.ioNewName = NULL;
2434 if ( NULL != copyName )
2435 {
2436 result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName);
2437 require_noerr(result, UnicodeNameGetHFSName);
2438
2439 pb.copyParam.ioCopyName = hfsName;
2440 }
2441 else
2442 {
2443 pb.copyParam.ioCopyName = NULL;
2444 }
2445 result = PBHCopyFileSync(&pb);
2446 require_noerr(result, PBHCopyFileSync);
2447
2448 if ( NULL != newRef )
2449 {
2450 verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID,
2451 pb.copyParam.ioCopyName, newRef));
2452 }
2453
2454PBHCopyFileSync:
2455UnicodeNameGetHFSName:
2456FSGetCatalogInfo_dstDirectoryRef:
2457NoCopyFileSupport:
2458FSGetCatalogInfo_srcFileRef:
2459
2460 return ( result );
2461}
2462
2463/*****************************************************************************/
2464
2465OSErr
2466FSMoveRename(
2467 const FSRef *srcFileRef,
2468 const FSRef *dstDirectoryRef,
2469 UniCharCount nameLength,
2470 const UniChar *moveName, /* can be NULL (no rename during move) */
2471 TextEncoding textEncodingHint,
2472 FSRef *newRef) /* can be NULL */
2473{
2474 OSErr result;
2475 FSSpec srcFileSpec;
2476 FSCatalogInfo catalogInfo;
2477 HParamBlockRec pb;
2478 Str31 hfsName;
2479 GetVolParmsInfoBuffer volParmsInfo;
2480 UInt32 infoSize;
2481
2482 /* get source FSSpec from source FSRef */
2483 result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL);
2484 require_noerr(result, FSGetCatalogInfo_srcFileRef);
2485
2486 /* Make sure the volume supports MoveRename */
2487 result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer),
2488 &volParmsInfo, &infoSize);
2489 require_action((noErr == result) && VolHasMoveRename(&volParmsInfo),
2490 NoMoveRenameSupport, result = paramErr);
2491
2492 /* get destination volume reference number and destination directory ID from destination FSRef */
2493 result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID,
2494 &catalogInfo, NULL, NULL, NULL);
2495 require_noerr(result, FSGetCatalogInfo_dstDirectoryRef);
2496
2497 /* make sure the source and destination are on the same volume */
2498 require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr);
2499
2500 /* tell the server to move and rename the object */
2501 pb.copyParam.ioVRefNum = srcFileSpec.vRefNum;
2502 pb.copyParam.ioDirID = srcFileSpec.parID;
2503 pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name;
2504 pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID;
2505 pb.copyParam.ioNewName = NULL;
2506 if ( NULL != moveName )
2507 {
2508 result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName);
2509 require_noerr(result, UnicodeNameGetHFSName);
2510
2511 pb.copyParam.ioCopyName = hfsName;
2512 }
2513 else
2514 {
2515 pb.copyParam.ioCopyName = NULL;
2516 }
2517 result = PBHMoveRenameSync(&pb);
2518 require_noerr(result, PBHMoveRenameSync);
2519
2520 if ( NULL != newRef )
2521 {
2522 verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID,
2523 pb.copyParam.ioCopyName, newRef));
2524 }
2525
2526PBHMoveRenameSync:
2527UnicodeNameGetHFSName:
2528NotSameVolume:
2529FSGetCatalogInfo_dstDirectoryRef:
2530NoMoveRenameSupport:
2531FSGetCatalogInfo_srcFileRef:
2532
2533 return ( result );
2534}
2535
2536/*****************************************************************************/
2537
2538#pragma mark ----- File ID Routines -----
2539
2540/*****************************************************************************/
2541
2542OSErr
2543FSResolveFileIDRef(
2544 FSVolumeRefNum volRefNum,
2545 SInt32 fileID,
2546 FSRef *ref)
2547{
2548 OSErr result;
2549 FIDParam pb;
2550 Str255 tempStr;
2551
2552 /* check parameters */
2553 require_action(NULL != ref, BadParameter, result = paramErr);
2554
2555 /* resolve the file ID reference */
2556 tempStr[0] = 0;
2557 pb.ioNamePtr = tempStr;
2558 pb.ioVRefNum = volRefNum;
2559 pb.ioFileID = fileID;
2560 result = PBResolveFileIDRefSync((HParmBlkPtr)&pb);
2561 require_noerr(result, PBResolveFileIDRefSync);
2562
2563 /* and then make an FSRef to the file */
2564 result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref);
2565 require_noerr(result, FSMakeFSRef);
2566
2567FSMakeFSRef:
2568PBResolveFileIDRefSync:
2569BadParameter:
2570
2571 return ( result );
2572}
2573
2574/*****************************************************************************/
2575
2576OSErr
2577FSCreateFileIDRef(
2578 const FSRef *ref,
2579 SInt32 *fileID)
2580{
2581 OSErr result;
2582 FSSpec spec;
2583 FIDParam pb;
2584
2585 /* check parameters */
2586 require_action(NULL != fileID, BadParameter, result = paramErr);
2587
2588 /* Get an FSSpec from the FSRef */
2589 result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL);
2590 require_noerr(result, FSGetCatalogInfo);
2591
2592 /* Create (or get) the file ID reference using the FSSpec */
2593 pb.ioNamePtr = (StringPtr)spec.name;
2594 pb.ioVRefNum = spec.vRefNum;
2595 pb.ioSrcDirID = spec.parID;
2596 result = PBCreateFileIDRefSync((HParmBlkPtr)&pb);
2597 require((noErr == result) || (fidExists == result) || (afpIDExists == result),
2598 PBCreateFileIDRefSync);
2599
2600 /* return the file ID reference */
2601 *fileID = pb.ioFileID;
2602
2603PBCreateFileIDRefSync:
2604FSGetCatalogInfo:
2605BadParameter:
2606
2607 return ( result );
2608}
2609
2610/*****************************************************************************/
2611
2612#pragma mark ----- Utility Routines -----
2613
2614/*****************************************************************************/
2615
2616Ptr
2617GetTempBuffer(
2618 ByteCount buffReqSize,
2619 ByteCount *buffActSize)
2620{
2621 enum
2622 {
2623 kSlopMemory = 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */
2624 };
2625
2626 Ptr tempPtr;
2627
2628 /* check parameters */
2629 require_action(NULL != buffActSize, BadParameter, tempPtr = NULL);
2630
2631 /* Make request a multiple of 4K bytes */
2632 buffReqSize = buffReqSize & 0xfffff000;
2633
2634 if ( buffReqSize < 0x00001000 )
2635 {
2636 /* Request was smaller than 4K bytes - make it 4K */
2637 buffReqSize = 0x00001000;
2638 }
2639
2640 /* Attempt to allocate the memory */
2641 tempPtr = NewPtr(buffReqSize);
2642
2643 /* If request failed, go to backup plan */
2644 if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) )
2645 {
2646 /*
2647 ** Try to get largest 4K byte block available
2648 ** leaving some slop for the toolbox if possible
2649 */
2650 long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000;
2651
2652 buffReqSize = MaxBlock() & 0xfffff000;
2653
2654 if ( buffReqSize > freeMemory )
2655 {
2656 buffReqSize = freeMemory;
2657 }
2658
2659 if ( buffReqSize == 0 )
2660 {
2661 buffReqSize = 0x00001000;
2662 }
2663
2664 tempPtr = NewPtr(buffReqSize);
2665 }
2666
2667 /* Return bytes allocated */
2668 if ( tempPtr != NULL )
2669 {
2670 *buffActSize = buffReqSize;
2671 }
2672 else
2673 {
2674 *buffActSize = 0;
2675 }
2676
2677BadParameter:
2678
2679 return ( tempPtr );
2680}
2681
2682/*****************************************************************************/
2683
2684OSErr
2685FileRefNumGetFSRef(
2686 short refNum,
2687 FSRef *ref)
2688{
2689 return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) );
2690}
2691
2692/*****************************************************************************/
2693
2694OSErr
2695FSSetDefault(
2696 const FSRef *newDefault,
2697 FSRef *oldDefault)
2698{
2699 OSErr result;
2700 FSVolumeRefNum vRefNum;
2701 long dirID;
2702 FSCatalogInfo catalogInfo;
2703
2704 /* check parameters */
2705 require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr);
2706
2707 /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */
2708 result = FSGetCatalogInfo(newDefault,
2709 kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
2710 &catalogInfo, NULL, NULL, NULL);
2711 require_noerr(result, FSGetCatalogInfo);
2712
2713 /* Make sure newDefault is a directory */
2714 require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory,
2715 result = dirNFErr);
2716
2717 /* Get the current working directory. */
2718 result = HGetVol(NULL, &vRefNum, &dirID);
2719 require_noerr(result, HGetVol);
2720
2721 /* Return the oldDefault FSRef */
2722 result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault);
2723 require_noerr(result, FSMakeFSRef);
2724
2725 /* Set the new current working directory */
2726 result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
2727 require_noerr(result, HSetVol);
2728
2729HSetVol:
2730FSMakeFSRef:
2731HGetVol:
2732NewDefaultNotDirectory:
2733FSGetCatalogInfo:
2734BadParameter:
2735
2736 return ( result );
2737}
2738
2739/*****************************************************************************/
2740
2741OSErr
2742FSRestoreDefault(
2743 const FSRef *oldDefault)
2744{
2745 OSErr result;
2746 FSCatalogInfo catalogInfo;
2747
2748 /* check parameters */
2749 require_action(NULL != oldDefault, BadParameter, result = paramErr);
2750
2751 /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */
2752 result = FSGetCatalogInfo(oldDefault,
2753 kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID,
2754 &catalogInfo, NULL, NULL, NULL);
2755 require_noerr(result, FSGetCatalogInfo);
2756
2757 /* Make sure oldDefault is a directory */
2758 require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory,
2759 result = dirNFErr);
2760
2761 /* Set the current working directory to oldDefault */
2762 result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID);
2763 require_noerr(result, HSetVol);
2764
2765HSetVol:
2766OldDefaultNotDirectory:
2767FSGetCatalogInfo:
2768BadParameter:
2769
2770 return ( result );
2771}
2772
2773/*****************************************************************************/
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