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