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. 
  46 #include <MacErrors.h> 
  47 #include <MacMemory.h> 
  55 #include <TextUtils.h> 
  58 #include <CodeFragments.h> 
  61 #define __COMPILINGMOREFILES 
  63 #include "MoreFiles.h" 
  64 #include "MoreDesktopMgr.h" 
  65 #include "FSpCompat.h" 
  67 #include "MoreFilesExtras.h" 
  69 /*****************************************************************************/ 
  71 /* Functions to get information out of GetVolParmsInfoBuffer. */ 
  73 /* version 1 field getters */ 
  75 pascal  short   GetVolParmsInfoVersion(const GetVolParmsInfoBuffer 
*volParms
) 
  77         return ( volParms
->vMVersion 
); 
  80 pascal  long    GetVolParmsInfoAttrib(const GetVolParmsInfoBuffer 
*volParms
) 
  82         return ( volParms
->vMAttrib 
); 
  85 pascal  Handle  
GetVolParmsInfoLocalHand(const GetVolParmsInfoBuffer 
*volParms
) 
  87         return ( volParms
->vMLocalHand 
); 
  90 pascal  long    GetVolParmsInfoServerAdr(const GetVolParmsInfoBuffer 
*volParms
) 
  92         return ( volParms
->vMServerAdr 
); 
  95 /* version 2 field getters (assume zero result if version < 2) */ 
  97 pascal  long    GetVolParmsInfoVolumeGrade(const GetVolParmsInfoBuffer 
*volParms
) 
  99         return ( (volParms
->vMVersion 
>= 2) ? volParms
->vMVolumeGrade 
: 0 ); 
 102 pascal  long    GetVolParmsInfoForeignPrivID(const GetVolParmsInfoBuffer 
*volParms
) 
 104         return ( (volParms
->vMVersion 
>= 2) ? volParms
->vMForeignPrivID 
: 0 ); 
 107 /* version 3 field getters (assume zero result if version < 3) */ 
 109 pascal  long    GetVolParmsInfoExtendedAttributes(const GetVolParmsInfoBuffer 
*volParms
) 
 111         return ( (volParms
->vMVersion 
>= 3) ? volParms
->vMExtendedAttributes 
: 0 ); 
 114 /* attribute bits supported by all versions of GetVolParmsInfoBuffer */ 
 116 pascal  Boolean 
isNetworkVolume(const GetVolParmsInfoBuffer 
*volParms
) 
 118         return ( volParms
->vMServerAdr 
!= 0 ); 
 121 pascal  Boolean 
hasLimitFCBs(const GetVolParmsInfoBuffer 
*volParms
) 
 123         return ( (volParms
->vMAttrib 
& (1L << bLimitFCBs
)) != 0 ); 
 126 pascal  Boolean 
hasLocalWList(const GetVolParmsInfoBuffer 
*volParms
) 
 128         return ( (volParms
->vMAttrib 
& (1L << bLocalWList
)) != 0 ); 
 131 pascal  Boolean 
hasNoMiniFndr(const GetVolParmsInfoBuffer 
*volParms
) 
 133         return ( (volParms
->vMAttrib 
& (1L << bNoMiniFndr
)) != 0 ); 
 136 pascal  Boolean 
hasNoVNEdit(const GetVolParmsInfoBuffer 
*volParms
) 
 138         return ( (volParms
->vMAttrib 
& (1L << bNoVNEdit
)) != 0 ); 
 141 pascal  Boolean 
hasNoLclSync(const GetVolParmsInfoBuffer 
*volParms
) 
 143         return ( (volParms
->vMAttrib 
& (1L << bNoLclSync
)) != 0 ); 
 146 pascal  Boolean 
hasTrshOffLine(const GetVolParmsInfoBuffer 
*volParms
) 
 148         return ( (volParms
->vMAttrib 
& (1L << bTrshOffLine
)) != 0 ); 
 151 pascal  Boolean 
hasNoSwitchTo(const GetVolParmsInfoBuffer 
*volParms
) 
 153         return ( (volParms
->vMAttrib 
& (1L << bNoSwitchTo
)) != 0 ); 
 156 pascal  Boolean 
hasNoDeskItems(const GetVolParmsInfoBuffer 
*volParms
) 
 158         return ( (volParms
->vMAttrib 
& (1L << bNoDeskItems
)) != 0 ); 
 161 pascal  Boolean 
hasNoBootBlks(const GetVolParmsInfoBuffer 
*volParms
) 
 163         return ( (volParms
->vMAttrib 
& (1L << bNoBootBlks
)) != 0 ); 
 166 pascal  Boolean 
hasAccessCntl(const GetVolParmsInfoBuffer 
*volParms
) 
 168         return ( (volParms
->vMAttrib 
& (1L << bAccessCntl
)) != 0 ); 
 171 pascal  Boolean 
hasNoSysDir(const GetVolParmsInfoBuffer 
*volParms
) 
 173         return ( (volParms
->vMAttrib 
& (1L << bNoSysDir
)) != 0 ); 
 176 pascal  Boolean 
hasExtFSVol(const GetVolParmsInfoBuffer 
*volParms
) 
 178         return ( (volParms
->vMAttrib 
& (1L << bHasExtFSVol
)) != 0 ); 
 181 pascal  Boolean 
hasOpenDeny(const GetVolParmsInfoBuffer 
*volParms
) 
 183         return ( (volParms
->vMAttrib 
& (1L << bHasOpenDeny
)) != 0 ); 
 186 pascal  Boolean 
hasCopyFile(const GetVolParmsInfoBuffer 
*volParms
) 
 188         return ( (volParms
->vMAttrib 
& (1L << bHasCopyFile
)) != 0 ); 
 191 pascal  Boolean 
hasMoveRename(const GetVolParmsInfoBuffer 
*volParms
) 
 193         return ( (volParms
->vMAttrib 
& (1L << bHasMoveRename
)) != 0 ); 
 196 pascal  Boolean 
hasDesktopMgr(const GetVolParmsInfoBuffer 
*volParms
) 
 198         return ( (volParms
->vMAttrib 
& (1L << bHasDesktopMgr
)) != 0 ); 
 201 pascal  Boolean 
hasShortName(const GetVolParmsInfoBuffer 
*volParms
) 
 203         return ( (volParms
->vMAttrib 
& (1L << bHasShortName
)) != 0 ); 
 206 pascal  Boolean 
hasFolderLock(const GetVolParmsInfoBuffer 
*volParms
) 
 208         return ( (volParms
->vMAttrib 
& (1L << bHasFolderLock
)) != 0 ); 
 211 pascal  Boolean 
hasPersonalAccessPrivileges(const GetVolParmsInfoBuffer 
*volParms
) 
 213         return ( (volParms
->vMAttrib 
& (1L << bHasPersonalAccessPrivileges
)) != 0 ); 
 216 pascal  Boolean 
hasUserGroupList(const GetVolParmsInfoBuffer 
*volParms
) 
 218         return ( (volParms
->vMAttrib 
& (1L << bHasUserGroupList
)) != 0 ); 
 221 pascal  Boolean 
hasCatSearch(const GetVolParmsInfoBuffer 
*volParms
) 
 223         return ( (volParms
->vMAttrib 
& (1L << bHasCatSearch
)) != 0 ); 
 226 pascal  Boolean 
hasFileIDs(const GetVolParmsInfoBuffer 
*volParms
) 
 228         return ( (volParms
->vMAttrib 
& (1L << bHasFileIDs
)) != 0 ); 
 231 pascal  Boolean 
hasBTreeMgr(const GetVolParmsInfoBuffer 
*volParms
) 
 233         return ( (volParms
->vMAttrib 
& (1L << bHasBTreeMgr
)) != 0 ); 
 236 pascal  Boolean 
hasBlankAccessPrivileges(const GetVolParmsInfoBuffer 
*volParms
) 
 238         return ( (volParms
->vMAttrib 
& (1L << bHasBlankAccessPrivileges
)) != 0 ); 
 241 pascal  Boolean 
supportsAsyncRequests(const GetVolParmsInfoBuffer 
*volParms
) 
 243         return ( (volParms
->vMAttrib 
& (1L << bSupportsAsyncRequests
)) != 0 ); 
 246 pascal  Boolean 
supportsTrashVolumeCache(const GetVolParmsInfoBuffer 
*volParms
) 
 248         return ( (volParms
->vMAttrib 
& (1L << bSupportsTrashVolumeCache
)) != 0 ); 
 251 /* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */ 
 253 pascal  Boolean 
volIsEjectable(const GetVolParmsInfoBuffer 
*volParms
) 
 255         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bIsEjectable
)) != 0 ); 
 258 pascal  Boolean 
volSupportsHFSPlusAPIs(const GetVolParmsInfoBuffer 
*volParms
) 
 260         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsHFSPlusAPIs
)) != 0 ); 
 263 pascal  Boolean 
volSupportsFSCatalogSearch(const GetVolParmsInfoBuffer 
*volParms
) 
 265         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsFSCatalogSearch
)) != 0 ); 
 268 pascal  Boolean 
volSupportsFSExchangeObjects(const GetVolParmsInfoBuffer 
*volParms
) 
 270         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsFSExchangeObjects
)) != 0 ); 
 273 pascal  Boolean 
volSupports2TBFiles(const GetVolParmsInfoBuffer 
*volParms
) 
 275         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupports2TBFiles
)) != 0 ); 
 278 pascal  Boolean 
volSupportsLongNames(const GetVolParmsInfoBuffer 
*volParms
) 
 280         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsLongNames
)) != 0 ); 
 283 pascal  Boolean 
volSupportsMultiScriptNames(const GetVolParmsInfoBuffer 
*volParms
) 
 285         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsMultiScriptNames
)) != 0 ); 
 288 pascal  Boolean 
volSupportsNamedForks(const GetVolParmsInfoBuffer 
*volParms
) 
 290         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsNamedForks
)) != 0 ); 
 293 pascal  Boolean 
volSupportsSubtreeIterators(const GetVolParmsInfoBuffer 
*volParms
) 
 295         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bSupportsSubtreeIterators
)) != 0 ); 
 298 pascal  Boolean 
volL2PCanMapFileBlocks(const GetVolParmsInfoBuffer 
*volParms
) 
 300         return ( (GetVolParmsInfoExtendedAttributes(volParms
) & (1L << bL2PCanMapFileBlocks
)) != 0 ); 
 303 /*****************************************************************************/ 
 305 /* Functions for testing ioACUser bits. */ 
 307 pascal  Boolean 
userIsOwner(SInt8 ioACUser
) 
 309         return ( (ioACUser 
& kioACUserNotOwnerMask
) == 0 ); 
 312 pascal  Boolean 
userHasFullAccess(SInt8 ioACUser
) 
 314         return ( (ioACUser 
& acUserAccessMask
) == acUserFull 
); 
 317 pascal  Boolean 
userHasDropBoxAccess(SInt8 ioACUser
) 
 319         return ( (ioACUser 
& acUserAccessMask
) == acUserDropBox 
); 
 322 pascal  Boolean 
userHasBulletinBoard(SInt8 ioACUser
) 
 324         return ( (ioACUser 
& acUserAccessMask
) == acUserBulletinBoard 
); 
 327 pascal  Boolean 
userHasNoAccess(SInt8 ioACUser
) 
 329         return ( (ioACUser 
& acUserAccessMask
) == acUserNone 
); 
 332 /*****************************************************************************/ 
 334 /* local data structures */ 
 336 /* The DeleteEnumGlobals structure is used to minimize the amount of 
 337 ** stack space used when recursively calling DeleteLevel and to hold 
 338 ** global information that might be needed at any time. */ 
 340 #if PRAGMA_STRUCT_ALIGN 
 341         #pragma options align=mac68k 
 342 #endif  //      PRAGMA_STRUCT_ALIGN 
 343 struct DeleteEnumGlobals
 
 345         OSErr                   error
;                          /* temporary holder of results - saves 2 bytes of stack each level */ 
 346         Str63                   itemName
;                       /* the name of the current item */ 
 347         UniversalFMPB   myPB
;                           /* the parameter block used for PBGetCatInfo calls */ 
 349 #if PRAGMA_STRUCT_ALIGN 
 350         #pragma options align=reset 
 351 #endif //       PRAGMA_STRUCT_ALIGN 
 353 typedef struct DeleteEnumGlobals DeleteEnumGlobals
; 
 354 typedef DeleteEnumGlobals 
*DeleteEnumGlobalsPtr
; 
 356 /*****************************************************************************/ 
 359 **      CallPBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync 
 360 **      File Manager requests from CFM-based programs. Apple added PBXGetVolInfoSync 
 361 **      to InterfaceLib in Mac OS 8.5, so if __MACOSEIGHTFIVEORLATER is defined, 
 362 **      CallPBXGetVolInfoSync is defined back to PBXGetVolInfoSync. 
 364 **      Non-CFM 68K programs don't needs this glue (and won't get it) because 
 365 **      they instead use the inline assembly glue found in the Files.h interface 
 369 #if TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM 
 371         // Carbon builds and 68K builds don't need this glue 
 372         #define CallPBXGetVolInfoSync PBXGetVolInfoSync 
 374 #else   //      TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM 
 376         #if     __WANTPASCALELIMINATION 
 378         #endif  //      __WANTPASCALELIMINATION 
 380         /* This is exactly like the simple mixed mode glue in InterfaceLib in Mac OS 8.5 and 8.6 */ 
 381         static pascal OSErr 
PBXGetVolInfoSyncGlue(XVolumeParamPtr paramBlock
) 
 385                         uppFSDispatchProcInfo 
= kRegisterBased
 
 386                                  | REGISTER_RESULT_LOCATION(kRegisterD0
) 
 387                                  | RESULT_SIZE(SIZE_CODE(sizeof(OSErr
))) 
 388                                  | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0
, SIZE_CODE(sizeof(long)))  /* selector */ 
 389                                  | REGISTER_ROUTINE_PARAMETER(2, kRegisterD1
, SIZE_CODE(sizeof(long)))  /* trap word */ 
 390                                  | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0
, SIZE_CODE(sizeof(XVolumeParamPtr
))) 
 393                 static UniversalProcPtr fsDispatchTrapAddress 
= NULL
; 
 395                 /* Is this the first time we've been called? */ 
 396                 if ( fsDispatchTrapAddress 
== NULL 
) 
 398                         /* Yes - Get the trap address of _FSDispatch */ 
 399                         fsDispatchTrapAddress 
= NGetTrapAddress(_FSDispatch
, OSTrap
); 
 401                 return ( CallOSTrapUniversalProc(fsDispatchTrapAddress
, 
 402                                                                                         uppFSDispatchProcInfo
, 
 409         ** PBXGetVolInfoSync was added to the File Manager in System software 7.5.2. 
 410         ** However, PBXGetVolInfoSync wasn't added to InterfaceLib until Mac OS 8.5. 
 411         ** This wrapper calls PBXGetVolInfoSync if it is found in InterfaceLib; 
 412         ** otherwise, it calls PBXGetVolInfoSyncGlue. This ensures that your program 
 413         ** is calling the latest implementation of PBXGetVolInfoSync. 
 415         static pascal OSErr 
CallPBXGetVolInfoSync(XVolumeParamPtr paramBlock
) 
 417                 typedef pascal OSErr (*PBXGetVolInfoProcPtr
) (XVolumeParamPtr paramBlock
); 
 420                 CFragConnectionID                       connID
; 
 423                 static PBXGetVolInfoProcPtr     PBXGetVolInfoSyncPtr 
= NULL
; 
 425                 //* Is this the first time we've been called? */ 
 426                 if ( PBXGetVolInfoSyncPtr 
== NULL 
) 
 428                         /* Yes - Get our connection ID to InterfaceLib */ 
 429                         result 
= GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch
, kLoadCFrag
, &connID
, &mainAddr
, errMessage
); 
 430                         if ( result 
== noErr 
) 
 432                                 /* See if PBXGetVolInfoSync is in InterfaceLib */ 
 433                                 if ( FindSymbol(connID
, "\pPBXGetVolInfoSync", &(Ptr
)PBXGetVolInfoSyncPtr
, NULL
) != noErr 
) 
 435                                         /* Use glue code if symbol isn't found */ 
 436                                         PBXGetVolInfoSyncPtr 
= PBXGetVolInfoSyncGlue
; 
 440                 /* Call PBXGetVolInfoSync if present; otherwise, call PBXGetVolInfoSyncGlue */ 
 441                 return ( (*PBXGetVolInfoSyncPtr
)(paramBlock
) ); 
 444         #if     __WANTPASCALELIMINATION 
 446         #endif  //      __WANTPASCALELIMINATION 
 448 #endif  //      TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM 
 450 /*****************************************************************************/ 
 452 pascal  void    TruncPString(StringPtr destination
, 
 453                                                          ConstStr255Param source
, 
 458         if ( source 
!= NULL 
&& destination 
!= NULL 
)    /* don't do anything stupid */ 
 460                 if ( source
[0] > maxLength 
) 
 462                         /* Make sure the string isn't truncated in the middle of */ 
 463                         /* a multi-byte character. */ 
 464                         while (maxLength 
!= 0) 
 466                                 // Note: CharacterByteType's textOffset parameter is zero-based from the textPtr parameter 
 467                                 charType 
= CharacterByteType((Ptr
)&source
[1], maxLength 
- 1, smSystemScript
); 
 468                                 if ( (charType 
== smSingleByte
) || (charType 
== smLastByte
) ) 
 469                                         break;  /* source[maxLength] is now a valid last character */  
 475                         maxLength 
= source
[0]; 
 477                 /* Set the destination string length */ 
 478                 destination
[0] = maxLength
; 
 479                 /* and copy maxLength characters (if needed) */ 
 480                 if ( source 
!= destination 
) 
 482                         while ( maxLength 
!= 0 ) 
 484                                 destination
[maxLength
] = source
[maxLength
]; 
 491 /*****************************************************************************/ 
 493 pascal  Ptr     
GetTempBuffer(long buffReqSize
, 
 498                 kSlopMemory 
= 0x00008000        /* 32K - Amount of free memory to leave when allocating buffers */ 
 502         /* Make request a multiple of 1024 bytes */ 
 503         buffReqSize 
= buffReqSize 
& 0xfffffc00; 
 505         if ( buffReqSize 
< 0x00000400 ) 
 507                 /* Request was smaller than 1024 bytes - make it 1024 */ 
 508                 buffReqSize 
= 0x00000400; 
 511         /* Attempt to allocate the memory */ 
 512         tempPtr 
= NewPtr(buffReqSize
); 
 514         /* If request failed, go to backup plan */ 
 515         if ( (tempPtr 
== NULL
) && (buffReqSize 
> 0x00000400) ) 
 518                 **      Try to get largest 1024-byte block available 
 519                 **      leaving some slop for the toolbox if possible 
 521                 long freeMemory 
= (FreeMem() - kSlopMemory
) & 0xfffffc00; 
 523                 buffReqSize 
= MaxBlock() & 0xfffffc00; 
 525                 if ( buffReqSize 
> freeMemory 
) 
 527                         buffReqSize 
= freeMemory
; 
 530                 if ( buffReqSize 
== 0 ) 
 532                         buffReqSize 
= 0x00000400; 
 535                 tempPtr 
= NewPtr(buffReqSize
); 
 538         /* Return bytes allocated */ 
 539         if ( tempPtr 
!= NULL 
) 
 541                 *buffActSize 
= buffReqSize
; 
 551 /*****************************************************************************/ 
 554 **      GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync 
 555 **      in cases where the returned volume name is not needed by the caller. 
 556 **      The pathname and vRefNum parameters are not touched, and the pb 
 557 **      parameter is initialized by PBHGetVInfoSync except that ioNamePtr in 
 558 **      the parameter block is always returned as NULL (since it might point 
 559 **      to the local tempPathname). 
 561 **      I noticed using this code in several places, so here it is once. 
 562 **      This reduces the code size of MoreFiles. 
 564 pascal  OSErr   
GetVolumeInfoNoName(ConstStr255Param pathname
, 
 571         /* Make sure pb parameter is not NULL */  
 574                 pb
->volumeParam
.ioVRefNum 
= vRefNum
; 
 575                 if ( pathname 
== NULL 
) 
 577                         pb
->volumeParam
.ioNamePtr 
= NULL
; 
 578                         pb
->volumeParam
.ioVolIndex 
= 0;         /* use ioVRefNum only */ 
 582                         BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); /* make a copy of the string and */ 
 583                         pb
->volumeParam
.ioNamePtr 
= (StringPtr
)tempPathname
;    /* use the copy so original isn't trashed */ 
 584                         pb
->volumeParam
.ioVolIndex 
= -1;        /* use ioNamePtr/ioVRefNum combination */ 
 586                 error 
= PBHGetVInfoSync(pb
); 
 587                 pb
->volumeParam
.ioNamePtr 
= NULL
;       /* ioNamePtr may point to local tempPathname, so don't return it */ 
 596 /*****************************************************************************/ 
 599 **      XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync 
 600 **      in cases where the returned volume name is not needed by the caller. 
 601 **      The pathname and vRefNum parameters are not touched, and the pb 
 602 **      parameter is initialized by PBXGetVolInfoSync except that ioNamePtr in 
 603 **      the parameter block is always returned as NULL (since it might point 
 604 **      to the local tempPathname). 
 606 pascal  OSErr   
XGetVolumeInfoNoName(ConstStr255Param pathname
, 
 613         /* Make sure pb parameter is not NULL */  
 616                 pb
->ioVRefNum 
= vRefNum
; 
 617                 pb
->ioXVersion 
= 0;                     /* this XVolumeParam version (0) */ 
 618                 if ( pathname 
== NULL 
) 
 620                         pb
->ioNamePtr 
= NULL
; 
 621                         pb
->ioVolIndex 
= 0;             /* use ioVRefNum only */ 
 625                         BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); /* make a copy of the string and */ 
 626                         pb
->ioNamePtr 
= (StringPtr
)tempPathname
;        /* use the copy so original isn't trashed */ 
 627                         pb
->ioVolIndex 
= -1;    /* use ioNamePtr/ioVRefNum combination */ 
 631 #if !TARGET_API_MAC_CARBON 
 634                         /* Is PBXGetVolInfo available? */ 
 635                         if ( ( Gestalt(gestaltFSAttr
, &response
) != noErr 
) || ((response 
& (1L << gestaltFSSupports2TBVols
)) == 0) ) 
 637                                 /* No, fall back on PBHGetVInfo */ 
 638                                 error 
= PBHGetVInfoSync((HParmBlkPtr
)pb
); 
 639                                 if ( error 
== noErr 
) 
 641                                         /* calculate the ioVTotalBytes and ioVFreeBytes fields */ 
 642                                         pb
->ioVTotalBytes 
= U64Multiply(U64SetU(pb
->ioVNmAlBlks
), U64SetU(pb
->ioVAlBlkSiz
)); 
 643                                         pb
->ioVFreeBytes 
= U64Multiply(U64SetU(pb
->ioVFrBlk
), U64SetU(pb
->ioVAlBlkSiz
)); 
 650                                 error 
= CallPBXGetVolInfoSync(pb
); 
 653                 pb
->ioNamePtr 
= NULL
;           /* ioNamePtr may point to local tempPathname, so don't return it */ 
 662 /*****************************************************************************/ 
 664 pascal  OSErr 
GetCatInfoNoName(short vRefNum
, 
 666                                                            ConstStr255Param name
, 
 672         /* Protection against File Sharing problem */ 
 673         if ( (name 
== NULL
) || (name
[0] == 0) ) 
 676                 pb
->dirInfo
.ioNamePtr 
= tempName
; 
 677                 pb
->dirInfo
.ioFDirIndex 
= -1;   /* use ioDirID */ 
 681                 pb
->dirInfo
.ioNamePtr 
= (StringPtr
)name
; 
 682                 pb
->dirInfo
.ioFDirIndex 
= 0;    /* use ioNamePtr and ioDirID */ 
 684         pb
->dirInfo
.ioVRefNum 
= vRefNum
; 
 685         pb
->dirInfo
.ioDrDirID 
= dirID
; 
 686         error 
= PBGetCatInfoSync(pb
); 
 687         pb
->dirInfo
.ioNamePtr 
= NULL
; 
 691 /*****************************************************************************/ 
 693 pascal  OSErr   
DetermineVRefNum(ConstStr255Param pathname
, 
 700         error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
 701         if ( error 
== noErr 
) 
 703                 *realVRefNum 
= pb
.volumeParam
.ioVRefNum
; 
 708 /*****************************************************************************/ 
 710 pascal  OSErr   
HGetVInfo(short volReference
, 
 713                                                   unsigned long *freeBytes
, 
 714                                                   unsigned long *totalBytes
) 
 720         // get the best values possible from XGetVInfo 
 721         result 
= XGetVInfo(volReference
, volName
, vRefNum
, &freeBytes64
, &totalBytes64
); 
 722         if ( result 
== noErr 
) 
 724                 // and pin those values if needed 
 725                 if ( UInt64ToUnsignedWide(freeBytes64
).hi 
!= 0 ) 
 727                         // pin to maximum 512-byte block aligned value 
 728                         *freeBytes 
= 0xfffffe00; 
 732                         *freeBytes 
= U32SetU(freeBytes64
); 
 735                 if ( UInt64ToUnsignedWide(totalBytes64
).hi 
!= 0 ) 
 737                         // pin to maximum 512-byte block aligned value 
 738                         *totalBytes 
= 0xfffffe00; 
 742                         *totalBytes 
= U32SetU(totalBytes64
); 
 749 /*****************************************************************************/ 
 751 pascal  OSErr   
XGetVInfo(short volReference
, 
 760 #if !TARGET_API_MAC_CARBON 
 764 #endif  //      !TARGET_API_MAC_CARBON 
 766         pb
.ioVRefNum 
= volReference
; 
 767         pb
.ioNamePtr 
= volName
; 
 768         pb
.ioXVersion 
= 0;      /* this XVolumeParam version (0) */ 
 769         pb
.ioVolIndex 
= 0;      /* use ioVRefNum only, return volume name */ 
 771 #if !TARGET_API_MAC_CARBON 
 773         /* See if large volume support is available */ 
 774         if ( ( Gestalt(gestaltFSAttr
, &response
) == noErr 
) && ((response 
& (1L << gestaltFSSupports2TBVols
)) != 0) ) 
 776 #endif  //      !TARGET_API_MAC_CARBON 
 779                 /* Large volume support is available */ 
 780                 result 
= CallPBXGetVolInfoSync(&pb
); 
 781                 if ( result 
== noErr 
) 
 783                         /* The volume name was returned in volName (if not NULL) and */ 
 784                         /* we have the volume's vRefNum and allocation block size */ 
 785                         *vRefNum 
= pb
.ioVRefNum
; 
 787                         /* return the freeBytes and totalBytes */ 
 788                         *totalBytes 
= pb
.ioVTotalBytes
; 
 789                         *freeBytes 
= pb
.ioVFreeBytes
; 
 793 #if !TARGET_API_MAC_CARBON 
 797                 /* No large volume support */ 
 798                 /* Use PBHGetVInfoSync to get the results */ 
 799                 result 
= PBHGetVInfoSync((HParmBlkPtr
)&pb
); 
 800                 if ( result 
== noErr 
) 
 804                         /* The volume name was returned in volName (if not NULL) and */ 
 805                         /* we have the volume's vRefNum */ 
 806                         *vRefNum 
= pb
.ioVRefNum
; 
 808                         /* System 7.5 (and beyond) pins the number of allocation blocks and */ 
 809                         /* the number of free allocation blocks returned by PBHGetVInfo to */ 
 810                         /* a value so that when multiplied by the allocation block size, */ 
 811                         /* the volume will look like it has $7fffffff bytes or less. This */ 
 812                         /* was done so older applications that use signed math or that use */ 
 813                         /* the GetVInfo function (which uses signed math) will continue to work. */ 
 814                         /* However, the unpinned numbers (which we want) are always available */ 
 815                         /* in the volume's VCB so we'll get those values from the VCB. */ 
 816                         /* Note: Carbon doesn't support the VCB queue, so this code cannot be */ 
 817                         /* used (and is conditionalized out) by Carbon applications. */ 
 819                         /* Find the volume's VCB */ 
 820                         theVCB 
= (VCB 
*)(GetVCBQHdr()->qHead
); 
 821                         while ( theVCB 
!= NULL 
) 
 823                                 if ( theVCB
->vcbVRefNum 
== *vRefNum 
) 
 828                                 theVCB 
= (VCB 
*)(theVCB
->qLink
);        /* next VCB */ 
 831                         if ( theVCB 
!= NULL 
) 
 833                                 /* Found a VCB we can use. Get the un-pinned number of allocation blocks */ 
 834                                 /* and the number of free blocks from the VCB. */ 
 835                                 *freeBytes 
= U64Multiply(U64SetU((unsigned short)theVCB
->vcbFreeBks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
)); 
 836                                 *totalBytes 
= U64Multiply(U64SetU((unsigned short)theVCB
->vcbNmAlBlks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
)); 
 840                                 /* Didn't find a VCB we can use. Return the number of allocation blocks */ 
 841                                 /* and the number of free blocks returned by PBHGetVInfoSync. */ 
 842                                 *freeBytes 
= U64Multiply(U64SetU((unsigned short)pb
.ioVFrBlk
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
)); 
 843                                 *totalBytes 
= U64Multiply(U64SetU((unsigned short)pb
.ioVNmAlBlks
), U64SetU((unsigned long)pb
.ioVAlBlkSiz
)); 
 849 #endif  //      !TARGET_API_MAC_CARBON 
 854 /*****************************************************************************/ 
 856 pascal  OSErr   
CheckVolLock(ConstStr255Param pathname
, 
 862         error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
 863         if ( error 
== noErr 
) 
 865                 if ( (pb
.volumeParam
.ioVAtrb 
& kHFSVolumeHardwareLockMask
) != 0 ) 
 867                         error 
= wPrErr
;         /* volume locked by hardware */ 
 869                 else if ( (pb
.volumeParam
.ioVAtrb 
& kHFSVolumeSoftwareLockMask
) != 0 ) 
 871                         error 
= vLckdErr
;       /* volume locked by software */ 
 878 /*****************************************************************************/ 
 880 //      The following routines call Mac OS routines that are not supported by 
 888 #if !TARGET_API_MAC_CARBON      //      { 
 890         /*****************************************************************************/ 
 892         pascal  OSErr 
GetDriverName(short driverRefNum
, 
 897                 DRVRHeaderPtr dHeaderPtr
; 
 899                 theDctl 
= GetDCtlEntry(driverRefNum
); 
 900                 if ( theDctl 
!= NULL 
) 
 902                     if ( (**theDctl
).dCtlFlags 
& dRAMBasedMask 
) 
 904                         /* dctlDriver is handle - dereference */ 
 905                                 dHeaderPtr 
= *((DRVRHeaderHandle
)(**theDctl
).dCtlDriver
); 
 909                                 /* dctlDriver is pointer */ 
 910                       dHeaderPtr 
= (DRVRHeaderPtr
)(**theDctl
).dCtlDriver
; 
 912                         BlockMoveData((*dHeaderPtr
).drvrName
, driverName
, (*dHeaderPtr
).drvrName
[0] + 1); 
 918                         result 
= badUnitErr
;    /* bad reference number */ 
 924         /*****************************************************************************/ 
 926         pascal  OSErr   
FindDrive(ConstStr255Param pathname
, 
 928                                                           DrvQElPtr 
*driveQElementPtr
) 
 934                 *driveQElementPtr 
= NULL
; 
 936                 /* First, use GetVolumeInfoNoName to determine the volume */ 
 937                 result 
= GetVolumeInfoNoName(pathname
, vRefNum
, &hPB
); 
 938                 if ( result 
== noErr 
) 
 941                         **      The volume can be either online, offline, or ejected. What we find in 
 942                         **      ioVDrvInfo and ioVDRefNum will tell us which it is. 
 943                         **      See Inside Macintosh: Files page 2-80 and the Technical Note 
 944                         **      "FL 34 - VCBs and Drive Numbers : The Real Story" 
 945                         **      Where we get the drive number depends on the state of the volume. 
 947                         if ( hPB
.volumeParam
.ioVDrvInfo 
!= 0 ) 
 949                                 /* The volume is online and not ejected */ 
 950                                 /* Get the drive number */ 
 951                                 driveNumber 
= hPB
.volumeParam
.ioVDrvInfo
; 
 955                                 /* The volume's is either offline or ejected */ 
 956                                 /* in either case, the volume is NOT online */ 
 958                                 /* Is it ejected or just offline? */ 
 959                                 if ( hPB
.volumeParam
.ioVDRefNum 
> 0 ) 
 961                                         /* It's ejected, the drive number is ioVDRefNum */ 
 962                                         driveNumber 
= hPB
.volumeParam
.ioVDRefNum
; 
 966                                         /* It's offline, the drive number is the negative of ioVDRefNum */ 
 967                                         driveNumber 
= (short)-hPB
.volumeParam
.ioVDRefNum
; 
 971                         /* Get pointer to first element in drive queue */ 
 972                         *driveQElementPtr 
= (DrvQElPtr
)(GetDrvQHdr()->qHead
); 
 974                         /* Search for a matching drive number */ 
 975                         while ( (*driveQElementPtr 
!= NULL
) && ((*driveQElementPtr
)->dQDrive 
!= driveNumber
) ) 
 977                                 *driveQElementPtr 
= (DrvQElPtr
)(*driveQElementPtr
)->qLink
; 
 980                         if ( *driveQElementPtr 
== NULL 
) 
 982                                 /* This should never happen since every volume must have a drive, but... */ 
 990         /*****************************************************************************/ 
 992         pascal  OSErr   
GetDiskBlocks(ConstStr255Param pathname
, 
 994                                                                   unsigned long *numBlocks
) 
 996                 /* Various constants for GetDiskBlocks() */ 
 999                         /* return format list status code */ 
1002                         /* reference number of .SONY driver */ 
1003                         kSonyRefNum 
= 0xfffb, 
1005                         /* values returned by DriveStatus in DrvSts.twoSideFmt */ 
1008                         kSingleSidedSize 
= 800,         /* 400K */ 
1009                         kDoubleSidedSize 
= 1600,        /* 800K */ 
1011                         /* values in DrvQEl.qType */ 
1015                         /* more than enough formatListRecords */ 
1016                         kMaxFormatListRecs 
= 16 
1019                 DrvQElPtr               driveQElementPtr
; 
1020                 unsigned long   blocks
; 
1022                 FormatListRec   formatListRecords
[kMaxFormatListRecs
]; 
1024                 short                   formatListRecIndex
; 
1029                 /* Find the drive queue element for this volume */ 
1030                 result 
= FindDrive(pathname
, vRefNum
, &driveQElementPtr
); 
1033                 **      Make sure this is a real driver (dQRefNum < 0). 
1034                 **      AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause 
1035                 **      problems if you try to use it as a driver refNum. 
1037                 if ( (result 
== noErr
) && (driveQElementPtr
->dQRefNum 
>= 0) ) 
1043                         /* Attempt to get the drive's format list. */ 
1044                         /* (see the Technical Note "What Your Sony Drives For You") */ 
1046                         pb
.cntrlParam
.ioVRefNum 
= driveQElementPtr
->dQDrive
; 
1047                         pb
.cntrlParam
.ioCRefNum 
= driveQElementPtr
->dQRefNum
; 
1048                         pb
.cntrlParam
.csCode 
= kFmtLstCode
; 
1049                         pb
.cntrlParam
.csParam
[0] = kMaxFormatListRecs
; 
1050                         *(long *)&pb
.cntrlParam
.csParam
[1] = (long)&formatListRecords
[0]; 
1052                         result 
= PBStatusSync(&pb
); 
1054                         if ( result 
== noErr 
) 
1056                                 /* The drive supports ReturnFormatList status call. */ 
1058                                 /* Get the current disk's size. */ 
1059                                 for( formatListRecIndex 
= 0; 
1060                                          formatListRecIndex 
< pb
.cntrlParam
.csParam
[0]; 
1061                                  ++formatListRecIndex 
) 
1063                                 if ( (formatListRecords
[formatListRecIndex
].formatFlags 
& 
1064                                           diCIFmtFlagsCurrentMask
) != 0 ) 
1066                                         blocks 
= formatListRecords
[formatListRecIndex
].volSize
; 
1071                                 /* This should never happen */ 
1075                         else if ( driveQElementPtr
->dQRefNum 
== (short)kSonyRefNum 
) 
1077                                 /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */ 
1079                                 result 
= DriveStatus(driveQElementPtr
->dQDrive
, &status
); 
1080                                 if ( result 
== noErr 
) 
1082                                         switch ( status
.twoSideFmt 
) 
1085                                                 blocks 
= kSingleSidedSize
; 
1088                                                 blocks 
= kDoubleSidedSize
; 
1091                                                 /* This should never happen */ 
1099                                 /* The drive is not a floppy and it doesn't support ReturnFormatList */ 
1100                                 /* so use the dQDrvSz field(s) */ 
1102                                 result 
= noErr
; /* reset result */ 
1103                                 switch ( driveQElementPtr
->qType 
) 
1106                                         blocks 
= driveQElementPtr
->dQDrvSz
; 
1109                                         blocks 
= ((unsigned long)driveQElementPtr
->dQDrvSz2 
<< 16) + 
1110                                                          driveQElementPtr
->dQDrvSz
; 
1113                                         /* This should never happen */ 
1120                 if ( result 
== noErr 
) 
1122                         *numBlocks 
= blocks
; 
1128         /*****************************************************************************/ 
1130         pascal  OSErr   
GetVolState(ConstStr255Param pathname
, 
1132                                                                 Boolean 
*volumeOnline
, 
1133                                                                 Boolean 
*volumeEjected
, 
1134                                                                 Boolean 
*driveEjectable
, 
1135                                                                 Boolean 
*driverWantsEject
) 
1141                 error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
1142                 if ( error 
== noErr 
) 
1144                         if ( pb
.volumeParam
.ioVDrvInfo 
!= 0 ) 
1146                                 /* the volume is online and not ejected */ 
1147                                 *volumeOnline 
= true; 
1148                                 *volumeEjected 
= false; 
1150                                 /* Get the drive number */ 
1151                                 driveNumber 
= pb
.volumeParam
.ioVDrvInfo
; 
1155                                 /* the volume's is either offline or ejected */ 
1156                                 /* in either case, the volume is NOT online */ 
1157                                 *volumeOnline 
= false; 
1159                                 /* Is it ejected? */ 
1160                                 *volumeEjected 
= pb
.volumeParam
.ioVDRefNum 
> 0; 
1162                                 if ( *volumeEjected 
) 
1164                                         /* If ejected, the drive number is ioVDRefNum */ 
1165                                         driveNumber 
= pb
.volumeParam
.ioVDRefNum
; 
1169                                         /* If offline, the drive number is the negative of ioVDRefNum */ 
1170                                         driveNumber 
= (short)-pb
.volumeParam
.ioVDRefNum
; 
1177                                 /* Find the drive queue element by searching the drive queue */ 
1178                                 drvQElem 
= (DrvQElPtr
)(GetDrvQHdr()->qHead
); 
1179                                 while ( (drvQElem 
!= NULL
) && (drvQElem
->dQDrive 
!= driveNumber
) ) 
1181                                         drvQElem 
= (DrvQElPtr
)drvQElem
->qLink
; 
1184                                 if ( drvQElem 
!= NULL 
) 
1187                                         **      Each drive queue element is preceded by 4 flag bytes. 
1188                                         **      Byte 1 (the second flag byte) has bits that tell us if a 
1189                                         **      drive is ejectable and if its driver wants an eject call. 
1190                                         **      See Inside Macintosh: Files, page 2-85. 
1195                                                 /* point to byte 1 of the flag bytes */ 
1196                                                 flagBytePtr 
= (Ptr
)drvQElem
; 
1200                                                 **      The drive is ejectable if flag byte 1 does not contain 
1201                                                 **      0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call). 
1204                                                 *driveEjectable 
= (*flagBytePtr 
!= 0x08) && (*flagBytePtr 
!= 0x48); 
1207                                                 **      The driver wants an eject call if flag byte 1 does not contain 
1208                                                 **      0x08 (nonejectable). This may seem like a minor point, but some 
1209                                                 **      disk drivers use the Eject request to flush their caches to disk 
1210                                                 **      and you wouldn't want to skip that step after unmounting a volume. 
1213                                                 *driverWantsEject 
= (*flagBytePtr 
!= 0x08); 
1218                                         /* Didn't find the drive (this should never happen) */ 
1219                                         *driveEjectable 
= false; 
1220                                         *driverWantsEject 
= false; 
1228         /*****************************************************************************/ 
1230 #endif  //      }       !TARGET_API_MAC_CARBON 
1232 /*****************************************************************************/ 
1234 pascal  OSErr   
GetVolFileSystemID(ConstStr255Param pathname
, 
1236                                                                    short *fileSystemID
) 
1241         error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
1242         if ( error 
== noErr 
) 
1244                 *fileSystemID 
= pb
.volumeParam
.ioVFSID
; 
1250 /*****************************************************************************/ 
1253 //      Note:   Under Carbon there are no drive numbers, so you cannot call 
1254 //                      Eject with a drive number after unmounting a volume. 
1255 //                      When a Carbon application calls UnmountVol, CarbonLib will make 
1256 //                      sure ejectable media is ejected (leaving ejectable media in the 
1257 //                      disk drive makes no sense to Carbon applications). 
1259 pascal  OSErr   
UnmountAndEject(ConstStr255Param pathname
, 
1265         error 
= GetVolumeInfoNoName(pathname
, vRefNum
, &pb
); 
1266         if ( error 
== noErr 
) 
1269 #if     !TARGET_API_MAC_CARBON 
1272                 Boolean ejected
, wantsEject
; 
1275                 if ( pb
.volumeParam
.ioVDrvInfo 
!= 0 ) 
1277                         /* the volume is online and not ejected */ 
1280                         /* Get the drive number */ 
1281                         driveNum 
= pb
.volumeParam
.ioVDrvInfo
; 
1285                         /* the volume is ejected or offline */ 
1287                         /* Is it ejected? */ 
1288                         ejected 
= pb
.volumeParam
.ioVDRefNum 
> 0; 
1292                                 /* If ejected, the drive number is ioVDRefNum */ 
1293                                 driveNum 
= pb
.volumeParam
.ioVDRefNum
; 
1297                                 /* If offline, the drive number is the negative of ioVDRefNum */ 
1298                                 driveNum 
= (short)-pb
.volumeParam
.ioVDRefNum
; 
1302                 /* find the drive queue element */ 
1303                 drvQElem 
= (DrvQElPtr
)(GetDrvQHdr()->qHead
); 
1304                 while ( (drvQElem 
!= NULL
) && (drvQElem
->dQDrive 
!= driveNum
) ) 
1306                         drvQElem 
= (DrvQElPtr
)drvQElem
->qLink
; 
1309                 if ( drvQElem 
!= NULL 
) 
1311                         /* does the drive want an eject call */ 
1312                         wantsEject 
= (*((Ptr
)((Ptr
)drvQElem 
- 3)) != 8); 
1316                         /* didn't find the drive!! */ 
1320 #endif  //      !TARGET_API_MAC_CARBON 
1322                 /* unmount the volume */ 
1323                 pb
.volumeParam
.ioNamePtr 
= NULL
; 
1324                 /* ioVRefNum is already filled in from PBHGetVInfo */ 
1325                 error 
= PBUnmountVol((ParmBlkPtr
)&pb
); 
1327 #if     !TARGET_API_MAC_CARBON 
1329                 if ( error 
== noErr 
) 
1331                         if ( wantsEject 
&& !ejected 
) 
1333                                 /* eject the media from the drive if needed */ 
1334                                 pb
.volumeParam
.ioVRefNum 
= driveNum
; 
1335                                 error 
= PBEject((ParmBlkPtr
)&pb
); 
1339 #endif  //      !TARGET_API_MAC_CARBON 
1346 /*****************************************************************************/ 
1348 pascal  OSErr   
OnLine(FSSpecPtr volumes
, 
1354         OSErr error 
= noErr
; 
1355         FSSpec 
*endVolArray
; 
1357         if ( *volIndex 
> 0 ) 
1360                 for ( endVolArray 
= volumes 
+ reqVolCount
; (volumes 
< endVolArray
) && (error 
== noErr
); ++volumes 
) 
1362                         pb
.volumeParam
.ioNamePtr 
= (StringPtr
) & volumes
->name
; 
1363                         pb
.volumeParam
.ioVolIndex 
= *volIndex
; 
1364                         error 
= PBHGetVInfoSync(&pb
); 
1365                         if ( error 
== noErr 
) 
1367                                 volumes
->parID 
= fsRtParID
;             /* the root directory's parent is 1 */ 
1368                                 volumes
->vRefNum 
= pb
.volumeParam
.ioVRefNum
; 
1382 /*****************************************************************************/ 
1384 pascal  OSErr 
SetDefault(short newVRefNum
, 
1391         /* Get the current default volume/directory. */ 
1392         error 
= HGetVol(NULL
, oldVRefNum
, oldDirID
); 
1393         if ( error 
== noErr 
) 
1395                 /* Set the new default volume/directory */ 
1396                 error 
= HSetVol(NULL
, newVRefNum
, newDirID
); 
1402 /*****************************************************************************/ 
1404 pascal  OSErr 
RestoreDefault(short oldVRefNum
, 
1409 #if     !TARGET_API_MAC_CARBON 
1411         short   defaultVRefNum
; 
1415         /* Determine if the default volume was a wdRefNum. */ 
1416         error 
= GetWDInfo(oldVRefNum
, &defaultVRefNum
, &defaultDirID
, &defaultProcID
); 
1417         if ( error 
== noErr 
) 
1419                 /* Restore the old default volume/directory, one way or the other. */ 
1420                 if ( defaultDirID 
!= fsRtDirID 
) 
1422                         /* oldVRefNum was a wdRefNum - use SetVol */ 
1423                         error 
= SetVol(NULL
, oldVRefNum
); 
1428 #endif  //      !TARGET_API_MAC_CARBON 
1430                         /* oldVRefNum was a real vRefNum - use HSetVol */ 
1431                         error 
= HSetVol(NULL
, oldVRefNum
, oldDirID
); 
1433 #if     !TARGET_API_MAC_CARBON 
1437 #endif  //      !TARGET_API_MAC_CARBON 
1442 /*****************************************************************************/ 
1444 pascal  OSErr 
GetDInfo(short vRefNum
, 
1446                                            ConstStr255Param name
, 
1452         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1453         if ( error 
== noErr 
) 
1455                 if ( (pb
.dirInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
1457                         /* it's a directory, return the DInfo */ 
1458                         *fndrInfo 
= pb
.dirInfo
.ioDrUsrWds
; 
1462                         /* oops, a file was passed */ 
1470 /*****************************************************************************/ 
1472 pascal  OSErr 
FSpGetDInfo(const FSSpec 
*spec
, 
1475         return ( GetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) ); 
1478 /*****************************************************************************/ 
1480 pascal  OSErr 
SetDInfo(short vRefNum
, 
1482                                            ConstStr255Param name
, 
1483                                            const DInfo 
*fndrInfo
) 
1489         /* Protection against File Sharing problem */ 
1490         if ( (name 
== NULL
) || (name
[0] == 0) ) 
1493                 pb
.dirInfo
.ioNamePtr 
= tempName
; 
1494                 pb
.dirInfo
.ioFDirIndex 
= -1;    /* use ioDirID */ 
1498                 pb
.dirInfo
.ioNamePtr 
= (StringPtr
)name
; 
1499                 pb
.dirInfo
.ioFDirIndex 
= 0;     /* use ioNamePtr and ioDirID */ 
1501         pb
.dirInfo
.ioVRefNum 
= vRefNum
; 
1502         pb
.dirInfo
.ioDrDirID 
= dirID
; 
1503         error 
= PBGetCatInfoSync(&pb
); 
1504         if ( error 
== noErr 
) 
1506                 if ( (pb
.dirInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
1508                         /* it's a directory, set the DInfo */ 
1509                         if ( pb
.dirInfo
.ioNamePtr 
== tempName 
) 
1511                                 pb
.dirInfo
.ioDrDirID 
= pb
.dirInfo
.ioDrParID
; 
1515                                 pb
.dirInfo
.ioDrDirID 
= dirID
; 
1517                         pb
.dirInfo
.ioDrUsrWds 
= *fndrInfo
; 
1518                         error 
= PBSetCatInfoSync(&pb
); 
1522                         /* oops, a file was passed */ 
1530 /*****************************************************************************/ 
1532 pascal  OSErr 
FSpSetDInfo(const FSSpec 
*spec
, 
1533                                                   const DInfo 
*fndrInfo
) 
1535         return ( SetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) ); 
1538 /*****************************************************************************/ 
1540 pascal  OSErr   
GetDirectoryID(short vRefNum
, 
1542                                                            ConstStr255Param name
, 
1544                                                            Boolean 
*isDirectory
) 
1549         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1550         if ( error 
== noErr 
) 
1552                 *isDirectory 
= (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0; 
1555                         *theDirID 
= pb
.dirInfo
.ioDrDirID
; 
1559                         *theDirID 
= pb
.hFileInfo
.ioFlParID
; 
1566 /*****************************************************************************/ 
1568 pascal  OSErr   
FSpGetDirectoryID(const FSSpec 
*spec
, 
1570                                                                   Boolean 
*isDirectory
) 
1572         return ( GetDirectoryID(spec
->vRefNum
, spec
->parID
, spec
->name
, 
1573                          theDirID
, isDirectory
) ); 
1576 /*****************************************************************************/ 
1578 pascal  OSErr   
GetDirName(short vRefNum
, 
1587                 pb
.dirInfo
.ioNamePtr 
= name
; 
1588                 pb
.dirInfo
.ioVRefNum 
= vRefNum
; 
1589                 pb
.dirInfo
.ioDrDirID 
= dirID
; 
1590                 pb
.dirInfo
.ioFDirIndex 
= -1;    /* get information about ioDirID */ 
1591                 error 
= PBGetCatInfoSync(&pb
); 
1601 /*****************************************************************************/ 
1603 pascal  OSErr   
GetIOACUser(short vRefNum
, 
1605                                                         ConstStr255Param name
, 
1611         /* Clear ioACUser before calling PBGetCatInfo since some file systems 
1612         ** don't bother to set or clear this field. If ioACUser isn't set by the 
1613         ** file system, then you'll get the zero value back (full access) which 
1614         ** is the access you have on volumes that don't support ioACUser. 
1616         pb
.dirInfo
.ioACUser 
= 0;        /* ioACUser used to be filler2 */ 
1617         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1618         if ( error 
== noErr 
) 
1620                 if ( (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) == 0 ) 
1622                         /* oops, a file was passed */ 
1627                         *ioACUser 
= pb
.dirInfo
.ioACUser
; 
1634 /*****************************************************************************/ 
1636 pascal  OSErr   
FSpGetIOACUser(const FSSpec 
*spec
, 
1639         return ( GetIOACUser(spec
->vRefNum
, spec
->parID
, spec
->name
, ioACUser
) ); 
1642 /*****************************************************************************/ 
1644 pascal  OSErr   
GetParentID(short vRefNum
, 
1646                                                         ConstStr255Param name
, 
1654         /* Protection against File Sharing problem */ 
1655         if ( (name 
== NULL
) || (name
[0] == 0) ) 
1658                 pb
.hFileInfo
.ioNamePtr 
= tempName
; 
1659                 pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1663                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
1664                 pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1666         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1667         pb
.hFileInfo
.ioDirID 
= dirID
; 
1668         error 
= PBGetCatInfoSync(&pb
); 
1669         if ( error 
== noErr 
) 
1672                 **      There's a bug in HFS where the wrong parent dir ID can be 
1673                 **      returned if multiple separators are used at the end of a 
1674                 **      pathname. For example, if the pathname: 
1675                 **              'volumeName:System Folder:Extensions::' 
1676                 **      is passed, the directory ID of the Extensions folder is 
1677                 **      returned in the ioFlParID field instead of fsRtDirID. Since 
1678                 **      multiple separators at the end of a pathname always specifies 
1679                 **      a directory, we only need to work-around cases where the 
1680                 **      object is a directory and there are multiple separators at 
1681                 **      the end of the name parameter. 
1683                 if ( (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
1685                         /* Its a directory */ 
1687                         /* is there a pathname? */ 
1688                         if ( pb
.hFileInfo
.ioNamePtr 
== name 
)    
1690                                 /* could it contain multiple separators? */ 
1693                                         /* does it contain multiple separators at the end? */ 
1694                                         if ( (name
[name
[0]] == ':') && (name
[name
[0] - 1] == ':') ) 
1696                                                 /* OK, then do the extra stuff to get the correct parID */ 
1698                                                 /* Get the real vRefNum (this should not fail) */ 
1699                                                 error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
1700                                                 if ( error 
== noErr 
) 
1702                                                         /* we don't need the parent's name, but add protect against File Sharing problem */ 
1704                                                         pb
.dirInfo
.ioNamePtr 
= tempName
; 
1705                                                         pb
.dirInfo
.ioVRefNum 
= realVRefNum
; 
1706                                                         /* pb.dirInfo.ioDrDirID already contains the */ 
1707                                                         /* dirID of the directory object */ 
1708                                                         pb
.dirInfo
.ioFDirIndex 
= -1;    /* get information about ioDirID */ 
1709                                                         error 
= PBGetCatInfoSync(&pb
); 
1710                                                         /* now, pb.dirInfo.ioDrParID contains the correct parID */ 
1717                 if ( error 
== noErr 
) 
1719                         /* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */ 
1720                         /* contains the parent ID */ 
1721                         *parID 
= pb
.hFileInfo
.ioFlParID
; 
1728 /*****************************************************************************/ 
1730 pascal  OSErr   
GetFilenameFromPathname(ConstStr255Param pathname
, 
1737         /* default to no filename */ 
1740         /* check for no pathname */ 
1741         if ( pathname 
!= NULL 
) 
1743                 /* get string length */ 
1744                 index 
= pathname
[0]; 
1746                 /* check for empty string */ 
1749                         /* skip over last trailing colon (if any) */ 
1750                         if ( pathname
[index
] == ':' ) 
1755                         /* save the end of the string */ 
1758                         /* if pathname ends with multiple colons, then this pathname refers */ 
1759                         /* to a directory, not a file */ 
1760                         if ( pathname
[index
] != ':' ) 
1762                                 /* parse backwards until we find a colon or hit the beginning of the pathname */ 
1763                                 while ( (index 
!= 0) && (pathname
[index
] != ':') ) 
1768                                 /* if we parsed to the beginning of the pathname and the pathname ended */ 
1769                                 /* with a colon, then pathname is a full pathname to a volume, not a file */ 
1770                                 if ( (index 
!= 0) || (pathname
[pathname
[0]] != ':') ) 
1772                                         /* get the filename and return noErr */ 
1773                                         filename
[0] = (char)(nameEnd 
- index
); 
1774                                         BlockMoveData(&pathname
[index
+1], &filename
[1], nameEnd 
- index
); 
1779                                         /* pathname to a volume, not a file */ 
1780                                         error 
= notAFileErr
; 
1785                                 /* directory, not a file */ 
1786                                 error 
= notAFileErr
; 
1791                         /* empty string isn't a file */ 
1792                         error 
= notAFileErr
; 
1797                 /* NULL pathname isn't a file */ 
1798                 error 
= notAFileErr
; 
1804 /*****************************************************************************/ 
1806 pascal  OSErr   
GetObjectLocation(short vRefNum
, 
1808                                                                   ConstStr255Param pathname
, 
1812                                                                   Boolean 
*isDirectory
) 
1816         Str255 tempPathname
; 
1824         **      Get the real vRefNum 
1826         error 
= DetermineVRefNum(pathname
, vRefNum
, realVRefNum
); 
1827         if ( error 
== noErr 
) 
1830                 **      Determine if the object already exists and if so, 
1831                 **      get the real parent directory ID if it's a file 
1834                 /* Protection against File Sharing problem */ 
1835                 if ( (pathname 
== NULL
) || (pathname
[0] == 0) ) 
1837                         tempPathname
[0] = 0; 
1838                         pb
.hFileInfo
.ioNamePtr 
= tempPathname
; 
1839                         pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1843                         pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)pathname
; 
1844                         pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1846                 pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1847                 pb
.hFileInfo
.ioDirID 
= dirID
; 
1848                 error 
= PBGetCatInfoSync(&pb
); 
1849                 if ( error 
== noErr 
) 
1852                         **      The file system object is present and we have the file's real parID 
1855                         /*      Is it a directory or a file? */ 
1856                         *isDirectory 
= (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0; 
1860                                 **      It's a directory, get its name and parent dirID, and then we're done 
1863                                 pb
.dirInfo
.ioNamePtr 
= realName
; 
1864                                 pb
.dirInfo
.ioVRefNum 
= *realVRefNum
; 
1865                                 /* pb.dirInfo.ioDrDirID already contains the dirID of the directory object */ 
1866                                 pb
.dirInfo
.ioFDirIndex 
= -1;    /* get information about ioDirID */ 
1867                                 error 
= PBGetCatInfoSync(&pb
); 
1869                                 /* get the parent ID here, because the file system can return the */ 
1870                                 /* wrong parent ID from the last call. */ 
1871                                 *realParID 
= pb
.dirInfo
.ioDrParID
; 
1876                                 **      It's a file - use the parent directory ID from the last call 
1877                                 **      to GetCatInfoparse, get the file name, and then we're done 
1879                                 *realParID 
= pb
.hFileInfo
.ioFlParID
;     
1880                                 error 
= GetFilenameFromPathname(pathname
, realName
); 
1883                 else if ( error 
== fnfErr 
) 
1886                         **      The file system object is not present - see if its parent is present 
1890                         **      Parse to get the object name from end of pathname 
1892                         error 
= GetFilenameFromPathname(pathname
, realName
); 
1894                         /* if we can't get the object name from the end, we can't continue */ 
1895                         if ( error 
== noErr 
) 
1898                                 **      What we want now is the pathname minus the object name 
1900                                 **      if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:' 
1901                                 **      if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:' 
1902                                 **      if pathname is ':dir:file' tempPathname becomes ':dir:' 
1903                                 **      if pathname is ':dir:file:' tempPathname becomes ':dir:' 
1904                                 **      if pathname is ':file' tempPathname becomes ':' 
1905                                 **      if pathname is 'file or file:' tempPathname becomes '' 
1908                                 /* get a copy of the pathname */ 
1909                                 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); 
1911                                 /* remove the object name */ 
1912                                 tempPathname
[0] -= realName
[0]; 
1913                                 /* and the trailing colon (if any) */ 
1914                                 if ( pathname
[pathname
[0]] == ':' ) 
1919                                 /* OK, now get the parent's directory ID */ 
1921                                 /* Protection against File Sharing problem */ 
1922                                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)tempPathname
; 
1923                                 if ( tempPathname
[0] != 0 ) 
1925                                         pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1929                                         pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1931                                 pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1932                                 pb
.hFileInfo
.ioDirID 
= dirID
; 
1933                                 error 
= PBGetCatInfoSync(&pb
); 
1934                                 *realParID 
= pb
.dirInfo
.ioDrDirID
; 
1936                                 *isDirectory 
= false;   /* we don't know what the object is really going to be */ 
1939                         if ( error 
!= noErr 
) 
1941                                 error 
= dirNFErr
;       /* couldn't find parent directory */ 
1945                                 error 
= fnfErr
; /* we found the parent, but not the file */ 
1953 /*****************************************************************************/ 
1955 pascal  OSErr   
GetDirItems(short vRefNum
, 
1957                                                         ConstStr255Param name
, 
1959                                                         Boolean getDirectories
, 
1962                                                         short *actItemCount
, 
1963                                                         short *itemIndex
) /* start with 1, then use what's returned */ 
1968         Boolean isDirectory
; 
1969         FSSpec 
*endItemsArray
; 
1971         if ( *itemIndex 
> 0 ) 
1973                 /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */ 
1974                 /* to this routine, I could rip out calls to DetermineVRefNum and GetDirectoryID and this */ 
1975                 /* routine would be much faster because of the overhead of DetermineVRefNum and */ 
1976                 /* GetDirectoryID and because GetDirectoryID blows away the directory index hint the Macintosh */ 
1977                 /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */ 
1978                 /* pass a big array of FSSpecs so you can get the directory's contents with few calls */ 
1979                 /* to this routine. */ 
1981                 /* get the real volume reference number */ 
1982                 error 
= DetermineVRefNum(name
, vRefNum
, &pb
.hFileInfo
.ioVRefNum
); 
1983                 if ( error 
== noErr 
) 
1985                         /* and the real directory ID of this directory (and make sure it IS a directory) */ 
1986                         error 
= GetDirectoryID(vRefNum
, dirID
, name
, &theDirID
, &isDirectory
); 
1987                         if ( error 
== noErr 
) 
1992                                         endItemsArray 
= items 
+ reqItemCount
; 
1993                                         while ( (items 
< endItemsArray
) && (error 
== noErr
) ) 
1995                                                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
) &items
->name
; 
1996                                                 pb
.hFileInfo
.ioDirID 
= theDirID
; 
1997                                                 pb
.hFileInfo
.ioFDirIndex 
= *itemIndex
; 
1998                                                 error 
= PBGetCatInfoSync(&pb
); 
1999                                                 if ( error 
== noErr 
) 
2001                                                         items
->parID 
= pb
.hFileInfo
.ioFlParID
;  /* return item's parID */ 
2002                                                         items
->vRefNum 
= pb
.hFileInfo
.ioVRefNum
;        /* return item's vRefNum */ 
2003                                                         ++*itemIndex
;   /* prepare to get next item in directory */ 
2005                                                         if ( (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
2007                                                                 if ( getDirectories 
) 
2009                                                                         ++*actItemCount
; /* keep this item */ 
2010                                                                         ++items
; /* point to next item */ 
2017                                                                         ++*actItemCount
; /* keep this item */ 
2018                                                                         ++items
; /* point to next item */ 
2026                                         /* it wasn't a directory */ 
2041 /*****************************************************************************/ 
2043 static  void    DeleteLevel(long dirToDelete
, 
2044                                                         DeleteEnumGlobalsPtr theGlobals
) 
2050                 /* prepare to delete directory */ 
2051                 theGlobals
->myPB
.ciPB
.dirInfo
.ioNamePtr 
= (StringPtr
)&theGlobals
->itemName
; 
2052                 theGlobals
->myPB
.ciPB
.dirInfo
.ioFDirIndex 
= 1;  /* get first item */ 
2053                 theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID 
= dirToDelete
;  /* in this directory */ 
2054                 theGlobals
->error 
= PBGetCatInfoSync(&(theGlobals
->myPB
.ciPB
)); 
2055                 if ( theGlobals
->error 
== noErr 
) 
2057                         savedDir 
= dirToDelete
; 
2058                         /* We have an item.  Is it a file or directory? */ 
2059                         if ( (theGlobals
->myPB
.ciPB
.dirInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ) 
2061                                 /* it's a directory */ 
2062                                 savedDir 
= theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
;     /* save dirID of directory instead */ 
2063                                 DeleteLevel(theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
, theGlobals
);       /* Delete its contents */ 
2064                                 theGlobals
->myPB
.ciPB
.dirInfo
.ioNamePtr 
= NULL
; /* prepare to delete directory */ 
2066                         if ( theGlobals
->error 
== noErr 
) 
2068                                 theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID 
= savedDir
;     /* restore dirID */ 
2069                                 theGlobals
->myPB
.hPB
.fileParam
.ioFVersNum 
= 0;  /* just in case it's used on an MFS volume... */ 
2070                                 theGlobals
->error 
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
));     /* delete this item */ 
2071                                 if ( theGlobals
->error 
== fLckdErr 
) 
2073                                         (void) PBHRstFLockSync(&(theGlobals
->myPB
.hPB
));        /* unlock it */ 
2074                                         theGlobals
->error 
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
));     /* and try again */ 
2078         } while ( theGlobals
->error 
== noErr 
); 
2080         if ( theGlobals
->error 
== fnfErr 
) 
2082                 theGlobals
->error 
= noErr
; 
2086 /*****************************************************************************/ 
2088 pascal  OSErr   
DeleteDirectoryContents(short vRefNum
, 
2090                                                                                 ConstStr255Param name
) 
2092         DeleteEnumGlobals theGlobals
; 
2093         Boolean isDirectory
; 
2096         /*  Get the real dirID and make sure it is a directory. */ 
2097         error 
= GetDirectoryID(vRefNum
, dirID
, name
, &dirID
, &isDirectory
); 
2098         if ( error 
== noErr 
) 
2102                         /* Get the real vRefNum */ 
2103                         error 
= DetermineVRefNum(name
, vRefNum
, &vRefNum
); 
2104                         if ( error 
== noErr 
) 
2106                                 /* Set up the globals we need to access from the recursive routine. */ 
2107                                 theGlobals
.myPB
.ciPB
.dirInfo
.ioVRefNum 
= vRefNum
; 
2109                                 /* Here we go into recursion land... */ 
2110                                 DeleteLevel(dirID
, &theGlobals
); 
2111                                 error 
= theGlobals
.error
; 
2123 /*****************************************************************************/ 
2125 pascal  OSErr   
DeleteDirectory(short vRefNum
, 
2127                                                                 ConstStr255Param name
) 
2131         /* Make sure a directory was specified and then delete its contents */ 
2132         error 
= DeleteDirectoryContents(vRefNum
, dirID
, name
); 
2133         if ( error 
== noErr 
) 
2135                 error 
= HDelete(vRefNum
, dirID
, name
); 
2136                 if ( error 
== fLckdErr 
) 
2138                         (void) HRstFLock(vRefNum
, dirID
, name
); /* unlock the directory locked by AppleShare */ 
2139                         error 
= HDelete(vRefNum
, dirID
, name
);  /* and try again */ 
2146 /*****************************************************************************/ 
2148 pascal  OSErr   
CheckObjectLock(short vRefNum
, 
2150                                                                 ConstStr255Param name
) 
2155         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
2156         if ( error 
== noErr 
) 
2158                 /* check locked bit */ 
2159                 if ( (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribLockedMask
) != 0 ) 
2168 /*****************************************************************************/ 
2170 pascal  OSErr   
FSpCheckObjectLock(const FSSpec 
*spec
) 
2172         return ( CheckObjectLock(spec
->vRefNum
, spec
->parID
, spec
->name
) ); 
2175 /*****************************************************************************/ 
2177 pascal  OSErr   
GetFileSize(short vRefNum
, 
2179                                                         ConstStr255Param fileName
, 
2186         pb
.fileParam
.ioNamePtr 
= (StringPtr
)fileName
; 
2187         pb
.fileParam
.ioVRefNum 
= vRefNum
; 
2188         pb
.fileParam
.ioFVersNum 
= 0; 
2189         pb
.fileParam
.ioDirID 
= dirID
; 
2190         pb
.fileParam
.ioFDirIndex 
= 0; 
2191         error 
= PBHGetFInfoSync(&pb
); 
2192         if ( error 
== noErr 
) 
2194                 *dataSize 
= pb
.fileParam
.ioFlLgLen
; 
2195                 *rsrcSize 
= pb
.fileParam
.ioFlRLgLen
; 
2201 /*****************************************************************************/ 
2203 pascal  OSErr   
FSpGetFileSize(const FSSpec 
*spec
, 
2207         return ( GetFileSize(spec
->vRefNum
, spec
->parID
, spec
->name
, dataSize
, rsrcSize
) ); 
2210 /*****************************************************************************/ 
2212 pascal  OSErr   
BumpDate(short vRefNum
, 
2214                                                  ConstStr255Param name
) 
2215 /* Given a file or directory, change its modification date to the current date/time. */ 
2222         /* Protection against File Sharing problem */ 
2223         if ( (name 
== NULL
) || (name
[0] == 0) ) 
2226                 pb
.hFileInfo
.ioNamePtr 
= tempName
; 
2227                 pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
2231                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
2232                 pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
2234         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
2235         pb
.hFileInfo
.ioDirID 
= dirID
; 
2236         error 
= PBGetCatInfoSync(&pb
); 
2237         if ( error 
== noErr 
) 
2240                 /* set mod date to current date, or one second into the future 
2241                         if mod date = current date */ 
2242                 pb
.hFileInfo
.ioFlMdDat 
= (secs 
== pb
.hFileInfo
.ioFlMdDat
) ? (++secs
) : (secs
); 
2243                 if ( pb
.dirInfo
.ioNamePtr 
== tempName 
) 
2245                         pb
.hFileInfo
.ioDirID 
= pb
.hFileInfo
.ioFlParID
; 
2249                         pb
.hFileInfo
.ioDirID 
= dirID
; 
2251                 error 
= PBSetCatInfoSync(&pb
); 
2257 /*****************************************************************************/ 
2259 pascal  OSErr   
FSpBumpDate(const FSSpec 
*spec
) 
2261         return ( BumpDate(spec
->vRefNum
, spec
->parID
, spec
->name
) ); 
2264 /*****************************************************************************/ 
2266 pascal  OSErr   
ChangeCreatorType(short vRefNum
, 
2268                                                                   ConstStr255Param name
, 
2277         pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
2278         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
2279         pb
.hFileInfo
.ioDirID 
= dirID
; 
2280         pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
2281         error 
= PBGetCatInfoSync(&pb
); 
2282         if ( error 
== noErr 
) 
2284                 if ( (pb
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) == 0 )      /* if file */ 
2286                         parID 
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */ 
2288                         /* If creator not 0x00000000, change creator */ 
2289                         if ( creator 
!= (OSType
)0x00000000 ) 
2291                                 pb
.hFileInfo
.ioFlFndrInfo
.fdCreator 
= creator
; 
2294                         /* If fileType not 0x00000000, change fileType */ 
2295                         if ( fileType 
!= (OSType
)0x00000000 ) 
2297                                 pb
.hFileInfo
.ioFlFndrInfo
.fdType 
= fileType
; 
2300                         pb
.hFileInfo
.ioDirID 
= dirID
; 
2301                         error 
= PBSetCatInfoSync(&pb
);  /* now, save the new information back to disk */ 
2303                         if ( (error 
== noErr
) && (parID 
!= fsRtParID
) ) /* can't bump fsRtParID */ 
2305                                 /* get the real vRefNum in case a full pathname was passed */ 
2306                                 error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
2307                                 if ( error 
== noErr 
) 
2309                                         error 
= BumpDate(realVRefNum
, parID
, NULL
); 
2310                                                 /* and bump the parent directory's mod date to wake up the Finder */ 
2311                                                 /* to the change we just made */ 
2317                         /* it was a directory, not a file */ 
2318                         error 
= notAFileErr
; 
2325 /*****************************************************************************/ 
2327 pascal  OSErr   
FSpChangeCreatorType(const FSSpec 
*spec
, 
2331         return ( ChangeCreatorType(spec
->vRefNum
, spec
->parID
, spec
->name
, creator
, fileType
) ); 
2334 /*****************************************************************************/ 
2336 pascal  OSErr   
ChangeFDFlags(short vRefNum
, 
2338                                                           ConstStr255Param name
, 
2340                                                           unsigned short flagBits
) 
2348         /* Protection against File Sharing problem */ 
2349         if ( (name 
== NULL
) || (name
[0] == 0) ) 
2352                 pb
.hFileInfo
.ioNamePtr 
= tempName
; 
2353                 pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
2357                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
2358                 pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
2360         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
2361         pb
.hFileInfo
.ioDirID 
= dirID
; 
2362         error 
= PBGetCatInfoSync(&pb
); 
2363         if ( error 
== noErr 
) 
2365                 parID 
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */ 
2367                 /* set or clear the appropriate bits in the Finder flags */ 
2370                         /* OR in the bits */ 
2371                         pb
.hFileInfo
.ioFlFndrInfo
.fdFlags 
|= flagBits
; 
2375                         /* AND out the bits */ 
2376                         pb
.hFileInfo
.ioFlFndrInfo
.fdFlags 
&= ~flagBits
; 
2379                 if ( pb
.dirInfo
.ioNamePtr 
== tempName 
) 
2381                         pb
.hFileInfo
.ioDirID 
= pb
.hFileInfo
.ioFlParID
; 
2385                         pb
.hFileInfo
.ioDirID 
= dirID
; 
2388                 error 
= PBSetCatInfoSync(&pb
);  /* now, save the new information back to disk */ 
2390                 if ( (error 
== noErr
) && (parID 
!= fsRtParID
) ) /* can't bump fsRtParID */ 
2392                         /* get the real vRefNum in case a full pathname was passed */ 
2393                         error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
2394                         if ( error 
== noErr 
) 
2396                                 error 
= BumpDate(realVRefNum
, parID
, NULL
); 
2397                                         /* and bump the parent directory's mod date to wake up the Finder */ 
2398                                         /* to the change we just made */ 
2406 /*****************************************************************************/ 
2408 pascal  OSErr   
FSpChangeFDFlags(const FSSpec 
*spec
, 
2410                                                                  unsigned short flagBits
) 
2412         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, setBits
, flagBits
) ); 
2415 /*****************************************************************************/ 
2417 pascal  OSErr   
SetIsInvisible(short vRefNum
, 
2419                                                            ConstStr255Param name
) 
2420         /* Given a file or directory, make it invisible. */ 
2422         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsInvisible
) ); 
2425 /*****************************************************************************/ 
2427 pascal  OSErr   
FSpSetIsInvisible(const FSSpec 
*spec
) 
2428         /* Given a file or directory, make it invisible. */ 
2430         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsInvisible
) ); 
2433 /*****************************************************************************/ 
2435 pascal  OSErr   
ClearIsInvisible(short vRefNum
, 
2437                                                                  ConstStr255Param name
) 
2438         /* Given a file or directory, make it visible. */ 
2440         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsInvisible
) ); 
2443 /*****************************************************************************/ 
2445 pascal  OSErr   
FSpClearIsInvisible(const FSSpec 
*spec
) 
2446         /* Given a file or directory, make it visible. */ 
2448         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsInvisible
) ); 
2451 /*****************************************************************************/ 
2453 pascal  OSErr   
SetNameLocked(short vRefNum
, 
2455                                                           ConstStr255Param name
) 
2456         /* Given a file or directory, lock its name. */ 
2458         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kNameLocked
) ); 
2461 /*****************************************************************************/ 
2463 pascal  OSErr   
FSpSetNameLocked(const FSSpec 
*spec
) 
2464         /* Given a file or directory, lock its name. */ 
2466         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kNameLocked
) ); 
2469 /*****************************************************************************/ 
2471 pascal  OSErr   
ClearNameLocked(short vRefNum
, 
2473                                                                 ConstStr255Param name
) 
2474         /* Given a file or directory, unlock its name. */ 
2476         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kNameLocked
) ); 
2479 /*****************************************************************************/ 
2481 pascal  OSErr   
FSpClearNameLocked(const FSSpec 
*spec
) 
2482         /* Given a file or directory, unlock its name. */ 
2484         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kNameLocked
) ); 
2487 /*****************************************************************************/ 
2489 pascal  OSErr   
SetIsStationery(short vRefNum
, 
2491                                                                 ConstStr255Param name
) 
2492         /* Given a file, make it a stationery pad. */ 
2494         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsStationery
) ); 
2497 /*****************************************************************************/ 
2499 pascal  OSErr   
FSpSetIsStationery(const FSSpec 
*spec
) 
2500         /* Given a file, make it a stationery pad. */ 
2502         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsStationery
) ); 
2505 /*****************************************************************************/ 
2507 pascal  OSErr   
ClearIsStationery(short vRefNum
, 
2509                                                                   ConstStr255Param name
) 
2510         /* Given a file, clear the stationery bit. */ 
2512         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsStationery
) ); 
2515 /*****************************************************************************/ 
2517 pascal  OSErr   
FSpClearIsStationery(const FSSpec 
*spec
) 
2518         /* Given a file, clear the stationery bit. */ 
2520         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsStationery
) ); 
2523 /*****************************************************************************/ 
2525 pascal  OSErr   
SetHasCustomIcon(short vRefNum
, 
2527                                                                  ConstStr255Param name
) 
2528         /* Given a file or directory, indicate that it has a custom icon. */ 
2530         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kHasCustomIcon
) ); 
2533 /*****************************************************************************/ 
2535 pascal  OSErr   
FSpSetHasCustomIcon(const FSSpec 
*spec
) 
2536         /* Given a file or directory, indicate that it has a custom icon. */ 
2538         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kHasCustomIcon
) ); 
2541 /*****************************************************************************/ 
2543 pascal  OSErr   
ClearHasCustomIcon(short vRefNum
, 
2545                                                                    ConstStr255Param name
) 
2546         /* Given a file or directory, indicate that it does not have a custom icon. */ 
2548         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasCustomIcon
) ); 
2551 /*****************************************************************************/ 
2553 pascal  OSErr   
FSpClearHasCustomIcon(const FSSpec 
*spec
) 
2554         /* Given a file or directory, indicate that it does not have a custom icon. */ 
2556         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasCustomIcon
) ); 
2559 /*****************************************************************************/ 
2561 pascal  OSErr   
ClearHasBeenInited(short vRefNum
, 
2563                                                                    ConstStr255Param name
) 
2564         /* Given a file, clear its "has been inited" bit. */ 
2566         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasBeenInited
) ); 
2569 /*****************************************************************************/ 
2571 pascal  OSErr   
FSpClearHasBeenInited(const FSSpec 
*spec
) 
2572         /* Given a file, clear its "has been inited" bit. */ 
2574         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasBeenInited
) ); 
2577 /*****************************************************************************/ 
2579 pascal  OSErr   
CopyFileMgrAttributes(short srcVRefNum
, 
2581                                                                           ConstStr255Param srcName
, 
2584                                                                           ConstStr255Param dstName
, 
2585                                                                           Boolean copyLockBit
) 
2590         Boolean objectIsDirectory
; 
2592         pb
.ciPB
.hFileInfo
.ioVRefNum 
= srcVRefNum
; 
2593         pb
.ciPB
.hFileInfo
.ioDirID 
= srcDirID
; 
2595         /* Protection against File Sharing problem */ 
2596         if ( (srcName 
== NULL
) || (srcName
[0] == 0) ) 
2599                 pb
.ciPB
.hFileInfo
.ioNamePtr 
= tempName
; 
2600                 pb
.ciPB
.hFileInfo
.ioFDirIndex 
= -1;     /* use ioDirID */ 
2604                 pb
.ciPB
.hFileInfo
.ioNamePtr 
= (StringPtr
)srcName
; 
2605                 pb
.ciPB
.hFileInfo
.ioFDirIndex 
= 0;      /* use ioNamePtr and ioDirID */ 
2607         error 
= PBGetCatInfoSync(&pb
.ciPB
); 
2608         if ( error 
== noErr 
) 
2610                 objectIsDirectory 
= ( (pb
.ciPB
.hFileInfo
.ioFlAttrib 
& kioFlAttribDirMask
) != 0 ); 
2611                 pb
.ciPB
.hFileInfo
.ioVRefNum 
= dstVRefNum
; 
2612                 pb
.ciPB
.hFileInfo
.ioDirID 
= dstDirID
; 
2613                 if ( (dstName 
!= NULL
) && (dstName
[0] == 0) ) 
2615                         pb
.ciPB
.hFileInfo
.ioNamePtr 
= NULL
; 
2619                         pb
.ciPB
.hFileInfo
.ioNamePtr 
= (StringPtr
)dstName
; 
2621                 /* don't copy the hasBeenInited bit */ 
2622                 pb
.ciPB
.hFileInfo
.ioFlFndrInfo
.fdFlags 
= ( pb
.ciPB
.hFileInfo
.ioFlFndrInfo
.fdFlags 
& ~kHasBeenInited 
); 
2623                 error 
= PBSetCatInfoSync(&pb
.ciPB
); 
2624                 if ( (error 
== noErr
) && (copyLockBit
) && ((pb
.ciPB
.hFileInfo
.ioFlAttrib 
& kioFlAttribLockedMask
) != 0) ) 
2626                         pb
.hPB
.fileParam
.ioFVersNum 
= 0; 
2627                         error 
= PBHSetFLockSync(&pb
.hPB
); 
2628                         if ( (error 
!= noErr
) && (objectIsDirectory
) ) 
2630                                 error 
= noErr
; /* ignore lock errors if destination is directory */ 
2637 /*****************************************************************************/ 
2639 pascal  OSErr   
FSpCopyFileMgrAttributes(const FSSpec 
*srcSpec
, 
2640                                                                                  const FSSpec 
*dstSpec
, 
2641                                                                                  Boolean copyLockBit
) 
2643         return ( CopyFileMgrAttributes(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
2644                                                                    dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
, 
2648 /*****************************************************************************/ 
2650 pascal  OSErr   
HOpenAware(short vRefNum
, 
2652                                                    ConstStr255Param fileName
, 
2658         GetVolParmsInfoBuffer volParmsInfo
; 
2659         long infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
2661         pb
.ioParam
.ioMisc 
= NULL
; 
2662         pb
.fileParam
.ioFVersNum 
= 0; 
2663         pb
.fileParam
.ioNamePtr 
= (StringPtr
)fileName
; 
2664         pb
.fileParam
.ioVRefNum 
= vRefNum
; 
2665         pb
.fileParam
.ioDirID 
= dirID
; 
2667         /* get volume attributes */ 
2668         /* this preflighting is needed because Foreign File Access based file systems don't */ 
2669         /* return the correct error result to the OpenDeny call */ 
2670         error 
= HGetVolParms(fileName
, vRefNum
, &volParmsInfo
, &infoSize
); 
2671         if ( (error 
== noErr
) && hasOpenDeny(&volParmsInfo
) ) 
2673                 /* if volume supports OpenDeny, use it and return */ 
2674                         pb
.accessParam
.ioDenyModes 
= denyModes
; 
2675                         error 
= PBHOpenDenySync(&pb
); 
2676                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2678         else if ( (error 
== noErr
) || (error 
== paramErr
) )     /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 
2680                 /* OpenDeny isn't supported, so try File Manager Open functions */ 
2682                 /* If request includes write permission, then see if the volume is */ 
2683                 /* locked by hardware or software. The HFS file system doesn't check */ 
2684                 /* for this when a file is opened - you only find out later when you */ 
2685                 /* try to write and the write fails with a wPrErr or a vLckdErr. */ 
2687                 if ( (denyModes 
& dmWr
) != 0 ) 
2689                         error 
= CheckVolLock(fileName
, vRefNum
); 
2696                 if ( error 
== noErr 
) 
2698                         /* Set File Manager permissions to closest thing possible */ 
2699                         if ( (denyModes 
== dmWr
) || (denyModes 
== dmRdWr
) ) 
2701                                 pb
.ioParam
.ioPermssn 
= fsRdWrShPerm
; 
2705                                 pb
.ioParam
.ioPermssn 
= denyModes 
% 4; 
2708                         error 
= PBHOpenDFSync(&pb
);                             /* Try OpenDF */ 
2709                         if ( error 
== paramErr 
) 
2711                                 error 
= PBHOpenSync(&pb
);                       /* OpenDF not supported, so try Open */ 
2713                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2720 /*****************************************************************************/ 
2722 pascal  OSErr   
FSpOpenAware(const FSSpec 
*spec
, 
2726         return ( HOpenAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) ); 
2729 /*****************************************************************************/ 
2731 pascal  OSErr   
HOpenRFAware(short vRefNum
, 
2733                                                          ConstStr255Param fileName
, 
2739         GetVolParmsInfoBuffer volParmsInfo
; 
2740         long infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
2742         pb
.ioParam
.ioMisc 
= NULL
; 
2743         pb
.fileParam
.ioFVersNum 
= 0; 
2744         pb
.fileParam
.ioNamePtr 
= (StringPtr
)fileName
; 
2745         pb
.fileParam
.ioVRefNum 
= vRefNum
; 
2746         pb
.fileParam
.ioDirID 
= dirID
; 
2748         /* get volume attributes */ 
2749         /* this preflighting is needed because Foreign File Access based file systems don't */ 
2750         /* return the correct error result to the OpenRFDeny call */ 
2751         error 
= HGetVolParms(fileName
, vRefNum
, &volParmsInfo
, &infoSize
); 
2752         if ( (error 
== noErr
) && hasOpenDeny(&volParmsInfo
) ) 
2754                 /* if volume supports OpenRFDeny, use it and return */ 
2755                 if ( hasOpenDeny(&volParmsInfo
) ) 
2757                         pb
.accessParam
.ioDenyModes 
= denyModes
; 
2758                         error 
= PBHOpenRFDenySync(&pb
); 
2759                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2762         else if ( (error 
== noErr
) || (error 
== paramErr
) )     /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 
2764                 /* OpenRFDeny isn't supported, so try File Manager OpenRF function */ 
2766                 /* If request includes write permission, then see if the volume is */ 
2767                 /* locked by hardware or software. The HFS file system doesn't check */ 
2768                 /* for this when a file is opened - you only find out later when you */ 
2769                 /* try to write and the write fails with a wPrErr or a vLckdErr. */ 
2771                 if ( (denyModes 
& dmWr
) != 0 ) 
2773                         error 
= CheckVolLock(fileName
, vRefNum
); 
2780                 if ( error 
== noErr 
) 
2782                         /* Set File Manager permissions to closest thing possible */ 
2783                         if ( (denyModes 
== dmWr
) || (denyModes 
== dmRdWr
) ) 
2785                                 pb
.ioParam
.ioPermssn 
= fsRdWrShPerm
; 
2789                                 pb
.ioParam
.ioPermssn 
= denyModes 
% 4; 
2792                         error 
= PBHOpenRFSync(&pb
); 
2793                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2800 /*****************************************************************************/ 
2802 pascal  OSErr   
FSpOpenRFAware(const FSSpec 
*spec
, 
2806         return ( HOpenRFAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) ); 
2809 /*****************************************************************************/ 
2811 pascal  OSErr   
FSReadNoCache(short refNum
, 
2818         pb
.ioParam
.ioRefNum 
= refNum
; 
2819         pb
.ioParam
.ioBuffer 
= (Ptr
)buffPtr
; 
2820         pb
.ioParam
.ioReqCount 
= *count
; 
2821         pb
.ioParam
.ioPosMode 
= fsAtMark 
+ noCacheMask
;  /* fsAtMark + noCacheMask */ 
2822         pb
.ioParam
.ioPosOffset 
= 0; 
2823         error 
= PBReadSync(&pb
); 
2824         *count 
= pb
.ioParam
.ioActCount
;                         /* always return count */ 
2828 /*****************************************************************************/ 
2830 pascal  OSErr   
FSWriteNoCache(short refNum
, 
2832                                                            const void *buffPtr
) 
2837         pb
.ioParam
.ioRefNum 
= refNum
; 
2838         pb
.ioParam
.ioBuffer 
= (Ptr
)buffPtr
; 
2839         pb
.ioParam
.ioReqCount 
= *count
; 
2840         pb
.ioParam
.ioPosMode 
= fsAtMark 
+ noCacheMask
;  /* fsAtMark + noCacheMask */ 
2841         pb
.ioParam
.ioPosOffset 
= 0; 
2842         error 
= PBWriteSync(&pb
); 
2843         *count 
= pb
.ioParam
.ioActCount
;                         /* always return count */ 
2847 /*****************************************************************************/ 
2850 **      See if numBytes bytes of buffer1 are equal to buffer2. 
2852 static  Boolean 
EqualMemory(const void *buffer1
, const void *buffer2
, unsigned long numBytes
) 
2854         register unsigned char *b1 
= (unsigned char *)buffer1
; 
2855         register unsigned char *b2 
= (unsigned char *)buffer2
; 
2857         if ( b1 
!= b2 
) /* if buffer pointers are same, then they are equal */ 
2859                 while ( numBytes 
> 0 ) 
2861                         /* compare the bytes and then increment the pointers */ 
2862                         if ( (*b1
++ - *b2
++) != 0 ) 
2873 /*****************************************************************************/ 
2876 **      Read any number of bytes from an open file using read-verify mode. 
2877 **      The FSReadVerify function reads any number of bytes from an open file 
2878 **      and verifies them against the data in the buffer pointed to by buffPtr. 
2880 **      Because of a bug in the HFS file system, only non-block aligned parts of 
2881 **      the read are verified against the buffer data and the rest is *copied* 
2882 **      into the buffer.  Thus, you shouldn't verify against your original data; 
2883 **      instead, you should verify against a copy of the original data and then 
2884 **      compare the read-verified copy against the original data after calling 
2885 **      FSReadVerify. That's why this function isn't exported - it needs the 
2886 **      wrapper provided by FSWriteVerify. 
2888 static  OSErr   
FSReadVerify(short refNum
, 
2895         pb
.ioParam
.ioRefNum 
= refNum
; 
2896         pb
.ioParam
.ioBuffer 
= (Ptr
)buffPtr
; 
2897         pb
.ioParam
.ioReqCount 
= *count
; 
2898         pb
.ioParam
.ioPosMode 
= fsAtMark 
+ rdVerify
; 
2899         pb
.ioParam
.ioPosOffset 
= 0; 
2900         result 
= PBReadSync(&pb
); 
2901         *count 
= pb
.ioParam
.ioActCount
;                 /* always return count */ 
2905 /*****************************************************************************/ 
2907 pascal  OSErr   
FSWriteVerify(short refNum
, 
2909                                                           const void *buffPtr
) 
2920         **      Allocate the verify buffer 
2921         **      Try to get get a large enough buffer to verify in one pass. 
2922         **      If that fails, use GetTempBuffer to get a buffer. 
2924         bufferSize 
= *count
; 
2925         verifyBuffer 
= NewPtr(bufferSize
); 
2926         if ( verifyBuffer 
== NULL 
) 
2928                 verifyBuffer 
= GetTempBuffer(bufferSize
, &bufferSize
); 
2930         if ( verifyBuffer 
!= NULL 
) 
2932                 /* Save the current position */ 
2933                 result 
= GetFPos(refNum
, &position
); 
2934                 if ( result 
== noErr 
) 
2936                         /* Write the data */ 
2937                         result 
= FSWrite(refNum
, count
, buffPtr
); 
2938                         if ( result 
== noErr 
) 
2940                                 /* Restore the original position */ 
2941                                 result 
= SetFPos(refNum
, fsFromStart
, position
); 
2942                                 if ( result 
== noErr 
) 
2945                                         **      *count                  = total number of bytes to verify 
2946                                         **      bufferSize              = the size of the verify buffer 
2947                                         **      bytesVerified   = number of bytes verified 
2948                                         **      byteCount               = number of bytes to verify this pass 
2949                                         **      startVerify             = position in buffPtr 
2952                                         startVerify 
= (Ptr
)buffPtr
; 
2953                                         while ( (bytesVerified 
< *count
) && ( result 
== noErr 
) ) 
2955                                                 if ( (*count 
- bytesVerified
) > bufferSize 
) 
2957                                                         byteCount 
= bufferSize
; 
2961                                                         byteCount 
= *count 
- bytesVerified
; 
2964                                                 **      Copy the write buffer into the verify buffer. 
2965                                                 **      This step is needed because the File Manager 
2966                                                 **      compares the data in any non-block aligned 
2967                                                 **      data at the beginning and end of the read-verify 
2968                                                 **      request back into the file system's cache 
2969                                                 **      to the data in verify Buffer. However, the 
2970                                                 **      File Manager does not compare any full blocks 
2971                                                 **      and instead copies them into the verify buffer 
2972                                                 **      so we still have to compare the buffers again 
2973                                                 **      after the read-verify request completes. 
2975                                                 BlockMoveData(startVerify
, verifyBuffer
, byteCount
); 
2977                                                 /* Read-verify the data back into the verify buffer */ 
2978                                                 result 
= FSReadVerify(refNum
, &byteCount
, verifyBuffer
); 
2979                                                 if ( result 
== noErr 
) 
2981                                                         /* See if the buffers are the same */ 
2982                                                         if ( !EqualMemory(verifyBuffer
, startVerify
, byteCount
) ) 
2986                                                         startVerify 
+= byteCount
; 
2987                                                         bytesVerified 
+= byteCount
; 
2993                 DisposePtr(verifyBuffer
); 
2997                 result 
= memFullErr
; 
3002 /*****************************************************************************/ 
3004 pascal  OSErr   
CopyFork(short srcRefNum
, 
3006                                                  void *copyBufferPtr
, 
3007                                                  long copyBufferSize
) 
3009         ParamBlockRec srcPB
; 
3010         ParamBlockRec dstPB
; 
3014         if ( (copyBufferPtr 
== NULL
) || (copyBufferSize 
== 0) ) 
3015                 return ( paramErr 
); 
3017         srcPB
.ioParam
.ioRefNum 
= srcRefNum
; 
3018         dstPB
.ioParam
.ioRefNum 
= dstRefNum
; 
3020         /* preallocate the destination fork and */ 
3021         /* ensure the destination fork's EOF is correct after the copy */ 
3022         srcError 
= PBGetEOFSync(&srcPB
); 
3023         if ( srcError 
!= noErr 
) 
3024                 return ( srcError 
); 
3025         dstPB
.ioParam
.ioMisc 
= srcPB
.ioParam
.ioMisc
; 
3026         dstError 
= PBSetEOFSync(&dstPB
); 
3027         if ( dstError 
!= noErr 
) 
3028                 return ( dstError 
); 
3030         /* reset source fork's mark */ 
3031         srcPB
.ioParam
.ioPosMode 
= fsFromStart
; 
3032         srcPB
.ioParam
.ioPosOffset 
= 0; 
3033         srcError 
= PBSetFPosSync(&srcPB
); 
3034         if ( srcError 
!= noErr 
) 
3035                 return ( srcError 
); 
3037         /* reset destination fork's mark */ 
3038         dstPB
.ioParam
.ioPosMode 
= fsFromStart
; 
3039         dstPB
.ioParam
.ioPosOffset 
= 0; 
3040         dstError 
= PBSetFPosSync(&dstPB
); 
3041         if ( dstError 
!= noErr 
) 
3042                 return ( dstError 
); 
3044         /* set up fields that won't change in the loop */ 
3045         srcPB
.ioParam
.ioBuffer 
= (Ptr
)copyBufferPtr
; 
3046         srcPB
.ioParam
.ioPosMode 
= fsAtMark 
+ noCacheMask
;/* fsAtMark + noCacheMask */ 
3047         /* If copyBufferSize is greater than 512 bytes, make it a multiple of 512 bytes */ 
3048         /* This will make writes on local volumes faster */ 
3049         if ( (copyBufferSize 
>= 512) && ((copyBufferSize 
& 0x1ff) != 0) ) 
3051                 srcPB
.ioParam
.ioReqCount 
= copyBufferSize 
& 0xfffffe00; 
3055                 srcPB
.ioParam
.ioReqCount 
= copyBufferSize
; 
3057         dstPB
.ioParam
.ioBuffer 
= (Ptr
)copyBufferPtr
; 
3058         dstPB
.ioParam
.ioPosMode 
= fsAtMark 
+ noCacheMask
;/* fsAtMark + noCacheMask */ 
3060         while ( (srcError 
== noErr
) && (dstError 
== noErr
) ) 
3062                 srcError 
= PBReadSync(&srcPB
); 
3063                 dstPB
.ioParam
.ioReqCount 
= srcPB
.ioParam
.ioActCount
; 
3064                 dstError 
= PBWriteSync(&dstPB
); 
3067         /* make sure there were no errors at the destination */ 
3068         if ( dstError 
!= noErr 
) 
3069                 return ( dstError 
); 
3071         /* make sure the only error at the source was eofErr */ 
3072         if ( srcError 
!= eofErr 
) 
3073                 return ( srcError 
); 
3078 /*****************************************************************************/ 
3080 pascal  OSErr   
GetFileLocation(short refNum
, 
3088         pb
.ioNamePtr 
= fileName
; 
3090         pb
.ioRefNum 
= refNum
; 
3092         error 
= PBGetFCBInfoSync(&pb
); 
3093         if ( error 
== noErr 
) 
3095                 *vRefNum 
= pb
.ioFCBVRefNum
; 
3096                 *dirID 
= pb
.ioFCBParID
; 
3101 /*****************************************************************************/ 
3103 pascal  OSErr   
FSpGetFileLocation(short refNum
, 
3106         return ( GetFileLocation(refNum
, &(spec
->vRefNum
), &(spec
->parID
), spec
->name
) ); 
3109 /*****************************************************************************/ 
3111 pascal  OSErr   
CopyDirectoryAccess(short srcVRefNum
, 
3113                                                                         ConstStr255Param srcName
, 
3116                                                                         ConstStr255Param dstName
) 
3119         GetVolParmsInfoBuffer infoBuffer
;       /* Where PBGetVolParms dumps its info */ 
3120         long    dstServerAdr
;                           /* AppleTalk server address of destination (if any) */ 
3121         long    ownerID
, groupID
, accessRights
; 
3124         /* See if destination supports directory access control */ 
3125         tempLong 
= sizeof(infoBuffer
); 
3126         error 
= HGetVolParms(dstName
, dstVRefNum
, &infoBuffer
, &tempLong
); 
3127         if ( (error 
== noErr
) && hasAccessCntl(&infoBuffer
) ) 
3129                 if ( hasAccessCntl(&infoBuffer
) ) 
3131                         dstServerAdr 
= infoBuffer
.vMServerAdr
; 
3133                         /* See if source supports directory access control and is on same server */ 
3134                         tempLong 
= sizeof(infoBuffer
); 
3135                         error 
= HGetVolParms(srcName
, srcVRefNum
, &infoBuffer
, &tempLong
); 
3136                         if ( error 
== noErr 
) 
3138                                 if ( hasAccessCntl(&infoBuffer
) && (dstServerAdr 
== infoBuffer
.vMServerAdr
) ) 
3140                                         /* both volumes support directory access control and they are */ 
3141                                         /*  on same server, so copy the access information */ 
3142                                         error 
= HGetDirAccess(srcVRefNum
, srcDirID
, srcName
, &ownerID
, &groupID
, &accessRights
); 
3143                                         if ( error 
== noErr 
) 
3145                                                 error 
= HSetDirAccess(dstVRefNum
, dstDirID
, dstName
, ownerID
, groupID
, accessRights
); 
3150                                         /* destination doesn't support directory access control or */ 
3151                                         /* they volumes aren't on the same server */ 
3158                         /* destination doesn't support directory access control */ 
3166 /*****************************************************************************/ 
3168 pascal  OSErr   
FSpCopyDirectoryAccess(const FSSpec 
*srcSpec
, 
3169                                                                            const FSSpec 
*dstSpec
) 
3171         return ( CopyDirectoryAccess(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
3172                                                                 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
) ); 
3175 /*****************************************************************************/ 
3177 pascal  OSErr   
HMoveRenameCompat(short vRefNum
, 
3179                                                                   ConstStr255Param srcName
, 
3181                                                                   ConstStr255Param dstpathName
, 
3182                                                                   ConstStr255Param copyName
) 
3185         GetVolParmsInfoBuffer   volParmsInfo
; 
3190         Boolean                                 isDirectory
; 
3191         long                                    tempItemsDirID
; 
3192         long                                    uniqueTempDirID
; 
3193         Str31                                   uniqueTempDirName
; 
3194         unsigned short                  uniqueNameoverflow
; 
3196         /* Get volume attributes */ 
3197         infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
3198         error 
= HGetVolParms((StringPtr
)srcName
, vRefNum
, &volParmsInfo
, &infoSize
); 
3199         if ( (error 
== noErr
) && hasMoveRename(&volParmsInfo
) ) 
3201                 /* If volume supports move and rename, so use it and return */ 
3202                 error 
= HMoveRename(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
, copyName
); 
3204         else if ( (error 
== noErr
) || (error 
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 
3206                 /* MoveRename isn't supported by this volume, so do it by hand */ 
3208                 /* If copyName isn't supplied, we can simply CatMove and return */ 
3209                 if ( copyName 
== NULL 
) 
3211                         error 
= CatMove(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
); 
3215                         /* Renaming is required, so we have some work to do... */ 
3217                         /* Get the object's real name, real parent ID and real vRefNum */ 
3218                         error 
= GetObjectLocation(vRefNum
, srcDirID
, (StringPtr
)srcName
, 
3219                                                                                 &realVRefNum
, &realParID
, realName
, &isDirectory
); 
3220                         if ( error 
== noErr 
) 
3222                                 /* Find the Temporary Items Folder on that volume */ 
3223                                 error 
= FindFolder(realVRefNum
, kTemporaryFolderType
, kCreateFolder
, 
3224                                                                         &realVRefNum
, &tempItemsDirID
); 
3225                                 if ( error 
== noErr 
) 
3227                                         /* Create a new uniquely named folder in the temporary items folder. */ 
3228                                         /* This is done to avoid the case where 'realName' or 'copyName' already */ 
3229                                         /* exists in the temporary items folder. */ 
3231                                         /* Start with current tick count as uniqueTempDirName */                                         
3232                                         NumToString(TickCount(), uniqueTempDirName
); 
3233                                         uniqueNameoverflow 
= 0; 
3236                                                 error 
= DirCreate(realVRefNum
, tempItemsDirID
, uniqueTempDirName
, &uniqueTempDirID
); 
3237                                                 if ( error 
== dupFNErr 
) 
3239                                                         /* Duplicate name - change the first character to the next ASCII character */ 
3240                                                         ++uniqueTempDirName
[1]; 
3241                                                         /* Make sure it isn't a colon! */ 
3242                                                         if ( uniqueTempDirName
[1] == ':' ) 
3244                                                                 ++uniqueTempDirName
[1]; 
3246                                                         /* Don't go too far... */ 
3247                                                         ++uniqueNameoverflow
; 
3249                                         } while ( (error 
== dupFNErr
) && (uniqueNameoverflow 
<= 64) ); /* 64 new files per 1/60th second - not likely! */ 
3250                                         if ( error 
== noErr 
) 
3252                                                 /* Move the object to the folder with uniqueTempDirID for renaming */ 
3253                                                 error 
= CatMove(realVRefNum
, realParID
, realName
, uniqueTempDirID
, NULL
); 
3254                                                 if ( error 
== noErr 
) 
3256                                                         /* Rename the object */  
3257                                                         error 
= HRename(realVRefNum
, uniqueTempDirID
, realName
, copyName
); 
3258                                                         if ( error 
== noErr 
) 
3260                                                                 /* Move object to its new home */ 
3261                                                                 error 
= CatMove(realVRefNum
, uniqueTempDirID
, copyName
, dstDirID
, dstpathName
); 
3262                                                                 if ( error 
!= noErr 
) 
3264                                                                         /* Error handling: rename object back to original name - ignore errors */ 
3265                                                                         (void) HRename(realVRefNum
, uniqueTempDirID
, copyName
, realName
); 
3268                                                         if ( error 
!= noErr 
) 
3270                                                                 /* Error handling: move object back to original location - ignore errors */ 
3271                                                                 (void) CatMove(realVRefNum
, uniqueTempDirID
, realName
, realParID
, NULL
); 
3274                                                 /* Done with ourTempDir, so delete it - ignore errors */ 
3275                                                 (void) HDelete(realVRefNum
, uniqueTempDirID
, NULL
); 
3285 /*****************************************************************************/ 
3287 pascal  OSErr   
FSpMoveRenameCompat(const FSSpec 
*srcSpec
, 
3288                                                                         const FSSpec 
*dstSpec
, 
3289                                                                         ConstStr255Param copyName
) 
3291         /* make sure the FSSpecs refer to the same volume */ 
3292         if (srcSpec
->vRefNum 
!= dstSpec
->vRefNum
) 
3293                 return (diffVolErr
); 
3294         return ( HMoveRenameCompat(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
3295                                           dstSpec
->parID
, dstSpec
->name
, copyName
) ); 
3298 /*****************************************************************************/ 
3300 pascal  OSErr   
BuildAFPVolMountInfo(short flags
, 
3310                                                                          AFPVolMountInfoPtr 
*afpInfoPtr
) 
3312         MyAFPVolMountInfoPtr    infoPtr
; 
3315         /* Allocate the AFPXVolMountInfo record */ 
3316         infoPtr 
= (MyAFPVolMountInfoPtr
)NewPtrClear(sizeof(MyAFPVolMountInfo
)); 
3317         if ( infoPtr 
!= NULL 
) 
3319                 /* Fill in an AFPVolMountInfo record that can be passed to VolumeMount */ 
3320                 infoPtr
->length 
= sizeof(MyAFPVolMountInfo
); 
3321                 infoPtr
->media 
= AppleShareMediaType
; 
3322                 infoPtr
->flags 
= flags
; 
3323                 infoPtr
->nbpInterval 
= nbpInterval
; 
3324                 infoPtr
->nbpCount 
= nbpCount
; 
3325                 infoPtr
->uamType 
= uamType
; 
3327                 infoPtr
->zoneNameOffset 
= offsetof(MyAFPVolMountInfo
, zoneName
); 
3328                 infoPtr
->serverNameOffset 
= offsetof(MyAFPVolMountInfo
, serverName
); 
3329                 infoPtr
->volNameOffset 
= offsetof(MyAFPVolMountInfo
, volName
); 
3330                 infoPtr
->userNameOffset 
= offsetof(MyAFPVolMountInfo
, userName
); 
3331                 infoPtr
->userPasswordOffset 
= offsetof(MyAFPVolMountInfo
, userPassword
); 
3332                 infoPtr
->volPasswordOffset 
= offsetof(MyAFPVolMountInfo
, volPassword
); 
3334                 BlockMoveData(zoneName
, infoPtr
->zoneName
, sizeof(Str32
)); 
3335                 BlockMoveData(serverName
, infoPtr
->serverName
, sizeof(Str32
)); 
3336                 BlockMoveData(volName
, infoPtr
->volName
, sizeof(Str27
)); 
3337                 BlockMoveData(userName
, infoPtr
->userName
, sizeof(Str31
)); 
3338                 BlockMoveData(userPassword
, infoPtr
->userPassword
, sizeof(Str8
)); 
3339                 BlockMoveData(volPassword
, infoPtr
->volPassword
, sizeof(Str8
)); 
3341                 *afpInfoPtr 
= (AFPVolMountInfoPtr
)infoPtr
; 
3352 /*****************************************************************************/ 
3354 pascal  OSErr   
RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr
, 
3358                                                                                 StringPtr serverName
, 
3365         /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */ 
3366         if ( afpInfoPtr
->media 
== AppleShareMediaType 
) 
3368                 *flags 
= afpInfoPtr
->flags
; 
3369                 *uamType 
= afpInfoPtr
->uamType
; 
3371                 if ( afpInfoPtr
->zoneNameOffset 
!= 0) 
3373                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->zoneNameOffset
); 
3374                         BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1); 
3377                 if ( afpInfoPtr
->serverNameOffset 
!= 0) 
3379                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->serverNameOffset
); 
3380                         BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1); 
3383                 if ( afpInfoPtr
->volNameOffset 
!= 0) 
3385                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->volNameOffset
); 
3386                         BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1); 
3389                 if ( afpInfoPtr
->userNameOffset 
!= 0) 
3391                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->userNameOffset
); 
3392                         BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1); 
3405 /*****************************************************************************/ 
3407 pascal  OSErr   
BuildAFPXVolMountInfo(short flags
, 
3418                                                                           unsigned long alternateAddressLength
, 
3419                                                                           void *alternateAddress
, 
3420                                                                           AFPXVolMountInfoPtr 
*afpXInfoPtr
) 
3423         MyAFPXVolMountInfoPtr   infoPtr
; 
3426         /* Calculate the size of the AFPXVolMountInfo record */ 
3427         infoSize 
= sizeof(MyAFPXVolMountInfo
) + alternateAddressLength 
- 1; 
3429         /* Allocate the AFPXVolMountInfo record */ 
3430         infoPtr 
= (MyAFPXVolMountInfoPtr
)NewPtrClear(infoSize
); 
3431         if ( infoPtr 
!= NULL 
) 
3433                 /* Fill in an AFPXVolMountInfo record that can be passed to VolumeMount */ 
3434                 infoPtr
->length 
= infoSize
; 
3435                 infoPtr
->media 
= AppleShareMediaType
; 
3436                 infoPtr
->flags 
= flags
; 
3437                 if ( alternateAddressLength 
!= 0 ) 
3439                         /* make sure the volMountExtendedFlagsBit is set if there's extended address info */ 
3440                         infoPtr
->flags 
|= volMountExtendedFlagsMask
; 
3441                         /* and set the only extendedFlags bit we know about */ 
3442                         infoPtr
->extendedFlags 
= kAFPExtendedFlagsAlternateAddressMask
; 
3446                         /* make sure the volMountExtendedFlagsBit is clear if there's no extended address info */ 
3447                         infoPtr
->flags 
&= ~volMountExtendedFlagsMask
; 
3448                         /* and clear the extendedFlags */ 
3449                         infoPtr
->extendedFlags 
= 0; 
3451                 infoPtr
->nbpInterval 
= nbpInterval
; 
3452                 infoPtr
->nbpCount 
= nbpCount
; 
3453                 infoPtr
->uamType 
= uamType
; 
3455                 infoPtr
->zoneNameOffset 
= offsetof(MyAFPXVolMountInfo
, zoneName
);                
3456                 infoPtr
->serverNameOffset 
= offsetof(MyAFPXVolMountInfo
, serverName
); 
3457                 infoPtr
->volNameOffset 
= offsetof(MyAFPXVolMountInfo
, volName
); 
3458                 infoPtr
->userNameOffset 
= offsetof(MyAFPXVolMountInfo
, userName
); 
3459                 infoPtr
->userPasswordOffset 
= offsetof(MyAFPXVolMountInfo
, userPassword
); 
3460                 infoPtr
->volPasswordOffset 
= offsetof(MyAFPXVolMountInfo
, volPassword
); 
3461                 infoPtr
->uamNameOffset 
= offsetof(MyAFPXVolMountInfo
, uamName
); 
3462                 infoPtr
->alternateAddressOffset 
= offsetof(MyAFPXVolMountInfo
, alternateAddress
); 
3464                 BlockMoveData(zoneName
, infoPtr
->zoneName
, sizeof(Str32
)); 
3465                 BlockMoveData(serverName
, infoPtr
->serverName
, sizeof(Str32
)); 
3466                 BlockMoveData(volName
, infoPtr
->volName
, sizeof(Str27
)); 
3467                 BlockMoveData(userName
, infoPtr
->userName
, sizeof(Str31
)); 
3468                 BlockMoveData(userPassword
, infoPtr
->userPassword
, sizeof(Str8
)); 
3469                 BlockMoveData(volPassword
, infoPtr
->volPassword
, sizeof(Str8
)); 
3470                 BlockMoveData(uamName
, infoPtr
->uamName
, sizeof(Str32
)); 
3471                 BlockMoveData(alternateAddress
, infoPtr
->alternateAddress
, alternateAddressLength
); 
3473                 *afpXInfoPtr 
= (AFPXVolMountInfoPtr
)infoPtr
; 
3484 /*****************************************************************************/ 
3486 pascal  OSErr   
RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr
, 
3490                                                                                  StringPtr serverName
, 
3494                                                                                  unsigned long *alternateAddressLength
, 
3495                                                                                  AFPAlternateAddress 
**alternateAddress
) 
3498         Ptr                     alternateAddressStart
; 
3499         Ptr                     alternateAddressEnd
; 
3500         Size            alternateAddressDataSize
; 
3504         /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */ 
3505         if ( afpXInfoPtr
->media 
== AppleShareMediaType 
) 
3507                 /* default to noErr */ 
3510                 /* Is this an extended record? */ 
3511                 if ( (afpXInfoPtr
->flags 
& volMountExtendedFlagsMask
) != 0 ) 
3513                         if ( ((afpXInfoPtr
->extendedFlags 
& kAFPExtendedFlagsAlternateAddressMask
) != 0) && 
3514                                  (afpXInfoPtr
->alternateAddressOffset 
!= 0) ) 
3517                                 alternateAddressStart 
= (Ptr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->alternateAddressOffset
); 
3518                                 alternateAddressEnd 
= alternateAddressStart 
+ 1;        /* skip over alternate address version byte */ 
3519                                 addressCount 
= *(UInt8
*)alternateAddressEnd
;            /* get the address count */ 
3520                                 ++alternateAddressEnd
;                                                          /* skip over alternate address count byte */ 
3521                                 /* alternateAddressEnd now equals &AFPAlternateAddress.fAddressList[0] */ 
3522                                 while ( addressCount 
!= 0 ) 
3524                                         /* parse the address list to find the end */ 
3525                                         alternateAddressEnd 
+= *(UInt8
*)alternateAddressEnd
;    /* add length of each AFPTagData record */ 
3528                                 /* get the size of the alternateAddressData */ 
3529                                 alternateAddressDataSize 
= alternateAddressEnd 
- alternateAddressStart
; 
3530                                 /* allocate memory for it */ 
3531                                 *alternateAddress 
= (AFPAlternateAddress 
*)NewPtr(alternateAddressDataSize
); 
3532                                 if ( *alternateAddress 
!= NULL 
) 
3534                                         /* and return the data */ 
3535                                         BlockMoveData(alternateAddressStart
, *alternateAddress
, alternateAddressDataSize
); 
3536                                         *alternateAddressLength 
= alternateAddressDataSize
; 
3540                                         /* no memory - fail now */ 
3545                         if ( error 
== noErr 
)   /* fill in more output parameters if everything is OK */ 
3547                                 if ( afpXInfoPtr
->uamNameOffset 
!= 0 ) 
3549                                         tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->uamNameOffset
); 
3550                                         BlockMoveData(tempPtr
, uamName
, tempPtr
[0] + 1); 
3555                 if ( error 
== noErr 
)   /* fill in more output parameters if everything is OK */ 
3557                         *flags 
= afpXInfoPtr
->flags
; 
3558                         *uamType 
= afpXInfoPtr
->uamType
; 
3560                         if ( afpXInfoPtr
->zoneNameOffset 
!= 0 ) 
3562                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->zoneNameOffset
); 
3563                                 BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1); 
3566                         if ( afpXInfoPtr
->serverNameOffset 
!= 0 ) 
3568                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->serverNameOffset
); 
3569                                 BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1); 
3572                         if ( afpXInfoPtr
->volNameOffset 
!= 0 ) 
3574                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->volNameOffset
); 
3575                                 BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1); 
3578                         if ( afpXInfoPtr
->userNameOffset 
!= 0 ) 
3580                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->userNameOffset
); 
3581                                 BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1); 
3593 /*****************************************************************************/ 
3595 pascal  OSErr   
GetUGEntries(short objType
, 
3598                                                          long *actEntryCount
, 
3602         OSErr error 
= noErr
; 
3603         UGEntry 
*endEntryArray
; 
3605         pb
.objParam
.ioObjType 
= objType
; 
3607         for ( endEntryArray 
= entries 
+ reqEntryCount
; (entries 
< endEntryArray
) && (error 
== noErr
); ++entries 
) 
3609                 pb
.objParam
.ioObjNamePtr 
= (StringPtr
)entries
->name
; 
3610                 pb
.objParam
.ioObjID 
= *objID
; 
3611                 /* Files.h in the universal interfaces, PBGetUGEntrySync takes a CMovePBPtr */ 
3612                 /* as the parameter. Inside Macintosh and the original glue used HParmBlkPtr. */ 
3613                 /* A CMovePBPtr works OK, but this will be changed in the future  back to */ 
3614                 /* HParmBlkPtr, so I'm just casting it here. */ 
3615                 error 
= PBGetUGEntrySync(&pb
); 
3616                 if ( error 
== noErr 
) 
3618                         entries
->objID 
= *objID 
= pb
.objParam
.ioObjID
; 
3619                         entries
->objType 
= objType
; 
3627 /*****************************************************************************/