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 65enum { 66 gestaltBugFixAttrsTwo = 'bugy', 67 gestaltFSpExchangeFilesCompatibilityFix = 26, 68 gestaltBugFixAttrsThree = 'bugx', 69 gestaltFSpCreateScriptSupportFix = 1 70}; 71 72/*****************************************************************************/ 73 74/* static prototypes */ 75 76 77#if !__MACOSSEVENORLATER 78static Boolean FSHasFSSpecCalls(void); 79 80static Boolean QTHasFSSpecCalls(void); 81#endif /* !__MACOSSEVENORLATER */ 82 83#if !__MACOSSEVENFIVEORLATER 84static Boolean HasFSpExchangeFilesCompatibilityFix(void); 85 86static OSErr GenerateUniqueName(short volume, 87 long *startSeed, 88 long dir1, 89 long dir2, 90 StringPtr uniqueName); 91#endif /* !__MACOSSEVENFIVEORLATER */ 92 93#if !__MACOSSEVENFIVEONEORLATER 94static Boolean HasFSpCreateScriptSupportFix(void); 95#endif /* !__MACOSSEVENFIVEONEORLATER */ 96 97/*****************************************************************************/ 98 99/* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */ 100 101#if !__MACOSSEVENORLATER 102static 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 134static 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 165static 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 199static 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 233pascal 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 268pascal 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 297pascal 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 326pascal 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 381pascal 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 427pascal 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 449pascal 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 476pascal 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 508pascal 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 530pascal 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 552pascal 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 576pascal 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 608static 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 661pascal 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 */ 842errorExit1: 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 */ 850errorExit2: 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 } 857errorExit3: { /* 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 875pascal 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 892pascal 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/*****************************************************************************/ 947