1/* 2 File: MoreFilesExtras.c 3 4 Contains: A collection of useful high-level File Manager routines 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: Jim Luther 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 [2500429] Changed null output parameters to real variables when 34 calling GetSharedLibrary to prevent crashes with older versions 35 of CFM. Added standard header. Updated names of includes. Added 36 C function implementations of accessors that used to be macros 37 since the generated Pascal headers no longer contain 38 implementations. Updated various other routines to use new 39 calling convention of the accessor functions. 40 <1> 12/06/99 JL MoreFiles 1.5. 41*/ 42 43#include <MacTypes.h> 44#if !TARGET_CARBON 45#include <Traps.h> 46#include <FSM.h> 47#include <Disks.h> 48#else 49#include <HFSVolumes.h> 50#endif 51#include <OSUtils.h> 52#include <MacErrors.h> 53#include <MacMemory.h> 54#include <Files.h> 55#include <Devices.h> 56#include <Finder.h> 57#include <Folders.h> 58#include <Gestalt.h> 59#include <TextUtils.h> 60#include <Script.h> 61#include <Math64.h> 62#include <CodeFragments.h> 63#include <stddef.h> 64 65#define __COMPILINGMOREFILES 66 67#include "MoreFiles.h" 68#include "MoreDesktopMgr.h" 69#include "FSpCompat.h" 70 71#include "MoreFilesExtras.h" 72 73/*****************************************************************************/ 74 75/* Functions to get information out of GetVolParmsInfoBuffer. */ 76 77/* version 1 field getters */ 78 79pascal short GetVolParmsInfoVersion(const GetVolParmsInfoBuffer *volParms) 80{ 81 return ( volParms->vMVersion ); 82} 83 84pascal long GetVolParmsInfoAttrib(const GetVolParmsInfoBuffer *volParms) 85{ 86 return ( volParms->vMAttrib ); 87} 88 89pascal Handle GetVolParmsInfoLocalHand(const GetVolParmsInfoBuffer *volParms) 90{ 91 return ( volParms->vMLocalHand ); 92} 93 94pascal long GetVolParmsInfoServerAdr(const GetVolParmsInfoBuffer *volParms) 95{ 96 return ( volParms->vMServerAdr ); 97} 98 99/* version 2 field getters (assume zero result if version < 2) */ 100 101pascal long GetVolParmsInfoVolumeGrade(const GetVolParmsInfoBuffer *volParms) 102{ 103 return ( (volParms->vMVersion >= 2) ? volParms->vMVolumeGrade : 0 ); 104} 105 106pascal long GetVolParmsInfoForeignPrivID(const GetVolParmsInfoBuffer *volParms) 107{ 108 return ( (volParms->vMVersion >= 2) ? volParms->vMForeignPrivID : 0 ); 109} 110 111/* version 3 field getters (assume zero result if version < 3) */ 112 113pascal long GetVolParmsInfoExtendedAttributes(const GetVolParmsInfoBuffer *volParms) 114{ 115 return ( (volParms->vMVersion >= 3) ? volParms->vMExtendedAttributes : 0 ); 116} 117 118/* attribute bits supported by all versions of GetVolParmsInfoBuffer */ 119 120pascal Boolean isNetworkVolume(const GetVolParmsInfoBuffer *volParms) 121{ 122 return ( volParms->vMServerAdr != 0 ); 123} 124 125pascal Boolean hasLimitFCBs(const GetVolParmsInfoBuffer *volParms) 126{ 127 return ( (volParms->vMAttrib & (1L << bLimitFCBs)) != 0 ); 128} 129 130pascal Boolean hasLocalWList(const GetVolParmsInfoBuffer *volParms) 131{ 132 return ( (volParms->vMAttrib & (1L << bLocalWList)) != 0 ); 133} 134 135pascal Boolean hasNoMiniFndr(const GetVolParmsInfoBuffer *volParms) 136{ 137 return ( (volParms->vMAttrib & (1L << bNoMiniFndr)) != 0 ); 138} 139 140pascal Boolean hasNoVNEdit(const GetVolParmsInfoBuffer *volParms) 141{ 142 return ( (volParms->vMAttrib & (1L << bNoVNEdit)) != 0 ); 143} 144 145pascal Boolean hasNoLclSync(const GetVolParmsInfoBuffer *volParms) 146{ 147 return ( (volParms->vMAttrib & (1L << bNoLclSync)) != 0 ); 148} 149 150pascal Boolean hasTrshOffLine(const GetVolParmsInfoBuffer *volParms) 151{ 152 return ( (volParms->vMAttrib & (1L << bTrshOffLine)) != 0 ); 153} 154 155pascal Boolean hasNoSwitchTo(const GetVolParmsInfoBuffer *volParms) 156{ 157 return ( (volParms->vMAttrib & (1L << bNoSwitchTo)) != 0 ); 158} 159 160pascal Boolean hasNoDeskItems(const GetVolParmsInfoBuffer *volParms) 161{ 162 return ( (volParms->vMAttrib & (1L << bNoDeskItems)) != 0 ); 163} 164 165pascal Boolean hasNoBootBlks(const GetVolParmsInfoBuffer *volParms) 166{ 167 return ( (volParms->vMAttrib & (1L << bNoBootBlks)) != 0 ); 168} 169 170pascal Boolean hasAccessCntl(const GetVolParmsInfoBuffer *volParms) 171{ 172 return ( (volParms->vMAttrib & (1L << bAccessCntl)) != 0 ); 173} 174 175pascal Boolean hasNoSysDir(const GetVolParmsInfoBuffer *volParms) 176{ 177 return ( (volParms->vMAttrib & (1L << bNoSysDir)) != 0 ); 178} 179 180pascal Boolean hasExtFSVol(const GetVolParmsInfoBuffer *volParms) 181{ 182 return ( (volParms->vMAttrib & (1L << bHasExtFSVol)) != 0 ); 183} 184 185pascal Boolean hasOpenDeny(const GetVolParmsInfoBuffer *volParms) 186{ 187 return ( (volParms->vMAttrib & (1L << bHasOpenDeny)) != 0 ); 188} 189 190pascal Boolean hasCopyFile(const GetVolParmsInfoBuffer *volParms) 191{ 192 return ( (volParms->vMAttrib & (1L << bHasCopyFile)) != 0 ); 193} 194 195pascal Boolean hasMoveRename(const GetVolParmsInfoBuffer *volParms) 196{ 197 return ( (volParms->vMAttrib & (1L << bHasMoveRename)) != 0 ); 198} 199 200pascal Boolean hasDesktopMgr(const GetVolParmsInfoBuffer *volParms) 201{ 202 return ( (volParms->vMAttrib & (1L << bHasDesktopMgr)) != 0 ); 203} 204 205pascal Boolean hasShortName(const GetVolParmsInfoBuffer *volParms) 206{ 207 return ( (volParms->vMAttrib & (1L << bHasShortName)) != 0 ); 208} 209 210pascal Boolean hasFolderLock(const GetVolParmsInfoBuffer *volParms) 211{ 212 return ( (volParms->vMAttrib & (1L << bHasFolderLock)) != 0 ); 213} 214 215pascal Boolean hasPersonalAccessPrivileges(const GetVolParmsInfoBuffer *volParms) 216{ 217 return ( (volParms->vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0 ); 218} 219 220pascal Boolean hasUserGroupList(const GetVolParmsInfoBuffer *volParms) 221{ 222 return ( (volParms->vMAttrib & (1L << bHasUserGroupList)) != 0 ); 223} 224 225pascal Boolean hasCatSearch(const GetVolParmsInfoBuffer *volParms) 226{ 227 return ( (volParms->vMAttrib & (1L << bHasCatSearch)) != 0 ); 228} 229 230pascal Boolean hasFileIDs(const GetVolParmsInfoBuffer *volParms) 231{ 232 return ( (volParms->vMAttrib & (1L << bHasFileIDs)) != 0 ); 233} 234 235pascal Boolean hasBTreeMgr(const GetVolParmsInfoBuffer *volParms) 236{ 237 return ( (volParms->vMAttrib & (1L << bHasBTreeMgr)) != 0 ); 238} 239 240pascal Boolean hasBlankAccessPrivileges(const GetVolParmsInfoBuffer *volParms) 241{ 242 return ( (volParms->vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0 ); 243} 244 245pascal Boolean supportsAsyncRequests(const GetVolParmsInfoBuffer *volParms) 246{ 247 return ( (volParms->vMAttrib & (1L << bSupportsAsyncRequests)) != 0 ); 248} 249 250pascal Boolean supportsTrashVolumeCache(const GetVolParmsInfoBuffer *volParms) 251{ 252 return ( (volParms->vMAttrib & (1L << bSupportsTrashVolumeCache)) != 0 ); 253} 254 255/* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */ 256 257pascal Boolean volIsEjectable(const GetVolParmsInfoBuffer *volParms) 258{ 259 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsEjectable)) != 0 ); 260} 261 262pascal Boolean volSupportsHFSPlusAPIs(const GetVolParmsInfoBuffer *volParms) 263{ 264 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsHFSPlusAPIs)) != 0 ); 265} 266 267pascal Boolean volSupportsFSCatalogSearch(const GetVolParmsInfoBuffer *volParms) 268{ 269 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSCatalogSearch)) != 0 ); 270} 271 272pascal Boolean volSupportsFSExchangeObjects(const GetVolParmsInfoBuffer *volParms) 273{ 274 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSExchangeObjects)) != 0 ); 275} 276 277pascal Boolean volSupports2TBFiles(const GetVolParmsInfoBuffer *volParms) 278{ 279 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupports2TBFiles)) != 0 ); 280} 281 282pascal Boolean volSupportsLongNames(const GetVolParmsInfoBuffer *volParms) 283{ 284 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsLongNames)) != 0 ); 285} 286 287pascal Boolean volSupportsMultiScriptNames(const GetVolParmsInfoBuffer *volParms) 288{ 289 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsMultiScriptNames)) != 0 ); 290} 291 292pascal Boolean volSupportsNamedForks(const GetVolParmsInfoBuffer *volParms) 293{ 294 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsNamedForks)) != 0 ); 295} 296 297pascal Boolean volSupportsSubtreeIterators(const GetVolParmsInfoBuffer *volParms) 298{ 299 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSubtreeIterators)) != 0 ); 300} 301 302pascal Boolean volL2PCanMapFileBlocks(const GetVolParmsInfoBuffer *volParms) 303{ 304 return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bL2PCanMapFileBlocks)) != 0 ); 305} 306 307/*****************************************************************************/ 308 309/* Functions for testing ioACUser bits. */ 310 311pascal Boolean userIsOwner(SInt8 ioACUser) 312{ 313 return ( (ioACUser & kioACUserNotOwnerMask) == 0 ); 314} 315 316pascal Boolean userHasFullAccess(SInt8 ioACUser) 317{ 318 return ( (ioACUser & acUserAccessMask) == acUserFull ); 319} 320 321pascal Boolean userHasDropBoxAccess(SInt8 ioACUser) 322{ 323 return ( (ioACUser & acUserAccessMask) == acUserDropBox ); 324} 325 326pascal Boolean userHasBulletinBoard(SInt8 ioACUser) 327{ 328 return ( (ioACUser & acUserAccessMask) == acUserBulletinBoard ); 329} 330 331pascal Boolean userHasNoAccess(SInt8 ioACUser) 332{ 333 return ( (ioACUser & acUserAccessMask) == acUserNone ); 334} 335 336/*****************************************************************************/ 337 338/* local data structures */ 339 340/* The DeleteEnumGlobals structure is used to minimize the amount of 341** stack space used when recursively calling DeleteLevel and to hold 342** global information that might be needed at any time. */ 343 344#if PRAGMA_STRUCT_ALIGN 345 #pragma options align=mac68k 346#endif // PRAGMA_STRUCT_ALIGN 347struct DeleteEnumGlobals 348{ 349 OSErr error; /* temporary holder of results - saves 2 bytes of stack each level */ 350 Str63 itemName; /* the name of the current item */ 351 UniversalFMPB myPB; /* the parameter block used for PBGetCatInfo calls */ 352}; 353#if PRAGMA_STRUCT_ALIGN 354 #pragma options align=reset 355#endif // PRAGMA_STRUCT_ALIGN 356 357typedef struct DeleteEnumGlobals DeleteEnumGlobals; 358typedef DeleteEnumGlobals *DeleteEnumGlobalsPtr; 359 360/*****************************************************************************/ 361 362/* 363** CallPBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync 364** File Manager requests from CFM-based programs. Apple added PBXGetVolInfoSync 365** to InterfaceLib in Mac OS 8.5, so if __MACOSEIGHTFIVEORLATER is defined, 366** CallPBXGetVolInfoSync is defined back to PBXGetVolInfoSync. 367** 368** Non-CFM 68K programs don't needs this glue (and won't get it) because 369** they instead use the inline assembly glue found in the Files.h interface 370** file. 371*/ 372 373#if TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM 374 375 // Carbon builds and 68K builds don't need this glue 376 #define CallPBXGetVolInfoSync PBXGetVolInfoSync 377 378#else // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM 379 380 #if __WANTPASCALELIMINATION 381 #undef pascal 382 #endif // __WANTPASCALELIMINATION 383 384 /* This is exactly like the simple mixed mode glue in InterfaceLib in Mac OS 8.5 and 8.6 */ 385 static pascal OSErr PBXGetVolInfoSyncGlue(XVolumeParamPtr paramBlock) 386 { 387 enum 388 { 389 uppFSDispatchProcInfo = kRegisterBased 390 | REGISTER_RESULT_LOCATION(kRegisterD0) 391 | RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) 392 | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0, SIZE_CODE(sizeof(long))) /* selector */ 393 | REGISTER_ROUTINE_PARAMETER(2, kRegisterD1, SIZE_CODE(sizeof(long))) /* trap word */ 394 | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr))) 395 }; 396 397 static UniversalProcPtr fsDispatchTrapAddress = NULL; 398 399 /* Is this the first time we've been called? */ 400 if ( fsDispatchTrapAddress == NULL ) 401 { 402 /* Yes - Get the trap address of _FSDispatch */ 403 fsDispatchTrapAddress = NGetTrapAddress(_FSDispatch, OSTrap); 404 } 405 return ( CallOSTrapUniversalProc(fsDispatchTrapAddress, 406 uppFSDispatchProcInfo, 407 kFSMXGetVolInfo, 408 _FSDispatch, 409 paramBlock) ); 410 } 411 412 /* 413 ** PBXGetVolInfoSync was added to the File Manager in System software 7.5.2. 414 ** However, PBXGetVolInfoSync wasn't added to InterfaceLib until Mac OS 8.5. 415 ** This wrapper calls PBXGetVolInfoSync if it is found in InterfaceLib; 416 ** otherwise, it calls PBXGetVolInfoSyncGlue. This ensures that your program 417 ** is calling the latest implementation of PBXGetVolInfoSync. 418 */ 419 static pascal OSErr CallPBXGetVolInfoSync(XVolumeParamPtr paramBlock) 420 { 421 typedef pascal OSErr (*PBXGetVolInfoProcPtr) (XVolumeParamPtr paramBlock); 422 423 OSErr result; 424 CFragConnectionID connID; 425 Ptr mainAddr; 426 Str255 errMessage; 427 static PBXGetVolInfoProcPtr PBXGetVolInfoSyncPtr = NULL; 428 429 //* Is this the first time we've been called? */ 430 if ( PBXGetVolInfoSyncPtr == NULL ) 431 { 432 /* Yes - Get our connection ID to InterfaceLib */ 433 result = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kLoadCFrag, &connID, &mainAddr, errMessage); 434 if ( result == noErr ) 435 { 436 /* See if PBXGetVolInfoSync is in InterfaceLib */ 437 if ( FindSymbol(connID, "\pPBXGetVolInfoSync", &(Ptr)PBXGetVolInfoSyncPtr, NULL) != noErr ) 438 { 439 /* Use glue code if symbol isn't found */ 440 PBXGetVolInfoSyncPtr = PBXGetVolInfoSyncGlue; 441 } 442 } 443 } 444 /* Call PBXGetVolInfoSync if present; otherwise, call PBXGetVolInfoSyncGlue */ 445 return ( (*PBXGetVolInfoSyncPtr)(paramBlock) ); 446 } 447 448 #if __WANTPASCALELIMINATION 449 #define pascal 450 #endif // __WANTPASCALELIMINATION 451 452#endif // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM 453 454/*****************************************************************************/ 455 456pascal void TruncPString(StringPtr destination, 457 ConstStr255Param source, 458 short maxLength) 459{ 460 short charType; 461 462 if ( source != NULL && destination != NULL ) /* don't do anything stupid */ 463 { 464 if ( source[0] > maxLength ) 465 { 466 /* Make sure the string isn't truncated in the middle of */ 467 /* a multi-byte character. */ 468 while (maxLength != 0) 469 { 470 // Note: CharacterByteType's textOffset parameter is zero-based from the textPtr parameter 471 charType = CharacterByteType((Ptr)&source[1], maxLength - 1, smSystemScript); 472 if ( (charType == smSingleByte) || (charType == smLastByte) ) 473 break; /* source[maxLength] is now a valid last character */ 474 --maxLength; 475 } 476 } 477 else 478 { 479 maxLength = source[0]; 480 } 481 /* Set the destination string length */ 482 destination[0] = maxLength; 483 /* and copy maxLength characters (if needed) */ 484 if ( source != destination ) 485 { 486 while ( maxLength != 0 ) 487 { 488 destination[maxLength] = source[maxLength]; 489 --maxLength; 490 } 491 } 492 } 493} 494 495/*****************************************************************************/ 496 497static pascal Ptr GetTempBuffer(long buffReqSize, 498 long *buffActSize) 499{ 500 enum 501 { 502 kSlopMemory = 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */ 503 }; 504 Ptr tempPtr; 505 506 /* Make request a multiple of 1024 bytes */ 507 buffReqSize = buffReqSize & 0xfffffc00; 508 509 if ( buffReqSize < 0x00000400 ) 510 { 511 /* Request was smaller than 1024 bytes - make it 1024 */ 512 buffReqSize = 0x00000400; 513 } 514 515 /* Attempt to allocate the memory */ 516 tempPtr = NewPtr(buffReqSize); 517 518 /* If request failed, go to backup plan */ 519 if ( (tempPtr == NULL) && (buffReqSize > 0x00000400) ) 520 { 521 /* 522 ** Try to get largest 1024-byte block available 523 ** leaving some slop for the toolbox if possible 524 */ 525 long freeMemory = (FreeMem() - kSlopMemory) & 0xfffffc00; 526 527 buffReqSize = MaxBlock() & 0xfffffc00; 528 529 if ( buffReqSize > freeMemory ) 530 { 531 buffReqSize = freeMemory; 532 } 533 534 if ( buffReqSize == 0 ) 535 { 536 buffReqSize = 0x00000400; 537 } 538 539 tempPtr = NewPtr(buffReqSize); 540 } 541 542 /* Return bytes allocated */ 543 if ( tempPtr != NULL ) 544 { 545 *buffActSize = buffReqSize; 546 } 547 else 548 { 549 *buffActSize = 0; 550 } 551 552 return ( tempPtr ); 553} 554 555/*****************************************************************************/ 556 557/* 558** GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync 559** in cases where the returned volume name is not needed by the caller. 560** The pathname and vRefNum parameters are not touched, and the pb 561** parameter is initialized by PBHGetVInfoSync except that ioNamePtr in 562** the parameter block is always returned as NULL (since it might point 563** to the local tempPathname). 564** 565** I noticed using this code in several places, so here it is once. 566** This reduces the code size of MoreFiles. 567*/ 568pascal OSErr GetVolumeInfoNoName(ConstStr255Param pathname, 569 short vRefNum, 570 HParmBlkPtr pb) 571{ 572 Str255 tempPathname; 573 OSErr error; 574 575 /* Make sure pb parameter is not NULL */ 576 if ( pb != NULL ) 577 { 578 pb->volumeParam.ioVRefNum = vRefNum; 579 if ( pathname == NULL ) 580 { 581 pb->volumeParam.ioNamePtr = NULL; 582 pb->volumeParam.ioVolIndex = 0; /* use ioVRefNum only */ 583 } 584 else 585 { 586 BlockMoveData(pathname, tempPathname, pathname[0] + 1); /* make a copy of the string and */ 587 pb->volumeParam.ioNamePtr = (StringPtr)tempPathname; /* use the copy so original isn't trashed */ 588 pb->volumeParam.ioVolIndex = -1; /* use ioNamePtr/ioVRefNum combination */ 589 } 590 error = PBHGetVInfoSync(pb); 591 pb->volumeParam.ioNamePtr = NULL; /* ioNamePtr may point to local tempPathname, so don't return it */ 592 } 593 else 594 { 595 error = paramErr; 596 } 597 return ( error ); 598} 599 600/*****************************************************************************/ 601 602/* 603** XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync 604** in cases where the returned volume name is not needed by the caller. 605** The pathname and vRefNum parameters are not touched, and the pb 606** parameter is initialized by PBXGetVolInfoSync except that ioNamePtr in 607** the parameter block is always returned as NULL (since it might point 608** to the local tempPathname). 609*/ 610pascal OSErr XGetVolumeInfoNoName(ConstStr255Param pathname, 611 short vRefNum, 612 XVolumeParamPtr pb) 613{ 614 Str255 tempPathname; 615 OSErr error; 616 617 /* Make sure pb parameter is not NULL */ 618 if ( pb != NULL ) 619 { 620 pb->ioVRefNum = vRefNum; 621 pb->ioXVersion = 0; /* this XVolumeParam version (0) */ 622 if ( pathname == NULL ) 623 { 624 pb->ioNamePtr = NULL; 625 pb->ioVolIndex = 0; /* use ioVRefNum only */ 626 } 627 else 628 { 629 BlockMoveData(pathname, tempPathname, pathname[0] + 1); /* make a copy of the string and */ 630 pb->ioNamePtr = (StringPtr)tempPathname; /* use the copy so original isn't trashed */ 631 pb->ioVolIndex = -1; /* use ioNamePtr/ioVRefNum combination */ 632 } 633 634 { 635#if !TARGET_API_MAC_CARBON 636 long response; 637 638 /* Is PBXGetVolInfo available? */ 639 if ( ( Gestalt(gestaltFSAttr, &response) != noErr ) || ((response & (1L << gestaltFSSupports2TBVols)) == 0) ) 640 { 641 /* No, fall back on PBHGetVInfo */ 642 error = PBHGetVInfoSync((HParmBlkPtr)pb); 643 if ( error == noErr ) 644 { 645 /* calculate the ioVTotalBytes and ioVFreeBytes fields */ 646 pb->ioVTotalBytes = U64Multiply(U64SetU(pb->ioVNmAlBlks), U64SetU(pb->ioVAlBlkSiz)); 647 pb->ioVFreeBytes = U64Multiply(U64SetU(pb->ioVFrBlk), U64SetU(pb->ioVAlBlkSiz)); 648 } 649 } 650 else 651#endif 652 { 653 /* Yes, so use it */ 654 error = CallPBXGetVolInfoSync(pb); 655 } 656 } 657 pb->ioNamePtr = NULL; /* ioNamePtr may point to local tempPathname, so don't return it */ 658 } 659 else 660 { 661 error = paramErr; 662 } 663 return ( error ); 664} 665 666/*****************************************************************************/ 667 668pascal OSErr GetCatInfoNoName(short vRefNum, 669 long dirID, 670 ConstStr255Param name, 671 CInfoPBPtr pb) 672{ 673 Str31 tempName; 674 OSErr error; 675 676 /* Protection against File Sharing problem */ 677 if ( (name == NULL) || (name[0] == 0) ) 678 { 679 tempName[0] = 0; 680 pb->dirInfo.ioNamePtr = tempName; 681 pb->dirInfo.ioFDirIndex = -1; /* use ioDirID */ 682 } 683 else 684 { 685 pb->dirInfo.ioNamePtr = (StringPtr)name; 686 pb->dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ 687 } 688 pb->dirInfo.ioVRefNum = vRefNum; 689 pb->dirInfo.ioDrDirID = dirID; 690 error = PBGetCatInfoSync(pb); 691 pb->dirInfo.ioNamePtr = NULL; 692 return ( error ); 693} 694 695/*****************************************************************************/ 696 697pascal OSErr DetermineVRefNum(ConstStr255Param pathname, 698 short vRefNum, 699 short *realVRefNum) 700{ 701 HParamBlockRec pb; 702 OSErr error; 703 704 error = GetVolumeInfoNoName(pathname,vRefNum, &pb); 705 if ( error == noErr ) 706 { 707 *realVRefNum = pb.volumeParam.ioVRefNum; 708 } 709 return ( error ); 710} 711 712/*****************************************************************************/ 713 714pascal OSErr HGetVInfo(short volReference, 715 StringPtr volName, 716 short *vRefNum, 717 unsigned long *freeBytes, 718 unsigned long *totalBytes) 719{ 720 OSErr result; 721 UInt64 freeBytes64; 722 UInt64 totalBytes64; 723 724 // get the best values possible from XGetVInfo 725 result = XGetVInfo(volReference, volName, vRefNum, &freeBytes64, &totalBytes64); 726 if ( result == noErr ) 727 { 728 // and pin those values if needed 729 if ( (UInt64ToUnsignedWide(freeBytes64)).hi != 0 ) 730 { 731 // pin to maximum 512-byte block aligned value 732 *freeBytes = 0xfffffe00; 733 } 734 else 735 { 736 *freeBytes = U32SetU(freeBytes64); 737 } 738 739 if ( (UInt64ToUnsignedWide(totalBytes64)).hi != 0 ) 740 { 741 // pin to maximum 512-byte block aligned value 742 *totalBytes = 0xfffffe00; 743 } 744 else 745 { 746 *totalBytes = U32SetU(totalBytes64); 747 } 748 } 749 750 return ( result ); 751} 752 753/*****************************************************************************/ 754 755pascal OSErr XGetVInfo(short volReference, 756 StringPtr volName, 757 short *vRefNum, 758 UInt64 *freeBytes, 759 UInt64 *totalBytes) 760{ 761 OSErr result; 762 XVolumeParam pb; 763 764#if !TARGET_API_MAC_CARBON 765 766 long response; 767 768#endif // !TARGET_API_MAC_CARBON 769 770 pb.ioVRefNum = volReference; 771 pb.ioNamePtr = volName; 772 pb.ioXVersion = 0; /* this XVolumeParam version (0) */ 773 pb.ioVolIndex = 0; /* use ioVRefNum only, return volume name */ 774 775#if !TARGET_API_MAC_CARBON 776 777 /* See if large volume support is available */ 778 if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) ) 779 780#endif // !TARGET_API_MAC_CARBON 781 782 { 783 /* Large volume support is available */ 784 result = CallPBXGetVolInfoSync(&pb); 785 if ( result == noErr ) 786 { 787 /* The volume name was returned in volName (if not NULL) and */ 788 /* we have the volume's vRefNum and allocation block size */ 789 *vRefNum = pb.ioVRefNum; 790 791 /* return the freeBytes and totalBytes */ 792 *totalBytes = pb.ioVTotalBytes; 793 *freeBytes = pb.ioVFreeBytes; 794 } 795 } 796 797#if !TARGET_API_MAC_CARBON 798 799 else 800 { 801 /* No large volume support */ 802 /* Use PBHGetVInfoSync to get the results */ 803 result = PBHGetVInfoSync((HParmBlkPtr)&pb); 804 if ( result == noErr ) 805 { 806 VCB *theVCB; 807 808 /* The volume name was returned in volName (if not NULL) and */ 809 /* we have the volume's vRefNum */ 810 *vRefNum = pb.ioVRefNum; 811 812 /* System 7.5 (and beyond) pins the number of allocation blocks and */ 813 /* the number of free allocation blocks returned by PBHGetVInfo to */ 814 /* a value so that when multiplied by the allocation block size, */ 815 /* the volume will look like it has $7fffffff bytes or less. This */ 816 /* was done so older applications that use signed math or that use */ 817 /* the GetVInfo function (which uses signed math) will continue to work. */ 818 /* However, the unpinned numbers (which we want) are always available */ 819 /* in the volume's VCB so we'll get those values from the VCB. */ 820 /* Note: Carbon doesn't support the VCB queue, so this code cannot be */ 821 /* used (and is conditionalized out) by Carbon applications. */ 822 823 /* Find the volume's VCB */ 824 theVCB = (VCB *)(GetVCBQHdr()->qHead); 825 while ( theVCB != NULL ) 826 { 827 if ( theVCB->vcbVRefNum == *vRefNum ) 828 { 829 break; 830 } 831 832 theVCB = (VCB *)(theVCB->qLink); /* next VCB */ 833 } 834 835 if ( theVCB != NULL ) 836 { 837 /* Found a VCB we can use. Get the un-pinned number of allocation blocks */ 838 /* and the number of free blocks from the VCB. */ 839 *freeBytes = U64Multiply(U64SetU((unsigned short)theVCB->vcbFreeBks), U64SetU((unsigned long)pb.ioVAlBlkSiz)); 840 *totalBytes = U64Multiply(U64SetU((unsigned short)theVCB->vcbNmAlBlks), U64SetU((unsigned long)pb.ioVAlBlkSiz)); 841 } 842 else 843 { 844 /* Didn't find a VCB we can use. Return the number of allocation blocks */ 845 /* and the number of free blocks returned by PBHGetVInfoSync. */ 846 *freeBytes = U64Multiply(U64SetU((unsigned short)pb.ioVFrBlk), U64SetU((unsigned long)pb.ioVAlBlkSiz)); 847 *totalBytes = U64Multiply(U64SetU((unsigned short)pb.ioVNmAlBlks), U64SetU((unsigned long)pb.ioVAlBlkSiz)); 848 } 849 850 } 851 } 852 853#endif // !TARGET_API_MAC_CARBON 854 855 return ( result ); 856} 857 858/*****************************************************************************/ 859 860pascal OSErr CheckVolLock(ConstStr255Param pathname, 861 short vRefNum) 862{ 863 HParamBlockRec pb; 864 OSErr error; 865 866 error = GetVolumeInfoNoName(pathname,vRefNum, &pb); 867 if ( error == noErr ) 868 { 869 if ( (pb.volumeParam.ioVAtrb & kHFSVolumeHardwareLockMask) != 0 ) 870 { 871 error = wPrErr; /* volume locked by hardware */ 872 } 873 else if ( (pb.volumeParam.ioVAtrb & kHFSVolumeSoftwareLockMask) != 0 ) 874 { 875 error = vLckdErr; /* volume locked by software */ 876 } 877 } 878 879 return ( error ); 880} 881 882/*****************************************************************************/ 883// 884// The following routines call Mac OS routines that are not supported by 885// Carbon: 886// 887// GetDriverName 888// FindDrive 889// GetDiskBlocks 890// GetVolState 891 892#if !TARGET_API_MAC_CARBON // { 893 894 /*****************************************************************************/ 895 896 pascal OSErr GetDriverName(short driverRefNum, 897 Str255 driverName) 898 { 899 OSErr result; 900 DCtlHandle theDctl; 901 DRVRHeaderPtr dHeaderPtr; 902 903 theDctl = GetDCtlEntry(driverRefNum); 904 if ( theDctl != NULL ) 905 { 906 if ( (**theDctl).dCtlFlags & dRAMBasedMask ) 907 { 908 /* dctlDriver is handle - dereference */ 909 dHeaderPtr = *((DRVRHeaderHandle)(**theDctl).dCtlDriver); 910 } 911 else 912 { 913 /* dctlDriver is pointer */ 914 dHeaderPtr = (DRVRHeaderPtr)(**theDctl).dCtlDriver; 915 } 916 BlockMoveData((*dHeaderPtr).drvrName, driverName, (*dHeaderPtr).drvrName[0] + 1); 917 result = noErr; 918 } 919 else 920 { 921 driverName[0] = 0; 922 result = badUnitErr; /* bad reference number */ 923 } 924 925 return ( result ); 926 } 927 928 /*****************************************************************************/ 929 930 pascal OSErr FindDrive(ConstStr255Param pathname, 931 short vRefNum, 932 DrvQElPtr *driveQElementPtr) 933 { 934 OSErr result; 935 HParamBlockRec hPB; 936 short driveNumber; 937 938 *driveQElementPtr = NULL; 939 940 /* First, use GetVolumeInfoNoName to determine the volume */ 941 result = GetVolumeInfoNoName(pathname, vRefNum, &hPB); 942 if ( result == noErr ) 943 { 944 /* 945 ** The volume can be either online, offline, or ejected. What we find in 946 ** ioVDrvInfo and ioVDRefNum will tell us which it is. 947 ** See Inside Macintosh: Files page 2-80 and the Technical Note 948 ** "FL 34 - VCBs and Drive Numbers : The Real Story" 949 ** Where we get the drive number depends on the state of the volume. 950 */ 951 if ( hPB.volumeParam.ioVDrvInfo != 0 ) 952 { 953 /* The volume is online and not ejected */ 954 /* Get the drive number */ 955 driveNumber = hPB.volumeParam.ioVDrvInfo; 956 } 957 else 958 { 959 /* The volume's is either offline or ejected */ 960 /* in either case, the volume is NOT online */ 961 962 /* Is it ejected or just offline? */ 963 if ( hPB.volumeParam.ioVDRefNum > 0 ) 964 { 965 /* It's ejected, the drive number is ioVDRefNum */ 966 driveNumber = hPB.volumeParam.ioVDRefNum; 967 } 968 else 969 { 970 /* It's offline, the drive number is the negative of ioVDRefNum */ 971 driveNumber = (short)-hPB.volumeParam.ioVDRefNum; 972 } 973 } 974 975 /* Get pointer to first element in drive queue */ 976 *driveQElementPtr = (DrvQElPtr)(GetDrvQHdr()->qHead); 977 978 /* Search for a matching drive number */ 979 while ( (*driveQElementPtr != NULL) && ((*driveQElementPtr)->dQDrive != driveNumber) ) 980 { 981 *driveQElementPtr = (DrvQElPtr)(*driveQElementPtr)->qLink; 982 } 983 984 if ( *driveQElementPtr == NULL ) 985 { 986 /* This should never happen since every volume must have a drive, but... */ 987 result = nsDrvErr; 988 } 989 } 990 991 return ( result ); 992 } 993 994 /*****************************************************************************/ 995 996 pascal OSErr GetDiskBlocks(ConstStr255Param pathname, 997 short vRefNum, 998 unsigned long *numBlocks) 999 { 1000 /* Various constants for GetDiskBlocks() */ 1001 enum 1002 { 1003 /* return format list status code */ 1004 kFmtLstCode = 6, 1005 1006 /* reference number of .SONY driver */ 1007 kSonyRefNum = 0xfffb, 1008 1009 /* values returned by DriveStatus in DrvSts.twoSideFmt */ 1010 kSingleSided = 0, 1011 kDoubleSided = -1, 1012 kSingleSidedSize = 800, /* 400K */ 1013 kDoubleSidedSize = 1600, /* 800K */ 1014 1015 /* values in DrvQEl.qType */ 1016 kWordDrvSiz = 0, 1017 kLongDrvSiz = 1, 1018 1019 /* more than enough formatListRecords */ 1020 kMaxFormatListRecs = 16 1021 }; 1022 1023 DrvQElPtr driveQElementPtr; 1024 unsigned long blocks; 1025 ParamBlockRec pb; 1026 FormatListRec formatListRecords[kMaxFormatListRecs]; 1027 DrvSts status; 1028 short formatListRecIndex; 1029 OSErr result; 1030 1031 blocks = 0; 1032 1033 /* Find the drive queue element for this volume */ 1034 result = FindDrive(pathname, vRefNum, &driveQElementPtr); 1035 1036 /* 1037 ** Make sure this is a real driver (dQRefNum < 0). 1038 ** AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause 1039 ** problems if you try to use it as a driver refNum. 1040 */ 1041 if ( (result == noErr) && (driveQElementPtr->dQRefNum >= 0) ) 1042 { 1043 result = paramErr; 1044 } 1045 else 1046 { 1047 /* Attempt to get the drive's format list. */ 1048 /* (see the Technical Note "What Your Sony Drives For You") */ 1049 1050 pb.cntrlParam.ioVRefNum = driveQElementPtr->dQDrive; 1051 pb.cntrlParam.ioCRefNum = driveQElementPtr->dQRefNum; 1052 pb.cntrlParam.csCode = kFmtLstCode; 1053 pb.cntrlParam.csParam[0] = kMaxFormatListRecs; 1054 *(long *)&pb.cntrlParam.csParam[1] = (long)&formatListRecords[0]; 1055 1056 result = PBStatusSync(&pb); 1057 1058 if ( result == noErr ) 1059 { 1060 /* The drive supports ReturnFormatList status call. */ 1061 1062 /* Get the current disk's size. */ 1063 for( formatListRecIndex = 0; 1064 formatListRecIndex < pb.cntrlParam.csParam[0]; 1065 ++formatListRecIndex ) 1066 { 1067 if ( (formatListRecords[formatListRecIndex].formatFlags & 1068 diCIFmtFlagsCurrentMask) != 0 ) 1069 { 1070 blocks = formatListRecords[formatListRecIndex].volSize; 1071 } 1072 } 1073 if ( blocks == 0 ) 1074 { 1075 /* This should never happen */ 1076 result = paramErr; 1077 } 1078 } 1079 else if ( driveQElementPtr->dQRefNum == (short)kSonyRefNum ) 1080 { 1081 /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */ 1082 1083 result = DriveStatus(driveQElementPtr->dQDrive, &status); 1084 if ( result == noErr ) 1085 { 1086 switch ( status.twoSideFmt ) 1087 { 1088 case kSingleSided: 1089 blocks = kSingleSidedSize; 1090 break; 1091 case kDoubleSided: 1092 blocks = kDoubleSidedSize; 1093 break; 1094 default: 1095 /* This should never happen */ 1096 result = paramErr; 1097 break; 1098 } 1099 } 1100 } 1101 else 1102 { 1103 /* The drive is not a floppy and it doesn't support ReturnFormatList */ 1104 /* so use the dQDrvSz field(s) */ 1105 1106 result = noErr; /* reset result */ 1107 switch ( driveQElementPtr->qType ) 1108 { 1109 case kWordDrvSiz: 1110 blocks = driveQElementPtr->dQDrvSz; 1111 break; 1112 case kLongDrvSiz: 1113 blocks = ((unsigned long)driveQElementPtr->dQDrvSz2 << 16) + 1114 driveQElementPtr->dQDrvSz; 1115 break; 1116 default: 1117 /* This should never happen */ 1118 result = paramErr; 1119 break; 1120 } 1121 } 1122 } 1123 1124 if ( result == noErr ) 1125 { 1126 *numBlocks = blocks; 1127 } 1128 1129 return ( result ); 1130 } 1131 1132 /*****************************************************************************/ 1133 1134 pascal OSErr GetVolState(ConstStr255Param pathname, 1135 short vRefNum, 1136 Boolean *volumeOnline, 1137 Boolean *volumeEjected, 1138 Boolean *driveEjectable, 1139 Boolean *driverWantsEject) 1140 { 1141 HParamBlockRec pb; 1142 short driveNumber; 1143 OSErr error; 1144 1145 error = GetVolumeInfoNoName(pathname,vRefNum, &pb); 1146 if ( error == noErr ) 1147 { 1148 if ( pb.volumeParam.ioVDrvInfo != 0 ) 1149 { 1150 /* the volume is online and not ejected */ 1151 *volumeOnline = true; 1152 *volumeEjected = false; 1153 1154 /* Get the drive number */ 1155 driveNumber = pb.volumeParam.ioVDrvInfo; 1156 } 1157 else 1158 { 1159 /* the volume's is either offline or ejected */ 1160 /* in either case, the volume is NOT online */ 1161 *volumeOnline = false; 1162 1163 /* Is it ejected? */ 1164 *volumeEjected = pb.volumeParam.ioVDRefNum > 0; 1165 1166 if ( *volumeEjected ) 1167 { 1168 /* If ejected, the drive number is ioVDRefNum */ 1169 driveNumber = pb.volumeParam.ioVDRefNum; 1170 } 1171 else 1172 { 1173 /* If offline, the drive number is the negative of ioVDRefNum */ 1174 driveNumber = (short)-pb.volumeParam.ioVDRefNum; 1175 } 1176 } 1177 1178 { 1179 DrvQElPtr drvQElem; 1180 1181 /* Find the drive queue element by searching the drive queue */ 1182 drvQElem = (DrvQElPtr)(GetDrvQHdr()->qHead); 1183 while ( (drvQElem != NULL) && (drvQElem->dQDrive != driveNumber) ) 1184 { 1185 drvQElem = (DrvQElPtr)drvQElem->qLink; 1186 } 1187 1188 if ( drvQElem != NULL ) 1189 { 1190 /* 1191 ** Each drive queue element is preceded by 4 flag bytes. 1192 ** Byte 1 (the second flag byte) has bits that tell us if a 1193 ** drive is ejectable and if its driver wants an eject call. 1194 ** See Inside Macintosh: Files, page 2-85. 1195 */ 1196 { 1197 Ptr flagBytePtr; 1198 1199 /* point to byte 1 of the flag bytes */ 1200 flagBytePtr = (Ptr)drvQElem; 1201 flagBytePtr -= 3; 1202 1203 /* 1204 ** The drive is ejectable if flag byte 1 does not contain 1205 ** 0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call). 1206 */ 1207 1208 *driveEjectable = (*flagBytePtr != 0x08) && (*flagBytePtr != 0x48); 1209 1210 /* 1211 ** The driver wants an eject call if flag byte 1 does not contain 1212 ** 0x08 (nonejectable). This may seem like a minor point, but some 1213 ** disk drivers use the Eject request to flush their caches to disk 1214 ** and you wouldn't want to skip that step after unmounting a volume. 1215 */ 1216 1217 *driverWantsEject = (*flagBytePtr != 0x08); 1218 } 1219 } 1220 else 1221 { 1222 /* Didn't find the drive (this should never happen) */ 1223 *driveEjectable = false; 1224 *driverWantsEject = false; 1225 } 1226 } 1227 } 1228 1229 return ( error ); 1230 } 1231 1232 /*****************************************************************************/ 1233 1234#endif // } !TARGET_API_MAC_CARBON 1235 1236/*****************************************************************************/ 1237 1238pascal OSErr GetVolFileSystemID(ConstStr255Param pathname, 1239 short vRefNum, 1240 short *fileSystemID) 1241{ 1242 HParamBlockRec pb; 1243 OSErr error; 1244 1245 error = GetVolumeInfoNoName(pathname,vRefNum, &pb); 1246 if ( error == noErr ) 1247 { 1248 *fileSystemID = pb.volumeParam.ioVFSID; 1249 } 1250 1251 return ( error ); 1252} 1253 1254/*****************************************************************************/ 1255 1256// 1257// Note: Under Carbon there are no drive numbers, so you cannot call 1258// Eject with a drive number after unmounting a volume. 1259// When a Carbon application calls UnmountVol, CarbonLib will make 1260// sure ejectable media is ejected (leaving ejectable media in the 1261// disk drive makes no sense to Carbon applications). 1262// 1263pascal OSErr UnmountAndEject(ConstStr255Param pathname, 1264 short vRefNum) 1265{ 1266 HParamBlockRec pb; 1267 OSErr error; 1268 1269 error = GetVolumeInfoNoName(pathname, vRefNum, &pb); 1270 if ( error == noErr ) 1271 { 1272 1273#if !TARGET_API_MAC_CARBON 1274 1275 short driveNum; 1276 Boolean ejected, wantsEject; 1277 DrvQElPtr drvQElem; 1278 1279 if ( pb.volumeParam.ioVDrvInfo != 0 ) 1280 { 1281 /* the volume is online and not ejected */ 1282 ejected = false; 1283 1284 /* Get the drive number */ 1285 driveNum = pb.volumeParam.ioVDrvInfo; 1286 } 1287 else 1288 { 1289 /* the volume is ejected or offline */ 1290 1291 /* Is it ejected? */ 1292 ejected = pb.volumeParam.ioVDRefNum > 0; 1293 1294 if ( ejected ) 1295 { 1296 /* If ejected, the drive number is ioVDRefNum */ 1297 driveNum = pb.volumeParam.ioVDRefNum; 1298 } 1299 else 1300 { 1301 /* If offline, the drive number is the negative of ioVDRefNum */ 1302 driveNum = (short)-pb.volumeParam.ioVDRefNum; 1303 } 1304 } 1305 1306 /* find the drive queue element */ 1307 drvQElem = (DrvQElPtr)(GetDrvQHdr()->qHead); 1308 while ( (drvQElem != NULL) && (drvQElem->dQDrive != driveNum) ) 1309 { 1310 drvQElem = (DrvQElPtr)drvQElem->qLink; 1311 } 1312 1313 if ( drvQElem != NULL ) 1314 { 1315 /* does the drive want an eject call */ 1316 wantsEject = (*((Ptr)((Ptr)drvQElem - 3)) != 8); 1317 } 1318 else 1319 { 1320 /* didn't find the drive!! */ 1321 wantsEject = false; 1322 } 1323 1324#endif // !TARGET_API_MAC_CARBON 1325 1326 /* unmount the volume */ 1327 pb.volumeParam.ioNamePtr = NULL; 1328 /* ioVRefNum is already filled in from PBHGetVInfo */ 1329 error = PBUnmountVol((ParmBlkPtr)&pb); 1330 1331#if !TARGET_API_MAC_CARBON 1332 1333 if ( error == noErr ) 1334 { 1335 if ( wantsEject && !ejected ) 1336 { 1337 /* eject the media from the drive if needed */ 1338 pb.volumeParam.ioVRefNum = driveNum; 1339 error = PBEject((ParmBlkPtr)&pb); 1340 } 1341 } 1342 1343#endif // !TARGET_API_MAC_CARBON 1344 1345 } 1346 1347 return ( error ); 1348} 1349 1350/*****************************************************************************/ 1351 1352pascal OSErr OnLine(FSSpecPtr volumes, 1353 short reqVolCount, 1354 short *actVolCount, 1355 short *volIndex) 1356{ 1357 HParamBlockRec pb; 1358 OSErr error = noErr; 1359 FSSpec *endVolArray; 1360 1361 if ( *volIndex > 0 ) 1362 { 1363 *actVolCount = 0; 1364 for ( endVolArray = volumes + reqVolCount; (volumes < endVolArray) && (error == noErr); ++volumes ) 1365 { 1366 pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name; 1367 pb.volumeParam.ioVolIndex = *volIndex; 1368 error = PBHGetVInfoSync(&pb); 1369 if ( error == noErr ) 1370 { 1371 volumes->parID = fsRtParID; /* the root directory's parent is 1 */ 1372 volumes->vRefNum = pb.volumeParam.ioVRefNum; 1373 ++*volIndex; 1374 ++*actVolCount; 1375 } 1376 } 1377 } 1378 else 1379 { 1380 error = paramErr; 1381 } 1382 1383 return ( error ); 1384} 1385 1386/*****************************************************************************/ 1387 1388pascal OSErr SetDefault(short newVRefNum, 1389 long newDirID, 1390 short *oldVRefNum, 1391 long *oldDirID) 1392{ 1393 OSErr error; 1394 1395 /* Get the current default volume/directory. */ 1396 error = HGetVol(NULL, oldVRefNum, oldDirID); 1397 if ( error == noErr ) 1398 { 1399 /* Set the new default volume/directory */ 1400 error = HSetVol(NULL, newVRefNum, newDirID); 1401 } 1402 1403 return ( error ); 1404} 1405 1406/*****************************************************************************/ 1407 1408pascal OSErr RestoreDefault(short oldVRefNum, 1409 long oldDirID) 1410{ 1411 OSErr error; 1412 1413#if !TARGET_API_MAC_CARBON 1414 1415 short defaultVRefNum; 1416 long defaultDirID; 1417 long defaultProcID; 1418 1419 /* Determine if the default volume was a wdRefNum. */ 1420 error = GetWDInfo(oldVRefNum, &defaultVRefNum, &defaultDirID, &defaultProcID); 1421 if ( error == noErr ) 1422 { 1423 /* Restore the old default volume/directory, one way or the other. */ 1424 if ( defaultDirID != fsRtDirID ) 1425 { 1426 /* oldVRefNum was a wdRefNum - use SetVol */ 1427 error = SetVol(NULL, oldVRefNum); 1428 } 1429 else 1430 { 1431 1432#endif // !TARGET_API_MAC_CARBON 1433 1434 /* oldVRefNum was a real vRefNum - use HSetVol */ 1435 error = HSetVol(NULL, oldVRefNum, oldDirID); 1436 1437#if !TARGET_API_MAC_CARBON 1438 1439 } 1440 } 1441#endif // !TARGET_API_MAC_CARBON 1442 1443 return ( error ); 1444} 1445 1446/*****************************************************************************/ 1447 1448pascal OSErr GetDInfo(short vRefNum, 1449 long dirID, 1450 ConstStr255Param name, 1451 DInfo *fndrInfo) 1452{ 1453 CInfoPBRec pb; 1454 OSErr error; 1455 1456 error = GetCatInfoNoName(vRefNum, dirID, name, &pb); 1457 if ( error == noErr ) 1458 { 1459 if ( (pb.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ) 1460 { 1461 /* it's a directory, return the DInfo */ 1462 *fndrInfo = pb.dirInfo.ioDrUsrWds; 1463 } 1464 else 1465 { 1466 /* oops, a file was passed */ 1467 error = dirNFErr; 1468 } 1469 } 1470 1471 return ( error ); 1472} 1473 1474/*****************************************************************************/ 1475 1476pascal OSErr FSpGetDInfo(const FSSpec *spec, 1477 DInfo *fndrInfo) 1478{ 1479 return ( GetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) ); 1480} 1481 1482/*****************************************************************************/ 1483 1484pascal OSErr SetDInfo(short vRefNum, 1485 long dirID, 1486 ConstStr255Param name, 1487 const DInfo *fndrInfo) 1488{ 1489 CInfoPBRec pb; 1490 Str31 tempName; 1491 OSErr error; 1492 1493 /* Protection against File Sharing problem */ 1494 if ( (name == NULL) || (name[0] == 0) ) 1495 { 1496 tempName[0] = 0; 1497 pb.dirInfo.ioNamePtr = tempName; 1498 pb.dirInfo.ioFDirIndex = -1; /* use ioDirID */ 1499 } 1500 else 1501 { 1502 pb.dirInfo.ioNamePtr = (StringPtr)name; 1503 pb.dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ 1504 } 1505 pb.dirInfo.ioVRefNum = vRefNum; 1506 pb.dirInfo.ioDrDirID = dirID; 1507 error = PBGetCatInfoSync(&pb); 1508 if ( error == noErr ) 1509 { 1510 if ( (pb.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ) 1511 { 1512 /* it's a directory, set the DInfo */ 1513 if ( pb.dirInfo.ioNamePtr == tempName ) 1514 { 1515 pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID; 1516 } 1517 else 1518 { 1519 pb.dirInfo.ioDrDirID = dirID; 1520 } 1521 pb.dirInfo.ioDrUsrWds = *fndrInfo; 1522 error = PBSetCatInfoSync(&pb); 1523 } 1524 else 1525 { 1526 /* oops, a file was passed */ 1527 error = dirNFErr; 1528 } 1529 } 1530 1531 return ( error ); 1532} 1533 1534/*****************************************************************************/ 1535 1536pascal OSErr FSpSetDInfo(const FSSpec *spec, 1537 const DInfo *fndrInfo) 1538{ 1539 return ( SetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) ); 1540} 1541 1542/*****************************************************************************/ 1543 1544pascal OSErr GetDirectoryID(short vRefNum, 1545 long dirID, 1546 ConstStr255Param name, 1547 long *theDirID, 1548 Boolean *isDirectory) 1549{ 1550 CInfoPBRec pb; 1551 OSErr error; 1552 1553 error = GetCatInfoNoName(vRefNum, dirID, name, &pb); 1554 if ( error == noErr ) 1555 { 1556 *isDirectory = (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0; 1557 if ( *isDirectory ) 1558 { 1559 *theDirID = pb.dirInfo.ioDrDirID; 1560 } 1561 else 1562 { 1563 *theDirID = pb.hFileInfo.ioFlParID; 1564 } 1565 } 1566 1567 return ( error ); 1568} 1569 1570/*****************************************************************************/ 1571 1572pascal OSErr FSpGetDirectoryID(const FSSpec *spec, 1573 long *theDirID, 1574 Boolean *isDirectory) 1575{ 1576 return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name, 1577 theDirID, isDirectory) ); 1578} 1579 1580/*****************************************************************************/ 1581 1582pascal OSErr GetDirName(short vRefNum, 1583 long dirID, 1584 Str31 name) 1585{ 1586 CInfoPBRec pb; 1587 OSErr error; 1588 1589 if ( name != NULL ) 1590 { 1591 pb.dirInfo.ioNamePtr = name; 1592 pb.dirInfo.ioVRefNum = vRefNum; 1593 pb.dirInfo.ioDrDirID = dirID; 1594 pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */ 1595 error = PBGetCatInfoSync(&pb); 1596 } 1597 else 1598 { 1599 error = paramErr; 1600 } 1601 1602 return ( error ); 1603} 1604 1605/*****************************************************************************/ 1606 1607pascal OSErr GetIOACUser(short vRefNum, 1608 long dirID, 1609 ConstStr255Param name, 1610 SInt8 *ioACUser) 1611{ 1612 CInfoPBRec pb; 1613 OSErr error; 1614 1615 /* Clear ioACUser before calling PBGetCatInfo since some file systems 1616 ** don't bother to set or clear this field. If ioACUser isn't set by the 1617 ** file system, then you'll get the zero value back (full access) which 1618 ** is the access you have on volumes that don't support ioACUser. 1619 */ 1620 pb.dirInfo.ioACUser = 0; /* ioACUser used to be filler2 */ 1621 error = GetCatInfoNoName(vRefNum, dirID, name, &pb); 1622 if ( error == noErr ) 1623 { 1624 if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) == 0 ) 1625 { 1626 /* oops, a file was passed */ 1627 error = dirNFErr; 1628 } 1629 else 1630 { 1631 *ioACUser = pb.dirInfo.ioACUser; 1632 } 1633 } 1634 1635 return ( error ); 1636} 1637 1638/*****************************************************************************/ 1639 1640pascal OSErr FSpGetIOACUser(const FSSpec *spec, 1641 SInt8 *ioACUser) 1642{ 1643 return ( GetIOACUser(spec->vRefNum, spec->parID, spec->name, ioACUser) ); 1644} 1645 1646/*****************************************************************************/ 1647 1648pascal OSErr GetParentID(short vRefNum, 1649 long dirID, 1650 ConstStr255Param name, 1651 long *parID) 1652{ 1653 CInfoPBRec pb; 1654 Str31 tempName; 1655 OSErr error; 1656 short realVRefNum; 1657 1658 /* Protection against File Sharing problem */ 1659 if ( (name == NULL) || (name[0] == 0) ) 1660 { 1661 tempName[0] = 0; 1662 pb.hFileInfo.ioNamePtr = tempName; 1663 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */ 1664 } 1665 else 1666 { 1667 pb.hFileInfo.ioNamePtr = (StringPtr)name; 1668 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ 1669 } 1670 pb.hFileInfo.ioVRefNum = vRefNum; 1671 pb.hFileInfo.ioDirID = dirID; 1672 error = PBGetCatInfoSync(&pb); 1673 if ( error == noErr ) 1674 { 1675 /* 1676 ** There's a bug in HFS where the wrong parent dir ID can be 1677 ** returned if multiple separators are used at the end of a 1678 ** pathname. For example, if the pathname: 1679 ** 'volumeName:System Folder:Extensions::' 1680 ** is passed, the directory ID of the Extensions folder is 1681 ** returned in the ioFlParID field instead of fsRtDirID. Since 1682 ** multiple separators at the end of a pathname always specifies 1683 ** a directory, we only need to work-around cases where the 1684 ** object is a directory and there are multiple separators at 1685 ** the end of the name parameter. 1686 */ 1687 if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ) 1688 { 1689 /* Its a directory */ 1690 1691 /* is there a pathname? */ 1692 if ( pb.hFileInfo.ioNamePtr == name ) 1693 { 1694 /* could it contain multiple separators? */ 1695 if ( name[0] >= 2 ) 1696 { 1697 /* does it contain multiple separators at the end? */ 1698 if ( (name[name[0]] == ':') && (name[name[0] - 1] == ':') ) 1699 { 1700 /* OK, then do the extra stuff to get the correct parID */ 1701 1702 /* Get the real vRefNum (this should not fail) */ 1703 error = DetermineVRefNum(name, vRefNum, &realVRefNum); 1704 if ( error == noErr ) 1705 { 1706 /* we don't need the parent's name, but add protect against File Sharing problem */ 1707 tempName[0] = 0; 1708 pb.dirInfo.ioNamePtr = tempName; 1709 pb.dirInfo.ioVRefNum = realVRefNum; 1710 /* pb.dirInfo.ioDrDirID already contains the */ 1711 /* dirID of the directory object */ 1712 pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */ 1713 error = PBGetCatInfoSync(&pb); 1714 /* now, pb.dirInfo.ioDrParID contains the correct parID */ 1715 } 1716 } 1717 } 1718 } 1719 } 1720 1721 if ( error == noErr ) 1722 { 1723 /* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */ 1724 /* contains the parent ID */ 1725 *parID = pb.hFileInfo.ioFlParID; 1726 } 1727 } 1728 1729 return ( error ); 1730} 1731 1732/*****************************************************************************/ 1733 1734pascal OSErr GetFilenameFromPathname(ConstStr255Param pathname, 1735 Str255 filename) 1736{ 1737 short index; 1738 short nameEnd; 1739 OSErr error; 1740 1741 /* default to no filename */ 1742 filename[0] = 0; 1743 1744 /* check for no pathname */ 1745 if ( pathname != NULL ) 1746 { 1747 /* get string length */ 1748 index = pathname[0]; 1749 1750 /* check for empty string */ 1751 if ( index != 0 ) 1752 { 1753 /* skip over last trailing colon (if any) */ 1754 if ( pathname[index] == ':' ) 1755 { 1756 --index; 1757 } 1758 1759 /* save the end of the string */ 1760 nameEnd = index; 1761 1762 /* if pathname ends with multiple colons, then this pathname refers */ 1763 /* to a directory, not a file */ 1764 if ( pathname[index] != ':' ) 1765 { 1766 /* parse backwards until we find a colon or hit the beginning of the pathname */ 1767 while ( (index != 0) && (pathname[index] != ':') ) 1768 { 1769 --index; 1770 } 1771 1772 /* if we parsed to the beginning of the pathname and the pathname ended */ 1773 /* with a colon, then pathname is a full pathname to a volume, not a file */ 1774 if ( (index != 0) || (pathname[pathname[0]] != ':') ) 1775 { 1776 /* get the filename and return noErr */ 1777 filename[0] = (char)(nameEnd - index); 1778 BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index); 1779 error = noErr; 1780 } 1781 else 1782 { 1783 /* pathname to a volume, not a file */ 1784 error = notAFileErr; 1785 } 1786 } 1787 else 1788 { 1789 /* directory, not a file */ 1790 error = notAFileErr; 1791 } 1792 } 1793 else 1794 { 1795 /* empty string isn't a file */ 1796 error = notAFileErr; 1797 } 1798 } 1799 else 1800 { 1801 /* NULL pathname isn't a file */ 1802 error = notAFileErr; 1803 } 1804 1805 return ( error ); 1806} 1807 1808/*****************************************************************************/ 1809 1810pascal OSErr GetObjectLocation(short vRefNum, 1811 long dirID, 1812 ConstStr255Param pathname, 1813 short *realVRefNum, 1814 long *realParID, 1815 Str255 realName, 1816 Boolean *isDirectory) 1817{ 1818 OSErr error; 1819 CInfoPBRec pb; 1820 Str255 tempPathname; 1821 1822 /* clear results */ 1823 *realVRefNum = 0; 1824 *realParID = 0; 1825 realName[0] = 0; 1826 1827 /* 1828 ** Get the real vRefNum 1829 */ 1830 error = DetermineVRefNum(pathname, vRefNum, realVRefNum); 1831 if ( error == noErr ) 1832 { 1833 /* 1834 ** Determine if the object already exists and if so, 1835 ** get the real parent directory ID if it's a file 1836 */ 1837 1838 /* Protection against File Sharing problem */ 1839 if ( (pathname == NULL) || (pathname[0] == 0) ) 1840 { 1841 tempPathname[0] = 0; 1842 pb.hFileInfo.ioNamePtr = tempPathname; 1843 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */ 1844 } 1845 else 1846 { 1847 pb.hFileInfo.ioNamePtr = (StringPtr)pathname; 1848 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ 1849 } 1850 pb.hFileInfo.ioVRefNum = vRefNum; 1851 pb.hFileInfo.ioDirID = dirID; 1852 error = PBGetCatInfoSync(&pb); 1853 if ( error == noErr ) 1854 { 1855 /* 1856 ** The file system object is present and we have the file's real parID 1857 */ 1858 1859 /* Is it a directory or a file? */ 1860 *isDirectory = (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0; 1861 if ( *isDirectory ) 1862 { 1863 /* 1864 ** It's a directory, get its name and parent dirID, and then we're done 1865 */ 1866 1867 pb.dirInfo.ioNamePtr = realName; 1868 pb.dirInfo.ioVRefNum = *realVRefNum; 1869 /* pb.dirInfo.ioDrDirID already contains the dirID of the directory object */ 1870 pb.dirInfo.ioFDirIndex = -1; /* get information about ioDirID */ 1871 error = PBGetCatInfoSync(&pb); 1872 1873 /* get the parent ID here, because the file system can return the */ 1874 /* wrong parent ID from the last call. */ 1875 *realParID = pb.dirInfo.ioDrParID; 1876 } 1877 else 1878 { 1879 /* 1880 ** It's a file - use the parent directory ID from the last call 1881 ** to GetCatInfoparse, get the file name, and then we're done 1882 */ 1883 *realParID = pb.hFileInfo.ioFlParID; 1884 error = GetFilenameFromPathname(pathname, realName); 1885 } 1886 } 1887 else if ( error == fnfErr ) 1888 { 1889 /* 1890 ** The file system object is not present - see if its parent is present 1891 */ 1892 1893 /* 1894 ** Parse to get the object name from end of pathname 1895 */ 1896 error = GetFilenameFromPathname(pathname, realName); 1897 1898 /* if we can't get the object name from the end, we can't continue */ 1899 if ( error == noErr ) 1900 { 1901 /* 1902 ** What we want now is the pathname minus the object name 1903 ** for example: 1904 ** if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:' 1905 ** if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:' 1906 ** if pathname is ':dir:file' tempPathname becomes ':dir:' 1907 ** if pathname is ':dir:file:' tempPathname becomes ':dir:' 1908 ** if pathname is ':file' tempPathname becomes ':' 1909 ** if pathname is 'file or file:' tempPathname becomes '' 1910 */ 1911 1912 /* get a copy of the pathname */ 1913 BlockMoveData(pathname, tempPathname, pathname[0] + 1); 1914 1915 /* remove the object name */ 1916 tempPathname[0] -= realName[0]; 1917 /* and the trailing colon (if any) */ 1918 if ( pathname[pathname[0]] == ':' ) 1919 { 1920 --tempPathname[0]; 1921 } 1922 1923 /* OK, now get the parent's directory ID */ 1924 1925 /* Protection against File Sharing problem */ 1926 pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname; 1927 if ( tempPathname[0] != 0 ) 1928 { 1929 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ 1930 } 1931 else 1932 { 1933 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */ 1934 } 1935 pb.hFileInfo.ioVRefNum = vRefNum; 1936 pb.hFileInfo.ioDirID = dirID; 1937 error = PBGetCatInfoSync(&pb); 1938 *realParID = pb.dirInfo.ioDrDirID; 1939 1940 *isDirectory = false; /* we don't know what the object is really going to be */ 1941 } 1942 1943 if ( error != noErr ) 1944 { 1945 error = dirNFErr; /* couldn't find parent directory */ 1946 } 1947 else 1948 { 1949 error = fnfErr; /* we found the parent, but not the file */ 1950 } 1951 } 1952 } 1953 1954 return ( error ); 1955} 1956 1957/*****************************************************************************/ 1958 1959pascal OSErr GetDirItems(short vRefNum, 1960 long dirID, 1961 ConstStr255Param name, 1962 Boolean getFiles, 1963 Boolean getDirectories, 1964 FSSpecPtr items, 1965 short reqItemCount, 1966 short *actItemCount, 1967 short *itemIndex) /* start with 1, then use what's returned */ 1968{ 1969 CInfoPBRec pb; 1970 OSErr error; 1971 long theDirID; 1972 Boolean isDirectory; 1973 FSSpec *endItemsArray; 1974 1975 if ( *itemIndex > 0 ) 1976 { 1977 /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */ 1978 /* to this routine, I could rip out calls to DetermineVRefNum and GetDirectoryID and this */ 1979 /* routine would be much faster because of the overhead of DetermineVRefNum and */ 1980 /* GetDirectoryID and because GetDirectoryID blows away the directory index hint the Macintosh */ 1981 /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */ 1982 /* pass a big array of FSSpecs so you can get the directory's contents with few calls */ 1983 /* to this routine. */ 1984 1985 /* get the real volume reference number */ 1986 error = DetermineVRefNum(name, vRefNum, &pb.hFileInfo.ioVRefNum); 1987 if ( error == noErr ) 1988 { 1989 /* and the real directory ID of this directory (and make sure it IS a directory) */ 1990 error = GetDirectoryID(vRefNum, dirID, name, &theDirID, &isDirectory); 1991 if ( error == noErr ) 1992 { 1993 if ( isDirectory ) 1994 { 1995 *actItemCount = 0; 1996 endItemsArray = items + reqItemCount; 1997 while ( (items < endItemsArray) && (error == noErr) ) 1998 { 1999 pb.hFileInfo.ioNamePtr = (StringPtr) &items->name; 2000 pb.hFileInfo.ioDirID = theDirID; 2001 pb.hFileInfo.ioFDirIndex = *itemIndex; 2002 error = PBGetCatInfoSync(&pb); 2003 if ( error == noErr ) 2004 { 2005 items->parID = pb.hFileInfo.ioFlParID; /* return item's parID */ 2006 items->vRefNum = pb.hFileInfo.ioVRefNum; /* return item's vRefNum */ 2007 ++*itemIndex; /* prepare to get next item in directory */ 2008 2009 if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ) 2010 { 2011 if ( getDirectories ) 2012 { 2013 ++*actItemCount; /* keep this item */ 2014 ++items; /* point to next item */ 2015 } 2016 } 2017 else 2018 { 2019 if ( getFiles ) 2020 { 2021 ++*actItemCount; /* keep this item */ 2022 ++items; /* point to next item */ 2023 } 2024 } 2025 } 2026 } 2027 } 2028 else 2029 { 2030 /* it wasn't a directory */ 2031 error = dirNFErr; 2032 } 2033 } 2034 } 2035 } 2036 else 2037 { 2038 /* bad itemIndex */ 2039 error = paramErr; 2040 } 2041 2042 return ( error ); 2043} 2044 2045/*****************************************************************************/ 2046 2047static void DeleteLevel(long dirToDelete, 2048 DeleteEnumGlobalsPtr theGlobals) 2049{ 2050 long savedDir; 2051 2052 do 2053 { 2054 /* prepare to delete directory */ 2055 theGlobals->myPB.ciPB.dirInfo.ioNamePtr = (StringPtr)&theGlobals->itemName; 2056 theGlobals->myPB.ciPB.dirInfo.ioFDirIndex = 1; /* get first item */ 2057 theGlobals->myPB.ciPB.dirInfo.ioDrDirID = dirToDelete; /* in this directory */ 2058 theGlobals->error = PBGetCatInfoSync(&(theGlobals->myPB.ciPB)); 2059 if ( theGlobals->error == noErr ) 2060 { 2061 savedDir = dirToDelete; 2062 /* We have an item. Is it a file or directory? */ 2063 if ( (theGlobals->myPB.ciPB.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ) 2064 { 2065 /* it's a directory */ 2066 savedDir = theGlobals->myPB.ciPB.dirInfo.ioDrDirID; /* save dirID of directory instead */ 2067 DeleteLevel(theGlobals->myPB.ciPB.dirInfo.ioDrDirID, theGlobals); /* Delete its contents */ 2068 theGlobals->myPB.ciPB.dirInfo.ioNamePtr = NULL; /* prepare to delete directory */ 2069 } 2070 if ( theGlobals->error == noErr ) 2071 { 2072 theGlobals->myPB.ciPB.dirInfo.ioDrDirID = savedDir; /* restore dirID */ 2073 theGlobals->myPB.hPB.fileParam.ioFVersNum = 0; /* just in case it's used on an MFS volume... */ 2074 theGlobals->error = PBHDeleteSync(&(theGlobals->myPB.hPB)); /* delete this item */ 2075 if ( theGlobals->error == fLckdErr ) 2076 { 2077 (void) PBHRstFLockSync(&(theGlobals->myPB.hPB)); /* unlock it */ 2078 theGlobals->error = PBHDeleteSync(&(theGlobals->myPB.hPB)); /* and try again */ 2079 } 2080 } 2081 } 2082 } while ( theGlobals->error == noErr ); 2083 2084 if ( theGlobals->error == fnfErr ) 2085 { 2086 theGlobals->error = noErr; 2087 } 2088} 2089 2090/*****************************************************************************/ 2091 2092pascal OSErr DeleteDirectoryContents(short vRefNum, 2093 long dirID, 2094 ConstStr255Param name) 2095{ 2096 DeleteEnumGlobals theGlobals; 2097 Boolean isDirectory; 2098 OSErr error; 2099 2100 /* Get the real dirID and make sure it is a directory. */ 2101 error = GetDirectoryID(vRefNum, dirID, name, &dirID, &isDirectory); 2102 if ( error == noErr ) 2103 { 2104 if ( isDirectory ) 2105 { 2106 /* Get the real vRefNum */ 2107 error = DetermineVRefNum(name, vRefNum, &vRefNum); 2108 if ( error == noErr ) 2109 { 2110 /* Set up the globals we need to access from the recursive routine. */ 2111 theGlobals.myPB.ciPB.dirInfo.ioVRefNum = vRefNum; 2112 2113 /* Here we go into recursion land... */ 2114 DeleteLevel(dirID, &theGlobals); 2115 error = theGlobals.error; 2116 } 2117 } 2118 else 2119 { 2120 error = dirNFErr; 2121 } 2122 } 2123 2124 return ( error ); 2125} 2126 2127/*****************************************************************************/ 2128 2129pascal OSErr DeleteDirectory(short vRefNum, 2130 long dirID, 2131 ConstStr255Param name) 2132{ 2133 OSErr error; 2134 2135 /* Make sure a directory was specified and then delete its contents */ 2136 error = DeleteDirectoryContents(vRefNum, dirID, name); 2137 if ( error == noErr ) 2138 { 2139 error = HDelete(vRefNum, dirID, name); 2140 if ( error == fLckdErr ) 2141 { 2142 (void) HRstFLock(vRefNum, dirID, name); /* unlock the directory locked by AppleShare */ 2143 error = HDelete(vRefNum, dirID, name); /* and try again */ 2144 } 2145 } 2146 2147 return ( error ); 2148} 2149 2150/*****************************************************************************/ 2151 2152pascal OSErr CheckObjectLock(short vRefNum, 2153 long dirID, 2154 ConstStr255Param name) 2155{ 2156 CInfoPBRec pb; 2157 OSErr error; 2158 2159 error = GetCatInfoNoName(vRefNum, dirID, name, &pb); 2160 if ( error == noErr ) 2161 { 2162 /* check locked bit */ 2163 if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribLockedMask) != 0 ) 2164 { 2165 error = fLckdErr; 2166 } 2167 } 2168 2169 return ( error ); 2170} 2171 2172/*****************************************************************************/ 2173 2174pascal OSErr FSpCheckObjectLock(const FSSpec *spec) 2175{ 2176 return ( CheckObjectLock(spec->vRefNum, spec->parID, spec->name) ); 2177} 2178 2179/*****************************************************************************/ 2180 2181pascal OSErr GetFileSize(short vRefNum, 2182 long dirID, 2183 ConstStr255Param fileName, 2184 long *dataSize, 2185 long *rsrcSize) 2186{ 2187 HParamBlockRec pb; 2188 OSErr error; 2189 2190 pb.fileParam.ioNamePtr = (StringPtr)fileName; 2191 pb.fileParam.ioVRefNum = vRefNum; 2192 pb.fileParam.ioFVersNum = 0; 2193 pb.fileParam.ioDirID = dirID; 2194 pb.fileParam.ioFDirIndex = 0; 2195 error = PBHGetFInfoSync(&pb); 2196 if ( error == noErr ) 2197 { 2198 *dataSize = pb.fileParam.ioFlLgLen; 2199 *rsrcSize = pb.fileParam.ioFlRLgLen; 2200 } 2201 2202 return ( error ); 2203} 2204 2205/*****************************************************************************/ 2206 2207pascal OSErr FSpGetFileSize(const FSSpec *spec, 2208 long *dataSize, 2209 long *rsrcSize) 2210{ 2211 return ( GetFileSize(spec->vRefNum, spec->parID, spec->name, dataSize, rsrcSize) ); 2212} 2213 2214/*****************************************************************************/ 2215 2216pascal OSErr BumpDate(short vRefNum, 2217 long dirID, 2218 ConstStr255Param name) 2219/* Given a file or directory, change its modification date to the current date/time. */ 2220{ 2221 CInfoPBRec pb; 2222 Str31 tempName; 2223 OSErr error; 2224 unsigned long secs; 2225 2226 /* Protection against File Sharing problem */ 2227 if ( (name == NULL) || (name[0] == 0) ) 2228 { 2229 tempName[0] = 0; 2230 pb.hFileInfo.ioNamePtr = tempName; 2231 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */ 2232 } 2233 else 2234 { 2235 pb.hFileInfo.ioNamePtr = (StringPtr)name; 2236 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ 2237 } 2238 pb.hFileInfo.ioVRefNum = vRefNum; 2239 pb.hFileInfo.ioDirID = dirID; 2240 error = PBGetCatInfoSync(&pb); 2241 if ( error == noErr ) 2242 { 2243 GetDateTime(&secs); 2244 /* set mod date to current date, or one second into the future 2245 if mod date = current date */ 2246 pb.hFileInfo.ioFlMdDat = (secs == pb.hFileInfo.ioFlMdDat) ? (++secs) : (secs); 2247 if ( pb.dirInfo.ioNamePtr == tempName ) 2248 { 2249 pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID; 2250 } 2251 else 2252 { 2253 pb.hFileInfo.ioDirID = dirID; 2254 } 2255 error = PBSetCatInfoSync(&pb); 2256 } 2257 2258 return ( error ); 2259} 2260 2261/*****************************************************************************/ 2262 2263pascal OSErr FSpBumpDate(const FSSpec *spec) 2264{ 2265 return ( BumpDate(spec->vRefNum, spec->parID, spec->name) ); 2266} 2267 2268/*****************************************************************************/ 2269 2270pascal OSErr ChangeCreatorType(short vRefNum, 2271 long dirID, 2272 ConstStr255Param name, 2273 OSType creator, 2274 OSType fileType) 2275{ 2276 CInfoPBRec pb; 2277 OSErr error; 2278 short realVRefNum; 2279 long parID; 2280 2281 pb.hFileInfo.ioNamePtr = (StringPtr)name; 2282 pb.hFileInfo.ioVRefNum = vRefNum; 2283 pb.hFileInfo.ioDirID = dirID; 2284 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ 2285 error = PBGetCatInfoSync(&pb); 2286 if ( error == noErr ) 2287 { 2288 if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) == 0 ) /* if file */ 2289 { 2290 parID = pb.hFileInfo.ioFlParID; /* save parent dirID for BumpDate call */ 2291 2292 /* If creator not 0x00000000, change creator */ 2293 if ( creator != (OSType)0x00000000 ) 2294 { 2295 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator; 2296 } 2297 2298 /* If fileType not 0x00000000, change fileType */ 2299 if ( fileType != (OSType)0x00000000 ) 2300 { 2301 pb.hFileInfo.ioFlFndrInfo.fdType = fileType; 2302 } 2303 2304 pb.hFileInfo.ioDirID = dirID; 2305 error = PBSetCatInfoSync(&pb); /* now, save the new information back to disk */ 2306 2307 if ( (error == noErr) && (parID != fsRtParID) ) /* can't bump fsRtParID */ 2308 { 2309 /* get the real vRefNum in case a full pathname was passed */ 2310 error = DetermineVRefNum(name, vRefNum, &realVRefNum); 2311 if ( error == noErr ) 2312 { 2313 error = BumpDate(realVRefNum, parID, NULL); 2314 /* and bump the parent directory's mod date to wake up the Finder */ 2315 /* to the change we just made */ 2316 } 2317 } 2318 } 2319 else 2320 { 2321 /* it was a directory, not a file */ 2322 error = notAFileErr; 2323 } 2324 } 2325 2326 return ( error ); 2327} 2328 2329/*****************************************************************************/ 2330 2331pascal OSErr FSpChangeCreatorType(const FSSpec *spec, 2332 OSType creator, 2333 OSType fileType) 2334{ 2335 return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name, creator, fileType) ); 2336} 2337 2338/*****************************************************************************/ 2339 2340pascal OSErr ChangeFDFlags(short vRefNum, 2341 long dirID, 2342 ConstStr255Param name, 2343 Boolean setBits, 2344 unsigned short flagBits) 2345{ 2346 CInfoPBRec pb; 2347 Str31 tempName; 2348 OSErr error; 2349 short realVRefNum; 2350 long parID; 2351 2352 /* Protection against File Sharing problem */ 2353 if ( (name == NULL) || (name[0] == 0) ) 2354 { 2355 tempName[0] = 0; 2356 pb.hFileInfo.ioNamePtr = tempName; 2357 pb.hFileInfo.ioFDirIndex = -1; /* use ioDirID */ 2358 } 2359 else 2360 { 2361 pb.hFileInfo.ioNamePtr = (StringPtr)name; 2362 pb.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ 2363 } 2364 pb.hFileInfo.ioVRefNum = vRefNum; 2365 pb.hFileInfo.ioDirID = dirID; 2366 error = PBGetCatInfoSync(&pb); 2367 if ( error == noErr ) 2368 { 2369 parID = pb.hFileInfo.ioFlParID; /* save parent dirID for BumpDate call */ 2370 2371 /* set or clear the appropriate bits in the Finder flags */ 2372 if ( setBits ) 2373 { 2374 /* OR in the bits */ 2375 pb.hFileInfo.ioFlFndrInfo.fdFlags |= flagBits; 2376 } 2377 else 2378 { 2379 /* AND out the bits */ 2380 pb.hFileInfo.ioFlFndrInfo.fdFlags &= ~flagBits; 2381 } 2382 2383 if ( pb.dirInfo.ioNamePtr == tempName ) 2384 { 2385 pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID; 2386 } 2387 else 2388 { 2389 pb.hFileInfo.ioDirID = dirID; 2390 } 2391 2392 error = PBSetCatInfoSync(&pb); /* now, save the new information back to disk */ 2393 2394 if ( (error == noErr) && (parID != fsRtParID) ) /* can't bump fsRtParID */ 2395 { 2396 /* get the real vRefNum in case a full pathname was passed */ 2397 error = DetermineVRefNum(name, vRefNum, &realVRefNum); 2398 if ( error == noErr ) 2399 { 2400 error = BumpDate(realVRefNum, parID, NULL); 2401 /* and bump the parent directory's mod date to wake up the Finder */ 2402 /* to the change we just made */ 2403 } 2404 } 2405 } 2406 2407 return ( error ); 2408} 2409 2410/*****************************************************************************/ 2411 2412pascal OSErr FSpChangeFDFlags(const FSSpec *spec, 2413 Boolean setBits, 2414 unsigned short flagBits) 2415{ 2416 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, setBits, flagBits) ); 2417} 2418 2419/*****************************************************************************/ 2420 2421pascal OSErr SetIsInvisible(short vRefNum, 2422 long dirID, 2423 ConstStr255Param name) 2424 /* Given a file or directory, make it invisible. */ 2425{ 2426 return ( ChangeFDFlags(vRefNum, dirID, name, true, kIsInvisible) ); 2427} 2428 2429/*****************************************************************************/ 2430 2431pascal OSErr FSpSetIsInvisible(const FSSpec *spec) 2432 /* Given a file or directory, make it invisible. */ 2433{ 2434 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kIsInvisible) ); 2435} 2436 2437/*****************************************************************************/ 2438 2439pascal OSErr ClearIsInvisible(short vRefNum, 2440 long dirID, 2441 ConstStr255Param name) 2442 /* Given a file or directory, make it visible. */ 2443{ 2444 return ( ChangeFDFlags(vRefNum, dirID, name, false, kIsInvisible) ); 2445} 2446 2447/*****************************************************************************/ 2448 2449pascal OSErr FSpClearIsInvisible(const FSSpec *spec) 2450 /* Given a file or directory, make it visible. */ 2451{ 2452 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kIsInvisible) ); 2453} 2454 2455/*****************************************************************************/ 2456 2457pascal OSErr SetNameLocked(short vRefNum, 2458 long dirID, 2459 ConstStr255Param name) 2460 /* Given a file or directory, lock its name. */ 2461{ 2462 return ( ChangeFDFlags(vRefNum, dirID, name, true, kNameLocked) ); 2463} 2464 2465/*****************************************************************************/ 2466 2467pascal OSErr FSpSetNameLocked(const FSSpec *spec) 2468 /* Given a file or directory, lock its name. */ 2469{ 2470 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kNameLocked) ); 2471} 2472 2473/*****************************************************************************/ 2474 2475pascal OSErr ClearNameLocked(short vRefNum, 2476 long dirID, 2477 ConstStr255Param name) 2478 /* Given a file or directory, unlock its name. */ 2479{ 2480 return ( ChangeFDFlags(vRefNum, dirID, name, false, kNameLocked) ); 2481} 2482 2483/*****************************************************************************/ 2484 2485pascal OSErr FSpClearNameLocked(const FSSpec *spec) 2486 /* Given a file or directory, unlock its name. */ 2487{ 2488 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kNameLocked) ); 2489} 2490 2491/*****************************************************************************/ 2492 2493pascal OSErr SetIsStationery(short vRefNum, 2494 long dirID, 2495 ConstStr255Param name) 2496 /* Given a file, make it a stationery pad. */ 2497{ 2498 return ( ChangeFDFlags(vRefNum, dirID, name, true, kIsStationery) ); 2499} 2500 2501/*****************************************************************************/ 2502 2503pascal OSErr FSpSetIsStationery(const FSSpec *spec) 2504 /* Given a file, make it a stationery pad. */ 2505{ 2506 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kIsStationery) ); 2507} 2508 2509/*****************************************************************************/ 2510 2511pascal OSErr ClearIsStationery(short vRefNum, 2512 long dirID, 2513 ConstStr255Param name) 2514 /* Given a file, clear the stationery bit. */ 2515{ 2516 return ( ChangeFDFlags(vRefNum, dirID, name, false, kIsStationery) ); 2517} 2518 2519/*****************************************************************************/ 2520 2521pascal OSErr FSpClearIsStationery(const FSSpec *spec) 2522 /* Given a file, clear the stationery bit. */ 2523{ 2524 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kIsStationery) ); 2525} 2526 2527/*****************************************************************************/ 2528 2529pascal OSErr SetHasCustomIcon(short vRefNum, 2530 long dirID, 2531 ConstStr255Param name) 2532 /* Given a file or directory, indicate that it has a custom icon. */ 2533{ 2534 return ( ChangeFDFlags(vRefNum, dirID, name, true, kHasCustomIcon) ); 2535} 2536 2537/*****************************************************************************/ 2538 2539pascal OSErr FSpSetHasCustomIcon(const FSSpec *spec) 2540 /* Given a file or directory, indicate that it has a custom icon. */ 2541{ 2542 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kHasCustomIcon) ); 2543} 2544 2545/*****************************************************************************/ 2546 2547pascal OSErr ClearHasCustomIcon(short vRefNum, 2548 long dirID, 2549 ConstStr255Param name) 2550 /* Given a file or directory, indicate that it does not have a custom icon. */ 2551{ 2552 return ( ChangeFDFlags(vRefNum, dirID, name, false, kHasCustomIcon) ); 2553} 2554 2555/*****************************************************************************/ 2556 2557pascal OSErr FSpClearHasCustomIcon(const FSSpec *spec) 2558 /* Given a file or directory, indicate that it does not have a custom icon. */ 2559{ 2560 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kHasCustomIcon) ); 2561} 2562 2563/*****************************************************************************/ 2564 2565pascal OSErr ClearHasBeenInited(short vRefNum, 2566 long dirID, 2567 ConstStr255Param name) 2568 /* Given a file, clear its "has been inited" bit. */ 2569{ 2570 return ( ChangeFDFlags(vRefNum, dirID, name, false, kHasBeenInited) ); 2571} 2572 2573/*****************************************************************************/ 2574 2575pascal OSErr FSpClearHasBeenInited(const FSSpec *spec) 2576 /* Given a file, clear its "has been inited" bit. */ 2577{ 2578 return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kHasBeenInited) ); 2579} 2580 2581/*****************************************************************************/ 2582 2583pascal OSErr CopyFileMgrAttributes(short srcVRefNum, 2584 long srcDirID, 2585 ConstStr255Param srcName, 2586 short dstVRefNum, 2587 long dstDirID, 2588 ConstStr255Param dstName, 2589 Boolean copyLockBit) 2590{ 2591 UniversalFMPB pb; 2592 Str31 tempName; 2593 OSErr error; 2594 Boolean objectIsDirectory; 2595 2596 pb.ciPB.hFileInfo.ioVRefNum = srcVRefNum; 2597 pb.ciPB.hFileInfo.ioDirID = srcDirID; 2598 2599 /* Protection against File Sharing problem */ 2600 if ( (srcName == NULL) || (srcName[0] == 0) ) 2601 { 2602 tempName[0] = 0; 2603 pb.ciPB.hFileInfo.ioNamePtr = tempName; 2604 pb.ciPB.hFileInfo.ioFDirIndex = -1; /* use ioDirID */ 2605 } 2606 else 2607 { 2608 pb.ciPB.hFileInfo.ioNamePtr = (StringPtr)srcName; 2609 pb.ciPB.hFileInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */ 2610 } 2611 error = PBGetCatInfoSync(&pb.ciPB); 2612 if ( error == noErr ) 2613 { 2614 objectIsDirectory = ( (pb.ciPB.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ); 2615 pb.ciPB.hFileInfo.ioVRefNum = dstVRefNum; 2616 pb.ciPB.hFileInfo.ioDirID = dstDirID; 2617 if ( (dstName != NULL) && (dstName[0] == 0) ) 2618 { 2619 pb.ciPB.hFileInfo.ioNamePtr = NULL; 2620 } 2621 else 2622 { 2623 pb.ciPB.hFileInfo.ioNamePtr = (StringPtr)dstName; 2624 } 2625 /* don't copy the hasBeenInited bit */ 2626 pb.ciPB.hFileInfo.ioFlFndrInfo.fdFlags = ( pb.ciPB.hFileInfo.ioFlFndrInfo.fdFlags & ~kHasBeenInited ); 2627 error = PBSetCatInfoSync(&pb.ciPB); 2628 if ( (error == noErr) && (copyLockBit) && ((pb.ciPB.hFileInfo.ioFlAttrib & kioFlAttribLockedMask) != 0) ) 2629 { 2630 pb.hPB.fileParam.ioFVersNum = 0; 2631 error = PBHSetFLockSync(&pb.hPB); 2632 if ( (error != noErr) && (objectIsDirectory) ) 2633 { 2634 error = noErr; /* ignore lock errors if destination is directory */ 2635 } 2636 } 2637 } 2638 return ( error ); 2639} 2640 2641/*****************************************************************************/ 2642 2643pascal OSErr FSpCopyFileMgrAttributes(const FSSpec *srcSpec, 2644 const FSSpec *dstSpec, 2645 Boolean copyLockBit) 2646{ 2647 return ( CopyFileMgrAttributes(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, 2648 dstSpec->vRefNum, dstSpec->parID, dstSpec->name, 2649 copyLockBit) ); 2650} 2651 2652/*****************************************************************************/ 2653 2654pascal OSErr HOpenAware(short vRefNum, 2655 long dirID, 2656 ConstStr255Param fileName, 2657 short denyModes, 2658 short *refNum) 2659{ 2660 HParamBlockRec pb; 2661 OSErr error; 2662 GetVolParmsInfoBuffer volParmsInfo; 2663 long infoSize = sizeof(GetVolParmsInfoBuffer); 2664 2665 pb.ioParam.ioMisc = NULL; 2666 pb.fileParam.ioFVersNum = 0; 2667 pb.fileParam.ioNamePtr = (StringPtr)fileName; 2668 pb.fileParam.ioVRefNum = vRefNum; 2669 pb.fileParam.ioDirID = dirID; 2670 2671 /* get volume attributes */ 2672 /* this preflighting is needed because Foreign File Access based file systems don't */ 2673 /* return the correct error result to the OpenDeny call */ 2674 error = HGetVolParms(fileName, vRefNum, &volParmsInfo, &infoSize); 2675 if ( (error == noErr) && hasOpenDeny(&volParmsInfo) ) 2676 { 2677 /* if volume supports OpenDeny, use it and return */ 2678 pb.accessParam.ioDenyModes = denyModes; 2679 error = PBHOpenDenySync(&pb); 2680 *refNum = pb.ioParam.ioRefNum; 2681 } 2682 else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 2683 { 2684 /* OpenDeny isn't supported, so try File Manager Open functions */ 2685 2686 /* If request includes write permission, then see if the volume is */ 2687 /* locked by hardware or software. The HFS file system doesn't check */ 2688 /* for this when a file is opened - you only find out later when you */ 2689 /* try to write and the write fails with a wPrErr or a vLckdErr. */ 2690 2691 if ( (denyModes & dmWr) != 0 ) 2692 { 2693 error = CheckVolLock(fileName, vRefNum); 2694 } 2695 else 2696 { 2697 error = noErr; 2698 } 2699 2700 if ( error == noErr ) 2701 { 2702 /* Set File Manager permissions to closest thing possible */ 2703 if ( (denyModes == dmWr) || (denyModes == dmRdWr) ) 2704 { 2705 pb.ioParam.ioPermssn = fsRdWrShPerm; 2706 } 2707 else 2708 { 2709 pb.ioParam.ioPermssn = denyModes % 4; 2710 } 2711 2712 error = PBHOpenDFSync(&pb); /* Try OpenDF */ 2713 if ( error == paramErr ) 2714 { 2715 error = PBHOpenSync(&pb); /* OpenDF not supported, so try Open */ 2716 } 2717 *refNum = pb.ioParam.ioRefNum; 2718 } 2719 } 2720 2721 return ( error ); 2722} 2723 2724/*****************************************************************************/ 2725 2726pascal OSErr FSpOpenAware(const FSSpec *spec, 2727 short denyModes, 2728 short *refNum) 2729{ 2730 return ( HOpenAware(spec->vRefNum, spec->parID, spec->name, denyModes, refNum) ); 2731} 2732 2733/*****************************************************************************/ 2734 2735pascal OSErr HOpenRFAware(short vRefNum, 2736 long dirID, 2737 ConstStr255Param fileName, 2738 short denyModes, 2739 short *refNum) 2740{ 2741 HParamBlockRec pb; 2742 OSErr error; 2743 GetVolParmsInfoBuffer volParmsInfo; 2744 long infoSize = sizeof(GetVolParmsInfoBuffer); 2745 2746 pb.ioParam.ioMisc = NULL; 2747 pb.fileParam.ioFVersNum = 0; 2748 pb.fileParam.ioNamePtr = (StringPtr)fileName; 2749 pb.fileParam.ioVRefNum = vRefNum; 2750 pb.fileParam.ioDirID = dirID; 2751 2752 /* get volume attributes */ 2753 /* this preflighting is needed because Foreign File Access based file systems don't */ 2754 /* return the correct error result to the OpenRFDeny call */ 2755 error = HGetVolParms(fileName, vRefNum, &volParmsInfo, &infoSize); 2756 if ( (error == noErr) && hasOpenDeny(&volParmsInfo) ) 2757 { 2758 /* if volume supports OpenRFDeny, use it and return */ 2759 if ( hasOpenDeny(&volParmsInfo) ) 2760 { 2761 pb.accessParam.ioDenyModes = denyModes; 2762 error = PBHOpenRFDenySync(&pb); 2763 *refNum = pb.ioParam.ioRefNum; 2764 } 2765 } 2766 else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 2767 { 2768 /* OpenRFDeny isn't supported, so try File Manager OpenRF function */ 2769 2770 /* If request includes write permission, then see if the volume is */ 2771 /* locked by hardware or software. The HFS file system doesn't check */ 2772 /* for this when a file is opened - you only find out later when you */ 2773 /* try to write and the write fails with a wPrErr or a vLckdErr. */ 2774 2775 if ( (denyModes & dmWr) != 0 ) 2776 { 2777 error = CheckVolLock(fileName, vRefNum); 2778 } 2779 else 2780 { 2781 error = noErr; 2782 } 2783 2784 if ( error == noErr ) 2785 { 2786 /* Set File Manager permissions to closest thing possible */ 2787 if ( (denyModes == dmWr) || (denyModes == dmRdWr) ) 2788 { 2789 pb.ioParam.ioPermssn = fsRdWrShPerm; 2790 } 2791 else 2792 { 2793 pb.ioParam.ioPermssn = denyModes % 4; 2794 } 2795 2796 error = PBHOpenRFSync(&pb); 2797 *refNum = pb.ioParam.ioRefNum; 2798 } 2799 } 2800 2801 return ( error ); 2802} 2803 2804/*****************************************************************************/ 2805 2806pascal OSErr FSpOpenRFAware(const FSSpec *spec, 2807 short denyModes, 2808 short *refNum) 2809{ 2810 return ( HOpenRFAware(spec->vRefNum, spec->parID, spec->name, denyModes, refNum) ); 2811} 2812 2813/*****************************************************************************/ 2814 2815pascal OSErr FSReadNoCache(short refNum, 2816 long *count, 2817 void *buffPtr) 2818{ 2819 ParamBlockRec pb; 2820 OSErr error; 2821 2822 pb.ioParam.ioRefNum = refNum; 2823 pb.ioParam.ioBuffer = (Ptr)buffPtr; 2824 pb.ioParam.ioReqCount = *count; 2825 pb.ioParam.ioPosMode = fsAtMark + noCacheMask; /* fsAtMark + noCacheMask */ 2826 pb.ioParam.ioPosOffset = 0; 2827 error = PBReadSync(&pb); 2828 *count = pb.ioParam.ioActCount; /* always return count */ 2829 return ( error ); 2830} 2831 2832/*****************************************************************************/ 2833 2834pascal OSErr FSWriteNoCache(short refNum, 2835 long *count, 2836 const void *buffPtr) 2837{ 2838 ParamBlockRec pb; 2839 OSErr error; 2840 2841 pb.ioParam.ioRefNum = refNum; 2842 pb.ioParam.ioBuffer = (Ptr)buffPtr; 2843 pb.ioParam.ioReqCount = *count; 2844 pb.ioParam.ioPosMode = fsAtMark + noCacheMask; /* fsAtMark + noCacheMask */ 2845 pb.ioParam.ioPosOffset = 0; 2846 error = PBWriteSync(&pb); 2847 *count = pb.ioParam.ioActCount; /* always return count */ 2848 return ( error ); 2849} 2850 2851/*****************************************************************************/ 2852 2853/* 2854** See if numBytes bytes of buffer1 are equal to buffer2. 2855*/ 2856static Boolean EqualMemory(const void *buffer1, const void *buffer2, unsigned long numBytes) 2857{ 2858 register unsigned char *b1 = (unsigned char *)buffer1; 2859 register unsigned char *b2 = (unsigned char *)buffer2; 2860 2861 if ( b1 != b2 ) /* if buffer pointers are same, then they are equal */ 2862 { 2863 while ( numBytes > 0 ) 2864 { 2865 /* compare the bytes and then increment the pointers */ 2866 if ( (*b1++ - *b2++) != 0 ) 2867 { 2868 return ( false ); 2869 } 2870 --numBytes; 2871 } 2872 } 2873 2874 return ( true ); 2875} 2876 2877/*****************************************************************************/ 2878 2879/* 2880** Read any number of bytes from an open file using read-verify mode. 2881** The FSReadVerify function reads any number of bytes from an open file 2882** and verifies them against the data in the buffer pointed to by buffPtr. 2883** 2884** Because of a bug in the HFS file system, only non-block aligned parts of 2885** the read are verified against the buffer data and the rest is *copied* 2886** into the buffer. Thus, you shouldn't verify against your original data; 2887** instead, you should verify against a copy of the original data and then 2888** compare the read-verified copy against the original data after calling 2889** FSReadVerify. That's why this function isn't exported - it needs the 2890** wrapper provided by FSWriteVerify. 2891*/ 2892static OSErr FSReadVerify(short refNum, 2893 long *count, 2894 void *buffPtr) 2895{ 2896 ParamBlockRec pb; 2897 OSErr result; 2898 2899 pb.ioParam.ioRefNum = refNum; 2900 pb.ioParam.ioBuffer = (Ptr)buffPtr; 2901 pb.ioParam.ioReqCount = *count; 2902 pb.ioParam.ioPosMode = fsAtMark + rdVerify; 2903 pb.ioParam.ioPosOffset = 0; 2904 result = PBReadSync(&pb); 2905 *count = pb.ioParam.ioActCount; /* always return count */ 2906 return ( result ); 2907} 2908 2909/*****************************************************************************/ 2910 2911pascal OSErr FSWriteVerify(short refNum, 2912 long *count, 2913 const void *buffPtr) 2914{ 2915 Ptr verifyBuffer; 2916 long position; 2917 long bufferSize; 2918 long byteCount; 2919 long bytesVerified; 2920 Ptr startVerify; 2921 OSErr result; 2922 2923 /* 2924 ** Allocate the verify buffer 2925 ** Try to get get a large enough buffer to verify in one pass. 2926 ** If that fails, use GetTempBuffer to get a buffer. 2927 */ 2928 bufferSize = *count; 2929 verifyBuffer = NewPtr(bufferSize); 2930 if ( verifyBuffer == NULL ) 2931 { 2932 verifyBuffer = GetTempBuffer(bufferSize, &bufferSize); 2933 } 2934 if ( verifyBuffer != NULL ) 2935 { 2936 /* Save the current position */ 2937 result = GetFPos(refNum, &position); 2938 if ( result == noErr ) 2939 { 2940 /* Write the data */ 2941 result = FSWrite(refNum, count, buffPtr); 2942 if ( result == noErr ) 2943 { 2944 /* Restore the original position */ 2945 result = SetFPos(refNum, fsFromStart, position); 2946 if ( result == noErr ) 2947 { 2948 /* 2949 ** *count = total number of bytes to verify 2950 ** bufferSize = the size of the verify buffer 2951 ** bytesVerified = number of bytes verified 2952 ** byteCount = number of bytes to verify this pass 2953 ** startVerify = position in buffPtr 2954 */ 2955 bytesVerified = 0; 2956 startVerify = (Ptr)buffPtr; 2957 while ( (bytesVerified < *count) && ( result == noErr ) ) 2958 { 2959 if ( (*count - bytesVerified) > bufferSize ) 2960 { 2961 byteCount = bufferSize; 2962 } 2963 else 2964 { 2965 byteCount = *count - bytesVerified; 2966 } 2967 /* 2968 ** Copy the write buffer into the verify buffer. 2969 ** This step is needed because the File Manager 2970 ** compares the data in any non-block aligned 2971 ** data at the beginning and end of the read-verify 2972 ** request back into the file system's cache 2973 ** to the data in verify Buffer. However, the 2974 ** File Manager does not compare any full blocks 2975 ** and instead copies them into the verify buffer 2976 ** so we still have to compare the buffers again 2977 ** after the read-verify request completes. 2978 */ 2979 BlockMoveData(startVerify, verifyBuffer, byteCount); 2980 2981 /* Read-verify the data back into the verify buffer */ 2982 result = FSReadVerify(refNum, &byteCount, verifyBuffer); 2983 if ( result == noErr ) 2984 { 2985 /* See if the buffers are the same */ 2986 if ( !EqualMemory(verifyBuffer, startVerify, byteCount) ) 2987 { 2988 result = ioErr; 2989 } 2990 startVerify += byteCount; 2991 bytesVerified += byteCount; 2992 } 2993 } 2994 } 2995 } 2996 } 2997 DisposePtr(verifyBuffer); 2998 } 2999 else 3000 { 3001 result = memFullErr; 3002 } 3003 return ( result ); 3004} 3005 3006/*****************************************************************************/ 3007 3008pascal OSErr CopyFork(short srcRefNum, 3009 short dstRefNum, 3010 void *copyBufferPtr, 3011 long copyBufferSize) 3012{ 3013 ParamBlockRec srcPB; 3014 ParamBlockRec dstPB; 3015 OSErr srcError; 3016 OSErr dstError; 3017 3018 if ( (copyBufferPtr == NULL) || (copyBufferSize == 0) ) 3019 return ( paramErr ); 3020 3021 srcPB.ioParam.ioRefNum = srcRefNum; 3022 dstPB.ioParam.ioRefNum = dstRefNum; 3023 3024 /* preallocate the destination fork and */ 3025 /* ensure the destination fork's EOF is correct after the copy */ 3026 srcError = PBGetEOFSync(&srcPB); 3027 if ( srcError != noErr ) 3028 return ( srcError ); 3029 dstPB.ioParam.ioMisc = srcPB.ioParam.ioMisc; 3030 dstError = PBSetEOFSync(&dstPB); 3031 if ( dstError != noErr ) 3032 return ( dstError ); 3033 3034 /* reset source fork's mark */ 3035 srcPB.ioParam.ioPosMode = fsFromStart; 3036 srcPB.ioParam.ioPosOffset = 0; 3037 srcError = PBSetFPosSync(&srcPB); 3038 if ( srcError != noErr ) 3039 return ( srcError ); 3040 3041 /* reset destination fork's mark */ 3042 dstPB.ioParam.ioPosMode = fsFromStart; 3043 dstPB.ioParam.ioPosOffset = 0; 3044 dstError = PBSetFPosSync(&dstPB); 3045 if ( dstError != noErr ) 3046 return ( dstError ); 3047 3048 /* set up fields that won't change in the loop */ 3049 srcPB.ioParam.ioBuffer = (Ptr)copyBufferPtr; 3050 srcPB.ioParam.ioPosMode = fsAtMark + noCacheMask;/* fsAtMark + noCacheMask */ 3051 /* If copyBufferSize is greater than 512 bytes, make it a multiple of 512 bytes */ 3052 /* This will make writes on local volumes faster */ 3053 if ( (copyBufferSize >= 512) && ((copyBufferSize & 0x1ff) != 0) ) 3054 { 3055 srcPB.ioParam.ioReqCount = copyBufferSize & 0xfffffe00; 3056 } 3057 else 3058 { 3059 srcPB.ioParam.ioReqCount = copyBufferSize; 3060 } 3061 dstPB.ioParam.ioBuffer = (Ptr)copyBufferPtr; 3062 dstPB.ioParam.ioPosMode = fsAtMark + noCacheMask;/* fsAtMark + noCacheMask */ 3063 3064 while ( (srcError == noErr) && (dstError == noErr) ) 3065 { 3066 srcError = PBReadSync(&srcPB); 3067 dstPB.ioParam.ioReqCount = srcPB.ioParam.ioActCount; 3068 dstError = PBWriteSync(&dstPB); 3069 } 3070 3071 /* make sure there were no errors at the destination */ 3072 if ( dstError != noErr ) 3073 return ( dstError ); 3074 3075 /* make sure the only error at the source was eofErr */ 3076 if ( srcError != eofErr ) 3077 return ( srcError ); 3078 3079 return ( noErr ); 3080} 3081 3082/*****************************************************************************/ 3083 3084pascal OSErr GetFileLocation(short refNum, 3085 short *vRefNum, 3086 long *dirID, 3087 StringPtr fileName) 3088{ 3089 FCBPBRec pb; 3090 OSErr error; 3091 3092 pb.ioNamePtr = fileName; 3093 pb.ioVRefNum = 0; 3094 pb.ioRefNum = refNum; 3095 pb.ioFCBIndx = 0; 3096 error = PBGetFCBInfoSync(&pb); 3097 if ( error == noErr ) 3098 { 3099 *vRefNum = pb.ioFCBVRefNum; 3100 *dirID = pb.ioFCBParID; 3101 } 3102 return ( error ); 3103} 3104 3105/*****************************************************************************/ 3106 3107pascal OSErr FSpGetFileLocation(short refNum, 3108 FSSpec *spec) 3109{ 3110 return ( GetFileLocation(refNum, &(spec->vRefNum), &(spec->parID), spec->name) ); 3111} 3112 3113/*****************************************************************************/ 3114 3115pascal OSErr CopyDirectoryAccess(short srcVRefNum, 3116 long srcDirID, 3117 ConstStr255Param srcName, 3118 short dstVRefNum, 3119 long dstDirID, 3120 ConstStr255Param dstName) 3121{ 3122 OSErr error; 3123 GetVolParmsInfoBuffer infoBuffer; /* Where PBGetVolParms dumps its info */ 3124 long dstServerAdr; /* AppleTalk server address of destination (if any) */ 3125 long ownerID, groupID, accessRights; 3126 long tempLong; 3127 3128 /* See if destination supports directory access control */ 3129 tempLong = sizeof(infoBuffer); 3130 error = HGetVolParms(dstName, dstVRefNum, &infoBuffer, &tempLong); 3131 if ( (error == noErr) && hasAccessCntl(&infoBuffer) ) 3132 { 3133 if ( hasAccessCntl(&infoBuffer) ) 3134 { 3135 dstServerAdr = infoBuffer.vMServerAdr; 3136 3137 /* See if source supports directory access control and is on same server */ 3138 tempLong = sizeof(infoBuffer); 3139 error = HGetVolParms(srcName, srcVRefNum, &infoBuffer, &tempLong); 3140 if ( error == noErr ) 3141 { 3142 if ( hasAccessCntl(&infoBuffer) && (dstServerAdr == infoBuffer.vMServerAdr) ) 3143 { 3144 /* both volumes support directory access control and they are */ 3145 /* on same server, so copy the access information */ 3146 error = HGetDirAccess(srcVRefNum, srcDirID, srcName, &ownerID, &groupID, &accessRights); 3147 if ( error == noErr ) 3148 { 3149 error = HSetDirAccess(dstVRefNum, dstDirID, dstName, ownerID, groupID, accessRights); 3150 } 3151 } 3152 else 3153 { 3154 /* destination doesn't support directory access control or */ 3155 /* they volumes aren't on the same server */ 3156 error = paramErr; 3157 } 3158 } 3159 } 3160 else 3161 { 3162 /* destination doesn't support directory access control */ 3163 error = paramErr; 3164 } 3165 } 3166 3167 return ( error ); 3168} 3169 3170/*****************************************************************************/ 3171 3172pascal OSErr FSpCopyDirectoryAccess(const FSSpec *srcSpec, 3173 const FSSpec *dstSpec) 3174{ 3175 return ( CopyDirectoryAccess(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, 3176 dstSpec->vRefNum, dstSpec->parID, dstSpec->name) ); 3177} 3178 3179/*****************************************************************************/ 3180 3181pascal OSErr HMoveRenameCompat(short vRefNum, 3182 long srcDirID, 3183 ConstStr255Param srcName, 3184 long dstDirID, 3185 ConstStr255Param dstpathName, 3186 ConstStr255Param copyName) 3187{ 3188 OSErr error; 3189 GetVolParmsInfoBuffer volParmsInfo; 3190 long infoSize; 3191 short realVRefNum; 3192 long realParID; 3193 Str31 realName; 3194 Boolean isDirectory; 3195 long tempItemsDirID; 3196 long uniqueTempDirID; 3197 Str31 uniqueTempDirName; 3198 unsigned short uniqueNameoverflow; 3199 3200 /* Get volume attributes */ 3201 infoSize = sizeof(GetVolParmsInfoBuffer); 3202 error = HGetVolParms((StringPtr)srcName, vRefNum, &volParmsInfo, &infoSize); 3203 if ( (error == noErr) && hasMoveRename(&volParmsInfo) ) 3204 { 3205 /* If volume supports move and rename, so use it and return */ 3206 error = HMoveRename(vRefNum, srcDirID, srcName, dstDirID, dstpathName, copyName); 3207 } 3208 else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 3209 { 3210 /* MoveRename isn't supported by this volume, so do it by hand */ 3211 3212 /* If copyName isn't supplied, we can simply CatMove and return */ 3213 if ( copyName == NULL ) 3214 { 3215 error = CatMove(vRefNum, srcDirID, srcName, dstDirID, dstpathName); 3216 } 3217 else 3218 { 3219 /* Renaming is required, so we have some work to do... */ 3220 3221 /* Get the object's real name, real parent ID and real vRefNum */ 3222 error = GetObjectLocation(vRefNum, srcDirID, (StringPtr)srcName, 3223 &realVRefNum, &realParID, realName, &isDirectory); 3224 if ( error == noErr ) 3225 { 3226 /* Find the Temporary Items Folder on that volume */ 3227 error = FindFolder(realVRefNum, kTemporaryFolderType, kCreateFolder, 3228 &realVRefNum, &tempItemsDirID); 3229 if ( error == noErr ) 3230 { 3231 /* Create a new uniquely named folder in the temporary items folder. */ 3232 /* This is done to avoid the case where 'realName' or 'copyName' already */ 3233 /* exists in the temporary items folder. */ 3234 3235 /* Start with current tick count as uniqueTempDirName */ 3236 NumToString(TickCount(), uniqueTempDirName); 3237 uniqueNameoverflow = 0; 3238 do 3239 { 3240 error = DirCreate(realVRefNum, tempItemsDirID, uniqueTempDirName, &uniqueTempDirID); 3241 if ( error == dupFNErr ) 3242 { 3243 /* Duplicate name - change the first character to the next ASCII character */ 3244 ++uniqueTempDirName[1]; 3245 /* Make sure it isn't a colon! */ 3246 if ( uniqueTempDirName[1] == ':' ) 3247 { 3248 ++uniqueTempDirName[1]; 3249 } 3250 /* Don't go too far... */ 3251 ++uniqueNameoverflow; 3252 } 3253 } while ( (error == dupFNErr) && (uniqueNameoverflow <= 64) ); /* 64 new files per 1/60th second - not likely! */ 3254 if ( error == noErr ) 3255 { 3256 /* Move the object to the folder with uniqueTempDirID for renaming */ 3257 error = CatMove(realVRefNum, realParID, realName, uniqueTempDirID, NULL); 3258 if ( error == noErr ) 3259 { 3260 /* Rename the object */ 3261 error = HRename(realVRefNum, uniqueTempDirID, realName, copyName); 3262 if ( error == noErr ) 3263 { 3264 /* Move object to its new home */ 3265 error = CatMove(realVRefNum, uniqueTempDirID, copyName, dstDirID, dstpathName); 3266 if ( error != noErr ) 3267 { 3268 /* Error handling: rename object back to original name - ignore errors */ 3269 (void) HRename(realVRefNum, uniqueTempDirID, copyName, realName); 3270 } 3271 } 3272 if ( error != noErr ) 3273 { 3274 /* Error handling: move object back to original location - ignore errors */ 3275 (void) CatMove(realVRefNum, uniqueTempDirID, realName, realParID, NULL); 3276 } 3277 } 3278 /* Done with ourTempDir, so delete it - ignore errors */ 3279 (void) HDelete(realVRefNum, uniqueTempDirID, NULL); 3280 } 3281 } 3282 } 3283 } 3284 } 3285 3286 return ( error ); 3287} 3288 3289/*****************************************************************************/ 3290 3291pascal OSErr FSpMoveRenameCompat(const FSSpec *srcSpec, 3292 const FSSpec *dstSpec, 3293 ConstStr255Param copyName) 3294{ 3295 /* make sure the FSSpecs refer to the same volume */ 3296 if (srcSpec->vRefNum != dstSpec->vRefNum) 3297 return (diffVolErr); 3298 return ( HMoveRenameCompat(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, 3299 dstSpec->parID, dstSpec->name, copyName) ); 3300} 3301 3302/*****************************************************************************/ 3303 3304pascal OSErr BuildAFPVolMountInfo(short flags, 3305 char nbpInterval, 3306 char nbpCount, 3307 short uamType, 3308 Str32 zoneName, 3309 Str32 serverName, 3310 Str27 volName, 3311 Str31 userName, 3312 Str8 userPassword, 3313 Str8 volPassword, 3314 AFPVolMountInfoPtr *afpInfoPtr) 3315{ 3316 MyAFPVolMountInfoPtr infoPtr; 3317 OSErr error; 3318 3319 /* Allocate the AFPXVolMountInfo record */ 3320 infoPtr = (MyAFPVolMountInfoPtr)NewPtrClear(sizeof(MyAFPVolMountInfo)); 3321 if ( infoPtr != NULL ) 3322 { 3323 /* Fill in an AFPVolMountInfo record that can be passed to VolumeMount */ 3324 infoPtr->length = sizeof(MyAFPVolMountInfo); 3325 infoPtr->media = AppleShareMediaType; 3326 infoPtr->flags = flags; 3327 infoPtr->nbpInterval = nbpInterval; 3328 infoPtr->nbpCount = nbpCount; 3329 infoPtr->uamType = uamType; 3330 3331 infoPtr->zoneNameOffset = offsetof(MyAFPVolMountInfo, zoneName); 3332 infoPtr->serverNameOffset = offsetof(MyAFPVolMountInfo, serverName); 3333 infoPtr->volNameOffset = offsetof(MyAFPVolMountInfo, volName); 3334 infoPtr->userNameOffset = offsetof(MyAFPVolMountInfo, userName); 3335 infoPtr->userPasswordOffset = offsetof(MyAFPVolMountInfo, userPassword); 3336 infoPtr->volPasswordOffset = offsetof(MyAFPVolMountInfo, volPassword); 3337 3338 BlockMoveData(zoneName, infoPtr->zoneName, sizeof(Str32)); 3339 BlockMoveData(serverName, infoPtr->serverName, sizeof(Str32)); 3340 BlockMoveData(volName, infoPtr->volName, sizeof(Str27)); 3341 BlockMoveData(userName, infoPtr->userName, sizeof(Str31)); 3342 BlockMoveData(userPassword, infoPtr->userPassword, sizeof(Str8)); 3343 BlockMoveData(volPassword, infoPtr->volPassword, sizeof(Str8)); 3344 3345 *afpInfoPtr = (AFPVolMountInfoPtr)infoPtr; 3346 error = noErr; 3347 } 3348 else 3349 { 3350 error = memFullErr; 3351 } 3352 3353 return ( error ); 3354} 3355 3356/*****************************************************************************/ 3357 3358pascal OSErr RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr, 3359 short *flags, 3360 short *uamType, 3361 StringPtr zoneName, 3362 StringPtr serverName, 3363 StringPtr volName, 3364 StringPtr userName) 3365{ 3366 StringPtr tempPtr; 3367 OSErr error; 3368 3369 /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */ 3370 if ( afpInfoPtr->media == AppleShareMediaType ) 3371 { 3372 *flags = afpInfoPtr->flags; 3373 *uamType = afpInfoPtr->uamType; 3374 3375 if ( afpInfoPtr->zoneNameOffset != 0) 3376 { 3377 tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->zoneNameOffset); 3378 BlockMoveData(tempPtr, zoneName, tempPtr[0] + 1); 3379 } 3380 3381 if ( afpInfoPtr->serverNameOffset != 0) 3382 { 3383 tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->serverNameOffset); 3384 BlockMoveData(tempPtr, serverName, tempPtr[0] + 1); 3385 } 3386 3387 if ( afpInfoPtr->volNameOffset != 0) 3388 { 3389 tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->volNameOffset); 3390 BlockMoveData(tempPtr, volName, tempPtr[0] + 1); 3391 } 3392 3393 if ( afpInfoPtr->userNameOffset != 0) 3394 { 3395 tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->userNameOffset); 3396 BlockMoveData(tempPtr, userName, tempPtr[0] + 1); 3397 } 3398 3399 error = noErr; 3400 } 3401 else 3402 { 3403 error = paramErr; 3404 } 3405 3406 return ( error ); 3407} 3408 3409/*****************************************************************************/ 3410 3411pascal OSErr BuildAFPXVolMountInfo(short flags, 3412 char nbpInterval, 3413 char nbpCount, 3414 short uamType, 3415 Str32 zoneName, 3416 Str32 serverName, 3417 Str27 volName, 3418 Str31 userName, 3419 Str8 userPassword, 3420 Str8 volPassword, 3421 Str32 uamName, 3422 unsigned long alternateAddressLength, 3423 void *alternateAddress, 3424 AFPXVolMountInfoPtr *afpXInfoPtr) 3425{ 3426 Size infoSize; 3427 MyAFPXVolMountInfoPtr infoPtr; 3428 OSErr error; 3429 3430 /* Calculate the size of the AFPXVolMountInfo record */ 3431 infoSize = sizeof(MyAFPXVolMountInfo) + alternateAddressLength - 1; 3432 3433 /* Allocate the AFPXVolMountInfo record */ 3434 infoPtr = (MyAFPXVolMountInfoPtr)NewPtrClear(infoSize); 3435 if ( infoPtr != NULL ) 3436 { 3437 /* Fill in an AFPXVolMountInfo record that can be passed to VolumeMount */ 3438 infoPtr->length = infoSize; 3439 infoPtr->media = AppleShareMediaType; 3440 infoPtr->flags = flags; 3441 if ( alternateAddressLength != 0 ) 3442 { 3443 /* make sure the volMountExtendedFlagsBit is set if there's extended address info */ 3444 infoPtr->flags |= volMountExtendedFlagsMask; 3445 /* and set the only extendedFlags bit we know about */ 3446 infoPtr->extendedFlags = kAFPExtendedFlagsAlternateAddressMask; 3447 } 3448 else 3449 { 3450 /* make sure the volMountExtendedFlagsBit is clear if there's no extended address info */ 3451 infoPtr->flags &= ~volMountExtendedFlagsMask; 3452 /* and clear the extendedFlags */ 3453 infoPtr->extendedFlags = 0; 3454 } 3455 infoPtr->nbpInterval = nbpInterval; 3456 infoPtr->nbpCount = nbpCount; 3457 infoPtr->uamType = uamType; 3458 3459 infoPtr->zoneNameOffset = offsetof(MyAFPXVolMountInfo, zoneName); 3460 infoPtr->serverNameOffset = offsetof(MyAFPXVolMountInfo, serverName); 3461 infoPtr->volNameOffset = offsetof(MyAFPXVolMountInfo, volName); 3462 infoPtr->userNameOffset = offsetof(MyAFPXVolMountInfo, userName); 3463 infoPtr->userPasswordOffset = offsetof(MyAFPXVolMountInfo, userPassword); 3464 infoPtr->volPasswordOffset = offsetof(MyAFPXVolMountInfo, volPassword); 3465 infoPtr->uamNameOffset = offsetof(MyAFPXVolMountInfo, uamName); 3466 infoPtr->alternateAddressOffset = offsetof(MyAFPXVolMountInfo, alternateAddress); 3467 3468 BlockMoveData(zoneName, infoPtr->zoneName, sizeof(Str32)); 3469 BlockMoveData(serverName, infoPtr->serverName, sizeof(Str32)); 3470 BlockMoveData(volName, infoPtr->volName, sizeof(Str27)); 3471 BlockMoveData(userName, infoPtr->userName, sizeof(Str31)); 3472 BlockMoveData(userPassword, infoPtr->userPassword, sizeof(Str8)); 3473 BlockMoveData(volPassword, infoPtr->volPassword, sizeof(Str8)); 3474 BlockMoveData(uamName, infoPtr->uamName, sizeof(Str32)); 3475 BlockMoveData(alternateAddress, infoPtr->alternateAddress, alternateAddressLength); 3476 3477 *afpXInfoPtr = (AFPXVolMountInfoPtr)infoPtr; 3478 error = noErr; 3479 } 3480 else 3481 { 3482 error = memFullErr; 3483 } 3484 3485 return ( error ); 3486} 3487 3488/*****************************************************************************/ 3489 3490pascal OSErr RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr, 3491 short *flags, 3492 short *uamType, 3493 StringPtr zoneName, 3494 StringPtr serverName, 3495 StringPtr volName, 3496 StringPtr userName, 3497 StringPtr uamName, 3498 unsigned long *alternateAddressLength, 3499 AFPAlternateAddress **alternateAddress) 3500{ 3501 StringPtr tempPtr; 3502 Ptr alternateAddressStart; 3503 Ptr alternateAddressEnd; 3504 Size alternateAddressDataSize; 3505 OSErr error; 3506 UInt8 addressCount; 3507 3508 /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */ 3509 if ( afpXInfoPtr->media == AppleShareMediaType ) 3510 { 3511 /* default to noErr */ 3512 error = noErr; 3513 3514 /* Is this an extended record? */ 3515 if ( (afpXInfoPtr->flags & volMountExtendedFlagsMask) != 0 ) 3516 { 3517 if ( ((afpXInfoPtr->extendedFlags & kAFPExtendedFlagsAlternateAddressMask) != 0) && 3518 (afpXInfoPtr->alternateAddressOffset != 0) ) 3519 { 3520 3521 alternateAddressStart = (Ptr)((long)afpXInfoPtr + afpXInfoPtr->alternateAddressOffset); 3522 alternateAddressEnd = alternateAddressStart + 1; /* skip over alternate address version byte */ 3523 addressCount = *(UInt8*)alternateAddressEnd; /* get the address count */ 3524 ++alternateAddressEnd; /* skip over alternate address count byte */ 3525 /* alternateAddressEnd now equals &AFPAlternateAddress.fAddressList[0] */ 3526 while ( addressCount != 0 ) 3527 { 3528 /* parse the address list to find the end */ 3529 alternateAddressEnd += *(UInt8*)alternateAddressEnd; /* add length of each AFPTagData record */ 3530 --addressCount; 3531 } 3532 /* get the size of the alternateAddressData */ 3533 alternateAddressDataSize = alternateAddressEnd - alternateAddressStart; 3534 /* allocate memory for it */ 3535 *alternateAddress = (AFPAlternateAddress *)NewPtr(alternateAddressDataSize); 3536 if ( *alternateAddress != NULL ) 3537 { 3538 /* and return the data */ 3539 BlockMoveData(alternateAddressStart, *alternateAddress, alternateAddressDataSize); 3540 *alternateAddressLength = alternateAddressDataSize; 3541 } 3542 else 3543 { 3544 /* no memory - fail now */ 3545 error = memFullErr; 3546 } 3547 } 3548 3549 if ( error == noErr ) /* fill in more output parameters if everything is OK */ 3550 { 3551 if ( afpXInfoPtr->uamNameOffset != 0 ) 3552 { 3553 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->uamNameOffset); 3554 BlockMoveData(tempPtr, uamName, tempPtr[0] + 1); 3555 } 3556 } 3557 } 3558 3559 if ( error == noErr ) /* fill in more output parameters if everything is OK */ 3560 { 3561 *flags = afpXInfoPtr->flags; 3562 *uamType = afpXInfoPtr->uamType; 3563 3564 if ( afpXInfoPtr->zoneNameOffset != 0 ) 3565 { 3566 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->zoneNameOffset); 3567 BlockMoveData(tempPtr, zoneName, tempPtr[0] + 1); 3568 } 3569 3570 if ( afpXInfoPtr->serverNameOffset != 0 ) 3571 { 3572 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->serverNameOffset); 3573 BlockMoveData(tempPtr, serverName, tempPtr[0] + 1); 3574 } 3575 3576 if ( afpXInfoPtr->volNameOffset != 0 ) 3577 { 3578 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->volNameOffset); 3579 BlockMoveData(tempPtr, volName, tempPtr[0] + 1); 3580 } 3581 3582 if ( afpXInfoPtr->userNameOffset != 0 ) 3583 { 3584 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->userNameOffset); 3585 BlockMoveData(tempPtr, userName, tempPtr[0] + 1); 3586 } 3587 } 3588 } 3589 else 3590 { 3591 error = paramErr; 3592 } 3593 3594 return ( error ); 3595} 3596 3597/*****************************************************************************/ 3598 3599pascal OSErr GetUGEntries(short objType, 3600 UGEntryPtr entries, 3601 long reqEntryCount, 3602 long *actEntryCount, 3603 long *objID) 3604{ 3605 HParamBlockRec pb; 3606 OSErr error = noErr; 3607 UGEntry *endEntryArray; 3608 3609 pb.objParam.ioObjType = objType; 3610 *actEntryCount = 0; 3611 for ( endEntryArray = entries + reqEntryCount; (entries < endEntryArray) && (error == noErr); ++entries ) 3612 { 3613 pb.objParam.ioObjNamePtr = (StringPtr)entries->name; 3614 pb.objParam.ioObjID = *objID; 3615 /* Files.h in the universal interfaces, PBGetUGEntrySync takes a CMovePBPtr */ 3616 /* as the parameter. Inside Macintosh and the original glue used HParmBlkPtr. */ 3617 /* A CMovePBPtr works OK, but this will be changed in the future back to */ 3618 /* HParmBlkPtr, so I'm just casting it here. */ 3619 error = PBGetUGEntrySync(&pb); 3620 if ( error == noErr ) 3621 { 3622 entries->objID = *objID = pb.objParam.ioObjID; 3623 entries->objType = objType; 3624 ++*actEntryCount; 3625 } 3626 } 3627 3628 return ( error ); 3629} 3630 3631/*****************************************************************************/ 3632 3633