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