2         File:           MoreFilesExtras.c 
   4         Contains:       A collection of useful high-level File Manager routines 
   8         Copyright:      © 1992-2001 by Apple Computer, Inc., all rights reserved. 
  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. 
  22                 Other Contact:          Apple Macintosh Developer Technical Support 
  23                                                         <http://developer.apple.com/bugreporter/> 
  25                 Technology:                     DTS Sample Code 
  31         Change History (most recent first): 
  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. 
  49 #include <HFSVolumes.h> 
  52 #include <MacErrors.h> 
  53 #include <MacMemory.h> 
  59 #include <TextUtils.h> 
  62 #include <CodeFragments.h> 
  65 #define __COMPILINGMOREFILES 
  67 #include "MoreFiles.h" 
  68 #include "MoreDesktopMgr.h" 
  69 #include "FSpCompat.h" 
  71 #include "MoreFilesExtras.h" 
  73 /*****************************************************************************/ 
  75 /* Functions to get information out of GetVolParmsInfoBuffer. */ 
  77 /* version 1 field getters */ 
  79 pascal  short   GetVolParmsInfoVersion(const GetVolParmsInfoBuffer 
*volParms
) 
  81         return ( volParms
->vMVersion 
); 
  84 pascal  long    GetVolParmsInfoAttrib(const GetVolParmsInfoBuffer 
*volParms
) 
  86         return ( volParms
->vMAttrib 
); 
  89 pascal  Handle  
GetVolParmsInfoLocalHand(const GetVolParmsInfoBuffer 
*volParms
) 
  91         return ( volParms
->vMLocalHand 
); 
  94 pascal  long    GetVolParmsInfoServerAdr(const GetVolParmsInfoBuffer 
*volParms
) 
  96         return ( volParms
->vMServerAdr 
); 
  99 /* version 2 field getters (assume zero result if version < 2) */ 
 101 pascal  long    GetVolParmsInfoVolumeGrade(const GetVolParmsInfoBuffer 
*volParms
) 
 103         return ( (volParms
->vMVersion 
>= 2) ? volParms
->vMVolumeGrade 
: 0 ); 
 106 pascal  long    GetVolParmsInfoForeignPrivID(const GetVolParmsInfoBuffer 
*volParms
) 
 108         return ( (volParms
->vMVersion 
>= 2) ? volParms
->vMForeignPrivID 
: 0 ); 
 111 /* version 3 field getters (assume zero result if version < 3) */ 
 113 pascal  long    GetVolParmsInfoExtendedAttributes(const GetVolParmsInfoBuffer 
*volParms
) 
 115         return ( (volParms
->vMVersion 
>= 3) ? volParms
->vMExtendedAttributes 
: 0 ); 
 118 /* attribute bits supported by all versions of GetVolParmsInfoBuffer */ 
 120 pascal  Boolean 
isNetworkVolume(const GetVolParmsInfoBuffer 
*volParms
) 
 122         return ( volParms
->vMServerAdr 
!= 0 ); 
 125 pascal  Boolean 
hasLimitFCBs(const GetVolParmsInfoBuffer 
*volParms
) 
 127         return ( (volParms
->vMAttrib 
& (1L << bLimitFCBs
)) != 0 ); 
 130 pascal  Boolean 
hasLocalWList(const GetVolParmsInfoBuffer 
*volParms
) 
 132         return ( (volParms
->vMAttrib 
& (1L << bLocalWList
)) != 0 ); 
 135 pascal  Boolean 
hasNoMiniFndr(const GetVolParmsInfoBuffer 
*volParms
) 
 137         return ( (volParms
->vMAttrib 
& (1L << bNoMiniFndr
)) != 0 ); 
 140 pascal  Boolean 
hasNoVNEdit(const GetVolParmsInfoBuffer 
*volParms
) 
 142         return ( (volParms
->vMAttrib 
& (1L << bNoVNEdit
)) != 0 ); 
 145 pascal  Boolean 
hasNoLclSync(const GetVolParmsInfoBuffer 
*volParms
) 
 147         return ( (volParms
->vMAttrib 
& (1L << bNoLclSync
)) != 0 ); 
 150 pascal  Boolean 
hasTrshOffLine(const GetVolParmsInfoBuffer 
*volParms
) 
 152         return ( (volParms
->vMAttrib 
& (1L << bTrshOffLine
)) != 0 ); 
 155 pascal  Boolean 
hasNoSwitchTo(const GetVolParmsInfoBuffer 
*volParms
) 
 157         return ( (volParms
->vMAttrib 
& (1L << bNoSwitchTo
)) != 0 ); 
 160 pascal  Boolean 
hasNoDeskItems(const GetVolParmsInfoBuffer 
*volParms
) 
 162         return ( (volParms
->vMAttrib 
& (1L << bNoDeskItems
)) != 0 ); 
 165 pascal  Boolean 
hasNoBootBlks(const GetVolParmsInfoBuffer 
*volParms
) 
 167         return ( (volParms
->vMAttrib 
& (1L << bNoBootBlks
)) != 0 ); 
 170 pascal  Boolean 
hasAccessCntl(const GetVolParmsInfoBuffer 
*volParms
) 
 172         return ( (volParms
->vMAttrib 
& (1L << bAccessCntl
)) != 0 ); 
 175 pascal  Boolean 
hasNoSysDir(const GetVolParmsInfoBuffer 
*volParms
) 
 177         return ( (volParms
->vMAttrib 
& (1L << bNoSysDir
)) != 0 ); 
 180 pascal  Boolean 
hasExtFSVol(const GetVolParmsInfoBuffer 
*volParms
) 
 182         return ( (volParms
->vMAttrib 
& (1L << bHasExtFSVol
)) != 0 ); 
 185 pascal  Boolean 
hasOpenDeny(const GetVolParmsInfoBuffer 
*volParms
) 
 187         return ( (volParms
->vMAttrib 
& (1L << bHasOpenDeny
)) != 0 ); 
 190 pascal  Boolean 
hasCopyFile(const GetVolParmsInfoBuffer 
*volParms
) 
 192         return ( (volParms
->vMAttrib 
& (1L << bHasCopyFile
)) != 0 ); 
 195 pascal  Boolean 
hasMoveRename(const GetVolParmsInfoBuffer 
*volParms
) 
 197         return ( (volParms
->vMAttrib 
& (1L << bHasMoveRename
)) != 0 ); 
 200 pascal  Boolean 
hasDesktopMgr(const GetVolParmsInfoBuffer 
*volParms
) 
 202         return ( (volParms
->vMAttrib 
& (1L << bHasDesktopMgr
)) != 0 ); 
 205 pascal  Boolean 
hasShortName(const GetVolParmsInfoBuffer 
*volParms
) 
 207         return ( (volParms
->vMAttrib 
& (1L << bHasShortName
)) != 0 ); 
 210 pascal  Boolean 
hasFolderLock(const GetVolParmsInfoBuffer 
*volParms
) 
 212         return ( (volParms
->vMAttrib 
& (1L << bHasFolderLock
)) != 0 ); 
 215 pascal  Boolean 
hasPersonalAccessPrivileges(const GetVolParmsInfoBuffer 
*volParms
) 
 217         return ( (volParms
->vMAttrib 
& (1L << bHasPersonalAccessPrivileges
)) != 0 ); 
 220 pascal  Boolean 
hasUserGroupList(const GetVolParmsInfoBuffer 
*volParms
) 
 222         return ( (volParms
->vMAttrib 
& (1L << bHasUserGroupList
)) != 0 ); 
 225 pascal  Boolean 
hasCatSearch(const GetVolParmsInfoBuffer 
*volParms
) 
 227         return ( (volParms
->vMAttrib 
& (1L << bHasCatSearch
)) != 0 ); 
 230 pascal  Boolean 
hasFileIDs(const GetVolParmsInfoBuffer 
*volParms
) 
 232         return ( (volParms
->vMAttrib 
& (1L << bHasFileIDs
)) != 0 ); 
 235 pascal  Boolean 
hasBTreeMgr(const GetVolParmsInfoBuffer 
*volParms
) 
 237         return ( (volParms
->vMAttrib 
& (1L << bHasBTreeMgr
)) != 0 ); 
 240 pascal  Boolean 
hasBlankAccessPrivileges(const GetVolParmsInfoBuffer 
*volParms
) 
 242         return ( (volParms
->vMAttrib 
& (1L << bHasBlankAccessPrivileges
)) != 0 ); 
 245 pascal  Boolean 
supportsAsyncRequests(const GetVolParmsInfoBuffer 
*volParms
) 
 247         return ( (volParms
->vMAttrib 
& (1L << bSupportsAsyncRequests
)) != 0 ); 
 250 pascal  Boolean 
supportsTrashVolumeCache(const GetVolParmsInfoBuffer 
*volParms
) 
 252         return ( (volParms
->vMAttrib 
& (1L << bSupportsTrashVolumeCache
)) != 0 ); 
 255 /* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */ 
 257 pascal  Boolean 
volIsEjectable(const GetVolParmsInfoBuffer 
*volParms
) 
 259         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bIsEjectable
)) != 0 ); 
 262 pascal  Boolean 
volSupportsHFSPlusAPIs(const GetVolParmsInfoBuffer 
*volParms
) 
 264         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsHFSPlusAPIs
)) != 0 ); 
 267 pascal  Boolean 
volSupportsFSCatalogSearch(const GetVolParmsInfoBuffer 
*volParms
) 
 269         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsFSCatalogSearch
)) != 0 ); 
 272 pascal  Boolean 
volSupportsFSExchangeObjects(const GetVolParmsInfoBuffer 
*volParms
) 
 274         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsFSExchangeObjects
)) != 0 ); 
 277 pascal  Boolean 
volSupports2TBFiles(const GetVolParmsInfoBuffer 
*volParms
) 
 279         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupports2TBFiles
)) != 0 ); 
 282 pascal  Boolean 
volSupportsLongNames(const GetVolParmsInfoBuffer 
*volParms
) 
 284         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsLongNames
)) != 0 ); 
 287 pascal  Boolean 
volSupportsMultiScriptNames(const GetVolParmsInfoBuffer 
*volParms
) 
 289         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsMultiScriptNames
)) != 0 ); 
 292 pascal  Boolean 
volSupportsNamedForks(const GetVolParmsInfoBuffer 
*volParms
) 
 294         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsNamedForks
)) != 0 ); 
 297 pascal  Boolean 
volSupportsSubtreeIterators(const GetVolParmsInfoBuffer 
*volParms
) 
 299         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsSubtreeIterators
)) != 0 ); 
 302 pascal  Boolean 
volL2PCanMapFileBlocks(const GetVolParmsInfoBuffer 
*volParms
) 
 304         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bL2PCanMapFileBlocks
)) != 0 ); 
 307 /*****************************************************************************/ 
 309 /* Functions for testing ioACUser bits. */ 
 311 pascal  Boolean 
userIsOwner(SInt8 ioACUser
) 
 313         return ( (ioACUser 
& kioACUserNotOwnerMask
) == 0 ); 
 316 pascal  Boolean 
userHasFullAccess(SInt8 ioACUser
) 
 318         return ( (ioACUser 
& acUserAccessMask
) == acUserFull 
); 
 321 pascal  Boolean 
userHasDropBoxAccess(SInt8 ioACUser
) 
 323         return ( (ioACUser 
& acUserAccessMask
) == acUserDropBox 
); 
 326 pascal  Boolean 
userHasBulletinBoard(SInt8 ioACUser
) 
 328         return ( (ioACUser 
& acUserAccessMask
) == acUserBulletinBoard 
); 
 331 pascal  Boolean 
userHasNoAccess(SInt8 ioACUser
) 
 333         return ( (ioACUser 
& acUserAccessMask
) == acUserNone 
); 
 336 /*****************************************************************************/ 
 338 /* local data structures */ 
 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. */ 
 344 #if PRAGMA_STRUCT_ALIGN 
 345         #pragma options align=mac68k 
 346 #endif  //      PRAGMA_STRUCT_ALIGN 
 347 struct DeleteEnumGlobals
 
 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 */ 
 353 #if PRAGMA_STRUCT_ALIGN 
 354         #pragma options align=reset 
 355 #endif //       PRAGMA_STRUCT_ALIGN 
 357 typedef struct DeleteEnumGlobals DeleteEnumGlobals
; 
 358 typedef DeleteEnumGlobals 
*DeleteEnumGlobalsPtr
; 
 360 /*****************************************************************************/ 
 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. 
 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 
 373 #if TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM 
 375         // Carbon builds and 68K builds don't need this glue 
 376         #define CallPBXGetVolInfoSync PBXGetVolInfoSync 
 378 #else   //      TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM 
 380         #if     __WANTPASCALELIMINATION 
 382         #endif  //      __WANTPASCALELIMINATION 
 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
) 
 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
))) 
 397                 static UniversalProcPtr fsDispatchTrapAddress 
= NULL
; 
 399                 /* Is this the first time we've been called? */ 
 400                 if ( fsDispatchTrapAddress 
== NULL 
) 
 402                         /* Yes - Get the trap address of _FSDispatch */ 
 403                         fsDispatchTrapAddress 
= NGetTrapAddress(_FSDispatch
, OSTrap
); 
 405                 return ( CallOSTrapUniversalProc(fsDispatchTrapAddress
, 
 406                                                                                         uppFSDispatchProcInfo
, 
 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. 
 419         static pascal OSErr 
CallPBXGetVolInfoSync(XVolumeParamPtr paramBlock
) 
 421                 typedef pascal OSErr (*PBXGetVolInfoProcPtr
) (XVolumeParamPtr paramBlock
); 
 424                 CFragConnectionID                       connID
; 
 427                 static PBXGetVolInfoProcPtr     PBXGetVolInfoSyncPtr 
= NULL
; 
 429                 //* Is this the first time we've been called? */ 
 430                 if ( PBXGetVolInfoSyncPtr 
== NULL 
) 
 432                         /* Yes - Get our connection ID to InterfaceLib */ 
 433                         result 
= GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch
, kLoadCFrag
, &connID
, &mainAddr
, errMessage
); 
 434                         if ( result 
== noErr 
) 
 436                                 /* See if PBXGetVolInfoSync is in InterfaceLib */ 
 437                                 if ( FindSymbol(connID
, "\pPBXGetVolInfoSync", &(Ptr
)PBXGetVolInfoSyncPtr
, NULL
) != noErr 
) 
 439                                         /* Use glue code if symbol isn't found */ 
 440                                         PBXGetVolInfoSyncPtr 
= PBXGetVolInfoSyncGlue
; 
 444                 /* Call PBXGetVolInfoSync if present; otherwise, call PBXGetVolInfoSyncGlue */ 
 445                 return ( (*PBXGetVolInfoSyncPtr
)(paramBlock
) ); 
 448         #if     __WANTPASCALELIMINATION 
 450         #endif  //      __WANTPASCALELIMINATION 
 452 #endif  //      TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM 
 454 /*****************************************************************************/ 
 456 pascal  void    TruncPString(StringPtr destination
, 
 457                                                          ConstStr255Param source
, 
 462         if ( source 
!= NULL 
&& destination 
!= NULL 
)    /* don't do anything stupid */ 
 464                 if ( source
[0] > maxLength 
) 
 466                         /* Make sure the string isn't truncated in the middle of */ 
 467                         /* a multi-byte character. */ 
 468                         while (maxLength 
!= 0) 
 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 */  
 479                         maxLength 
= source
[0]; 
 481                 /* Set the destination string length */ 
 482                 destination
[0] = maxLength
; 
 483                 /* and copy maxLength characters (if needed) */ 
 484                 if ( source 
!= destination 
) 
 486                         while ( maxLength 
!= 0 ) 
 488                                 destination
[maxLength
] = source
[maxLength
]; 
 495 /*****************************************************************************/ 
 497 static pascal   Ptr     
GetTempBuffer(long buffReqSize
, 
 502                 kSlopMemory 
= 0x00008000        /* 32K - Amount of free memory to leave when allocating buffers */ 
 506         /* Make request a multiple of 1024 bytes */ 
 507         buffReqSize 
= buffReqSize 
& 0xfffffc00; 
 509         if ( buffReqSize 
< 0x00000400 ) 
 511                 /* Request was smaller than 1024 bytes - make it 1024 */ 
 512                 buffReqSize 
= 0x00000400; 
 515         /* Attempt to allocate the memory */ 
 516         tempPtr 
= NewPtr(buffReqSize
); 
 518         /* If request failed, go to backup plan */ 
 519         if ( (tempPtr 
== NULL
) && (buffReqSize 
> 0x00000400) ) 
 522                 **      Try to get largest 1024-byte block available 
 523                 **      leaving some slop for the toolbox if possible 
 525                 long freeMemory 
= (FreeMem() - kSlopMemory
) & 0xfffffc00; 
 527                 buffReqSize 
= MaxBlock() & 0xfffffc00; 
 529                 if ( buffReqSize 
> freeMemory 
) 
 531                         buffReqSize 
= freeMemory
; 
 534                 if ( buffReqSize 
== 0 ) 
 536                         buffReqSize 
= 0x00000400; 
 539                 tempPtr 
= NewPtr(buffReqSize
); 
 542         /* Return bytes allocated */ 
 543         if ( tempPtr 
!= NULL 
) 
 545                 *buffActSize 
= buffReqSize
; 
 555 /*****************************************************************************/ 
 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). 
 565 **      I noticed using this code in several places, so here it is once. 
 566 **      This reduces the code size of MoreFiles. 
 568 pascal  OSErr   
GetVolumeInfoNoName(ConstStr255Param pathname
, 
 575         /* Make sure pb parameter is not NULL */  
 578                 pb
->volumeParam
.ioVRefNum 
= vRefNum
; 
 579                 if ( pathname 
== NULL 
) 
 581                         pb
->volumeParam
.ioNamePtr 
= NULL
; 
 582                         pb
->volumeParam
.ioVolIndex 
= 0;         /* use ioVRefNum only */ 
 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 */ 
 590                 error 
= PBHGetVInfoSync(pb
); 
 591                 pb
->volumeParam
.ioNamePtr 
= NULL
;       /* ioNamePtr may point to local tempPathname, so don't return it */ 
 600 /*****************************************************************************/ 
 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). 
 610 pascal  OSErr   
XGetVolumeInfoNoName(ConstStr255Param pathname
, 
 617         /* Make sure pb parameter is not NULL */  
 620                 pb
->ioVRefNum 
= vRefNum
; 
 621                 pb
->ioXVersion 
= 0;                     /* this XVolumeParam version (0) */ 
 622                 if ( pathname 
== NULL 
) 
 624                         pb
->ioNamePtr 
= NULL
; 
 625                         pb
->ioVolIndex 
= 0;             /* use ioVRefNum only */ 
 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 */ 
 635 #if !TARGET_API_MAC_CARBON 
 638                         /* Is PBXGetVolInfo available? */ 
 639                         if ( ( Gestalt(gestaltFSAttr
, &response
) != noErr 
) || ((response 
& (1L << gestaltFSSupports2TBVols
)) == 0) ) 
 641                                 /* No, fall back on PBHGetVInfo */ 
 642                                 error 
= PBHGetVInfoSync((HParmBlkPtr
)pb
); 
 643                                 if ( error 
== noErr 
) 
 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
)); 
 654                                 error 
= CallPBXGetVolInfoSync(pb
); 
 657                 pb
->ioNamePtr 
= NULL
;           /* ioNamePtr may point to local tempPathname, so don't return it */ 
 666 /*****************************************************************************/ 
 668 pascal  OSErr 
GetCatInfoNoName(short vRefNum
, 
 670                                                            ConstStr255Param name
, 
 676         /* Protection against File Sharing problem */ 
 677         if ( (name 
== NULL
) || (name
[0] == 0) ) 
 680                 pb
->dirInfo
.ioNamePtr 
= tempName
; 
 681                 pb
->dirInfo
.ioFDirIndex 
= -1;   /* use ioDirID */ 
 685                 pb
->dirInfo
.ioNamePtr 
= (StringPtr
)name
; 
 686                 pb
->dirInfo
.ioFDirIndex 
= 0;    /* use ioNamePtr and ioDirID */ 
 688         pb
->dirInfo
.ioVRefNum 
= vRefNum
; 
 689         pb
->dirInfo
.ioDrDirID 
= dirID
; 
 690         error 
= PBGetCatInfoSync(pb
); 
 691         pb
->dirInfo
.ioNamePtr 
= NULL
; 
 695 /*****************************************************************************/ 
 697 pascal  OSErr   
DetermineVRefNum(ConstStr255Param pathname
, 
 704         error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
 705         if ( error 
== noErr 
) 
 707                 *realVRefNum 
= pb
.volumeParam
.ioVRefNum
; 
 712 /*****************************************************************************/ 
 714 pascal  OSErr   
HGetVInfo(short volReference
, 
 717                                                   unsigned long *freeBytes
, 
 718                                                   unsigned long *totalBytes
) 
 724         // get the best values possible from XGetVInfo 
 725         result 
= XGetVInfo(volReference
, volName
, vRefNum
, &freeBytes64
, &totalBytes64
); 
 726         if ( result 
== noErr 
) 
 728                 // and pin those values if needed 
 729                 if ( (UInt64ToUnsignedWide(freeBytes64
)).hi 
!= 0 ) 
 731                         // pin to maximum 512-byte block aligned value 
 732                         *freeBytes 
= 0xfffffe00; 
 736                         *freeBytes 
= U32SetU(freeBytes64
); 
 739                 if ( (UInt64ToUnsignedWide(totalBytes64
)).hi 
!= 0 ) 
 741                         // pin to maximum 512-byte block aligned value 
 742                         *totalBytes 
= 0xfffffe00; 
 746                         *totalBytes 
= U32SetU(totalBytes64
); 
 753 /*****************************************************************************/ 
 755 pascal  OSErr   
XGetVInfo(short volReference
, 
 764 #if !TARGET_API_MAC_CARBON 
 768 #endif  //      !TARGET_API_MAC_CARBON 
 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 */ 
 775 #if !TARGET_API_MAC_CARBON 
 777         /* See if large volume support is available */ 
 778         if ( ( Gestalt(gestaltFSAttr
, &response
) == noErr 
) && ((response 
& (1L << gestaltFSSupports2TBVols
)) != 0) ) 
 780 #endif  //      !TARGET_API_MAC_CARBON 
 783                 /* Large volume support is available */ 
 784                 result 
= CallPBXGetVolInfoSync(&pb
); 
 785                 if ( result 
== noErr 
) 
 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
; 
 791                         /* return the freeBytes and totalBytes */ 
 792                         *totalBytes 
= pb
.ioVTotalBytes
; 
 793                         *freeBytes 
= pb
.ioVFreeBytes
; 
 797 #if !TARGET_API_MAC_CARBON 
 801                 /* No large volume support */ 
 802                 /* Use PBHGetVInfoSync to get the results */ 
 803                 result 
= PBHGetVInfoSync((HParmBlkPtr
)&pb
); 
 804                 if ( result 
== noErr 
) 
 808                         /* The volume name was returned in volName (if not NULL) and */ 
 809                         /* we have the volume's vRefNum */ 
 810                         *vRefNum 
= pb
.ioVRefNum
; 
 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. */ 
 823                         /* Find the volume's VCB */ 
 824                         theVCB 
= (VCB 
*)(GetVCBQHdr()->qHead
); 
 825                         while ( theVCB 
!= NULL 
) 
 827                                 if ( theVCB
->vcbVRefNum 
== *vRefNum 
) 
 832                                 theVCB 
= (VCB 
*)(theVCB
->qLink
);        /* next VCB */ 
 835                         if ( theVCB 
!= NULL 
) 
 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
)); 
 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
)); 
 853 #endif  //      !TARGET_API_MAC_CARBON 
 858 /*****************************************************************************/ 
 860 pascal  OSErr   
CheckVolLock(ConstStr255Param pathname
, 
 866         error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
 867         if ( error 
== noErr 
) 
 869                 if ( (pb
.volumeParam
.ioVAtrb 
& kHFSVolumeHardwareLockMask
) != 0 ) 
 871                         error 
= wPrErr
;         /* volume locked by hardware */ 
 873                 else if ( (pb
.volumeParam
.ioVAtrb 
& kHFSVolumeSoftwareLockMask
) != 0 ) 
 875                         error 
= vLckdErr
;       /* volume locked by software */ 
 882 /*****************************************************************************/ 
 884 //      The following routines call Mac OS routines that are not supported by 
 892 #if !TARGET_API_MAC_CARBON      //      { 
 894         /*****************************************************************************/ 
 896         pascal  OSErr 
GetDriverName(short driverRefNum
, 
 901                 DRVRHeaderPtr dHeaderPtr
; 
 903                 theDctl 
= GetDCtlEntry(driverRefNum
); 
 904                 if ( theDctl 
!= NULL 
) 
 906                     if ( (**theDctl
).dCtlFlags 
& dRAMBasedMask 
) 
 908                         /* dctlDriver is handle - dereference */ 
 909                                 dHeaderPtr 
= *((DRVRHeaderHandle
)(**theDctl
).dCtlDriver
); 
 913                                 /* dctlDriver is pointer */ 
 914                       dHeaderPtr 
= (DRVRHeaderPtr
)(**theDctl
).dCtlDriver
; 
 916                         BlockMoveData((*dHeaderPtr
).drvrName
, driverName
, (*dHeaderPtr
).drvrName
[0] + 1); 
 922                         result 
= badUnitErr
;    /* bad reference number */ 
 928         /*****************************************************************************/ 
 930         pascal  OSErr   
FindDrive(ConstStr255Param pathname
, 
 932                                                           DrvQElPtr 
*driveQElementPtr
) 
 938                 *driveQElementPtr 
= NULL
; 
 940                 /* First, use GetVolumeInfoNoName to determine the volume */ 
 941                 result 
= GetVolumeInfoNoName(pathname
, vRefNum
, &hPB
); 
 942                 if ( result 
== noErr 
) 
 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. 
 951                         if ( hPB
.volumeParam
.ioVDrvInfo 
!= 0 ) 
 953                                 /* The volume is online and not ejected */ 
 954                                 /* Get the drive number */ 
 955                                 driveNumber 
= hPB
.volumeParam
.ioVDrvInfo
; 
 959                                 /* The volume's is either offline or ejected */ 
 960                                 /* in either case, the volume is NOT online */ 
 962                                 /* Is it ejected or just offline? */ 
 963                                 if ( hPB
.volumeParam
.ioVDRefNum 
> 0 ) 
 965                                         /* It's ejected, the drive number is ioVDRefNum */ 
 966                                         driveNumber 
= hPB
.volumeParam
.ioVDRefNum
; 
 970                                         /* It's offline, the drive number is the negative of ioVDRefNum */ 
 971                                         driveNumber 
= (short)-hPB
.volumeParam
.ioVDRefNum
; 
 975                         /* Get pointer to first element in drive queue */ 
 976                         *driveQElementPtr 
= (DrvQElPtr
)(GetDrvQHdr()->qHead
); 
 978                         /* Search for a matching drive number */ 
 979                         while ( (*driveQElementPtr 
!= NULL
) && ((*driveQElementPtr
)->dQDrive 
!= driveNumber
) ) 
 981                                 *driveQElementPtr 
= (DrvQElPtr
)(*driveQElementPtr
)->qLink
; 
 984                         if ( *driveQElementPtr 
== NULL 
) 
 986                                 /* This should never happen since every volume must have a drive, but... */ 
 994         /*****************************************************************************/ 
 996         pascal  OSErr   
GetDiskBlocks(ConstStr255Param pathname
, 
 998                                                                   unsigned long *numBlocks
) 
1000                 /* Various constants for GetDiskBlocks() */ 
1003                         /* return format list status code */ 
1006                         /* reference number of .SONY driver */ 
1007                         kSonyRefNum 
= 0xfffb, 
1009                         /* values returned by DriveStatus in DrvSts.twoSideFmt */ 
1012                         kSingleSidedSize 
= 800,         /* 400K */ 
1013                         kDoubleSidedSize 
= 1600,        /* 800K */ 
1015                         /* values in DrvQEl.qType */ 
1019                         /* more than enough formatListRecords */ 
1020                         kMaxFormatListRecs 
= 16 
1023                 DrvQElPtr               driveQElementPtr
; 
1024                 unsigned long   blocks
; 
1026                 FormatListRec   formatListRecords
[kMaxFormatListRecs
]; 
1028                 short                   formatListRecIndex
; 
1033                 /* Find the drive queue element for this volume */ 
1034                 result 
= FindDrive(pathname
, vRefNum
, &driveQElementPtr
); 
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. 
1041                 if ( (result 
== noErr
) && (driveQElementPtr
->dQRefNum 
>= 0) ) 
1047                         /* Attempt to get the drive's format list. */ 
1048                         /* (see the Technical Note "What Your Sony Drives For You") */ 
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]; 
1056                         result 
= PBStatusSync(&pb
); 
1058                         if ( result 
== noErr 
) 
1060                                 /* The drive supports ReturnFormatList status call. */ 
1062                                 /* Get the current disk's size. */ 
1063                                 for( formatListRecIndex 
= 0; 
1064                                          formatListRecIndex 
< pb
.cntrlParam
.csParam
[0]; 
1065                                  ++formatListRecIndex 
) 
1067                                 if ( (formatListRecords
[formatListRecIndex
].formatFlags 
& 
1068                                           diCIFmtFlagsCurrentMask
) != 0 ) 
1070                                         blocks 
= formatListRecords
[formatListRecIndex
].volSize
; 
1075                                 /* This should never happen */ 
1079                         else if ( driveQElementPtr
->dQRefNum 
== (short)kSonyRefNum 
) 
1081                                 /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */ 
1083                                 result 
= DriveStatus(driveQElementPtr
->dQDrive
, &status
); 
1084                                 if ( result 
== noErr 
) 
1086                                         switch ( status
.twoSideFmt 
) 
1089                                                 blocks 
= kSingleSidedSize
; 
1092                                                 blocks 
= kDoubleSidedSize
; 
1095                                                 /* This should never happen */ 
1103                                 /* The drive is not a floppy and it doesn't support ReturnFormatList */ 
1104                                 /* so use the dQDrvSz field(s) */ 
1106                                 result 
= noErr
; /* reset result */ 
1107                                 switch ( driveQElementPtr
->qType 
) 
1110                                         blocks 
= driveQElementPtr
->dQDrvSz
; 
1113                                         blocks 
= ((unsigned long)driveQElementPtr
->dQDrvSz2 
<< 16) + 
1114                                                          driveQElementPtr
->dQDrvSz
; 
1117                                         /* This should never happen */ 
1124                 if ( result 
== noErr 
) 
1126                         *numBlocks 
= blocks
; 
1132         /*****************************************************************************/ 
1134         pascal  OSErr   
GetVolState(ConstStr255Param pathname
, 
1136                                                                 Boolean 
*volumeOnline
, 
1137                                                                 Boolean 
*volumeEjected
, 
1138                                                                 Boolean 
*driveEjectable
, 
1139                                                                 Boolean 
*driverWantsEject
) 
1145                 error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
1146                 if ( error 
== noErr 
) 
1148                         if ( pb
.volumeParam
.ioVDrvInfo 
!= 0 ) 
1150                                 /* the volume is online and not ejected */ 
1151                                 *volumeOnline 
= true; 
1152                                 *volumeEjected 
= false; 
1154                                 /* Get the drive number */ 
1155                                 driveNumber 
= pb
.volumeParam
.ioVDrvInfo
; 
1159                                 /* the volume's is either offline or ejected */ 
1160                                 /* in either case, the volume is NOT online */ 
1161                                 *volumeOnline 
= false; 
1163                                 /* Is it ejected? */ 
1164                                 *volumeEjected 
= pb
.volumeParam
.ioVDRefNum 
> 0; 
1166                                 if ( *volumeEjected 
) 
1168                                         /* If ejected, the drive number is ioVDRefNum */ 
1169                                         driveNumber 
= pb
.volumeParam
.ioVDRefNum
; 
1173                                         /* If offline, the drive number is the negative of ioVDRefNum */ 
1174                                         driveNumber 
= (short)-pb
.volumeParam
.ioVDRefNum
; 
1181                                 /* Find the drive queue element by searching the drive queue */ 
1182                                 drvQElem 
= (DrvQElPtr
)(GetDrvQHdr()->qHead
); 
1183                                 while ( (drvQElem 
!= NULL
) && (drvQElem
->dQDrive 
!= driveNumber
) ) 
1185                                         drvQElem 
= (DrvQElPtr
)drvQElem
->qLink
; 
1188                                 if ( drvQElem 
!= NULL 
) 
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. 
1199                                                 /* point to byte 1 of the flag bytes */ 
1200                                                 flagBytePtr 
= (Ptr
)drvQElem
; 
1204                                                 **      The drive is ejectable if flag byte 1 does not contain 
1205                                                 **      0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call). 
1208                                                 *driveEjectable 
= (*flagBytePtr 
!= 0x08) && (*flagBytePtr 
!= 0x48); 
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. 
1217                                                 *driverWantsEject 
= (*flagBytePtr 
!= 0x08); 
1222                                         /* Didn't find the drive (this should never happen) */ 
1223                                         *driveEjectable 
= false; 
1224                                         *driverWantsEject 
= false; 
1232         /*****************************************************************************/ 
1234 #endif  //      }       !TARGET_API_MAC_CARBON 
1236 /*****************************************************************************/ 
1238 pascal  OSErr   
GetVolFileSystemID(ConstStr255Param pathname
, 
1240                                                                    short *fileSystemID
) 
1245         error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
1246         if ( error 
== noErr 
) 
1248                 *fileSystemID 
= pb
.volumeParam
.ioVFSID
; 
1254 /*****************************************************************************/ 
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). 
1263 pascal  OSErr   
UnmountAndEject(ConstStr255Param pathname
, 
1269         error 
= GetVolumeInfoNoName(pathname
, vRefNum
, &pb
); 
1270         if ( error 
== noErr 
) 
1273 #if     !TARGET_API_MAC_CARBON 
1276                 Boolean ejected
, wantsEject
; 
1279                 if ( pb
.volumeParam
.ioVDrvInfo 
!= 0 ) 
1281                         /* the volume is online and not ejected */ 
1284                         /* Get the drive number */ 
1285                         driveNum 
= pb
.volumeParam
.ioVDrvInfo
; 
1289                         /* the volume is ejected or offline */ 
1291                         /* Is it ejected? */ 
1292                         ejected 
= pb
.volumeParam
.ioVDRefNum 
> 0; 
1296                                 /* If ejected, the drive number is ioVDRefNum */ 
1297                                 driveNum 
= pb
.volumeParam
.ioVDRefNum
; 
1301                                 /* If offline, the drive number is the negative of ioVDRefNum */ 
1302                                 driveNum 
= (short)-pb
.volumeParam
.ioVDRefNum
; 
1306                 /* find the drive queue element */ 
1307                 drvQElem 
= (DrvQElPtr
)(GetDrvQHdr()->qHead
); 
1308                 while ( (drvQElem 
!= NULL
) && (drvQElem
->dQDrive 
!= driveNum
) ) 
1310                         drvQElem 
= (DrvQElPtr
)drvQElem
->qLink
; 
1313                 if ( drvQElem 
!= NULL 
) 
1315                         /* does the drive want an eject call */ 
1316                         wantsEject 
= (*((Ptr
)((Ptr
)drvQElem 
- 3)) != 8); 
1320                         /* didn't find the drive!! */ 
1324 #endif  //      !TARGET_API_MAC_CARBON 
1326                 /* unmount the volume */ 
1327                 pb
.volumeParam
.ioNamePtr 
= NULL
; 
1328                 /* ioVRefNum is already filled in from PBHGetVInfo */ 
1329                 error 
= PBUnmountVol((ParmBlkPtr
)&pb
); 
1331 #if     !TARGET_API_MAC_CARBON 
1333                 if ( error 
== noErr 
) 
1335                         if ( wantsEject 
&& !ejected 
) 
1337                                 /* eject the media from the drive if needed */ 
1338                                 pb
.volumeParam
.ioVRefNum 
= driveNum
; 
1339                                 error 
= PBEject((ParmBlkPtr
)&pb
); 
1343 #endif  //      !TARGET_API_MAC_CARBON 
1350 /*****************************************************************************/ 
1352 pascal  OSErr   
OnLine(FSSpecPtr volumes
, 
1358         OSErr error 
= noErr
; 
1359         FSSpec 
*endVolArray
; 
1361         if ( *volIndex 
> 0 ) 
1364                 for ( endVolArray 
= volumes 
+ reqVolCount
; (volumes 
< endVolArray
) && (error 
== noErr
); ++volumes 
) 
1366                         pb
.volumeParam
.ioNamePtr 
= (StringPtr
) & volumes
->name
; 
1367                         pb
.volumeParam
.ioVolIndex 
= *volIndex
; 
1368                         error 
= PBHGetVInfoSync(&pb
); 
1369                         if ( error 
== noErr 
) 
1371                                 volumes
->parID 
= fsRtParID
;             /* the root directory's parent is 1 */ 
1372                                 volumes
->vRefNum 
= pb
.volumeParam
.ioVRefNum
; 
1386 /*****************************************************************************/ 
1388 pascal  OSErr 
SetDefault(short newVRefNum
, 
1395         /* Get the current default volume/directory. */ 
1396         error 
= HGetVol(NULL
, oldVRefNum
, oldDirID
); 
1397         if ( error 
== noErr 
) 
1399                 /* Set the new default volume/directory */ 
1400                 error 
= HSetVol(NULL
, newVRefNum
, newDirID
); 
1406 /*****************************************************************************/ 
1408 pascal  OSErr 
RestoreDefault(short oldVRefNum
, 
1413 #if     !TARGET_API_MAC_CARBON 
1415         short   defaultVRefNum
; 
1419         /* Determine if the default volume was a wdRefNum. */ 
1420         error 
= GetWDInfo(oldVRefNum
, &defaultVRefNum
, &defaultDirID
, &defaultProcID
); 
1421         if ( error 
== noErr 
) 
1423                 /* Restore the old default volume/directory, one way or the other. */ 
1424                 if ( defaultDirID 
!= fsRtDirID 
) 
1426                         /* oldVRefNum was a wdRefNum - use SetVol */ 
1427                         error 
= SetVol(NULL
, oldVRefNum
); 
1432 #endif  //      !TARGET_API_MAC_CARBON 
1434                         /* oldVRefNum was a real vRefNum - use HSetVol */ 
1435                         error 
= HSetVol(NULL
, oldVRefNum
, oldDirID
); 
1437 #if     !TARGET_API_MAC_CARBON 
1441 #endif  //      !TARGET_API_MAC_CARBON 
1446 /*****************************************************************************/ 
1448 pascal  OSErr 
GetDInfo(short vRefNum
, 
1450                                            ConstStr255Param name
, 
1456         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1457         if ( error 
== noErr 
) 
1459                 if ( (pb
.dirInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
1461                         /* it's a directory, return the DInfo */ 
1462                         *fndrInfo 
= pb
.dirInfo
.ioDrUsrWds
; 
1466                         /* oops, a file was passed */ 
1474 /*****************************************************************************/ 
1476 pascal  OSErr 
FSpGetDInfo(const FSSpec 
*spec
, 
1479         return ( GetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) ); 
1482 /*****************************************************************************/ 
1484 pascal  OSErr 
SetDInfo(short vRefNum
, 
1486                                            ConstStr255Param name
, 
1487                                            const DInfo 
*fndrInfo
) 
1493         /* Protection against File Sharing problem */ 
1494         if ( (name 
== NULL
) || (name
[0] == 0) ) 
1497                 pb
.dirInfo
.ioNamePtr 
= tempName
; 
1498                 pb
.dirInfo
.ioFDirIndex 
= -1;    /* use ioDirID */ 
1502                 pb
.dirInfo
.ioNamePtr 
= (StringPtr
)name
; 
1503                 pb
.dirInfo
.ioFDirIndex 
= 0;     /* use ioNamePtr and ioDirID */ 
1505         pb
.dirInfo
.ioVRefNum 
= vRefNum
; 
1506         pb
.dirInfo
.ioDrDirID 
= dirID
; 
1507         error 
= PBGetCatInfoSync(&pb
); 
1508         if ( error 
== noErr 
) 
1510                 if ( (pb
.dirInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
1512                         /* it's a directory, set the DInfo */ 
1513                         if ( pb
.dirInfo
.ioNamePtr 
== tempName 
) 
1515                                 pb
.dirInfo
.ioDrDirID 
= pb
.dirInfo
.ioDrParID
; 
1519                                 pb
.dirInfo
.ioDrDirID 
= dirID
; 
1521                         pb
.dirInfo
.ioDrUsrWds 
= *fndrInfo
; 
1522                         error 
= PBSetCatInfoSync(&pb
); 
1526                         /* oops, a file was passed */ 
1534 /*****************************************************************************/ 
1536 pascal  OSErr 
FSpSetDInfo(const FSSpec 
*spec
, 
1537                                                   const DInfo 
*fndrInfo
) 
1539         return ( SetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) ); 
1542 /*****************************************************************************/ 
1544 pascal  OSErr   
GetDirectoryID(short vRefNum
, 
1546                                                            ConstStr255Param name
, 
1548                                                            Boolean 
*isDirectory
) 
1553         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1554         if ( error 
== noErr 
) 
1556                 *isDirectory 
= (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0; 
1559                         *theDirID 
= pb
.dirInfo
.ioDrDirID
; 
1563                         *theDirID 
= pb
.hFileInfo
.ioFlParID
; 
1570 /*****************************************************************************/ 
1572 pascal  OSErr   
FSpGetDirectoryID(const FSSpec 
*spec
, 
1574                                                                   Boolean 
*isDirectory
) 
1576         return ( GetDirectoryID(spec
->vRefNum
, spec
->parID
, spec
->name
, 
1577                          theDirID
, isDirectory
) ); 
1580 /*****************************************************************************/ 
1582 pascal  OSErr   
GetDirName(short vRefNum
, 
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
); 
1605 /*****************************************************************************/ 
1607 pascal  OSErr   
GetIOACUser(short vRefNum
, 
1609                                                         ConstStr255Param name
, 
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. 
1620         pb
.dirInfo
.ioACUser 
= 0;        /* ioACUser used to be filler2 */ 
1621         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1622         if ( error 
== noErr 
) 
1624                 if ( (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) == 0 ) 
1626                         /* oops, a file was passed */ 
1631                         *ioACUser 
= pb
.dirInfo
.ioACUser
; 
1638 /*****************************************************************************/ 
1640 pascal  OSErr   
FSpGetIOACUser(const FSSpec 
*spec
, 
1643         return ( GetIOACUser(spec
->vRefNum
, spec
->parID
, spec
->name
, ioACUser
) ); 
1646 /*****************************************************************************/ 
1648 pascal  OSErr   
GetParentID(short vRefNum
, 
1650                                                         ConstStr255Param name
, 
1658         /* Protection against File Sharing problem */ 
1659         if ( (name 
== NULL
) || (name
[0] == 0) ) 
1662                 pb
.hFileInfo
.ioNamePtr 
= tempName
; 
1663                 pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1667                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
1668                 pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1670         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1671         pb
.hFileInfo
.ioDirID 
= dirID
; 
1672         error 
= PBGetCatInfoSync(&pb
); 
1673         if ( error 
== noErr 
) 
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. 
1687                 if ( (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
1689                         /* Its a directory */ 
1691                         /* is there a pathname? */ 
1692                         if ( pb
.hFileInfo
.ioNamePtr 
== name 
)    
1694                                 /* could it contain multiple separators? */ 
1697                                         /* does it contain multiple separators at the end? */ 
1698                                         if ( (name
[name
[0]] == ':') && (name
[name
[0] - 1] == ':') ) 
1700                                                 /* OK, then do the extra stuff to get the correct parID */ 
1702                                                 /* Get the real vRefNum (this should not fail) */ 
1703                                                 error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
1704                                                 if ( error 
== noErr 
) 
1706                                                         /* we don't need the parent's name, but add protect against File Sharing problem */ 
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 */ 
1721                 if ( error 
== noErr 
) 
1723                         /* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */ 
1724                         /* contains the parent ID */ 
1725                         *parID 
= pb
.hFileInfo
.ioFlParID
; 
1732 /*****************************************************************************/ 
1734 pascal  OSErr   
GetFilenameFromPathname(ConstStr255Param pathname
, 
1741         /* default to no filename */ 
1744         /* check for no pathname */ 
1745         if ( pathname 
!= NULL 
) 
1747                 /* get string length */ 
1748                 index 
= pathname
[0]; 
1750                 /* check for empty string */ 
1753                         /* skip over last trailing colon (if any) */ 
1754                         if ( pathname
[index
] == ':' ) 
1759                         /* save the end of the string */ 
1762                         /* if pathname ends with multiple colons, then this pathname refers */ 
1763                         /* to a directory, not a file */ 
1764                         if ( pathname
[index
] != ':' ) 
1766                                 /* parse backwards until we find a colon or hit the beginning of the pathname */ 
1767                                 while ( (index 
!= 0) && (pathname
[index
] != ':') ) 
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]] != ':') ) 
1776                                         /* get the filename and return noErr */ 
1777                                         filename
[0] = (char)(nameEnd 
- index
); 
1778                                         BlockMoveData(&pathname
[index
+1], &filename
[1], nameEnd 
- index
); 
1783                                         /* pathname to a volume, not a file */ 
1784                                         error 
= notAFileErr
; 
1789                                 /* directory, not a file */ 
1790                                 error 
= notAFileErr
; 
1795                         /* empty string isn't a file */ 
1796                         error 
= notAFileErr
; 
1801                 /* NULL pathname isn't a file */ 
1802                 error 
= notAFileErr
; 
1808 /*****************************************************************************/ 
1810 pascal  OSErr   
GetObjectLocation(short vRefNum
, 
1812                                                                   ConstStr255Param pathname
, 
1816                                                                   Boolean 
*isDirectory
) 
1820         Str255 tempPathname
; 
1828         **      Get the real vRefNum 
1830         error 
= DetermineVRefNum(pathname
, vRefNum
, realVRefNum
); 
1831         if ( error 
== noErr 
) 
1834                 **      Determine if the object already exists and if so, 
1835                 **      get the real parent directory ID if it's a file 
1838                 /* Protection against File Sharing problem */ 
1839                 if ( (pathname 
== NULL
) || (pathname
[0] == 0) ) 
1841                         tempPathname
[0] = 0; 
1842                         pb
.hFileInfo
.ioNamePtr 
= tempPathname
; 
1843                         pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1847                         pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)pathname
; 
1848                         pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1850                 pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1851                 pb
.hFileInfo
.ioDirID 
= dirID
; 
1852                 error 
= PBGetCatInfoSync(&pb
); 
1853                 if ( error 
== noErr 
) 
1856                         **      The file system object is present and we have the file's real parID 
1859                         /*      Is it a directory or a file? */ 
1860                         *isDirectory 
= (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0; 
1864                                 **      It's a directory, get its name and parent dirID, and then we're done 
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
); 
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
; 
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 
1883                                 *realParID 
= pb
.hFileInfo
.ioFlParID
;     
1884                                 error 
= GetFilenameFromPathname(pathname
, realName
); 
1887                 else if ( error 
== fnfErr 
) 
1890                         **      The file system object is not present - see if its parent is present 
1894                         **      Parse to get the object name from end of pathname 
1896                         error 
= GetFilenameFromPathname(pathname
, realName
); 
1898                         /* if we can't get the object name from the end, we can't continue */ 
1899                         if ( error 
== noErr 
) 
1902                                 **      What we want now is the pathname minus the object name 
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 '' 
1912                                 /* get a copy of the pathname */ 
1913                                 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); 
1915                                 /* remove the object name */ 
1916                                 tempPathname
[0] -= realName
[0]; 
1917                                 /* and the trailing colon (if any) */ 
1918                                 if ( pathname
[pathname
[0]] == ':' ) 
1923                                 /* OK, now get the parent's directory ID */ 
1925                                 /* Protection against File Sharing problem */ 
1926                                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)tempPathname
; 
1927                                 if ( tempPathname
[0] != 0 ) 
1929                                         pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1933                                         pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1935                                 pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1936                                 pb
.hFileInfo
.ioDirID 
= dirID
; 
1937                                 error 
= PBGetCatInfoSync(&pb
); 
1938                                 *realParID 
= pb
.dirInfo
.ioDrDirID
; 
1940                                 *isDirectory 
= false;   /* we don't know what the object is really going to be */ 
1943                         if ( error 
!= noErr 
) 
1945                                 error 
= dirNFErr
;       /* couldn't find parent directory */ 
1949                                 error 
= fnfErr
; /* we found the parent, but not the file */ 
1957 /*****************************************************************************/ 
1959 pascal  OSErr   
GetDirItems(short vRefNum
, 
1961                                                         ConstStr255Param name
, 
1963                                                         Boolean getDirectories
, 
1966                                                         short *actItemCount
, 
1967                                                         short *itemIndex
) /* start with 1, then use what's returned */ 
1972         Boolean isDirectory
; 
1973         FSSpec 
*endItemsArray
; 
1975         if ( *itemIndex 
> 0 ) 
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. */ 
1985                 /* get the real volume reference number */ 
1986                 error 
= DetermineVRefNum(name
, vRefNum
, &pb
.hFileInfo
.ioVRefNum
); 
1987                 if ( error 
== noErr 
) 
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 
) 
1996                                         endItemsArray 
= items 
+ reqItemCount
; 
1997                                         while ( (items 
< endItemsArray
) && (error 
== noErr
) ) 
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 
) 
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 */ 
2009                                                         if ( (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
2011                                                                 if ( getDirectories 
) 
2013                                                                         ++*actItemCount
; /* keep this item */ 
2014                                                                         ++items
; /* point to next item */ 
2021                                                                         ++*actItemCount
; /* keep this item */ 
2022                                                                         ++items
; /* point to next item */ 
2030                                         /* it wasn't a directory */ 
2045 /*****************************************************************************/ 
2047 static  void    DeleteLevel(long dirToDelete
, 
2048                                                         DeleteEnumGlobalsPtr theGlobals
) 
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 
) 
2061                         savedDir 
= dirToDelete
; 
2062                         /* We have an item.  Is it a file or directory? */ 
2063                         if ( (theGlobals
->myPB
.ciPB
.dirInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
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 */ 
2070                         if ( theGlobals
->error 
== noErr 
) 
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 
) 
2077                                         (void) PBHRstFLockSync(&(theGlobals
->myPB
.hPB
));        /* unlock it */ 
2078                                         theGlobals
->error 
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
));     /* and try again */ 
2082         } while ( theGlobals
->error 
== noErr 
); 
2084         if ( theGlobals
->error 
== fnfErr 
) 
2086                 theGlobals
->error 
= noErr
; 
2090 /*****************************************************************************/ 
2092 pascal  OSErr   
DeleteDirectoryContents(short vRefNum
, 
2094                                                                                 ConstStr255Param name
) 
2096         DeleteEnumGlobals theGlobals
; 
2097         Boolean isDirectory
; 
2100         /*  Get the real dirID and make sure it is a directory. */ 
2101         error 
= GetDirectoryID(vRefNum
, dirID
, name
, &dirID
, &isDirectory
); 
2102         if ( error 
== noErr 
) 
2106                         /* Get the real vRefNum */ 
2107                         error 
= DetermineVRefNum(name
, vRefNum
, &vRefNum
); 
2108                         if ( error 
== noErr 
) 
2110                                 /* Set up the globals we need to access from the recursive routine. */ 
2111                                 theGlobals
.myPB
.ciPB
.dirInfo
.ioVRefNum 
= vRefNum
; 
2113                                 /* Here we go into recursion land... */ 
2114                                 DeleteLevel(dirID
, &theGlobals
); 
2115                                 error 
= theGlobals
.error
; 
2127 /*****************************************************************************/ 
2129 pascal  OSErr   
DeleteDirectory(short vRefNum
, 
2131                                                                 ConstStr255Param name
) 
2135         /* Make sure a directory was specified and then delete its contents */ 
2136         error 
= DeleteDirectoryContents(vRefNum
, dirID
, name
); 
2137         if ( error 
== noErr 
) 
2139                 error 
= HDelete(vRefNum
, dirID
, name
); 
2140                 if ( error 
== fLckdErr 
) 
2142                         (void) HRstFLock(vRefNum
, dirID
, name
); /* unlock the directory locked by AppleShare */ 
2143                         error 
= HDelete(vRefNum
, dirID
, name
);  /* and try again */ 
2150 /*****************************************************************************/ 
2152 pascal  OSErr   
CheckObjectLock(short vRefNum
, 
2154                                                                 ConstStr255Param name
) 
2159         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
2160         if ( error 
== noErr 
) 
2162                 /* check locked bit */ 
2163                 if ( (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribLockedMask
) != 0 ) 
2172 /*****************************************************************************/ 
2174 pascal  OSErr   
FSpCheckObjectLock(const FSSpec 
*spec
) 
2176         return ( CheckObjectLock(spec
->vRefNum
, spec
->parID
, spec
->name
) ); 
2179 /*****************************************************************************/ 
2181 pascal  OSErr   
GetFileSize(short vRefNum
, 
2183                                                         ConstStr255Param fileName
, 
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 
) 
2198                 *dataSize 
= pb
.fileParam
.ioFlLgLen
; 
2199                 *rsrcSize 
= pb
.fileParam
.ioFlRLgLen
; 
2205 /*****************************************************************************/ 
2207 pascal  OSErr   
FSpGetFileSize(const FSSpec 
*spec
, 
2211         return ( GetFileSize(spec
->vRefNum
, spec
->parID
, spec
->name
, dataSize
, rsrcSize
) ); 
2214 /*****************************************************************************/ 
2216 pascal  OSErr   
BumpDate(short vRefNum
, 
2218                                                  ConstStr255Param name
) 
2219 /* Given a file or directory, change its modification date to the current date/time. */ 
2226         /* Protection against File Sharing problem */ 
2227         if ( (name 
== NULL
) || (name
[0] == 0) ) 
2230                 pb
.hFileInfo
.ioNamePtr 
= tempName
; 
2231                 pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
2235                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
2236                 pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
2238         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
2239         pb
.hFileInfo
.ioDirID 
= dirID
; 
2240         error 
= PBGetCatInfoSync(&pb
); 
2241         if ( error 
== noErr 
) 
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 
) 
2249                         pb
.hFileInfo
.ioDirID 
= pb
.hFileInfo
.ioFlParID
; 
2253                         pb
.hFileInfo
.ioDirID 
= dirID
; 
2255                 error 
= PBSetCatInfoSync(&pb
); 
2261 /*****************************************************************************/ 
2263 pascal  OSErr   
FSpBumpDate(const FSSpec 
*spec
) 
2265         return ( BumpDate(spec
->vRefNum
, spec
->parID
, spec
->name
) ); 
2268 /*****************************************************************************/ 
2270 pascal  OSErr   
ChangeCreatorType(short vRefNum
, 
2272                                                                   ConstStr255Param name
, 
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 
) 
2288                 if ( (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) == 0 )      /* if file */ 
2290                         parID 
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */ 
2292                         /* If creator not 0x00000000, change creator */ 
2293                         if ( creator 
!= (OSType
)0x00000000 ) 
2295                                 pb
.hFileInfo
.ioFlFndrInfo
.fdCreator 
= creator
; 
2298                         /* If fileType not 0x00000000, change fileType */ 
2299                         if ( fileType 
!= (OSType
)0x00000000 ) 
2301                                 pb
.hFileInfo
.ioFlFndrInfo
.fdType 
= fileType
; 
2304                         pb
.hFileInfo
.ioDirID 
= dirID
; 
2305                         error 
= PBSetCatInfoSync(&pb
);  /* now, save the new information back to disk */ 
2307                         if ( (error 
== noErr
) && (parID 
!= fsRtParID
) ) /* can't bump fsRtParID */ 
2309                                 /* get the real vRefNum in case a full pathname was passed */ 
2310                                 error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
2311                                 if ( error 
== noErr 
) 
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 */ 
2321                         /* it was a directory, not a file */ 
2322                         error 
= notAFileErr
; 
2329 /*****************************************************************************/ 
2331 pascal  OSErr   
FSpChangeCreatorType(const FSSpec 
*spec
, 
2335         return ( ChangeCreatorType(spec
->vRefNum
, spec
->parID
, spec
->name
, creator
, fileType
) ); 
2338 /*****************************************************************************/ 
2340 pascal  OSErr   
ChangeFDFlags(short vRefNum
, 
2342                                                           ConstStr255Param name
, 
2344                                                           unsigned short flagBits
) 
2352         /* Protection against File Sharing problem */ 
2353         if ( (name 
== NULL
) || (name
[0] == 0) ) 
2356                 pb
.hFileInfo
.ioNamePtr 
= tempName
; 
2357                 pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
2361                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
2362                 pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
2364         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
2365         pb
.hFileInfo
.ioDirID 
= dirID
; 
2366         error 
= PBGetCatInfoSync(&pb
); 
2367         if ( error 
== noErr 
) 
2369                 parID 
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */ 
2371                 /* set or clear the appropriate bits in the Finder flags */ 
2374                         /* OR in the bits */ 
2375                         pb
.hFileInfo
.ioFlFndrInfo
.fdFlags 
|= flagBits
; 
2379                         /* AND out the bits */ 
2380                         pb
.hFileInfo
.ioFlFndrInfo
.fdFlags 
&= ~flagBits
; 
2383                 if ( pb
.dirInfo
.ioNamePtr 
== tempName 
) 
2385                         pb
.hFileInfo
.ioDirID 
= pb
.hFileInfo
.ioFlParID
; 
2389                         pb
.hFileInfo
.ioDirID 
= dirID
; 
2392                 error 
= PBSetCatInfoSync(&pb
);  /* now, save the new information back to disk */ 
2394                 if ( (error 
== noErr
) && (parID 
!= fsRtParID
) ) /* can't bump fsRtParID */ 
2396                         /* get the real vRefNum in case a full pathname was passed */ 
2397                         error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
2398                         if ( error 
== noErr 
) 
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 */ 
2410 /*****************************************************************************/ 
2412 pascal  OSErr   
FSpChangeFDFlags(const FSSpec 
*spec
, 
2414                                                                  unsigned short flagBits
) 
2416         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, setBits
, flagBits
) ); 
2419 /*****************************************************************************/ 
2421 pascal  OSErr   
SetIsInvisible(short vRefNum
, 
2423                                                            ConstStr255Param name
) 
2424         /* Given a file or directory, make it invisible. */ 
2426         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsInvisible
) ); 
2429 /*****************************************************************************/ 
2431 pascal  OSErr   
FSpSetIsInvisible(const FSSpec 
*spec
) 
2432         /* Given a file or directory, make it invisible. */ 
2434         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsInvisible
) ); 
2437 /*****************************************************************************/ 
2439 pascal  OSErr   
ClearIsInvisible(short vRefNum
, 
2441                                                                  ConstStr255Param name
) 
2442         /* Given a file or directory, make it visible. */ 
2444         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsInvisible
) ); 
2447 /*****************************************************************************/ 
2449 pascal  OSErr   
FSpClearIsInvisible(const FSSpec 
*spec
) 
2450         /* Given a file or directory, make it visible. */ 
2452         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsInvisible
) ); 
2455 /*****************************************************************************/ 
2457 pascal  OSErr   
SetNameLocked(short vRefNum
, 
2459                                                           ConstStr255Param name
) 
2460         /* Given a file or directory, lock its name. */ 
2462         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kNameLocked
) ); 
2465 /*****************************************************************************/ 
2467 pascal  OSErr   
FSpSetNameLocked(const FSSpec 
*spec
) 
2468         /* Given a file or directory, lock its name. */ 
2470         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kNameLocked
) ); 
2473 /*****************************************************************************/ 
2475 pascal  OSErr   
ClearNameLocked(short vRefNum
, 
2477                                                                 ConstStr255Param name
) 
2478         /* Given a file or directory, unlock its name. */ 
2480         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kNameLocked
) ); 
2483 /*****************************************************************************/ 
2485 pascal  OSErr   
FSpClearNameLocked(const FSSpec 
*spec
) 
2486         /* Given a file or directory, unlock its name. */ 
2488         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kNameLocked
) ); 
2491 /*****************************************************************************/ 
2493 pascal  OSErr   
SetIsStationery(short vRefNum
, 
2495                                                                 ConstStr255Param name
) 
2496         /* Given a file, make it a stationery pad. */ 
2498         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsStationery
) ); 
2501 /*****************************************************************************/ 
2503 pascal  OSErr   
FSpSetIsStationery(const FSSpec 
*spec
) 
2504         /* Given a file, make it a stationery pad. */ 
2506         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsStationery
) ); 
2509 /*****************************************************************************/ 
2511 pascal  OSErr   
ClearIsStationery(short vRefNum
, 
2513                                                                   ConstStr255Param name
) 
2514         /* Given a file, clear the stationery bit. */ 
2516         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsStationery
) ); 
2519 /*****************************************************************************/ 
2521 pascal  OSErr   
FSpClearIsStationery(const FSSpec 
*spec
) 
2522         /* Given a file, clear the stationery bit. */ 
2524         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsStationery
) ); 
2527 /*****************************************************************************/ 
2529 pascal  OSErr   
SetHasCustomIcon(short vRefNum
, 
2531                                                                  ConstStr255Param name
) 
2532         /* Given a file or directory, indicate that it has a custom icon. */ 
2534         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kHasCustomIcon
) ); 
2537 /*****************************************************************************/ 
2539 pascal  OSErr   
FSpSetHasCustomIcon(const FSSpec 
*spec
) 
2540         /* Given a file or directory, indicate that it has a custom icon. */ 
2542         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kHasCustomIcon
) ); 
2545 /*****************************************************************************/ 
2547 pascal  OSErr   
ClearHasCustomIcon(short vRefNum
, 
2549                                                                    ConstStr255Param name
) 
2550         /* Given a file or directory, indicate that it does not have a custom icon. */ 
2552         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasCustomIcon
) ); 
2555 /*****************************************************************************/ 
2557 pascal  OSErr   
FSpClearHasCustomIcon(const FSSpec 
*spec
) 
2558         /* Given a file or directory, indicate that it does not have a custom icon. */ 
2560         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasCustomIcon
) ); 
2563 /*****************************************************************************/ 
2565 pascal  OSErr   
ClearHasBeenInited(short vRefNum
, 
2567                                                                    ConstStr255Param name
) 
2568         /* Given a file, clear its "has been inited" bit. */ 
2570         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasBeenInited
) ); 
2573 /*****************************************************************************/ 
2575 pascal  OSErr   
FSpClearHasBeenInited(const FSSpec 
*spec
) 
2576         /* Given a file, clear its "has been inited" bit. */ 
2578         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasBeenInited
) ); 
2581 /*****************************************************************************/ 
2583 pascal  OSErr   
CopyFileMgrAttributes(short srcVRefNum
, 
2585                                                                           ConstStr255Param srcName
, 
2588                                                                           ConstStr255Param dstName
, 
2589                                                                           Boolean copyLockBit
) 
2594         Boolean objectIsDirectory
; 
2596         pb
.ciPB
.hFileInfo
.ioVRefNum 
= srcVRefNum
; 
2597         pb
.ciPB
.hFileInfo
.ioDirID 
= srcDirID
; 
2599         /* Protection against File Sharing problem */ 
2600         if ( (srcName 
== NULL
) || (srcName
[0] == 0) ) 
2603                 pb
.ciPB
.hFileInfo
.ioNamePtr 
= tempName
; 
2604                 pb
.ciPB
.hFileInfo
.ioFDirIndex 
= -1;     /* use ioDirID */ 
2608                 pb
.ciPB
.hFileInfo
.ioNamePtr 
= (StringPtr
)srcName
; 
2609                 pb
.ciPB
.hFileInfo
.ioFDirIndex 
= 0;      /* use ioNamePtr and ioDirID */ 
2611         error 
= PBGetCatInfoSync(&pb
.ciPB
); 
2612         if ( error 
== noErr 
) 
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) ) 
2619                         pb
.ciPB
.hFileInfo
.ioNamePtr 
= NULL
; 
2623                         pb
.ciPB
.hFileInfo
.ioNamePtr 
= (StringPtr
)dstName
; 
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) ) 
2630                         pb
.hPB
.fileParam
.ioFVersNum 
= 0; 
2631                         error 
= PBHSetFLockSync(&pb
.hPB
); 
2632                         if ( (error 
!= noErr
) && (objectIsDirectory
) ) 
2634                                 error 
= noErr
; /* ignore lock errors if destination is directory */ 
2641 /*****************************************************************************/ 
2643 pascal  OSErr   
FSpCopyFileMgrAttributes(const FSSpec 
*srcSpec
, 
2644                                                                                  const FSSpec 
*dstSpec
, 
2645                                                                                  Boolean copyLockBit
) 
2647         return ( CopyFileMgrAttributes(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
2648                                                                    dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
, 
2652 /*****************************************************************************/ 
2654 pascal  OSErr   
HOpenAware(short vRefNum
, 
2656                                                    ConstStr255Param fileName
, 
2662         GetVolParmsInfoBuffer volParmsInfo
; 
2663         long infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
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
; 
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
) ) 
2677                 /* if volume supports OpenDeny, use it and return */ 
2678                         pb
.accessParam
.ioDenyModes 
= denyModes
; 
2679                         error 
= PBHOpenDenySync(&pb
); 
2680                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2682         else if ( (error 
== noErr
) || (error 
== paramErr
) )     /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 
2684                 /* OpenDeny isn't supported, so try File Manager Open functions */ 
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. */ 
2691                 if ( (denyModes 
& dmWr
) != 0 ) 
2693                         error 
= CheckVolLock(fileName
, vRefNum
); 
2700                 if ( error 
== noErr 
) 
2702                         /* Set File Manager permissions to closest thing possible */ 
2703                         if ( (denyModes 
== dmWr
) || (denyModes 
== dmRdWr
) ) 
2705                                 pb
.ioParam
.ioPermssn 
= fsRdWrShPerm
; 
2709                                 pb
.ioParam
.ioPermssn 
= denyModes 
% 4; 
2712                         error 
= PBHOpenDFSync(&pb
);                             /* Try OpenDF */ 
2713                         if ( error 
== paramErr 
) 
2715                                 error 
= PBHOpenSync(&pb
);                       /* OpenDF not supported, so try Open */ 
2717                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2724 /*****************************************************************************/ 
2726 pascal  OSErr   
FSpOpenAware(const FSSpec 
*spec
, 
2730         return ( HOpenAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) ); 
2733 /*****************************************************************************/ 
2735 pascal  OSErr   
HOpenRFAware(short vRefNum
, 
2737                                                          ConstStr255Param fileName
, 
2743         GetVolParmsInfoBuffer volParmsInfo
; 
2744         long infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
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
; 
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
) ) 
2758                 /* if volume supports OpenRFDeny, use it and return */ 
2759                 if ( hasOpenDeny(&volParmsInfo
) ) 
2761                         pb
.accessParam
.ioDenyModes 
= denyModes
; 
2762                         error 
= PBHOpenRFDenySync(&pb
); 
2763                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2766         else if ( (error 
== noErr
) || (error 
== paramErr
) )     /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 
2768                 /* OpenRFDeny isn't supported, so try File Manager OpenRF function */ 
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. */ 
2775                 if ( (denyModes 
& dmWr
) != 0 ) 
2777                         error 
= CheckVolLock(fileName
, vRefNum
); 
2784                 if ( error 
== noErr 
) 
2786                         /* Set File Manager permissions to closest thing possible */ 
2787                         if ( (denyModes 
== dmWr
) || (denyModes 
== dmRdWr
) ) 
2789                                 pb
.ioParam
.ioPermssn 
= fsRdWrShPerm
; 
2793                                 pb
.ioParam
.ioPermssn 
= denyModes 
% 4; 
2796                         error 
= PBHOpenRFSync(&pb
); 
2797                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2804 /*****************************************************************************/ 
2806 pascal  OSErr   
FSpOpenRFAware(const FSSpec 
*spec
, 
2810         return ( HOpenRFAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) ); 
2813 /*****************************************************************************/ 
2815 pascal  OSErr   
FSReadNoCache(short refNum
, 
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 */ 
2832 /*****************************************************************************/ 
2834 pascal  OSErr   
FSWriteNoCache(short refNum
, 
2836                                                            const void *buffPtr
) 
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 */ 
2851 /*****************************************************************************/ 
2854 **      See if numBytes bytes of buffer1 are equal to buffer2. 
2856 static  Boolean 
EqualMemory(const void *buffer1
, const void *buffer2
, unsigned long numBytes
) 
2858         register unsigned char *b1 
= (unsigned char *)buffer1
; 
2859         register unsigned char *b2 
= (unsigned char *)buffer2
; 
2861         if ( b1 
!= b2 
) /* if buffer pointers are same, then they are equal */ 
2863                 while ( numBytes 
> 0 ) 
2865                         /* compare the bytes and then increment the pointers */ 
2866                         if ( (*b1
++ - *b2
++) != 0 ) 
2877 /*****************************************************************************/ 
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. 
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. 
2892 static  OSErr   
FSReadVerify(short refNum
, 
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 */ 
2909 /*****************************************************************************/ 
2911 pascal  OSErr   
FSWriteVerify(short refNum
, 
2913                                                           const void *buffPtr
) 
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. 
2928         bufferSize 
= *count
; 
2929         verifyBuffer 
= NewPtr(bufferSize
); 
2930         if ( verifyBuffer 
== NULL 
) 
2932                 verifyBuffer 
= GetTempBuffer(bufferSize
, &bufferSize
); 
2934         if ( verifyBuffer 
!= NULL 
) 
2936                 /* Save the current position */ 
2937                 result 
= GetFPos(refNum
, &position
); 
2938                 if ( result 
== noErr 
) 
2940                         /* Write the data */ 
2941                         result 
= FSWrite(refNum
, count
, buffPtr
); 
2942                         if ( result 
== noErr 
) 
2944                                 /* Restore the original position */ 
2945                                 result 
= SetFPos(refNum
, fsFromStart
, position
); 
2946                                 if ( result 
== noErr 
) 
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 
2956                                         startVerify 
= (Ptr
)buffPtr
; 
2957                                         while ( (bytesVerified 
< *count
) && ( result 
== noErr 
) ) 
2959                                                 if ( (*count 
- bytesVerified
) > bufferSize 
) 
2961                                                         byteCount 
= bufferSize
; 
2965                                                         byteCount 
= *count 
- bytesVerified
; 
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. 
2979                                                 BlockMoveData(startVerify
, verifyBuffer
, byteCount
); 
2981                                                 /* Read-verify the data back into the verify buffer */ 
2982                                                 result 
= FSReadVerify(refNum
, &byteCount
, verifyBuffer
); 
2983                                                 if ( result 
== noErr 
) 
2985                                                         /* See if the buffers are the same */ 
2986                                                         if ( !EqualMemory(verifyBuffer
, startVerify
, byteCount
) ) 
2990                                                         startVerify 
+= byteCount
; 
2991                                                         bytesVerified 
+= byteCount
; 
2997                 DisposePtr(verifyBuffer
); 
3001                 result 
= memFullErr
; 
3006 /*****************************************************************************/ 
3008 pascal  OSErr   
CopyFork(short srcRefNum
, 
3010                                                  void *copyBufferPtr
, 
3011                                                  long copyBufferSize
) 
3013         ParamBlockRec srcPB
; 
3014         ParamBlockRec dstPB
; 
3018         if ( (copyBufferPtr 
== NULL
) || (copyBufferSize 
== 0) ) 
3019                 return ( paramErr 
); 
3021         srcPB
.ioParam
.ioRefNum 
= srcRefNum
; 
3022         dstPB
.ioParam
.ioRefNum 
= dstRefNum
; 
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 
); 
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 
); 
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 
); 
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) ) 
3055                 srcPB
.ioParam
.ioReqCount 
= copyBufferSize 
& 0xfffffe00; 
3059                 srcPB
.ioParam
.ioReqCount 
= copyBufferSize
; 
3061         dstPB
.ioParam
.ioBuffer 
= (Ptr
)copyBufferPtr
; 
3062         dstPB
.ioParam
.ioPosMode 
= fsAtMark 
+ noCacheMask
;/* fsAtMark + noCacheMask */ 
3064         while ( (srcError 
== noErr
) && (dstError 
== noErr
) ) 
3066                 srcError 
= PBReadSync(&srcPB
); 
3067                 dstPB
.ioParam
.ioReqCount 
= srcPB
.ioParam
.ioActCount
; 
3068                 dstError 
= PBWriteSync(&dstPB
); 
3071         /* make sure there were no errors at the destination */ 
3072         if ( dstError 
!= noErr 
) 
3073                 return ( dstError 
); 
3075         /* make sure the only error at the source was eofErr */ 
3076         if ( srcError 
!= eofErr 
) 
3077                 return ( srcError 
); 
3082 /*****************************************************************************/ 
3084 pascal  OSErr   
GetFileLocation(short refNum
, 
3092         pb
.ioNamePtr 
= fileName
; 
3094         pb
.ioRefNum 
= refNum
; 
3096         error 
= PBGetFCBInfoSync(&pb
); 
3097         if ( error 
== noErr 
) 
3099                 *vRefNum 
= pb
.ioFCBVRefNum
; 
3100                 *dirID 
= pb
.ioFCBParID
; 
3105 /*****************************************************************************/ 
3107 pascal  OSErr   
FSpGetFileLocation(short refNum
, 
3110         return ( GetFileLocation(refNum
, &(spec
->vRefNum
), &(spec
->parID
), spec
->name
) ); 
3113 /*****************************************************************************/ 
3115 pascal  OSErr   
CopyDirectoryAccess(short srcVRefNum
, 
3117                                                                         ConstStr255Param srcName
, 
3120                                                                         ConstStr255Param dstName
) 
3123         GetVolParmsInfoBuffer infoBuffer
;       /* Where PBGetVolParms dumps its info */ 
3124         long    dstServerAdr
;                           /* AppleTalk server address of destination (if any) */ 
3125         long    ownerID
, groupID
, accessRights
; 
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
) ) 
3133                 if ( hasAccessCntl(&infoBuffer
) ) 
3135                         dstServerAdr 
= infoBuffer
.vMServerAdr
; 
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 
) 
3142                                 if ( hasAccessCntl(&infoBuffer
) && (dstServerAdr 
== infoBuffer
.vMServerAdr
) ) 
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 
) 
3149                                                 error 
= HSetDirAccess(dstVRefNum
, dstDirID
, dstName
, ownerID
, groupID
, accessRights
); 
3154                                         /* destination doesn't support directory access control or */ 
3155                                         /* they volumes aren't on the same server */ 
3162                         /* destination doesn't support directory access control */ 
3170 /*****************************************************************************/ 
3172 pascal  OSErr   
FSpCopyDirectoryAccess(const FSSpec 
*srcSpec
, 
3173                                                                            const FSSpec 
*dstSpec
) 
3175         return ( CopyDirectoryAccess(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
3176                                                                 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
) ); 
3179 /*****************************************************************************/ 
3181 pascal  OSErr   
HMoveRenameCompat(short vRefNum
, 
3183                                                                   ConstStr255Param srcName
, 
3185                                                                   ConstStr255Param dstpathName
, 
3186                                                                   ConstStr255Param copyName
) 
3189         GetVolParmsInfoBuffer   volParmsInfo
; 
3194         Boolean                                 isDirectory
; 
3195         long                                    tempItemsDirID
; 
3196         long                                    uniqueTempDirID
; 
3197         Str31                                   uniqueTempDirName
; 
3198         unsigned short                  uniqueNameoverflow
; 
3200         /* Get volume attributes */ 
3201         infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
3202         error 
= HGetVolParms((StringPtr
)srcName
, vRefNum
, &volParmsInfo
, &infoSize
); 
3203         if ( (error 
== noErr
) && hasMoveRename(&volParmsInfo
) ) 
3205                 /* If volume supports move and rename, so use it and return */ 
3206                 error 
= HMoveRename(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
, copyName
); 
3208         else if ( (error 
== noErr
) || (error 
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 
3210                 /* MoveRename isn't supported by this volume, so do it by hand */ 
3212                 /* If copyName isn't supplied, we can simply CatMove and return */ 
3213                 if ( copyName 
== NULL 
) 
3215                         error 
= CatMove(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
); 
3219                         /* Renaming is required, so we have some work to do... */ 
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 
) 
3226                                 /* Find the Temporary Items Folder on that volume */ 
3227                                 error 
= FindFolder(realVRefNum
, kTemporaryFolderType
, kCreateFolder
, 
3228                                                                         &realVRefNum
, &tempItemsDirID
); 
3229                                 if ( error 
== noErr 
) 
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. */ 
3235                                         /* Start with current tick count as uniqueTempDirName */                                         
3236                                         NumToString(TickCount(), uniqueTempDirName
); 
3237                                         uniqueNameoverflow 
= 0; 
3240                                                 error 
= DirCreate(realVRefNum
, tempItemsDirID
, uniqueTempDirName
, &uniqueTempDirID
); 
3241                                                 if ( error 
== dupFNErr 
) 
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] == ':' ) 
3248                                                                 ++uniqueTempDirName
[1]; 
3250                                                         /* Don't go too far... */ 
3251                                                         ++uniqueNameoverflow
; 
3253                                         } while ( (error 
== dupFNErr
) && (uniqueNameoverflow 
<= 64) ); /* 64 new files per 1/60th second - not likely! */ 
3254                                         if ( error 
== noErr 
) 
3256                                                 /* Move the object to the folder with uniqueTempDirID for renaming */ 
3257                                                 error 
= CatMove(realVRefNum
, realParID
, realName
, uniqueTempDirID
, NULL
); 
3258                                                 if ( error 
== noErr 
) 
3260                                                         /* Rename the object */  
3261                                                         error 
= HRename(realVRefNum
, uniqueTempDirID
, realName
, copyName
); 
3262                                                         if ( error 
== noErr 
) 
3264                                                                 /* Move object to its new home */ 
3265                                                                 error 
= CatMove(realVRefNum
, uniqueTempDirID
, copyName
, dstDirID
, dstpathName
); 
3266                                                                 if ( error 
!= noErr 
) 
3268                                                                         /* Error handling: rename object back to original name - ignore errors */ 
3269                                                                         (void) HRename(realVRefNum
, uniqueTempDirID
, copyName
, realName
); 
3272                                                         if ( error 
!= noErr 
) 
3274                                                                 /* Error handling: move object back to original location - ignore errors */ 
3275                                                                 (void) CatMove(realVRefNum
, uniqueTempDirID
, realName
, realParID
, NULL
); 
3278                                                 /* Done with ourTempDir, so delete it - ignore errors */ 
3279                                                 (void) HDelete(realVRefNum
, uniqueTempDirID
, NULL
); 
3289 /*****************************************************************************/ 
3291 pascal  OSErr   
FSpMoveRenameCompat(const FSSpec 
*srcSpec
, 
3292                                                                         const FSSpec 
*dstSpec
, 
3293                                                                         ConstStr255Param copyName
) 
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
) ); 
3302 /*****************************************************************************/ 
3304 pascal  OSErr   
BuildAFPVolMountInfo(short flags
, 
3314                                                                          AFPVolMountInfoPtr 
*afpInfoPtr
) 
3316         MyAFPVolMountInfoPtr    infoPtr
; 
3319         /* Allocate the AFPXVolMountInfo record */ 
3320         infoPtr 
= (MyAFPVolMountInfoPtr
)NewPtrClear(sizeof(MyAFPVolMountInfo
)); 
3321         if ( infoPtr 
!= NULL 
) 
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
; 
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
); 
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
)); 
3345                 *afpInfoPtr 
= (AFPVolMountInfoPtr
)infoPtr
; 
3356 /*****************************************************************************/ 
3358 pascal  OSErr   
RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr
, 
3362                                                                                 StringPtr serverName
, 
3369         /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */ 
3370         if ( afpInfoPtr
->media 
== AppleShareMediaType 
) 
3372                 *flags 
= afpInfoPtr
->flags
; 
3373                 *uamType 
= afpInfoPtr
->uamType
; 
3375                 if ( afpInfoPtr
->zoneNameOffset 
!= 0) 
3377                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->zoneNameOffset
); 
3378                         BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1); 
3381                 if ( afpInfoPtr
->serverNameOffset 
!= 0) 
3383                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->serverNameOffset
); 
3384                         BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1); 
3387                 if ( afpInfoPtr
->volNameOffset 
!= 0) 
3389                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->volNameOffset
); 
3390                         BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1); 
3393                 if ( afpInfoPtr
->userNameOffset 
!= 0) 
3395                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->userNameOffset
); 
3396                         BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1); 
3409 /*****************************************************************************/ 
3411 pascal  OSErr   
BuildAFPXVolMountInfo(short flags
, 
3422                                                                           unsigned long alternateAddressLength
, 
3423                                                                           void *alternateAddress
, 
3424                                                                           AFPXVolMountInfoPtr 
*afpXInfoPtr
) 
3427         MyAFPXVolMountInfoPtr   infoPtr
; 
3430         /* Calculate the size of the AFPXVolMountInfo record */ 
3431         infoSize 
= sizeof(MyAFPXVolMountInfo
) + alternateAddressLength 
- 1; 
3433         /* Allocate the AFPXVolMountInfo record */ 
3434         infoPtr 
= (MyAFPXVolMountInfoPtr
)NewPtrClear(infoSize
); 
3435         if ( infoPtr 
!= NULL 
) 
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 ) 
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
; 
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; 
3455                 infoPtr
->nbpInterval 
= nbpInterval
; 
3456                 infoPtr
->nbpCount 
= nbpCount
; 
3457                 infoPtr
->uamType 
= uamType
; 
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
); 
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
); 
3477                 *afpXInfoPtr 
= (AFPXVolMountInfoPtr
)infoPtr
; 
3488 /*****************************************************************************/ 
3490 pascal  OSErr   
RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr
, 
3494                                                                                  StringPtr serverName
, 
3498                                                                                  unsigned long *alternateAddressLength
, 
3499                                                                                  AFPAlternateAddress 
**alternateAddress
) 
3502         Ptr                     alternateAddressStart
; 
3503         Ptr                     alternateAddressEnd
; 
3504         Size            alternateAddressDataSize
; 
3508         /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */ 
3509         if ( afpXInfoPtr
->media 
== AppleShareMediaType 
) 
3511                 /* default to noErr */ 
3514                 /* Is this an extended record? */ 
3515                 if ( (afpXInfoPtr
->flags 
& volMountExtendedFlagsMask
) != 0 ) 
3517                         if ( ((afpXInfoPtr
->extendedFlags 
& kAFPExtendedFlagsAlternateAddressMask
) != 0) && 
3518                                  (afpXInfoPtr
->alternateAddressOffset 
!= 0) ) 
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 ) 
3528                                         /* parse the address list to find the end */ 
3529                                         alternateAddressEnd 
+= *(UInt8
*)alternateAddressEnd
;    /* add length of each AFPTagData record */ 
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 
) 
3538                                         /* and return the data */ 
3539                                         BlockMoveData(alternateAddressStart
, *alternateAddress
, alternateAddressDataSize
); 
3540                                         *alternateAddressLength 
= alternateAddressDataSize
; 
3544                                         /* no memory - fail now */ 
3549                         if ( error 
== noErr 
)   /* fill in more output parameters if everything is OK */ 
3551                                 if ( afpXInfoPtr
->uamNameOffset 
!= 0 ) 
3553                                         tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->uamNameOffset
); 
3554                                         BlockMoveData(tempPtr
, uamName
, tempPtr
[0] + 1); 
3559                 if ( error 
== noErr 
)   /* fill in more output parameters if everything is OK */ 
3561                         *flags 
= afpXInfoPtr
->flags
; 
3562                         *uamType 
= afpXInfoPtr
->uamType
; 
3564                         if ( afpXInfoPtr
->zoneNameOffset 
!= 0 ) 
3566                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->zoneNameOffset
); 
3567                                 BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1); 
3570                         if ( afpXInfoPtr
->serverNameOffset 
!= 0 ) 
3572                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->serverNameOffset
); 
3573                                 BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1); 
3576                         if ( afpXInfoPtr
->volNameOffset 
!= 0 ) 
3578                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->volNameOffset
); 
3579                                 BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1); 
3582                         if ( afpXInfoPtr
->userNameOffset 
!= 0 ) 
3584                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->userNameOffset
); 
3585                                 BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1); 
3597 /*****************************************************************************/ 
3599 pascal  OSErr   
GetUGEntries(short objType
, 
3602                                                          long *actEntryCount
, 
3606         OSErr error 
= noErr
; 
3607         UGEntry 
*endEntryArray
; 
3609         pb
.objParam
.ioObjType 
= objType
; 
3611         for ( endEntryArray 
= entries 
+ reqEntryCount
; (entries 
< endEntryArray
) && (error 
== noErr
); ++entries 
) 
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 
) 
3622                         entries
->objID 
= *objID 
= pb
.objParam
.ioObjID
; 
3623                         entries
->objType 
= objType
; 
3631 /*****************************************************************************/