VirtualBox

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

Last change on this file since 4837 was 4481, checked in by vboxsync, 17 years ago

remove Apple disclaimer as permitted by original disclaimer and make it MPL/GPL

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

© 2023 Oracle
ContactPrivacy policyTerms of Use