Ejemplo n.º 1
0
AsyncFile *
AS_OpenAsyncFH( BPTR handle, OpenModes mode, LONG bufferSize, BOOL closeIt )
#endif
{
	struct FileHandle	*fh;
	AsyncFile		*file = NULL;
	BPTR	lock = NULL;
	LONG	blockSize, blockSize2;
	D_S( struct InfoData, infoData );

	if( mode == MODE_READ )
	{
		if( handle )
		{
			lock = DupLockFromFH( handle );
		}
	}
	else
	{
		if( mode == MODE_APPEND )
		{
			/* in append mode, we open for writing, and then seek to the
			 * end of the file. That way, the initial write will happen at
			 * the end of the file, thus extending it
			 */

			if( handle )
			{
				if( Seek( handle, 0, OFFSET_END ) < 0 )
				{
					if( closeIt )
					{
						Close( handle );
					}

					handle = NULL;
				}
			}
		}

		/* we want a lock on the same device as where the file is. We can't
		 * use DupLockFromFH() for a write-mode file though. So we get sneaky
		 * and get a lock on the parent of the file
		 */
		if( handle )
		{
			lock = ParentOfFH( handle );
		}
	}

	if( handle )
	{
		/* if it was possible to obtain a lock on the same device as the
		 * file we're working on, get the block size of that device and
		 * round up our buffer size to be a multiple of the block size.
		 * This maximizes DMA efficiency.
		 */

		blockSize = 512;
		blockSize2 = 1024;

		if( lock )
		{
			if( Info( lock, infoData ) )
			{
				blockSize = infoData->id_BytesPerBlock;
				blockSize2 = blockSize * 2;
				bufferSize = ( ( bufferSize + blockSize2 - 1 ) / blockSize2 ) * blockSize2;
			}

			UnLock(lock);
		}

		/* now allocate the ASyncFile structure, as well as the read buffers.
		 * Add 15 bytes to the total size in order to allow for later
		 * quad-longword alignement of the buffers
		 */

		for( ;; )
		{
			if(( file = AllocVec( sizeof( AsyncFile ) + bufferSize + 15, MEMF_PUBLIC | MEMF_ANY ) ))
			{
				break;
			}
			else
			{
				if( bufferSize > blockSize2 )
				{
					bufferSize -= blockSize2;
				}
				else
				{
					break;
				}
			}
		}

		if( file )
		{
			file->af_File		= handle;
			file->af_ReadMode	= ( mode == MODE_READ );
			file->af_BlockSize	= blockSize;
			file->af_CloseFH	= closeIt;

			/* initialize the ASyncFile structure. We do as much as we can here,
			 * in order to avoid doing it in more critical sections
			 *
			 * Note how the two buffers used are quad-longword aligned. This
			 * helps performance on 68040 systems with copyback cache. Aligning
			 * the data avoids a nasty side-effect of the 040 caches on DMA.
			 * Not aligning the data causes the device driver to have to do
			 * some magic to avoid the cache problem. This magic will generally
			 * involve flushing the CPU caches. This is very costly on an 040.
			 * Aligning things avoids the need for magic, at the cost of at
			 * most 15 bytes of ram.
			 */

			fh			= BADDR( file->af_File );
			file->af_Handler	= fh->fh_Type;
			file->af_BufferSize	= ( ULONG ) bufferSize / 2;
			file->af_Buffers[ 0 ]	= ( APTR ) ( ( ( ULONG ) file + sizeof( AsyncFile ) + 15 ) & 0xfffffff0 );
			file->af_Buffers[ 1 ]	= file->af_Buffers[ 0 ] + file->af_BufferSize;
			file->af_CurrentBuf	= 0;
			file->af_SeekOffset	= 0;
			file->af_PacketPending	= FALSE;
			file->af_SeekPastEOF	= FALSE;
#ifdef ASIO_NOEXTERNALS
			file->af_SysBase	= SysBase;
			file->af_DOSBase	= DOSBase;
#endif

			/* this is the port used to get the packets we send out back.
			 * It is initialized to PA_IGNORE, which means that no signal is
			 * generated when a message comes in to the port. The signal bit
			 * number is initialized to SIGB_SINGLE, which is the special bit
			 * that can be used for one-shot signalling. The signal will never
			 * be set, since the port is of type PA_IGNORE. We'll change the
			 * type of the port later on to PA_SIGNAL whenever we need to wait
			 * for a message to come in.
			 *
			 * The trick used here avoids the need to allocate an extra signal
			 * bit for the port. It is quite efficient.
			 */

			file->af_PacketPort.mp_MsgList.lh_Head		= ( struct Node * ) &file->af_PacketPort.mp_MsgList.lh_Tail;
			file->af_PacketPort.mp_MsgList.lh_Tail		= NULL;
			file->af_PacketPort.mp_MsgList.lh_TailPred	= ( struct Node * ) &file->af_PacketPort.mp_MsgList.lh_Head;
			file->af_PacketPort.mp_Node.ln_Type		= NT_MSGPORT;
			/* MH: Avoid problems with SnoopDos */
			file->af_PacketPort.mp_Node.ln_Name		= NULL;
			file->af_PacketPort.mp_Flags			= PA_IGNORE;
			file->af_PacketPort.mp_SigBit			= SIGB_SINGLE;
			file->af_PacketPort.mp_SigTask			= FindTask( NULL );

			file->af_Packet.sp_Pkt.dp_Link			= &file->af_Packet.sp_Msg;
			file->af_Packet.sp_Pkt.dp_Arg1			= fh->fh_Arg1;
			file->af_Packet.sp_Pkt.dp_Arg3			= file->af_BufferSize;
			file->af_Packet.sp_Pkt.dp_Res1			= 0;
			file->af_Packet.sp_Pkt.dp_Res2			= 0;
			file->af_Packet.sp_Msg.mn_Node.ln_Name		= ( STRPTR ) &file->af_Packet.sp_Pkt;
			file->af_Packet.sp_Msg.mn_Node.ln_Type		= NT_MESSAGE;
			file->af_Packet.sp_Msg.mn_Length		= sizeof( struct StandardPacket );

			if( mode == MODE_READ )
			{
				/* if we are in read mode, send out the first read packet to
				 * the file system. While the application is getting ready to
				 * read data, the file system will happily fill in this buffer
				 * with DMA transfers, so that by the time the application
				 * needs the data, it will be in the buffer waiting
				 */

				file->af_Packet.sp_Pkt.dp_Type	= ACTION_READ;
				file->af_BytesLeft		= 0;

				/* MH: We set the offset to the buffer not being filled, in
				 * order to avoid special case code in SeekAsync. ReadAsync
				 * isn't affected by this, since af_BytesLeft == 0.
				 */
				file->af_Offset = file->af_Buffers[ 1 ];

				if( file->af_Handler )
				{
					AS_SendPacket( file, file->af_Buffers[ 0 ] );
				}
			}
			else
			{
				file->af_Packet.sp_Pkt.dp_Type	= ACTION_WRITE;
				file->af_BytesLeft		= file->af_BufferSize;
				file->af_Offset			= file->af_Buffers[ 0 ];
			}
		}
		else
		{
			if( closeIt )
			{
				Close( handle );
			}
		}
	}

	return( file );
}
Ejemplo n.º 2
0
	int fchdir(

/*  SYNOPSIS */
	int fd )

/*  FUNCTION
	Change the current working directory to the directory given as an open
	file descriptor.

    INPUTS
        fd - File descriptor of the directory to change to.
	
    RESULT
	If the current directory was changed successfully, zero is returned.	
    	Otherwise, -1 is returned and errno set apropriately.
	
    NOTES
    	At program exit, the current working directory will be changed back
	to the one that was current when the program first started. If you
	do not desire this behaviour, use dos.library/CurrentDir() instead.

    EXAMPLE

    BUGS

    SEE ALSO

    INTERNALS

******************************************************************************/
{
    BPTR oldlock = NULL;
    BPTR newlock = NULL;
    BPTR handle = NULL;
    
    if ( __get_default_file(fd, (long*) &handle) != 0 )
    {
    	errno = EBADF;
        goto error;    
    }

    newlock = DupLockFromFH(handle);

    if( newlock == NULL )
    {
        errno = IoErr2errno( IoErr() );
        goto error;
    }
    oldlock = CurrentDir( newlock ); 

    if( __startup_cd_changed )
    {
    	UnLock( oldlock );
    }
    else
    {
    	__startup_cd_changed = TRUE;
	__startup_cd_lock    = oldlock;
    }       
    return 0;

error:
    if( newlock != NULL ) 
        UnLock( newlock );
    
    return -1;
}
Ejemplo n.º 3
0
int __stat(BPTR lock, struct stat *sb, BOOL filehandle)
{
    struct FileInfoBlock *fib;
    UBYTE *buffer;
    int buffersize = 256;
    int fallback_to_defaults = 0;
    BOOL Examined;

    fib = AllocDosObject(DOS_FIB, NULL);

    if (!fib)
    {
        errno = __stdc_ioerr2errno(IoErr());

        return -1;
    }

    Examined = filehandle
             ? ExamineFH(lock, fib)
             : Examine(lock, fib);
    if (!Examined)
    {
	if(IoErr() == ERROR_NOT_IMPLEMENTED ||
	   IoErr() == ERROR_ACTION_NOT_KNOWN)
	{
	    fallback_to_defaults = 1;
	}
	else
	{
            errno = __stdc_ioerr2errno(IoErr());
            FreeDosObject(DOS_FIB, fib);
            return -1;
	}
    }

    /* Get the full path of the stated filesystem object and use it to
       compute hash value */
    do
    {
        BOOL GotName;

        if(!(buffer = AllocVec(buffersize, MEMF_ANY)))
        {
            errno = ENOMEM;
            FreeDosObject(DOS_FIB, fib);
            return -1;
        }

        GotName = filehandle
                ? NameFromFH(lock, buffer, buffersize)
                : NameFromLock(lock, buffer, buffersize);
        if(GotName)
            break;
        else if(   IoErr() == ERROR_OBJECT_IN_USE
                || IoErr() == ERROR_NOT_IMPLEMENTED
                || IoErr() == ERROR_ACTION_NOT_KNOWN
                || (IoErr() == ERROR_OBJECT_NOT_FOUND && fib->fib_EntryType == ST_PIPEFILE))
        {
            /* We can't retrieve name because lock is an exclusive lock
               or Examine is not implemented in this handler
               or the lock refers to an XPIPE: file having always empty name */
            buffer[0] = '\0';
            break;
        }
        else if(IoErr() != ERROR_LINE_TOO_LONG)
        {
            errno = __stdc_ioerr2errno(IoErr());
            FreeDosObject(DOS_FIB, fib);
            FreeVec(buffer);
            return -1;
        }
        FreeVec(buffer);
        buffersize *= 2;
    }
    while(TRUE);

    // We need a FileLock. Otherwise a call of Info() within __fill_statbuffer() will crash
    // FIXME: how can we get a lock on an exclusive file?
    if (filehandle)
    {
        BPTR filelock = DupLockFromFH(lock);
        __fill_statbuffer(sb, (char*) buffer, fib, fallback_to_defaults, filelock);
        UnLock(filelock);
    }
    else
    {
        __fill_statbuffer(sb, (char*) buffer, fib, fallback_to_defaults, lock);
    }

    FreeVec(buffer);
    FreeDosObject(DOS_FIB, fib);

    return 0;
}
Ejemplo n.º 4
0
/*
 * rpipe() - gets a `cmd' to run and a `file descriptor' to use as its stdin.
 */
int
rpipe(UBYTE * cmd, int fd)
{
    BPTR         fdFH = 0,	/* FileHandle of passed file descriptor */
                 outPH = 0,	/* Pipe (File) Handle for child to write to. */
                 inPH = 0,	/* Pipe (File) Handle for child to read from. */
                 lock = 0;
    int          fdr = 0;
    char         pname[32], *pc;
    extern char  o_shell[];

    if (isOldDOS())
	return -1;

    /*-
     * Sorry, I'm playing with an AZTEC internal here:
     * _devtab[fd].fd is Aztec's FileHandle for the file descriptor `fd'.
     * 
     * HINT: For your compiler, look in your compiler's fcntl.h.
     */

    switch (fd)
    {
    case 0:
	inPH = Open((UBYTE *) "*", MODE_READWRITE);
	break;
    default:

#ifdef	AZTEC_C
	fdFH = _devtab[fd].fd;		/* Grab FileHandle from fd */
#elif	_DCC
	fdFH = fdtofh(fd);		/* DCC does it right! */
#else
	return -1;			/* Sorry, can't help you. */
#endif

	/*
	 * Get a FileHandle to use for the child's stdin.
	 * The only reason we Dup is because we'll run the child ASynch,
	 * and it will close its Input and Output on exit.
	 */
	lock = DupLockFromFH(fdFH);
	if (!lock)
	    return -1;
	inPH = OpenFromLock(lock);
    }

    if (!inPH)
    {
	if (lock)
	    UnLock(lock);
	return -1;
    }

    /*
     * Get a pipe to use for the child's stdout, which we will read from.
     */
    strcpy(pname, "PIPE:ElvisXXX.XXX");
    pc = mktemp(pname);			/* Get a unique PIPE: */
    if (!*pc)
    {
    	Close(inPH);
	return -1;			/* Failure. */
    }

    /*
     * Get a FileHandle to use for the child's stdout.
     */
    if ((BPTR) 0 == (outPH = Open((UBYTE *) pc, MODE_NEWFILE)))
    {
	Close(inPH);
	return -1;			/* Failure. */
    }

    /* Get a file descriptor to return to the calling function */
    if ((fdr = open(pc, O_RDONLY)) < 0)
    {
	Close(inPH);
	Close(outPH);
	return -1;			/* Failure. */
    }

    /* exec the cmd */
    systags[0].ti_Data = inPH;		/* Input FileHandle for child */
    systags[1].ti_Data = outPH;		/* Output FileHandle for child */
    systags[2].ti_Data = (long) o_shell;/* which shell to use */

    if (System((UBYTE *) cmd, systags))
    {
	close(fdr);
	return -1;			/* Failure. */
    }

    return fdr;				/* Success! */
}