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