Code Search for Developers
 
 
  

ThreadedFile.c from redshed at Krugle


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) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->ioParam );
	BlockRedShedThread( thread );
		
	if( paramBlock->ioParam.ioResult == paramErr ) {
		//	OpenDF not supported, try Open.
		ReadyRedShedThread( thread );
		PBHOpenAsync( (HParmBlkPtr) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->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) &paramBlock->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

redshed

Code for Mac+WebObjects.

Project homepage: http://sourceforge.net/projects/redshed
Programming language(s): C,Java,Objective C
License: other

  CFMA5.h
  ThreadedFile.c
  ThreadedFile.h
  ThreadedOT.c
  ThreadedOT.h
  WaitRedShedThread.c
  WaitRedShedThread.h