~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/xpcom/MoreFiles/MoreFilesX.c.orig

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

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