2 **      Apple Macintosh Developer Technical Support 
   4 **      A collection of useful high-level File Manager routines. 
   6 **      by Jim Luther, Apple Developer Technical Support Emeritus 
   8 **      File:           MoreFilesExtras.c 
  10 **      Copyright © 1992-1998 Apple Computer, Inc. 
  11 **      All rights reserved. 
  13 **      You may incorporate this sample code into your applications without 
  14 **      restriction, though the sample code has been provided "AS IS" and the 
  15 **      responsibility for its operation is 100% yours.  However, what you are 
  16 **      not permitted to do is to redistribute the source as "DSC Sample Code" 
  17 **      after having made changes. If you're going to re-distribute the source, 
  18 **      we require that you make it clear in the source that the code was 
  19 **      descended from Apple Sample Code, but that you've made changes. 
  33 #include <TextUtils.h> 
  38 #define __COMPILINGMOREFILES 
  45 /*****************************************************************************/ 
  47 /* local data structures */ 
  49 /* The DeleteEnumGlobals structure is used to minimize the amount of 
  50 ** stack space used when recursively calling DeleteLevel and to hold 
  51 ** global information that might be needed at any time. */ 
  53 #if PRAGMA_ALIGN_SUPPORTED 
  54 #pragma options align=mac68k 
  56 struct DeleteEnumGlobals
 
  58         OSErr                   error
;                          /* temporary holder of results - saves 2 bytes of stack each level */ 
  59         Str63                   itemName
;                       /* the name of the current item */ 
  60         UniversalFMPB   myPB
;                           /* the parameter block used for PBGetCatInfo calls */ 
  62 #if PRAGMA_ALIGN_SUPPORTED 
  63 #pragma options align=reset 
  66 typedef struct DeleteEnumGlobals DeleteEnumGlobals
; 
  67 typedef DeleteEnumGlobals 
*DeleteEnumGlobalsPtr
; 
  69 /*****************************************************************************/ 
  71 pascal  void    TruncPString(StringPtr destination
, 
  72                                                          ConstStr255Param source
, 
  77         if ( source 
!= NULL 
&& destination 
!= NULL 
)    /* don't do anything stupid */ 
  79                 if ( source
[0] > maxLength 
) 
  81                         /* Make sure the string isn't truncated in the middle of */ 
  82                         /* a multi-byte character. */ 
  83                         while (maxLength 
!= 0) 
  85                                 charType 
= CharByte((Ptr
)&source
[1], maxLength
); 
  86                                 if ( (charType 
== smSingleByte
) || (charType 
== smLastByte
) ) 
  87                                         break;  /* source[maxLength] is now a valid last character */  
  93                         maxLength 
= source
[0]; 
  95                 /* Set the destination string length */ 
  96                 destination
[0] = maxLength
; 
  97                 /* and copy maxLength characters (if needed) */ 
  98                 if ( source 
!= destination 
) 
 100                         while ( maxLength 
!= 0 ) 
 102                                 destination
[maxLength
] = source
[maxLength
]; 
 109 /*****************************************************************************/ 
 111 pascal  Ptr     
GetTempBuffer(long buffReqSize
, 
 116                 kSlopMemory 
= 0x00008000        /* 32K - Amount of free memory to leave when allocating buffers */ 
 120         /* Make request a multiple of 1024 bytes */ 
 121         buffReqSize 
= buffReqSize 
& 0xfffffc00; 
 123         if ( buffReqSize 
< 0x00000400 ) 
 125                 /* Request was smaller than 1024 bytes - make it 1024 */ 
 126                 buffReqSize 
= 0x00000400; 
 129         /* Attempt to allocate the memory */ 
 130         tempPtr 
= NewPtr(buffReqSize
); 
 132         /* If request failed, go to backup plan */ 
 133         if ( (tempPtr 
== NULL
) && (buffReqSize 
> 0x00000400) ) 
 136                 **      Try to get largest 1024-byte block available 
 137                 **      leaving some slop for the toolbox if possible 
 139                 long freeMemory 
= (FreeMem() - kSlopMemory
) & 0xfffffc00; 
 141                 buffReqSize 
= MaxBlock() & 0xfffffc00; 
 143                 if ( buffReqSize 
> freeMemory 
) 
 145                         buffReqSize 
= freeMemory
; 
 148                 if ( buffReqSize 
== 0 ) 
 150                         buffReqSize 
= 0x00000400; 
 153                 tempPtr 
= NewPtr(buffReqSize
); 
 156         /* Return bytes allocated */ 
 157         if ( tempPtr 
!= NULL 
) 
 159                 *buffActSize 
= buffReqSize
; 
 169 /*****************************************************************************/ 
 172 **      GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync 
 173 **      in cases where the returned volume name is not needed by the caller. 
 174 **      The pathname and vRefNum parameters are not touched, and the pb 
 175 **      parameter is initialized by PBHGetVInfoSync except that ioNamePtr in 
 176 **      the parameter block is always returned as NULL (since it might point 
 177 **      to the local tempPathname). 
 179 **      I noticed using this code in several places, so here it is once. 
 180 **      This reduces the code size of MoreFiles. 
 182 pascal  OSErr   
GetVolumeInfoNoName(ConstStr255Param pathname
, 
 189         /* Make sure pb parameter is not NULL */  
 192                 pb
->volumeParam
.ioVRefNum 
= vRefNum
; 
 193                 if ( pathname 
== NULL 
) 
 195                         pb
->volumeParam
.ioNamePtr 
= NULL
; 
 196                         pb
->volumeParam
.ioVolIndex 
= 0;         /* use ioVRefNum only */ 
 200                         BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); /* make a copy of the string and */ 
 201                         pb
->volumeParam
.ioNamePtr 
= (StringPtr
)tempPathname
;    /* use the copy so original isn't trashed */ 
 202                         pb
->volumeParam
.ioVolIndex 
= -1;        /* use ioNamePtr/ioVRefNum combination */ 
 204                 error 
= PBHGetVInfoSync(pb
); 
 205                 pb
->volumeParam
.ioNamePtr 
= NULL
;       /* ioNamePtr may point to local tempPathname, so don't return it */ 
 214 /*****************************************************************************/ 
 217 **      XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync 
 218 **      in cases where the returned volume name is not needed by the caller. 
 219 **      The pathname and vRefNum parameters are not touched, and the pb 
 220 **      parameter is initialized by PBXGetVolInfoSync except that ioNamePtr in 
 221 **      the parameter block is always returned as NULL (since it might point 
 222 **      to the local tempPathname). 
 224 pascal  OSErr   
XGetVolumeInfoNoName(ConstStr255Param pathname
, 
 232         /* Make sure pb parameter is not NULL */  
 235                 pb
->ioVRefNum 
= vRefNum
; 
 236                 pb
->ioXVersion 
= 0;                     /* this XVolumeParam version (0) */ 
 237                 if ( pathname 
== NULL 
) 
 239                         pb
->ioNamePtr 
= NULL
; 
 240                         pb
->ioVolIndex 
= 0;             /* use ioVRefNum only */ 
 244                         BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); /* make a copy of the string and */ 
 245                         pb
->ioNamePtr 
= (StringPtr
)tempPathname
;        /* use the copy so original isn't trashed */ 
 246                         pb
->ioVolIndex 
= -1;    /* use ioNamePtr/ioVRefNum combination */ 
 248 #if     !__MACOSSEVENFIVEONEORLATER 
 249                 /* Is PBXGetVolInfo available? */ 
 250                 if ( ( Gestalt(gestaltFSAttr
, &response
) != noErr 
) || ((response 
& (1L << gestaltFSSupports2TBVols
)) == 0) ) 
 252                         /* No, fall back on PBHGetVInfo */ 
 253                         error 
= PBHGetVInfoSync((HParmBlkPtr
)pb
); 
 254                         if ( error 
== noErr 
) 
 256                                 /* calculate the ioVTotalBytes and ioVFreeBytes fields */ 
 257                                 pb
->ioVTotalBytes
.hi 
= 0; 
 258                                 pb
->ioVTotalBytes
.lo 
= pb
->ioVNmAlBlks 
* pb
->ioVAlBlkSiz
;       /* calculated total number of bytes on volume */ 
 259                                 pb
->ioVFreeBytes
.hi 
= 0; 
 260                                 pb
->ioVFreeBytes
.lo 
= pb
->ioVFrBlk 
* pb
->ioVAlBlkSiz
;   /* calculated number of free bytes on volume */ 
 264 #endif  // !__MACOSSEVENFIVEONEORLATER 
 267                         error 
= PBXGetVolInfoSync(pb
); 
 269                 pb
->ioNamePtr 
= NULL
;           /* ioNamePtr may point to local tempPathname, so don't return it */ 
 278 /*****************************************************************************/ 
 280 pascal  OSErr 
GetCatInfoNoName(short vRefNum
, 
 282                                                            ConstStr255Param name
, 
 288         /* Protection against File Sharing problem */ 
 289         if ( (name 
== NULL
) || (name
[0] == 0) ) 
 292                 pb
->dirInfo
.ioNamePtr 
= tempName
; 
 293                 pb
->dirInfo
.ioFDirIndex 
= -1;   /* use ioDirID */ 
 297                 pb
->dirInfo
.ioNamePtr 
= (StringPtr
)name
; 
 298                 pb
->dirInfo
.ioFDirIndex 
= 0;    /* use ioNamePtr and ioDirID */ 
 300         pb
->dirInfo
.ioVRefNum 
= vRefNum
; 
 301         pb
->dirInfo
.ioDrDirID 
= dirID
; 
 302         error 
= PBGetCatInfoSync(pb
); 
 303         pb
->dirInfo
.ioNamePtr 
= NULL
; 
 307 /*****************************************************************************/ 
 309 pascal  OSErr   
DetermineVRefNum(ConstStr255Param pathname
, 
 316         error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
 317         if ( error 
== noErr 
) 
 319                 *realVRefNum 
= pb
.volumeParam
.ioVRefNum
; 
 324 /*****************************************************************************/ 
 326 pascal  OSErr   
HGetVInfo(short volReference
, 
 329                                                   unsigned long *freeBytes
, 
 330                                                   unsigned long *totalBytes
) 
 333         unsigned long   allocationBlockSize
; 
 334         unsigned short  numAllocationBlocks
; 
 335         unsigned short  numFreeBlocks
; 
 340         /* Use the File Manager to get the real vRefNum */ 
 341         pb
.volumeParam
.ioVRefNum 
= volReference
; 
 342         pb
.volumeParam
.ioNamePtr 
= volName
; 
 343         pb
.volumeParam
.ioVolIndex 
= 0;  /* use ioVRefNum only, return volume name */ 
 344         result 
= PBHGetVInfoSync(&pb
); 
 346         if ( result 
== noErr 
) 
 348                 /* The volume name was returned in volName (if not NULL) and */ 
 349                 /* we have the volume's vRefNum and allocation block size */ 
 350                 *vRefNum 
= pb
.volumeParam
.ioVRefNum
; 
 351                 allocationBlockSize 
= (unsigned long)pb
.volumeParam
.ioVAlBlkSiz
; 
 353                 /* System 7.5 (and beyond) pins the number of allocation blocks and */ 
 354                 /* the number of free allocation blocks returned by PBHGetVInfo to */ 
 355                 /* a value so that when multiplied by the allocation block size, */ 
 356                 /* the volume will look like it has $7fffffff bytes or less. This */ 
 357                 /* was done so older applications that use signed math or that use */ 
 358                 /* the GetVInfo function (which uses signed math) will continue to work. */ 
 359                 /* However, the unpinned numbers (which we want) are always available */ 
 360                 /* in the volume's VCB so we'll get those values from the VCB if possible. */ 
 362                 /* Find the volume's VCB */ 
 364                 theVCB 
= (VCB 
*)(GetVCBQHdr()->qHead
); 
 365                 while ( (theVCB 
!= NULL
) && !vcbFound 
) 
 367                         /* Check VCB signature before using VCB. Don't have to check for */ 
 368                         /* MFS (0xd2d7) because they can't get big enough to be pinned */ 
 369                         if ( theVCB
->vcbSigWord 
== 0x4244 ) 
 371                                 if ( theVCB
->vcbVRefNum 
== *vRefNum 
) 
 379                                 theVCB 
= (VCB 
*)(theVCB
->qLink
); 
 383                 if ( theVCB 
!= NULL 
) 
 385                         /* Found a VCB we can use. Get the un-pinned number of allocation blocks */ 
 386                         /* and the number of free blocks from the VCB. */ 
 387                         numAllocationBlocks 
= (unsigned short)theVCB
->vcbNmAlBlks
; 
 388                         numFreeBlocks 
= (unsigned short)theVCB
->vcbFreeBks
; 
 392                         /* Didn't find a VCB we can use. Return the number of allocation blocks */ 
 393                         /* and the number of free blocks returned by PBHGetVInfoSync. */ 
 394                         numAllocationBlocks 
= (unsigned short)pb
.volumeParam
.ioVNmAlBlks
; 
 395                         numFreeBlocks 
= (unsigned short)pb
.volumeParam
.ioVFrBlk
; 
 398                 /* Now, calculate freeBytes and totalBytes using unsigned values */ 
 399                 *freeBytes 
= numFreeBlocks 
* allocationBlockSize
; 
 400                 *totalBytes 
= numAllocationBlocks 
* allocationBlockSize
; 
 406 /*****************************************************************************/ 
 409 **      PBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync 
 410 **      File Manager requests from CFM-based programs. At some point, Apple 
 411 **      will get around to adding this to the standard libraries you link with 
 412 **      and you'll get a duplicate symbol link error. At that time, just delete 
 413 **      this code (or comment it out). 
 415 **      Non-CFM 68K programs don't needs this glue (and won't get it) because 
 416 **      they instead use the inline assembly glue found in the Files.h interface 
 420 #if     __WANTPASCALELIMINATION 
 425 pascal OSErr 
PBXGetVolInfoSync(XVolumeParamPtr paramBlock
) 
 429                 kXGetVolInfoSelector 
= 0x0012,  /* Selector for XGetVolInfo */ 
 431                 uppFSDispatchProcInfo 
= kRegisterBased
 
 432                          | REGISTER_RESULT_LOCATION(kRegisterD0
) 
 433                          | RESULT_SIZE(SIZE_CODE(sizeof(OSErr
))) 
 434                          | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1
, SIZE_CODE(sizeof(long)))  /* trap word */ 
 435                          | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0
, SIZE_CODE(sizeof(long)))  /* selector */ 
 436                          | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0
, SIZE_CODE(sizeof(XVolumeParamPtr
))) 
 439         return ( CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch
, OSTrap
), 
 440                                                                                 uppFSDispatchProcInfo
, 
 442                                                                                 kXGetVolInfoSelector
, 
 447 #if     __WANTPASCALELIMINATION 
 451 /*****************************************************************************/ 
 453 pascal  OSErr   
XGetVInfo(short volReference
, 
 456                                                   UnsignedWide 
*freeBytes
, 
 457                                                   UnsignedWide 
*totalBytes
) 
 463         /* See if large volume support is available */ 
 464         if ( ( Gestalt(gestaltFSAttr
, &response
) == noErr 
) && ((response 
& (1L << gestaltFSSupports2TBVols
)) != 0) ) 
 466                 /* Large volume support is available */ 
 467                 pb
.ioVRefNum 
= volReference
; 
 468                 pb
.ioNamePtr 
= volName
; 
 469                 pb
.ioXVersion 
= 0;      /* this XVolumeParam version (0) */ 
 470                 pb
.ioVolIndex 
= 0;      /* use ioVRefNum only, return volume name */ 
 471                 result 
= PBXGetVolInfoSync(&pb
); 
 472                 if ( result 
== noErr 
) 
 474                         /* The volume name was returned in volName (if not NULL) and */ 
 475                         /* we have the volume's vRefNum and allocation block size */ 
 476                         *vRefNum 
= pb
.ioVRefNum
; 
 478                         /* return the freeBytes and totalBytes */ 
 479                         *totalBytes 
= pb
.ioVTotalBytes
; 
 480                         *freeBytes 
= pb
.ioVFreeBytes
; 
 485                 /* No large volume support */ 
 487                 /* Use HGetVInfo to get the results */ 
 488                 result 
= HGetVInfo(volReference
, volName
, vRefNum
, &freeBytes
->lo
, &totalBytes
->lo
); 
 489                 if ( result 
== noErr 
) 
 491                         /* zero the high longs of totalBytes and freeBytes */ 
 499 /*****************************************************************************/ 
 501 pascal  OSErr   
CheckVolLock(ConstStr255Param pathname
, 
 507         error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
 508         if ( error 
== noErr 
) 
 510                 if ( (pb
.volumeParam
.ioVAtrb 
& 0x0080) != 0 ) 
 512                         error 
= wPrErr
;         /* volume locked by hardware */ 
 514                 else if ( (pb
.volumeParam
.ioVAtrb 
& 0x8000) != 0 ) 
 516                         error 
= vLckdErr
;       /* volume locked by software */ 
 523 /*****************************************************************************/ 
 525 pascal  OSErr 
GetDriverName(short driverRefNum
, 
 530         DRVRHeaderPtr dHeaderPtr
; 
 532         theDctl 
= GetDCtlEntry(driverRefNum
); 
 533         if ( theDctl 
!= NULL 
) 
 535             if ( (**theDctl
).dCtlFlags 
& 0x40 ) 
 537                 /* dctlDriver is handle - dereference */ 
 538                         dHeaderPtr 
= *((DRVRHeaderHandle
)(**theDctl
).dCtlDriver
); 
 542                         /* dctlDriver is pointer */ 
 543               dHeaderPtr 
= (DRVRHeaderPtr
)(**theDctl
).dCtlDriver
; 
 545                 BlockMoveData((*dHeaderPtr
).drvrName
, driverName
, (*dHeaderPtr
).drvrName
[0] + 1); 
 551                 result 
= badUnitErr
;    /* bad reference number */ 
 557 /*****************************************************************************/ 
 559 pascal  OSErr   
FindDrive(ConstStr255Param pathname
, 
 561                                                   DrvQElPtr 
*driveQElementPtr
) 
 567         *driveQElementPtr 
= NULL
; 
 569         /* First, use GetVolumeInfoNoName to determine the volume */ 
 570         result 
= GetVolumeInfoNoName(pathname
, vRefNum
, &hPB
); 
 571         if ( result 
== noErr 
) 
 574                 **      The volume can be either online, offline, or ejected. What we find in 
 575                 **      ioVDrvInfo and ioVDRefNum will tell us which it is. 
 576                 **      See Inside Macintosh: Files page 2-80 and the Technical Note 
 577                 **      "FL 34 - VCBs and Drive Numbers : The Real Story" 
 578                 **      Where we get the drive number depends on the state of the volume. 
 580                 if ( hPB
.volumeParam
.ioVDrvInfo 
!= 0 ) 
 582                         /* The volume is online and not ejected */ 
 583                         /* Get the drive number */ 
 584                         driveNumber 
= hPB
.volumeParam
.ioVDrvInfo
; 
 588                         /* The volume's is either offline or ejected */ 
 589                         /* in either case, the volume is NOT online */ 
 591                         /* Is it ejected or just offline? */ 
 592                         if ( hPB
.volumeParam
.ioVDRefNum 
> 0 ) 
 594                                 /* It's ejected, the drive number is ioVDRefNum */ 
 595                                 driveNumber 
= hPB
.volumeParam
.ioVDRefNum
; 
 599                                 /* It's offline, the drive number is the negative of ioVDRefNum */ 
 600                                 driveNumber 
= (short)-hPB
.volumeParam
.ioVDRefNum
; 
 604                 /* Get pointer to first element in drive queue */ 
 605                 *driveQElementPtr 
= (DrvQElPtr
)(GetDrvQHdr()->qHead
); 
 607                 /* Search for a matching drive number */ 
 608                 while ( (*driveQElementPtr 
!= NULL
) && ((*driveQElementPtr
)->dQDrive 
!= driveNumber
) ) 
 610                         *driveQElementPtr 
= (DrvQElPtr
)(*driveQElementPtr
)->qLink
; 
 613                 if ( *driveQElementPtr 
== NULL 
) 
 615                         /* This should never happen since every volume must have a drive, but... */ 
 623 /*****************************************************************************/ 
 625 pascal  OSErr   
GetDiskBlocks(ConstStr255Param pathname
, 
 627                                                           unsigned long *numBlocks
) 
 629         /* Various constants for GetDiskBlocks() */ 
 632                 /* return format list status code */ 
 635                 /* reference number of .SONY driver */ 
 636                 kSonyRefNum 
= 0xfffb, 
 638                 /* values returned by DriveStatus in DrvSts.twoSideFmt */ 
 641                 kSingleSidedSize 
= 800,         /* 400K */ 
 642                 kDoubleSidedSize 
= 1600,        /* 800K */ 
 644                 /* values in DrvQEl.qType */ 
 648                 /* more than enough formatListRecords */ 
 649                 kMaxFormatListRecs 
= 16 
 652         DrvQElPtr               driveQElementPtr
; 
 653         unsigned long   blocks
; 
 655         FormatListRec   formatListRecords
[kMaxFormatListRecs
]; 
 657         short                   formatListRecIndex
; 
 662         /* Find the drive queue element for this volume */ 
 663         result 
= FindDrive(pathname
, vRefNum
, &driveQElementPtr
); 
 666         **      Make sure this is a real driver (dQRefNum < 0). 
 667         **      AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause 
 668         **      problems if you try to use it as a driver refNum. 
 670         if ( (result 
== noErr
) && (driveQElementPtr
->dQRefNum 
>= 0) ) 
 676                 /* Attempt to get the drive's format list. */ 
 677                 /* (see the Technical Note "What Your Sony Drives For You") */ 
 679                 pb
.cntrlParam
.ioVRefNum 
= driveQElementPtr
->dQDrive
; 
 680                 pb
.cntrlParam
.ioCRefNum 
= driveQElementPtr
->dQRefNum
; 
 681                 pb
.cntrlParam
.csCode 
= kFmtLstCode
; 
 682                 pb
.cntrlParam
.csParam
[0] = kMaxFormatListRecs
; 
 683                 *(long *)&pb
.cntrlParam
.csParam
[1] = (long)&formatListRecords
[0]; 
 685                 result 
= PBStatusSync(&pb
); 
 687                 if ( result 
== noErr 
) 
 689                         /* The drive supports ReturnFormatList status call. */ 
 691                         /* Get the current disk's size. */ 
 692                         for( formatListRecIndex 
= 0; 
 693                                  formatListRecIndex 
< pb
.cntrlParam
.csParam
[0]; 
 694                          ++formatListRecIndex 
) 
 696                         if ( (formatListRecords
[formatListRecIndex
].formatFlags 
& 
 697                                   diCIFmtFlagsCurrentMask
) != 0 ) 
 699                                 blocks 
= formatListRecords
[formatListRecIndex
].volSize
; 
 704                         /* This should never happen */ 
 708                 else if ( driveQElementPtr
->dQRefNum 
== (short)kSonyRefNum 
) 
 710                         /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */ 
 712                         result 
= DriveStatus(driveQElementPtr
->dQDrive
, &status
); 
 713                         if ( result 
== noErr 
) 
 715                                 switch ( status
.twoSideFmt 
) 
 718                                         blocks 
= kSingleSidedSize
; 
 721                                         blocks 
= kDoubleSidedSize
; 
 724                                         /* This should never happen */ 
 732                         /* The drive is not a floppy and it doesn't support ReturnFormatList */ 
 733                         /* so use the dQDrvSz field(s) */ 
 735                         result 
= noErr
; /* reset result */ 
 736                         switch ( driveQElementPtr
->qType 
) 
 739                                 blocks 
= driveQElementPtr
->dQDrvSz
; 
 742                                 blocks 
= ((unsigned long)driveQElementPtr
->dQDrvSz2 
<< 16) + 
 743                                                  driveQElementPtr
->dQDrvSz
; 
 746                                 /* This should never happen */ 
 753         if ( result 
== noErr 
) 
 761 /*****************************************************************************/ 
 763 pascal  OSErr   
GetVolFileSystemID(ConstStr255Param pathname
, 
 770         error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
 771         if ( error 
== noErr 
) 
 773                 *fileSystemID 
= pb
.volumeParam
.ioVFSID
; 
 779 /*****************************************************************************/ 
 781 pascal  OSErr   
GetVolState(ConstStr255Param pathname
, 
 783                                                         Boolean 
*volumeOnline
, 
 784                                                         Boolean 
*volumeEjected
, 
 785                                                         Boolean 
*driveEjectable
, 
 786                                                         Boolean 
*driverWantsEject
) 
 792         error 
= GetVolumeInfoNoName(pathname
,vRefNum
, &pb
); 
 793         if ( error 
== noErr 
) 
 795                 if ( pb
.volumeParam
.ioVDrvInfo 
!= 0 ) 
 797                         /* the volume is online and not ejected */ 
 798                         *volumeOnline 
= true; 
 799                         *volumeEjected 
= false; 
 801                         /* Get the drive number */ 
 802                         driveNumber 
= pb
.volumeParam
.ioVDrvInfo
; 
 806                         /* the volume's is either offline or ejected */ 
 807                         /* in either case, the volume is NOT online */ 
 808                         *volumeOnline 
= false; 
 811                         *volumeEjected 
= pb
.volumeParam
.ioVDRefNum 
> 0; 
 813                         if ( *volumeEjected 
) 
 815                                 /* If ejected, the drive number is ioVDRefNum */ 
 816                                 driveNumber 
= pb
.volumeParam
.ioVDRefNum
; 
 820                                 /* If offline, the drive number is the negative of ioVDRefNum */ 
 821                                 driveNumber 
= (short)-pb
.volumeParam
.ioVDRefNum
; 
 828                         /* Find the drive queue element by searching the drive queue */ 
 829                         drvQElem 
= (DrvQElPtr
)(GetDrvQHdr()->qHead
); 
 830                         while ( (drvQElem 
!= NULL
) && (drvQElem
->dQDrive 
!= driveNumber
) ) 
 832                                 drvQElem 
= (DrvQElPtr
)drvQElem
->qLink
; 
 835                         if ( drvQElem 
!= NULL 
) 
 838                                 **      Each drive queue element is preceded by 4 flag bytes. 
 839                                 **      Byte 1 (the second flag byte) has bits that tell us if a 
 840                                 **      drive is ejectable and if its driver wants an eject call. 
 841                                 **      See Inside Macintosh: Files, page 2-85. 
 846                                         /* point to byte 1 of the flag bytes */ 
 847                                         flagBytePtr 
= (Ptr
)drvQElem
; 
 851                                         **      The drive is ejectable if flag byte 1 does not contain 
 852                                         **      0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call). 
 855                                         *driveEjectable 
= (*flagBytePtr 
!= 0x08) && (*flagBytePtr 
!= 0x48); 
 858                                         **      The driver wants an eject call if flag byte 1 does not contain 
 859                                         **      0x08 (nonejectable). This may seem like a minor point, but some 
 860                                         **      disk drivers use the Eject request to flush their caches to disk 
 861                                         **      and you wouldn't want to skip that step after unmounting a volume. 
 864                                         *driverWantsEject 
= (*flagBytePtr 
!= 0x08); 
 869                                 /* Didn't find the drive (this should never happen) */ 
 870                                 *driveEjectable 
= false; 
 871                                 *driverWantsEject 
= false; 
 879 /*****************************************************************************/ 
 881 pascal  OSErr   
UnmountAndEject(ConstStr255Param pathname
, 
 886         Boolean ejected
, wantsEject
; 
 890         error 
= GetVolumeInfoNoName(pathname
, vRefNum
, &pb
); 
 891         if ( error 
== noErr 
) 
 893                 if ( pb
.volumeParam
.ioVDrvInfo 
!= 0 ) 
 895                         /* the volume is online and not ejected */ 
 898                         /* Get the drive number */ 
 899                         driveNum 
= pb
.volumeParam
.ioVDrvInfo
; 
 903                         /* the volume is ejected or offline */ 
 906                         ejected 
= pb
.volumeParam
.ioVDRefNum 
> 0; 
 910                                 /* If ejected, the drive number is ioVDRefNum */ 
 911                                 driveNum 
= pb
.volumeParam
.ioVDRefNum
; 
 915                                 /* If offline, the drive number is the negative of ioVDRefNum */ 
 916                                 driveNum 
= (short)-pb
.volumeParam
.ioVDRefNum
; 
 920                 /* find the drive queue element */ 
 921                 drvQElem 
= (DrvQElPtr
)(GetDrvQHdr()->qHead
); 
 922                 while ( (drvQElem 
!= NULL
) && (drvQElem
->dQDrive 
!= driveNum
) ) 
 924                         drvQElem 
= (DrvQElPtr
)drvQElem
->qLink
; 
 927                 if ( drvQElem 
!= NULL 
) 
 929                         /* does the drive want an eject call */ 
 930                         wantsEject 
= (*((Ptr
)((Ptr
)drvQElem 
- 3)) != 8); 
 934                         /* didn't find the drive!! */ 
 938                 /* unmount the volume */ 
 939                 pb
.volumeParam
.ioNamePtr 
= NULL
; 
 940                 /* ioVRefNum is already filled in from PBHGetVInfo */ 
 941                 error 
= PBUnmountVol((ParmBlkPtr
)&pb
); 
 942                 if ( error 
== noErr 
) 
 944                         if ( wantsEject 
&& !ejected 
) 
 946                                 /* eject the media from the drive if needed */ 
 947                                 pb
.volumeParam
.ioVRefNum 
= driveNum
; 
 948                                 error 
= PBEject((ParmBlkPtr
)&pb
); 
 956 /*****************************************************************************/ 
 958 pascal  OSErr   
OnLine(FSSpecPtr volumes
, 
 970                 for ( endVolArray 
= volumes 
+ reqVolCount
; (volumes 
< endVolArray
) && (error 
== noErr
); ++volumes 
) 
 972                         pb
.volumeParam
.ioNamePtr 
= (StringPtr
) & volumes
->name
; 
 973                         pb
.volumeParam
.ioVolIndex 
= *volIndex
; 
 974                         error 
= PBHGetVInfoSync(&pb
); 
 975                         if ( error 
== noErr 
) 
 977                                 volumes
->parID 
= fsRtParID
;             /* the root directory's parent is 1 */ 
 978                                 volumes
->vRefNum 
= pb
.volumeParam
.ioVRefNum
; 
 992 /*****************************************************************************/ 
 994 pascal  OSErr 
SetDefault(short newVRefNum
, 
1001         /* Get the current default volume/directory. */ 
1002         error 
= HGetVol(NULL
, oldVRefNum
, oldDirID
); 
1003         if ( error 
== noErr 
) 
1005                 /* Set the new default volume/directory */ 
1006                 error 
= HSetVol(NULL
, newVRefNum
, newDirID
); 
1012 /*****************************************************************************/ 
1014 pascal  OSErr 
RestoreDefault(short oldVRefNum
, 
1018         short   defaultVRefNum
; 
1022         /* Determine if the default volume was a wdRefNum. */ 
1023         error 
= GetWDInfo(oldVRefNum
, &defaultVRefNum
, &defaultDirID
, &defaultProcID
); 
1024         if ( error 
== noErr 
) 
1026                 /* Restore the old default volume/directory, one way or the other. */ 
1027                 if ( defaultDirID 
!= fsRtDirID 
) 
1029                         /* oldVRefNum was a wdRefNum - use SetVol */ 
1030                         error 
= SetVol(NULL
, oldVRefNum
); 
1034                         /* oldVRefNum was a real vRefNum - use HSetVol */ 
1035                         error 
= HSetVol(NULL
, oldVRefNum
, oldDirID
); 
1042 /*****************************************************************************/ 
1044 pascal  OSErr 
GetDInfo(short vRefNum
, 
1046                                            ConstStr255Param name
, 
1052         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1053         if ( error 
== noErr 
) 
1055                 if ( (pb
.dirInfo
.ioFlAttrib 
& ioDirMask
) != 0 ) 
1057                         /* it's a directory, return the DInfo */ 
1058                         *fndrInfo 
= pb
.dirInfo
.ioDrUsrWds
; 
1062                         /* oops, a file was passed */ 
1070 /*****************************************************************************/ 
1072 pascal  OSErr 
FSpGetDInfo(const FSSpec 
*spec
, 
1075         return ( GetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) ); 
1078 /*****************************************************************************/ 
1080 pascal  OSErr 
SetDInfo(short vRefNum
, 
1082                                            ConstStr255Param name
, 
1083                                            const DInfo 
*fndrInfo
) 
1089         /* Protection against File Sharing problem */ 
1090         if ( (name 
== NULL
) || (name
[0] == 0) ) 
1093                 pb
.dirInfo
.ioNamePtr 
= tempName
; 
1094                 pb
.dirInfo
.ioFDirIndex 
= -1;    /* use ioDirID */ 
1098                 pb
.dirInfo
.ioNamePtr 
= (StringPtr
)name
; 
1099                 pb
.dirInfo
.ioFDirIndex 
= 0;     /* use ioNamePtr and ioDirID */ 
1101         pb
.dirInfo
.ioVRefNum 
= vRefNum
; 
1102         pb
.dirInfo
.ioDrDirID 
= dirID
; 
1103         error 
= PBGetCatInfoSync(&pb
); 
1104         if ( error 
== noErr 
) 
1106                 if ( (pb
.dirInfo
.ioFlAttrib 
& ioDirMask
) != 0 ) 
1108                         /* it's a directory, set the DInfo */ 
1109                         if ( pb
.dirInfo
.ioNamePtr 
== tempName 
) 
1111                                 pb
.dirInfo
.ioDrDirID 
= pb
.dirInfo
.ioDrParID
; 
1115                                 pb
.dirInfo
.ioDrDirID 
= dirID
; 
1117                         pb
.dirInfo
.ioDrUsrWds 
= *fndrInfo
; 
1118                         error 
= PBSetCatInfoSync(&pb
); 
1122                         /* oops, a file was passed */ 
1130 /*****************************************************************************/ 
1132 pascal  OSErr 
FSpSetDInfo(const FSSpec 
*spec
, 
1133                                                   const DInfo 
*fndrInfo
) 
1135         return ( SetDInfo(spec
->vRefNum
, spec
->parID
, spec
->name
, fndrInfo
) ); 
1138 /*****************************************************************************/ 
1140 pascal  OSErr   
GetDirectoryID(short vRefNum
, 
1142                                                            ConstStr255Param name
, 
1144                                                            Boolean 
*isDirectory
) 
1149         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1150         if ( error 
== noErr 
) 
1152                 *isDirectory 
= (pb
.hFileInfo
.ioFlAttrib 
& ioDirMask
) != 0; 
1155                         *theDirID 
= pb
.dirInfo
.ioDrDirID
; 
1159                         *theDirID 
= pb
.hFileInfo
.ioFlParID
; 
1166 /*****************************************************************************/ 
1168 pascal  OSErr   
FSpGetDirectoryID(const FSSpec 
*spec
, 
1170                                                                   Boolean 
*isDirectory
) 
1172         return ( GetDirectoryID(spec
->vRefNum
, spec
->parID
, spec
->name
, 
1173                          theDirID
, isDirectory
) ); 
1176 /*****************************************************************************/ 
1178 pascal  OSErr   
GetDirName(short vRefNum
, 
1187                 pb
.dirInfo
.ioNamePtr 
= name
; 
1188                 pb
.dirInfo
.ioVRefNum 
= vRefNum
; 
1189                 pb
.dirInfo
.ioDrDirID 
= dirID
; 
1190                 pb
.dirInfo
.ioFDirIndex 
= -1;    /* get information about ioDirID */ 
1191                 error 
= PBGetCatInfoSync(&pb
); 
1201 /*****************************************************************************/ 
1203 pascal  OSErr   
GetIOACUser(short vRefNum
, 
1205                                                         ConstStr255Param name
, 
1211         /* Clear ioACUser before calling PBGetCatInfo since some file systems 
1212         ** don't bother to set or clear this field. If ioACUser isn't set by the 
1213         ** file system, then you'll get the zero value back (full access) which 
1214         ** is the access you have on volumes that don't support ioACUser. 
1216         pb
.dirInfo
.ioACUser 
= 0;        /* ioACUser used to be filler2 */ 
1217         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1218         if ( error 
== noErr 
) 
1220                 if ( (pb
.hFileInfo
.ioFlAttrib 
& ioDirMask
) == 0 ) 
1222                         /* oops, a file was passed */ 
1227                         *ioACUser 
= pb
.dirInfo
.ioACUser
; 
1234 /*****************************************************************************/ 
1236 pascal  OSErr   
FSpGetIOACUser(const FSSpec 
*spec
, 
1239         return ( GetIOACUser(spec
->vRefNum
, spec
->parID
, spec
->name
, ioACUser
) ); 
1242 /*****************************************************************************/ 
1244 pascal  OSErr   
GetParentID(short vRefNum
, 
1246                                                         ConstStr255Param name
, 
1254         /* Protection against File Sharing problem */ 
1255         if ( (name 
== NULL
) || (name
[0] == 0) ) 
1258                 pb
.hFileInfo
.ioNamePtr 
= tempName
; 
1259                 pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1263                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
1264                 pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1266         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1267         pb
.hFileInfo
.ioDirID 
= dirID
; 
1268         error 
= PBGetCatInfoSync(&pb
); 
1269         if ( error 
== noErr 
) 
1272                 **      There's a bug in HFS where the wrong parent dir ID can be 
1273                 **      returned if multiple separators are used at the end of a 
1274                 **      pathname. For example, if the pathname: 
1275                 **              'volumeName:System Folder:Extensions::' 
1276                 **      is passed, the directory ID of the Extensions folder is 
1277                 **      returned in the ioFlParID field instead of fsRtDirID. Since 
1278                 **      multiple separators at the end of a pathname always specifies 
1279                 **      a directory, we only need to work-around cases where the 
1280                 **      object is a directory and there are multiple separators at 
1281                 **      the end of the name parameter. 
1283                 if ( (pb
.hFileInfo
.ioFlAttrib 
& ioDirMask
) != 0 ) 
1285                         /* Its a directory */ 
1287                         /* is there a pathname? */ 
1288                         if ( pb
.hFileInfo
.ioNamePtr 
== name 
)    
1290                                 /* could it contain multiple separators? */ 
1293                                         /* does it contain multiple separators at the end? */ 
1294                                         if ( (name
[name
[0]] == ':') && (name
[name
[0] - 1] == ':') ) 
1296                                                 /* OK, then do the extra stuff to get the correct parID */ 
1298                                                 /* Get the real vRefNum (this should not fail) */ 
1299                                                 error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
1300                                                 if ( error 
== noErr 
) 
1302                                                         /* we don't need the parent's name, but add protect against File Sharing problem */ 
1304                                                         pb
.dirInfo
.ioNamePtr 
= tempName
; 
1305                                                         pb
.dirInfo
.ioVRefNum 
= realVRefNum
; 
1306                                                         /* pb.dirInfo.ioDrDirID already contains the */ 
1307                                                         /* dirID of the directory object */ 
1308                                                         pb
.dirInfo
.ioFDirIndex 
= -1;    /* get information about ioDirID */ 
1309                                                         error 
= PBGetCatInfoSync(&pb
); 
1310                                                         /* now, pb.dirInfo.ioDrParID contains the correct parID */ 
1317                 if ( error 
== noErr 
) 
1319                         /* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */ 
1320                         /* contains the parent ID */ 
1321                         *parID 
= pb
.hFileInfo
.ioFlParID
; 
1328 /*****************************************************************************/ 
1330 pascal  OSErr   
GetFilenameFromPathname(ConstStr255Param pathname
, 
1337         /* default to no filename */ 
1340         /* check for no pathname */ 
1341         if ( pathname 
!= NULL 
) 
1343                 /* get string length */ 
1344                 index 
= pathname
[0]; 
1346                 /* check for empty string */ 
1349                         /* skip over last trailing colon (if any) */ 
1350                         if ( pathname
[index
] == ':' ) 
1355                         /* save the end of the string */ 
1358                         /* if pathname ends with multiple colons, then this pathname refers */ 
1359                         /* to a directory, not a file */ 
1360                         if ( pathname
[index
] != ':' ) 
1362                                 /* parse backwards until we find a colon or hit the beginning of the pathname */ 
1363                                 while ( (index 
!= 0) && (pathname
[index
] != ':') ) 
1368                                 /* if we parsed to the beginning of the pathname and the pathname ended */ 
1369                                 /* with a colon, then pathname is a full pathname to a volume, not a file */ 
1370                                 if ( (index 
!= 0) || (pathname
[pathname
[0]] != ':') ) 
1372                                         /* get the filename and return noErr */ 
1373                                         filename
[0] = (char)(nameEnd 
- index
); 
1374                                         BlockMoveData(&pathname
[index
+1], &filename
[1], nameEnd 
- index
); 
1379                                         /* pathname to a volume, not a file */ 
1380                                         error 
= notAFileErr
; 
1385                                 /* directory, not a file */ 
1386                                 error 
= notAFileErr
; 
1391                         /* empty string isn't a file */ 
1392                         error 
= notAFileErr
; 
1397                 /* NULL pathname isn't a file */ 
1398                 error 
= notAFileErr
; 
1404 /*****************************************************************************/ 
1406 pascal  OSErr   
GetObjectLocation(short vRefNum
, 
1408                                                                   ConstStr255Param pathname
, 
1412                                                                   Boolean 
*isDirectory
) 
1416         Str255 tempPathname
; 
1424         **      Get the real vRefNum 
1426         error 
= DetermineVRefNum(pathname
, vRefNum
, realVRefNum
); 
1427         if ( error 
== noErr 
) 
1430                 **      Determine if the object already exists and if so, 
1431                 **      get the real parent directory ID if it's a file 
1434                 /* Protection against File Sharing problem */ 
1435                 if ( (pathname 
== NULL
) || (pathname
[0] == 0) ) 
1437                         tempPathname
[0] = 0; 
1438                         pb
.hFileInfo
.ioNamePtr 
= tempPathname
; 
1439                         pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1443                         pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)pathname
; 
1444                         pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1446                 pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1447                 pb
.hFileInfo
.ioDirID 
= dirID
; 
1448                 error 
= PBGetCatInfoSync(&pb
); 
1449                 if ( error 
== noErr 
) 
1452                         **      The file system object is present and we have the file's real parID 
1455                         /*      Is it a directory or a file? */ 
1456                         *isDirectory 
= (pb
.hFileInfo
.ioFlAttrib 
& ioDirMask
) != 0; 
1460                                 **      It's a directory, get its name and parent dirID, and then we're done 
1463                                 pb
.dirInfo
.ioNamePtr 
= realName
; 
1464                                 pb
.dirInfo
.ioVRefNum 
= *realVRefNum
; 
1465                                 /* pb.dirInfo.ioDrDirID already contains the dirID of the directory object */ 
1466                                 pb
.dirInfo
.ioFDirIndex 
= -1;    /* get information about ioDirID */ 
1467                                 error 
= PBGetCatInfoSync(&pb
); 
1469                                 /* get the parent ID here, because the file system can return the */ 
1470                                 /* wrong parent ID from the last call. */ 
1471                                 *realParID 
= pb
.dirInfo
.ioDrParID
; 
1476                                 **      It's a file - use the parent directory ID from the last call 
1477                                 **      to GetCatInfoparse, get the file name, and then we're done 
1479                                 *realParID 
= pb
.hFileInfo
.ioFlParID
;     
1480                                 error 
= GetFilenameFromPathname(pathname
, realName
); 
1483                 else if ( error 
== fnfErr 
) 
1486                         **      The file system object is not present - see if its parent is present 
1490                         **      Parse to get the object name from end of pathname 
1492                         error 
= GetFilenameFromPathname(pathname
, realName
); 
1494                         /* if we can't get the object name from the end, we can't continue */ 
1495                         if ( error 
== noErr 
) 
1498                                 **      What we want now is the pathname minus the object name 
1500                                 **      if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:' 
1501                                 **      if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:' 
1502                                 **      if pathname is ':dir:file' tempPathname becomes ':dir:' 
1503                                 **      if pathname is ':dir:file:' tempPathname becomes ':dir:' 
1504                                 **      if pathname is ':file' tempPathname becomes ':' 
1505                                 **      if pathname is 'file or file:' tempPathname becomes '' 
1508                                 /* get a copy of the pathname */ 
1509                                 BlockMoveData(pathname
, tempPathname
, pathname
[0] + 1); 
1511                                 /* remove the object name */ 
1512                                 tempPathname
[0] -= realName
[0]; 
1513                                 /* and the trailing colon (if any) */ 
1514                                 if ( pathname
[pathname
[0]] == ':' ) 
1519                                 /* OK, now get the parent's directory ID */ 
1521                                 /* Protection against File Sharing problem */ 
1522                                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)tempPathname
; 
1523                                 if ( tempPathname
[0] != 0 ) 
1525                                         pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1529                                         pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1531                                 pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1532                                 pb
.hFileInfo
.ioDirID 
= dirID
; 
1533                                 error 
= PBGetCatInfoSync(&pb
); 
1534                                 *realParID 
= pb
.dirInfo
.ioDrDirID
; 
1536                                 *isDirectory 
= false;   /* we don't know what the object is really going to be */ 
1539                         if ( error 
!= noErr 
) 
1541                                 error 
= dirNFErr
;       /* couldn't find parent directory */ 
1545                                 error 
= fnfErr
; /* we found the parent, but not the file */ 
1553 /*****************************************************************************/ 
1555 pascal  OSErr   
GetDirItems(short vRefNum
, 
1557                                                         ConstStr255Param name
, 
1559                                                         Boolean getDirectories
, 
1562                                                         short *actItemCount
, 
1563                                                         short *itemIndex
) /* start with 1, then use what's returned */ 
1568         Boolean isDirectory
; 
1569         FSSpec 
*endItemsArray
; 
1571         if ( *itemIndex 
> 0 ) 
1573                 /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */ 
1574                 /* to this routine, I could rip out calls to DetermineVRefNum and GetDirectoryID and this */ 
1575                 /* routine would be much faster because of the overhead of DetermineVRefNum and */ 
1576                 /* GetDirectoryID and because GetDirectoryID blows away the directory index hint the Macintosh */ 
1577                 /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */ 
1578                 /* pass a big array of FSSpecs so you can get the directory's contents with few calls */ 
1579                 /* to this routine. */ 
1581                 /* get the real volume reference number */ 
1582                 error 
= DetermineVRefNum(name
, vRefNum
, &pb
.hFileInfo
.ioVRefNum
); 
1583                 if ( error 
== noErr 
) 
1585                         /* and the real directory ID of this directory (and make sure it IS a directory) */ 
1586                         error 
= GetDirectoryID(vRefNum
, dirID
, name
, &theDirID
, &isDirectory
); 
1587                         if ( error 
== noErr 
) 
1592                                         endItemsArray 
= items 
+ reqItemCount
; 
1593                                         while ( (items 
< endItemsArray
) && (error 
== noErr
) ) 
1595                                                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
) &items
->name
; 
1596                                                 pb
.hFileInfo
.ioDirID 
= theDirID
; 
1597                                                 pb
.hFileInfo
.ioFDirIndex 
= *itemIndex
; 
1598                                                 error 
= PBGetCatInfoSync(&pb
); 
1599                                                 if ( error 
== noErr 
) 
1601                                                         items
->parID 
= pb
.hFileInfo
.ioFlParID
;  /* return item's parID */ 
1602                                                         items
->vRefNum 
= pb
.hFileInfo
.ioVRefNum
;        /* return item's vRefNum */ 
1603                                                         ++*itemIndex
;   /* prepare to get next item in directory */ 
1605                                                         if ( (pb
.hFileInfo
.ioFlAttrib 
& ioDirMask
) != 0 ) 
1607                                                                 if ( getDirectories 
) 
1609                                                                         ++*actItemCount
; /* keep this item */ 
1610                                                                         ++items
; /* point to next item */ 
1617                                                                         ++*actItemCount
; /* keep this item */ 
1618                                                                         ++items
; /* point to next item */ 
1626                                         /* it wasn't a directory */ 
1641 /*****************************************************************************/ 
1643 static  void    DeleteLevel(long dirToDelete
, 
1644                                                         DeleteEnumGlobalsPtr theGlobals
) 
1650                 /* prepare to delete directory */ 
1651                 theGlobals
->myPB
.ciPB
.dirInfo
.ioNamePtr 
= (StringPtr
)&theGlobals
->itemName
; 
1652                 theGlobals
->myPB
.ciPB
.dirInfo
.ioFDirIndex 
= 1;  /* get first item */ 
1653                 theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID 
= dirToDelete
;  /* in this directory */ 
1654                 theGlobals
->error 
= PBGetCatInfoSync(&(theGlobals
->myPB
.ciPB
)); 
1655                 if ( theGlobals
->error 
== noErr 
) 
1657                         savedDir 
= dirToDelete
; 
1658                         /* We have an item.  Is it a file or directory? */ 
1659                         if ( (theGlobals
->myPB
.ciPB
.dirInfo
.ioFlAttrib 
& ioDirMask
) != 0 ) 
1661                                 /* it's a directory */ 
1662                                 savedDir 
= theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
;     /* save dirID of directory instead */ 
1663                                 DeleteLevel(theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID
, theGlobals
);       /* Delete its contents */ 
1664                                 theGlobals
->myPB
.ciPB
.dirInfo
.ioNamePtr 
= NULL
; /* prepare to delete directory */ 
1666                         if ( theGlobals
->error 
== noErr 
) 
1668                                 theGlobals
->myPB
.ciPB
.dirInfo
.ioDrDirID 
= savedDir
;     /* restore dirID */ 
1669                                 theGlobals
->myPB
.hPB
.fileParam
.ioFVersNum 
= 0;  /* just in case it's used on an MFS volume... */ 
1670                                 theGlobals
->error 
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
));     /* delete this item */ 
1671                                 if ( theGlobals
->error 
== fLckdErr 
) 
1673                                         (void) PBHRstFLockSync(&(theGlobals
->myPB
.hPB
));        /* unlock it */ 
1674                                         theGlobals
->error 
= PBHDeleteSync(&(theGlobals
->myPB
.hPB
));     /* and try again */ 
1678         } while ( theGlobals
->error 
== noErr 
); 
1680         if ( theGlobals
->error 
== fnfErr 
) 
1682                 theGlobals
->error 
= noErr
; 
1686 /*****************************************************************************/ 
1688 pascal  OSErr   
DeleteDirectoryContents(short vRefNum
, 
1690                                                                                 ConstStr255Param name
) 
1692         DeleteEnumGlobals theGlobals
; 
1693         Boolean isDirectory
; 
1696         /*  Get the real dirID and make sure it is a directory. */ 
1697         error 
= GetDirectoryID(vRefNum
, dirID
, name
, &dirID
, &isDirectory
); 
1698         if ( error 
== noErr 
) 
1702                         /* Get the real vRefNum */ 
1703                         error 
= DetermineVRefNum(name
, vRefNum
, &vRefNum
); 
1704                         if ( error 
== noErr 
) 
1706                                 /* Set up the globals we need to access from the recursive routine. */ 
1707                                 theGlobals
.myPB
.ciPB
.dirInfo
.ioVRefNum 
= vRefNum
; 
1709                                 /* Here we go into recursion land... */ 
1710                                 DeleteLevel(dirID
, &theGlobals
); 
1711                                 error 
= theGlobals
.error
; 
1723 /*****************************************************************************/ 
1725 pascal  OSErr   
DeleteDirectory(short vRefNum
, 
1727                                                                 ConstStr255Param name
) 
1731         /* Make sure a directory was specified and then delete its contents */ 
1732         error 
= DeleteDirectoryContents(vRefNum
, dirID
, name
); 
1733         if ( error 
== noErr 
) 
1735                 error 
= HDelete(vRefNum
, dirID
, name
); 
1736                 if ( error 
== fLckdErr 
) 
1738                         (void) HRstFLock(vRefNum
, dirID
, name
); /* unlock the directory locked by AppleShare */ 
1739                         error 
= HDelete(vRefNum
, dirID
, name
);  /* and try again */ 
1746 /*****************************************************************************/ 
1748 pascal  OSErr   
CheckObjectLock(short vRefNum
, 
1750                                                                 ConstStr255Param name
) 
1755         error 
= GetCatInfoNoName(vRefNum
, dirID
, name
, &pb
); 
1756         if ( error 
== noErr 
) 
1758                 /* check locked bit */ 
1759                 if ( (pb
.hFileInfo
.ioFlAttrib 
& 0x01) != 0 ) 
1768 /*****************************************************************************/ 
1770 pascal  OSErr   
FSpCheckObjectLock(const FSSpec 
*spec
) 
1772         return ( CheckObjectLock(spec
->vRefNum
, spec
->parID
, spec
->name
) ); 
1775 /*****************************************************************************/ 
1777 pascal  OSErr   
GetFileSize(short vRefNum
, 
1779                                                         ConstStr255Param fileName
, 
1786         pb
.fileParam
.ioNamePtr 
= (StringPtr
)fileName
; 
1787         pb
.fileParam
.ioVRefNum 
= vRefNum
; 
1788         pb
.fileParam
.ioFVersNum 
= 0; 
1789         pb
.fileParam
.ioDirID 
= dirID
; 
1790         pb
.fileParam
.ioFDirIndex 
= 0; 
1791         error 
= PBHGetFInfoSync(&pb
); 
1792         if ( error 
== noErr 
) 
1794                 *dataSize 
= pb
.fileParam
.ioFlLgLen
; 
1795                 *rsrcSize 
= pb
.fileParam
.ioFlRLgLen
; 
1801 /*****************************************************************************/ 
1803 pascal  OSErr   
FSpGetFileSize(const FSSpec 
*spec
, 
1807         return ( GetFileSize(spec
->vRefNum
, spec
->parID
, spec
->name
, dataSize
, rsrcSize
) ); 
1810 /*****************************************************************************/ 
1812 pascal  OSErr   
BumpDate(short vRefNum
, 
1814                                                  ConstStr255Param name
) 
1815 /* Given a file or directory, change its modification date to the current date/time. */ 
1822         /* Protection against File Sharing problem */ 
1823         if ( (name 
== NULL
) || (name
[0] == 0) ) 
1826                 pb
.hFileInfo
.ioNamePtr 
= tempName
; 
1827                 pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1831                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
1832                 pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1834         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1835         pb
.hFileInfo
.ioDirID 
= dirID
; 
1836         error 
= PBGetCatInfoSync(&pb
); 
1837         if ( error 
== noErr 
) 
1840                 /* set mod date to current date, or one second into the future 
1841                         if mod date = current date */ 
1842                 pb
.hFileInfo
.ioFlMdDat 
= (secs 
== pb
.hFileInfo
.ioFlMdDat
) ? (++secs
) : (secs
); 
1843                 if ( pb
.dirInfo
.ioNamePtr 
== tempName 
) 
1845                         pb
.hFileInfo
.ioDirID 
= pb
.hFileInfo
.ioFlParID
; 
1849                         pb
.hFileInfo
.ioDirID 
= dirID
; 
1851                 error 
= PBSetCatInfoSync(&pb
); 
1857 /*****************************************************************************/ 
1859 pascal  OSErr   
FSpBumpDate(const FSSpec 
*spec
) 
1861         return ( BumpDate(spec
->vRefNum
, spec
->parID
, spec
->name
) ); 
1864 /*****************************************************************************/ 
1866 pascal  OSErr   
ChangeCreatorType(short vRefNum
, 
1868                                                                   ConstStr255Param name
, 
1877         pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
1878         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1879         pb
.hFileInfo
.ioDirID 
= dirID
; 
1880         pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1881         error 
= PBGetCatInfoSync(&pb
); 
1882         if ( error 
== noErr 
) 
1884                 if ( (pb
.hFileInfo
.ioFlAttrib 
& ioDirMask
) == 0 )       /* if file */ 
1886                         parID 
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */ 
1888                         /* If creator not 0x00000000, change creator */ 
1889                         if ( creator 
!= (OSType
)0x00000000 ) 
1891                                 pb
.hFileInfo
.ioFlFndrInfo
.fdCreator 
= creator
; 
1894                         /* If fileType not 0x00000000, change fileType */ 
1895                         if ( fileType 
!= (OSType
)0x00000000 ) 
1897                                 pb
.hFileInfo
.ioFlFndrInfo
.fdType 
= fileType
; 
1900                         pb
.hFileInfo
.ioDirID 
= dirID
; 
1901                         error 
= PBSetCatInfoSync(&pb
);  /* now, save the new information back to disk */ 
1903                         if ( (error 
== noErr
) && (parID 
!= fsRtParID
) ) /* can't bump fsRtParID */ 
1905                                 /* get the real vRefNum in case a full pathname was passed */ 
1906                                 error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
1907                                 if ( error 
== noErr 
) 
1909                                         error 
= BumpDate(realVRefNum
, parID
, NULL
); 
1910                                                 /* and bump the parent directory's mod date to wake up the Finder */ 
1911                                                 /* to the change we just made */ 
1917                         /* it was a directory, not a file */ 
1918                         error 
= notAFileErr
; 
1925 /*****************************************************************************/ 
1927 pascal  OSErr   
FSpChangeCreatorType(const FSSpec 
*spec
, 
1931         return ( ChangeCreatorType(spec
->vRefNum
, spec
->parID
, spec
->name
, creator
, fileType
) ); 
1934 /*****************************************************************************/ 
1936 pascal  OSErr   
ChangeFDFlags(short vRefNum
, 
1938                                                           ConstStr255Param name
, 
1940                                                           unsigned short flagBits
) 
1948         /* Protection against File Sharing problem */ 
1949         if ( (name 
== NULL
) || (name
[0] == 0) ) 
1952                 pb
.hFileInfo
.ioNamePtr 
= tempName
; 
1953                 pb
.hFileInfo
.ioFDirIndex 
= -1;  /* use ioDirID */ 
1957                 pb
.hFileInfo
.ioNamePtr 
= (StringPtr
)name
; 
1958                 pb
.hFileInfo
.ioFDirIndex 
= 0;   /* use ioNamePtr and ioDirID */ 
1960         pb
.hFileInfo
.ioVRefNum 
= vRefNum
; 
1961         pb
.hFileInfo
.ioDirID 
= dirID
; 
1962         error 
= PBGetCatInfoSync(&pb
); 
1963         if ( error 
== noErr 
) 
1965                 parID 
= pb
.hFileInfo
.ioFlParID
; /* save parent dirID for BumpDate call */ 
1967                 /* set or clear the appropriate bits in the Finder flags */ 
1970                         /* OR in the bits */ 
1971                         pb
.hFileInfo
.ioFlFndrInfo
.fdFlags 
|= flagBits
; 
1975                         /* AND out the bits */ 
1976                         pb
.hFileInfo
.ioFlFndrInfo
.fdFlags 
&= ~flagBits
; 
1979                 if ( pb
.dirInfo
.ioNamePtr 
== tempName 
) 
1981                         pb
.hFileInfo
.ioDirID 
= pb
.hFileInfo
.ioFlParID
; 
1985                         pb
.hFileInfo
.ioDirID 
= dirID
; 
1988                 error 
= PBSetCatInfoSync(&pb
);  /* now, save the new information back to disk */ 
1990                 if ( (error 
== noErr
) && (parID 
!= fsRtParID
) ) /* can't bump fsRtParID */ 
1992                         /* get the real vRefNum in case a full pathname was passed */ 
1993                         error 
= DetermineVRefNum(name
, vRefNum
, &realVRefNum
); 
1994                         if ( error 
== noErr 
) 
1996                                 error 
= BumpDate(realVRefNum
, parID
, NULL
); 
1997                                         /* and bump the parent directory's mod date to wake up the Finder */ 
1998                                         /* to the change we just made */ 
2006 /*****************************************************************************/ 
2008 pascal  OSErr   
FSpChangeFDFlags(const FSSpec 
*spec
, 
2010                                                                  unsigned short flagBits
) 
2012         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, setBits
, flagBits
) ); 
2015 /*****************************************************************************/ 
2017 pascal  OSErr   
SetIsInvisible(short vRefNum
, 
2019                                                            ConstStr255Param name
) 
2020         /* Given a file or directory, make it invisible. */ 
2022         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsInvisible
) ); 
2025 /*****************************************************************************/ 
2027 pascal  OSErr   
FSpSetIsInvisible(const FSSpec 
*spec
) 
2028         /* Given a file or directory, make it invisible. */ 
2030         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsInvisible
) ); 
2033 /*****************************************************************************/ 
2035 pascal  OSErr   
ClearIsInvisible(short vRefNum
, 
2037                                                                  ConstStr255Param name
) 
2038         /* Given a file or directory, make it visible. */ 
2040         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsInvisible
) ); 
2043 /*****************************************************************************/ 
2045 pascal  OSErr   
FSpClearIsInvisible(const FSSpec 
*spec
) 
2046         /* Given a file or directory, make it visible. */ 
2048         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsInvisible
) ); 
2051 /*****************************************************************************/ 
2053 pascal  OSErr   
SetNameLocked(short vRefNum
, 
2055                                                           ConstStr255Param name
) 
2056         /* Given a file or directory, lock its name. */ 
2058         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kNameLocked
) ); 
2061 /*****************************************************************************/ 
2063 pascal  OSErr   
FSpSetNameLocked(const FSSpec 
*spec
) 
2064         /* Given a file or directory, lock its name. */ 
2066         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kNameLocked
) ); 
2069 /*****************************************************************************/ 
2071 pascal  OSErr   
ClearNameLocked(short vRefNum
, 
2073                                                                 ConstStr255Param name
) 
2074         /* Given a file or directory, unlock its name. */ 
2076         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kNameLocked
) ); 
2079 /*****************************************************************************/ 
2081 pascal  OSErr   
FSpClearNameLocked(const FSSpec 
*spec
) 
2082         /* Given a file or directory, unlock its name. */ 
2084         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kNameLocked
) ); 
2087 /*****************************************************************************/ 
2089 pascal  OSErr   
SetIsStationery(short vRefNum
, 
2091                                                                 ConstStr255Param name
) 
2092         /* Given a file, make it a stationery pad. */ 
2094         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kIsStationery
) ); 
2097 /*****************************************************************************/ 
2099 pascal  OSErr   
FSpSetIsStationery(const FSSpec 
*spec
) 
2100         /* Given a file, make it a stationery pad. */ 
2102         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kIsStationery
) ); 
2105 /*****************************************************************************/ 
2107 pascal  OSErr   
ClearIsStationery(short vRefNum
, 
2109                                                                   ConstStr255Param name
) 
2110         /* Given a file, clear the stationery bit. */ 
2112         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kIsStationery
) ); 
2115 /*****************************************************************************/ 
2117 pascal  OSErr   
FSpClearIsStationery(const FSSpec 
*spec
) 
2118         /* Given a file, clear the stationery bit. */ 
2120         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kIsStationery
) ); 
2123 /*****************************************************************************/ 
2125 pascal  OSErr   
SetHasCustomIcon(short vRefNum
, 
2127                                                                  ConstStr255Param name
) 
2128         /* Given a file or directory, indicate that it has a custom icon. */ 
2130         return ( ChangeFDFlags(vRefNum
, dirID
, name
, true, kHasCustomIcon
) ); 
2133 /*****************************************************************************/ 
2135 pascal  OSErr   
FSpSetHasCustomIcon(const FSSpec 
*spec
) 
2136         /* Given a file or directory, indicate that it has a custom icon. */ 
2138         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, true, kHasCustomIcon
) ); 
2141 /*****************************************************************************/ 
2143 pascal  OSErr   
ClearHasCustomIcon(short vRefNum
, 
2145                                                                    ConstStr255Param name
) 
2146         /* Given a file or directory, indicate that it does not have a custom icon. */ 
2148         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasCustomIcon
) ); 
2151 /*****************************************************************************/ 
2153 pascal  OSErr   
FSpClearHasCustomIcon(const FSSpec 
*spec
) 
2154         /* Given a file or directory, indicate that it does not have a custom icon. */ 
2156         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasCustomIcon
) ); 
2159 /*****************************************************************************/ 
2161 pascal  OSErr   
ClearHasBeenInited(short vRefNum
, 
2163                                                                    ConstStr255Param name
) 
2164         /* Given a file, clear its "has been inited" bit. */ 
2166         return ( ChangeFDFlags(vRefNum
, dirID
, name
, false, kHasBeenInited
) ); 
2169 /*****************************************************************************/ 
2171 pascal  OSErr   
FSpClearHasBeenInited(const FSSpec 
*spec
) 
2172         /* Given a file, clear its "has been inited" bit. */ 
2174         return ( ChangeFDFlags(spec
->vRefNum
, spec
->parID
, spec
->name
, false, kHasBeenInited
) ); 
2177 /*****************************************************************************/ 
2179 pascal  OSErr   
CopyFileMgrAttributes(short srcVRefNum
, 
2181                                                                           ConstStr255Param srcName
, 
2184                                                                           ConstStr255Param dstName
, 
2185                                                                           Boolean copyLockBit
) 
2190         Boolean objectIsDirectory
; 
2192         pb
.ciPB
.hFileInfo
.ioVRefNum 
= srcVRefNum
; 
2193         pb
.ciPB
.hFileInfo
.ioDirID 
= srcDirID
; 
2195         /* Protection against File Sharing problem */ 
2196         if ( (srcName 
== NULL
) || (srcName
[0] == 0) ) 
2199                 pb
.ciPB
.hFileInfo
.ioNamePtr 
= tempName
; 
2200                 pb
.ciPB
.hFileInfo
.ioFDirIndex 
= -1;     /* use ioDirID */ 
2204                 pb
.ciPB
.hFileInfo
.ioNamePtr 
= (StringPtr
)srcName
; 
2205                 pb
.ciPB
.hFileInfo
.ioFDirIndex 
= 0;      /* use ioNamePtr and ioDirID */ 
2207         error 
= PBGetCatInfoSync(&pb
.ciPB
); 
2208         if ( error 
== noErr 
) 
2210                 objectIsDirectory 
= ( (pb
.ciPB
.hFileInfo
.ioFlAttrib 
& ioDirMask
) != 0 ); 
2211                 pb
.ciPB
.hFileInfo
.ioVRefNum 
= dstVRefNum
; 
2212                 pb
.ciPB
.hFileInfo
.ioDirID 
= dstDirID
; 
2213                 if ( (dstName 
!= NULL
) && (dstName
[0] == 0) ) 
2215                         pb
.ciPB
.hFileInfo
.ioNamePtr 
= NULL
; 
2219                         pb
.ciPB
.hFileInfo
.ioNamePtr 
= (StringPtr
)dstName
; 
2221                 /* don't copy the hasBeenInited bit */ 
2222                 pb
.ciPB
.hFileInfo
.ioFlFndrInfo
.fdFlags 
= ( pb
.ciPB
.hFileInfo
.ioFlFndrInfo
.fdFlags 
& 0xfeff ); 
2223                 error 
= PBSetCatInfoSync(&pb
.ciPB
); 
2224                 if ( (error 
== noErr
) && (copyLockBit
) && ((pb
.ciPB
.hFileInfo
.ioFlAttrib 
& 0x01) != 0) ) 
2226                         pb
.hPB
.fileParam
.ioFVersNum 
= 0; 
2227                         error 
= PBHSetFLockSync(&pb
.hPB
); 
2228                         if ( (error 
!= noErr
) && (objectIsDirectory
) ) 
2230                                 error 
= noErr
; /* ignore lock errors if destination is directory */ 
2237 /*****************************************************************************/ 
2239 pascal  OSErr   
FSpCopyFileMgrAttributes(const FSSpec 
*srcSpec
, 
2240                                                                                  const FSSpec 
*dstSpec
, 
2241                                                                                  Boolean copyLockBit
) 
2243         return ( CopyFileMgrAttributes(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
2244                                                                    dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
, 
2248 /*****************************************************************************/ 
2250 pascal  OSErr   
HOpenAware(short vRefNum
, 
2252                                                    ConstStr255Param fileName
, 
2258         GetVolParmsInfoBuffer volParmsInfo
; 
2259         long infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
2261         pb
.ioParam
.ioMisc 
= NULL
; 
2262         pb
.fileParam
.ioFVersNum 
= 0; 
2263         pb
.fileParam
.ioNamePtr 
= (StringPtr
)fileName
; 
2264         pb
.fileParam
.ioVRefNum 
= vRefNum
; 
2265         pb
.fileParam
.ioDirID 
= dirID
; 
2267         /* get volume attributes */ 
2268         /* this preflighting is needed because Foreign File Access based file systems don't */ 
2269         /* return the correct error result to the OpenDeny call */ 
2270         error 
= HGetVolParms(fileName
, vRefNum
, &volParmsInfo
, &infoSize
); 
2271         if ( (error 
== noErr
) && hasOpenDeny(volParmsInfo
) ) 
2273                 /* if volume supports OpenDeny, use it and return */ 
2274                         pb
.accessParam
.ioDenyModes 
= denyModes
; 
2275                         error 
= PBHOpenDenySync(&pb
); 
2276                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2278         else if ( (error 
== noErr
) || (error 
== paramErr
) )     /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 
2280                 /* OpenDeny isn't supported, so try File Manager Open functions */ 
2282                 /* If request includes write permission, then see if the volume is */ 
2283                 /* locked by hardware or software. The HFS file system doesn't check */ 
2284                 /* for this when a file is opened - you only find out later when you */ 
2285                 /* try to write and the write fails with a wPrErr or a vLckdErr. */ 
2287                 if ( (denyModes 
& dmWr
) != 0 ) 
2289                         error 
= CheckVolLock(fileName
, vRefNum
); 
2296                 if ( error 
== noErr 
) 
2298                         /* Set File Manager permissions to closest thing possible */ 
2299                         if ( (denyModes 
== dmWr
) || (denyModes 
== dmRdWr
) ) 
2301                                 pb
.ioParam
.ioPermssn 
= fsRdWrShPerm
; 
2305                                 pb
.ioParam
.ioPermssn 
= denyModes 
% 4; 
2308                         error 
= PBHOpenDFSync(&pb
);                             /* Try OpenDF */ 
2309                         if ( error 
== paramErr 
) 
2311                                 error 
= PBHOpenSync(&pb
);                       /* OpenDF not supported, so try Open */ 
2313                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2320 /*****************************************************************************/ 
2322 pascal  OSErr   
FSpOpenAware(const FSSpec 
*spec
, 
2326         return ( HOpenAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) ); 
2329 /*****************************************************************************/ 
2331 pascal  OSErr   
HOpenRFAware(short vRefNum
, 
2333                                                          ConstStr255Param fileName
, 
2339         GetVolParmsInfoBuffer volParmsInfo
; 
2340         long infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
2342         pb
.ioParam
.ioMisc 
= NULL
; 
2343         pb
.fileParam
.ioFVersNum 
= 0; 
2344         pb
.fileParam
.ioNamePtr 
= (StringPtr
)fileName
; 
2345         pb
.fileParam
.ioVRefNum 
= vRefNum
; 
2346         pb
.fileParam
.ioDirID 
= dirID
; 
2348         /* get volume attributes */ 
2349         /* this preflighting is needed because Foreign File Access based file systems don't */ 
2350         /* return the correct error result to the OpenRFDeny call */ 
2351         error 
= HGetVolParms(fileName
, vRefNum
, &volParmsInfo
, &infoSize
); 
2352         if ( (error 
== noErr
) && hasOpenDeny(volParmsInfo
) ) 
2354                 /* if volume supports OpenRFDeny, use it and return */ 
2355                 if ( hasOpenDeny(volParmsInfo
) ) 
2357                         pb
.accessParam
.ioDenyModes 
= denyModes
; 
2358                         error 
= PBHOpenRFDenySync(&pb
); 
2359                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2362         else if ( (error 
== noErr
) || (error 
== paramErr
) )     /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 
2364                 /* OpenRFDeny isn't supported, so try File Manager OpenRF function */ 
2366                 /* If request includes write permission, then see if the volume is */ 
2367                 /* locked by hardware or software. The HFS file system doesn't check */ 
2368                 /* for this when a file is opened - you only find out later when you */ 
2369                 /* try to write and the write fails with a wPrErr or a vLckdErr. */ 
2371                 if ( (denyModes 
& dmWr
) != 0 ) 
2373                         error 
= CheckVolLock(fileName
, vRefNum
); 
2380                 if ( error 
== noErr 
) 
2382                         /* Set File Manager permissions to closest thing possible */ 
2383                         if ( (denyModes 
== dmWr
) || (denyModes 
== dmRdWr
) ) 
2385                                 pb
.ioParam
.ioPermssn 
= fsRdWrShPerm
; 
2389                                 pb
.ioParam
.ioPermssn 
= denyModes 
% 4; 
2392                         error 
= PBHOpenRFSync(&pb
); 
2393                         *refNum 
= pb
.ioParam
.ioRefNum
; 
2400 /*****************************************************************************/ 
2402 pascal  OSErr   
FSpOpenRFAware(const FSSpec 
*spec
, 
2406         return ( HOpenRFAware(spec
->vRefNum
, spec
->parID
, spec
->name
, denyModes
, refNum
) ); 
2409 /*****************************************************************************/ 
2411 pascal  OSErr   
FSReadNoCache(short refNum
, 
2418         pb
.ioParam
.ioRefNum 
= refNum
; 
2419         pb
.ioParam
.ioBuffer 
= (Ptr
)buffPtr
; 
2420         pb
.ioParam
.ioReqCount 
= *count
; 
2421         pb
.ioParam
.ioPosMode 
= fsAtMark 
+ 0x0020;       /* fsAtMark + noCacheBit */ 
2422         pb
.ioParam
.ioPosOffset 
= 0; 
2423         error 
= PBReadSync(&pb
); 
2424         *count 
= pb
.ioParam
.ioActCount
;                         /* always return count */ 
2428 /*****************************************************************************/ 
2430 pascal  OSErr   
FSWriteNoCache(short refNum
, 
2432                                                            const void *buffPtr
) 
2437         pb
.ioParam
.ioRefNum 
= refNum
; 
2438         pb
.ioParam
.ioBuffer 
= (Ptr
)buffPtr
; 
2439         pb
.ioParam
.ioReqCount 
= *count
; 
2440         pb
.ioParam
.ioPosMode 
= fsAtMark 
+ 0x0020;       /* fsAtMark + noCacheBit */ 
2441         pb
.ioParam
.ioPosOffset 
= 0; 
2442         error 
= PBWriteSync(&pb
); 
2443         *count 
= pb
.ioParam
.ioActCount
;                         /* always return count */ 
2447 /*****************************************************************************/ 
2450 **      See if numBytes bytes of buffer1 are equal to buffer2. 
2452 static  Boolean 
EqualMemory(const void *buffer1
, const void *buffer2
, unsigned long numBytes
) 
2454         register unsigned char *b1 
= (unsigned char *)buffer1
; 
2455         register unsigned char *b2 
= (unsigned char *)buffer2
; 
2457         if ( b1 
!= b2 
) /* if buffer pointers are same, then they are equal */ 
2459                 while ( numBytes 
> 0 ) 
2461                         /* compare the bytes and then increment the pointers */ 
2462                         if ( (*b1
++ - *b2
++) != 0 ) 
2473 /*****************************************************************************/ 
2476 **      Read any number of bytes from an open file using read-verify mode. 
2477 **      The FSReadVerify function reads any number of bytes from an open file 
2478 **      and verifies them against the data in the buffer pointed to by buffPtr. 
2480 **      Because of a bug in the HFS file system, only non-block aligned parts of 
2481 **      the read are verified against the buffer data and the rest is *copied* 
2482 **      into the buffer.  Thus, you shouldn't verify against your original data; 
2483 **      instead, you should verify against a copy of the original data and then 
2484 **      compare the read-verified copy against the original data after calling 
2485 **      FSReadVerify. That's why this function isn't exported - it needs the 
2486 **      wrapper provided by FSWriteVerify. 
2488 static  OSErr   
FSReadVerify(short refNum
, 
2495         pb
.ioParam
.ioRefNum 
= refNum
; 
2496         pb
.ioParam
.ioBuffer 
= (Ptr
)buffPtr
; 
2497         pb
.ioParam
.ioReqCount 
= *count
; 
2498         pb
.ioParam
.ioPosMode 
= fsAtMark 
+ rdVerify
; 
2499         pb
.ioParam
.ioPosOffset 
= 0; 
2500         result 
= PBReadSync(&pb
); 
2501         *count 
= pb
.ioParam
.ioActCount
;                 /* always return count */ 
2505 /*****************************************************************************/ 
2507 pascal  OSErr   
FSWriteVerify(short refNum
, 
2509                                                           const void *buffPtr
) 
2520         **      Allocate the verify buffer 
2521         **      Try to get get a large enough buffer to verify in one pass. 
2522         **      If that fails, use GetTempBuffer to get a buffer. 
2524         bufferSize 
= *count
; 
2525         verifyBuffer 
= NewPtr(bufferSize
); 
2526         if ( verifyBuffer 
== NULL 
) 
2528                 verifyBuffer 
= GetTempBuffer(bufferSize
, &bufferSize
); 
2530         if ( verifyBuffer 
!= NULL 
) 
2532                 /* Save the current position */ 
2533                 result 
= GetFPos(refNum
, &position
); 
2534                 if ( result 
== noErr 
) 
2536                         /* Write the data */ 
2537                         result 
= FSWrite(refNum
, count
, buffPtr
); 
2538                         if ( result 
== noErr 
) 
2540                                 /* Restore the original position */ 
2541                                 result 
= SetFPos(refNum
, fsFromStart
, position
); 
2542                                 if ( result 
== noErr 
) 
2545                                         **      *count                  = total number of bytes to verify 
2546                                         **      bufferSize              = the size of the verify buffer 
2547                                         **      bytesVerified   = number of bytes verified 
2548                                         **      byteCount               = number of bytes to verify this pass 
2549                                         **      startVerify             = position in buffPtr 
2552                                         startVerify 
= (Ptr
)buffPtr
; 
2553                                         while ( (bytesVerified 
< *count
) && ( result 
== noErr 
) ) 
2555                                                 if ( (*count 
- bytesVerified
) > bufferSize 
) 
2557                                                         byteCount 
= bufferSize
; 
2561                                                         byteCount 
= *count 
- bytesVerified
; 
2564                                                 **      Copy the write buffer into the verify buffer. 
2565                                                 **      This step is needed because the File Manager 
2566                                                 **      compares the data in any non-block aligned 
2567                                                 **      data at the beginning and end of the read-verify 
2568                                                 **      request back into the file system's cache 
2569                                                 **      to the data in verify Buffer. However, the 
2570                                                 **      File Manager does not compare any full blocks 
2571                                                 **      and instead copies them into the verify buffer 
2572                                                 **      so we still have to compare the buffers again 
2573                                                 **      after the read-verify request completes. 
2575                                                 BlockMoveData(startVerify
, verifyBuffer
, byteCount
); 
2577                                                 /* Read-verify the data back into the verify buffer */ 
2578                                                 result 
= FSReadVerify(refNum
, &byteCount
, verifyBuffer
); 
2579                                                 if ( result 
== noErr 
) 
2581                                                         /* See if the buffers are the same */ 
2582                                                         if ( !EqualMemory(verifyBuffer
, startVerify
, byteCount
) ) 
2586                                                         startVerify 
+= byteCount
; 
2587                                                         bytesVerified 
+= byteCount
; 
2593                 DisposePtr(verifyBuffer
); 
2597                 result 
= memFullErr
; 
2602 /*****************************************************************************/ 
2604 pascal  OSErr   
CopyFork(short srcRefNum
, 
2606                                                  void *copyBufferPtr
, 
2607                                                  long copyBufferSize
) 
2609         ParamBlockRec srcPB
; 
2610         ParamBlockRec dstPB
; 
2614         if ( (copyBufferPtr 
== NULL
) || (copyBufferSize 
== 0) ) 
2615                 return ( paramErr 
); 
2617         srcPB
.ioParam
.ioRefNum 
= srcRefNum
; 
2618         dstPB
.ioParam
.ioRefNum 
= dstRefNum
; 
2620         /* preallocate the destination fork and */ 
2621         /* ensure the destination fork's EOF is correct after the copy */ 
2622         srcError 
= PBGetEOFSync(&srcPB
); 
2623         if ( srcError 
!= noErr 
) 
2624                 return ( srcError 
); 
2625         dstPB
.ioParam
.ioMisc 
= srcPB
.ioParam
.ioMisc
; 
2626         dstError 
= PBSetEOFSync(&dstPB
); 
2627         if ( dstError 
!= noErr 
) 
2628                 return ( dstError 
); 
2630         /* reset source fork's mark */ 
2631         srcPB
.ioParam
.ioPosMode 
= fsFromStart
; 
2632         srcPB
.ioParam
.ioPosOffset 
= 0; 
2633         srcError 
= PBSetFPosSync(&srcPB
); 
2634         if ( srcError 
!= noErr 
) 
2635                 return ( srcError 
); 
2637         /* reset destination fork's mark */ 
2638         dstPB
.ioParam
.ioPosMode 
= fsFromStart
; 
2639         dstPB
.ioParam
.ioPosOffset 
= 0; 
2640         dstError 
= PBSetFPosSync(&dstPB
); 
2641         if ( dstError 
!= noErr 
) 
2642                 return ( dstError 
); 
2644         /* set up fields that won't change in the loop */ 
2645         srcPB
.ioParam
.ioBuffer 
= (Ptr
)copyBufferPtr
; 
2646         srcPB
.ioParam
.ioPosMode 
= fsAtMark 
+ 0x0020;/* fsAtMark + noCacheBit */ 
2647         /* If copyBufferSize is greater than 512 bytes, make it a multiple of 512 bytes */ 
2648         /* This will make writes on local volumes faster */ 
2649         if ( (copyBufferSize 
>= 512) && ((copyBufferSize 
& 0x1ff) != 0) ) 
2651                 srcPB
.ioParam
.ioReqCount 
= copyBufferSize 
& 0xfffffe00; 
2655                 srcPB
.ioParam
.ioReqCount 
= copyBufferSize
; 
2657         dstPB
.ioParam
.ioBuffer 
= (Ptr
)copyBufferPtr
; 
2658         dstPB
.ioParam
.ioPosMode 
= fsAtMark 
+ 0x0020;/* fsAtMark + noCacheBit */ 
2660         while ( (srcError 
== noErr
) && (dstError 
== noErr
) ) 
2662                 srcError 
= PBReadSync(&srcPB
); 
2663                 dstPB
.ioParam
.ioReqCount 
= srcPB
.ioParam
.ioActCount
; 
2664                 dstError 
= PBWriteSync(&dstPB
); 
2667         /* make sure there were no errors at the destination */ 
2668         if ( dstError 
!= noErr 
) 
2669                 return ( dstError 
); 
2671         /* make sure the only error at the source was eofErr */ 
2672         if ( srcError 
!= eofErr 
) 
2673                 return ( srcError 
); 
2678 /*****************************************************************************/ 
2680 pascal  OSErr   
GetFileLocation(short refNum
, 
2688         pb
.ioNamePtr 
= fileName
; 
2690         pb
.ioRefNum 
= refNum
; 
2692         error 
= PBGetFCBInfoSync(&pb
); 
2693         if ( error 
== noErr 
) 
2695                 *vRefNum 
= pb
.ioFCBVRefNum
; 
2696                 *dirID 
= pb
.ioFCBParID
; 
2701 /*****************************************************************************/ 
2703 pascal  OSErr   
FSpGetFileLocation(short refNum
, 
2706         return ( GetFileLocation(refNum
, &(spec
->vRefNum
), &(spec
->parID
), spec
->name
) ); 
2709 /*****************************************************************************/ 
2711 pascal  OSErr   
CopyDirectoryAccess(short srcVRefNum
, 
2713                                                                         ConstStr255Param srcName
, 
2716                                                                         ConstStr255Param dstName
) 
2719         GetVolParmsInfoBuffer infoBuffer
;       /* Where PBGetVolParms dumps its info */ 
2720         long    dstServerAdr
;                           /* AppleTalk server address of destination (if any) */ 
2721         long    ownerID
, groupID
, accessRights
; 
2724         /* See if destination supports directory access control */ 
2725         tempLong 
= sizeof(infoBuffer
); 
2726         error 
= HGetVolParms(dstName
, dstVRefNum
, &infoBuffer
, &tempLong
); 
2727         if ( (error 
== noErr
) && hasAccessCntl(infoBuffer
) ) 
2729                 if ( hasAccessCntl(infoBuffer
) ) 
2731                         dstServerAdr 
= infoBuffer
.vMServerAdr
; 
2733                         /* See if source supports directory access control and is on same server */ 
2734                         tempLong 
= sizeof(infoBuffer
); 
2735                         error 
= HGetVolParms(srcName
, srcVRefNum
, &infoBuffer
, &tempLong
); 
2736                         if ( error 
== noErr 
) 
2738                                 if ( hasAccessCntl(infoBuffer
) && (dstServerAdr 
== infoBuffer
.vMServerAdr
) ) 
2740                                         /* both volumes support directory access control and they are */ 
2741                                         /*  on same server, so copy the access information */ 
2742                                         error 
= HGetDirAccess(srcVRefNum
, srcDirID
, srcName
, &ownerID
, &groupID
, &accessRights
); 
2743                                         if ( error 
== noErr 
) 
2745                                                 error 
= HSetDirAccess(dstVRefNum
, dstDirID
, dstName
, ownerID
, groupID
, accessRights
); 
2750                                         /* destination doesn't support directory access control or */ 
2751                                         /* they volumes aren't on the same server */ 
2758                         /* destination doesn't support directory access control */ 
2766 /*****************************************************************************/ 
2768 pascal  OSErr   
FSpCopyDirectoryAccess(const FSSpec 
*srcSpec
, 
2769                                                                            const FSSpec 
*dstSpec
) 
2771         return ( CopyDirectoryAccess(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
2772                                                                 dstSpec
->vRefNum
, dstSpec
->parID
, dstSpec
->name
) ); 
2775 /*****************************************************************************/ 
2777 pascal  OSErr   
HMoveRenameCompat(short vRefNum
, 
2779                                                                   ConstStr255Param srcName
, 
2781                                                                   ConstStr255Param dstpathName
, 
2782                                                                   ConstStr255Param copyName
) 
2785         GetVolParmsInfoBuffer   volParmsInfo
; 
2790         Boolean                                 isDirectory
; 
2791         long                                    tempItemsDirID
; 
2792         long                                    uniqueTempDirID
; 
2793         Str31                                   uniqueTempDirName
; 
2794         unsigned short                  uniqueNameoverflow
; 
2796         /* Get volume attributes */ 
2797         infoSize 
= sizeof(GetVolParmsInfoBuffer
); 
2798         error 
= HGetVolParms((StringPtr
)srcName
, vRefNum
, &volParmsInfo
, &infoSize
); 
2799         if ( (error 
== noErr
) && hasMoveRename(volParmsInfo
) ) 
2801                 /* If volume supports move and rename, so use it and return */ 
2802                 error 
= HMoveRename(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
, copyName
); 
2804         else if ( (error 
== noErr
) || (error 
== paramErr
) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */ 
2806                 /* MoveRename isn't supported by this volume, so do it by hand */ 
2808                 /* If copyName isn't supplied, we can simply CatMove and return */ 
2809                 if ( copyName 
== NULL 
) 
2811                         error 
= CatMove(vRefNum
, srcDirID
, srcName
, dstDirID
, dstpathName
); 
2815                         /* Renaming is required, so we have some work to do... */ 
2817                         /* Get the object's real name, real parent ID and real vRefNum */ 
2818                         error 
= GetObjectLocation(vRefNum
, srcDirID
, (StringPtr
)srcName
, 
2819                                                                                 &realVRefNum
, &realParID
, realName
, &isDirectory
); 
2820                         if ( error 
== noErr 
) 
2822                                 /* Find the Temporary Items Folder on that volume */ 
2823                                 error 
= FindFolder(realVRefNum
, kTemporaryFolderType
, kCreateFolder
, 
2824                                                                         &realVRefNum
, &tempItemsDirID
); 
2825                                 if ( error 
== noErr 
) 
2827                                         /* Create a new uniquely named folder in the temporary items folder. */ 
2828                                         /* This is done to avoid the case where 'realName' or 'copyName' already */ 
2829                                         /* exists in the temporary items folder. */ 
2831                                         /* Start with current tick count as uniqueTempDirName */                                         
2832                                         NumToString(TickCount(), uniqueTempDirName
); 
2833                                         uniqueNameoverflow 
= 0; 
2836                                                 error 
= DirCreate(realVRefNum
, tempItemsDirID
, uniqueTempDirName
, &uniqueTempDirID
); 
2837                                                 if ( error 
== dupFNErr 
) 
2839                                                         /* Duplicate name - change the first character to the next ASCII character */ 
2840                                                         ++uniqueTempDirName
[1]; 
2841                                                         /* Make sure it isn't a colon! */ 
2842                                                         if ( uniqueTempDirName
[1] == ':' ) 
2844                                                                 ++uniqueTempDirName
[1]; 
2846                                                         /* Don't go too far... */ 
2847                                                         ++uniqueNameoverflow
; 
2849                                         } while ( (error 
== dupFNErr
) && (uniqueNameoverflow 
<= 64) ); /* 64 new files per 1/60th second - not likely! */ 
2850                                         if ( error 
== noErr 
) 
2852                                                 /* Move the object to the folder with uniqueTempDirID for renaming */ 
2853                                                 error 
= CatMove(realVRefNum
, realParID
, realName
, uniqueTempDirID
, NULL
); 
2854                                                 if ( error 
== noErr 
) 
2856                                                         /* Rename the object */  
2857                                                         error 
= HRename(realVRefNum
, uniqueTempDirID
, realName
, copyName
); 
2858                                                         if ( error 
== noErr 
) 
2860                                                                 /* Move object to its new home */ 
2861                                                                 error 
= CatMove(realVRefNum
, uniqueTempDirID
, copyName
, dstDirID
, dstpathName
); 
2862                                                                 if ( error 
!= noErr 
) 
2864                                                                         /* Error handling: rename object back to original name - ignore errors */ 
2865                                                                         (void) HRename(realVRefNum
, uniqueTempDirID
, copyName
, realName
); 
2868                                                         if ( error 
!= noErr 
) 
2870                                                                 /* Error handling: move object back to original location - ignore errors */ 
2871                                                                 (void) CatMove(realVRefNum
, uniqueTempDirID
, realName
, realParID
, NULL
); 
2874                                                 /* Done with ourTempDir, so delete it - ignore errors */ 
2875                                                 (void) HDelete(realVRefNum
, uniqueTempDirID
, NULL
); 
2885 /*****************************************************************************/ 
2887 pascal  OSErr   
FSpMoveRenameCompat(const FSSpec 
*srcSpec
, 
2888                                                                         const FSSpec 
*dstSpec
, 
2889                                                                         ConstStr255Param copyName
) 
2891         /* make sure the FSSpecs refer to the same volume */ 
2892         if (srcSpec
->vRefNum 
!= dstSpec
->vRefNum
) 
2893                 return (diffVolErr
); 
2894         return ( HMoveRenameCompat(srcSpec
->vRefNum
, srcSpec
->parID
, srcSpec
->name
, 
2895                                           dstSpec
->parID
, dstSpec
->name
, copyName
) ); 
2898 /*****************************************************************************/ 
2900 pascal  OSErr   
BuildAFPVolMountInfo(short flags
, 
2910                                                                          AFPVolMountInfoPtr 
*afpInfoPtr
) 
2912         MyAFPVolMountInfoPtr    infoPtr
; 
2915         /* Allocate the AFPXVolMountInfo record */ 
2916         infoPtr 
= (MyAFPVolMountInfoPtr
)NewPtrClear(sizeof(MyAFPVolMountInfo
)); 
2917         if ( infoPtr 
!= NULL 
) 
2919                 /* Fill in an AFPVolMountInfo record that can be passed to VolumeMount */ 
2920                 infoPtr
->length 
= sizeof(MyAFPVolMountInfo
); 
2921                 infoPtr
->media 
= AppleShareMediaType
; 
2922                 infoPtr
->flags 
= flags
; 
2923                 infoPtr
->nbpInterval 
= nbpInterval
; 
2924                 infoPtr
->nbpCount 
= nbpCount
; 
2925                 infoPtr
->uamType 
= uamType
; 
2927                 infoPtr
->zoneNameOffset 
= offsetof(MyAFPVolMountInfo
, zoneName
); 
2928                 infoPtr
->serverNameOffset 
= offsetof(MyAFPVolMountInfo
, serverName
); 
2929                 infoPtr
->volNameOffset 
= offsetof(MyAFPVolMountInfo
, volName
); 
2930                 infoPtr
->userNameOffset 
= offsetof(MyAFPVolMountInfo
, userName
); 
2931                 infoPtr
->userPasswordOffset 
= offsetof(MyAFPVolMountInfo
, userPassword
); 
2932                 infoPtr
->volPasswordOffset 
= offsetof(MyAFPVolMountInfo
, volPassword
); 
2934                 BlockMoveData(zoneName
, infoPtr
->zoneName
, sizeof(Str32
)); 
2935                 BlockMoveData(serverName
, infoPtr
->serverName
, sizeof(Str32
)); 
2936                 BlockMoveData(volName
, infoPtr
->volName
, sizeof(Str27
)); 
2937                 BlockMoveData(userName
, infoPtr
->userName
, sizeof(Str31
)); 
2938                 BlockMoveData(userPassword
, infoPtr
->userPassword
, sizeof(Str8
)); 
2939                 BlockMoveData(volPassword
, infoPtr
->volPassword
, sizeof(Str8
)); 
2941                 *afpInfoPtr 
= (AFPVolMountInfoPtr
)infoPtr
; 
2952 /*****************************************************************************/ 
2954 pascal  OSErr   
RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr
, 
2958                                                                                 StringPtr serverName
, 
2965         /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */ 
2966         if ( afpInfoPtr
->media 
== AppleShareMediaType 
) 
2968                 *flags 
= afpInfoPtr
->flags
; 
2969                 *uamType 
= afpInfoPtr
->uamType
; 
2971                 if ( afpInfoPtr
->zoneNameOffset 
!= 0) 
2973                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->zoneNameOffset
); 
2974                         BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1); 
2977                 if ( afpInfoPtr
->serverNameOffset 
!= 0) 
2979                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->serverNameOffset
); 
2980                         BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1); 
2983                 if ( afpInfoPtr
->volNameOffset 
!= 0) 
2985                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->volNameOffset
); 
2986                         BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1); 
2989                 if ( afpInfoPtr
->userNameOffset 
!= 0) 
2991                         tempPtr 
= (StringPtr
)((long)afpInfoPtr 
+ afpInfoPtr
->userNameOffset
); 
2992                         BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1); 
3005 /*****************************************************************************/ 
3007 pascal  OSErr   
BuildAFPXVolMountInfo(short flags
, 
3018                                                                           unsigned long alternateAddressLength
, 
3019                                                                           void *alternateAddress
, 
3020                                                                           AFPXVolMountInfoPtr 
*afpXInfoPtr
) 
3023         MyAFPXVolMountInfoPtr   infoPtr
; 
3026         /* Calculate the size of the AFPXVolMountInfo record */ 
3027         infoSize 
= sizeof(MyAFPXVolMountInfo
) + alternateAddressLength 
- 1; 
3029         /* Allocate the AFPXVolMountInfo record */ 
3030         infoPtr 
= (MyAFPXVolMountInfoPtr
)NewPtrClear(infoSize
); 
3031         if ( infoPtr 
!= NULL 
) 
3033                 /* Fill in an AFPXVolMountInfo record that can be passed to VolumeMount */ 
3034                 infoPtr
->length 
= infoSize
; 
3035                 infoPtr
->media 
= AppleShareMediaType
; 
3036                 infoPtr
->flags 
= flags
; 
3037                 if ( alternateAddressLength 
!= 0 ) 
3039                         /* make sure the volMountExtendedFlagsBit is set if there's extended address info */ 
3040                         infoPtr
->flags 
|= volMountExtendedFlagsMask
; 
3041                         /* and set the only extendedFlags bit we know about */ 
3042                         infoPtr
->extendedFlags 
= kAFPExtendedFlagsAlternateAddressMask
; 
3046                         /* make sure the volMountExtendedFlagsBit is clear if there's no extended address info */ 
3047                         infoPtr
->flags 
&= ~volMountExtendedFlagsMask
; 
3048                         /* and clear the extendedFlags */ 
3049                         infoPtr
->extendedFlags 
= 0; 
3051                 infoPtr
->nbpInterval 
= nbpInterval
; 
3052                 infoPtr
->nbpCount 
= nbpCount
; 
3053                 infoPtr
->uamType 
= uamType
; 
3055                 infoPtr
->zoneNameOffset 
= offsetof(MyAFPXVolMountInfo
, zoneName
);                
3056                 infoPtr
->serverNameOffset 
= offsetof(MyAFPXVolMountInfo
, serverName
); 
3057                 infoPtr
->volNameOffset 
= offsetof(MyAFPXVolMountInfo
, volName
); 
3058                 infoPtr
->userNameOffset 
= offsetof(MyAFPXVolMountInfo
, userName
); 
3059                 infoPtr
->userPasswordOffset 
= offsetof(MyAFPXVolMountInfo
, userPassword
); 
3060                 infoPtr
->volPasswordOffset 
= offsetof(MyAFPXVolMountInfo
, volPassword
); 
3061                 infoPtr
->uamNameOffset 
= offsetof(MyAFPXVolMountInfo
, uamName
); 
3062                 infoPtr
->alternateAddressOffset 
= offsetof(MyAFPXVolMountInfo
, alternateAddress
); 
3064                 BlockMoveData(zoneName
, infoPtr
->zoneName
, sizeof(Str32
)); 
3065                 BlockMoveData(serverName
, infoPtr
->serverName
, sizeof(Str32
)); 
3066                 BlockMoveData(volName
, infoPtr
->volName
, sizeof(Str27
)); 
3067                 BlockMoveData(userName
, infoPtr
->userName
, sizeof(Str31
)); 
3068                 BlockMoveData(userPassword
, infoPtr
->userPassword
, sizeof(Str8
)); 
3069                 BlockMoveData(volPassword
, infoPtr
->volPassword
, sizeof(Str8
)); 
3070                 BlockMoveData(uamName
, infoPtr
->uamName
, sizeof(Str32
)); 
3071                 BlockMoveData(alternateAddress
, infoPtr
->alternateAddress
, alternateAddressLength
); 
3073                 *afpXInfoPtr 
= (AFPXVolMountInfoPtr
)infoPtr
; 
3084 /*****************************************************************************/ 
3086 pascal  OSErr   
RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr
, 
3090                                                                                  StringPtr serverName
, 
3094                                                                                  unsigned long *alternateAddressLength
, 
3095                                                                                  AFPAlternateAddress 
**alternateAddress
) 
3098         Ptr                     alternateAddressStart
; 
3099         Ptr                     alternateAddressEnd
; 
3100         Size            alternateAddressDataSize
; 
3104         /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */ 
3105         if ( afpXInfoPtr
->media 
== AppleShareMediaType 
) 
3107                 /* default to noErr */ 
3110                 /* Is this an extended record? */ 
3111                 if ( (afpXInfoPtr
->flags 
& volMountExtendedFlagsMask
) != 0 ) 
3113                         if ( ((afpXInfoPtr
->extendedFlags 
& kAFPExtendedFlagsAlternateAddressMask
) != 0) && 
3114                                  (afpXInfoPtr
->alternateAddressOffset 
!= 0) ) 
3117                                 alternateAddressStart 
= (Ptr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->alternateAddressOffset
); 
3118                                 alternateAddressEnd 
= alternateAddressStart 
+ 1;        /* skip over alternate address version byte */ 
3119                                 addressCount 
= *(UInt8
*)alternateAddressEnd
;            /* get the address count */ 
3120                                 ++alternateAddressEnd
;                                                          /* skip over alternate address count byte */ 
3121                                 /* alternateAddressEnd now equals &AFPAlternateAddress.fAddressList[0] */ 
3122                                 while ( addressCount 
!= 0 ) 
3124                                         /* parse the address list to find the end */ 
3125                                         alternateAddressEnd 
+= *(UInt8
*)alternateAddressEnd
;    /* add length of each AFPTagData record */ 
3128                                 /* get the size of the alternateAddressData */ 
3129                                 alternateAddressDataSize 
= alternateAddressEnd 
- alternateAddressStart
; 
3130                                 /* allocate memory for it */ 
3131                                 *alternateAddress 
= (AFPAlternateAddress 
*)NewPtr(alternateAddressDataSize
); 
3132                                 if ( *alternateAddress 
!= NULL 
) 
3134                                         /* and return the data */ 
3135                                         BlockMoveData(alternateAddressStart
, *alternateAddress
, alternateAddressDataSize
); 
3136                                         *alternateAddressLength 
= alternateAddressDataSize
; 
3140                                         /* no memory - fail now */ 
3145                         if ( error 
== noErr 
)   /* fill in more output parameters if everything is OK */ 
3147                                 if ( afpXInfoPtr
->uamNameOffset 
!= 0 ) 
3149                                         tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->uamNameOffset
); 
3150                                         BlockMoveData(tempPtr
, uamName
, tempPtr
[0] + 1); 
3155                 if ( error 
== noErr 
)   /* fill in more output parameters if everything is OK */ 
3157                         *flags 
= afpXInfoPtr
->flags
; 
3158                         *uamType 
= afpXInfoPtr
->uamType
; 
3160                         if ( afpXInfoPtr
->zoneNameOffset 
!= 0 ) 
3162                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->zoneNameOffset
); 
3163                                 BlockMoveData(tempPtr
, zoneName
, tempPtr
[0] + 1); 
3166                         if ( afpXInfoPtr
->serverNameOffset 
!= 0 ) 
3168                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->serverNameOffset
); 
3169                                 BlockMoveData(tempPtr
, serverName
, tempPtr
[0] + 1); 
3172                         if ( afpXInfoPtr
->volNameOffset 
!= 0 ) 
3174                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->volNameOffset
); 
3175                                 BlockMoveData(tempPtr
, volName
, tempPtr
[0] + 1); 
3178                         if ( afpXInfoPtr
->userNameOffset 
!= 0 ) 
3180                                 tempPtr 
= (StringPtr
)((long)afpXInfoPtr 
+ afpXInfoPtr
->userNameOffset
); 
3181                                 BlockMoveData(tempPtr
, userName
, tempPtr
[0] + 1); 
3193 /*****************************************************************************/ 
3195 pascal  OSErr   
GetUGEntries(short objType
, 
3198                                                          long *actEntryCount
, 
3202         OSErr error 
= noErr
; 
3203         UGEntry 
*endEntryArray
; 
3205         pb
.objParam
.ioObjType 
= objType
; 
3207         for ( endEntryArray 
= entries 
+ reqEntryCount
; (entries 
< endEntryArray
) && (error 
== noErr
); ++entries 
) 
3209                 pb
.objParam
.ioObjNamePtr 
= (StringPtr
)entries
->name
; 
3210                 pb
.objParam
.ioObjID 
= *objID
; 
3211                 /* Files.h in the universal interfaces, PBGetUGEntrySync takes a CMovePBPtr */ 
3212                 /* as the parameter. Inside Macintosh and the original glue used HParmBlkPtr. */ 
3213                 /* A CMovePBPtr works OK, but this will be changed in the future  back to */ 
3214                 /* HParmBlkPtr, so I'm just casting it here. */ 
3215                 error 
= PBGetUGEntrySync(&pb
); 
3216                 if ( error 
== noErr 
) 
3218                         entries
->objID 
= *objID 
= pb
.objParam
.ioObjID
; 
3219                         entries
->objType 
= objType
; 
3227 /*****************************************************************************/