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