MoreFilesExtras.c

Go to the documentation of this file.
00001 
00002 /*  $Id: MoreFilesExtras.c 355 2005-01-11 22:48:55Z andreradke $    */
00003 
00004 /*
00005 **  Apple Macintosh Developer Technical Support
00006 **
00007 **  A collection of useful high-level File Manager routines.
00008 **
00009 **  by Jim Luther, Apple Developer Technical Support Emeritus
00010 **
00011 **  File:       MoreFilesExtras.c
00012 **
00013 **  Copyright  1992-1999 Apple Computer, Inc.
00014 **  All rights reserved.
00015 **
00016 **  You may incorporate this sample code into your applications without
00017 **  restriction, though the sample code has been provided "AS IS" and the
00018 **  responsibility for its operation is 100% yours.  However, what you are
00019 **  not permitted to do is to redistribute the source as "DSC Sample Code"
00020 **  after having made changes. If you're going to re-distribute the source,
00021 **  we require that you make it clear in the source that the code was
00022 **  descended from Apple Sample Code, but that you've made changes.
00023 */
00024 
00025 #include <Types.h>
00026 #include <Traps.h>
00027 #include <OSUtils.h>
00028 #include <Errors.h>
00029 #include <Files.h>
00030 #include <Devices.h>
00031 #include <Finder.h>
00032 #include <Folders.h>
00033 #include <FSM.h>
00034 #include <Disks.h>
00035 #include <Gestalt.h>
00036 #include <TextUtils.h>
00037 #include <Script.h>
00038 #include <Math64.h>
00039 #include <CodeFragments.h>
00040 #include <stddef.h>
00041 
00042 #define __COMPILINGMOREFILES
00043 
00044 #include "MoreFiles.h"
00045 #include "MoreFilesExtras.h"
00046 #include "MoreDesktopMgr.h"
00047 #include "FSpCompat.h"
00048 
00049 /*****************************************************************************/
00050 
00051 /* local data structures */
00052 
00053 /* The DeleteEnumGlobals structure is used to minimize the amount of
00054 ** stack space used when recursively calling DeleteLevel and to hold
00055 ** global information that might be needed at any time. */
00056 
00057 #if PRAGMA_STRUCT_ALIGN
00058     #pragma options align=mac68k
00059 #endif  //  PRAGMA_STRUCT_ALIGN
00060 struct DeleteEnumGlobals
00061 {
00062     OSErr           error;              /* temporary holder of results - saves 2 bytes of stack each level */
00063     Str63           itemName;           /* the name of the current item */
00064     UniversalFMPB   myPB;               /* the parameter block used for PBGetCatInfo calls */
00065 };
00066 #if PRAGMA_STRUCT_ALIGN
00067     #pragma options align=reset
00068 #endif //   PRAGMA_STRUCT_ALIGN
00069 
00070 typedef struct DeleteEnumGlobals DeleteEnumGlobals;
00071 typedef DeleteEnumGlobals *DeleteEnumGlobalsPtr;
00072 
00073 /*****************************************************************************/
00074 
00075 /*
00076 **  CallPBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
00077 **  File Manager requests from CFM-based programs. Apple added PBXGetVolInfoSync
00078 **  to InterfaceLib in Mac OS 8.5, so if __MACOSEIGHTFIVEORLATER is defined,
00079 **  CallPBXGetVolInfoSync is defined back to PBXGetVolInfoSync.
00080 **
00081 **  Non-CFM 68K programs don't needs this glue (and won't get it) because
00082 **  they instead use the inline assembly glue found in the Files.h interface
00083 **  file.
00084 */
00085 
00086 #if TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
00087 
00088     // Carbon builds and 68K builds don't need this glue
00089     #define CallPBXGetVolInfoSync PBXGetVolInfoSync
00090 
00091 #else   //  TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
00092 
00093     #if __WANTPASCALELIMINATION
00094         #undef  pascal
00095     #endif  //  __WANTPASCALELIMINATION
00096     
00097     /* This is exactly like the simple mixed mode glue in InterfaceLib in Mac OS 8.5 and 8.6 */
00098     static pascal OSErr PBXGetVolInfoSyncGlue(XVolumeParamPtr paramBlock)
00099     {
00100         enum
00101         {
00102             uppFSDispatchProcInfo = kRegisterBased
00103                  | REGISTER_RESULT_LOCATION(kRegisterD0)
00104                  | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
00105                  | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0, SIZE_CODE(sizeof(long)))  /* selector */
00106                  | REGISTER_ROUTINE_PARAMETER(2, kRegisterD1, SIZE_CODE(sizeof(long)))  /* trap word */
00107                  | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr)))
00108         };
00109         
00110         static UniversalProcPtr fsDispatchTrapAddress = NULL;
00111         
00112         /* Is this the first time we've been called? */
00113         if ( fsDispatchTrapAddress == NULL )
00114         {
00115             /* Yes - Get the trap address of _FSDispatch */
00116             fsDispatchTrapAddress = NGetTrapAddress(_FSDispatch, OSTrap);
00117         }
00118         return ( CallOSTrapUniversalProc(fsDispatchTrapAddress,
00119                                             uppFSDispatchProcInfo,
00120                                             kFSMXGetVolInfo,
00121                                             _FSDispatch,
00122                                             paramBlock) );
00123     }
00124     
00125     /*
00126     ** PBXGetVolInfoSync was added to the File Manager in System software 7.5.2.
00127     ** However, PBXGetVolInfoSync wasn't added to InterfaceLib until Mac OS 8.5.
00128     ** This wrapper calls PBXGetVolInfoSync if it is found in InterfaceLib;
00129     ** otherwise, it calls PBXGetVolInfoSyncGlue. This ensures that your program
00130     ** is calling the latest implementation of PBXGetVolInfoSync.
00131     */
00132     static pascal OSErr CallPBXGetVolInfoSync(XVolumeParamPtr paramBlock)
00133     {
00134         typedef pascal OSErr (*PBXGetVolInfoProcPtr) (XVolumeParamPtr paramBlock);
00135         
00136         OSErr                       result;
00137         CFragConnectionID           connID;
00138         static PBXGetVolInfoProcPtr PBXGetVolInfoSyncPtr = NULL;
00139         
00140         //* Is this the first time we've been called? */
00141         if ( PBXGetVolInfoSyncPtr == NULL )
00142         {
00143             /* Yes - Get our connection ID to InterfaceLib */
00144             result = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kLoadCFrag, &connID, NULL, NULL);
00145             if ( result == noErr )
00146             {
00147                 /* See if PBXGetVolInfoSync is in InterfaceLib */
00148                 if ( FindSymbol(connID, "\pPBXGetVolInfoSync", &(Ptr)PBXGetVolInfoSyncPtr, NULL) != noErr )
00149                 {
00150                     /* Use glue code if symbol isn't found */
00151                     PBXGetVolInfoSyncPtr = PBXGetVolInfoSyncGlue;
00152                 }
00153             }
00154         }
00155         /* Call PBXGetVolInfoSync if present; otherwise, call PBXGetVolInfoSyncGlue */
00156         return ( (*PBXGetVolInfoSyncPtr)(paramBlock) );
00157     }
00158 
00159     #if __WANTPASCALELIMINATION
00160         #define pascal  
00161     #endif  //  __WANTPASCALELIMINATION
00162 
00163 #endif  //  TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM
00164 
00165 /*****************************************************************************/
00166 
00167 pascal  void    TruncPString(StringPtr destination,
00168                              ConstStr255Param source,
00169                              short maxLength)
00170 {
00171     short   charType;
00172     
00173     if ( source != NULL && destination != NULL )    /* don't do anything stupid */
00174     {
00175         if ( source[0] > maxLength )
00176         {
00177             /* Make sure the string isn't truncated in the middle of */
00178             /* a multi-byte character. */
00179             while (maxLength != 0)
00180             {
00181                 // Note: CharacterByteType's textOffset parameter is zero-based from the textPtr parameter
00182                 charType = CharacterByteType((Ptr)&source[1], maxLength - 1, smSystemScript);
00183                 if ( (charType == smSingleByte) || (charType == smLastByte) )
00184                     break;  /* source[maxLength] is now a valid last character */ 
00185                 --maxLength;
00186             }
00187         }
00188         else
00189         {
00190             maxLength = source[0];
00191         }
00192         /* Set the destination string length */
00193         destination[0] = maxLength;
00194         /* and copy maxLength characters (if needed) */
00195         if ( source != destination )
00196         {
00197             while ( maxLength != 0 )
00198             {
00199                 destination[maxLength] = source[maxLength];
00200                 --maxLength;
00201             }
00202         }
00203     }
00204 }
00205 
00206 /*****************************************************************************/
00207 
00208 pascal  Ptr GetTempBuffer(long buffReqSize,
00209                           long *buffActSize)
00210 {
00211     enum
00212     {
00213         kSlopMemory = 0x00008000    /* 32K - Amount of free memory to leave when allocating buffers */
00214     };
00215     Ptr tempPtr;
00216     
00217     /* Make request a multiple of 1024 bytes */
00218     buffReqSize = buffReqSize & 0xfffffc00;
00219     
00220     if ( buffReqSize < 0x00000400 )
00221     {
00222         /* Request was smaller than 1024 bytes - make it 1024 */
00223         buffReqSize = 0x00000400;
00224     }
00225     
00226     /* Attempt to allocate the memory */
00227     tempPtr = NewPtr(buffReqSize);
00228     
00229     /* If request failed, go to backup plan */
00230     if ( (tempPtr == NULL) && (buffReqSize > 0x00000400) )
00231     {
00232         /*
00233         **  Try to get largest 1024-byte block available
00234         **  leaving some slop for the toolbox if possible
00235         */
00236         long freeMemory = (FreeMem() - kSlopMemory) & 0xfffffc00;
00237         
00238         buffReqSize = MaxBlock() & 0xfffffc00;
00239         
00240         if ( buffReqSize > freeMemory )
00241         {
00242             buffReqSize = freeMemory;
00243         }
00244         
00245         if ( buffReqSize == 0 )
00246         {
00247             buffReqSize = 0x00000400;
00248         }
00249         
00250         tempPtr = NewPtr(buffReqSize);
00251     }
00252     
00253     /* Return bytes allocated */
00254     if ( tempPtr != NULL )
00255     {
00256         *buffActSize = buffReqSize;
00257     }
00258     else
00259     {
00260         *buffActSize = 0;
00261     }
00262     
00263     return ( tempPtr );
00264 }
00265 
00266 /*****************************************************************************/
00267 
00268 /*
00269 **  GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
00270 **  in cases where the returned volume name is not needed by the caller.
00271 **  The pathname and vRefNum parameters are not touched, and the pb
00272 **  parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
00273 **  the parameter block is always returned as NULL (since it might point
00274 **  to the local tempPathname).
00275 **
00276 **  I noticed using this code in several places, so here it is once.
00277 **  This reduces the code size of MoreFiles.
00278 */
00279 pascal  OSErr   GetVolumeInfoNoName(ConstStr255Param pathname,
00280                                     short vRefNum,
00281                                     HParmBlkPtr pb)
00282 {
00283     Str255 tempPathname;
00284     OSErr error;
00285     
00286     /* Make sure pb parameter is not NULL */ 
00287     if ( pb != NULL )
00288     {
00289         pb->volumeParam.ioVRefNum = vRefNum;
00290         if ( pathname == NULL )
00291         {
00292             pb->volumeParam.ioNamePtr = NULL;
00293             pb->volumeParam.ioVolIndex = 0;     /* use ioVRefNum only */
00294         }
00295         else
00296         {
00297             BlockMoveData(pathname, tempPathname, pathname[0] + 1); /* make a copy of the string and */
00298             pb->volumeParam.ioNamePtr = (StringPtr)tempPathname;    /* use the copy so original isn't trashed */
00299             pb->volumeParam.ioVolIndex = -1;    /* use ioNamePtr/ioVRefNum combination */
00300         }
00301         error = PBHGetVInfoSync(pb);
00302         pb->volumeParam.ioNamePtr = NULL;   /* ioNamePtr may point to local tempPathname, so don't return it */
00303     }
00304     else
00305     {
00306         error = paramErr;
00307     }
00308     return ( error );
00309 }
00310 
00311 /*****************************************************************************/
00312 
00313 /*
00314 **  XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync
00315 **  in cases where the returned volume name is not needed by the caller.
00316 **  The pathname and vRefNum parameters are not touched, and the pb
00317 **  parameter is initialized by PBXGetVolInfoSync except that ioNamePtr in
00318 **  the parameter block is always returned as NULL (since it might point
00319 **  to the local tempPathname).
00320 */
00321 pascal  OSErr   XGetVolumeInfoNoName(ConstStr255Param pathname,
00322                                     short vRefNum,
00323                                     XVolumeParamPtr pb)
00324 {
00325     Str255 tempPathname;
00326     OSErr error;
00327     
00328     /* Make sure pb parameter is not NULL */ 
00329     if ( pb != NULL )
00330     {
00331         pb->ioVRefNum = vRefNum;
00332         pb->ioXVersion = 0;         /* this XVolumeParam version (0) */
00333         if ( pathname == NULL )
00334         {
00335             pb->ioNamePtr = NULL;
00336             pb->ioVolIndex = 0;     /* use ioVRefNum only */
00337         }
00338         else
00339         {
00340             BlockMoveData(pathname, tempPathname, pathname[0] + 1); /* make a copy of the string and */
00341             pb->ioNamePtr = (StringPtr)tempPathname;    /* use the copy so original isn't trashed */
00342             pb->ioVolIndex = -1;    /* use ioNamePtr/ioVRefNum combination */
00343         }
00344         
00345         {
00346 #if !TARGET_API_MAC_CARBON
00347             long response;
00348             
00349             /* Is PBXGetVolInfo available? */
00350             if ( ( Gestalt(gestaltFSAttr, &response) != noErr ) || ((response & (1L << gestaltFSSupports2TBVols)) == 0) )
00351             {
00352                 /* No, fall back on PBHGetVInfo */
00353                 error = PBHGetVInfoSync((HParmBlkPtr)pb);
00354                 if ( error == noErr )
00355                 {
00356                     /* calculate the ioVTotalBytes and ioVFreeBytes fields */
00357                     pb->ioVTotalBytes = U64Multiply(U64SetU(pb->ioVNmAlBlks), U64SetU(pb->ioVAlBlkSiz));
00358                     pb->ioVFreeBytes = U64Multiply(U64SetU(pb->ioVFrBlk), U64SetU(pb->ioVAlBlkSiz));
00359                 }
00360             }
00361             else
00362 #endif
00363             {
00364                 /* Yes, so use it */
00365                 error = CallPBXGetVolInfoSync(pb);
00366             }
00367         }
00368         pb->ioNamePtr = NULL;       /* ioNamePtr may point to local tempPathname, so don't return it */
00369     }
00370     else
00371     {
00372         error = paramErr;
00373     }
00374     return ( error );
00375 }
00376 
00377 /*****************************************************************************/
00378 
00379 pascal  OSErr GetCatInfoNoName(short vRefNum,
00380                                long dirID,
00381                                ConstStr255Param name,
00382                                CInfoPBPtr pb)
00383 {
00384     Str31 tempName;
00385     OSErr error;
00386     
00387     /* Protection against File Sharing problem */
00388     if ( (name == NULL) || (name[0] == 0) )
00389     {
00390         tempName[0] = 0;
00391         pb->dirInfo.ioNamePtr = tempName;
00392         pb->dirInfo.ioFDirIndex = -1;   /* use ioDirID */
00393     }
00394     else
00395     {
00396         pb->dirInfo.ioNamePtr = (StringPtr)name;
00397         pb->dirInfo.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
00398     }
00399     pb->dirInfo.ioVRefNum = vRefNum;
00400     pb->dirInfo.ioDrDirID = dirID;
00401     error = PBGetCatInfoSync(pb);
00402     pb->dirInfo.ioNamePtr = NULL;
00403     return ( error );
00404 }
00405 
00406 /*****************************************************************************/
00407 
00408 pascal  OSErr   DetermineVRefNum(ConstStr255Param pathname,
00409                                  short vRefNum,
00410                                  short *realVRefNum)
00411 {
00412     HParamBlockRec pb;
00413     OSErr error;
00414 
00415     error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
00416     if ( error == noErr )
00417     {
00418         *realVRefNum = pb.volumeParam.ioVRefNum;
00419     }
00420     return ( error );
00421 }
00422 
00423 /*****************************************************************************/
00424 
00425 pascal  OSErr   HGetVInfo(short volReference,
00426                           StringPtr volName,
00427                           short *vRefNum,
00428                           unsigned long *freeBytes,
00429                           unsigned long *totalBytes)
00430 {
00431     OSErr   result;
00432     UInt64  freeBytes64;
00433     UInt64  totalBytes64;
00434     
00435     // get the best values possible from XGetVInfo
00436     result = XGetVInfo(volReference, volName, vRefNum, &freeBytes64, &totalBytes64);
00437     if ( result == noErr )
00438     {
00439         // and pin those values if needed
00440         if ( UInt64ToUnsignedWide(freeBytes64).hi != 0 )
00441         {
00442             // pin to maximum 512-byte block aligned value
00443             *freeBytes = 0xfffffe00;
00444         }
00445         else
00446         {
00447             *freeBytes = U32SetU(freeBytes64);
00448         }
00449         
00450         if ( UInt64ToUnsignedWide(totalBytes64).hi != 0 )
00451         {
00452             // pin to maximum 512-byte block aligned value
00453             *totalBytes = 0xfffffe00;
00454         }
00455         else
00456         {
00457             *totalBytes = U32SetU(totalBytes64);
00458         }
00459     }
00460     
00461     return ( result );
00462 }
00463 
00464 /*****************************************************************************/
00465 
00466 pascal  OSErr   XGetVInfo(short volReference,
00467                           StringPtr volName,
00468                           short *vRefNum,
00469                           UInt64 *freeBytes,
00470                           UInt64 *totalBytes)
00471 {
00472     OSErr           result;
00473     XVolumeParam    pb;
00474     
00475 #if !TARGET_API_MAC_CARBON
00476     
00477     long            response;
00478     
00479 #endif  //  !TARGET_API_MAC_CARBON
00480     
00481     pb.ioVRefNum = volReference;
00482     pb.ioNamePtr = volName;
00483     pb.ioXVersion = 0;  /* this XVolumeParam version (0) */
00484     pb.ioVolIndex = 0;  /* use ioVRefNum only, return volume name */
00485     
00486 #if !TARGET_API_MAC_CARBON
00487 
00488     /* See if large volume support is available */
00489     if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) )
00490     
00491 #endif  //  !TARGET_API_MAC_CARBON
00492     
00493     {
00494         /* Large volume support is available */
00495         result = CallPBXGetVolInfoSync(&pb);
00496         if ( result == noErr )
00497         {
00498             /* The volume name was returned in volName (if not NULL) and */
00499             /* we have the volume's vRefNum and allocation block size */
00500             *vRefNum = pb.ioVRefNum;
00501             
00502             /* return the freeBytes and totalBytes */
00503             *totalBytes = pb.ioVTotalBytes;
00504             *freeBytes = pb.ioVFreeBytes;
00505         }
00506     }
00507     
00508 #if !TARGET_API_MAC_CARBON
00509     
00510     else
00511     {
00512         /* No large volume support */
00513         /* Use PBHGetVInfoSync to get the results */
00514         result = PBHGetVInfoSync((HParmBlkPtr)&pb);
00515         if ( result == noErr )
00516         {
00517             VCB             *theVCB;
00518         
00519             /* The volume name was returned in volName (if not NULL) and */
00520             /* we have the volume's vRefNum */
00521             *vRefNum = pb.ioVRefNum;
00522             
00523             /* System 7.5 (and beyond) pins the number of allocation blocks and */
00524             /* the number of free allocation blocks returned by PBHGetVInfo to */
00525             /* a value so that when multiplied by the allocation block size, */
00526             /* the volume will look like it has $7fffffff bytes or less. This */
00527             /* was done so older applications that use signed math or that use */
00528             /* the GetVInfo function (which uses signed math) will continue to work. */
00529             /* However, the unpinned numbers (which we want) are always available */
00530             /* in the volume's VCB so we'll get those values from the VCB. */
00531             /* Note: Carbon doesn't support the VCB queue, so this code cannot be */
00532             /* used (and is conditionalized out) by Carbon applications. */
00533             
00534             /* Find the volume's VCB */
00535             theVCB = (VCB *)(GetVCBQHdr()->qHead);
00536             while ( theVCB != NULL )
00537             {
00538                 if ( theVCB->vcbVRefNum == *vRefNum )
00539                 {
00540                     break;
00541                 }
00542                 
00543                 theVCB = (VCB *)(theVCB->qLink);    /* next VCB */
00544             }
00545             
00546             if ( theVCB != NULL )
00547             {
00548                 /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
00549                 /* and the number of free blocks from the VCB. */
00550                 *freeBytes = U64Multiply(U64SetU((unsigned short)theVCB->vcbFreeBks), U64SetU((unsigned long)pb.ioVAlBlkSiz));
00551                 *totalBytes = U64Multiply(U64SetU((unsigned short)theVCB->vcbNmAlBlks), U64SetU((unsigned long)pb.ioVAlBlkSiz));
00552             }
00553             else
00554             {
00555                 /* Didn't find a VCB we can use. Return the number of allocation blocks */
00556                 /* and the number of free blocks returned by PBHGetVInfoSync. */
00557                 *freeBytes = U64Multiply(U64SetU((unsigned short)pb.ioVFrBlk), U64SetU((unsigned long)pb.ioVAlBlkSiz));
00558                 *totalBytes = U64Multiply(U64SetU((unsigned short)pb.ioVNmAlBlks), U64SetU((unsigned long)pb.ioVAlBlkSiz));
00559             }
00560             
00561         }
00562     }
00563     
00564 #endif  //  !TARGET_API_MAC_CARBON
00565     
00566     return ( result );
00567 }
00568 
00569 /*****************************************************************************/
00570 
00571 pascal  OSErr   CheckVolLock(ConstStr255Param pathname,
00572                              short vRefNum)
00573 {
00574     HParamBlockRec pb;
00575     OSErr error;
00576 
00577     error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
00578     if ( error == noErr )
00579     {
00580         if ( (pb.volumeParam.ioVAtrb & kHFSVolumeHardwareLockMask) != 0 )
00581         {
00582             error = wPrErr;     /* volume locked by hardware */
00583         }
00584         else if ( (pb.volumeParam.ioVAtrb & kHFSVolumeSoftwareLockMask) != 0 )
00585         {
00586             error = vLckdErr;   /* volume locked by software */
00587         }
00588     }
00589     
00590     return ( error );
00591 }
00592 
00593 /*****************************************************************************/
00594 //
00595 //  The following routines call Mac OS routines that are not supported by
00596 //  Carbon:
00597 //  
00598 //      GetDriverName
00599 //      FindDrive
00600 //      GetDiskBlocks
00601 //      GetVolState
00602 
00603 #if !TARGET_API_MAC_CARBON  //  {
00604 
00605     /*****************************************************************************/
00606 
00607     pascal  OSErr GetDriverName(short driverRefNum,
00608                                 Str255 driverName)
00609     {
00610         OSErr result;
00611         DCtlHandle theDctl;
00612         DRVRHeaderPtr dHeaderPtr;
00613         
00614         theDctl = GetDCtlEntry(driverRefNum);
00615         if ( theDctl != NULL )
00616         {
00617             if ( (**theDctl).dCtlFlags & dRAMBasedMask )
00618             {
00619                 /* dctlDriver is handle - dereference */
00620                 dHeaderPtr = *((DRVRHeaderHandle)(**theDctl).dCtlDriver);
00621             }
00622             else
00623             {
00624                 /* dctlDriver is pointer */
00625               dHeaderPtr = (DRVRHeaderPtr)(**theDctl).dCtlDriver;
00626             }
00627             BlockMoveData((*dHeaderPtr).drvrName, driverName, (*dHeaderPtr).drvrName[0] + 1);
00628             result = noErr;
00629         }
00630         else
00631         {
00632             driverName[0] = 0;
00633             result = badUnitErr;    /* bad reference number */
00634         }
00635         
00636         return ( result );
00637     }
00638 
00639     /*****************************************************************************/
00640 
00641     pascal  OSErr   FindDrive(ConstStr255Param pathname,
00642                               short vRefNum,
00643                               DrvQElPtr *driveQElementPtr)
00644     {
00645         OSErr           result;
00646         HParamBlockRec  hPB;
00647         short           driveNumber;
00648         
00649         *driveQElementPtr = NULL;
00650         
00651         /* First, use GetVolumeInfoNoName to determine the volume */
00652         result = GetVolumeInfoNoName(pathname, vRefNum, &hPB);
00653         if ( result == noErr )
00654         {
00655             /*
00656             **  The volume can be either online, offline, or ejected. What we find in
00657             **  ioVDrvInfo and ioVDRefNum will tell us which it is.
00658             **  See Inside Macintosh: Files page 2-80 and the Technical Note
00659             **  "FL 34 - VCBs and Drive Numbers : The Real Story"
00660             **  Where we get the drive number depends on the state of the volume.
00661             */
00662             if ( hPB.volumeParam.ioVDrvInfo != 0 )
00663             {
00664                 /* The volume is online and not ejected */
00665                 /* Get the drive number */
00666                 driveNumber = hPB.volumeParam.ioVDrvInfo;
00667             }
00668             else
00669             {
00670                 /* The volume's is either offline or ejected */
00671                 /* in either case, the volume is NOT online */
00672 
00673                 /* Is it ejected or just offline? */
00674                 if ( hPB.volumeParam.ioVDRefNum > 0 )
00675                 {
00676                     /* It's ejected, the drive number is ioVDRefNum */
00677                     driveNumber = hPB.volumeParam.ioVDRefNum;
00678                 }
00679                 else
00680                 {
00681                     /* It's offline, the drive number is the negative of ioVDRefNum */
00682                     driveNumber = (short)-hPB.volumeParam.ioVDRefNum;
00683                 }
00684             }
00685             
00686             /* Get pointer to first element in drive queue */
00687             *driveQElementPtr = (DrvQElPtr)(GetDrvQHdr()->qHead);
00688             
00689             /* Search for a matching drive number */
00690             while ( (*driveQElementPtr != NULL) && ((*driveQElementPtr)->dQDrive != driveNumber) )
00691             {
00692                 *driveQElementPtr = (DrvQElPtr)(*driveQElementPtr)->qLink;
00693             }
00694             
00695             if ( *driveQElementPtr == NULL )
00696             {
00697                 /* This should never happen since every volume must have a drive, but... */
00698                 result = nsDrvErr;
00699             }
00700         }
00701         
00702         return ( result );
00703     }
00704 
00705     /*****************************************************************************/
00706 
00707     pascal  OSErr   GetDiskBlocks(ConstStr255Param pathname,
00708                                   short vRefNum,
00709                                   unsigned long *numBlocks)
00710     {
00711         /* Various constants for GetDiskBlocks() */
00712         enum
00713         {
00714             /* return format list status code */
00715             kFmtLstCode = 6,
00716             
00717             /* reference number of .SONY driver */
00718             kSonyRefNum = 0xfffb,
00719             
00720             /* values returned by DriveStatus in DrvSts.twoSideFmt */
00721             kSingleSided = 0,
00722             kDoubleSided = -1,
00723             kSingleSidedSize = 800,     /* 400K */
00724             kDoubleSidedSize = 1600,    /* 800K */
00725             
00726             /* values in DrvQEl.qType */
00727             kWordDrvSiz = 0,
00728             kLongDrvSiz = 1,
00729             
00730             /* more than enough formatListRecords */
00731             kMaxFormatListRecs = 16
00732         };
00733         
00734         DrvQElPtr       driveQElementPtr;
00735         unsigned long   blocks;
00736         ParamBlockRec   pb;
00737         FormatListRec   formatListRecords[kMaxFormatListRecs];
00738         DrvSts          status;
00739         short           formatListRecIndex;
00740         OSErr           result;
00741 
00742         blocks = 0;
00743         
00744         /* Find the drive queue element for this volume */
00745         result = FindDrive(pathname, vRefNum, &driveQElementPtr);
00746         
00747         /* 
00748         **  Make sure this is a real driver (dQRefNum < 0).
00749         **  AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause
00750         **  problems if you try to use it as a driver refNum.
00751         */ 
00752         if ( (result == noErr) && (driveQElementPtr->dQRefNum >= 0) )
00753         {
00754             result = paramErr;
00755         }
00756         else
00757         {
00758             /* Attempt to get the drive's format list. */
00759             /* (see the Technical Note "What Your Sony Drives For You") */
00760             
00761             pb.cntrlParam.ioVRefNum = driveQElementPtr->dQDrive;
00762             pb.cntrlParam.ioCRefNum = driveQElementPtr->dQRefNum;
00763             pb.cntrlParam.csCode = kFmtLstCode;
00764             pb.cntrlParam.csParam[0] = kMaxFormatListRecs;
00765             *(long *)&pb.cntrlParam.csParam[1] = (long)&formatListRecords[0];
00766             
00767             result = PBStatusSync(&pb);
00768             
00769             if ( result == noErr )
00770             {
00771                 /* The drive supports ReturnFormatList status call. */
00772                 
00773                 /* Get the current disk's size. */
00774                 for( formatListRecIndex = 0;
00775                      formatListRecIndex < pb.cntrlParam.csParam[0];
00776                      ++formatListRecIndex )
00777                 {
00778                     if ( (formatListRecords[formatListRecIndex].formatFlags &
00779                           diCIFmtFlagsCurrentMask) != 0 )
00780                     {
00781                         blocks = formatListRecords[formatListRecIndex].volSize;
00782                     }
00783                 }
00784                 if ( blocks == 0 )
00785                 {
00786                     /* This should never happen */
00787                     result = paramErr;
00788                 }
00789             }
00790             else if ( driveQElementPtr->dQRefNum == (short)kSonyRefNum )
00791             {
00792                 /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */
00793                 
00794                 result = DriveStatus(driveQElementPtr->dQDrive, &status);
00795                 if ( result == noErr )
00796                 {
00797                     switch ( status.twoSideFmt )
00798                     {
00799                     case kSingleSided:
00800                         blocks = kSingleSidedSize;
00801                         break;
00802                     case kDoubleSided:
00803                         blocks = kDoubleSidedSize;
00804                         break;
00805                     default:
00806                         /* This should never happen */
00807                         result = paramErr;
00808                         break;
00809                     }
00810                 }
00811             }
00812             else
00813             {
00814                 /* The drive is not a floppy and it doesn't support ReturnFormatList */
00815                 /* so use the dQDrvSz field(s) */
00816                 
00817                 result = noErr; /* reset result */
00818                 switch ( driveQElementPtr->qType )
00819                 {
00820                 case kWordDrvSiz:
00821                     blocks = driveQElementPtr->dQDrvSz;
00822                     break;
00823                 case kLongDrvSiz:
00824                     blocks = ((unsigned long)driveQElementPtr->dQDrvSz2 << 16) +
00825                              driveQElementPtr->dQDrvSz;
00826                     break;
00827                 default:
00828                     /* This should never happen */
00829                     result = paramErr;
00830                     break;
00831                 }
00832             }
00833         }
00834         
00835         if ( result == noErr )
00836         {
00837             *numBlocks = blocks;
00838         }
00839         
00840         return ( result );
00841     }
00842 
00843     /*****************************************************************************/
00844 
00845     pascal  OSErr   GetVolState(ConstStr255Param pathname,
00846                                 short vRefNum,
00847                                 Boolean *volumeOnline,
00848                                 Boolean *volumeEjected,
00849                                 Boolean *driveEjectable,
00850                                 Boolean *driverWantsEject)
00851     {
00852         HParamBlockRec pb;
00853         short driveNumber;
00854         OSErr error;
00855 
00856         error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
00857         if ( error == noErr )
00858         {
00859             if ( pb.volumeParam.ioVDrvInfo != 0 )
00860             {
00861                 /* the volume is online and not ejected */
00862                 *volumeOnline = true;
00863                 *volumeEjected = false;
00864                 
00865                 /* Get the drive number */
00866                 driveNumber = pb.volumeParam.ioVDrvInfo;
00867             }
00868             else
00869             {
00870                 /* the volume's is either offline or ejected */
00871                 /* in either case, the volume is NOT online */
00872                 *volumeOnline = false;
00873 
00874                 /* Is it ejected? */
00875                 *volumeEjected = pb.volumeParam.ioVDRefNum > 0;
00876                 
00877                 if ( *volumeEjected )
00878                 {
00879                     /* If ejected, the drive number is ioVDRefNum */
00880                     driveNumber = pb.volumeParam.ioVDRefNum;
00881                 }
00882                 else
00883                 {
00884                     /* If offline, the drive number is the negative of ioVDRefNum */
00885                     driveNumber = (short)-pb.volumeParam.ioVDRefNum;
00886                 }
00887             }
00888             
00889             {
00890                 DrvQElPtr drvQElem;
00891                 
00892                 /* Find the drive queue element by searching the drive queue */
00893                 drvQElem = (DrvQElPtr)(GetDrvQHdr()->qHead);
00894                 while ( (drvQElem != NULL) && (drvQElem->dQDrive != driveNumber) )
00895                 {
00896                     drvQElem = (DrvQElPtr)drvQElem->qLink;
00897                 }
00898                 
00899                 if ( drvQElem != NULL )
00900                 {
00901                     /*
00902                     **  Each drive queue element is preceded by 4 flag bytes.
00903                     **  Byte 1 (the second flag byte) has bits that tell us if a
00904                     **  drive is ejectable and if its driver wants an eject call.
00905                     **  See Inside Macintosh: Files, page 2-85.
00906                     */
00907                     {
00908                         Ptr     flagBytePtr;
00909                         
00910                         /* point to byte 1 of the flag bytes */
00911                         flagBytePtr = (Ptr)drvQElem;
00912                         flagBytePtr -= 3;
00913                         
00914                         /*
00915                         **  The drive is ejectable if flag byte 1 does not contain
00916                         **  0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call).
00917                         */
00918                         
00919                         *driveEjectable = (*flagBytePtr != 0x08) && (*flagBytePtr != 0x48);
00920                         
00921                         /*
00922                         **  The driver wants an eject call if flag byte 1 does not contain
00923                         **  0x08 (nonejectable). This may seem like a minor point, but some
00924                         **  disk drivers use the Eject request to flush their caches to disk
00925                         **  and you wouldn't want to skip that step after unmounting a volume.
00926                         */
00927                         
00928                         *driverWantsEject = (*flagBytePtr != 0x08);
00929                     }
00930                 }
00931                 else
00932                 {
00933                     /* Didn't find the drive (this should never happen) */
00934                     *driveEjectable = false;
00935                     *driverWantsEject = false;
00936                 }
00937             }
00938         }
00939         
00940         return ( error );
00941     }
00942 
00943     /*****************************************************************************/
00944 
00945 #endif  //  }   !TARGET_API_MAC_CARBON
00946 
00947 /*****************************************************************************/
00948 
00949 pascal  OSErr   GetVolFileSystemID(ConstStr255Param pathname,
00950                                    short vRefNum,
00951                                    short *fileSystemID)
00952 {
00953     HParamBlockRec pb;
00954     OSErr error;
00955 
00956     error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
00957     if ( error == noErr )
00958     {
00959         *fileSystemID = pb.volumeParam.ioVFSID;
00960     }
00961     
00962     return ( error );
00963 }
00964 
00965 /*****************************************************************************/
00966 
00967 //
00968 //  Note:   Under Carbon there are no drive numbers, so you cannot call
00969 //          Eject with a drive number after unmounting a volume.
00970 //          When a Carbon application calls UnmountVol, CarbonLib will make
00971 //          sure ejectable media is ejected (leaving ejectable media in the
00972 //          disk drive makes no sense to Carbon applications).
00973 //
00974 pascal  OSErr   UnmountAndEject(ConstStr255Param pathname,
00975                                 short vRefNum)
00976 {
00977     HParamBlockRec pb;
00978     OSErr error;
00979 
00980     error = GetVolumeInfoNoName(pathname, vRefNum, &pb);
00981     if ( error == noErr )
00982     {
00983     
00984 #if !TARGET_API_MAC_CARBON
00985 
00986         short driveNum;
00987         Boolean ejected, wantsEject;
00988         DrvQElPtr drvQElem;
00989         
00990         if ( pb.volumeParam.ioVDrvInfo != 0 )
00991         {
00992             /* the volume is online and not ejected */
00993             ejected = false;
00994             
00995             /* Get the drive number */
00996             driveNum = pb.volumeParam.ioVDrvInfo;
00997         }
00998         else
00999         {
01000             /* the volume is ejected or offline */
01001             
01002             /* Is it ejected? */
01003             ejected = pb.volumeParam.ioVDRefNum > 0;
01004             
01005             if ( ejected )
01006             {
01007                 /* If ejected, the drive number is ioVDRefNum */
01008                 driveNum = pb.volumeParam.ioVDRefNum;
01009             }
01010             else
01011             {
01012                 /* If offline, the drive number is the negative of ioVDRefNum */
01013                 driveNum = (short)-pb.volumeParam.ioVDRefNum;
01014             }
01015         }
01016         
01017         /* find the drive queue element */
01018         drvQElem = (DrvQElPtr)(GetDrvQHdr()->qHead);
01019         while ( (drvQElem != NULL) && (drvQElem->dQDrive != driveNum) )
01020         {
01021             drvQElem = (DrvQElPtr)drvQElem->qLink;
01022         }
01023         
01024         if ( drvQElem != NULL )
01025         {
01026             /* does the drive want an eject call */
01027             wantsEject = (*((Ptr)((Ptr)drvQElem - 3)) != 8);
01028         }
01029         else
01030         {
01031             /* didn't find the drive!! */
01032             wantsEject = false;
01033         }
01034         
01035 #endif  //  !TARGET_API_MAC_CARBON
01036 
01037         /* unmount the volume */
01038         pb.volumeParam.ioNamePtr = NULL;
01039         /* ioVRefNum is already filled in from PBHGetVInfo */
01040         error = PBUnmountVol((ParmBlkPtr)&pb);
01041 
01042 #if !TARGET_API_MAC_CARBON
01043 
01044         if ( error == noErr )
01045         {
01046             if ( wantsEject && !ejected )
01047             {
01048                 /* eject the media from the drive if needed */
01049                 pb.volumeParam.ioVRefNum = driveNum;
01050                 error = PBEject((ParmBlkPtr)&pb);
01051             }
01052         }
01053         
01054 #endif  //  !TARGET_API_MAC_CARBON
01055 
01056     }
01057     
01058     return ( error );
01059 }
01060 
01061 /*****************************************************************************/
01062 
01063 pascal  OSErr   OnLine(FSSpecPtr volumes,
01064                        short reqVolCount,
01065                        short *actVolCount,
01066                        short *volIndex)
01067 {
01068     HParamBlockRec pb;
01069     OSErr error = noErr;
01070     FSSpec *endVolArray;
01071 
01072     if ( *volIndex > 0 )
01073     {
01074         *actVolCount = 0;
01075         for ( endVolArray = volumes + reqVolCount; (volumes < endVolArray) && (error == noErr); ++volumes )
01076         {
01077             pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name;
01078             pb.volumeParam.ioVolIndex = *volIndex;
01079             error = PBHGetVInfoSync(&pb);
01080             if ( error == noErr )
01081             {
01082                 volumes->parID = fsRtParID;     /* the root directory's parent is 1 */
01083                 volumes->vRefNum = pb.volumeParam.ioVRefNum;
01084                 ++*volIndex;
01085                 ++*actVolCount;
01086             }
01087         }
01088     }
01089     else
01090     {
01091         error = paramErr;
01092     }
01093     
01094     return ( error );
01095 }
01096 
01097 /*****************************************************************************/
01098 
01099 pascal  OSErr SetDefault(short newVRefNum,
01100                          long newDirID,
01101                          short *oldVRefNum,
01102                          long *oldDirID)
01103 {
01104     OSErr   error;
01105     
01106     /* Get the current default volume/directory. */
01107     error = HGetVol(NULL, oldVRefNum, oldDirID);
01108     if ( error == noErr )
01109     {
01110         /* Set the new default volume/directory */
01111         error = HSetVol(NULL, newVRefNum, newDirID);
01112     }
01113     
01114     return ( error );
01115 }
01116 
01117 /*****************************************************************************/
01118 
01119 pascal  OSErr RestoreDefault(short oldVRefNum,
01120                              long oldDirID)
01121 {
01122     OSErr   error;
01123     
01124 #if !TARGET_API_MAC_CARBON
01125 
01126     short   defaultVRefNum;
01127     long    defaultDirID;
01128     long    defaultProcID;
01129     
01130     /* Determine if the default volume was a wdRefNum. */
01131     error = GetWDInfo(oldVRefNum, &defaultVRefNum, &defaultDirID, &defaultProcID);
01132     if ( error == noErr )
01133     {
01134         /* Restore the old default volume/directory, one way or the other. */
01135         if ( defaultDirID != fsRtDirID )
01136         {
01137             /* oldVRefNum was a wdRefNum - use SetVol */
01138             error = SetVol(NULL, oldVRefNum);
01139         }
01140         else
01141         {
01142         
01143 #endif  //  !TARGET_API_MAC_CARBON
01144 
01145             /* oldVRefNum was a real vRefNum - use HSetVol */
01146             error = HSetVol(NULL, oldVRefNum, oldDirID);
01147 
01148 #if !TARGET_API_MAC_CARBON
01149 
01150         }
01151     }
01152 #endif  //  !TARGET_API_MAC_CARBON
01153     
01154     return ( error );
01155 }
01156 
01157 /*****************************************************************************/
01158 
01159 pascal  OSErr GetDInfo(short vRefNum,
01160                        long dirID,
01161                        ConstStr255Param name,
01162                        DInfo *fndrInfo)
01163 {
01164     CInfoPBRec pb;
01165     OSErr error;
01166     
01167     error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
01168     if ( error == noErr )
01169     {
01170         if ( (pb.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
01171         {
01172             /* it's a directory, return the DInfo */
01173             *fndrInfo = pb.dirInfo.ioDrUsrWds;
01174         }
01175         else
01176         {
01177             /* oops, a file was passed */
01178             error = dirNFErr;
01179         }
01180     }
01181     
01182     return ( error );
01183 }
01184 
01185 /*****************************************************************************/
01186 
01187 pascal  OSErr FSpGetDInfo(const FSSpec *spec,
01188                           DInfo *fndrInfo)
01189 {
01190     return ( GetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
01191 }
01192 
01193 /*****************************************************************************/
01194 
01195 pascal  OSErr SetDInfo(short vRefNum,
01196                        long dirID,
01197                        ConstStr255Param name,
01198                        const DInfo *fndrInfo)
01199 {
01200     CInfoPBRec pb;
01201     Str31 tempName;
01202     OSErr error;
01203 
01204     /* Protection against File Sharing problem */
01205     if ( (name == NULL) || (name[0] == 0) )
01206     {
01207         tempName[0] = 0;
01208         pb.dirInfo.ioNamePtr = tempName;
01209         pb.dirInfo.ioFDirIndex = -1;    /* use ioDirID */
01210     }
01211     else
01212     {
01213         pb.dirInfo.ioNamePtr = (StringPtr)name;
01214         pb.dirInfo.ioFDirIndex = 0; /* use ioNamePtr and ioDirID */
01215     }
01216     pb.dirInfo.ioVRefNum = vRefNum;
01217     pb.dirInfo.ioDrDirID = dirID;
01218     error = PBGetCatInfoSync(&pb);
01219     if ( error == noErr )
01220     {
01221         if ( (pb.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
01222         {
01223             /* it's a directory, set the DInfo */
01224             if ( pb.dirInfo.ioNamePtr == tempName )
01225             {
01226                 pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
01227             }
01228             else
01229             {
01230                 pb.dirInfo.ioDrDirID = dirID;
01231             }
01232             pb.dirInfo.ioDrUsrWds = *fndrInfo;
01233             error = PBSetCatInfoSync(&pb);
01234         }
01235         else
01236         {
01237             /* oops, a file was passed */
01238             error = dirNFErr;
01239         }
01240     }
01241     
01242     return ( error );
01243 }
01244 
01245 /*****************************************************************************/
01246 
01247 pascal  OSErr FSpSetDInfo(const FSSpec *spec,
01248                           const DInfo *fndrInfo)
01249 {
01250     return ( SetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
01251 }
01252 
01253 /*****************************************************************************/
01254 
01255 pascal  OSErr   GetDirectoryID(short vRefNum,
01256                                long dirID,
01257                                ConstStr255Param name,
01258                                long *theDirID,
01259                                Boolean *isDirectory)
01260 {
01261     CInfoPBRec pb;
01262     OSErr error;
01263 
01264     error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
01265     if ( error == noErr )
01266     {
01267         *isDirectory = (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0;
01268         if ( *isDirectory )
01269         {
01270             *theDirID = pb.dirInfo.ioDrDirID;
01271         }
01272         else
01273         {
01274             *theDirID = pb.hFileInfo.ioFlParID;
01275         }
01276     }
01277     
01278     return ( error );
01279 }
01280 
01281 /*****************************************************************************/
01282 
01283 pascal  OSErr   FSpGetDirectoryID(const FSSpec *spec,
01284                                   long *theDirID,
01285                                   Boolean *isDirectory)
01286 {
01287     return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
01288              theDirID, isDirectory) );
01289 }
01290 
01291 /*****************************************************************************/
01292 
01293 pascal  OSErr   GetDirName(short vRefNum,
01294                            long dirID,
01295                            Str31 name)
01296 {
01297     CInfoPBRec pb;
01298     OSErr error;
01299 
01300     if ( name != NULL )
01301     {
01302         pb.dirInfo.ioNamePtr = name;
01303         pb.dirInfo.ioVRefNum = vRefNum;
01304         pb.dirInfo.ioDrDirID = dirID;
01305         pb.dirInfo.ioFDirIndex = -1;    /* get information about ioDirID */
01306         error = PBGetCatInfoSync(&pb);
01307     }
01308     else
01309     {
01310         error = paramErr;
01311     }
01312     
01313     return ( error );
01314 }
01315 
01316 /*****************************************************************************/
01317 
01318 pascal  OSErr   GetIOACUser(short vRefNum,
01319                             long dirID,
01320                             ConstStr255Param name,
01321                             SInt8 *ioACUser)
01322 {
01323     CInfoPBRec pb;
01324     OSErr error;
01325     
01326     /* Clear ioACUser before calling PBGetCatInfo since some file systems
01327     ** don't bother to set or clear this field. If ioACUser isn't set by the
01328     ** file system, then you'll get the zero value back (full access) which
01329     ** is the access you have on volumes that don't support ioACUser.
01330     */
01331     pb.dirInfo.ioACUser = 0;    /* ioACUser used to be filler2 */
01332     error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
01333     if ( error == noErr )
01334     {
01335         if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) == 0 )
01336         {
01337             /* oops, a file was passed */
01338             error = dirNFErr;
01339         }
01340         else
01341         {
01342             *ioACUser = pb.dirInfo.ioACUser;
01343         }
01344     }
01345     
01346     return ( error );
01347 }
01348 
01349 /*****************************************************************************/
01350 
01351 pascal  OSErr   FSpGetIOACUser(const FSSpec *spec,
01352                                SInt8 *ioACUser)
01353 {
01354     return ( GetIOACUser(spec->vRefNum, spec->parID, spec->name, ioACUser) );
01355 }
01356 
01357 /*****************************************************************************/
01358 
01359 pascal  OSErr   GetParentID(short vRefNum,
01360                             long dirID,
01361                             ConstStr255Param name,
01362                             long *parID)
01363 {
01364     CInfoPBRec pb;
01365     Str31 tempName;
01366     OSErr error;
01367     short realVRefNum;
01368     
01369     /* Protection against File Sharing problem */
01370     if ( (name == NULL) || (name[0] == 0) )
01371     {
01372         tempName[0] = 0;
01373         pb.hFileInfo.ioNamePtr = tempName;
01374         pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
01375     }
01376     else
01377     {
01378         pb.hFileInfo.ioNamePtr = (StringPtr)name;
01379         pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
01380     }
01381     pb.hFileInfo.ioVRefNum = vRefNum;
01382     pb.hFileInfo.ioDirID = dirID;
01383     error = PBGetCatInfoSync(&pb);
01384     if ( error == noErr )
01385     {
01386         /*
01387         **  There's a bug in HFS where the wrong parent dir ID can be
01388         **  returned if multiple separators are used at the end of a
01389         **  pathname. For example, if the pathname:
01390         **      'volumeName:System Folder:Extensions::'
01391         **  is passed, the directory ID of the Extensions folder is
01392         **  returned in the ioFlParID field instead of fsRtDirID. Since
01393         **  multiple separators at the end of a pathname always specifies
01394         **  a directory, we only need to work-around cases where the
01395         **  object is a directory and there are multiple separators at
01396         **  the end of the name parameter.
01397         */
01398         if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
01399         {
01400             /* Its a directory */
01401             
01402             /* is there a pathname? */
01403             if ( pb.hFileInfo.ioNamePtr == name )   
01404             {
01405                 /* could it contain multiple separators? */
01406                 if ( name[0] >= 2 )
01407                 {
01408                     /* does it contain multiple separators at the end? */
01409                     if ( (name[name[0]] == ':') && (name[name[0] - 1] == ':') )
01410                     {
01411                         /* OK, then do the extra stuff to get the correct parID */
01412                         
01413                         /* Get the real vRefNum (this should not fail) */
01414                         error = DetermineVRefNum(name, vRefNum, &realVRefNum);
01415                         if ( error == noErr )
01416                         {
01417                             /* we don't need the parent's name, but add protect against File Sharing problem */
01418                             tempName[0] = 0;
01419                             pb.dirInfo.ioNamePtr = tempName;
01420                             pb.dirInfo.ioVRefNum = realVRefNum;
01421                             /* pb.dirInfo.ioDrDirID already contains the */
01422                             /* dirID of the directory object */
01423                             pb.dirInfo.ioFDirIndex = -1;    /* get information about ioDirID */
01424                             error = PBGetCatInfoSync(&pb);
01425                             /* now, pb.dirInfo.ioDrParID contains the correct parID */
01426                         }
01427                     }
01428                 }
01429             }
01430         }
01431         
01432         if ( error == noErr )
01433         {
01434             /* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */
01435             /* contains the parent ID */
01436             *parID = pb.hFileInfo.ioFlParID;
01437         }
01438     }
01439     
01440     return ( error );
01441 }
01442 
01443 /*****************************************************************************/
01444 
01445 pascal  OSErr   GetFilenameFromPathname(ConstStr255Param pathname,
01446                                         Str255 filename)
01447 {
01448     short   index;
01449     short   nameEnd;
01450     OSErr   error;
01451 
01452     /* default to no filename */
01453     filename[0] = 0;
01454 
01455     /* check for no pathname */
01456     if ( pathname != NULL )
01457     {
01458         /* get string length */
01459         index = pathname[0];
01460         
01461         /* check for empty string */
01462         if ( index != 0 )
01463         {
01464             /* skip over last trailing colon (if any) */
01465             if ( pathname[index] == ':' )
01466             {
01467                 --index;
01468             }
01469 
01470             /* save the end of the string */
01471             nameEnd = index;
01472 
01473             /* if pathname ends with multiple colons, then this pathname refers */
01474             /* to a directory, not a file */
01475             if ( pathname[index] != ':' )
01476             {
01477                 /* parse backwards until we find a colon or hit the beginning of the pathname */
01478                 while ( (index != 0) && (pathname[index] != ':') )
01479                 {
01480                     --index;
01481                 }
01482                 
01483                 /* if we parsed to the beginning of the pathname and the pathname ended */
01484                 /* with a colon, then pathname is a full pathname to a volume, not a file */
01485                 if ( (index != 0) || (pathname[pathname[0]] != ':') )
01486                 {
01487                     /* get the filename and return noErr */
01488                     filename[0] = (char)(nameEnd - index);
01489                     BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
01490                     error = noErr;
01491                 }
01492                 else
01493                 {
01494                     /* pathname to a volume, not a file */
01495                     error = notAFileErr;
01496                 }
01497             }
01498             else
01499             {
01500                 /* directory, not a file */
01501                 error = notAFileErr;
01502             }
01503         }
01504         else
01505         {
01506             /* empty string isn't a file */
01507             error = notAFileErr;
01508         }
01509     }
01510     else
01511     {
01512         /* NULL pathname isn't a file */
01513         error = notAFileErr;
01514     }
01515     
01516     return ( error );
01517 }
01518 
01519 /*****************************************************************************/
01520 
01521 pascal  OSErr   GetObjectLocation(short vRefNum,
01522                                   long dirID,
01523                                   ConstStr255Param pathname,
01524                                   short *realVRefNum,
01525                                   long *realParID,
01526                                   Str255 realName,
01527                                   Boolean *isDirectory)
01528 {
01529     OSErr error;
01530     CInfoPBRec pb;
01531     Str255 tempPathname;
01532     
01533     /* clear results */
01534     *realVRefNum = 0;
01535     *realParID = 0;
01536     realName[0] = 0;
01537     
01538     /*
01539     **  Get the real vRefNum
01540     */
01541     error = DetermineVRefNum(pathname, vRefNum, realVRefNum);
01542     if ( error == noErr )
01543     {
01544         /*
01545         **  Determine if the object already exists and if so,
01546         **  get the real parent directory ID if it's a file
01547         */
01548         
01549         /* Protection against File Sharing problem */
01550         if ( (pathname == NULL) || (pathname[0] == 0) )
01551         {
01552             tempPathname[0] = 0;
01553             pb.hFileInfo.ioNamePtr = tempPathname;
01554             pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
01555         }
01556         else
01557         {
01558             pb.hFileInfo.ioNamePtr = (StringPtr)pathname;
01559             pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
01560         }
01561         pb.hFileInfo.ioVRefNum = vRefNum;
01562         pb.hFileInfo.ioDirID = dirID;
01563         error = PBGetCatInfoSync(&pb);
01564         if ( error == noErr )
01565         {
01566             /*
01567             **  The file system object is present and we have the file's real parID
01568             */
01569             
01570             /*  Is it a directory or a file? */
01571             *isDirectory = (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0;
01572             if ( *isDirectory )
01573             {
01574                 /*
01575                 **  It's a directory, get its name and parent dirID, and then we're done
01576                 */
01577                 
01578                 pb.dirInfo.ioNamePtr = realName;
01579                 pb.dirInfo.ioVRefNum = *realVRefNum;
01580                 /* pb.dirInfo.ioDrDirID already contains the dirID of the directory object */
01581                 pb.dirInfo.ioFDirIndex = -1;    /* get information about ioDirID */
01582                 error = PBGetCatInfoSync(&pb);
01583                 
01584                 /* get the parent ID here, because the file system can return the */
01585                 /* wrong parent ID from the last call. */
01586                 *realParID = pb.dirInfo.ioDrParID;
01587             }
01588             else
01589             {
01590                 /*
01591                 **  It's a file - use the parent directory ID from the last call
01592                 **  to GetCatInfoparse, get the file name, and then we're done
01593                 */
01594                 *realParID = pb.hFileInfo.ioFlParID;    
01595                 error = GetFilenameFromPathname(pathname, realName);
01596             }
01597         }
01598         else if ( error == fnfErr )
01599         {
01600             /*
01601             **  The file system object is not present - see if its parent is present
01602             */
01603             
01604             /*
01605             **  Parse to get the object name from end of pathname
01606             */
01607             error = GetFilenameFromPathname(pathname, realName);
01608             
01609             /* if we can't get the object name from the end, we can't continue */
01610             if ( error == noErr )
01611             {
01612                 /*
01613                 **  What we want now is the pathname minus the object name
01614                 **  for example:
01615                 **  if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
01616                 **  if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
01617                 **  if pathname is ':dir:file' tempPathname becomes ':dir:'
01618                 **  if pathname is ':dir:file:' tempPathname becomes ':dir:'
01619                 **  if pathname is ':file' tempPathname becomes ':'
01620                 **  if pathname is 'file or file:' tempPathname becomes ''
01621                 */
01622                 
01623                 /* get a copy of the pathname */
01624                 BlockMoveData(pathname, tempPathname, pathname[0] + 1);
01625                 
01626                 /* remove the object name */
01627                 tempPathname[0] -= realName[0];
01628                 /* and the trailing colon (if any) */
01629                 if ( pathname[pathname[0]] == ':' )
01630                 {
01631                     --tempPathname[0];
01632                 }
01633                 
01634                 /* OK, now get the parent's directory ID */
01635                 
01636                 /* Protection against File Sharing problem */
01637                 pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname;
01638                 if ( tempPathname[0] != 0 )
01639                 {
01640                     pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
01641                 }
01642                 else
01643                 {
01644                     pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
01645                 }
01646                 pb.hFileInfo.ioVRefNum = vRefNum;
01647                 pb.hFileInfo.ioDirID = dirID;
01648                 error = PBGetCatInfoSync(&pb);
01649                 *realParID = pb.dirInfo.ioDrDirID;
01650 
01651                 *isDirectory = false;   /* we don't know what the object is really going to be */
01652             }
01653             
01654             if ( error != noErr )
01655             {
01656                 error = dirNFErr;   /* couldn't find parent directory */
01657             }
01658             else
01659             {
01660                 error = fnfErr; /* we found the parent, but not the file */
01661             }
01662         }
01663     }
01664     
01665     return ( error );
01666 }
01667 
01668 /*****************************************************************************/
01669 
01670 pascal  OSErr   GetDirItems(short vRefNum,
01671                             long dirID,
01672                             ConstStr255Param name,
01673                             Boolean getFiles,
01674                             Boolean getDirectories,
01675                             FSSpecPtr items,
01676                             short reqItemCount,
01677                             short *actItemCount,
01678                             short *itemIndex) /* start with 1, then use what's returned */
01679 {
01680     CInfoPBRec pb;
01681     OSErr error;
01682     long theDirID;
01683     Boolean isDirectory;
01684     FSSpec *endItemsArray;
01685     
01686     if ( *itemIndex > 0 )
01687     {
01688         /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */
01689         /* to this routine, I could rip out calls to DetermineVRefNum and GetDirectoryID and this */
01690         /* routine would be much faster because of the overhead of DetermineVRefNum and */
01691         /* GetDirectoryID and because GetDirectoryID blows away the directory index hint the Macintosh */
01692         /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */
01693         /* pass a big array of FSSpecs so you can get the directory's contents with few calls */
01694         /* to this routine. */
01695         
01696         /* get the real volume reference number */
01697         error = DetermineVRefNum(name, vRefNum, &pb.hFileInfo.ioVRefNum);
01698         if ( error == noErr )
01699         {
01700             /* and the real directory ID of this directory (and make sure it IS a directory) */
01701             error = GetDirectoryID(vRefNum, dirID, name, &theDirID, &isDirectory);
01702             if ( error == noErr )
01703             {
01704                 if ( isDirectory )
01705                 {
01706                     *actItemCount = 0;
01707                     endItemsArray = items + reqItemCount;
01708                     while ( (items < endItemsArray) && (error == noErr) )
01709                     {
01710                         pb.hFileInfo.ioNamePtr = (StringPtr) &items->name;
01711                         pb.hFileInfo.ioDirID = theDirID;
01712                         pb.hFileInfo.ioFDirIndex = *itemIndex;
01713                         error = PBGetCatInfoSync(&pb);
01714                         if ( error == noErr )
01715                         {
01716                             items->parID = pb.hFileInfo.ioFlParID;  /* return item's parID */
01717                             items->vRefNum = pb.hFileInfo.ioVRefNum;    /* return item's vRefNum */
01718                             ++*itemIndex;   /* prepare to get next item in directory */
01719                             
01720                             if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
01721                             {
01722                                 if ( getDirectories )
01723                                 {
01724                                     ++*actItemCount; /* keep this item */
01725                                     ++items; /* point to next item */
01726                                 }
01727                             }
01728                             else
01729                             {
01730                                 if ( getFiles )
01731                                 {
01732                                     ++*actItemCount; /* keep this item */
01733                                     ++items; /* point to next item */
01734                                 }
01735                             }
01736                         }
01737                     }
01738                 }
01739                 else
01740                 {
01741                     /* it wasn't a directory */
01742                     error = dirNFErr;
01743                 }
01744             }
01745         }
01746     }
01747     else
01748     {
01749         /* bad itemIndex */
01750         error = paramErr;
01751     }
01752     
01753     return ( error );
01754 }
01755 
01756 /*****************************************************************************/
01757 
01758 static  void    DeleteLevel(long dirToDelete,
01759                             DeleteEnumGlobalsPtr theGlobals)
01760 {
01761     long savedDir;
01762     
01763     do
01764     {
01765         /* prepare to delete directory */
01766         theGlobals->myPB.ciPB.dirInfo.ioNamePtr = (StringPtr)&theGlobals->itemName;
01767         theGlobals->myPB.ciPB.dirInfo.ioFDirIndex = 1;  /* get first item */
01768         theGlobals->myPB.ciPB.dirInfo.ioDrDirID = dirToDelete;  /* in this directory */
01769         theGlobals->error = PBGetCatInfoSync(&(theGlobals->myPB.ciPB));
01770         if ( theGlobals->error == noErr )
01771         {
01772             savedDir = dirToDelete;
01773             /* We have an item.  Is it a file or directory? */
01774             if ( (theGlobals->myPB.ciPB.dirInfo.ioFlAttrib & kioFlAttribDirMask) != 0 )
01775             {
01776                 /* it's a directory */
01777                 savedDir = theGlobals->myPB.ciPB.dirInfo.ioDrDirID; /* save dirID of directory instead */
01778                 DeleteLevel(theGlobals->myPB.ciPB.dirInfo.ioDrDirID, theGlobals);   /* Delete its contents */
01779                 theGlobals->myPB.ciPB.dirInfo.ioNamePtr = NULL; /* prepare to delete directory */
01780             }
01781             if ( theGlobals->error == noErr )
01782             {
01783                 theGlobals->myPB.ciPB.dirInfo.ioDrDirID = savedDir; /* restore dirID */
01784                 theGlobals->myPB.hPB.fileParam.ioFVersNum = 0;  /* just in case it's used on an MFS volume... */
01785                 theGlobals->error = PBHDeleteSync(&(theGlobals->myPB.hPB)); /* delete this item */
01786                 if ( theGlobals->error == fLckdErr )
01787                 {
01788                     (void) PBHRstFLockSync(&(theGlobals->myPB.hPB));    /* unlock it */
01789                     theGlobals->error = PBHDeleteSync(&(theGlobals->myPB.hPB)); /* and try again */
01790                 }
01791             }
01792         }
01793     } while ( theGlobals->error == noErr );
01794     
01795     if ( theGlobals->error == fnfErr )
01796     {
01797         theGlobals->error = noErr;
01798     }
01799 }
01800 
01801 /*****************************************************************************/
01802 
01803 pascal  OSErr   DeleteDirectoryContents(short vRefNum,
01804                                         long dirID,
01805                                         ConstStr255Param name)
01806 {
01807     DeleteEnumGlobals theGlobals;
01808     Boolean isDirectory;
01809     OSErr error;
01810 
01811     /*  Get the real dirID and make sure it is a directory. */
01812     error = GetDirectoryID(vRefNum, dirID, name, &dirID, &isDirectory);
01813     if ( error == noErr )
01814     {
01815         if ( isDirectory )
01816         {
01817             /* Get the real vRefNum */
01818             error = DetermineVRefNum(name, vRefNum, &vRefNum);
01819             if ( error == noErr )
01820             {
01821                 /* Set up the globals we need to access from the recursive routine. */
01822                 theGlobals.myPB.ciPB.dirInfo.ioVRefNum = vRefNum;
01823                     
01824                 /* Here we go into recursion land... */
01825                 DeleteLevel(dirID, &theGlobals);
01826                 error = theGlobals.error;
01827             }
01828         }
01829         else
01830         {
01831             error = dirNFErr;
01832         }
01833     }
01834     
01835     return ( error );
01836 }
01837 
01838 /*****************************************************************************/
01839 
01840 pascal  OSErr   DeleteDirectory(short vRefNum,
01841                                 long dirID,
01842                                 ConstStr255Param name)
01843 {
01844     OSErr error;
01845     
01846     /* Make sure a directory was specified and then delete its contents */
01847     error = DeleteDirectoryContents(vRefNum, dirID, name);
01848     if ( error == noErr )
01849     {
01850         error = HDelete(vRefNum, dirID, name);
01851         if ( error == fLckdErr )
01852         {
01853             (void) HRstFLock(vRefNum, dirID, name); /* unlock the directory locked by AppleShare */
01854             error = HDelete(vRefNum, dirID, name);  /* and try again */
01855         }
01856     }
01857     
01858     return ( error );
01859 }
01860 
01861 /*****************************************************************************/
01862 
01863 pascal  OSErr   CheckObjectLock(short vRefNum,
01864                                 long dirID,
01865                                 ConstStr255Param name)
01866 {
01867     CInfoPBRec pb;
01868     OSErr error;
01869     
01870     error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
01871     if ( error == noErr )
01872     {
01873         /* check locked bit */
01874         if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribLockedMask) != 0 )
01875         {
01876             error = fLckdErr;
01877         }
01878     }
01879     
01880     return ( error );
01881 }
01882 
01883 /*****************************************************************************/
01884 
01885 pascal  OSErr   FSpCheckObjectLock(const FSSpec *spec)
01886 {
01887     return ( CheckObjectLock(spec->vRefNum, spec->parID, spec->name) );
01888 }
01889 
01890 /*****************************************************************************/
01891 
01892 pascal  OSErr   GetFileSize(short vRefNum,
01893                             long dirID,
01894                             ConstStr255Param fileName,
01895                             long *dataSize,
01896                             long *rsrcSize)
01897 {
01898     HParamBlockRec pb;
01899     OSErr error;
01900     
01901     pb.fileParam.ioNamePtr = (StringPtr)fileName;
01902     pb.fileParam.ioVRefNum = vRefNum;
01903     pb.fileParam.ioFVersNum = 0;
01904     pb.fileParam.ioDirID = dirID;
01905     pb.fileParam.ioFDirIndex = 0;
01906     error = PBHGetFInfoSync(&pb);
01907     if ( error == noErr )
01908     {
01909         *dataSize = pb.fileParam.ioFlLgLen;
01910         *rsrcSize = pb.fileParam.ioFlRLgLen;
01911     }
01912     
01913     return ( error );
01914 }
01915 
01916 /*****************************************************************************/
01917 
01918 pascal  OSErr   FSpGetFileSize(const FSSpec *spec,
01919                                long *dataSize,
01920                                long *rsrcSize)
01921 {
01922     return ( GetFileSize(spec->vRefNum, spec->parID, spec->name, dataSize, rsrcSize) );
01923 }
01924 
01925 /*****************************************************************************/
01926 
01927 pascal  OSErr   BumpDate(short vRefNum,
01928                          long dirID,
01929                          ConstStr255Param name)
01930 /* Given a file or directory, change its modification date to the current date/time. */
01931 {
01932     CInfoPBRec pb;
01933     Str31 tempName;
01934     OSErr error;
01935     unsigned long secs;
01936 
01937     /* Protection against File Sharing problem */
01938     if ( (name == NULL) || (name[0] == 0) )
01939     {
01940         tempName[0] = 0;
01941         pb.hFileInfo.ioNamePtr = tempName;
01942         pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
01943     }
01944     else
01945     {
01946         pb.hFileInfo.ioNamePtr = (StringPtr)name;
01947         pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
01948     }
01949     pb.hFileInfo.ioVRefNum = vRefNum;
01950     pb.hFileInfo.ioDirID = dirID;
01951     error = PBGetCatInfoSync(&pb);
01952     if ( error == noErr )
01953     {
01954         GetDateTime(&secs);
01955         /* set mod date to current date, or one second into the future
01956             if mod date = current date */
01957         pb.hFileInfo.ioFlMdDat = (secs == pb.hFileInfo.ioFlMdDat) ? (++secs) : (secs);
01958         if ( pb.dirInfo.ioNamePtr == tempName )
01959         {
01960             pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
01961         }
01962         else
01963         {
01964             pb.hFileInfo.ioDirID = dirID;
01965         }
01966         error = PBSetCatInfoSync(&pb);
01967     }
01968     
01969     return ( error );
01970 }
01971 
01972 /*****************************************************************************/
01973 
01974 pascal  OSErr   FSpBumpDate(const FSSpec *spec)
01975 {
01976     return ( BumpDate(spec->vRefNum, spec->parID, spec->name) );
01977 }
01978 
01979 /*****************************************************************************/
01980 
01981 pascal  OSErr   ChangeCreatorType(short vRefNum,
01982                                   long dirID,
01983                                   ConstStr255Param name,
01984                                   OSType creator,
01985                                   OSType fileType)
01986 {
01987     CInfoPBRec pb;
01988     OSErr error;
01989     short realVRefNum;
01990     long parID;
01991 
01992     pb.hFileInfo.ioNamePtr = (StringPtr)name;
01993     pb.hFileInfo.ioVRefNum = vRefNum;
01994     pb.hFileInfo.ioDirID = dirID;
01995     pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
01996     error = PBGetCatInfoSync(&pb);
01997     if ( error == noErr )
01998     {
01999         if ( (pb.hFileInfo.ioFlAttrib & kioFlAttribDirMask) == 0 )  /* if file */
02000         {
02001             parID = pb.hFileInfo.ioFlParID; /* save parent dirID for BumpDate call */
02002 
02003             /* If creator not 0x00000000, change creator */
02004             if ( creator != (OSType)0x00000000 )
02005             {
02006                 pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
02007             }
02008             
02009             /* If fileType not 0x00000000, change fileType */
02010             if ( fileType != (OSType)0x00000000 )
02011             {
02012                 pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
02013             }
02014                 
02015             pb.hFileInfo.ioDirID = dirID;
02016             error = PBSetCatInfoSync(&pb);  /* now, save the new information back to disk */
02017 
02018             if ( (error == noErr) && (parID != fsRtParID) ) /* can't bump fsRtParID */
02019             {
02020                 /* get the real vRefNum in case a full pathname was passed */
02021                 error = DetermineVRefNum(name, vRefNum, &realVRefNum);
02022                 if ( error == noErr )
02023                 {
02024                     error = BumpDate(realVRefNum, parID, NULL);
02025                         /* and bump the parent directory's mod date to wake up the Finder */
02026                         /* to the change we just made */
02027                 }
02028             }
02029         }
02030         else
02031         {
02032             /* it was a directory, not a file */
02033             error = notAFileErr;
02034         }
02035     }
02036     
02037     return ( error );
02038 }
02039 
02040 /*****************************************************************************/
02041 
02042 pascal  OSErr   FSpChangeCreatorType(const FSSpec *spec,
02043                                      OSType creator,
02044                                      OSType fileType)
02045 {
02046     return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name, creator, fileType) );
02047 }
02048 
02049 /*****************************************************************************/
02050 
02051 pascal  OSErr   ChangeFDFlags(short vRefNum,
02052                               long dirID,
02053                               ConstStr255Param name,
02054                               Boolean   setBits,
02055                               unsigned short flagBits)
02056 {
02057     CInfoPBRec pb;
02058     Str31 tempName;
02059     OSErr error;
02060     short realVRefNum;
02061     long parID;
02062 
02063     /* Protection against File Sharing problem */
02064     if ( (name == NULL) || (name[0] == 0) )
02065     {
02066         tempName[0] = 0;
02067         pb.hFileInfo.ioNamePtr = tempName;
02068         pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
02069     }
02070     else
02071     {
02072         pb.hFileInfo.ioNamePtr = (StringPtr)name;
02073         pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
02074     }
02075     pb.hFileInfo.ioVRefNum = vRefNum;
02076     pb.hFileInfo.ioDirID = dirID;
02077     error = PBGetCatInfoSync(&pb);
02078     if ( error == noErr )
02079     {
02080         parID = pb.hFileInfo.ioFlParID; /* save parent dirID for BumpDate call */
02081         
02082         /* set or clear the appropriate bits in the Finder flags */
02083         if ( setBits )
02084         {
02085             /* OR in the bits */
02086             pb.hFileInfo.ioFlFndrInfo.fdFlags |= flagBits;
02087         }
02088         else
02089         {
02090             /* AND out the bits */
02091             pb.hFileInfo.ioFlFndrInfo.fdFlags &= ~flagBits;
02092         }
02093             
02094         if ( pb.dirInfo.ioNamePtr == tempName )
02095         {
02096             pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
02097         }
02098         else
02099         {
02100             pb.hFileInfo.ioDirID = dirID;
02101         }
02102         
02103         error = PBSetCatInfoSync(&pb);  /* now, save the new information back to disk */
02104 
02105         if ( (error == noErr) && (parID != fsRtParID) ) /* can't bump fsRtParID */
02106         {
02107             /* get the real vRefNum in case a full pathname was passed */
02108             error = DetermineVRefNum(name, vRefNum, &realVRefNum);
02109             if ( error == noErr )
02110             {
02111                 error = BumpDate(realVRefNum, parID, NULL);
02112                     /* and bump the parent directory's mod date to wake up the Finder */
02113                     /* to the change we just made */
02114             }
02115         }
02116     }
02117     
02118     return ( error );
02119 }
02120 
02121 /*****************************************************************************/
02122 
02123 pascal  OSErr   FSpChangeFDFlags(const FSSpec *spec,
02124                                  Boolean setBits,
02125                                  unsigned short flagBits)
02126 {
02127     return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, setBits, flagBits) );
02128 }
02129 
02130 /*****************************************************************************/
02131 
02132 pascal  OSErr   SetIsInvisible(short vRefNum,
02133                                long dirID,
02134                                ConstStr255Param name)
02135     /* Given a file or directory, make it invisible. */
02136 {
02137     return ( ChangeFDFlags(vRefNum, dirID, name, true, kIsInvisible) );
02138 }
02139 
02140 /*****************************************************************************/
02141 
02142 pascal  OSErr   FSpSetIsInvisible(const FSSpec *spec)
02143     /* Given a file or directory, make it invisible. */
02144 {
02145     return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kIsInvisible) );
02146 }
02147 
02148 /*****************************************************************************/
02149 
02150 pascal  OSErr   ClearIsInvisible(short vRefNum,
02151                                  long dirID,
02152                                  ConstStr255Param name)
02153     /* Given a file or directory, make it visible. */
02154 {
02155     return ( ChangeFDFlags(vRefNum, dirID, name, false, kIsInvisible) );
02156 }
02157 
02158 /*****************************************************************************/
02159 
02160 pascal  OSErr   FSpClearIsInvisible(const FSSpec *spec)
02161     /* Given a file or directory, make it visible. */
02162 {
02163     return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kIsInvisible) );
02164 }
02165 
02166 /*****************************************************************************/
02167 
02168 pascal  OSErr   SetNameLocked(short vRefNum,
02169                               long dirID,
02170                               ConstStr255Param name)
02171     /* Given a file or directory, lock its name. */
02172 {
02173     return ( ChangeFDFlags(vRefNum, dirID, name, true, kNameLocked) );
02174 }
02175 
02176 /*****************************************************************************/
02177 
02178 pascal  OSErr   FSpSetNameLocked(const FSSpec *spec)
02179     /* Given a file or directory, lock its name. */
02180 {
02181     return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kNameLocked) );
02182 }
02183 
02184 /*****************************************************************************/
02185 
02186 pascal  OSErr   ClearNameLocked(short vRefNum,
02187                                 long dirID,
02188                                 ConstStr255Param name)
02189     /* Given a file or directory, unlock its name. */
02190 {
02191     return ( ChangeFDFlags(vRefNum, dirID, name, false, kNameLocked) );
02192 }
02193 
02194 /*****************************************************************************/
02195 
02196 pascal  OSErr   FSpClearNameLocked(const FSSpec *spec)
02197     /* Given a file or directory, unlock its name. */
02198 {
02199     return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kNameLocked) );
02200 }
02201 
02202 /*****************************************************************************/
02203 
02204 pascal  OSErr   SetIsStationery(short vRefNum,
02205                                 long dirID,
02206                                 ConstStr255Param name)
02207     /* Given a file, make it a stationery pad. */
02208 {
02209     return ( ChangeFDFlags(vRefNum, dirID, name, true, kIsStationery) );
02210 }
02211 
02212 /*****************************************************************************/
02213 
02214 pascal  OSErr   FSpSetIsStationery(const FSSpec *spec)
02215     /* Given a file, make it a stationery pad. */
02216 {
02217     return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kIsStationery) );
02218 }
02219 
02220 /*****************************************************************************/
02221 
02222 pascal  OSErr   ClearIsStationery(short vRefNum,
02223                                   long dirID,
02224                                   ConstStr255Param name)
02225     /* Given a file, clear the stationery bit. */
02226 {
02227     return ( ChangeFDFlags(vRefNum, dirID, name, false, kIsStationery) );
02228 }
02229 
02230 /*****************************************************************************/
02231 
02232 pascal  OSErr   FSpClearIsStationery(const FSSpec *spec)
02233     /* Given a file, clear the stationery bit. */
02234 {
02235     return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kIsStationery) );
02236 }
02237 
02238 /*****************************************************************************/
02239 
02240 pascal  OSErr   SetHasCustomIcon(short vRefNum,
02241                                  long dirID,
02242                                  ConstStr255Param name)
02243     /* Given a file or directory, indicate that it has a custom icon. */
02244 {
02245     return ( ChangeFDFlags(vRefNum, dirID, name, true, kHasCustomIcon) );
02246 }
02247 
02248 /*****************************************************************************/
02249 
02250 pascal  OSErr   FSpSetHasCustomIcon(const FSSpec *spec)
02251     /* Given a file or directory, indicate that it has a custom icon. */
02252 {
02253     return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kHasCustomIcon) );
02254 }
02255 
02256 /*****************************************************************************/
02257 
02258 pascal  OSErr   ClearHasCustomIcon(short vRefNum,
02259                                    long dirID,
02260                                    ConstStr255Param name)
02261     /* Given a file or directory, indicate that it does not have a custom icon. */
02262 {
02263     return ( ChangeFDFlags(vRefNum, dirID, name, false, kHasCustomIcon) );
02264 }
02265 
02266 /*****************************************************************************/
02267 
02268 pascal  OSErr   FSpClearHasCustomIcon(const FSSpec *spec)
02269     /* Given a file or directory, indicate that it does not have a custom icon. */
02270 {
02271     return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kHasCustomIcon) );
02272 }
02273 
02274 /*****************************************************************************/
02275 
02276 pascal  OSErr   ClearHasBeenInited(short vRefNum,
02277                                    long dirID,
02278                                    ConstStr255Param name)
02279     /* Given a file, clear its "has been inited" bit. */
02280 {
02281     return ( ChangeFDFlags(vRefNum, dirID, name, false, kHasBeenInited) );
02282 }
02283 
02284 /*****************************************************************************/
02285 
02286 pascal  OSErr   FSpClearHasBeenInited(const FSSpec *spec)
02287     /* Given a file, clear its "has been inited" bit. */
02288 {
02289     return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kHasBeenInited) );
02290 }
02291 
02292 /*****************************************************************************/
02293 
02294 pascal  OSErr   CopyFileMgrAttributes(short srcVRefNum,
02295                                       long srcDirID,
02296                                       ConstStr255Param srcName,
02297                                       short dstVRefNum,
02298                                       long dstDirID,
02299                                       ConstStr255Param dstName,
02300                                       Boolean copyLockBit)
02301 {
02302     UniversalFMPB pb;
02303     Str31 tempName;
02304     OSErr error;
02305     Boolean objectIsDirectory;
02306 
02307     pb.ciPB.hFileInfo.ioVRefNum = srcVRefNum;
02308     pb.ciPB.hFileInfo.ioDirID = srcDirID;
02309 
02310     /* Protection against File Sharing problem */
02311     if ( (srcName == NULL) || (srcName[0] == 0) )
02312     {
02313         tempName[0] = 0;
02314         pb.ciPB.hFileInfo.ioNamePtr = tempName;
02315         pb.ciPB.hFileInfo.ioFDirIndex = -1; /* use ioDirID */
02316     }
02317     else
02318     {
02319         pb.ciPB.hFileInfo.ioNamePtr = (StringPtr)srcName;
02320         pb.ciPB.hFileInfo.ioFDirIndex = 0;  /* use ioNamePtr and ioDirID */
02321     }
02322     error = PBGetCatInfoSync(&pb.ciPB);
02323     if ( error == noErr )
02324     {
02325         objectIsDirectory = ( (pb.ciPB.hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 );
02326         pb.ciPB.hFileInfo.ioVRefNum = dstVRefNum;
02327         pb.ciPB.hFileInfo.ioDirID = dstDirID;
02328         if ( (dstName != NULL) && (dstName[0] == 0) )
02329         {
02330             pb.ciPB.hFileInfo.ioNamePtr = NULL;
02331         }
02332         else
02333         {
02334             pb.ciPB.hFileInfo.ioNamePtr = (StringPtr)dstName;
02335         }
02336         /* don't copy the hasBeenInited bit */
02337         pb.ciPB.hFileInfo.ioFlFndrInfo.fdFlags = ( pb.ciPB.hFileInfo.ioFlFndrInfo.fdFlags & ~kHasBeenInited );
02338         error = PBSetCatInfoSync(&pb.ciPB);
02339         if ( (error == noErr) && (copyLockBit) && ((pb.ciPB.hFileInfo.ioFlAttrib & kioFlAttribLockedMask) != 0) )
02340         {
02341             pb.hPB.fileParam.ioFVersNum = 0;
02342             error = PBHSetFLockSync(&pb.hPB);
02343             if ( (error != noErr) && (objectIsDirectory) )
02344             {
02345                 error = noErr; /* ignore lock errors if destination is directory */
02346             }
02347         }
02348     }
02349     return ( error );
02350 }
02351 
02352 /*****************************************************************************/
02353 
02354 pascal  OSErr   FSpCopyFileMgrAttributes(const FSSpec *srcSpec,
02355                                          const FSSpec *dstSpec,
02356                                          Boolean copyLockBit)
02357 {
02358     return ( CopyFileMgrAttributes(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
02359                                    dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
02360                                    copyLockBit) );
02361 }
02362 
02363 /*****************************************************************************/
02364 
02365 pascal  OSErr   HOpenAware(short vRefNum,
02366                            long dirID,
02367                            ConstStr255Param fileName,
02368                            short denyModes,
02369                            short *refNum)
02370 {
02371     HParamBlockRec pb;
02372     OSErr error;
02373     GetVolParmsInfoBuffer volParmsInfo;
02374     long infoSize = sizeof(GetVolParmsInfoBuffer);
02375 
02376     pb.ioParam.ioMisc = NULL;
02377     pb.fileParam.ioFVersNum = 0;
02378     pb.fileParam.ioNamePtr = (StringPtr)fileName;
02379     pb.fileParam.ioVRefNum = vRefNum;
02380     pb.fileParam.ioDirID = dirID;
02381 
02382     /* get volume attributes */
02383     /* this preflighting is needed because Foreign File Access based file systems don't */
02384     /* return the correct error result to the OpenDeny call */
02385     error = HGetVolParms(fileName, vRefNum, &volParmsInfo, &infoSize);
02386     if ( (error == noErr) && hasOpenDeny(volParmsInfo) )
02387     {
02388         /* if volume supports OpenDeny, use it and return */
02389             pb.accessParam.ioDenyModes = denyModes;
02390             error = PBHOpenDenySync(&pb);
02391             *refNum = pb.ioParam.ioRefNum;
02392     }
02393     else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
02394     {
02395         /* OpenDeny isn't supported, so try File Manager Open functions */
02396         
02397         /* If request includes write permission, then see if the volume is */
02398         /* locked by hardware or software. The HFS file system doesn't check */
02399         /* for this when a file is opened - you only find out later when you */
02400         /* try to write and the write fails with a wPrErr or a vLckdErr. */
02401         
02402         if ( (denyModes & dmWr) != 0 )
02403         {
02404             error = CheckVolLock(fileName, vRefNum);
02405         }
02406         else
02407         {
02408             error = noErr;
02409         }
02410         
02411         if ( error == noErr )
02412         {
02413             /* Set File Manager permissions to closest thing possible */
02414             if ( (denyModes == dmWr) || (denyModes == dmRdWr) )
02415             {
02416                 pb.ioParam.ioPermssn = fsRdWrShPerm;
02417             }
02418             else
02419             {
02420                 pb.ioParam.ioPermssn = denyModes % 4;
02421             }
02422 
02423             error = PBHOpenDFSync(&pb);             /* Try OpenDF */
02424             if ( error == paramErr )
02425             {
02426                 error = PBHOpenSync(&pb);           /* OpenDF not supported, so try Open */
02427             }
02428             *refNum = pb.ioParam.ioRefNum;
02429         }
02430     }
02431     
02432     return ( error );
02433 }
02434 
02435 /*****************************************************************************/
02436 
02437 pascal  OSErr   FSpOpenAware(const FSSpec *spec,
02438                              short denyModes,
02439                              short *refNum)
02440 {
02441     return ( HOpenAware(spec->vRefNum, spec->parID, spec->name, denyModes, refNum) );
02442 }
02443 
02444 /*****************************************************************************/
02445 
02446 pascal  OSErr   HOpenRFAware(short vRefNum,
02447                              long dirID,
02448                              ConstStr255Param fileName,
02449                              short denyModes,
02450                              short *refNum)
02451 {
02452     HParamBlockRec pb;
02453     OSErr error;
02454     GetVolParmsInfoBuffer volParmsInfo;
02455     long infoSize = sizeof(GetVolParmsInfoBuffer);
02456 
02457     pb.ioParam.ioMisc = NULL;
02458     pb.fileParam.ioFVersNum = 0;
02459     pb.fileParam.ioNamePtr = (StringPtr)fileName;
02460     pb.fileParam.ioVRefNum = vRefNum;
02461     pb.fileParam.ioDirID = dirID;
02462 
02463     /* get volume attributes */
02464     /* this preflighting is needed because Foreign File Access based file systems don't */
02465     /* return the correct error result to the OpenRFDeny call */
02466     error = HGetVolParms(fileName, vRefNum, &volParmsInfo, &infoSize);
02467     if ( (error == noErr) && hasOpenDeny(volParmsInfo) )
02468     {
02469         /* if volume supports OpenRFDeny, use it and return */
02470         if ( hasOpenDeny(volParmsInfo) )
02471         {
02472             pb.accessParam.ioDenyModes = denyModes;
02473             error = PBHOpenRFDenySync(&pb);
02474             *refNum = pb.ioParam.ioRefNum;
02475         }
02476     }
02477     else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
02478     {
02479         /* OpenRFDeny isn't supported, so try File Manager OpenRF function */
02480         
02481         /* If request includes write permission, then see if the volume is */
02482         /* locked by hardware or software. The HFS file system doesn't check */
02483         /* for this when a file is opened - you only find out later when you */
02484         /* try to write and the write fails with a wPrErr or a vLckdErr. */
02485         
02486         if ( (denyModes & dmWr) != 0 )
02487         {
02488             error = CheckVolLock(fileName, vRefNum);
02489         }
02490         else
02491         {
02492             error = noErr;
02493         }
02494         
02495         if ( error == noErr )
02496         {
02497             /* Set File Manager permissions to closest thing possible */
02498             if ( (denyModes == dmWr) || (denyModes == dmRdWr) )
02499             {
02500                 pb.ioParam.ioPermssn = fsRdWrShPerm;
02501             }
02502             else
02503             {
02504                 pb.ioParam.ioPermssn = denyModes % 4;
02505             }
02506 
02507             error = PBHOpenRFSync(&pb);
02508             *refNum = pb.ioParam.ioRefNum;
02509         }
02510     }
02511 
02512     return ( error );
02513 }
02514 
02515 /*****************************************************************************/
02516 
02517 pascal  OSErr   FSpOpenRFAware(const FSSpec *spec,
02518                                short denyModes,
02519                                short *refNum)
02520 {
02521     return ( HOpenRFAware(spec->vRefNum, spec->parID, spec->name, denyModes, refNum) );
02522 }
02523 
02524 /*****************************************************************************/
02525 
02526 pascal  OSErr   FSReadNoCache(short refNum,
02527                               long *count,
02528                               void *buffPtr)
02529 {
02530     ParamBlockRec pb;
02531     OSErr error;
02532 
02533     pb.ioParam.ioRefNum = refNum;
02534     pb.ioParam.ioBuffer = (Ptr)buffPtr;
02535     pb.ioParam.ioReqCount = *count;
02536     pb.ioParam.ioPosMode = fsAtMark + noCacheMask;  /* fsAtMark + noCacheMask */
02537     pb.ioParam.ioPosOffset = 0;
02538     error = PBReadSync(&pb);
02539     *count = pb.ioParam.ioActCount;             /* always return count */
02540     return ( error );
02541 }
02542 
02543 /*****************************************************************************/
02544 
02545 pascal  OSErr   FSWriteNoCache(short refNum,
02546                                long *count,
02547                                const void *buffPtr)
02548 {
02549     ParamBlockRec pb;
02550     OSErr error;
02551 
02552     pb.ioParam.ioRefNum = refNum;
02553     pb.ioParam.ioBuffer = (Ptr)buffPtr;
02554     pb.ioParam.ioReqCount = *count;
02555     pb.ioParam.ioPosMode = fsAtMark + noCacheMask;  /* fsAtMark + noCacheMask */
02556     pb.ioParam.ioPosOffset = 0;
02557     error = PBWriteSync(&pb);
02558     *count = pb.ioParam.ioActCount;             /* always return count */
02559     return ( error );
02560 }
02561 
02562 /*****************************************************************************/
02563 
02564 /*
02565 **  See if numBytes bytes of buffer1 are equal to buffer2.
02566 */
02567 static  Boolean EqualMemory(const void *buffer1, const void *buffer2, unsigned long numBytes)
02568 {
02569     register unsigned char *b1 = (unsigned char *)buffer1;
02570     register unsigned char *b2 = (unsigned char *)buffer2;
02571 
02572     if ( b1 != b2 ) /* if buffer pointers are same, then they are equal */
02573     {
02574         while ( numBytes > 0 )
02575         {
02576             /* compare the bytes and then increment the pointers */
02577             if ( (*b1++ - *b2++) != 0 )
02578             {
02579                 return ( false );
02580             }
02581             --numBytes;
02582         }
02583     }
02584     
02585     return ( true );
02586 }
02587 
02588 /*****************************************************************************/
02589 
02590 /*
02591 **  Read any number of bytes from an open file using read-verify mode.
02592 **  The FSReadVerify function reads any number of bytes from an open file
02593 **  and verifies them against the data in the buffer pointed to by buffPtr.
02594 **  
02595 **  Because of a bug in the HFS file system, only non-block aligned parts of
02596 **  the read are verified against the buffer data and the rest is *copied*
02597 **  into the buffer.  Thus, you shouldn't verify against your original data;
02598 **  instead, you should verify against a copy of the original data and then
02599 **  compare the read-verified copy against the original data after calling
02600 **  FSReadVerify. That's why this function isn't exported - it needs the
02601 **  wrapper provided by FSWriteVerify.
02602 */
02603 static  OSErr   FSReadVerify(short refNum,
02604                              long *count,
02605                              void *buffPtr)
02606 {
02607     ParamBlockRec   pb;
02608     OSErr           result;
02609 
02610     pb.ioParam.ioRefNum = refNum;
02611     pb.ioParam.ioBuffer = (Ptr)buffPtr;
02612     pb.ioParam.ioReqCount = *count;
02613     pb.ioParam.ioPosMode = fsAtMark + rdVerify;
02614     pb.ioParam.ioPosOffset = 0;
02615     result = PBReadSync(&pb);
02616     *count = pb.ioParam.ioActCount;         /* always return count */
02617     return ( result );
02618 }
02619 
02620 /*****************************************************************************/
02621 
02622 pascal  OSErr   FSWriteVerify(short refNum,
02623                               long *count,
02624                               const void *buffPtr)
02625 {
02626     Ptr     verifyBuffer;
02627     long    position;
02628     long    bufferSize;
02629     long    byteCount;
02630     long    bytesVerified;
02631     Ptr     startVerify;
02632     OSErr   result;
02633     
02634     /*
02635     **  Allocate the verify buffer
02636     **  Try to get get a large enough buffer to verify in one pass.
02637     **  If that fails, use GetTempBuffer to get a buffer.
02638     */
02639     bufferSize = *count;
02640     verifyBuffer = NewPtr(bufferSize);
02641     if ( verifyBuffer == NULL )
02642     {
02643         verifyBuffer = GetTempBuffer(bufferSize, &bufferSize);
02644     }
02645     if ( verifyBuffer != NULL )
02646     {       
02647         /* Save the current position */
02648         result = GetFPos(refNum, &position);
02649         if ( result == noErr )
02650         {
02651             /* Write the data */
02652             result = FSWrite(refNum, count, buffPtr);
02653             if ( result == noErr )
02654             {
02655                 /* Restore the original position */
02656                 result = SetFPos(refNum, fsFromStart, position);
02657                 if ( result == noErr )
02658                 {
02659                     /*
02660                     **  *count          = total number of bytes to verify
02661                     **  bufferSize      = the size of the verify buffer
02662                     **  bytesVerified   = number of bytes verified
02663                     **  byteCount       = number of bytes to verify this pass
02664                     **  startVerify     = position in buffPtr
02665                     */
02666                     bytesVerified = 0;
02667                     startVerify = (Ptr)buffPtr;
02668                     while ( (bytesVerified < *count) && ( result == noErr ) )
02669                     {
02670                         if ( (*count - bytesVerified) > bufferSize )
02671                         {
02672                             byteCount = bufferSize;
02673                         }
02674                         else
02675                         {
02676                             byteCount = *count - bytesVerified;
02677                         }
02678                         /*
02679                         **  Copy the write buffer into the verify buffer.
02680                         **  This step is needed because the File Manager
02681                         **  compares the data in any non-block aligned
02682                         **  data at the beginning and end of the read-verify
02683                         **  request back into the file system's cache
02684                         **  to the data in verify Buffer. However, the
02685                         **  File Manager does not compare any full blocks
02686                         **  and instead copies them into the verify buffer
02687                         **  so we still have to compare the buffers again
02688                         **  after the read-verify request completes.
02689                         */
02690                         BlockMoveData(startVerify, verifyBuffer, byteCount);
02691                         
02692                         /* Read-verify the data back into the verify buffer */
02693                         result = FSReadVerify(refNum, &byteCount, verifyBuffer);
02694                         if ( result == noErr )
02695                         {
02696                             /* See if the buffers are the same */
02697                             if ( !EqualMemory(verifyBuffer, startVerify, byteCount) )
02698                             {
02699                                 result = ioErr;
02700                             }
02701                             startVerify += byteCount;
02702                             bytesVerified += byteCount;
02703                         }
02704                     }
02705                 }
02706             }
02707         }
02708         DisposePtr(verifyBuffer);
02709     }
02710     else
02711     {
02712         result = memFullErr;
02713     }
02714     return ( result );
02715 }
02716 
02717 /*****************************************************************************/
02718 
02719 pascal  OSErr   CopyFork(short srcRefNum,
02720                          short dstRefNum,
02721                          void *copyBufferPtr,
02722                          long copyBufferSize)
02723 {
02724     ParamBlockRec srcPB;
02725     ParamBlockRec dstPB;
02726     OSErr srcError;
02727     OSErr dstError;
02728 
02729     if ( (copyBufferPtr == NULL) || (copyBufferSize == 0) )
02730         return ( paramErr );
02731     
02732     srcPB.ioParam.ioRefNum = srcRefNum;
02733     dstPB.ioParam.ioRefNum = dstRefNum;
02734 
02735     /* preallocate the destination fork and */
02736     /* ensure the destination fork's EOF is correct after the copy */
02737     srcError = PBGetEOFSync(&srcPB);
02738     if ( srcError != noErr )
02739         return ( srcError );
02740     dstPB.ioParam.ioMisc = srcPB.ioParam.ioMisc;
02741     dstError = PBSetEOFSync(&dstPB);
02742     if ( dstError != noErr )
02743         return ( dstError );
02744 
02745     /* reset source fork's mark */
02746     srcPB.ioParam.ioPosMode = fsFromStart;
02747     srcPB.ioParam.ioPosOffset = 0;
02748     srcError = PBSetFPosSync(&srcPB);
02749     if ( srcError != noErr )
02750         return ( srcError );
02751 
02752     /* reset destination fork's mark */
02753     dstPB.ioParam.ioPosMode = fsFromStart;
02754     dstPB.ioParam.ioPosOffset = 0;
02755     dstError = PBSetFPosSync(&dstPB);
02756     if ( dstError != noErr )
02757         return ( dstError );
02758 
02759     /* set up fields that won't change in the loop */
02760     srcPB.ioParam.ioBuffer = (Ptr)copyBufferPtr;
02761     srcPB.ioParam.ioPosMode = fsAtMark + noCacheMask;/* fsAtMark + noCacheMask */
02762     /* If copyBufferSize is greater than 512 bytes, make it a multiple of 512 bytes */
02763     /* This will make writes on local volumes faster */
02764     if ( (copyBufferSize >= 512) && ((copyBufferSize & 0x1ff) != 0) )
02765     {
02766         srcPB.ioParam.ioReqCount = copyBufferSize & 0xfffffe00;
02767     }
02768     else
02769     {
02770         srcPB.ioParam.ioReqCount = copyBufferSize;
02771     }
02772     dstPB.ioParam.ioBuffer = (Ptr)copyBufferPtr;
02773     dstPB.ioParam.ioPosMode = fsAtMark + noCacheMask;/* fsAtMark + noCacheMask */
02774 
02775     while ( (srcError == noErr) && (dstError == noErr) )
02776     {
02777         srcError = PBReadSync(&srcPB);
02778         dstPB.ioParam.ioReqCount = srcPB.ioParam.ioActCount;
02779         dstError = PBWriteSync(&dstPB);
02780     }
02781 
02782     /* make sure there were no errors at the destination */
02783     if ( dstError != noErr )
02784         return ( dstError );
02785 
02786     /* make sure the only error at the source was eofErr */
02787     if ( srcError != eofErr )
02788         return ( srcError );
02789 
02790     return ( noErr );
02791 }
02792 
02793 /*****************************************************************************/
02794 
02795 pascal  OSErr   GetFileLocation(short refNum,
02796                                 short *vRefNum,
02797                                 long *dirID,
02798                                 StringPtr fileName)
02799 {
02800     FCBPBRec pb;
02801     OSErr error;
02802 
02803     pb.ioNamePtr = fileName;
02804     pb.ioVRefNum = 0;
02805     pb.ioRefNum = refNum;
02806     pb.ioFCBIndx = 0;
02807     error = PBGetFCBInfoSync(&pb);
02808     if ( error == noErr )
02809     {
02810         *vRefNum = pb.ioFCBVRefNum;
02811         *dirID = pb.ioFCBParID;
02812     }
02813     return ( error );
02814 }
02815 
02816 /*****************************************************************************/
02817 
02818 pascal  OSErr   FSpGetFileLocation(short refNum,
02819                                    FSSpec *spec)
02820 {
02821     return ( GetFileLocation(refNum, &(spec->vRefNum), &(spec->parID), spec->name) );
02822 }
02823 
02824 /*****************************************************************************/
02825 
02826 pascal  OSErr   CopyDirectoryAccess(short srcVRefNum,
02827                                     long srcDirID,
02828                                     ConstStr255Param srcName,
02829                                     short dstVRefNum,
02830                                     long dstDirID,
02831                                     ConstStr255Param dstName)
02832 {   
02833     OSErr error;
02834     GetVolParmsInfoBuffer infoBuffer;   /* Where PBGetVolParms dumps its info */
02835     long    dstServerAdr;               /* AppleTalk server address of destination (if any) */
02836     long    ownerID, groupID, accessRights;
02837     long    tempLong;
02838 
02839     /* See if destination supports directory access control */
02840     tempLong = sizeof(infoBuffer);
02841     error = HGetVolParms(dstName, dstVRefNum, &infoBuffer, &tempLong);
02842     if ( (error == noErr) && hasAccessCntl(infoBuffer) )
02843     {
02844         if ( hasAccessCntl(infoBuffer) )
02845         {
02846             dstServerAdr = infoBuffer.vMServerAdr;
02847             
02848             /* See if source supports directory access control and is on same server */
02849             tempLong = sizeof(infoBuffer);
02850             error = HGetVolParms(srcName, srcVRefNum, &infoBuffer, &tempLong);
02851             if ( error == noErr )
02852             {
02853                 if ( hasAccessCntl(infoBuffer) && (dstServerAdr == infoBuffer.vMServerAdr) )
02854                 {
02855                     /* both volumes support directory access control and they are */
02856                     /*  on same server, so copy the access information */
02857                     error = HGetDirAccess(srcVRefNum, srcDirID, srcName, &ownerID, &groupID, &accessRights);
02858                     if ( error == noErr )
02859                     {
02860                         error = HSetDirAccess(dstVRefNum, dstDirID, dstName, ownerID, groupID, accessRights);
02861                     }
02862                 }
02863                 else
02864                 {
02865                     /* destination doesn't support directory access control or */
02866                     /* they volumes aren't on the same server */
02867                     error = paramErr;
02868                 }
02869             }
02870         }
02871         else
02872         {
02873             /* destination doesn't support directory access control */
02874             error = paramErr;
02875         }
02876     }
02877     
02878     return ( error );
02879 }
02880 
02881 /*****************************************************************************/
02882 
02883 pascal  OSErr   FSpCopyDirectoryAccess(const FSSpec *srcSpec,
02884                                        const FSSpec *dstSpec)
02885 {
02886     return ( CopyDirectoryAccess(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
02887                                 dstSpec->vRefNum, dstSpec->parID, dstSpec->name) );
02888 }
02889 
02890 /*****************************************************************************/
02891 
02892 pascal  OSErr   HMoveRenameCompat(short vRefNum,
02893                                   long srcDirID,
02894                                   ConstStr255Param srcName,
02895                                   long dstDirID,
02896                                   ConstStr255Param dstpathName,
02897                                   ConstStr255Param copyName)
02898 {
02899     OSErr                   error;
02900     GetVolParmsInfoBuffer   volParmsInfo;
02901     long                    infoSize;
02902     short                   realVRefNum;
02903     long                    realParID;
02904     Str31                   realName;
02905     Boolean                 isDirectory;
02906     long                    tempItemsDirID;
02907     long                    uniqueTempDirID;
02908     Str31                   uniqueTempDirName;
02909     unsigned short          uniqueNameoverflow;
02910     
02911     /* Get volume attributes */
02912     infoSize = sizeof(GetVolParmsInfoBuffer);
02913     error = HGetVolParms((StringPtr)srcName, vRefNum, &volParmsInfo, &infoSize);
02914     if ( (error == noErr) && hasMoveRename(volParmsInfo) )
02915     {
02916         /* If volume supports move and rename, so use it and return */
02917         error = HMoveRename(vRefNum, srcDirID, srcName, dstDirID, dstpathName, copyName);
02918     }
02919     else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
02920     {
02921         /* MoveRename isn't supported by this volume, so do it by hand */
02922         
02923         /* If copyName isn't supplied, we can simply CatMove and return */
02924         if ( copyName == NULL )
02925         {
02926             error = CatMove(vRefNum, srcDirID, srcName, dstDirID, dstpathName);
02927         }
02928         else
02929         {
02930             /* Renaming is required, so we have some work to do... */
02931             
02932             /* Get the object's real name, real parent ID and real vRefNum */
02933             error = GetObjectLocation(vRefNum, srcDirID, (StringPtr)srcName,
02934                                         &realVRefNum, &realParID, realName, &isDirectory);
02935             if ( error == noErr )
02936             {
02937                 /* Find the Temporary Items Folder on that volume */
02938                 error = FindFolder(realVRefNum, kTemporaryFolderType, kCreateFolder,
02939                                     &realVRefNum, &tempItemsDirID);
02940                 if ( error == noErr )
02941                 {
02942                     /* Create a new uniquely named folder in the temporary items folder. */
02943                     /* This is done to avoid the case where 'realName' or 'copyName' already */
02944                     /* exists in the temporary items folder. */
02945                     
02946                     /* Start with current tick count as uniqueTempDirName */                    
02947                     NumToString(TickCount(), uniqueTempDirName);
02948                     uniqueNameoverflow = 0;
02949                     do
02950                     {
02951                         error = DirCreate(realVRefNum, tempItemsDirID, uniqueTempDirName, &uniqueTempDirID);
02952                         if ( error == dupFNErr )
02953                         {
02954                             /* Duplicate name - change the first character to the next ASCII character */
02955                             ++uniqueTempDirName[1];
02956                             /* Make sure it isn't a colon! */
02957                             if ( uniqueTempDirName[1] == ':' )
02958                             {
02959                                 ++uniqueTempDirName[1];
02960                             }
02961                             /* Don't go too far... */
02962                             ++uniqueNameoverflow;
02963                         }
02964                     } while ( (error == dupFNErr) && (uniqueNameoverflow <= 64) ); /* 64 new files per 1/60th second - not likely! */
02965                     if ( error == noErr )
02966                     {
02967                         /* Move the object to the folder with uniqueTempDirID for renaming */
02968                         error = CatMove(realVRefNum, realParID, realName, uniqueTempDirID, NULL);
02969                         if ( error == noErr )
02970                         {
02971                             /* Rename the object */ 
02972                             error = HRename(realVRefNum, uniqueTempDirID, realName, copyName);
02973                             if ( error == noErr )
02974                             {
02975                                 /* Move object to its new home */
02976                                 error = CatMove(realVRefNum, uniqueTempDirID, copyName, dstDirID, dstpathName);
02977                                 if ( error != noErr )
02978                                 {
02979                                     /* Error handling: rename object back to original name - ignore errors */
02980                                     (void) HRename(realVRefNum, uniqueTempDirID, copyName, realName);
02981                                 }
02982                             }
02983                             if ( error != noErr )
02984                             {
02985                                 /* Error handling: move object back to original location - ignore errors */
02986                                 (void) CatMove(realVRefNum, uniqueTempDirID, realName, realParID, NULL);
02987                             }
02988                         }
02989                         /* Done with ourTempDir, so delete it - ignore errors */
02990                         (void) HDelete(realVRefNum, uniqueTempDirID, NULL);
02991                     }
02992                 }
02993             }
02994         }
02995     }
02996     
02997     return ( error );
02998 }
02999 
03000 /*****************************************************************************/
03001 
03002 pascal  OSErr   FSpMoveRenameCompat(const FSSpec *srcSpec,
03003                                     const FSSpec *dstSpec,
03004                                     ConstStr255Param copyName)
03005 {
03006     /* make sure the FSSpecs refer to the same volume */
03007     if (srcSpec->vRefNum != dstSpec->vRefNum)
03008         return (diffVolErr);
03009     return ( HMoveRenameCompat(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
03010                       dstSpec->parID, dstSpec->name, copyName) );
03011 }
03012 
03013 /*****************************************************************************/
03014 
03015 pascal  OSErr   BuildAFPVolMountInfo(short flags,
03016                                      char nbpInterval,
03017                                      char nbpCount,
03018                                      short uamType,
03019                                      Str32 zoneName,
03020                                      Str32 serverName,
03021                                      Str27 volName,
03022                                      Str31 userName,
03023                                      Str8 userPassword,
03024                                      Str8 volPassword,
03025                                      AFPVolMountInfoPtr *afpInfoPtr)
03026 {
03027     MyAFPVolMountInfoPtr    infoPtr;
03028     OSErr                   error;
03029     
03030     /* Allocate the AFPXVolMountInfo record */
03031     infoPtr = (MyAFPVolMountInfoPtr)NewPtrClear(sizeof(MyAFPVolMountInfo));
03032     if ( infoPtr != NULL )
03033     {
03034         /* Fill in an AFPVolMountInfo record that can be passed to VolumeMount */
03035         infoPtr->length = sizeof(MyAFPVolMountInfo);
03036         infoPtr->media = AppleShareMediaType;
03037         infoPtr->flags = flags;
03038         infoPtr->nbpInterval = nbpInterval;
03039         infoPtr->nbpCount = nbpCount;
03040         infoPtr->uamType = uamType;
03041         
03042         infoPtr->zoneNameOffset = offsetof(MyAFPVolMountInfo, zoneName);
03043         infoPtr->serverNameOffset = offsetof(MyAFPVolMountInfo, serverName);
03044         infoPtr->volNameOffset = offsetof(MyAFPVolMountInfo, volName);
03045         infoPtr->userNameOffset = offsetof(MyAFPVolMountInfo, userName);
03046         infoPtr->userPasswordOffset = offsetof(MyAFPVolMountInfo, userPassword);
03047         infoPtr->volPasswordOffset = offsetof(MyAFPVolMountInfo, volPassword);
03048         
03049         BlockMoveData(zoneName, infoPtr->zoneName, sizeof(Str32));
03050         BlockMoveData(serverName, infoPtr->serverName, sizeof(Str32));
03051         BlockMoveData(volName, infoPtr->volName, sizeof(Str27));
03052         BlockMoveData(userName, infoPtr->userName, sizeof(Str31));
03053         BlockMoveData(userPassword, infoPtr->userPassword, sizeof(Str8));
03054         BlockMoveData(volPassword, infoPtr->volPassword, sizeof(Str8));
03055         
03056         *afpInfoPtr = (AFPVolMountInfoPtr)infoPtr;
03057         error = noErr;
03058     }
03059     else
03060     {
03061         error = memFullErr;
03062     }
03063     
03064     return ( error );
03065 }
03066 
03067 /*****************************************************************************/
03068 
03069 pascal  OSErr   RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr,
03070                                         short *flags,
03071                                         short *uamType,
03072                                         StringPtr zoneName,
03073                                         StringPtr serverName,
03074                                         StringPtr volName,
03075                                         StringPtr userName)
03076 {
03077     StringPtr   tempPtr;
03078     OSErr       error;
03079         
03080     /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
03081     if ( afpInfoPtr->media == AppleShareMediaType )
03082     {
03083         *flags = afpInfoPtr->flags;
03084         *uamType = afpInfoPtr->uamType;
03085         
03086         if ( afpInfoPtr->zoneNameOffset != 0)
03087         {
03088             tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->zoneNameOffset);
03089             BlockMoveData(tempPtr, zoneName, tempPtr[0] + 1);
03090         }
03091         
03092         if ( afpInfoPtr->serverNameOffset != 0)
03093         {
03094             tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->serverNameOffset);
03095             BlockMoveData(tempPtr, serverName, tempPtr[0] + 1);
03096         }
03097         
03098         if ( afpInfoPtr->volNameOffset != 0)
03099         {
03100             tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->volNameOffset);
03101             BlockMoveData(tempPtr, volName, tempPtr[0] + 1);
03102         }
03103         
03104         if ( afpInfoPtr->userNameOffset != 0)
03105         {
03106             tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->userNameOffset);
03107             BlockMoveData(tempPtr, userName, tempPtr[0] + 1);
03108         }
03109         
03110         error = noErr;
03111     }
03112     else
03113     {
03114         error = paramErr;
03115     }
03116     
03117     return ( error );
03118 }
03119 
03120 /*****************************************************************************/
03121 
03122 pascal  OSErr   BuildAFPXVolMountInfo(short flags,
03123                                       char nbpInterval,
03124                                       char nbpCount,
03125                                       short uamType,
03126                                       Str32 zoneName,
03127                                       Str32 serverName,
03128                                       Str27 volName,
03129                                       Str31 userName,
03130                                       Str8 userPassword,
03131                                       Str8 volPassword,
03132                                       Str32 uamName,
03133                                       unsigned long alternateAddressLength,
03134                                       void *alternateAddress,
03135                                       AFPXVolMountInfoPtr *afpXInfoPtr)
03136 {
03137     Size                    infoSize;
03138     MyAFPXVolMountInfoPtr   infoPtr;
03139     OSErr                   error;
03140     
03141     /* Calculate the size of the AFPXVolMountInfo record */
03142     infoSize = sizeof(MyAFPXVolMountInfo) + alternateAddressLength - 1;
03143     
03144     /* Allocate the AFPXVolMountInfo record */
03145     infoPtr = (MyAFPXVolMountInfoPtr)NewPtrClear(infoSize);
03146     if ( infoPtr != NULL )
03147     {
03148         /* Fill in an AFPXVolMountInfo record that can be passed to VolumeMount */
03149         infoPtr->length = infoSize;
03150         infoPtr->media = AppleShareMediaType;
03151         infoPtr->flags = flags;
03152         if ( alternateAddressLength != 0 )
03153         {
03154             /* make sure the volMountExtendedFlagsBit is set if there's extended address info */
03155             infoPtr->flags |= volMountExtendedFlagsMask;
03156             /* and set the only extendedFlags bit we know about */
03157             infoPtr->extendedFlags = kAFPExtendedFlagsAlternateAddressMask;
03158         }
03159         else
03160         {
03161             /* make sure the volMountExtendedFlagsBit is clear if there's no extended address info */
03162             infoPtr->flags &= ~volMountExtendedFlagsMask;
03163             /* and clear the extendedFlags */
03164             infoPtr->extendedFlags = 0;
03165         }
03166         infoPtr->nbpInterval = nbpInterval;
03167         infoPtr->nbpCount = nbpCount;
03168         infoPtr->uamType = uamType;
03169         
03170         infoPtr->zoneNameOffset = offsetof(MyAFPXVolMountInfo, zoneName);       
03171         infoPtr->serverNameOffset = offsetof(MyAFPXVolMountInfo, serverName);
03172         infoPtr->volNameOffset = offsetof(MyAFPXVolMountInfo, volName);
03173         infoPtr->userNameOffset = offsetof(MyAFPXVolMountInfo, userName);
03174         infoPtr->userPasswordOffset = offsetof(MyAFPXVolMountInfo, userPassword);
03175         infoPtr->volPasswordOffset = offsetof(MyAFPXVolMountInfo, volPassword);
03176         infoPtr->uamNameOffset = offsetof(MyAFPXVolMountInfo, uamName);
03177         infoPtr->alternateAddressOffset = offsetof(MyAFPXVolMountInfo, alternateAddress);
03178         
03179         BlockMoveData(zoneName, infoPtr->zoneName, sizeof(Str32));
03180         BlockMoveData(serverName, infoPtr->serverName, sizeof(Str32));
03181         BlockMoveData(volName, infoPtr->volName, sizeof(Str27));
03182         BlockMoveData(userName, infoPtr->userName, sizeof(Str31));
03183         BlockMoveData(userPassword, infoPtr->userPassword, sizeof(Str8));
03184         BlockMoveData(volPassword, infoPtr->volPassword, sizeof(Str8));
03185         BlockMoveData(uamName, infoPtr->uamName, sizeof(Str32));
03186         BlockMoveData(alternateAddress, infoPtr->alternateAddress, alternateAddressLength);
03187         
03188         *afpXInfoPtr = (AFPXVolMountInfoPtr)infoPtr;
03189         error = noErr;
03190     }
03191     else
03192     {
03193         error = memFullErr;
03194     }
03195     
03196     return ( error );
03197 }
03198 
03199 /*****************************************************************************/
03200 
03201 pascal  OSErr   RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr,
03202                                          short *flags,
03203                                          short *uamType,
03204                                          StringPtr zoneName,
03205                                          StringPtr serverName,
03206                                          StringPtr volName,
03207                                          StringPtr userName,
03208                                          StringPtr uamName,
03209                                          unsigned long *alternateAddressLength,
03210                                          AFPAlternateAddress **alternateAddress)
03211 {
03212     StringPtr   tempPtr;
03213     Ptr         alternateAddressStart;
03214     Ptr         alternateAddressEnd;
03215     Size        alternateAddressDataSize;
03216     OSErr       error;
03217     UInt8       addressCount;
03218         
03219     /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
03220     if ( afpXInfoPtr->media == AppleShareMediaType )
03221     {
03222         /* default to noErr */
03223         error = noErr;
03224         
03225         /* Is this an extended record? */
03226         if ( (afpXInfoPtr->flags & volMountExtendedFlagsMask) != 0 )
03227         {
03228             if ( ((afpXInfoPtr->extendedFlags & kAFPExtendedFlagsAlternateAddressMask) != 0) &&
03229                  (afpXInfoPtr->alternateAddressOffset != 0) )
03230             {
03231                 
03232                 alternateAddressStart = (Ptr)((long)afpXInfoPtr + afpXInfoPtr->alternateAddressOffset);
03233                 alternateAddressEnd = alternateAddressStart + 1;    /* skip over alternate address version byte */
03234                 addressCount = *(UInt8*)alternateAddressEnd;        /* get the address count */
03235                 ++alternateAddressEnd;                              /* skip over alternate address count byte */
03236                 /* alternateAddressEnd now equals &AFPAlternateAddress.fAddressList[0] */
03237                 while ( addressCount != 0 )
03238                 {
03239                     /* parse the address list to find the end */
03240                     alternateAddressEnd += *(UInt8*)alternateAddressEnd;    /* add length of each AFPTagData record */
03241                     --addressCount;
03242                 }
03243                 /* get the size of the alternateAddressData */
03244                 alternateAddressDataSize = alternateAddressEnd - alternateAddressStart;
03245                 /* allocate memory for it */
03246                 *alternateAddress = (AFPAlternateAddress *)NewPtr(alternateAddressDataSize);
03247                 if ( *alternateAddress != NULL )
03248                 {
03249                     /* and return the data */
03250                     BlockMoveData(alternateAddressStart, *alternateAddress, alternateAddressDataSize);
03251                     *alternateAddressLength = alternateAddressDataSize;
03252                 }
03253                 else
03254                 {
03255                     /* no memory - fail now */
03256                     error = memFullErr;
03257                 }
03258             }
03259             
03260             if ( error == noErr )   /* fill in more output parameters if everything is OK */
03261             {
03262                 if ( afpXInfoPtr->uamNameOffset != 0 )
03263                 {
03264                     tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->uamNameOffset);
03265                     BlockMoveData(tempPtr, uamName, tempPtr[0] + 1);
03266                 }
03267             }
03268         }
03269         
03270         if ( error == noErr )   /* fill in more output parameters if everything is OK */
03271         {
03272             *flags = afpXInfoPtr->flags;
03273             *uamType = afpXInfoPtr->uamType;
03274             
03275             if ( afpXInfoPtr->zoneNameOffset != 0 )
03276             {
03277                 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->zoneNameOffset);
03278                 BlockMoveData(tempPtr, zoneName, tempPtr[0] + 1);
03279             }
03280             
03281             if ( afpXInfoPtr->serverNameOffset != 0 )
03282             {
03283                 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->serverNameOffset);
03284                 BlockMoveData(tempPtr, serverName, tempPtr[0] + 1);
03285             }
03286             
03287             if ( afpXInfoPtr->volNameOffset != 0 )
03288             {
03289                 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->volNameOffset);
03290                 BlockMoveData(tempPtr, volName, tempPtr[0] + 1);
03291             }
03292             
03293             if ( afpXInfoPtr->userNameOffset != 0 )
03294             {
03295                 tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->userNameOffset);
03296                 BlockMoveData(tempPtr, userName, tempPtr[0] + 1);
03297             }
03298         }
03299     }
03300     else
03301     {
03302         error = paramErr;
03303     }
03304     
03305     return ( error );
03306 }
03307 
03308 /*****************************************************************************/
03309 
03310 pascal  OSErr   GetUGEntries(short objType,
03311                              UGEntryPtr entries,
03312                              long reqEntryCount,
03313                              long *actEntryCount,
03314                              long *objID)
03315 {
03316     HParamBlockRec pb;
03317     OSErr error = noErr;
03318     UGEntry *endEntryArray;
03319 
03320     pb.objParam.ioObjType = objType;
03321     *actEntryCount = 0;
03322     for ( endEntryArray = entries + reqEntryCount; (entries < endEntryArray) && (error == noErr); ++entries )
03323     {
03324         pb.objParam.ioObjNamePtr = (StringPtr)entries->name;
03325         pb.objParam.ioObjID = *objID;
03326         /* Files.h in the universal interfaces, PBGetUGEntrySync takes a CMovePBPtr */
03327         /* as the parameter. Inside Macintosh and the original glue used HParmBlkPtr. */
03328         /* A CMovePBPtr works OK, but this will be changed in the future  back to */
03329         /* HParmBlkPtr, so I'm just casting it here. */
03330         error = PBGetUGEntrySync(&pb);
03331         if ( error == noErr )
03332         {
03333             entries->objID = *objID = pb.objParam.ioObjID;
03334             entries->objType = objType;
03335             ++*actEntryCount;
03336         }
03337     }
03338     
03339     return ( error );
03340 }
03341 
03342 /*****************************************************************************/
03343 

Generated on Wed May 31 18:19:55 2006 for frontierkernel 10.1.10a by  doxygen 1.4.6