Show ThreadedFile.c syntax highlighted
/****************************************************************************************
ThreadedFile.c $Revision: 1.2 $
<http://rentzsch.com/redshedthreads>
Copyright © 2000-2002 Red Shed Software. All rights reserved.
by Jonathan 'Wolf' Rentzsch (jon at redshed dot net)
************************************************************************************/
#include "ThreadedFile.h"
#include "require.h"
#include "CFMA5.h"
#define kStackBufferSize 8 * 1024 // Should be a multiple of 512, at most 16K.
// Set WaitForSystemTask to 1 (true) if you want to make sure the following calls return
// at System Task time. This handy if you want to follow your program's flow
// in a debugger that can't be invoked at interrupt time (like CodeWarrior's
// debugger), but slows down your code.
// Set SyncAsyncWorkaround to 1 (true) to activate work-around code for early-
// generation IDE/ATA PowerMacs like the PowerMac 6500 and the PowerBook Duo 2300c.
// These machines' ATA controllers only operate synchronously. It's still legal to
// call the File Manager at interrupt time on these machines, however your job will
// always be completed immediately, and your ioCompletion routine will be immediately
// called directly from within the File Manager call. Couple this behavior with
// Sync/BlockRedShedThread, and you fall into the pathological situation of a thread
// trying to pulse itself. RedShedThreads now detects this situation, and no longer
// crashes. However, your thread never comes up for air, and never yields and thus hogs
// the machine. The work-around code reads how long the thread has been running and
// yields if it exceeds an acceptable limit. Even if you leave SyncAsyncWorkaround on,
// the work-around code should never be executed on machines with true asynchronous
// behavior, so it's not much of a performance hit on machines that don't need it.
#define WaitForSystemTask 0
#define SyncAsyncWorkaround 0
#if TARGET_API_MAC_CARBON
#define LMGetTicks TickCount
#endif
#if SyncAsyncWorkaround
#include "WaitRedShedThread.h" // For WaitEventTask() or WaitTimeTask().
#if WaitForSystemTask
#define YieldIfNecessary( THREAD ) \
if( (LMGetTicks() - (THREAD)->startPulseTime) > 5 ) \
WaitEventTask( (THREAD), 10 )
#else
#define YieldIfNecessary( THREAD ) \
if( (LMGetTicks() - (THREAD)->startPulseTime) > 5 ) \
WaitTimeTask( (THREAD), 125 )
#endif
#else
#if WaitForSystemTask
#include "EventTasks.h" // For kPriority.
#include "WaitRedShedThread.h" // For WaitEventTask().
#define YieldIfNecessary( THREAD ) WaitEventTask( (THREAD), kPriority )
#else
#define YieldIfNecessary( THREAD )
#endif
#endif
/**************************
*
* Funky Protos
*
**************************/
#pragma mark (Funky Protos)
pascal
void
ThreadedFileCompletion(
ParmBlkPtr paramBlock );
#if TARGET_API_MAC_CARBON
IOCompletionUPP gThreadedFileCompletion = NewIOCompletionUPP( ThreadedFileCompletion );
#else
#if TARGET_RT_MAC_CFM
RoutineDescriptor rdThreadedFileCompletion = BUILD_ROUTINE_DESCRIPTOR( uppIOCompletionProcInfo, ThreadedFileCompletion );
IOCompletionUPP gThreadedFileCompletion = &rdThreadedFileCompletion;
#else
void ThreadedFileCompletionGlue();
IOCompletionUPP gThreadedFileCompletion = (IOCompletionUPP) ThreadedFileCompletionGlue;
#endif
#endif
/****************************************************************************************
*
* Public
*
****************************************************************************************/
#pragma mark -
#pragma mark (Public)
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Mon, Mar 20, 2000 Created.
************************************************************************************/
OSErr
TPBGetCatInfo(
RedShedThread *thread,
TCInfoPBPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->dirInfo.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBGetCatInfoAsync( (CInfoPBPtr) ¶mBlock->dirInfo.qLink );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->dirInfo.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Mar 22, 2000 Created.
************************************************************************************/
OSErr
TPBSetCatInfo(
RedShedThread *thread,
TCInfoPBPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->dirInfo.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBSetCatInfoAsync( (CInfoPBPtr) ¶mBlock->dirInfo.qLink );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->dirInfo.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sun, Mar 26, 2000 Created.
************************************************************************************/
OSErr
TGetDirCount(
RedShedThread *thread,
short vRefNum,
long dirID,
ConstStr255Param name,
UInt16 *count )
{
Str255 name_;
OSErr err;
TCInfoPBRec info;
info.dirInfo.ioVRefNum = vRefNum;
info.dirInfo.ioACUser = 0;
info.dirInfo.ioDrDirID = dirID;
RequireRedShedThread( thread );
RequirePtr( count );
if( name == nil || name[ 0 ] == 0 ) {
name_[ 0 ] = 0;
info.dirInfo.ioNamePtr = name_;
info.dirInfo.ioFDirIndex = -1; // Use ioDirID.
} else {
info.dirInfo.ioNamePtr = (StringPtr) name;
info.dirInfo.ioFDirIndex = 0; // Use ioNamePtr and ioDirID.
}
err = TPBGetCatInfo( thread, &info );
if( !err ) {
if( (info.hFileInfo.ioFlAttrib & kioFlAttribDirMask) == 0 ) {
err = dirNFErr;
}
*count = info.dirInfo.ioDrNmFls;
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Mar 21, 2000 Created.
************************************************************************************/
OSErr
TPBHDelete(
RedShedThread *thread,
THParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBHDeleteAsync( (HParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Mar 21, 2000 Created.
************************************************************************************/
OSErr
TPBGetEOF(
RedShedThread *thread,
TParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBGetEOFAsync( (ParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Mar 21, 2000 Created.
************************************************************************************/
OSErr
TPBSetEOF(
RedShedThread *thread,
TParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBSetEOFAsync( (ParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Mar 21, 2000 Created.
************************************************************************************/
OSErr
TPBSetFPos(
RedShedThread *thread,
TParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBSetFPosAsync( (ParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Mar 21, 2000 Created.
************************************************************************************/
OSErr
TPBRead(
RedShedThread *thread,
TParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBReadAsync( (ParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Mar 21, 2000 Created.
************************************************************************************/
OSErr
TPBWrite(
RedShedThread *thread,
TParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBWriteAsync( (ParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Mar 21, 2000 Created.
wolf Sat, Oct 28, 2000 Added requirements.
Added buffer and bufferSize parameters to support
larger buffers managed by the calller.
wolf Tue, Dec 26, 2000 Added a couple of explicit casts (from the UInt32
to a long) and a requirement to make sure the
bufferSize doesn't exceed a signed 32 bit integer.
************************************************************************************/
OSErr
TCopyFork(
RedShedThread *thread,
short fromRefNum,
short toRefNum,
void *buffer, // Can be nil.
UInt32 bufferSize ) // Can be zero.
{
char internalBuffer[ kStackBufferSize ];
TParamBlockRec fromPB;
TParamBlockRec toPB;
Boolean done = false;
OSErr err;
RequireRedShedThread( thread );
Require( fromRefNum );
Require( toRefNum );
RequirePtrIfNotNil( buffer );
Require( bufferSize < 16 * 1024 * 1024 ); // Arbitrary 16MB sanity limit.
RequireSInt32( bufferSize );
fromPB.ioParam.ioRefNum = fromRefNum;
toPB.ioParam.ioRefNum = toRefNum;
// Set the destination's EOF to the source's EOF.
err = TPBGetEOF( thread, &fromPB );
RequireNoErr( err );
if( !err ) {
toPB.ioParam.ioMisc = fromPB.ioParam.ioMisc;
err = TPBSetEOF( thread, &toPB );
RequireNoErr( err );
}
// Set the source's file position to 0.
if( !err ) {
fromPB.ioParam.ioPosMode = fsFromStart;
fromPB.ioParam.ioPosOffset = 0;
err = TPBSetFPos( thread, &fromPB );
RequireNoErr( err );
}
// Set the destination's file position to 0.
if( !err ) {
toPB.ioParam.ioPosMode = fsFromStart;
toPB.ioParam.ioPosOffset = 0;
err = TPBSetFPos( thread, &toPB );
RequireNoErr( err );
}
// Copy over the data in blocks.
if( !err ) {
// If the user didn't supply a buffer, or the supplied buffer is smaller than
// our internal buffer, use our internal buffer.
if( buffer == nil || bufferSize < kStackBufferSize ) {
buffer = internalBuffer;
bufferSize = kStackBufferSize;
}
fromPB.ioParam.ioBuffer = (Ptr) buffer;
fromPB.ioParam.ioReqCount = (long) bufferSize;
fromPB.ioParam.ioPosMode = fsAtMark + noCacheMask;
toPB.ioParam.ioBuffer = (Ptr) buffer;
toPB.ioParam.ioReqCount = (long) bufferSize;
toPB.ioParam.ioPosMode = fsAtMark + noCacheMask;
while( !err && !done ) {
err = TPBRead( thread, &fromPB );
if( err == eofErr ) {
err = noErr;
done = true;
toPB.ioParam.ioReqCount = fromPB.ioParam.ioActCount;
}
RequireNoErr( err );
if( !err ) {
err = TPBWrite( thread, &toPB );
RequireNoErr( err );
}
}
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
Ignore this function. TCopyFork is faster.
************************************************************************************/
OSErr
TCopyFork2(
RedShedThread *thread,
short fromRefNum,
short toRefNum,
void *buffer, // Can be nil.
UInt32 bufferSize ) // Can be zero.
{
char internalBuffer[ kStackBufferSize ];
long logEOF;
Boolean done = false;
OSErr err;
RequireRedShedThread( thread );
Require( fromRefNum );
Require( toRefNum );
RequirePtrIfNotNil( buffer );
Require( bufferSize < 16 * 1024 * 1024 ); // Arbitrary 16MB sanity limit.
RequireSInt32( bufferSize );
// Set the destination's EOF to the source's EOF.
err = TGetEOF( thread, fromRefNum, &logEOF );
if( !err )
err = TSetEOF( thread, toRefNum, logEOF );
// Set the source's file position to 0.
if( !err )
err = TSetFPos( thread, fromRefNum, fsFromStart, 0 );
// Set the destination's file position to 0.
if( !err )
err = TSetFPos( thread, toRefNum, fsFromStart, 0 );
// Copy over the data in blocks.
if( !err ) {
// If the user didn't supply a buffer, or the supplied buffer is smaller than
// our internal buffer, use our internal buffer.
if( buffer == nil || bufferSize < kStackBufferSize ) {
buffer = internalBuffer;
bufferSize = kStackBufferSize;
}
while( !err && !done ) {
err = TFSRead( thread, fromRefNum, (long*) &bufferSize, buffer );
if( err == eofErr ) {
err = noErr;
done = true;
}
if( !err )
err = TFSWrite( thread, toRefNum, (long*) &bufferSize, buffer );
}
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Mar 22, 2000 Created.
************************************************************************************/
OSErr
TPBHOpenDF(
RedShedThread *thread,
THParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBHOpenDFAsync( (HParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
if( paramBlock->ioParam.ioResult == paramErr ) {
// OpenDF not supported, try Open.
ReadyRedShedThread( thread );
PBHOpenAsync( (HParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
}
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Mar 22, 2000 Created.
************************************************************************************/
OSErr
TPBHOpenRF(
RedShedThread *thread,
THParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBHOpenRFAsync( (HParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Mar 22, 2000 Created.
************************************************************************************/
OSErr
TPBHCreate(
RedShedThread *thread,
THParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBHCreateAsync( (HParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sun, Mar 26, 2000 Created.
************************************************************************************/
OSErr
TPBDirCreate(
RedShedThread *thread,
THParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBDirCreateAsync( (HParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Mar 22, 2000 Created.
wolf Sat, Oct 28, 2000 Added buffer and bufferSize parameters to support
larger buffers managed by the calller.
************************************************************************************/
OSErr
TFileCopy(
RedShedThread *thread,
short fromVRefNum,
long fromDirID,
ConstStr255Param fromName,
short fromDeskRefNum,
short toVRefNum,
long toDirID,
short toDeskRefNum,
void *buffer, // Can be nil.
UInt32 bufferSize ) // Can be zero.
{
THParamBlockRec pb;
TCInfoPBRec info;
TDTPBRec desk;
Str255 comment;
short fromRefNum, toRefNum;
OSErr err, err2;
RequireRedShedThread( thread );
Require( fromVRefNum );
Require( fromDirID );
RequirePtr( fromName );
Require( toVRefNum );
Require( toDirID );
RequirePtrIfNotNil( buffer );
Require( bufferSize < 16 * 1024 * 1024 ); // Arbitrary 16MB sanity limit.
//-------------------------------------------------
// Create the destintation file.
pb.fileParam.ioNamePtr = (StringPtr) fromName;
pb.fileParam.ioVRefNum = toVRefNum;
pb.fileParam.ioDirID = toDirID;
err = TPBHCreate( thread, &pb );
RequireNoErr( err );
//-------------------------------------------------
// Get information about the source file.
if( !err ) {
info.dirInfo.ioNamePtr = (StringPtr) fromName;
info.dirInfo.ioVRefNum = fromVRefNum;
info.dirInfo.ioFDirIndex = 0;
info.dirInfo.ioACUser = 0;
info.dirInfo.ioDrDirID = fromDirID;
err = TPBGetCatInfo( thread, &info );
RequireNoErr( err );
}
//-------------------------------------------------
// Copy the data fork from the source to the destination.
if( !err && info.hFileInfo.ioFlLgLen != 0 ) {
// There's a data fork, copy it over.
fromRefNum = toRefNum = 0;
// Open the source.
pb.fileParam.ioNamePtr = (StringPtr) fromName;
pb.fileParam.ioVRefNum = fromVRefNum;
pb.ioParam.ioPermssn = fsRdPerm;
pb.fileParam.ioDirID = fromDirID;
err = TPBHOpenDF( thread, &pb );
RequireNoErr( err );
if( !err ) {
fromRefNum = pb.ioParam.ioRefNum;
// Open the destination.
pb.fileParam.ioNamePtr = (StringPtr) fromName;
pb.fileParam.ioVRefNum = toVRefNum;
pb.ioParam.ioPermssn = fsWrPerm;
pb.fileParam.ioDirID = toDirID;
err = TPBHOpenDF( thread, &pb );
RequireNoErr( err );
}
if( !err ) {
toRefNum = pb.ioParam.ioRefNum;
// Copy over the fork.
err = TCopyFork( thread, fromRefNum, toRefNum, buffer, bufferSize );
RequireNoErr( err );
}
// If opened, close the destination regardless of any error.
if( toRefNum ) {
err2 = TClose( thread, &toRefNum );
RequireNoErr( err2 );
if( !err )
err = err2;
}
// If opened, close the source regardless of any error.
if( fromRefNum ) {
err2 = TClose( thread, &fromRefNum );
RequireNoErr( err2 );
if( !err )
err = err2;
}
}
//-------------------------------------------------
// Copy the resource fork from the source to the destination.
if( !err && info.hFileInfo.ioFlRLgLen != 0 ) {
// There's a resource fork, copy it over.
fromRefNum = toRefNum = 0;
// Open the source.
pb.fileParam.ioNamePtr = (StringPtr) fromName;
pb.fileParam.ioVRefNum = fromVRefNum;
pb.ioParam.ioPermssn = fsRdPerm;
pb.fileParam.ioDirID = fromDirID;
err = TPBHOpenRF( thread, &pb );
RequireNoErr( err );
if( !err ) {
fromRefNum = pb.ioParam.ioRefNum;
// Open the destination.
pb.fileParam.ioNamePtr = (StringPtr) fromName;
pb.fileParam.ioVRefNum = toVRefNum;
pb.ioParam.ioPermssn = fsWrPerm;
pb.fileParam.ioDirID = toDirID;
err = TPBHOpenRF( thread, &pb );
RequireNoErr( err );
}
if( !err ) {
toRefNum = pb.ioParam.ioRefNum;
// Copy over the fork.
err = TCopyFork( thread, fromRefNum, toRefNum, buffer, bufferSize );
RequireNoErr( err );
}
// If opened, close the destination regardless of any error.
if( toRefNum ) {
err2 = TClose( thread, &toRefNum );
RequireNoErr( err2 );
if( !err )
err = err2;
}
// If opened, close the source regardless of any error.
if( fromRefNum ) {
err2 = TClose( thread, &fromRefNum );
RequireNoErr( err2 );
if( !err )
err = err2;
}
}
//-------------------------------------------------
// Copy the attributes from the source to the destination.
if( !err ) {
// Target the destination file.
info.dirInfo.ioNamePtr = (StringPtr) fromName;
info.dirInfo.ioVRefNum = toVRefNum;
info.dirInfo.ioFDirIndex = 0;
info.dirInfo.ioACUser = 0;
info.dirInfo.ioDrDirID = toDirID;
// Clear the hasBeenInited flag.
info.hFileInfo.ioFlFndrInfo.fdFlags &= ~kHasBeenInited;
// Set the attributes.
err = TPBSetCatInfo( thread, &info );
RequireNoErr( err );
if( !err && (info.hFileInfo.ioFlAttrib & kioFlAttribLockedMask) != 0 ) {
// The source was locked, lock the destination.
pb.fileParam.ioNamePtr = (StringPtr) fromName;
pb.fileParam.ioVRefNum = toVRefNum;
pb.fileParam.ioDirID = toDirID;
err = TPBHSetFLock( thread, &pb );
RequireNoErr( err );
}
}
//-------------------------------------------------
// Copy the comments from the source to the destination.
if( !err && fromDeskRefNum && toDeskRefNum ) {
desk.ioNamePtr = (StringPtr) fromName;
desk.ioVRefNum = fromVRefNum;
desk.ioDTRefNum = fromDeskRefNum;
desk.ioDTBuffer = (Ptr) comment + 1;
desk.ioDTReqCount = sizeof( Str255 ) - 1;
desk.ioDirID = fromDirID;
err = TPBDTGetComment( thread, &desk );
RequireNoErr( err );
if( err ) {
if( err == afpItemNotFound )
err = noErr;
RequireNoErr( err );
} else if( desk.ioDTActCount > 0 ) {
desk.ioNamePtr = (StringPtr) fromName;
desk.ioVRefNum = toVRefNum;
desk.ioDTRefNum = toDeskRefNum;
desk.ioDTBuffer = (Ptr) comment + 1;
if( desk.ioDTActCount > 200 )
desk.ioDTReqCount = 200;
else
desk.ioDTReqCount = desk.ioDTActCount;
desk.ioDirID = toDirID;
err = TPBDTSetComment( thread, &desk );
RequireNoErr( err );
}
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Sun, Mar 26, 2000 Created.
************************************************************************************/
OSErr
TFolderCopy( // Doesn't copy contents.
RedShedThread *thread,
short fromVRefNum,
long fromDirID,
ConstStr255Param fromName,
short fromDeskRefNum,
short toVRefNum,
long *toDirID,
short toDeskRefNum )
{
THParamBlockRec pb;
TCInfoPBRec info;
TDTPBRec desk;
Str255 comment;
long toDirID_;
OSErr err;
RequireRedShedThread( thread );
Require( fromVRefNum );
Require( fromDirID );
RequirePtr( fromName );
Require( toVRefNum );
RequirePtr( toDirID );
Require( *toDirID );
toDirID_ = *toDirID;
//-------------------------------------------------
// Create the destintation folder.
pb.fileParam.ioNamePtr = (StringPtr) fromName;
pb.fileParam.ioVRefNum = toVRefNum;
pb.fileParam.ioDirID = toDirID_;
err = TPBDirCreate( thread, &pb );
RequireNoErr( err );
//-------------------------------------------------
// Get the attributes of the source folder.
if( !err ) {
*toDirID = pb.fileParam.ioDirID;
info.dirInfo.ioNamePtr = (StringPtr) fromName;
info.dirInfo.ioVRefNum = fromVRefNum;
info.dirInfo.ioFDirIndex = 0;
info.dirInfo.ioACUser = 0;
info.dirInfo.ioDrDirID = fromDirID;
err = TPBGetCatInfo( thread, &info );
RequireNoErr( err );
}
//-------------------------------------------------
// Copy the attributes from the source to the destination.
if( !err ) {
// Target the destination file.
info.dirInfo.ioNamePtr = (StringPtr) fromName;
info.dirInfo.ioVRefNum = toVRefNum;
info.dirInfo.ioFDirIndex = 0;
info.dirInfo.ioACUser = 0;
info.dirInfo.ioDrDirID = toDirID_;
// Clear the hasBeenInited flag.
info.hFileInfo.ioFlFndrInfo.fdFlags &= ~kHasBeenInited;
// Set the attributes.
err = TPBSetCatInfo( thread, &info );
RequireNoErr( err );
}
//-------------------------------------------------
// Copy the comments from the source to the destination.
if( !err && fromDeskRefNum && toDeskRefNum ) {
desk.ioNamePtr = (StringPtr) fromName;
desk.ioVRefNum = fromVRefNum;
desk.ioDTRefNum = fromDeskRefNum;
desk.ioDTBuffer = (Ptr) comment + 1;
desk.ioDTReqCount = sizeof( Str255 ) - 1;
desk.ioDirID = fromDirID;
err = TPBDTGetComment( thread, &desk );
if( err ) {
if( err == afpItemNotFound )
err = noErr;
RequireNoErr( err );
} else if( desk.ioDTActCount > 0 ) {
desk.ioNamePtr = (StringPtr) fromName;
desk.ioVRefNum = toVRefNum;
desk.ioDTRefNum = toDeskRefNum;
desk.ioDTBuffer = (Ptr) comment + 1;
if( desk.ioDTActCount > 200 )
desk.ioDTReqCount = 200;
else
desk.ioDTReqCount = desk.ioDTActCount;
desk.ioDirID = toDirID_;
err = TPBDTSetComment( thread, &desk );
RequireNoErr( err );
}
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Wed, Mar 22, 2000 Created.
************************************************************************************/
OSErr
TClose(
RedShedThread *thread,
short *refNum )
{
TParamBlockRec pb;
RequireRedShedThread( thread );
RequirePtr( refNum );
pb.header.thread = thread;
pb.header.a5 = GetA5();
pb.ioParam.ioCompletion = gThreadedFileCompletion;
pb.ioParam.ioRefNum = *refNum;
*refNum = 0;
ReadyRedShedThread( thread );
PBCloseAsync( (ParmBlkPtr) &pb.ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( pb.ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 23, 2000 Created.
************************************************************************************/
OSErr
TPBHSetFLock(
RedShedThread *thread,
THParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBHSetFLockAsync( (HParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Fri, Mar 24, 2000 Created.
************************************************************************************/
OSErr
TPBHRstFLock(
RedShedThread *thread,
THParmBlkPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioParam.ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBHRstFLockAsync( (HParmBlkPtr) ¶mBlock->ioParam );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioParam.ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 23, 2000 Created.
************************************************************************************/
OSErr
TPBDTGetComment(
RedShedThread *thread,
TDTPBPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBDTGetCommentAsync( (DTPBPtr) ¶mBlock->qLink );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 23, 2000 Created.
************************************************************************************/
OSErr
TPBDTSetComment(
RedShedThread *thread,
TDTPBPtr paramBlock )
{
RequireRedShedThread( thread );
RequirePtr( paramBlock );
paramBlock->header.thread = thread;
paramBlock->header.a5 = GetA5();
paramBlock->ioCompletion = gThreadedFileCompletion;
ReadyRedShedThread( thread );
PBDTSetCommentAsync( (DTPBPtr) ¶mBlock->qLink );
BlockRedShedThread( thread );
YieldIfNecessary( thread );
return( paramBlock->ioResult );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Tue, Mar 6, 2001 Created.
************************************************************************************/
OSErr
THCreate(
RedShedThread *thread,
short vRefNum,
long dirID,
ConstStr255Param fileName,
OSType creator,
OSType fileType )
{
THParamBlockRec pb;
TCInfoPBRec info;
OSErr err;
RequireRedShedThread( thread );
RequirePString( fileName, 1, 255 );
pb.fileParam.ioNamePtr = (StringPtr) fileName;
pb.fileParam.ioVRefNum = vRefNum;
pb.fileParam.ioDirID = dirID;
err = TPBHCreate( thread, &pb );
if( !err ) {
info.hFileInfo.ioNamePtr = (StringPtr) fileName;
info.hFileInfo.ioVRefNum = vRefNum;
info.hFileInfo.ioFDirIndex = 0;
info.hFileInfo.ioACUser = 0;
info.hFileInfo.ioDirID = dirID;
err = TPBGetCatInfo( thread, &info );
}
if( !err ) {
info.hFileInfo.ioNamePtr = (StringPtr) fileName;
info.hFileInfo.ioVRefNum = vRefNum;
info.hFileInfo.ioFDirIndex = 0;
info.hFileInfo.ioACUser = 0;
info.hFileInfo.ioDirID = dirID;
info.hFileInfo.ioFlFndrInfo.fdType = fileType;
info.hFileInfo.ioFlFndrInfo.fdCreator = creator;
err = TPBSetCatInfo( thread, &info );
}
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
This function is unique in that it must be called at SystemTask time. I would *love*
to put a big fat WaitEventTask( thread, kPriority ) right after the requirement
checking. The wouldn't cost much and would ensure you wouldn't crash even if you
called this function at interrupt time. However that would completely tie this
package to the EventTasks package for one measly function. Here, I think maintaining
separation of the packages is more important than shielding the programmer from a
potential bug that should be avoided by reading this comment or caught in testing.
This function is really out of place here since you can't open the desktop database
asynchronously. Instead, this function is mostly a convenience routine for avoiding
parameter blocks. It's logic is ripped off from Jim Luther's DTOpen routine in
MoreFiles.
************************************************************************************/
OSErr
TDTOpen(
RedShedThread *thread, // ->
ConstStr255Param volName, // -> Can be nil if you set vRefNum.
short vRefNum, // -> Can be zero if you set volName.
short *dtRefNum, // <-
Boolean *newDTDatabase ) // <- Can be nil.
{
HParamBlockRec volPB;
GetVolParmsInfoBuffer volInfo;
DTPBRec deskPB;
OSErr err;
RequireRedShedThread( thread );
RequirePtrIf( vRefNum == 0, volName );
RequireIf( volName == nil, vRefNum != 0 );
Require( volName != nil || vRefNum != 0 );
RequirePtr( dtRefNum );
RequirePtrIfNotNil( &newDTDatabase );
volPB.ioParam.ioNamePtr = (StringPtr) volName;
volPB.ioParam.ioVRefNum = vRefNum;
volPB.ioParam.ioBuffer = (Ptr) &volInfo;
volPB.ioParam.ioReqCount = sizeof( volInfo );
err = PBHGetVolParmsSync( &volPB );
if( !err ) {
if( (volInfo.vMAttrib & (1L << bHasDesktopMgr)) != 0 ) {
// While PBDTOpenInform is documented as operating synchronously,
// I'm paranoid and am setting the callback to nil. I don't like the
// idea of a random address being in the ioCompletion field if and when
// PBDTOpenInform changes its implemention and decides to start calling
// completion routines.
deskPB.ioCompletion = nil;
deskPB.ioNamePtr = (StringPtr) volName;
deskPB.ioVRefNum = vRefNum;
err = PBDTOpenInform( &deskPB );
// Jim Luther says:
// "PBDTOpenInform informs us if the desktop was just created
// by leaving the low bit of ioTagInfo clear (0)"
if( newDTDatabase )
*newDTDatabase = ((deskPB.ioTagInfo & 1L) == 0);
if( err == paramErr ) {
err = PBDTGetPath( &deskPB );
// Jim Luther says:
// "PBDTGetPath doesn't tell us if the database is new
// so assume it is not new"
if( newDTDatabase )
*newDTDatabase = false;
}
*dtRefNum = deskPB.ioDTRefNum;
} else {
err = paramErr;
}
}
return( noErr );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
Concept and logic ripped off from Jim Luther's GetCatInfoNoName in MoreFiles.
************************************************************************************/
OSErr
TGetCatInfoNoName(
RedShedThread *thread, // ->
short vRefNum, // ->
long dirID, // ->
ConstStr255Param name, // -> Can be nil.
TCInfoPBPtr paramBlock ) // <-
{
Str31 tempName;
OSErr err;
RequireRedShedThread( thread );
RequirePtrIfNotNil( name );
RequirePtr( paramBlock );
// Jim says:
// "Protection against File Sharing problem";
if( (name == nil) || (name[ 0 ] == 0) ) {
tempName[ 0 ] = 0;
paramBlock->dirInfo.ioNamePtr = tempName;
paramBlock->dirInfo.ioFDirIndex = -1;
} else {
paramBlock->dirInfo.ioNamePtr = (StringPtr) name;
// Jim says:
// "use ioNamePtr and ioDirID"
paramBlock->dirInfo.ioFDirIndex = 0;
}
paramBlock->dirInfo.ioVRefNum = vRefNum;
paramBlock->dirInfo.ioDrDirID = dirID;
err = TPBGetCatInfo( thread, paramBlock );
paramBlock->dirInfo.ioNamePtr = nil;
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TFSpGetCatInfoNoName(
RedShedThread *thread, // ->
const FSSpec *spec, // ->
TCInfoPBPtr paramBlock ) // <-
{
RequireRedShedThread( thread );
RequirePtr( spec );
RequireFSSpec( spec );
RequirePtr( paramBlock );
return( TGetCatInfoNoName( thread, spec->vRefNum, spec->parID, spec->name, paramBlock ));
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TFSpSetCatInfo(
RedShedThread *thread, // ->
const FSSpec *spec, // ->
TCInfoPBPtr paramBlock ) // ->
{
RequireRedShedThread( thread );
RequirePtr( spec );
RequireFSSpec( spec );
RequirePtr( paramBlock );
paramBlock->dirInfo.ioNamePtr = (StringPtr) spec->name;
paramBlock->dirInfo.ioVRefNum = spec->vRefNum;
paramBlock->dirInfo.ioFDirIndex = 0;
paramBlock->dirInfo.ioACUser = 0;
paramBlock->dirInfo.ioDrDirID = spec->parID;
return( TPBSetCatInfo( thread, paramBlock ));
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TFSpOpenDF(
RedShedThread *thread, // ->
const FSSpec *spec, // ->
SInt8 permission, // ->
short *refNum ) // <-
{
THParamBlockRec pb;
OSErr err;
RequireRedShedThread( thread );
RequirePtr( spec );
RequireFSSpec( spec );
RequirePtr( refNum );
pb.fileParam.ioNamePtr = (StringPtr) spec->name;
pb.fileParam.ioVRefNum = spec->vRefNum;
pb.ioParam.ioPermssn = permission;
pb.fileParam.ioDirID = spec->parID;
err = TPBHOpenDF( thread, &pb );
*refNum = err ? 0: pb.ioParam.ioRefNum;
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TFSpOpenRF(
RedShedThread *thread, // ->
const FSSpec *spec, // ->
SInt8 permission, // ->
short *refNum ) // <-
{
THParamBlockRec pb;
OSErr err;
RequireRedShedThread( thread );
RequirePtr( spec );
RequireFSSpec( spec );
RequirePtr( refNum );
pb.fileParam.ioNamePtr = (StringPtr) spec->name;
pb.fileParam.ioVRefNum = spec->vRefNum;
pb.ioParam.ioPermssn = permission;
pb.fileParam.ioDirID = spec->parID;
err = TPBHOpenRF( thread, &pb );
*refNum = err ? 0: pb.ioParam.ioRefNum;
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TGetEOF(
RedShedThread *thread, // ->
short refNum, // ->
long *logEOF ) // <-
{
TParamBlockRec pb;
OSErr err;
RequireRedShedThread( thread );
RequireRefNum( refNum );
RequirePtr( logEOF );
pb.ioParam.ioRefNum = refNum;
err = TPBGetEOF( thread, &pb );
if( !err )
*logEOF = (long) pb.ioParam.ioMisc;
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TSetEOF(
RedShedThread *thread, // ->
short refNum, // ->
long logEOF ) // ->
{
TParamBlockRec pb;
RequireRedShedThread( thread );
RequireRefNum( refNum );
pb.ioParam.ioRefNum = refNum;
pb.ioParam.ioMisc = (Ptr) logEOF;
return( TPBSetEOF( thread, &pb ));
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TSetFPos(
RedShedThread *thread, // ->
short refNum, // ->
short posMode, // ->
long posOff ) // ->
{
TParamBlockRec pb;
RequireRedShedThread( thread );
RequireRefNum( refNum );
pb.ioParam.ioRefNum = refNum;
pb.ioParam.ioPosMode = posMode;
pb.ioParam.ioPosOffset = posOff;
return( TPBSetFPos( thread, &pb ));
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TFSRead(
RedShedThread *thread, // ->
short refNum, // ->
long *count, // <> in: bytes to read. out: bytes read.
void *buffPtr ) // <-
{
TParamBlockRec pb;
OSErr err;
RequireRedShedThread( thread );
RequireRefNum( refNum );
RequirePtr( count );
RequirePtr( buffPtr );
pb.ioParam.ioRefNum = refNum;
pb.ioParam.ioBuffer = (Ptr) buffPtr;
pb.ioParam.ioReqCount = *count;
pb.ioParam.ioPosMode = fsAtMark;
err = TPBRead( thread, &pb );
*count = pb.ioParam.ioActCount;
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TFSWrite(
RedShedThread *thread, // ->
short refNum, // ->
long *count, // <> in: bytes to write. out: bytes written.
const void *buffPtr ) // ->
{
TParamBlockRec pb;
OSErr err;
RequireRedShedThread( thread );
RequireRefNum( refNum );
RequirePtr( count );
RequirePtr( buffPtr );
pb.ioParam.ioRefNum = refNum;
pb.ioParam.ioBuffer = (Ptr) buffPtr;
pb.ioParam.ioReqCount = *count;
pb.ioParam.ioPosMode = fsAtMark;
err = TPBWrite( thread, &pb );
*count = pb.ioParam.ioActCount;
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TFSpSetFLock(
RedShedThread *thread, // ->
const FSSpec *spec ) // ->
{
THParamBlockRec pb;
RequireRedShedThread( thread );
RequirePtr( spec );
RequireFSSpec( spec );
// The source was locked, lock the destination.
pb.fileParam.ioNamePtr = (StringPtr) spec->name;
pb.fileParam.ioVRefNum = spec->vRefNum;
pb.fileParam.ioDirID = spec->parID;
return( TPBHSetFLock( thread, &pb ));
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TFSpGetComment(
RedShedThread *thread, // ->
const FSSpec *spec, // ->
short dtRefNum, // -> Desktop database refnum.
StringPtr comment ) // <- Must be a Str255.
{
TDTPBRec desk;
OSErr err;
RequireRedShedThread( thread );
RequirePtr( spec );
RequireFSSpec( spec );
RequireRefNum( dtRefNum );
RequirePtr( comment );
desk.ioNamePtr = (StringPtr) spec->name;
desk.ioVRefNum = spec->vRefNum;
desk.ioDTRefNum = dtRefNum;
desk.ioDTBuffer = (Ptr) comment + 1;
desk.ioDTReqCount = sizeof( Str255 ) - 1;
desk.ioDirID = spec->parID;
err = TPBDTGetComment( thread, &desk );
comment[ 0 ] = desk.ioDTActCount;
return( err );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Thu, Mar 8, 2001 Created.
************************************************************************************/
OSErr
TFSpSetComment(
RedShedThread *thread, // ->
const FSSpec *spec, // ->
short dtRefNum, // -> Desktop database refnum.
ConstStr255Param comment ) // ->
{
TDTPBRec desk;
RequireRedShedThread( thread );
RequirePtr( spec );
RequireFSSpec( spec );
RequireRefNum( dtRefNum );
RequirePtr( comment );
desk.ioNamePtr = (StringPtr) spec->name;
desk.ioVRefNum = spec->vRefNum;
desk.ioDTRefNum = dtRefNum;
desk.ioDTBuffer = (Ptr) comment + 1;
desk.ioDTReqCount = comment[ 0 ] > 200 ? 200 : comment[ 0 ];
desk.ioDirID = spec->parID;
return( TPBDTSetComment( thread, &desk ));
}
/****************************************************************************************
*
* Private
*
****************************************************************************************/
#pragma mark -
#pragma mark (Private)
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Mon, Mar 20, 2000 Created.
************************************************************************************/
pascal
void
ThreadedFileCompletion(
ParmBlkPtr paramBlock )
{
TPBHeader *header;
char *ptr;
long oldA5;
RequirePtr( paramBlock );
ptr = (char*) paramBlock; // Grab the pointer to the parameter block.
ptr -= sizeof( TPBHeader ); // Back it off by the size of the header.
header = (TPBHeader*) ptr; // Now we have a pointer to the header.
RequirePtr( header );
oldA5 = SwapA5( header->a5 );
RequireRedShedThread( header->thread );
PulseRedShedThread( header->thread );
RestoreA5( oldA5 );
}
/****************************************************************************************
Commenter Date Comment
--------- ----------------- -----------------------------------------------------
wolf Mon, Mar 20, 2000 Created.
************************************************************************************/
#if !TARGET_API_MAC_CARBON && !TARGET_RT_MAC_CFM
asm
void
ThreadedFileCompletionGlue()
{
movem.l a2-a6/d3-d7, -(a7) // Save registers.
move.l a0, -(a7) // Push parameter block.
jsr ThreadedFileCompletion // Call the real guy.
movem.l (a7)+, a2-a6/d3-d7 // Restore registers.
rts // We're outta here.
}
#endif
See more files for this project here