--- /dev/null
+/*
+** 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) );
+}
+
+/*****************************************************************************/
+
--- /dev/null
+/*
+** 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__ */
--- /dev/null
+/*
+** 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;
+ }
+}
+
+/*****************************************************************************/
--- /dev/null
+/*
+** 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__ */
+
--- /dev/null
+/*
+** 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) );
+}
+
+/*****************************************************************************/
+
--- /dev/null
+/*
+** 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__ */
--- /dev/null
+/*
+** 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 );
+}
+
+/*****************************************************************************/
+
--- /dev/null
+/*
+** 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
--- /dev/null
+/*
+** 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) );
+}
+
+/*****************************************************************************/
--- /dev/null
+/*
+** 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__ */
--- /dev/null
+/*
+** 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));
+}
+
+/*****************************************************************************/
--- /dev/null
+/*
+** 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__ */
--- /dev/null
+/*
+** 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 );
+}
+
+/*****************************************************************************/
+
--- /dev/null
+/*
+** 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__ */
--- /dev/null
+/*
+** 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 );
+}
+
+/*****************************************************************************/
--- /dev/null
+/*
+** 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__ */
--- /dev/null
+/*
+** 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
+
--- /dev/null
+/*
+** 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
--- /dev/null
+/*
+** 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 );
+}
+
+/*****************************************************************************/
--- /dev/null
+/*
+** 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__ */