]> git.saurik.com Git - wxWidgets.git/commitdiff
latest CW additions
authorStefan Csomor <csomor@advancedconcepts.ch>
Mon, 1 Feb 1999 15:43:00 +0000 (15:43 +0000)
committerStefan Csomor <csomor@advancedconcepts.ch>
Mon, 1 Feb 1999 15:43:00 +0000 (15:43 +0000)
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@1561 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

22 files changed:
samples/minimal/make_cw.mcp
src/mac/morefile/Director.cpp [new file with mode: 0644]
src/mac/morefile/Director.h [new file with mode: 0644]
src/mac/morefile/FSpCompa.cpp [new file with mode: 0644]
src/mac/morefile/FSpCompa.h [new file with mode: 0644]
src/mac/morefile/FileCopy.cpp [new file with mode: 0644]
src/mac/morefile/FileCopy.h [new file with mode: 0644]
src/mac/morefile/FullPath.cpp [new file with mode: 0644]
src/mac/morefile/FullPath.h [new file with mode: 0644]
src/mac/morefile/IterateD.cpp [new file with mode: 0644]
src/mac/morefile/IterateD.h [new file with mode: 0644]
src/mac/morefile/MoreDesk.cpp [new file with mode: 0644]
src/mac/morefile/MoreDesk.h [new file with mode: 0644]
src/mac/morefile/MoreExtr.cpp [new file with mode: 0644]
src/mac/morefile/MoreExtr.h [new file with mode: 0644]
src/mac/morefile/MoreFile.cpp [new file with mode: 0644]
src/mac/morefile/MoreFile.h [new file with mode: 0644]
src/mac/morefile/Optim.h [new file with mode: 0644]
src/mac/morefile/OptimEnd.h [new file with mode: 0644]
src/mac/morefile/Search.cpp [new file with mode: 0644]
src/mac/morefile/Search.h [new file with mode: 0644]
src/make_cw.mcp

index 3450e5aa43d419576670b3294ab07be5d062c95c..38041ef961f2aed0fa349f56007aa80df208e0cb 100644 (file)
Binary files a/samples/minimal/make_cw.mcp and b/samples/minimal/make_cw.mcp differ
diff --git a/src/mac/morefile/Director.cpp b/src/mac/morefile/Director.cpp
new file mode 100644 (file)
index 0000000..f8b0d0a
--- /dev/null
@@ -0,0 +1,653 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     DirectoryCopy: A robust, general purpose directory copy routine.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           DirectoryCopy.c
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#include <Types.h>
+#include <Errors.h>
+#include <Memory.h>
+#include <Files.h>
+#include <Script.h>
+
+#define        __COMPILINGMOREFILES
+
+#include "MoreFile.h"
+#include "MoreExtr.h"
+#include "MoreDesk.h"
+#include "FileCopy.h"
+#include "Director.h"
+
+/*****************************************************************************/
+
+/* local constants */
+
+enum
+{
+       dirCopyBigCopyBuffSize  = 0x00004000,
+       dirCopyMinCopyBuffSize  = 0x00000200
+};
+
+
+/*****************************************************************************/
+
+/* local data structures */
+
+/* The EnumerateGlobals structure is used to minimize the amount of
+** stack space used when recursively calling CopyLevel and to hold
+** global information that might be needed at any time. */
+
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=mac68k
+#endif
+struct EnumerateGlobals
+{
+       Ptr                     copyBuffer;                     /* pointer to buffer used for file copy operations */
+       long            bufferSize;                     /* the size of the copy buffer */
+       CopyErrProcPtr errorHandler;    /* pointer to error handling function */
+       CopyFilterProcPtr copyFilterProc; /* pointer to filter function */
+       OSErr           error;                          /* temporary holder of results - saves 2 bytes of stack each level */
+       Boolean         bailout;                        /* set to true to by error handling function if fatal error */
+       short           destinationVRefNum;     /* the destination vRefNum */
+       Str63           itemName;                       /* the name of the current item */
+       CInfoPBRec      myCPB;                          /* the parameter block used for PBGetCatInfo calls */
+};
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=reset
+#endif
+
+typedef struct EnumerateGlobals EnumerateGlobals;
+typedef EnumerateGlobals *EnumerateGlobalsPtr;
+
+
+/* The PreflightGlobals structure is used to minimize the amount of
+** stack space used when recursively calling GetLevelSize and to hold
+** global information that might be needed at any time. */
+
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=mac68k
+#endif
+struct PreflightGlobals
+{
+       OSErr                   result;                         /* temporary holder of results - saves 2 bytes of stack each level */
+       Str63                   itemName;                       /* the name of the current item */
+       CInfoPBRec              myCPB;                          /* the parameter block used for PBGetCatInfo calls */
+
+       unsigned long   dstBlksPerAllocBlk;     /* the number of 512 byte blocks per allocation block on destination */
+                                                                               
+       unsigned long   allocBlksNeeded;        /* the total number of allocation blocks needed  */
+
+       unsigned long   tempBlocks;                     /* temporary storage for calculations (save some stack space)  */
+       CopyFilterProcPtr copyFilterProc;       /* pointer to filter function */
+};
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=reset
+#endif
+
+typedef struct PreflightGlobals PreflightGlobals;
+typedef PreflightGlobals *PreflightGlobalsPtr;
+
+/*****************************************************************************/
+
+/* static prototypes */
+
+static void    GetLevelSize(long currentDirID,
+                                                        PreflightGlobals *theGlobals);
+
+static OSErr   PreflightDirectoryCopySpace(short srcVRefNum,
+                                                                                       long srcDirID,
+                                                                                       short dstVRefNum,
+                                                                                       CopyFilterProcPtr copyFilterProc,
+                                                                                       Boolean *spaceOK);
+
+static void    CopyLevel(long sourceDirID,
+                                                 long dstDirID,
+                                                 EnumerateGlobals *theGlobals);
+                                                 
+/*****************************************************************************/
+
+static void    GetLevelSize(long currentDirID,
+                                                        PreflightGlobals *theGlobals)
+{
+       short   index = 1;
+       
+       do
+       {
+               theGlobals->myCPB.dirInfo.ioFDirIndex = index;
+               theGlobals->myCPB.dirInfo.ioDrDirID = currentDirID;     /* we need to do this every time */
+                                                                                                                       /* through, since GetCatInfo  */
+                                                                                                                       /* returns ioFlNum in this field */
+               theGlobals->result = PBGetCatInfoSync(&theGlobals->myCPB);
+               if ( theGlobals->result == noErr )
+               {
+                       if ( (theGlobals->copyFilterProc == NULL) ||
+                                CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */
+                       {
+                               /* Either there's no filter proc OR the filter proc says to use this item */
+                               if ( (theGlobals->myCPB.dirInfo.ioFlAttrib & ioDirMask) != 0 )
+                               {
+                                       /* we have a directory */
+                                       
+                                       GetLevelSize(theGlobals->myCPB.dirInfo.ioDrDirID, theGlobals); /* recurse */
+                                       theGlobals->result = noErr; /* clear error return on way back */
+                               }
+                               else
+                               {
+                                       /* We have a file - add its allocation blocks to allocBlksNeeded. */
+                                       /* Since space on Mac OS disks is always allocated in allocation blocks, */
+                                       /* this takes into account rounding up to the end of an allocation block. */
+                                       
+                                       /* get number of 512-byte blocks needed for data fork */
+                                       if ( ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen & 0x000001ff) != 0 )
+                                       {
+                                               theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9) + 1;
+                                       }
+                                       else
+                                       {
+                                               theGlobals->tempBlocks = (unsigned long)theGlobals->myCPB.hFileInfo.ioFlLgLen >> 9;
+                                       }
+                                       /* now, calculate number of new allocation blocks needed for the data fork and add it to the total */
+                                       if ( theGlobals->tempBlocks % theGlobals->dstBlksPerAllocBlk )
+                                       {
+                                               theGlobals->allocBlksNeeded += (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1;
+                                       }
+                                       else
+                                       {
+                                               theGlobals->allocBlksNeeded += theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk;
+                                       }
+                                       
+                                       /* get number of 512-byte blocks needed for resource fork */
+                                       if ( ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen & 0x000001ff) != 0 )
+                                       {
+                                               theGlobals->tempBlocks = ((unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9) + 1;
+                                       }
+                                       else
+                                       {
+                                               theGlobals->tempBlocks = (unsigned long)theGlobals->myCPB.hFileInfo.ioFlRLgLen >> 9;
+                                       }
+                                       /* now, calculate number of new allocation blocks needed for the resource  fork and add it to the total */
+                                       if ( theGlobals->tempBlocks % theGlobals->dstBlksPerAllocBlk )
+                                       {
+                                               theGlobals->allocBlksNeeded += (theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk) + 1;
+                                       }
+                                       else
+                                       {
+                                               theGlobals->allocBlksNeeded += theGlobals->tempBlocks / theGlobals->dstBlksPerAllocBlk;
+                                       }
+                               }
+                       }
+               }
+               ++index;
+       } while ( theGlobals->result == noErr );
+}
+
+/*****************************************************************************/
+
+static OSErr   PreflightDirectoryCopySpace(short srcVRefNum,
+                                                                                       long srcDirID,
+                                                                                       short dstVRefNum,
+                                                                                       CopyFilterProcPtr copyFilterProc,
+                                                                                       Boolean *spaceOK)
+{
+       XVolumeParam pb;
+       OSErr error;
+       unsigned long dstFreeBlocks;
+       PreflightGlobals theGlobals;
+       
+       error = XGetVolumeInfoNoName(NULL, dstVRefNum, &pb);
+       if ( error == noErr )
+       {
+               /* Convert freeBytes to free disk blocks (512-byte blocks) */
+               dstFreeBlocks = (pb.ioVFreeBytes.hi << 23) + (pb.ioVFreeBytes.lo >> 9);
+               
+               /* get allocation block size (always multiple of 512) and divide by 512
+                 to get number of 512-byte blocks per allocation block */
+               theGlobals.dstBlksPerAllocBlk = ((unsigned long)pb.ioVAlBlkSiz >> 9);
+               
+               theGlobals.allocBlksNeeded = 0;
+
+               theGlobals.myCPB.dirInfo.ioNamePtr = theGlobals.itemName;
+               theGlobals.myCPB.dirInfo.ioVRefNum = srcVRefNum;
+               
+               theGlobals.copyFilterProc = copyFilterProc;
+               
+               GetLevelSize(srcDirID, &theGlobals);
+               
+               /* Is there enough room on the destination volume for the source file?                                  */
+               /* Note:        This will work because the largest number of disk blocks supported                      */
+               /*                      on a 2TB volume is 0xffffffff and (allocBlksNeeded * dstBlksPerAllocBlk)        */
+               /*                      will always be less than 0xffffffff.                                                                            */
+               *spaceOK = ((theGlobals.allocBlksNeeded * theGlobals.dstBlksPerAllocBlk) <= dstFreeBlocks);
+       }
+
+       return ( error );
+}
+
+/*****************************************************************************/
+
+static void    CopyLevel(long sourceDirID,
+                                                 long dstDirID,
+                                                 EnumerateGlobals *theGlobals)
+{
+       long currentSrcDirID;
+       long newDirID;
+       short index = 1;
+       
+       do
+       {       
+               /* Get next source item at the current directory level */
+               
+               theGlobals->myCPB.dirInfo.ioFDirIndex = index;
+               theGlobals->myCPB.dirInfo.ioDrDirID = sourceDirID;
+               theGlobals->error = PBGetCatInfoSync(&theGlobals->myCPB);               
+
+               if ( theGlobals->error == noErr )
+               {
+                       if ( (theGlobals->copyFilterProc == NULL) ||
+                                CallCopyFilterProc(theGlobals->copyFilterProc, &theGlobals->myCPB) ) /* filter if filter proc was supplied */
+                       {
+                               /* Either there's no filter proc OR the filter proc says to use this item */
+
+                               /* We have an item.  Is it a file or directory? */
+                               if ( (theGlobals->myCPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+                               {
+                                       /* We have a directory */
+                                       
+                                       /* Create a new directory at the destination. No errors allowed! */
+                                       theGlobals->error = DirCreate(theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName, &newDirID);
+                                       if ( theGlobals->error == noErr )
+                                       {
+                                               /* Save the current source directory ID where we can get it when we come back
+                                               ** from recursion land. */
+                                               currentSrcDirID = theGlobals->myCPB.dirInfo.ioDrDirID;
+                                               
+                                               /* Dive again (copy the directory level we just found below this one) */
+                                               CopyLevel(theGlobals->myCPB.dirInfo.ioDrDirID, newDirID, theGlobals);
+                                               
+                                               if ( !theGlobals->bailout )
+                                               {
+                                                       /* Copy comment from old to new directory. */
+                                                       /* Ignore the result because we really don't care if it worked or not. */
+                                                       (void) DTCopyComment(theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, theGlobals->destinationVRefNum, newDirID, NULL);
+                                                       
+                                                       /* Copy directory attributes (dates, etc.) to newDirID. */
+                                                       /* No errors allowed */
+                                                       theGlobals->error = CopyFileMgrAttributes(theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL, theGlobals->destinationVRefNum, newDirID, NULL, true);
+                                                       
+                                                       /* handle any errors from CopyFileMgrAttributes */
+                                                       if ( theGlobals->error != noErr )
+                                                       {
+                                                               if ( theGlobals->errorHandler != NULL )
+                                                               {
+                                                                       theGlobals->bailout =  CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, copyDirFMAttributesOp,
+                                                                                                                       theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL,
+                                                                                                                       theGlobals->destinationVRefNum, newDirID, NULL);
+                                                               }
+                                                               else
+                                                               {
+                                                                       /* If you don't handle the errors with an error handler, */
+                                                                       /* then the copy stops here. */
+                                                                       theGlobals->bailout = true;
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       else    /* error handling for DirCreate */
+                                       {
+                                               if ( theGlobals->errorHandler != NULL )
+                                               {
+                                                       theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, dirCreateOp,
+                                                                                                               theGlobals->myCPB.dirInfo.ioVRefNum, currentSrcDirID, NULL,
+                                                                                                               theGlobals->destinationVRefNum, dstDirID, theGlobals->itemName);
+                                               }
+                                               else
+                                               {
+                                                       /* If you don't handle the errors with an error handler, */
+                                                       /* then the copy stops here. */
+                                                       theGlobals->bailout = true;
+                                               }
+                                       }
+                                       
+                                       if ( !theGlobals->bailout )
+                                       {
+                                               /* clear error return on way back if we aren't bailing out */
+                                               theGlobals->error = noErr;
+                                       }
+                               }
+                               else
+                               {
+                                       /* We have a file, so copy it */
+                                       
+                                       theGlobals->error = FileCopy(theGlobals->myCPB.hFileInfo.ioVRefNum,
+                                                                                                theGlobals->myCPB.hFileInfo.ioFlParID,
+                                                                                                theGlobals->itemName,
+                                                                                                theGlobals->destinationVRefNum,
+                                                                                                dstDirID,
+                                                                                                NULL,
+                                                                                                NULL,
+                                                                                                theGlobals->copyBuffer,
+                                                                                                theGlobals->bufferSize,
+                                                                                                false);
+                                                       
+                                       /* handle any errors from FileCopy */
+                                       if ( theGlobals->error != noErr )
+                                       {
+                                               if ( theGlobals->errorHandler != NULL )
+                                               {
+                                                       theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, fileCopyOp,
+                                                                                                       theGlobals->myCPB.hFileInfo.ioVRefNum, theGlobals->myCPB.hFileInfo.ioFlParID, theGlobals->itemName,
+                                                                                                       theGlobals->destinationVRefNum, dstDirID, NULL);
+                                                       if ( !theGlobals->bailout )
+                                                       {
+                                                               /* If the CopyErrProc handled the problem, clear the error here */
+                                                               theGlobals->error = noErr;
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       /* If you don't handle the errors with an error handler, */
+                                                       /* then the copy stops here. */
+                                                       theGlobals->bailout = true;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               else
+               {       /* error handling for PBGetCatInfo */
+                       /* it's normal to get a fnfErr when indexing; that only means you've hit the end of the directory */
+                       if ( theGlobals->error != fnfErr )
+                       {
+                               if ( theGlobals->errorHandler != NULL )
+                               { 
+                                       theGlobals->bailout = CallCopyErrProc(theGlobals->errorHandler, theGlobals->error, getNextItemOp,
+                                                                                       theGlobals->myCPB.dirInfo.ioVRefNum, sourceDirID, NULL, 0, 0, NULL);
+                                       if ( !theGlobals->bailout )
+                                       {
+                                               /* If the CopyErrProc handled the problem, clear the error here */
+                                               theGlobals->error = noErr;
+                                       }
+                               }
+                               else
+                               {
+                                       /* If you don't handle the errors with an error handler, */
+                                       /* then the copy stops here. */
+                                       theGlobals->bailout = true;
+                               }
+                       }
+               }
+               ++index; /* prepare to get next item */
+       } while ( (theGlobals->error == noErr) && (!theGlobals->bailout) ); /* time to fall back a level? */
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FilteredDirectoryCopy(short srcVRefNum,
+                                                                         long srcDirID,
+                                                                         ConstStr255Param srcName,
+                                                                         short dstVRefNum,
+                                                                         long dstDirID,
+                                                                         ConstStr255Param dstName,
+                                                                         void *copyBufferPtr,
+                                                                         long copyBufferSize,
+                                                                         Boolean preflight,
+                                                                         CopyErrProcPtr copyErrHandler,
+                                                                         CopyFilterProcPtr copyFilterProc)
+{
+       EnumerateGlobals theGlobals;
+       Boolean isDirectory;
+       OSErr   error;
+       Boolean ourCopyBuffer = false;
+       Str63   srcDirName, oldDiskName;
+       Boolean spaceOK;                        
+       
+       /* Make sure a copy buffer is allocated. */
+       if ( copyBufferPtr == NULL )
+       {
+               /* The caller didn't supply a copy buffer so grab one from the application heap.
+               ** Try to get a big copy buffer, if we can't, try for a 512-byte buffer.
+               ** If 512 bytes aren't available, we're in trouble. */
+               copyBufferSize = dirCopyBigCopyBuffSize;
+               copyBufferPtr = NewPtr(copyBufferSize);
+               if ( copyBufferPtr == NULL )
+               {
+                       copyBufferSize = dirCopyMinCopyBuffSize;
+                       copyBufferPtr = NewPtr(copyBufferSize);
+                       if ( copyBufferPtr == NULL )
+                       {
+                               return ( memFullErr );
+                       }
+               }
+               ourCopyBuffer = true;
+       }
+       
+       /* Get the real dirID where we're copying from and make sure it is a directory. */
+       error = GetDirectoryID(srcVRefNum, srcDirID, srcName, &srcDirID, &isDirectory);
+       if ( error != noErr )
+       {
+               goto ErrorExit;
+       }
+       if ( !isDirectory )
+       {
+               error = dirNFErr;
+               goto ErrorExit;
+       }
+       
+       /* Special case destination if it is the root parent directory. */
+       /* Since you can't create the root directory, this is needed if */
+       /* you want to copy a directory's content to a disk's root directory. */
+       if ( (dstDirID == fsRtParID) && (dstName == NULL) )
+       {
+               dstDirID = fsRtParID;
+               isDirectory = true;
+               error = noErr;
+       }
+       else
+       {
+               /*  Get the real dirID where we're going to put the copy and make sure it is a directory. */
+               error = GetDirectoryID(dstVRefNum, dstDirID, dstName, &dstDirID, &isDirectory);
+               if ( error != noErr )
+               {
+                       goto ErrorExit;
+               }
+               if ( !isDirectory )
+               {
+                       error =  dirNFErr;
+                       goto ErrorExit;
+               }
+       }
+       
+       /* Get the real vRefNum of both the source and destination */
+       error = DetermineVRefNum(srcName, srcVRefNum, &srcVRefNum);
+       if ( error != noErr )
+       {
+               goto ErrorExit;
+       }
+       error = DetermineVRefNum(dstName, dstVRefNum, &dstVRefNum);
+       if ( error != noErr )
+       {
+               goto ErrorExit;
+       }
+       
+       if ( preflight )
+       {
+               error = PreflightDirectoryCopySpace(srcVRefNum, srcDirID, dstVRefNum, copyFilterProc, &spaceOK);
+               if ( error != noErr )
+               {
+                       goto ErrorExit;
+               }
+               if ( !spaceOK )
+               {
+                       error = dskFulErr; /* not enough room on destination */
+                       goto ErrorExit;
+               }
+       }
+
+       /* Create the new directory in the destination directory with the */
+       /* same name as the source directory. */
+       error = GetDirName(srcVRefNum, srcDirID, srcDirName);
+       if ( error != noErr )
+       {
+               goto ErrorExit;
+       }
+       
+       /* Again, special case destination if the destination is the */
+       /* root parent directory. This time, we'll rename the disk to */
+       /* the source directory name. */
+       if ( dstDirID == fsRtParID )
+       {
+               /* Get the current name of the destination disk */
+               error = GetDirName(dstVRefNum, fsRtDirID, oldDiskName);
+               if ( error == noErr )   
+               {
+                       /* Shorten the name if it's too long to be the volume name */
+                       TruncPString(srcDirName, srcDirName, 27);
+                       
+                       /* Rename the disk */
+                       error = HRename(dstVRefNum, fsRtParID, oldDiskName, srcDirName);
+                       /* and copy to the root directory */
+                       dstDirID = fsRtDirID;
+               }
+       }
+       else
+       {
+               error = DirCreate(dstVRefNum, dstDirID, srcDirName, &dstDirID);
+       }
+       if ( error != noErr )
+       {
+               /* handle any errors from DirCreate */
+               if ( copyErrHandler != NULL )
+               {
+                       if ( CallCopyErrProc(copyErrHandler, error, dirCreateOp,
+                                                                                                       srcVRefNum, srcDirID, NULL,
+                                                                                                       dstVRefNum, dstDirID, srcDirName) )
+                       {
+                               goto ErrorExit;
+                       }
+                       else
+                       {
+                               /* If the CopyErrProc handled the problem, clear the error here */
+                               /* and continue */
+                               error = noErr;
+                       }
+               }
+               else
+               {
+                       /* If you don't handle the errors with an error handler, */
+                       /* then the copy stops here. */
+                       goto ErrorExit;
+               }
+       }
+       
+       /* dstDirID is now the newly created directory! */
+               
+       /* Set up the globals we need to access from the recursive routine. */
+       theGlobals.copyBuffer = (Ptr)copyBufferPtr;
+       theGlobals.bufferSize = copyBufferSize;
+       theGlobals.destinationVRefNum = dstVRefNum; /* so we can get to it always */
+       theGlobals.myCPB.hFileInfo.ioNamePtr = (StringPtr)&theGlobals.itemName;
+       theGlobals.myCPB.hFileInfo.ioVRefNum = srcVRefNum;
+       theGlobals.errorHandler = copyErrHandler;
+       theGlobals.bailout = false;
+       theGlobals.copyFilterProc =  copyFilterProc;
+               
+       /* Here we go into recursion land... */
+       CopyLevel(srcDirID, dstDirID, &theGlobals);
+       error = theGlobals.error;       /* get the result */
+       
+       if ( !theGlobals.bailout )
+       {
+               /* Copy comment from source to destination directory. */
+               /* Ignore the result because we really don't care if it worked or not. */
+               (void) DTCopyComment(srcVRefNum, srcDirID, NULL, dstVRefNum, dstDirID, NULL);
+               
+               /* Copy the File Manager attributes */
+               error = CopyFileMgrAttributes(srcVRefNum, srcDirID, NULL,
+                                       dstVRefNum, dstDirID, NULL, true);
+               
+               /* handle any errors from CopyFileMgrAttributes */
+               if ( (error != noErr) && (copyErrHandler != NULL) )
+               {
+                       theGlobals.bailout = CallCopyErrProc(copyErrHandler, error, copyDirFMAttributesOp,
+                                                                                               srcVRefNum, srcDirID, NULL,
+                                                                                               dstVRefNum, dstDirID, NULL);
+               }
+       }
+
+ErrorExit:
+       /* Get rid of the copy buffer if we allocated it. */
+       if ( ourCopyBuffer )
+       {
+               DisposePtr((Ptr)copyBufferPtr);
+       }
+
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DirectoryCopy(short srcVRefNum,
+                                                         long srcDirID,
+                                                         ConstStr255Param srcName,
+                                                         short dstVRefNum,
+                                                         long dstDirID,
+                                                         ConstStr255Param dstName,
+                                                         void *copyBufferPtr,
+                                                         long copyBufferSize,
+                                                         Boolean preflight,
+                                                         CopyErrProcPtr copyErrHandler)
+{
+       return ( FilteredDirectoryCopy(srcVRefNum, srcDirID, srcName,
+                                                                  dstVRefNum, dstDirID, dstName,
+                                                                  copyBufferPtr, copyBufferSize, preflight,
+                                                                  copyErrHandler, NULL) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpFilteredDirectoryCopy(const FSSpec *srcSpec,
+                                                                                const FSSpec *dstSpec,
+                                                                                void *copyBufferPtr,
+                                                                                long copyBufferSize,
+                                                                                Boolean preflight,
+                                                                                CopyErrProcPtr copyErrHandler,
+                                                                                CopyFilterProcPtr copyFilterProc)
+{
+       return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
+                                                                  dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
+                                                                  copyBufferPtr, copyBufferSize, preflight,
+                                                                  copyErrHandler, copyFilterProc) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDirectoryCopy(const FSSpec *srcSpec,
+                                                                const FSSpec *dstSpec,
+                                                                void *copyBufferPtr,
+                                                                long copyBufferSize,
+                                                                Boolean preflight,
+                                                                CopyErrProcPtr copyErrHandler)
+{
+       return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
+                                                                  dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
+                                                                  copyBufferPtr, copyBufferSize, preflight,
+                                                                  copyErrHandler, NULL) );
+}
+
+/*****************************************************************************/
+
diff --git a/src/mac/morefile/Director.h b/src/mac/morefile/Director.h
new file mode 100644 (file)
index 0000000..a042fd7
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     DirectoryCopy: A robust, general purpose directory copy routine.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           DirectoryCopy.h
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#ifndef __DIRECTORYCOPY__
+#define __DIRECTORYCOPY__
+
+#include <Types.h>
+#include <Files.h>
+
+#include "Optim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+enum
+{
+       getNextItemOp                   = 1,    /* couldn't access items in this directory - no access privileges */
+       copyDirCommentOp                = 2,    /* couldn't copy directory's Finder comment */
+       copyDirAccessPrivsOp    = 3,    /* couldn't copy directory's AFP access privileges */
+       copyDirFMAttributesOp   = 4,    /* couldn't copy directory's File Manager attributes */
+       dirCreateOp                             = 5,    /* couldn't create destination directory */
+       fileCopyOp                              = 6             /* couldn't copy file */
+};
+
+/*****************************************************************************/
+
+typedef        pascal  Boolean (*CopyErrProcPtr) (OSErr error,
+                                                                                  short failedOperation,
+                                                                                  short srcVRefNum,
+                                                                                  long srcDirID,
+                                                                                  ConstStr255Param srcName,
+                                                                                  short dstVRefNum,
+                                                                                  long dstDirID,
+                                                                                  ConstStr255Param dstName);
+/*     ¦ Prototype for the CopyErrProc function DirectoryCopy calls.
+       This is the prototype for the CopyErrProc function DirectoryCopy
+       calls if an error condition is detected sometime during the copy.  If
+       CopyErrProc returns false, then DirectoryCopy attempts to continue with
+       the directory copy operation.  If CopyErrProc returns true, then
+       DirectoryCopy stops the directory copy operation.
+
+       error                   input:  The error result code that caused CopyErrProc to
+                                                       be called.
+       failedOperation input:  The operation that returned an error to
+                                                       DirectoryCopy.
+       srcVRefNum              input:  Source volume specification.
+       srcDirID                input:  Source directory ID.
+       srcName                 input:  Source file or directory name, or nil if
+                                                       srcDirID specifies the directory.
+       dstVRefNum              input:  Destination volume specification.
+       dstDirID                input:  Destination directory ID.
+       dstName                 input:  Destination file or directory name, or nil if
+                                                       dstDirID specifies the directory.
+
+       __________
+       
+       Also see:       FilteredDirectoryCopy, FSpFilteredDirectoryCopy, DirectoryCopy, FSpDirectoryCopy
+*/
+
+#define CallCopyErrProc(userRoutine, error, failedOperation, srcVRefNum, srcDirID, srcName, dstVRefNum, dstDirID, dstName) \
+               (*(userRoutine))((error), (failedOperation), (srcVRefNum), (srcDirID), (srcName), (dstVRefNum), (dstDirID), (dstName))
+
+/*****************************************************************************/
+
+typedef        pascal  Boolean (*CopyFilterProcPtr) (const CInfoPBRec * const cpbPtr);
+
+/*     ¦ Prototype for the CopyFilterProc function.
+       This is the prototype for the CopyFilterProc function called by
+       FilteredDirectoryCopy and GetLevelSize. If true is returned,
+       the file/folder is included in the copy, otherwise it is excluded.
+       
+       pb      input:  Points to the CInfoPBRec for the item under consideration.
+
+       __________
+       
+       Also see:       FilteredDirectoryCopy, FSpFilteredDirectoryCopy
+*/
+
+#define CallCopyFilterProc(userRoutine, cpbPtr) (*(userRoutine))((cpbPtr))
+
+/*****************************************************************************/
+
+pascal OSErr   FilteredDirectoryCopy(short srcVRefNum,
+                                                                         long srcDirID,
+                                                                         ConstStr255Param srcName,
+                                                                         short dstVRefNum,
+                                                                         long dstDirID,
+                                                                         ConstStr255Param dstName,
+                                                                         void *copyBufferPtr,
+                                                                         long copyBufferSize,
+                                                                         Boolean preflight,
+                                                                         CopyErrProcPtr copyErrHandler,
+                                                                         CopyFilterProcPtr copyFilterProc);
+/*     ¦ Make a copy of a directory structure in a new location with item filtering.
+       The FilteredDirectoryCopy function makes a copy of a directory
+       structure in a new location. If copyBufferPtr <> NIL, it points to
+       a buffer of copyBufferSize that is used to copy files data. The
+       larger the supplied buffer, the faster the copy. If
+       copyBufferPtr = NIL, then this routine allocates a buffer in the
+       application heap. If you pass a copy buffer to this routine, make
+       its size a multiple of 512 ($200) bytes for optimum performance.
+       
+       The optional copyFilterProc parameter lets a routine you define
+       decide what files or directories are copied to the destination.
+       
+       FilteredDirectoryCopy normally creates a new directory *in* the
+       specified destination directory and copies the source directory's
+       content into the new directory. However, if root parent directory
+       (fsRtParID) is passed as the dstDirID parameter and NULL is
+       passed as the dstName parameter, DirectoryCopy renames the
+       destination volume to the source directory's name (truncating
+       if the name is longer than 27 characters) and copies the source
+       directory's content into the destination volume's root directory.
+       This special case is supported by FilteredDirectoryCopy, but
+       not by FSpFilteredDirectoryCopy since with FSpFilteredDirectoryCopy,
+       the dstName parameter can not be NULL.
+       
+       srcVRefNum              input:  Source volume specification.
+       srcDirID                input:  Source directory ID.
+       srcName                 input:  Source directory name, or nil if
+                                                       srcDirID specifies the directory.
+       dstVRefNum              input:  Destination volume specification.
+       dstDirID                input:  Destination directory ID.
+       dstName                 input:  Destination directory name, or nil if
+                                                       dstDirID specifies the directory.
+       copyBufferPtr   input:  Points to a buffer of copyBufferSize that
+                                                       is used the i/o buffer for the copy or
+                                                       nil if you want DirectoryCopy to allocate its
+                                                       own buffer in the application heap.
+       copyBufferSize  input:  The size of the buffer pointed to
+                                                       by copyBufferPtr.
+       preflight               input:  If true, DirectoryCopy makes sure there are
+                                                       enough allocation blocks on the destination
+                                                       volume to hold the directory's files before
+                                                       starting the copy.
+       copyErrHandler  input:  A pointer to the routine you want called if an
+                                                       error condition is detected during the copy, or
+                                                       nil if you don't want to handle error conditions.
+                                                       If you don't handle error conditions, the first
+                                                       error will cause the copy to quit and
+                                                       DirectoryCopy will return the error.
+                                                       Error handling is recommended...
+       copyFilterProc  input:  A pointer to the filter routine you want called
+                                                       for each item in the source directory, or NULL
+                                                       if you don't want to filter.
+       
+       Result Codes
+               noErr                           0               No error
+               readErr                         Ð19             Driver does not respond to read requests
+               writErr                         Ð20             Driver does not respond to write requests
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies a
+                                                                       nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+               dskFulErr                       -34             Destination volume is full
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               tmfoErr                         -42             Too many files open
+               fnfErr                          -43             Source file not found, or destination
+                                                                       directory does not exist
+               wPrErr                          -44             Volume locked by hardware
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Destination volume is read-only
+               fBsyErr                         -47             The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               dupFNErr                        -48             Destination file already exists
+               opWrErr                         -49             File already open for writing
+               paramErr                        -50             No default volume or function not
+                                                                       supported by volume
+               permErr                         -54             File is already open and cannot be opened using specified deny modes
+               memFullErr                      -108    Copy buffer could not be allocated
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               wrgVolTypErr            -123    Function not supported by volume
+               afpAccessDenied         -5000   User does not have the correct access
+               afpDenyConflict         -5006   The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               afpObjectTypeErr        -5025   Source is a directory, directory not found
+                                                                       or incomplete pathname
+       
+       __________
+       
+       Also see:       CopyErrProcPtr, CopyFilterProcPtr, FSpFilteredDirectoryCopy,
+                               DirectoryCopy, FSpDirectoryCopy, FileCopy, FSpFileCopy
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpFilteredDirectoryCopy(const FSSpec *srcSpec,
+                                                                                const FSSpec *dstSpec,
+                                                                                void *copyBufferPtr,
+                                                                                long copyBufferSize,
+                                                                                Boolean preflight,
+                                                                                CopyErrProcPtr copyErrHandler,
+                                                                                CopyFilterProcPtr copyFilterProc);
+/*     ¦ Make a copy of a directory structure in a new location with item filtering.
+       The FSpFilteredDirectoryCopy function makes a copy of a directory
+       structure in a new location. If copyBufferPtr <> NIL, it points to
+       a buffer of copyBufferSize that is used to copy files data. The
+       larger the supplied buffer, the faster the copy. If
+       copyBufferPtr = NIL, then this routine allocates a buffer in the
+       application heap. If you pass a copy buffer to this routine, make
+       its size a multiple of 512 ($200) bytes for optimum performance.
+       
+       The optional copyFilterProc parameter lets a routine you define
+       decide what files or directories are copied to the destination.
+       
+       srcSpec                 input:  An FSSpec record specifying the directory to copy.
+       dstSpec                 input:  An FSSpec record specifying destination directory
+                                                       of the copy.
+       copyBufferPtr   input:  Points to a buffer of copyBufferSize that
+                                                       is used the i/o buffer for the copy or
+                                                       nil if you want DirectoryCopy to allocate its
+                                                       own buffer in the application heap.
+       copyBufferSize  input:  The size of the buffer pointed to
+                                                       by copyBufferPtr.
+       preflight               input:  If true, FSpDirectoryCopy makes sure there are
+                                                       enough allocation blocks on the destination
+                                                       volume to hold the directory's files before
+                                                       starting the copy.
+       copyErrHandler  input:  A pointer to the routine you want called if an
+                                                       error condition is detected during the copy, or
+                                                       nil if you don't want to handle error conditions.
+                                                       If you don't handle error conditions, the first
+                                                       error will cause the copy to quit and
+                                                       DirectoryCopy will return the error.
+                                                       Error handling is recommended...
+       copyFilterProc  input:  A pointer to the filter routine you want called
+                                                       for each item in the source directory, or NULL
+                                                       if you don't want to filter.
+       
+       Result Codes
+               noErr                           0               No error
+               readErr                         Ð19             Driver does not respond to read requests
+               writErr                         Ð20             Driver does not respond to write requests
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies a
+                                                                       nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+               dskFulErr                       -34             Destination volume is full
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               tmfoErr                         -42             Too many files open
+               fnfErr                          -43             Source file not found, or destination
+                                                                       directory does not exist
+               wPrErr                          -44             Volume locked by hardware
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Destination volume is read-only
+               fBsyErr                         -47             The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               dupFNErr                        -48             Destination file already exists
+               opWrErr                         -49             File already open for writing
+               paramErr                        -50             No default volume or function not
+                                                                       supported by volume
+               permErr                         -54             File is already open and cannot be opened using specified deny modes
+               memFullErr                      -108    Copy buffer could not be allocated
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               wrgVolTypErr            -123    Function not supported by volume
+               afpAccessDenied         -5000   User does not have the correct access
+               afpDenyConflict         -5006   The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               afpObjectTypeErr        -5025   Source is a directory, directory not found
+                                                                       or incomplete pathname
+       
+       __________
+       
+       Also see:       CopyErrProcPtr, CopyFilterProcPtr, FilteredDirectoryCopy,
+                               DirectoryCopy, FSpDirectoryCopy, FileCopy, FSpFileCopy
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DirectoryCopy(short srcVRefNum,
+                                                         long srcDirID,
+                                                         ConstStr255Param srcName,
+                                                         short dstVRefNum,
+                                                         long dstDirID,
+                                                         ConstStr255Param dstName,
+                                                         void *copyBufferPtr,
+                                                         long copyBufferSize,
+                                                         Boolean preflight,
+                                                         CopyErrProcPtr copyErrHandler);
+/*     ¦ Make a copy of a directory structure in a new location.
+       The DirectoryCopy function makes a copy of a directory structure in a
+       new location. If copyBufferPtr <> NIL, it points to a buffer of
+       copyBufferSize that is used to copy files data.  The larger the
+       supplied buffer, the faster the copy.  If copyBufferPtr = NIL, then this
+       routine allocates a buffer in the application heap. If you pass a
+       copy buffer to this routine, make its size a multiple of 512
+       ($200) bytes for optimum performance.
+       
+       DirectoryCopy normally creates a new directory *in* the specified
+       destination directory and copies the source directory's content into
+       the new directory. However, if root parent directory (fsRtParID)
+       is passed as the dstDirID parameter and NULL is passed as the
+       dstName parameter, DirectoryCopy renames the destination volume to
+       the source directory's name (truncating if the name is longer than
+       27 characters) and copies the source directory's content into the
+       destination volume's root directory. This special case is supported
+       by DirectoryCopy, but not by FSpDirectoryCopy since with
+       FSpDirectoryCopy, the dstName parameter can not be NULL.
+       
+       srcVRefNum              input:  Source volume specification.
+       srcDirID                input:  Source directory ID.
+       srcName                 input:  Source directory name, or nil if
+                                                       srcDirID specifies the directory.
+       dstVRefNum              input:  Destination volume specification.
+       dstDirID                input:  Destination directory ID.
+       dstName                 input:  Destination directory name, or nil if
+                                                       dstDirID specifies the directory.
+       copyBufferPtr   input:  Points to a buffer of copyBufferSize that
+                                                       is used the i/o buffer for the copy or
+                                                       nil if you want DirectoryCopy to allocate its
+                                                       own buffer in the application heap.
+       copyBufferSize  input:  The size of the buffer pointed to
+                                                       by copyBufferPtr.
+       preflight               input:  If true, DirectoryCopy makes sure there are
+                                                       enough allocation blocks on the destination
+                                                       volume to hold the directory's files before
+                                                       starting the copy.
+       copyErrHandler  input:  A pointer to the routine you want called if an
+                                                       error condition is detected during the copy, or
+                                                       nil if you don't want to handle error conditions.
+                                                       If you don't handle error conditions, the first
+                                                       error will cause the copy to quit and
+                                                       DirectoryCopy will return the error.
+                                                       Error handling is recommended...
+       
+       Result Codes
+               noErr                           0               No error
+               readErr                         Ð19             Driver does not respond to read requests
+               writErr                         Ð20             Driver does not respond to write requests
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies a
+                                                                       nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+               dskFulErr                       -34             Destination volume is full
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               tmfoErr                         -42             Too many files open
+               fnfErr                          -43             Source file not found, or destination
+                                                                       directory does not exist
+               wPrErr                          -44             Volume locked by hardware
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Destination volume is read-only
+               fBsyErr                         -47             The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               dupFNErr                        -48             Destination file already exists
+               opWrErr                         -49             File already open for writing
+               paramErr                        -50             No default volume or function not
+                                                                       supported by volume
+               permErr                         -54             File is already open and cannot be opened using specified deny modes
+               memFullErr                      -108    Copy buffer could not be allocated
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               wrgVolTypErr            -123    Function not supported by volume
+               afpAccessDenied         -5000   User does not have the correct access
+               afpDenyConflict         -5006   The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               afpObjectTypeErr        -5025   Source is a directory, directory not found
+                                                                       or incomplete pathname
+       
+       __________
+       
+       Also see:       CopyErrProcPtr, FSpDirectoryCopy, FilteredDirectoryCopy,
+                               FSpFilteredDirectoryCopy, FileCopy, FSpFileCopy
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDirectoryCopy(const FSSpec *srcSpec,
+                                                                const FSSpec *dstSpec,
+                                                                void *copyBufferPtr,
+                                                                long copyBufferSize,
+                                                                Boolean preflight,
+                                                                CopyErrProcPtr copyErrHandler);
+/*     ¦ Make a copy of a directory structure in a new location.
+       The FSpDirectoryCopy function makes a copy of a directory structure in a
+       new location. If copyBufferPtr <> NIL, it points to a buffer of
+       copyBufferSize that is used to copy files data.  The larger the
+       supplied buffer, the faster the copy.  If copyBufferPtr = NIL, then this
+       routine allocates a buffer in the application heap. If you pass a
+       copy buffer to this routine, make its size a multiple of 512
+       ($200) bytes for optimum performance.
+       
+       srcSpec                 input:  An FSSpec record specifying the directory to copy.
+       dstSpec                 input:  An FSSpec record specifying destination directory
+                                                       of the copy.
+       copyBufferPtr   input:  Points to a buffer of copyBufferSize that
+                                                       is used the i/o buffer for the copy or
+                                                       nil if you want DirectoryCopy to allocate its
+                                                       own buffer in the application heap.
+       copyBufferSize  input:  The size of the buffer pointed to
+                                                       by copyBufferPtr.
+       preflight               input:  If true, FSpDirectoryCopy makes sure there are
+                                                       enough allocation blocks on the destination
+                                                       volume to hold the directory's files before
+                                                       starting the copy.
+       copyErrHandler  input:  A pointer to the routine you want called if an
+                                                       error condition is detected during the copy, or
+                                                       nil if you don't want to handle error conditions.
+                                                       If you don't handle error conditions, the first
+                                                       error will cause the copy to quit and
+                                                       DirectoryCopy will return the error.
+                                                       Error handling is recommended...
+       
+       Result Codes
+               noErr                           0               No error
+               readErr                         Ð19             Driver does not respond to read requests
+               writErr                         Ð20             Driver does not respond to write requests
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies a
+                                                                       nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+               dskFulErr                       -34             Destination volume is full
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               tmfoErr                         -42             Too many files open
+               fnfErr                          -43             Source file not found, or destination
+                                                                       directory does not exist
+               wPrErr                          -44             Volume locked by hardware
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Destination volume is read-only
+               fBsyErr                         -47             The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               dupFNErr                        -48             Destination file already exists
+               opWrErr                         -49             File already open for writing
+               paramErr                        -50             No default volume or function not
+                                                                       supported by volume
+               permErr                         -54             File is already open and cannot be opened using specified deny modes
+               memFullErr                      -108    Copy buffer could not be allocated
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               wrgVolTypErr            -123    Function not supported by volume
+               afpAccessDenied         -5000   User does not have the correct access
+               afpDenyConflict         -5006   The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               afpObjectTypeErr        -5025   Source is a directory, directory not found
+                                                                       or incomplete pathname
+       
+       __________
+       
+       Also see:       CopyErrProcPtr, DirectoryCopy, FilteredDirectoryCopy,
+                               FSpFilteredDirectoryCopy, FileCopy, FSpFileCopy
+*/
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "OptimEnd.h"
+
+#endif /* __DIRECTORYCOPY__ */
diff --git a/src/mac/morefile/FSpCompa.cpp b/src/mac/morefile/FSpCompa.cpp
new file mode 100644 (file)
index 0000000..b35e20e
--- /dev/null
@@ -0,0 +1,928 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     FSSpec compatibility functions.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           FSpCompat.c
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+/*
+**     If building application 68K code, set GENERATENODATA to 0 for faster code.
+**     If building stand-alone 68K code, set GENERATENODATA to 1 so globals
+**             (static variables) are not used.
+*/
+#ifndef GENERATENODATA
+#define GENERATENODATA 0
+#endif
+
+#include <Types.h>
+#include <Errors.h>
+#include <LowMem.h>
+#include <Gestalt.h>
+#include <Resources.h>
+#include <Script.h>
+
+#define        __COMPILINGMOREFILES
+
+#include "MoreExtr.h"
+#include "FSpCompa.h"
+
+/*****************************************************************************/
+
+/* local constants */
+
+enum {
+       gestaltBugFixAttrsTwo                                   = 'bugy',
+       gestaltFSpExchangeFilesCompatibilityFix = 26,
+       gestaltBugFixAttrsThree                                 = 'bugx',
+       gestaltFSpCreateScriptSupportFix                = 1
+};
+
+/*****************************************************************************/
+
+/* static prototypes */
+
+
+#if !__MACOSSEVENORLATER
+static Boolean FSHasFSSpecCalls(void);
+
+static Boolean QTHasFSSpecCalls(void);
+#endif /* !__MACOSSEVENORLATER */
+
+#if !__MACOSSEVENFIVEORLATER
+static Boolean HasFSpExchangeFilesCompatibilityFix(void);
+
+static OSErr   GenerateUniqueName(short volume,
+                                                                  long *startSeed,
+                                                                  long dir1,
+                                                                  long dir2,
+                                                                  StringPtr uniqueName);
+#endif /* !__MACOSSEVENFIVEORLATER */
+
+#if !__MACOSSEVENFIVEONEORLATER
+static Boolean HasFSpCreateScriptSupportFix(void);
+#endif /* !__MACOSSEVENFIVEONEORLATER */
+
+/*****************************************************************************/
+
+/* FSHasFSSpecCalls returns true if the file system provides FSSpec calls. */
+
+#if !__MACOSSEVENORLATER
+static Boolean FSHasFSSpecCalls(void)
+{
+       long                    response;
+#if !GENERATENODATA
+       static Boolean  tested = false;
+       static Boolean  result = false;
+#else
+       Boolean result = false;
+#endif
+       
+#if !GENERATENODATA
+       if ( !tested )
+       {
+               tested = true;
+#endif
+               if ( Gestalt(gestaltFSAttr, &response) == noErr )
+               {
+                       result = ((response & (1L << gestaltHasFSSpecCalls)) != 0);
+               }
+#if !GENERATENODATA
+       }
+#endif
+       return ( result );
+}
+#endif /* !__MACOSSEVENORLATER */
+
+/*****************************************************************************/
+
+/* QTHasFSSpecCalls returns true if QuickTime provides FSSpec calls */
+/* except for FSpExchangeFiles. */
+
+#if !__MACOSSEVENORLATER
+static Boolean QTHasFSSpecCalls(void)
+{
+       long                    response;
+#if !GENERATENODATA
+       static Boolean  tested = false;
+       static Boolean  result = false;
+#else
+       Boolean result = false;
+#endif
+       
+#if !GENERATENODATA
+       if ( !tested )
+       {
+               tested = true;
+#endif
+               result = (Gestalt(gestaltQuickTimeVersion, &response) == noErr);
+#if !GENERATENODATA
+       }
+#endif
+       return ( result );
+}
+#endif /* !__MACOSSEVENORLATER */
+
+/*****************************************************************************/
+
+/* HasFSpExchangeFilesCompatibilityFix returns true if FSpExchangeFiles */
+/* compatibility code has been fixed in system software. */
+/* This was fixed by System Update 3.0, so if SystemSevenFiveOrLater */
+/* is true, then we know the fix is in. */
+
+#if !__MACOSSEVENFIVEORLATER
+static Boolean HasFSpExchangeFilesCompatibilityFix(void)
+{
+       long                    response;
+#if !GENERATENODATA
+       static Boolean  tested = false;
+       static Boolean  result = false;
+#else  /* !GENERATENODATA */
+       Boolean result = false;
+#endif /* !GENERATENODATA */
+       
+#if !GENERATENODATA
+       if ( !tested )
+       {
+               tested = true;
+#endif /* !GENERATENODATA */
+               if ( Gestalt(gestaltBugFixAttrsTwo, &response) == noErr )
+               {
+                       result = ((response & (1L << gestaltFSpExchangeFilesCompatibilityFix)) != 0);
+               }
+#if !GENERATENODATA
+       }
+#endif /* !GENERATENODATA */
+       return ( result );
+}
+#endif /* !__MACOSSEVENFIVEORLATER */
+
+/*****************************************************************************/
+
+/* HasFSpCreateScriptSupportFix returns true if FSpCreate and */
+/* FSpCreateResFile have been fixed in system software to correctly set */
+/* the scriptCode in the volume's catalog. */
+/* This was fixed by System 7.5 Update 1.0 */
+
+#if !__MACOSSEVENFIVEONEORLATER
+static Boolean HasFSpCreateScriptSupportFix(void)
+{
+       long                    response;
+#if !GENERATENODATA
+       static Boolean  tested = false;
+       static Boolean  result = false;
+#else
+       Boolean result = false;
+#endif /* !GENERATENODATA */
+       
+#if !GENERATENODATA
+       if ( !tested )
+       {
+               tested = true;
+#endif /* !GENERATENODATA */
+               if ( Gestalt(gestaltBugFixAttrsThree, &response) == noErr )
+               {
+                       result = ((response & (1L << gestaltFSpCreateScriptSupportFix)) != 0);
+               }
+#if !GENERATENODATA
+       }
+#endif /* !GENERATENODATA */
+       return ( result );
+}
+#endif /* !__MACOSSEVENFIVEONEORLATER */
+
+/*****************************************************************************/
+
+/*
+**     File Manager FSp calls
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSMakeFSSpecCompat(short vRefNum,
+                                                                  long dirID,
+                                                                  ConstStr255Param fileName,
+                                                                  FSSpec *spec)
+{
+       OSErr   result;
+       
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               Boolean isDirectory;
+               
+               result = GetObjectLocation(vRefNum, dirID, fileName,
+                                                                       &(spec->vRefNum), &(spec->parID), spec->name,
+                                                                       &isDirectory);
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               /* Let the file system create the FSSpec if it can since it does the job */
+               /* much more efficiently than I can. */
+               result = FSMakeFSSpec(vRefNum, dirID, fileName, spec);
+
+               /* Fix a bug in Macintosh PC Exchange's MakeFSSpec code where 0 is */
+               /* returned in the parID field when making an FSSpec to the volume's */
+               /* root directory by passing a full pathname in MakeFSSpec's */
+               /* fileName parameter. Fixed in Mac OS 8.1 */
+               if ( (result == noErr) && (spec->parID == 0) )
+                       spec->parID = fsRtParID;
+       }
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpOpenDFCompat(const FSSpec *spec,
+                                                               char permission,
+                                                               short *refNum)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               OSErr                   result;
+               HParamBlockRec  pb;
+               
+               pb.ioParam.ioVRefNum = spec->vRefNum;
+               pb.fileParam.ioDirID = spec->parID;
+               pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
+               pb.ioParam.ioVersNum = 0;
+               pb.ioParam.ioPermssn = permission;
+               pb.ioParam.ioMisc = NULL;
+               result = PBHOpenSync(&pb);      /* OpenDF not supported by System 6, so use Open */
+               *refNum = pb.ioParam.ioRefNum;
+               return ( result );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpOpenDF(spec, permission, refNum) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpOpenRFCompat(const FSSpec *spec,
+                                                               char permission,
+                                                               short *refNum)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               OSErr                   result;
+               HParamBlockRec  pb;
+               
+               pb.ioParam.ioVRefNum = spec->vRefNum;
+               pb.fileParam.ioDirID = spec->parID;
+               pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
+               pb.ioParam.ioVersNum = 0;
+               pb.ioParam.ioPermssn = permission;
+               pb.ioParam.ioMisc = NULL;
+               result = PBHOpenRFSync(&pb);
+               *refNum = pb.ioParam.ioRefNum;
+               return ( result );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpOpenRF(spec, permission, refNum) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCreateCompat(const FSSpec *spec,
+                                                               OSType creator,
+                                                               OSType fileType,
+                                                               ScriptCode scriptTag)
+{
+#if !__MACOSSEVENFIVEONEORLATER
+       OSErr                   result;
+       UniversalFMPB   pb;
+
+       
+       if (
+#if !__MACOSSEVENORLATER
+                (!FSHasFSSpecCalls() && !QTHasFSSpecCalls()) ||
+#endif /* !__MACOSSEVENORLATER */
+                !HasFSpCreateScriptSupportFix() )
+       {
+               /*      If FSpCreate isn't called, this code will be executed */
+               pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
+               pb.hPB.fileParam.ioDirID = spec->parID;
+               pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
+               pb.hPB.fileParam.ioFVersNum = 0;
+               result = PBHCreateSync(&(pb.hPB));
+               if ( result == noErr )
+               {
+                       /* get info on created item */
+                       pb.ciPB.hFileInfo.ioFDirIndex = 0;
+                       result = PBGetCatInfoSync(&(pb.ciPB));
+                       if ( result == noErr )
+                       {
+                               /* Set fdScript in FXInfo */
+                               /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
+                               /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
+                               /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
+                               pb.ciPB.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
+                                                                                                                       ((char)scriptTag | (char)0x80) :
+                                                                                                                       (smRoman);
+                               /* Set creator/fileType */
+                               pb.ciPB.hFileInfo.ioFlFndrInfo.fdCreator = creator;
+                               pb.ciPB.hFileInfo.ioFlFndrInfo.fdType = fileType;
+                               /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
+                               pb.ciPB.hFileInfo.ioDirID = spec->parID;
+                               result = PBSetCatInfoSync(&(pb.ciPB));
+                       }
+               }
+               return ( result );
+       }
+       else
+#endif /* !__MACOSSEVENFIVEONEORLATER */
+       {
+               return ( FSpCreate(spec, creator, fileType, scriptTag) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDirCreateCompat(const FSSpec *spec,
+                                                                  ScriptCode scriptTag,
+                                                                  long *createdDirID)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               OSErr                   result;
+               UniversalFMPB   pb;
+               
+               pb.hPB.fileParam.ioVRefNum = spec->vRefNum;
+               pb.hPB.fileParam.ioDirID = spec->parID;
+               pb.hPB.fileParam.ioNamePtr = (StringPtr) &(spec->name);
+               result = PBDirCreateSync(&(pb.hPB));
+               *createdDirID = pb.hPB.fileParam.ioDirID;
+               if ( result == noErr )
+               {
+                       /* get info on created item */
+                       pb.ciPB.dirInfo.ioFDirIndex = 0;
+                       pb.ciPB.dirInfo.ioDrDirID = spec->parID;
+                       result = PBGetCatInfoSync(&(pb.ciPB));
+                       if ( result == noErr )
+                       {
+                               /* Set frScript in DXInfo */
+                               /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
+                               /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
+                               /* (smRoman is 0). frScript is valid if high bit is set (see IM-6, page 9-38) */
+                               pb.ciPB.dirInfo.ioDrFndrInfo.frScript = (scriptTag >= smRoman) ?
+                                                                                                                       ((char)scriptTag | (char)0x80) :
+                                                                                                                       (smRoman);
+                               /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
+                               pb.ciPB.dirInfo.ioDrDirID = spec->parID;                        
+                               result = PBSetCatInfoSync(&(pb.ciPB));
+                       }
+               }
+               return ( result );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpDirCreate(spec, scriptTag, createdDirID) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDeleteCompat(const FSSpec *spec)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               HParamBlockRec  pb;
+               
+               pb.ioParam.ioVRefNum = spec->vRefNum;
+               pb.fileParam.ioDirID = spec->parID;
+               pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
+               pb.ioParam.ioVersNum = 0;
+               return ( PBHDeleteSync(&pb) );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpDelete(spec) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetFInfoCompat(const FSSpec *spec,
+                                                                 FInfo *fndrInfo)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               OSErr                   result;
+               HParamBlockRec  pb;
+               
+               pb.fileParam.ioVRefNum = spec->vRefNum;
+               pb.fileParam.ioDirID = spec->parID;
+               pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
+               pb.fileParam.ioFVersNum = 0;
+               pb.fileParam.ioFDirIndex = 0;
+               result = PBHGetFInfoSync(&pb);
+               *fndrInfo = pb.fileParam.ioFlFndrInfo;
+               return ( result );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpGetFInfo(spec, fndrInfo) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetFInfoCompat(const FSSpec *spec,
+                                                                 const FInfo *fndrInfo)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               OSErr                   result;
+               HParamBlockRec  pb;
+               
+               pb.fileParam.ioVRefNum = spec->vRefNum;
+               pb.fileParam.ioDirID = spec->parID;
+               pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
+               pb.fileParam.ioFVersNum = 0;
+               pb.fileParam.ioFDirIndex = 0;
+               result = PBHGetFInfoSync(&pb);
+               if ( result == noErr )
+               {
+                       pb.fileParam.ioFlFndrInfo = *fndrInfo;
+                       pb.fileParam.ioDirID = spec->parID;
+                       result = PBHSetFInfoSync(&pb);
+               }
+               return ( result );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpSetFInfo(spec, fndrInfo) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetFLockCompat(const FSSpec *spec)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               HParamBlockRec  pb;
+               
+               pb.fileParam.ioVRefNum = spec->vRefNum;
+               pb.fileParam.ioDirID = spec->parID;
+               pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
+               pb.fileParam.ioFVersNum = 0;
+               return ( PBHSetFLockSync(&pb) );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpSetFLock(spec) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpRstFLockCompat(const FSSpec *spec)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               HParamBlockRec  pb;
+               
+               pb.fileParam.ioVRefNum = spec->vRefNum;
+               pb.fileParam.ioDirID = spec->parID;
+               pb.fileParam.ioNamePtr = (StringPtr) &(spec->name);
+               pb.fileParam.ioFVersNum = 0;
+               return ( PBHRstFLockSync(&pb) );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpRstFLock(spec) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpRenameCompat(const FSSpec *spec,
+                                                               ConstStr255Param newName)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               HParamBlockRec  pb;
+               
+               pb.ioParam.ioVRefNum = spec->vRefNum;
+               pb.fileParam.ioDirID = spec->parID;
+               pb.ioParam.ioNamePtr = (StringPtr) &(spec->name);
+               pb.ioParam.ioVersNum = 0;
+               pb.ioParam.ioMisc = (Ptr) newName;
+               return ( PBHRenameSync(&pb) );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpRename(spec, newName) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCatMoveCompat(const FSSpec *source,
+                                                                const FSSpec *dest)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               CMovePBRec      pb;
+               
+               /* source and destination volume must be the same */
+               if ( source->vRefNum != dest->vRefNum )
+                       return ( paramErr );
+               
+               pb.ioNamePtr = (StringPtr) &(source->name);
+               pb.ioVRefNum = source->vRefNum;
+               pb.ioDirID = source->parID;
+               pb.ioNewDirID = dest->parID;
+               pb.ioNewName = (StringPtr) &(dest->name);
+               return ( PBCatMoveSync(&pb) );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpCatMove(source, dest) );
+       }
+}
+
+/*****************************************************************************/
+
+/* GenerateUniqueName generates a name that is unique in both dir1 and dir2 */
+/* on the specified volume. Ripped off from Feldman's code. */
+
+#if !__MACOSSEVENFIVEORLATER
+static OSErr   GenerateUniqueName(short volume,
+                                                                  long *startSeed,
+                                                                  long dir1,
+                                                                  long dir2,
+                                                                  StringPtr uniqueName)
+{
+       OSErr                   error = noErr;
+       long                    i;
+       CInfoPBRec              cinfo;
+       unsigned char   hexStr[16];
+       
+       for ( i = 0; i < 16; ++i )
+       {
+               if ( i < 10 )
+               {
+                       hexStr[i] = 0x30 + i;
+               }
+               else
+               {
+                       hexStr[i] = 0x37 + i;
+               }
+       }
+       
+       cinfo.hFileInfo.ioVRefNum = volume;
+       cinfo.hFileInfo.ioFDirIndex = 0;
+       cinfo.hFileInfo.ioNamePtr = uniqueName;
+
+       while ( error != fnfErr )
+       {
+               (*startSeed)++;         
+               cinfo.hFileInfo.ioNamePtr[0] = 8;
+               for ( i = 1; i <= 8; i++ )
+               {
+                       cinfo.hFileInfo.ioNamePtr[i] = hexStr[((*startSeed >> ((8-i)*4)) & 0xf)];
+               }
+               cinfo.hFileInfo.ioDirID = dir1;
+               error = fnfErr;
+               for ( i = 1; i <= 2; i++ )
+               {
+                       error = error & PBGetCatInfoSync(&cinfo);
+                       cinfo.hFileInfo.ioDirID = dir2;
+                       if ( (error != fnfErr) && (error != noErr) )
+                       {
+                               return ( error );
+                       }
+               }
+       }
+       return ( noErr );
+}
+#endif /* !__MACOSSEVENFIVEORLATER */
+
+/*****************************************************************************/
+
+pascal OSErr   FSpExchangeFilesCompat(const FSSpec *source,
+                                                                          const FSSpec *dest)
+{
+#if !__MACOSSEVENFIVEORLATER
+       if ( 
+#if !__MACOSSEVENORLATER
+                !FSHasFSSpecCalls() ||
+#endif /* !__MACOSSEVENORLATER */
+                !HasFSpExchangeFilesCompatibilityFix() )
+       {
+               HParamBlockRec                  pb;
+               CInfoPBRec                              catInfoSource, catInfoDest;
+               OSErr                                   result, result2;
+               Str31                                   unique1, unique2;
+               StringPtr                               unique1Ptr, unique2Ptr, swapola;
+               GetVolParmsInfoBuffer   volInfo;
+               long                                    theSeed, temp;
+               
+               /* Make sure the source and destination are on the same volume */
+               if ( source->vRefNum != dest->vRefNum )
+               {
+                       result = diffVolErr;
+                       goto errorExit3;
+               }
+               
+               /* Try PBExchangeFiles first since it preserves the file ID reference */
+               pb.fidParam.ioNamePtr = (StringPtr) &(source->name);
+               pb.fidParam.ioVRefNum = source->vRefNum;
+               pb.fidParam.ioDestNamePtr = (StringPtr) &(dest->name);
+               pb.fidParam.ioDestDirID = dest->parID;
+               pb.fidParam.ioSrcDirID = source->parID;
+       
+               result = PBExchangeFilesSync(&pb);
+       
+               /* Note: The compatibility case won't work for files with *Btree control blocks. */
+               /* Right now the only *Btree files are created by the system. */
+               if ( result != noErr )
+               {
+                       pb.ioParam.ioNamePtr = NULL;
+                       pb.ioParam.ioBuffer = (Ptr) &volInfo;
+                       pb.ioParam.ioReqCount = sizeof(volInfo);
+                       result2 = PBHGetVolParmsSync(&pb);
+                       
+                       /* continue if volume has no fileID support (or no GetVolParms support) */
+                       if ( (result2 == noErr) && hasFileIDs(volInfo) )
+                       {
+                               goto errorExit3;
+                       }
+       
+                       /* Get the catalog information for each file */
+                       /* and make sure both files are *really* files */
+                       catInfoSource.hFileInfo.ioVRefNum = source->vRefNum;
+                       catInfoSource.hFileInfo.ioFDirIndex = 0;
+                       catInfoSource.hFileInfo.ioNamePtr = (StringPtr) &(source->name);
+                       catInfoSource.hFileInfo.ioDirID = source->parID;
+                       catInfoSource.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
+                       result = PBGetCatInfoSync(&catInfoSource);
+                       if ( result != noErr )
+                       {
+                               goto errorExit3;
+                       }
+                       if ( (catInfoSource.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+                       {
+                               result = notAFileErr;
+                               goto errorExit3;
+                       }
+                       
+                       catInfoDest.hFileInfo.ioVRefNum = dest->vRefNum;
+                       catInfoDest.hFileInfo.ioFDirIndex = 0;
+                       catInfoDest.hFileInfo.ioNamePtr = (StringPtr) &(dest->name);
+                       catInfoDest.hFileInfo.ioDirID = dest->parID;
+                       catInfoDest.hFileInfo.ioACUser = 0; /* ioACUser used to be filler2 */
+                       result = PBGetCatInfoSync(&catInfoDest);
+                       if ( result != noErr )
+                       {
+                               goto errorExit3;
+                       }
+                       if ( (catInfoDest.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+                       {
+                               result = notAFileErr;
+                               goto errorExit3;
+                       }
+                       
+                       /* generate 2 filenames that are unique in both directories */
+                       theSeed = 0x64666A6C;   /* a fine unlikely filename */
+                       unique1Ptr = (StringPtr)&unique1;
+                       unique2Ptr = (StringPtr)&unique2;
+                       
+                       result = GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique1Ptr);
+                       if ( result != noErr )
+                       {
+                               goto errorExit3;
+                       }
+       
+                       GenerateUniqueName(source->vRefNum, &theSeed, source->parID, dest->parID, unique2Ptr);
+                       if ( result != noErr )
+                       {
+                               goto errorExit3;
+                       }
+       
+                       /* rename source to unique1 */
+                       pb.fileParam.ioNamePtr = (StringPtr) &(source->name);
+                       pb.ioParam.ioMisc = (Ptr) unique1Ptr;
+                       pb.ioParam.ioVersNum = 0;
+                       result = PBHRenameSync(&pb);
+                       if ( result != noErr )
+                       {
+                               goto errorExit3;
+                       }
+                       
+                       /* rename dest to unique2 */
+                       pb.ioParam.ioMisc = (Ptr) unique2Ptr;
+                       pb.ioParam.ioVersNum = 0;
+                       pb.fileParam.ioNamePtr = (StringPtr) &(dest->name);
+                       pb.fileParam.ioDirID = dest->parID;
+                       result = PBHRenameSync(&pb);
+                       if ( result != noErr )
+                       {
+                               goto errorExit2;        /* back out gracefully by renaming unique1 back to source */
+                       }
+                               
+                       /* If files are not in same directory, swap their locations */
+                       if ( source->parID != dest->parID )
+                       {
+                               /* move source file to dest directory */
+                               pb.copyParam.ioNamePtr = unique1Ptr;
+                               pb.copyParam.ioNewName = NULL;
+                               pb.copyParam.ioNewDirID = dest->parID;
+                               pb.copyParam.ioDirID = source->parID;
+                               result = PBCatMoveSync((CMovePBPtr) &pb);
+                               if ( result != noErr )
+                               {
+                                       goto errorExit1;        /* back out gracefully by renaming both files to original names */
+                               }
+                               
+                               /* move dest file to source directory */
+                               pb.copyParam.ioNamePtr = unique2Ptr;
+                               pb.copyParam.ioNewDirID = source->parID;
+                               pb.copyParam.ioDirID = dest->parID;
+                               result = PBCatMoveSync((CMovePBPtr) &pb);
+                               if ( result != noErr)
+                               {
+                                       /* life is very bad.  We'll at least try to move source back */
+                                       pb.copyParam.ioNamePtr = unique1Ptr;
+                                       pb.copyParam.ioNewName = NULL;
+                                       pb.copyParam.ioNewDirID = source->parID;
+                                       pb.copyParam.ioDirID = dest->parID;
+                                       (void) PBCatMoveSync((CMovePBPtr) &pb); /* ignore errors */
+                                       goto errorExit1;        /* back out gracefully by renaming both files to original names */
+                               }
+                       }
+                       
+                       /* Make unique1Ptr point to file in source->parID */
+                       /* and unique2Ptr point to file in dest->parID */
+                       /* This lets us fall through to the rename code below */
+                       swapola = unique1Ptr;
+                       unique1Ptr = unique2Ptr;
+                       unique2Ptr = swapola;
+       
+                       /* At this point, the files are in their new locations (if they were moved) */
+                       /* Source is named Unique1 (name pointed to by unique2Ptr) and is in dest->parID */
+                       /* Dest is named Unique2 (name pointed to by unique1Ptr) and is in source->parID */
+                       /* Need to swap attributes except mod date and swap names */
+       
+                       /* swap the catalog info by re-aiming the CInfoPB's */
+                       catInfoSource.hFileInfo.ioNamePtr = unique1Ptr;
+                       catInfoDest.hFileInfo.ioNamePtr = unique2Ptr;
+                       
+                       catInfoSource.hFileInfo.ioDirID = source->parID;
+                       catInfoDest.hFileInfo.ioDirID = dest->parID;
+                       
+                       /* Swap the original mod dates with each file */
+                       temp = catInfoSource.hFileInfo.ioFlMdDat;
+                       catInfoSource.hFileInfo.ioFlMdDat = catInfoDest.hFileInfo.ioFlMdDat;
+                       catInfoDest.hFileInfo.ioFlMdDat = temp;
+                       
+                       /* Here's the swap (ignore errors) */
+                       (void) PBSetCatInfoSync(&catInfoSource); 
+                       (void) PBSetCatInfoSync(&catInfoDest);
+                       
+                       /* rename unique2 back to dest */
+errorExit1:
+                       pb.ioParam.ioMisc = (Ptr) &(dest->name);
+                       pb.ioParam.ioVersNum = 0;
+                       pb.fileParam.ioNamePtr = unique2Ptr;
+                       pb.fileParam.ioDirID = dest->parID;
+                       (void) PBHRenameSync(&pb);      /* ignore errors */
+       
+                       /* rename unique1 back to source */
+errorExit2:
+                       pb.ioParam.ioMisc = (Ptr) &(source->name);
+                       pb.ioParam.ioVersNum = 0;
+                       pb.fileParam.ioNamePtr = unique1Ptr;
+                       pb.fileParam.ioDirID = source->parID;
+                       (void) PBHRenameSync(&pb); /* ignore errors */
+               }
+errorExit3: { /* null statement */ }
+               return ( result );
+       }
+       else
+#endif /* !__MACOSSEVENFIVEORLATER */
+       {
+               return ( FSpExchangeFiles(source, dest) );
+       }
+}
+
+/*****************************************************************************/
+
+/* 
+**     Resource Manager FSp calls
+*/
+
+/*****************************************************************************/
+
+pascal short   FSpOpenResFileCompat(const FSSpec *spec,
+                                                                        SignedByte permission)
+{
+#if !__MACOSSEVENORLATER
+       if ( !FSHasFSSpecCalls() && !QTHasFSSpecCalls() )
+       {
+               return ( HOpenResFile(spec->vRefNum, spec->parID, spec->name, permission) );
+       }
+       else
+#endif /* !__MACOSSEVENORLATER */
+       {
+               return ( FSpOpenResFile(spec, permission) );
+       }
+}
+
+/*****************************************************************************/
+
+pascal void    FSpCreateResFileCompat(const FSSpec *spec,
+                                                                          OSType creator,
+                                                                          OSType fileType,
+                                                                          ScriptCode scriptTag)
+{      
+#if !__MACOSSEVENFIVEONEORLATER
+       if (
+#if !__MACOSSEVENORLATER
+                (!FSHasFSSpecCalls() && !QTHasFSSpecCalls()) ||
+#endif /* !__MACOSSEVENORLATER */
+                !HasFSpCreateScriptSupportFix() )
+       {
+               OSErr                   result;
+               CInfoPBRec              pb;
+               
+               HCreateResFile(spec->vRefNum, spec->parID, spec->name);
+               if ( ResError() == noErr )
+               {
+                       /* get info on created item */
+                       pb.hFileInfo.ioVRefNum = spec->vRefNum;
+                       pb.hFileInfo.ioDirID = spec->parID;
+                       pb.hFileInfo.ioNamePtr = (StringPtr) &(spec->name);
+                       pb.hFileInfo.ioFDirIndex = 0;
+                       result = PBGetCatInfoSync(&pb);
+                       if ( result == noErr )
+                       {
+                               /* Set fdScript in FXInfo */
+                               /* The negative script constants (smSystemScript, smCurrentScript, and smAllScripts) */
+                               /* don't make sense on disk, so only use scriptTag if scriptTag >= smRoman */
+                               /* (smRoman is 0). fdScript is valid if high bit is set (see IM-6, page 9-38) */
+                               pb.hFileInfo.ioFlXFndrInfo.fdScript = (scriptTag >= smRoman) ?
+                                                                                                               ((char)scriptTag | (char)0x80) :
+                                                                                                               (smRoman);
+                               /* Set creator/fileType */
+                               pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
+                               pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
+                               
+                               /* Restore ioDirID field in pb which was changed by PBGetCatInfo */
+                               pb.hFileInfo.ioDirID = spec->parID;
+                               result = PBSetCatInfoSync(&pb);
+                       }
+                       /* Set ResErr low memory global to result */
+                       LMSetResErr(result);
+               }
+               return;
+       }
+       else
+#endif /* !__MACOSSEVENFIVEONEORLATER */
+       {
+               FSpCreateResFile(spec, creator, fileType, scriptTag);
+               return;
+       }
+}
+
+/*****************************************************************************/
diff --git a/src/mac/morefile/FSpCompa.h b/src/mac/morefile/FSpCompa.h
new file mode 100644 (file)
index 0000000..1dbc11f
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     FSSpec compatibility functions.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           FSpCompat.h
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#ifndef __FSPCOMPAT__
+#define __FSPCOMPAT__
+
+#include <Types.h>
+#include <Files.h>
+
+#include "Optim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+pascal OSErr   FSMakeFSSpecCompat(short vRefNum,
+                                                                  long dirID,
+                                                                  ConstStr255Param fileName,
+                                                                  FSSpec *spec);
+/*     ¦ Initialize a FSSpec record.
+       The FSMakeFSSpecCompat function fills in the fields of an FSSpec record.
+       If the file system can't create the FSSpec, then the compatibility code
+       creates a FSSpec that is exactly like an FSSpec except that spec.name
+       for a file may not have the same capitalization as the file's catalog
+       entry on the disk volume. That is because fileName is parsed to get the
+       name instead of getting the name back from the file system. This works
+       fine with System 6 where FSMakeSpec isn't available.
+       
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       fileName        input:  Pointer to object name, or nil when dirID specifies
+                                               a directory that's the object.
+       spec            output: A file system specification to be filled in by
+                                               FSMakeFSSpecCompat.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             Volume doesnÕt exist    
+               fnfErr                          -43             File or directory does not exist
+                                                                       (FSSpec is still valid) 
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpOpenDFCompat(const FSSpec *spec,
+                                                               char permission,
+                                                               short *refNum);
+/*     ¦ Open a file's data fork.
+       The FSpOpenDFCompat function opens the data fork of the file specified
+       by spec.
+       Differences from FSpOpenDF: If FSpOpenDF isn't available,
+       FSpOpenDFCompat uses PHBOpen because System 6 doesn't support PBHOpenDF.
+       This means FSpOpenDFCompat could accidentally open a driver if the
+       spec->name begins with a period.
+       
+       spec            input:  An FSSpec record specifying the file whose data
+                                               fork is to be opened.
+       permission      input:  A constant indicating the desired file access
+                                               permissions.
+       refNum          output: A reference number of an access path to the file's
+                                               data fork.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               bdNamErr                        -37             Bad filename    
+               tmfoErr                         -42             Too many files open     
+               fnfErr                          -43             File not found  
+               opWrErr                         -49             File already open for writing   
+               permErr                         -54             Attempt to open locked file for writing 
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access to
+                                                                       the file
+       
+       __________
+       
+       See also:       FSpOpenAware
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpOpenRFCompat(const FSSpec *spec,
+                                                               char permission,
+                                                               short *refNum);
+/*     ¦ Open a file's resource fork.
+       The FSpOpenRFCompat function opens the resource fork of the file
+       specified by spec.
+       
+       spec            input:  An FSSpec record specifying the file whose resource
+                                               fork is to be opened.
+       permission      input:  A constant indicating the desired file access
+                                               permissions.
+       refNum          output: A reference number of an access path to the file's
+                                               resource fork.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               bdNamErr                        -37             Bad filename    
+               tmfoErr                         -42             Too many files open     
+               fnfErr                          -43             File not found  
+               opWrErr                         -49             File already open for writing   
+               permErr                         -54             Attempt to open locked file for writing 
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access to
+                                                                       the file
+       
+       __________
+       
+       See also:       FSpOpenRFAware
+*/
+
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCreateCompat(const FSSpec *spec,
+                                                               OSType creator,
+                                                               OSType fileType,
+                                                               ScriptCode scriptTag);
+/*     ¦ Create a new file.
+       The FSpCreateCompat function creates a new file with the specified
+       type, creator, and script code.
+       Differences from FSpCreate: FSpCreateCompat correctly sets the
+       fdScript in the file's FXInfo record to scriptTag if the problem
+       isn't fixed in the File Manager code.
+       
+       spec            input:  An FSSpec record specifying the file to create.
+       creator         input:  The creator of the new file.
+       fileType        input   The file type of the new file.
+       scriptCode      input:  The code of the script system in which the file
+                                               name is to be displayed.
+       
+       Result Codes
+               noErr                           0               No error        
+               dirFulErr                       -33             File directory full     
+               dskFulErr                       -34             Disk is full    
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               bdNamErr                        -37             Bad filename    
+               fnfErr                          -43             Directory not found or incomplete pathname      
+               wPrErr                          -44             Hardware volume lock    
+               vLckdErr                        -46             Software volume lock    
+               dupFNErr                        -48             Duplicate filename and version  
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname      
+               afpAccessDenied         -5000   User does not have the correct access   
+               afpObjectTypeErr        -5025   A directory exists with that name       
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDirCreateCompat(const FSSpec *spec,
+                                                                  ScriptCode scriptTag,
+                                                                  long *createdDirID);
+/*     ¦ Create a new directory.
+       The FSpDirCreateCompat function creates a new directory and returns the
+       directory ID of the newDirectory.
+       
+       spec                    input:  An FSSpec record specifying the directory to
+                                                       create.
+       scriptCode              input:  The code of the script system in which the
+                                                       directory name is to be displayed.
+       createdDirID    output: The directory ID of the directory that was
+                                                       created.
+       
+       Result Codes
+               noErr                           0               No error        
+               dirFulErr                       -33             File directory full     
+               dskFulErr                       -34             Disk is full    
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               bdNamErr                        -37             Bad filename    
+               fnfErr                          -43             Directory not found or incomplete pathname      
+               wPrErr                          -44             Hardware volume lock    
+               vLckdErr                        -46             Software volume lock    
+               dupFNErr                        -48             Duplicate filename and version  
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname      
+               wrgVolTypErr            -123    Not an HFS volume       
+               afpAccessDenied         -5000   User does not have the correct access   
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDeleteCompat(const FSSpec *spec);
+/*     ¦ Delete a file or directory.
+       The FSpDeleteCompat function deletes a file or directory.
+       
+       spec                    input:  An FSSpec record specifying the file or 
+                                                       directory to delete.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               bdNamErr                        -37             Bad filename    
+               fnfErr                          -43             File not found  
+               wPrErr                          -44             Hardware volume lock    
+               fLckdErr                        -45             File is locked  
+               vLckdErr                        -46             Software volume lock    
+               fBsyErr                         -47             File busy, directory not empty, or
+                                                                       working directory control block open    
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname      
+               afpAccessDenied         -5000   User does not have the correct access   
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetFInfoCompat(const FSSpec *spec,
+                                                                 FInfo *fndrInfo);
+/*     ¦ Get the finder information for a file.
+       The FSpGetFInfoCompat function gets the finder information for a file.
+
+       spec            input:  An FSSpec record specifying the file.
+       fndrInfo        output: If the object is a file, then its FInfo.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               bdNamErr                        -37             Bad filename    
+               fnfErr                          -43             File not found  
+               paramErr                        -50             No default volume       
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname      
+               afpAccessDenied         -5000   User does not have the correct access   
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname      
+       
+       __________
+       
+       Also see:       FSpGetDInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetFInfoCompat(const FSSpec *spec,
+                                                                 const FInfo *fndrInfo);
+/*     ¦ Set the finder information for a file.
+       The FSpSetFInfoCompat function sets the finder information for a file.
+
+       spec            input:  An FSSpec record specifying the file.
+       fndrInfo        input:  The FInfo.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               bdNamErr                        -37             Bad filename    
+               fnfErr                          -43             File not found  
+               wPrErr                          -44             Hardware volume lock    
+               fLckdErr                        -45             File is locked  
+               vLckdErr                        -46             Software volume lock    
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname      
+               afpAccessDenied         -5000   User does not have the correct access   
+               afpObjectTypeErr        -5025   Object was a directory  
+       
+       __________
+       
+       Also see:       FSpSetDInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetFLockCompat(const FSSpec *spec);
+/*     ¦ Lock a file.
+       The FSpSetFLockCompat function locks a file.
+
+       spec            input:  An FSSpec record specifying the file.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               fnfErr                          -43             File not found  
+               wPrErr                          -44             Hardware volume lock    
+               vLckdErr                        -46             Software volume lock    
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname      
+               afpAccessDenied         -5000   User does not have the correct access to
+                                                                       the file        
+               afpObjectTypeErr        -5025   Folder locking not supported by volume  
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpRstFLockCompat(const FSSpec *spec);
+/*     ¦ Unlock a file.
+       The FSpRstFLockCompat function unlocks a file.
+
+       spec            input:  An FSSpec record specifying the file.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               fnfErr                          -43             File not found  
+               wPrErr                          -44             Hardware volume lock    
+               vLckdErr                        -46             Software volume lock    
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname      
+               afpAccessDenied         -5000   User does not have the correct access to
+                                                                       the file        
+               afpObjectTypeErr        -5025   Folder locking not supported by volume  
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpRenameCompat(const FSSpec *spec,
+                                                               ConstStr255Param newName);
+/*     ¦ Rename a file or directory.
+       The FSpRenameCompat function renames a file or directory.
+
+       spec            input:  An FSSpec record specifying the file.
+       newName         input:  The new name of the file or directory.
+       
+       Result Codes
+               noErr                           0               No error        
+               dirFulErr                       -33             File directory full     
+               dskFulErr                       -34             Volume is full  
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               bdNamErr                        -37             Bad filename    
+               fnfErr                          -43             File not found  
+               wPrErr                          -44             Hardware volume lock    
+               fLckdErr                        -45             File is locked  
+               vLckdErr                        -46             Software volume lock    
+               dupFNErr                        -48             Duplicate filename and version  
+               paramErr                        -50             No default volume       
+               fsRnErr                         -59             Problem during rename   
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname      
+               afpAccessDenied         -5000   User does not have the correct access to
+                                                                       the file        
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCatMoveCompat(const FSSpec *source,
+                                                                const FSSpec *dest);
+/*     ¦ Move a file or directory to a different location on on the same volume.
+       The FSpCatMoveCompat function moves a file or directory to a different
+       location on on the same volume.
+
+       source          input:  An FSSpec record specifying the file or directory.
+       dest            input:  An FSSpec record specifying the name and location
+                                               of the directory into which the source file or
+                                               directory is to be moved.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             No such volume  
+               ioErr                           -36             I/O error       
+               bdNamErr                        -37             Bad filename or attempt to move into
+                                                                       a file  
+               fnfErr                          -43             File not found  
+               wPrErr                          -44             Hardware volume lock    
+               fLckdErr                        -45             Target directory is locked      
+               vLckdErr                        -46             Software volume lock    
+               dupFNErr                        -48             Duplicate filename and version  
+               paramErr                        -50             No default volume       
+               badMovErr                       -122    Attempt to move into offspring  
+               wrgVolTypErr            -123    Not an HFS volume       
+               afpAccessDenied         -5000   User does not have the correct access to
+                                                                       the file        
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpExchangeFilesCompat(const FSSpec *source,
+                                                                          const FSSpec *dest);
+/*     ¦ Exchange the data stored in two files on the same volume.
+       The FSpExchangeFilesCompat function swaps the data in two files by
+       changing the information in the volume's catalog and, if the files
+       are open, in the file control blocks.
+       Differences from FSpExchangeFiles: Correctly exchanges files on volumes
+       that don't support PBExchangeFiles. FSpExchangeFiles attempts to support
+       volumes that don't support PBExchangeFiles, but in System 7, 7.0.1, 7.1,
+       and 7 Pro, the compatibility code just doesn't work on volumes that
+       don't support PBExchangeFiles (even though you may get a noErr result).
+       System Update 3.0 and System 7.5 and later have the problems in
+       FSpExchangeFiles corrected.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             Volume not found        
+               ioErr                           -36             I/O error       
+               fnfErr                          -43             File not found  
+               fLckdErr                        -45             File is locked  
+               vLckdErr                        -46             Volume is locked or read-only   
+               paramErr                        -50             Function not supported by volume        
+               volOfflinErr            -53             Volume is offline       
+               wrgVolTypErr            -123    Not an HFS volume       
+               diffVolErr                      -1303   Files on different volumes      
+               afpAccessDenied         -5000   User does not have the correct access   
+               afpObjectTypeErr        -5025   Object is a directory, not a file       
+               afpSameObjectErr        -5038   Source and destination files are the same       
+*/
+
+/*****************************************************************************/
+
+pascal short   FSpOpenResFileCompat(const FSSpec *spec,
+                                                                        SignedByte permission);
+/*     ¦ Open a file's resource file.
+       The FSpOpenResFileCompat function opens the resource file specified
+       by spec.
+       
+       spec                    input:  An FSSpec record specifying the file whose
+                                                       resource file is to be opened.
+       permission              input:  A constant indicating the desired file access
+                                                       permissions.
+       function result output: A resource file reference number, or if there's
+                                                       an error -1.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          Ð35             No such volume
+               ioErr                           Ð36             I/O error
+               bdNamErr                        Ð37             Bad filename or volume name (perhaps zero
+                                                                       length)
+               eofErr                          Ð39             End of file
+               tmfoErr                         Ð42             Too many files open
+               fnfErr                          Ð43             File not found
+               opWrErr                         Ð49             File already open with write permission
+               permErr                         Ð54             Permissions error (on file open)
+               extFSErr                        Ð58             Volume belongs to an external file system
+               memFullErr                      Ð108    Not enough room in heap zone
+               dirNFErr                        Ð120    Directory not found
+               mapReadErr                      Ð199    Map inconsistent with operation
+*/
+
+/*****************************************************************************/
+
+pascal void    FSpCreateResFileCompat(const FSSpec *spec,
+                                                                          OSType creator,
+                                                                          OSType fileType,
+                                                                          ScriptCode scriptTag);
+/*     ¦ Create a resource file.
+       The FSpCreateResFileCompat function creates a new resource file with
+       the specified type, creator, and script code.
+       Differences from FSpCreateResFile: FSpCreateResFileCompat correctly
+       sets the fdScript in the file's FXInfo record to scriptTag if the
+       problem isn't fixed in the File Manager code.
+       
+       spec            input:  An FSSpec record specifying the resource file to create.
+       creator         input:  The creator of the new file.
+       fileType        input   The file type of the new file.
+       scriptCode      input:  The code of the script system in which the file
+                                               name is to be displayed.
+       
+       Result Codes
+               noErr                           0               No error
+               dirFulErr                       Ð33             Directory full
+               dskFulErr                       Ð34             Disk full
+               nsvErr                          Ð35             No such volume
+               ioErr                           Ð36             I/O error
+               bdNamErr                        Ð37             Bad filename or volume name (perhaps zero
+                                                                       length)
+               tmfoErr                         Ð42             Too many files open
+               wPrErrw                         Ð44             Disk is write-protected
+               fLckdErr                        Ð45             File is locked
+*/
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "OptimEnd.h"
+
+#endif /* __FSPCOMPAT__ */
+
diff --git a/src/mac/morefile/FileCopy.cpp b/src/mac/morefile/FileCopy.cpp
new file mode 100644 (file)
index 0000000..8843c9b
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     FileCopy: A robust, general purpose file copy routine.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           FileCopy.c
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#include <Types.h>
+#include <Errors.h>
+#include <Memory.h>
+#include <Files.h>
+
+#define        __COMPILINGMOREFILES
+
+#include "MoreFile.h"
+#include "MoreExtr.h"
+#include "MoreDesk.h"
+#include "FileCopy.h"
+
+/*****************************************************************************/
+
+/* local constants */
+
+/*     The deny-mode privileges to use when opening the source and destination files. */
+
+enum
+{
+       srcCopyMode = dmRdDenyWr,
+       dstCopyMode = dmWrDenyRdWr
+};
+
+/*     The largest (16K) and smallest (.5K) copy buffer to use if the caller doesn't supply 
+**     their own copy buffer. */
+
+enum
+{
+       bigCopyBuffSize  = 0x00004000,
+       minCopyBuffSize  = 0x00000200
+};
+
+/*****************************************************************************/
+
+/* static prototypes */
+
+static OSErr   GetDestinationDirInfo(short vRefNum,
+                                                                         long dirID,
+                                                                         ConstStr255Param name,
+                                                                         long *theDirID,
+                                                                         Boolean *isDirectory,
+                                                                         Boolean *isDropBox);
+/*     GetDestinationDirInfo tells us if the destination is a directory, it's
+       directory ID, and if it's an AppleShare drop box (write privileges only --
+       no read or search privileges).
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       name            input:  Pointer to object name, or nil when dirID
+                                               specifies a directory that's the object.
+       theDirID        output: If the object is a file, then its parent directory
+                                               ID. If the object is a directory, then its ID.
+       isDirectory     output: True if object is a directory; false if
+                                               object is a file.
+       isDropBox       output: True if directory is an AppleShare drop box.
+*/
+
+static OSErr   CheckForForks(short vRefNum,
+                                                         long dirID,
+                                                         ConstStr255Param name,
+                                                         Boolean *hasDataFork,
+                                                         Boolean *hasResourceFork);
+/*     CheckForForks tells us if there is a data or resource fork to copy.
+       vRefNum         input:  Volume specification of the file's current
+                                                       location.
+       dirID           input:  Directory ID of the file's current location.
+       name            input:  The name of the file.
+*/
+
+static OSErr   PreflightFileCopySpace(short srcVRefNum,
+                                                                          long srcDirID,
+                                                                          ConstStr255Param srcName,
+                                                                          ConstStr255Param dstVolName,
+                                                                          short dstVRefNum,
+                                                                          Boolean *spaceOK);
+/*     PreflightFileCopySpace determines if there's enough space on a
+       volume to copy the specified file to that volume.
+       Note: The results of this routine are not perfect. For example if the
+       volume's catalog or extents overflow file grows when the new file is
+       created, more allocation blocks may be needed beyond those needed for
+       the file's data and resource forks.
+
+       srcVRefNum              input:  Volume specification of the file's current
+                                                       location.
+       srcDirID                input:  Directory ID of the file's current location.
+       srcName                 input:  The name of the file.
+       dstVolName              input:  A pointer to the name of the volume where
+                                                       the file will be copied or NULL.
+       dstVRefNum              input:  Volume specification indicating the volume
+                                                       where the file will be copied.
+       spaceOK                 output: true if there's enough space on the volume for
+                                                       the file's data and resource forks.
+*/
+
+/*****************************************************************************/
+
+static OSErr   GetDestinationDirInfo(short vRefNum,
+                                                                         long dirID,
+                                                                         ConstStr255Param name,
+                                                                         long *theDirID,
+                                                                         Boolean *isDirectory,
+                                                                         Boolean *isDropBox)
+{
+       CInfoPBRec pb;
+       OSErr error;
+
+       pb.dirInfo.ioACUser = 0;        /* ioACUser used to be filler2, clear it before calling GetCatInfo */
+       error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+       *theDirID = pb.dirInfo.ioDrDirID;
+       *isDirectory = (pb.dirInfo.ioFlAttrib & ioDirMask) != 0;
+       /* see if access priviledges are make changes, not see folder, and not see files (drop box) */
+       *isDropBox = ((pb.dirInfo.ioACUser & 0x07) == 0x03);
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+static OSErr   CheckForForks(short vRefNum,
+                                                         long dirID,
+                                                         ConstStr255Param name,
+                                                         Boolean *hasDataFork,
+                                                         Boolean *hasResourceFork)
+{
+       HParamBlockRec pb;
+       OSErr error;
+       
+       pb.fileParam.ioNamePtr = (StringPtr)name;
+       pb.fileParam.ioVRefNum = vRefNum;
+       pb.fileParam.ioFVersNum = 0;
+       pb.fileParam.ioDirID = dirID;
+       pb.fileParam.ioFDirIndex = 0;
+       error = PBHGetFInfoSync(&pb);
+       *hasDataFork = (pb.fileParam.ioFlLgLen != 0);
+       *hasResourceFork = (pb.fileParam.ioFlRLgLen != 0);
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+static OSErr   PreflightFileCopySpace(short srcVRefNum,
+                                                                          long srcDirID,
+                                                                          ConstStr255Param srcName,
+                                                                          ConstStr255Param dstVolName,
+                                                                          short dstVRefNum,
+                                                                          Boolean *spaceOK)
+{
+       UniversalFMPB pb;
+       OSErr error;
+       unsigned long dstFreeBlocks;
+       unsigned long dstBlksPerAllocBlk;
+       unsigned long srcDataBlks;
+       unsigned long srcResourceBlks;
+       
+       error = XGetVolumeInfoNoName(dstVolName, dstVRefNum, &pb.xPB);
+       if ( error == noErr )
+       {
+               /* get allocation block size (always multiple of 512) and divide by 512
+                 to get number of 512-byte blocks per allocation block */
+               dstBlksPerAllocBlk = ((unsigned long)pb.xPB.ioVAlBlkSiz >> 9);
+               
+               /* Convert freeBytes to free disk blocks (512-byte blocks) */
+               dstFreeBlocks = (pb.xPB.ioVFreeBytes.hi << 23) + (pb.xPB.ioVFreeBytes.lo >> 9);
+               
+               /* Now, get the size of the file's data resource forks */
+               pb.hPB.fileParam.ioNamePtr = (StringPtr)srcName;
+               pb.hPB.fileParam.ioVRefNum = srcVRefNum;
+               pb.hPB.fileParam.ioFVersNum = 0;
+               pb.hPB.fileParam.ioDirID = srcDirID;
+               pb.hPB.fileParam.ioFDirIndex = 0;
+               error = PBHGetFInfoSync(&pb.hPB);
+               if ( error == noErr )
+               {
+                       /* Since space on Mac OS disks is always allocated in allocation blocks, */
+                       /* this code takes into account rounding up to the end of an allocation block. */
+
+                       /* get number of 512-byte blocks needed for data fork */
+                       if ( ((unsigned long)pb.hPB.fileParam.ioFlLgLen & 0x000001ff) != 0 )
+                       {
+                               srcDataBlks = ((unsigned long)pb.hPB.fileParam.ioFlLgLen >> 9) + 1;
+                       }
+                       else
+                       {
+                               srcDataBlks = (unsigned long)pb.hPB.fileParam.ioFlLgLen >> 9;
+                       }
+                       
+                       /* now, calculate number of new allocation blocks needed */
+                       if ( srcDataBlks % dstBlksPerAllocBlk )
+                       {
+                               srcDataBlks = (srcDataBlks / dstBlksPerAllocBlk) + 1;
+                       }
+                       else
+                       {
+                               srcDataBlks /= dstBlksPerAllocBlk;
+                       }
+               
+                       /* get number of 512-byte blocks needed for resource fork */
+                       if ( ((unsigned long)pb.hPB.fileParam.ioFlRLgLen & 0x000001ff) != 0 )
+                       {
+                               srcResourceBlks = ((unsigned long)pb.hPB.fileParam.ioFlRLgLen >> 9) + 1;
+                       }
+                       else
+                       {
+                               srcResourceBlks = (unsigned long)pb.hPB.fileParam.ioFlRLgLen >> 9;
+                       }
+
+                       /* now, calculate number of new allocation blocks needed */
+                       if ( srcResourceBlks % dstBlksPerAllocBlk )
+                       {
+                               srcResourceBlks = (srcResourceBlks / dstBlksPerAllocBlk) + 1;
+                       }
+                       else
+                       {
+                               srcResourceBlks /= dstBlksPerAllocBlk;
+                       }
+                       
+                       /* Is there enough room on the destination volume for the source file? */
+                       *spaceOK = ( ((srcDataBlks + srcResourceBlks) * dstBlksPerAllocBlk) <= dstFreeBlocks );
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FileCopy(short srcVRefNum,
+                                                long srcDirID,
+                                                ConstStr255Param srcName,
+                                                short dstVRefNum,
+                                                long dstDirID,
+                                                ConstStr255Param dstPathname,
+                                                ConstStr255Param copyName,
+                                                void *copyBufferPtr,
+                                                long copyBufferSize,
+                                                Boolean preflight)
+{
+       OSErr   err;
+
+       short   srcRefNum = 0,                  /* 0 when source data and resource fork are closed  */
+                       dstDataRefNum = 0,              /* 0 when destination data fork is closed */
+                       dstRsrcRefNum = 0;              /* 0 when destination resource fork is closed */
+       
+       Str63   dstName;                                /* The filename of the destination. It might be the
+                                                                       ** source filename, it might be a new name... */
+       
+       GetVolParmsInfoBuffer infoBuffer; /* Where PBGetVolParms dumps its info */
+       long    srcServerAdr;                   /* AppleTalk server address of source (if any) */
+       
+       Boolean dstCreated = false,             /* true when destination file has been created */
+                       ourCopyBuffer = false,  /* true if we had to allocate the copy buffer */
+                       isDirectory,                    /* true if destination is really a directory */
+                       isDropBox;                              /* true if destination is an AppleShare drop box */
+       
+       long    tempLong;
+       short   tempInt;
+       
+       Boolean spaceOK;                                /* true if there's enough room to copy the file to the destination volume */
+
+       Boolean hasDataFork;
+       Boolean hasResourceFork;
+
+       /* Preflight for size */
+       if ( preflight )
+       {
+               err = PreflightFileCopySpace(srcVRefNum, srcDirID, srcName,
+                                                                        dstPathname, dstVRefNum, &spaceOK);
+               if ( err != noErr )
+               {
+                       return ( err );
+               }
+               
+               if ( !spaceOK )
+               {
+                       return ( dskFulErr );
+               }
+       }
+
+       /* get the destination's real dirID and make sure it really is a directory */
+       err = GetDestinationDirInfo(dstVRefNum, dstDirID, dstPathname,
+                                                               &dstDirID, &isDirectory, &isDropBox);
+       if ( err != noErr )
+       {
+               goto ErrorExit;
+       }
+       
+       if ( !isDirectory )
+       {
+               return ( dirNFErr );
+       }
+
+       /* get the destination's real vRefNum */
+       err = DetermineVRefNum(dstPathname, dstVRefNum, &dstVRefNum);
+       if ( err != noErr )
+       {
+               goto ErrorExit;
+       }
+       
+       /* See if PBHCopyFile can be used.  Using PBHCopyFile saves time by letting the file server
+       ** copy the file if the source and destination locations are on the same file server. */
+       tempLong = sizeof(infoBuffer);
+       err = HGetVolParms(srcName, srcVRefNum, &infoBuffer, &tempLong);
+       if ( (err != noErr) && (err != paramErr) )
+       {
+               return ( err );
+       }
+
+       if ( (err != paramErr) && hasCopyFile(infoBuffer) )
+       {
+               /* The source volume supports PBHCopyFile. */
+               srcServerAdr = infoBuffer.vMServerAdr;
+
+               /* Now, see if the destination volume is on the same file server. */
+               tempLong = sizeof(infoBuffer);
+               err = HGetVolParms(NULL, dstVRefNum, &infoBuffer, &tempLong);
+               if ( (err != noErr) && (err != paramErr) )
+               {
+                       return ( err );
+               }
+               if ( (err != paramErr) && (srcServerAdr == infoBuffer.vMServerAdr) )
+               {
+                       /* Source and Dest are on same server and PBHCopyFile is supported. Copy with CopyFile. */
+                       err = HCopyFile(srcVRefNum, srcDirID, srcName, dstVRefNum, dstDirID, NULL, copyName);
+                       if ( err != noErr )
+                       {
+                               return ( err );
+                       }
+                                               
+                       /* AppleShare's CopyFile clears the isAlias bit, so I still need to attempt to copy
+                          the File's attributes to attempt to get things right. */
+                       if ( copyName != NULL )                         /* Did caller supply copy file name? */
+                       {
+                               /* Yes, use the caller supplied copy file name. */
+                               (void) CopyFileMgrAttributes(srcVRefNum, srcDirID, srcName,
+                                                                                        dstVRefNum, dstDirID, copyName, true);
+                       }
+                       else
+                       {
+                               /* They didn't, so get the source file name and use it. */
+                               if ( GetFilenameFromPathname(srcName, dstName) == noErr )
+                               {
+                                       /* */
+                                       (void) CopyFileMgrAttributes(srcVRefNum, srcDirID, srcName,
+                                                                                                dstVRefNum, dstDirID, dstName, true);
+                               }
+                       }
+                       return ( err );
+               }
+       }
+
+       /* If we're here, then PBHCopyFile couldn't be used so we have to copy the file by hand. */
+
+       /* Make sure a copy buffer is allocated. */
+       if ( copyBufferPtr == NULL )
+       {
+               /* The caller didn't supply a copy buffer so grab one from the application heap.
+               ** Try to get a big copy buffer, if we can't, try for a 512-byte buffer.
+               ** If 512 bytes aren't available, we're in trouble. */
+               copyBufferSize = bigCopyBuffSize;
+               copyBufferPtr = NewPtr(copyBufferSize);
+               if ( copyBufferPtr == NULL )
+               {
+                       copyBufferSize = minCopyBuffSize;
+                       copyBufferPtr = NewPtr(copyBufferSize);
+                       if ( copyBufferPtr == NULL )
+                       {
+                               return ( memFullErr );
+                       }
+               }
+               ourCopyBuffer = true;
+       }
+
+       /* Open the source data fork. */
+       err = HOpenAware(srcVRefNum, srcDirID, srcName, srcCopyMode, &srcRefNum);
+       if ( err != noErr )
+               return ( err );
+       
+       /* Once a file is opened, we have to exit via ErrorExit to make sure things are cleaned up */
+       
+       /* See if the copy will be renamed. */
+       if ( copyName != NULL )                         /* Did caller supply copy file name? */
+               BlockMoveData(copyName, dstName, copyName[0] + 1);      /* Yes, use the caller supplied copy file name. */
+       else
+       {       /* They didn't, so get the source file name and use it. */
+               err = GetFileLocation(srcRefNum, &tempInt, &tempLong, dstName);
+               if ( err != noErr )
+               {
+                       goto ErrorExit;
+               }
+       }
+
+       /* Create the destination file. */
+       err = HCreateMinimum(dstVRefNum, dstDirID, dstName);
+       if ( err != noErr )
+       {
+               goto ErrorExit;
+       }
+       dstCreated = true;      /* After creating the destination file, any
+                                               ** error conditions should delete the destination file */
+
+       /* An AppleShare dropbox folder is a folder for which the user has the Make Changes
+       ** privilege (write access), but not See Files (read access) and See Folders (search access).
+       ** Copying a file into an AppleShare dropbox presents some special problems. Here are the
+       ** rules we have to follow to copy a file into a dropbox:
+       ** ¥ File attributes can be changed only when both forks of a file are empty.
+       ** ¥ DeskTop Manager comments can be added to a file only when both forks of a file 
+       **   are empty.
+       ** ¥ A fork can be opened for write access only when both forks of a file are empty.
+       ** So, with those rules to live with, we'll do those operations now while both forks
+       ** are empty. */
+
+       if ( isDropBox )
+       {
+               /* We only set the file attributes now if the file is being copied into a
+               ** drop box. In all other cases, it is better to set the attributes last
+               ** so that if FileCopy is modified to give up time to other processes
+               ** periodicly, the Finder won't try to read any bundle information (because
+               ** the bundle-bit will still be clear) from a partially copied file. If the
+               ** copy is into a drop box, we have to set the attributes now, but since the
+               ** destination forks are opened with write/deny-read/deny-write permissions,
+               ** any Finder that might see the file in the drop box won't be able to open
+               ** its resource fork until the resource fork is closed.
+               **
+               ** Note: if you do modify FileCopy to give up time to other processes, don't
+               ** give up time between the time the destination file is created (above) and
+               ** the time both forks are opened (below). That way, you stand the best chance
+               ** of making sure the Finder doesn't read a partially copied resource fork.
+               */
+               /* Copy attributes but don't lock the destination. */
+               err = CopyFileMgrAttributes(srcVRefNum, srcDirID, srcName,
+                                                                       dstVRefNum, dstDirID, dstName, false);
+               if ( err != noErr )
+               {
+                       goto ErrorExit;
+               }
+       }
+
+       /* Attempt to copy the comments while both forks are empty.
+       ** Ignore the result because we really don't care if it worked or not. */
+       (void) DTCopyComment(srcVRefNum, srcDirID, srcName, dstVRefNum, dstDirID, dstName);
+
+       /* See which forks we need to copy. By doing this, we won't create a data or resource fork
+       ** for the destination unless it's really needed (some foreign file systems such as
+       ** the ProDOS File System and Macintosh PC Exchange have to create additional disk
+       ** structures to support resource forks). */
+       err = CheckForForks(srcVRefNum, srcDirID, srcName, &hasDataFork, &hasResourceFork);
+       if ( err != noErr )
+       {
+               goto ErrorExit;
+       }
+       
+       if ( hasDataFork )
+       {
+               /* Open the destination data fork. */
+               err = HOpenAware(dstVRefNum, dstDirID, dstName, dstCopyMode, &dstDataRefNum);
+               if ( err != noErr )
+               {
+                       goto ErrorExit;
+               }
+       }
+
+       if ( hasResourceFork )
+       {
+               /* Open the destination resource fork. */
+               err = HOpenRFAware(dstVRefNum, dstDirID, dstName, dstCopyMode, &dstRsrcRefNum);
+               if ( err != noErr )
+               {
+                       goto ErrorExit;
+               }
+       }
+
+       if ( hasDataFork )
+       {
+               /* Copy the data fork. */
+               err = CopyFork(srcRefNum, dstDataRefNum, copyBufferPtr, copyBufferSize);
+               if ( err != noErr )
+               {
+                       goto ErrorExit;
+               }
+       
+               /* Close both data forks and clear reference numbers. */
+               (void) FSClose(srcRefNum);
+               (void) FSClose(dstDataRefNum);
+               srcRefNum = dstDataRefNum = 0;
+       }
+       else
+       {
+               /* Close the source data fork since it was opened earlier */
+               (void) FSClose(srcRefNum);
+               srcRefNum = 0;
+       }
+
+       if ( hasResourceFork )
+       {
+               /* Open the source resource fork. */
+               err = HOpenRFAware(srcVRefNum, srcDirID, srcName, srcCopyMode, &srcRefNum);
+               if ( err != noErr )
+               {
+                       goto ErrorExit;
+               }
+       
+               /* Copy the resource fork. */
+               err = CopyFork(srcRefNum, dstRsrcRefNum, copyBufferPtr, copyBufferSize);
+               if ( err != noErr )
+               {
+                       goto ErrorExit;
+               }
+       
+               /* Close both resource forks and clear reference numbers. */
+               (void) FSClose(srcRefNum);
+               (void) FSClose(dstRsrcRefNum);
+               srcRefNum = dstRsrcRefNum = 0;
+       }
+
+       /* Get rid of the copy buffer if we allocated it. */
+       if ( ourCopyBuffer )
+       {
+               DisposePtr((Ptr)copyBufferPtr);
+       }
+
+       /* Attempt to copy attributes again to set mod date.  Copy lock condition this time
+       ** since we're done with the copy operation.  This operation will fail if we're copying
+       ** into an AppleShare dropbox, so we don't check for error conditions. */
+       CopyFileMgrAttributes(srcVRefNum, srcDirID, srcName,
+                                                       dstVRefNum, dstDirID, dstName, true);
+
+       /* Hey, we did it! */
+       return ( noErr );
+       
+ErrorExit:
+       if ( srcRefNum != 0 )
+       {
+               (void) FSClose(srcRefNum);              /* Close the source file */
+       }
+       if ( dstDataRefNum != 0 )
+       {
+               (void) FSClose(dstDataRefNum);  /* Close the destination file data fork */
+       }
+       if ( dstRsrcRefNum != 0 )
+       {
+               (void) FSClose(dstRsrcRefNum);  /* Close the destination file resource fork */
+       }
+       if ( dstCreated )
+       {
+               (void) HDelete(dstVRefNum, dstDirID, dstName);  /* Delete dest file.  This may fail if the file 
+                                                                                                  is in a "drop folder" */
+       }
+       if ( ourCopyBuffer )    /* dispose of any memory we allocated */
+       {
+               DisposePtr((Ptr)copyBufferPtr);
+       }
+       
+       return ( err );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpFileCopy(const FSSpec *srcSpec,
+                                                       const FSSpec *dstSpec,
+                                                       ConstStr255Param copyName,
+                                                       void *copyBufferPtr,
+                                                       long copyBufferSize,
+                                                       Boolean preflight)
+{
+       return ( FileCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
+                                        dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
+                                        copyName, copyBufferPtr, copyBufferSize, preflight) );
+}
+
+/*****************************************************************************/
+
diff --git a/src/mac/morefile/FileCopy.h b/src/mac/morefile/FileCopy.h
new file mode 100644 (file)
index 0000000..5f4c008
--- /dev/null
@@ -0,0 +1,220 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     FileCopy: A robust, general purpose file copy routine.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           FileCopy.h
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#ifndef __FILECOPY__
+#define __FILECOPY__
+
+#include <Types.h>
+#include <Files.h>
+
+#include "Optim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+pascal OSErr   FileCopy(short srcVRefNum,
+                                                long srcDirID,
+                                                ConstStr255Param srcName,
+                                                short dstVRefNum,
+                                                long dstDirID,
+                                                ConstStr255Param dstPathname,
+                                                ConstStr255Param copyName,
+                                                void *copyBufferPtr,
+                                                long copyBufferSize,
+                                                Boolean preflight);
+/*     ¦ Duplicate a file and optionally rename it.
+       The FileCopy function duplicates a file and optionally renames it.
+       Since the PBHCopyFile routine is only available on some
+       AFP server volumes under specific conditions, this routine
+       either uses PBHCopyFile, or does all of the work PBHCopyFile
+       does.  The srcVRefNum, srcDirID and srcName are used to
+       determine the location of the file to copy.  The dstVRefNum
+       dstDirID and dstPathname are used to determine the location of
+       the destination directory.  If copyName <> NIL, then it points
+       to the name of the new file.  If copyBufferPtr <> NIL, it
+       points to a buffer of copyBufferSize that is used to copy
+       the file's data.  The larger the supplied buffer, the
+       faster the copy.  If copyBufferPtr = NIL, then this routine
+       allocates a buffer in the application heap. If you pass a
+       copy buffer to this routine, make its size a multiple of 512
+       ($200) bytes for optimum performance.
+       
+       srcVRefNum              input:  Source volume specification.
+       srcDirID                input:  Source directory ID.
+       srcName                 input:  Source file name.
+       dstVRefNum              input:  Destination volume specification.
+       dstDirID                input:  Destination directory ID.
+       dstPathname             input:  Pointer to destination directory name, or
+                                                       nil when dstDirID specifies a directory.
+       copyName                input:  Points to the new file name if the file is
+                                                       to be renamed or nil if the file isn't to
+                                                       be renamed.
+       copyBufferPtr   input:  Points to a buffer of copyBufferSize that
+                                                       is used the i/o buffer for the copy or
+                                                       nil if you want FileCopy to allocate its
+                                                       own buffer in the application heap.
+       copyBufferSize  input:  The size of the buffer pointed to
+                                                       by copyBufferPtr.
+       preflight               input:  If true, FileCopy makes sure there are enough
+                                                       allocation blocks on the destination volume to
+                                                       hold both the data and resource forks before
+                                                       starting the copy.
+       
+       Result Codes
+               noErr                           0               No error
+               readErr                         Ð19             Driver does not respond to read requests
+               writErr                         Ð20             Driver does not respond to write requests
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies a
+                                                                       nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+               dskFulErr                       -34             Destination volume is full
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               tmfoErr                         -42             Too many files open
+               fnfErr                          -43             Source file not found, or destination
+                                                                       directory does not exist
+               wPrErr                          -44             Volume locked by hardware
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Destination volume is read-only
+               fBsyErr                         -47             The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               dupFNErr                        -48             Destination file already exists
+               opWrErr                         -49             File already open for writing
+               paramErr                        -50             No default volume or function not
+                                                                       supported by volume
+               permErr                         -54             File is already open and cannot be opened using specified deny modes
+               memFullErr                      -108    Copy buffer could not be allocated
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               wrgVolTypErr            -123    Function not supported by volume
+               afpAccessDenied         -5000   User does not have the correct access
+               afpDenyConflict         -5006   The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               afpObjectTypeErr        -5025   Source is a directory, directory not found
+                                                                       or incomplete pathname
+       
+       __________
+       
+       Also see:       FSpFileCopy, DirectoryCopy, FSpDirectoryCopy
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpFileCopy(const FSSpec *srcSpec,
+                                                       const FSSpec *dstSpec,
+                                                       ConstStr255Param copyName,
+                                                       void *copyBufferPtr,
+                                                       long copyBufferSize,
+                                                       Boolean preflight);
+/*     ¦ Duplicate a file and optionally rename it.
+       The FSpFileCopy function duplicates a file and optionally renames it.
+       Since the PBHCopyFile routine is only available on some
+       AFP server volumes under specific conditions, this routine
+       either uses PBHCopyFile, or does all of the work PBHCopyFile
+       does.  The srcSpec is used to
+       determine the location of the file to copy.  The dstSpec is
+       used to determine the location of the
+       destination directory.  If copyName <> NIL, then it points
+       to the name of the new file.  If copyBufferPtr <> NIL, it
+       points to a buffer of copyBufferSize that is used to copy
+       the file's data.  The larger the supplied buffer, the
+       faster the copy.  If copyBufferPtr = NIL, then this routine
+       allocates a buffer in the application heap. If you pass a
+       copy buffer to this routine, make its size a multiple of 512
+       ($200) bytes for optimum performance.
+       
+       srcSpec                 input:  An FSSpec record specifying the source file.
+       dstSpec                 input:  An FSSpec record specifying the destination
+                                                       directory.
+       copyName                input:  Points to the new file name if the file is
+                                                       to be renamed or nil if the file isn't to
+                                                       be renamed.
+       copyBufferPtr   input:  Points to a buffer of copyBufferSize that
+                                                       is used the i/o buffer for the copy or
+                                                       nil if you want FileCopy to allocate its
+                                                       own buffer in the application heap.
+       copyBufferSize  input:  The size of the buffer pointed to
+                                                       by copyBufferPtr.
+       preflight               input:  If true, FSpFileCopy makes sure there are
+                                                       enough allocation blocks on the destination
+                                                       volume to hold both the data and resource forks
+                                                       before starting the copy.
+       
+       Result Codes
+               noErr                           0               No error
+               readErr                         Ð19             Driver does not respond to read requests
+               writErr                         Ð20             Driver does not respond to write requests
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies a
+                                                                       nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+               dskFulErr                       -34             Destination volume is full
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               tmfoErr                         -42             Too many files open
+               fnfErr                          -43             Source file not found, or destination
+                                                                       directory does not exist
+               wPrErr                          -44             Volume locked by hardware
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Destination volume is read-only
+               fBsyErr                         -47             The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               dupFNErr                        -48             Destination file already exists
+               opWrErr                         -49             File already open for writing
+               paramErr                        -50             No default volume or function not
+                                                                       supported by volume
+               permErr                         -54             File is already open and cannot be opened using specified deny modes
+               memFullErr                      -108    Copy buffer could not be allocated
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               wrgVolTypErr            -123    Function not supported by volume
+               afpAccessDenied         -5000   User does not have the correct access
+               afpDenyConflict         -5006   The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               afpObjectTypeErr        -5025   Source is a directory, directory not found
+                                                                       or incomplete pathname
+       
+       __________
+       
+       Also see:       FileCopy, DirectoryCopy, FSpDirectoryCopy
+*/
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "OptimEnd.h"
+
+#endif /* __FILECOPY__ */
diff --git a/src/mac/morefile/FullPath.cpp b/src/mac/morefile/FullPath.cpp
new file mode 100644 (file)
index 0000000..3ad50b4
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     Routines for dealing with full pathnames... if you really must.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           FullPath.c
+**
+**     Copyright © 1995-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#include <Types.h>
+#include <Errors.h>
+#include <Memory.h>
+#include <Files.h>
+#include <TextUtils.h>
+#include <Aliases.h>
+
+#define        __COMPILINGMOREFILES
+
+#include "FSpCompa.h"
+#include "FullPath.h"
+
+/*
+       IMPORTANT NOTE:
+       
+       The use of full pathnames is strongly discouraged. Full pathnames are
+       particularly unreliable as a means of identifying files, directories
+       or volumes within your application, for two primary reasons:
+       
+       ¥       The user can change the name of any element in the path at virtually
+               any time.
+       ¥       Volume names on the Macintosh are *not* unique. Multiple
+               mounted volumes can have the same name. For this reason, the use of
+               a full pathname to identify a specific volume may not produce the
+               results you expect. If more than one volume has the same name and
+               a full pathname is used, the File Manager currently uses the first
+               mounted volume it finds with a matching name in the volume queue.
+       
+       In general, you should use a fileÕs name, parent directory ID, and
+       volume reference number to identify a file you want to open, delete,
+       or otherwise manipulate.
+       
+       If you need to remember the location of a particular file across
+       subsequent system boots, use the Alias Manager to create an alias record
+       describing the file. If the Alias Manager is not available, you can save
+       the fileÕs name, its parent directory ID, and the name of the volume on
+       which itÕs located. Although none of these methods is foolproof, they are
+       much more reliable than using full pathnames to identify files.
+       
+       Nonetheless, it is sometimes useful to display a fileÕs full pathname to
+       the user. For example, a backup utility might display a list of full
+       pathnames of files as it copies them onto the backup medium. Or, a
+       utility might want to display a dialog box showing the full pathname of
+       a file when it needs the userÕs confirmation to delete the file. No
+       matter how unreliable full pathnames may be from a file-specification
+       viewpoint, users understand them more readily than volume reference
+       numbers or directory IDs. (Hint: Use the TruncString function from
+       TextUtils.h with truncMiddle as the truncWhere argument to shorten
+       full pathnames to a displayable length.)
+       
+       The following technique for constructing the full pathname of a file is
+       intended for display purposes only. Applications that depend on any
+       particular structure of a full pathname are likely to fail on alternate
+       foreign file systems or under future system software versions.
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetFullPath(short vRefNum,
+                                                       long dirID,
+                                                       ConstStr255Param name,
+                                                       short *fullPathLength,
+                                                       Handle *fullPath)
+{
+       OSErr           result;
+       FSSpec          spec;
+       
+       *fullPathLength = 0;
+       *fullPath = NULL;
+       
+       result = FSMakeFSSpecCompat(vRefNum, dirID, name, &spec);
+       if ( (result == noErr) || (result == fnfErr) )
+       {
+               result = FSpGetFullPath(&spec, fullPathLength, fullPath);
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetFullPath(const FSSpec *spec,
+                                                          short *fullPathLength,
+                                                          Handle *fullPath)
+{
+       OSErr           result;
+       OSErr           realResult;
+       FSSpec          tempSpec;
+       CInfoPBRec      pb;
+       
+       *fullPathLength = 0;
+       *fullPath = NULL;
+       
+       // Default to noErr
+       realResult = noErr;
+       
+       /* Make a copy of the input FSSpec that can be modified */
+       BlockMoveData(spec, &tempSpec, sizeof(FSSpec));
+       
+       if ( tempSpec.parID == fsRtParID )
+       {
+               /* The object is a volume */
+               
+               /* Add a colon to make it a full pathname */
+               ++tempSpec.name[0];
+               tempSpec.name[tempSpec.name[0]] = ':';
+               
+               /* We're done */
+               result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+       }
+       else
+       {
+               /* The object isn't a volume */
+               
+               /* Is the object a file or a directory? */
+               pb.dirInfo.ioNamePtr = tempSpec.name;
+               pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+               pb.dirInfo.ioDrDirID = tempSpec.parID;
+               pb.dirInfo.ioFDirIndex = 0;
+               result = PBGetCatInfoSync(&pb);
+               // Allow file/directory name at end of path to not exist.
+               realResult = result;
+               if ( (result == noErr) || (result == fnfErr) )
+               {
+                       /* if the object is a directory, append a colon so full pathname ends with colon */
+                       if ( (result == noErr) && (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+                       {
+                               ++tempSpec.name[0];
+                               tempSpec.name[tempSpec.name[0]] = ':';
+                       }
+                       
+                       /* Put the object name in first */
+                       result = PtrToHand(&tempSpec.name[1], fullPath, tempSpec.name[0]);
+                       if ( result == noErr )
+                       {
+                               /* Get the ancestor directory names */
+                               pb.dirInfo.ioNamePtr = tempSpec.name;
+                               pb.dirInfo.ioVRefNum = tempSpec.vRefNum;
+                               pb.dirInfo.ioDrParID = tempSpec.parID;
+                               do      /* loop until we have an error or find the root directory */
+                               {
+                                       pb.dirInfo.ioFDirIndex = -1;
+                                       pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
+                                       result = PBGetCatInfoSync(&pb);
+                                       if ( result == noErr )
+                                       {
+                                               /* Append colon to directory name */
+                                               ++tempSpec.name[0];
+                                               tempSpec.name[tempSpec.name[0]] = ':';
+                                               
+                                               /* Add directory name to beginning of fullPath */
+                                               (void) Munger(*fullPath, 0, NULL, 0, &tempSpec.name[1], tempSpec.name[0]);
+                                               result = MemError();
+                                       }
+                               } while ( (result == noErr) && (pb.dirInfo.ioDrDirID != fsRtDirID) );
+                       }
+               }
+       }
+       if ( result == noErr )
+       {
+               /* Return the length */
+               *fullPathLength = InlineGetHandleSize(*fullPath);
+               result = realResult;    // return realResult in case it was fnfErr
+       }
+       else
+       {
+               /* Dispose of the handle and return NULL and zero length */
+               if ( *fullPath != NULL )
+               {
+                       DisposeHandle(*fullPath);
+               }
+               *fullPath = NULL;
+               *fullPathLength = 0;
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpLocationFromFullPath(short fullPathLength,
+                                                                        const void *fullPath,
+                                                                        FSSpec *spec)
+{
+       AliasHandle     alias;
+       OSErr           result;
+       Boolean         wasChanged;
+       Str32           nullString;
+       
+       /* Create a minimal alias from the full pathname */
+       nullString[0] = 0;      /* null string to indicate no zone or server name */
+       result = NewAliasMinimalFromFullPath(fullPathLength, fullPath, nullString, nullString, &alias);
+       if ( result == noErr )
+       {
+               /* Let the Alias Manager resolve the alias. */
+               result = ResolveAlias(NULL, alias, spec, &wasChanged);
+               
+               DisposeHandle((Handle)alias);   /* Free up memory used */
+       }
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr LocationFromFullPath(short fullPathLength,
+                                                                 const void *fullPath,
+                                                                 short *vRefNum,
+                                                                 long *parID,
+                                                                 Str31 name)
+{
+       OSErr   result;
+       FSSpec  spec;
+       
+       result = FSpLocationFromFullPath(fullPathLength, fullPath, &spec);
+       if ( result == noErr )
+       {
+               *vRefNum = spec.vRefNum;
+               *parID = spec.parID;
+               BlockMoveData(&spec.name[0], &name[0], spec.name[0] + 1);
+       }
+       return ( result );
+}
+
+/*****************************************************************************/
+
diff --git a/src/mac/morefile/FullPath.h b/src/mac/morefile/FullPath.h
new file mode 100644 (file)
index 0000000..5a49e40
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     Routines for dealing with full pathnames... if you really must.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           FullPath.h
+**
+**     Copyright © 1995-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#ifndef __FULLPATH__
+#define __FULLPATH__
+
+#include <Types.h>
+#include <Files.h>
+
+#include "Optim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+       IMPORTANT NOTE:
+       
+       The use of full pathnames is strongly discouraged. Full pathnames are
+       particularly unreliable as a means of identifying files, directories
+       or volumes within your application, for two primary reasons:
+       
+       ¥       The user can change the name of any element in the path at
+               virtually any time.
+       ¥       Volume names on the Macintosh are *not* unique. Multiple
+               mounted volumes can have the same name. For this reason, the use of
+               a full pathname to identify a specific volume may not produce the
+               results you expect. If more than one volume has the same name and
+               a full pathname is used, the File Manager currently uses the first
+               mounted volume it finds with a matching name in the volume queue.
+       
+       In general, you should use a fileÕs name, parent directory ID, and
+       volume reference number to identify a file you want to open, delete,
+       or otherwise manipulate.
+       
+       If you need to remember the location of a particular file across
+       subsequent system boots, use the Alias Manager to create an alias
+       record describing the file. If the Alias Manager is not available, you
+       can save the fileÕs name, its parent directory ID, and the name of the
+       volume on which itÕs located. Although none of these methods is
+       foolproof, they are much more reliable than using full pathnames to
+       identify files.
+       
+       Nonetheless, it is sometimes useful to display a fileÕs full pathname
+       to the user. For example, a backup utility might display a list of full
+       pathnames of files as it copies them onto the backup medium. Or, a
+       utility might want to display a dialog box showing the full pathname of
+       a file when it needs the userÕs confirmation to delete the file. No
+       matter how unreliable full pathnames may be from a file-specification
+       viewpoint, users understand them more readily than volume reference
+       numbers or directory IDs. (Hint: Use the TruncString function from
+       TextUtils.h with truncMiddle as the truncWhere argument to shorten
+       full pathnames to a displayable length.)
+       
+       The following technique for constructing the full pathname of a file is
+       intended for display purposes only. Applications that depend on any
+       particular structure of a full pathname are likely to fail on alternate
+       foreign file systems or under future system software versions.
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetFullPath(short vRefNum,
+                                                       long dirID,
+                                                       ConstStr255Param name,
+                                                       short *fullPathLength,
+                                                       Handle *fullPath);
+/*     ¦ Get a full pathname to a volume, directory or file.
+       The GetFullPath function builds a full pathname to the specified
+       object. The full pathname is returned in the newly created handle
+       fullPath and the length of the full pathname is returned in
+       fullPathLength. Your program is responsible for disposing of the
+       fullPath handle.
+       
+       Note that a full pathname can be made to a file/directory that does not
+       yet exist if all directories up to that file/directory exist. In this case,
+       GetFullPath will return a fnfErr.
+       
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to object name, or nil when dirID
+                                                       specifies a directory that's the object.
+       fullPathLength  output: The number of characters in the full pathname.
+                                                       If the function fails to create a full
+                                                       pathname, it sets fullPathLength to 0.
+       fullPath                output: A handle to the newly created full pathname
+                                                       buffer. If the function fails to create a
+                                                       full pathname, it sets fullPath to NULL.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File or directory does not exist (fullPath
+                                                                       and fullPathLength are still valid)
+               paramErr                        -50             No default volume
+               memFullErr                      -108    Not enough memory
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpGetFullPath
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetFullPath(const FSSpec *spec,
+                                                          short *fullPathLength,
+                                                          Handle *fullPath);
+/*     ¦ Get a full pathname to a volume, directory or file.
+       The GetFullPath function builds a full pathname to the specified
+       object. The full pathname is returned in the newly created handle
+       fullPath and the length of the full pathname is returned in
+       fullPathLength. Your program is responsible for disposing of the
+       fullPath handle.
+       
+       Note that a full pathname can be made to a file/directory that does not
+       yet exist if all directories up to that file/directory exist. In this case,
+       FSpGetFullPath will return a fnfErr.
+       
+       spec                    input:  An FSSpec record specifying the object.
+       fullPathLength  output: The number of characters in the full pathname.
+                                                       If the function fails to create a full pathname,
+                                                       it sets fullPathLength to 0.
+       fullPath                output: A handle to the newly created full pathname
+                                                       buffer. If the function fails to create a
+                                                       full pathname, it sets fullPath to NULL.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File or directory does not exist (fullPath
+                                                                       and fullPathLength are still valid)
+               paramErr                        -50             No default volume
+               memFullErr                      -108    Not enough memory
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       GetFullPath
+*/
+
+/*****************************************************************************/
+
+pascal OSErr FSpLocationFromFullPath(short fullPathLength,
+                                                                        const void *fullPath,
+                                                                        FSSpec *spec);
+/*     ¦ Get a FSSpec from a full pathname.
+       The FSpLocationFromFullPath function returns a FSSpec to the object
+       specified by full pathname. This function requires the Alias Manager.
+       
+       fullPathLength  input:  The number of characters in the full pathname
+                                                       of the target.
+       fullPath                input:  A pointer to a buffer that contains the full
+                                                       pathname of the target. The full pathname
+                                                       starts with the name of the volume, includes
+                                                       all of the directory names in the path to the
+                                                       target, and ends with the target name.
+       spec                    output: An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             The volume is not mounted
+               fnfErr                          -43             Target not found, but volume and parent
+                                                                       directory found
+               paramErr                        -50             Parameter error
+               usrCanceledErr          -128    The user canceled the operation
+       
+       __________
+       
+       See also:       LocationFromFullPath
+*/
+
+/*****************************************************************************/
+
+pascal OSErr LocationFromFullPath(short fullPathLength,
+                                                                 const void *fullPath,
+                                                                 short *vRefNum,
+                                                                 long *parID,
+                                                                 Str31 name);
+/*     ¦ Get an object's location from a full pathname.
+       The LocationFromFullPath function returns the volume reference number,
+       parent directory ID and name of the object specified by full pathname.
+       This function requires the Alias Manager.
+       
+       fullPathLength  input:  The number of characters in the full pathname
+                                                       of the target.
+       fullPath                input:  A pointer to a buffer that contains the full
+                                                       pathname of the target. The full pathname starts
+                                                       with the name of the volume, includes all of
+                                                       the directory names in the path to the target,
+                                                       and ends with the target name.
+       vRefNum                 output: The volume reference number.
+       parID                   output: The parent directory ID of the specified object.
+       name                    output: The name of the specified object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             The volume is not mounted
+               fnfErr                          -43             Target not found, but volume and parent
+                                                                       directory found
+               paramErr                        -50             Parameter error
+               usrCanceledErr          -128    The user canceled the operation
+       
+       __________
+       
+       See also:       FSpLocationFromFullPath
+*/
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "OptimEnd.h"
+
+#endif /* __FULLPATH__ */
\ No newline at end of file
diff --git a/src/mac/morefile/IterateD.cpp b/src/mac/morefile/IterateD.cpp
new file mode 100644 (file)
index 0000000..6b7e52a
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+**     IterateDirectory: File Manager directory iterator routines.
+**
+**     by Jim Luther
+**
+**     File:           IterateDirectory.c
+**
+**     Copyright © 1995-1998 Jim Luther and Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.
+**
+**     IterateDirectory is designed to drop into the MoreFiles sample code
+**     library I wrote while in Apple Developer Technical Support
+*/
+
+#include <Types.h>
+#include <Errors.h>
+#include <Files.h>
+
+#define        __COMPILINGMOREFILES
+
+#include "MoreExtr.h"
+#include "IterateD.h"
+
+/*
+**     Type definitions
+*/
+
+/* The IterateGlobals structure is used to minimize the amount of
+** stack space used when recursively calling IterateDirectoryLevel
+** and to hold global information that might be needed at any time.
+*/
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=mac68k
+#endif
+struct IterateGlobals
+{
+       IterateFilterProcPtr    iterateFilter;  /* pointer to IterateFilterProc */
+       CInfoPBRec                              cPB;                    /* the parameter block used for PBGetCatInfo calls */
+       Str63                                   itemName;               /* the name of the current item */
+       OSErr                                   result;                 /* temporary holder of results - saves 2 bytes of stack each level */
+       Boolean                                 quitFlag;               /* set to true if filter wants to kill interation */
+       unsigned short                  maxLevels;              /* Maximum levels to iterate through */
+       unsigned short                  currentLevel;   /* The current level IterateLevel is on */
+       void                                    *yourDataPtr;   /* A pointer to caller data the filter may need to access */
+};
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=reset
+#endif
+
+typedef struct IterateGlobals IterateGlobals;
+typedef IterateGlobals *IterateGlobalsPtr;
+
+/*****************************************************************************/
+
+/*     Static Prototype */
+
+static void    IterateDirectoryLevel(long dirID,
+                                                                         IterateGlobals *theGlobals);
+
+/*****************************************************************************/
+
+/*
+**     Functions
+*/
+
+static void    IterateDirectoryLevel(long dirID,
+                                                                         IterateGlobals *theGlobals)
+{
+       if ( (theGlobals->maxLevels == 0) ||                                            /* if maxLevels is zero, we aren't checking levels */
+                (theGlobals->currentLevel < theGlobals->maxLevels) )   /* if currentLevel < maxLevels, look at this level */
+       {
+               short index = 1;
+               
+               ++theGlobals->currentLevel;     /* go to next level */
+               
+               do
+               {       /* Isn't C great... What I'd give for a "WITH theGlobals DO" about now... */
+               
+                       /* Get next source item at the current directory level */
+                       
+                       theGlobals->cPB.dirInfo.ioFDirIndex = index;
+                       theGlobals->cPB.dirInfo.ioDrDirID = dirID;
+                       theGlobals->result = PBGetCatInfoSync((CInfoPBPtr)&theGlobals->cPB);            
+       
+                       if ( theGlobals->result == noErr )
+                       {
+                               /* Call the IterateFilterProc */
+                               CallIterateFilterProc(theGlobals->iterateFilter, &theGlobals->cPB, &theGlobals->quitFlag, theGlobals->yourDataPtr);
+                               
+                               /* Is it a directory? */
+                               if ( (theGlobals->cPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+                               {
+                                       /* We have a directory */
+                                       if ( !theGlobals->quitFlag )
+                                       {
+                                               /* Dive again if the IterateFilterProc didn't say "quit" */
+                                               IterateDirectoryLevel(theGlobals->cPB.dirInfo.ioDrDirID, theGlobals);
+                                       }
+                               }
+                       }
+                       
+                       ++index; /* prepare to get next item */
+               } while ( (theGlobals->result == noErr) && (!theGlobals->quitFlag) ); /* time to fall back a level? */
+               
+               if ( (theGlobals->result == fnfErr) ||  /* fnfErr is OK - it only means we hit the end of this level */
+                        (theGlobals->result == afpAccessDenied) ) /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */
+               {
+                       theGlobals->result = noErr;
+               }
+                       
+               --theGlobals->currentLevel;     /* return to previous level as we leave */
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   IterateDirectory(short vRefNum,
+                                                                long dirID,
+                                                                ConstStr255Param name,
+                                                                unsigned short maxLevels,
+                                                                IterateFilterProcPtr iterateFilter,
+                                                                void *yourDataPtr)
+{
+       IterateGlobals  theGlobals;
+       OSErr                   result;
+       long                    theDirID;
+       short                   theVRefNum;
+       Boolean                 isDirectory;
+       
+       /* Make sure there is a IterateFilter */
+       if ( iterateFilter != NULL )
+       {
+               /* Get the real directory ID and make sure it is a directory */
+               result = GetDirectoryID(vRefNum, dirID, name, &theDirID, &isDirectory);
+               if ( result == noErr )
+               {
+                       if ( isDirectory == true )
+                       {
+                               /* Get the real vRefNum */
+                               result = DetermineVRefNum(name, vRefNum, &theVRefNum);
+                               if ( result == noErr )
+                               {
+                                       /* Set up the globals we need to access from the recursive routine. */
+                                       theGlobals.iterateFilter = iterateFilter;
+                                       theGlobals.cPB.hFileInfo.ioNamePtr = (StringPtr)&theGlobals.itemName;
+                                       theGlobals.cPB.hFileInfo.ioVRefNum = theVRefNum;
+                                       theGlobals.itemName[0] = 0;
+                                       theGlobals.result = noErr;
+                                       theGlobals.quitFlag = false;
+                                       theGlobals.maxLevels = maxLevels;
+                                       theGlobals.currentLevel = 0;    /* start at level 0 */
+                                       theGlobals.yourDataPtr = yourDataPtr;
+                               
+                                       /* Here we go into recursion land... */
+                                       IterateDirectoryLevel(theDirID, &theGlobals);
+                                       
+                                       result = theGlobals.result;     /* set the result */
+                               }
+                       }
+                       else
+                       {
+                               result = dirNFErr;      /* a file was passed instead of a directory */
+                       }
+               }
+       }
+       else
+       {
+               result = paramErr;      /* iterateFilter was NULL */
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpIterateDirectory(const FSSpec *spec,
+                                                                       unsigned short maxLevels,
+                                                                       IterateFilterProcPtr iterateFilter,
+                                                                       void *yourDataPtr)
+{
+       return ( IterateDirectory(spec->vRefNum, spec->parID, spec->name,
+                                               maxLevels, iterateFilter, yourDataPtr) );
+}
+
+/*****************************************************************************/
diff --git a/src/mac/morefile/IterateD.h b/src/mac/morefile/IterateD.h
new file mode 100644 (file)
index 0000000..ec36ee4
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+**     IterateDirectory: File Manager directory iterator routines.
+**
+**     by Jim Luther
+**
+**     File:           IterateDirectory.h
+**
+**     Copyright © 1995-1998 Jim Luther and Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.
+**
+**     IterateDirectory is designed to drop into the MoreFiles sample code
+**     library I wrote while in Apple Developer Technical Support
+*/
+
+#ifndef __ITERATEDIRECTORY__
+#define __ITERATEDIRECTORY__
+
+#include <Types.h>
+#include <Files.h>
+
+#include "Optim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+typedef        pascal  void (*IterateFilterProcPtr) (const CInfoPBRec * const cpbPtr,
+                                                                                         Boolean *quitFlag,
+                                                                                         void *yourDataPtr);
+/*     ¦ Prototype for the IterateFilterProc function IterateDirectory calls.
+       This is the prototype for the IterateFilterProc function which is
+       called once for each file and directory found by IterateDirectory. The
+       IterateFilterProc gets a pointer to the CInfoPBRec that IterateDirectory
+       used to call PBGetCatInfo. The IterateFilterProc can use the read-only
+       data in the CInfoPBRec for whatever it wants.
+       
+       If the IterateFilterProc wants to stop IterateDirectory, it can set
+       quitFlag to true (quitFlag will be passed to the IterateFilterProc
+       false).
+       
+       The yourDataPtr parameter can point to whatever data structure you might
+       want to access from within the IterateFilterProc.
+
+       cpbPtr          input:  A pointer to the CInfoPBRec that IterateDirectory
+                                               used to call PBGetCatInfo. The CInfoPBRec and the
+                                               data it points to must not be changed by your
+                                               IterateFilterProc.
+       quitFlag        output: Your IterateFilterProc can set quitFlag to true
+                                               if it wants to stop IterateDirectory.
+       yourDataPtr     input:  A pointer to whatever data structure you might
+                                               want to access from within the IterateFilterProc.
+       
+       __________
+       
+       Also see:       IterateDirectory, FSpIterateDirectory
+*/
+
+#define CallIterateFilterProc(userRoutine, cpbPtr, quitFlag, yourDataPtr) \
+               (*(userRoutine))((cpbPtr), (quitFlag), (yourDataPtr))
+
+/*****************************************************************************/
+
+pascal OSErr   IterateDirectory(short vRefNum,
+                                                                long dirID,
+                                                                ConstStr255Param name,
+                                                                unsigned short maxLevels,
+                                                                IterateFilterProcPtr iterateFilter,
+                                                                void *yourDataPtr);
+/*     ¦ Iterate (scan) through a directory's content.
+       The IterateDirectory function performs a recursive iteration (scan) of
+       the specified directory and calls your IterateFilterProc function once
+       for each file and directory found.
+       
+       The maxLevels parameter lets you control how deep the recursion goes.
+       If maxLevels is 1, IterateDirectory only scans the specified directory;
+       if maxLevels is 2, IterateDirectory scans the specified directory and
+       one subdirectory below the specified directory; etc. Set maxLevels to
+       zero to scan all levels.
+       
+       The yourDataPtr parameter can point to whatever data structure you might
+       want to access from within the IterateFilterProc.
+
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to object name, or nil when dirID
+                                                       specifies a directory that's the object.
+       maxLevels               input:  Maximum number of directory levels to scan or
+                                                       zero to scan all directory levels.
+       iterateFilter   input:  A pointer to the routine you want called once
+                                                       for each file and directory found by
+                                                       IterateDirectory.
+       yourDataPtr             input:  A pointer to whatever data structure you might
+                                                       want to access from within the IterateFilterProc.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume or iterateFilter was NULL
+               dirNFErr                        -120    Directory not found or incomplete pathname
+                                                                       or a file was passed instead of a directory
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+               
+       __________
+       
+       See also:       IterateFilterProcPtr, FSpIterateDirectory
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpIterateDirectory(const FSSpec *spec,
+                                                                       unsigned short maxLevels,
+                                                                       IterateFilterProcPtr iterateFilter,
+                                                                       void *yourDataPtr);
+/*     ¦ Iterate (scan) through a directory's content.
+       The FSpIterateDirectory function performs a recursive iteration (scan)
+       of the specified directory and calls your IterateFilterProc function once
+       for each file and directory found.
+       
+       The maxLevels parameter lets you control how deep the recursion goes.
+       If maxLevels is 1, FSpIterateDirectory only scans the specified directory;
+       if maxLevels is 2, FSpIterateDirectory scans the specified directory and
+       one subdirectory below the specified directory; etc. Set maxLevels to
+       zero to scan all levels.
+       
+       The yourDataPtr parameter can point to whatever data structure you might
+       want to access from within the IterateFilterProc.
+
+       spec                    input:  An FSSpec record specifying the directory to scan.
+       maxLevels               input:  Maximum number of directory levels to scan or
+                                                       zero to scan all directory levels.
+       iterateFilter   input:  A pointer to the routine you want called once
+                                                       for each file and directory found by
+                                                       FSpIterateDirectory.
+       yourDataPtr             input:  A pointer to whatever data structure you might
+                                                       want to access from within the IterateFilterProc.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume or iterateFilter was NULL
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+               
+       __________
+       
+       See also:       IterateFilterProcPtr, IterateDirectory
+*/
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "OptimEnd.h"
+
+#endif /* __ITERATEDIRECTORY__ */
diff --git a/src/mac/morefile/MoreDesk.cpp b/src/mac/morefile/MoreDesk.cpp
new file mode 100644 (file)
index 0000000..74a59fd
--- /dev/null
@@ -0,0 +1,1254 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     A collection of useful high-level Desktop Manager routines.
+**     If the Desktop Manager isn't available, use the Desktop file
+**     for 'read' operations.
+**
+**     We do more because we can...
+**
+**     by Jim Luther and Nitin Ganatra, Apple Developer Technical Support Emeriti
+**
+**     File:   MoreDesktopMgr.c
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#include <Types.h>
+#include <Errors.h>
+#include <Memory.h>
+#include <Files.h>
+#include <Resources.h>
+#include <Icons.h>
+
+#define        __COMPILINGMOREFILES
+
+#include "MoreFile.h"
+#include "MoreExtr.h"
+#include "Search.h"
+#include "MoreDesk.h"
+
+/*****************************************************************************/
+
+/*     Desktop file notes:
+**
+**     ¥       The Desktop file is owned by the Finder and is normally open by the
+**             Finder. That means that we only have read-only access to the Desktop
+**             file.
+**     ¥       Since the Resource Manager doesn't support shared access to resource
+**             files and we're using read-only access, we don't ever leave the
+**             Desktop file open.  We open a path to it, get the data we want out
+**             of it, and then close the open path. This is the only safe way to
+**             open a resource file with read-only access since some other program
+**             could have it open with write access.
+**     ¥       The bundle related resources in the Desktop file are normally
+**             purgable, so when we're looking through them, we don't bother to
+**             release resources we're done looking at - closing the resource file
+**             (which we always do) will release them.
+**     ¥       Since we can't assume the Desktop file is named "Desktop"
+**             (it probably is everywhere but France), we get the Desktop
+**             file's name by searching the volume's root directory for a file
+**             with fileType == 'FNDR' and creator == 'ERIK'. The only problem with
+**             this scheme is that someone could create another file with that type
+**             and creator in the root directory and we'd find the wrong file.
+**             The chances of this are very slim.
+*/
+
+/*****************************************************************************/
+
+/* local defines */
+
+enum
+{
+       kBNDLResType    = 'BNDL',
+       kFREFResType    = 'FREF',
+       kIconFamResType = 'ICN#',
+       kFCMTResType    = 'FCMT',
+       kAPPLResType    = 'APPL'
+};
+
+/*****************************************************************************/
+
+/* local data structures */
+
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=mac68k
+#endif
+
+struct IDRec
+{
+       short           localID;
+       short           rsrcID;
+};
+typedef struct IDRec IDRec;
+typedef        IDRec *IDRecPtr;
+
+struct BundleType
+{
+       OSType          type;                   /* 'ICN#' or 'FREF' */
+       short           count;                  /* number of IDRecs - 1 */
+       IDRec           idArray[1];
+};
+typedef struct BundleType BundleType;
+typedef BundleType *BundleTypePtr;
+
+struct BNDLRec
+{
+       OSType          signature;              /* creator type signature */
+       short           versionID;              /* version - should always be 0 */
+       short           numTypes;               /* number of elements in typeArray - 1 */
+       BundleType      typeArray[1];
+};
+typedef struct BNDLRec BNDLRec;
+typedef BNDLRec **BNDLRecHandle;
+
+struct FREFRec
+{
+       OSType          fileType;               /* file type */
+       short           iconID;                 /* icon local ID */
+       Str255          fileName;               /* file name */
+};
+typedef struct FREFRec FREFRec;
+typedef FREFRec **FREFRecHandle;
+
+struct APPLRec
+{
+       OSType          creator;                /* creator type signature */
+       long            parID;                  /* parent directory ID */
+       Str255          applName;               /* application name */
+};
+typedef struct APPLRec APPLRec;
+typedef APPLRec *APPLRecPtr;
+
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=reset
+#endif
+
+/*****************************************************************************/
+
+/* static prototypes */
+
+static OSErr   GetDesktopFileName(short vRefNum,
+                                                                  Str255 desktopName);
+
+static OSErr   GetAPPLFromDesktopFile(ConstStr255Param volName,
+                                                                          short vRefNum,
+                                                                          OSType creator,
+                                                                          short *applVRefNum,
+                                                                          long *applParID,
+                                                                          Str255 applName);
+
+static OSErr   FindBundleGivenCreator(OSType creator,
+                                                                          BNDLRecHandle *returnBndl);
+                                                                          
+static OSErr   FindTypeInBundle(OSType typeToFind,
+                                                                BNDLRecHandle theBndl,
+                                                                BundleTypePtr *returnBundleType);
+                                                                                
+static OSErr   GetLocalIDFromFREF(BundleTypePtr theBundleType,
+                                                                  OSType fileType,
+                                                                  short *iconLocalID);
+
+static OSErr   GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
+                                                                                short iconLocalID,
+                                                                                short *iconRsrcID);
+
+static OSType  DTIconToResIcon(short iconType);
+
+static OSErr   GetIconFromDesktopFile(ConstStr255Param volName,
+                                                                          short vRefNum,
+                                                                          short iconType,
+                                                                          OSType fileCreator,
+                                                                          OSType fileType,
+                                                                          Handle *iconHandle);
+
+static OSErr   GetCommentID(short vRefNum,
+                                                        long dirID,
+                                                        ConstStr255Param name,
+                                                        short *commentID);
+
+static OSErr   GetCommentFromDesktopFile(short vRefNum,
+                                                                                 long dirID,
+                                                                                 ConstStr255Param name,
+                                                                                 Str255 comment);
+
+/*****************************************************************************/
+
+/*
+**     GetDesktopFileName
+**
+**     Get the name of the Desktop file.
+*/
+static OSErr   GetDesktopFileName(short vRefNum,
+                                                                  Str255 desktopName)
+{
+       OSErr                   error;
+       HParamBlockRec  pb;
+       short                   index;
+       Boolean                 found;
+       
+       pb.fileParam.ioNamePtr = desktopName;
+       pb.fileParam.ioVRefNum = vRefNum;
+       pb.fileParam.ioFVersNum = 0;
+       index = 1;
+       found = false;
+       do
+       {
+               pb.fileParam.ioDirID = fsRtDirID;
+               pb.fileParam.ioFDirIndex = index;
+               error = PBHGetFInfoSync(&pb);
+               if ( error == noErr )
+               {
+                       if ( (pb.fileParam.ioFlFndrInfo.fdType == 'FNDR') &&
+                                (pb.fileParam.ioFlFndrInfo.fdCreator == 'ERIK') )
+                       {
+                               found = true;
+                       }
+               }
+               ++index;
+       } while ( (error == noErr) && !found );
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DTOpen(ConstStr255Param volName,
+                                          short vRefNum,
+                                          short *dtRefNum,
+                                          Boolean *newDTDatabase)
+{
+       OSErr error;
+       GetVolParmsInfoBuffer volParmsInfo;
+       long infoSize;
+       DTPBRec pb;
+       
+       /* Check for volume Desktop Manager support before calling */
+       infoSize = sizeof(GetVolParmsInfoBuffer);
+       error = HGetVolParms(volName, vRefNum, &volParmsInfo, &infoSize);
+       if ( error == noErr )
+       {
+               if ( hasDesktopMgr(volParmsInfo) )
+               {
+                       pb.ioNamePtr = (StringPtr)volName;
+                       pb.ioVRefNum = vRefNum;
+                       error = PBDTOpenInform(&pb);
+                       /* PBDTOpenInform informs us if the desktop was just created */
+                       /* by leaving the low bit of ioTagInfo clear (0) */
+                       *newDTDatabase = ((pb.ioTagInfo & 1L) == 0);
+                       if ( error == paramErr )
+                       {
+                               error = PBDTGetPath(&pb);
+                               /* PBDTGetPath doesn't tell us if the database is new */
+                               /* so assume it is not new */
+                               *newDTDatabase = false;
+                       }
+                       *dtRefNum = pb.ioDTRefNum;
+               }
+               else
+               {
+                       error = paramErr;
+               }
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**     GetAPPLFromDesktopFile
+**
+**     Get a application's location from the
+**     Desktop file's 'APPL' resources.
+*/
+static OSErr   GetAPPLFromDesktopFile(ConstStr255Param volName,
+                                                                          short vRefNum,
+                                                                          OSType creator,
+                                                                          short *applVRefNum,
+                                                                          long *applParID,
+                                                                          Str255 applName)
+{
+       OSErr error;
+       short realVRefNum;
+       Str255 desktopName;
+       short savedResFile;
+       short dfRefNum;
+       Handle applResHandle;
+       Boolean foundCreator;
+       Ptr applPtr;
+       long applSize;
+       
+       error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
+       if ( error == noErr )
+       {
+               error = GetDesktopFileName(realVRefNum, desktopName);
+               if ( error == noErr )
+               {
+                       savedResFile = CurResFile();
+                       /*
+                       **      Open the 'Desktop' file in the root directory. (because
+                       **      opening the resource file could preload unwanted resources,
+                       **      bracket the call with SetResLoad(s))
+                       */
+                       SetResLoad(false);
+                       dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
+                       SetResLoad(true);
+                       
+                       if ( dfRefNum != -1)
+                       {
+                               /* Get 'APPL' resource ID 0 */
+                               applResHandle = Get1Resource(kAPPLResType, 0);
+                               if ( applResHandle != NULL )
+                               {
+                                       applSize = InlineGetHandleSize((Handle)applResHandle);
+                                       if ( applSize != 0 )    /* make sure the APPL resource isn't empty */
+                                       {
+                                               foundCreator = false;
+                                               applPtr = *applResHandle;
+                                               
+                                               /* APPL's don't have a count so I have to use the size as the bounds */
+                                               while ( (foundCreator == false) &&
+                                                               (applPtr < (*applResHandle + applSize)) )
+                                               {
+                                                       if ( ((APPLRecPtr)applPtr)->creator == creator )
+                                                       {
+                                                               foundCreator = true;
+                                                       }
+                                                       else
+                                                       {
+                                                               /* fun with pointer math... */
+                                                               applPtr += sizeof(OSType) +
+                                                                                  sizeof(long) +
+                                                                                  ((APPLRecPtr)applPtr)->applName[0] + 1;
+                                                               /* application mappings are word aligned within the resource */
+                                                               if ( ((unsigned long)applPtr % 2) != 0 )
+                                                               {
+                                                                       applPtr += 1;
+                                                               }
+                                                       }
+                                               }
+                                               if ( foundCreator == true )
+                                               {
+                                                       *applVRefNum = realVRefNum;
+                                                       *applParID = ((APPLRecPtr)applPtr)->parID;
+                                                       BlockMoveData(((APPLRecPtr)applPtr)->applName,
+                                                                                 applName,
+                                                                                 ((APPLRecPtr)applPtr)->applName[0] + 1);
+                                                       /* error is already noErr */
+                                               }
+                                               else
+                                               {
+                                                       error = afpItemNotFound;        /* didn't find a creator match */
+                                               }
+                                       }
+                                       else
+                                       {
+                                               error = afpItemNotFound;        /* no APPL mapping available */
+                                       }
+                               }
+                               else
+                               {
+                                       error = afpItemNotFound;        /* no APPL mapping available */
+                               }
+                               
+                               /* restore the resource chain and close the Desktop file */
+                               UseResFile(savedResFile);
+                               CloseResFile(dfRefNum);
+                       }
+                       else
+                       {
+                               error = afpItemNotFound;
+                       }
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DTXGetAPPL(ConstStr255Param volName,
+                                                  short vRefNum,
+                                                  OSType creator,
+                                                  Boolean searchCatalog,
+                                                  short *applVRefNum,
+                                                  long *applParID,
+                                                  Str255 applName)
+{
+       OSErr error;
+       UniversalFMPB pb;
+       short dtRefNum;
+       Boolean newDTDatabase;
+       short realVRefNum;
+       short index;
+       Boolean applFound;
+       FSSpec spec;
+       long actMatchCount;
+       
+       /* get the real vRefNum */
+       error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
+       if ( error == noErr )
+       {
+               error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
+               if ( error == noErr )
+               {
+                       if ( !newDTDatabase )
+                       {
+                               index = 0;
+                               applFound = false;
+                               do
+                               {
+                                       pb.dtPB.ioNamePtr = applName;
+                                       pb.dtPB.ioDTRefNum = dtRefNum;
+                                       pb.dtPB.ioIndex = index;
+                                       pb.dtPB.ioFileCreator = creator;
+                                       error = PBDTGetAPPLSync(&pb.dtPB);
+                                       if ( error == noErr )
+                                       {
+                                               /* got a match - see if it is valid */
+                                               
+                                               *applVRefNum = realVRefNum; /* get the vRefNum now */
+                                               *applParID = pb.dtPB.ioAPPLParID; /* get the parent ID now */
+       
+                                               /* pb.hPB.fileParam.ioNamePtr is already set */
+                                               pb.hPB.fileParam.ioVRefNum = realVRefNum;
+                                               pb.hPB.fileParam.ioFVersNum = 0;
+                                               pb.hPB.fileParam.ioDirID = *applParID;
+                                               pb.hPB.fileParam.ioFDirIndex = 0;       /* use ioNamePtr and ioDirID */
+                                               if ( PBHGetFInfoSync(&pb.hPB) == noErr )
+                                               {
+                                                       if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator == creator) &&
+                                                                (pb.hPB.fileParam.ioFlFndrInfo.fdType == 'APPL') )
+                                                       {
+                                                               applFound = true;
+                                                       }
+                                               }
+                                       }
+                                       ++index;
+                               } while ( (error == noErr) && !applFound );
+                               if ( error != noErr )
+                               {
+                                       error = afpItemNotFound;
+                               }
+                       }
+                       else
+                       {
+                               /* Desktop database is empty (new), set error to try CatSearch */
+                               error = afpItemNotFound;
+                       }
+               }
+               /* acceptable errors from Desktop Manager to continue are paramErr or afpItemNotFound */
+               if ( error == paramErr )
+               {
+                       /* if paramErr, the volume didn't support the Desktop Manager */
+                       /* try the Desktop file */
+                       
+                       error = GetAPPLFromDesktopFile(volName, vRefNum, creator,
+                                                                                       applVRefNum, applParID, applName);
+                       if ( error == noErr )
+                       {
+                               /* got a match - see if it is valid */
+                               
+                               pb.hPB.fileParam.ioNamePtr = applName;
+                               pb.hPB.fileParam.ioVRefNum = *applVRefNum;
+                               pb.hPB.fileParam.ioFVersNum = 0;
+                               pb.hPB.fileParam.ioDirID = *applParID;
+                               pb.hPB.fileParam.ioFDirIndex = 0;       /* use ioNamePtr and ioDirID */
+                               if ( PBHGetFInfoSync(&pb.hPB) == noErr )
+                               {
+                                       if ( (pb.hPB.fileParam.ioFlFndrInfo.fdCreator != creator) ||
+                                                (pb.hPB.fileParam.ioFlFndrInfo.fdType != 'APPL') )
+                                       {
+                                               error = afpItemNotFound;
+                                       }
+                               }
+                               else if ( error == fnfErr )
+                               {
+                                       error = afpItemNotFound;
+                               }
+                       }
+               }
+               /* acceptable error from DesktopFile code to continue is afpItemNotFound */
+               if ( (error == afpItemNotFound) && searchCatalog)
+               {
+                       /* Couldn't be found in the Desktop file either, */
+                       /* try searching with CatSearch if requested */
+                       
+                       error = CreatorTypeFileSearch(NULL, realVRefNum, creator, kAPPLResType, &spec, 1,
+                                                                                       &actMatchCount, true);
+                       if ( (error == noErr) || (error == eofErr) )
+                       {
+                               if ( actMatchCount > 0 )
+                               {
+                                       *applVRefNum = spec.vRefNum;
+                                       *applParID = spec.parID;
+                                       BlockMoveData(spec.name, applName, spec.name[0] + 1);
+                               }
+                               else
+                               {
+                                       error = afpItemNotFound;
+                               }
+                       }
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDTXGetAPPL(ConstStr255Param volName,
+                                                         short vRefNum,
+                                                         OSType creator,
+                                                         Boolean searchCatalog,
+                                                         FSSpec *spec)
+{
+       return ( DTXGetAPPL(volName, vRefNum, creator, searchCatalog,
+                                               &(spec->vRefNum), &(spec->parID), spec->name) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DTGetAPPL(ConstStr255Param volName,
+                                                 short vRefNum,
+                                                 OSType creator,
+                                                 short *applVRefNum,
+                                                 long *applParID,
+                                                 Str255 applName)
+{
+       /* Call DTXGetAPPL with the "searchCatalog" parameter true */ 
+       return ( DTXGetAPPL(volName, vRefNum, creator, true,
+                                               applVRefNum, applParID, applName) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDTGetAPPL(ConstStr255Param volName,
+                                                        short vRefNum,
+                                                        OSType creator,
+                                                        FSSpec *spec)
+{
+       /* Call DTXGetAPPL with the "searchCatalog" parameter true */ 
+       return ( DTXGetAPPL(volName, vRefNum, creator, true,
+                                               &(spec->vRefNum), &(spec->parID), spec->name) );
+}
+
+/*****************************************************************************/
+
+/*
+**     FindBundleGivenCreator
+**
+**     Search the current resource file for the 'BNDL' resource with the given
+**     creator and return a handle to it.
+*/
+static OSErr   FindBundleGivenCreator(OSType creator,
+                                                                          BNDLRecHandle *returnBndl)
+{
+       OSErr                   error;
+       short                   numOfBundles;
+       short                   index;
+       BNDLRecHandle   theBndl;
+       
+       error = afpItemNotFound;        /* default to not found */
+       
+       /* Search each BNDL resource until we find the one with a matching creator. */
+       
+       numOfBundles = Count1Resources(kBNDLResType);
+       index = 1;
+       *returnBndl = NULL;
+       
+       while ( (index <= numOfBundles) && (*returnBndl == NULL) )
+       {
+               theBndl = (BNDLRecHandle)Get1IndResource(kBNDLResType, index);
+               
+               if ( theBndl != NULL )
+               {
+                       if ( (*theBndl)->signature == creator )
+                       {
+                               /* numTypes and typeArray->count will always be the actual count minus 1, */
+                               /* so 0 in both fields is valid. */
+                               if ( ((*theBndl)->numTypes >= 0) && ((*theBndl)->typeArray->count >= 0) )
+                               {
+                                       /* got it */
+                                       *returnBndl = theBndl;
+                                       error = noErr;
+                               }
+                       }
+               }       
+               
+               index ++;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**     FindTypeInBundle
+**
+**     Given a Handle to a BNDL return a pointer to the desired type
+**     in it. If the type is not found, or if the type's count < 0,
+**     return afpItemNotFound.
+*/
+static OSErr   FindTypeInBundle(OSType typeToFind,
+                                                                BNDLRecHandle theBndl,
+                                                                BundleTypePtr *returnBundleType)
+{
+       OSErr                   error;
+       short                   index;
+       Ptr                             ptrIterator;    /* use a Ptr so we can do ugly pointer math */
+       
+       error = afpItemNotFound;        /* default to not found */
+       
+       ptrIterator = (Ptr)((*theBndl)->typeArray);
+       index = 0;
+       *returnBundleType = NULL;
+
+       while ( (index < ((*theBndl)->numTypes + 1)) &&
+                       (*returnBundleType == NULL) )
+       {
+               if ( (((BundleTypePtr)ptrIterator)->type == typeToFind) &&
+                        (((BundleTypePtr)ptrIterator)->count >= 0) )
+               {
+                               *returnBundleType = (BundleTypePtr)ptrIterator;
+                               error = noErr;
+               }
+               else
+               {
+                       ptrIterator += ( sizeof(OSType) +
+                                                        sizeof(short) +
+                                                        ( sizeof(IDRec) * (((BundleTypePtr)ptrIterator)->count + 1) ) );
+                       ++index;
+               }
+       }
+               
+       return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**     GetLocalIDFromFREF
+**
+**     Given a pointer to a 'FREF' BundleType record, load each 'FREF' resource
+**     looking for a matching fileType. If a matching fileType is found, return
+**     its icon local ID. If no match is found, return afpItemNotFound as the
+**     function result.
+*/
+static OSErr   GetLocalIDFromFREF(BundleTypePtr theBundleType,
+                                                                  OSType fileType,
+                                                                  short *iconLocalID)
+{
+       OSErr                   error;
+       short                   index;
+       IDRecPtr                idIterator;
+       FREFRecHandle   theFref;
+       
+       error = afpItemNotFound;        /* default to not found */
+       
+       /* For each localID in this type, get the FREF resource looking for fileType */
+       index = 0;
+       idIterator = &theBundleType->idArray[0];
+       *iconLocalID = 0;
+       
+       while ( (index <= theBundleType->count) && (*iconLocalID == 0) )
+       {
+               theFref = (FREFRecHandle)Get1Resource(kFREFResType, idIterator->rsrcID);
+               if ( theFref != NULL )
+               {
+                       if ( (*theFref)->fileType == fileType )
+                       {
+                               *iconLocalID = (*theFref)->iconID;
+                               error = noErr;
+                       }
+               }
+               
+               ++idIterator;
+               ++index;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**     GetIconRsrcIDFromLocalID
+**
+**     Given a pointer to a 'ICN#' BundleType record, look for the IDRec with
+**     the localID that matches iconLocalID. If a matching IDRec is found,
+**     return the IDRec's rsrcID field value. If no match is found, return
+**     afpItemNotFound as the function result.
+*/
+static OSErr   GetIconRsrcIDFromLocalID(BundleTypePtr theBundleType,
+                                                                                short iconLocalID,
+                                                                                short *iconRsrcID)
+{
+       OSErr           error;
+       short           index;
+       IDRecPtr        idIterator;
+       
+       error = afpItemNotFound;        /* default to not found */
+       
+       /* Find the rsrcID of the icon family type, given the localID */
+       index = 0;
+       idIterator = &theBundleType->idArray[0];
+       *iconRsrcID = 0;
+       
+       while ( (index <= theBundleType->count) && (*iconRsrcID == 0) )
+       {
+               if ( idIterator->localID == iconLocalID )
+               {
+                       *iconRsrcID = idIterator->rsrcID;
+                       error = noErr;
+               }
+               
+               idIterator ++;
+               index ++;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**     DTIconToResIcon
+**
+**     Map a Desktop Manager icon type to the corresponding resource type.
+**     Return (OSType)0 if there is no corresponding resource type.
+*/
+static OSType  DTIconToResIcon(short iconType)
+{
+       OSType  resType;
+       
+       switch ( iconType )
+       {
+               case kLargeIcon:
+                       resType = large1BitMask;
+                       break;
+               case kLarge4BitIcon:
+                       resType = large4BitData;
+                       break;
+               case kLarge8BitIcon:
+                       resType = large8BitData;
+                       break;
+               case kSmallIcon:
+                       resType = small1BitMask;
+                       break;
+               case kSmall4BitIcon:
+                       resType = small4BitData;
+                       break;
+               case kSmall8BitIcon:
+                       resType = small8BitData;
+                       break;
+               default:
+                       resType = (OSType)0;
+                       break;
+       }
+       
+       return ( resType );
+}
+
+/*****************************************************************************/
+
+/*
+**     GetIconFromDesktopFile
+**
+**     INPUT a pointer to a non-existent Handle, because we'll allocate one
+**
+**     search each BNDL resource for the right fileCreator and once we get it
+**             find the 'FREF' type in BNDL
+**             for each localID in the type, open the FREF resource
+**                     if the FREF is the desired fileType
+**                             get its icon localID
+**                             get the ICN# type in BNDL
+**                             get the icon resource number from the icon localID
+**                             get the icon resource type from the desktop mgr's iconType
+**                             get the icon of that type and number
+*/
+static OSErr   GetIconFromDesktopFile(ConstStr255Param volName,
+                                                                          short vRefNum,
+                                                                          short iconType,
+                                                                          OSType fileCreator,
+                                                                          OSType fileType,
+                                                                          Handle *iconHandle)
+{
+       OSErr                   error;
+       short                   realVRefNum;
+       Str255                  desktopName;
+       short                   savedResFile;
+       short                   dfRefNum;
+       BNDLRecHandle   theBndl = NULL;
+       BundleTypePtr   theBundleType;
+       short                   iconLocalID;
+       short                   iconRsrcID;
+       OSType                  iconRsrcType;
+       Handle                  returnIconHandle;       
+       char                    bndlState;
+       
+       *iconHandle = NULL;
+       
+       error = DetermineVRefNum(volName, vRefNum, &realVRefNum);
+       if ( error == noErr )
+       {
+               error = GetDesktopFileName(realVRefNum, desktopName);
+               if ( error == noErr )
+               {
+                       savedResFile = CurResFile();
+               
+                       /*
+                       **      Open the 'Desktop' file in the root directory. (because
+                       **      opening the resource file could preload unwanted resources,
+                       **      bracket the call with SetResLoad(s))
+                       */
+                       SetResLoad(false);
+                       dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
+                       SetResLoad(true);
+               
+                       if ( dfRefNum != -1 )
+                       {
+                               /*
+                               **      Find the BNDL resource with the specified creator.
+                               */
+                               error = FindBundleGivenCreator(fileCreator, &theBndl);
+                               if ( error == noErr )
+                               {
+                                       /* Lock the BNDL resource so it won't be purged when other resources are loaded */
+                                       bndlState = HGetState((Handle)theBndl);
+                                       HLock((Handle)theBndl);
+                                       
+                                       /* Find the 'FREF' BundleType record in the BNDL resource. */
+                                       error = FindTypeInBundle(kFREFResType, theBndl, &theBundleType);
+                                       if ( error == noErr )
+                                       {
+                                               /* Find the local ID in the 'FREF' resource with the specified fileType */
+                                               error = GetLocalIDFromFREF(theBundleType, fileType, &iconLocalID);
+                                               if ( error == noErr )
+                                               {
+                                                       /* Find the 'ICN#' BundleType record in the BNDL resource. */
+                                                       error = FindTypeInBundle(kIconFamResType, theBndl, &theBundleType);
+                                                       if ( error == noErr )
+                                                       {
+                                                               /* Find the icon's resource ID in the 'ICN#' BundleType record */
+                                                               error = GetIconRsrcIDFromLocalID(theBundleType, iconLocalID, &iconRsrcID);
+                                                               if ( error == noErr )
+                                                               {
+                                                                       /* Map Desktop Manager icon type to resource type */
+                                                                       iconRsrcType = DTIconToResIcon(iconType);
+                                                                       
+                                                                       if ( iconRsrcType != (OSType)0 )
+                                                                       {
+                                                                               /* Load the icon */
+                                                                               returnIconHandle = Get1Resource(iconRsrcType, iconRsrcID);
+                                                                               if ( returnIconHandle != NULL )
+                                                                               {
+                                                                                       /* Copy the resource handle, and return the copy */
+                                                                                       HandToHand(&returnIconHandle);
+                                                                                       if ( MemError() == noErr )
+                                                                                       {
+                                                                                               *iconHandle = returnIconHandle;
+                                                                                       }
+                                                                                       else
+                                                                                       {
+                                                                                               error = afpItemNotFound;
+                                                                                       }
+                                                                               }
+                                                                               else
+                                                                               {
+                                                                                       error = afpItemNotFound;
+                                                                               }
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                                       /* Restore the state of the BNDL resource */ 
+                                       HSetState((Handle)theBndl, bndlState);
+                               }
+                               /* Restore the resource chain and close the Desktop file */
+                               UseResFile(savedResFile);
+                               CloseResFile(dfRefNum);
+                       }
+                       else
+                       {
+                               error = ResError(); /* could not open Desktop file */
+                       }
+               }
+               if ( (error != noErr) && (error != memFullErr) )
+               {
+                       error = afpItemNotFound;        /* force an error we should return */
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DTGetIcon(ConstStr255Param volName,
+                                                 short vRefNum,
+                                                 short iconType,
+                                                 OSType fileCreator,
+                                                 OSType fileType,
+                                                 Handle *iconHandle)
+{
+       OSErr error;
+       DTPBRec pb;
+       short dtRefNum;
+       Boolean newDTDatabase;
+       Size bufferSize;
+       
+       *iconHandle = NULL;
+       error = DTOpen(volName, vRefNum, &dtRefNum, &newDTDatabase);
+       if ( error == noErr )
+       {
+               /* there was a desktop database and it's now open */
+               
+               if ( !newDTDatabase )   /* don't bother to look in a new (empty) database */
+               {
+                       /* get the buffer size for the requested icon type */
+                       switch ( iconType )
+                       {
+                               case kLargeIcon:
+                                       bufferSize = kLargeIconSize;
+                                       break;
+                               case kLarge4BitIcon:
+                                       bufferSize = kLarge4BitIconSize;
+                                       break;
+                               case kLarge8BitIcon:
+                                       bufferSize = kLarge8BitIconSize;
+                                       break;
+                               case kSmallIcon:
+                                       bufferSize = kSmallIconSize;
+                                       break;
+                               case kSmall4BitIcon:
+                                       bufferSize = kSmall4BitIconSize;
+                                       break;
+                               case kSmall8BitIcon:
+                                       bufferSize = kSmall8BitIconSize;
+                                       break;
+                               default:
+                                       iconType = 0;
+                                       bufferSize = 0;
+                                       break;
+                       }
+                       if ( bufferSize != 0 )
+                       {
+                               *iconHandle = NewHandle(bufferSize);
+                               if ( *iconHandle != NULL )
+                               {
+                                       HLock(*iconHandle);
+               
+                                       pb.ioDTRefNum = dtRefNum;
+                                       pb.ioTagInfo = 0;
+                                       pb.ioDTBuffer = **iconHandle;
+                                       pb.ioDTReqCount = bufferSize;
+                                       pb.ioIconType = iconType;
+                                       pb.ioFileCreator = fileCreator;
+                                       pb.ioFileType = fileType;
+                                       error = PBDTGetIconSync(&pb);
+       
+                                       HUnlock(*iconHandle);
+                                       
+                                       if ( error != noErr )
+                                       {
+                                               DisposeHandle(*iconHandle);     /* dispose of the allocated memory */
+                                               *iconHandle = NULL;
+                                       }
+                               }
+                               else
+                               {
+                                       error = memFullErr;     /* handle could not be allocated */
+                               }
+                       }
+                       else
+                       {
+                               error = paramErr;       /* unknown icon type requested */
+                       }
+               }
+               else
+               {
+                       error = afpItemNotFound;        /* the desktop database was empty - nothing to return */
+               }
+       }
+       else
+       {
+               /* There is no desktop database - try the Desktop file */
+               
+               error = GetIconFromDesktopFile(volName, vRefNum, iconType,
+                                                                               fileCreator, fileType, iconHandle);
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DTSetComment(short vRefNum,
+                                                        long dirID,
+                                                        ConstStr255Param name,
+                                                        ConstStr255Param comment)
+{
+       DTPBRec pb;
+       OSErr error;
+       short dtRefNum;
+       Boolean newDTDatabase;
+
+       error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
+       if ( error == noErr )
+       {
+               pb.ioDTRefNum = dtRefNum;
+               pb.ioNamePtr = (StringPtr)name;
+               pb.ioDirID = dirID;
+               pb.ioDTBuffer = (Ptr)&comment[1];
+               /* Truncate the comment to 200 characters just in case */
+               /* some file system doesn't range check */
+               if ( comment[0] <= 200 )
+               {
+                       pb.ioDTReqCount = comment[0];
+               }
+               else
+               {
+                       pb.ioDTReqCount = 200;
+               }
+               error = PBDTSetCommentSync(&pb);
+       }
+       return (error);
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDTSetComment(const FSSpec *spec,
+                                                         ConstStr255Param comment)
+{
+       return (DTSetComment(spec->vRefNum, spec->parID, spec->name, comment));
+}
+
+/*****************************************************************************/
+
+/*
+**     GetCommentID
+**
+**     Get the comment ID number for the Desktop file's 'FCMT' resource ID from
+**     the file or folders fdComment (frComment) field.
+*/
+static OSErr   GetCommentID(short vRefNum,
+                                                        long dirID,
+                                                        ConstStr255Param name,
+                                                        short *commentID)
+{
+       CInfoPBRec pb;
+       OSErr error;
+
+       error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+       *commentID = pb.hFileInfo.ioFlXFndrInfo.fdComment;
+       return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**     GetCommentFromDesktopFile
+**
+**     Get a file or directory's Finder comment field (if any) from the
+**     Desktop file's 'FCMT' resources.
+*/
+static OSErr   GetCommentFromDesktopFile(short vRefNum,
+                                                                                 long dirID,
+                                                                                 ConstStr255Param name,
+                                                                                 Str255 comment)
+{
+       OSErr error;
+       short commentID;
+       short realVRefNum;
+       Str255 desktopName;
+       short savedResFile;
+       short dfRefNum;
+       StringHandle commentHandle;
+       
+       /* Get the comment ID number */
+       error = GetCommentID(vRefNum, dirID, name, &commentID);
+       if ( error == noErr )
+       {
+               if ( commentID != 0 )   /* commentID == 0 means there's no comment */
+               {
+                       error = DetermineVRefNum(name, vRefNum, &realVRefNum);
+                       if ( error == noErr )
+                       {
+                               error = GetDesktopFileName(realVRefNum, desktopName);
+                               if ( error == noErr )
+                               {
+                                       savedResFile = CurResFile();
+                                       /*
+                                       **      Open the 'Desktop' file in the root directory. (because
+                                       **      opening the resource file could preload unwanted resources,
+                                       **      bracket the call with SetResLoad(s))
+                                       */
+                                       SetResLoad(false);
+                                       dfRefNum = HOpenResFile(realVRefNum, fsRtDirID, desktopName, fsRdPerm);
+                                       SetResLoad(true);
+                                       
+                                       if ( dfRefNum != -1)
+                                       {
+                                               /* Get the comment resource */
+                                               commentHandle = (StringHandle)Get1Resource(kFCMTResType,commentID);
+                                               if ( commentHandle != NULL )
+                                               {
+                                                       if ( InlineGetHandleSize((Handle)commentHandle) > 0 )
+                                                       {
+                                                               BlockMoveData(*commentHandle, comment, *commentHandle[0] + 1);
+                                                       }
+                                                       else
+                                                       {
+                                                               error = afpItemNotFound;        /* no comment available */
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       error = afpItemNotFound;        /* no comment available */
+                                               }
+                                               
+                                               /* restore the resource chain and close the Desktop file */
+                                               UseResFile(savedResFile);
+                                               CloseResFile(dfRefNum);
+                                       }
+                                       else
+                                       {
+                                               error = afpItemNotFound;
+                                       }
+                               }
+                               else
+                               {
+                                       error = afpItemNotFound;
+                               }
+                       }
+               }
+               else
+               {
+                       error = afpItemNotFound;        /* no comment available */
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DTGetComment(short vRefNum,
+                                                        long dirID,
+                                                        ConstStr255Param name,
+                                                        Str255 comment)
+{
+       DTPBRec pb;
+       OSErr error;
+       short dtRefNum;
+       Boolean newDTDatabase;
+
+       if (comment != NULL)
+       {
+               comment[0] = 0; /* return nothing by default */
+               
+               /* attempt to open the desktop database */
+               error = DTOpen(name, vRefNum, &dtRefNum, &newDTDatabase);
+               if ( error == noErr )
+               {
+                       /* There was a desktop database and it's now open */
+                       
+                       if ( !newDTDatabase )
+                       {
+                               pb.ioDTRefNum = dtRefNum;
+                               pb.ioNamePtr = (StringPtr)name;
+                               pb.ioDirID = dirID;
+                               pb.ioDTBuffer = (Ptr)&comment[1];
+                               /*
+                               **      IMPORTANT NOTE #1: Inside Macintosh says that comments
+                               **      are up to 200 characters. While that may be correct for
+                               **      the HFS file system's Desktop Manager, other file
+                               **      systems (such as Apple Photo Access) return up to
+                               **      255 characters. Make sure the comment buffer is a Str255
+                               **      or you'll regret it.
+                               **
+                               **      IMPORTANT NOTE #2: Although Inside Macintosh doesn't
+                               **      mention it, ioDTReqCount is a input field to
+                               **      PBDTGetCommentSync. Some file systems (like HFS) ignore
+                               **      ioDTReqCount and always return the full comment --
+                               **      others (like AppleShare) respect ioDTReqCount and only
+                               **      return up to ioDTReqCount characters of the comment.
+                               */
+                               pb.ioDTReqCount = sizeof(Str255) - 1;
+                               error = PBDTGetCommentSync(&pb);
+                               if (error == noErr)
+                               {
+                                       comment[0] = (unsigned char)pb.ioDTActCount;
+                               }
+                       }
+               }
+               else
+               {
+                       /* There is no desktop database - try the Desktop file */
+                       error = GetCommentFromDesktopFile(vRefNum, dirID, name, comment);
+                       if ( error != noErr )
+                       {
+                               error = afpItemNotFound;        /* return an expected error */
+                       }
+               }
+       }
+       else
+       {
+               error = paramErr;
+       }
+       
+       return (error);
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDTGetComment(const FSSpec *spec,
+                                                         Str255 comment)
+{
+       return (DTGetComment(spec->vRefNum, spec->parID, spec->name, comment));
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DTCopyComment(short srcVRefNum,
+                                                         long srcDirID,
+                                                         ConstStr255Param srcName,
+                                                         short dstVRefNum,
+                                                         long dstDirID,
+                                                         ConstStr255Param dstName)
+/* The destination volume must support the Desktop Manager for this to work */
+{
+       OSErr error;
+       Str255 comment;
+
+       error = DTGetComment(srcVRefNum, srcDirID, srcName, comment);
+       if ( (error == noErr) && (comment[0] > 0) )
+       {
+               error = DTSetComment(dstVRefNum, dstDirID, dstName, comment);
+       }
+       return (error);
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDTCopyComment(const FSSpec *srcSpec,
+                                                          const FSSpec *dstSpec)
+/* The destination volume must support the Desktop Manager for this to work */
+{
+       return (DTCopyComment(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
+                                               dstSpec->vRefNum, dstSpec->parID, dstSpec->name));
+}
+
+/*****************************************************************************/
diff --git a/src/mac/morefile/MoreDesk.h b/src/mac/morefile/MoreDesk.h
new file mode 100644 (file)
index 0000000..be2bfd3
--- /dev/null
@@ -0,0 +1,541 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     A collection of useful high-level Desktop Manager routines.
+**     If the Desktop Manager isn't available, use the Desktop file
+**     for 'read' operations.
+**
+**     We do more because we can...
+**
+**     by Jim Luther and Nitin Ganatra, Apple Developer Technical Support Emeriti
+**
+**     File:   MoreDesktopMgr.h
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#ifndef __MOREDESKTOPMGR__
+#define __MOREDESKTOPMGR__
+
+#include <Types.h>
+#include <Files.h>
+
+#include "Optim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+pascal OSErr   DTOpen(ConstStr255Param volName,
+                                          short vRefNum,
+                                          short *dtRefNum,
+                                          Boolean *newDTDatabase);
+/*     ¦ Open a volume's desktop database and return the desktop database refNum.
+       The DTOpen function opens a volume's desktop database. It returns
+       the reference number of the desktop database and indicates if the
+       desktop database was created as a result of this call (if it was created,
+       then it is empty).
+
+       volName                 input:  A pointer to the name of a mounted volume
+                                                       or nil.
+       vRefNum                 input:  Volume specification.
+       dtRefNum                output: The reference number of Desktop Manager's
+                                                       desktop database on the specified volume.
+       newDTDatabase   output: true if the desktop database was created as a
+                                                       result of this call and thus empty.
+                                                       false if the desktop database was already created,
+                                                       or if it could not be determined if it was already
+                                                       created.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               paramErr                        -50             Volume doesn't support this function
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DTXGetAPPL(ConstStr255Param volName,
+                                                  short vRefNum,
+                                                  OSType creator,
+                                                  Boolean searchCatalog,
+                                                  short *applVRefNum,
+                                                  long *applParID,
+                                                  Str255 applName);
+/*     ¦ Find an application on a volume that can open a file with a given creator.
+       The DTXGetAPPL function finds an application (file type 'APPL') with
+       the specified creator on the specified volume. It first tries to get
+       the application mapping from the desktop database. If that fails,
+       then it tries to find an application in the Desktop file. If that
+       fails and searchCatalog is true, then it tries to find an application
+       with the specified creator using the File Manager's CatSearch routine. 
+
+       volName                 input:  A pointer to the name of a mounted volume
+                                                       or nil.
+       vRefNum                 input:  Volume specification.
+       creator                 input:  The file's creator type.
+       searchCatalog   input:  If true, search the catalog for the application
+                                                       if it isn't found in the desktop database.
+       applVRefNum             output: The volume reference number of the volume the
+                                                       application is on.
+       applParID               output: The parent directory ID of the application.
+       applName                output: The name of the application.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               paramErr                        -50             No default volume
+               rfNumErr                        -51             Reference number invalid
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+               afpItemNotFound         -5012   Information not found
+       
+       __________
+       
+       Also see:       FSpDTGetAPPL
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDTXGetAPPL(ConstStr255Param volName,
+                                                         short vRefNum,
+                                                         OSType creator,
+                                                         Boolean searchCatalog,
+                                                         FSSpec *spec);
+/*     ¦ Find an application on a volume that can open a file with a given creator.
+       The FSpDTXGetAPPL function finds an application (file type 'APPL') with
+       the specified creator on the specified volume. It first tries to get
+       the application mapping from the desktop database. If that fails,
+       then it tries to find an application in the Desktop file. If that
+       fails and searchCatalog is true, then it tries to find an application
+       with the specified creator using the File Manager's CatSearch routine. 
+
+       volName                 input:  A pointer to the name of a mounted volume
+                                                       or nil.
+       vRefNum                 input:  Volume specification.
+       creator                 input:  The file's creator type.
+       searchCatalog   input:  If true, search the catalog for the application
+                                                       if it isn't found in the desktop database.
+       spec                    output: FSSpec record containing the application name and
+                                                       location.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               paramErr                        -50             No default volume
+               rfNumErr                        -51             Reference number invalid
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+               afpItemNotFound         -5012   Information not found
+       
+       __________
+       
+       Also see:       FSpDTGetAPPL
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DTGetAPPL(ConstStr255Param volName,
+                                                 short vRefNum,
+                                                 OSType creator,
+                                                 short *applVRefNum,
+                                                 long *applParID,
+                                                 Str255 applName);
+/*     ¦ Find an application on a volume that can open a file with a given creator.
+       The DTGetAPPL function finds an application (file type 'APPL') with
+       the specified creator on the specified volume. It first tries to get
+       the application mapping from the desktop database. If that fails,
+       then it tries to find an application in the Desktop file. If that
+       fails, then it tries to find an application with the specified creator
+       using the File Manager's CatSearch routine. 
+
+       volName         input:  A pointer to the name of a mounted volume
+                                               or nil.
+       vRefNum         input:  Volume specification.
+       creator         input:  The file's creator type.
+       applVRefNum     output: The volume reference number of the volume the
+                                               application is on.
+       applParID       output: The parent directory ID of the application.
+       applName        output: The name of the application.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               paramErr                        -50             No default volume
+               rfNumErr                        -51             Reference number invalid
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+               afpItemNotFound         -5012   Information not found
+       
+       __________
+       
+       Also see:       FSpDTGetAPPL
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDTGetAPPL(ConstStr255Param volName,
+                                                        short vRefNum,
+                                                        OSType creator,
+                                                        FSSpec *spec);
+/*     ¦ Find an application on a volume that can open a file with a given creator.
+       The FSpDTGetAPPL function finds an application (file type 'APPL') with
+       the specified creator on the specified volume. It first tries to get
+       the application mapping from the desktop database. If that fails,
+       then it tries to find an application in the Desktop file. If that
+       fails, then it tries to find an application with the specified creator
+       using the File Manager's CatSearch routine. 
+
+       volName         input:  A pointer to the name of a mounted volume
+                                               or nil.
+       vRefNum         input:  Volume specification.
+       creator         input:  The file's creator type.
+       spec            output: FSSpec record containing the application name and
+                                               location.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               paramErr                        -50             No default volume
+               rfNumErr                        -51             Reference number invalid
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+               afpItemNotFound         -5012   Information not found
+       
+       __________
+       
+       Also see:       DTGetAPPL
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DTGetIcon(ConstStr255Param volName,
+                                                 short vRefNum,
+                                                 short iconType,
+                                                 OSType fileCreator,
+                                                 OSType fileType,
+                                                 Handle *iconHandle);
+/*     ¦ Get an icon from the desktop database or Desktop file.
+       The DTGetIcon function retrieves the specified icon and returns it in
+       a newly created handle. The icon is retrieves from the Desktop Manager
+       or if the Desktop Manager is not available, from the Finder's Desktop
+       file. Your program is responsible for disposing of the handle when it is
+       done using the icon.
+
+       volName         input:  A pointer to the name of a mounted volume
+                                               or nil.
+       vRefNum         input:  Volume specification.
+       iconType        input:  The icon type as defined in Files.h. Valid values are:
+                                                       kLargeIcon
+                                                       kLarge4BitIcon
+                                                       kLarge8BitIcon
+                                                       kSmallIcon
+                                                       kSmall4BitIcon
+                                                       kSmall8BitIcon
+       fileCreator     input:  The icon's creator type.
+       fileType        input:  The icon's file type.
+       iconHandle      output: A Handle containing the newly created icon.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               paramErr                        -50             Volume doesn't support this function
+               rfNumErr                        -51             Reference number invalid
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call
+               memFullErr                      -108    iconHandle could not be allocated
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+               afpItemNotFound         -5012   Information not found
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DTSetComment(short vRefNum,
+                                                        long dirID,
+                                                        ConstStr255Param name,
+                                                        ConstStr255Param comment);
+/*     ¦ Set a file or directory's Finder comment field.
+       The DTSetComment function sets a file or directory's Finder comment
+       field. The volume must support the Desktop Manager because you only
+       have read access to the Desktop file.
+
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID
+                                       specifies a directory that's the object.
+       comment input:  The comment to add. Comments are limited to 200 characters;
+                                       longer comments are truncated.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          Ð43             File or directory doesnÕt exist
+               paramErr                        -50             Volume doesn't support this function
+               wPrErr                          Ð44             Volume is locked through hardware
+               vLckdErr                        Ð46             Volume is locked through software
+               rfNumErr                        Ð51             Reference number invalid
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+       
+       __________
+       
+       Also see:       DTCopyComment, FSpDTCopyComment, FSpDTSetComment, DTGetComment,
+                               FSpDTGetComment
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDTSetComment(const FSSpec *spec,
+                                                               ConstStr255Param comment);
+/*     ¦ Set a file or directory's Finder comment field.
+       The FSpDTSetComment function sets a file or directory's Finder comment
+       field. The volume must support the Desktop Manager because you only
+       have read access to the Desktop file.
+
+       spec    input:  An FSSpec record specifying the file or directory.
+       comment input:  The comment to add. Comments are limited to 200 characters;
+                                       longer comments are truncated.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          Ð43             File or directory doesnÕt exist
+               wPrErr                          Ð44             Volume is locked through hardware
+               vLckdErr                        Ð46             Volume is locked through software
+               rfNumErr                        Ð51             Reference number invalid
+               paramErr                        -50             Volume doesn't support this function
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+       
+       __________
+       
+       Also see:       DTCopyComment, FSpDTCopyComment, DTSetComment, DTGetComment,
+                               FSpDTGetComment
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DTGetComment(short vRefNum,
+                                                        long dirID,
+                                                        ConstStr255Param name,
+                                                        Str255 comment);
+/*     ¦ Get a file or directory's Finder comment field (if any).
+       The DTGetComment function gets a file or directory's Finder comment
+       field (if any) from the Desktop Manager or if the Desktop Manager is
+       not available, from the Finder's Desktop file.
+
+       IMPORTANT NOTE: Inside Macintosh says that comments are up to
+       200 characters. While that may be correct for the HFS file system's
+       Desktop Manager, other file systems (such as Apple Photo Access) return
+       up to 255 characters. Make sure the comment buffer is a Str255 or you'll
+       regret it.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID
+                                       specifies a directory that's the object.
+       comment output: A Str255 where the comment is to be returned.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          -43             File not found
+               paramErr                        -50             Volume doesn't support this function
+               rfNumErr                        Ð51             Reference number invalid
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+               afpItemNotFound         -5012   Information not found
+               
+       __________
+       
+       Also see:       DTCopyComment, FSpDTCopyComment, DTSetComment, FSpDTSetComment,
+                               FSpDTGetComment
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDTGetComment(const FSSpec *spec,
+                                                               Str255 comment);
+/*     ¦ Get a file or directory's Finder comment field (if any).
+       The FSpDTGetComment function gets a file or directory's Finder comment
+       field (if any) from the Desktop Manager or if the Desktop Manager is
+       not available, from the Finder's Desktop file.
+
+       IMPORTANT NOTE: Inside Macintosh says that comments are up to
+       200 characters. While that may be correct for the HFS file system's
+       Desktop Manager, other file systems (such as Apple Photo Access) return
+       up to 255 characters. Make sure the comment buffer is a Str255 or you'll
+       regret it.
+       
+       spec    input:  An FSSpec record specifying the file or directory.
+       comment output: A Str255 where the comment is to be returned.
+
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          -43             File not found
+               paramErr                        -50             Volume doesn't support this function
+               rfNumErr                        Ð51             Reference number invalid
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+               afpItemNotFound         -5012   Information not found
+               
+       __________
+       
+       Also see:       DTCopyComment, FSpDTCopyComment, DTSetComment, FSpDTSetComment,
+                               DTGetComment
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DTCopyComment(short srcVRefNum,
+                                                         long srcDirID,
+                                                         ConstStr255Param srcName,
+                                                         short dstVRefNum,
+                                                         long dstDirID,
+                                                         ConstStr255Param dstName);
+/*     ¦ Copy the file or folder comment from the source to the destination object.
+       The DTCopyComment function copies the file or folder comment from the
+       source to the destination object.  The destination volume must support
+       the Desktop Manager because you only have read access to the Desktop file.
+       
+       srcVRefNum      input:  Source volume specification.
+       srcDirID        input:  Source directory ID.
+       srcName         input:  Pointer to source object name, or nil when srcDirID
+                                               specifies a directory that's the object.
+       dstVRefNum      input:  Destination volume specification.
+       dstDirID        input:  Destination directory ID.
+       dstName         input:  Pointer to destination object name, or nil when
+                                               dstDirID specifies a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          Ð43             File or directory doesnÕt exist
+               wPrErr                          Ð44             Volume is locked through hardware
+               vLckdErr                        Ð46             Volume is locked through software
+               paramErr                        -50             Volume doesn't support this function
+               rfNumErr                        Ð51             Reference number invalid
+               paramErr                        -50             Volume doesn't support this function
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+               afpItemNotFound         -5012   Information not found
+               
+       __________
+       
+       Also see:       FSpDTCopyComment, DTSetComment, FSpDTSetComment, DTGetComment,
+                               FSpDTGetComment
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpDTCopyComment(const FSSpec *srcSpec,
+                                                                const FSSpec *dstSpec);
+/*     ¦ Copy the desktop database comment from the source to the destination object.
+       The FSpDTCopyComment function copies the desktop database comment from
+       the source to the destination object.  Both the source and the
+       destination volumes must support the Desktop Manager.
+       
+       srcSpec         input:  An FSSpec record specifying the source object.
+       dstSpec         input:  An FSSpec record specifying the destination object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          Ð43             File or directory doesnÕt exist
+               wPrErr                          Ð44             Volume is locked through hardware
+               vLckdErr                        Ð46             Volume is locked through software
+               paramErr                        -50             Volume doesn't support this function
+               rfNumErr                        Ð51             Reference number invalid
+               paramErr                        -50             Volume doesn't support this function
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               desktopDamagedErr       -1305   The desktop database has become corrupted - 
+                                                                       the Finder will fix this, but if your
+                                                                       application is not running with the
+                                                                       Finder, use PBDTReset or PBDTDelete
+               afpItemNotFound         -5012   Information not found
+               
+       __________
+       
+       Also see:       DTCopyComment, DTSetComment, FSpDTSetComment, DTGetComment,
+                               FSpDTGetComment
+*/
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "OptimEnd.h"
+
+#endif /* __MOREDESKTOPMGR__ */
diff --git a/src/mac/morefile/MoreExtr.cpp b/src/mac/morefile/MoreExtr.cpp
new file mode 100644 (file)
index 0000000..cc64cd6
--- /dev/null
@@ -0,0 +1,3228 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     A collection of useful high-level File Manager routines.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           MoreFilesExtras.c
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#include <Types.h>
+#include <Traps.h>
+#include <OSUtils.h>
+#include <Errors.h>
+#include <Files.h>
+#include <Devices.h>
+#include <Finder.h>
+#include <Folders.h>
+#include <FSM.h>
+#include <Disks.h>
+#include <Gestalt.h>
+#include <TextUtils.h>
+#include <Script.h>
+#include <Script.h>
+#include <stddef.h>
+
+#define        __COMPILINGMOREFILES
+
+#include "MoreFile.h"
+#include "MoreExtr.h"
+#include "MoreDesk.h"
+#include "FSpCompa.h"
+
+/*****************************************************************************/
+
+/* local data structures */
+
+/* The DeleteEnumGlobals structure is used to minimize the amount of
+** stack space used when recursively calling DeleteLevel and to hold
+** global information that might be needed at any time. */
+
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=mac68k
+#endif
+struct DeleteEnumGlobals
+{
+       OSErr                   error;                          /* temporary holder of results - saves 2 bytes of stack each level */
+       Str63                   itemName;                       /* the name of the current item */
+       UniversalFMPB   myPB;                           /* the parameter block used for PBGetCatInfo calls */
+};
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=reset
+#endif
+
+typedef struct DeleteEnumGlobals DeleteEnumGlobals;
+typedef DeleteEnumGlobals *DeleteEnumGlobalsPtr;
+
+/*****************************************************************************/
+
+pascal void    TruncPString(StringPtr destination,
+                                                        ConstStr255Param source,
+                                                        short maxLength)
+{
+       short   charType;
+       
+       if ( source != NULL && destination != NULL )    /* don't do anything stupid */
+       {
+               if ( source[0] > maxLength )
+               {
+                       /* Make sure the string isn't truncated in the middle of */
+                       /* a multi-byte character. */
+                       while (maxLength != 0)
+                       {
+                               charType = CharByte((Ptr)&source[1], maxLength);
+                               if ( (charType == smSingleByte) || (charType == smLastByte) )
+                                       break;  /* source[maxLength] is now a valid last character */ 
+                               --maxLength;
+                       }
+               }
+               else
+               {
+                       maxLength = source[0];
+               }
+               /* Set the destination string length */
+               destination[0] = maxLength;
+               /* and copy maxLength characters (if needed) */
+               if ( source != destination )
+               {
+                       while ( maxLength != 0 )
+                       {
+                               destination[maxLength] = source[maxLength];
+                               --maxLength;
+                       }
+               }
+       }
+}
+
+/*****************************************************************************/
+
+pascal Ptr     GetTempBuffer(long buffReqSize,
+                                                 long *buffActSize)
+{
+       enum
+       {
+               kSlopMemory = 0x00008000        /* 32K - Amount of free memory to leave when allocating buffers */
+       };
+       Ptr     tempPtr;
+       
+       /* Make request a multiple of 1024 bytes */
+       buffReqSize = buffReqSize & 0xfffffc00;
+       
+       if ( buffReqSize < 0x00000400 )
+       {
+               /* Request was smaller than 1024 bytes - make it 1024 */
+               buffReqSize = 0x00000400;
+       }
+       
+       /* Attempt to allocate the memory */
+       tempPtr = NewPtr(buffReqSize);
+       
+       /* If request failed, go to backup plan */
+       if ( (tempPtr == NULL) && (buffReqSize > 0x00000400) )
+       {
+               /*
+               **      Try to get largest 1024-byte block available
+               **      leaving some slop for the toolbox if possible
+               */
+               long freeMemory = (FreeMem() - kSlopMemory) & 0xfffffc00;
+               
+               buffReqSize = MaxBlock() & 0xfffffc00;
+               
+               if ( buffReqSize > freeMemory )
+               {
+                       buffReqSize = freeMemory;
+               }
+               
+               if ( buffReqSize == 0 )
+               {
+                       buffReqSize = 0x00000400;
+               }
+               
+               tempPtr = NewPtr(buffReqSize);
+       }
+       
+       /* Return bytes allocated */
+       if ( tempPtr != NULL )
+       {
+               *buffActSize = buffReqSize;
+       }
+       else
+       {
+               *buffActSize = 0;
+       }
+       
+       return ( tempPtr );
+}
+
+/*****************************************************************************/
+
+/*
+**     GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
+**     in cases where the returned volume name is not needed by the caller.
+**     The pathname and vRefNum parameters are not touched, and the pb
+**     parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
+**     the parameter block is always returned as NULL (since it might point
+**     to the local tempPathname).
+**
+**     I noticed using this code in several places, so here it is once.
+**     This reduces the code size of MoreFiles.
+*/
+pascal OSErr   GetVolumeInfoNoName(ConstStr255Param pathname,
+                                                                       short vRefNum,
+                                                                       HParmBlkPtr pb)
+{
+       Str255 tempPathname;
+       OSErr error;
+       
+       /* Make sure pb parameter is not NULL */ 
+       if ( pb != NULL )
+       {
+               pb->volumeParam.ioVRefNum = vRefNum;
+               if ( pathname == NULL )
+               {
+                       pb->volumeParam.ioNamePtr = NULL;
+                       pb->volumeParam.ioVolIndex = 0;         /* use ioVRefNum only */
+               }
+               else
+               {
+                       BlockMoveData(pathname, tempPathname, pathname[0] + 1); /* make a copy of the string and */
+                       pb->volumeParam.ioNamePtr = (StringPtr)tempPathname;    /* use the copy so original isn't trashed */
+                       pb->volumeParam.ioVolIndex = -1;        /* use ioNamePtr/ioVRefNum combination */
+               }
+               error = PBHGetVInfoSync(pb);
+               pb->volumeParam.ioNamePtr = NULL;       /* ioNamePtr may point to local tempPathname, so don't return it */
+       }
+       else
+       {
+               error = paramErr;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**     XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync
+**     in cases where the returned volume name is not needed by the caller.
+**     The pathname and vRefNum parameters are not touched, and the pb
+**     parameter is initialized by PBXGetVolInfoSync except that ioNamePtr in
+**     the parameter block is always returned as NULL (since it might point
+**     to the local tempPathname).
+*/
+pascal OSErr   XGetVolumeInfoNoName(ConstStr255Param pathname,
+                                                                       short vRefNum,
+                                                                       XVolumeParamPtr pb)
+{
+       Str255 tempPathname;
+       long response;
+       OSErr error;
+       
+       /* Make sure pb parameter is not NULL */ 
+       if ( pb != NULL )
+       {
+               pb->ioVRefNum = vRefNum;
+               pb->ioXVersion = 0;                     /* this XVolumeParam version (0) */
+               if ( pathname == NULL )
+               {
+                       pb->ioNamePtr = NULL;
+                       pb->ioVolIndex = 0;             /* use ioVRefNum only */
+               }
+               else
+               {
+                       BlockMoveData(pathname, tempPathname, pathname[0] + 1); /* make a copy of the string and */
+                       pb->ioNamePtr = (StringPtr)tempPathname;        /* use the copy so original isn't trashed */
+                       pb->ioVolIndex = -1;    /* use ioNamePtr/ioVRefNum combination */
+               }
+#if    !__MACOSSEVENFIVEONEORLATER
+               /* Is PBXGetVolInfo available? */
+               if ( ( Gestalt(gestaltFSAttr, &response) != noErr ) || ((response & (1L << gestaltFSSupports2TBVols)) == 0) )
+               {
+                       /* No, fall back on PBHGetVInfo */
+                       error = PBHGetVInfoSync((HParmBlkPtr)pb);
+                       if ( error == noErr )
+                       {
+                               /* calculate the ioVTotalBytes and ioVFreeBytes fields */
+                               pb->ioVTotalBytes.hi = 0;
+                               pb->ioVTotalBytes.lo = pb->ioVNmAlBlks * pb->ioVAlBlkSiz;       /* calculated total number of bytes on volume */
+                               pb->ioVFreeBytes.hi = 0;
+                               pb->ioVFreeBytes.lo = pb->ioVFrBlk * pb->ioVAlBlkSiz;   /* calculated number of free bytes on volume */
+                       }
+               }
+               else
+#endif // !__MACOSSEVENFIVEONEORLATER
+               {
+                       /* Yes, so use it */
+                       error = PBXGetVolInfoSync(pb);
+               }
+               pb->ioNamePtr = NULL;           /* ioNamePtr may point to local tempPathname, so don't return it */
+       }
+       else
+       {
+               error = paramErr;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr GetCatInfoNoName(short vRefNum,
+                                                          long dirID,
+                                                          ConstStr255Param name,
+                                                          CInfoPBPtr pb)
+{
+       Str31 tempName;
+       OSErr error;
+       
+       /* Protection against File Sharing problem */
+       if ( (name == NULL) || (name[0] == 0) )
+       {
+               tempName[0] = 0;
+               pb->dirInfo.ioNamePtr = tempName;
+               pb->dirInfo.ioFDirIndex = -1;   /* use ioDirID */
+       }
+       else
+       {
+               pb->dirInfo.ioNamePtr = (StringPtr)name;
+               pb->dirInfo.ioFDirIndex = 0;    /* use ioNamePtr and ioDirID */
+       }
+       pb->dirInfo.ioVRefNum = vRefNum;
+       pb->dirInfo.ioDrDirID = dirID;
+       error = PBGetCatInfoSync(pb);
+       pb->dirInfo.ioNamePtr = NULL;
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DetermineVRefNum(ConstStr255Param pathname,
+                                                                short vRefNum,
+                                                                short *realVRefNum)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
+       if ( error == noErr )
+       {
+               *realVRefNum = pb.volumeParam.ioVRefNum;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HGetVInfo(short volReference,
+                                                 StringPtr volName,
+                                                 short *vRefNum,
+                                                 unsigned long *freeBytes,
+                                                 unsigned long *totalBytes)
+{
+       HParamBlockRec  pb;
+       unsigned long   allocationBlockSize;
+       unsigned short  numAllocationBlocks;
+       unsigned short  numFreeBlocks;
+       VCB                             *theVCB;
+       Boolean                 vcbFound;
+       OSErr                   result;
+       
+       /* Use the File Manager to get the real vRefNum */
+       pb.volumeParam.ioVRefNum = volReference;
+       pb.volumeParam.ioNamePtr = volName;
+       pb.volumeParam.ioVolIndex = 0;  /* use ioVRefNum only, return volume name */
+       result = PBHGetVInfoSync(&pb);
+       
+       if ( result == noErr )
+       {
+               /* The volume name was returned in volName (if not NULL) and */
+               /* we have the volume's vRefNum and allocation block size */
+               *vRefNum = pb.volumeParam.ioVRefNum;
+               allocationBlockSize = (unsigned long)pb.volumeParam.ioVAlBlkSiz;
+               
+               /* System 7.5 (and beyond) pins the number of allocation blocks and */
+               /* the number of free allocation blocks returned by PBHGetVInfo to */
+               /* a value so that when multiplied by the allocation block size, */
+               /* the volume will look like it has $7fffffff bytes or less. This */
+               /* was done so older applications that use signed math or that use */
+               /* the GetVInfo function (which uses signed math) will continue to work. */
+               /* However, the unpinned numbers (which we want) are always available */
+               /* in the volume's VCB so we'll get those values from the VCB if possible. */
+               
+               /* Find the volume's VCB */
+               vcbFound = false;
+               theVCB = (VCB *)(GetVCBQHdr()->qHead);
+               while ( (theVCB != NULL) && !vcbFound )
+               {
+                       /* Check VCB signature before using VCB. Don't have to check for */
+                       /* MFS (0xd2d7) because they can't get big enough to be pinned */
+                       if ( theVCB->vcbSigWord == 0x4244 )
+                       {
+                               if ( theVCB->vcbVRefNum == *vRefNum )
+                               {
+                                       vcbFound = true;
+                               }
+                       }
+                       
+                       if ( !vcbFound )
+                       {
+                               theVCB = (VCB *)(theVCB->qLink);
+                       }
+               }
+               
+               if ( theVCB != NULL )
+               {
+                       /* Found a VCB we can use. Get the un-pinned number of allocation blocks */
+                       /* and the number of free blocks from the VCB. */
+                       numAllocationBlocks = (unsigned short)theVCB->vcbNmAlBlks;
+                       numFreeBlocks = (unsigned short)theVCB->vcbFreeBks;
+               }
+               else
+               {
+                       /* Didn't find a VCB we can use. Return the number of allocation blocks */
+                       /* and the number of free blocks returned by PBHGetVInfoSync. */
+                       numAllocationBlocks = (unsigned short)pb.volumeParam.ioVNmAlBlks;
+                       numFreeBlocks = (unsigned short)pb.volumeParam.ioVFrBlk;
+               }
+               
+               /* Now, calculate freeBytes and totalBytes using unsigned values */
+               *freeBytes = numFreeBlocks * allocationBlockSize;
+               *totalBytes = numAllocationBlocks * allocationBlockSize;
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+**     PBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync
+**     File Manager requests from CFM-based programs. At some point, Apple
+**     will get around to adding this to the standard libraries you link with
+**     and you'll get a duplicate symbol link error. At that time, just delete
+**     this code (or comment it out).
+**
+**     Non-CFM 68K programs don't needs this glue (and won't get it) because
+**     they instead use the inline assembly glue found in the Files.h interface
+**     file.
+*/
+
+#if    __WANTPASCALELIMINATION
+#undef pascal
+#endif
+
+#if GENERATINGCFM
+pascal OSErr PBXGetVolInfoSync(XVolumeParamPtr paramBlock)
+{
+       enum
+       {
+               kXGetVolInfoSelector = 0x0012,  /* Selector for XGetVolInfo */
+               
+               uppFSDispatchProcInfo = kRegisterBased
+                        | REGISTER_RESULT_LOCATION(kRegisterD0)
+                        | RESULT_SIZE(SIZE_CODE(sizeof(OSErr)))
+                        | REGISTER_ROUTINE_PARAMETER(1, kRegisterD1, SIZE_CODE(sizeof(long)))  /* trap word */
+                        | REGISTER_ROUTINE_PARAMETER(2, kRegisterD0, SIZE_CODE(sizeof(long)))  /* selector */
+                        | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr)))
+       };
+       
+       return ( CallOSTrapUniversalProc(NGetTrapAddress(_FSDispatch, OSTrap),
+                                                                               uppFSDispatchProcInfo,
+                                                                               _FSDispatch,
+                                                                               kXGetVolInfoSelector,
+                                                                               paramBlock) );
+}
+#endif
+
+#if    __WANTPASCALELIMINATION
+#define        pascal  
+#endif
+
+/*****************************************************************************/
+
+pascal OSErr   XGetVInfo(short volReference,
+                                                 StringPtr volName,
+                                                 short *vRefNum,
+                                                 UnsignedWide *freeBytes,
+                                                 UnsignedWide *totalBytes)
+{
+       OSErr                   result;
+       long                    response;
+       XVolumeParam    pb;
+       
+       /* See if large volume support is available */
+       if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) )
+       {
+               /* Large volume support is available */
+               pb.ioVRefNum = volReference;
+               pb.ioNamePtr = volName;
+               pb.ioXVersion = 0;      /* this XVolumeParam version (0) */
+               pb.ioVolIndex = 0;      /* use ioVRefNum only, return volume name */
+               result = PBXGetVolInfoSync(&pb);
+               if ( result == noErr )
+               {
+                       /* The volume name was returned in volName (if not NULL) and */
+                       /* we have the volume's vRefNum and allocation block size */
+                       *vRefNum = pb.ioVRefNum;
+                       
+                       /* return the freeBytes and totalBytes */
+                       *totalBytes = pb.ioVTotalBytes;
+                       *freeBytes = pb.ioVFreeBytes;
+               }
+       }
+       else
+       {
+               /* No large volume support */
+               
+               /* Use HGetVInfo to get the results */
+               result = HGetVInfo(volReference, volName, vRefNum, &freeBytes->lo, &totalBytes->lo);
+               if ( result == noErr )
+               {
+                       /* zero the high longs of totalBytes and freeBytes */
+                       totalBytes->hi = 0;
+                       freeBytes->hi = 0;
+               }
+       }
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   CheckVolLock(ConstStr255Param pathname,
+                                                        short vRefNum)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
+       if ( error == noErr )
+       {
+               if ( (pb.volumeParam.ioVAtrb & 0x0080) != 0 )
+               {
+                       error = wPrErr;         /* volume locked by hardware */
+               }
+               else if ( (pb.volumeParam.ioVAtrb & 0x8000) != 0 )
+               {
+                       error = vLckdErr;       /* volume locked by software */
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr GetDriverName(short driverRefNum,
+                                                       Str255 driverName)
+{
+       OSErr result;
+       DCtlHandle theDctl;
+       DRVRHeaderPtr dHeaderPtr;
+       
+       theDctl = GetDCtlEntry(driverRefNum);
+       if ( theDctl != NULL )
+       {
+           if ( (**theDctl).dCtlFlags & 0x40 )
+           {
+               /* dctlDriver is handle - dereference */
+                       dHeaderPtr = *((DRVRHeaderHandle)(**theDctl).dCtlDriver);
+           }
+           else
+           {
+                       /* dctlDriver is pointer */
+             dHeaderPtr = (DRVRHeaderPtr)(**theDctl).dCtlDriver;
+           }
+               BlockMoveData((*dHeaderPtr).drvrName, driverName, (*dHeaderPtr).drvrName[0] + 1);
+               result = noErr;
+       }
+       else
+       {
+               driverName[0] = 0;
+               result = badUnitErr;    /* bad reference number */
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FindDrive(ConstStr255Param pathname,
+                                                 short vRefNum,
+                                                 DrvQElPtr *driveQElementPtr)
+{
+       OSErr                   result;
+       HParamBlockRec  hPB;
+       short                   driveNumber;
+       
+       *driveQElementPtr = NULL;
+       
+       /* First, use GetVolumeInfoNoName to determine the volume */
+       result = GetVolumeInfoNoName(pathname, vRefNum, &hPB);
+       if ( result == noErr )
+       {
+               /*
+               **      The volume can be either online, offline, or ejected. What we find in
+               **      ioVDrvInfo and ioVDRefNum will tell us which it is.
+               **      See Inside Macintosh: Files page 2-80 and the Technical Note
+               **      "FL 34 - VCBs and Drive Numbers : The Real Story"
+               **      Where we get the drive number depends on the state of the volume.
+               */
+               if ( hPB.volumeParam.ioVDrvInfo != 0 )
+               {
+                       /* The volume is online and not ejected */
+                       /* Get the drive number */
+                       driveNumber = hPB.volumeParam.ioVDrvInfo;
+               }
+               else
+               {
+                       /* The volume's is either offline or ejected */
+                       /* in either case, the volume is NOT online */
+
+                       /* Is it ejected or just offline? */
+                       if ( hPB.volumeParam.ioVDRefNum > 0 )
+                       {
+                               /* It's ejected, the drive number is ioVDRefNum */
+                               driveNumber = hPB.volumeParam.ioVDRefNum;
+                       }
+                       else
+                       {
+                               /* It's offline, the drive number is the negative of ioVDRefNum */
+                               driveNumber = (short)-hPB.volumeParam.ioVDRefNum;
+                       }
+               }
+               
+               /* Get pointer to first element in drive queue */
+               *driveQElementPtr = (DrvQElPtr)(GetDrvQHdr()->qHead);
+               
+               /* Search for a matching drive number */
+               while ( (*driveQElementPtr != NULL) && ((*driveQElementPtr)->dQDrive != driveNumber) )
+               {
+                       *driveQElementPtr = (DrvQElPtr)(*driveQElementPtr)->qLink;
+               }
+               
+               if ( *driveQElementPtr == NULL )
+               {
+                       /* This should never happen since every volume must have a drive, but... */
+                       result = nsDrvErr;
+               }
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetDiskBlocks(ConstStr255Param pathname,
+                                                         short vRefNum,
+                                                         unsigned long *numBlocks)
+{
+       /* Various constants for GetDiskBlocks() */
+       enum
+       {
+               /* return format list status code */
+               kFmtLstCode = 6,
+               
+               /* reference number of .SONY driver */
+               kSonyRefNum = 0xfffb,
+               
+               /* values returned by DriveStatus in DrvSts.twoSideFmt */
+               kSingleSided = 0,
+               kDoubleSided = -1,
+               kSingleSidedSize = 800,         /* 400K */
+               kDoubleSidedSize = 1600,        /* 800K */
+               
+               /* values in DrvQEl.qType */
+               kWordDrvSiz = 0,
+               kLongDrvSiz = 1,
+               
+               /* more than enough formatListRecords */
+               kMaxFormatListRecs = 16
+       };
+       
+       DrvQElPtr               driveQElementPtr;
+       unsigned long   blocks;
+       ParamBlockRec   pb;
+       FormatListRec   formatListRecords[kMaxFormatListRecs];
+       DrvSts                  status;
+       short                   formatListRecIndex;
+       OSErr                   result;
+
+       blocks = 0;
+       
+       /* Find the drive queue element for this volume */
+       result = FindDrive(pathname, vRefNum, &driveQElementPtr);
+       
+       /* 
+       **      Make sure this is a real driver (dQRefNum < 0).
+       **      AOCE's Mail Enclosures volume uses 0 for dQRefNum which will cause
+       **      problems if you try to use it as a driver refNum.
+       */ 
+       if ( (result == noErr) && (driveQElementPtr->dQRefNum >= 0) )
+       {
+               result = paramErr;
+       }
+       else
+       {
+               /* Attempt to get the drive's format list. */
+               /* (see the Technical Note "What Your Sony Drives For You") */
+               
+               pb.cntrlParam.ioVRefNum = driveQElementPtr->dQDrive;
+               pb.cntrlParam.ioCRefNum = driveQElementPtr->dQRefNum;
+               pb.cntrlParam.csCode = kFmtLstCode;
+               pb.cntrlParam.csParam[0] = kMaxFormatListRecs;
+               *(long *)&pb.cntrlParam.csParam[1] = (long)&formatListRecords[0];
+               
+               result = PBStatusSync(&pb);
+               
+               if ( result == noErr )
+               {
+                       /* The drive supports ReturnFormatList status call. */
+                       
+                       /* Get the current disk's size. */
+                       for( formatListRecIndex = 0;
+                                formatListRecIndex < pb.cntrlParam.csParam[0];
+                        ++formatListRecIndex )
+               {
+                       if ( (formatListRecords[formatListRecIndex].formatFlags &
+                                 diCIFmtFlagsCurrentMask) != 0 )
+                       {
+                               blocks = formatListRecords[formatListRecIndex].volSize;
+                       }
+                       }
+               if ( blocks == 0 )
+               {
+                       /* This should never happen */
+                       result = paramErr;
+               }
+               }
+               else if ( driveQElementPtr->dQRefNum == (short)kSonyRefNum )
+               {
+                       /* The drive is a non-SuperDrive floppy which only supports 400K and 800K disks */
+                       
+                       result = DriveStatus(driveQElementPtr->dQDrive, &status);
+                       if ( result == noErr )
+                       {
+                               switch ( status.twoSideFmt )
+                               {
+                               case kSingleSided:
+                                       blocks = kSingleSidedSize;
+                                       break;
+                               case kDoubleSided:
+                                       blocks = kDoubleSidedSize;
+                                       break;
+                               default:
+                                       /* This should never happen */
+                                       result = paramErr;
+                                       break;
+                               }
+                       }
+               }
+               else
+               {
+                       /* The drive is not a floppy and it doesn't support ReturnFormatList */
+                       /* so use the dQDrvSz field(s) */
+                       
+                       result = noErr; /* reset result */
+                       switch ( driveQElementPtr->qType )
+                       {
+                       case kWordDrvSiz:
+                               blocks = driveQElementPtr->dQDrvSz;
+                               break;
+                       case kLongDrvSiz:
+                               blocks = ((unsigned long)driveQElementPtr->dQDrvSz2 << 16) +
+                                                driveQElementPtr->dQDrvSz;
+                               break;
+                       default:
+                               /* This should never happen */
+                               result = paramErr;
+                               break;
+                       }
+               }
+       }
+       
+       if ( result == noErr )
+       {
+               *numBlocks = blocks;
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetVolFileSystemID(ConstStr255Param pathname,
+                                                                  short vRefNum,
+                                                                  short *fileSystemID)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
+       if ( error == noErr )
+       {
+               *fileSystemID = pb.volumeParam.ioVFSID;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetVolState(ConstStr255Param pathname,
+                                                       short vRefNum,
+                                                       Boolean *volumeOnline,
+                                                       Boolean *volumeEjected,
+                                                       Boolean *driveEjectable,
+                                                       Boolean *driverWantsEject)
+{
+       HParamBlockRec pb;
+       short driveNumber;
+       OSErr error;
+
+       error = GetVolumeInfoNoName(pathname,vRefNum, &pb);
+       if ( error == noErr )
+       {
+               if ( pb.volumeParam.ioVDrvInfo != 0 )
+               {
+                       /* the volume is online and not ejected */
+                       *volumeOnline = true;
+                       *volumeEjected = false;
+                       
+                       /* Get the drive number */
+                       driveNumber = pb.volumeParam.ioVDrvInfo;
+               }
+               else
+               {
+                       /* the volume's is either offline or ejected */
+                       /* in either case, the volume is NOT online */
+                       *volumeOnline = false;
+
+                       /* Is it ejected? */
+                       *volumeEjected = pb.volumeParam.ioVDRefNum > 0;
+                       
+                       if ( *volumeEjected )
+                       {
+                               /* If ejected, the drive number is ioVDRefNum */
+                               driveNumber = pb.volumeParam.ioVDRefNum;
+                       }
+                       else
+                       {
+                               /* If offline, the drive number is the negative of ioVDRefNum */
+                               driveNumber = (short)-pb.volumeParam.ioVDRefNum;
+                       }
+               }
+               
+               {
+                       DrvQElPtr drvQElem;
+                       
+                       /* Find the drive queue element by searching the drive queue */
+                       drvQElem = (DrvQElPtr)(GetDrvQHdr()->qHead);
+                       while ( (drvQElem != NULL) && (drvQElem->dQDrive != driveNumber) )
+                       {
+                               drvQElem = (DrvQElPtr)drvQElem->qLink;
+                       }
+                       
+                       if ( drvQElem != NULL )
+                       {
+                               /*
+                               **      Each drive queue element is preceded by 4 flag bytes.
+                               **      Byte 1 (the second flag byte) has bits that tell us if a
+                               **      drive is ejectable and if its driver wants an eject call.
+                               **      See Inside Macintosh: Files, page 2-85.
+                               */
+                               {
+                                       Ptr             flagBytePtr;
+                                       
+                                       /* point to byte 1 of the flag bytes */
+                                       flagBytePtr = (Ptr)drvQElem;
+                                       flagBytePtr -= 3;
+                                       
+                                       /*
+                                       **      The drive is ejectable if flag byte 1 does not contain
+                                       **      0x08 (nonejectable) or 0x48 (nonejectable, but wants eject call).
+                                       */
+                                       
+                                       *driveEjectable = (*flagBytePtr != 0x08) && (*flagBytePtr != 0x48);
+                                       
+                                       /*
+                                       **      The driver wants an eject call if flag byte 1 does not contain
+                                       **      0x08 (nonejectable). This may seem like a minor point, but some
+                                       **      disk drivers use the Eject request to flush their caches to disk
+                                       **      and you wouldn't want to skip that step after unmounting a volume.
+                                       */
+                                       
+                                       *driverWantsEject = (*flagBytePtr != 0x08);
+                               }
+                       }
+                       else
+                       {
+                               /* Didn't find the drive (this should never happen) */
+                               *driveEjectable = false;
+                               *driverWantsEject = false;
+                       }
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   UnmountAndEject(ConstStr255Param pathname,
+                                                               short vRefNum)
+{
+       HParamBlockRec pb;
+       short driveNum;
+       Boolean ejected, wantsEject;
+       DrvQElPtr drvQElem;
+       OSErr error;
+
+       error = GetVolumeInfoNoName(pathname, vRefNum, &pb);
+       if ( error == noErr )
+       {
+               if ( pb.volumeParam.ioVDrvInfo != 0 )
+               {
+                       /* the volume is online and not ejected */
+                       ejected = false;
+                       
+                       /* Get the drive number */
+                       driveNum = pb.volumeParam.ioVDrvInfo;
+               }
+               else
+               {
+                       /* the volume is ejected or offline */
+                       
+                       /* Is it ejected? */
+                       ejected = pb.volumeParam.ioVDRefNum > 0;
+                       
+                       if ( ejected )
+                       {
+                               /* If ejected, the drive number is ioVDRefNum */
+                               driveNum = pb.volumeParam.ioVDRefNum;
+                       }
+                       else
+                       {
+                               /* If offline, the drive number is the negative of ioVDRefNum */
+                               driveNum = (short)-pb.volumeParam.ioVDRefNum;
+                       }
+               }
+               
+               /* find the drive queue element */
+               drvQElem = (DrvQElPtr)(GetDrvQHdr()->qHead);
+               while ( (drvQElem != NULL) && (drvQElem->dQDrive != driveNum) )
+               {
+                       drvQElem = (DrvQElPtr)drvQElem->qLink;
+               }
+               
+               if ( drvQElem != NULL )
+               {
+                       /* does the drive want an eject call */
+                       wantsEject = (*((Ptr)((Ptr)drvQElem - 3)) != 8);
+               }
+               else
+               {
+                       /* didn't find the drive!! */
+                       wantsEject = false;
+               }
+               
+               /* unmount the volume */
+               pb.volumeParam.ioNamePtr = NULL;
+               /* ioVRefNum is already filled in from PBHGetVInfo */
+               error = PBUnmountVol((ParmBlkPtr)&pb);
+               if ( error == noErr )
+               {
+                       if ( wantsEject && !ejected )
+                       {
+                               /* eject the media from the drive if needed */
+                               pb.volumeParam.ioVRefNum = driveNum;
+                               error = PBEject((ParmBlkPtr)&pb);
+                       }
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   OnLine(FSSpecPtr volumes,
+                                          short reqVolCount,
+                                          short *actVolCount,
+                                          short *volIndex)
+{
+       HParamBlockRec pb;
+       OSErr error = noErr;
+       FSSpec *endVolArray;
+
+       if ( *volIndex > 0 )
+       {
+               *actVolCount = 0;
+               for ( endVolArray = volumes + reqVolCount; (volumes < endVolArray) && (error == noErr); ++volumes )
+               {
+                       pb.volumeParam.ioNamePtr = (StringPtr) & volumes->name;
+                       pb.volumeParam.ioVolIndex = *volIndex;
+                       error = PBHGetVInfoSync(&pb);
+                       if ( error == noErr )
+                       {
+                               volumes->parID = fsRtParID;             /* the root directory's parent is 1 */
+                               volumes->vRefNum = pb.volumeParam.ioVRefNum;
+                               ++*volIndex;
+                               ++*actVolCount;
+                       }
+               }
+       }
+       else
+       {
+               error = paramErr;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr SetDefault(short newVRefNum,
+                                                long newDirID,
+                                                short *oldVRefNum,
+                                                long *oldDirID)
+{
+       OSErr   error;
+       
+       /* Get the current default volume/directory. */
+       error = HGetVol(NULL, oldVRefNum, oldDirID);
+       if ( error == noErr )
+       {
+               /* Set the new default volume/directory */
+               error = HSetVol(NULL, newVRefNum, newDirID);
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr RestoreDefault(short oldVRefNum,
+                                                        long oldDirID)
+{
+       OSErr   error;
+       short   defaultVRefNum;
+       long    defaultDirID;
+       long    defaultProcID;
+       
+       /* Determine if the default volume was a wdRefNum. */
+       error = GetWDInfo(oldVRefNum, &defaultVRefNum, &defaultDirID, &defaultProcID);
+       if ( error == noErr )
+       {
+               /* Restore the old default volume/directory, one way or the other. */
+               if ( defaultDirID != fsRtDirID )
+               {
+                       /* oldVRefNum was a wdRefNum - use SetVol */
+                       error = SetVol(NULL, oldVRefNum);
+               }
+               else
+               {
+                       /* oldVRefNum was a real vRefNum - use HSetVol */
+                       error = HSetVol(NULL, oldVRefNum, oldDirID);
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr GetDInfo(short vRefNum,
+                                          long dirID,
+                                          ConstStr255Param name,
+                                          DInfo *fndrInfo)
+{
+       CInfoPBRec pb;
+       OSErr error;
+       
+       error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+       if ( error == noErr )
+       {
+               if ( (pb.dirInfo.ioFlAttrib & ioDirMask) != 0 )
+               {
+                       /* it's a directory, return the DInfo */
+                       *fndrInfo = pb.dirInfo.ioDrUsrWds;
+               }
+               else
+               {
+                       /* oops, a file was passed */
+                       error = dirNFErr;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpGetDInfo(const FSSpec *spec,
+                                                 DInfo *fndrInfo)
+{
+       return ( GetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr SetDInfo(short vRefNum,
+                                          long dirID,
+                                          ConstStr255Param name,
+                                          const DInfo *fndrInfo)
+{
+       CInfoPBRec pb;
+       Str31 tempName;
+       OSErr error;
+
+       /* Protection against File Sharing problem */
+       if ( (name == NULL) || (name[0] == 0) )
+       {
+               tempName[0] = 0;
+               pb.dirInfo.ioNamePtr = tempName;
+               pb.dirInfo.ioFDirIndex = -1;    /* use ioDirID */
+       }
+       else
+       {
+               pb.dirInfo.ioNamePtr = (StringPtr)name;
+               pb.dirInfo.ioFDirIndex = 0;     /* use ioNamePtr and ioDirID */
+       }
+       pb.dirInfo.ioVRefNum = vRefNum;
+       pb.dirInfo.ioDrDirID = dirID;
+       error = PBGetCatInfoSync(&pb);
+       if ( error == noErr )
+       {
+               if ( (pb.dirInfo.ioFlAttrib & ioDirMask) != 0 )
+               {
+                       /* it's a directory, set the DInfo */
+                       if ( pb.dirInfo.ioNamePtr == tempName )
+                       {
+                               pb.dirInfo.ioDrDirID = pb.dirInfo.ioDrParID;
+                       }
+                       else
+                       {
+                               pb.dirInfo.ioDrDirID = dirID;
+                       }
+                       pb.dirInfo.ioDrUsrWds = *fndrInfo;
+                       error = PBSetCatInfoSync(&pb);
+               }
+               else
+               {
+                       /* oops, a file was passed */
+                       error = dirNFErr;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr FSpSetDInfo(const FSSpec *spec,
+                                                 const DInfo *fndrInfo)
+{
+       return ( SetDInfo(spec->vRefNum, spec->parID, spec->name, fndrInfo) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetDirectoryID(short vRefNum,
+                                                          long dirID,
+                                                          ConstStr255Param name,
+                                                          long *theDirID,
+                                                          Boolean *isDirectory)
+{
+       CInfoPBRec pb;
+       OSErr error;
+
+       error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+       if ( error == noErr )
+       {
+               *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
+               if ( *isDirectory )
+               {
+                       *theDirID = pb.dirInfo.ioDrDirID;
+               }
+               else
+               {
+                       *theDirID = pb.hFileInfo.ioFlParID;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetDirectoryID(const FSSpec *spec,
+                                                                 long *theDirID,
+                                                                 Boolean *isDirectory)
+{
+       return ( GetDirectoryID(spec->vRefNum, spec->parID, spec->name,
+                        theDirID, isDirectory) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetDirName(short vRefNum,
+                                                  long dirID,
+                                                  Str31 name)
+{
+       CInfoPBRec pb;
+       OSErr error;
+
+       if ( name != NULL )
+       {
+               pb.dirInfo.ioNamePtr = name;
+               pb.dirInfo.ioVRefNum = vRefNum;
+               pb.dirInfo.ioDrDirID = dirID;
+               pb.dirInfo.ioFDirIndex = -1;    /* get information about ioDirID */
+               error = PBGetCatInfoSync(&pb);
+       }
+       else
+       {
+               error = paramErr;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetIOACUser(short vRefNum,
+                                                       long dirID,
+                                                       ConstStr255Param name,
+                                                       SInt8 *ioACUser)
+{
+       CInfoPBRec pb;
+       OSErr error;
+       
+       /* Clear ioACUser before calling PBGetCatInfo since some file systems
+       ** don't bother to set or clear this field. If ioACUser isn't set by the
+       ** file system, then you'll get the zero value back (full access) which
+       ** is the access you have on volumes that don't support ioACUser.
+       */
+       pb.dirInfo.ioACUser = 0;        /* ioACUser used to be filler2 */
+       error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+       if ( error == noErr )
+       {
+               if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 )
+               {
+                       /* oops, a file was passed */
+                       error = dirNFErr;
+               }
+               else
+               {
+                       *ioACUser = pb.dirInfo.ioACUser;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetIOACUser(const FSSpec *spec,
+                                                          SInt8 *ioACUser)
+{
+       return ( GetIOACUser(spec->vRefNum, spec->parID, spec->name, ioACUser) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetParentID(short vRefNum,
+                                                       long dirID,
+                                                       ConstStr255Param name,
+                                                       long *parID)
+{
+       CInfoPBRec pb;
+       Str31 tempName;
+       OSErr error;
+       short realVRefNum;
+       
+       /* Protection against File Sharing problem */
+       if ( (name == NULL) || (name[0] == 0) )
+       {
+               tempName[0] = 0;
+               pb.hFileInfo.ioNamePtr = tempName;
+               pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
+       }
+       else
+       {
+               pb.hFileInfo.ioNamePtr = (StringPtr)name;
+               pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
+       }
+       pb.hFileInfo.ioVRefNum = vRefNum;
+       pb.hFileInfo.ioDirID = dirID;
+       error = PBGetCatInfoSync(&pb);
+       if ( error == noErr )
+       {
+               /*
+               **      There's a bug in HFS where the wrong parent dir ID can be
+               **      returned if multiple separators are used at the end of a
+               **      pathname. For example, if the pathname:
+               **              'volumeName:System Folder:Extensions::'
+               **      is passed, the directory ID of the Extensions folder is
+               **      returned in the ioFlParID field instead of fsRtDirID. Since
+               **      multiple separators at the end of a pathname always specifies
+               **      a directory, we only need to work-around cases where the
+               **      object is a directory and there are multiple separators at
+               **      the end of the name parameter.
+               */
+               if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+               {
+                       /* Its a directory */
+                       
+                       /* is there a pathname? */
+                       if ( pb.hFileInfo.ioNamePtr == name )   
+                       {
+                               /* could it contain multiple separators? */
+                               if ( name[0] >= 2 )
+                               {
+                                       /* does it contain multiple separators at the end? */
+                                       if ( (name[name[0]] == ':') && (name[name[0] - 1] == ':') )
+                                       {
+                                               /* OK, then do the extra stuff to get the correct parID */
+                                               
+                                               /* Get the real vRefNum (this should not fail) */
+                                               error = DetermineVRefNum(name, vRefNum, &realVRefNum);
+                                               if ( error == noErr )
+                                               {
+                                                       /* we don't need the parent's name, but add protect against File Sharing problem */
+                                                       tempName[0] = 0;
+                                                       pb.dirInfo.ioNamePtr = tempName;
+                                                       pb.dirInfo.ioVRefNum = realVRefNum;
+                                                       /* pb.dirInfo.ioDrDirID already contains the */
+                                                       /* dirID of the directory object */
+                                                       pb.dirInfo.ioFDirIndex = -1;    /* get information about ioDirID */
+                                                       error = PBGetCatInfoSync(&pb);
+                                                       /* now, pb.dirInfo.ioDrParID contains the correct parID */
+                                               }
+                                       }
+                               }
+                       }
+               }
+               
+               if ( error == noErr )
+               {
+                       /* if no errors, then pb.hFileInfo.ioFlParID (pb.dirInfo.ioDrParID) */
+                       /* contains the parent ID */
+                       *parID = pb.hFileInfo.ioFlParID;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetFilenameFromPathname(ConstStr255Param pathname,
+                                                                               Str255 filename)
+{
+       short   index;
+       short   nameEnd;
+       OSErr   error;
+
+       /* default to no filename */
+       filename[0] = 0;
+
+       /* check for no pathname */
+       if ( pathname != NULL )
+       {
+               /* get string length */
+               index = pathname[0];
+               
+               /* check for empty string */
+               if ( index != 0 )
+               {
+                       /* skip over last trailing colon (if any) */
+                       if ( pathname[index] == ':' )
+                       {
+                               --index;
+                       }
+
+                       /* save the end of the string */
+                       nameEnd = index;
+
+                       /* if pathname ends with multiple colons, then this pathname refers */
+                       /* to a directory, not a file */
+                       if ( pathname[index] != ':' )
+                       {
+                               /* parse backwards until we find a colon or hit the beginning of the pathname */
+                               while ( (index != 0) && (pathname[index] != ':') )
+                               {
+                                       --index;
+                               }
+                               
+                               /* if we parsed to the beginning of the pathname and the pathname ended */
+                               /* with a colon, then pathname is a full pathname to a volume, not a file */
+                               if ( (index != 0) || (pathname[pathname[0]] != ':') )
+                               {
+                                       /* get the filename and return noErr */
+                                       filename[0] = (char)(nameEnd - index);
+                                       BlockMoveData(&pathname[index+1], &filename[1], nameEnd - index);
+                                       error = noErr;
+                               }
+                               else
+                               {
+                                       /* pathname to a volume, not a file */
+                                       error = notAFileErr;
+                               }
+                       }
+                       else
+                       {
+                               /* directory, not a file */
+                               error = notAFileErr;
+                       }
+               }
+               else
+               {
+                       /* empty string isn't a file */
+                       error = notAFileErr;
+               }
+       }
+       else
+       {
+               /* NULL pathname isn't a file */
+               error = notAFileErr;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetObjectLocation(short vRefNum,
+                                                                 long dirID,
+                                                                 ConstStr255Param pathname,
+                                                                 short *realVRefNum,
+                                                                 long *realParID,
+                                                                 Str255 realName,
+                                                                 Boolean *isDirectory)
+{
+       OSErr error;
+       CInfoPBRec pb;
+       Str255 tempPathname;
+       
+       /* clear results */
+       *realVRefNum = 0;
+       *realParID = 0;
+       realName[0] = 0;
+       
+       /*
+       **      Get the real vRefNum
+       */
+       error = DetermineVRefNum(pathname, vRefNum, realVRefNum);
+       if ( error == noErr )
+       {
+               /*
+               **      Determine if the object already exists and if so,
+               **      get the real parent directory ID if it's a file
+               */
+               
+               /* Protection against File Sharing problem */
+               if ( (pathname == NULL) || (pathname[0] == 0) )
+               {
+                       tempPathname[0] = 0;
+                       pb.hFileInfo.ioNamePtr = tempPathname;
+                       pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
+               }
+               else
+               {
+                       pb.hFileInfo.ioNamePtr = (StringPtr)pathname;
+                       pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
+               }
+               pb.hFileInfo.ioVRefNum = vRefNum;
+               pb.hFileInfo.ioDirID = dirID;
+               error = PBGetCatInfoSync(&pb);
+               if ( error == noErr )
+               {
+                       /*
+                       **      The file system object is present and we have the file's real parID
+                       */
+                       
+                       /*      Is it a directory or a file? */
+                       *isDirectory = (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0;
+                       if ( *isDirectory )
+                       {
+                               /*
+                               **      It's a directory, get its name and parent dirID, and then we're done
+                               */
+                               
+                               pb.dirInfo.ioNamePtr = realName;
+                               pb.dirInfo.ioVRefNum = *realVRefNum;
+                               /* pb.dirInfo.ioDrDirID already contains the dirID of the directory object */
+                               pb.dirInfo.ioFDirIndex = -1;    /* get information about ioDirID */
+                               error = PBGetCatInfoSync(&pb);
+                               
+                               /* get the parent ID here, because the file system can return the */
+                               /* wrong parent ID from the last call. */
+                               *realParID = pb.dirInfo.ioDrParID;
+                       }
+                       else
+                       {
+                               /*
+                               **      It's a file - use the parent directory ID from the last call
+                               **      to GetCatInfoparse, get the file name, and then we're done
+                               */
+                               *realParID = pb.hFileInfo.ioFlParID;    
+                               error = GetFilenameFromPathname(pathname, realName);
+                       }
+               }
+               else if ( error == fnfErr )
+               {
+                       /*
+                       **      The file system object is not present - see if its parent is present
+                       */
+                       
+                       /*
+                       **      Parse to get the object name from end of pathname
+                       */
+                       error = GetFilenameFromPathname(pathname, realName);
+                       
+                       /* if we can't get the object name from the end, we can't continue */
+                       if ( error == noErr )
+                       {
+                               /*
+                               **      What we want now is the pathname minus the object name
+                               **      for example:
+                               **      if pathname is 'vol:dir:file' tempPathname becomes 'vol:dir:'
+                               **      if pathname is 'vol:dir:file:' tempPathname becomes 'vol:dir:'
+                               **      if pathname is ':dir:file' tempPathname becomes ':dir:'
+                               **      if pathname is ':dir:file:' tempPathname becomes ':dir:'
+                               **      if pathname is ':file' tempPathname becomes ':'
+                               **      if pathname is 'file or file:' tempPathname becomes ''
+                               */
+                               
+                               /* get a copy of the pathname */
+                               BlockMoveData(pathname, tempPathname, pathname[0] + 1);
+                               
+                               /* remove the object name */
+                               tempPathname[0] -= realName[0];
+                               /* and the trailing colon (if any) */
+                               if ( pathname[pathname[0]] == ':' )
+                               {
+                                       --tempPathname[0];
+                               }
+                               
+                               /* OK, now get the parent's directory ID */
+                               
+                               /* Protection against File Sharing problem */
+                               pb.hFileInfo.ioNamePtr = (StringPtr)tempPathname;
+                               if ( tempPathname[0] != 0 )
+                               {
+                                       pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
+                               }
+                               else
+                               {
+                                       pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
+                               }
+                               pb.hFileInfo.ioVRefNum = vRefNum;
+                               pb.hFileInfo.ioDirID = dirID;
+                               error = PBGetCatInfoSync(&pb);
+                               *realParID = pb.dirInfo.ioDrDirID;
+
+                               *isDirectory = false;   /* we don't know what the object is really going to be */
+                       }
+                       
+                       if ( error != noErr )
+                       {
+                               error = dirNFErr;       /* couldn't find parent directory */
+                       }
+                       else
+                       {
+                               error = fnfErr; /* we found the parent, but not the file */
+                       }
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetDirItems(short vRefNum,
+                                                       long dirID,
+                                                       ConstStr255Param name,
+                                                       Boolean getFiles,
+                                                       Boolean getDirectories,
+                                                       FSSpecPtr items,
+                                                       short reqItemCount,
+                                                       short *actItemCount,
+                                                       short *itemIndex) /* start with 1, then use what's returned */
+{
+       CInfoPBRec pb;
+       OSErr error;
+       long theDirID;
+       Boolean isDirectory;
+       FSSpec *endItemsArray;
+       
+       if ( *itemIndex > 0 )
+       {
+               /* NOTE: If I could be sure that the caller passed a real vRefNum and real directory */
+               /* to this routine, I could rip out calls to DetermineVRefNum and GetDirectoryID and this */
+               /* routine would be much faster because of the overhead of DetermineVRefNum and */
+               /* GetDirectoryID and because GetDirectoryID blows away the directory index hint the Macintosh */
+               /* file system keeps for indexed calls. I can't be sure, so for maximum throughput, */
+               /* pass a big array of FSSpecs so you can get the directory's contents with few calls */
+               /* to this routine. */
+               
+               /* get the real volume reference number */
+               error = DetermineVRefNum(name, vRefNum, &pb.hFileInfo.ioVRefNum);
+               if ( error == noErr )
+               {
+                       /* and the real directory ID of this directory (and make sure it IS a directory) */
+                       error = GetDirectoryID(vRefNum, dirID, name, &theDirID, &isDirectory);
+                       if ( error == noErr )
+                       {
+                               if ( isDirectory )
+                               {
+                                       *actItemCount = 0;
+                                       endItemsArray = items + reqItemCount;
+                                       while ( (items < endItemsArray) && (error == noErr) )
+                                       {
+                                               pb.hFileInfo.ioNamePtr = (StringPtr) &items->name;
+                                               pb.hFileInfo.ioDirID = theDirID;
+                                               pb.hFileInfo.ioFDirIndex = *itemIndex;
+                                               error = PBGetCatInfoSync(&pb);
+                                               if ( error == noErr )
+                                               {
+                                                       items->parID = pb.hFileInfo.ioFlParID;  /* return item's parID */
+                                                       items->vRefNum = pb.hFileInfo.ioVRefNum;        /* return item's vRefNum */
+                                                       ++*itemIndex;   /* prepare to get next item in directory */
+                                                       
+                                                       if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+                                                       {
+                                                               if ( getDirectories )
+                                                               {
+                                                                       ++*actItemCount; /* keep this item */
+                                                                       ++items; /* point to next item */
+                                                               }
+                                                       }
+                                                       else
+                                                       {
+                                                               if ( getFiles )
+                                                               {
+                                                                       ++*actItemCount; /* keep this item */
+                                                                       ++items; /* point to next item */
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               else
+                               {
+                                       /* it wasn't a directory */
+                                       error = dirNFErr;
+                               }
+                       }
+               }
+       }
+       else
+       {
+               /* bad itemIndex */
+               error = paramErr;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+static void    DeleteLevel(long dirToDelete,
+                                                       DeleteEnumGlobalsPtr theGlobals)
+{
+       long savedDir;
+       
+       do
+       {
+               /* prepare to delete directory */
+               theGlobals->myPB.ciPB.dirInfo.ioNamePtr = (StringPtr)&theGlobals->itemName;
+               theGlobals->myPB.ciPB.dirInfo.ioFDirIndex = 1;  /* get first item */
+               theGlobals->myPB.ciPB.dirInfo.ioDrDirID = dirToDelete;  /* in this directory */
+               theGlobals->error = PBGetCatInfoSync(&(theGlobals->myPB.ciPB));
+               if ( theGlobals->error == noErr )
+               {
+                       savedDir = dirToDelete;
+                       /* We have an item.  Is it a file or directory? */
+                       if ( (theGlobals->myPB.ciPB.dirInfo.ioFlAttrib & ioDirMask) != 0 )
+                       {
+                               /* it's a directory */
+                               savedDir = theGlobals->myPB.ciPB.dirInfo.ioDrDirID;     /* save dirID of directory instead */
+                               DeleteLevel(theGlobals->myPB.ciPB.dirInfo.ioDrDirID, theGlobals);       /* Delete its contents */
+                               theGlobals->myPB.ciPB.dirInfo.ioNamePtr = NULL; /* prepare to delete directory */
+                       }
+                       if ( theGlobals->error == noErr )
+                       {
+                               theGlobals->myPB.ciPB.dirInfo.ioDrDirID = savedDir;     /* restore dirID */
+                               theGlobals->myPB.hPB.fileParam.ioFVersNum = 0;  /* just in case it's used on an MFS volume... */
+                               theGlobals->error = PBHDeleteSync(&(theGlobals->myPB.hPB));     /* delete this item */
+                               if ( theGlobals->error == fLckdErr )
+                               {
+                                       (void) PBHRstFLockSync(&(theGlobals->myPB.hPB));        /* unlock it */
+                                       theGlobals->error = PBHDeleteSync(&(theGlobals->myPB.hPB));     /* and try again */
+                               }
+                       }
+               }
+       } while ( theGlobals->error == noErr );
+       
+       if ( theGlobals->error == fnfErr )
+       {
+               theGlobals->error = noErr;
+       }
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DeleteDirectoryContents(short vRefNum,
+                                                                               long dirID,
+                                                                               ConstStr255Param name)
+{
+       DeleteEnumGlobals theGlobals;
+       Boolean isDirectory;
+       OSErr error;
+
+       /*  Get the real dirID and make sure it is a directory. */
+       error = GetDirectoryID(vRefNum, dirID, name, &dirID, &isDirectory);
+       if ( error == noErr )
+       {
+               if ( isDirectory )
+               {
+                       /* Get the real vRefNum */
+                       error = DetermineVRefNum(name, vRefNum, &vRefNum);
+                       if ( error == noErr )
+                       {
+                               /* Set up the globals we need to access from the recursive routine. */
+                               theGlobals.myPB.ciPB.dirInfo.ioVRefNum = vRefNum;
+                                       
+                               /* Here we go into recursion land... */
+                               DeleteLevel(dirID, &theGlobals);
+                               error = theGlobals.error;
+                       }
+               }
+               else
+               {
+                       error = dirNFErr;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DeleteDirectory(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name)
+{
+       OSErr error;
+       
+       /* Make sure a directory was specified and then delete its contents */
+       error = DeleteDirectoryContents(vRefNum, dirID, name);
+       if ( error == noErr )
+       {
+               error = HDelete(vRefNum, dirID, name);
+               if ( error == fLckdErr )
+               {
+                       (void) HRstFLock(vRefNum, dirID, name); /* unlock the directory locked by AppleShare */
+                       error = HDelete(vRefNum, dirID, name);  /* and try again */
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   CheckObjectLock(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name)
+{
+       CInfoPBRec pb;
+       OSErr error;
+       
+       error = GetCatInfoNoName(vRefNum, dirID, name, &pb);
+       if ( error == noErr )
+       {
+               /* check locked bit */
+               if ( (pb.hFileInfo.ioFlAttrib & 0x01) != 0 )
+               {
+                       error = fLckdErr;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCheckObjectLock(const FSSpec *spec)
+{
+       return ( CheckObjectLock(spec->vRefNum, spec->parID, spec->name) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetFileSize(short vRefNum,
+                                                       long dirID,
+                                                       ConstStr255Param fileName,
+                                                       long *dataSize,
+                                                       long *rsrcSize)
+{
+       HParamBlockRec pb;
+       OSErr error;
+       
+       pb.fileParam.ioNamePtr = (StringPtr)fileName;
+       pb.fileParam.ioVRefNum = vRefNum;
+       pb.fileParam.ioFVersNum = 0;
+       pb.fileParam.ioDirID = dirID;
+       pb.fileParam.ioFDirIndex = 0;
+       error = PBHGetFInfoSync(&pb);
+       if ( error == noErr )
+       {
+               *dataSize = pb.fileParam.ioFlLgLen;
+               *rsrcSize = pb.fileParam.ioFlRLgLen;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetFileSize(const FSSpec *spec,
+                                                          long *dataSize,
+                                                          long *rsrcSize)
+{
+       return ( GetFileSize(spec->vRefNum, spec->parID, spec->name, dataSize, rsrcSize) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   BumpDate(short vRefNum,
+                                                long dirID,
+                                                ConstStr255Param name)
+/* Given a file or directory, change its modification date to the current date/time. */
+{
+       CInfoPBRec pb;
+       Str31 tempName;
+       OSErr error;
+       unsigned long secs;
+
+       /* Protection against File Sharing problem */
+       if ( (name == NULL) || (name[0] == 0) )
+       {
+               tempName[0] = 0;
+               pb.hFileInfo.ioNamePtr = tempName;
+               pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
+       }
+       else
+       {
+               pb.hFileInfo.ioNamePtr = (StringPtr)name;
+               pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
+       }
+       pb.hFileInfo.ioVRefNum = vRefNum;
+       pb.hFileInfo.ioDirID = dirID;
+       error = PBGetCatInfoSync(&pb);
+       if ( error == noErr )
+       {
+               GetDateTime(&secs);
+               /* set mod date to current date, or one second into the future
+                       if mod date = current date */
+               pb.hFileInfo.ioFlMdDat = (secs == pb.hFileInfo.ioFlMdDat) ? (++secs) : (secs);
+               if ( pb.dirInfo.ioNamePtr == tempName )
+               {
+                       pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
+               }
+               else
+               {
+                       pb.hFileInfo.ioDirID = dirID;
+               }
+               error = PBSetCatInfoSync(&pb);
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpBumpDate(const FSSpec *spec)
+{
+       return ( BumpDate(spec->vRefNum, spec->parID, spec->name) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   ChangeCreatorType(short vRefNum,
+                                                                 long dirID,
+                                                                 ConstStr255Param name,
+                                                                 OSType creator,
+                                                                 OSType fileType)
+{
+       CInfoPBRec pb;
+       OSErr error;
+       short realVRefNum;
+       long parID;
+
+       pb.hFileInfo.ioNamePtr = (StringPtr)name;
+       pb.hFileInfo.ioVRefNum = vRefNum;
+       pb.hFileInfo.ioDirID = dirID;
+       pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
+       error = PBGetCatInfoSync(&pb);
+       if ( error == noErr )
+       {
+               if ( (pb.hFileInfo.ioFlAttrib & ioDirMask) == 0 )       /* if file */
+               {
+                       parID = pb.hFileInfo.ioFlParID; /* save parent dirID for BumpDate call */
+
+                       /* If creator not 0x00000000, change creator */
+                       if ( creator != (OSType)0x00000000 )
+                       {
+                               pb.hFileInfo.ioFlFndrInfo.fdCreator = creator;
+                       }
+                       
+                       /* If fileType not 0x00000000, change fileType */
+                       if ( fileType != (OSType)0x00000000 )
+                       {
+                               pb.hFileInfo.ioFlFndrInfo.fdType = fileType;
+                       }
+                               
+                       pb.hFileInfo.ioDirID = dirID;
+                       error = PBSetCatInfoSync(&pb);  /* now, save the new information back to disk */
+
+                       if ( (error == noErr) && (parID != fsRtParID) ) /* can't bump fsRtParID */
+                       {
+                               /* get the real vRefNum in case a full pathname was passed */
+                               error = DetermineVRefNum(name, vRefNum, &realVRefNum);
+                               if ( error == noErr )
+                               {
+                                       error = BumpDate(realVRefNum, parID, NULL);
+                                               /* and bump the parent directory's mod date to wake up the Finder */
+                                               /* to the change we just made */
+                               }
+                       }
+               }
+               else
+               {
+                       /* it was a directory, not a file */
+                       error = notAFileErr;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpChangeCreatorType(const FSSpec *spec,
+                                                                        OSType creator,
+                                                                        OSType fileType)
+{
+       return ( ChangeCreatorType(spec->vRefNum, spec->parID, spec->name, creator, fileType) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   ChangeFDFlags(short vRefNum,
+                                                         long dirID,
+                                                         ConstStr255Param name,
+                                                         Boolean       setBits,
+                                                         unsigned short flagBits)
+{
+       CInfoPBRec pb;
+       Str31 tempName;
+       OSErr error;
+       short realVRefNum;
+       long parID;
+
+       /* Protection against File Sharing problem */
+       if ( (name == NULL) || (name[0] == 0) )
+       {
+               tempName[0] = 0;
+               pb.hFileInfo.ioNamePtr = tempName;
+               pb.hFileInfo.ioFDirIndex = -1;  /* use ioDirID */
+       }
+       else
+       {
+               pb.hFileInfo.ioNamePtr = (StringPtr)name;
+               pb.hFileInfo.ioFDirIndex = 0;   /* use ioNamePtr and ioDirID */
+       }
+       pb.hFileInfo.ioVRefNum = vRefNum;
+       pb.hFileInfo.ioDirID = dirID;
+       error = PBGetCatInfoSync(&pb);
+       if ( error == noErr )
+       {
+               parID = pb.hFileInfo.ioFlParID; /* save parent dirID for BumpDate call */
+               
+               /* set or clear the appropriate bits in the Finder flags */
+               if ( setBits )
+               {
+                       /* OR in the bits */
+                       pb.hFileInfo.ioFlFndrInfo.fdFlags |= flagBits;
+               }
+               else
+               {
+                       /* AND out the bits */
+                       pb.hFileInfo.ioFlFndrInfo.fdFlags &= ~flagBits;
+               }
+                       
+               if ( pb.dirInfo.ioNamePtr == tempName )
+               {
+                       pb.hFileInfo.ioDirID = pb.hFileInfo.ioFlParID;
+               }
+               else
+               {
+                       pb.hFileInfo.ioDirID = dirID;
+               }
+               
+               error = PBSetCatInfoSync(&pb);  /* now, save the new information back to disk */
+
+               if ( (error == noErr) && (parID != fsRtParID) ) /* can't bump fsRtParID */
+               {
+                       /* get the real vRefNum in case a full pathname was passed */
+                       error = DetermineVRefNum(name, vRefNum, &realVRefNum);
+                       if ( error == noErr )
+                       {
+                               error = BumpDate(realVRefNum, parID, NULL);
+                                       /* and bump the parent directory's mod date to wake up the Finder */
+                                       /* to the change we just made */
+                       }
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpChangeFDFlags(const FSSpec *spec,
+                                                                Boolean setBits,
+                                                                unsigned short flagBits)
+{
+       return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, setBits, flagBits) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   SetIsInvisible(short vRefNum,
+                                                          long dirID,
+                                                          ConstStr255Param name)
+       /* Given a file or directory, make it invisible. */
+{
+       return ( ChangeFDFlags(vRefNum, dirID, name, true, kIsInvisible) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetIsInvisible(const FSSpec *spec)
+       /* Given a file or directory, make it invisible. */
+{
+       return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kIsInvisible) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   ClearIsInvisible(short vRefNum,
+                                                                long dirID,
+                                                                ConstStr255Param name)
+       /* Given a file or directory, make it visible. */
+{
+       return ( ChangeFDFlags(vRefNum, dirID, name, false, kIsInvisible) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpClearIsInvisible(const FSSpec *spec)
+       /* Given a file or directory, make it visible. */
+{
+       return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kIsInvisible) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   SetNameLocked(short vRefNum,
+                                                         long dirID,
+                                                         ConstStr255Param name)
+       /* Given a file or directory, lock its name. */
+{
+       return ( ChangeFDFlags(vRefNum, dirID, name, true, kNameLocked) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetNameLocked(const FSSpec *spec)
+       /* Given a file or directory, lock its name. */
+{
+       return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kNameLocked) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   ClearNameLocked(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name)
+       /* Given a file or directory, unlock its name. */
+{
+       return ( ChangeFDFlags(vRefNum, dirID, name, false, kNameLocked) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpClearNameLocked(const FSSpec *spec)
+       /* Given a file or directory, unlock its name. */
+{
+       return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kNameLocked) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   SetIsStationery(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name)
+       /* Given a file, make it a stationery pad. */
+{
+       return ( ChangeFDFlags(vRefNum, dirID, name, true, kIsStationery) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetIsStationery(const FSSpec *spec)
+       /* Given a file, make it a stationery pad. */
+{
+       return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kIsStationery) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   ClearIsStationery(short vRefNum,
+                                                                 long dirID,
+                                                                 ConstStr255Param name)
+       /* Given a file, clear the stationery bit. */
+{
+       return ( ChangeFDFlags(vRefNum, dirID, name, false, kIsStationery) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpClearIsStationery(const FSSpec *spec)
+       /* Given a file, clear the stationery bit. */
+{
+       return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kIsStationery) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   SetHasCustomIcon(short vRefNum,
+                                                                long dirID,
+                                                                ConstStr255Param name)
+       /* Given a file or directory, indicate that it has a custom icon. */
+{
+       return ( ChangeFDFlags(vRefNum, dirID, name, true, kHasCustomIcon) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetHasCustomIcon(const FSSpec *spec)
+       /* Given a file or directory, indicate that it has a custom icon. */
+{
+       return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, true, kHasCustomIcon) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   ClearHasCustomIcon(short vRefNum,
+                                                                  long dirID,
+                                                                  ConstStr255Param name)
+       /* Given a file or directory, indicate that it does not have a custom icon. */
+{
+       return ( ChangeFDFlags(vRefNum, dirID, name, false, kHasCustomIcon) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpClearHasCustomIcon(const FSSpec *spec)
+       /* Given a file or directory, indicate that it does not have a custom icon. */
+{
+       return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kHasCustomIcon) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   ClearHasBeenInited(short vRefNum,
+                                                                  long dirID,
+                                                                  ConstStr255Param name)
+       /* Given a file, clear its "has been inited" bit. */
+{
+       return ( ChangeFDFlags(vRefNum, dirID, name, false, kHasBeenInited) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpClearHasBeenInited(const FSSpec *spec)
+       /* Given a file, clear its "has been inited" bit. */
+{
+       return ( ChangeFDFlags(spec->vRefNum, spec->parID, spec->name, false, kHasBeenInited) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   CopyFileMgrAttributes(short srcVRefNum,
+                                                                         long srcDirID,
+                                                                         ConstStr255Param srcName,
+                                                                         short dstVRefNum,
+                                                                         long dstDirID,
+                                                                         ConstStr255Param dstName,
+                                                                         Boolean copyLockBit)
+{
+       UniversalFMPB pb;
+       Str31 tempName;
+       OSErr error;
+       Boolean objectIsDirectory;
+
+       pb.ciPB.hFileInfo.ioVRefNum = srcVRefNum;
+       pb.ciPB.hFileInfo.ioDirID = srcDirID;
+
+       /* Protection against File Sharing problem */
+       if ( (srcName == NULL) || (srcName[0] == 0) )
+       {
+               tempName[0] = 0;
+               pb.ciPB.hFileInfo.ioNamePtr = tempName;
+               pb.ciPB.hFileInfo.ioFDirIndex = -1;     /* use ioDirID */
+       }
+       else
+       {
+               pb.ciPB.hFileInfo.ioNamePtr = (StringPtr)srcName;
+               pb.ciPB.hFileInfo.ioFDirIndex = 0;      /* use ioNamePtr and ioDirID */
+       }
+       error = PBGetCatInfoSync(&pb.ciPB);
+       if ( error == noErr )
+       {
+               objectIsDirectory = ( (pb.ciPB.hFileInfo.ioFlAttrib & ioDirMask) != 0 );
+               pb.ciPB.hFileInfo.ioVRefNum = dstVRefNum;
+               pb.ciPB.hFileInfo.ioDirID = dstDirID;
+               if ( (dstName != NULL) && (dstName[0] == 0) )
+               {
+                       pb.ciPB.hFileInfo.ioNamePtr = NULL;
+               }
+               else
+               {
+                       pb.ciPB.hFileInfo.ioNamePtr = (StringPtr)dstName;
+               }
+               /* don't copy the hasBeenInited bit */
+               pb.ciPB.hFileInfo.ioFlFndrInfo.fdFlags = ( pb.ciPB.hFileInfo.ioFlFndrInfo.fdFlags & 0xfeff );
+               error = PBSetCatInfoSync(&pb.ciPB);
+               if ( (error == noErr) && (copyLockBit) && ((pb.ciPB.hFileInfo.ioFlAttrib & 0x01) != 0) )
+               {
+                       pb.hPB.fileParam.ioFVersNum = 0;
+                       error = PBHSetFLockSync(&pb.hPB);
+                       if ( (error != noErr) && (objectIsDirectory) )
+                       {
+                               error = noErr; /* ignore lock errors if destination is directory */
+                       }
+               }
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCopyFileMgrAttributes(const FSSpec *srcSpec,
+                                                                                const FSSpec *dstSpec,
+                                                                                Boolean copyLockBit)
+{
+       return ( CopyFileMgrAttributes(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
+                                                                  dstSpec->vRefNum, dstSpec->parID, dstSpec->name,
+                                                                  copyLockBit) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HOpenAware(short vRefNum,
+                                                  long dirID,
+                                                  ConstStr255Param fileName,
+                                                  short denyModes,
+                                                  short *refNum)
+{
+       HParamBlockRec pb;
+       OSErr error;
+       GetVolParmsInfoBuffer volParmsInfo;
+       long infoSize = sizeof(GetVolParmsInfoBuffer);
+
+       pb.ioParam.ioMisc = NULL;
+       pb.fileParam.ioFVersNum = 0;
+       pb.fileParam.ioNamePtr = (StringPtr)fileName;
+       pb.fileParam.ioVRefNum = vRefNum;
+       pb.fileParam.ioDirID = dirID;
+
+       /* get volume attributes */
+       /* this preflighting is needed because Foreign File Access based file systems don't */
+       /* return the correct error result to the OpenDeny call */
+       error = HGetVolParms(fileName, vRefNum, &volParmsInfo, &infoSize);
+       if ( (error == noErr) && hasOpenDeny(volParmsInfo) )
+       {
+               /* if volume supports OpenDeny, use it and return */
+                       pb.accessParam.ioDenyModes = denyModes;
+                       error = PBHOpenDenySync(&pb);
+                       *refNum = pb.ioParam.ioRefNum;
+       }
+       else if ( (error == noErr) || (error == paramErr) )     /* paramErr is OK, it just means this volume doesn't support GetVolParms */
+       {
+               /* OpenDeny isn't supported, so try File Manager Open functions */
+               
+               /* If request includes write permission, then see if the volume is */
+               /* locked by hardware or software. The HFS file system doesn't check */
+               /* for this when a file is opened - you only find out later when you */
+               /* try to write and the write fails with a wPrErr or a vLckdErr. */
+               
+               if ( (denyModes & dmWr) != 0 )
+               {
+                       error = CheckVolLock(fileName, vRefNum);
+               }
+               else
+               {
+                       error = noErr;
+               }
+               
+               if ( error == noErr )
+               {
+                       /* Set File Manager permissions to closest thing possible */
+                       if ( (denyModes == dmWr) || (denyModes == dmRdWr) )
+                       {
+                               pb.ioParam.ioPermssn = fsRdWrShPerm;
+                       }
+                       else
+                       {
+                               pb.ioParam.ioPermssn = denyModes % 4;
+                       }
+
+                       error = PBHOpenDFSync(&pb);                             /* Try OpenDF */
+                       if ( error == paramErr )
+                       {
+                               error = PBHOpenSync(&pb);                       /* OpenDF not supported, so try Open */
+                       }
+                       *refNum = pb.ioParam.ioRefNum;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpOpenAware(const FSSpec *spec,
+                                                        short denyModes,
+                                                        short *refNum)
+{
+       return ( HOpenAware(spec->vRefNum, spec->parID, spec->name, denyModes, refNum) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HOpenRFAware(short vRefNum,
+                                                        long dirID,
+                                                        ConstStr255Param fileName,
+                                                        short denyModes,
+                                                        short *refNum)
+{
+       HParamBlockRec pb;
+       OSErr error;
+       GetVolParmsInfoBuffer volParmsInfo;
+       long infoSize = sizeof(GetVolParmsInfoBuffer);
+
+       pb.ioParam.ioMisc = NULL;
+       pb.fileParam.ioFVersNum = 0;
+       pb.fileParam.ioNamePtr = (StringPtr)fileName;
+       pb.fileParam.ioVRefNum = vRefNum;
+       pb.fileParam.ioDirID = dirID;
+
+       /* get volume attributes */
+       /* this preflighting is needed because Foreign File Access based file systems don't */
+       /* return the correct error result to the OpenRFDeny call */
+       error = HGetVolParms(fileName, vRefNum, &volParmsInfo, &infoSize);
+       if ( (error == noErr) && hasOpenDeny(volParmsInfo) )
+       {
+               /* if volume supports OpenRFDeny, use it and return */
+               if ( hasOpenDeny(volParmsInfo) )
+               {
+                       pb.accessParam.ioDenyModes = denyModes;
+                       error = PBHOpenRFDenySync(&pb);
+                       *refNum = pb.ioParam.ioRefNum;
+               }
+       }
+       else if ( (error == noErr) || (error == paramErr) )     /* paramErr is OK, it just means this volume doesn't support GetVolParms */
+       {
+               /* OpenRFDeny isn't supported, so try File Manager OpenRF function */
+               
+               /* If request includes write permission, then see if the volume is */
+               /* locked by hardware or software. The HFS file system doesn't check */
+               /* for this when a file is opened - you only find out later when you */
+               /* try to write and the write fails with a wPrErr or a vLckdErr. */
+               
+               if ( (denyModes & dmWr) != 0 )
+               {
+                       error = CheckVolLock(fileName, vRefNum);
+               }
+               else
+               {
+                       error = noErr;
+               }
+               
+               if ( error == noErr )
+               {
+                       /* Set File Manager permissions to closest thing possible */
+                       if ( (denyModes == dmWr) || (denyModes == dmRdWr) )
+                       {
+                               pb.ioParam.ioPermssn = fsRdWrShPerm;
+                       }
+                       else
+                       {
+                               pb.ioParam.ioPermssn = denyModes % 4;
+                       }
+
+                       error = PBHOpenRFSync(&pb);
+                       *refNum = pb.ioParam.ioRefNum;
+               }
+       }
+
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpOpenRFAware(const FSSpec *spec,
+                                                          short denyModes,
+                                                          short *refNum)
+{
+       return ( HOpenRFAware(spec->vRefNum, spec->parID, spec->name, denyModes, refNum) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSReadNoCache(short refNum,
+                                                         long *count,
+                                                         void *buffPtr)
+{
+       ParamBlockRec pb;
+       OSErr error;
+
+       pb.ioParam.ioRefNum = refNum;
+       pb.ioParam.ioBuffer = (Ptr)buffPtr;
+       pb.ioParam.ioReqCount = *count;
+       pb.ioParam.ioPosMode = fsAtMark + 0x0020;       /* fsAtMark + noCacheBit */
+       pb.ioParam.ioPosOffset = 0;
+       error = PBReadSync(&pb);
+       *count = pb.ioParam.ioActCount;                         /* always return count */
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSWriteNoCache(short refNum,
+                                                          long *count,
+                                                          const void *buffPtr)
+{
+       ParamBlockRec pb;
+       OSErr error;
+
+       pb.ioParam.ioRefNum = refNum;
+       pb.ioParam.ioBuffer = (Ptr)buffPtr;
+       pb.ioParam.ioReqCount = *count;
+       pb.ioParam.ioPosMode = fsAtMark + 0x0020;       /* fsAtMark + noCacheBit */
+       pb.ioParam.ioPosOffset = 0;
+       error = PBWriteSync(&pb);
+       *count = pb.ioParam.ioActCount;                         /* always return count */
+       return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**     See if numBytes bytes of buffer1 are equal to buffer2.
+*/
+static Boolean EqualMemory(const void *buffer1, const void *buffer2, unsigned long numBytes)
+{
+       register unsigned char *b1 = (unsigned char *)buffer1;
+       register unsigned char *b2 = (unsigned char *)buffer2;
+
+       if ( b1 != b2 ) /* if buffer pointers are same, then they are equal */
+       {
+               while ( numBytes > 0 )
+               {
+                       /* compare the bytes and then increment the pointers */
+                       if ( (*b1++ - *b2++) != 0 )
+                       {
+                               return ( false );
+                       }
+                       --numBytes;
+               }
+       }
+       
+       return ( true );
+}
+
+/*****************************************************************************/
+
+/*
+**     Read any number of bytes from an open file using read-verify mode.
+**     The FSReadVerify function reads any number of bytes from an open file
+**     and verifies them against the data in the buffer pointed to by buffPtr.
+**     
+**     Because of a bug in the HFS file system, only non-block aligned parts of
+**     the read are verified against the buffer data and the rest is *copied*
+**     into the buffer.  Thus, you shouldn't verify against your original data;
+**     instead, you should verify against a copy of the original data and then
+**     compare the read-verified copy against the original data after calling
+**     FSReadVerify. That's why this function isn't exported - it needs the
+**     wrapper provided by FSWriteVerify.
+*/
+static OSErr   FSReadVerify(short refNum,
+                                                        long *count,
+                                                        void *buffPtr)
+{
+       ParamBlockRec   pb;
+       OSErr                   result;
+
+       pb.ioParam.ioRefNum = refNum;
+       pb.ioParam.ioBuffer = (Ptr)buffPtr;
+       pb.ioParam.ioReqCount = *count;
+       pb.ioParam.ioPosMode = fsAtMark + rdVerify;
+       pb.ioParam.ioPosOffset = 0;
+       result = PBReadSync(&pb);
+       *count = pb.ioParam.ioActCount;                 /* always return count */
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSWriteVerify(short refNum,
+                                                         long *count,
+                                                         const void *buffPtr)
+{
+       Ptr             verifyBuffer;
+       long    position;
+       long    bufferSize;
+       long    byteCount;
+       long    bytesVerified;
+       Ptr             startVerify;
+       OSErr   result;
+       
+       /*
+       **      Allocate the verify buffer
+       **      Try to get get a large enough buffer to verify in one pass.
+       **      If that fails, use GetTempBuffer to get a buffer.
+       */
+       bufferSize = *count;
+       verifyBuffer = NewPtr(bufferSize);
+       if ( verifyBuffer == NULL )
+       {
+               verifyBuffer = GetTempBuffer(bufferSize, &bufferSize);
+       }
+       if ( verifyBuffer != NULL )
+       {               
+               /* Save the current position */
+               result = GetFPos(refNum, &position);
+               if ( result == noErr )
+               {
+                       /* Write the data */
+                       result = FSWrite(refNum, count, buffPtr);
+                       if ( result == noErr )
+                       {
+                               /* Restore the original position */
+                               result = SetFPos(refNum, fsFromStart, position);
+                               if ( result == noErr )
+                               {
+                                       /*
+                                       **      *count                  = total number of bytes to verify
+                                       **      bufferSize              = the size of the verify buffer
+                                       **      bytesVerified   = number of bytes verified
+                                       **      byteCount               = number of bytes to verify this pass
+                                       **      startVerify             = position in buffPtr
+                                       */
+                                       bytesVerified = 0;
+                                       startVerify = (Ptr)buffPtr;
+                                       while ( (bytesVerified < *count) && ( result == noErr ) )
+                                       {
+                                               if ( (*count - bytesVerified) > bufferSize )
+                                               {
+                                                       byteCount = bufferSize;
+                                               }
+                                               else
+                                               {
+                                                       byteCount = *count - bytesVerified;
+                                               }
+                                               /*
+                                               **      Copy the write buffer into the verify buffer.
+                                               **      This step is needed because the File Manager
+                                               **      compares the data in any non-block aligned
+                                               **      data at the beginning and end of the read-verify
+                                               **      request back into the file system's cache
+                                               **      to the data in verify Buffer. However, the
+                                               **      File Manager does not compare any full blocks
+                                               **      and instead copies them into the verify buffer
+                                               **      so we still have to compare the buffers again
+                                               **      after the read-verify request completes.
+                                               */
+                                               BlockMoveData(startVerify, verifyBuffer, byteCount);
+                                               
+                                               /* Read-verify the data back into the verify buffer */
+                                               result = FSReadVerify(refNum, &byteCount, verifyBuffer);
+                                               if ( result == noErr )
+                                               {
+                                                       /* See if the buffers are the same */
+                                                       if ( !EqualMemory(verifyBuffer, startVerify, byteCount) )
+                                                       {
+                                                               result = ioErr;
+                                                       }
+                                                       startVerify += byteCount;
+                                                       bytesVerified += byteCount;
+                                               }
+                                       }
+                               }
+                       }
+               }
+               DisposePtr(verifyBuffer);
+       }
+       else
+       {
+               result = memFullErr;
+       }
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   CopyFork(short srcRefNum,
+                                                short dstRefNum,
+                                                void *copyBufferPtr,
+                                                long copyBufferSize)
+{
+       ParamBlockRec srcPB;
+       ParamBlockRec dstPB;
+       OSErr srcError;
+       OSErr dstError;
+
+       if ( (copyBufferPtr == NULL) || (copyBufferSize == 0) )
+               return ( paramErr );
+       
+       srcPB.ioParam.ioRefNum = srcRefNum;
+       dstPB.ioParam.ioRefNum = dstRefNum;
+
+       /* preallocate the destination fork and */
+       /* ensure the destination fork's EOF is correct after the copy */
+       srcError = PBGetEOFSync(&srcPB);
+       if ( srcError != noErr )
+               return ( srcError );
+       dstPB.ioParam.ioMisc = srcPB.ioParam.ioMisc;
+       dstError = PBSetEOFSync(&dstPB);
+       if ( dstError != noErr )
+               return ( dstError );
+
+       /* reset source fork's mark */
+       srcPB.ioParam.ioPosMode = fsFromStart;
+       srcPB.ioParam.ioPosOffset = 0;
+       srcError = PBSetFPosSync(&srcPB);
+       if ( srcError != noErr )
+               return ( srcError );
+
+       /* reset destination fork's mark */
+       dstPB.ioParam.ioPosMode = fsFromStart;
+       dstPB.ioParam.ioPosOffset = 0;
+       dstError = PBSetFPosSync(&dstPB);
+       if ( dstError != noErr )
+               return ( dstError );
+
+       /* set up fields that won't change in the loop */
+       srcPB.ioParam.ioBuffer = (Ptr)copyBufferPtr;
+       srcPB.ioParam.ioPosMode = fsAtMark + 0x0020;/* fsAtMark + noCacheBit */
+       /* If copyBufferSize is greater than 512 bytes, make it a multiple of 512 bytes */
+       /* This will make writes on local volumes faster */
+       if ( (copyBufferSize >= 512) && ((copyBufferSize & 0x1ff) != 0) )
+       {
+               srcPB.ioParam.ioReqCount = copyBufferSize & 0xfffffe00;
+       }
+       else
+       {
+               srcPB.ioParam.ioReqCount = copyBufferSize;
+       }
+       dstPB.ioParam.ioBuffer = (Ptr)copyBufferPtr;
+       dstPB.ioParam.ioPosMode = fsAtMark + 0x0020;/* fsAtMark + noCacheBit */
+
+       while ( (srcError == noErr) && (dstError == noErr) )
+       {
+               srcError = PBReadSync(&srcPB);
+               dstPB.ioParam.ioReqCount = srcPB.ioParam.ioActCount;
+               dstError = PBWriteSync(&dstPB);
+       }
+
+       /* make sure there were no errors at the destination */
+       if ( dstError != noErr )
+               return ( dstError );
+
+       /* make sure the only error at the source was eofErr */
+       if ( srcError != eofErr )
+               return ( srcError );
+
+       return ( noErr );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetFileLocation(short refNum,
+                                                               short *vRefNum,
+                                                               long *dirID,
+                                                               StringPtr fileName)
+{
+       FCBPBRec pb;
+       OSErr error;
+
+       pb.ioNamePtr = fileName;
+       pb.ioVRefNum = 0;
+       pb.ioRefNum = refNum;
+       pb.ioFCBIndx = 0;
+       error = PBGetFCBInfoSync(&pb);
+       if ( error == noErr )
+       {
+               *vRefNum = pb.ioFCBVRefNum;
+               *dirID = pb.ioFCBParID;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetFileLocation(short refNum,
+                                                                  FSSpec *spec)
+{
+       return ( GetFileLocation(refNum, &(spec->vRefNum), &(spec->parID), spec->name) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   CopyDirectoryAccess(short srcVRefNum,
+                                                                       long srcDirID,
+                                                                       ConstStr255Param srcName,
+                                                                       short dstVRefNum,
+                                                                       long dstDirID,
+                                                                       ConstStr255Param dstName)
+{      
+       OSErr error;
+       GetVolParmsInfoBuffer infoBuffer;       /* Where PBGetVolParms dumps its info */
+       long    dstServerAdr;                           /* AppleTalk server address of destination (if any) */
+       long    ownerID, groupID, accessRights;
+       long    tempLong;
+
+       /* See if destination supports directory access control */
+       tempLong = sizeof(infoBuffer);
+       error = HGetVolParms(dstName, dstVRefNum, &infoBuffer, &tempLong);
+       if ( (error == noErr) && hasAccessCntl(infoBuffer) )
+       {
+               if ( hasAccessCntl(infoBuffer) )
+               {
+                       dstServerAdr = infoBuffer.vMServerAdr;
+                       
+                       /* See if source supports directory access control and is on same server */
+                       tempLong = sizeof(infoBuffer);
+                       error = HGetVolParms(srcName, srcVRefNum, &infoBuffer, &tempLong);
+                       if ( error == noErr )
+                       {
+                               if ( hasAccessCntl(infoBuffer) && (dstServerAdr == infoBuffer.vMServerAdr) )
+                               {
+                                       /* both volumes support directory access control and they are */
+                                       /*  on same server, so copy the access information */
+                                       error = HGetDirAccess(srcVRefNum, srcDirID, srcName, &ownerID, &groupID, &accessRights);
+                                       if ( error == noErr )
+                                       {
+                                               error = HSetDirAccess(dstVRefNum, dstDirID, dstName, ownerID, groupID, accessRights);
+                                       }
+                               }
+                               else
+                               {
+                                       /* destination doesn't support directory access control or */
+                                       /* they volumes aren't on the same server */
+                                       error = paramErr;
+                               }
+                       }
+               }
+               else
+               {
+                       /* destination doesn't support directory access control */
+                       error = paramErr;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCopyDirectoryAccess(const FSSpec *srcSpec,
+                                                                          const FSSpec *dstSpec)
+{
+       return ( CopyDirectoryAccess(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
+                                                               dstSpec->vRefNum, dstSpec->parID, dstSpec->name) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HMoveRenameCompat(short vRefNum,
+                                                                 long srcDirID,
+                                                                 ConstStr255Param srcName,
+                                                                 long dstDirID,
+                                                                 ConstStr255Param dstpathName,
+                                                                 ConstStr255Param copyName)
+{
+       OSErr                                   error;
+       GetVolParmsInfoBuffer   volParmsInfo;
+       long                                    infoSize;
+       short                                   realVRefNum;
+       long                                    realParID;
+       Str31                                   realName;
+       Boolean                                 isDirectory;
+       long                                    tempItemsDirID;
+       long                                    uniqueTempDirID;
+       Str31                                   uniqueTempDirName;
+       unsigned short                  uniqueNameoverflow;
+       
+       /* Get volume attributes */
+       infoSize = sizeof(GetVolParmsInfoBuffer);
+       error = HGetVolParms((StringPtr)srcName, vRefNum, &volParmsInfo, &infoSize);
+       if ( (error == noErr) && hasMoveRename(volParmsInfo) )
+       {
+               /* If volume supports move and rename, so use it and return */
+               error = HMoveRename(vRefNum, srcDirID, srcName, dstDirID, dstpathName, copyName);
+       }
+       else if ( (error == noErr) || (error == paramErr) ) /* paramErr is OK, it just means this volume doesn't support GetVolParms */
+       {
+               /* MoveRename isn't supported by this volume, so do it by hand */
+               
+               /* If copyName isn't supplied, we can simply CatMove and return */
+               if ( copyName == NULL )
+               {
+                       error = CatMove(vRefNum, srcDirID, srcName, dstDirID, dstpathName);
+               }
+               else
+               {
+                       /* Renaming is required, so we have some work to do... */
+                       
+                       /* Get the object's real name, real parent ID and real vRefNum */
+                       error = GetObjectLocation(vRefNum, srcDirID, (StringPtr)srcName,
+                                                                               &realVRefNum, &realParID, realName, &isDirectory);
+                       if ( error == noErr )
+                       {
+                               /* Find the Temporary Items Folder on that volume */
+                               error = FindFolder(realVRefNum, kTemporaryFolderType, kCreateFolder,
+                                                                       &realVRefNum, &tempItemsDirID);
+                               if ( error == noErr )
+                               {
+                                       /* Create a new uniquely named folder in the temporary items folder. */
+                                       /* This is done to avoid the case where 'realName' or 'copyName' already */
+                                       /* exists in the temporary items folder. */
+                                       
+                                       /* Start with current tick count as uniqueTempDirName */                                        
+                                       NumToString(TickCount(), uniqueTempDirName);
+                                       uniqueNameoverflow = 0;
+                                       do
+                                       {
+                                               error = DirCreate(realVRefNum, tempItemsDirID, uniqueTempDirName, &uniqueTempDirID);
+                                               if ( error == dupFNErr )
+                                               {
+                                                       /* Duplicate name - change the first character to the next ASCII character */
+                                                       ++uniqueTempDirName[1];
+                                                       /* Make sure it isn't a colon! */
+                                                       if ( uniqueTempDirName[1] == ':' )
+                                                       {
+                                                               ++uniqueTempDirName[1];
+                                                       }
+                                                       /* Don't go too far... */
+                                                       ++uniqueNameoverflow;
+                                               }
+                                       } while ( (error == dupFNErr) && (uniqueNameoverflow <= 64) ); /* 64 new files per 1/60th second - not likely! */
+                                       if ( error == noErr )
+                                       {
+                                               /* Move the object to the folder with uniqueTempDirID for renaming */
+                                               error = CatMove(realVRefNum, realParID, realName, uniqueTempDirID, NULL);
+                                               if ( error == noErr )
+                                               {
+                                                       /* Rename the object */ 
+                                                       error = HRename(realVRefNum, uniqueTempDirID, realName, copyName);
+                                                       if ( error == noErr )
+                                                       {
+                                                               /* Move object to its new home */
+                                                               error = CatMove(realVRefNum, uniqueTempDirID, copyName, dstDirID, dstpathName);
+                                                               if ( error != noErr )
+                                                               {
+                                                                       /* Error handling: rename object back to original name - ignore errors */
+                                                                       (void) HRename(realVRefNum, uniqueTempDirID, copyName, realName);
+                                                               }
+                                                       }
+                                                       if ( error != noErr )
+                                                       {
+                                                               /* Error handling: move object back to original location - ignore errors */
+                                                               (void) CatMove(realVRefNum, uniqueTempDirID, realName, realParID, NULL);
+                                                       }
+                                               }
+                                               /* Done with ourTempDir, so delete it - ignore errors */
+                                               (void) HDelete(realVRefNum, uniqueTempDirID, NULL);
+                                       }
+                               }
+                       }
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpMoveRenameCompat(const FSSpec *srcSpec,
+                                                                       const FSSpec *dstSpec,
+                                                                       ConstStr255Param copyName)
+{
+       /* make sure the FSSpecs refer to the same volume */
+       if (srcSpec->vRefNum != dstSpec->vRefNum)
+               return (diffVolErr);
+       return ( HMoveRenameCompat(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
+                                         dstSpec->parID, dstSpec->name, copyName) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   BuildAFPVolMountInfo(short flags,
+                                                                        char nbpInterval,
+                                                                        char nbpCount,
+                                                                        short uamType,
+                                                                        Str32 zoneName,
+                                                                        Str32 serverName,
+                                                                        Str27 volName,
+                                                                        Str31 userName,
+                                                                        Str8 userPassword,
+                                                                        Str8 volPassword,
+                                                                        AFPVolMountInfoPtr *afpInfoPtr)
+{
+       MyAFPVolMountInfoPtr    infoPtr;
+       OSErr                                   error;
+       
+       /* Allocate the AFPXVolMountInfo record */
+       infoPtr = (MyAFPVolMountInfoPtr)NewPtrClear(sizeof(MyAFPVolMountInfo));
+       if ( infoPtr != NULL )
+       {
+               /* Fill in an AFPVolMountInfo record that can be passed to VolumeMount */
+               infoPtr->length = sizeof(MyAFPVolMountInfo);
+               infoPtr->media = AppleShareMediaType;
+               infoPtr->flags = flags;
+               infoPtr->nbpInterval = nbpInterval;
+               infoPtr->nbpCount = nbpCount;
+               infoPtr->uamType = uamType;
+               
+               infoPtr->zoneNameOffset = offsetof(MyAFPVolMountInfo, zoneName);
+               infoPtr->serverNameOffset = offsetof(MyAFPVolMountInfo, serverName);
+               infoPtr->volNameOffset = offsetof(MyAFPVolMountInfo, volName);
+               infoPtr->userNameOffset = offsetof(MyAFPVolMountInfo, userName);
+               infoPtr->userPasswordOffset = offsetof(MyAFPVolMountInfo, userPassword);
+               infoPtr->volPasswordOffset = offsetof(MyAFPVolMountInfo, volPassword);
+               
+               BlockMoveData(zoneName, infoPtr->zoneName, sizeof(Str32));
+               BlockMoveData(serverName, infoPtr->serverName, sizeof(Str32));
+               BlockMoveData(volName, infoPtr->volName, sizeof(Str27));
+               BlockMoveData(userName, infoPtr->userName, sizeof(Str31));
+               BlockMoveData(userPassword, infoPtr->userPassword, sizeof(Str8));
+               BlockMoveData(volPassword, infoPtr->volPassword, sizeof(Str8));
+               
+               *afpInfoPtr = (AFPVolMountInfoPtr)infoPtr;
+               error = noErr;
+       }
+       else
+       {
+               error = memFullErr;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr,
+                                                                               short *flags,
+                                                                               short *uamType,
+                                                                               StringPtr zoneName,
+                                                                               StringPtr serverName,
+                                                                               StringPtr volName,
+                                                                               StringPtr userName)
+{
+       StringPtr       tempPtr;
+       OSErr           error;
+               
+       /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
+       if ( afpInfoPtr->media == AppleShareMediaType )
+       {
+               *flags = afpInfoPtr->flags;
+               *uamType = afpInfoPtr->uamType;
+               
+               if ( afpInfoPtr->zoneNameOffset != 0)
+               {
+                       tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->zoneNameOffset);
+                       BlockMoveData(tempPtr, zoneName, tempPtr[0] + 1);
+               }
+               
+               if ( afpInfoPtr->serverNameOffset != 0)
+               {
+                       tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->serverNameOffset);
+                       BlockMoveData(tempPtr, serverName, tempPtr[0] + 1);
+               }
+               
+               if ( afpInfoPtr->volNameOffset != 0)
+               {
+                       tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->volNameOffset);
+                       BlockMoveData(tempPtr, volName, tempPtr[0] + 1);
+               }
+               
+               if ( afpInfoPtr->userNameOffset != 0)
+               {
+                       tempPtr = (StringPtr)((long)afpInfoPtr + afpInfoPtr->userNameOffset);
+                       BlockMoveData(tempPtr, userName, tempPtr[0] + 1);
+               }
+               
+               error = noErr;
+       }
+       else
+       {
+               error = paramErr;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   BuildAFPXVolMountInfo(short flags,
+                                                                         char nbpInterval,
+                                                                         char nbpCount,
+                                                                         short uamType,
+                                                                         Str32 zoneName,
+                                                                         Str32 serverName,
+                                                                         Str27 volName,
+                                                                         Str31 userName,
+                                                                         Str8 userPassword,
+                                                                         Str8 volPassword,
+                                                                         Str32 uamName,
+                                                                         unsigned long alternateAddressLength,
+                                                                         void *alternateAddress,
+                                                                         AFPXVolMountInfoPtr *afpXInfoPtr)
+{
+       Size                                    infoSize;
+       MyAFPXVolMountInfoPtr   infoPtr;
+       OSErr                                   error;
+       
+       /* Calculate the size of the AFPXVolMountInfo record */
+       infoSize = sizeof(MyAFPXVolMountInfo) + alternateAddressLength - 1;
+       
+       /* Allocate the AFPXVolMountInfo record */
+       infoPtr = (MyAFPXVolMountInfoPtr)NewPtrClear(infoSize);
+       if ( infoPtr != NULL )
+       {
+               /* Fill in an AFPXVolMountInfo record that can be passed to VolumeMount */
+               infoPtr->length = infoSize;
+               infoPtr->media = AppleShareMediaType;
+               infoPtr->flags = flags;
+               if ( alternateAddressLength != 0 )
+               {
+                       /* make sure the volMountExtendedFlagsBit is set if there's extended address info */
+                       infoPtr->flags |= volMountExtendedFlagsMask;
+                       /* and set the only extendedFlags bit we know about */
+                       infoPtr->extendedFlags = kAFPExtendedFlagsAlternateAddressMask;
+               }
+               else
+               {
+                       /* make sure the volMountExtendedFlagsBit is clear if there's no extended address info */
+                       infoPtr->flags &= ~volMountExtendedFlagsMask;
+                       /* and clear the extendedFlags */
+                       infoPtr->extendedFlags = 0;
+               }
+               infoPtr->nbpInterval = nbpInterval;
+               infoPtr->nbpCount = nbpCount;
+               infoPtr->uamType = uamType;
+               
+               infoPtr->zoneNameOffset = offsetof(MyAFPXVolMountInfo, zoneName);               
+               infoPtr->serverNameOffset = offsetof(MyAFPXVolMountInfo, serverName);
+               infoPtr->volNameOffset = offsetof(MyAFPXVolMountInfo, volName);
+               infoPtr->userNameOffset = offsetof(MyAFPXVolMountInfo, userName);
+               infoPtr->userPasswordOffset = offsetof(MyAFPXVolMountInfo, userPassword);
+               infoPtr->volPasswordOffset = offsetof(MyAFPXVolMountInfo, volPassword);
+               infoPtr->uamNameOffset = offsetof(MyAFPXVolMountInfo, uamName);
+               infoPtr->alternateAddressOffset = offsetof(MyAFPXVolMountInfo, alternateAddress);
+               
+               BlockMoveData(zoneName, infoPtr->zoneName, sizeof(Str32));
+               BlockMoveData(serverName, infoPtr->serverName, sizeof(Str32));
+               BlockMoveData(volName, infoPtr->volName, sizeof(Str27));
+               BlockMoveData(userName, infoPtr->userName, sizeof(Str31));
+               BlockMoveData(userPassword, infoPtr->userPassword, sizeof(Str8));
+               BlockMoveData(volPassword, infoPtr->volPassword, sizeof(Str8));
+               BlockMoveData(uamName, infoPtr->uamName, sizeof(Str32));
+               BlockMoveData(alternateAddress, infoPtr->alternateAddress, alternateAddressLength);
+               
+               *afpXInfoPtr = (AFPXVolMountInfoPtr)infoPtr;
+               error = noErr;
+       }
+       else
+       {
+               error = memFullErr;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr,
+                                                                                short *flags,
+                                                                                short *uamType,
+                                                                                StringPtr zoneName,
+                                                                                StringPtr serverName,
+                                                                                StringPtr volName,
+                                                                                StringPtr userName,
+                                                                                StringPtr uamName,
+                                                                                unsigned long *alternateAddressLength,
+                                                                                AFPAlternateAddress **alternateAddress)
+{
+       StringPtr       tempPtr;
+       Ptr                     alternateAddressStart;
+       Ptr                     alternateAddressEnd;
+       Size            alternateAddressDataSize;
+       OSErr           error;
+       UInt8           addressCount;
+               
+       /* Retrieve the AFP mounting information from an AFPVolMountInfo record. */
+       if ( afpXInfoPtr->media == AppleShareMediaType )
+       {
+               /* default to noErr */
+               error = noErr;
+               
+               /* Is this an extended record? */
+               if ( (afpXInfoPtr->flags & volMountExtendedFlagsMask) != 0 )
+               {
+                       if ( ((afpXInfoPtr->extendedFlags & kAFPExtendedFlagsAlternateAddressMask) != 0) &&
+                                (afpXInfoPtr->alternateAddressOffset != 0) )
+                       {
+                               
+                               alternateAddressStart = (Ptr)((long)afpXInfoPtr + afpXInfoPtr->alternateAddressOffset);
+                               alternateAddressEnd = alternateAddressStart + 1;        /* skip over alternate address version byte */
+                               addressCount = *(UInt8*)alternateAddressEnd;            /* get the address count */
+                               ++alternateAddressEnd;                                                          /* skip over alternate address count byte */
+                               /* alternateAddressEnd now equals &AFPAlternateAddress.fAddressList[0] */
+                               while ( addressCount != 0 )
+                               {
+                                       /* parse the address list to find the end */
+                                       alternateAddressEnd += *(UInt8*)alternateAddressEnd;    /* add length of each AFPTagData record */
+                                       --addressCount;
+                               }
+                               /* get the size of the alternateAddressData */
+                               alternateAddressDataSize = alternateAddressEnd - alternateAddressStart;
+                               /* allocate memory for it */
+                               *alternateAddress = (AFPAlternateAddress *)NewPtr(alternateAddressDataSize);
+                               if ( *alternateAddress != NULL )
+                               {
+                                       /* and return the data */
+                                       BlockMoveData(alternateAddressStart, *alternateAddress, alternateAddressDataSize);
+                                       *alternateAddressLength = alternateAddressDataSize;
+                               }
+                               else
+                               {
+                                       /* no memory - fail now */
+                                       error = memFullErr;
+                               }
+                       }
+                       
+                       if ( error == noErr )   /* fill in more output parameters if everything is OK */
+                       {
+                               if ( afpXInfoPtr->uamNameOffset != 0 )
+                               {
+                                       tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->uamNameOffset);
+                                       BlockMoveData(tempPtr, uamName, tempPtr[0] + 1);
+                               }
+                       }
+               }
+               
+               if ( error == noErr )   /* fill in more output parameters if everything is OK */
+               {
+                       *flags = afpXInfoPtr->flags;
+                       *uamType = afpXInfoPtr->uamType;
+                       
+                       if ( afpXInfoPtr->zoneNameOffset != 0 )
+                       {
+                               tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->zoneNameOffset);
+                               BlockMoveData(tempPtr, zoneName, tempPtr[0] + 1);
+                       }
+                       
+                       if ( afpXInfoPtr->serverNameOffset != 0 )
+                       {
+                               tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->serverNameOffset);
+                               BlockMoveData(tempPtr, serverName, tempPtr[0] + 1);
+                       }
+                       
+                       if ( afpXInfoPtr->volNameOffset != 0 )
+                       {
+                               tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->volNameOffset);
+                               BlockMoveData(tempPtr, volName, tempPtr[0] + 1);
+                       }
+                       
+                       if ( afpXInfoPtr->userNameOffset != 0 )
+                       {
+                               tempPtr = (StringPtr)((long)afpXInfoPtr + afpXInfoPtr->userNameOffset);
+                               BlockMoveData(tempPtr, userName, tempPtr[0] + 1);
+                       }
+               }
+       }
+       else
+       {
+               error = paramErr;
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetUGEntries(short objType,
+                                                        UGEntryPtr entries,
+                                                        long reqEntryCount,
+                                                        long *actEntryCount,
+                                                        long *objID)
+{
+       HParamBlockRec pb;
+       OSErr error = noErr;
+       UGEntry *endEntryArray;
+
+       pb.objParam.ioObjType = objType;
+       *actEntryCount = 0;
+       for ( endEntryArray = entries + reqEntryCount; (entries < endEntryArray) && (error == noErr); ++entries )
+       {
+               pb.objParam.ioObjNamePtr = (StringPtr)entries->name;
+               pb.objParam.ioObjID = *objID;
+               /* Files.h in the universal interfaces, PBGetUGEntrySync takes a CMovePBPtr */
+               /* as the parameter. Inside Macintosh and the original glue used HParmBlkPtr. */
+               /* A CMovePBPtr works OK, but this will be changed in the future  back to */
+               /* HParmBlkPtr, so I'm just casting it here. */
+               error = PBGetUGEntrySync(&pb);
+               if ( error == noErr )
+               {
+                       entries->objID = *objID = pb.objParam.ioObjID;
+                       entries->objType = objType;
+                       ++*actEntryCount;
+               }
+       }
+       
+       return ( error );
+}
+
+/*****************************************************************************/
+
diff --git a/src/mac/morefile/MoreExtr.h b/src/mac/morefile/MoreExtr.h
new file mode 100644 (file)
index 0000000..927a824
--- /dev/null
@@ -0,0 +1,3141 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     A collection of useful high-level File Manager routines.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           MoreFilesExtras.h
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#ifndef __MOREFILESEXTRAS__
+#define __MOREFILESEXTRAS__
+
+#include <Types.h>
+#include <Files.h>
+
+#ifndef true
+#define true 1 
+#define false 0
+#endif
+
+#include "Optim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+/* Constants and types from Universal Interfaces 3.0.1 Files.h */
+
+#if    UNIVERSAL_INTERFACES_VERSION < 0x0301
+
+enum {
+       volMountNoLoginMsgFlagBit       = 0,                                                    /* Input to VolumeMount: If set, the file system */
+       volMountNoLoginMsgFlagMask      = 0x0001,                                               /*  should suppresss any log-in message/greeting dialog */
+       volMountExtendedFlagsBit        = 7,                                                    /* Input to VolumeMount: If set, the mount info is a */
+       volMountExtendedFlagsMask       = 0x0080                                                /*  AFPXVolMountInfo record for 3.7 AppleShare Client */
+};
+
+/* AFPXVolMountInfo is the new AFP volume mount info record, requires the 3.7 AppleShare Client */
+
+struct AFPXVolMountInfo {
+       short                                                   length;                                         /* length of location data (including self) */
+       VolumeType                                              media;                                          /* type of media */
+       short                                                   flags;                                          /* bits for no messages, no reconnect */
+       SInt8                                                   nbpInterval;                            /* NBP Interval parameter (IM2, p.322) */
+       SInt8                                                   nbpCount;                                       /* NBP Interval parameter (IM2, p.322) */
+       short                                                   uamType;                                        /* User Authentication Method type */
+       short                                                   zoneNameOffset;                         /* short positive offset from start of struct to Zone Name */
+       short                                                   serverNameOffset;                       /* offset to pascal Server Name string */
+       short                                                   volNameOffset;                          /* offset to pascal Volume Name string */
+       short                                                   userNameOffset;                         /* offset to pascal User Name string */
+       short                                                   userPasswordOffset;                     /* offset to pascal User Password string */
+       short                                                   volPasswordOffset;                      /* offset to pascal Volume Password string */
+       short                                                   extendedFlags;                          /* extended flags word */
+       short                                                   uamNameOffset;                          /* offset to a pascal UAM name string */
+       short                                                   alternateAddressOffset;         /* offset to Alternate Addresses in tagged format */
+       char                                                    AFPData[176];                           /* variable length data may follow */
+};
+typedef struct AFPXVolMountInfo                        AFPXVolMountInfo;
+typedef AFPXVolMountInfo *                             AFPXVolMountInfoPtr;
+
+enum {
+       kAFPExtendedFlagsAlternateAddressMask = 1                                       /*  bit in AFPXVolMountInfo.extendedFlags that means alternateAddressOffset is used*/
+};
+
+enum {
+                                                                                                                               /* constants for use in AFPTagData.fType field*/
+       kAFPTagTypeIP                           = 0x01,
+       kAFPTagTypeIPPort                       = 0x02,
+       kAFPTagTypeDDP                          = 0x03                                                  /* Currently unused*/
+};
+
+enum {
+                                                                                                                               /* constants for use in AFPTagData.fLength field*/
+       kAFPTagLengthIP                         = 0x06,
+       kAFPTagLengthIPPort                     = 0x08,
+       kAFPTagLengthDDP                        = 0x06
+};
+
+struct AFPTagData {
+       UInt8                                                   fLength;                                        /* length of this data tag including the fLength field */
+       UInt8                                                   fType;
+       UInt8                                                   fData[1];                                       /* variable length data */
+};
+typedef struct AFPTagData                              AFPTagData;
+
+struct AFPAlternateAddress {
+       UInt8                                                   fAddressCount;
+       UInt8                                                   fAddressList[1];                        /* actually variable length packed set of AFPTagData */
+};
+typedef struct AFPAlternateAddress             AFPAlternateAddress;
+
+#endif
+
+/*****************************************************************************/
+
+/*
+**     Macros to get information out of GetVolParmsInfoBuffer
+*/
+
+#define        isNetworkVolume(volParms)       ((volParms).vMServerAdr != 0)
+#define        hasLimitFCBs(volParms)          (((volParms).vMAttrib & (1L << bLimitFCBs)) != 0)
+#define        hasLocalWList(volParms)         (((volParms).vMAttrib & (1L << bLocalWList)) != 0)
+#define        hasNoMiniFndr(volParms)         (((volParms).vMAttrib & (1L << bNoMiniFndr)) != 0)
+#define hasNoVNEdit(volParms)          (((volParms).vMAttrib & (1L << bNoVNEdit)) != 0)
+#define hasNoLclSync(volParms)         (((volParms).vMAttrib & (1L << bNoLclSync)) != 0)
+#define hasTrshOffLine(volParms)       (((volParms).vMAttrib & (1L << bTrshOffLine)) != 0)
+#define hasNoSwitchTo(volParms)                (((volParms).vMAttrib & (1L << bNoSwitchTo)) != 0)
+#define hasNoDeskItems(volParms)       (((volParms).vMAttrib & (1L << bNoDeskItems)) != 0)
+#define hasNoBootBlks(volParms)                (((volParms).vMAttrib & (1L << bNoBootBlks)) != 0)
+#define hasAccessCntl(volParms)                (((volParms).vMAttrib & (1L << bAccessCntl)) != 0)
+#define hasNoSysDir(volParms)          (((volParms).vMAttrib & (1L << bNoSysDir)) != 0)
+#define hasExtFSVol(volParms)          (((volParms).vMAttrib & (1L << bHasExtFSVol)) != 0)
+#define hasOpenDeny(volParms)          (((volParms).vMAttrib & (1L << bHasOpenDeny)) != 0)
+#define hasCopyFile(volParms)          (((volParms).vMAttrib & (1L << bHasCopyFile)) != 0)
+#define hasMoveRename(volParms)                (((volParms).vMAttrib & (1L << bHasMoveRename)) != 0)
+#define hasDesktopMgr(volParms)                (((volParms).vMAttrib & (1L << bHasDesktopMgr)) != 0)
+#define hasShortName(volParms)         (((volParms).vMAttrib & (1L << bHasShortName)) != 0)
+#define hasFolderLock(volParms)                (((volParms).vMAttrib & (1L << bHasFolderLock)) != 0)
+#define hasPersonalAccessPrivileges(volParms) \
+               (((volParms).vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0)
+#define hasUserGroupList(volParms)     (((volParms).vMAttrib & (1L << bHasUserGroupList)) != 0)
+#define hasCatSearch(volParms)         (((volParms).vMAttrib & (1L << bHasCatSearch)) != 0)
+#define hasFileIDs(volParms)           (((volParms).vMAttrib & (1L << bHasFileIDs)) != 0)
+#define hasBTreeMgr(volParms)          (((volParms).vMAttrib & (1L << bHasBTreeMgr)) != 0)
+#define hasBlankAccessPrivileges(volParms) \
+               (((volParms).vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0)
+
+/*****************************************************************************/
+
+
+/*
+**     Bit masks and macros to get common information out of ioACUser returned
+**     by PBGetCatInfo (remember to clear ioACUser before calling PBGetCatInfo
+**     since some file systems don't bother to set this field).
+**
+**     Use the GetDirAccessRestrictions or FSpGetDirAccessRestrictions
+**     functions to retrieve the ioACUser access restrictions byte for
+**     a folder.
+**
+**     Note:   The access restriction byte returned by PBGetCatInfo is the
+**                     2's complement of the user's privileges byte returned in
+**                     ioACAccess by PBHGetDirAccess.
+*/
+
+enum
+{
+       /* bits defined in ioACUser */
+       acUserNoSeeFoldersMask  = 0x01,
+       acUserNoSeeFilesMask    = 0x02,
+       acUserNoMakeChangesMask = 0x04,
+       acUserNotOwnerMask              = 0x80,
+       
+       /* mask for just the access restriction bits */
+       acUserAccessMask                = 0x07,
+       
+       /* common access privilege settings */
+       acUserFull                              = 0x00,                                         /* no access restiction bits on */
+       acUserNone                              = acUserAccessMask,                     /* all access restiction bits on */
+       acUserDropBox                   = acUserNoSeeFoldersMask + acUserNoSeeFilesMask, /* make changes, but not see files or folders */
+       acUserBulletinBoard             = acUserNoMakeChangesMask       /* see files and folders, but not make changes */
+};
+
+/* Macros for testing ioACUser bits */
+#define        userIsOwner(ioACUser)   \
+               (((ioACUser) & acUserNotOwnerMask) == 0)
+#define        userHasFullAccess(ioACUser)     \
+               (((ioACUser) & (acUserAccessMask)) == acUserFull)
+#define        userHasDropBoxAccess(ioACUser)  \
+               (((ioACUser) & acUserAccessMask) == acUserDropBox)
+#define        userHasBulletinBoard(ioACUser)  \
+               (((ioACUser) & acUserAccessMask) == acUserBulletinBoard)
+#define        userHasNoAccess(ioACUser)               \
+               (((ioACUser) & acUserAccessMask) == acUserNone)
+
+/*****************************************************************************/
+
+/*
+**     Deny mode permissions for use with the HOpenAware, HOpenRFAware,
+**     FSpOpenAware, and FSpOpenRFAware functions.
+*/
+
+enum
+{
+       dmNone                  = 0x0000,
+       dmNoneDenyRd    = 0x0010,
+       dmNoneDenyWr    = 0x0020,
+       dmNoneDenyRdWr  = 0x0030,
+       dmRd                    = 0x0001,       /* Single writer, multiple readers; the readers */
+       dmRdDenyRd              = 0x0011,
+       dmRdDenyWr              = 0x0021,       /* Browsing - equivalent to fsRdPerm */
+       dmRdDenyRdWr    = 0x0031,
+       dmWr                    = 0x0002,
+       dmWrDenyRd              = 0x0012,
+       dmWrDenyWr              = 0x0022,
+       dmWrDenyRdWr    = 0x0032,
+       dmRdWr                  = 0x0003,       /* Shared access - equivalent to fsRdWrShPerm */
+       dmRdWrDenyRd    = 0x0013,
+       dmRdWrDenyWr    = 0x0023,       /* Single writer, multiple readers; the writer */
+       dmRdWrDenyRdWr  = 0x0033        /* Exclusive access - equivalent to fsRdWrPerm */
+};
+       
+/*****************************************************************************/
+
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=mac68k
+#endif
+
+/*
+**     For those times where you need to use more than one kind of File Manager parameter
+**     block but don't feel like wasting stack space, here's a parameter block you can reuse.
+*/
+
+union UniversalFMPB
+{
+       ParamBlockRec   PB;
+       CInfoPBRec              ciPB;
+       DTPBRec                 dtPB;
+       HParamBlockRec  hPB;
+       CMovePBRec              cmPB;
+       WDPBRec                 wdPB;
+       FCBPBRec                fcbPB;
+       XVolumeParam    xPB;
+};
+typedef union UniversalFMPB UniversalFMPB;
+typedef UniversalFMPB *UniversalFMPBPtr, **UniversalFMPBHandle;
+
+
+/*
+**     Used by GetUGEntries to return user or group lists
+*/
+
+struct UGEntry
+{
+       short   objType;        /* object type: -1 = group; 0 = user */
+       long    objID;          /* the user or group ID */
+       Str31   name;           /* the user or group name */
+};
+typedef struct UGEntry UGEntry;
+typedef UGEntry *UGEntryPtr, **UGEntryHandle;
+
+
+typedef unsigned char Str8[9];
+
+
+/*
+**     I use the following records instead of the AFPVolMountInfo and AFPXVolMountInfo structures in Files.h
+*/
+
+struct MyAFPVolMountInfo
+{
+       short length;                           /* length of this record */
+       VolumeType media;                       /* type of media, always AppleShareMediaType */
+       short flags;                            /* 0 = normal mount; set bit 0 to inhibit greeting messages */
+       char nbpInterval;                       /* NBP interval parameter; 7 is a good choice */
+       char nbpCount;                          /* NBP count parameter; 5 is a good choice */
+       short uamType;                          /* User Authentication Method */
+       short zoneNameOffset;           /* offset from start of record to zoneName */
+       short serverNameOffset;         /* offset from start of record to serverName */
+       short volNameOffset;            /* offset from start of record to volName */
+       short userNameOffset;           /* offset from start of record to userName */
+       short userPasswordOffset;       /* offset from start of record to userPassword */
+       short volPasswordOffset;        /* offset from start of record to volPassword */
+       Str32 zoneName;                         /* server's AppleTalk zone name */                                      
+       char filler1;                           /* to word align volPassword */
+       Str32 serverName;                       /* server name */                                       
+       char filler2;                           /* to word align volPassword */
+       Str27 volName;                          /* volume name */                                       
+       Str31 userName;                         /* user name (zero length Pascal string for guest) */
+       Str8 userPassword;                      /* user password (zero length Pascal string if no user password) */                                     
+       char filler3;                           /* to word align volPassword */
+       Str8 volPassword;                       /* volume password (zero length Pascal string if no volume password) */                                 
+       char filler4;                           /* to end record on word boundry */
+};
+typedef struct MyAFPVolMountInfo MyAFPVolMountInfo;
+typedef MyAFPVolMountInfo *MyAFPVolMountInfoPtr, **MyAFPVolMountInfoHandle;
+
+struct MyAFPXVolMountInfo
+{
+       short length;                           /* length of this record */
+       VolumeType media;                       /* type of media, always AppleShareMediaType */
+       short flags;                            /* bits for no messages, no reconnect, etc */
+       char nbpInterval;                       /* NBP interval parameter; 7 is a good choice */
+       char nbpCount;                          /* NBP count parameter; 5 is a good choice */
+       short uamType;                          /* User Authentication Method */
+       short zoneNameOffset;           /* offset from start of record to zoneName */
+       short serverNameOffset;         /* offset from start of record to serverName */
+       short volNameOffset;            /* offset from start of record to volName */
+       short userNameOffset;           /* offset from start of record to userName */
+       short userPasswordOffset;       /* offset from start of record to userPassword */
+       short volPasswordOffset;        /* offset from start of record to volPassword */
+       short extendedFlags;            /* extended flags word */
+       short uamNameOffset;            /* offset to a pascal UAM name string */
+       short alternateAddressOffset; /* offset to Alternate Addresses in tagged format */
+       Str32 zoneName;                         /* server's AppleTalk zone name */                                      
+       char filler1;                           /* to word align volPassword */
+       Str32 serverName;                       /* server name */                                       
+       char filler2;                           /* to word align volPassword */
+       Str27 volName;                          /* volume name */                                       
+       Str31 userName;                         /* user name (zero length Pascal string for guest) */
+       Str8 userPassword;                      /* user password (zero length Pascal string if no user password) */                                     
+       char filler3;                           /* to word align volPassword */
+       Str8 volPassword;                       /* volume password (zero length Pascal string if no volume password) */                                 
+       char filler4;                           /* to word align uamNameOffset */
+       Str32 uamName;                          /* UAM name */
+       char filler5;                           /* to word align alternateAddress */
+       char alternateAddress[kVariableLengthArray];    /* AFPAlternateAddress */
+};
+typedef struct MyAFPXVolMountInfo MyAFPXVolMountInfo;
+typedef MyAFPXVolMountInfo *MyAFPXVolMountInfoPtr, **MyAFPXVolMountInfoHandle;
+
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=reset
+#endif
+
+/*****************************************************************************/
+
+pascal void    TruncPString(StringPtr destination,
+                                                        ConstStr255Param source,
+                                                        short maxLength);
+/*     ¦ International friendly string truncate routine.
+       The TruncPString function copies up to maxLength characters from
+       the source Pascal string to the destination Pascal string. TruncPString
+       ensures that the truncated string ends on a single-byte character, or on
+       the last byte of a multi-byte character.
+       
+       destination             output: destination Pascal string.
+       source                  input:  source Pascal string.
+       maxLength               output: The maximum allowable length of the destination
+                                                       string.
+*/
+
+/*****************************************************************************/
+
+pascal Ptr     GetTempBuffer(long buffReqSize,
+                                                 long *buffActSize);
+/*     ¦ Allocate a temporary copy or search buffer.
+       The GetTempBuffer function allocates a temporary buffer for file system
+       operations which is at least 1024 bytes (1K) and a multiple of
+       1024 bytes.
+       
+       buffReqSize             input:  Size you'd like the buffer to be.
+       buffActSize             output: Size of buffer allocated.
+       function result output: Pointer to memory allocated or nil if no memory
+                                                       was available. The caller is responsible for
+                                                       disposing of this buffer with DisposePtr.
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetVolumeInfoNoName(ConstStr255Param pathname,
+                                                                       short vRefNum,
+                                                                       HParmBlkPtr pb);
+/*     ¦ Call PBHGetVInfoSync ignoring returned name.
+       GetVolumeInfoNoName uses pathname and vRefNum to call PBHGetVInfoSync
+       in cases where the returned volume name is not needed by the caller.
+       The pathname and vRefNum parameters are not touched, and the pb
+       parameter is initialized by PBHGetVInfoSync except that ioNamePtr in
+       the parameter block is always returned as NULL (since it might point
+       to GetVolumeInfoNoName's local variable tempPathname).
+
+       I noticed using this code in several places, so here it is once.
+       This reduces the code size of MoreFiles.
+
+       pathName        input:  Pointer to a full pathname or nil.  If you pass in a 
+                                               partial pathname, it is ignored. A full pathname to a
+                                               volume must end with a colon character (:).
+       vRefNum         input:  Volume specification (volume reference number, working
+                                               directory number, drive number, or 0).
+       pb                      input:  A pointer to HParamBlockRec.
+                               output: The parameter block as filled in by PBHGetVInfoSync
+                                               except that ioNamePtr will always be NULL.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               paramErr                        -50             No default volume, or pb was NULL
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   XGetVolumeInfoNoName(ConstStr255Param pathname,
+                                                                       short vRefNum,
+                                                                       XVolumeParamPtr pb);
+/*     ¦ Call PBXGetVolInfoSync ignoring returned name.
+       XGetVolumeInfoNoName uses pathname and vRefNum to call PBXGetVolInfoSync
+       in cases where the returned volume name is not needed by the caller.
+       The pathname and vRefNum parameters are not touched, and the pb
+       parameter is initialized by PBXGetVolInfoSync except that ioNamePtr in
+       the parameter block is always returned as NULL (since it might point
+       to XGetVolumeInfoNoName's local variable tempPathname).
+
+       pathName        input:  Pointer to a full pathname or nil.  If you pass in a 
+                                               partial pathname, it is ignored. A full pathname to a
+                                               volume must end with a colon character (:).
+       vRefNum         input:  Volume specification (volume reference number, working
+                                               directory number, drive number, or 0).
+       pb                      input:  A pointer to HParamBlockRec.
+                               output: The parameter block as filled in by PBXGetVolInfoSync
+                                               except that ioNamePtr will always be NULL.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               paramErr                        -50             No default volume, or pb was NULL
+*/
+
+/*****************************************************************************/
+
+pascal OSErr GetCatInfoNoName(short vRefNum,
+                                                          long dirID,
+                                                          ConstStr255Param name,
+                                                          CInfoPBPtr pb);
+/*     ¦ Call PBGetCatInfoSync ignoring returned name.
+       GetCatInfoNoName uses vRefNum, dirID and name to call PBGetCatInfoSync
+       in cases where the returned object is not needed by the caller.
+       The vRefNum, dirID and name parameters are not touched, and the pb
+       parameter is initialized by PBGetCatInfoSync except that ioNamePtr in
+       the parameter block is always returned as NULL (since it might point
+       to GetCatInfoNoName's local variable tempName).
+
+       I noticed using this code in several places, so here it is once.
+       This reduces the code size of MoreFiles.
+
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to object name, or nil when dirID
+                                                       specifies a directory that's the object.
+       pb                              input:  A pointer to CInfoPBRec.
+                                       output: The parameter block as filled in by
+                                                       PBGetCatInfoSync except that ioNamePtr will
+                                                       always be NULL.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+               
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DetermineVRefNum(ConstStr255Param pathname,
+                                                                short vRefNum,
+                                                                short *realVRefNum);
+/*     ¦ Determine the real volume reference number.
+       The DetermineVRefNum function determines the volume reference number of
+       a volume from a pathname, a volume specification, or a combination
+       of the two.
+       WARNING: Volume names on the Macintosh are *not* unique -- Multiple
+       mounted volumes can have the same name. For this reason, the use of a
+       volume name or full pathname to identify a specific volume may not
+       produce the results you expect.  If more than one volume has the same
+       name and a volume name or full pathname is used, the File Manager
+       currently uses the first volume it finds with a matching name in the
+       volume queue.
+
+       pathName        input:  Pointer to a full pathname or nil.  If you pass in a 
+                                               partial pathname, it is ignored. A full pathname to a
+                                               volume must end with a colon character (:).
+       vRefNum         input:  Volume specification (volume reference number, working
+                                               directory number, drive number, or 0).
+       realVRefNum     output: The real volume reference number.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               paramErr                        -50             No default volume
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HGetVInfo(short volReference,
+                                                 StringPtr volName,
+                                                 short *vRefNum,
+                                                 unsigned long *freeBytes,
+                                                 unsigned long *totalBytes);
+/*     ¦ Get information about a mounted volume.
+       The HGetVInfo function returns the name, volume reference number,
+       available space (in bytes), and total space (in bytes) for the
+       specified volume. You can specify the volume by providing its drive
+       number, volume reference number, or 0 for the default volume.
+       This routine is compatible with volumes up to 4 gigabytes.
+       
+       volReference    input:  The drive number, volume reference number,
+                                                       or 0 for the default volume.
+       volName                 input:  A pointer to a buffer (minimum Str27) where
+                                                       the volume name is to be returned or must
+                                                       be nil.
+                                       output: The volume name.
+       vRefNum                 output: The volume reference number.
+       freeBytes               output: The number of free bytes on the volume.
+                                                       freeBytes is an unsigned long value.
+       totalBytes              output: The total number of bytes on the volume.
+                                                       totalBytes is an unsigned long value.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               paramErr                        -50             No default volume
+       
+       __________
+       
+       Also see:       XGetVInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   XGetVInfo(short volReference,
+                                                 StringPtr volName,
+                                                 short *vRefNum,
+                                                 UnsignedWide *freeBytes,
+                                                 UnsignedWide *totalBytes);
+/*     ¦ Get extended information about a mounted volume.
+       The XGetVInfo function returns the name, volume reference number,
+       available space (in bytes), and total space (in bytes) for the
+       specified volume. You can specify the volume by providing its drive
+       number, volume reference number, or 0 for the default volume.
+       This routine is compatible with volumes up to 2 terabytes.
+       
+       volReference    input:  The drive number, volume reference number,
+                                                       or 0 for the default volume.
+       volName                 input:  A pointer to a buffer (minimum Str27) where
+                                                       the volume name is to be returned or must
+                                                       be nil.
+                                       output: The volume name.
+       vRefNum                 output: The volume reference number.
+       freeBytes               output: The number of free bytes on the volume.
+                                                       freeBytes is an UnsignedWide value.
+       totalBytes              output: The total number of bytes on the volume.
+                                                       totalBytes is an UnsignedWide value.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               paramErr                        -50             No default volume
+       
+       __________
+       
+       Also see:       HGetVInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   CheckVolLock(ConstStr255Param pathname,
+                                                        short vRefNum);
+/*     ¦ Determine if a volume is locked.
+       The CheckVolLock function determines if a volume is locked - either by
+       hardware or by software. If CheckVolLock returns noErr, then the volume
+       is not locked.
+
+       pathName        input:  Pointer to a full pathname or nil.  If you pass in a 
+                                               partial pathname, it is ignored. A full pathname to a
+                                               volume must end with a colon character (:).
+       vRefNum         input:  Volume specification (volume reference number, working
+                                               directory number, drive number, or 0).
+       
+       Result Codes
+               noErr                           0               No error - volume not locked
+               nsvErr                          -35             No such volume
+               wPrErr                          -44             Volume locked by hardware
+               vLckdErr                        -46             Volume locked by software
+               paramErr                        -50             No default volume
+*/
+
+/*****************************************************************************/
+
+pascal OSErr GetDriverName(short driverRefNum,
+                                                       Str255 driverName);
+/*     ¦ Get a device driver's name.
+       The GetDriverName function returns a device driver's name.
+
+       driverRefNum    input:  The driver reference number.
+       driverName              output: The driver's name.
+       
+       Result Codes
+               noErr                           0               No error
+               badUnitErr                      -21             Bad driver reference number
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FindDrive(ConstStr255Param pathname,
+                                                 short vRefNum,
+                                                 DrvQElPtr *driveQElementPtr);
+/*     ¦ Find a volume's drive queue element in the drive queue.
+       The FindDrive function returns a pointer to a mounted volume's
+       drive queue element.
+
+       pathName                        input:  Pointer to a full pathname or nil. If you
+                                                               pass in a partial pathname, it is ignored.
+                                                               A full pathname to a volume must end with
+                                                               a colon character (:).
+       vRefNum                         input:  Volume specification (volume reference
+                                                               number, working directory number, drive
+                                                               number, or 0).
+       driveQElementPtr        output: Pointer to a volume's drive queue element
+                                                               in the drive queue. DO NOT change the
+                                                               DrvQEl.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               paramErr                        -50             No default volume
+               nsDrvErr                        -56             No such drive
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetDiskBlocks(ConstStr255Param pathname,
+                                                         short vRefNum,
+                                                         unsigned long *numBlocks);
+/*     ¦ Return the number of physical disk blocks on a disk drive.
+       The GetDiskBlocks function returns the number of physical disk
+       blocks on a disk drive. NOTE: This is not the same as volume
+       allocation blocks!
+
+       pathName        input:  Pointer to a full pathname or nil. If you
+                                               pass in a partial pathname, it is ignored.
+                                               A full pathname to a volume must end with
+                                               a colon character (:).
+       vRefNum         input:  Volume specification (volume reference
+                                               number, working directory number, drive
+                                               number, or 0).
+       numBlocks       output: The number of physical disk blocks on the disk drive.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               paramErr                        -50             No default volume, driver reference
+                                                                       number is zero, ReturnFormatList
+                                                                       returned zero blocks, DriveStatus
+                                                                       returned an unknown value, or
+                                                                       driveQElementPtr->qType is unknown
+               nsDrvErr                        -56             No such drive
+               statusErr                       Ð18             Driver does not respond to this
+                                                                       status request
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies
+                                                                       a nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetVolFileSystemID(ConstStr255Param pathname,
+                                                                  short vRefNum,
+                                                                  short *fileSystemID);
+/*     ¦ Get a volume's file system ID.
+       The GetVolFileSystemID function returned the file system ID of
+       a mounted volume. The file system ID identifies the file system
+       that handles requests to a particular volume. Here's a partial list
+       of file system ID numbers (only Apple's file systems are listed):
+               FSID    File System
+               -----   -----------------------------------------------------
+               $0000   Macintosh HFS or MFS
+               $0100   ProDOS File System
+               $0101   PowerTalk Mail Enclosures
+               $4147   ISO 9660 File Access (through Foreign File Access)
+               $4242   High Sierra File Access (through Foreign File Access)
+               $464D   QuickTake File System (through Foreign File Access)
+               $4953   Macintosh PC Exchange (MS-DOS)
+               $4A48   Audio CD Access (through Foreign File Access)
+               $4D4B   Apple Photo Access (through Foreign File Access)
+       
+       See the Technical Note "FL 35 - Determining Which File System
+       Is Active" and the "Guide to the File System Manager" for more
+       information.
+       
+       pathName                input:  Pointer to a full pathname or nil.  If you pass
+                                                       in a partial pathname, it is ignored. A full
+                                                       pathname to a volume must contain at least
+                                                       one colon character (:) and must not start with
+                                                       a colon character.
+       vRefNum                 input:  Volume specification (volume reference number,
+                                                       working directory number, drive number, or 0).
+       fileSystemID    output: The volume's file system ID.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               paramErr                        -50             No default volume, or pb was NULL
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetVolState(ConstStr255Param pathname,
+                                                       short vRefNum,
+                                                       Boolean *volumeOnline,
+                                                       Boolean *volumeEjected,
+                                                       Boolean *driveEjectable,
+                                                       Boolean *driverWantsEject);
+/*     ¦ Returns a volume's online and eject information.
+       The GetVolState function determines if a volume is online or offline,
+       if an offline volume is ejected, and if the volume's driver is
+       ejectable or wants eject calls.
+       
+       pathName                        input:  Pointer to a full pathname or nil.
+       vRefNum                         input:  Volume specification (volume reference number,
+                                                               working directory number, drive number, or 0).
+       volumeOnline            output: True if the volume is online;
+                                                               False if the volume is offline.
+       volumeEjected           output: True if the volume is ejected (ejected
+                                                               volumes are always offline); False if the
+                                                               volume is not ejected.
+       driveEjectable          output: True if the volume's drive is ejectable;
+                                                               False if the volume's drive is not ejectable.
+       driverWantsEject        output: True if the volume's driver wants an Eject
+                                                               request after unmount (even if the drive
+                                                               is not ejectable); False if the volume's
+                                                               driver does not need an eject request.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               paramErr                        -50             No default volume, or pb was NULL
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   UnmountAndEject(ConstStr255Param pathname,
+                                                               short vRefNum);
+/*     ¦ Unmount and eject a volume.
+       The UnmountAndEject function unmounts and ejects a volume. The volume
+       is ejected only if it is ejectable and not already ejected.
+       
+       pathName        input:  Pointer to a full pathname or nil.  If you pass in a 
+                                               partial pathname, it is ignored. A full pathname to a
+                                               volume must end with a colon character (:).
+       vRefNum         input:  Volume specification (volume reference number, working
+                                               directory number, drive number, or 0).
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad volume name
+               fBsyErr                         -47             One or more files are open
+               paramErr                        -50             No default volume
+               nsDrvErr                        -56             No such drive
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   OnLine(FSSpecPtr volumes,
+                                          short reqVolCount,
+                                          short *actVolCount,
+                                          short *volIndex);
+/*     ¦ Return the list of volumes currently mounted.
+       The OnLine function returns the list of volumes currently mounted in
+       an array of FSSpec records.
+       
+       A noErr result indicates that the volumes array was filled
+       (actVolCount == reqVolCount) and there may be additional volumes
+       mounted. A nsvErr result indicates that the end of the volume list
+       was found and actVolCount volumes were actually found this time.
+
+       volumes         input:  Pointer to array of FSSpec where the volume list
+                                               is returned.
+       reqVolCount     input:  Maximum number of volumes to return     (the number of
+                                               elements in the volumes array).
+       actVolCount     output: The number of volumes actually returned.
+       volIndex        input:  The current volume index position. Set to 1 to
+                                               start with the first volume.
+                               output: The volume index position to get the next volume.
+                                               Pass this value the next time you call OnLine to
+                                               start where you left off.
+       
+       Result Codes
+               noErr                           0               No error, but there are more volumes
+                                                                       to list
+               nsvErr                          -35             No more volumes to be listed
+               paramErr                        -50             volIndex was <= 0
+*/
+
+/*****************************************************************************/
+
+pascal OSErr SetDefault(short newVRefNum,
+                                                long newDirID,
+                                                short *oldVRefNum,
+                                                long *oldDirID);
+/*     ¦ Set the default volume before making Standard I/O requests.
+       The SetDefault function sets the default volume and directory to the
+       volume specified by newVRefNum and the directory specified by newDirID.
+       The current default volume reference number and directory ID are
+       returned in oldVRefNum and oldDir and must be used to restore the
+       default volume and directory to their previous state *as soon as
+       possible* with the RestoreDefault function. These two functions are
+       designed to be used as a wrapper around Standard I/O routines where
+       the location of the file is implied to be the default volume and
+       directory. In other words, this is how you should use these functions:
+       
+               error = SetDefault(newVRefNum, newDirID, &oldVRefNum, &oldDirID);
+               if ( error == noErr )
+               {
+                       // call the Stdio functions like remove, rename, tmpfile,
+                       // fopen, freopen, etc. or non-ANSI extensions like
+                       // fdopen,fsetfileinfo, -- create, open, unlink, etc. here!
+                       
+                       error = RestoreDefault(oldVRefNum, oldDirID);
+               }
+       
+       By using these functions as a wrapper, you won't need to open a working
+       directory (because SetDefault and RestoreDefault use HSetVol) and you
+       won't have to worry about the effects of using HSetVol (documented in
+       Technical Note "FL 11 - PBHSetVol is Dangerous" and in the
+       Inside Macintosh: Files book in the description of the HSetVol and 
+       PBHSetVol functions) because the default volume/directory is restored
+       before giving up control to code that might be affected by HSetVol.
+       
+       newVRefNum      input:  Volume specification (volume reference number,
+                                               working directory number, drive number, or 0) of
+                                               the new default volume.
+       newDirID        input:  Directory ID of the new default directory.
+       oldVRefNum      output: The volume specification to save for use with
+                                               RestoreDefault.
+       oldDirID        output: The directory ID to save for use with
+                                               RestoreDefault.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               bdNamErr                        -37             Bad volume name
+               fnfErr                          -43             Directory not found
+               paramErr                        -50             No default volume
+               afpAccessDenied         -5000   User does not have access to the directory
+       
+       __________
+       
+       Also see:       RestoreDefault
+*/
+
+/*****************************************************************************/
+
+pascal OSErr RestoreDefault(short oldVRefNum,
+                                                        long oldDirID);
+/*     ¦ Restore the default volume after making Standard C I/O requests.
+       The RestoreDefault function restores the default volume and directory
+       to the volume specified by oldVRefNum and the directory specified by 
+       oldDirID. The oldVRefNum and oldDirID parameters were previously
+       obtained from the SetDefault function. These two functions are designed
+       to be used as a wrapper around Standard C I/O routines where the
+       location of the file is implied to be the default volume and directory.
+       In other words, this is how you should use these functions:
+       
+               error = SetDefault(newVRefNum, newDirID, &oldVRefNum, &oldDirID);
+               if ( error == noErr )
+               {
+                       // call the Stdio functions like remove, rename, tmpfile,
+                       // fopen, freopen, etc. or non-ANSI extensions like
+                       // fdopen,fsetfileinfo, -- create, open, unlink, etc. here!
+                       
+                       error = RestoreDefault(oldVRefNum, oldDirID);
+               }
+       
+       By using these functions as a wrapper, you won't need to open a working
+       directory (because SetDefault and RestoreDefault use HSetVol) and you
+       won't have to worry about the effects of using HSetVol (documented in
+       Technical Note "FL 11 - PBHSetVol is Dangerous" and in the
+       Inside Macintosh: Files book in the description of the HSetVol and 
+       PBHSetVol functions) because the default volume/directory is restored
+       before giving up control to code that might be affected by HSetVol.
+       
+       oldVRefNum      input: The volume specification to restore.
+       oldDirID        input:  The directory ID to restore.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               bdNamErr                        -37             Bad volume name
+               fnfErr                          -43             Directory not found
+               paramErr                        -50             No default volume
+               rfNumErr                        -51             Bad working directory reference number
+               afpAccessDenied         -5000   User does not have access to the directory
+       
+       __________
+       
+       Also see:       SetDefault
+*/
+
+/*****************************************************************************/
+
+pascal OSErr GetDInfo(short vRefNum,
+                                          long dirID,
+                                          ConstStr255Param name,
+                                          DInfo *fndrInfo);
+/*     ¦ Get the finder information for a directory.
+       The GetDInfo function gets the finder information for a directory.
+
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to object name, or nil when dirID
+                                                       specifies a directory that's the object.
+       fndrInfo                output: If the object is a directory, then its DInfo.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+               
+       __________
+       
+       Also see:       FSpGetDInfo, FSpGetFInfoCompat
+*/
+
+/*****************************************************************************/
+
+pascal OSErr FSpGetDInfo(const FSSpec *spec,
+                                                 DInfo *fndrInfo);
+/*     ¦ Get the finder information for a directory.
+       The FSpGetDInfo function gets the finder information for a directory.
+
+       spec            input:  An FSSpec record specifying the directory.
+       fndrInfo        output: If the object is a directory, then its DInfo.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+               
+       __________
+       
+       Also see:       FSpGetFInfoCompat, GetDInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr SetDInfo(short vRefNum,
+                                          long dirID,
+                                          ConstStr255Param name,
+                                          const DInfo *fndrInfo);
+/*     ¦ Set the finder information for a directory.
+       The SetDInfo function sets the finder information for a directory.
+
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to object name, or nil when dirID
+                                                       specifies a directory that's the object.
+       fndrInfo                input:  The DInfo.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       Also see:       FSpSetDInfo, FSpSetFInfoCompat
+*/
+
+/*****************************************************************************/
+
+pascal OSErr FSpSetDInfo(const FSSpec *spec,
+                                                 const DInfo *fndrInfo);
+/*     ¦ Set the finder information for a directory.
+       The FSpSetDInfo function sets the finder information for a directory.
+
+       spec            input:  An FSSpec record specifying the directory.
+       fndrInfo        input:  The DInfo.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       Also see:       FSpSetFInfoCompat, SetDInfo
+*/
+
+/*****************************************************************************/
+
+#if OLDROUTINENAMES
+#define        GetDirID(vRefNum, dirID, name, theDirID, isDirectory)   \
+               GetDirectoryID(vRefNum, dirID, name, theDirID, isDirectory)
+#endif
+
+pascal OSErr   GetDirectoryID(short vRefNum,
+                                                          long dirID,
+                                                          ConstStr255Param name,
+                                                          long *theDirID,
+                                                          Boolean *isDirectory);
+/*     ¦ Get the directory ID number of the directory specified.
+       The GetDirectoryID function gets the directory ID number of the
+       directory specified.  If a file is specified, then the parent
+       directory of the file is returned and isDirectory is false.  If
+       a directory is specified, then that directory's ID number is
+       returned and isDirectory is true.
+       WARNING: Volume names on the Macintosh are *not* unique -- Multiple
+       mounted volumes can have the same name. For this reason, the use of a
+       volume name or full pathname to identify a specific volume may not
+       produce the results you expect.  If more than one volume has the same
+       name and a volume name or full pathname is used, the File Manager
+       currently uses the first volume it finds with a matching name in the
+       volume queue.
+       
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to object name, or nil when dirID
+                                                       specifies a directory that's the object.
+       theDirID                output: If the object is a file, then its parent directory
+                                                       ID. If the object is a directory, then its ID.
+       isDirectory             output: True if object is a directory; false if
+                                                       object is a file.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+*/
+
+/*****************************************************************************/
+
+#if OLDROUTINENAMES
+#define        DirIDFromFSSpec(spec, theDirID, isDirectory)    \
+               FSpGetDirectoryID(spec, theDirID, isDirectory)
+#endif
+
+pascal OSErr   FSpGetDirectoryID(const FSSpec *spec,
+                                                                 long *theDirID,
+                                                                 Boolean *isDirectory);
+/*     ¦ Get the directory ID number of a directory.
+       The FSpGetDirectoryID function gets the directory ID number of the
+       directory specified by spec. If spec is to a file, then the parent
+       directory of the file is returned and isDirectory is false.  If
+       spec is to a directory, then that directory's ID number is
+       returned and isDirectory is true.
+       
+       spec                    input:  An FSSpec record specifying the directory.
+       theDirID                output: The directory ID.
+       isDirectory             output: True if object is a directory; false if
+                                                       object is a file.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetDirName(short vRefNum,
+                                                  long dirID,
+                                                  Str31 name);
+/*     ¦ Get the name of a directory from its directory ID.
+       The GetDirName function gets the name of a directory from its
+       directory ID.
+
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       name            output: Points to a Str31 where the directory name is to be
+                                               returned.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume or
+                                                                       name parameter was NULL
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetIOACUser(short vRefNum,
+                                                       long dirID,
+                                                       ConstStr255Param name,
+                                                       SInt8 *ioACUser);
+/*     ¦ Get a directory's access restrictions byte.
+       GetIOACUser returns a directory's access restrictions byte.
+       Use the masks and macro defined in MoreFilesExtras to check for
+       specific access priviledges.
+       
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       name            input:  Pointer to object name, or nil when dirID
+                                               specifies a directory that's the object.
+       ioACUser        output: The access restriction byte
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetIOACUser(const FSSpec *spec,
+                                                          SInt8 *ioACUser);
+/*     ¦ Get a directory's access restrictions byte.
+       FSpGetIOACUser returns a directory's access restrictions byte.
+       Use the masks and macro defined in MoreFilesExtras to check for
+       specific access priviledges.
+       
+       spec            input:  An FSSpec record specifying the directory.
+       ioACUser        output: The access restriction byte
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetParentID(short vRefNum,
+                                                       long dirID,
+                                                       ConstStr255Param name,
+                                                       long *parID);
+/*     ¦ Get the parent directory ID number of the specified object.
+       The GetParentID function gets the parent directory ID number of the
+       specified object.
+       
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       name            input:  Pointer to object name, or nil when dirID specifies
+                                               a directory that's the object.
+       parID           output: The parent directory ID of the specified object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetFilenameFromPathname(ConstStr255Param pathname,
+                                                                               Str255 filename);
+/*     ¦ Get the object name from the end of a full or partial pathname.
+       The GetFilenameFromPathname function gets the file (or directory) name
+       from the end of a full or partial pathname. Returns notAFileErr if the
+       pathname is nil, the pathname is empty, or the pathname cannot refer to
+       a filename (with a noErr result, the pathname could still refer to a
+       directory).
+       
+       pathname        input:  A full or partial pathname.
+       filename        output: The file (or directory) name.
+       
+       Result Codes
+               noErr                           0               No error
+               notAFileErr                     -1302   The pathname is nil, the pathname
+                                                                       is empty, or the pathname cannot refer
+                                                                       to a filename
+       
+       __________
+       
+       See also:       GetObjectLocation.
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetObjectLocation(short vRefNum,
+                                                                 long dirID,
+                                                                 ConstStr255Param pathname,
+                                                                 short *realVRefNum,
+                                                                 long *realParID,
+                                                                 Str255 realName,
+                                                                 Boolean *isDirectory);
+/*     ¦ Get a file system object's location.
+       The GetObjectLocation function gets a file system object's location -
+       that is, its real volume reference number, real parent directory ID,
+       and name. While we're at it, determine if the object is a file or directory.
+       If GetObjectLocation returns fnfErr, then the location information
+       returned is valid, but it describes an object that doesn't exist.
+       You can use the location information for another operation, such as
+       creating a file or directory.
+       
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       pathname        input:  Pointer to object name, or nil when dirID specifies
+                                               a directory that's the object.
+       realVRefNum     output: The real volume reference number.
+       realParID       output: The parent directory ID of the specified object.
+       realName        output: The name of the specified object (the case of the
+                                               object name may not be the same as the object's
+                                               catalog entry on disk - since the Macintosh file
+                                               system is not case sensitive, it shouldn't matter).
+       isDirectory     output: True if object is a directory; false if object
+                                               is a file.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               notAFileErr                     -1302   The pathname is nil, the pathname
+                                                                       is empty, or the pathname cannot refer
+                                                                       to a filename
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSMakeFSSpecCompat
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetDirItems(short vRefNum,
+                                                       long dirID,
+                                                       ConstStr255Param name,
+                                                       Boolean getFiles,
+                                                       Boolean getDirectories,
+                                                       FSSpecPtr items,
+                                                       short reqItemCount,
+                                                       short *actItemCount,
+                                                       short *itemIndex);
+/*     ¦ Return a list of items in a directory.
+       The GetDirItems function returns a list of items in the specified
+       directory in an array of FSSpec records. File, subdirectories, or
+       both can be returned in the list.
+       
+       A noErr result indicates that the items array was filled
+       (actItemCount == reqItemCount) and there may be additional items
+       left in the directory. A fnfErr result indicates that the end of
+       the directory list was found and actItemCount items were actually
+       found this time.
+
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to object name, or nil when dirID
+                                                       specifies a directory that's the object.
+       getFiles                input:  Pass true to have files added to the items list.
+       getDirectories  input:  Pass true to have directories added to the
+                                                       items list.
+       items                   input:  Pointer to array of FSSpec where the item list
+                                                       is returned.
+       reqItemCount    input:  Maximum number of items to return (the number
+                                                       of elements in the items array).
+       actItemCount    output: The number of items actually returned.
+       itemIndex               input:  The current item index position. Set to 1 to
+                                                       start with the first item in the directory.
+                                       output: The item index position to get the next item.
+                                                       Pass this value the next time you call
+                                                       GetDirItems to start where you left off.
+       
+       Result Codes
+               noErr                           0               No error, but there are more items
+                                                                       to list
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found, there are no more items
+                                                                       to be listed.
+               paramErr                        -50             No default volume or itemIndex was <= 0
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DeleteDirectoryContents(short vRefNum,
+                                                                               long dirID,
+                                                                               ConstStr255Param name);
+/*     ¦ Delete the contents of a directory.
+       The DeleteDirectoryContents function deletes the contents of a directory.
+       All files and subdirectories in the specified directory are deleted.
+       If a locked file or directory is encountered, it is unlocked and then
+       deleted.  If any unexpected errors are encountered,
+       DeleteDirectoryContents quits and returns to the caller.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to directory name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               wPrErr                          -44             Hardware volume lock    
+               fLckdErr                        -45             File is locked  
+               vLckdErr                        -46             Software volume lock    
+               fBsyErr                         -47             File busy, directory not empty, or working directory control block open 
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       Also see:       DeleteDirectory
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DeleteDirectory(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name);
+/*     ¦ Delete a directory and its contents.
+       The DeleteDirectory function deletes a directory and its contents.
+       All files and subdirectories in the specified directory are deleted.
+       If a locked file or directory is encountered, it is unlocked and then
+       deleted.  After deleting the directories contents, the directory is
+       deleted. If any unexpected errors are encountered, DeleteDirectory
+       quits and returns to the caller.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to directory name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               wPrErr                          -44             Hardware volume lock
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Software volume lock
+               fBsyErr                         -47             File busy, directory not empty, or working directory control block open 
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       Also see:       DeleteDirectoryContents
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   CheckObjectLock(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name);
+/*     ¦ Determine if a file or directory is locked.
+       The CheckObjectLock function determines if a file or directory is locked.
+       If CheckObjectLock returns noErr, then the file or directory
+       is not locked. If CheckObjectLock returns fLckdErr, the it is locked.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       Also see:       FSpCheckObjectLock
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCheckObjectLock(const FSSpec *spec);
+/*     ¦ Determine if a file or directory is locked.
+       The FSpCheckObjectLock function determines if a file or directory is locked.
+       If FSpCheckObjectLock returns noErr, then the file or directory
+       is not locked.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       Also see:       CheckObjectLock
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetFileSize(short vRefNum,
+                                                       long dirID,
+                                                       ConstStr255Param fileName,
+                                                       long *dataSize,
+                                                       long *rsrcSize);
+/*     ¦ Get the logical sizes of a file's forks.
+       The GetFileSize function returns the logical size of a file's
+       data and resource fork.
+       
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       name            input:  The name of the file.
+       dataSize        output: The number of bytes in the file's data fork.
+       rsrcSize        output: The number of bytes in the file's resource fork.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpGetFileSize
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetFileSize(const FSSpec *spec,
+                                                          long *dataSize,
+                                                          long *rsrcSize);
+/*     ¦ Get the logical sizes of a file's forks.
+       The FSpGetFileSize function returns the logical size of a file's
+       data and resource fork.
+       
+       spec            input:  An FSSpec record specifying the file.
+       dataSize        output: The number of bytes in the file's data fork.
+       rsrcSize        output: The number of bytes in the file's resource fork.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               paramErr                        -50             No default volume
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       GetFileSize
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   BumpDate(short vRefNum,
+                                                long dirID,
+                                                ConstStr255Param name);
+/*     ¦ Update the modification date of a file or directory.
+       The BumpDate function changes the modification date of a file or
+       directory to the current date/time.  If the modification date is already
+       equal to the current date/time, then add one second to the
+       modification date.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpBumpDate
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpBumpDate(const FSSpec *spec);
+/*     ¦ Update the modification date of a file or directory.
+       The FSpBumpDate function changes the modification date of a file or
+       directory to the current date/time.  If the modification date is already
+       equal to the current date/time, then add one second to the
+       modification date.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       BumpDate
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   ChangeCreatorType(short vRefNum,
+                                                                 long dirID,
+                                                                 ConstStr255Param name,
+                                                                 OSType creator,
+                                                                 OSType fileType);
+/*     ¦ Change the creator or file type of a file.
+       The ChangeCreatorType function changes the creator or file type of a file.
+
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       name            input:  The name of the file.
+       creator         input:  The new creator type or 0x00000000 to leave
+                                               the creator type alone.
+       fileType        input:  The new file type or 0x00000000 to leave the
+                                               file type alone.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               notAFileErr                     -1302   Name was not a file
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpChangeCreatorType
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpChangeCreatorType(const FSSpec *spec,
+                                                                        OSType creator,
+                                                                        OSType fileType);
+/*     ¦ Change the creator or file type of a file.
+       The FSpChangeCreatorType function changes the creator or file type of a file.
+
+       spec            input:  An FSSpec record specifying the file.
+       creator         input:  The new creator type or 0x00000000 to leave
+                                               the creator type alone.
+       fileType        input:  The new file type or 0x00000000 to leave the
+                                               file type alone.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               notAFileErr                     -1302   Name was not a file
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       ChangeCreatorType
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   ChangeFDFlags(short vRefNum,
+                                                         long dirID,
+                                                         ConstStr255Param name,
+                                                         Boolean       setBits,
+                                                         unsigned short flagBits);
+/*     ¦ Set or clear Finder Flag bits.
+       The ChangeFDFlags function sets or clears Finder Flag bits in the
+       fdFlags field of a file or directory's FInfo record.
+       
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       name            input:  Pointer to object name, or nil when dirID specifies
+                                               a directory that's the object.
+       setBits         input:  If true, then set the bits specified in flagBits.
+                                               If false, then clear the bits specified in flagBits.
+       flagBits        input:  The flagBits parameter specifies which Finder Flag
+                                               bits to set or clear. If a bit in flagBits is set,
+                                               then the same bit in fdFlags is either set or
+                                               cleared depending on the state of the setBits
+                                               parameter.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpChangeFDFlags
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpChangeFDFlags(const FSSpec *spec,
+                                                                Boolean setBits,
+                                                                unsigned short flagBits);
+/*     ¦ Set or clear Finder Flag bits.
+       The FSpChangeFDFlags function sets or clears Finder Flag bits in the
+       fdFlags field of a file or directory's FInfo record.
+       
+       spec            input:  An FSSpec record specifying the object.
+       setBits         input:  If true, then set the bits specified in flagBits.
+                                               If false, then clear the bits specified in flagBits.
+       flagBits        input:  The flagBits parameter specifies which Finder Flag
+                                               bits to set or clear. If a bit in flagBits is set,
+                                               then the same bit in fdFlags is either set or
+                                               cleared depending on the state of the setBits
+                                               parameter.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       ChangeFDFlags
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   SetIsInvisible(short vRefNum,
+                                                          long dirID,
+                                                          ConstStr255Param name);
+/*     ¦ Set the invisible Finder Flag bit.
+       The SetIsInvisible function sets the invisible bit in the fdFlags
+       word of the specified file or directory's finder information.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpSetIsInvisible, ClearIsInvisible, FSpClearIsInvisible
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetIsInvisible(const FSSpec *spec);
+/*     ¦ Set the invisible Finder Flag bit.
+       The FSpSetIsInvisible function sets the invisible bit in the fdFlags
+       word of the specified file or directory's finder information.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetIsInvisible, ClearIsInvisible, FSpClearIsInvisible
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   ClearIsInvisible(short vRefNum,
+                                                                long dirID,
+                                                                ConstStr255Param name);
+/*     ¦ Clear the invisible Finder Flag bit.
+       The ClearIsInvisible function clears the invisible bit in the fdFlags
+       word of the specified file or directory's finder information.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetIsInvisible, FSpSetIsInvisible, FSpClearIsInvisible
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpClearIsInvisible(const FSSpec *spec);
+/*     ¦ Clear the invisible Finder Flag bit.
+       The FSpClearIsInvisible function clears the invisible bit in the fdFlags
+       word of the specified file or directory's finder information.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetIsInvisible, FSpSetIsInvisible, ClearIsInvisible
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   SetNameLocked(short vRefNum,
+                                                         long dirID,
+                                                         ConstStr255Param name);
+/*     ¦ Set the nameLocked Finder Flag bit.
+       The SetNameLocked function sets the nameLocked bit in the fdFlags word
+       of the specified file or directory's finder information.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpSetNameLocked, ClearNameLocked, FSpClearNameLocked
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetNameLocked(const FSSpec *spec);
+/*     ¦ Set the nameLocked Finder Flag bit.
+       The FSpSetNameLocked function sets the nameLocked bit in the fdFlags word
+       of the specified file or directory's finder information.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetNameLocked, ClearNameLocked, FSpClearNameLocked
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   ClearNameLocked(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name);
+/*     ¦ Clear the nameLocked Finder Flag bit.
+       The ClearNameLocked function clears the nameLocked bit in the fdFlags
+       word of the specified file or directory's finder information.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetNameLocked, FSpSetNameLocked, FSpClearNameLocked
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpClearNameLocked(const FSSpec *spec);
+/*     ¦ Clear the nameLocked Finder Flag bit.
+       The FSpClearNameLocked function clears the nameLocked bit in the fdFlags
+       word of the specified file or directory's finder information.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetNameLocked, FSpSetNameLocked, ClearNameLocked
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   SetIsStationery(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name);
+/*     ¦ Set the isStationery Finder Flag bit.
+       The SetIsStationery function sets the isStationery bit in the
+       fdFlags word of the specified file or directory's finder information.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpSetIsStationery, ClearIsStationery, FSpClearIsStationery
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetIsStationery(const FSSpec *spec);
+/*     ¦ Set the isStationery Finder Flag bit.
+       The FSpSetIsStationery function sets the isStationery bit in the
+       fdFlags word of the specified file or directory's finder information.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetIsStationery, ClearIsStationery, FSpClearIsStationery
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   ClearIsStationery(short vRefNum,
+                                                                 long dirID,
+                                                                 ConstStr255Param name);
+/*     ¦ Clear the isStationery Finder Flag bit.
+       The ClearIsStationery function clears the isStationery bit in the
+       fdFlags word of the specified file or directory's finder information.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetIsStationery, FSpSetIsStationery, FSpClearIsStationery
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpClearIsStationery(const FSSpec *spec);
+/*     ¦ Clear the isStationery Finder Flag bit.
+       The FSpClearIsStationery function clears the isStationery bit in the
+       fdFlags word of the specified file or directory's finder information.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetIsStationery, FSpSetIsStationery, ClearIsStationery
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   SetHasCustomIcon(short vRefNum,
+                                                                long dirID,
+                                                                ConstStr255Param name);
+/*     ¦ Set the hasCustomIcon Finder Flag bit.
+       The SetHasCustomIcon function sets the hasCustomIcon bit in the
+       fdFlags word of the specified file or directory's finder information.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpSetHasCustomIcon, ClearHasCustomIcon, FSpClearHasCustomIcon
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetHasCustomIcon(const FSSpec *spec);
+/*     ¦ Set the hasCustomIcon Finder Flag bit.
+       The FSpSetHasCustomIcon function sets the hasCustomIcon bit in the
+       fdFlags word of the specified file or directory's finder information.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetHasCustomIcon, ClearHasCustomIcon, FSpClearHasCustomIcon
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   ClearHasCustomIcon(short vRefNum,
+                                                                  long dirID,
+                                                                  ConstStr255Param name);
+/*     ¦ Clear the hasCustomIcon Finder Flag bit.
+       The ClearHasCustomIcon function clears the hasCustomIcon bit in the
+       fdFlags word of the specified file or directory's finder information.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetHasCustomIcon, FSpSetHasCustomIcon, FSpClearHasCustomIcon
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpClearHasCustomIcon(const FSSpec *spec);
+/*     ¦ Clear the hasCustomIcon Finder Flag bit.
+       The FSpClearHasCustomIcon function clears the hasCustomIcon bit in the
+       fdFlags word of the specified file or directory's finder information.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       SetHasCustomIcon, FSpSetHasCustomIcon, ClearHasCustomIcon
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   ClearHasBeenInited(short vRefNum,
+                                                                  long dirID,
+                                                                  ConstStr255Param name);
+/*     ¦ Clear the hasBeenInited Finder Flag bit.
+       The ClearHasBeenInited function clears the hasBeenInited bit in the
+       fdFlags word of the specified file or directory's finder information.
+       
+       vRefNum input:  Volume specification.
+       dirID   input:  Directory ID.
+       name    input:  Pointer to object name, or nil when dirID specifies
+                                       a directory that's the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpClearHasBeenInited
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpClearHasBeenInited(const FSSpec *spec);
+/*     ¦ Clear the hasBeenInited Finder Flag bit.
+       The FSpClearHasBeenInited function clears the hasBeenInited bit in the
+       fdFlags word of the specified file or directory's finder information.
+       
+       spec    input:  An FSSpec record specifying the object.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       ClearHasBeenInited
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   CopyFileMgrAttributes(short srcVRefNum,
+                                                                         long srcDirID,
+                                                                         ConstStr255Param srcName,
+                                                                         short dstVRefNum,
+                                                                         long dstDirID,
+                                                                         ConstStr255Param dstName,
+                                                                         Boolean copyLockBit);
+/*     ¦ Copy all File Manager attributes from the source to the destination.
+       The CopyFileMgrAttributes function copies all File Manager attributes
+       from the source file or directory to the destination file or directory.
+       If copyLockBit is true, then set the locked state of the destination
+       to match the source.
+
+       srcVRefNum      input:  Source volume specification.
+       srcDirID        input:  Source directory ID.
+       srcName         input:  Pointer to source object name, or nil when
+                                               srcDirID specifies a directory that's the object.
+       dstVRefNum      input:  Destination volume specification.
+       dstDirID        input:  Destination directory ID.
+       dstName         input:  Pointer to destination object name, or nil when
+                                               dstDirID specifies a directory that's the object.
+       copyLockBit     input:  If true, set the locked state of the destination
+                                               to match the source.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       FSpCopyFileMgrAttributes
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCopyFileMgrAttributes(const FSSpec *srcSpec,
+                                                                                const FSSpec *dstSpec,
+                                                                                Boolean copyLockBit);
+/*     ¦ Copy all File Manager attributes from the source to the destination.
+       The FSpCopyFileMgrAttributes function copies all File Manager attributes
+       from the source file or directory to the destination file or directory.
+       If copyLockBit is true, then set the locked state of the destination
+       to match the source.
+
+       srcSpec         input:  An FSSpec record specifying the source object.
+       dstSpec         input:  An FSSpec record specifying the destination object.
+       copyLockBit     input:  If true, set the locked state of the destination
+                                               to match the source.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             No default volume
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+       
+       __________
+       
+       See also:       CopyFileMgrAttributes
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HOpenAware(short vRefNum,
+                                                  long dirID,
+                                                  ConstStr255Param fileName,
+                                                  short denyModes,
+                                                  short *refNum);
+/*     ¦ Open the data fork of a file using deny mode permissions.
+       The HOpenAware function opens the data fork of a file using deny mode
+       permissions instead the normal File Manager permissions.  If OpenDeny
+       is not available, then HOpenAware translates the deny modes to the
+       closest File Manager permissions and tries to open the file with
+       OpenDF first, and then Open if OpenDF isn't available. By using
+       HOpenAware with deny mode permissions, a program can be "AppleShare
+       aware" and fall back on the standard File Manager open calls
+       automatically.
+
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       fileName        input:  The name of the file.
+       denyModes       input:  The deny modes access under which to open the file.
+       refNum          output: The file reference number of the opened file.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               tmfoErr                         -42             Too many files open
+               fnfErr                          -43             File not found
+               wPrErr                          -44             Volume locked by hardware
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               opWrErr                         -49             File already open for writing
+               paramErr                        -50             No default volume
+               permErr                         -54             File is already open and cannot be opened using specified deny modes
+               afpAccessDenied         -5000   User does not have the correct access to the file
+               afpDenyConflict         -5006   Requested access permission not possible
+       
+       __________
+       
+       See also:       FSpOpenAware, HOpenRFAware, FSpOpenRFAware
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpOpenAware(const FSSpec *spec,
+                                                        short denyModes,
+                                                        short *refNum);
+/*     ¦ Open the data fork of a file using deny mode permissions.
+       The FSpOpenAware function opens the data fork of a file using deny mode
+       permissions instead the normal File Manager permissions.  If OpenDeny
+       is not available, then FSpOpenAware translates the deny modes to the
+       closest File Manager permissions and tries to open the file with
+       OpenDF first, and then Open if OpenDF isn't available. By using
+       FSpOpenAware with deny mode permissions, a program can be "AppleShare
+       aware" and fall back on the standard File Manager open calls
+       automatically.
+
+       spec            input:  An FSSpec record specifying the file.
+       denyModes       input:  The deny modes access under which to open the file.
+       refNum          output: The file reference number of the opened file.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               tmfoErr                         -42             Too many files open
+               fnfErr                          -43             File not found
+               wPrErr                          -44             Volume locked by hardware
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               opWrErr                         -49             File already open for writing
+               paramErr                        -50             No default volume
+               permErr                         -54             File is already open and cannot be opened using specified deny modes
+               afpAccessDenied         -5000   User does not have the correct access to the file
+               afpDenyConflict         -5006   Requested access permission not possible
+       
+       __________
+       
+       See also:       HOpenAware, HOpenRFAware, FSpOpenRFAware
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HOpenRFAware(short vRefNum,
+                                                        long dirID,
+                                                        ConstStr255Param fileName,
+                                                        short denyModes,
+                                                        short *refNum);
+/*     ¦ Open the resource fork of a file using deny mode permissions.
+       The HOpenRFAware function opens the resource fork of a file using deny
+       mode permissions instead the normal File Manager permissions.  If
+       OpenRFDeny is not available, then HOpenRFAware translates the deny
+       modes to the closest File Manager permissions and tries to open the
+       file with OpenRF. By using HOpenRFAware with deny mode permissions,
+       a program can be "AppleShare aware" and fall back on the standard
+       File Manager open calls automatically.
+
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       fileName        input:  The name of the file.
+       denyModes       input:  The deny modes access under which to open the file.
+       refNum          output: The file reference number of the opened file.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               tmfoErr                         -42             Too many files open
+               fnfErr                          -43             File not found
+               wPrErr                          -44             Volume locked by hardware
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               opWrErr                         -49             File already open for writing
+               paramErr                        -50             No default volume
+               permErr                         -54             File is already open and cannot be opened using specified deny modes
+               afpAccessDenied         -5000   User does not have the correct access to the file
+               afpDenyConflict         -5006   Requested access permission not possible
+       
+       __________
+       
+       See also:       HOpenAware, FSpOpenAware, FSpOpenRFAware
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpOpenRFAware(const FSSpec *spec,
+                                                          short denyModes,
+                                                          short *refNum);
+/*     ¦ Open the resource fork of a file using deny mode permissions.
+       The FSpOpenRFAware function opens the resource fork of a file using deny
+       mode permissions instead the normal File Manager permissions.  If
+       OpenRFDeny is not available, then FSpOpenRFAware translates the deny
+       modes to the closest File Manager permissions and tries to open the
+       file with OpenRF. By using FSpOpenRFAware with deny mode permissions,
+       a program can be "AppleShare aware" and fall back on the standard
+       File Manager open calls automatically.
+
+       spec            input:  An FSSpec record specifying the file.
+       denyModes       input:  The deny modes access under which to open the file.
+       refNum          output: The file reference number of the opened file.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             No such volume
+               tmfoErr                         -42             Too many files open
+               fnfErr                          -43             File not found
+               wPrErr                          -44             Volume locked by hardware
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               opWrErr                         -49             File already open for writing
+               paramErr                        -50             No default volume
+               permErr                         -54             File is already open and cannot be opened using specified deny modes
+               afpAccessDenied         -5000   User does not have the correct access to the file
+               afpDenyConflict         -5006   Requested access permission not possible
+       
+       __________
+       
+       See also:       HOpenAware, FSpOpenAware, HOpenRFAware
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSReadNoCache(short refNum,
+                                                         long *count,
+                                                         void *buffPtr);
+/*     ¦ Read any number of bytes from an open file requesting no caching.
+       The FSReadNoCache function reads any number of bytes from an open file
+       while asking the file system to bypass its cache mechanism.
+       
+       refNum  input:  The file reference number of an open file.
+       count   input:  The number of bytes to read.
+                       output: The number of bytes actually read.
+       buffPtr input:  A pointer to the data buffer into which the bytes are
+                                       to be read.
+       
+       Result Codes
+               noErr                           0               No error
+               readErr                         Ð19             Driver does not respond to read requests
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies a
+                                                                       nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+               ioErr                           Ð36             Data does not match in read-verify mode
+               fnOpnErr                        -38             File not open
+               rfNumErr                        -51             Bad reference number
+               afpAccessDenied         -5000   User does not have the correct access to
+                                                                       the file
+
+       __________
+       
+       See also:       FSWriteNoCache
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSWriteNoCache(short refNum,
+                                                          long *count,
+                                                          const void *buffPtr);
+/*     ¦ Write any number of bytes to an open file requesting no caching.
+       The FSReadNoCache function writes any number of bytes to an open file
+       while asking the file system to bypass its cache mechanism.
+       
+       refNum  input:  The file reference number of an open file.
+       count   input:  The number of bytes to write to the file.
+                       output: The number of bytes actually written.
+       buffPtr input:  A pointer to the data buffer from which the bytes are
+                                       to be written.
+       
+       Result Codes
+               noErr                           0               No error
+               writErr                         Ð20             Driver does not respond to write requests
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies a
+                                                                       nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+               dskFulErr                       -34             Disk full       
+               ioErr                           Ð36             Data does not match in read-verify mode
+               fnOpnErr                        -38             File not open
+               wPrErr                          -44             Hardware volume lock    
+               fLckdErr                        -45             File is locked  
+               vLckdErr                        -46             Software volume lock    
+               rfNumErr                        -51             Bad reference number
+               wrPermErr                       -61             Read/write permission doesnÕt
+                                                                       allow writing   
+               afpAccessDenied         -5000   User does not have the correct access to
+                                                                       the file
+
+       __________
+       
+       See also:       FSReadNoCache
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSWriteVerify(short refNum,
+                                                         long *count,
+                                                         const void *buffPtr);
+/*     ¦ Write any number of bytes to an open file and then verify the data was written.
+       The FSWriteVerify function writes any number of bytes to an open file
+       and then verifies that the data was actually written to the device.
+       
+       refNum  input:  The file reference number of an open file.
+       count   input:  The number of bytes to write to the file.
+                       output: The number of bytes actually written and verified.
+       buffPtr input:  A pointer to the data buffer from which the bytes are
+                                       to be written.
+       
+       Result Codes
+               noErr                           0               No error
+               readErr                         Ð19             Driver does not respond to read requests
+               writErr                         Ð20             Driver does not respond to write requests
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies a
+                                                                       nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+               dskFulErr                       -34             Disk full       
+               ioErr                           Ð36             Data does not match in read-verify mode
+               fnOpnErr                        -38             File not open
+               eofErr                          -39             Logical end-of-file reached
+               posErr                          -40             Attempt to position mark before start
+                                                                       of file
+               wPrErr                          -44             Hardware volume lock    
+               fLckdErr                        -45             File is locked  
+               vLckdErr                        -46             Software volume lock    
+               rfNumErr                        -51             Bad reference number
+               gfpErr                          -52             Error during GetFPos
+               wrPermErr                       -61             Read/write permission doesnÕt
+                                                                       allow writing   
+               memFullErr                      -108    Not enough room in heap zone to allocate
+                                                                       verify buffer
+               afpAccessDenied         -5000   User does not have the correct access to
+                                                                       the file
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   CopyFork(short srcRefNum,
+                                                short dstRefNum,
+                                                void *copyBufferPtr,
+                                                long copyBufferSize);
+/*     ¦ Copy all data from the source fork to the destination fork of open file forks.
+       The CopyFork function copies all data from the source fork to the
+       destination fork of open file forks and makes sure the destination EOF
+       is equal to the source EOF.
+       
+       srcRefNum               input:  The source file reference number.
+       dstRefNum               input:  The destination file reference number.
+       copyBufferPtr   input:  Pointer to buffer to use during copy. The
+                                                       buffer should be at least 512-bytes minimum.
+                                                       The larger the buffer, the faster the copy.
+       copyBufferSize  input:  The size of the copy buffer.
+       
+       Result Codes
+               noErr                           0               No error
+               readErr                         Ð19             Driver does not respond to read requests
+               writErr                         Ð20             Driver does not respond to write requests
+               badUnitErr                      Ð21             Driver reference number does not
+                                                                       match unit table
+               unitEmptyErr            Ð22             Driver reference number specifies a
+                                                                       nil handle in unit table
+               abortErr                        Ð27             Request aborted by KillIO
+               notOpenErr                      Ð28             Driver not open
+               dskFulErr                       -34             Disk full       
+               ioErr                           Ð36             Data does not match in read-verify mode
+               fnOpnErr                        -38             File not open
+               wPrErr                          -44             Hardware volume lock    
+               fLckdErr                        -45             File is locked  
+               vLckdErr                        -46             Software volume lock    
+               rfNumErr                        -51             Bad reference number
+               wrPermErr                       -61             Read/write permission doesnÕt
+                                                                       allow writing   
+               afpAccessDenied         -5000   User does not have the correct access to
+                                                                       the file
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetFileLocation(short refNum,
+                                                               short *vRefNum,
+                                                               long *dirID,
+                                                               StringPtr fileName);
+/*     ¦ Get the location of an open file.
+       The GetFileLocation function gets the location (volume reference number,
+       directory ID, and fileName) of an open file.
+
+       refNum          input:  The file reference number of an open file.
+       vRefNum         output: The volume reference number.
+       dirID           output: The parent directory ID.
+       fileName        input:  Points to a buffer (minimum Str63) where the
+                                               filename is to be returned or must be nil.
+                               output: The filename.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Specified volume doesnÕt exist
+               fnOpnErr                        -38             File not open
+               rfNumErr                        -51             Reference number specifies nonexistent
+                                                                       access path
+       
+       __________
+       
+       See also:       FSpGetFileLocation
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetFileLocation(short refNum,
+                                                                  FSSpec *spec);
+/*     ¦ Get the location of an open file in an FSSpec record.
+       The FSpGetFileLocation function gets the location of an open file in
+       an FSSpec record.
+
+       refNum          input:  The file reference number of an open file.
+       spec            output: FSSpec record containing the file name and location.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Specified volume doesnÕt exist
+               fnOpnErr                        -38             File not open
+               rfNumErr                        -51             Reference number specifies nonexistent
+                                                                       access path
+       
+       __________
+       
+       See also:       GetFileLocation
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   CopyDirectoryAccess(short srcVRefNum,
+                                                                       long srcDirID,
+                                                                       ConstStr255Param srcName,
+                                                                       short dstVRefNum,
+                                                                       long dstDirID,
+                                                                       ConstStr255Param dstName);
+/*     ¦ Copy the AFP directory access privileges.
+       The CopyDirectoryAccess function copies the AFP directory access
+       privileges from one directory to another. Both directories must be on
+       the same file server, but not necessarily on the same server volume.
+       
+       srcVRefNum      input:  Source volume specification.
+       srcDirID        input:  Source directory ID.
+       srcName         input:  Pointer to source directory name, or nil when
+                                               srcDirID specifies the directory.
+       dstVRefNum      input:  Destination volume specification.
+       dstDirID        input:  Destination directory ID.
+       dstName         input:  Pointer to destination directory name, or nil when
+                                               dstDirID specifies the directory.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               fnfErr                          -43             Directory not found
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             Volume doesn't support this function
+               afpAccessDenied         -5000   User does not have the correct access
+                                                                       to the directory
+               afpObjectTypeErr        -5025   Object is a file, not a directory
+       
+       __________
+       
+       See also:       FSpCopyDirectoryAccess
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCopyDirectoryAccess(const FSSpec *srcSpec,
+                                                                          const FSSpec *dstSpec);
+/*     ¦ Copy the AFP directory access privileges.
+       The FSpCopyDirectoryAccess function copies the AFP directory access
+       privileges from one directory to another. Both directories must be on
+       the same file server, but not necessarily on the same server volume.
+
+       srcSpec         input:  An FSSpec record specifying the source directory.
+       dstSpec         input:  An FSSpec record specifying the destination directory.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               fnfErr                          -43             Directory not found
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             Volume doesn't support this function
+               afpAccessDenied         -5000   User does not have the correct access
+                                                                       to the directory
+               afpObjectTypeErr        -5025   Object is a file, not a directory
+       
+       __________
+       
+       See also:       CopyDirectoryAccess
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HMoveRenameCompat(short vRefNum,
+                                                                 long srcDirID,
+                                                                 ConstStr255Param srcName,
+                                                                 long dstDirID,
+                                                                 ConstStr255Param dstpathName,
+                                                                 ConstStr255Param copyName);
+/*     ¦ Move a file or directory and optionally rename it.
+       The HMoveRenameCompat function moves a file or directory and optionally
+       renames it.  The source and destination locations must be on the same
+       volume. This routine works even if the volume doesn't support MoveRename.
+       
+       vRefNum         input:  Volume specification.
+       srcDirID        input:  Source directory ID.
+       srcName         input:  The source object name.
+       dstDirID        input:  Destination directory ID.
+       dstName         input:  Pointer to destination directory name, or
+                                               nil when dstDirID specifies a directory.
+       copyName        input:  Points to the new name if the object is to be
+                                               renamed or nil if the object isn't to be renamed.
+       
+       Result Codes
+               noErr                           0               No error
+               dirFulErr                       -33             File directory full
+               dskFulErr                       -34             Disk is full
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename or attempt to move into
+                                                                       a file
+               fnfErr                          -43             Source file or directory not found
+               wPrErr                          -44             Hardware volume lock
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Destination volume is read-only
+               fBsyErr                         -47             File busy, directory not empty, or
+                                                                       working directory control block open
+               dupFNErr                        -48             Destination already exists
+               paramErr                        -50             Volume doesn't support this function,
+                                                                       no default volume, or source and
+               volOfflinErr            -53             Volume is offline
+               fsRnErr                         -59             Problem during rename
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               badMovErr                       -122    Attempted to move directory into
+                                                                       offspring
+               wrgVolTypErr            -123    Not an HFS volume (it's a MFS volume)
+               notAFileErr                     -1302   The pathname is nil, the pathname
+                                                                       is empty, or the pathname cannot refer
+                                                                       to a filename
+               diffVolErr                      -1303   Files on different volumes
+               afpAccessDenied         -5000   The user does not have the right to
+                                                                       move the file  or directory
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+               afpSameObjectErr        -5038   Source and destination files are the same
+       
+       __________
+       
+       See also:       FSpMoveRenameCompat
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpMoveRenameCompat(const FSSpec *srcSpec,
+                                                                       const FSSpec *dstSpec,
+                                                                       ConstStr255Param copyName);
+/*     ¦ Move a file or directory and optionally rename it.
+       The FSpMoveRenameCompat function moves a file or directory and optionally
+       renames it.  The source and destination locations must be on the same
+       volume. This routine works even if the volume doesn't support MoveRename.
+       
+       srcSpec         input:  An FSSpec record specifying the source object.
+       dstSpec         input:  An FSSpec record specifying the destination
+                                               directory.
+       copyName        input:  Points to the new name if the object is to be
+                                               renamed or nil if the object isn't to be renamed.
+       
+       Result Codes
+               noErr                           0               No error
+               dirFulErr                       -33             File directory full
+               dskFulErr                       -34             Disk is full
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename or attempt to move into
+                                                                       a file
+               fnfErr                          -43             Source file or directory not found
+               wPrErr                          -44             Hardware volume lock
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Destination volume is read-only
+               fBsyErr                         -47             File busy, directory not empty, or
+                                                                       working directory control block open
+               dupFNErr                        -48             Destination already exists
+               paramErr                        -50             Volume doesn't support this function,
+                                                                       no default volume, or source and
+               volOfflinErr            -53             Volume is offline
+               fsRnErr                         -59             Problem during rename
+               dirNFErr                        -120    Directory not found or incomplete pathname
+               badMovErr                       -122    Attempted to move directory into
+                                                                       offspring
+               wrgVolTypErr            -123    Not an HFS volume (it's a MFS volume)
+               notAFileErr                     -1302   The pathname is nil, the pathname
+                                                                       is empty, or the pathname cannot refer
+                                                                       to a filename
+               diffVolErr                      -1303   Files on different volumes
+               afpAccessDenied         -5000   The user does not have the right to
+                                                                       move the file  or directory
+               afpObjectTypeErr        -5025   Directory not found or incomplete pathname
+               afpSameObjectErr        -5038   Source and destination files are the same
+       
+       __________
+       
+       See also:       HMoveRenameCompat
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   BuildAFPVolMountInfo(short flags,
+                                                                        char nbpInterval,
+                                                                        char nbpCount,
+                                                                        short uamType,
+                                                                        Str32 zoneName,
+                                                                        Str31 serverName,
+                                                                        Str27 volName,
+                                                                        Str31 userName,
+                                                                        Str8 userPassword,
+                                                                        Str8 volPassword,
+                                                                        AFPVolMountInfoPtr *afpInfoPtr);
+/*     ¦ Allocate and initializes the fields of an AFPVolMountInfo record.
+       The BuildAFPVolMountInfo function allocates and initializes the fields
+       of an AFPVolMountInfo record before using that record to call
+       the VolumeMount function.
+       
+       flags                   input:  The AFP mounting flags. 0 = normal mount;
+                                                       set bit 0 to inhibit greeting messages.
+       nbpInterval             input:  The interval used for VolumeMount's
+                                                       NBP Lookup call. 7 is a good choice.
+       nbpCount                input:  The retry count used for VolumeMount's
+                                                       NBP Lookup call. 5 is a good choice.
+       uamType                 input:  The user authentication method to use.
+       zoneName                input:  The AppleTalk zone name of the server.
+       serverName              input:  The AFP server name.
+       volName                 input:  The AFP volume name.
+       userName                input:  The user name (zero length Pascal string for
+                                                       guest).
+       userPassWord    input:  The user password (zero length Pascal string
+                                                       if no user password)
+       volPassWord             input:  The volume password (zero length Pascal string
+                                                       if no volume password)
+       afpInfoPtr              output: A pointer to the newly created and initialized
+                                                       AFPVolMountInfo record. If the function fails to
+                                                       create an AFPVolMountInfo record, it sets
+                                                       afpInfoPtr to NULL and the function result is
+                                                       memFullErr. Your program is responsible
+                                                       for disposing of this pointer when it is finished
+                                                       with it.
+       
+       Result Codes
+               noErr                           0               No error
+               memFullErr                      -108    memory full error
+       
+       __________
+       
+       Also see:       GetVolMountInfoSize, GetVolMountInfo, VolumeMount,
+                               RetrieveAFPVolMountInfo, BuildAFPXVolMountInfo,
+                               RetrieveAFPXVolMountInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   RetrieveAFPVolMountInfo(AFPVolMountInfoPtr afpInfoPtr,
+                                                                               short *flags,
+                                                                               short *uamType,
+                                                                               StringPtr zoneName,
+                                                                               StringPtr serverName,
+                                                                               StringPtr volName,
+                                                                               StringPtr userName);
+/*     ¦ Retrieve the AFP mounting information from an AFPVolMountInfo record.
+       The RetrieveAFPVolMountInfo function retrieves the AFP mounting
+       information returned in an AFPVolMountInfo record by the
+       GetVolMountInfo function.
+       
+       afpInfoPtr              input:  Pointer to AFPVolMountInfo record that contains
+                                                       the AFP mounting information.
+       flags                   output: The AFP mounting flags.
+       uamType                 output: The user authentication method used.
+       zoneName                output: The AppleTalk zone name of the server.
+       serverName              output: The AFP server name.
+       volName                 output: The AFP volume name.
+       userName                output: The user name (zero length Pascal string for
+                                                       guest).
+       
+       Result Codes
+               noErr                           0               No error
+               paramErr                        -50             media field in AFP mounting information
+                                                                       was not AppleShareMediaType
+       
+       __________
+       
+       Also see:       GetVolMountInfoSize, GetVolMountInfo, VolumeMount,
+                               BuildAFPVolMountInfo, BuildAFPXVolMountInfo,
+                               RetrieveAFPXVolMountInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   BuildAFPXVolMountInfo(short flags,
+                                                                         char nbpInterval,
+                                                                         char nbpCount,
+                                                                         short uamType,
+                                                                         Str32 zoneName,
+                                                                         Str31 serverName,
+                                                                         Str27 volName,
+                                                                         Str31 userName,
+                                                                         Str8 userPassword,
+                                                                         Str8 volPassword,
+                                                                         Str32 uamName,
+                                                                         unsigned long alternateAddressLength,
+                                                                         void *alternateAddress,
+                                                                         AFPXVolMountInfoPtr *afpXInfoPtr);
+/*     ¦ Allocate and initializes the fields of an AFPXVolMountInfo record.
+       The BuildAFPXVolMountInfo function allocates and initializes the fields
+       of an AFPXVolMountInfo record before using that record to call
+       the VolumeMount function.
+       
+       flags                                   input:  The AFP mounting flags.
+       nbpInterval                             input:  The interval used for VolumeMount's
+                                                                       NBP Lookup call. 7 is a good choice.
+       nbpCount                                input:  The retry count used for VolumeMount's
+                                                                       NBP Lookup call. 5 is a good choice.
+       uamType                                 input:  The user authentication method to use.
+       zoneName                                input:  The AppleTalk zone name of the server.
+       serverName                              input:  The AFP server name.
+       volName                                 input:  The AFP volume name.
+       userName                                input:  The user name (zero length Pascal string
+                                                                       for guest).
+       userPassWord                    input:  The user password (zero length Pascal
+                                                                       string if no user password)
+       volPassWord                             input:  The volume password (zero length Pascal
+                                                                       string if no volume password)
+       uamName                                 input:  The User Authentication Method name.
+       alternateAddressLength  input:  Length of alternateAddress data.
+       alternateAddress                input   The AFPAlternateAddress (variable length)
+       afpXInfoPtr                             output: A pointer to the newly created and
+                                                                       initialized AFPVolMountInfo record.
+                                                                       If the function fails to create an
+                                                                       AFPVolMountInfo record, it sets
+                                                                       afpInfoPtr to NULL and the function
+                                                                       result is memFullErr. Your program is
+                                                                       responsible for disposing of this pointer
+                                                                       when it is finished with it.
+       
+       Result Codes
+               noErr                           0               No error
+               memFullErr                      -108    memory full error
+       
+       __________
+       
+       Also see:       GetVolMountInfoSize, GetVolMountInfo, VolumeMount,
+                               BuildAFPVolMountInfo, RetrieveAFPVolMountInfo,
+                               RetrieveAFPXVolMountInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   RetrieveAFPXVolMountInfo(AFPXVolMountInfoPtr afpXInfoPtr,
+                                                                                short *flags,
+                                                                                short *uamType,
+                                                                                StringPtr zoneName,
+                                                                                StringPtr serverName,
+                                                                                StringPtr volName,
+                                                                                StringPtr userName,
+                                                                                StringPtr uamName,
+                                                                                unsigned long *alternateAddressLength,
+                                                                                AFPAlternateAddress **alternateAddress);
+/*     ¦ Retrieve the AFP mounting information from an AFPXVolMountInfo record.
+       The RetrieveAFPXVolMountInfo function retrieves the AFP mounting
+       information returned in an AFPXVolMountInfo record by the
+       GetVolMountInfo function.
+       
+       afpXInfoPtr                             input:  Pointer to AFPXVolMountInfo record that
+                                                                       contains the AFP mounting information.
+       flags                                   output: The AFP mounting flags.
+       uamType                                 output: The user authentication method used.
+       zoneName                                output: The AppleTalk zone name of the server.
+       serverName                              output: The AFP server name.
+       volName                                 output: The AFP volume name.
+       userName                                output: The user name (zero length Pascal
+                                                                       string for guest).
+       uamName                                 output: The User Authentication Method name.
+       alternateAddressLength  output: Length of alternateAddress data returned.
+       alternateAddress:               output: A pointer to the newly created and
+                                                                       AFPAlternateAddress record (a variable
+                                                                       length record). If the function fails to
+                                                                       create an AFPAlternateAddress record,
+                                                                       it sets alternateAddress to NULL and the
+                                                                       function result is memFullErr. Your
+                                                                       program is responsible for disposing of
+                                                                       this pointer when it is finished with it.
+       
+       Result Codes
+               noErr                           0               No error
+               paramErr                        -50             media field in AFP mounting information
+                                                                       was not AppleShareMediaType
+               memFullErr                      -108    memory full error
+       
+       __________
+       
+       Also see:       GetVolMountInfoSize, GetVolMountInfo, VolumeMount,
+                               BuildAFPVolMountInfo, RetrieveAFXVolMountInfo,
+                               BuildAFPXVolMountInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetUGEntries(short objType,
+                                                        UGEntryPtr entries,
+                                                        long reqEntryCount,
+                                                        long *actEntryCount,
+                                                        long *objID);
+/*     ¦ Retrieve a list of user or group entries from the local file server.
+       The GetUGEntries functions retrieves a list of user or group entries
+       from the local file server.
+
+       objType                 input:  The object type: -1 = group; 0 = user
+       UGEntries               input:  Pointer to array of UGEntry records where the list
+                                                       is returned.
+       reqEntryCount   input:  The number of elements in the UGEntries array.
+       actEntryCount   output: The number of entries returned.
+       objID                   input:  The current index position. Set to 0 to start with
+                                                       the first entry.
+                                       output: The index position to get the next entry. Pass this
+                                                       value the next time you call GetUGEntries to start
+                                                       where you left off.
+       
+       Result Codes
+               noErr                           0               No error        
+               fnfErr                          -43             No more users or groups 
+               paramErr                        -50             Function not supported; or, ioObjID is
+                                                                       negative        
+
+       __________
+       
+       Also see:       GetUGEntry
+*/
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "OptimEnd.h"
+
+#endif /* __MOREFILESEXTRAS__ */
diff --git a/src/mac/morefile/MoreFile.cpp b/src/mac/morefile/MoreFile.cpp
new file mode 100644 (file)
index 0000000..1679568
--- /dev/null
@@ -0,0 +1,628 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     The long lost high-level and FSSpec File Manager functions.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           MoreFiles.c
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#include <Types.h>
+#include <Errors.h>
+#include <Files.h>
+
+#define        __COMPILINGMOREFILES
+
+#include "MoreFile.h"
+#include "MoreExtr.h"
+
+/*****************************************************************************/
+
+pascal OSErr   HGetVolParms(ConstStr255Param volName,
+                                                        short vRefNum,
+                                                        GetVolParmsInfoBuffer *volParmsInfo,
+                                                        long *infoSize)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       pb.ioParam.ioNamePtr = (StringPtr)volName;
+       pb.ioParam.ioVRefNum = vRefNum;
+       pb.ioParam.ioBuffer = (Ptr)volParmsInfo;
+       pb.ioParam.ioReqCount = *infoSize;
+       error = PBHGetVolParmsSync(&pb);
+       if ( error == noErr )
+       {
+               *infoSize = pb.ioParam.ioActCount;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HCreateMinimum(short vRefNum,
+                                                          long dirID,
+                                                          ConstStr255Param fileName)
+{
+       HParamBlockRec pb;
+
+       pb.fileParam.ioNamePtr = (StringPtr)fileName;
+       pb.fileParam.ioVRefNum = vRefNum;
+       pb.ioParam.ioVersNum = 0;
+       pb.fileParam.ioDirID = dirID;
+       return ( PBHCreateSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCreateMinimum(const FSSpec *spec)
+{
+       return ( HCreateMinimum(spec->vRefNum, spec->parID, spec->name) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   ExchangeFiles(short vRefNum,
+                                                         long srcDirID,
+                                                         ConstStr255Param srcName,
+                                                         long dstDirID,
+                                                         ConstStr255Param dstName)
+{
+       HParamBlockRec pb;
+
+       pb.fidParam.ioVRefNum = vRefNum;
+       pb.fidParam.ioSrcDirID = srcDirID;
+       pb.fidParam.ioNamePtr = (StringPtr)srcName;
+       pb.fidParam.ioDestDirID = dstDirID;
+       pb.fidParam.ioDestNamePtr = (StringPtr)dstName;
+       return ( PBExchangeFilesSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   ResolveFileIDRef(ConstStr255Param volName,
+                                                                short vRefNum,
+                                                                long fileID,
+                                                                long *parID,
+                                                                StringPtr fileName)
+{
+       HParamBlockRec pb;
+       OSErr error;
+       Str255 tempStr;
+       
+       tempStr[0] = 0;
+       if ( volName != NULL )
+       {
+               BlockMoveData(volName, tempStr, volName[0] + 1);
+       }
+       pb.fidParam.ioNamePtr = (StringPtr)tempStr;
+       pb.fidParam.ioVRefNum = vRefNum;
+       pb.fidParam.ioFileID = fileID;
+       error = PBResolveFileIDRefSync(&pb);
+       if ( error == noErr )
+       {
+               *parID = pb.fidParam.ioSrcDirID;
+               if ( fileName != NULL )
+               {
+                       BlockMoveData(tempStr, fileName, tempStr[0] + 1);
+               }
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpResolveFileIDRef(ConstStr255Param volName,
+                                                                       short vRefNum,
+                                                                       long fileID,
+                                                                       FSSpec *spec)
+{
+       OSErr   error;
+       
+       error = DetermineVRefNum(volName, vRefNum, &(spec->vRefNum));
+       if ( error == noErr )
+       {
+               error = ResolveFileIDRef(volName, vRefNum, fileID, &(spec->parID), spec->name);
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   CreateFileIDRef(short vRefNum,
+                                                               long parID,
+                                                               ConstStr255Param fileName,
+                                                               long *fileID)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       pb.fidParam.ioNamePtr = (StringPtr)fileName;
+       pb.fidParam.ioVRefNum = vRefNum;
+       pb.fidParam.ioSrcDirID = parID;
+       error = PBCreateFileIDRefSync(&pb);
+       if ( error == noErr )
+       {
+               *fileID = pb.fidParam.ioFileID;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCreateFileIDRef(const FSSpec *spec,
+                                                                  long *fileID)
+{
+       return ( CreateFileIDRef(spec->vRefNum, spec->parID, spec->name, fileID) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   DeleteFileIDRef(ConstStr255Param volName,
+                                                               short vRefNum,
+                                                               long fileID)
+{
+       HParamBlockRec pb;
+
+       pb.fidParam.ioNamePtr = (StringPtr)volName;
+       pb.fidParam.ioVRefNum = vRefNum;
+       pb.fidParam.ioFileID = fileID;
+       return ( PBDeleteFileIDRefSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FlushFile(short refNum)
+{
+       ParamBlockRec pb;
+
+       pb.ioParam.ioRefNum = refNum;
+       return ( PBFlushFileSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   LockRange(short refNum,
+                                                 long rangeLength,
+                                                 long rangeStart)
+{
+       ParamBlockRec pb;
+
+       pb.ioParam.ioRefNum = refNum;
+       pb.ioParam.ioReqCount = rangeLength;
+       pb.ioParam.ioPosMode = fsFromStart;
+       pb.ioParam.ioPosOffset = rangeStart;
+       return ( PBLockRangeSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   UnlockRange(short refNum,
+                                                       long rangeLength,
+                                                       long rangeStart)
+{
+       ParamBlockRec pb;
+
+       pb.ioParam.ioRefNum = refNum;
+       pb.ioParam.ioReqCount = rangeLength;
+       pb.ioParam.ioPosMode = fsFromStart;
+       pb.ioParam.ioPosOffset = rangeStart;
+       return ( PBUnlockRangeSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetForeignPrivs(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name,
+                                                               void *foreignPrivBuffer,
+                                                               long *foreignPrivSize,
+                                                               long *foreignPrivInfo1,
+                                                               long *foreignPrivInfo2,
+                                                               long *foreignPrivInfo3,
+                                                               long *foreignPrivInfo4)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       pb.foreignPrivParam.ioNamePtr = (StringPtr)name;
+       pb.foreignPrivParam.ioVRefNum = vRefNum;
+       pb.foreignPrivParam.ioForeignPrivDirID = dirID; 
+       pb.foreignPrivParam.ioForeignPrivBuffer = (Ptr)foreignPrivBuffer;
+       pb.foreignPrivParam.ioForeignPrivReqCount = *foreignPrivSize;
+       error = PBGetForeignPrivsSync(&pb);
+       *foreignPrivSize = pb.foreignPrivParam.ioForeignPrivActCount;
+       *foreignPrivInfo1 = pb.foreignPrivParam.ioForeignPrivInfo1;
+       *foreignPrivInfo2 = pb.foreignPrivParam.ioForeignPrivInfo2;
+       *foreignPrivInfo3 = pb.foreignPrivParam.ioForeignPrivInfo3;
+       *foreignPrivInfo4 = pb.foreignPrivParam.ioForeignPrivInfo4;
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetForeignPrivs(const FSSpec *spec,
+                                                                  void *foreignPrivBuffer,
+                                                                  long *foreignPrivSize,
+                                                                  long *foreignPrivInfo1,
+                                                                  long *foreignPrivInfo2,
+                                                                  long *foreignPrivInfo3,
+                                                                  long *foreignPrivInfo4)
+{
+       return ( GetForeignPrivs(spec->vRefNum, spec->parID, spec->name,
+                                                        foreignPrivBuffer, foreignPrivSize,
+                                                        foreignPrivInfo1, foreignPrivInfo2,
+                                                        foreignPrivInfo3, foreignPrivInfo4) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   SetForeignPrivs(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name,
+                                                               const void *foreignPrivBuffer,
+                                                               long *foreignPrivSize,
+                                                               long foreignPrivInfo1,
+                                                               long foreignPrivInfo2,
+                                                               long foreignPrivInfo3,
+                                                               long foreignPrivInfo4)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       pb.foreignPrivParam.ioNamePtr = (StringPtr)name;
+       pb.foreignPrivParam.ioVRefNum = vRefNum;
+       pb.foreignPrivParam.ioForeignPrivDirID = dirID; 
+       pb.foreignPrivParam.ioForeignPrivBuffer = (Ptr)foreignPrivBuffer;
+       pb.foreignPrivParam.ioForeignPrivReqCount = *foreignPrivSize;
+       pb.foreignPrivParam.ioForeignPrivInfo1 = foreignPrivInfo1;
+       pb.foreignPrivParam.ioForeignPrivInfo2 = foreignPrivInfo2;
+       pb.foreignPrivParam.ioForeignPrivInfo3 = foreignPrivInfo3;
+       pb.foreignPrivParam.ioForeignPrivInfo4 = foreignPrivInfo4;
+       error = PBSetForeignPrivsSync(&pb);
+       if ( error == noErr )
+       {
+               *foreignPrivSize = pb.foreignPrivParam.ioForeignPrivActCount;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetForeignPrivs(const FSSpec *spec,
+                                                                  const void *foreignPrivBuffer,
+                                                                  long *foreignPrivSize,
+                                                                  long foreignPrivInfo1,
+                                                                  long foreignPrivInfo2,
+                                                                  long foreignPrivInfo3,
+                                                                  long foreignPrivInfo4)
+{
+       return ( SetForeignPrivs(spec->vRefNum, spec->parID, spec->name,
+                                                        foreignPrivBuffer, foreignPrivSize,
+                                                        foreignPrivInfo1, foreignPrivInfo2,
+                                                        foreignPrivInfo3, foreignPrivInfo4) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HGetLogInInfo(ConstStr255Param volName,
+                                                         short vRefNum,
+                                                         short *loginMethod,
+                                                         StringPtr userName)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       pb.objParam.ioNamePtr = (StringPtr)volName;
+       pb.objParam.ioVRefNum = vRefNum;
+       pb.objParam.ioObjNamePtr = userName;
+       error = PBHGetLogInInfoSync(&pb);
+       if ( error == noErr )
+       {
+               *loginMethod = pb.objParam.ioObjType;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HGetDirAccess(short vRefNum,
+                                                         long dirID,
+                                                         ConstStr255Param name,
+                                                         long *ownerID,
+                                                         long *groupID,
+                                                         long *accessRights)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       pb.accessParam.ioNamePtr = (StringPtr)name;
+       pb.accessParam.ioVRefNum = vRefNum;
+       pb.fileParam.ioDirID = dirID;
+       error = PBHGetDirAccessSync(&pb);
+       if ( error == noErr )
+       {
+               *ownerID = pb.accessParam.ioACOwnerID;
+               *groupID = pb.accessParam.ioACGroupID;
+               *accessRights = pb.accessParam.ioACAccess;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetDirAccess(const FSSpec *spec,
+                                                               long *ownerID,
+                                                               long *groupID,
+                                                               long *accessRights)
+{
+       return ( HGetDirAccess(spec->vRefNum, spec->parID, spec->name,
+                                                  ownerID, groupID, accessRights) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HSetDirAccess(short vRefNum,
+                                                         long dirID,
+                                                         ConstStr255Param name,
+                                                         long ownerID,
+                                                         long groupID,
+                                                         long accessRights)
+{
+       HParamBlockRec pb;
+
+       pb.accessParam.ioNamePtr = (StringPtr)name;
+       pb.accessParam.ioVRefNum = vRefNum;
+       pb.fileParam.ioDirID = dirID;
+       pb.accessParam.ioACOwnerID = ownerID;
+       pb.accessParam.ioACGroupID = groupID;
+       pb.accessParam.ioACAccess = accessRights;
+       return ( PBHSetDirAccessSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetDirAccess(const FSSpec *spec,
+                                                               long ownerID,
+                                                               long groupID,
+                                                               long accessRights)
+{
+       return ( HSetDirAccess(spec->vRefNum, spec->parID, spec->name,
+                                                  ownerID, groupID, accessRights) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HMapID(ConstStr255Param volName,
+                                          short vRefNum,
+                                          long ugID,
+                                          short objType,
+                                          StringPtr name)
+{
+       HParamBlockRec pb;
+
+       pb.objParam.ioNamePtr = (StringPtr)volName;
+       pb.objParam.ioVRefNum = vRefNum;
+       pb.objParam.ioObjType = objType;
+       pb.objParam.ioObjNamePtr = name;
+       pb.objParam.ioObjID = ugID;
+       return ( PBHMapIDSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HMapName(ConstStr255Param volName,
+                                                short vRefNum,
+                                                ConstStr255Param name,
+                                                short objType,
+                                                long *ugID)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       pb.objParam.ioNamePtr = (StringPtr)volName;
+       pb.objParam.ioVRefNum = vRefNum;
+       pb.objParam.ioObjType = objType;
+       pb.objParam.ioObjNamePtr = (StringPtr)name;
+       error = PBHMapNameSync(&pb);
+       if ( error == noErr )
+       {
+               *ugID = pb.objParam.ioObjID;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HCopyFile(short srcVRefNum,
+                                                 long srcDirID,
+                                                 ConstStr255Param srcName,
+                                                 short dstVRefNum,
+                                                 long dstDirID,
+                                                 ConstStr255Param dstPathname,
+                                                 ConstStr255Param copyName)
+{
+       HParamBlockRec pb;
+
+       pb.copyParam.ioVRefNum = srcVRefNum;
+       pb.copyParam.ioDirID = srcDirID;
+       pb.copyParam.ioNamePtr = (StringPtr)srcName;
+       pb.copyParam.ioDstVRefNum = dstVRefNum;
+       pb.copyParam.ioNewDirID = dstDirID;
+       pb.copyParam.ioNewName = (StringPtr)dstPathname;
+       pb.copyParam.ioCopyName = (StringPtr)copyName;
+       return ( PBHCopyFileSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCopyFile(const FSSpec *srcSpec,
+                                                       const FSSpec *dstSpec,
+                                                       ConstStr255Param copyName)
+{
+       return ( HCopyFile(srcSpec->vRefNum, srcSpec->parID, srcSpec->name,
+                                          dstSpec->vRefNum, dstSpec->parID,
+                                          dstSpec->name, copyName) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   HMoveRename(short vRefNum,
+                                                       long srcDirID,
+                                                       ConstStr255Param srcName,
+                                                       long dstDirID,
+                                                       ConstStr255Param dstpathName,
+                                                       ConstStr255Param copyName)
+{
+       HParamBlockRec pb;
+
+       pb.copyParam.ioVRefNum = vRefNum;
+       pb.copyParam.ioDirID = srcDirID;
+       pb.copyParam.ioNamePtr = (StringPtr)srcName;
+       pb.copyParam.ioNewDirID = dstDirID;
+       pb.copyParam.ioNewName = (StringPtr)dstpathName;
+       pb.copyParam.ioCopyName = (StringPtr)copyName;
+       return ( PBHMoveRenameSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpMoveRename(const FSSpec *srcSpec,
+                                                         const FSSpec *dstSpec,
+                                                         ConstStr255Param copyName)
+{
+       OSErr   error;
+       
+       /* make sure the FSSpecs refer to the same volume */
+       if ( srcSpec->vRefNum != dstSpec->vRefNum )
+       {
+               error = diffVolErr;
+       }
+       else
+       {
+               error = HMoveRename(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, 
+                                                       dstSpec->parID, dstSpec->name, copyName);
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetVolMountInfoSize(ConstStr255Param volName,
+                                                                       short vRefNum,
+                                                                       short *size)
+{
+       ParamBlockRec pb;
+
+       pb.ioParam.ioNamePtr = (StringPtr)volName;
+       pb.ioParam.ioVRefNum = vRefNum;
+       pb.ioParam.ioBuffer = (Ptr)size;
+       return ( PBGetVolMountInfoSize(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetVolMountInfo(ConstStr255Param volName,
+                                                               short vRefNum,
+                                                               void *volMountInfo)
+{
+       ParamBlockRec pb;
+
+       pb.ioParam.ioNamePtr = (StringPtr)volName;
+       pb.ioParam.ioVRefNum = vRefNum;
+       pb.ioParam.ioBuffer = (Ptr)volMountInfo;
+       return ( PBGetVolMountInfo(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   VolumeMount(const void *volMountInfo,
+                                                       short *vRefNum)
+{
+       ParamBlockRec pb;
+       OSErr error;
+
+       pb.ioParam.ioBuffer = (Ptr)volMountInfo;
+       error = PBVolumeMount(&pb);
+       if ( error == noErr )
+       {
+               *vRefNum = pb.ioParam.ioVRefNum;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   Share(short vRefNum,
+                                         long dirID,
+                                         ConstStr255Param name)
+{
+       HParamBlockRec pb;
+
+       pb.fileParam.ioNamePtr = (StringPtr)name;
+       pb.fileParam.ioVRefNum = vRefNum;
+       pb.fileParam.ioDirID = dirID;
+       return ( PBShareSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpShare(const FSSpec *spec)
+{
+       return ( Share(spec->vRefNum, spec->parID, spec->name) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   Unshare(short vRefNum,
+                                               long dirID,
+                                               ConstStr255Param name)
+{
+       HParamBlockRec pb;
+
+       pb.fileParam.ioNamePtr = (StringPtr)name;
+       pb.fileParam.ioVRefNum = vRefNum;
+       pb.fileParam.ioDirID = dirID;
+       return ( PBUnshareSync(&pb) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   FSpUnshare(const FSSpec *spec)
+{
+       return ( Unshare(spec->vRefNum, spec->parID, spec->name) );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   GetUGEntry(short objType,
+                                                  StringPtr objName,
+                                                  long *objID)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       pb.objParam.ioObjType = objType;
+       pb.objParam.ioObjNamePtr = objName;
+       pb.objParam.ioObjID = *objID;
+       error = PBGetUGEntrySync(&pb);
+       if ( error == noErr )
+       {
+               *objID = pb.objParam.ioObjID;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
diff --git a/src/mac/morefile/MoreFile.h b/src/mac/morefile/MoreFile.h
new file mode 100644 (file)
index 0000000..e4d4bb8
--- /dev/null
@@ -0,0 +1,1244 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     The long lost high-level and FSSpec File Manager functions.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           MoreFiles.h
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#ifndef __MOREFILES__
+#define __MOREFILES__
+
+#include <Types.h>
+#include <Files.h>
+
+#ifndef true
+#define true 1 
+#define false 0
+#endif
+
+#include "Optim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+pascal OSErr   HGetVolParms(ConstStr255Param volName,
+                                                        short vRefNum,
+                                                        GetVolParmsInfoBuffer *volParmsInfo,
+                                                        long *infoSize);
+/*     ¦ Determine the characteristics of a volume.
+       The HGetVolParms function returns information about the characteristics
+       of a volume. A result of paramErr usually just means the volume doesn't
+       support PBHGetVolParms and the feature you were going to check
+       for isn't available.
+
+       volName                 input:  A pointer to the name of a mounted volume
+                                                       or nil.
+       vRefNum                 input:  Volume specification.
+       volParmsInfo    input:  Pointer to GetVolParmsInfoBuffer where the
+                                                       volume attributes information is returned.
+                                       output: Atributes information.
+       infoSize                input:  Size of buffer pointed to by volParmsInfo.
+                                       output: Size of data actually returned.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               paramErr                        -50             Volume doesn't support this function
+       
+       __________
+       
+       Also see the macros for checking attribute bits in MoreFilesExtras.h
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HCreateMinimum(short vRefNum,
+                                                          long dirID,
+                                                          ConstStr255Param fileName);
+/*     ¦ Create a new file with no creator or file type.
+       The HCreateMinimum function creates a new file without attempting to set
+       the creator and file type of the new file.  This function is needed to
+       create a file in an AppleShare "drop box" where the user can make
+       changes, but cannot see folder or files.
+       
+       vRefNum         input:  Volume specification.
+       dirID           input:  Directory ID.
+       fileName        input:  The name of the new file.
+       
+       Result Codes
+               noErr                           0               No error
+               dirFulErr                       -33             File directory full
+               dskFulErr                       -34             Disk is full
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             Directory not found or incomplete pathname
+               wPrErr                          -44             Hardware volume lock
+               vLckdErr                        -46             Software volume lock
+               dupFNErr                        -48             Duplicate filename and version
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   A directory exists with that name
+       
+       __________
+       
+       Also see:       FSpCreateMinimum
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCreateMinimum(const FSSpec *spec);
+/*     ¦ Create a new file with no creator or file type.
+       The FSpCreateMinimum function creates a new file without attempting to set 
+       the the creator and file type of the new file.  This function is needed to
+       create a file in an AppleShare "dropbox" where the user can make
+       changes, but cannot see folder or files. 
+       
+       spec            input:  An FSSpec record specifying the file to create.
+       
+       Result Codes
+               noErr                           0               No error
+               dirFulErr                       -33             File directory full
+               dskFulErr                       -34             Disk is full
+               nsvErr                          -35             No such volume
+               ioErr                           -36             I/O error
+               bdNamErr                        -37             Bad filename
+               fnfErr                          -43             Directory not found or incomplete pathname
+               wPrErr                          -44             Hardware volume lock
+               vLckdErr                        -46             Software volume lock
+               dupFNErr                        -48             Duplicate filename and version
+               dirNFErrdirNFErr        -120    Directory not found or incomplete pathname
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   A directory exists with that name
+       
+       __________
+       
+       Also see:       HCreateMinimum
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   ExchangeFiles(short vRefNum,
+                                                         long srcDirID,
+                                                         ConstStr255Param srcName,
+                                                         long dstDirID,
+                                                         ConstStr255Param dstName);
+/*     ¦ Exchange the data stored in two files on the same volume.
+       The ExchangeFiles function swaps the data in two files on the same
+       volume by changing some of the information in the volume catalog and,
+       if the files are open, in the file control blocks.
+
+       vRefNum         input:  Volume specification.
+       srcDirID        input:  Source directory ID.
+       srcName         input:  Source file name.
+       dstDirID        input:  Destination directory ID.
+       dstName         input:  Destination file name.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          -43             File not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             Function not supported by volume
+               volOfflinErr            -53             Volume is offline
+               wrgVolTypErr            -123    Not an HFS volume
+               diffVolErr                      -1303   Files on different volumes
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Object is a directory, not a file
+               afpSameObjectErr        -5038   Source and destination are the same
+
+       __________
+       
+       Also see:       FSpExchangeFilesCompat
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   ResolveFileIDRef(ConstStr255Param volName,
+                                                                short vRefNum,
+                                                                long fileID,
+                                                                long *parID,
+                                                                StringPtr fileName);
+/*     ¦ Retrieve the location of the file with the specified file ID reference.
+       The ResolveFileIDRef function returns the filename and parent directory ID
+       of the file with the specified file ID reference.
+       
+       volName input:  A pointer to the name of a mounted volume
+                                       or nil.
+       vRefNum input:  Volume specification.
+       fileID  input:  The file ID reference.
+       parID   output: The parent directory ID of the file.
+       name    input:  Points to a buffer (minimum Str63) where the filename
+                                       is to be returned or must be nil.
+                       output: The filename.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          -43             File not found
+               paramErr                        -50             Function not supported by volume
+               volOfflinErr            -53             Volume is offline
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               wrgVolTypErr            -123    Not an HFS volume
+               fidNotFoundErr          -1300   File ID reference not found
+               notAFileErr                     -1302   Specified file is a directory
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Specified file is a directory
+               afpIDNotFound           -5034   File ID reference not found
+               afpBadIDErr                     -5039   File ID reference not found
+       
+       __________
+       
+       Also see:       FSpResolveFileIDRef, CreateFileIDRef, FSpCreateFileIDRef,
+                               DeleteFileIDRef
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpResolveFileIDRef(ConstStr255Param volName,
+                                                                       short vRefNum,
+                                                                       long fileID,
+                                                                       FSSpecPtr spec);
+/*     ¦ Retrieve the location of the file with the specified file ID reference.
+       The FSpResolveFileIDRef function fills in an FSSpec with the location
+       of the file with the specified file ID reference.
+       
+       volName input:  A pointer to the name of a mounted volume
+                                       or nil.
+       vRefNum input:  Volume specification.
+       fileID  input:  The file ID reference.
+       spec    input:  A pointer to a FSSpec record.
+                       output: A file system specification to be filled in by
+                                       FSpResolveFileIDRef.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          -43             File not found
+               paramErr                        -50             Function not supported by volume or
+                                                                       no default volume
+               volOfflinErr            -53             Volume is offline
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               wrgVolTypErr            -123    Not an HFS volume
+               fidNotFoundErr          -1300   File ID reference not found
+               notAFileErr                     -1302   Specified file is a directory
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Specified file is a directory
+               afpIDNotFound           -5034   File ID reference not found
+               afpBadIDErr                     -5039   File ID reference not found
+       
+       __________
+       
+       Also see:       ResolveFileIDRef, CreateFileIDRef, FSpCreateFileIDRef,
+                               DeleteFileIDRef
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   CreateFileIDRef(short vRefNum,
+                                                               long parID,
+                                                               ConstStr255Param fileName,
+                                                               long *fileID);
+/*     ¦ Establish a file ID reference for a file.
+       The CreateFileIDRef function creates a file ID reference for the
+       specified file, or if a file ID reference already exists, supplies
+       the file ID reference and returns the result code fidExists.
+
+       vRefNum         input:  Volume specification.
+       parID           input:  Directory ID.
+       fileName        input:  The name of the file.
+       fileID          output: The file ID reference.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          -43             File not found
+               wPrErr                          -44             Hardware volume lock
+               vLckdErr                        -46             Software volume lock
+               paramErr                        -50             Function not supported by volume
+               volOfflinErr            -53             Volume is offline
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               wrgVolTypErr            -123    Not an HFS volume
+               fidExists                       -1301   File ID reference already exists
+               notAFileErrn            -1302   Specified file is a directory
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Specified file is a directory
+               afpIDExists                     -5035   File ID reference already exists
+       
+       __________
+       
+       Also see:       FSpResolveFileIDRef, ResolveFileIDRef, FSpCreateFileIDRef,
+                               DeleteFileIDRef
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCreateFileIDRef(const FSSpec *spec,
+                                                                  long *fileID);
+/*     ¦ Establish a file ID reference for a file.
+       The FSpCreateFileIDRef function creates a file ID reference for the
+       specified file, or if a file ID reference already exists, supplies
+       the file ID reference and returns the result code fidExists.
+
+       spec            input:  An FSSpec record specifying the file.
+       fileID          output: The file ID reference.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          -43             File not found
+               wPrErr                          -44             Hardware volume lock
+               vLckdErr                        -46             Software volume lock
+               paramErr                        -50             Function not supported by volume
+               volOfflinErr            -53             Volume is offline
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               wrgVolTypErr            -123    Not an HFS volume
+               fidExists                       -1301   File ID reference already exists
+               notAFileErrn            -1302   Specified file is a directory
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Specified file is a directory
+               afpIDExists                     -5035   File ID reference already exists
+       
+       __________
+       
+       Also see:       FSpResolveFileIDRef, ResolveFileIDRef, CreateFileIDRef,
+                               DeleteFileIDRef
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   DeleteFileIDRef(ConstStr255Param volName,
+                                                               short vRefNum,
+                                                               long fileID);
+/*     ¦ Delete a file ID reference.
+       The DeleteFileIDRef function deletes a file ID reference.
+
+       volName input:  A pointer to the name of a mounted volume
+                                       or nil.
+       vRefNum input:  Volume specification.
+       fileID  input:  The file ID reference.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnfErr                          -43             File not found
+               wPrErr                          -44             Hardware volume lock
+               vLckdErr                        -46             Software volume lock
+               paramErr                        -50             Function not supported by volume
+               volOfflinErr            -53             Volume is offline
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               wrgVolTypErr            -123    Function is not supported by volume
+               fidNotFoundErr          -1300   File ID reference not found
+               afpAccessDenied         -5000   User does not have the correct access
+               afpObjectTypeErr        -5025   Specified file is a directory
+               afpIDNotFound           -5034   File ID reference not found
+       
+       __________
+       
+       Also see:       FSpResolveFileIDRef, ResolveFileIDRef, CreateFileIDRef,
+                               FSpCreateFileIDRef
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FlushFile(short refNum);
+/*     ¦ Write the contents of a file's access path buffer (the fork data).
+       The FlushFile function writes the contents of a file's access path
+       buffer (the fork data) to the volume. Note: some of the file's catalog
+       information stored on the volume may not be correct until FlushVol
+       is called.
+
+       refNum  input:  The file reference number of an open file.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               fnOpnErr                        -38             File not open
+               fnfErr                          -43             File not found
+               rfNumErr                        -51             Bad reference number
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   LockRange(short refNum,
+                                                 long rangeLength,
+                                                 long rangeStart);
+/*     ¦ Lock a portion of a file.
+       The LockRange function locks (denies access to) a portion of a file
+       that was opened with shared read/write permission.
+
+       refNum          input:  The file reference number of an open file.
+       rangeLength     input:  The number of bytes in the range.
+       rangeStart      input:  The starting byte in the range to lock.
+       
+       Result Codes
+               noErr                           0               No error
+               ioErr                           -36             I/O error
+               fnOpnErr                        -38             File not open
+               eofErr                          -39             Logical end-of-file reached
+               fLckdErr                        -45             File is locked by another user
+               paramErr                        -50             Negative ioReqCount
+               rfNumErr                        -51             Bad reference number
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               volGoneErr                      -124    Server volume has been disconnected
+               afpNoMoreLocks          -5015   No more ranges can be locked
+               afpRangeOverlap         -5021   Part of range is already locked
+
+       __________
+       
+       Also see:       UnlockRange
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   UnlockRange(short refNum,
+                                                       long rangeLength,
+                                                       long rangeStart);
+/*     ¦ Unlock a previously locked range.
+       The UnlockRange function unlocks (allows access to) a previously locked
+       portion of a file that was opened with shared read/write permission.
+
+       refNum          input:  The file reference number of an open file.
+       rangeLength     input:  The number of bytes in the range.
+       rangeStart      input:  The starting byte in the range to unlock.
+       
+       Result Codes
+               noErr                           0               No error
+               ioErr                           -36             I/O error
+               fnOpnErr                        -38             File not open
+               eofErr                          -39             Logical end-of-file reached
+               paramErr                        -50             Negative ioReqCount
+               rfNumErr                        -51             Bad reference number
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               volGoneErr                      -124    Server volume has been disconnected
+               afpRangeNotLocked       -5020   Specified range was not locked
+
+       __________
+       
+       Also see:       LockRange
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetForeignPrivs(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name,
+                                                               void *foreignPrivBuffer,
+                                                               long *foreignPrivSize,
+                                                               long *foreignPrivInfo1,
+                                                               long *foreignPrivInfo2,
+                                                               long *foreignPrivInfo3,
+                                                               long *foreignPrivInfo4);
+/*     ¦ Retrieve the native access-control information.
+       The GetForeignPrivs function retrieves the native access-control
+       information for a file or directory stored on a volume managed by
+       a foreign file system.
+       
+       vRefNum                         input:  Volume specification.
+       dirID                           input:  Directory ID.
+       name                            input:  Pointer to object name, or nil when dirID
+                                                               specifies a directory that's the object.
+       foreignPrivBuffer       input:  Pointer to buffer where the privilege
+                                                               information is returned.
+                                               output: Privilege information.
+       foreignPrivSize         input:  Size of buffer pointed to by
+                                                               foreignPrivBuffer.
+                                               output: Amount of buffer actually used.
+       foreignPrivInfo1        output: Information specific to privilege model.
+       foreignPrivInfo2        output: Information specific to privilege model.
+       foreignPrivInfo3        output: Information specific to privilege model.
+       foreignPrivInfo4        output: Information specific to privilege model.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               paramErr                        -50             Volume is HFS or MFS (that is, it has
+                                                                       no foreign privilege model), or foreign
+                                                                       volume does not support these calls
+       
+       __________
+       
+       Also see:       FSpGetForeignPrivs, SetForeignPrivs, FSpSetForeignPrivs
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetForeignPrivs(const FSSpec *spec,
+                                                                  void *foreignPrivBuffer,
+                                                                  long *foreignPrivSize,
+                                                                  long *foreignPrivInfo1,
+                                                                  long *foreignPrivInfo2,
+                                                                  long *foreignPrivInfo3,
+                                                                  long *foreignPrivInfo4);
+/*     ¦ Retrieve the native access-control information.
+       The FSpGetForeignPrivs function retrieves the native access-control
+       information for a file or directory stored on a volume managed by
+       a foreign file system.
+       
+       spec                            input:  An FSSpec record specifying the object.
+       foreignPrivBuffer       input:  Pointer to buffer where the privilege
+                                                               information is returned.
+                                               output: Privilege information.
+       foreignPrivSize         input:  Size of buffer pointed to by
+                                                               foreignPrivBuffer.
+                                               output: Amount of buffer actually used.
+       foreignPrivInfo1        output: Information specific to privilege model.
+       foreignPrivInfo2        output: Information specific to privilege model.
+       foreignPrivInfo3        output: Information specific to privilege model.
+       foreignPrivInfo4        output: Information specific to privilege model.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               paramErr                        -50             Volume is HFS or MFS (that is, it has
+                                                                       no foreign privilege model), or foreign
+                                                                       volume does not support these calls
+       
+       __________
+       
+       Also see:       GetForeignPrivs, SetForeignPrivs, FSpSetForeignPrivs
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   SetForeignPrivs(short vRefNum,
+                                                               long dirID,
+                                                               ConstStr255Param name,
+                                                               const void *foreignPrivBuffer,
+                                                               long *foreignPrivSize,
+                                                               long foreignPrivInfo1,
+                                                               long foreignPrivInfo2,
+                                                               long foreignPrivInfo3,
+                                                               long foreignPrivInfo4);
+/*     ¦ Change the native access-control information.
+       The SetForeignPrivs function changes the native access-control
+       information for a file or directory stored on a volume managed by
+       a foreign file system.
+       
+       vRefNum                         input:  Volume specification.
+       dirID                           input:  Directory ID.
+       name                            input:  Pointer to object name, or nil when dirID
+                                                               specifies a directory that's the object.
+       foreignPrivBuffer       input:  Pointer to privilege information buffer.
+       foreignPrivSize         input:  Size of buffer pointed to by
+                                                               foreignPrivBuffer.
+                                               output: Amount of buffer actually used.
+       foreignPrivInfo1        input:  Information specific to privilege model.
+       foreignPrivInfo2        input:  Information specific to privilege model.
+       foreignPrivInfo3        input:  Information specific to privilege model.
+       foreignPrivInfo4        input:  Information specific to privilege model.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               paramErr                        -50             Volume is HFS or MFS (that is, it has
+                                                                       no foreign privilege model), or foreign
+                                                                       volume does not support these calls
+       
+       __________
+       
+       Also see:       GetForeignPrivs, FSpGetForeignPrivs, FSpSetForeignPrivs
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetForeignPrivs(const FSSpec *spec,
+                                                                  const void *foreignPrivBuffer,
+                                                                  long *foreignPrivSize,
+                                                                  long foreignPrivInfo1,
+                                                                  long foreignPrivInfo2,
+                                                                  long foreignPrivInfo3,
+                                                                  long foreignPrivInfo4);
+/*     ¦ Change the native access-control information.
+       The FSpSetForeignPrivs function changes the native access-control
+       information for a file or directory stored on a volume managed by
+       a foreign file system.
+       
+       spec                            input:  An FSSpec record specifying the object.
+       foreignPrivBuffer       input:  Pointer to privilege information buffer.
+       foreignPrivSize         input:  Size of buffer pointed to by
+                                                               foreignPrivBuffer.
+                                               output: Amount of buffer actually used.
+       foreignPrivInfo1        input:  Information specific to privilege model.
+       foreignPrivInfo2        input:  Information specific to privilege model.
+       foreignPrivInfo3        input:  Information specific to privilege model.
+       foreignPrivInfo4        input:  Information specific to privilege model.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               paramErr                        -50             Volume is HFS or MFS (that is, it has
+                                                                       no foreign privilege model), or foreign
+                                                                       volume does not support these calls
+       
+       __________
+       
+       Also see:       GetForeignPrivs, FSpGetForeignPrivs, SetForeignPrivs
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HGetLogInInfo(ConstStr255Param volName,
+                                                         short vRefNum,
+                                                         short *loginMethod,
+                                                         StringPtr userName);
+/*     ¦ Get the login method and user name used to log on to a shared volume.
+       The HGetLogInInfo function retrieves the login method and user name
+       used to log on to a particular shared volume.
+       
+       volName         input:  A pointer to the name of a mounted volume
+                                               or nil.
+       vRefNum         input:  The volume reference number.
+       loginMethod     output: The login method used (kNoUserAuthentication,
+                                               kPassword, kEncryptPassword, or
+                                               kTwoWayEncryptPassword).
+       userName        input:  Points to a buffer (minimum Str31) where the user
+                                               name is to be returned or must be nil.
+                               output: The user name.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Specified volume doesnÕt exist
+               paramErr                        -50             Function not supported by volume
+       
+       __________
+       
+       Also see:       HGetDirAccess, FSpGetDirAccess, HSetDirAccess,
+                               FSpSetDirAccess, HMapName, HMapID
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HGetDirAccess(short vRefNum,
+                                                         long dirID,
+                                                         ConstStr255Param name,
+                                                         long *ownerID,
+                                                         long *groupID,
+                                                         long *accessRights);
+/*     ¦ Get a directory's access control information on a shared volume.
+       The HGetDirAccess function retrieves the directory access control
+       information for a directory on a shared volume.
+       
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to directory name, or nil if dirID
+                                                       specifies the directory.
+       ownerID                 output: The directory's owner ID.
+       groupID                 output: The directory's group ID or
+                                                       0 if no group affiliation.
+       accessRights    output: The directory's access rights.
+       
+       Result Codes
+               noErr                           0               No error
+               fnfErr                          -43             Directory not found
+               paramErr                        -50             Function not supported by volume
+               afpAccessDenied         -5000   User does not have the correct access
+                                                                       to the directory
+       
+       __________
+       
+       Also see:       HGetLogInInfo, FSpGetDirAccess, HSetDirAccess,
+                               FSpSetDirAccess, HMapName, HMapID
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpGetDirAccess(const FSSpec *spec,
+                                                               long *ownerID,
+                                                               long *groupID,
+                                                               long *accessRights);
+/*     ¦ Get a directory's access control information on a shared volume.
+       The FSpGetDirAccess function retrieves the directory access control
+       information for a directory on a shared volume.
+       
+       spec                    input:  An FSSpec record specifying the directory.
+       ownerID                 output: The directory's owner ID.
+       groupID                 output: The directory's group ID or
+                                                       0 if no group affiliation.
+       accessRights    output: The directory's access rights.
+       
+       Result Codes
+               noErr                           0               No error
+               fnfErr                          -43             Directory not found
+               paramErr                        -50             Function not supported by volume
+               afpAccessDenied         -5000   User does not have the correct access
+                                                                       to the directory
+       
+       __________
+       
+       Also see:       HGetLogInInfo, HGetDirAccess, HSetDirAccess,
+                               FSpSetDirAccess, HMapName, HMapID
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HSetDirAccess(short vRefNum,
+                                                         long dirID,
+                                                         ConstStr255Param name,
+                                                         long ownerID,
+                                                         long groupID,
+                                                         long accessRights);
+/*     ¦ Set a directory's access control information on a shared volume.
+       The HSetDirAccess function changes the directory access control
+       information for a directory on a shared volume. You must own a directory
+       to change its access control information.
+       
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to directory name, or nil if dirID
+                                                       specifies the directory.
+       ownerID                 input:  The directory's owner ID.
+       groupID                 input:  The directory's group ID or
+                                                       0 if no group affiliation.
+       accessRights    input:  The directory's access rights.
+       
+       Result Codes
+               noErr                           0               No error
+               fnfErr                          -43             Directory not found
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             Parameter error
+               afpAccessDenied         -5000   User does not have the correct access
+                                                                       to the directory
+               afpObjectTypeErr        -5025   Object is a file, not a directory
+       
+       __________
+       
+       Also see:       HGetLogInInfo, HGetDirAccess, FSpGetDirAccess,
+                               FSpSetDirAccess, HMapName, HMapID
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpSetDirAccess(const FSSpec *spec,
+                                                               long ownerID,
+                                                               long groupID,
+                                                               long accessRights);
+/*     ¦ Set a directory's access control information on a shared volume.
+       The FSpSetDirAccess function changes the directory access control
+       information for a directory on a shared volume. You must own a directory
+       to change its access control information.
+       
+       spec                    input:  An FSSpec record specifying the directory.
+       ownerID                 input:  The directory's owner ID.
+       groupID                 input:  The directory's group ID or
+                                                       0 if no group affiliation.
+       accessRights    input:  The directory's access rights.
+       
+       Result Codes
+               noErr                           0               No error
+               fnfErr                          -43             Directory not found
+               vLckdErr                        -46             Volume is locked or read-only
+               paramErr                        -50             Parameter error
+               afpAccessDenied         -5000   User does not have the correct access
+                                                                       to the directory
+               afpObjectTypeErr        -5025   Object is a file, not a directory
+       
+       __________
+       
+       Also see:       HGetLogInInfo, HGetDirAccess, FSpGetDirAccess, HSetDirAccess,
+                               HMapName, HMapID
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HMapID(ConstStr255Param volName,
+                                          short vRefNum,
+                                          long ugID,
+                                          short objType,
+                                          StringPtr name);
+/*     ¦ Map a user or group ID to a user or group name.
+       The HMapID function determines the name of a user or group if you know
+       the user or group ID.
+       
+       volName         input:  A pointer to the name of a mounted volume
+                                               or nil.
+       vRefNum         input:  Volume specification.
+       objType         input:  The mapping function code: 1 if you're mapping a
+                                               user ID to a user name or 2 if you're mapping a
+                                               group ID to a group name.
+       name            input:  Points to a buffer (minimum Str31) where the user
+                                               or group name is to be returned or must be nil.
+                               output: The user or group name.
+       
+       Result Codes
+               noErr                           0               No error
+               fnfErr                          -43             Unrecognizable owner or group name
+               paramErr                        -50             Function not supported by volume
+       
+       __________
+       
+       Also see:       HGetLogInInfo, HGetDirAccess, FSpGetDirAccess, HSetDirAccess,
+                               FSpSetDirAccess, HMapName
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HMapName(ConstStr255Param volName,
+                                                short vRefNum,
+                                                ConstStr255Param name,
+                                                short objType,
+                                                long *ugID);
+/*     ¦ Map a user or group name to a user or group ID.
+       The HMapName function determines the user or group ID if you know the
+       user or group name.
+       
+       volName         input:  A pointer to the name of a mounted volume
+                                               or nil.
+       vRefNum         input:  Volume specification.
+       name            input:  The user or group name.
+       objType         input:  The mapping function code: 3 if you're mapping a
+                                               user name to a user ID or 4 if you're mapping a
+                                               group name to a group ID.
+       ugID            output: The user or group ID.
+
+       Result Codes
+               noErr                           0               No error
+               fnfErr                          -43             Unrecognizable owner or group name
+               paramErr                        -50             Function not supported by volume
+       
+       __________
+       
+       Also see:       HGetLogInInfo, HGetDirAccess, FSpGetDirAccess, HSetDirAccess,
+                               FSpSetDirAccess, HMapID
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HCopyFile(short srcVRefNum,
+                                                 long srcDirID,
+                                                 ConstStr255Param srcName,
+                                                 short dstVRefNum,
+                                                 long dstDirID,
+                                                 ConstStr255Param dstPathname,
+                                                 ConstStr255Param copyName);
+/*     ¦ Duplicate a file on a file server and optionally to rename it.
+       The HCopyFile function duplicates a file and optionally to renames it.
+       The source and destination volumes must be on the same file server.
+       This function instructs the server to copy the file.
+       
+       srcVRefNum      input:  Source volume specification.
+       srcDirID        input:  Source directory ID.
+       srcName         input:  Source file name.
+       dstVRefNum      input:  Destination volume specification.
+       dstDirID        input:  Destination directory ID.
+       dstPathname     input:  Pointer to destination directory name, or
+                                               nil when dstDirID specifies a directory.
+       copyName        input:  Points to the new file name if the file is to be
+                                               renamed or nil if the file isn't to be renamed.
+       
+       Result Codes
+               noErr                           0               No error
+               dskFulErr                       -34             Destination volume is full
+               fnfErr                          -43             Source file not found, or destination
+                                                                       directory does not exist
+               vLckdErr                        -46             Destination volume is read-only
+               fBsyErr                         -47             The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               dupFNErr                        -48             Destination file already exists
+               paramErr                        -50             Function not supported by volume
+               wrgVolTypErr            -123    Function not supported by volume
+               afpAccessDenied         -5000   The user does not have the right to
+                                                                       read the source or write to the
+                                                                       destination
+               afpDenyConflict         -5006   The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               afpObjectTypeErr        -5025   Source is a directory
+       
+       __________
+       
+       Also see:       FSpCopyFile, FileCopy, FSpFileCopy
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpCopyFile(const FSSpec *srcSpec,
+                                                       const FSSpec *dstSpec,
+                                                       ConstStr255Param copyName);
+/*     ¦ Duplicate a file on a file server and optionally to rename it.
+       The FSpCopyFile function duplicates a file and optionally to renames it.
+       The source and destination volumes must be on the same file server.
+       This function instructs the server to copy the file.
+       
+       srcSpec         input:  An FSSpec record specifying the source file.
+       dstSpec         input:  An FSSpec record specifying the destination
+                                               directory.
+       copyName        input:  Points to the new file name if the file is to be
+                                               renamed or nil if the file isn't to be renamed.
+       
+       Result Codes
+               noErr                           0               No error
+               dskFulErr                       -34             Destination volume is full
+               fnfErr                          -43             Source file not found, or destination
+                                                                       directory does not exist
+               vLckdErr                        -46             Destination volume is read-only
+               fBsyErr                         -47             The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               dupFNErr                        -48             Destination file already exists
+               paramErr                        -50             Function not supported by volume
+               wrgVolTypErr            -123    Function not supported by volume
+               afpAccessDenied         -5000   The user does not have the right to
+                                                                       read the source or write to the
+                                                                       destination
+               afpDenyConflict         -5006   The source or destination file could
+                                                                       not be opened with the correct access
+                                                                       modes
+               afpObjectTypeErr        -5025   Source is a directory
+       
+       __________
+       
+       Also see:       HCopyFile, FileCopy, FSpFileCopy
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   HMoveRename(short vRefNum,
+                                                       long srcDirID,
+                                                       ConstStr255Param srcName,
+                                                       long dstDirID,
+                                                       ConstStr255Param dstpathName,
+                                                       ConstStr255Param copyName);
+/*     ¦ Move a file or directory on a file server and optionally to rename it.
+       The HMoveRename function moves a file or directory and optionally
+       renames it. The source and destination locations must be on the same
+       shared volume.
+       
+       vRefNum         input:  Volume specification.
+       srcDirID        input:  Source directory ID.
+       srcName         input:  The source object name.
+       dstDirID        input:  Destination directory ID.
+       dstName         input:  Pointer to destination directory name, or
+                                               nil when dstDirID specifies a directory.
+       copyName        input:  Points to the new name if the object is to be
+                                               renamed or nil if the object isn't to be renamed.
+       
+       Result Codes
+               noErr                           0               No error
+               fnfErr                          -43             Source file or directory not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Destination volume is read-only
+               dupFNErr                        -48             Destination already exists
+               paramErr                        -50             Function not supported by volume
+               badMovErr                       -122    Attempted to move directory into
+                                                                       offspring
+               afpAccessDenied         -5000   The user does not have the right to
+                                                                       move the file  or directory
+       
+       __________
+       
+       Also see:       FSpMoveRename, HMoveRenameCompat, FSpMoveRenameCompat
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpMoveRename(const FSSpec *srcSpec,
+                                                         const FSSpec *dstSpec,
+                                                         ConstStr255Param copyName);
+/*     ¦ Move a file or directory on a file server and optionally to rename it.
+       The FSpMoveRename function moves a file or directory and optionally
+       renames it. The source and destination locations must be on the same
+       shared volume.
+       
+       srcSpec         input:  An FSSpec record specifying the source object.
+       dstSpec         input:  An FSSpec record specifying the destination
+                                               directory.
+       copyName        input:  Points to the new name if the object is to be
+                                               renamed or nil if the object isn't to be renamed.
+       
+       Result Codes
+               noErr                           0               No error
+               fnfErr                          -43             Source file or directory not found
+               fLckdErr                        -45             File is locked
+               vLckdErr                        -46             Destination volume is read-only
+               dupFNErr                        -48             Destination already exists
+               paramErr                        -50             Function not supported by volume
+               badMovErr                       -122    Attempted to move directory into
+                                                                       offspring
+               afpAccessDenied         -5000   The user does not have the right to
+                                                                       move the file  or directory
+       
+       __________
+       
+       Also see:       HMoveRename, HMoveRenameCompat, FSpMoveRenameCompat
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetVolMountInfoSize(ConstStr255Param volName,
+                                                                       short vRefNum,
+                                                                       short *size);
+/*     ¦ Get the size of a volume mounting information record.
+       The GetVolMountInfoSize function determines the how much space the
+       program needs to allocate for a volume mounting information record.
+       
+       volName         input:  A pointer to the name of a mounted volume
+                                               or nil.
+       vRefNum         input:  Volume specification.
+       size            output: The space needed (in bytes) of the volume mounting
+                                               information record.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               paramErr                        -50             Parameter error
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+
+       __________
+       
+       Also see:       GetVolMountInfo, VolumeMount BuildAFPVolMountInfo,
+                               RetrieveAFPVolMountInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetVolMountInfo(ConstStr255Param volName,
+                                                               short vRefNum,
+                                                               void *volMountInfo);
+/*     ¦ Retrieve a volume mounting information record.
+       The GetVolMountInfo function retrieves a volume mounting information
+       record containing all the information needed to mount the volume,
+       except for passwords.
+       
+       volName                 input:  A pointer to the name of a mounted volume
+                                                       or nil.
+       vRefNum                 input:  Volume specification.
+       volMountInfo    output: Points to a volume mounting information
+                                                       record where the mounting information is to
+                                                       be returned.
+       
+       Result Codes
+               noErr                           0               No error        
+               nsvErr                          -35             Volume not found        
+               paramErr                        -50             Parameter error 
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+
+       __________
+       
+       Also see:       GetVolMountInfoSize, VolumeMount, BuildAFPVolMountInfo,
+                               RetrieveAFPVolMountInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   VolumeMount(const void *volMountInfo,
+                                                       short *vRefNum);
+/*     ¦ Mount a volume using a volume mounting information record.
+       The VolumeMount function mounts a volume using a volume mounting
+       information record.
+       
+       volMountInfo    input:  Points to a volume mounting information record.
+       vRefNum                 output: A volume reference number.
+       
+       Result Codes
+               noErr                           0               No error
+               notOpenErr                      -28             AppleTalk is not open
+               nsvErr                          -35             Volume not found
+               paramErr                        -50             Parameter error; typically, zone, server,
+                                                                       and volume name combination is not valid
+                                                                       or not complete, or the user name is not
+                                                                       recognized
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               memFullErr                      -108    Not enough memory to create a new volume
+                                                                       control block for mounting the volume
+               afpBadUAM                       -5002   User authentication method is unknown
+               afpBadVersNum           -5003   Workstation is using an AFP version that
+                                                                       the server doesnÕt recognize
+               afpNoServer                     -5016   Server is not responding
+               afpUserNotAuth          -5023   User authentication failed (usually,
+                                                                       password  is not correct)
+               afpPwdExpired           -5042   Password has expired on server
+               afpBadDirIDType         -5060   Not a fixed directory ID volume
+               afpCantMountMoreSrvrs -5061     Maximum number of volumes has been
+                                                                       mounted
+               afpAlreadyMounted       -5062   Volume already mounted
+               afpSameNodeErr          -5063   Attempt to log on to a server running
+                                                                       on the same machine
+
+       __________
+       
+       Also see:       GetVolMountInfoSize, GetVolMountInfo, BuildAFPVolMountInfo,
+                               RetrieveAFPVolMountInfo
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   Share(short vRefNum,
+                                         long dirID,
+                                         ConstStr255Param name);
+/*     ¦ Establish a local volume or directory as a share point.
+       The Share function establishes a local volume or directory as a
+       share point.
+
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to directory name, or nil if dirID
+                                                       specifies the directory.
+       
+       Result Codes
+               noErr                           0               No error        
+               tmfoErr                         -42             Too many share points   
+               fnfErr                          -43             File not found  
+               dupFNErr                        -48             Already a share point with this name    
+               paramErr                        -50             Function not supported by volume        
+               dirNFErrdirNFErr        -120    Directory not found     
+               afpAccessDenied         -5000   This directory cannot be shared 
+               afpObjectTypeErr        -5025   Object was a file, not a directory      
+               afpContainsSharedErr -5033      The directory contains a share point    
+               afpInsideSharedErr      -5043   The directory is inside a shared directory      
+
+       __________
+       
+       Also see:       FSpShare, Unshare, FSpUnshare
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpShare(const FSSpec *spec);
+/*     ¦ Establish a local volume or directory as a share point.
+       The FSpShare function establishes a local volume or directory as a
+       share point.
+
+       spec    input:  An FSSpec record specifying the share point.
+       
+       Result Codes
+               noErr                           0               No error        
+               tmfoErr                         -42             Too many share points   
+               fnfErr                          -43             File not found  
+               dupFNErr                        -48             Already a share point with this name    
+               paramErr                        -50             Function not supported by volume        
+               dirNFErrdirNFErr        -120    Directory not found     
+               afpAccessDenied         -5000   This directory cannot be shared 
+               afpObjectTypeErr        -5025   Object was a file, not a directory      
+               afpContainsSharedErr -5033      The directory contains a share point    
+               afpInsideSharedErr      -5043   The directory is inside a shared directory      
+
+       __________
+       
+       Also see:       Share, Unshare, FSpUnshare
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   Unshare(short vRefNum,
+                                               long dirID,
+                                               ConstStr255Param name);
+/*     ¦ Remove a share point.
+       The Unshare function removes a share point.
+
+       vRefNum                 input:  Volume specification.
+       dirID                   input:  Directory ID.
+       name                    input:  Pointer to directory name, or nil if dirID
+                                                       specifies the directory.
+       
+       Result Codes
+               noErr                           0               No error        
+               fnfErr                          -43             File not found  
+               paramErr                        -50             Function not supported by volume        
+               dirNFErrdirNFErr        -120    Directory not found     
+               afpObjectTypeErr        -5025   Object was a file, not a directory; or,
+                                                                       this directory is not a share point     
+
+       __________
+       
+       Also see:       Share, FSpShare, FSpUnshare
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   FSpUnshare(const FSSpec *spec);
+/*     ¦ Remove a share point.
+       The FSpUnshare function removes a share point.
+
+       spec    input:  An FSSpec record specifying the share point.
+       
+       Result Codes
+               noErr                           0               No error        
+               fnfErr                          -43             File not found  
+               paramErr                        -50             Function not supported by volume        
+               dirNFErrdirNFErr        -120    Directory not found     
+               afpObjectTypeErr        -5025   Object was a file, not a directory; or,
+                                                                       this directory is not a share point     
+
+       __________
+       
+       Also see:       Share, FSpShare, Unshare
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   GetUGEntry(short objType,
+                                                  StringPtr objName,
+                                                  long *objID);
+/*     ¦ Retrieve a user or group entry from the local file server.
+       The GetUGEntry function retrieves user or group entries from the
+       local file server.
+
+       objType         input:  The object type: -1 = group; 0 = user
+       objName         input:  Points to a buffer (minimum Str31) where the user
+                                               or group name is to be returned or must be nil.
+                               output: The user or group name.
+       objID           input:  O to get the first user or group. If the entry objID
+                                               last returned by GetUGEntry is passed, then user or
+                                               group whose alphabetically next in the list of entries
+                                               is returned.
+                               output: The user or group ID.
+       
+       Result Codes
+               noErr                           0               No error        
+               fnfErr                          -43             No more users or groups 
+               paramErr                        -50             Function not supported; or, ioObjID is
+                                                                       negative        
+
+       __________
+       
+       Also see:       GetUGEntries
+*/
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "OptimEnd.h"
+
+#endif /* __MOREFILES__ */
diff --git a/src/mac/morefile/Optim.h b/src/mac/morefile/Optim.h
new file mode 100644 (file)
index 0000000..d09caf7
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     DirectoryCopy: #defines that let you make MoreFiles code more efficient.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           Optimization.h
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+**
+**     The Optimization changes to MoreFiles source and header files, along with
+**     this file and OptimizationEnd.h, let you optimize the code produced
+**     by MoreFiles in several ways.
+**
+**     1 -- MoreFiles contains extra code so that many routines can run under
+**     Mac OS systems back to System 6. If your program requires a specific
+**     version of Mac OS and your program checks for that version before
+**     calling MoreFiles routines, then you can remove a lot of compatibility
+**     code by defining one of the following to 1:
+**
+**             __MACOSSEVENFIVEONEORLATER      // assume Mac OS 7.5.1 or later
+**             __MACOSSEVENFIVEORLATER         // assume Mac OS 7.5 or later
+**             __MACOSSEVENORLATER                     // assume Mac OS 7.0 or later
+**
+**     By default, all compatibility code is ON.
+**
+**     2 -- You may disable Pascal calling conventions in all MoreFiles routines
+**     except for system callbacks that require Pascal calling conventions.
+**     This will make C programs both smaller and faster.
+**     Just define __WANTPASCALELIMINATION to be 1 to turn this optimization on
+**     when building MoreFiles for use from C programs (you'll need to keep
+**     Pascal calling conventions when linking MoreFiles routines with Pascal
+**     programs).
+**
+**     3 -- If Metrowerks compiler is used, "#pragma internal on" may help produce
+**     better code. However, this option can also cause problems if you're
+**     trying to build MoreFiles as a shared library, so it is by default not used.
+**     Just define __USEPRAGMAINTERNAL to be 1 to turn this optimization on.
+**
+**     Original changes supplied by Fabrizio Oddone
+**
+**     File:   Optimization.h
+*/
+
+
+#ifndef __MACOSSEVENFIVEONEORLATER
+       #define __MACOSSEVENFIVEONEORLATER 0
+#endif
+
+#ifndef __MACOSSEVENFIVEORLATER
+       #define __MACOSSEVENFIVEORLATER __MACOSSEVENFIVEONEORLATER
+#endif
+
+#ifndef __MACOSSEVENORLATER
+       #if GENERATINGCFM
+               #define __MACOSSEVENORLATER 1
+       #else
+               #define __MACOSSEVENORLATER __MACOSSEVENFIVEORLATER
+       #endif
+#endif
+
+
+#ifndef        __WANTPASCALELIMINATION
+       #define __WANTPASCALELIMINATION 0
+#endif
+
+#if    __WANTPASCALELIMINATION
+       #define pascal  
+#endif
+
+
+#ifndef __USEPRAGMAINTERNAL
+       #define __USEPRAGMAINTERNAL     0
+#endif
+
+#if    __USEPRAGMAINTERNAL
+       #if defined(__MWERKS__)
+               #pragma internal on
+       #endif
+#endif
+
diff --git a/src/mac/morefile/OptimEnd.h b/src/mac/morefile/OptimEnd.h
new file mode 100644 (file)
index 0000000..5cab00a
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     DirectoryCopy: #defines that let you make MoreFiles code more efficient.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           OptimizationEnd.h
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+**
+**     The Optimization changes to MoreFiles source and header files, along with
+**     this file and Optimization.h, let you optimize the code produced by MoreFiles
+**     in several ways.
+**
+**     Original changes supplied by Fabrizio Oddone
+*/
+
+
+#if    __USEPRAGMAINTERNAL
+       #if defined(__MWERKS__)
+               #pragma internal reset
+       #endif
+#endif
+
+
+#if    __WANTPASCALELIMINATION
+       #ifndef __COMPILINGMOREFILES
+               #undef pascal
+       #endif
+#endif
diff --git a/src/mac/morefile/Search.cpp b/src/mac/morefile/Search.cpp
new file mode 100644 (file)
index 0000000..bdcfd9f
--- /dev/null
@@ -0,0 +1,1275 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     IndexedSearch and the PBCatSearch compatibility function.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           Search.c
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#include <Types.h>
+#include <Gestalt.h>
+#include <Timer.h>
+#include <Errors.h>
+#include <Memory.h>
+#include <Files.h>
+#include <TextUtils.h>
+
+#define        __COMPILINGMOREFILES
+
+#include "MoreFile.h"
+#include "MoreExtr.h"
+#include "Search.h"
+
+/*****************************************************************************/
+
+enum
+{
+       /* Number of LevelRecs to add each time the searchStack is grown */
+       /* 20 levels is probably more than reasonable for most volumes. */
+       /* If more are needed, they are allocated 20 levels at a time. */
+       kAdditionalLevelRecs = 20
+};
+
+/*****************************************************************************/
+
+/*
+**     LevelRecs are used to store the directory ID and index whenever
+**     IndexedSearch needs to either scan a sub-directory, or return control
+**     to the caller because the call has timed out or the number of
+**     matches requested has been found. LevelRecs are stored in an array
+**     used as a stack.
+*/
+struct LevelRec
+{
+       long    dirModDate;     /* for detecting most (but not all) catalog changes */
+       long    dirID;
+       short   index;
+};
+typedef struct LevelRec LevelRec;
+typedef LevelRec *LevelRecPtr, **LevelRecHandle;
+
+
+/*
+**     SearchPositionRec is my version of a CatPositionRec. It holds the
+**     information I need to resuming searching.
+*/
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=mac68k
+#endif
+struct SearchPositionRec
+{
+       long                    initialize;             /* Goofy checksum of volume information used to make */
+                                                                       /* sure we're resuming a search on the same volume. */
+       unsigned short  stackDepth;             /* Current depth on searchStack. */
+       short                   priv[11];               /* For future use... */
+};
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=reset
+#endif
+typedef struct SearchPositionRec SearchPositionRec;
+typedef SearchPositionRec *SearchPositionRecPtr;
+
+
+/*
+**     ExtendedTMTask is a TMTask record extended to hold the timer flag.
+*/
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=mac68k
+#endif
+struct ExtendedTMTask
+{
+       TMTask                  theTask;
+       Boolean                 stopSearch;             /* the Time Mgr task will set stopSearch to */
+                                                                       /* true when the timer expires */
+};
+#if PRAGMA_ALIGN_SUPPORTED
+#pragma options align=reset
+#endif
+typedef struct ExtendedTMTask ExtendedTMTask;
+typedef ExtendedTMTask *ExtendedTMTaskPtr;
+
+/*****************************************************************************/
+
+static OSErr   CheckVol(ConstStr255Param pathname,
+                                                short vRefNum,
+                                                short *realVRefNum,
+                                                long *volID);
+
+static OSErr   CheckStack(unsigned short stackDepth,
+                                                  LevelRecHandle searchStack,
+                                                  Size *searchStackSize);
+
+static OSErr   VerifyUserPB(CSParamPtr userPB,
+                                                        Boolean *includeFiles,
+                                                        Boolean *includeDirs,
+                                                        Boolean *includeNames);
+
+static Boolean IsSubString(ConstStr255Param aStringPtr,
+                                                       ConstStr255Param subStringPtr);
+
+static Boolean CompareMasked(const long *data1,
+                                                         const long *data2,
+                                                         const long *mask,
+                                                         short longsToCompare);
+
+static void    CheckForMatches(CInfoPBPtr cPB,
+                                                               CSParamPtr userPB,
+                                                               const Str63 matchName,
+                                                               Boolean includeFiles,
+                                                               Boolean includeDirs);
+
+#if    __WANTPASCALELIMINATION
+#undef pascal
+#endif
+
+#if GENERATINGCFM
+
+static pascal  void    TimeOutTask(TMTaskPtr tmTaskPtr);
+
+#else
+
+static pascal  TMTaskPtr       GetTMTaskPtr(void);
+
+static void    TimeOutTask(void);
+
+#endif
+
+#if    __WANTPASCALELIMINATION
+#define        pascal  
+#endif
+
+static long    GetDirModDate(short vRefNum,
+                                                         long dirID);
+
+/*****************************************************************************/
+
+/*
+**     CheckVol gets the volume's real vRefNum and builds a volID. The volID
+**     is used to help insure that calls to resume searching with IndexedSearch
+**     are to the same volume as the last call to IndexedSearch.
+*/
+static OSErr   CheckVol(ConstStr255Param pathname,
+                                                short vRefNum,
+                                                short *realVRefNum,
+                                                long *volID)
+{
+       HParamBlockRec pb;
+       OSErr error;
+
+       error = GetVolumeInfoNoName(pathname, vRefNum, &pb);
+       if ( error == noErr )
+       {
+               /* Return the real vRefNum */
+               *realVRefNum = pb.volumeParam.ioVRefNum;
+
+               /* Add together a bunch of things that aren't supposed to change on */
+               /* a mounted volume that's being searched and that should come up with */
+               /* a fairly unique number */
+               *volID = pb.volumeParam.ioVCrDate +
+                                pb.volumeParam.ioVRefNum +
+                                pb.volumeParam.ioVNmAlBlks +
+                                pb.volumeParam.ioVAlBlkSiz +
+                                pb.volumeParam.ioVFSID;
+       }
+       return ( error );
+}
+
+/*****************************************************************************/
+
+/*
+**     CheckStack checks the size of the search stack (array) to see if there's
+**     room to push another LevelRec. If not, CheckStack grows the stack by
+**     another kAdditionalLevelRecs elements.
+*/
+static OSErr   CheckStack(unsigned short stackDepth,
+                                                  LevelRecHandle searchStack,
+                                                  Size *searchStackSize)
+{
+       OSErr   result;
+       
+       if ( (*searchStackSize / sizeof(LevelRec)) == (stackDepth + 1) )
+       {
+               /* Time to grow stack */
+               SetHandleSize((Handle)searchStack, *searchStackSize + (kAdditionalLevelRecs * sizeof(LevelRec)));
+               result = MemError();    /* should be noErr */
+               *searchStackSize = InlineGetHandleSize((Handle)searchStack);
+       }
+       else
+       {
+               result = noErr;
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+**     VerifyUserPB makes sure the parameter block passed to IndexedSearch has
+**     valid parameters. By making this check once, we don't have to worry about
+**     things like NULL pointers, strings being too long, etc.
+**     VerifyUserPB also determines if the search includes files and/or
+**     directories, and determines if a full or partial name search was requested.
+*/
+static OSErr   VerifyUserPB(CSParamPtr userPB,
+                                                        Boolean *includeFiles,
+                                                        Boolean *includeDirs,
+                                                        Boolean *includeNames)
+{
+       CInfoPBPtr      searchInfo1;
+       CInfoPBPtr      searchInfo2;
+       
+       searchInfo1 = userPB->ioSearchInfo1;
+       searchInfo2 = userPB->ioSearchInfo2;
+       
+       /* ioMatchPtr cannot be NULL */
+       if ( userPB->ioMatchPtr == NULL )
+       {
+               goto ParamErrExit;
+       }
+       
+       /* ioSearchInfo1 cannot be NULL */
+       if ( searchInfo1 == NULL )
+       {
+               goto ParamErrExit;
+       }
+       
+       /* If any bits except partialName, fullName, or negate are set, then */
+       /* ioSearchInfo2 cannot be NULL because information in ioSearchInfo2 is required  */
+       if ( ((userPB->ioSearchBits & ~(fsSBPartialName | fsSBFullName | fsSBNegate)) != 0) &&
+                ( searchInfo2 == NULL ))
+       {
+               goto ParamErrExit;
+       }
+       
+       *includeFiles = false;
+       *includeDirs = false;
+       *includeNames = false;
+       
+       if ( (userPB->ioSearchBits & (fsSBPartialName | fsSBFullName)) != 0 )
+       {
+               /* If any kind of name matching is requested, then ioNamePtr in */
+               /* ioSearchInfo1 cannot be NULL or a zero-length string */
+               if ( (searchInfo1->hFileInfo.ioNamePtr == NULL) ||
+                        (searchInfo1->hFileInfo.ioNamePtr[0] == 0) ||
+                        (searchInfo1->hFileInfo.ioNamePtr[0] > (sizeof(Str63) - 1)) )
+               {
+                       goto ParamErrExit;
+               }
+               
+               *includeNames = true;
+       }
+       
+       if ( (userPB->ioSearchBits & fsSBFlAttrib) != 0 )
+       {
+               /* The only attributes you can search on are the directory flag */
+               /* and the locked flag. */
+               if ( (searchInfo2->hFileInfo.ioFlAttrib & ~(ioDirMask | 0x01)) != 0 )
+               {
+                       goto ParamErrExit;
+               }
+               
+               /* interested in the directory bit? */
+               if ( (searchInfo2->hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+               {
+                       /* yes, so do they want just directories or just files? */
+                       if ( (searchInfo1->hFileInfo.ioFlAttrib & ioDirMask) != 0 )
+                       {
+                               *includeDirs = true;
+                       }
+                       else
+                       {
+                               *includeFiles = true;
+                       }
+               }
+               else
+               {
+                       /* no interest in directory bit - get both files and directories */
+                       *includeDirs = true;
+                       *includeFiles = true;
+               }
+       }
+       else
+       {
+               /* no attribute checking - get both files and directories */
+               *includeDirs = true;
+               *includeFiles = true;
+       }
+       
+       /* If directories are included in the search, */
+       /* then the locked attribute cannot be requested. */
+       if ( *includeDirs &&
+                ((userPB->ioSearchBits & fsSBFlAttrib) != 0) &&
+                ((searchInfo2->hFileInfo.ioFlAttrib & 0x01) != 0) )
+       {
+               goto ParamErrExit;
+       }
+       
+       /* If files are included in the search, then there cannot be */
+       /* a search on the number of files. */
+       if ( *includeFiles &&
+                ((userPB->ioSearchBits & fsSBDrNmFls) != 0) )
+       {
+               goto ParamErrExit;
+       }
+       
+       /* If directories are included in the search, then there cannot */
+       /* be a search on file lengths. */
+       if ( *includeDirs &&
+                ((userPB->ioSearchBits & (fsSBFlLgLen | fsSBFlPyLen | fsSBFlRLgLen | fsSBFlRPyLen)) != 0) )
+       {
+               goto ParamErrExit;
+       }
+       
+       return ( noErr );
+                
+ParamErrExit:
+       return ( paramErr );
+}
+
+/*****************************************************************************/
+
+/*
+**     IsSubString checks to see if a string is a substring of another string.
+**     Both input strings have already been converted to all uppercase using
+**     UprString (the same non-international call the File Manager uses).
+*/
+static Boolean IsSubString(ConstStr255Param aStringPtr,
+                                                       ConstStr255Param subStringPtr)
+{
+       short   strLength;              /* length of string */
+       short   subStrLength;   /* length of subString */
+       Boolean found;                  /* result of test */
+       short   index;                  /* current index into string */
+       
+       found = false;
+       strLength = aStringPtr[0];
+       subStrLength = subStringPtr[0];
+               
+       if ( subStrLength <= strLength)
+       {
+               register short  count;                  /* search counter */
+               register short  strIndex;               /* running index into string */
+               register short  subStrIndex;    /* running index into subString */
+               
+               /* start looking at first character */
+               index = 1;
+               
+               /* continue looking until remaining string is shorter than substring */
+               count = strLength - subStrLength + 1;
+               
+               do
+               {
+                       strIndex = index;       /* start string index at index */
+                       subStrIndex = 1;        /* start subString index at 1 */
+                       
+                       while ( !found && (aStringPtr[strIndex] == subStringPtr[subStrIndex]) )
+                       {
+                               if ( subStrIndex == subStrLength )
+                               {
+                                       /* all characters in subString were found */
+                                       found = true;
+                               }
+                               else
+                               {
+                                       /* check next character of substring against next character of string */
+                                       ++subStrIndex;
+                                       ++strIndex;
+                               }
+                       }
+                       
+                       if ( !found )
+                       {
+                               /* start substring search again at next string character */
+                               ++index;
+                               --count;
+                       }
+               } while ( count != 0 && (!found) );
+       }
+       
+       return ( found );
+}
+
+/*****************************************************************************/
+
+/*
+**     CompareMasked does a bitwise comparison with mask on 1 or more longs.
+**     data1 and data2 are first exclusive-ORed together resulting with bits set
+**     where they are different. That value is then ANDed with the mask resulting
+**     with bits set if the test fails. true is returned if the tests pass.
+*/
+static Boolean CompareMasked(const long *data1,
+                                                         const long *data2,
+                                                         const long *mask,
+                                                         short longsToCompare)
+{
+       Boolean result = true;
+       
+       while ( (longsToCompare != 0) && (result == true) )
+       {
+               /* (*data1 ^ *data2) = bits that are different, so... */
+               /* ((*data1 ^ *data2) & *mask) = bits that are different that we're interested in */
+               
+               if ( ((*data1 ^ *data2) & *mask) != 0 )
+                       result = false;
+               
+               ++data1;
+               ++data2;
+               ++mask;
+               --longsToCompare;
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+/*
+**     Check for matches compares the search criteria in userPB to the file
+**     system object in cPB. If there's a match, then the information in cPB is
+**     is added to the match array and the actual match count is incremented.
+*/
+static void    CheckForMatches(CInfoPBPtr cPB,
+                                                               CSParamPtr userPB,
+                                                               const Str63 matchName,
+                                                               Boolean includeFiles,
+                                                               Boolean includeDirs)
+{
+       long            searchBits;
+       CInfoPBPtr      searchInfo1;
+       CInfoPBPtr      searchInfo2;
+       Str63           itemName;               /* copy of object's name for partial name matching */
+       Boolean         foundMatch;
+       
+       foundMatch = false;                     /* default to no match */
+       
+       searchBits = userPB->ioSearchBits;
+       searchInfo1 = userPB->ioSearchInfo1;
+       searchInfo2 = userPB->ioSearchInfo2;
+       
+       /* Into the if statements that go on forever... */
+       
+       if ( (cPB->hFileInfo.ioFlAttrib & ioDirMask) == 0 )
+       {
+               if (!includeFiles)
+               {
+                       goto Failed;
+               }
+       }
+       else
+       {
+               if (!includeDirs)
+               {
+                       goto Failed;
+               }
+       }
+       
+       if ( (searchBits & fsSBPartialName) != 0 )
+       {
+               if ( (cPB->hFileInfo.ioNamePtr[0] > 0) &&
+                        (cPB->hFileInfo.ioNamePtr[0] <= (sizeof(Str63) - 1)) )
+               {
+                       /* Make uppercase copy of object name */
+                       BlockMoveData(cPB->hFileInfo.ioNamePtr,
+                                                       itemName,
+                                                       cPB->hFileInfo.ioNamePtr[0] + 1);
+                       /* Use the same non-international call the File Manager uses */
+                       UpperString(itemName, true);
+               }
+               else
+               {
+                       goto Failed;
+               }
+               
+               {
+                       if ( !IsSubString(itemName, matchName) )
+                       {
+                               goto Failed;
+                       }
+                       else if ( searchBits == fsSBPartialName )
+                       {
+                               /* optimize for name matching only since it is most common way to search */
+                               goto Hit;
+                       }
+               }
+       }
+       
+       if ( (searchBits & fsSBFullName) != 0 )
+       {
+               /* Use the same non-international call the File Manager uses */
+               if ( !EqualString(cPB->hFileInfo.ioNamePtr, matchName, false, true) )
+               {
+                       goto Failed;
+               }
+               else if ( searchBits == fsSBFullName )
+               {
+                       /* optimize for name matching only since it is most common way to search */
+                       goto Hit;
+               }
+       }
+       
+       if ( (searchBits & fsSBFlParID) != 0 )
+       {
+               if ( ((unsigned long)(cPB->hFileInfo.ioFlParID) < (unsigned long)(searchInfo1->hFileInfo.ioFlParID)) ||
+                        ((unsigned long)(cPB->hFileInfo.ioFlParID) > (unsigned long)(searchInfo2->hFileInfo.ioFlParID)) )
+               {
+                       goto Failed;
+               }
+       }
+       
+       if ( (searchBits & fsSBFlAttrib) != 0 )
+       {
+               if ( ((cPB->hFileInfo.ioFlAttrib ^ searchInfo1->hFileInfo.ioFlAttrib) &
+                         searchInfo2->hFileInfo.ioFlAttrib) != 0 )
+               {
+                       goto Failed;
+               }
+       }
+       
+       if ( (searchBits & fsSBDrNmFls) != 0 )
+       {
+               if ( ((unsigned long)(cPB->dirInfo.ioDrNmFls) < (unsigned long)(searchInfo1->dirInfo.ioDrNmFls)) ||
+                        ((unsigned long)(cPB->dirInfo.ioDrNmFls) > (unsigned long)(searchInfo2->dirInfo.ioDrNmFls)) )
+               {
+                       goto Failed;
+               }
+       }
+
+       if ( (searchBits & fsSBFlFndrInfo) != 0 )       /* fsSBFlFndrInfo is same as fsSBDrUsrWds */
+       {
+               if ( !CompareMasked((long *)&(cPB->hFileInfo.ioFlFndrInfo),
+                                                       (long *)&(searchInfo1->hFileInfo.ioFlFndrInfo),
+                                                       (long *)&(searchInfo2->hFileInfo.ioFlFndrInfo),
+                                                       sizeof(FInfo) / sizeof(long)) )
+               {
+                       goto Failed;
+               }
+       }
+       
+       if ( (searchBits & fsSBFlXFndrInfo) != 0 )      /* fsSBFlXFndrInfo is same as fsSBDrFndrInfo */
+       {
+               if ( !CompareMasked((long *)&(cPB->hFileInfo.ioFlXFndrInfo),
+                                                       (long *)&(searchInfo1->hFileInfo.ioFlXFndrInfo),
+                                                       (long *)&(searchInfo2->hFileInfo.ioFlXFndrInfo),
+                                                       sizeof(FXInfo) / sizeof(long)) )
+               {
+                       goto Failed;
+               }
+       }
+       
+       if ( (searchBits & fsSBFlLgLen) != 0 )
+       {
+               if ( ((unsigned long)(cPB->hFileInfo.ioFlLgLen) < (unsigned long)(searchInfo1->hFileInfo.ioFlLgLen)) ||
+                        ((unsigned long)(cPB->hFileInfo.ioFlLgLen) > (unsigned long)(searchInfo2->hFileInfo.ioFlLgLen)) )
+               {
+                       goto Failed;
+               }
+       }
+
+       if ( (searchBits & fsSBFlPyLen) != 0 )
+       {
+               if ( ((unsigned long)(cPB->hFileInfo.ioFlPyLen) < (unsigned long)(searchInfo1->hFileInfo.ioFlPyLen)) ||
+                        ((unsigned long)(cPB->hFileInfo.ioFlPyLen) > (unsigned long)(searchInfo2->hFileInfo.ioFlPyLen)) )
+               {
+                       goto Failed;
+               }
+       }
+
+       if ( (searchBits & fsSBFlRLgLen) != 0 )
+       {
+               if ( ((unsigned long)(cPB->hFileInfo.ioFlRLgLen) < (unsigned long)(searchInfo1->hFileInfo.ioFlRLgLen)) ||
+                        ((unsigned long)(cPB->hFileInfo.ioFlRLgLen) > (unsigned long)(searchInfo2->hFileInfo.ioFlRLgLen)) )
+               {
+                       goto Failed;
+               }
+       }
+
+       if ( (searchBits & fsSBFlRPyLen) != 0 )
+       {
+               if ( ((unsigned long)(cPB->hFileInfo.ioFlRPyLen) < (unsigned long)(searchInfo1->hFileInfo.ioFlRPyLen)) ||
+                        ((unsigned long)(cPB->hFileInfo.ioFlRPyLen) > (unsigned long)(searchInfo2->hFileInfo.ioFlRPyLen)) )
+               {
+                       goto Failed;
+               }
+       }
+
+       if ( (searchBits & fsSBFlCrDat) != 0 )  /* fsSBFlCrDat is same as fsSBDrCrDat */
+       {
+               if ( ((unsigned long)(cPB->hFileInfo.ioFlCrDat) < (unsigned long)(searchInfo1->hFileInfo.ioFlCrDat)) ||
+                        ((unsigned long)(cPB->hFileInfo.ioFlCrDat) > (unsigned long)(searchInfo2->hFileInfo.ioFlCrDat)) )
+               {
+                       goto Failed;
+               }
+       }
+
+       if ( (searchBits & fsSBFlMdDat) != 0 )  /* fsSBFlMdDat is same as fsSBDrMdDat */
+       {
+               if ( ((unsigned long)(cPB->hFileInfo.ioFlMdDat) < (unsigned long)(searchInfo1->hFileInfo.ioFlMdDat)) ||
+                        ((unsigned long)(cPB->hFileInfo.ioFlMdDat) > (unsigned long)(searchInfo2->hFileInfo.ioFlMdDat)) )
+               {
+                       goto Failed;
+               }
+       }
+
+       if ( (searchBits & fsSBFlBkDat) != 0 )  /* fsSBFlBkDat is same as fsSBDrBkDat */
+       {
+               if ( ((unsigned long)(cPB->hFileInfo.ioFlBkDat) < (unsigned long)(searchInfo1->hFileInfo.ioFlBkDat)) ||
+                        ((unsigned long)(cPB->hFileInfo.ioFlBkDat) > (unsigned long)(searchInfo2->hFileInfo.ioFlBkDat)) )
+               {
+                       goto Failed;
+               }
+       }
+
+       /* Hey, we passed all of the tests! */
+       
+Hit:
+       foundMatch = true;
+
+/* foundMatch is false if code jumps to Failed */
+Failed:
+       /* Do we reverse our findings? */
+       if ( (searchBits & fsSBNegate) != 0 )
+       {
+               foundMatch = !foundMatch;       /* matches are not, not matches are */
+       }
+       
+       if ( foundMatch )
+       {
+
+               /* Move the match into the match buffer */
+               userPB->ioMatchPtr[userPB->ioActMatchCount].vRefNum = cPB->hFileInfo.ioVRefNum;
+               userPB->ioMatchPtr[userPB->ioActMatchCount].parID = cPB->hFileInfo.ioFlParID;
+               if ( cPB->hFileInfo.ioNamePtr[0] > 63 )
+               {
+                       cPB->hFileInfo.ioNamePtr[0] = 63;
+               }
+               BlockMoveData(cPB->hFileInfo.ioNamePtr,
+                                         userPB->ioMatchPtr[userPB->ioActMatchCount].name,
+                                         cPB->hFileInfo.ioNamePtr[0] + 1);
+               
+               /* increment the actual count */
+               ++(userPB->ioActMatchCount);
+       }
+}
+
+/*****************************************************************************/
+
+/*
+**     TimeOutTask is executed when the timer goes off. It simply sets the
+**     stopSearch field to true. After each object is found and possibly added
+**     to the matches buffer, stopSearch is checked to see if the search should
+**     continue.
+*/
+
+#if    __WANTPASCALELIMINATION
+#undef pascal
+#endif
+
+#if GENERATINGCFM
+
+static pascal  void    TimeOutTask(TMTaskPtr tmTaskPtr)
+{
+       ((ExtendedTMTaskPtr)tmTaskPtr)->stopSearch = true;
+}
+
+#else
+
+static pascal  TMTaskPtr       GetTMTaskPtr(void)
+       ONEWORDINLINE(0x2e89);  /* MOVE.L A1,(SP) */
+       
+static void    TimeOutTask(void)
+{
+       ((ExtendedTMTaskPtr)GetTMTaskPtr())->stopSearch = true;
+}
+
+#endif
+
+#if    __WANTPASCALELIMINATION
+#define        pascal  
+#endif
+
+/*****************************************************************************/
+
+/*
+**     GetDirModDate returns the modification date of a directory. If there is
+**     an error getting the modification date, -1 is returned to indicate
+**     something went wrong.
+*/
+static long    GetDirModDate(short vRefNum,
+                                                         long dirID)
+{
+       CInfoPBRec pb;
+       Str31 tempName;
+       long modDate;
+
+       /* Protection against File Sharing problem */
+       tempName[0] = 0;
+       pb.dirInfo.ioNamePtr = tempName;
+       pb.dirInfo.ioVRefNum = vRefNum;
+       pb.dirInfo.ioDrDirID = dirID;
+       pb.dirInfo.ioFDirIndex = -1;    /* use ioDrDirID */
+       
+       if ( PBGetCatInfoSync(&pb) == noErr )
+       {
+               modDate = pb.dirInfo.ioDrMdDat;
+       }
+       else
+       {
+               modDate = -1;
+       }
+       
+       return ( modDate );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   IndexedSearch(CSParamPtr pb,
+                                                         long dirID)
+{
+       static LevelRecHandle   searchStack = NULL;             /* static handle to LevelRec stack */
+       static Size                             searchStackSize = 0;    /* size of static handle */
+       SearchPositionRecPtr    catPosition;
+       long                                    modDate;
+       short                                   index;
+       ExtendedTMTask                  timerTask;
+       OSErr                                   result;
+       short                                   realVRefNum;
+       Str63                                   itemName;
+       CInfoPBRec                              cPB;
+       long                                    tempLong;
+       Boolean                                 includeFiles;
+       Boolean                                 includeDirs;
+       Boolean                                 includeNames;
+       Str63                                   upperName;
+       
+       timerTask.stopSearch = false;   /* don't stop yet! */
+       
+       /* If request has a timeout, install a Time Manager task. */
+       if ( pb->ioSearchTime != 0 )
+       {
+               /* Start timer */
+               timerTask.theTask.tmAddr = NewTimerProc(TimeOutTask);
+               InsTime((QElemPtr)&(timerTask.theTask));
+               PrimeTime((QElemPtr)&(timerTask.theTask), pb->ioSearchTime);
+       }
+       
+       /* Check the parameter block passed for things that we don't want to assume */
+       /* are OK later in the code. For example, make sure pointers to data structures */
+       /* and buffers are not NULL.  And while we're in there, see if the request */
+       /* specified searching for files, directories, or both, and see if the search */
+       /* was by full or partial name. */
+       result = VerifyUserPB(pb, &includeFiles, &includeDirs, &includeNames);
+       if ( result == noErr )
+       {
+               pb->ioActMatchCount = 0;        /* no matches yet */
+       
+               if ( includeNames )
+               {
+                       /* The search includes seach by full or partial name. */
+                       /* Make an upper case copy of the match string to pass to */
+                       /* CheckForMatches. */
+                       BlockMoveData(pb->ioSearchInfo1->hFileInfo.ioNamePtr,
+                                                       upperName,
+                                                       pb->ioSearchInfo1->hFileInfo.ioNamePtr[0] + 1);
+                       /* Use the same non-international call the File Manager uses */
+                       UpperString(upperName, true);
+               }
+               
+               /* Prevent casting to my type throughout code */
+               catPosition = (SearchPositionRecPtr)&pb->ioCatPosition;
+               
+               /* Create searchStack first time called */
+               if ( searchStack == NULL )
+               {
+                       searchStack = (LevelRecHandle)NewHandle(kAdditionalLevelRecs * sizeof(LevelRec));
+               }
+               
+               /* Make sure searchStack really exists */
+               if ( searchStack != NULL )
+               {
+                       searchStackSize = InlineGetHandleSize((Handle)searchStack);
+                       
+                       /* See if the search is a new search or a resumed search. */
+                       if ( catPosition->initialize == 0 )
+                       {
+                               /* New search. */
+                               
+                               /* Get the real vRefNum and fill in catPosition->initialize. */ 
+                               result = CheckVol(pb->ioNamePtr, pb->ioVRefNum, &realVRefNum, &catPosition->initialize);
+                               if ( result == noErr )
+                               {
+                                       /* clear searchStack */
+                                       catPosition->stackDepth = 0;
+                                       
+                                       /* use dirID parameter passed and... */
+                                       index = -1;     /* start with the passed directory itself! */
+                               }
+                       }
+                       else
+                       {
+                               /* We're resuming a search. */
+       
+                               /* Get the real vRefNum and make sure catPosition->initialize is valid. */ 
+                               result = CheckVol(pb->ioNamePtr, pb->ioVRefNum, &realVRefNum, &tempLong);
+                               if ( result == noErr )
+                               {
+                                       /* Make sure the resumed search is to the same volume! */
+                                       if ( catPosition->initialize == tempLong )
+                                       {
+                                               /* For resume, catPosition->stackDepth > 0 */
+                                               if ( catPosition->stackDepth > 0 )
+                                               {
+                                                       /* Position catPosition->stackDepth to access last saved level */
+                                                       --(catPosition->stackDepth);
+                       
+                                                       /* Get the dirID and index for the next item */
+                                                       dirID = (*searchStack)[catPosition->stackDepth].dirID;
+                                                       index = (*searchStack)[catPosition->stackDepth].index;
+                                                       
+                                                       /* Check the dir's mod date against the saved mode date on our "stack" */
+                                                       modDate = GetDirModDate(realVRefNum, dirID);
+                                                       if ( modDate != (*searchStack)[catPosition->stackDepth].dirModDate )
+                                                       {
+                                                               result = catChangedErr;
+                                                       }
+                                               }
+                                               else
+                                               {
+                                                       /* Invalid catPosition record was passed */
+                                                       result = paramErr;
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* The volume is not the same */
+                                               result = catChangedErr;
+                                       }
+                               }
+                       }
+                       
+                       if ( result == noErr )
+                       {
+                               /* ioNamePtr and ioVRefNum only need to be set up once. */
+                               cPB.hFileInfo.ioNamePtr = itemName;
+                               cPB.hFileInfo.ioVRefNum = realVRefNum;
+                               
+                               /*
+                               **      Here's the loop that:
+                               **              Finds the next item on the volume.
+                               **              If noErr, calls the code to check for matches and add matches
+                               **                      to the match buffer.
+                               **              Sets up dirID and index for to find the next item on the volume.
+                               **
+                               **      The looping ends when:
+                               **              (a) an unexpected error is returned by PBGetCatInfo. All that
+                               **                      is expected is noErr and fnfErr (after the last item in a
+                               **                      directory is found).
+                               **              (b) the caller specified a timeout and our Time Manager task
+                               **                      has fired.
+                               **              (c) the number of matches requested by the caller has been found.
+                               **              (d) the last item on the volume was found.
+                               */
+                               do
+                               {
+                                       /* get the next item */
+                                       cPB.hFileInfo.ioFDirIndex = index;
+                                       cPB.hFileInfo.ioDirID = dirID;
+                                       result = PBGetCatInfoSync(&cPB);
+                                       if ( index != -1 )
+                                       {
+                                               if ( result == noErr )
+                                               {
+                                                       /* We found something */
+               
+                                                       CheckForMatches(&cPB, pb, upperName, includeFiles, includeDirs);
+                                                       
+                                                       ++index;
+                                                       if ( (cPB.dirInfo.ioFlAttrib & ioDirMask) != 0 )
+                                                       {
+                                                               /* It's a directory */
+                                                               
+                                                               result = CheckStack(catPosition->stackDepth, searchStack, &searchStackSize);
+                                                               if ( result == noErr )
+                                                               {
+                                                                       /* Save the current state on the searchStack */
+                                                                       /* when we come back, this is where we'll start */
+                                                                       (*searchStack)[catPosition->stackDepth].dirID = dirID;
+                                                                       (*searchStack)[catPosition->stackDepth].index = index;
+                                                                       (*searchStack)[catPosition->stackDepth].dirModDate = GetDirModDate(realVRefNum, dirID);
+                                                                       
+                                                                       /* position catPosition->stackDepth for next saved level */
+                                                                       ++(catPosition->stackDepth);
+                                                                       
+                                                                       /* The next item to get is the 1st item in the child directory */
+                                                                       dirID = cPB.dirInfo.ioDrDirID;
+                                                                       index = 1;
+                                                               }
+                                                       }
+                                                       /* else do nothing for files */
+                                               }
+                                               else
+                                               {
+                                                       /* End of directory found (or we had some error and that */
+                                                       /* means we have to drop out of this directory). */
+                                                       /* Restore last thing put on stack and */
+                                                       /* see if we need to continue or quit. */
+                                                       if ( catPosition->stackDepth > 0 )
+                                                       {
+                                                               /* position catPosition->stackDepth to access last saved level */
+                                                               --(catPosition->stackDepth);
+                                                               
+                                                               dirID = (*searchStack)[catPosition->stackDepth].dirID;
+                                                               index = (*searchStack)[catPosition->stackDepth].index;
+                                                               
+                                                               /* Check the dir's mod date against the saved mode date on our "stack" */
+                                                               modDate = GetDirModDate(realVRefNum, dirID);
+                                                               if ( modDate != (*searchStack)[catPosition->stackDepth].dirModDate )
+                                                               {
+                                                                       result = catChangedErr;
+                                                               }
+                                                               else
+                                                               {
+                                                                       /* Going back to ancestor directory. */
+                                                                       /* Clear error so we can continue. */
+                                                                       result = noErr;
+                                                               }
+                                                       }
+                                                       else
+                                                       {
+                                                               /* We hit the bottom of the stack, so we'll let the */
+                                                               /* the eofErr drop us out of the loop. */
+                                                               result = eofErr;
+                                                       }
+                                               }
+                                       }
+                                       else
+                                       {
+                                               /* Special case for index == -1; that means that we're starting */
+                                               /* a new search and so the first item to check is the directory */
+                                               /* passed to us. */
+                                               if ( result == noErr )
+                                               {
+                                                       /* We found something */
+               
+                                                       CheckForMatches(&cPB, pb, upperName, includeFiles, includeDirs);
+                                                       
+                                                       /* Now, set the index to 1 and then we're ready to look inside */
+                                                       /* the passed directory. */
+                                                       index = 1;
+                                               }
+                                       }
+                               } while ( (!timerTask.stopSearch) &&    /* timer hasn't fired */
+                                                 (result == noErr) &&                  /* no unexpected errors */
+                                                 (pb->ioReqMatchCount > pb->ioActMatchCount) ); /* we haven't found our limit */
+                               
+                               /* Did we drop out of the loop because of timeout or */
+                               /* ioReqMatchCount was found? */
+                               if ( result == noErr )
+                               {
+                                       result = CheckStack(catPosition->stackDepth, searchStack, &searchStackSize);
+                                       if ( result == noErr )
+                                       {
+                                               /* Either there was a timeout or ioReqMatchCount was reached. */
+                                               /* Save the dirID and index for the next time we're called. */
+                                               
+                                               (*searchStack)[catPosition->stackDepth].dirID = dirID;
+                                               (*searchStack)[catPosition->stackDepth].index = index;
+                                               (*searchStack)[catPosition->stackDepth].dirModDate = GetDirModDate(realVRefNum, dirID);
+                                               
+                                               /* position catPosition->stackDepth for next saved level */
+                                               
+                                               ++(catPosition->stackDepth);
+                                       }
+                               }
+                       }
+               }
+               else
+               {
+                       /* searchStack Handle could not be allocated */
+                       result = memFullErr;
+               }
+       }
+       
+       if ( pb->ioSearchTime != 0 )
+       {
+               /* Stop Time Manager task here if it was installed */
+               RmvTime((QElemPtr)&(timerTask.theTask));
+               DisposeRoutineDescriptor(timerTask.theTask.tmAddr);
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr PBCatSearchSyncCompat(CSParamPtr paramBlock)
+{
+       static Boolean                  fullExtFSDispatchingtested = false;
+       static Boolean                  hasFullExtFSDispatching = false;
+       OSErr                                   result;
+       Boolean                                 supportsCatSearch;
+       long                                    response;
+       GetVolParmsInfoBuffer   volParmsInfo;
+       long                                    infoSize;
+       
+       result = noErr;
+
+       /* See if File Manager will pass CatSearch requests to external file systems */
+       /* we'll store the results in a static variable so we don't have to call Gestalt */
+       /* everytime we're called. */
+       if ( !fullExtFSDispatchingtested )
+       {
+               fullExtFSDispatchingtested = true;
+               if ( Gestalt(gestaltFSAttr, &response) == noErr )
+               {
+                       hasFullExtFSDispatching = ((response & (1L << gestaltFullExtFSDispatching)) != 0);
+               }
+       }
+       
+       /* CatSearch is a per volume attribute, so we have to check each time we're */
+       /* called to see if it is available on the volume specified. */
+       supportsCatSearch = false;
+       if ( hasFullExtFSDispatching )
+       {
+               infoSize = sizeof(GetVolParmsInfoBuffer);
+               result = HGetVolParms(paramBlock->ioNamePtr, paramBlock->ioVRefNum,
+                                                       &volParmsInfo, &infoSize);
+               if ( result == noErr )
+               {
+                       supportsCatSearch = hasCatSearch(volParmsInfo);
+               }
+       }
+       
+       /* noErr or paramErr is OK here. */
+       /* paramErr just means that GetVolParms isn't supported by this volume */
+       if ( (result == noErr) || (result == paramErr) )
+       {
+               if ( supportsCatSearch )
+               {
+                       /* Volume supports CatSearch so use it. */
+                       /* CatSearch is faster than an indexed search. */
+                       result = PBCatSearchSync(paramBlock);
+               }
+               else
+               {
+                       /* Volume doesn't support CatSearch so */
+                       /* search using IndexedSearch from root directory. */
+                       result = IndexedSearch(paramBlock, fsRtDirID);
+               }
+       }
+       
+       return ( result );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   NameFileSearch(ConstStr255Param volName,
+                                                          short vRefNum,
+                                                          ConstStr255Param fileName,
+                                                          FSSpecPtr matches,
+                                                          long reqMatchCount,
+                                                          long *actMatchCount,
+                                                          Boolean newSearch,
+                                                          Boolean partial)
+{
+       CInfoPBRec              searchInfo1, searchInfo2;
+       HParamBlockRec  pb;
+       OSErr                   error;
+       static CatPositionRec catPosition;
+       static short    lastVRefNum = 0;
+       
+       /* get the real volume reference number */
+       error = DetermineVRefNum(volName, vRefNum, &vRefNum);
+       if ( error != noErr )
+               return ( error );
+       
+       pb.csParam.ioNamePtr = NULL;
+       pb.csParam.ioVRefNum = vRefNum;
+       pb.csParam.ioMatchPtr = matches;
+       pb.csParam.ioReqMatchCount = reqMatchCount;
+       if ( partial )  /* tell CatSearch what we're looking for: */
+       {
+               pb.csParam.ioSearchBits = fsSBPartialName + fsSBFlAttrib;       /* partial name file matches or */
+       }
+       else
+       {
+               pb.csParam.ioSearchBits =  fsSBFullName + fsSBFlAttrib;         /* full name file matches */
+       }
+       pb.csParam.ioSearchInfo1 = &searchInfo1;
+       pb.csParam.ioSearchInfo2 = &searchInfo2;
+       pb.csParam.ioSearchTime = 0;
+       if ( (newSearch) ||                             /* If caller specified new search */
+                (lastVRefNum != vRefNum) )     /* or if last search was to another volume, */
+       {
+               catPosition.initialize = 0;     /* then search from beginning of catalog */
+       }
+       pb.csParam.ioCatPosition = catPosition;
+       pb.csParam.ioOptBuffer = GetTempBuffer(0x00004000, &pb.csParam.ioOptBufSize);
+
+       /* search for fileName */
+       searchInfo1.hFileInfo.ioNamePtr = (StringPtr)fileName;
+       searchInfo2.hFileInfo.ioNamePtr = NULL;
+       
+       /* only match files (not directories) */
+       searchInfo1.hFileInfo.ioFlAttrib = 0x00;
+       searchInfo2.hFileInfo.ioFlAttrib = ioDirMask;
+
+       error = PBCatSearchSyncCompat((CSParamPtr)&pb);
+       
+       if ( (error == noErr) ||                                                        /* If no errors or the end of catalog was */
+                (error == eofErr) )                                                    /* found, then the call was successful so */
+       {
+               *actMatchCount = pb.csParam.ioActMatchCount;    /* return the match count */
+       }
+       else
+       {
+               *actMatchCount = 0;                                                     /* else no matches found */
+       }
+       
+       if ( (error == noErr) ||                                                /* If no errors */
+                (error == catChangedErr) )                                     /* or there was a change in the catalog */
+       {
+               catPosition = pb.csParam.ioCatPosition;
+               lastVRefNum = vRefNum;
+                       /* we can probably start the next search where we stopped this time */
+       }
+       else
+       {
+               catPosition.initialize = 0;
+                       /* start the next search from beginning of catalog */
+       }
+       
+       if ( pb.csParam.ioOptBuffer != NULL )
+       {
+               DisposePtr(pb.csParam.ioOptBuffer);
+       }
+               
+       return ( error );
+}
+
+/*****************************************************************************/
+
+pascal OSErr   CreatorTypeFileSearch(ConstStr255Param volName,
+                                                                         short vRefNum,
+                                                                         OSType creator,
+                                                                         OSType fileType,
+                                                                         FSSpecPtr matches,
+                                                                         long reqMatchCount,
+                                                                         long *actMatchCount,
+                                                                         Boolean newSearch)
+{
+       CInfoPBRec              searchInfo1, searchInfo2;
+       HParamBlockRec  pb;
+       OSErr                   error;
+       static CatPositionRec catPosition;
+       static short    lastVRefNum = 0;
+       
+       /* get the real volume reference number */
+       error = DetermineVRefNum(volName, vRefNum, &vRefNum);
+       if ( error != noErr )
+               return ( error );
+       
+       pb.csParam.ioNamePtr = NULL;
+       pb.csParam.ioVRefNum = vRefNum;
+       pb.csParam.ioMatchPtr = matches;
+       pb.csParam.ioReqMatchCount = reqMatchCount;
+       pb.csParam.ioSearchBits = fsSBFlAttrib + fsSBFlFndrInfo;        /* Looking for finder info file matches */
+       pb.csParam.ioSearchInfo1 = &searchInfo1;
+       pb.csParam.ioSearchInfo2 = &searchInfo2;
+       pb.csParam.ioSearchTime = 0;
+       if ( (newSearch) ||                             /* If caller specified new search */
+                (lastVRefNum != vRefNum) )     /* or if last search was to another volume, */
+       {
+               catPosition.initialize = 0;     /* then search from beginning of catalog */
+       }
+       pb.csParam.ioCatPosition = catPosition;
+       pb.csParam.ioOptBuffer = GetTempBuffer(0x00004000, &pb.csParam.ioOptBufSize);
+
+       /* no fileName */
+       searchInfo1.hFileInfo.ioNamePtr = NULL;
+       searchInfo2.hFileInfo.ioNamePtr = NULL;
+       
+       /* only match files (not directories) */
+       searchInfo1.hFileInfo.ioFlAttrib = 0x00;
+       searchInfo2.hFileInfo.ioFlAttrib = ioDirMask;
+       
+       /* search for creator; if creator = 0x00000000, ignore creator */
+       searchInfo1.hFileInfo.ioFlFndrInfo.fdCreator = creator;
+       if ( creator == (OSType)0x00000000 )
+       {
+               searchInfo2.hFileInfo.ioFlFndrInfo.fdCreator = (OSType)0x00000000;
+       }
+       else
+       {
+               searchInfo2.hFileInfo.ioFlFndrInfo.fdCreator = (OSType)0xffffffff;
+       }
+       
+       /* search for fileType; if fileType = 0x00000000, ignore fileType */
+       searchInfo1.hFileInfo.ioFlFndrInfo.fdType = fileType;
+       if ( fileType == (OSType)0x00000000 )
+       {
+               searchInfo2.hFileInfo.ioFlFndrInfo.fdType = (OSType)0x00000000;
+       }
+       else
+       {
+               searchInfo2.hFileInfo.ioFlFndrInfo.fdType = (OSType)0xffffffff;
+       }
+       
+       /* zero all other FInfo fields */
+       searchInfo1.hFileInfo.ioFlFndrInfo.fdFlags = 0;
+       searchInfo1.hFileInfo.ioFlFndrInfo.fdLocation.v = 0;
+       searchInfo1.hFileInfo.ioFlFndrInfo.fdLocation.h = 0;
+       searchInfo1.hFileInfo.ioFlFndrInfo.fdFldr = 0;
+       
+       searchInfo2.hFileInfo.ioFlFndrInfo.fdFlags = 0;
+       searchInfo2.hFileInfo.ioFlFndrInfo.fdLocation.v = 0;
+       searchInfo2.hFileInfo.ioFlFndrInfo.fdLocation.h = 0;
+       searchInfo2.hFileInfo.ioFlFndrInfo.fdFldr = 0;
+
+       error = PBCatSearchSyncCompat((CSParamPtr)&pb);
+       
+       if ( (error == noErr) ||                                                        /* If no errors or the end of catalog was */
+                (error == eofErr) )                                                    /* found, then the call was successful so */
+       {
+               *actMatchCount = pb.csParam.ioActMatchCount;    /* return the match count */
+       }
+       else
+       {
+               *actMatchCount = 0;                                                     /* else no matches found */
+       }
+       
+       if ( (error == noErr) ||                                                /* If no errors */
+                (error == catChangedErr) )                                     /* or there was a change in the catalog */
+       {
+               catPosition = pb.csParam.ioCatPosition;
+               lastVRefNum = vRefNum;
+                       /* we can probably start the next search where we stopped this time */
+       }
+       else
+       {
+               catPosition.initialize = 0;
+                       /* start the next search from beginning of catalog */
+       }
+       
+       if ( pb.csParam.ioOptBuffer != NULL )
+       {
+               DisposePtr(pb.csParam.ioOptBuffer);
+       }
+               
+       return ( error );
+}
+
+/*****************************************************************************/
diff --git a/src/mac/morefile/Search.h b/src/mac/morefile/Search.h
new file mode 100644 (file)
index 0000000..fe79c12
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+**     Apple Macintosh Developer Technical Support
+**
+**     IndexedSearch and the PBCatSearch compatibility function.
+**
+**     by Jim Luther, Apple Developer Technical Support Emeritus
+**
+**     File:           Search.h
+**
+**     Copyright © 1992-1998 Apple Computer, Inc.
+**     All rights reserved.
+**
+**     You may incorporate this sample code into your applications without
+**     restriction, though the sample code has been provided "AS IS" and the
+**     responsibility for its operation is 100% yours.  However, what you are
+**     not permitted to do is to redistribute the source as "DSC Sample Code"
+**     after having made changes. If you're going to re-distribute the source,
+**     we require that you make it clear in the source that the code was
+**     descended from Apple Sample Code, but that you've made changes.
+*/
+
+#ifndef __SEARCH__
+#define __SEARCH__
+
+#include <Types.h>
+#include <Files.h>
+
+#include "Optim.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*****************************************************************************/
+
+pascal OSErr   IndexedSearch(CSParamPtr pb,
+                                                         long dirID);
+/*     ¦ Search in and below a directory.
+       The IndexedSearch function performs an indexed search in and below the
+       specified directory using the same parameters (in pb) as is passed to
+       PBCatSearch. See Inside Macintosh: Files for a description of the
+       parameter block.
+       
+       pb                      input:  A CSParamPtr record specifying the volume to search
+                                               and the search criteria.
+                               output: Fields in the parameter block are returned indicating
+                                               the number of matches found, the matches, and if the
+                                               search ended with noErr, the CatPosition record that
+                                               lets you resume a search where the last search left
+                                               off.
+       dirID           input:  The directory to search. If fsRtDirID is passed,
+                                               the entire volume is searched.
+       
+       Note:   If you use a high-level debugger and use ioSearchTime to limit
+                       the length of time to run the search, you'll want to step over
+                       calls to IndexedSearch because it installs a Time Manager task.
+                       Most high-level debuggers don't deal gracefully with interrupt
+                       driven code.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               eofErr                          -39             End of catalog found (this is normal!)
+               paramErr                        -50             Parameter block has invalid parameters
+                                                                       (see source for VerifyUserPB) or
+                                                                       invalid catPosition record was passed
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               memFullErr                      -108    Memory could not be allocated in heap
+               catChangedErr           -1304   Catalog has changed and catalog position
+                                                                       record may be invalid
+       
+       __________
+       
+       See also:       PBCatSearch, PBCatSearchSyncCompat
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   PBCatSearchSyncCompat(CSParamPtr paramBlock);
+/*     ¦ Search a volume using PBCatSearch or IndexedSearch.
+       The PBCatSearchSyncCompat function uses PBCatSearch (if available) or
+       IndexedSearch (if PBCatSearch is not available) to search a volume
+       using a set of search criteria that you specify. It builds a list of all
+       files or directories that meet your specifications.
+       
+       pb                      input:  A CSParamPtr record specifying the volume to search
+                                               and the search criteria.
+                               output: Fields in the parameter block are returned indicating
+                                               the number of matches found, the matches, and if the
+                                               search ended with noErr, the CatPosition record that
+                                               lets you resume a search where the last search left
+                                               off.
+       
+       Note:   If you use a high-level debugger and use ioSearchTime to limit
+                       the length of time to run the search, you'll want to step over
+                       calls to PBCatSearchSyncCompat because it calls IndexedSearch
+                       which installs a Time Manager task. Most high-level debuggers
+                       don't deal gracefully with interrupt driven code.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               eofErr                          -39             End of catalog found (this is normal!)
+               paramErr                        -50             Parameter block has invalid parameters
+                                                                       (see source for VerifyUserPB) or
+                                                                       invalid catPosition record was passed
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               memFullErr                      -108    Memory could not be allocated in heap
+               catChangedErr           -1304   Catalog has changed and catalog position
+                                                                       record may be invalid
+               afpCatalogChanged       -5037   Catalog has changed and search cannot
+                                                                       be resumed
+       
+       __________
+       
+       See also:       PBCatSearch, IndexedSearch
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   NameFileSearch(ConstStr255Param volName,
+                                                          short vRefNum,
+                                                          ConstStr255Param fileName,
+                                                          FSSpecPtr matches,
+                                                          long reqMatchCount,
+                                                          long *actMatchCount,
+                                                          Boolean newSearch,
+                                                          Boolean partial);
+/*     ¦ Search for files by file name with PBCatSearch.
+       The NameFileSearch function searches for files with a specific file
+       name on a volume that supports PBCatSearch.
+       Note: A result of catChangedErr means the catalog has changed between
+       searches, but the search can be continued with the possiblity that you
+       may miss some matches or get duplicate matches.  For all other results
+       (except for noErr), the search cannot be continued.
+
+       volName                 input:  A pointer to the name of a mounted volume
+                                                       or nil.
+       vRefNum                 input:  Volume specification.
+       fileName                input:  The name of the file to search for.
+       matches                 input:  Pointer to array of FSSpec where the match list is
+                                                       returned.
+       reqMatchCount   input:  Maximum number of matches to return     (the number of
+                                                       elements in the matches array).
+       actMatchCount   output: The number of matches actually returned.
+       newSearch               input:  If true, start a new search. If false and if
+                                                       vRefNum is the same as the last call to
+                                                       NameFileSearch, then start searching at the
+                                                       position where the last search left off.
+       partial                 input:  If the partial parameter is false, then only files
+                                                       that exactly match fileName will be found.  If the
+                                                       partial parameter is true, then all file names that
+                                                       contain fileName will be found.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               eofErr                          -39             End of catalog found (this is normal!)
+               paramErr                        -50             Parameter block has invalid parameters
+                                                                       (see source for VerifyUserPB) or
+                                                                       invalid catPosition record was passed
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               memFullErr                      -108    Memory could not be allocated in heap
+               catChangedErr           -1304   Catalog has changed and catalog position
+                                                                       record may be invalid
+               afpCatalogChanged       -5037   Catalog has changed and search cannot
+                                                                       be resumed
+       
+       __________
+       
+       Also see:       CreatorTypeFileSearch
+*/
+
+/*****************************************************************************/
+
+pascal OSErr   CreatorTypeFileSearch(ConstStr255Param volName,
+                                                                         short vRefNum,
+                                                                         OSType creator,
+                                                                         OSType fileType,
+                                                                         FSSpecPtr matches,
+                                                                         long reqMatchCount,
+                                                                         long *actMatchCount,
+                                                                         Boolean newSearch);
+/*     ¦ Search for files by creator/fileType with PBCatSearch.
+       The CreatorTypeFileSearch function searches for files with a specific
+       creator or fileType on a volume that supports PBCatSearch.
+       Note: A result of catChangedErr means the catalog has changed between
+       searches, but the search can be continued with the possiblity that you
+       may miss some matches or get duplicate matches.  For all other results
+       (except for noErr), the search cannot be continued.
+
+       volName                 input:  A pointer to the name of a mounted volume
+                                                       or nil.
+       vRefNum                 input:  Volume specification.
+       creator                 input:  The creator type of the file to search for.
+                                                       To ignore the creator type, pass 0x00000000 in
+                                                       this field.
+       fileType                input:  The file type of the file to search for.
+                                                       To ignore the file type, pass 0x00000000 in
+                                                       this field.
+       matches                 input:  Pointer to array of FSSpec where the match list is
+                                                       returned.
+       reqMatchCount   input:  Maximum number of matches to return     (the number of
+                                                       elements in the matches array).
+       actMatchCount   output: The number of matches actually returned.
+       newSearch               input:  If true, start a new search. If false and if
+                                                       vRefNum is the same as the last call to
+                                                       CreatorTypeFileSearch, then start searching at the
+                                                       position where the last search left off.
+       
+       Result Codes
+               noErr                           0               No error
+               nsvErr                          -35             Volume not found
+               ioErr                           -36             I/O error
+               eofErr                          -39             End of catalog found (this is normal!)
+               paramErr                        -50             Parameter block has invalid parameters
+                                                                       (see source for VerifyUserPB) or
+                                                                       invalid catPosition record was passed
+               extFSErr                        -58             External file system error - no file
+                                                                       system claimed this call.
+               memFullErr                      -108    Memory could not be allocated in heap
+               catChangedErr           -1304   Catalog has changed and catalog position
+                                                                       record may be invalid
+               afpCatalogChanged       -5037   Catalog has changed and search cannot
+                                                                       be resumed
+       
+       __________
+       
+       Also see:       NameFileSearch
+*/
+
+/*****************************************************************************/
+
+#ifdef __cplusplus
+}
+#endif
+
+#include "OptimEnd.h"
+
+#endif /* __SEARCH__ */
index 4a0fabde9453f3f18fa6ac2232b381ba41d01229..4f2472ee1f4322adb5698199af94548660d81fcc 100644 (file)
Binary files a/src/make_cw.mcp and b/src/make_cw.mcp differ