home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.6
/
ffcollection-1-6-1993-02.iso
/
ff_disks
/
061-090
/
ff_084.lha
/
PipeHandler
/
pipecreate.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-06-28
|
14KB
|
487 lines
/****************************************************************************
** File: pipecreate.c
** Program: pipe-handler - an AmigaDOS handler for named pipes
** Version: 1.1
** Author: Ed Puckett qix@mit-oz
**
** Copyright 1987 by EpAc Software. All Rights Reserved.
**
** History: 05-Jan-87 Original Version (1.0)
** 07-Feb-87 Added lock initialization to OpenPipe()
** for locks on individual pipes.
** 12-Feb-87 Fixed bug in OpenPipe(): previously ignored
** lock passed in packet. Bug uncovered when
** pipes became lockable, and thus assignable.
** 26-Mar-87 Fixed bug in ClosePipe(): not closing r/w
** mode properly (extraneous else).
*/
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <libraries/filehandler.h>
#include <exec/exec.h>
#include "pipelists.h"
#include "pipename.h"
#include "pipebuf.h"
#include "pipecreate.h"
#include "pipesched.h"
#include "pipe-handler.h"
#if PIPEDIR
# include "pipedir.h"
#endif PIPEDIR
#ifdef DEBUG
# include "pipedebug.h"
#endif DEBUG
/*---------------------------------------------------------------------------
** pipecreate.c
** ------------
** This module handles opens and closes for pipes.
**
** Visible Functions
** -----------------
** void OpenPipe (pkt, tapfh)
** void ClosePipe (pkt)
** void DiscardPipe (pipe)
**
** Macros (in pipecreate.h)
** ------------------------
** - none -
**
** Local Functions
** ---------------
** int TapFormsLoop (tapfh, pipe)
** void OpenTap (pkt, tapname)
** void CloseTap (tapfh)
*/
/*---------------------------------------------------------------------------
** OpenPipe() handles open requests. The DosPacket from the client and the
** filehandle of the tap are sent. If tapfh is 0, but the name sent
** indicates a tap is desired (see ParsePipeName() in pipename.c), then
** an OpenTap() request is initiated and OpenPipe() is immediately exited.
** Later, when the request returns (to HandleTapReply()), OpenPipe() is
** called again with the same client packet and the newly returned tapfh.
** If tapfh is nonzero, or if it is zero but no tap is desired, then
** the an attempt to open the pipe is made. If a existent pipe with a tap is
** to be opened and a new tapfh is given, the old tap is closed.
** If the name's syntax is incorrect, then the request is returned
** unsuccessful. Otherwise, if the pipe named by the request does not
** already exist, a new pipe is created (if there is enough memory).
** If it does exist, but it is already open for the mode requested, an error
** is returned (a maximum of one reader and one writer is allowed).
** A successful open returns the client's filehandle with its Arg1 field
** pointing to a PIPEKEY, which in turn identifies the pipe and open mode.
** Unless an OpenTap() is required, the packet is returned to the cleint
** by this function. If an OpenTap() is required, it will be returned by the
** the later call to this function when the tap open request is returned.
** Note: the code which checks if the lock sent in the packet relies on
** the fact that the pipe-handler does not allow subdirectories. If a lock
** on a pipe is passed in, then that pipe is opened. Otherwise, the name is
** parsed without reference to the lock.
*/
void OpenPipe (pkt, tapfh)
struct DosPacket *pkt;
BPTR tapfh;
{ void OpenTap(), CloseTap();
LONG openmode;
struct FileHandle *handle;
struct FileLock *lock;
char *pipename = NULL, *tapname = NULL;
ULONG pipesize;
PIPEKEY *pipekey = NULL;
PIPEDATA *pipe;
int TapFormsLoop();
pkt->dp_Res1= 0; /* error, for now */
if (! ParsePipeName (BPTRtoCptr (pkt->dp_Arg3), &pipename, &pipesize, &tapname))
{ pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
goto OPENREPLY;
}
if ( (tapfh == 0) && (tapname != NULL) && (tapname[0] != '\0') )
{ OpenTap (pkt, tapname); /* start tap open request */
return; /* HandleTapReply() re-calls when request returns */
}
openmode= pkt->dp_Type;
lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg2);
pipe= NULL;
if ( (lock == NULL) || ((pipe= (PIPEDATA *) lock->fl_Key) == NULL) )
{ if (pipename[0] == '\0')
#if AUTONAME
pipename= get_autoname ((openmode == MODE_NEWFILE) || (openmode == MODE_READWRITE));
#else !AUTONAME
{ pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
goto OPENREPLY;
}
#endif AUTONAME
pipe= FindPipe (pipename);
}
else /* packet's lock was on the pipe */
{ if (pipename[0] != '\0')
{ pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
goto OPENREPLY;
}
pipename= pipe->name;
}
handle= (struct FileHandle *) BPTRtoCptr (pkt->dp_Arg1);
if ((pipekey= (PIPEKEY *) AllocMem (sizeof (PIPEKEY), ALLOCMEM_FLAGS)) == NULL)
{ pkt->dp_Res2= ERROR_NO_FREE_STORE;
goto OPENREPLY;
}
if (pipe == NULL) /* then PIPE NOT FOUND */
{ if (openmode == MODE_READONLY)
{ pkt->dp_Res2= ERROR_OBJECT_NOT_FOUND;
goto OPENREPLY;
}
pkt->dp_Res2= ERROR_NO_FREE_STORE; /* in case of AllocMem error */
if ((pipe= (PIPEDATA *) AllocMem (sizeof (PIPEDATA), ALLOCMEM_FLAGS)) == NULL)
goto OPENMEMERR1;
if ((pipe->buf= AllocPipebuf (pipesize)) == NULL)
goto OPENMEMERR2;
if ((pipe->lock= (struct FileLock *) AllocMem (sizeof (struct FileLock), ALLOCMEM_FLAGS)) == NULL)
{ FreePipebuf (pipe->buf);
OPENMEMERR2:
FreeMem (pipe, sizeof (PIPEDATA));
OPENMEMERR1:
goto OPENREPLY;
}
l_strcpy (pipe->name, pipename);
pipekey->pipe= pipe;
pipekey->openmode= openmode;
if (openmode == MODE_READONLY)
{ pipekey->iotype= PIPEREAD;
pipe->flags |= OPEN_FOR_READ;
}
else if (openmode == MODE_NEWFILE)
{ pipekey->iotype= PIPEWRITE;
pipe->flags= OPEN_FOR_WRITE;
}
else /* MODE_READWRITE */
{ pipekey->iotype= PIPERW;
pipe->flags= (OPEN_FOR_READ | OPEN_FOR_WRITE);
}
InitList (&pipe->readerlist);
InitList (&pipe->writerlist);
pipe->tapfh= tapfh;
#if PIPEDIR
pipe->lockct= 0;
InitLock (pipe->lock, pipe);
#endif PIPEDIR
InsertTail (&pipelist, pipe); /* at tail for directory's sake */
#ifdef DEBUG
OS ("*** created pipe '"); OS (pipe->name);
OS ("' [buflen "); OL (pipe->buf->len); OS ("]\n");
#endif DEBUG
}
else /* PIPE WAS FOUND */
{ if (TapFormsLoop (tapfh, pipe))
{ pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
goto OPENREPLY;
}
pipekey->pipe= pipe;
pipekey->openmode= openmode;
pkt->dp_Res2= ERROR_OBJECT_IN_USE; /* in case of openmode error */
if (openmode == MODE_READONLY)
{ if (pipe->flags & OPEN_FOR_READ)
goto OPENREPLY;
pipekey->iotype= PIPEREAD;
pipe->flags |= OPEN_FOR_READ;
}
else if (openmode == MODE_NEWFILE)
{ if (pipe->flags & OPEN_FOR_WRITE)
goto OPENREPLY;
pipekey->iotype= PIPEWRITE;
pipe->flags |= OPEN_FOR_WRITE;
}
else /* MODE_READWRITE */
{ if (pipe->flags & (OPEN_FOR_READ | OPEN_FOR_WRITE))
goto OPENREPLY;
pipekey->iotype= PIPERW;
pipe->flags= (OPEN_FOR_READ | OPEN_FOR_WRITE);
}
if (tapfh != 0)
{ if (pipe->tapfh != 0)
CloseTap (pipe->tapfh); /* close old tap first */
pipe->tapfh= tapfh;
}
}
handle->fh_Arg1= (LONG) pipekey; /* for identification on Read, Write, Close */
pkt->dp_Res1= 1;
pkt->dp_Res2= 0; /* for successful open */
OPENREPLY:
if (pkt->dp_Res1 == 0) /* then there was an error */
{ if (pipekey != NULL)
FreeMem (pipekey, sizeof (PIPEKEY));
if (tapfh != 0)
CloseTap (tapfh);
}
#if PIPEDIR
else
SetPipeDate (pipe);
#endif PIPEDIR
ReplyPkt (pkt);
}
/*---------------------------------------------------------------------------
** This routine checks for "the old loop in the pipe trick" (86). If the
** handler has a loop through its tap, the handler will endlessly pass
** packets to itself. This would be disastrous if the handler is running at
** high priority.
*/
static int TapFormsLoop (tapfh, pipe)
BPTR tapfh;
PIPEDATA *pipe;
{ struct FileHandle *handle;
PIPEKEY *tapkey;
PIPEDATA *tappipe;
int numchecks; /* protection */
for (numchecks= 0; ((tapfh != 0) && (numchecks < 10000)); ++numchecks)
{ handle= (struct FileHandle *) BPTRtoCptr (tapfh);
if (handle->fh_Type == PipePort) /* then the tap is a pipe, too */
{ if ( ((tapkey= (PIPEKEY *) handle->fh_Arg1) == NULL) ||
((tappipe= tapkey->pipe) == NULL) )
return FALSE;
if (tappipe == pipe)
return TRUE;
tapfh= tappipe->tapfh;
}
else
return FALSE;
}
return FALSE;
}
/*---------------------------------------------------------------------------
** The previous open performed on a pipe is terminated. The PIPEKEY
** allocated for the client when the pipe was opened is freed. Then,
** CheckWaiting() is called -- it will discard the pipe if it becomes empty
** and is not opened for read or write.
*/
void ClosePipe (pkt)
struct DosPacket *pkt;
{ PIPEKEY *pipekey;
PIPEDATA *pipe;
void DeletePipe();
pipekey= (PIPEKEY *) pkt->dp_Arg1;
pipe= pipekey->pipe;
if ((pipekey->iotype == PIPEREAD) || (pipekey->iotype == PIPERW))
pipe->flags &= ~OPEN_FOR_READ;
if ((pipekey->iotype == PIPEWRITE) || (pipekey->iotype == PIPERW))
pipe->flags &= ~OPEN_FOR_WRITE;
FreeMem (pipekey, sizeof (PIPEKEY));
CheckWaiting (pipe); /* will discard if empty */
pkt->dp_Res1= 1;
pkt->dp_Res2= 0;
ReplyPkt (pkt);
}
/*---------------------------------------------------------------------------
** Remove a pipe from the pipe list and release its memory. The pipe is
** assumed empty and having no clients.
*/
void DiscardPipe (pipe)
PIPEDATA *pipe;
{
#ifdef DEBUG
OS ("*** discarding pipe '"); OS (pipe->name); OS ("'\n");
#endif DEBUG
Delete (&pipelist, pipe);
FreePipebuf (pipe->buf);
FreeMem (pipe->lock, sizeof (struct FileLock));
if (pipe->tapfh != 0)
CloseTap (pipe->tapfh);
FreeMem (pipe, sizeof (PIPEDATA));
}
/*---------------------------------------------------------------------------
** An open request for a tap is performed. A WAITINGDATA structure is
** allocated to hold the client packet until later. HandleTapReply() will
** deal with the reply and, if successful, re-call OpenPipe().
*/
static void OpenTap (pkt, tapname)
struct DosPacket *pkt;
char *tapname;
{ char *Bname;
struct FileHandle *handle;
WAITINGDATA *wd;
struct DosPacket *tappkt;
struct MsgPort *Handler;
struct FileLock *Lock;
void StartTapIO();
if ( (tapname == NULL) ||
((Bname= (char *) AllocMem (OPENTAP_STRSIZE, ALLOCMEM_FLAGS)) == NULL) )
goto OPENTAPERR;
if ((handle= (struct FileHandle *) AllocMem (sizeof (struct FileHandle), (ALLOCMEM_FLAGS | MEMF_CLEAR))) == NULL)
goto OPENTAPERR1;
if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL)
goto OPENTAPERR2;
if ((tappkt= AllocPacket (TapReplyPort)) == NULL)
goto OPENTAPERR3;
if ((Handler= DeviceProc (tapname)) == NULL)
{ FreePacket (tappkt);
OPENTAPERR3:
FreeMem (wd, sizeof (WAITINGDATA));
OPENTAPERR2:
FreeMem (handle, sizeof (struct FileHandle));
OPENTAPERR1:
FreeMem (Bname, OPENTAP_STRSIZE);
OPENTAPERR:
pkt->dp_Res1= 0;
pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
ReplyPkt (pkt);
return;
}
Lock= (struct FileLock *) IoErr ();
CstrtoBSTR (tapname, Bname, OPENTAP_STRSIZE);
handle->fh_Pos= -1;
handle->fh_End= -1;
handle->fh_Type= Handler; /* initialize file handle */
wd->pkt= tappkt;
wd->pktinfo.tapwait.clientpkt= pkt;
wd->pktinfo.tapwait.handle= handle; /* for HandleTapReply() */
StartTapIO ( tappkt, MODE_NEWFILE,
CptrtoBPTR (handle), CptrtoBPTR (Lock), CptrtoBPTR (Bname),
Handler );
InsertHead (&tapwaitlist, wd);
}
/*---------------------------------------------------------------------------
** A close request for a tap filehandle is initiated. When HandleTapReply()
** gets the reply, it merely discards it.
*/
static void CloseTap (tapfh)
BPTR tapfh;
{ struct FileHandle *taphandle;
struct DosPacket *tappkt;
WAITINGDATA *wd;
void StartTapIO();
taphandle= (struct FileHandle *) BPTRtoCptr (tapfh);
if ((tappkt= AllocPacket (TapReplyPort)) == NULL)
goto CLOSETAPERR;
if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL)
{ FreePacket (tappkt);
CLOSETAPERR:
FreeMem (taphandle, sizeof (struct FileHandle));
#ifdef DEBUG
OS ("!!! ERROR - CloseTap() failed\n");
#endif DEBUG
return;
}
wd->pkt= tappkt;
/* don't need ...tapwait.clientpkt */
wd->pktinfo.tapwait.handle= taphandle; /* for HandleTapReply() */
StartTapIO ( tappkt, ACTION_END,
taphandle->fh_Arg1, 0, 0,
taphandle->fh_Type );
InsertHead (&tapwaitlist, wd);
}