From 7b001ed84abe2ccb15f39886d9c6492f8c384bf2 Mon Sep 17 00:00:00 2001 From: Nicholas Shanks Date: Fri, 29 Mar 2002 14:59:03 +0000 Subject: [PATCH] Add MoreFiles 1.5.2 and MoreFilesX 1.0 --- External/MoreFiles/DirectoryCopy.c | 1 + External/MoreFiles/DirectoryCopy.h | 1 + External/MoreFiles/FSpCompat.c | 1 + External/MoreFiles/FSpCompat.h | 1 + External/MoreFiles/FileCopy.c | 1 + External/MoreFiles/FileCopy.h | 1 + External/MoreFiles/FullPath.c | 1 + External/MoreFiles/FullPath.h | 1 + External/MoreFiles/IterateDirectory.c | 1 + External/MoreFiles/IterateDirectory.h | 1 + External/MoreFiles/MoreDesktopMgr.c | 1 + External/MoreFiles/MoreDesktopMgr.h | 1 + External/MoreFiles/MoreFiles.c | 1 + External/MoreFiles/MoreFiles.h | 1 + External/MoreFiles/MoreFilesExtras.c | 1 + External/MoreFiles/MoreFilesExtras.h | 1 + External/MoreFiles/Optimization.h | 1 + External/MoreFiles/OptimizationEnd.h | 1 + External/MoreFiles/Search.c | 1 + External/MoreFiles/Search.h | 1 + External/MoreFilesX/MoreFilesX.c | 1 + External/MoreFilesX/MoreFilesX.h | 1 + 22 files changed, 22 insertions(+) create mode 100755 External/MoreFiles/DirectoryCopy.c create mode 100755 External/MoreFiles/DirectoryCopy.h create mode 100755 External/MoreFiles/FSpCompat.c create mode 100755 External/MoreFiles/FSpCompat.h create mode 100755 External/MoreFiles/FileCopy.c create mode 100755 External/MoreFiles/FileCopy.h create mode 100755 External/MoreFiles/FullPath.c create mode 100755 External/MoreFiles/FullPath.h create mode 100755 External/MoreFiles/IterateDirectory.c create mode 100755 External/MoreFiles/IterateDirectory.h create mode 100755 External/MoreFiles/MoreDesktopMgr.c create mode 100755 External/MoreFiles/MoreDesktopMgr.h create mode 100755 External/MoreFiles/MoreFiles.c create mode 100755 External/MoreFiles/MoreFiles.h create mode 100755 External/MoreFiles/MoreFilesExtras.c create mode 100755 External/MoreFiles/MoreFilesExtras.h create mode 100755 External/MoreFiles/Optimization.h create mode 100755 External/MoreFiles/OptimizationEnd.h create mode 100755 External/MoreFiles/Search.c create mode 100755 External/MoreFiles/Search.h create mode 100644 External/MoreFilesX/MoreFilesX.c create mode 100644 External/MoreFilesX/MoreFilesX.h diff --git a/External/MoreFiles/DirectoryCopy.c b/External/MoreFiles/DirectoryCopy.c new file mode 100755 index 0000000..e15a55f --- /dev/null +++ b/External/MoreFiles/DirectoryCopy.c @@ -0,0 +1 @@ +/* File: DirectoryCopy.c Contains: A robust, general purpose directory copy routine. Version: MoreFiles Copyright: © 1992-2001 by 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <2> 2/7/01 JL Added standard header. Updated names of includes. <1> 12/06/99 JL MoreFiles 1.5. */ #include #include #include #include #include #include #define __COMPILINGMOREFILES #include "MoreFiles.h" #include "MoreFilesExtras.h" #include "MoreDesktopMgr.h" #include "FileCopy.h" #include "DirectoryCopy.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_STRUCT_ALIGN #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_STRUCT_ALIGN #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_STRUCT_ALIGN #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_STRUCT_ALIGN #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 & kioFlAttribDirMask) != 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 = U32SetU(U64ShiftRight(pb.ioVFreeBytes, 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 & kioFlAttribDirMask) != 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, ConstStr255Param copyName, 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 ) { /* use the copyName as srcDirName if supplied */ if ( copyName != NULL ) { /* make a copy since copyName is a const input */ BlockMoveData(copyName, srcDirName, sizeof(Str31)); } /* 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 { /* use the copyName as srcDirName if supplied */ error = DirCreate(dstVRefNum, dstDirID, ((copyName != NULL) ? copyName : 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, ConstStr255Param copyName, void *copyBufferPtr, long copyBufferSize, Boolean preflight, CopyErrProcPtr copyErrHandler) { return ( FilteredDirectoryCopy(srcVRefNum, srcDirID, srcName, dstVRefNum, dstDirID, dstName, copyName, copyBufferPtr, copyBufferSize, preflight, copyErrHandler, NULL) ); } /*****************************************************************************/ pascal OSErr FSpFilteredDirectoryCopy(const FSSpec *srcSpec, const FSSpec *dstSpec, ConstStr255Param copyName, void *copyBufferPtr, long copyBufferSize, Boolean preflight, CopyErrProcPtr copyErrHandler, CopyFilterProcPtr copyFilterProc) { return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, dstSpec->vRefNum, dstSpec->parID, dstSpec->name, copyName, copyBufferPtr, copyBufferSize, preflight, copyErrHandler, copyFilterProc) ); } /*****************************************************************************/ pascal OSErr FSpDirectoryCopy(const FSSpec *srcSpec, const FSSpec *dstSpec, ConstStr255Param copyName, void *copyBufferPtr, long copyBufferSize, Boolean preflight, CopyErrProcPtr copyErrHandler) { return ( FilteredDirectoryCopy(srcSpec->vRefNum, srcSpec->parID, srcSpec->name, dstSpec->vRefNum, dstSpec->parID, dstSpec->name, copyName, copyBufferPtr, copyBufferSize, preflight, copyErrHandler, NULL) ); } /*****************************************************************************/ \ No newline at end of file diff --git a/External/MoreFiles/DirectoryCopy.h b/External/MoreFiles/DirectoryCopy.h new file mode 100755 index 0000000..36c4d84 --- /dev/null +++ b/External/MoreFiles/DirectoryCopy.h @@ -0,0 +1 @@ +/* File: DirectoryCopy.h Contains: A robust, general purpose directory copy routine. Version: Technology: MoreFiles Release: 1.5.2 Copyright: © 1992-2001 by Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ */ /* 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__ #ifndef __MACTYPES__ #include #endif #ifndef __FILES__ #include #endif #include "Optimization.h" #if PRAGMA_ONCE #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if PRAGMA_IMPORT #pragma import on #endif #if PRAGMA_STRUCT_ALIGN #pragma options align=mac68k #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(push, 2) #elif PRAGMA_STRUCT_PACK #pragma pack(2) #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 CALLBACK_API( Boolean , CopyErrProcPtr )(OSErr error, short failedOperation, short srcVRefNum, long srcDirID, ConstStr255Param srcName, short dstVRefNum, long dstDirID, ConstStr255Param dstName); /* 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 CALLBACK_API( Boolean , CopyFilterProcPtr )(const CInfoPBRec * cpbPtr); /* 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)) /*****************************************************************************/ EXTERN_API( OSErr ) FilteredDirectoryCopy( short srcVRefNum, long srcDirID, ConstStr255Param srcName, short dstVRefNum, long dstDirID, ConstStr255Param dstName, ConstStr255Param copyName, void * copyBufferPtr, long copyBufferSize, Boolean preflight, CopyErrProcPtr copyErrHandler, CopyFilterProcPtr copyFilterProc); /* 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. copyName input: Points to the new directory name if the directory is to be renamed or nil if the directory 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 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpFilteredDirectoryCopy( const FSSpec * srcSpec, const FSSpec * dstSpec, ConstStr255Param copyName, void * copyBufferPtr, long copyBufferSize, Boolean preflight, CopyErrProcPtr copyErrHandler, CopyFilterProcPtr copyFilterProc); /* 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. copyName input: Points to the new directory name if the directory is to be renamed or nil if the directory 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 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DirectoryCopy( short srcVRefNum, long srcDirID, ConstStr255Param srcName, short dstVRefNum, long dstDirID, ConstStr255Param dstName, ConstStr255Param copyName, void * copyBufferPtr, long copyBufferSize, Boolean preflight, CopyErrProcPtr copyErrHandler); /* 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. copyName input: Points to the new directory name if the directory is to be renamed or nil if the directory 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 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpDirectoryCopy( const FSSpec * srcSpec, const FSSpec * dstSpec, ConstStr255Param copyName, void * copyBufferPtr, long copyBufferSize, Boolean preflight, CopyErrProcPtr copyErrHandler); /* 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. copyName input: Points to the new directory name if the directory is to be renamed or nil if the directory 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 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 */ /*****************************************************************************/ #include "OptimizationEnd.h" #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(pop) #elif PRAGMA_STRUCT_PACK #pragma pack() #endif #ifdef PRAGMA_IMPORT_OFF #pragma import off #elif PRAGMA_IMPORT #pragma import reset #endif #ifdef __cplusplus } #endif #endif /* __DIRECTORYCOPY__ */ \ No newline at end of file diff --git a/External/MoreFiles/FSpCompat.c b/External/MoreFiles/FSpCompat.c new file mode 100755 index 0000000..a189ccf --- /dev/null +++ b/External/MoreFiles/FSpCompat.c @@ -0,0 +1 @@ +/* File: FSpCompat.c Contains: FSSpec compatibility functions. Version: MoreFiles Copyright: © 1992-2001 by 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <2> 2/7/01 JL Added standard header. Updated names of includes. Updated various routines to use new calling convention of the MoreFilesExtras accessor functions. <1> 12/06/99 JL MoreFiles 1.5. */ /* ** 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 #include #include #include #include #include #include #define __COMPILINGMOREFILES #include "MoreFilesExtras.h" #include "FSpCompat.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 & kioFlAttribDirMask) != 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 & kioFlAttribDirMask) != 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; } } /*****************************************************************************/ \ No newline at end of file diff --git a/External/MoreFiles/FSpCompat.h b/External/MoreFiles/FSpCompat.h new file mode 100755 index 0000000..a1ffc49 --- /dev/null +++ b/External/MoreFiles/FSpCompat.h @@ -0,0 +1 @@ +/* File: FSpCompat.h Contains: FSSpec compatibility functions. Version: Technology: MoreFiles Release: 1.5.2 Copyright: © 1992-2001 by Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ */ /* 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__ #ifndef __MACTYPES__ #include #endif #ifndef __FILES__ #include #endif #include "Optimization.h" #if PRAGMA_ONCE #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if PRAGMA_IMPORT #pragma import on #endif #if PRAGMA_STRUCT_ALIGN #pragma options align=mac68k #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(push, 2) #elif PRAGMA_STRUCT_PACK #pragma pack(2) #endif /*****************************************************************************/ EXTERN_API( OSErr ) FSMakeFSSpecCompat( short vRefNum, long dirID, ConstStr255Param fileName, FSSpec * spec); /* 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) */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpOpenDFCompat( const FSSpec * spec, char permission, short * refNum); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpOpenRFCompat( const FSSpec * spec, char permission, short * refNum); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpCreateCompat( const FSSpec * spec, OSType creator, OSType fileType, ScriptCode scriptTag); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpDirCreateCompat( const FSSpec * spec, ScriptCode scriptTag, long * createdDirID); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpDeleteCompat(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpGetFInfoCompat( const FSSpec * spec, FInfo * fndrInfo); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpSetFInfoCompat( const FSSpec * spec, const FInfo * fndrInfo); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpSetFLockCompat(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpRstFLockCompat(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpRenameCompat( const FSSpec * spec, ConstStr255Param newName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpCatMoveCompat( const FSSpec * source, const FSSpec * dest); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpExchangeFilesCompat( const FSSpec * source, const FSSpec * dest); /* 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 */ /*****************************************************************************/ EXTERN_API( short ) FSpOpenResFileCompat( const FSSpec * spec, SignedByte permission); /* 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 */ /*****************************************************************************/ EXTERN_API( void ) FSpCreateResFileCompat( const FSSpec * spec, OSType creator, OSType fileType, ScriptCode scriptTag); /* 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 */ /*****************************************************************************/ #include "OptimizationEnd.h" #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(pop) #elif PRAGMA_STRUCT_PACK #pragma pack() #endif #ifdef PRAGMA_IMPORT_OFF #pragma import off #elif PRAGMA_IMPORT #pragma import reset #endif #ifdef __cplusplus } #endif #endif /* __FSPCOMPAT__ */ \ No newline at end of file diff --git a/External/MoreFiles/FileCopy.c b/External/MoreFiles/FileCopy.c new file mode 100755 index 0000000..55f9b7d --- /dev/null +++ b/External/MoreFiles/FileCopy.c @@ -0,0 +1 @@ +/* File: FileCopy.c Contains: A robust, general purpose file copy routine. Version: MoreFiles Copyright: © 1992-2001 by 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <2> 2/7/01 JL Added standard header. Updated names of includes. Updated various routines to use new calling convention of the MoreFilesExtras accessor functions. <1> 12/06/99 JL MoreFiles 1.5. */ #include #include #include #include #include #define __COMPILINGMOREFILES #include "MoreFiles.h" #include "MoreFilesExtras.h" #include "MoreDesktopMgr.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 & kioFlAttribDirMask) != 0; /* see if access priviledges are make changes, not see folder, and not see files (drop box) */ *isDropBox = userHasDropBoxAccess(pb.dirInfo.ioACUser); 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 = U32SetU(U64ShiftRight(pb.xPB.ioVFreeBytes, 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) ); } /*****************************************************************************/ \ No newline at end of file diff --git a/External/MoreFiles/FileCopy.h b/External/MoreFiles/FileCopy.h new file mode 100755 index 0000000..284484f --- /dev/null +++ b/External/MoreFiles/FileCopy.h @@ -0,0 +1 @@ +/* File: FileCopy.h Contains: A robust, general purpose file copy routine. Version: Technology: MoreFiles Release: 1.5.2 Copyright: © 1992-2001 by Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ */ /* 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__ #ifndef __MACTYPES__ #include #endif #ifndef __FILES__ #include #endif #include "Optimization.h" #if PRAGMA_ONCE #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if PRAGMA_IMPORT #pragma import on #endif #if PRAGMA_STRUCT_ALIGN #pragma options align=mac68k #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(push, 2) #elif PRAGMA_STRUCT_PACK #pragma pack(2) #endif /*****************************************************************************/ EXTERN_API( OSErr ) FileCopy( short srcVRefNum, long srcDirID, ConstStr255Param srcName, short dstVRefNum, long dstDirID, ConstStr255Param dstPathname, ConstStr255Param copyName, void * copyBufferPtr, long copyBufferSize, Boolean preflight); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpFileCopy( const FSSpec * srcSpec, const FSSpec * dstSpec, ConstStr255Param copyName, void * copyBufferPtr, long copyBufferSize, Boolean preflight); /* 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 */ /*****************************************************************************/ #include "OptimizationEnd.h" #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(pop) #elif PRAGMA_STRUCT_PACK #pragma pack() #endif #ifdef PRAGMA_IMPORT_OFF #pragma import off #elif PRAGMA_IMPORT #pragma import reset #endif #ifdef __cplusplus } #endif #endif /* __FILECOPY__ */ \ No newline at end of file diff --git a/External/MoreFiles/FullPath.c b/External/MoreFiles/FullPath.c new file mode 100755 index 0000000..6ef49a7 --- /dev/null +++ b/External/MoreFiles/FullPath.c @@ -0,0 +1 @@ +/* File: FullPath.c Contains: Routines for dealing with full pathnames... if you really must. Version: MoreFiles Copyright: © 1995-2001 by 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <2> 2/7/01 JL Added standard header. Updated names of includes. <1> 12/06/99 JL MoreFiles 1.5. */ #include #include #include #include #include #include #define __COMPILINGMOREFILES #include "FSpCompat.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 = result = noErr; /* work around Nav Services "bug" (it returns invalid FSSpecs with empty names) */ if ( spec->name[0] == 0 ) { result = FSMakeFSSpecCompat(spec->vRefNum, spec->parID, spec->name, &tempSpec); } else { /* Make a copy of the input FSSpec that can be modified */ BlockMoveData(spec, &tempSpec, sizeof(FSSpec)); } if ( result == noErr ) { 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 & kioFlAttribDirMask) != 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 = GetHandleSize(*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); /* work around Alias Mgr sloppy volume matching bug */ if ( spec->vRefNum == 0 ) { /* invalidate wrong FSSpec */ spec->parID = 0; spec->name[0] = 0; result = nsvErr; } 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 ); } /*****************************************************************************/ \ No newline at end of file diff --git a/External/MoreFiles/FullPath.h b/External/MoreFiles/FullPath.h new file mode 100755 index 0000000..0b57cd9 --- /dev/null +++ b/External/MoreFiles/FullPath.h @@ -0,0 +1 @@ +/* File: FullPath.h Contains: Routines for dealing with full pathnames... if you really must. Version: Technology: MoreFiles Release: 1.5.2 Copyright: © 1995-2001 by Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ */ /* 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. */ /* 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. */ #ifndef __FULLPATH__ #define __FULLPATH__ #ifndef __MACTYPES__ #include #endif #ifndef __FILES__ #include #endif #include "Optimization.h" #if PRAGMA_ONCE #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if PRAGMA_IMPORT #pragma import on #endif #if PRAGMA_STRUCT_ALIGN #pragma options align=mac68k #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(push, 2) #elif PRAGMA_STRUCT_PACK #pragma pack(2) #endif /*****************************************************************************/ EXTERN_API( OSErr ) GetFullPath( short vRefNum, long dirID, ConstStr255Param name, short * fullPathLength, Handle * fullPath); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpGetFullPath( const FSSpec * spec, short * fullPathLength, Handle * fullPath); /* 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. IMPORTANT: The definition of a FSSpec is a volume reference number (not a drive number, working directory number, or 0), a parent directory ID (not 0), and the name of a file or folder (not an empty name, a full pathname, or a partial pathname containing one or more colon (:) characters). FSpGetFullPath assumes it is getting a FSSpec that matches the rules. If you have an FSSpec record that wasn't created by FSMakeFSSpec (or FSMakeFSSpecCompat from FSpCompat in MoreFiles which correctly builds FSSpecs), you should call GetFullPath instead of FSpGetFullPath. 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpLocationFromFullPath( short fullPathLength, const void * fullPath, FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) LocationFromFullPath( short fullPathLength, const void * fullPath, short * vRefNum, long * parID, Str31 name); /* 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 */ /*****************************************************************************/ #include "OptimizationEnd.h" #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(pop) #elif PRAGMA_STRUCT_PACK #pragma pack() #endif #ifdef PRAGMA_IMPORT_OFF #pragma import off #elif PRAGMA_IMPORT #pragma import reset #endif #ifdef __cplusplus } #endif #endif /* __FULLPATH__ */ \ No newline at end of file diff --git a/External/MoreFiles/IterateDirectory.c b/External/MoreFiles/IterateDirectory.c new file mode 100755 index 0000000..d649560 --- /dev/null +++ b/External/MoreFiles/IterateDirectory.c @@ -0,0 +1 @@ +/* File: IterateDirectory.c Contains: File Manager directory iterator routines. Version: MoreFiles Copyright: © 1995-2001 by 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. 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <2> 2/7/01 JL Added standard header. Updated names of includes. <1> 12/06/99 JL MoreFiles 1.5. */ #include #include #include #define __COMPILINGMOREFILES #include "MoreFilesExtras.h" #include "IterateDirectory.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_STRUCT_ALIGN #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_STRUCT_ALIGN #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 & kioFlAttribDirMask) != 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) ); } /*****************************************************************************/ \ No newline at end of file diff --git a/External/MoreFiles/IterateDirectory.h b/External/MoreFiles/IterateDirectory.h new file mode 100755 index 0000000..83e89de --- /dev/null +++ b/External/MoreFiles/IterateDirectory.h @@ -0,0 +1 @@ +/* File: IterateDirectory.h Contains: File Manager directory iterator routines. Version: Technology: MoreFiles Release: 1.5.2 Copyright: © 1995-2001 by Jim Luther and Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ */ /* 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 __ITERATEDIRECTORY__ #define __ITERATEDIRECTORY__ #ifndef __MACTYPES__ #include #endif #ifndef __FILES__ #include #endif #include "Optimization.h" #if PRAGMA_ONCE #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if PRAGMA_IMPORT #pragma import on #endif #if PRAGMA_STRUCT_ALIGN #pragma options align=mac68k #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(push, 2) #elif PRAGMA_STRUCT_PACK #pragma pack(2) #endif /*****************************************************************************/ typedef CALLBACK_API( void , IterateFilterProcPtr )(const CInfoPBRec *cpbPtr, Boolean *quitFlag, void *yourDataPtr); /* 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)) /*****************************************************************************/ EXTERN_API( OSErr ) IterateDirectory( short vRefNum, long dirID, ConstStr255Param name, unsigned short maxLevels, IterateFilterProcPtr iterateFilter, void * yourDataPtr); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpIterateDirectory( const FSSpec * spec, unsigned short maxLevels, IterateFilterProcPtr iterateFilter, void * yourDataPtr); /* 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 */ /*****************************************************************************/ #include "OptimizationEnd.h" #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(pop) #elif PRAGMA_STRUCT_PACK #pragma pack() #endif #ifdef PRAGMA_IMPORT_OFF #pragma import off #elif PRAGMA_IMPORT #pragma import reset #endif #ifdef __cplusplus } #endif #endif /* __ITERATEDIRECTORY__ */ \ No newline at end of file diff --git a/External/MoreFiles/MoreDesktopMgr.c b/External/MoreFiles/MoreDesktopMgr.c new file mode 100755 index 0000000..3b05c4f --- /dev/null +++ b/External/MoreFiles/MoreDesktopMgr.c @@ -0,0 +1 @@ +/* File: MoreDesktopMgr.c Contains: A collection of useful high-level Desktop Manager routines. If the Desktop Manager is not available, use the Desktop file for 'read' operations. Version: MoreFiles Copyright: © 1992-2001 by 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther (NG) Nitin Ganatra Change History (most recent first): <2> 2/7/01 JL Added standard header. Updated names of includes. Updated various routines to use new calling convention of the MoreFilesExtras accessor functions. <1> 12/06/99 JL MoreFiles 1.5. */ #include #include #include #include #include #include #define __COMPILINGMOREFILES #include "MoreFiles.h" #include "MoreFilesExtras.h" #include "Search.h" #include "MoreDesktopMgr.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_STRUCT_ALIGN #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_STRUCT_ALIGN #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 = GetHandleSize((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 ( GetHandleSize((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)); } /*****************************************************************************/ \ No newline at end of file diff --git a/External/MoreFiles/MoreDesktopMgr.h b/External/MoreFiles/MoreDesktopMgr.h new file mode 100755 index 0000000..b4276df --- /dev/null +++ b/External/MoreFiles/MoreDesktopMgr.h @@ -0,0 +1 @@ +/* File: MoreDesktopMgr.h Contains: A collection of useful high-level Desktop Manager routines. If the Desktop Manager is not available, use the Desktop file for 'read' operations. Version: Technology: MoreFiles Release: 1.5.2 Copyright: © 1992-2001 by Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ */ /* 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__ #ifndef __MACTYPES__ #include #endif #ifndef __FILES__ #include #endif #include "Optimization.h" #if PRAGMA_ONCE #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if PRAGMA_IMPORT #pragma import on #endif #if PRAGMA_STRUCT_ALIGN #pragma options align=mac68k #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(push, 2) #elif PRAGMA_STRUCT_PACK #pragma pack(2) #endif /*****************************************************************************/ EXTERN_API( OSErr ) DTOpen( ConstStr255Param volName, short vRefNum, short * dtRefNum, Boolean * newDTDatabase); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DTXGetAPPL( ConstStr255Param volName, short vRefNum, OSType creator, Boolean searchCatalog, short * applVRefNum, long * applParID, Str255 applName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpDTXGetAPPL( ConstStr255Param volName, short vRefNum, OSType creator, Boolean searchCatalog, FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DTGetAPPL( ConstStr255Param volName, short vRefNum, OSType creator, short * applVRefNum, long * applParID, Str255 applName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpDTGetAPPL( ConstStr255Param volName, short vRefNum, OSType creator, FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DTGetIcon( ConstStr255Param volName, short vRefNum, short iconType, OSType fileCreator, OSType fileType, Handle * iconHandle); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DTSetComment( short vRefNum, long dirID, ConstStr255Param name, ConstStr255Param comment); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpDTSetComment( const FSSpec * spec, ConstStr255Param comment); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DTGetComment( short vRefNum, long dirID, ConstStr255Param name, Str255 comment); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpDTGetComment( const FSSpec * spec, Str255 comment); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DTCopyComment( short srcVRefNum, long srcDirID, ConstStr255Param srcName, short dstVRefNum, long dstDirID, ConstStr255Param dstName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpDTCopyComment( const FSSpec * srcSpec, const FSSpec * dstSpec); /* 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 */ /*****************************************************************************/ #include "OptimizationEnd.h" #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(pop) #elif PRAGMA_STRUCT_PACK #pragma pack() #endif #ifdef PRAGMA_IMPORT_OFF #pragma import off #elif PRAGMA_IMPORT #pragma import reset #endif #ifdef __cplusplus } #endif #endif /* __MOREDESKTOPMGR__ */ \ No newline at end of file diff --git a/External/MoreFiles/MoreFiles.c b/External/MoreFiles/MoreFiles.c new file mode 100755 index 0000000..0883aa8 --- /dev/null +++ b/External/MoreFiles/MoreFiles.c @@ -0,0 +1 @@ +/* File: MoreFiles.c Contains: The long lost high-level and FSSpec File Manager functions. Version: MoreFiles Copyright: © 1992-2001 by 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <2> 2/7/01 JL Added standard header. Updated names of includes. <1> 12/06/99 JL MoreFiles 1.5. */ #include #include #include #define __COMPILINGMOREFILES #include "MoreFiles.h" #include "MoreFilesExtras.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) || (error == fidExists) || (error == afpIDExists) ) { *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 ); } /*****************************************************************************/ \ No newline at end of file diff --git a/External/MoreFiles/MoreFiles.h b/External/MoreFiles/MoreFiles.h new file mode 100755 index 0000000..edd804e --- /dev/null +++ b/External/MoreFiles/MoreFiles.h @@ -0,0 +1 @@ +/* File: MoreFiles.h Contains: The long lost high-level and FSSpec File Manager functions. Version: Technology: MoreFiles Release: 1.5.2 Copyright: © 1992-2001 by Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ */ /* 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__ #ifndef __MACTYPES__ #include #endif #ifndef __FILES__ #include #endif #include "Optimization.h" #if PRAGMA_ONCE #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if PRAGMA_IMPORT #pragma import on #endif #if PRAGMA_STRUCT_ALIGN #pragma options align=mac68k #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(push, 2) #elif PRAGMA_STRUCT_PACK #pragma pack(2) #endif /*****************************************************************************/ EXTERN_API( OSErr ) HGetVolParms( ConstStr255Param volName, short vRefNum, GetVolParmsInfoBuffer * volParmsInfo, long * infoSize); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HCreateMinimum( short vRefNum, long dirID, ConstStr255Param fileName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpCreateMinimum(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) ExchangeFiles( short vRefNum, long srcDirID, ConstStr255Param srcName, long dstDirID, ConstStr255Param dstName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) ResolveFileIDRef( ConstStr255Param volName, short vRefNum, long fileID, long * parID, StringPtr fileName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpResolveFileIDRef( ConstStr255Param volName, short vRefNum, long fileID, FSSpecPtr spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) CreateFileIDRef( short vRefNum, long parID, ConstStr255Param fileName, long * fileID); /* 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 or afpIDExists. vRefNum input: Volume specification. parID input: Directory ID. fileName input: The name of the file. fileID output: The file ID reference (if result is noErr, fidExists, or afpIDExists). 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpCreateFileIDRef( const FSSpec * spec, long * fileID); /* 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 or afpIDExists. spec input: An FSSpec record specifying the file. fileID output: The file ID reference (if result is noErr, fidExists, or afpIDExists). 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DeleteFileIDRef( ConstStr255Param volName, short vRefNum, long fileID); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FlushFile(short refNum); /* 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. */ /*****************************************************************************/ EXTERN_API( OSErr ) LockRange( short refNum, long rangeLength, long rangeStart); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) UnlockRange( short refNum, long rangeLength, long rangeStart); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetForeignPrivs( short vRefNum, long dirID, ConstStr255Param name, void * foreignPrivBuffer, long * foreignPrivSize, long * foreignPrivInfo1, long * foreignPrivInfo2, long * foreignPrivInfo3, long * foreignPrivInfo4); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpGetForeignPrivs( const FSSpec * spec, void * foreignPrivBuffer, long * foreignPrivSize, long * foreignPrivInfo1, long * foreignPrivInfo2, long * foreignPrivInfo3, long * foreignPrivInfo4); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) SetForeignPrivs( short vRefNum, long dirID, ConstStr255Param name, const void * foreignPrivBuffer, long * foreignPrivSize, long foreignPrivInfo1, long foreignPrivInfo2, long foreignPrivInfo3, long foreignPrivInfo4); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpSetForeignPrivs( const FSSpec * spec, const void * foreignPrivBuffer, long * foreignPrivSize, long foreignPrivInfo1, long foreignPrivInfo2, long foreignPrivInfo3, long foreignPrivInfo4); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HGetLogInInfo( ConstStr255Param volName, short vRefNum, short * loginMethod, StringPtr userName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HGetDirAccess( short vRefNum, long dirID, ConstStr255Param name, long * ownerID, long * groupID, long * accessRights); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpGetDirAccess( const FSSpec * spec, long * ownerID, long * groupID, long * accessRights); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HSetDirAccess( short vRefNum, long dirID, ConstStr255Param name, long ownerID, long groupID, long accessRights); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpSetDirAccess( const FSSpec * spec, long ownerID, long groupID, long accessRights); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HMapID( ConstStr255Param volName, short vRefNum, long ugID, short objType, StringPtr 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HMapName( ConstStr255Param volName, short vRefNum, ConstStr255Param name, short objType, long * ugID); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HCopyFile( short srcVRefNum, long srcDirID, ConstStr255Param srcName, short dstVRefNum, long dstDirID, ConstStr255Param dstPathname, ConstStr255Param copyName); /* The HCopyFile function duplicates a file and optionally 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpCopyFile( const FSSpec * srcSpec, const FSSpec * dstSpec, ConstStr255Param copyName); /* The FSpCopyFile function duplicates a file and optionally 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HMoveRename( short vRefNum, long srcDirID, ConstStr255Param srcName, long dstDirID, ConstStr255Param dstpathName, ConstStr255Param copyName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpMoveRename( const FSSpec * srcSpec, const FSSpec * dstSpec, ConstStr255Param copyName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetVolMountInfoSize( ConstStr255Param volName, short vRefNum, short * size); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetVolMountInfo( ConstStr255Param volName, short vRefNum, void * volMountInfo); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) VolumeMount( const void * volMountInfo, short * vRefNum); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) Share( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpShare(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) Unshare( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpUnshare(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetUGEntry( short objType, StringPtr objName, long * objID); /* 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 */ /*****************************************************************************/ #include "OptimizationEnd.h" #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(pop) #elif PRAGMA_STRUCT_PACK #pragma pack() #endif #ifdef PRAGMA_IMPORT_OFF #pragma import off #elif PRAGMA_IMPORT #pragma import reset #endif #ifdef __cplusplus } #endif #endif /* __MOREFILES__ */ \ No newline at end of file diff --git a/External/MoreFiles/MoreFilesExtras.c b/External/MoreFiles/MoreFilesExtras.c new file mode 100755 index 0000000..0a39002 --- /dev/null +++ b/External/MoreFiles/MoreFilesExtras.c @@ -0,0 +1 @@ +/* File: MoreFilesExtras.c Contains: A collection of useful high-level File Manager routines Version: MoreFiles Copyright: © 1992-2001 by 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. File Ownership: DRI: Jim Luther Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <2> 2/7/01 JL [2500429] Changed null output parameters to real variables when calling GetSharedLibrary to prevent crashes with older versions of CFM. Added standard header. Updated names of includes. Added C function implementations of accessors that used to be macros since the generated Pascal headers no longer contain implementations. Updated various other routines to use new calling convention of the accessor functions. <1> 12/06/99 JL MoreFiles 1.5. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define __COMPILINGMOREFILES #include "MoreFiles.h" #include "MoreDesktopMgr.h" #include "FSpCompat.h" #include "MoreFilesExtras.h" /*****************************************************************************/ /* Functions to get information out of GetVolParmsInfoBuffer. */ /* version 1 field getters */ pascal short GetVolParmsInfoVersion(const GetVolParmsInfoBuffer *volParms) { return ( volParms->vMVersion ); } pascal long GetVolParmsInfoAttrib(const GetVolParmsInfoBuffer *volParms) { return ( volParms->vMAttrib ); } pascal Handle GetVolParmsInfoLocalHand(const GetVolParmsInfoBuffer *volParms) { return ( volParms->vMLocalHand ); } pascal long GetVolParmsInfoServerAdr(const GetVolParmsInfoBuffer *volParms) { return ( volParms->vMServerAdr ); } /* version 2 field getters (assume zero result if version < 2) */ pascal long GetVolParmsInfoVolumeGrade(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMVersion >= 2) ? volParms->vMVolumeGrade : 0 ); } pascal long GetVolParmsInfoForeignPrivID(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMVersion >= 2) ? volParms->vMForeignPrivID : 0 ); } /* version 3 field getters (assume zero result if version < 3) */ pascal long GetVolParmsInfoExtendedAttributes(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMVersion >= 3) ? volParms->vMExtendedAttributes : 0 ); } /* attribute bits supported by all versions of GetVolParmsInfoBuffer */ pascal Boolean isNetworkVolume(const GetVolParmsInfoBuffer *volParms) { return ( volParms->vMServerAdr != 0 ); } pascal Boolean hasLimitFCBs(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bLimitFCBs)) != 0 ); } pascal Boolean hasLocalWList(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bLocalWList)) != 0 ); } pascal Boolean hasNoMiniFndr(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bNoMiniFndr)) != 0 ); } pascal Boolean hasNoVNEdit(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bNoVNEdit)) != 0 ); } pascal Boolean hasNoLclSync(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bNoLclSync)) != 0 ); } pascal Boolean hasTrshOffLine(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bTrshOffLine)) != 0 ); } pascal Boolean hasNoSwitchTo(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bNoSwitchTo)) != 0 ); } pascal Boolean hasNoDeskItems(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bNoDeskItems)) != 0 ); } pascal Boolean hasNoBootBlks(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bNoBootBlks)) != 0 ); } pascal Boolean hasAccessCntl(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bAccessCntl)) != 0 ); } pascal Boolean hasNoSysDir(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bNoSysDir)) != 0 ); } pascal Boolean hasExtFSVol(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasExtFSVol)) != 0 ); } pascal Boolean hasOpenDeny(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasOpenDeny)) != 0 ); } pascal Boolean hasCopyFile(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasCopyFile)) != 0 ); } pascal Boolean hasMoveRename(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasMoveRename)) != 0 ); } pascal Boolean hasDesktopMgr(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasDesktopMgr)) != 0 ); } pascal Boolean hasShortName(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasShortName)) != 0 ); } pascal Boolean hasFolderLock(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasFolderLock)) != 0 ); } pascal Boolean hasPersonalAccessPrivileges(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0 ); } pascal Boolean hasUserGroupList(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasUserGroupList)) != 0 ); } pascal Boolean hasCatSearch(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasCatSearch)) != 0 ); } pascal Boolean hasFileIDs(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasFileIDs)) != 0 ); } pascal Boolean hasBTreeMgr(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasBTreeMgr)) != 0 ); } pascal Boolean hasBlankAccessPrivileges(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0 ); } pascal Boolean supportsAsyncRequests(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bSupportsAsyncRequests)) != 0 ); } pascal Boolean supportsTrashVolumeCache(const GetVolParmsInfoBuffer *volParms) { return ( (volParms->vMAttrib & (1L << bSupportsTrashVolumeCache)) != 0 ); } /* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */ pascal Boolean volIsEjectable(const GetVolParmsInfoBuffer *volParms) { return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsEjectable)) != 0 ); } pascal Boolean volSupportsHFSPlusAPIs(const GetVolParmsInfoBuffer *volParms) { return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsHFSPlusAPIs)) != 0 ); } pascal Boolean volSupportsFSCatalogSearch(const GetVolParmsInfoBuffer *volParms) { return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSCatalogSearch)) != 0 ); } pascal Boolean volSupportsFSExchangeObjects(const GetVolParmsInfoBuffer *volParms) { return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSExchangeObjects)) != 0 ); } pascal Boolean volSupports2TBFiles(const GetVolParmsInfoBuffer *volParms) { return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupports2TBFiles)) != 0 ); } pascal Boolean volSupportsLongNames(const GetVolParmsInfoBuffer *volParms) { return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsLongNames)) != 0 ); } pascal Boolean volSupportsMultiScriptNames(const GetVolParmsInfoBuffer *volParms) { return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsMultiScriptNames)) != 0 ); } pascal Boolean volSupportsNamedForks(const GetVolParmsInfoBuffer *volParms) { return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsNamedForks)) != 0 ); } pascal Boolean volSupportsSubtreeIterators(const GetVolParmsInfoBuffer *volParms) { return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSubtreeIterators)) != 0 ); } pascal Boolean volL2PCanMapFileBlocks(const GetVolParmsInfoBuffer *volParms) { return ( (GetVolParmsInfoExtendedAttributes(volParms) & (1L << bL2PCanMapFileBlocks)) != 0 ); } /*****************************************************************************/ /* Functions for testing ioACUser bits. */ pascal Boolean userIsOwner(SInt8 ioACUser) { return ( (ioACUser & kioACUserNotOwnerMask) == 0 ); } pascal Boolean userHasFullAccess(SInt8 ioACUser) { return ( (ioACUser & acUserAccessMask) == acUserFull ); } pascal Boolean userHasDropBoxAccess(SInt8 ioACUser) { return ( (ioACUser & acUserAccessMask) == acUserDropBox ); } pascal Boolean userHasBulletinBoard(SInt8 ioACUser) { return ( (ioACUser & acUserAccessMask) == acUserBulletinBoard ); } pascal Boolean userHasNoAccess(SInt8 ioACUser) { return ( (ioACUser & acUserAccessMask) == acUserNone ); } /*****************************************************************************/ /* 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_STRUCT_ALIGN #pragma options align=mac68k #endif // PRAGMA_STRUCT_ALIGN 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_STRUCT_ALIGN #pragma options align=reset #endif // PRAGMA_STRUCT_ALIGN typedef struct DeleteEnumGlobals DeleteEnumGlobals; typedef DeleteEnumGlobals *DeleteEnumGlobalsPtr; /*****************************************************************************/ /* ** CallPBXGetVolInfoSync is the glue code needed to make PBXGetVolInfoSync ** File Manager requests from CFM-based programs. Apple added PBXGetVolInfoSync ** to InterfaceLib in Mac OS 8.5, so if __MACOSEIGHTFIVEORLATER is defined, ** CallPBXGetVolInfoSync is defined back to PBXGetVolInfoSync. ** ** 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 TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM // Carbon builds and 68K builds don't need this glue #define CallPBXGetVolInfoSync PBXGetVolInfoSync #else // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM #if __WANTPASCALELIMINATION #undef pascal #endif // __WANTPASCALELIMINATION /* This is exactly like the simple mixed mode glue in InterfaceLib in Mac OS 8.5 and 8.6 */ static pascal OSErr PBXGetVolInfoSyncGlue(XVolumeParamPtr paramBlock) { enum { uppFSDispatchProcInfo = kRegisterBased | REGISTER_RESULT_LOCATION(kRegisterD0) | RESULT_SIZE(SIZE_CODE(sizeof(OSErr))) | REGISTER_ROUTINE_PARAMETER(1, kRegisterD0, SIZE_CODE(sizeof(long))) /* selector */ | REGISTER_ROUTINE_PARAMETER(2, kRegisterD1, SIZE_CODE(sizeof(long))) /* trap word */ | REGISTER_ROUTINE_PARAMETER(3, kRegisterA0, SIZE_CODE(sizeof(XVolumeParamPtr))) }; static UniversalProcPtr fsDispatchTrapAddress = NULL; /* Is this the first time we've been called? */ if ( fsDispatchTrapAddress == NULL ) { /* Yes - Get the trap address of _FSDispatch */ fsDispatchTrapAddress = NGetTrapAddress(_FSDispatch, OSTrap); } return ( CallOSTrapUniversalProc(fsDispatchTrapAddress, uppFSDispatchProcInfo, kFSMXGetVolInfo, _FSDispatch, paramBlock) ); } /* ** PBXGetVolInfoSync was added to the File Manager in System software 7.5.2. ** However, PBXGetVolInfoSync wasn't added to InterfaceLib until Mac OS 8.5. ** This wrapper calls PBXGetVolInfoSync if it is found in InterfaceLib; ** otherwise, it calls PBXGetVolInfoSyncGlue. This ensures that your program ** is calling the latest implementation of PBXGetVolInfoSync. */ static pascal OSErr CallPBXGetVolInfoSync(XVolumeParamPtr paramBlock) { typedef pascal OSErr (*PBXGetVolInfoProcPtr) (XVolumeParamPtr paramBlock); OSErr result; CFragConnectionID connID; Ptr mainAddr; Str255 errMessage; static PBXGetVolInfoProcPtr PBXGetVolInfoSyncPtr = NULL; //* Is this the first time we've been called? */ if ( PBXGetVolInfoSyncPtr == NULL ) { /* Yes - Get our connection ID to InterfaceLib */ result = GetSharedLibrary("\pInterfaceLib", kPowerPCCFragArch, kLoadCFrag, &connID, &mainAddr, errMessage); if ( result == noErr ) { /* See if PBXGetVolInfoSync is in InterfaceLib */ if ( FindSymbol(connID, "\pPBXGetVolInfoSync", &(Ptr)PBXGetVolInfoSyncPtr, NULL) != noErr ) { /* Use glue code if symbol isn't found */ PBXGetVolInfoSyncPtr = PBXGetVolInfoSyncGlue; } } } /* Call PBXGetVolInfoSync if present; otherwise, call PBXGetVolInfoSyncGlue */ return ( (*PBXGetVolInfoSyncPtr)(paramBlock) ); } #if __WANTPASCALELIMINATION #define pascal #endif // __WANTPASCALELIMINATION #endif // TARGET_API_MAC_CARBON || !TARGET_RT_MAC_CFM /*****************************************************************************/ 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) { // Note: CharacterByteType's textOffset parameter is zero-based from the textPtr parameter charType = CharacterByteType((Ptr)&source[1], maxLength - 1, smSystemScript); 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; 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 !TARGET_API_MAC_CARBON long response; /* 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 = U64Multiply(U64SetU(pb->ioVNmAlBlks), U64SetU(pb->ioVAlBlkSiz)); pb->ioVFreeBytes = U64Multiply(U64SetU(pb->ioVFrBlk), U64SetU(pb->ioVAlBlkSiz)); } } else #endif { /* Yes, so use it */ error = CallPBXGetVolInfoSync(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) { OSErr result; UInt64 freeBytes64; UInt64 totalBytes64; // get the best values possible from XGetVInfo result = XGetVInfo(volReference, volName, vRefNum, &freeBytes64, &totalBytes64); if ( result == noErr ) { // and pin those values if needed if ( UInt64ToUnsignedWide(freeBytes64).hi != 0 ) { // pin to maximum 512-byte block aligned value *freeBytes = 0xfffffe00; } else { *freeBytes = U32SetU(freeBytes64); } if ( UInt64ToUnsignedWide(totalBytes64).hi != 0 ) { // pin to maximum 512-byte block aligned value *totalBytes = 0xfffffe00; } else { *totalBytes = U32SetU(totalBytes64); } } return ( result ); } /*****************************************************************************/ pascal OSErr XGetVInfo(short volReference, StringPtr volName, short *vRefNum, UInt64 *freeBytes, UInt64 *totalBytes) { OSErr result; XVolumeParam pb; #if !TARGET_API_MAC_CARBON long response; #endif // !TARGET_API_MAC_CARBON pb.ioVRefNum = volReference; pb.ioNamePtr = volName; pb.ioXVersion = 0; /* this XVolumeParam version (0) */ pb.ioVolIndex = 0; /* use ioVRefNum only, return volume name */ #if !TARGET_API_MAC_CARBON /* See if large volume support is available */ if ( ( Gestalt(gestaltFSAttr, &response) == noErr ) && ((response & (1L << gestaltFSSupports2TBVols)) != 0) ) #endif // !TARGET_API_MAC_CARBON { /* Large volume support is available */ result = CallPBXGetVolInfoSync(&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; } } #if !TARGET_API_MAC_CARBON else { /* No large volume support */ /* Use PBHGetVInfoSync to get the results */ result = PBHGetVInfoSync((HParmBlkPtr)&pb); if ( result == noErr ) { VCB *theVCB; /* The volume name was returned in volName (if not NULL) and */ /* we have the volume's vRefNum */ *vRefNum = pb.ioVRefNum; /* 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. */ /* Note: Carbon doesn't support the VCB queue, so this code cannot be */ /* used (and is conditionalized out) by Carbon applications. */ /* Find the volume's VCB */ theVCB = (VCB *)(GetVCBQHdr()->qHead); while ( theVCB != NULL ) { if ( theVCB->vcbVRefNum == *vRefNum ) { break; } theVCB = (VCB *)(theVCB->qLink); /* next VCB */ } 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. */ *freeBytes = U64Multiply(U64SetU((unsigned short)theVCB->vcbFreeBks), U64SetU((unsigned long)pb.ioVAlBlkSiz)); *totalBytes = U64Multiply(U64SetU((unsigned short)theVCB->vcbNmAlBlks), U64SetU((unsigned long)pb.ioVAlBlkSiz)); } else { /* Didn't find a VCB we can use. Return the number of allocation blocks */ /* and the number of free blocks returned by PBHGetVInfoSync. */ *freeBytes = U64Multiply(U64SetU((unsigned short)pb.ioVFrBlk), U64SetU((unsigned long)pb.ioVAlBlkSiz)); *totalBytes = U64Multiply(U64SetU((unsigned short)pb.ioVNmAlBlks), U64SetU((unsigned long)pb.ioVAlBlkSiz)); } } } #endif // !TARGET_API_MAC_CARBON 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 & kHFSVolumeHardwareLockMask) != 0 ) { error = wPrErr; /* volume locked by hardware */ } else if ( (pb.volumeParam.ioVAtrb & kHFSVolumeSoftwareLockMask) != 0 ) { error = vLckdErr; /* volume locked by software */ } } return ( error ); } /*****************************************************************************/ // // The following routines call Mac OS routines that are not supported by // Carbon: // // GetDriverName // FindDrive // GetDiskBlocks // GetVolState #if !TARGET_API_MAC_CARBON // { /*****************************************************************************/ pascal OSErr GetDriverName(short driverRefNum, Str255 driverName) { OSErr result; DCtlHandle theDctl; DRVRHeaderPtr dHeaderPtr; theDctl = GetDCtlEntry(driverRefNum); if ( theDctl != NULL ) { if ( (**theDctl).dCtlFlags & dRAMBasedMask ) { /* 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 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 ); } /*****************************************************************************/ #endif // } !TARGET_API_MAC_CARBON /*****************************************************************************/ 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 ); } /*****************************************************************************/ // // Note: Under Carbon there are no drive numbers, so you cannot call // Eject with a drive number after unmounting a volume. // When a Carbon application calls UnmountVol, CarbonLib will make // sure ejectable media is ejected (leaving ejectable media in the // disk drive makes no sense to Carbon applications). // pascal OSErr UnmountAndEject(ConstStr255Param pathname, short vRefNum) { HParamBlockRec pb; OSErr error; error = GetVolumeInfoNoName(pathname, vRefNum, &pb); if ( error == noErr ) { #if !TARGET_API_MAC_CARBON short driveNum; Boolean ejected, wantsEject; DrvQElPtr drvQElem; 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; } #endif // !TARGET_API_MAC_CARBON /* unmount the volume */ pb.volumeParam.ioNamePtr = NULL; /* ioVRefNum is already filled in from PBHGetVInfo */ error = PBUnmountVol((ParmBlkPtr)&pb); #if !TARGET_API_MAC_CARBON if ( error == noErr ) { if ( wantsEject && !ejected ) { /* eject the media from the drive if needed */ pb.volumeParam.ioVRefNum = driveNum; error = PBEject((ParmBlkPtr)&pb); } } #endif // !TARGET_API_MAC_CARBON } 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; #if !TARGET_API_MAC_CARBON 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 { #endif // !TARGET_API_MAC_CARBON /* oldVRefNum was a real vRefNum - use HSetVol */ error = HSetVol(NULL, oldVRefNum, oldDirID); #if !TARGET_API_MAC_CARBON } } #endif // !TARGET_API_MAC_CARBON 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 & kioFlAttribDirMask) != 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 & kioFlAttribDirMask) != 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 & kioFlAttribDirMask) != 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 & kioFlAttribDirMask) == 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 & kioFlAttribDirMask) != 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 & kioFlAttribDirMask) != 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 & kioFlAttribDirMask) != 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 & kioFlAttribDirMask) != 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 & kioFlAttribLockedMask) != 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 & kioFlAttribDirMask) == 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 & kioFlAttribDirMask) != 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 & ~kHasBeenInited ); error = PBSetCatInfoSync(&pb.ciPB); if ( (error == noErr) && (copyLockBit) && ((pb.ciPB.hFileInfo.ioFlAttrib & kioFlAttribLockedMask) != 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 + noCacheMask; /* fsAtMark + noCacheMask */ 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 + noCacheMask; /* fsAtMark + noCacheMask */ 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 + noCacheMask;/* fsAtMark + noCacheMask */ /* 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 + noCacheMask;/* fsAtMark + noCacheMask */ 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 ); } /*****************************************************************************/ \ No newline at end of file diff --git a/External/MoreFiles/MoreFilesExtras.h b/External/MoreFiles/MoreFilesExtras.h new file mode 100755 index 0000000..500f99a --- /dev/null +++ b/External/MoreFiles/MoreFilesExtras.h @@ -0,0 +1 @@ +/* File: MoreFilesExtras.h Contains: A collection of useful high-level File Manager routines. Version: Technology: MoreFiles Release: 1.5.2 Copyright: © 1992-2001 by Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ */ /* 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__ #ifndef __MACTYPES__ #include #endif #ifndef __FILES__ #include #endif #include "Optimization.h" #if PRAGMA_ONCE #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if PRAGMA_IMPORT #pragma import on #endif #if PRAGMA_STRUCT_ALIGN #pragma options align=mac68k #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(push, 2) #elif PRAGMA_STRUCT_PACK #pragma pack(2) #endif /*****************************************************************************/ /* ** 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 { /* mask for just the access restriction bits */ acUserAccessMask = (kioACUserNoSeeFolderMask + kioACUserNoSeeFilesMask + kioACUserNoMakeChangesMask), /* common access privilege settings */ acUserFull = 0x00, /* no access restiction bits on */ acUserNone = acUserAccessMask, /* all access restiction bits on */ acUserDropBox = kioACUserNoSeeFolderMask + kioACUserNoSeeFilesMask, /* make changes, but not see files or folders */ acUserBulletinBoard = kioACUserNoMakeChangesMask /* see files and folders, but not make changes */ }; /*****************************************************************************/ /* ** Deny mode permissions for use with the HOpenAware, HOpenRFAware, ** FSpOpenAware, and FSpOpenRFAware functions. ** Note: Common settings are the ones with comments. */ enum { dmNone = 0x0000, dmNoneDenyRd = fsRdDenyPerm, dmNoneDenyWr = fsWrDenyPerm, dmNoneDenyRdWr = (fsRdDenyPerm + fsWrDenyPerm), dmRd = fsRdPerm, /* Single writer, multiple readers; the readers */ dmRdDenyRd = (fsRdPerm + fsRdDenyPerm), dmRdDenyWr = (fsRdPerm + fsWrDenyPerm), /* Browsing - equivalent to fsRdPerm */ dmRdDenyRdWr = (fsRdPerm + fsRdDenyPerm + fsWrDenyPerm), dmWr = fsWrPerm, dmWrDenyRd = (fsWrPerm + fsRdDenyPerm), dmWrDenyWr = (fsWrPerm + fsWrDenyPerm), dmWrDenyRdWr = (fsWrPerm + fsRdDenyPerm + fsWrDenyPerm), dmRdWr = fsRdWrPerm, /* Shared access - equivalent to fsRdWrShPerm */ dmRdWrDenyRd = (fsRdWrPerm + fsRdDenyPerm), dmRdWrDenyWr = (fsRdWrPerm + fsWrDenyPerm), /* Single writer, multiple readers; the writer */ dmRdWrDenyRdWr = (fsRdWrPerm + fsRdDenyPerm + fsWrDenyPerm) /* Exclusive access - equivalent to fsRdWrPerm */ }; /*****************************************************************************/ /* ** 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; typedef 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; typedef UGEntryPtr * UGEntryHandle; /* ** I use the following records instead of the AFPVolMountInfo and AFPXVolMountInfo structures in Files.h */ typedef unsigned char Str8[9]; 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; typedef 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[1]; /* AFPAlternateAddress */ }; typedef struct MyAFPXVolMountInfo MyAFPXVolMountInfo; typedef MyAFPXVolMountInfo * MyAFPXVolMountInfoPtr; typedef MyAFPXVolMountInfoPtr * MyAFPXVolMountInfoHandle; /*****************************************************************************/ /* Functions to get information out of GetVolParmsInfoBuffer. */ /* version 1 field getters */ EXTERN_API( short ) GetVolParmsInfoVersion(const GetVolParmsInfoBuffer * volParms); EXTERN_API( long ) GetVolParmsInfoAttrib(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Handle ) GetVolParmsInfoLocalHand(const GetVolParmsInfoBuffer * volParms); EXTERN_API( long ) GetVolParmsInfoServerAdr(const GetVolParmsInfoBuffer * volParms); /* version 2 field getters (assume zero result if version < 2) */ EXTERN_API( long ) GetVolParmsInfoVolumeGrade(const GetVolParmsInfoBuffer * volParms); EXTERN_API( long ) GetVolParmsInfoForeignPrivID(const GetVolParmsInfoBuffer * volParms); /* version 3 field getters (assume zero result if version < 3) */ EXTERN_API( long ) GetVolParmsInfoExtendedAttributes(const GetVolParmsInfoBuffer * volParms); /* attribute bits supported by all versions of GetVolParmsInfoBuffer */ EXTERN_API( Boolean ) isNetworkVolume(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasLimitFCBs(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasLocalWList(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasNoMiniFndr(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasNoVNEdit(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasNoLclSync(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasTrshOffLine(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasNoSwitchTo(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasNoDeskItems(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasNoBootBlks(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasAccessCntl(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasNoSysDir(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasExtFSVol(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasOpenDeny(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasCopyFile(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasMoveRename(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasDesktopMgr(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasShortName(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasFolderLock(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasPersonalAccessPrivileges(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasUserGroupList(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasCatSearch(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasFileIDs(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasBTreeMgr(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) hasBlankAccessPrivileges(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) supportsAsyncRequests(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) supportsTrashVolumeCache(const GetVolParmsInfoBuffer * volParms); /* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */ EXTERN_API( Boolean ) volIsEjectable(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) volSupportsHFSPlusAPIs(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) volSupportsFSCatalogSearch(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) volSupportsFSExchangeObjects(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) volSupports2TBFiles(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) volSupportsLongNames(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) volSupportsMultiScriptNames(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) volSupportsNamedForks(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) volSupportsSubtreeIterators(const GetVolParmsInfoBuffer * volParms); EXTERN_API( Boolean ) volL2PCanMapFileBlocks(const GetVolParmsInfoBuffer * volParms); /*****************************************************************************/ /* Functions for testing ioACUser bits. */ EXTERN_API( Boolean ) userIsOwner(SInt8 ioACUser); EXTERN_API( Boolean ) userHasFullAccess(SInt8 ioACUser); EXTERN_API( Boolean ) userHasDropBoxAccess(SInt8 ioACUser); EXTERN_API( Boolean ) userHasBulletinBoard(SInt8 ioACUser); EXTERN_API( Boolean ) userHasNoAccess(SInt8 ioACUser); /*****************************************************************************/ EXTERN_API( void ) TruncPString( StringPtr destination, ConstStr255Param source, short maxLength); /* 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. */ /*****************************************************************************/ EXTERN_API( Ptr ) GetTempBuffer( long buffReqSize, long * buffActSize); /* 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. */ /*****************************************************************************/ EXTERN_API( OSErr ) GetVolumeInfoNoName( ConstStr255Param pathname, short vRefNum, HParmBlkPtr pb); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) XGetVolumeInfoNoName( ConstStr255Param pathname, short vRefNum, XVolumeParamPtr pb); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetCatInfoNoName( short vRefNum, long dirID, ConstStr255Param name, CInfoPBPtr pb); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DetermineVRefNum( ConstStr255Param pathname, short vRefNum, short * realVRefNum); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HGetVInfo( short volReference, StringPtr volName, short * vRefNum, unsigned long * freeBytes, unsigned long * totalBytes); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) XGetVInfo( short volReference, StringPtr volName, short * vRefNum, UInt64 * freeBytes, UInt64 * totalBytes); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) CheckVolLock( ConstStr255Param pathname, short vRefNum); /* 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 */ /*****************************************************************************/ /* ** The following routines call Mac OS routines that are not supported by ** Carbon: ** ** GetDriverName ** FindDrive ** GetDiskBlocks ** GetVolState */ #if !TARGET_API_MAC_CARBON // { /*****************************************************************************/ EXTERN_API( OSErr ) GetDriverName( short driverRefNum, Str255 driverName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FindDrive( ConstStr255Param pathname, short vRefNum, DrvQElPtr * driveQElementPtr); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetDiskBlocks( ConstStr255Param pathname, short vRefNum, unsigned long * numBlocks); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetVolState( ConstStr255Param pathname, short vRefNum, Boolean * volumeOnline, Boolean * volumeEjected, Boolean * driveEjectable, Boolean * driverWantsEject); /* 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 */ /*****************************************************************************/ #endif // } !TARGET_API_MAC_CARBON /*****************************************************************************/ EXTERN_API( OSErr ) GetVolFileSystemID( ConstStr255Param pathname, short vRefNum, short * fileSystemID); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) UnmountAndEject( ConstStr255Param pathname, short vRefNum); /* 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. */ /*****************************************************************************/ EXTERN_API( OSErr ) OnLine( FSSpecPtr volumes, short reqVolCount, short * actVolCount, short * volIndex); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) SetDefault( short newVRefNum, long newDirID, short * oldVRefNum, long * oldDirID); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) RestoreDefault( short oldVRefNum, long oldDirID); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetDInfo( short vRefNum, long dirID, ConstStr255Param name, DInfo * fndrInfo); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpGetDInfo( const FSSpec * spec, DInfo * fndrInfo); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) SetDInfo( short vRefNum, long dirID, ConstStr255Param name, const DInfo * fndrInfo); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpSetDInfo( const FSSpec * spec, const DInfo * fndrInfo); /* 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 EXTERN_API( OSErr ) GetDirectoryID( short vRefNum, long dirID, ConstStr255Param name, long * theDirID, Boolean * isDirectory); /* 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 EXTERN_API( OSErr ) FSpGetDirectoryID( const FSSpec * spec, long * theDirID, Boolean * isDirectory); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetDirName( short vRefNum, long dirID, Str31 name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetIOACUser( short vRefNum, long dirID, ConstStr255Param name, SInt8 * ioACUser); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpGetIOACUser( const FSSpec * spec, SInt8 * ioACUser); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetParentID( short vRefNum, long dirID, ConstStr255Param name, long * parID); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetFilenameFromPathname( ConstStr255Param pathname, Str255 filename); /* 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. */ /*****************************************************************************/ EXTERN_API( OSErr ) GetObjectLocation( short vRefNum, long dirID, ConstStr255Param pathname, short * realVRefNum, long * realParID, Str255 realName, Boolean * isDirectory); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetDirItems( short vRefNum, long dirID, ConstStr255Param name, Boolean getFiles, Boolean getDirectories, FSSpecPtr items, short reqItemCount, short * actItemCount, short * itemIndex); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DeleteDirectoryContents( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) DeleteDirectory( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) CheckObjectLock( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpCheckObjectLock(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetFileSize( short vRefNum, long dirID, ConstStr255Param fileName, long * dataSize, long * rsrcSize); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpGetFileSize( const FSSpec * spec, long * dataSize, long * rsrcSize); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) BumpDate( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpBumpDate(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) ChangeCreatorType( short vRefNum, long dirID, ConstStr255Param name, OSType creator, OSType fileType); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpChangeCreatorType( const FSSpec * spec, OSType creator, OSType fileType); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) ChangeFDFlags( short vRefNum, long dirID, ConstStr255Param name, Boolean setBits, unsigned short flagBits); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpChangeFDFlags( const FSSpec * spec, Boolean setBits, unsigned short flagBits); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) SetIsInvisible( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpSetIsInvisible(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) ClearIsInvisible( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpClearIsInvisible(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) SetNameLocked( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpSetNameLocked(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) ClearNameLocked( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpClearNameLocked(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) SetIsStationery( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpSetIsStationery(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) ClearIsStationery( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpClearIsStationery(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) SetHasCustomIcon( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpSetHasCustomIcon(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) ClearHasCustomIcon( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpClearHasCustomIcon(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) ClearHasBeenInited( short vRefNum, long dirID, ConstStr255Param name); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpClearHasBeenInited(const FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) CopyFileMgrAttributes( short srcVRefNum, long srcDirID, ConstStr255Param srcName, short dstVRefNum, long dstDirID, ConstStr255Param dstName, Boolean copyLockBit); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpCopyFileMgrAttributes( const FSSpec * srcSpec, const FSSpec * dstSpec, Boolean copyLockBit); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HOpenAware( short vRefNum, long dirID, ConstStr255Param fileName, short denyModes, short * refNum); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpOpenAware( const FSSpec * spec, short denyModes, short * refNum); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HOpenRFAware( short vRefNum, long dirID, ConstStr255Param fileName, short denyModes, short * refNum); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpOpenRFAware( const FSSpec * spec, short denyModes, short * refNum); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSReadNoCache( short refNum, long * count, void * buffPtr); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSWriteNoCache( short refNum, long * count, const void * buffPtr); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSWriteVerify( short refNum, long * count, const void * buffPtr); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) CopyFork( short srcRefNum, short dstRefNum, void * copyBufferPtr, long copyBufferSize); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetFileLocation( short refNum, short * vRefNum, long * dirID, StringPtr fileName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpGetFileLocation( short refNum, FSSpec * spec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) CopyDirectoryAccess( short srcVRefNum, long srcDirID, ConstStr255Param srcName, short dstVRefNum, long dstDirID, ConstStr255Param dstName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpCopyDirectoryAccess( const FSSpec * srcSpec, const FSSpec * dstSpec); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) HMoveRenameCompat( short vRefNum, long srcDirID, ConstStr255Param srcName, long dstDirID, ConstStr255Param dstpathName, ConstStr255Param copyName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) FSpMoveRenameCompat( const FSSpec * srcSpec, const FSSpec * dstSpec, ConstStr255Param copyName); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) BuildAFPVolMountInfo( short flags, char nbpInterval, char nbpCount, short uamType, Str32 zoneName, Str31 serverName, Str27 volName, Str31 userName, Str8 userPassword, Str8 volPassword, AFPVolMountInfoPtr * afpInfoPtr); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) RetrieveAFPVolMountInfo( AFPVolMountInfoPtr afpInfoPtr, short * flags, short * uamType, StringPtr zoneName, StringPtr serverName, StringPtr volName, StringPtr userName); /* 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 */ /*****************************************************************************/ EXTERN_API( 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); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) RetrieveAFPXVolMountInfo( AFPXVolMountInfoPtr afpXInfoPtr, short * flags, short * uamType, StringPtr zoneName, StringPtr serverName, StringPtr volName, StringPtr userName, StringPtr uamName, unsigned long * alternateAddressLength, AFPAlternateAddress ** alternateAddress); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) GetUGEntries( short objType, UGEntryPtr entries, long reqEntryCount, long * actEntryCount, long * objID); /* 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 */ /*****************************************************************************/ #include "OptimizationEnd.h" #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(pop) #elif PRAGMA_STRUCT_PACK #pragma pack() #endif #ifdef PRAGMA_IMPORT_OFF #pragma import off #elif PRAGMA_IMPORT #pragma import reset #endif #ifdef __cplusplus } #endif #endif /* __MOREFILESEXTRAS__ */ \ No newline at end of file diff --git a/External/MoreFiles/Optimization.h b/External/MoreFiles/Optimization.h new file mode 100755 index 0000000..dee395d --- /dev/null +++ b/External/MoreFiles/Optimization.h @@ -0,0 +1 @@ +/* File: Optimization.h Contains: Defines that let you make MoreFiles code more efficient. Version: MoreFiles Copyright: © 1992-2001 by 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <1> 2/7/01 JL first checked in */ /* 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 If you're compiling 68K code, the default is to include all compatibility code. If you're compiling PowerPC code (TARGET_RT_MAC_CFM), the default is __MACOSSEVENORLATER If you're compiling for Carbon code (TARGET_API_MAC_CARBON), the default is __MACOSSEVENFIVEONEORLATER 2 -- You may disable Pascal calling conventions in all MoreFiles routines except for system callbacks that require Pascal calling conventions. This will make 68K C programs both smaller and faster. (PowerPC compilers ignore pascal calling conventions.) 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 */ #include // if we're compiling for Carbon, then we're running on Mac OS 8.1 or later #ifndef __MACOSSEVENFIVEONEORLATER #define __MACOSSEVENFIVEONEORLATER TARGET_API_MAC_CARBON #endif #ifndef __MACOSSEVENFIVEORLATER #define __MACOSSEVENFIVEORLATER __MACOSSEVENFIVEONEORLATER #endif #ifndef __MACOSSEVENORLATER #if TARGET_RT_MAC_CFM #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 \ No newline at end of file diff --git a/External/MoreFiles/OptimizationEnd.h b/External/MoreFiles/OptimizationEnd.h new file mode 100755 index 0000000..a73945d --- /dev/null +++ b/External/MoreFiles/OptimizationEnd.h @@ -0,0 +1 @@ +/* File: OptimizationEnd.h Contains: Defines that let you make MoreFiles code more efficient. Version: MoreFiles Copyright: © 1992-2001 by 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <1> 2/7/01 JL first checked in */ /* 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 \ No newline at end of file diff --git a/External/MoreFiles/Search.c b/External/MoreFiles/Search.c new file mode 100755 index 0000000..2f1de42 --- /dev/null +++ b/External/MoreFiles/Search.c @@ -0,0 +1 @@ +/* File: Search.c Contains: IndexedSearch and the PBCatSearch compatibility function. Version: MoreFiles Copyright: © 1992-2001 by 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. File Ownership: DRI: Jim Luther Other Contact: Apple Macintosh Developer Technical Support Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <2> 2/7/01 JL Added standard header. Updated names of includes. Updated various routines to use new calling convention of the MoreFilesExtras accessor functions. Added TARGET_API_MAC_CARBON conditional checks around TimeOutTask. <1> 12/06/99 JL MoreFiles 1.5. */ #include #include #include #include #include #include #include #define __COMPILINGMOREFILES #include "MoreFiles.h" #include "MoreFilesExtras.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_STRUCT_ALIGN #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_STRUCT_ALIGN #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_STRUCT_ALIGN #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_STRUCT_ALIGN #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 TARGET_RT_MAC_CFM || TARGET_API_MAC_CARBON 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 = GetHandleSize((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 & ~(kioFlAttribDirMask | kioFlAttribLockedMask)) != 0 ) { goto ParamErrExit; } /* interested in the directory bit? */ if ( (searchInfo2->hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 0 ) { /* yes, so do they want just directories or just files? */ if ( (searchInfo1->hFileInfo.ioFlAttrib & kioFlAttribDirMask) != 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 & kioFlAttribLockedMask) != 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 & kioFlAttribDirMask) == 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 TARGET_RT_MAC_CFM || TARGET_API_MAC_CARBON 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 = NewTimerUPP(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 = GetHandleSize((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 & kioFlAttribDirMask) != 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)); DisposeTimerUPP(timerTask.theTask.tmAddr); } return ( result ); } /*****************************************************************************/ pascal OSErr PBCatSearchSyncCompat(CSParamPtr paramBlock) { OSErr result; Boolean supportsCatSearch; GetVolParmsInfoBuffer volParmsInfo; long infoSize; #if !__MACOSSEVENORLATER static Boolean fullExtFSDispatchingtested = false; static Boolean hasFullExtFSDispatching = false; long response; #endif result = noErr; #if !__MACOSSEVENORLATER /* 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. (System 7.0 and later always do this) */ if ( !fullExtFSDispatchingtested ) { fullExtFSDispatchingtested = true; if ( Gestalt(gestaltFSAttr, &response) == noErr ) { hasFullExtFSDispatching = ((response & (1L << gestaltFullExtFSDispatching)) != 0); } } #endif /* 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 !__MACOSSEVENORLATER if ( hasFullExtFSDispatching ) #endif { 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 = kioFlAttribDirMask; 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 = kioFlAttribDirMask; /* 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 ); } /*****************************************************************************/ \ No newline at end of file diff --git a/External/MoreFiles/Search.h b/External/MoreFiles/Search.h new file mode 100755 index 0000000..07f4463 --- /dev/null +++ b/External/MoreFiles/Search.h @@ -0,0 +1 @@ +/* File: Search.h Contains: IndexedSearch and the PBCatSearch compatibility function. Version: Technology: MoreFiles Release: 1.5.2 Copyright: © 1992-2001 by Apple Computer, Inc., all rights reserved. Bugs?: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ */ /* 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__ #ifndef __MACTYPES__ #include #endif #ifndef __FILES__ #include #endif #include "Optimization.h" #if PRAGMA_ONCE #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if PRAGMA_IMPORT #pragma import on #endif #if PRAGMA_STRUCT_ALIGN #pragma options align=mac68k #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(push, 2) #elif PRAGMA_STRUCT_PACK #pragma pack(2) #endif /*****************************************************************************/ EXTERN_API( OSErr ) IndexedSearch( CSParamPtr pb, long dirID); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) PBCatSearchSyncCompat(CSParamPtr paramBlock); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) NameFileSearch( ConstStr255Param volName, short vRefNum, ConstStr255Param fileName, FSSpecPtr matches, long reqMatchCount, long * actMatchCount, Boolean newSearch, Boolean partial); /* 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 */ /*****************************************************************************/ EXTERN_API( OSErr ) CreatorTypeFileSearch( ConstStr255Param volName, short vRefNum, OSType creator, OSType fileType, FSSpecPtr matches, long reqMatchCount, long * actMatchCount, Boolean newSearch); /* 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 */ /*****************************************************************************/ #include "OptimizationEnd.h" #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(pop) #elif PRAGMA_STRUCT_PACK #pragma pack() #endif #ifdef PRAGMA_IMPORT_OFF #pragma import off #elif PRAGMA_IMPORT #pragma import reset #endif #ifdef __cplusplus } #endif #endif /* __SEARCH__ */ \ No newline at end of file diff --git a/External/MoreFilesX/MoreFilesX.c b/External/MoreFilesX/MoreFilesX.c new file mode 100644 index 0000000..901ef56 --- /dev/null +++ b/External/MoreFilesX/MoreFilesX.c @@ -0,0 +1 @@ +/* File: MoreFilesX.c Contains: A collection of useful high-level File Manager routines which use the HFS Plus APIs wherever possible. Version: MoreFilesX 1.0 Copyright: © 1992-2002 by 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <1> 1/25/02 JL MoreFilesX 1.0 */ #if 0 #include #else #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #endif #include "MoreFilesX.h" /* Set BuildingMoreFilesXForMacOS9 to 1 if building for Mac OS 9 */ #ifndef BuildingMoreFilesXForMacOS9 #define BuildingMoreFilesXForMacOS9 0 #endif /*****************************************************************************/ #pragma mark ----- Local type definitions ----- struct FSIterateContainerGlobals { IterateContainerFilterProcPtr iterateFilter; /* pointer to IterateFilterProc */ FSCatalogInfoBitmap whichInfo; /* fields of the CatalogInfo to get */ FSCatalogInfo catalogInfo; /* FSCatalogInfo */ FSRef ref; /* FSRef */ FSSpec spec; /* FSSpec */ FSSpec *specPtr; /* pointer to spec field, or NULL */ HFSUniStr255 name; /* HFSUniStr255 */ HFSUniStr255 *namePtr; /* pointer to name field, or NULL */ void *yourDataPtr; /* a pointer to caller supplied data the filter may need to access */ ItemCount maxLevels; /* maximum levels to iterate through */ ItemCount currentLevel; /* the current level FSIterateContainerLevel is on */ Boolean quitFlag; /* set to true if filter wants to kill interation */ Boolean containerChanged; /* temporary - set to true if the current container changed during iteration */ OSErr result; /* result */ ItemCount actualObjects; /* number of objects returned */ }; typedef struct FSIterateContainerGlobals FSIterateContainerGlobals; struct FSDeleteContainerGlobals { OSErr result; /* result */ ItemCount actualObjects; /* number of objects returned */ FSCatalogInfo catalogInfo; /* FSCatalogInfo */ }; typedef struct FSDeleteContainerGlobals FSDeleteContainerGlobals; /*****************************************************************************/ #pragma mark ----- Local prototypes ----- static void DeleteLevel( const FSRef *container, FSDeleteContainerGlobals *theGlobals); static void FSIterateContainerLevel( FSIterateContainerGlobals *theGlobals); static OSErr GenerateUniqueHFSUniStr( long *startSeed, const FSRef *dir1, const FSRef *dir2, HFSUniStr255 *uniqueName); /*****************************************************************************/ #pragma mark ----- File Access Routines ----- /*****************************************************************************/ OSErr FSCopyFork( SInt16 srcRefNum, SInt16 dstRefNum, void *copyBufferPtr, ByteCount copyBufferSize) { OSErr srcResult; OSErr dstResult; OSErr result; SInt64 forkSize; ByteCount readActualCount; /* check input parameters */ require_action((NULL != copyBufferPtr) && (0 != copyBufferSize), BadParameter, result = paramErr); /* get source fork size */ result = FSGetForkSize(srcRefNum, &forkSize); require_noerr(result, SourceFSGetForkSizeFailed); /* allocate disk space for destination fork */ result = FSSetForkSize(dstRefNum, fsFromStart, forkSize); require_noerr(result, DestinationFSSetForkSizeFailed); /* reset source fork's position to 0 */ result = FSSetForkPosition(srcRefNum, fsFromStart, 0); require_noerr(result, SourceFSSetForkPositionFailed); /* reset destination fork's position to 0 */ result = FSSetForkPosition(dstRefNum, fsFromStart, 0); require_noerr(result, DestinationFSSetForkPositionFailed); /* If copyBufferSize is greater than 4K bytes, make it a multiple of 4k bytes */ /* This will make writes on local volumes faster */ if ( (copyBufferSize >= 0x00001000) && ((copyBufferSize & 0x00000fff) != 0) ) { copyBufferSize &= ~(0x00001000 - 1); } /* copy source to destination */ srcResult = dstResult = noErr; while ( (noErr == srcResult) && (noErr == dstResult) ) { srcResult = FSReadFork(srcRefNum, fsAtMark + noCacheMask, 0, copyBufferSize, copyBufferPtr, &readActualCount); dstResult = FSWriteFork(dstRefNum, fsAtMark + noCacheMask, 0, readActualCount, copyBufferPtr, NULL); } /* make sure there were no errors at the destination */ require_noerr_action(dstResult, DestinationFSWriteForkFailed, result = dstResult); /* make sure the error at the source was eofErr */ require_action(eofErr == srcResult, SourceResultNotEofErr, result = srcResult); /* everything went as expected */ result = noErr; SourceResultNotEofErr: DestinationFSWriteForkFailed: DestinationFSSetForkPositionFailed: SourceFSSetForkPositionFailed: DestinationFSAllocateForkFailed: DestinationFSSetForkSizeFailed: SourceFSGetForkSizeFailed: BadParameter: return ( result ); } /*****************************************************************************/ #pragma mark ----- Volume Access Routines ----- /*****************************************************************************/ OSErr FSGetVolParms( FSVolumeRefNum volRefNum, UInt32 bufferSize, GetVolParmsInfoBuffer *volParmsInfo, UInt32 *actualInfoSize) { OSErr result; HParamBlockRec pb; /* check parameters */ require_action((NULL != volParmsInfo) && (NULL != actualInfoSize), BadParameter, result = paramErr); pb.ioParam.ioNamePtr = NULL; pb.ioParam.ioVRefNum = volRefNum; pb.ioParam.ioBuffer = (Ptr)volParmsInfo; pb.ioParam.ioReqCount = (SInt32)bufferSize; result = PBHGetVolParmsSync(&pb); require_noerr(result, PBHGetVolParmsSync); /* return number of bytes the file system returned in volParmsInfo buffer */ *actualInfoSize = (UInt32)pb.ioParam.ioActCount; PBHGetVolParmsSync: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSGetVRefNum( const FSRef *ref, FSVolumeRefNum *vRefNum) { OSErr result; FSCatalogInfo catalogInfo; /* check parameters */ require_action(NULL != vRefNum, BadParameter, result = paramErr); /* get the volume refNum from the FSRef */ result = FSGetCatalogInfo(ref, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL); require_noerr(result, FSGetCatalogInfo); /* return volume refNum from catalogInfo */ *vRefNum = catalogInfo.volume; FSGetCatalogInfo: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSGetVInfo( FSVolumeRefNum volume, HFSUniStr255 *volumeName, /* can be NULL */ UInt64 *freeBytes, /* can be NULL */ UInt64 *totalBytes) /* can be NULL */ { OSErr result; FSVolumeInfo info; /* ask for the volume's sizes only if needed */ result = FSGetVolumeInfo(volume, 0, NULL, (((NULL != freeBytes) || (NULL != totalBytes)) ? kFSVolInfoSizes : kFSVolInfoNone), &info, volumeName, NULL); require_noerr(result, FSGetVolumeInfo); if ( NULL != freeBytes ) { *freeBytes = info.freeBytes; } if ( NULL != totalBytes ) { *totalBytes = info.totalBytes; } FSGetVolumeInfo: return ( result ); } /*****************************************************************************/ OSErr FSGetVolFileSystemID( FSVolumeRefNum volume, UInt16 *fileSystemID, /* can be NULL */ UInt16 *signature) /* can be NULL */ { OSErr result; FSVolumeInfo info; result = FSGetVolumeInfo(volume, 0, NULL, kFSVolInfoFSInfo, &info, NULL, NULL); require_noerr(result, FSGetVolumeInfo); if ( NULL != fileSystemID ) { *fileSystemID = info.filesystemID; } if ( NULL != signature ) { *signature = info.signature; } FSGetVolumeInfo: return ( result ); } /*****************************************************************************/ OSErr FSGetMountedVolumes( FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */ ItemCount *numVolumes) { OSErr result; OSErr memResult; ItemCount volumeIndex; FSRef ref; /* check parameters */ require_action((NULL != volumeRefsHandle) && (NULL != numVolumes), BadParameter, result = paramErr); /* No volumes yet */ *numVolumes = 0; /* Allocate a handle for the results */ *volumeRefsHandle = (FSRef **)NewHandle(0); require_action(NULL != *volumeRefsHandle, NewHandle, result = memFullErr); /* Call FSGetVolumeInfo in loop to get all volumes starting with the first */ volumeIndex = 1; do { result = FSGetVolumeInfo(0, volumeIndex, NULL, kFSVolInfoNone, NULL, NULL, &ref); if ( noErr == result ) { /* concatenate the FSRef to the end of the handle */ PtrAndHand(&ref, (Handle)*volumeRefsHandle, sizeof(FSRef)); memResult = MemError(); require_noerr_action(memResult, MemoryAllocationFailed, result = memResult); ++(*numVolumes); /* increment the volume count */ ++volumeIndex; /* and the volumeIndex to get the next volume*/ } } while ( noErr == result ); /* nsvErr is OK -- it just means there are no more volumes */ require(nsvErr == result, FSGetVolumeInfo); return ( noErr ); /**********************/ MemoryAllocationFailed: FSGetVolumeInfo: /* dispose of handle if already allocated and clear the outputs */ if ( NULL != *volumeRefsHandle ) { DisposeHandle((Handle)*volumeRefsHandle); *volumeRefsHandle = NULL; } *numVolumes = 0; NewHandle: BadParameter: return ( result ); } /*****************************************************************************/ #pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines ----- /*****************************************************************************/ OSErr FSRefMakeFSSpec( const FSRef *ref, FSSpec *spec) { OSErr result; /* check parameters */ require_action(NULL != spec, BadParameter, result = paramErr); result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, spec, NULL); require_noerr(result, FSGetCatalogInfo); FSGetCatalogInfo: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSMakeFSRef( FSVolumeRefNum volRefNum, SInt32 dirID, ConstStr255Param name, FSRef *ref) { OSErr result; FSRefParam pb; /* check parameters */ require_action(NULL != ref, BadParameter, result = paramErr); pb.ioVRefNum = volRefNum; pb.ioDirID = dirID; pb.ioNamePtr = (StringPtr)name; pb.newRef = ref; result = PBMakeFSRefSync(&pb); require_noerr(result, PBMakeFSRefSync); PBMakeFSRefSync: BadParameter: return ( result ); } /*****************************************************************************/ OSStatus FSMakePath( SInt16 volRefNum, SInt32 dirID, ConstStr255Param name, UInt8 *path, UInt32 maxPathSize) { OSStatus result; FSRef ref; /* check parameters */ require_action(NULL != path, BadParameter, result = paramErr); /* convert the inputs to an FSRef */ result = FSMakeFSRef(volRefNum, dirID, name, &ref); require_noerr(result, FSMakeFSRef); /* and then convert the FSRef to a path */ result = FSRefMakePath(&ref, path, maxPathSize); require_noerr(result, FSRefMakePath); FSRefMakePath: FSMakeFSRef: BadParameter: return ( result ); } /*****************************************************************************/ OSStatus FSPathMakeFSSpec( const UInt8 *path, FSSpec *spec, Boolean *isDirectory) /* can be NULL */ { OSStatus result; FSRef ref; /* check parameters */ require_action(NULL != spec, BadParameter, result = paramErr); /* convert the POSIX path to an FSRef */ result = FSPathMakeRef(path, &ref, isDirectory); require_noerr(result, FSPathMakeRef); /* and then convert the FSRef to an FSSpec */ result = FSGetCatalogInfo(&ref, kFSCatInfoNone, NULL, NULL, spec, NULL); require_noerr(result, FSGetCatalogInfo); FSGetCatalogInfo: FSPathMakeRef: BadParameter: return ( result ); } /*****************************************************************************/ OSErr UnicodeNameGetHFSName( UniCharCount nameLength, const UniChar *name, TextEncoding textEncodingHint, Boolean isVolumeName, Str31 hfsName) { OSStatus result; ByteCount unicodeByteLength; ByteCount unicodeBytesConverted; ByteCount actualPascalBytes; UnicodeMapping uMapping; UnicodeToTextInfo utInfo; /* check parameters */ require_action(NULL != hfsName, BadParameter, result = paramErr); /* make sure output is valid in case we get errors or there's nothing to convert */ StrLength(hfsName) = 0; unicodeByteLength = nameLength * sizeof(UniChar); if ( 0 == unicodeByteLength ) { /* do nothing */ result = noErr; } else { /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ if ( kTextEncodingUnknown == textEncodingHint ) { ScriptCode script; RegionCode region; script = (ScriptCode)GetScriptManagerVariable(smSysScript); region = (RegionCode)GetScriptManagerVariable(smRegionCode); result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region, NULL, &textEncodingHint ); if ( paramErr == result ) { /* ok, ignore the region and try again */ result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, kTextRegionDontCare, NULL, &textEncodingHint ); } if ( noErr != result ) { /* ok... try something */ textEncodingHint = kTextEncodingMacRoman; } } uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0, kUnicodeCanonicalDecompVariant, kUnicode16BitFormat); uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint); uMapping.mappingVersion = kUnicodeUseHFSPlusMapping; result = CreateUnicodeToTextInfo(&uMapping, &utInfo); require_noerr(result, CreateUnicodeToTextInfo); result = ConvertFromUnicodeToText(utInfo, unicodeByteLength, name, kUnicodeLooseMappingsMask, 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */ isVolumeName ? kHFSMaxVolumeNameChars : kHFSMaxFileNameChars, &unicodeBytesConverted, &actualPascalBytes, &hfsName[1]); require_noerr(result, ConvertFromUnicodeToText); StrLength(hfsName) = (unsigned char)actualPascalBytes; /* fill in length byte */ ConvertFromUnicodeToText: /* verify the result in debug builds -- there's really not anything you can do if it fails */ verify_noerr(DisposeUnicodeToTextInfo(&utInfo)); } CreateUnicodeToTextInfo: BadParameter: return ( result ); } /*****************************************************************************/ OSErr HFSNameGetUnicodeName( ConstStr31Param hfsName, TextEncoding textEncodingHint, HFSUniStr255 *unicodeName) { ByteCount unicodeByteLength; OSStatus result; UnicodeMapping uMapping; TextToUnicodeInfo tuInfo; ByteCount pascalCharsRead; /* check parameters */ require_action(NULL != unicodeName, BadParameter, result = paramErr); /* make sure output is valid in case we get errors or there's nothing to convert */ unicodeName->length = 0; if ( 0 == StrLength(hfsName) ) { result = noErr; } else { /* if textEncodingHint is kTextEncodingUnknown, get a "default" textEncodingHint */ if ( kTextEncodingUnknown == textEncodingHint ) { ScriptCode script; RegionCode region; script = GetScriptManagerVariable(smSysScript); region = GetScriptManagerVariable(smRegionCode); result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, region, NULL, &textEncodingHint); if ( paramErr == result ) { /* ok, ignore the region and try again */ result = UpgradeScriptInfoToTextEncoding(script, kTextLanguageDontCare, kTextRegionDontCare, NULL, &textEncodingHint); } if ( noErr != result ) { /* ok... try something */ textEncodingHint = kTextEncodingMacRoman; } } uMapping.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeV2_0, kUnicodeCanonicalDecompVariant, kUnicode16BitFormat); uMapping.otherEncoding = GetTextEncodingBase(textEncodingHint); uMapping.mappingVersion = kUnicodeUseHFSPlusMapping; result = CreateTextToUnicodeInfo(&uMapping, &tuInfo); require_noerr(result, CreateTextToUnicodeInfo); result = ConvertFromTextToUnicode(tuInfo, hfsName[0], &hfsName[1], 0, /* no control flag bits */ 0, NULL, 0, NULL, /* offsetCounts & offsetArrays */ sizeof(unicodeName->unicode), /* output buffer size in bytes */ &pascalCharsRead, &unicodeByteLength, unicodeName->unicode); require_noerr(result, ConvertFromTextToUnicode); /* convert from byte count to char count */ unicodeName->length = unicodeByteLength / sizeof(UniChar); ConvertFromTextToUnicode: /* verify the result in debug builds -- there's really not anything you can do if it fails */ verify_noerr(DisposeTextToUnicodeInfo(&tuInfo)); } CreateTextToUnicodeInfo: BadParameter: return ( result ); } /*****************************************************************************/ #pragma mark ----- File/Directory Manipulation Routines ----- /*****************************************************************************/ Boolean FSRefValid(const FSRef *ref) { return ( noErr == FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, NULL, NULL) ); } /*****************************************************************************/ OSErr FSGetParentRef( const FSRef *ref, FSRef *parentRef) { OSErr result; FSCatalogInfo catalogInfo; /* check parameters */ require_action(NULL != parentRef, BadParameter, result = paramErr); result = FSGetCatalogInfo(ref, kFSCatInfoNodeID, &catalogInfo, NULL, NULL, parentRef); require_noerr(result, FSGetCatalogInfo); /* * Note: FSRefs always point to real file system objects. So, there cannot * be a FSRef to the parent of volume root directories. Early versions of * Mac OS X do not handle this case correctly and incorrectly return a * FSRef for the parent of volume root directories instead of returning an * invalid FSRef (a cleared FSRef is invalid). The next three lines of code * ensure that you won't run into this bug. WW9D! */ if ( fsRtDirID == catalogInfo.nodeID ) { /* clear parentRef and return noErr which is the proper behavior */ memset(parentRef, 0, sizeof(FSRef)); } FSGetCatalogInfo: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSGetFileDirName( const FSRef *ref, HFSUniStr255 *outName) { OSErr result; /* check parameters */ require_action(NULL != outName, BadParameter, result = paramErr); result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, outName, NULL, NULL); require_noerr(result, FSGetCatalogInfo); FSGetCatalogInfo: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSGetNodeID( const FSRef *ref, long *nodeID, /* can be NULL */ Boolean *isDirectory) /* can be NULL */ { OSErr result; FSCatalogInfo catalogInfo; FSCatalogInfoBitmap whichInfo; /* determine what catalog information to get */ whichInfo = kFSCatInfoNone; /* start with none */ if ( NULL != nodeID ) { whichInfo |= kFSCatInfoNodeID; } if ( NULL != isDirectory ) { whichInfo |= kFSCatInfoNodeFlags; } result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL); require_noerr(result, FSGetCatalogInfo); if ( NULL != nodeID ) { *nodeID = catalogInfo.nodeID; } if ( NULL != isDirectory ) { *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags)); } FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSGetUserPrivilegesPermissions( const FSRef *ref, UInt8 *userPrivileges, /* can be NULL */ UInt32 permissions[4]) /* can be NULL */ { OSErr result; FSCatalogInfo catalogInfo; FSCatalogInfoBitmap whichInfo; /* determine what catalog information to get */ whichInfo = kFSCatInfoNone; /* start with none */ if ( NULL != userPrivileges ) { whichInfo |= kFSCatInfoUserPrivs; } if ( NULL != permissions ) { whichInfo |= kFSCatInfoPermissions; } result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL); require_noerr(result, FSGetCatalogInfo); if ( NULL != userPrivileges ) { *userPrivileges = catalogInfo.userPrivileges; } if ( NULL != permissions ) { BlockMoveData(&catalogInfo.permissions, permissions, sizeof(UInt32) * 4); } FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSCheckLock( const FSRef *ref) { OSErr result; FSCatalogInfo catalogInfo; FSVolumeInfo volumeInfo; /* get nodeFlags and vRefNum for container */ result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoVolume, &catalogInfo, NULL, NULL,NULL); require_noerr(result, FSGetCatalogInfo); /* is file locked? */ if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) ) { result = fLckdErr; /* file is locked */ } else { /* file isn't locked, but is volume locked? */ /* get volume flags */ result = FSGetVolumeInfo(catalogInfo.volume, 0, NULL, kFSVolInfoFlags, &volumeInfo, NULL, NULL); require_noerr(result, FSGetVolumeInfo); if ( 0 != (volumeInfo.flags & kFSVolFlagHardwareLockedMask) ) { result = wPrErr; /* volume locked by hardware */ } else if ( 0 != (volumeInfo.flags & kFSVolFlagSoftwareLockedMask) ) { result = vLckdErr; /* volume locked by software */ } } FSGetVolumeInfo: FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSGetForkSizes( const FSRef *ref, UInt64 *dataLogicalSize, /* can be NULL */ UInt64 *rsrcLogicalSize) /* can be NULL */ { OSErr result; FSCatalogInfoBitmap whichInfo; FSCatalogInfo catalogInfo; whichInfo = kFSCatInfoNodeFlags; if ( NULL != dataLogicalSize ) { /* get data fork size */ whichInfo |= kFSCatInfoDataSizes; } if ( NULL != rsrcLogicalSize ) { /* get resource fork size */ whichInfo |= kFSCatInfoRsrcSizes; } /* get nodeFlags and catalog info */ result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL,NULL); require_noerr(result, FSGetCatalogInfo); /* make sure FSRef was to a file */ require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr); if ( NULL != dataLogicalSize ) { /* return data fork size */ *dataLogicalSize = catalogInfo.dataLogicalSize; } if ( NULL != rsrcLogicalSize ) { /* return resource fork size */ *rsrcLogicalSize = catalogInfo.rsrcLogicalSize; } FSRefNotFile: FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSGetTotalForkSizes( const FSRef *ref, UInt64 *totalLogicalSize, /* can be NULL */ UInt64 *totalPhysicalSize, /* can be NULL */ ItemCount *forkCount) /* can be NULL */ { OSErr result; CatPositionRec forkIterator; SInt64 forkSize; SInt64 *forkSizePtr; UInt64 forkPhysicalSize; UInt64 *forkPhysicalSizePtr; /* Determine if forkSize needed */ if ( NULL != totalLogicalSize) { *totalLogicalSize = 0; forkSizePtr = &forkSize; } else { forkSizePtr = NULL; } /* Determine if forkPhysicalSize is needed */ if ( NULL != totalPhysicalSize ) { *totalPhysicalSize = 0; forkPhysicalSizePtr = &forkPhysicalSize; } else { forkPhysicalSizePtr = NULL; } /* zero fork count if returning it */ if ( NULL != forkCount ) { *forkCount = 0; } /* Iterate through the forks to get the sizes */ forkIterator.initialize = 0; do { result = FSIterateForks(ref, &forkIterator, NULL, forkSizePtr, forkPhysicalSizePtr); if ( noErr == result ) { if ( NULL != totalLogicalSize ) { *totalLogicalSize += forkSize; } if ( NULL != totalPhysicalSize ) { *totalPhysicalSize += forkPhysicalSize; } if ( NULL != forkCount ) { ++*forkCount; } } } while ( noErr == result ); /* any error result other than errFSNoMoreItems is serious */ require(errFSNoMoreItems == result, FSIterateForks); /* Normal exit */ result = noErr; FSIterateForks: return ( result ); } /*****************************************************************************/ OSErr FSBumpDate( const FSRef *ref) { OSStatus result; FSCatalogInfo catalogInfo; UTCDateTime oldDateTime; #if !BuildingMoreFilesXForMacOS9 FSRef parentRef; Boolean notifyParent; #endif #if !BuildingMoreFilesXForMacOS9 /* Get the node flags, the content modification date and time, and the parent ref */ result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoContentMod, &catalogInfo, NULL, NULL, &parentRef); require_noerr(result, FSGetCatalogInfo); /* Notify the parent if this is a file */ notifyParent = (0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask)); #else /* Get the content modification date and time */ result = FSGetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo, NULL, NULL, NULL); require_noerr(result, FSGetCatalogInfo); #endif oldDateTime = catalogInfo.contentModDate; /* Get the current date and time */ result = GetUTCDateTime(&catalogInfo.contentModDate, kUTCDefaultOptions); require_noerr(result, GetUTCDateTime); /* if the old date and time is the the same as the current, bump the seconds by one */ if ( (catalogInfo.contentModDate.fraction == oldDateTime.fraction) && (catalogInfo.contentModDate.lowSeconds == oldDateTime.lowSeconds) && (catalogInfo.contentModDate.highSeconds == oldDateTime.highSeconds) ) { ++catalogInfo.contentModDate.lowSeconds; if ( 0 == catalogInfo.contentModDate.lowSeconds ) { ++catalogInfo.contentModDate.highSeconds; } } /* Bump the content modification date and time */ result = FSSetCatalogInfo(ref, kFSCatInfoContentMod, &catalogInfo); require_noerr(result, FSSetCatalogInfo); #if !BuildingMoreFilesXForMacOS9 /* * The problem with FNNotify is that it is not available under Mac OS 9 * and there's no way to test for that except for looking for the symbol * or something. So, I'll just conditionalize this for those who care * to send a notification. */ /* Send a notification for the parent of the file, or for the directory */ result = FNNotify(notifyParent ? &parentRef : ref, kFNDirectoryModifiedMessage, kNilOptions); require_noerr(result, FNNotify); #endif /* ignore errors from FSSetCatalogInfo (volume might be write protected) and FNNotify */ FNNotify: FSSetCatalogInfo: return ( noErr ); /**********************/ GetUTCDateTime: FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSGetFinderInfo( const FSRef *ref, FinderInfo *info, /* can be NULL */ ExtendedFinderInfo *extendedInfo, /* can be NULL */ Boolean *isDirectory) /* can be NULL */ { OSErr result; FSCatalogInfo catalogInfo; FSCatalogInfoBitmap whichInfo; /* determine what catalog information is really needed */ whichInfo = kFSCatInfoNone; if ( NULL != info ) { /* get FinderInfo */ whichInfo |= kFSCatInfoFinderInfo; } if ( NULL != extendedInfo ) { /* get ExtendedFinderInfo */ whichInfo |= kFSCatInfoFinderXInfo; } if ( NULL != isDirectory ) { whichInfo |= kFSCatInfoNodeFlags; } result = FSGetCatalogInfo(ref, whichInfo, &catalogInfo, NULL, NULL, NULL); require_noerr(result, FSGetCatalogInfo); /* return FinderInfo if requested */ if ( NULL != info ) { BlockMoveData(catalogInfo.finderInfo, info, sizeof(FinderInfo)); } /* return ExtendedFinderInfo if requested */ if ( NULL != extendedInfo) { BlockMoveData(catalogInfo.extFinderInfo, extendedInfo, sizeof(ExtendedFinderInfo)); } /* set isDirectory Boolean if requested */ if ( NULL != isDirectory) { *isDirectory = (0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags)); } FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSSetFinderInfo( const FSRef *ref, const FinderInfo *info, const ExtendedFinderInfo *extendedInfo) { OSErr result; FSCatalogInfo catalogInfo; FSCatalogInfoBitmap whichInfo; /* determine what catalog information will be set */ whichInfo = kFSCatInfoNone; /* start with none */ if ( NULL != info ) { /* set FinderInfo */ whichInfo |= kFSCatInfoFinderInfo; BlockMoveData(info, catalogInfo.finderInfo, sizeof(FinderInfo)); } if ( NULL != extendedInfo ) { /* set ExtendedFinderInfo */ whichInfo |= kFSCatInfoFinderXInfo; BlockMoveData(extendedInfo, catalogInfo.extFinderInfo, sizeof(ExtendedFinderInfo)); } result = FSSetCatalogInfo(ref, whichInfo, &catalogInfo); require_noerr(result, FSGetCatalogInfo); FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSChangeCreatorType( const FSRef *ref, OSType fileCreator, OSType fileType) { OSErr result; FSCatalogInfo catalogInfo; FSRef parentRef; /* get nodeFlags, finder info, and parent FSRef */ result = FSGetCatalogInfo(ref, kFSCatInfoNodeFlags + kFSCatInfoFinderInfo, &catalogInfo , NULL, NULL, &parentRef); require_noerr(result, FSGetCatalogInfo); /* make sure FSRef was to a file */ require_action(0 == (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), FSRefNotFile, result = notAFileErr); /* If fileType not 0x00000000, change fileType */ if ( fileType != (OSType)0x00000000 ) { ((FileInfo *)&catalogInfo.finderInfo)->fileType = fileType; } /* If creator not 0x00000000, change creator */ if ( fileCreator != (OSType)0x00000000 ) { ((FileInfo *)&catalogInfo.finderInfo)->fileCreator = fileCreator; } /* now, save the new information back to disk */ result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo); require_noerr(result, FSSetCatalogInfo); /* and attempt to bump the parent directory's mod date to wake up */ /* the Finder to the change we just made (ignore errors from this) */ verify_noerr(FSBumpDate(&parentRef)); FSSetCatalogInfo: FSRefNotFile: FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSChangeFinderFlags( const FSRef *ref, Boolean setBits, UInt16 flagBits) { OSErr result; FSCatalogInfo catalogInfo; FSRef parentRef; /* get the current finderInfo */ result = FSGetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo, NULL, NULL, &parentRef); require_noerr(result, FSGetCatalogInfo); /* set or clear the appropriate bits in the finderInfo.finderFlags */ if ( setBits ) { /* OR in the bits */ ((FileInfo *)&catalogInfo.finderInfo)->finderFlags |= flagBits; } else { /* AND out the bits */ ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~flagBits; } /* save the modified finderInfo */ result = FSSetCatalogInfo(ref, kFSCatInfoFinderInfo, &catalogInfo); require_noerr(result, FSSetCatalogInfo); /* and attempt to bump the parent directory's mod date to wake up the Finder */ /* to the change we just made (ignore errors from this) */ verify_noerr(FSBumpDate(&parentRef)); FSSetCatalogInfo: FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSSetInvisible( const FSRef *ref) { return ( FSChangeFinderFlags(ref, true, kIsInvisible) ); } OSErr FSClearInvisible( const FSRef *ref) { return ( FSChangeFinderFlags(ref, false, kIsInvisible) ); } /*****************************************************************************/ OSErr FSSetNameLocked( const FSRef *ref) { return ( FSChangeFinderFlags(ref, true, kNameLocked) ); } OSErr FSClearNameLocked( const FSRef *ref) { return ( FSChangeFinderFlags(ref, false, kNameLocked) ); } /*****************************************************************************/ OSErr FSSetIsStationery( const FSRef *ref) { return ( FSChangeFinderFlags(ref, true, kIsStationery) ); } OSErr FSClearIsStationery( const FSRef *ref) { return ( FSChangeFinderFlags(ref, false, kIsStationery) ); } /*****************************************************************************/ OSErr FSSetHasCustomIcon( const FSRef *ref) { return ( FSChangeFinderFlags(ref, true, kHasCustomIcon) ); } OSErr FSClearHasCustomIcon( const FSRef *ref) { return ( FSChangeFinderFlags(ref, false, kHasCustomIcon) ); } /*****************************************************************************/ OSErr FSClearHasBeenInited( const FSRef *ref) { return ( FSChangeFinderFlags(ref, false, kHasBeenInited) ); } /*****************************************************************************/ OSErr FSCopyFileMgrAttributes( const FSRef *sourceRef, const FSRef *destinationRef, Boolean copyLockBit) { OSErr result; FSCatalogInfo catalogInfo; /* get the source information */ result = FSGetCatalogInfo(sourceRef, kFSCatInfoSettableInfo, &catalogInfo, NULL, NULL, NULL); require_noerr(result, FSGetCatalogInfo); /* don't copy the hasBeenInited bit; clear it */ ((FileInfo *)&catalogInfo.finderInfo)->finderFlags &= ~kHasBeenInited; /* should the locked bit be copied? */ if ( !copyLockBit ) { /* no, make sure the locked bit is clear */ catalogInfo.nodeFlags &= ~kFSNodeLockedMask; } /* set the destination information */ result = FSSetCatalogInfo(destinationRef, kFSCatInfoSettableInfo, &catalogInfo); require_noerr(result, FSSetCatalogInfo); FSSetCatalogInfo: FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSMoveRenameObjectUnicode( const FSRef *ref, const FSRef *destDirectory, UniCharCount nameLength, const UniChar *name, /* can be NULL (no rename during move) */ TextEncoding textEncodingHint, FSRef *newRef) /* if function fails along the way, newRef is final location of file */ { OSErr result; FSVolumeRefNum vRefNum; FSCatalogInfo catalogInfo; FSRef originalDirectory; TextEncoding originalTextEncodingHint; HFSUniStr255 originalName; long tempItemsDirID; Str31 uniqueTempDirName; long uniqueTempDirID; FSRef uniqueTempDirRef; /* check parameters */ require_action(NULL != newRef, BadParameter, result = paramErr); /* newRef = input to start with */ BlockMoveData(ref, newRef, sizeof(FSRef)); /* get destDirectory's vRefNum */ result = FSGetCatalogInfo(destDirectory, kFSCatInfoVolume, &catalogInfo, NULL, NULL, NULL); require_noerr(result, DestinationBad); /* save vRefNum */ vRefNum = catalogInfo.volume; /* get ref's vRefNum, TextEncoding, name and parent directory*/ result = FSGetCatalogInfo(ref, kFSCatInfoTextEncoding + kFSCatInfoVolume, &catalogInfo, &originalName, NULL, &originalDirectory); require_noerr(result, SourceBad); /* save TextEncoding */ originalTextEncodingHint = catalogInfo.textEncodingHint; /* make sure ref and destDirectory are on same volume */ require_action(vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr); /* Skip a lot of steps if we're not renaming */ if ( NULL != name ) { /* find the Temporary Items Folder on sourcevRefNum */ result = FindFolder(vRefNum, kTemporaryFolderType, kCreateFolder, &vRefNum, &tempItemsDirID); require_noerr(result, NoTemporaryFolder); /* 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 'A' plus the current tick count as uniqueTempDirName */ NumToString(TickCount(), &uniqueTempDirName[1]); uniqueTempDirName[0] = uniqueTempDirName[1] + 1; uniqueTempDirName[1] = 'A'; do { result = DirCreate(vRefNum, tempItemsDirID, uniqueTempDirName, &uniqueTempDirID); if ( dupFNErr == result ) { /* Duplicate name - change the first character to the next ASCII character */ ++uniqueTempDirName[1]; } } while ( (dupFNErr == result) && (uniqueTempDirName[1] < 'Z') ); /* 26 new weirdly named directories per 1/60th second - not likely! */ require_noerr(result, CouldNotCreateUniqueTempDir); /* get FSRef to UniqueTempDir */ result = FSMakeFSRef(vRefNum, uniqueTempDirID, NULL, &uniqueTempDirRef); require_noerr(result, FSMakeFSRef); /* Move the object to the folder with uniqueTempDirRef for renaming */ result = FSMoveObject(ref, &uniqueTempDirRef, newRef); require_noerr(result, FSMoveObjectBeforeRenameFailed); /* Rename the object */ result = FSRenameUnicode(newRef, nameLength, name, textEncodingHint, newRef); require_noerr(result, FSRenameUnicode); /* Move object to its new home */ result = FSMoveObject(newRef, destDirectory, newRef); require_noerr(result, FSMoveObjectAfterRenameFailed); /* Done with ourTempDir, so delete it - ignore errors */ verify_noerr(HDelete(vRefNum, uniqueTempDirID, NULL)); } else { /* Move object to its new home */ result = FSMoveObject(newRef, destDirectory, newRef); require_noerr(result, FSMoveObjectNoRenameFailed); } return ( result ); /*************/ /* * failure handling code when renaming */ FSMoveObjectAfterRenameFailed: /* Error handling: rename object back to original name - ignore errors */ verify_noerr(FSRenameUnicode(newRef, originalName.length, originalName.unicode, originalTextEncodingHint, newRef)); FSRenameUnicode: /* Error handling: move object back to original location - ignore errors */ verify_noerr(FSMoveObject(newRef, &originalDirectory, newRef)); FSMoveObjectBeforeRenameFailed: FSMakeFSRef: /* Done with ourTempDir, so delete it - ignore errors */ verify_noerr(HDelete(vRefNum, uniqueTempDirID, NULL)); CouldNotCreateUniqueTempDir: NoTemporaryFolder: /* * failure handling code for renaming or not */ FSMoveObjectNoRenameFailed: NotSameVolume: SourceBad: DestinationBad: BadParameter: return ( result ); } /*****************************************************************************/ /* The FSDeleteContainerLevel function deletes the contents of a container directory. All files and subdirectories in the specified container are deleted. If a locked file or directory is encountered, it is unlocked and then deleted. If any unexpected errors are encountered, FSDeleteContainerLevel quits and returns to the caller. container --> FSRef to a directory. theGlobals --> A pointer to a FSDeleteContainerGlobals struct which contains the variables that do not need to be allocated each time FSDeleteContainerLevel recurses. That lets FSDeleteContainerLevel use less stack space per recursion level. */ static void FSDeleteContainerLevel( const FSRef *container, FSDeleteContainerGlobals *theGlobals) { /* level locals */ FSIterator iterator; FSRef itemToDelete; UInt16 nodeFlags; /* Open FSIterator for flat access and give delete optimization hint */ theGlobals->result = FSOpenIterator(container, kFSIterateFlat + kFSIterateDelete, &iterator); require_noerr(theGlobals->result, FSOpenIterator); /* delete the contents of the directory */ do { /* get 1 item to delete */ theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects, NULL, kFSCatInfoNodeFlags, &theGlobals->catalogInfo, &itemToDelete, NULL, NULL); if ( (noErr == theGlobals->result) && (1 == theGlobals->actualObjects) ) { /* save node flags in local in case we have to recurse */ nodeFlags = theGlobals->catalogInfo.nodeFlags; /* is it a file or directory? */ if ( 0 != (nodeFlags & kFSNodeIsDirectoryMask) ) { /* it's a directory -- delete its contents before attempting to delete it */ FSDeleteContainerLevel(&itemToDelete, theGlobals); } /* are we still OK to delete? */ if ( noErr == theGlobals->result ) { /* is item locked? */ if ( 0 != (nodeFlags & kFSNodeLockedMask) ) { /* then attempt to unlock it (ignore result since FSDeleteObject will set it correctly) */ theGlobals->catalogInfo.nodeFlags = nodeFlags & ~kFSNodeLockedMask; (void) FSSetCatalogInfo(&itemToDelete, kFSCatInfoNodeFlags, &theGlobals->catalogInfo); } /* delete the item */ theGlobals->result = FSDeleteObject(&itemToDelete); } } } while ( noErr == theGlobals->result ); /* we found the end of the items normally, so return noErr */ if ( errFSNoMoreItems == theGlobals->result ) { theGlobals->result = noErr; } /* close the FSIterator (closing an open iterator should never fail) */ verify_noerr(FSCloseIterator(iterator)); FSOpenIterator: return; } /*****************************************************************************/ OSErr FSDeleteContainerContents( const FSRef *container) { FSDeleteContainerGlobals theGlobals; /* delete container's contents */ FSDeleteContainerLevel(container, &theGlobals); return ( theGlobals.result ); } /*****************************************************************************/ OSErr FSDeleteContainer( const FSRef *container) { OSErr result; FSCatalogInfo catalogInfo; /* get nodeFlags for container */ result = FSGetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo, NULL, NULL,NULL); require_noerr(result, FSGetCatalogInfo); /* make sure container is a directory */ require_action(0 != (catalogInfo.nodeFlags & kFSNodeIsDirectoryMask), ContainerNotDirectory, result = dirNFErr); /* delete container's contents */ result = FSDeleteContainerContents(container); require_noerr(result, FSDeleteContainerContents); /* is container locked? */ if ( 0 != (catalogInfo.nodeFlags & kFSNodeLockedMask) ) { /* then attempt to unlock container (ignore result since FSDeleteObject will set it correctly) */ catalogInfo.nodeFlags &= ~kFSNodeLockedMask; (void) FSSetCatalogInfo(container, kFSCatInfoNodeFlags, &catalogInfo); } /* delete the container */ result = FSDeleteObject(container); FSDeleteContainerContents: ContainerNotDirectory: FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ /* The FSIterateContainerLevel function iterates the contents of a container directory and calls a IterateContainerFilterProc function once for each file and directory found. theGlobals --> A pointer to a FSIterateContainerGlobals struct which contains the variables needed globally by all recusion levels of FSIterateContainerLevel. That makes FSIterateContainer thread safe since each call to it uses its own global world. It also contains the variables that do not need to be allocated each time FSIterateContainerLevel recurses. That lets FSIterateContainerLevel use less stack space per recursion level. */ static void FSIterateContainerLevel( FSIterateContainerGlobals *theGlobals) { FSIterator iterator; /* If maxLevels is zero, we aren't checking levels */ /* If currentLevel < maxLevels, look at this level */ if ( (theGlobals->maxLevels == 0) || (theGlobals->currentLevel < theGlobals->maxLevels) ) { /* Open FSIterator for flat access to theGlobals->ref */ theGlobals->result = FSOpenIterator(&theGlobals->ref, kFSIterateFlat, &iterator); require_noerr(theGlobals->result, FSOpenIterator); ++theGlobals->currentLevel; /* Go to next level */ /* Call FSGetCatalogInfoBulk in loop to get all items in the container */ do { theGlobals->result = FSGetCatalogInfoBulk(iterator, 1, &theGlobals->actualObjects, &theGlobals->containerChanged, theGlobals->whichInfo, &theGlobals->catalogInfo, &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr); if ( (noErr == theGlobals->result || errFSNoMoreItems == theGlobals->result) && (0 != theGlobals->actualObjects) ) { /* Call the IterateFilterProc */ theGlobals->quitFlag = CallIterateContainerFilterProc(theGlobals->iterateFilter, theGlobals->containerChanged, theGlobals->currentLevel, &theGlobals->catalogInfo, &theGlobals->ref, theGlobals->specPtr, theGlobals->namePtr, theGlobals->yourDataPtr); /* Is it a directory? */ if ( 0 != (theGlobals->catalogInfo.nodeFlags & kFSNodeIsDirectoryMask) ) { /* Keep going? */ if ( !theGlobals->quitFlag ) { /* Dive again if the IterateFilterProc didn't say "quit" */ FSIterateContainerLevel(theGlobals); } } } /* time to fall back a level? */ } while ( (noErr == theGlobals->result) && (!theGlobals->quitFlag) ); /* errFSNoMoreItems is OK - it only means we hit the end of this level */ /* afpAccessDenied is OK, too - it only means we cannot see inside a directory */ if ( (errFSNoMoreItems == theGlobals->result) || (afpAccessDenied == theGlobals->result) ) { theGlobals->result = noErr; } --theGlobals->currentLevel; /* Return to previous level as we leave */ /* Close the FSIterator (closing an open iterator should never fail) */ verify_noerr(FSCloseIterator(iterator)); } FSOpenIterator: return; } /*****************************************************************************/ OSErr FSIterateContainer( const FSRef *container, ItemCount maxLevels, FSCatalogInfoBitmap whichInfo, Boolean wantFSSpec, Boolean wantName, IterateContainerFilterProcPtr iterateFilter, void *yourDataPtr) { OSErr result; FSIterateContainerGlobals theGlobals; /* make sure there is an iterateFilter */ require_action(iterateFilter != NULL, NoIterateFilter, result = paramErr); /* * set up the globals we need to access from the recursive routine */ theGlobals.iterateFilter = iterateFilter; /* we need the node flags no matter what was requested so we can detect files vs. directories */ theGlobals.whichInfo = whichInfo | kFSCatInfoNodeFlags; /* start with input container -- the first OpenIterator will ensure it is a directory */ theGlobals.ref = *container; if ( wantFSSpec ) { theGlobals.specPtr = &theGlobals.spec; } else { theGlobals.specPtr = NULL; } if ( wantName ) { theGlobals.namePtr = &theGlobals.name; } else { theGlobals.namePtr = NULL; } theGlobals.yourDataPtr = yourDataPtr; theGlobals.maxLevels = maxLevels; theGlobals.currentLevel = 0; theGlobals.quitFlag = false; theGlobals.containerChanged = false; theGlobals.result = noErr; theGlobals.actualObjects = 0; /* here we go into recursion land... */ FSIterateContainerLevel(&theGlobals); result = theGlobals.result; require_noerr(result, FSIterateContainerLevel); FSIterateContainerLevel: NoIterateFilter: return ( result ); } /*****************************************************************************/ OSErr FSGetDirectoryItems( const FSRef *container, FSRef ***refsHandle, /* pointer to handle of FSRefs */ ItemCount *numRefs, Boolean *containerChanged) { /* Grab items 10 at a time. */ enum { kMaxItemsPerBulkCall = 10 }; OSErr result; OSErr memResult; FSIterator iterator; FSRef refs[kMaxItemsPerBulkCall]; ItemCount actualObjects; Boolean changed; /* check parameters */ require_action((NULL != refsHandle) && (NULL != numRefs) && (NULL != containerChanged), BadParameter, result = paramErr); *numRefs = 0; *containerChanged = false; *refsHandle = (FSRef **)NewHandle(0); require_action(NULL != *refsHandle, NewHandle, result = memFullErr); /* open an FSIterator */ result = FSOpenIterator(container, kFSIterateFlat, &iterator); require_noerr(result, FSOpenIterator); /* Call FSGetCatalogInfoBulk in loop to get all items in the container */ do { result = FSGetCatalogInfoBulk(iterator, kMaxItemsPerBulkCall, &actualObjects, &changed, kFSCatInfoNone, NULL, refs, NULL, NULL); /* if the container changed, set containerChanged for output, but keep going */ if ( changed ) { *containerChanged = changed; } /* any result other than noErr and errFSNoMoreItems is serious */ require((noErr == result) || (errFSNoMoreItems == result), FSGetCatalogInfoBulk); /* add objects to output array and count */ if ( 0 != actualObjects ) { /* concatenate the FSRefs to the end of the handle */ PtrAndHand(refs, (Handle)*refsHandle, actualObjects * sizeof(FSRef)); memResult = MemError(); require_noerr_action(memResult, MemoryAllocationFailed, result = memResult); *numRefs += actualObjects; } } while ( noErr == result ); verify_noerr(FSCloseIterator(iterator)); /* closing an open iterator should never fail, but... */ return ( noErr ); /**********************/ MemoryAllocationFailed: FSGetCatalogInfoBulk: /* close the iterator */ verify_noerr(FSCloseIterator(iterator)); FSOpenIterator: /* dispose of handle if already allocated and clear the outputs */ if ( NULL != *refsHandle ) { DisposeHandle((Handle)*refsHandle); *refsHandle = NULL; } *numRefs = 0; NewHandle: BadParameter: return ( result ); } /*****************************************************************************/ /* The GenerateUniqueName function generates a HFSUniStr255 name that is unique in both dir1 and dir2. startSeed --> A pointer to a long which is used to generate the unique name. <-- It is modified on output to a value which should be used to generate the next unique name. dir1 --> The first directory. dir2 --> The second directory. uniqueName <-- A pointer to a HFSUniStr255 where the unique name is to be returned. */ static OSErr GenerateUniqueHFSUniStr( long *startSeed, const FSRef *dir1, const FSRef *dir2, HFSUniStr255 *uniqueName) { OSErr result; long i; FSRefParam pb; FSRef newRef; unsigned char hexStr[16] = "0123456789ABCDEF"; /* set up the parameter block */ pb.name = uniqueName->unicode; pb.nameLength = 8; /* always 8 characters */ pb.textEncodingHint = kTextEncodingUnknown; pb.newRef = &newRef; /* loop until we get fnfErr with a filename in both directories */ result = noErr; while ( fnfErr != result ) { /* convert startSeed to 8 character Unicode string */ uniqueName->length = 8; for ( i = 0; i < 8; ++i ) { uniqueName->unicode[i] = hexStr[((*startSeed >> ((7-i)*4)) & 0xf)]; } /* try in dir1 */ pb.ref = dir1; result = PBMakeFSRefUnicodeSync(&pb); if ( fnfErr == result ) { /* try in dir2 */ pb.ref = dir2; result = PBMakeFSRefUnicodeSync(&pb); if ( fnfErr != result ) { /* exit if anything other than noErr or fnfErr */ require_noerr(result, Dir2PBMakeFSRefUnicodeSyncFailed); } } else { /* exit if anything other than noErr or fnfErr */ require_noerr(result, Dir1PBMakeFSRefUnicodeSyncFailed); } /* increment seed for next pass through loop, */ /* or for next call to GenerateUniqueHFSUniStr */ ++(*startSeed); } /* we have a unique file name which doesn't exist in dir1 or dir2 */ result = noErr; Dir2PBMakeFSRefUnicodeSyncFailed: Dir1PBMakeFSRefUnicodeSyncFailed: return ( result ); } /*****************************************************************************/ OSErr FSExchangeObjectsCompat( const FSRef *sourceRef, const FSRef *destRef, FSRef *newSourceRef, FSRef *newDestRef) { enum { /* get all settable info except for mod dates, plus the volume refNum and parent directory ID */ kGetCatInformationMask = (kFSCatInfoSettableInfo | kFSCatInfoVolume | kFSCatInfoParentDirID) & ~(kFSCatInfoContentMod | kFSCatInfoAttrMod), /* set everything possible except for mod dates */ kSetCatinformationMask = kFSCatInfoSettableInfo & ~(kFSCatInfoContentMod | kFSCatInfoAttrMod) }; OSErr result; GetVolParmsInfoBuffer volParmsInfo; UInt32 infoSize; FSCatalogInfo sourceCatalogInfo; /* source file's catalog information */ FSCatalogInfo destCatalogInfo; /* destination file's catalog information */ HFSUniStr255 sourceName; /* source file's Unicode name */ HFSUniStr255 destName; /* destination file's Unicode name */ FSRef sourceCurrentRef; /* FSRef to current location of source file throughout this function */ FSRef destCurrentRef; /* FSRef to current location of destination file throughout this function */ FSRef sourceParentRef; /* FSRef to parent directory of source file */ FSRef destParentRef; /* FSRef to parent directory of destination file */ HFSUniStr255 sourceUniqueName; /* unique name given to source file while exchanging it with destination */ HFSUniStr255 destUniqueName; /* unique name given to destination file while exchanging it with source */ long theSeed; /* the seed for generating unique names */ Boolean sameParentDirs; /* true if source and destinatin parent directory is the same */ /* check parameters */ require_action((NULL != newSourceRef) && (NULL != newDestRef), BadParameter, result = paramErr); /* output refs and current refs = input refs to start with */ BlockMoveData(sourceRef, newSourceRef, sizeof(FSRef)); BlockMoveData(sourceRef, &sourceCurrentRef, sizeof(FSRef)); BlockMoveData(destRef, newDestRef, sizeof(FSRef)); BlockMoveData(destRef, &destCurrentRef, sizeof(FSRef)); /* get source volume's vRefNum */ result = FSGetCatalogInfo(&sourceCurrentRef, kFSCatInfoVolume, &sourceCatalogInfo, NULL, NULL, NULL); require_noerr(result, DetermineSourceVRefNumFailed); /* see if that volume supports FSExchangeObjects */ result = FSGetVolParms(sourceCatalogInfo.volume, sizeof(GetVolParmsInfoBuffer), &volParmsInfo, &infoSize); if ( (noErr == result) && VolSupportsFSExchangeObjects(&volParmsInfo) ) { /* yes - use FSExchangeObjects */ result = FSExchangeObjects(sourceRef, destRef); } else { /* no - emulate FSExchangeObjects */ /* Note: The compatibility case won't work for files with *Btree control blocks. */ /* Right now the only *Btree files are created by the system. */ /* get all catalog information and Unicode names for each file */ result = FSGetCatalogInfo(&sourceCurrentRef, kGetCatInformationMask, &sourceCatalogInfo, &sourceName, NULL, &sourceParentRef); require_noerr(result, SourceFSGetCatalogInfoFailed); result = FSGetCatalogInfo(&destCurrentRef, kGetCatInformationMask, &destCatalogInfo, &destName, NULL, &destParentRef); require_noerr(result, DestFSGetCatalogInfoFailed); /* make sure source and destination are on same volume */ require_action(sourceCatalogInfo.volume == destCatalogInfo.volume, NotSameVolume, result = diffVolErr); /* make sure both files are *really* files */ require_action((0 == (sourceCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)) && (0 == (destCatalogInfo.nodeFlags & kFSNodeIsDirectoryMask)), NotAFile, result = notAFileErr); /* generate 2 names that are unique in both directories */ theSeed = 0x4a696d4c; /* a fine unlikely filename */ result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &sourceUniqueName); require_noerr(result, GenerateUniqueHFSUniStr1Failed); result = GenerateUniqueHFSUniStr(&theSeed, &sourceParentRef, &destParentRef, &destUniqueName); require_noerr(result, GenerateUniqueHFSUniStr2Failed); /* rename sourceCurrentRef to sourceUniqueName */ result = FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef); require_noerr(result, FSRenameUnicode1Failed); BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); /* rename destCurrentRef to destUniqueName */ result = FSRenameUnicode(&destCurrentRef, destUniqueName.length, destUniqueName.unicode, kTextEncodingUnknown, newDestRef); require_noerr(result, FSRenameUnicode2Failed); BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef)); /* are the source and destination parent directories the same? */ sameParentDirs = ( sourceCatalogInfo.parentDirID == destCatalogInfo.parentDirID ); if ( !sameParentDirs ) { /* move source file to dest parent directory */ result = FSMoveObject(&sourceCurrentRef, &destParentRef, newSourceRef); require_noerr(result, FSMoveObject1Failed); BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); /* move dest file to source parent directory */ result = FSMoveObject(&destCurrentRef, &sourceParentRef, newDestRef); require_noerr(result, FSMoveObject2Failed); BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef)); } /* At this point, the files are in their new locations (if they were moved). */ /* The source file is named sourceUniqueName and is in the directory referred to */ /* by destParentRef. The destination file is named destUniqueName and is in the */ /* directory referred to by sourceParentRef. */ /* give source file the dest file's catalog information except for mod dates */ result = FSSetCatalogInfo(&sourceCurrentRef, kSetCatinformationMask, &destCatalogInfo); require_noerr(result, FSSetCatalogInfo1Failed); /* give dest file the source file's catalog information except for mod dates */ result = FSSetCatalogInfo(&destCurrentRef, kSetCatinformationMask, &sourceCatalogInfo); require_noerr(result, FSSetCatalogInfo2Failed); /* rename source file with dest file's name */ result = FSRenameUnicode(&sourceCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newSourceRef); require_noerr(result, FSRenameUnicode3Failed); BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); /* rename dest file with source file's name */ result = FSRenameUnicode(&destCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newDestRef); require_noerr(result, FSRenameUnicode4Failed); /* we're done with no errors, so swap newSourceRef and newDestRef */ BlockMoveData(newDestRef, newSourceRef, sizeof(FSRef)); BlockMoveData(&sourceCurrentRef, newDestRef, sizeof(FSRef)); } return ( result ); /**********************/ /* If there are any failures while emulating FSExchangeObjects, attempt to reverse any steps */ /* already taken. In any case, newSourceRef and newDestRef will refer to the files in whatever */ /* state and location they ended up in so that both files can be found by the calling code. */ FSRenameUnicode4Failed: /* attempt to rename source file to sourceUniqueName */ if ( noErr == FSRenameUnicode(&sourceCurrentRef, sourceUniqueName.length, sourceUniqueName.unicode, kTextEncodingUnknown, newSourceRef) ) { BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); } FSRenameUnicode3Failed: /* attempt to restore dest file's catalog information */ verify_noerr(FSSetCatalogInfo(&destCurrentRef, kFSCatInfoSettableInfo, &destCatalogInfo)); FSSetCatalogInfo2Failed: /* attempt to restore source file's catalog information */ verify_noerr(FSSetCatalogInfo(&sourceCurrentRef, kFSCatInfoSettableInfo, &sourceCatalogInfo)); FSSetCatalogInfo1Failed: if ( !sameParentDirs ) { /* attempt to move dest file back to dest directory */ if ( noErr == FSMoveObject(&destCurrentRef, &destParentRef, newDestRef) ) { BlockMoveData(newDestRef, &destCurrentRef, sizeof(FSRef)); } } FSMoveObject2Failed: if ( !sameParentDirs ) { /* attempt to move source file back to source directory */ if ( noErr == FSMoveObject(&sourceCurrentRef, &sourceParentRef, newSourceRef) ) { BlockMoveData(newSourceRef, &sourceCurrentRef, sizeof(FSRef)); } } FSMoveObject1Failed: /* attempt to rename dest file to original name */ verify_noerr(FSRenameUnicode(&destCurrentRef, destName.length, destName.unicode, destCatalogInfo.textEncodingHint, newDestRef)); FSRenameUnicode2Failed: /* attempt to rename source file to original name */ verify_noerr(FSRenameUnicode(&sourceCurrentRef, sourceName.length, sourceName.unicode, sourceCatalogInfo.textEncodingHint, newSourceRef)); FSRenameUnicode1Failed: GenerateUniqueHFSUniStr2Failed: GenerateUniqueHFSUniStr1Failed: NotAFile: NotSameVolume: DestFSGetCatalogInfoFailed: SourceFSGetCatalogInfoFailed: FSGetVolParmsFailed: DetermineSourceVRefNumFailed: BadParameter: return ( result ); } /*****************************************************************************/ #pragma mark ----- Shared Environment Routines ----- /*****************************************************************************/ OSErr FSLockRange( SInt16 refNum, SInt32 rangeLength, SInt32 rangeStart) { OSErr result; ParamBlockRec pb; pb.ioParam.ioRefNum = refNum; pb.ioParam.ioReqCount = rangeLength; pb.ioParam.ioPosMode = fsFromStart; pb.ioParam.ioPosOffset = rangeStart; result = PBLockRangeSync(&pb); require_noerr(result, PBLockRangeSync); PBLockRangeSync: return ( result ); } /*****************************************************************************/ OSErr FSUnlockRange( SInt16 refNum, SInt32 rangeLength, SInt32 rangeStart) { OSErr result; ParamBlockRec pb; pb.ioParam.ioRefNum = refNum; pb.ioParam.ioReqCount = rangeLength; pb.ioParam.ioPosMode = fsFromStart; pb.ioParam.ioPosOffset = rangeStart; result = PBUnlockRangeSync(&pb); require_noerr(result, PBUnlockRangeSync); PBUnlockRangeSync: return ( result ); } /*****************************************************************************/ OSErr FSGetDirAccess( const FSRef *ref, SInt32 *ownerID, /* can be NULL */ SInt32 *groupID, /* can be NULL */ SInt32 *accessRights) /* can be NULL */ { OSErr result; FSSpec spec; HParamBlockRec pb; /* get FSSpec from FSRef */ result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL); require_noerr(result, FSGetCatalogInfo); /* get directory access info for FSSpec */ pb.accessParam.ioNamePtr = (StringPtr)spec.name; pb.accessParam.ioVRefNum = spec.vRefNum; pb.fileParam.ioDirID = spec.parID; result = PBHGetDirAccessSync(&pb); require_noerr(result, PBHGetDirAccessSync); /* return the IDs and access rights */ if ( NULL != ownerID ) { *ownerID = pb.accessParam.ioACOwnerID; } if ( NULL != groupID ) { *groupID = pb.accessParam.ioACGroupID; } if ( NULL != accessRights ) { *accessRights = pb.accessParam.ioACAccess; } PBHGetDirAccessSync: FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSSetDirAccess( const FSRef *ref, SInt32 ownerID, SInt32 groupID, SInt32 accessRights) { OSErr result; FSSpec spec; HParamBlockRec pb; enum { /* Just the bits that can be set */ kSetDirAccessSettableMask = (kioACAccessBlankAccessMask + kioACAccessEveryoneWriteMask + kioACAccessEveryoneReadMask + kioACAccessEveryoneSearchMask + kioACAccessGroupWriteMask + kioACAccessGroupReadMask + kioACAccessGroupSearchMask + kioACAccessOwnerWriteMask + kioACAccessOwnerReadMask + kioACAccessOwnerSearchMask) }; /* get FSSpec from FSRef */ result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL); require_noerr(result, FSGetCatalogInfo); /* set directory access info for FSSpec */ pb.accessParam.ioNamePtr = (StringPtr)spec.name; pb.accessParam.ioVRefNum = spec.vRefNum; pb.fileParam.ioDirID = spec.parID; pb.accessParam.ioACOwnerID = ownerID; pb.accessParam.ioACGroupID = groupID; pb.accessParam.ioACAccess = accessRights & kSetDirAccessSettableMask; result = PBHSetDirAccessSync(&pb); require_noerr(result, PBHSetDirAccessSync); PBHSetDirAccessSync: FSGetCatalogInfo: return ( result ); } /*****************************************************************************/ OSErr FSGetVolMountInfoSize( FSVolumeRefNum volRefNum, SInt16 *size) { OSErr result; ParamBlockRec pb; /* check parameters */ require_action(NULL != size, BadParameter, result = paramErr); pb.ioParam.ioNamePtr = NULL; pb.ioParam.ioVRefNum = volRefNum; pb.ioParam.ioBuffer = (Ptr)size; result = PBGetVolMountInfoSize(&pb); require_noerr(result, PBGetVolMountInfoSize); PBGetVolMountInfoSize: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSGetVolMountInfo( FSVolumeRefNum volRefNum, void *volMountInfo) { OSErr result; ParamBlockRec pb; /* check parameters */ require_action(NULL != volMountInfo, BadParameter, result = paramErr); pb.ioParam.ioNamePtr = NULL; pb.ioParam.ioVRefNum = volRefNum; pb.ioParam.ioBuffer = (Ptr)volMountInfo; result = PBGetVolMountInfo(&pb); require_noerr(result, PBGetVolMountInfo); PBGetVolMountInfo: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSVolumeMount( const void *volMountInfo, FSVolumeRefNum *volRefNum) { OSErr result; ParamBlockRec pb; /* check parameters */ require_action(NULL != volRefNum, BadParameter, result = paramErr); pb.ioParam.ioBuffer = (Ptr)volMountInfo; result = PBVolumeMount(&pb); require_noerr(result, PBVolumeMount); /* return the volume reference number */ *volRefNum = pb.ioParam.ioVRefNum; PBVolumeMount: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSMapID( FSVolumeRefNum volRefNum, SInt32 ugID, SInt16 objType, Str31 name) { OSErr result; HParamBlockRec pb; /* check parameters */ require_action(NULL != name, BadParameter, result = paramErr); pb.objParam.ioNamePtr = NULL; pb.objParam.ioVRefNum = volRefNum; pb.objParam.ioObjType = objType; pb.objParam.ioObjNamePtr = name; pb.objParam.ioObjID = ugID; result = PBHMapIDSync(&pb); require_noerr(result, PBHMapIDSync); PBHMapIDSync: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSMapName( FSVolumeRefNum volRefNum, ConstStr255Param name, SInt16 objType, SInt32 *ugID) { OSErr result; HParamBlockRec pb; /* check parameters */ require_action(NULL != ugID, BadParameter, result = paramErr); pb.objParam.ioNamePtr = NULL; pb.objParam.ioVRefNum = volRefNum; pb.objParam.ioObjType = objType; pb.objParam.ioObjNamePtr = (StringPtr)name; result = PBHMapNameSync(&pb); require_noerr(result, PBHMapNameSync); /* return the user or group ID */ *ugID = pb.objParam.ioObjID; PBHMapNameSync: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSCopyFile( const FSRef *srcFileRef, const FSRef *dstDirectoryRef, UniCharCount nameLength, const UniChar *copyName, /* can be NULL (no rename during copy) */ TextEncoding textEncodingHint, FSRef *newRef) /* can be NULL */ { OSErr result; FSSpec srcFileSpec; FSCatalogInfo catalogInfo; HParamBlockRec pb; Str31 hfsName; GetVolParmsInfoBuffer volParmsInfo; UInt32 infoSize; /* get source FSSpec from source FSRef */ result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL); require_noerr(result, FSGetCatalogInfo_srcFileRef); /* Make sure the volume supports CopyFile */ result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer), &volParmsInfo, &infoSize); require_action((noErr == result) && VolHasCopyFile(&volParmsInfo), NoCopyFileSupport, result = paramErr); /* get destination volume reference number and destination directory ID from destination FSRef */ result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID, &catalogInfo, NULL, NULL, NULL); require_noerr(result, FSGetCatalogInfo_dstDirectoryRef); /* tell the server to copy the object */ pb.copyParam.ioVRefNum = srcFileSpec.vRefNum; pb.copyParam.ioDirID = srcFileSpec.parID; pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name; pb.copyParam.ioDstVRefNum = catalogInfo.volume; pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID; pb.copyParam.ioNewName = NULL; if ( NULL != copyName ) { result = UnicodeNameGetHFSName(nameLength, copyName, textEncodingHint, false, hfsName); require_noerr(result, UnicodeNameGetHFSName); pb.copyParam.ioCopyName = hfsName; } else { pb.copyParam.ioCopyName = NULL; } result = PBHCopyFileSync(&pb); require_noerr(result, PBHCopyFileSync); if ( NULL != newRef ) { verify_noerr(FSMakeFSRef(pb.copyParam.ioDstVRefNum, pb.copyParam.ioNewDirID, pb.copyParam.ioCopyName, newRef)); } PBHCopyFileSync: UnicodeNameGetHFSName: FSGetCatalogInfo_dstDirectoryRef: NoCopyFileSupport: FSGetCatalogInfo_srcFileRef: return ( result ); } /*****************************************************************************/ OSErr FSMoveRename( const FSRef *srcFileRef, const FSRef *dstDirectoryRef, UniCharCount nameLength, const UniChar *moveName, /* can be NULL (no rename during move) */ TextEncoding textEncodingHint, FSRef *newRef) /* can be NULL */ { OSErr result; FSSpec srcFileSpec; FSCatalogInfo catalogInfo; HParamBlockRec pb; Str31 hfsName; GetVolParmsInfoBuffer volParmsInfo; UInt32 infoSize; /* get source FSSpec from source FSRef */ result = FSGetCatalogInfo(srcFileRef, kFSCatInfoNone, NULL, NULL, &srcFileSpec, NULL); require_noerr(result, FSGetCatalogInfo_srcFileRef); /* Make sure the volume supports MoveRename */ result = FSGetVolParms(srcFileSpec.vRefNum, sizeof(GetVolParmsInfoBuffer), &volParmsInfo, &infoSize); require_action((noErr == result) && VolHasMoveRename(&volParmsInfo), NoMoveRenameSupport, result = paramErr); /* get destination volume reference number and destination directory ID from destination FSRef */ result = FSGetCatalogInfo(dstDirectoryRef, kFSCatInfoVolume + kFSCatInfoNodeID, &catalogInfo, NULL, NULL, NULL); require_noerr(result, FSGetCatalogInfo_dstDirectoryRef); /* make sure the source and destination are on the same volume */ require_action(srcFileSpec.vRefNum == catalogInfo.volume, NotSameVolume, result = diffVolErr); /* tell the server to move and rename the object */ pb.copyParam.ioVRefNum = srcFileSpec.vRefNum; pb.copyParam.ioDirID = srcFileSpec.parID; pb.copyParam.ioNamePtr = (StringPtr)srcFileSpec.name; pb.copyParam.ioNewDirID = (long)catalogInfo.nodeID; pb.copyParam.ioNewName = NULL; if ( NULL != moveName ) { result = UnicodeNameGetHFSName(nameLength, moveName, textEncodingHint, false, hfsName); require_noerr(result, UnicodeNameGetHFSName); pb.copyParam.ioCopyName = hfsName; } else { pb.copyParam.ioCopyName = NULL; } result = PBHMoveRenameSync(&pb); require_noerr(result, PBHMoveRenameSync); if ( NULL != newRef ) { verify_noerr(FSMakeFSRef(pb.copyParam.ioVRefNum, pb.copyParam.ioNewDirID, pb.copyParam.ioCopyName, newRef)); } PBHMoveRenameSync: UnicodeNameGetHFSName: NotSameVolume: FSGetCatalogInfo_dstDirectoryRef: NoMoveRenameSupport: FSGetCatalogInfo_srcFileRef: return ( result ); } /*****************************************************************************/ #pragma mark ----- File ID Routines ----- /*****************************************************************************/ OSErr FSResolveFileIDRef( FSVolumeRefNum volRefNum, SInt32 fileID, FSRef *ref) { OSErr result; FIDParam pb; Str255 tempStr; /* check parameters */ require_action(NULL != ref, BadParameter, result = paramErr); /* resolve the file ID reference */ StrLength(tempStr) = 0; pb.ioNamePtr = tempStr; pb.ioVRefNum = volRefNum; pb.ioFileID = fileID; result = PBResolveFileIDRefSync((HParmBlkPtr)&pb); require_noerr(result, PBResolveFileIDRefSync); /* and then make an FSRef to the file */ result = FSMakeFSRef(volRefNum, pb.ioSrcDirID, tempStr, ref); require_noerr(result, FSMakeFSRef); FSMakeFSRef: PBResolveFileIDRefSync: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSCreateFileIDRef( const FSRef *ref, SInt32 *fileID) { OSErr result; FSSpec spec; FIDParam pb; /* check parameters */ require_action(NULL != fileID, BadParameter, result = paramErr); /* Get an FSSpec from the FSRef */ result = FSGetCatalogInfo(ref, kFSCatInfoNone, NULL, NULL, &spec, NULL); require_noerr(result, FSGetCatalogInfo); /* Create (or get) the file ID reference using the FSSpec */ pb.ioNamePtr = (StringPtr)spec.name; pb.ioVRefNum = spec.vRefNum; pb.ioSrcDirID = spec.parID; result = PBCreateFileIDRefSync((HParmBlkPtr)&pb); require((noErr == result) || (fidExists == result) || (afpIDExists == result), PBCreateFileIDRefSync); /* return the file ID reference */ *fileID = pb.ioFileID; PBCreateFileIDRefSync: FSGetCatalogInfo: BadParameter: return ( result ); } /*****************************************************************************/ #pragma mark ----- Utility Routines ----- /*****************************************************************************/ Ptr GetTempBuffer( ByteCount buffReqSize, ByteCount *buffActSize) { enum { kSlopMemory = 0x00008000 /* 32K - Amount of free memory to leave when allocating buffers */ }; Ptr tempPtr; /* check parameters */ require_action(NULL != buffActSize, BadParameter, tempPtr = NULL); /* Make request a multiple of 4K bytes */ buffReqSize = buffReqSize & 0xfffff000; if ( buffReqSize < 0x00001000 ) { /* Request was smaller than 4K bytes - make it 4K */ buffReqSize = 0x00001000; } /* Attempt to allocate the memory */ tempPtr = NewPtr(buffReqSize); /* If request failed, go to backup plan */ if ( (tempPtr == NULL) && (buffReqSize > 0x00001000) ) { /* ** Try to get largest 4K byte block available ** leaving some slop for the toolbox if possible */ long freeMemory = (FreeMem() - kSlopMemory) & 0xfffff000; buffReqSize = MaxBlock() & 0xfffff000; if ( buffReqSize > freeMemory ) { buffReqSize = freeMemory; } if ( buffReqSize == 0 ) { buffReqSize = 0x00001000; } tempPtr = NewPtr(buffReqSize); } /* Return bytes allocated */ if ( tempPtr != NULL ) { *buffActSize = buffReqSize; } else { *buffActSize = 0; } BadParameter: return ( tempPtr ); } /*****************************************************************************/ OSErr FileRefNumGetFSRef( short refNum, FSRef *ref) { return ( FSGetForkCBInfo(refNum, 0, NULL, NULL, NULL, ref, NULL) ); } /*****************************************************************************/ OSErr FSSetDefault( const FSRef *newDefault, FSRef *oldDefault) { OSErr result; FSVolumeRefNum vRefNum; long dirID; FSCatalogInfo catalogInfo; /* check parameters */ require_action((NULL != newDefault) && (NULL != oldDefault), BadParameter, result = paramErr); /* Get nodeFlags, vRefNum and dirID (nodeID) of newDefault */ result = FSGetCatalogInfo(newDefault, kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID, &catalogInfo, NULL, NULL, NULL); require_noerr(result, FSGetCatalogInfo); /* Make sure newDefault is a directory */ require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), NewDefaultNotDirectory, result = dirNFErr); /* Get the current working directory. */ result = HGetVol(NULL, &vRefNum, &dirID); require_noerr(result, HGetVol); /* Return the oldDefault FSRef */ result = FSMakeFSRef(vRefNum, dirID, NULL, oldDefault); require_noerr(result, FSMakeFSRef); /* Set the new current working directory */ result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID); require_noerr(result, HSetVol); HSetVol: FSMakeFSRef: HGetVol: NewDefaultNotDirectory: FSGetCatalogInfo: BadParameter: return ( result ); } /*****************************************************************************/ OSErr FSRestoreDefault( const FSRef *oldDefault) { OSErr result; FSCatalogInfo catalogInfo; /* check parameters */ require_action(NULL != oldDefault, BadParameter, result = paramErr); /* Get nodeFlags, vRefNum and dirID (nodeID) of oldDefault */ result = FSGetCatalogInfo(oldDefault, kFSCatInfoNodeFlags + kFSCatInfoVolume + kFSCatInfoNodeID, &catalogInfo, NULL, NULL, NULL); require_noerr(result, FSGetCatalogInfo); /* Make sure oldDefault is a directory */ require_action(0 != (kFSNodeIsDirectoryMask & catalogInfo.nodeFlags), OldDefaultNotDirectory, result = dirNFErr); /* Set the current working directory to oldDefault */ result = HSetVol(NULL, catalogInfo.volume, catalogInfo.nodeID); require_noerr(result, HSetVol); HSetVol: OldDefaultNotDirectory: FSGetCatalogInfo: BadParameter: return ( result ); } /*****************************************************************************/ \ No newline at end of file diff --git a/External/MoreFilesX/MoreFilesX.h b/External/MoreFilesX/MoreFilesX.h new file mode 100644 index 0000000..d18a83a --- /dev/null +++ b/External/MoreFilesX/MoreFilesX.h @@ -0,0 +1 @@ +/* File: MoreFilesX.h Contains: A collection of useful high-level File Manager routines which use the HFS Plus APIs wherever possible. Version: MoreFilesX 1.0 Copyright: © 1992-2002 by 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. File Ownership: DRI: Apple Macintosh Developer Technical Support Other Contact: For bug reports, consult the following page on the World Wide Web: http://developer.apple.com/bugreporter/ Technology: DTS Sample Code Writers: (JL) Jim Luther Change History (most recent first): <1> 1/25/02 JL MoreFilesX 1.0 Notes: What do those arrows in the documentation for each routine mean? --> The parameter is an input <-- The parameter is an output. The pointer to the variable where the output will be returned (must not be NULL). <** The parameter is an optional output. If it is not a NULL pointer, it points to the variable where the output will be returned. If it is a NULL pointer, the output will not be returned and will possibly let the routine and the File Manager do less work. If you don't need an optional output, don't ask for it. **> The parameter is an optional input. If it is not a NULL pointer, it points to the variable containing the input data. If it is a NULL pointer, the input is not used and will possibly let the routine and the File Manager do less work. */ #ifndef __MOREFILESX__ #define __MOREFILESX__ #ifndef __MACTYPES__ #include #endif #ifndef __FINDER__ #include #endif #ifndef __FILES__ #include #endif #ifndef __TEXTCOMMON__ #include #endif #if PRAGMA_ONCE #pragma once #endif #ifdef __cplusplus extern "C" { #endif #if PRAGMA_IMPORT #pragma import on #endif #if PRAGMA_STRUCT_ALIGN #pragma options align=mac68k #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(push, 2) #elif PRAGMA_STRUCT_PACK #pragma pack(2) #endif /*****************************************************************************/ #pragma mark ----- FinderInfo and ExtendedFinderInfo ----- /* * FSGetFinderInfo and FSSetFinderInfo use these unions for Finder information. */ union FinderInfo { FileInfo file; FolderInfo folder; }; typedef union FinderInfo FinderInfo; union ExtendedFinderInfo { ExtendedFileInfo file; ExtendedFolderInfo folder; }; typedef union ExtendedFinderInfo ExtendedFinderInfo; /*****************************************************************************/ #pragma mark ----- GetVolParmsInfoBuffer Macros ----- /* * Macros to get information out of GetVolParmsInfoBuffer. */ /* version 1 field getters */ #define GetVolParmsInfoVersion(volParms) \ ((volParms)->vMVersion) #define GetVolParmsInfoAttrib(volParms) \ ((volParms)->vMAttrib) #define GetVolParmsInfoLocalHand(volParms) \ ((volParms)->vMLocalHand) #define GetVolParmsInfoServerAdr(volParms) \ ((volParms)->vMServerAdr) /* version 2 field getters (assume zero result if version < 2) */ #define GetVolParmsInfoVolumeGrade(volParms) \ (((volParms)->vMVersion >= 2) ? (volParms)->vMVolumeGrade : 0) #define GetVolParmsInfoForeignPrivID(volParms) \ (((volParms)->vMVersion >= 2) ? (volParms)->vMForeignPrivID : 0) /* version 3 field getters (assume zero result if version < 3) */ #define GetVolParmsInfoExtendedAttributes(volParms) \ (((volParms)->vMVersion >= 3) ? (volParms)->vMExtendedAttributes : 0) /* attribute bits supported by all versions of GetVolParmsInfoBuffer */ #define VolIsNetworkVolume(volParms) \ ((volParms)->vMServerAdr != 0) #define VolHasLimitFCBs(volParms) \ (((volParms)->vMAttrib & (1L << bLimitFCBs)) != 0) #define VolHasLocalWList(volParms) \ (((volParms)->vMAttrib & (1L << bLocalWList)) != 0) #define VolHasNoMiniFndr(volParms) \ (((volParms)->vMAttrib & (1L << bNoMiniFndr)) != 0) #define VolHasNoVNEdit(volParms) \ (((volParms)->vMAttrib & (1L << bNoVNEdit)) != 0) #define VolHasNoLclSync(volParms) \ (((volParms)->vMAttrib & (1L << bNoLclSync)) != 0) #define VolHasTrshOffLine(volParms) \ (((volParms)->vMAttrib & (1L << bTrshOffLine)) != 0) #define VolHasNoSwitchTo(volParms) \ (((volParms)->vMAttrib & (1L << bNoSwitchTo)) != 0) #define VolHasNoDeskItems(volParms) \ (((volParms)->vMAttrib & (1L << bNoDeskItems)) != 0) #define VolHasNoBootBlks(volParms) \ (((volParms)->vMAttrib & (1L << bNoBootBlks)) != 0) #define VolHasAccessCntl(volParms) \ (((volParms)->vMAttrib & (1L << bAccessCntl)) != 0) #define VolHasNoSysDir(volParms) \ (((volParms)->vMAttrib & (1L << bNoSysDir)) != 0) #define VolHasExtFSVol(volParms) \ (((volParms)->vMAttrib & (1L << bHasExtFSVol)) != 0) #define VolHasOpenDeny(volParms) \ (((volParms)->vMAttrib & (1L << bHasOpenDeny)) != 0) #define VolHasCopyFile(volParms) \ (((volParms)->vMAttrib & (1L << bHasCopyFile)) != 0) #define VolHasMoveRename(volParms) \ (((volParms)->vMAttrib & (1L << bHasMoveRename)) != 0) #define VolHasDesktopMgr(volParms) \ (((volParms)->vMAttrib & (1L << bHasDesktopMgr)) != 0) #define VolHasShortName(volParms) \ (((volParms)->vMAttrib & (1L << bHasShortName)) != 0) #define VolHasFolderLock(volParms) \ (((volParms)->vMAttrib & (1L << bHasFolderLock)) != 0) #define VolHasPersonalAccessPrivileges(volParms) \ (((volParms)->vMAttrib & (1L << bHasPersonalAccessPrivileges)) != 0) #define VolHasUserGroupList(volParms) \ (((volParms)->vMAttrib & (1L << bHasUserGroupList)) != 0) #define VolHasCatSearch(volParms) \ (((volParms)->vMAttrib & (1L << bHasCatSearch)) != 0) #define VolHasFileIDs(volParms) \ (((volParms)->vMAttrib & (1L << bHasFileIDs)) != 0) #define VolHasBTreeMgr(volParms) \ (((volParms)->vMAttrib & (1L << bHasBTreeMgr)) != 0) #define VolHasBlankAccessPrivileges(volParms) \ (((volParms)->vMAttrib & (1L << bHasBlankAccessPrivileges)) != 0) #define VolSupportsAsyncRequests(volParms) \ (((volParms)->vMAttrib & (1L << bSupportsAsyncRequests)) != 0) #define VolSupportsTrashVolumeCache(volParms) \ (((volParms)->vMAttrib & (1L << bSupportsTrashVolumeCache)) != 0) /* attribute bits supported by version 3 and greater versions of GetVolParmsInfoBuffer */ #define VolIsEjectable(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsEjectable)) != 0) #define VolSupportsHFSPlusAPIs(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsHFSPlusAPIs)) != 0) #define VolSupportsFSCatalogSearch(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSCatalogSearch)) != 0) #define VolSupportsFSExchangeObjects(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsFSExchangeObjects)) != 0) #define VolSupports2TBFiles(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupports2TBFiles)) != 0) #define VolSupportsLongNames(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsLongNames)) != 0) #define VolSupportsMultiScriptNames(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsMultiScriptNames)) != 0) #define VolSupportsNamedForks(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsNamedForks)) != 0) #define VolSupportsSubtreeIterators(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSubtreeIterators)) != 0) #define VolL2PCanMapFileBlocks(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bL2PCanMapFileBlocks)) != 0) #define VolParentModDateChanges(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bParentModDateChanges)) != 0) #define VolAncestorModDateChanges(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bAncestorModDateChanges)) != 0) #define VolSupportsSymbolicLinks(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bSupportsSymbolicLinks)) != 0) #define VolIsAutoMounted(volParms) \ ((GetVolParmsInfoExtendedAttributes(volParms) & (1L << bIsAutoMounted)) != 0) /*****************************************************************************/ #pragma mark ----- userPrivileges Bit Masks and Macros ----- /* * Bit masks and macros to get common information out of userPrivileges byte * returned by FSGetCatalogInfo. * * Note: The userPrivileges byte is the same as the ioACUser byte returned * by PBGetCatInfo, and is the 1's complement of the user's privileges * byte returned in ioACAccess by PBHGetDirAccess. That's where the * ioACUser names came from. * * The userPrivileges are user's effective privileges based on the * user ID and the groups that user belongs to, and the owner, group, * and everyone privileges for the given directory. */ enum { /* mask for just the access restriction bits */ kioACUserAccessMask = (kioACUserNoSeeFolderMask + kioACUserNoSeeFilesMask + kioACUserNoMakeChangesMask), /* common access privilege settings */ kioACUserFull = 0x00, /* no access restiction bits on */ kioACUserNone = kioACUserAccessMask, /* all access restiction bits on */ kioACUserDropBox = (kioACUserNoSeeFolderMask + kioACUserNoSeeFilesMask), /* make changes, but not see files or folders */ kioACUserBulletinBoard = kioACUserNoMakeChangesMask /* see files and folders, but not make changes */ }; /* Macros for testing ioACUser bits. */ #define UserIsOwner(userPrivileges) \ (((userPrivileges) & kioACUserNotOwnerMask) == 0) #define UserHasFullAccess(userPrivileges) \ (((userPrivileges) & (kioACUserAccessMask)) == kioACUserFull) #define UserHasDropBoxAccess(userPrivileges) \ (((userPrivileges) & kioACUserAccessMask) == kioACUserDropBox) #define UserHasBulletinBoard(userPrivileges) \ (((userPrivileges) & kioACUserAccessMask) == kioACUserBulletinBoard) #define UserHasNoAccess(userPrivileges) \ (((userPrivileges) & kioACUserAccessMask) == kioACUserNone) /*****************************************************************************/ #pragma mark ----- File Access Routines ----- /*****************************************************************************/ #pragma mark FSCopyFork OSErr FSCopyFork( SInt16 srcRefNum, SInt16 dstRefNum, void *copyBufferPtr, ByteCount copyBufferSize); /* The FSCopyFork 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 --> The source file reference number. dstRefNum --> The destination file reference number. copyBufferPtr --> Pointer to buffer to use during copy. The buffer should be at least 4K-bytes minimum. The larger the buffer, the faster the copy (up to a point). copyBufferSize --> The size of the copy buffer. */ /*****************************************************************************/ #pragma mark ----- Volume Access Routines ----- /*****************************************************************************/ #pragma mark FSGetVolParms OSErr FSGetVolParms( FSVolumeRefNum volRefNum, UInt32 bufferSize, GetVolParmsInfoBuffer *volParmsInfo, UInt32 *actualInfoSize); /* The FSGetVolParms function returns information about the characteristics of a volume. A result of paramErr usually just means the volume doesn't support GetVolParms and the feature you were going to check for isn't available. volRefNum --> Volume specification. bufferSize --> Size of buffer pointed to by volParmsInfo. volParmsInfo <-- A GetVolParmsInfoBuffer record where the volume attributes information is returned. actualInfoSize <-- The number of bytes actually returned in volParmsInfo. __________ Also see: The GetVolParmsInfoBuffer Macros for checking attribute bits in this file */ /*****************************************************************************/ #pragma mark FSGetVRefNum OSErr FSGetVRefNum( const FSRef *ref, FSVolumeRefNum *vRefNum); /* The FSGetVRefNum function determines the volume reference number of a volume from a FSRef. ref --> The FSRef. vRefNum <-- The volume reference number. */ /*****************************************************************************/ #pragma mark FSGetVInfo OSErr FSGetVInfo( FSVolumeRefNum volume, HFSUniStr255 *volumeName, /* can be NULL */ UInt64 *freeBytes, /* can be NULL */ UInt64 *totalBytes); /* can be NULL */ /* The FSGetVInfo function returns the name, available space (in bytes), and total space (in bytes) for the specified volume. volume --> The volume reference number. volumeName <** An optional pointer to a HFSUniStr255. If not NULL, the volume name will be returned in the HFSUniStr255. freeBytes <** An optional pointer to a UInt64. If not NULL, the number of free bytes on the volume will be returned in the UInt64. totalBytes <** An optional pointer to a UInt64. If not NULL, the total number of bytes on the volume will be returned in the UInt64. */ /*****************************************************************************/ #pragma mark FSGetVolFileSystemID OSErr FSGetVolFileSystemID( FSVolumeRefNum volume, UInt16 *fileSystemID, /* can be NULL */ UInt16 *signature); /* can be NULL */ /* The FSGetVolFileSystemID function returns the file system ID and signature of a mounted volume. The file system ID identifies the file system that handles requests to a particular volume. The signature identifies the volume type of the volume (for example, FSID 0 is Macintosh HFS Plus, HFS or MFS, where a signature of 0x4244 identifies the volume as HFS). Here's a partial list of file system ID numbers (only Apple's file systems are listed): FSID File System ----- ----------------------------------------------------- $0000 Macintosh HFS Plus, 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) $6173 AppleShare (later versions of AppleShare only) See the Technical Note "FL 35 - Determining Which File System Is Active" and the "Guide to the File System Manager" for more information. volume --> The volume reference number. fileSystemID <** An optional pointer to a UInt16. If not NULL, the volume's file system ID will be returned in the UInt16. signature <** An optional pointer to a UInt16. If not NULL, the volume's signature will be returned in the UInt16. */ /*****************************************************************************/ #pragma mark FSGetMountedVolumes OSErr FSGetMountedVolumes( FSRef ***volumeRefsHandle, /* pointer to handle of FSRefs */ ItemCount *numVolumes); /* The FSGetMountedVolumes function returns the list of volumes currently mounted in an array of FSRef records. The array of FSRef records is returned in a Handle, volumeRefsHandle, which is allocated by FSGetMountedVolumes. The caller is responsible for disposing of volumeRefsHandle if the FSGetMountedVolumes returns noErr. volumeRefsHandle <-- Pointer to an FSRef Handle where the array of FSRefs is to be returned. numVolumes <-- The number of volumes returned in the array. */ /*****************************************************************************/ #pragma mark ----- FSRef/FSpec/Path/Name Conversion Routines ----- /*****************************************************************************/ #pragma mark FSRefMakeFSSpec OSErr FSRefMakeFSSpec( const FSRef *ref, FSSpec *spec); /* The FSRefMakeFSSpec function returns an FSSpec for the file or directory specified by the ref parameter. ref --> An FSRef specifying the file or directory. spec <-- The FSSpec. */ /*****************************************************************************/ #pragma mark FSMakeFSRef OSErr FSMakeFSRef( FSVolumeRefNum volRefNum, SInt32 dirID, ConstStr255Param name, FSRef *ref); /* The FSMakeFSRef function creates an FSRef from the traditional volume reference number, directory ID and pathname inputs. It is functionally equivalent to FSMakeFSSpec followed by FSpMakeFSRef. volRefNum --> Volume specification. dirID --> Directory specification. name --> The file or directory name, or NULL. ref <-- The FSRef. */ /*****************************************************************************/ #pragma mark FSMakePath OSStatus FSMakePath( SInt16 vRefNum, SInt32 dirID, ConstStr255Param name, UInt8 *path, UInt32 maxPathSize); /* The FSMakePath function creates a pathname from the traditional volume reference number, directory ID, and pathname inputs. It is functionally equivalent to FSMakeFSSpec, FSpMakeFSRef, FSRefMakePath. volRefNum --> Volume specification. dirID --> Directory specification. name --> The file or directory name, or NULL. path <-- A pointer to a buffer which FSMakePath will fill with a C string representing the pathname to the file or directory specified. The format of the pathname returned can be determined with the Gestalt selector gestaltFSAttr's gestaltFSUsesPOSIXPathsForConversion bit. If the gestaltFSUsesPOSIXPathsForConversion bit is clear, the pathname is a Mac OS File Manager full pathname in a C string, and file or directory names in the pathname may be mangled as returned by the File Manager. If the gestaltFSUsesPOSIXPathsForConversion bit is set, the pathname is a UTF8 encoded POSIX absolute pathname in a C string. In either case, the pathname returned can be passed back to FSPathMakeRef to create an FSRef to the file or directory, or FSPathMakeFSSpec to craete an FSSpec to the file or directory. maxPathSize --> The size of the path buffer in bytes. If the path buffer is too small for the pathname string, FSMakePath returns pathTooLongErr or buffersTooSmall. */ /*****************************************************************************/ #pragma mark FSPathMakeFSSpec OSStatus FSPathMakeFSSpec( const UInt8 *path, FSSpec *spec, Boolean *isDirectory); /* can be NULL */ /* The FSPathMakeFSSpec function converts a pathname to an FSSpec. path --> A pointer to a C String that is the pathname. The format of the pathname you must supply can be determined with the Gestalt selector gestaltFSAttr's gestaltFSUsesPOSIXPathsForConversion bit. If the gestaltFSUsesPOSIXPathsForConversion bit is clear, the pathname must be a Mac OS File Manager full pathname in a C string. If the gestaltFSUsesPOSIXPathsForConversion bit is set, the pathname must be a UTF8 encoded POSIX absolute pathname in a C string. spec <-- The FSSpec. isDirectory <** An optional pointer to a Boolean. If not NULL, true will be returned in the Boolean if the specified path is a directory, or false will be returned in the Boolean if the specified path is a file. */ /*****************************************************************************/ #pragma mark UnicodeNameGetHFSName OSErr UnicodeNameGetHFSName( UniCharCount nameLength, const UniChar *name, TextEncoding textEncodingHint, Boolean isVolumeName, Str31 hfsName); /* The UnicodeNameGetHFSName function converts a Unicode string to a Pascal Str31 (or Str27) string using an algorithm similar to that used by the File Manager. Note that if the name is too long or cannot be converted using the given text encoding hint, you will get an error instead of the mangled name that the File Manager would return. nameLength --> Number of UniChar in name parameter. name --> The Unicode string to convert. textEncodingHint --> The text encoding hint used for the conversion. You can pass kTextEncodingUnknown to use the "default" textEncodingHint. isVolumeName --> If true, the output name will be limited to 27 characters (kHFSMaxVolumeNameChars). If false, the output name will be limited to 31 characters (kHFSMaxFileNameChars). hfsName <-- The hfsName as a Pascal string. __________ Also see: HFSNameGetUnicodeName */ /*****************************************************************************/ #pragma mark HFSNameGetUnicodeName OSErr HFSNameGetUnicodeName( ConstStr31Param hfsName, TextEncoding textEncodingHint, HFSUniStr255 *unicodeName); /* The HFSNameGetUnicodeName function converts a Pascal Str31 string to an Unicode HFSUniStr255 string using the same routines as the File Manager. hfsName --> The Pascal string to convert. textEncodingHint --> The text encoding hint used for the conversion. You can pass kTextEncodingUnknown to use the "default" textEncodingHint. unicodeName <-- The Unicode string. __________ Also see: UnicodeNameGetHFSName */ /*****************************************************************************/ #pragma mark ----- File/Directory Manipulation Routines ----- /*****************************************************************************/ #pragma mark FSRefValid Boolean FSRefValid(const FSRef *ref); /* The FSRefValid function determines if an FSRef is valid. If the result is true, then the FSRef refers to an existing file or directory. ref --> FSRef to a file or directory. */ /*****************************************************************************/ #pragma mark FSGetParentRef OSErr FSGetParentRef( const FSRef *ref, FSRef *parentRef); /* The FSGetParentRef function gets the parent directory FSRef of the specified object. Note: FSRefs always point to real file system objects. So, there cannot be a FSRef to the parent of volume root directories. If you call FSGetParentRef with a ref to the root directory of a volume, the function result will be noErr and the parentRef will be invalid (using it for other file system requests will fail). ref --> FSRef to a file or directory. parentRef <-- The parent directory's FSRef. */ /*****************************************************************************/ #pragma mark FSGetFileDirName OSErr FSGetFileDirName( const FSRef *ref, HFSUniStr255 *outName); /* The FSGetFileDirName function gets the name of the file or directory specified. ref --> FSRef to a file or directory. outName <-- The file or directory name. */ /*****************************************************************************/ #pragma mark FSGetNodeID OSErr FSGetNodeID( const FSRef *ref, long *nodeID, /* can be NULL */ Boolean *isDirectory); /* can be NULL */ /* The GetNodeIDFromFSRef function gets the node ID number of the file or directory specified (note: the node ID is the directory ID for directories). ref --> FSRef to a file or directory. nodeID <** An optional pointer to a long. If not NULL, the node ID will be returned in the long. isDirectory <** An optional pointer to a Boolean. If not NULL, true will be returned in the Boolean if the object is a directory, or false will be returned in the Boolean if object is a file. */ /*****************************************************************************/ #pragma mark FSGetUserPrivilegesPermissions OSErr FSGetUserPrivilegesPermissions( const FSRef *ref, UInt8 *userPrivileges, /* can be NULL */ UInt32 permissions[4]); /* can be NULL */ /* The FSGetUserPrivilegesPermissions function gets the userPrivileges and/or permissions of the file or directory specified. ref --> FSRef to a file or directory. userPrivileges <** An optional pointer to a UInt8. If not NULL, the userPrivileges will be returned in the UInt8. permissions <** An optional pointer to an UInt32[4] array. If not NULL, the permissions will be returned in the UInt32[4] array. */ /*****************************************************************************/ #pragma mark FSCheckLock OSErr FSCheckLock( const FSRef *ref); /* The FSCheckLock function determines if a file or directory is locked. If FSCheckLock returns noErr, then the file or directory is not locked and the volume it is on is not locked either. If FSCheckLock returns fLckdErr, then the file or directory is locked. If FSCheckLock returns wPrErr, then the volume is locked by hardware (i.e., locked tab on removable media). If FSCheckLock returns vLckdErr, then the volume is locked by software. ref --> FSRef to a file or directory. */ /*****************************************************************************/ #pragma mark FSGetForkSizes OSErr FSGetForkSizes( const FSRef *ref, UInt64 *dataLogicalSize, /* can be NULL */ UInt64 *rsrcLogicalSize); /* can be NULL */ /* The FSGetForkSizes returns the size of the data and/or resource fork for the specified file. ref --> FSRef to a file or directory. dataLogicalSize <** An optional pointer to a UInt64. If not NULL, the data fork's size will be returned in the UInt64. rsrcLogicalSize <** An optional pointer to a UInt64. If not NULL, the resource fork's size will be returned in the UInt64. __________ Also see: FSGetTotalForkSizes */ /*****************************************************************************/ #pragma mark FSGetTotalForkSizes OSErr FSGetTotalForkSizes( const FSRef *ref, UInt64 *totalLogicalSize, /* can be NULL */ UInt64 *totalPhysicalSize, /* can be NULL */ ItemCount *forkCount); /* can be NULL */ /* The FSGetTotalForkSizes returns the total logical size and/or the total physical size of the specified file (i.e., it adds the sizes of all file forks). It optionally returns the number of file forks. ref --> FSRef to a file or directory. totalLogicalSize <** An optional pointer to a UInt64. If not NULL, the sum of all fork logical sizes will be returned in the UInt64. totalPhysicalSize <** An optional pointer to a UInt64. If not NULL, the sum of all fork physical sizes will be returned in the UInt64. forkCount <** An optional pointer to a ItemCount. If not NULL, the number of file forks will be returned in the ItemCount. __________ Also see: FSGetForkSizes */ /*****************************************************************************/ #pragma mark FSBumpDate OSErr FSBumpDate( const FSRef *ref); /* The FSBumpDate function changes the content modification date of a file or directory to the current date/time. If the content modification date is already equal to the current date/time, then add one second to the content modification date. ref --> FSRef to a file or directory. */ /*****************************************************************************/ #pragma mark FSGetFinderInfo OSErr FSGetFinderInfo( const FSRef *ref, FinderInfo *info, /* can be NULL */ ExtendedFinderInfo *extendedInfo, /* can be NULL */ Boolean *isDirectory); /* can be NULL */ /* The FSGetFinderInfo function gets the finder information for a file or directory. ref --> FSRef to a file or directory. info <** An optional pointer to a FinderInfo. If not NULL, the FileInfo (if ref is a file) or the FolderInfo (if ref is a folder) will be returned in the FinderInfo. extendedInfo <** An optional pointer to a ExtendedFinderInfo. If not NULL, the ExtendedFileInfo (if ref is a file) or the ExtendedFolderInfo (if ref is a folder) will be returned in the ExtendedFinderInfo. isDirectory <** An optional pointer to a Boolean. If not NULL, true will be returned in the Boolean if the object is a directory, or false will be returned in the Boolean if object is a file. __________ Also see: FSSetFinderInfo */ /*****************************************************************************/ #pragma mark FSSetFinderInfo OSErr FSSetFinderInfo( const FSRef *ref, const FinderInfo *info, /* can be NULL */ const ExtendedFinderInfo *extendedInfo); /* can be NULL */ /* The FSSetFinderInfo function sets the finder information for a file or directory. ref --> FSRef to a file or directory. info **> A pointer to a FinderInfo record with the new FileInfo (if ref is a file) or new FolderInfo (if ref is a folder), or NULL if the FinderInfo is not to be changed. extendedInfo **> A pointer to a FinderInfo record with the new ExtendedFileInfo (if ref is a file) or new ExtendedFolderInfo (if ref is a folder), or NULL if the ExtendedFinderInfo is not to be changed. __________ Also see: FSGetFinderInfo */ /*****************************************************************************/ #pragma mark FSChangeCreatorType OSErr FSChangeCreatorType( const FSRef *ref, OSType fileCreator, OSType fileType); /* The FSChangeCreatorType function changes the creator and/or file type of a file. ref --> FSRef to a file. creator --> The new creator type or 0x00000000 to leave the creator type alone. fileType --> The new file type or 0x00000000 to leave the file type alone. */ /*****************************************************************************/ #pragma mark FSChangeFinderFlags OSErr FSChangeFinderFlags( const FSRef *ref, Boolean setBits, UInt16 flagBits); /* The FSChangeFinderFlags function sets or clears flag bits in the finderFlags field of a file's FileInfo record or a directory's FolderInfo record. ref --> FSRef to a file or directory. setBits --> If true, then set the bits specified in flagBits. If false, then clear the bits specified in flagBits. flagBits --> 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. */ /*****************************************************************************/ #pragma mark FSSetInvisible OSErr FSSetInvisible( const FSRef *ref); #pragma mark FSClearInvisible OSErr FSClearInvisible( const FSRef *ref); /* The FSSetInvisible and FSClearInvisible functions set or clear the kIsInvisible bit in the finderFlags field of the specified file or directory's finder information. ref --> FSRef to a file or directory. */ /*****************************************************************************/ #pragma mark FSSetNameLocked OSErr FSSetNameLocked( const FSRef *ref); #pragma mark FSClearNameLocked OSErr FSClearNameLocked( const FSRef *ref); /* The FSSetNameLocked and FSClearNameLocked functions set or clear the kNameLocked bit bit in the finderFlags field of the specified file or directory's finder information. ref --> FSRef to a file or directory. */ /*****************************************************************************/ #pragma mark FSSetIsStationery OSErr FSSetIsStationery( const FSRef *ref); #pragma mark FSClearIsStationery OSErr FSClearIsStationery( const FSRef *ref); /* The FSSetIsStationery and FSClearIsStationery functions set or clear the kIsStationery bit bit in the finderFlags field of the specified file or directory's finder information. ref --> FSRef to a file or directory. */ /*****************************************************************************/ #pragma mark FSSetHasCustomIcon OSErr FSSetHasCustomIcon( const FSRef *ref); #pragma mark FSClearHasCustomIcon OSErr FSClearHasCustomIcon( const FSRef *ref); /* The FSSetHasCustomIcon and FSClearHasCustomIcon functions set or clear the kHasCustomIcon bit bit in the finderFlags field of the specified file or directory's finder information. ref --> FSRef to a file or directory. */ /*****************************************************************************/ #pragma mark FSClearHasBeenInited OSErr FSClearHasBeenInited( const FSRef *ref); /* The FSClearHasBeenInited function clears the kHasBeenInited bit in the finderFlags field of the specified file or directory's finder information. Note: There is no FSSetHasBeenInited function because ONLY the Finder should set the kHasBeenInited bit. ref --> FSRef to a file or directory. */ /*****************************************************************************/ #pragma mark FSCopyFileMgrAttributes OSErr FSCopyFileMgrAttributes( const FSRef *sourceRef, const FSRef *destinationRef, Boolean copyLockBit); /* 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. sourceRef --> FSRef to a file or directory. destinationRef --> FSRef to a file or directory. copyLockBit --> If true, set the locked state of the destination to match the source. */ /*****************************************************************************/ #pragma mark FSMoveRenameObjectUnicode OSErr FSMoveRenameObjectUnicode( const FSRef *ref, const FSRef *destDirectory, UniCharCount nameLength, const UniChar *name, /* can be NULL (no rename during move) */ TextEncoding textEncodingHint, FSRef *newRef); /* if function fails along the way, newRef is final location of file */ /* The FSMoveRenameObjectUnicode function moves a file or directory and optionally renames it. The source and destination locations must be on the same volume. Note: If the input ref parameter is invalid, this call will fail and newRef, like ref, will be invalid. ref --> FSRef to a file or directory. destDirectory --> FSRef to the destination directory. nameLength --> Number of UniChar in name parameter. name --> An Unicode string with the new name for the moved object, or NULL if no rename is wanted. textEncodingHint --> The text encoding hint used for the rename. You can pass kTextEncodingUnknown to use the "default" textEncodingHint. newRef <-- The new FSRef of the object moved. Note that if this function fails at any step along the way, newRef is still then final location of the object. */ /*****************************************************************************/ #pragma mark FSDeleteContainerContents OSErr FSDeleteContainerContents( const FSRef *container); /* The FSDeleteContainerContents function deletes the contents of a container directory. All files and subdirectories in the specified container are deleted. If a locked file or directory is encountered, it is unlocked and then deleted. If any unexpected errors are encountered, FSDeleteContainerContents quits and returns to the caller. container --> FSRef to a directory. __________ Also see: FSDeleteContainer */ /*****************************************************************************/ #pragma mark FSDeleteContainer OSErr FSDeleteContainer( const FSRef *container); /* The FSDeleteContainer function deletes a container directory and its contents. All files and subdirectories in the specified container are deleted. If a locked file or directory is encountered, it is unlocked and then deleted. After deleting the container's contents, the container is deleted. If any unexpected errors are encountered, FSDeleteContainer quits and returns to the caller. container --> FSRef to a directory. __________ Also see: FSDeleteContainerContents */ /*****************************************************************************/ #pragma mark IterateContainerFilterProcPtr typedef CALLBACK_API( Boolean , IterateContainerFilterProcPtr ) ( Boolean containerChanged, ItemCount currentLevel, const FSCatalogInfo *catalogInfo, const FSRef *ref, const FSSpec *spec, const HFSUniStr255 *name, void *yourDataPtr); /* This is the prototype for the IterateContainerFilterProc function which is called once for each file and directory found by FSIterateContainer. The IterateContainerFilterProc can use the read-only data it receives for whatever it wants. The result of the IterateContainerFilterProc function indicates if iteration should be stopped. To stop iteration, return true; to continue iteration, return false. The yourDataPtr parameter can point to whatever data structure you might want to access from within the IterateContainerFilterProc. containerChanged --> Set to true if the container's contents changed during iteration. currentLevel --> The current recursion level into the container. 1 = the container, 2 = the container's immediate subdirectories, etc. catalogInfo --> The catalog information for the current object. Only the fields requested by the whichInfo parameter passed to FSIterateContainer are valid. ref --> The FSRef to the current object. spec --> The FSSpec to the current object if the wantFSSpec parameter passed to FSIterateContainer is true. name --> The name of the current object if the wantName parameter passed to FSIterateContainer is true. yourDataPtr --> An optional pointer to whatever data structure you might want to access from within the IterateFilterProc. result <-- To stop iteration, return true; to continue iteration, return false. __________ Also see: FSIterateContainer */ /*****************************************************************************/ #pragma mark CallIterateContainerFilterProc #define CallIterateContainerFilterProc(userRoutine, containerChanged, currentLevel, catalogInfo, ref, spec, name, yourDataPtr) \ (*(userRoutine))((containerChanged), (currentLevel), (catalogInfo), (ref), (spec), (name), (yourDataPtr)) /*****************************************************************************/ #pragma mark FSIterateContainer OSErr FSIterateContainer( const FSRef *container, ItemCount maxLevels, FSCatalogInfoBitmap whichInfo, Boolean wantFSSpec, Boolean wantName, IterateContainerFilterProcPtr iterateFilter, void *yourDataPtr); /* The FSIterateContainer function performs a recursive iteration (scan) of the specified container directory and calls your IterateContainerFilterProc function once for each file and directory found. The maxLevels parameter lets you control how deep the recursion goes. If maxLevels is 1, FSIterateContainer only scans the specified directory; if maxLevels is 2, FSIterateContainer 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 your IterateContainerFilterProc. container --> The FSRef to the container directory to iterate. maxLevels --> Maximum number of directory levels to scan or zero to scan all directory levels. whichInfo --> The fields of the FSCatalogInfo you wish to get. wantFSSpec --> Set to true if you want the FSSpec to each object passed to your IterateContainerFilterProc. wantName --> Set to true if you want the name of each object passed to your IterateContainerFilterProc. iterateFilter --> A pointer to the IterateContainerFilterProc you want called once for each file and directory found by FSIterateContainer. yourDataPtr --> An optional pointer to whatever data structure you might want to access from within the IterateFilterProc. */ /*****************************************************************************/ #pragma mark FSGetDirectoryItems OSErr FSGetDirectoryItems( const FSRef *container, FSRef ***refsHandle, /* pointer to handle of FSRefs */ ItemCount *numRefs, Boolean *containerChanged); /* The FSGetDirectoryItems function returns the list of items in the specified container. The array of FSRef records is returned in a Handle, refsHandle, which is allocated by FSGetDirectoryItems. The caller is responsible for disposing of refsHandle if the FSGetDirectoryItems returns noErr. container --> FSRef to a directory. refsHandle <-- Pointer to an FSRef Handle where the array of FSRefs is to be returned. numRefs <-- The number of FSRefs returned in the array. containerChanged <-- Set to true if the container changes while the list of items is being obtained. */ /*****************************************************************************/ #pragma mark FSExchangeObjectsCompat OSErr FSExchangeObjectsCompat( const FSRef *sourceRef, const FSRef *destRef, FSRef *newSourceRef, FSRef *newDestRef); /* The FSExchangeObjectsCompat function exchanges the data between two files. The FSExchangeObjectsCompat function is an enhanced version of FSExchangeObjects function. The two enhancements FSExchangeObjectsCompat provides are: 1, FSExchangeObjectsCompat will work on volumes which do not support FSExchangeObjects. FSExchangeObjectsCompat does this by emulating FSExchangeObjects through a series of File Manager operations. If there is a failure at any step along the way, FSExchangeObjectsCompat attempts to undo any steps already taken to leave the files in their original state in their original locations. 2. FSExchangeObjectsCompat returns new FSRefs to the source and destination files. Note that if this function fails at any step along the way, newSourceRef and newDestRef still give you access to the final locations of the files being exchanged -- even if they are renamed or not in their original locations. sourceRef --> FSRef to the source file. destRef --> FSRef to the destination file. newSourceRef <-- The new FSRef to the source file. newDestRef <-- The new FSRef to the destination file. */ /*****************************************************************************/ #pragma mark ----- Shared Environment Routines ----- /*****************************************************************************/ #pragma mark FSLockRange OSErr FSLockRange( SInt16 refNum, SInt32 rangeLength, SInt32 rangeStart); /* The LockRange function locks (denies access to) a portion of a file that was opened with shared read/write permission. refNum --> The file reference number of an open file. rangeLength --> The number of bytes in the range. rangeStart --> The starting byte in the range to lock. __________ Also see: UnlockRange */ /*****************************************************************************/ #pragma mark FSUnlockRange OSErr FSUnlockRange( SInt16 refNum, SInt32 rangeLength, SInt32 rangeStart); /* The UnlockRange function unlocks (allows access to) a previously locked portion of a file that was opened with shared read/write permission. refNum --> The file reference number of an open file. rangeLength --> The number of bytes in the range. rangeStart --> The starting byte in the range to unlock. __________ Also see: LockRange */ /*****************************************************************************/ #pragma mark FSGetDirAccess OSErr FSGetDirAccess( const FSRef *ref, SInt32 *ownerID, /* can be NULL */ SInt32 *groupID, /* can be NULL */ SInt32 *accessRights); /* can be NULL */ /* The FSGetDirAccess function retrieves the directory access control information for a directory on a shared volume. ref --> An FSRef specifying the directory. ownerID <** An optional pointer to a SInt32. If not NULL, the directory's owner ID will be returned in the SInt32. groupID <** An optional pointer to a SInt32. If not NULL, the directory's group ID, or 0 if no group affiliation, will be returned in the SInt32. accessRights <** An optional pointer to a SInt32. If not NULL, the directory's access rights will be returned in the SInt32. __________ Also see: FSSetDirAccess, FSMapID, FSMapName */ /*****************************************************************************/ #pragma mark FSSetDirAccess OSErr FSSetDirAccess( const FSRef *ref, SInt32 ownerID, SInt32 groupID, SInt32 accessRights); /* The FSpSetDirAccess function changes the directory access control information for a directory on a shared volume. You must be the owner of a directory to change its access control information. ref --> An FSRef specifying the directory. ownerID --> The directory's owner ID. groupID --> The directory's group ID or 0 if no group affiliation. accessRights --> The directory's access rights. __________ Also see: FSGetDirAccess, FSMapID, FSMapName */ /*****************************************************************************/ #pragma mark FSGetVolMountInfoSize OSErr FSGetVolMountInfoSize( FSVolumeRefNum volRefNum, SInt16 *size); /* The FSGetVolMountInfoSize function determines the how much space the program needs to allocate for a volume mounting information record. volRefNum --> Volume specification. size <-- The space needed (in bytes) of the volume mounting information record. __________ Also see: FSGetVolMountInfo, VolumeMount */ /*****************************************************************************/ #pragma mark FSGetVolMountInfo OSErr FSGetVolMountInfo( FSVolumeRefNum volRefNum, void *volMountInfo); /* The FSGetVolMountInfo function retrieves a volume mounting information record containing all the information needed to mount the volume, except for passwords. volRefNum --> Volume specification. volMountInfo <-- The volume mounting information. __________ Also see: FSGetVolMountInfoSize, VolumeMount */ /*****************************************************************************/ #pragma mark FSVolumeMount OSErr FSVolumeMount( const void *volMountInfo, FSVolumeRefNum *volRefNum); /* The VolumeMount function mounts a volume using a volume mounting information record. volMountInfo --> A volume mounting information record. volRefNum <-- The volume reference number. __________ Also see: FSGetVolMountInfoSize, FSGetVolMountInfo */ /*****************************************************************************/ #pragma mark FSMapID OSErr FSMapID( FSVolumeRefNum volRefNum, SInt32 ugID, SInt16 objType, Str31 name); /* The FSMapID function determines the name of a user or group if you know the user or group ID. volRefNum --> Volume specification. objType --> The mapping function code: kOwnerID2Name to map a user ID to a user name kGroupID2Name to map a group ID to a group name name <** An optional pointer to a buffer (minimum Str31). If not NULL, the user or group name will be returned in the buffer. __________ Also see: FSGetDirAccess, FSSetDirAccess, FSMapName */ /*****************************************************************************/ #pragma mark FSMapName OSErr FSMapName( FSVolumeRefNum volRefNum, ConstStr255Param name, SInt16 objType, SInt32 *ugID); /* The FSMapName function determines the user or group ID if you know the user or group name. volRefNum --> Volume specification. name --> The user or group name. objType --> The mapping function code: kOwnerName2ID to map a user name to a user ID kGroupName2ID to map a user name to a group ID ugID <-- The user or group ID. __________ Also see: FSGetDirAccess, FSSetDirAccess, FSMapID */ /*****************************************************************************/ #pragma mark FSCopyFile OSErr FSCopyFile( const FSRef *srcFileRef, const FSRef *dstDirectoryRef, UniCharCount nameLength, const UniChar *copyName, /* can be NULL (no rename during copy) */ TextEncoding textEncodingHint, FSRef *newRef); /* can be NULL */ /* The FSCopyFile function duplicates a file and optionally renames it. The source and destination volumes must be on the same file server. This function instructs the server to copy the file. srcFileRef --> An FSRef specifying the source file. dstDirectoryRef --> An FSRef specifying the destination directory. nameLength --> Number of UniChar in copyName parameter (ignored if copyName is NULL). copyName --> Points to the new file name if the file is to be renamed, or NULL if the file isn't to be renamed. textEncodingHint --> The text encoding hint used for the rename. You can pass kTextEncodingUnknown to use the "default" textEncodingHint. newRef <** An optional pointer to a FSRef. If not NULL, the FSRef of the duplicated file will be returned in the FSRef. */ /*****************************************************************************/ #pragma mark FSMoveRename OSErr FSMoveRename( const FSRef *srcFileRef, const FSRef *dstDirectoryRef, UniCharCount nameLength, const UniChar *moveName, /* can be NULL (no rename during move) */ TextEncoding textEncodingHint, FSRef *newRef); /* can be NULL */ /* The FSMoveRename function moves a file or directory (object), and optionally renames it. The source and destination locations must be on the same shared volume. srcFileRef --> An FSRef specifying the source file. dstDirectoryRef --> An FSRef specifying the destination directory. nameLength --> Number of UniChar in moveName parameter (ignored if copyName is NULL) moveName --> Points to the new object name if the object is to be renamed, or NULL if the object isn't to be renamed. textEncodingHint --> The text encoding hint used for the rename. You can pass kTextEncodingUnknown to use the "default" textEncodingHint. newRef <** An optional pointer to a FSRef. If not NULL, the FSRef of the moved object will be returned in the FSRef. */ /*****************************************************************************/ #pragma mark ----- File ID Routines ----- /*****************************************************************************/ #pragma mark FSResolveFileIDRef OSErr FSResolveFileIDRef( FSVolumeRefNum volRefNum, SInt32 fileID, FSRef *ref); /* The FSResolveFileIDRef function returns an FSRef for the file with the specified file ID reference. volRefNum --> Volume specification. fileID --> The file ID reference. ref <-- The FSRef for the file ID reference. __________ Also see: FSCreateFileIDRef, FSDeleteFileIDRef */ /*****************************************************************************/ #pragma mark FSCreateFileIDRef OSErr FSCreateFileIDRef( const FSRef *ref, SInt32 *fileID); /* The FSCreateFileIDRef 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 or afpIDExists. ref --> The FSRef for the file. fileID <-- The file ID reference (if result is noErr, fidExists, or afpIDExists). __________ Also see: GetFSRefFromFileIDRef, FSDeleteFileIDRef */ /*****************************************************************************/ #pragma mark FSDeleteFileIDRef /* Why is there no FSDeleteFileIDRef routine? There are two reasons: 1. Since Mac OS 8.1, PBDeleteFileIDRef hasn't deleted file ID references. On HFS volumes, deleting a file ID reference breaks aliases (which use file ID references to track files as they are moved around on a volume) and file ID references are automatically deleted when the file they refer to is deleted. On HFS Plus volumes, file ID references are always created when a file is created, deleted when the file is deleted, and cannot be deleted at any other time. 2. PBDeleteFileIDRef causes a memory access fault under Mac OS X 10.0 through 10.1.x. While this will be fixed in a future release, the implementation, like the Mac OS 8/9 implementation, does not delete file ID references. __________ Also see: GetFSRefFromFileIDRef, FSCreateFileIDRef */ /*****************************************************************************/ #pragma mark ----- Utility Routines ----- /*****************************************************************************/ #pragma mark GetTempBuffer Ptr GetTempBuffer( ByteCount buffReqSize, ByteCount *buffActSize); /* The GetTempBuffer function allocates a temporary buffer for file system operations which is at least 4K bytes and a multiple of 4K bytes. buffReqSize --> Size you'd like the buffer to be. buffActSize <-- The size of the buffer allocated. function result <-- Pointer to memory allocated, or NULL if no memory was available. The caller is responsible for disposing of this buffer with DisposePtr. */ /*****************************************************************************/ #pragma mark FileRefNumGetFSRef OSErr FileRefNumGetFSRef( short refNum, FSRef *ref); /* The FileRefNumGetFSRef function gets the FSRef of an open file. refNum --> The file reference number of an open file. ref <-- The FSRef to the open file. */ /*****************************************************************************/ #pragma mark FSSetDefault OSErr FSSetDefault( const FSRef *newDefault, FSRef *oldDefault); /* The FSSetDefault function sets the current working directory to the directory specified by newDefault. The previous current working directory is returned in oldDefault and must be used to restore the current working directory to its previous state with the FSRestoreDefault 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 current working directory. This is how you should use these functions: result = FSSetDefault(&newDefault, &oldDefault); if ( noErr == result ) { // call the Stdio functions like remove, rename, // fopen, freopen, etc here! result = FSRestoreDefault(&oldDefault); } newDefault --> An FSRef that specifies the new current working directory. oldDefault <-- The previous current working directory's FSRef. __________ Also see: FSRestoreDefault */ /*****************************************************************************/ #pragma mark FSRestoreDefault OSErr FSRestoreDefault( const FSRef *oldDefault); /* The FSRestoreDefault function restores the current working directory to the directory specified by oldDefault. The oldDefault parameter was previously obtained from the FSSetDefault 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 current working directory. This is how you should use these functions: result = FSSetDefault(&newDefault, &oldDefault); if ( noErr == result ) { // call the Stdio functions like remove, rename, // fopen, freopen, etc here! result = FSRestoreDefault(&oldDefault); } oldDefault --> The FSRef of the location to restore. __________ Also see: FSSetDefault */ /*****************************************************************************/ #if PRAGMA_STRUCT_ALIGN #pragma options align=reset #elif PRAGMA_STRUCT_PACKPUSH #pragma pack(pop) #elif PRAGMA_STRUCT_PACK #pragma pack() #endif #ifdef PRAGMA_IMPORT_OFF #pragma import off #elif PRAGMA_IMPORT #pragma import reset #endif #ifdef __cplusplus } #endif #endif /* __MOREFILESX__ */ \ No newline at end of file