]> git.saurik.com Git - wxWidgets.git/blob - src/mac/morefile/FSpCompa.cpp
Replaced 'erase' with $(RM) so that the default file deletion program can be overriden
[wxWidgets.git] / src / mac / morefile / FSpCompa.cpp
1 /*
2 ** Apple Macintosh Developer Technical Support
3 **
4 ** FSSpec compatibility functions.
5 **
6 ** by Jim Luther, Apple Developer Technical Support Emeritus
7 **
8 ** File: FSpCompat.c
9 **
10 ** Copyright © 1992-1998 Apple Computer, Inc.
11 ** All rights reserved.
12 **
13 ** You may incorporate this sample code into your applications without
14 ** restriction, though the sample code has been provided "AS IS" and the
15 ** responsibility for its operation is 100% yours. However, what you are
16 ** not permitted to do is to redistribute the source as "DSC Sample Code"
17 ** after having made changes. If you're going to re-distribute the source,
18 ** we require that you make it clear in the source that the code was
19 ** descended from Apple Sample Code, but that you've made changes.
20 */
21
22 /*
23 ** If building application 68K code, set GENERATENODATA to 0 for faster code.
24 ** If building stand-alone 68K code, set GENERATENODATA to 1 so globals
25 ** (static variables) are not used.
26 */
27 #ifndef GENERATENODATA
28 #define GENERATENODATA 0
29 #endif
30
31 #include <Types.h>
32 #include <Errors.h>
33 #include <LowMem.h>
34 #include <Gestalt.h>
35 #include <Resources.h>
36 #include <Script.h>
37
38 #define __COMPILINGMOREFILES
39
40 #include "moreextr.h"
41 #include "fspcompa.h"
42
43 /*****************************************************************************/
44
45 /* local constants */
46
47 enum {
48 gestaltBugFixAttrsTwo = 'bugy',
49 gestaltFSpExchangeFilesCompatibilityFix = 26,
50 gestaltBugFixAttrsThree = 'bugx',
51 gestaltFSpCreateScriptSupportFix = 1
52 };
53
54 /*****************************************************************************/
55
56 /* static prototypes */
57
58
59 #if !__MACOSSEVENORLATER
60 static Boolean FSHasFSSpecCalls(void);
61
62 static Boolean QTHasFSSpecCalls(void);
63 #endif /* !__MACOSSEVENORLATER */
64
65 #if !__MACOSSEVENFIVEORLATER
66 static Boolean HasFSpExchangeFilesCompatibilityFix(void);
67
68 static OSErr GenerateUniqueName(short volume,
69 long *startSeed,
70 long dir1,
71 long dir2,
72 StringPtr uniqueName);
73 #endif /* !__MACOSSEVENFIVEORLATER */
74
75 #if !__MACOSSEVENFIVEONEORLATER
76 static Boolean HasFSpCreateScriptSupportFix(void);
77 #endif /* !__MACOSSEVENFIVEONEORLATER */
78
79 /*****************************************************************************/
80
81 /* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
82
83 #if !__MACOSSEVENORLATER
84 static Boolean FSHasFSSpecCalls(void)
85 {
86 long response;
87 #if !GENERATENODATA
88 static Boolean tested = false;
89 static Boolean result = false;
90 #else
91 Boolean result = false;
92 #endif
93
94 #if !GENERATENODATA
95 if ( !tested )
96 {
97 tested = true;
98 #endif
99 if ( Gestalt(gestaltFSAttr, &response) == noErr )
100 {
101 result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
102 }
103 #if !GENERATENODATA
104 }
105 #endif
106 return ( result );
107 }
108 #endif /* !__MACOSSEVENORLATER */
109
110 /*****************************************************************************/
111
112 /* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
113 /* except for FSpExchangeFiles. */
114
115 #if !__MACOSSEVENORLATER
116 static Boolean QTHasFSSpecCalls(void)
117 {
118 long response;
119 #if !GENERATENODATA
120 static Boolean tested = false;
121 static Boolean result = false;
122 #else
123 Boolean result = false;
124 #endif
125
126 #if !GENERATENODATA
127 if ( !tested )
128 {
129 tested = true;
130 #endif
131 result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
132 #if !GENERATENODATA
133 }
134 #endif
135 return ( result );
136 }
137 #endif /* !__MACOSSEVENORLATER */
138
139 /*****************************************************************************/
140
141 /* HasFSpExchangeFilesCompatibilityFix returns true if FSpExchangeFiles */
142 /* compatibility code has been fixed in system software. */
143 /* This was fixed by System Update 3.0, so if SystemSevenFiveOrLater */
144 /* is true, then we know the fix is in. */
145
146 #if !__MACOSSEVENFIVEORLATER
147 static Boolean HasFSpExchangeFilesCompatibilityFix(void)
148 {
149 long response;
150 #if !GENERATENODATA
151 static Boolean tested = false;
152 static Boolean result = false;
153 #else /* !GENERATENODATA */
154 Boolean result = false;
155 #endif /* !GENERATENODATA */
156
157 #if !GENERATENODATA
158 if ( !tested )
159 {
160 tested = true;
161 #endif /* !GENERATENODATA */
162 if ( Gestalt(gestaltBugFixAttrsTwo, &response) == noErr )
163 {
164 result = ((response & (1L << gestaltFSpExchangeFilesCompatibilityFix)) != 0);
165 }
166 #if !GENERATENODATA
167 }
168 #endif /* !GENERATENODATA */
169 return ( result );
170 }
171 #endif /* !__MACOSSEVENFIVEORLATER */
172
173 /*****************************************************************************/
174
175 /* HasFSpCreateScriptSupportFix returns true if FSpCreate and */
176 /* FSpCreateResFile have been fixed in system software to correctly set */
177 /* the scriptCode in the volume's catalog. */
178 /* This was fixed by System 7.5 Update 1.0 */
179
180 #if !__MACOSSEVENFIVEONEORLATER
181 static Boolean HasFSpCreateScriptSupportFix(void)
182 {
183 long response;
184 #if !GENERATENODATA
185 static Boolean tested = false;
186 static Boolean result = false;
187 #else
188 Boolean result = false;
189 #endif /* !GENERATENODATA */
190
191 #if !GENERATENODATA
192 if ( !tested )
193 {
194 tested = true;
195 #endif /* !GENERATENODATA */
196 if ( Gestalt(gestaltBugFixAttrsThree, &response) == noErr )
197 {
198 result = ((response & (1L << gestaltFSpCreateScriptSupportFix)) != 0);
199 }
200 #if !GENERATENODATA
201 }
202 #endif /* !GENERATENODATA */
203 return ( result );
204 }
205 #endif /* !__MACOSSEVENFIVEONEORLATER */
206
207 /*****************************************************************************/
208
209 /*
210 ** File Manager FSp calls
211 */
212
213 /*****************************************************************************/
214
215 pascal OSErr FSMakeFSSpecCompat(short vRefNum,
216 long dirID,
217 ConstStr255Param fileName,
218 FSSpec *spec)
219 {
220 OSErr result;
221
222 #if !__MACOSSEVENORLATER
223 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
224 {
225 Boolean isDirectory;
226
227 result = GetObjectLocation(vRefNum, dirID, fileName,
228 &(spec->vRefNum), &(spec->parID), spec->name,
229 &isDirectory);
230 }
231 else
232 #endif /* !__MACOSSEVENORLATER */
233 {
234 /* Let the file system create the FSSpec if it can since it does the job */
235 /* much more efficiently than I can. */
236 result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
237
238 /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
239 /* returned in the parID field when making an FSSpec to the volume's */
240 /* root directory by passing a full pathname in MakeFSSpec's */
241 /* fileName parameter. Fixed in Mac OS 8.1 */
242 if ( (result == noErr) && (spec->parID == 0) )
243 spec->parID = fsRtParID;
244 }
245 return ( result );
246 }
247
248 /*****************************************************************************/
249
250 pascal OSErr FSpOpenDFCompat(const FSSpec *spec,
251 char permission,
252 short *refNum)
253 {
254 #if !__MACOSSEVENORLATER
255 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
256 {
257 OSErr result;
258 HParamBlockRec pb;
259
260 pb.ioParam.ioVRefNum = spec->vRefNum;
261 pb.fileParam.ioDirID = spec->parID;
262 pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
263 pb.ioParam.ioVersNum = 0;
264 pb.ioParam.ioPermssn = permission;
265 pb.ioParam.ioMisc = NULL;
266 result = PBHOpenSync(&pb); /* OpenDF not supported by System 6, so use Open */
267 *refNum = pb.ioParam.ioRefNum;
268 return ( result );
269 }
270 else
271 #endif /* !__MACOSSEVENORLATER */
272 {
273 return ( FSpOpenDF(spec, permission, refNum) );
274 }
275 }
276
277 /*****************************************************************************/
278
279 pascal OSErr FSpOpenRFCompat(const FSSpec *spec,
280 char permission,
281 short *refNum)
282 {
283 #if !__MACOSSEVENORLATER
284 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
285 {
286 OSErr result;
287 HParamBlockRec pb;
288
289 pb.ioParam.ioVRefNum = spec->vRefNum;
290 pb.fileParam.ioDirID = spec->parID;
291 pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
292 pb.ioParam.ioVersNum = 0;
293 pb.ioParam.ioPermssn = permission;
294 pb.ioParam.ioMisc = NULL;
295 result = PBHOpenRFSync(&pb);
296 *refNum = pb.ioParam.ioRefNum;
297 return ( result );
298 }
299 else
300 #endif /* !__MACOSSEVENORLATER */
301 {
302 return ( FSpOpenRF(spec, permission, refNum) );
303 }
304 }
305
306 /*****************************************************************************/
307
308 pascal OSErr FSpCreateCompat(const FSSpec *spec,
309 OSType creator,
310 OSType fileType,
311 ScriptCode scriptTag)
312 {
313 #if !__MACOSSEVENFIVEONEORLATER
314 OSErr result;
315 UniversalFMPB pb;
316
317
318 if (
319 #if !__MACOSSEVENORLATER
320 (!FSHasFSSpecCalls() && !QTHasFSSpecCalls()) ||
321 #endif /* !__MACOSSEVENORLATER */
322 !HasFSpCreateScriptSupportFix() )
323 {
324 /* If FSpCreate isn't called, this code will be executed */
325 pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
326 pb.hPB.fileParam.ioDirID = spec->parID;
327 pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
328 pb.hPB.fileParam.ioFVersNum = 0;
329 result = PBHCreateSync(&(pb.hPB));
330 if ( result == noErr )
331 {
332 /* get info on created item */
333 pb.ciPB.hFileInfo.ioFDirIndex = 0;
334 result = PBGetCatInfoSync(&(pb.ciPB));
335 if ( result == noErr )
336 {
337 /* Set fdScript in FXInfo */
338 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
339 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
340 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
341 pb.ciPB.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
342 ((char)scriptTag | (char)0x80) :
343 (smRoman);
344 /* Set creator/fileType */
345 pb.ciPB.hFileInfo.ioFlFndrInfo.fdCreator = creator;
346 pb.ciPB.hFileInfo.ioFlFndrInfo.fdType = fileType;
347 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
348 pb.ciPB.hFileInfo.ioDirID = spec->parID;
349 result = PBSetCatInfoSync(&(pb.ciPB));
350 }
351 }
352 return ( result );
353 }
354 else
355 #endif /* !__MACOSSEVENFIVEONEORLATER */
356 {
357 return ( FSpCreate(spec, creator, fileType, scriptTag) );
358 }
359 }
360
361 /*****************************************************************************/
362
363 pascal OSErr FSpDirCreateCompat(const FSSpec *spec,
364 ScriptCode scriptTag,
365 long *createdDirID)
366 {
367 #if !__MACOSSEVENORLATER
368 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
369 {
370 OSErr result;
371 UniversalFMPB pb;
372
373 pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
374 pb.hPB.fileParam.ioDirID = spec->parID;
375 pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
376 result = PBDirCreateSync(&(pb.hPB));
377 *createdDirID = pb.hPB.fileParam.ioDirID;
378 if ( result == noErr )
379 {
380 /* get info on created item */
381 pb.ciPB.dirInfo.ioFDirIndex = 0;
382 pb.ciPB.dirInfo.ioDrDirID = spec->parID;
383 result = PBGetCatInfoSync(&(pb.ciPB));
384 if ( result == noErr )
385 {
386 /* Set frScript in DXInfo */
387 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
388 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
389 /* (smRoman is 0). frScript is valid if high bit is set (see IM-6, page 9-38) */
390 pb.ciPB.dirInfo.ioDrFndrInfo.frScript = (scriptTag >= smRoman) ?
391 ((char)scriptTag | (char)0x80) :
392 (smRoman);
393 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
394 pb.ciPB.dirInfo.ioDrDirID = spec->parID;
395 result = PBSetCatInfoSync(&(pb.ciPB));
396 }
397 }
398 return ( result );
399 }
400 else
401 #endif /* !__MACOSSEVENORLATER */
402 {
403 return ( FSpDirCreate(spec, scriptTag, createdDirID) );
404 }
405 }
406
407 /*****************************************************************************/
408
409 pascal OSErr FSpDeleteCompat(const FSSpec *spec)
410 {
411 #if !__MACOSSEVENORLATER
412 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
413 {
414 HParamBlockRec pb;
415
416 pb.ioParam.ioVRefNum = spec->vRefNum;
417 pb.fileParam.ioDirID = spec->parID;
418 pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
419 pb.ioParam.ioVersNum = 0;
420 return ( PBHDeleteSync(&pb) );
421 }
422 else
423 #endif /* !__MACOSSEVENORLATER */
424 {
425 return ( FSpDelete(spec) );
426 }
427 }
428
429 /*****************************************************************************/
430
431 pascal OSErr FSpGetFInfoCompat(const FSSpec *spec,
432 FInfo *fndrInfo)
433 {
434 #if !__MACOSSEVENORLATER
435 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
436 {
437 OSErr result;
438 HParamBlockRec pb;
439
440 pb.fileParam.ioVRefNum = spec->vRefNum;
441 pb.fileParam.ioDirID = spec->parID;
442 pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
443 pb.fileParam.ioFVersNum = 0;
444 pb.fileParam.ioFDirIndex = 0;
445 result = PBHGetFInfoSync(&pb);
446 *fndrInfo = pb.fileParam.ioFlFndrInfo;
447 return ( result );
448 }
449 else
450 #endif /* !__MACOSSEVENORLATER */
451 {
452 return ( FSpGetFInfo(spec, fndrInfo) );
453 }
454 }
455
456 /*****************************************************************************/
457
458 pascal OSErr FSpSetFInfoCompat(const FSSpec *spec,
459 const FInfo *fndrInfo)
460 {
461 #if !__MACOSSEVENORLATER
462 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
463 {
464 OSErr result;
465 HParamBlockRec pb;
466
467 pb.fileParam.ioVRefNum = spec->vRefNum;
468 pb.fileParam.ioDirID = spec->parID;
469 pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
470 pb.fileParam.ioFVersNum = 0;
471 pb.fileParam.ioFDirIndex = 0;
472 result = PBHGetFInfoSync(&pb);
473 if ( result == noErr )
474 {
475 pb.fileParam.ioFlFndrInfo = *fndrInfo;
476 pb.fileParam.ioDirID = spec->parID;
477 result = PBHSetFInfoSync(&pb);
478 }
479 return ( result );
480 }
481 else
482 #endif /* !__MACOSSEVENORLATER */
483 {
484 return ( FSpSetFInfo(spec, fndrInfo) );
485 }
486 }
487
488 /*****************************************************************************/
489
490 pascal OSErr FSpSetFLockCompat(const FSSpec *spec)
491 {
492 #if !__MACOSSEVENORLATER
493 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
494 {
495 HParamBlockRec pb;
496
497 pb.fileParam.ioVRefNum = spec->vRefNum;
498 pb.fileParam.ioDirID = spec->parID;
499 pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
500 pb.fileParam.ioFVersNum = 0;
501 return ( PBHSetFLockSync(&pb) );
502 }
503 else
504 #endif /* !__MACOSSEVENORLATER */
505 {
506 return ( FSpSetFLock(spec) );
507 }
508 }
509
510 /*****************************************************************************/
511
512 pascal OSErr FSpRstFLockCompat(const FSSpec *spec)
513 {
514 #if !__MACOSSEVENORLATER
515 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
516 {
517 HParamBlockRec pb;
518
519 pb.fileParam.ioVRefNum = spec->vRefNum;
520 pb.fileParam.ioDirID = spec->parID;
521 pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
522 pb.fileParam.ioFVersNum = 0;
523 return ( PBHRstFLockSync(&pb) );
524 }
525 else
526 #endif /* !__MACOSSEVENORLATER */
527 {
528 return ( FSpRstFLock(spec) );
529 }
530 }
531
532 /*****************************************************************************/
533
534 pascal OSErr FSpRenameCompat(const FSSpec *spec,
535 ConstStr255Param newName)
536 {
537 #if !__MACOSSEVENORLATER
538 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
539 {
540 HParamBlockRec pb;
541
542 pb.ioParam.ioVRefNum = spec->vRefNum;
543 pb.fileParam.ioDirID = spec->parID;
544 pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
545 pb.ioParam.ioVersNum = 0;
546 pb.ioParam.ioMisc = (Ptr) newName;
547 return ( PBHRenameSync(&pb) );
548 }
549 else
550 #endif /* !__MACOSSEVENORLATER */
551 {
552 return ( FSpRename(spec, newName) );
553 }
554 }
555
556 /*****************************************************************************/
557
558 pascal OSErr FSpCatMoveCompat(const FSSpec *source,
559 const FSSpec *dest)
560 {
561 #if !__MACOSSEVENORLATER
562 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
563 {
564 CMovePBRec pb;
565
566 /* source and destination volume must be the same */
567 if ( source->vRefNum != dest->vRefNum )
568 return ( paramErr );
569
570 pb.ioNamePtr = (StringPtr) &(source->name);
571 pb.ioVRefNum = source->vRefNum;
572 pb.ioDirID = source->parID;
573 pb.ioNewDirID = dest->parID;
574 pb.ioNewName = (StringPtr) &(dest->name);
575 return ( PBCatMoveSync(&pb) );
576 }
577 else
578 #endif /* !__MACOSSEVENORLATER */
579 {
580 return ( FSpCatMove(source, dest) );
581 }
582 }
583
584 /*****************************************************************************/
585
586 /* GenerateUniqueName generates a name that is unique in both dir1 and dir2 */
587 /* on the specified volume. Ripped off from Feldman's code. */
588
589 #if !__MACOSSEVENFIVEORLATER
590 static OSErr GenerateUniqueName(short volume,
591 long *startSeed,
592 long dir1,
593 long dir2,
594 StringPtr uniqueName)
595 {
596 OSErr error = noErr;
597 long i;
598 CInfoPBRec cinfo;
599 unsigned char hexStr[16];
600
601 for ( i = 0; i < 16; ++i )
602 {
603 if ( i < 10 )
604 {
605 hexStr[i] = 0x30 + i;
606 }
607 else
608 {
609 hexStr[i] = 0x37 + i;
610 }
611 }
612
613 cinfo.hFileInfo.ioVRefNum = volume;
614 cinfo.hFileInfo.ioFDirIndex = 0;
615 cinfo.hFileInfo.ioNamePtr = uniqueName;
616
617 while ( error != fnfErr )
618 {
619 (*startSeed)++;
620 cinfo.hFileInfo.ioNamePtr[0] = 8;
621 for ( i = 1; i <= 8; i++ )
622 {
623 cinfo.hFileInfo.ioNamePtr[i] = hexStr[((*startSeed >> ((8-i)*4)) & 0xf)];
624 }
625 cinfo.hFileInfo.ioDirID = dir1;
626 error = fnfErr;
627 for ( i = 1; i <= 2; i++ )
628 {
629 error = error & PBGetCatInfoSync(&cinfo);
630 cinfo.hFileInfo.ioDirID = dir2;
631 if ( (error != fnfErr) && (error != noErr) )
632 {
633 return ( error );
634 }
635 }
636 }
637 return ( noErr );
638 }
639 #endif /* !__MACOSSEVENFIVEORLATER */
640
641 /*****************************************************************************/
642
643 pascal OSErr FSpExchangeFilesCompat(const FSSpec *source,
644 const FSSpec *dest)
645 {
646 #if !__MACOSSEVENFIVEORLATER
647 if (
648 #if !__MACOSSEVENORLATER
649 !FSHasFSSpecCalls() ||
650 #endif /* !__MACOSSEVENORLATER */
651 !HasFSpExchangeFilesCompatibilityFix() )
652 {
653 HParamBlockRec pb;
654 CInfoPBRec catInfoSource, catInfoDest;
655 OSErr result, result2;
656 Str31 unique1, unique2;
657 StringPtr unique1Ptr, unique2Ptr, swapola;
658 GetVolParmsInfoBuffer volInfo;
659 long theSeed, temp;
660
661 /* Make sure the source and destination are on the same volume */
662 if ( source->vRefNum != dest->vRefNum )
663 {
664 result = diffVolErr;
665 goto errorExit3;
666 }
667
668 /* Try PBExchangeFiles first since it preserves the file ID reference */
669 pb.fidParam.ioNamePtr = (StringPtr) &(source->name);
670 pb.fidParam.ioVRefNum = source->vRefNum;
671 pb.fidParam.ioDestNamePtr = (StringPtr) &(dest->name);
672 pb.fidParam.ioDestDirID = dest->parID;
673 pb.fidParam.ioSrcDirID = source->parID;
674
675 result = PBExchangeFilesSync(&pb);
676
677 /* Note: The compatibility case won't work for files with *Btree control blocks. */
678 /* Right now the only *Btree files are created by the system. */
679 if ( result != noErr )
680 {
681 pb.ioParam.ioNamePtr = NULL;
682 pb.ioParam.ioBuffer = (Ptr) &volInfo;
683 pb.ioParam.ioReqCount = sizeof(volInfo);
684 result2 = PBHGetVolParmsSync(&pb);
685
686 /* continue if volume has no fileID support (or no GetVolParms support) */
687 if ( (result2 == noErr) && hasFileIDs(volInfo) )
688 {
689 goto errorExit3;
690 }
691
692 /* Get the catalog information for each file */
693 /* and make sure both files are *really* files */
694 catInfoSource.hFileInfo.ioVRefNum = source->vRefNum;
695 catInfoSource.hFileInfo.ioFDirIndex = 0;
696 catInfoSource.hFileInfo.ioNamePtr = (StringPtr) &(source->name);
697 catInfoSource.hFileInfo.ioDirID = source->parID;
698 catInfoSource.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
699 result = PBGetCatInfoSync(&catInfoSource);
700 if ( result != noErr )
701 {
702 goto errorExit3;
703 }
704 if ( (catInfoSource.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
705 {
706 result = notAFileErr;
707 goto errorExit3;
708 }
709
710 catInfoDest.hFileInfo.ioVRefNum = dest->vRefNum;
711 catInfoDest.hFileInfo.ioFDirIndex = 0;
712 catInfoDest.hFileInfo.ioNamePtr = (StringPtr) &(dest->name);
713 catInfoDest.hFileInfo.ioDirID = dest->parID;
714 catInfoDest.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
715 result = PBGetCatInfoSync(&catInfoDest);
716 if ( result != noErr )
717 {
718 goto errorExit3;
719 }
720 if ( (catInfoDest.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
721 {
722 result = notAFileErr;
723 goto errorExit3;
724 }
725
726 /* generate 2 filenames that are unique in both directories */
727 theSeed = 0x64666A6C; /* a fine unlikely filename */
728 unique1Ptr = (StringPtr)&unique1;
729 unique2Ptr = (StringPtr)&unique2;
730
731 result = GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique1Ptr);
732 if ( result != noErr )
733 {
734 goto errorExit3;
735 }
736
737 GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique2Ptr);
738 if ( result != noErr )
739 {
740 goto errorExit3;
741 }
742
743 /* rename source to unique1 */
744 pb.fileParam.ioNamePtr = (StringPtr) &(source->name);
745 pb.ioParam.ioMisc = (Ptr) unique1Ptr;
746 pb.ioParam.ioVersNum = 0;
747 result = PBHRenameSync(&pb);
748 if ( result != noErr )
749 {
750 goto errorExit3;
751 }
752
753 /* rename dest to unique2 */
754 pb.ioParam.ioMisc = (Ptr) unique2Ptr;
755 pb.ioParam.ioVersNum = 0;
756 pb.fileParam.ioNamePtr = (StringPtr) &(dest->name);
757 pb.fileParam.ioDirID = dest->parID;
758 result = PBHRenameSync(&pb);
759 if ( result != noErr )
760 {
761 goto errorExit2; /* back out gracefully by renaming unique1 back to source */
762 }
763
764 /* If files are not in same directory, swap their locations */
765 if ( source->parID != dest->parID )
766 {
767 /* move source file to dest directory */
768 pb.copyParam.ioNamePtr = unique1Ptr;
769 pb.copyParam.ioNewName = NULL;
770 pb.copyParam.ioNewDirID = dest->parID;
771 pb.copyParam.ioDirID = source->parID;
772 result = PBCatMoveSync((CMovePBPtr) &pb);
773 if ( result != noErr )
774 {
775 goto errorExit1; /* back out gracefully by renaming both files to original names */
776 }
777
778 /* move dest file to source directory */
779 pb.copyParam.ioNamePtr = unique2Ptr;
780 pb.copyParam.ioNewDirID = source->parID;
781 pb.copyParam.ioDirID = dest->parID;
782 result = PBCatMoveSync((CMovePBPtr) &pb);
783 if ( result != noErr)
784 {
785 /* life is very bad. We'll at least try to move source back */
786 pb.copyParam.ioNamePtr = unique1Ptr;
787 pb.copyParam.ioNewName = NULL;
788 pb.copyParam.ioNewDirID = source->parID;
789 pb.copyParam.ioDirID = dest->parID;
790 (void) PBCatMoveSync((CMovePBPtr) &pb); /* ignore errors */
791 goto errorExit1; /* back out gracefully by renaming both files to original names */
792 }
793 }
794
795 /* Make unique1Ptr point to file in source->parID */
796 /* and unique2Ptr point to file in dest->parID */
797 /* This lets us fall through to the rename code below */
798 swapola = unique1Ptr;
799 unique1Ptr = unique2Ptr;
800 unique2Ptr = swapola;
801
802 /* At this point, the files are in their new locations (if they were moved) */
803 /* Source is named Unique1 (name pointed to by unique2Ptr) and is in dest->parID */
804 /* Dest is named Unique2 (name pointed to by unique1Ptr) and is in source->parID */
805 /* Need to swap attributes except mod date and swap names */
806
807 /* swap the catalog info by re-aiming the CInfoPB's */
808 catInfoSource.hFileInfo.ioNamePtr = unique1Ptr;
809 catInfoDest.hFileInfo.ioNamePtr = unique2Ptr;
810
811 catInfoSource.hFileInfo.ioDirID = source->parID;
812 catInfoDest.hFileInfo.ioDirID = dest->parID;
813
814 /* Swap the original mod dates with each file */
815 temp = catInfoSource.hFileInfo.ioFlMdDat;
816 catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
817 catInfoDest.hFileInfo.ioFlMdDat = temp;
818
819 /* Here's the swap (ignore errors) */
820 (void) PBSetCatInfoSync(&catInfoSource);
821 (void) PBSetCatInfoSync(&catInfoDest);
822
823 /* rename unique2 back to dest */
824 errorExit1:
825 pb.ioParam.ioMisc = (Ptr) &(dest->name);
826 pb.ioParam.ioVersNum = 0;
827 pb.fileParam.ioNamePtr = unique2Ptr;
828 pb.fileParam.ioDirID = dest->parID;
829 (void) PBHRenameSync(&pb); /* ignore errors */
830
831 /* rename unique1 back to source */
832 errorExit2:
833 pb.ioParam.ioMisc = (Ptr) &(source->name);
834 pb.ioParam.ioVersNum = 0;
835 pb.fileParam.ioNamePtr = unique1Ptr;
836 pb.fileParam.ioDirID = source->parID;
837 (void) PBHRenameSync(&pb); /* ignore errors */
838 }
839 errorExit3: { /* null statement */ }
840 return ( result );
841 }
842 else
843 #endif /* !__MACOSSEVENFIVEORLATER */
844 {
845 return ( FSpExchangeFiles(source, dest) );
846 }
847 }
848
849 /*****************************************************************************/
850
851 /*
852 ** Resource Manager FSp calls
853 */
854
855 /*****************************************************************************/
856
857 pascal short FSpOpenResFileCompat(const FSSpec *spec,
858 SignedByte permission)
859 {
860 #if !__MACOSSEVENORLATER
861 if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
862 {
863 return ( HOpenResFile(spec->vRefNum, spec->parID, spec->name, permission) );
864 }
865 else
866 #endif /* !__MACOSSEVENORLATER */
867 {
868 return ( FSpOpenResFile(spec, permission) );
869 }
870 }
871
872 /*****************************************************************************/
873
874 pascal void FSpCreateResFileCompat(const FSSpec *spec,
875 OSType creator,
876 OSType fileType,
877 ScriptCode scriptTag)
878 {
879 #if !__MACOSSEVENFIVEONEORLATER
880 if (
881 #if !__MACOSSEVENORLATER
882 (!FSHasFSSpecCalls() && !QTHasFSSpecCalls()) ||
883 #endif /* !__MACOSSEVENORLATER */
884 !HasFSpCreateScriptSupportFix() )
885 {
886 OSErr result;
887 CInfoPBRec pb;
888
889 HCreateResFile(spec->vRefNum, spec->parID, spec->name);
890 if ( ResError() == noErr )
891 {
892 /* get info on created item */
893 pb.hFileInfo.ioVRefNum = spec->vRefNum;
894 pb.hFileInfo.ioDirID = spec->parID;
895 pb.hFileInfo.ioNamePtr = (StringPtr) &(spec->name);
896 pb.hFileInfo.ioFDirIndex = 0;
897 result = PBGetCatInfoSync(&pb);
898 if ( result == noErr )
899 {
900 /* Set fdScript in FXInfo */
901 /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
902 /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
903 /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
904 pb.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
905 ((char)scriptTag | (char)0x80) :
906 (smRoman);
907 /* Set creator/fileType */
908 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
909 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
910
911 /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
912 pb.hFileInfo.ioDirID = spec->parID;
913 result = PBSetCatInfoSync(&pb);
914 }
915 /* Set ResErr low memory global to result */
916 LMSetResErr(result);
917 }
918 return;
919 }
920 else
921 #endif /* !__MACOSSEVENFIVEONEORLATER */
922 {
923 FSpCreateResFile(spec, creator, fileType, scriptTag);
924 return;
925 }
926 }
927
928 /*****************************************************************************/