Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP
Path: utzoo!mnetor!seismo!ut-sally!husc6!think!ames!ptsfa!ihnp4!inuxc!iuvax!pur-ee!j.cc.purdue.edu!h.cc.purdue.edu!s.cc.purdue.edu!qix
From: qix@ihlpa.UUCP (Ed Puckett)
Newsgroups: comp.sources.amiga
Subject: P: a pipe-handler (shar 1 of 2)
Message-ID: <465@s.cc.purdue.edu>
Date: Wed, 8-Jul-87 02:50:46 EDT
Article-I.D.: s.465
Posted: Wed Jul 8 02:50:46 1987
Date-Received: Sat, 11-Jul-87 06:03:14 EDT
Sender: doc@s.cc.purdue.edu
Reply-To: doc@s.cc.purdue.edu (Craig Norborg)
Distribution: world
Organization: Purdue University Computing Center
Lines: 1888
Approved: doc@s.cc.purdue.edu
Here is part 1 of 2 of the source to Ed Puckett's pipe handler.
This is the latest version including the bug fix he posted to the net.
Binaries available in comp.binaries.amiga.
# This is a shell archive.
# Remove everything above and including the cut line.
# Then run the rest of the file through sh.
#----cut here-----cut here-----cut here-----cut here----#
#!/bin/sh
# Xshar: Extended Shell Archiver.
# This is part 1 out of 2.
# This archive created: Wed Jul 8 01:44:10 1987
# By: Craig Norborg (Purdue University Computing Center)
# Run the following text with /bin/sh to create:
# Makefile
# README
# cc
# loader.asm
# pipe-handler.c
# pipebuf.c
# pipecreate.h
# pipedebug.c
# pipedebug.h
# pipedir.c
# pipesched.h
# prelude_Mount
cat << \SHAR_EOF > Makefile
# remove the -DDEBUG from CFLAGS if not debugging
CFLAGS =
# -DDEBUG
# set the DEBUG variables to null strings if not debugging
DEBUG_H =
# pipedebug.h
DEBUG_O =
# pipedebug.o
PIPEHDR = pipe-handler.h pipelists.h pipename.h pipebuf.h \
pipecreate.h pipesched.h pipedir.h
OBJ = pipe-handler.o pipelists.o pipename.o pipebuf.o \
pipecreate.o pipesched.o pipedir.o
mount : loader_mount
handler : loader_pipe-handler
obj : $(OBJ) $(DEBUG_O)
prelude_mount : prelude_pipe-handler
Copy prelude_pipe-handler L:pipe-handler
Copy prelude_Mount DEVS:Mountlist
Mount P:
loader_mount : loader loader_pipe-handler
Copy pipe-handler-loader L:
Copy loader_pipe-handler L:pipe-handler
Copy loader_Mount DEVS:Mountlist
Mount P:
prelude_pipe-handler : prelude.o $(OBJ) $(DEBUG_O)
BLink FROM prelude.o $(OBJ) $(DEBUG_O) \
TO prelude_pipe-handler \
LIBRARY CLIB:lc.lib CLIB:amiga.lib
loader_pipe-handler : $(OBJ) $(DEBUG_O)
BLink FROM $(OBJ) $(DEBUG_O) \
TO loader_pipe-handler \
LIBRARY CLIB:lc.lib CLIB:amiga.lib
prelude : prelude.o
prelude.o : prelude.asm
Assem prelude -o prelude.o
loader : loader.o
BLink FROM loader.o TO pipe-handler-loader
loader.o : loader.asm
Assem loader.asm -i :include -o loader.o -c w100000
pipedebug.o : pipedebug.h pipedebug.c
EXECUTE cc pipedebug $(CFLAGS)
pipe-handler.o : $(PIPEHDR) pipe-handler.c $(DEBUG_H)
EXECUTE cc pipe-handler $(CFLAGS)
pipelists.o : pipelists.h pipelists.c
EXECUTE cc pipelists $(CFLAGS)
pipename.o : pipe-handler.h pipelists.h pipename.h pipebuf.h
pipename.o : pipecreate.h pipesched.h
pipename.o : pipename.c
EXECUTE cc pipename $(CFLAGS)
pipebuf.o : pipe-handler.h pipelists.h pipename.h pipebuf.h
pipebuf.o : pipecreate.h pipesched.h
pipebuf.o : pipebuf.c
EXECUTE cc pipebuf $(CFLAGS)
pipecreate.o : $(PIPEHDR) pipecreate.c $(DEBUG_H)
EXECUTE cc pipecreate $(CFLAGS)
pipesched.o : $(PIPEHDR) pipesched.c $(DEBUG_H)
EXECUTE cc pipesched $(CFLAGS)
pipedir.o : $(PIPEHDR) pipedir.c
EXECUTE cc pipedir $(CFLAGS)
SHAR_EOF
cat << \SHAR_EOF > README
README file for pipe-handler (version 1.2 13-Jun-87)
====================================================
This program and source are freely distributable, provided the file headers
remain intact (i.e., my name is on them!!!).
Ed Puckett accepts no responsibility for others' use of this program.
...but you shouldn't have any problems!
WHAT IS THIS?
-------------
Pipe-handler is an AmigaDOS device. It supports OPEN, CLOSE, READ and
WRITE (of course), and also LOCK, EXAMINE, EXNEXT. Therefore, you can
CD to the handler, use Dir and List on it, and ASSIGN to it as well as
to individual pipes in it. Here is a complete list of the packet
types it supports:
MODE_READWRITE
ACTION_FINDINPUT (syn: MODE_READONLY, MODE_OLDFILE)
ACTION_FINDOUTPUT (syn: MODE_NEWFILE)
ACTION_END
ACTION_READ
ACTION_WRITE
ACTION_LOCATE_OBJECT
ACTION_COPY_DIR
ACTION_FREE_LOCK
ACTION_EXAMINE_OBJECT
ACTION_EXAMINE_NEXT
ACTION_PARENT
You cannot Seek() pipes nor can you create pipe subdirectories.
INSTALLATION
------------
1. Perform the following:
Copy pipe-handler-l L:pipe-handler-loader
Copy pipe-handler L:pipe-handler
2. Add to S:Startup-Sequence (do not include !'s - they denote start of line):
!Mount P:
!Dir >NIL: P:
3. Add to DEVS:Mountlist (do not include !'s - they denote start of line):
!P: Handler = L:pipe-handler-loader
! Stacksize = 3000
! Priority = 5
!#
4. Reboot
NOTES ON INSTALLATION
---------------------
* The handler, once installed, requires approximately 18k of memory. This
memory cannot be reclaimed (unless you reboot and do not load the handler).
Each pipe requires additional memory while it exists (its buffer size +
about 100 bytes or so).
* You can skip the reboot, and just perform the "Mount" and "Dir" from the
startup-sequence manually.
* After the "Dir", the pipe-handler is loaded into the system, and the files
"L:pipe-handler-loader" and "L:pipe-handler" will not be accessed until the
next reboot. This means you may remove them from L: if you want (until
next reboot). I do this because I copy L: into Ram:.
* TO CHANGE THE HANDLER NAME: change "P:" to whatever you want (e.g., "PIPE:")
in the following 2 files:
DEVS:Mountlist (1 occurrence)
S:Startup-Sequence (2 occurrences)
* Feel free to shorten or otherwise change the names "pipe-handler-loader"
and "pipe-handler". Just be sure to reflect those changes in
"S:Startup-Sequence" and "DEVS:Mountlist".
TAPS
----
The handler also supports "taps". These are essentially tees off of the
pipe, and can specify any destination to which a copy of the pipe's stream
is to be sent. One interesting application of this is tapping to a
CON: window; you can then see what is going through the pipe, and you
can also stop pipe throughput by typing a character into this window.
Taps can also be other pipes.
For an interesting demo of taps, EXECUTE the file "tap_demo".
All pipe I/O is asynchronous, so you will not be able to lock up the
handler by stopping one of its pipes. A single reader / single writer
discipline in enforced.
Pipe buffers are dynamically allocated. A pipe is removed from memory
when all openers have closed it and it is empty. The size of a pipe buffer
may be specified as part of its name. Otherwise, pipe buffers have a default
size of 4096 bytes.
Pipes behave in most respects like ordinary files. Some differences follow:
Pipes block for writing (i.e., the write request is suspended) when the
pipe's buffer is full, and block for reading when the pipe's buffer is
empty. Thus, pipes are sort of like bounded ram: files. EOF is returned
for reading when the pipe's buffer is empty and no process has the pipe
open for writing.
NAME SYNTAX
-----------
In addition to the pipe's identifier, its name can specify its size
and a tap. The syntax is
name[/size][/[tapname]]
where the parts enclosed in "[]" are optional. The size must begin with
a digit in the range 0-9. If first digit is not "0", the size is
interpreted as decimal. If the size begins with "0x", it is interpreted
as hexadecimal. Otherwise, if the size begins with "0" but not "0x", it
is interpreted as octal.
If an empty tapname is specified, the default tap CON:10/15/300/70/name
is used (where "name" is the pipe's name given).
EXAMPLES OF PIPE NAMES
----------------------
The following assume that the pipe-handler is mounted as device P:
P:x Opens a pipe named "x" with buffer size 4096
P:x/100 Opens a pipe named "x" with buffer size 100
P:hold/ Opens a pipe named "hold" with buffer size
4096, and also opens a window which displays
the data which passes through the pipe.
P:xyzzy/plugh Opens a pipe named "xyzzy" with buffer size
4096, and also directs the data passing
through into the file "plugh". (Note that
taps may be specified without specifying
a size.)
P:thru/0x40/ram:thru-log Opens a pipe named "thru" with buffer size
64 (decimal), and also directs the data
passing through the pipe into the file
"ram:thru-log".
WHAT IS THIS SILLY "LOADER" FILE?
---------------------------------
According to _The_AmigaDOS_Manual_ (Bantam Books, Feb 1986), page 291:
If you write your device handler in C, you cannot use the automatic
load and process creation provided by the kernel. In this case you
must load the code yourself . . . .
Well, I know others have gotten around this, and I did, too. The "prelude"
version of the handler (see the Makefile) does it all with one file.
However, I noticed that doing it this way, the handler would take about
3 seconds to "Mount" (after first access to it). This made me very nervous -
visions of wild linking through memory, etc. The loader version mounts
almost immediately.
Anyway, due to my (possibly unfounded) paranoia, I instead use the BCPL-like
assembly module "pipe-handler-loader" which LoadSeg()'s pipe-handler. There
are undoubtedly better ways of handling this, but this works and, for me,
it is not too annoying to put up with the extra file.
COMPILATION
-----------
The supplied C source files were compiled with Lattice v3.03.
The assembly programs were assembled using the Commodore Assembler.
See the Makefile for information on creating a debugging version
(this puts up a window and tells you what packets are received by
the handler - fun!). Basically, you just compile with a -DDEBUG
option and link in the debugging modules.
The Makefile will make either a "prelude" version (no "loader file)
or a "loader" version (the default).
I use an EXECUTE file "cc" to driver the compiler. It is supplied.
INQUIRIES / COMMENTS / SUGGESTIONS
----------------------------------
Ed Puckett
US Mail: MIT Branch PO - PO Box 61
Cambridge, MA 02139
E Mail: ...!ihnp4!mit-eddie!mit-oz!qix
SHAR_EOF
cat << \SHAR_EOF > cc
.KEY xxx_file,opt1,opt2,opt3
; Compile a C program Version 4.00
; Works with Lattice version 3.03 and above
IF NOT EXISTS .c
ECHO "File .c does not exist."
SKIP END
ENDIF
ECHO "-- compiling....c"
IF NOT EXISTS "Ram:cctempdir"
MAKEDIR Ram:cctempdir
ENDIF
:c/LC1 -oRam:cctempdir/cctemp.q -i:include/ -i:include/lattice/
IF NOT EXISTS "Ram:cctempdir/cctemp.q"
ECHO "Compile failed."
QUIT 20
ENDIF
:c/LC2 -v -o.o Ram:cctempdir/cctemp
DELETE Ram:cctempdir all
ECHO "-- done compiling ''. --"
LAB END
SHAR_EOF
cat << \SHAR_EOF > loader.asm
; loader.asm
INCLUDE "exec/types.i"
INCLUDE "exec/exec.i"
INCLUDE "libraries/dosextens.i"
INCLUDE "libraries/amiga._LVO.i"
STRUCTURE STACKDATA,0
APTR Packet
LONG ReturnVal
APTR DOSBase
BPTR Segment
BYTE STACKDATA_SIZE
LINKEXE: MACRO
MOVEA.L _AbsExecBase,A6
JSR _LVO\1(A6)
ENDM
LINKDOS: MACRO
MOVEA.L DOSBase(SP),A6
JSR _LVO\1(A6)
ENDM
_AbsExecBase EQU 4
;----------------------------------------------------------------------------
StartModule: DC.L (EndModule-StartModule)/4 ; for BCPL linking
EntryPoint: SUBA.L #STACKDATA_SIZE,SP
LSL.L #2,D1 ; convert to byte pointer
MOVE.L D1,Packet(SP)
CLR.L ReturnVal(SP) ; no error - for now
OpenDOS: LEA DOSName(PC),A1
CLR.L D0
LINKEXE OpenLibrary
MOVE.L D0,DOSBase(SP)
BNE LoadCode
MOVE.L #ERROR_INVALID_RESIDENT_LIBRARY,ReturnVal(SP)
BRA Return
LoadCode: LEA HandlerName(PC),A1
MOVE.L A1,D1
LINKDOS LoadSeg
MOVE.L D0,Segment(SP)
BNE CallHandler
MOVE.L #ERROR_OBJECT_NOT_FOUND,ReturnVal(SP)
BRA CloseDOS
CallHandler: LEA SPsave(PC),A1
MOVE.L SP,(A1) ; save current SP
MOVE.L Segment(SP),D0 ; BPTR to segment
LSL.L #2,D0
MOVEA.L D0,A0 ; byte pointer to segment
MOVE.L Packet(SP),D0 ; packet address
MOVE.L D0,-(SP) ; push (not sure if safe above)
; --- Now, call the loaded handler code.
; --- It is sent the byte address of the startup packet passed to this code.
JSR 4(A0) ; call first code in segment
MOVEA.L SPsave(PC),SP ; restore SP
UnloadCode: MOVE.L Segment(SP),D1
LINKDOS UnLoadSeg
CloseDOS: MOVE.L DOSBase(SP),A1
LINKEXE CloseLibrary
Return: MOVE.L ReturnVal(SP),D0 ; retrieve return value
ADDA.L #STACKDATA_SIZE,SP
RTS
SPsave: DC.L 0
DOSName: DOSNAME
HandlerName: DC.B 'L:'
ProcessName: DC.B 'pipe-handler',0
; trailing definitions for BCPL linking
CNOP 0,4 ; align to lonword boundary
DC.L 0 ; End Marker
DC.L 1 ; Global 1
DC.L EntryPoint-StartModule ; Offset
DC.L 1 ; Highest Global Used
EndModule: END
SHAR_EOF
cat << \SHAR_EOF > pipe-handler.c
/****************************************************************************
** File: pipe-handler.c
** Program: pipe-handler - an AmigaDOS handler for named pipes
** Version: 1.2
** 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 shared locks for individual pipes.
** PIPEDATA structure modified to include
** a FileLock structure.
** 07-Feb-87 Added #if's forautomatic pipe naming "feature"
** for pipes specified with empty names.
** 12-Feb-87 Added ParentDir packet handling.
** 12-Feb-87 Fixed bug in OpenPipe() and PipeLock():
** they previously ignored the lock passed in
** packet. Bug uncovered when pipes became
** lockable, and thus assignable.
** 27-Mar-87 Added the case for PipeDupLock(). This was
** missing in the original version!
** 28-Mar-87 Added code to handler() to remove ':' from
** end of handler name. This caused problems
** with Examine(); it expects no ending ':'.
*/
#include
#include
#include
#include
#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
/*---------------------------------------------------------------------------
** pipe-handler.c
** --------------
** This is the main module for the handler. Handlers are started with
** register D1 containing a BPTR to a startup packet, which in turn contains
** (BCPL) pointers to the name and DeviceNode. Since the entry, handler(),
** expects a byte address of the startup packet, an assembly language startup
** must be used to convert the BCPL pointer, and pass it on the stack.
**
** Problems arise if a handler tries to do I/O via the DOS functions Open(),
** Close(), Read() and Write(). DOS sends request packets to the handler
** via its DOS port (the one whose address forms the process ID). This is
** also the port used by the I/O functions. Therefore, if a request comes,
** and then an Open() call is performed, DOS will send a request packet for
** the open and erroneously pick up the request packet meant for the handler
** as its reply. A crash ensues.
**
** This is the reason for the I/O functions in pipedebug.c. They implement
** the regualar I/O calls, but use a different ReplyPort. With no debugging,
** these functions are unneeded, since all of the handler's normal I/O is
** performed asynchronously, using PutMsg().
**
** An alternate solution is to patch the handler's Task field with a new port
** instead of the handler's DOS port. This works, except that DOS always
** sends the initial request packets to the DOS port (when the handler is
** first started). This is probably because DeviceProc(), upon seeing that
** the handler has not yet been loaded, returns the result from its call to
** CreateProc() for the handler process. Only on subsequent calls to
** DeviceProc() will the patched field be returned. The upshot of this is
** that an alternate port can be used for handler requests, but there are
** always an unspecified number that may come over the DOS port regardless.
** Note that since not all handlers patch their Task field (because they want
** to be restarted each time), DOS is doing the "right" thing, or at least
** the best it can.
**
** Visible Functions
** -----------------
** void handler (StartPkt)
** PIPEDATA *FindPipe (name)
**
** Macros (in pipe-handler.h)
** --------------------------
** BPTRtoCptr (Bp)
** CptrtoBPTR (Cp)
** ReplyPkt (pkt)
**
** Local Functions
** ---------------
** struct DosPacket *GetPkt (port)
*/
/*---------------------------------------------------------------------------
** HandlerName : passed as a BSTR in startup packet Arg1, our device name.
** Everything from the ':' and beyond is removed.
** Used by PipeExamine() for the handler's "directory" name.
**
** DevNode : passed as a BPTR in startup packet Arg3. This is a pointer
** to our DeviceNode entry in the system device list (DevInfo).
**
** Pipeort : our DOS MsgPort, as well as our process ID. See above for
** notes about why we can't let DOS use this.
**
** pipelist : the list of currently existing pipes. PIPEDATA nodes are
** linked into this list.
**
** tapwaitlist : the list of requests waiting on tap opens/closes/writes.
** WAITINGDATA nodes are linked into this list. See pipesched.c
** and pipecreate.c.
**
** TapReplyPort : this is the MsgPort to which tap I/O replys are returned.
**
** SysBase,
** DOSBase : Standard system library pointers. Since we don't have the
** usual startup code, we must initialize these ourselves.
**
** PipeDate : If compiled with PIPEDIR true, the handler responds to some
** directory-like actions. This is the date for the entire
** handler, i.e., the directory date. The flag UPDATE_PIPEDATE
** controls whether this date is updated with each pipe access
** (true) or not (false). See SetPipeDate() and PipeExamine().
*/
char HandlerName[30];
struct DeviceNode *DevNode = NULL;
struct MsgPort *PipePort = NULL;
PIPELISTHEADER pipelist;
PIPELISTHEADER tapwaitlist;
struct MsgPort *TapReplyPort = NULL;
struct Library *SysBase = NULL;
struct Library *DOSBase = NULL;
#if PIPEDIR
struct DateStamp PipeDate;
#endif PIPEDIR
/*---------------------------------------------------------------------------
** Performs initialization, replies to startup packet, and dispatches
** incoming request packets to the apropriate functions. The TapReplyPort is
** also monitored for returning requests which were sent out by the handler.
** These returned requests are routed to HandleTapReply().
** Our DeviceNode Task field is patched with our process ID so that this
** process is used for subsequent handler requests. The function exits only
** if there is some initialization error.
*/
void handler (StartPkt)
struct DosPacket *StartPkt;
{ char *cp;
struct Task *Task;
ULONG PipeMask, TapReplyMask, WakeupMask, SigMask;
struct DosPacket *pkt, *GetPkt();
void OpenPipe(), ClosePipe();
SysBase= AbsExecBase;
if ((DOSBase= OpenLibrary (DOSNAME, 0)) == NULL)
goto QUIT;
BSTRtoCstr (BPTRtoCptr (StartPkt->dp_Arg1), HandlerName, sizeof (HandlerName));
for (cp= HandlerName; *cp != '\0'; ++cp)
if (*cp == ':') /* remainder of handler's first refernece follows */
{ *cp= '\0';
break;
}
Task= FindTask (0);
PipePort= (struct MsgPort *) ((ULONG) Task + sizeof (struct Task));
((struct Process *) Task)->pr_CurrentDir= 0; /* initial file system root */
if ((TapReplyPort= CreatePort (NULL, PipePort->mp_Node.ln_Pri)) == NULL)
goto QUIT;
#ifdef DEBUG
if (! InitDebugIO (PipePort->mp_Node.ln_Pri))
goto QUIT;
#endif DEBUG
PipeMask= (1L << PipePort->mp_SigBit);
TapReplyMask= (1L << TapReplyPort->mp_SigBit);
WakeupMask= (PipeMask | TapReplyMask);
DevNode= (struct DeviceNode *) BPTRtoCptr (StartPkt->dp_Arg3);
DevNode->dn_Task= PipePort;
InitList (&pipelist);
InitList (&tapwaitlist);
#if PIPEDIR
(void) DateStamp (&PipeDate);
#endif PIPEDIR
ReplyPkt (StartPkt);
LOOP:
SigMask= Wait (WakeupMask);
if (SigMask & TapReplyMask)
while ((pkt= GetPkt (TapReplyPort)) != NULL)
HandleTapReply (pkt);
if (SigMask & PipeMask)
while ((pkt= GetPkt (PipePort)) != NULL)
switch (pkt->dp_Type)
{ case MODE_READWRITE:
#ifdef DEBUG
OS ("Open READWRITE packet received\n");
#endif DEBUG
OpenPipe (pkt, 0);
break;
case MODE_READONLY: /* syn: MODE_OLDFILE, ACTION_FINDINPUT */
#ifdef DEBUG
OS ("Open READONLY packet received\n");
#endif DEBUG
OpenPipe (pkt, 0);
break;
case MODE_NEWFILE: /* syn: ACTION_FINDOUTPUT */
#ifdef DEBUG
OS ("Open NEWFILE packet received\n");
#endif DEBUG
OpenPipe (pkt, 0);
break;
case ACTION_END:
#ifdef DEBUG
OS ("Close packet received\n");
#endif DEBUG
ClosePipe (pkt);
break;
case ACTION_READ:
#ifdef DEBUG
OS ("<<< Read packet received\n");
#endif DEBUG
StartPipeIO (pkt, PIPEREAD);
break;
case ACTION_WRITE:
#ifdef DEBUG
OS (">>> Write packet received\n");
#endif DEBUG
StartPipeIO (pkt, PIPEWRITE);
break;
#if PIPEDIR
case ACTION_LOCATE_OBJECT:
# ifdef DEBUG
OS ( "Lock packet received\n");
# endif DEBUG
PipeLock (pkt);
break;
case ACTION_COPY_DIR:
# ifdef DEBUG
OS ( "DupLock packet received\n");
# endif DEBUG
PipeDupLock (pkt);
break;
case ACTION_FREE_LOCK:
# ifdef DEBUG
OS ( "UnLock packet received\n");
# endif DEBUG
PipeUnLock (pkt);
break;
case ACTION_EXAMINE_OBJECT:
# ifdef DEBUG
OS ( "Examine packet received\n");
# endif DEBUG
PipeExamine (pkt);
break;
case ACTION_EXAMINE_NEXT:
# ifdef DEBUG
OS ( "ExNext packet received\n");
# endif DEBUG
PipeExNext (pkt);
break;
case ACTION_PARENT:
# ifdef DEBUG
OS ( "ParentDir packet received\n");
# endif DEBUG
PipeParentDir (pkt);
break;
#endif PIPEDIR
default:
#ifdef DEBUG
OS ("BAD packet received, type = "); OL (pkt->dp_Type); NL;
#endif DEBUG
pkt->dp_Res1= 0;
pkt->dp_Res2= ERROR_ACTION_NOT_KNOWN;
ReplyPkt (pkt);
}
goto LOOP;
QUIT:
DevNode->dn_Task= NULL; /* bad if someone in process of accessing us . . . */
if (TapReplyPort != NULL)
FreeMem (TapReplyPort, sizeof (struct MsgPort)); /* signal bit won't matter */
#ifdef DEBUG
CleanupDebugIO ();
#endif DEBUG
if (DOSBase != NULL)
CloseLibrary (DOSBase);
}
/*---------------------------------------------------------------------------
** Returns the DosPacket associated with the next message on "port", or NULL
** if the port is empty. The message is removed from the port.
** A related macro, ReplyPkt() is provided in pipe-handler.h.
*/
static struct DosPacket *GetPkt (port)
register struct MsgPort *port;
{ register struct Message *msg;
return ((msg= GetMsg (port)) == NULL)
? NULL
: (struct DosPacket *) msg->mn_Node.ln_Name;
}
/*---------------------------------------------------------------------------
** Searches "pipelist" for a pipe whose name is "name". If found, a pointer
** to the pipe returns. Otherwise, NULL returns.
*/
PIPEDATA *FindPipe (name)
char *name;
{ PIPEDATA *p;
char *cp, *strdiff();
for (p= (PIPEDATA *) FirstItem (&pipelist); p != NULL; p= (PIPEDATA *) NextItem (p))
{ cp= strdiff (name, p->name);
if ((*cp == '\0') && (p->name[(LONG) cp - (LONG) name] == '\0'))
return p; /* same name */
}
return NULL; /* no match found */
}
SHAR_EOF
cat << \SHAR_EOF > pipebuf.c
/****************************************************************************
** File: pipebuf.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)
*/
#include
#include
#include
#include
#include "pipelists.h"
#include "pipename.h"
#include "pipebuf.h"
#include "pipecreate.h"
#include "pipesched.h"
#include "pipe-handler.h"
/*---------------------------------------------------------------------------
** pipebuf.c
** ---------
** This module contains functions that manage the circular buffer for pipes.
**
** Visible Functions
** -----------------
** PIPEBUF *AllocPipebuf (len)
** ULONG MoveFromPipebuf (pb, dest, amt)
** ULONG MoveToPipebuf (pb, src, amt)
**
** Macros (in pipebuf.h)
** ---------------------
** PipebufEmpty (pb)
** PipebufFull (pb)
** FreePipebuf (pb)
**
** Local Functions
** ---------------
** - none -
*/
/*---------------------------------------------------------------------------
** AllocPipebuf() returns a pointer to a new PIPEBUF structure if there is
** enough free memory to allocate one with the requested ("len") storage.
** The structure is iinitialized as empty. Notice that the buffer storage
** area is the tail part of the structure.
*/
PIPEBUF *AllocPipebuf (len)
ULONG len;
{ PIPEBUF *pb = NULL;
if ( (len > 0) && (len <= MAX_PIPELEN) &&
((pb= (PIPEBUF *) AllocMem (sizeof (PIPEBUF) - 1 + len, ALLOCMEM_FLAGS)) != NULL) )
{ pb->head= pb->tail= 0;
pb->full= FALSE;
pb->len= len;
}
return pb;
}
/*---------------------------------------------------------------------------
** Move bytes from the PIPEBUF to the memory pointed to by "dest". At most
** "amt" bytes are moved. The actual number moved is returned.
*/
ULONG MoveFromPipebuf (pb, dest, amt)
PIPEBUF *pb;
register BYTE *dest;
ULONG amt;
{ register BYTE *src;
register LONG ct;
ULONG amtleft;
if ((amt <= 0) || PipebufEmpty (pb))
return 0L;
amtleft= amt;
src= pb->buf + pb->tail;
if (pb->tail >= pb->head) /* then have to wrap around */
{ if ((ct= (pb->len - pb->tail)) > amtleft)
ct= amtleft; /* more than needed in end of pipebuf */
CopyMem (src, dest, ct);
pb->tail= (pb->tail + ct) % pb->len;
amtleft -= ct;
src= pb->buf + pb->tail;
dest += ct;
}
if ( (amtleft > 0) && (ct= (pb->head - pb->tail)) )
{ if (ct > amtleft)
ct= amtleft; /* more than needed */
CopyMem (src, dest, ct);
pb->tail += ct; /* no need to mod */
amtleft -= ct;
}
pb->full= FALSE; /* has to be: nonzero amt */
return (amt - amtleft);
}
/*---------------------------------------------------------------------------
** Move bytes to the PIPEBUF from the memory pointed to by "src". At most
** "amt" bytes are moved. The actual number moved is returned.
*/
ULONG MoveToPipebuf (pb, src, amt)
PIPEBUF *pb;
register BYTE *src;
ULONG amt;
{ register BYTE *dest;
register LONG ct;
ULONG amtleft;
if ((amt <= 0) || PipebufFull (pb))
return 0L;
amtleft= amt;
dest= pb->buf + pb->head;
if (pb->head >= pb->tail) /* then have to wrap around */
{ if ((ct= (pb->len - pb->head)) > amtleft)
ct= amtleft; /* more than will fit in end of pipebuf */
CopyMem (src, dest, ct);
pb->head= (pb->head + ct) % pb->len;
amtleft -= ct;
src += ct;
dest= pb->buf + pb->head;
}
if ( (amtleft > 0) && (ct= (pb->tail - pb->head)) )
{ if (ct > amtleft)
ct= amtleft; /* more than will fit */
CopyMem (src, dest, ct);
pb->head += ct; /* no need to mod */
amtleft -= ct;
}
pb->full= (pb->head == pb->tail);
return (amt - amtleft);
}
SHAR_EOF
cat << \SHAR_EOF > pipecreate.h
/****************************************************************************
** File: pipecreate.h
** 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.
*/
#define OPENTAP_STRSIZE 108
extern void OpenPipe ( /* pkt, tapfh */ );
extern void ClosePipe ( /* pkt */ );
extern void DiscardPipe ( /* pipe */ );
SHAR_EOF
cat << \SHAR_EOF > pipedebug.c
/****************************************************************************
** File: pipedebug.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)
*/
#include
#include
#include
#include "pipedebug.h"
/*---------------------------------------------------------------------------
** pipedebug.c
** -----------
** This module contains debugging functions. In need only be included if the
** other modules are compiled with DEBUG defined.
**
** Visible Functions
** -----------------
** int InitDebugIO (NodePri)
** void CleanupDebugIO ()
** BPTR DebugOpen (name, mode)
** void DebugClose (fh)
** int DebugWrite (fh, buf, len)
** void OutStr (str, fh)
** void OutLONG (n, fh)
**
** Macros (in pipedebug.h)
** -----------------------
** OS (s)
** NL
** OL (n)
**
** Local Functions
** ---------------
** void DebugIO (Handler, Type, Arg1, Arg2, Arg3)
*/
#define BPTRtoCptr(Bp) ((char *) ((ULONG) (Bp) << 2))
#define CptrtoBPTR(Cp) ((BPTR) ((ULONG) (Cp) >> 2))
#define MEMFLAGS (MEMF_PUBLIC | MEMF_CLEAR)
static struct MsgPort *DebugDOSPort = NULL;
static struct Message *DebugMsg = NULL;
static struct DosPacket *DebugPkt = NULL;
BPTR DebugFH = 0;
/*---------------------------------------------------------------------------
** InitDebugIO() allocates things for the debugging functions, and opens a
** window for output. It MUST be called before any of the I/O operations
** are used. CleanupDebugIO() frees the resources allocated here, and closes
** the window.
** The routines DebugOpen(), DebugClose(), and DebugWrite() mimic their
** corresponding DOS functions, except they use a private reply port, not
** the process' DOS port. DOS does bad things if a handler request comes in
** while it is waiting or a reply to one of its requests made on your behalf.
** The return value is nonzero iff no error occurred.
*/
int InitDebugIO (NodePri)
BYTE NodePri;
{ struct MsgPort *CreatePort();
BYTE *AllocMem();
DebugDOSPort= NULL;
DebugMsg= NULL;
DebugPkt= NULL;
DebugFH= 0;
if ( ((DebugDOSPort= CreatePort (NULL, NodePri)) == NULL) ||
((DebugMsg= (struct Message *) AllocMem (sizeof (struct Message), MEMFLAGS)) == NULL) ||
((DebugPkt= (struct DosPacket *) AllocMem (sizeof (struct DosPacket), MEMFLAGS)) == NULL) ||
((DebugFH= DebugOpen (DEBUG_CON_NAME, MODE_NEWFILE)) == 0) )
{ CleanupDebugIO ();
return FALSE;
}
return TRUE;
}
/*---------------------------------------------------------------------------
** Cleanup things allocated by InitDebugIO, and close the window.
*/
void CleanupDebugIO ()
{ void FreeMem();
if (DebugFH != 0)
DebugClose (DebugFH);
if (DebugPkt != NULL)
FreeMem (DebugPkt, sizeof (struct DosPacket));
if (DebugMsg != NULL)
FreeMem (DebugMsg, sizeof (struct Message));
if (DebugDOSPort != NULL)
{ FreeSignal (DebugDOSPort->mp_SigBit);
FreeMem (DebugDOSPort, sizeof (struct MsgPort));
}
}
/*---------------------------------------------------------------------------
** DebugOpen() performs just like the DOS function Open().
** InitDebugIO() MUST have been called and returned successful before calling
** this function.
*/
BPTR DebugOpen (name, mode)
char *name;
int mode;
{ char Bnamebuf[DEBUGOPEN_MAXNAMELEN + 3 + 2], *Bname;
UBYTE namelen;
struct MsgPort *HandlerPID, *DeviceProc();
int IoErr();
struct FileLock *Lock;
struct FileHandle *handle;
BYTE *AllocMem();
void DebugIO(), FreeMem();
Bname= (char *) (((ULONG) Bnamebuf + 3) & (~0 << 2)); /* longword align */
for (namelen= 0; (Bname[namelen + 1]= name[namelen]); ++namelen)
if (namelen > DEBUGOPEN_MAXNAMELEN)
return 0;
Bname[0]= (char) namelen; /* make a BSTR */
HandlerPID= DeviceProc (name);
if (HandlerPID == NULL)
return 0;
Lock= (struct FileLock *) IoErr ();
if ((handle= (struct FileHandle *) AllocMem (sizeof (struct FileHandle), MEMFLAGS)) == NULL)
return 0;
handle->fh_Pos= -1;
handle->fh_End= -1;
handle->fh_Type= HandlerPID;
DebugIO (HandlerPID, mode, CptrtoBPTR (handle), CptrtoBPTR (Lock), CptrtoBPTR (Bname));
if (DebugPkt->dp_Res1 == 0)
{ FreeMem (handle, sizeof (struct FileHandle));
return 0;
}
return CptrtoBPTR (handle);
}
/*---------------------------------------------------------------------------
** DebugClose() performs just like the DOS function Close().
** InitDebugIO() MUST have been called and returned successful before calling
** this function.
*/
void DebugClose (fh)
BPTR fh;
{ struct FileHandle *handle;
void DebugIO(), FreeMem();
handle= (struct FileHandle *) BPTRtoCptr (fh);
DebugIO (handle->fh_Type, 1007, handle->fh_Arg1, 0, 0);
FreeMem (handle, sizeof (struct FileHandle));
}
/*---------------------------------------------------------------------------
** DebugWrite() performs just like the DOS function Write().
** InitDebugIO() MUST have been called and returned successful before calling
** this function.
*/
int DebugWrite (fh, buf, len)
BPTR fh;
BYTE *buf;
ULONG len;
{ struct FileHandle *handle;
void DebugIO();
handle= (struct FileHandle *) BPTRtoCptr (fh);
DebugIO (handle->fh_Type, ACTION_WRITE, handle->fh_Arg1, buf, len);
return DebugPkt->dp_Res1;
}
/*---------------------------------------------------------------------------
** DebugIO() sets up the DosPacket with the specified information, initiates
** the request, and waits for the reply.
*/
static void DebugIO (Handler, Type, Arg1, Arg2, Arg3)
struct MsgPort *Handler;
LONG Type;
LONG Arg1;
LONG Arg2;
LONG Arg3;
{ void PutMsg();
struct MsgPort *WaitPort(), *Getmsg();
DebugMsg->mn_ReplyPort= DebugDOSPort;
DebugMsg->mn_Node.ln_Type= NT_MESSAGE;
DebugMsg->mn_Node.ln_Name= (char *) DebugPkt;
DebugPkt->dp_Link= DebugMsg;
DebugPkt->dp_Port= DebugDOSPort;
DebugPkt->dp_Type= Type;
DebugPkt->dp_Arg1= Arg1;
DebugPkt->dp_Arg2= Arg2;
DebugPkt->dp_Arg3= Arg3;
PutMsg (Handler, DebugMsg);
(void) WaitPort (DebugDOSPort);
(void) GetMsg (DebugDOSPort); /* assume it is DebugMsg */
}
/*---------------------------------------------------------------------------
** OutStr() outputs the null-terminated string "str" to the filehandle "fh".
*/
void OutStr (str, fh)
char *str;
BPTR fh;
{ int strlen();
DebugWrite (fh, str, strlen (str));
}
/*---------------------------------------------------------------------------
** OutLONG() outputs the decimal representaion on "n" to the filehandle "fh".
** The conversion function stcu_d() is used -- this may not be available
** on all systems. In that case, such a function will need to be written.
*/
void OutLONG (n, fh)
ULONG n;
BPTR fh;
{ char buf[80];
int stcu_d(); /* Lattice C Library conversion function */
(void) stcu_d (buf, n, 80);
OutStr (buf, fh);
}
SHAR_EOF
cat << \SHAR_EOF > pipedebug.h
/****************************************************************************
** File: pipedebug.h
** 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)
*/
#define DEBUGOPEN_MAXNAMELEN 108
#define DEBUG_CON_NAME "CON:10/30/300/100/pipe-handler DEBUG"
#define OS(s) OutStr ((s), DebugFH)
#define NL OutStr ("\n", DebugFH)
#define OL(n) OutLONG ((n), DebugFH)
extern BPTR DebugFH;
extern int InitDebugIO ( /* NodePri */ );
extern void CleanupDebugIO ( );
extern BPTR DebugOpen ( /* name, mode */ );
extern void DebugClose ( /* fh */ );
extern int DebugWrite ( /* fh, buf, len */ );
extern void OutStr ( /* str, fh */ );
extern void OutLONG ( /* n, fh */ );
SHAR_EOF
cat << \SHAR_EOF > pipedir.c
/****************************************************************************
** File: pipedir.c
** Program: pipe-handler - an AmigaDOS handler for named pipes
** Version: 1.2
** 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 modifications for allowing shared locks
** on individual pipes.
** 12-Feb-87 Added PipeParentDir.
** 12-Feb-87 Fixed bug in PipeLock(): previously ignored
** lock passed in packet. Bug uncovered when
** pipes became lockable, and thus assignable.
** 27-Mar-87 Added PipeDupLock(). This was missing
** in the original version!
*/
#include
#include
#include
#include
#include "pipelists.h"
#include "pipename.h"
#include "pipebuf.h"
#include "pipecreate.h"
#include "pipesched.h"
#include "pipe-handler.h"
#include "pipedir.h"
/*---------------------------------------------------------------------------
** pipedir.c
** ---------
** This module handles the directory-related requests to the handler.
** The functions contained here are not needed if the compile-time flag
** PIPEDIR is false.
**
** Visible Functions
** -----------------
** void SetPipeDate (pipe)
** void PipeLock (pkt)
** void PipeDupLock (pkt)
** void PipeUnLock (pkt)
** void PipeExamine (pkt)
** void PipeExNext (pkt)
** void InitLock (lock, key)
**
** Macros (in pipedir.h)
** ---------------------
** - none -
**
** Local Functions
** ---------------
** void InitPipedirLock ()
** void FillFIB (fib, DiskKey, FileName, Protection, Type, Size, NumBlocks, Datep)
*/
/*---------------------------------------------------------------------------
** "PipedirLock" is the lock returned by PipeLock() to clients requesting a
** shared lock on the handler. "LockBytes" is used for the storage of the
** lock. InitLock() sets "PipedirLock" to point to the first longword within
** "LockBytes" to ensure longword alignment for BCPL's sake.
*/
static BYTE LockBytes[sizeof (struct FileLock) + 3];
static struct FileLock *PipedirLock = NULL;
/*---------------------------------------------------------------------------
** SetPipeDate() modifies the date field for the pipe sent. If the compile-
** time flag UPDATE_PIPEDATE is true (see pipe-handler.h), the handler's date
** is modified as well.
*/
void SetPipeDate (pipe)
PIPEDATA *pipe;
{ (void) DateStamp (&pipe->accessdate);
#if UPDATE_PIPEDATE
(void) DateStamp (&PipeDate);
#endif UPDATE_PIPEDATE
}
/*---------------------------------------------------------------------------
** PipeLock() responds to Lock requests. Only multiple access locks are
** granted. The same lock is returned to all clients for a given entity.
** 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 PipeLock (pkt)
struct DosPacket *pkt;
{ char *name, *tapname;
ULONG size;
struct FileLock *lock;
PIPEDATA *pipe;
void InitPipedirLock();
InitPipedirLock ();
pkt->dp_Res1= 0; /* error, for now */
pkt->dp_Res2= 0; /* clear for case of no error */
lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg1);
if (pkt->dp_Arg3 != SHARED_LOCK)
{ pkt->dp_Res2= ERROR_OBJECT_WRONG_TYPE;
goto PLOCKEXIT;
}
if (! ParsePipeName (BPTRtoCptr (pkt->dp_Arg2), &name, &size, &tapname))
{ pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
goto PLOCKEXIT;
}
if ( (lock == NULL) || ((pipe= (PIPEDATA *) lock->fl_Key) == NULL) )
{ if (name[0] == '\0')
pkt->dp_Res1= CptrtoBPTR (PipedirLock);
else
{ if ((pipe= FindPipe (name)) == NULL)
{ pkt->dp_Res2= ERROR_OBJECT_NOT_FOUND;
goto PLOCKEXIT;
}
pkt->dp_Res1= CptrtoBPTR (pipe->lock);
++pipe->lockct;
}
}
else /* lock sent in packet was on the pipe */
{ if (name[0] != '\0')
{ pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
goto PLOCKEXIT;
}
pkt->dp_Res1= CptrtoBPTR (pipe->lock);
++pipe->lockct;
}
PLOCKEXIT:
ReplyPkt (pkt);
}
/*---------------------------------------------------------------------------
** PipeDupLock() responds to DupLock requests. It is assumed that the lock
** sent is valid. The same lock is returned; the only action taken is to
** increment the lock count if the lock is on an individual pipe. If the
** zero lock is sent, the zero lock is (properly) returned, even though this
** handler should never receive that request. Notice that this routine never
** returns an error.
*/
void PipeDupLock (pkt)
struct DosPacket *pkt;
{ struct FileLock *lock;
PIPEDATA *pipe;
pkt->dp_Res1= pkt->dp_Arg1; /* reuse same structure */
pkt->dp_Res2= 0;
if ((lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg1)) != NULL)
{ if ((pipe= (PIPEDATA *) lock->fl_Key) != NULL)
++pipe->lockct; /* lock is on an individual pipe */
}
ReplyPkt (pkt);
}
/*---------------------------------------------------------------------------
** PipeUnLock() responds to UnLock requests.
*/
void PipeUnLock (pkt)
struct DosPacket *pkt;
{ struct FileLock *lock;
PIPEDATA *pipe;
if ((lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg1)) == NULL)
{ pkt->dp_Res1= 0;
pkt->dp_Res2= ERROR_INVALID_LOCK;
}
else
{ if ((pipe= (PIPEDATA *) lock->fl_Key) != NULL)
{ --pipe->lockct;
CheckWaiting (pipe); /* will discard if totally unused */
}
pkt->dp_Res1= 1; /* no error */
pkt->dp_Res2= 0;
}
ReplyPkt (pkt);
}
/*---------------------------------------------------------------------------
** PipeExamine() responds to Examine requests. For locks on the handler, the
** address first item of the pipelist is stored in the DiskKey field for
** PipeExNext()'s reference.
*/
void PipeExamine (pkt)
struct DosPacket *pkt;
{ struct FileInfoBlock *fib;
struct FileLock *lock;
PIPEDATA *pipe;
void FillFIB();
pkt->dp_Res1= 1; /* no error, for now */
pkt->dp_Res2= 0;
fib= (struct FileInfoBlock *) BPTRtoCptr (pkt->dp_Arg2);
if ((lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg1)) == NULL)
{ pkt->dp_Res1= 0;
pkt->dp_Res2= ERROR_OBJECT_NOT_FOUND;
}
else
{ if ((pipe= (PIPEDATA *) lock->fl_Key) == NULL) /* then this is a lock on the handler */
{ FillFIB ( fib, FirstItem (&pipelist), HandlerName,
(FIBF_EXECUTE | FIBF_DELETE), 1,
0, 0, &PipeDate );
}
else
{ FillFIB ( fib, NULL, pipe->name,
(FIBF_EXECUTE | FIBF_DELETE), -1,
pipe->buf->len, 1, &pipe->accessdate );
}
}
ReplyPkt (pkt);
}
/*---------------------------------------------------------------------------
** PipeExNext() responds to ExNext requests. The DiskKey field of the
** FileInfoBlock is assumed to be a pointer to the next pipe in the pipelist
** which is to be listed in the directory. We then scan pipelist for this
** pointer, and upon finding it, store its information in the FileInfoBlock
** and store the address of the next pipe in pipelist in the DiskKey field.
** If the pipe is not found in the list, or if DiskKey is NULL, then
** ERROR_NO_MORE_ENTRIES is returned.
** By rescanning the list each time, deletion of a pipe cannot hurt us
** by causing a dangling pointer in DiskKey -- we just end the directory
** listing there. This can cause incomplete directory information for the
** cleint, however, if the last listed pipe is deleted before the client's
** next ExNext() call.
*/
void PipeExNext (pkt)
struct DosPacket *pkt;
{ struct FileLock *lock;
struct FileInfoBlock *fib;
PIPEDATA *listitem, *pipe;
void FillFIB();
pkt->dp_Res1= 0; /* error, for now */
if ((lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg1)) == NULL)
{ pkt->dp_Res2= ERROR_INVALID_LOCK;
goto EXNEXTREPLY;
}
if (lock->fl_Key != NULL) /* then an individual pipe */
{ pkt->dp_Res2= ERROR_OBJECT_WRONG_TYPE;
goto EXNEXTREPLY;
}
pkt->dp_Res2= ERROR_NO_MORE_ENTRIES; /* until found otherwise */
fib= (struct FileInfoBlock *) BPTRtoCptr (pkt->dp_Arg2);
if ((listitem= (PIPEDATA *) fib->fib_DiskKey) == NULL)
goto EXNEXTREPLY;
for (pipe= (PIPEDATA *) FirstItem (&pipelist); pipe != NULL; pipe= (PIPEDATA *) NextItem (pipe))
if (listitem == pipe)
break;
if (listitem == pipe) /* then found next entry */
{ FillFIB ( fib, NextItem (listitem), listitem->name,
(FIBF_EXECUTE | FIBF_DELETE), -1,
listitem->buf->len, 1, &listitem->accessdate );
pkt->dp_Res1= 1;
pkt->dp_Res2= 0;
}
EXNEXTREPLY:
ReplyPkt (pkt);
}
/*---------------------------------------------------------------------------
** PipeParentDir() responds to ParentDir requests.
*/
void PipeParentDir (pkt)
struct DosPacket *pkt;
{ struct FileLock *lock;
void InitPipedirLock();
InitPipedirLock ();
pkt->dp_Res2= 0;
if ((lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg1)) == NULL)
{ pkt->dp_Res1= 0;
pkt->dp_Res2= ERROR_INVALID_LOCK;
}
else
{ if (lock->fl_Key == NULL) /* then lock is on handler */
pkt->dp_Res1= 0; /* root of current filing system */
else
pkt->dp_Res1= CptrtoBPTR (PipedirLock);
}
ReplyPkt (pkt);
}
/*---------------------------------------------------------------------------
*/
static void InitPipedirLock ()
{ if (PipedirLock == NULL)
{ PipedirLock= (struct FileLock *) (((ULONG) LockBytes + 3) & ((~0)<<2));
InitLock (PipedirLock, NULL);
}
}
/*---------------------------------------------------------------------------
** InitLock() initializes locks returned to clients by PipeLock(). For locks
** on individual pipes, the "fl_Key" field points to the associated pipe's
** PIPEDATA structure. For the handler, the "fl_Key" field is NULL.
*/
void InitLock (lock, key)
struct FileLock *lock;
LONG key;
{ lock->fl_Link= 0;
lock->fl_Key= key;
lock->fl_Access= SHARED_LOCK; /* only mode allowed */
lock->fl_Task= PipePort; /* set during handler init */
lock->fl_Volume= CptrtoBPTR (DevNode); /* also set during init */
}
/*---------------------------------------------------------------------------
** FillFIB() fills a FileInfoBlock with the specified information. Note
** that handlers must store BSTR's in the FileInfoBlock.
*/
static void FillFIB (fib, DiskKey, FileName, Protection, Type, Size, NumBlocks, Datep)
struct FileInfoBlock *fib;
LONG DiskKey;
char *FileName; /* null-terminated */
LONG Protection;
LONG Type;
LONG Size;
LONG NumBlocks;
struct DateStamp *Datep;
{ fib->fib_DiskKey= DiskKey;
fib->fib_DirEntryType= Type;
CstrtoBSTR (FileName, fib->fib_FileName, sizeof (fib->fib_FileName));
fib->fib_Protection= Protection;
fib->fib_EntryType= Type; /* ??? */
fib->fib_Size= Size;
fib->fib_NumBlocks= NumBlocks;
CopyMem (Datep, &fib->fib_Date, sizeof (struct DateStamp));
fib->fib_Comment[0]= '\0'; /* empty BSTR */
}
SHAR_EOF
cat << \SHAR_EOF > pipesched.h
/****************************************************************************
** File: pipesched.h
** 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 "lockct" check in CheckWaiting().
*/
typedef enum iotype
{ PIPEREAD,
PIPEWRITE,
PIPERW
}
IOTYPE;
struct pipewait
{ BYTE *buf; /* the next position for read/write */
ULONG len; /* the remaining length t read/write */
IOTYPE reqtype; /* PIPEREAD or PIPEWRITE only */
};
struct tapwait
{ struct DosPacket *clientpkt; /* the client's packet */
struct FileHandle *handle; /* the associated filehandle */
};
union pktinfo
{ struct pipewait pipewait; /* for packet waiting on pipe */
struct tapwait tapwait; /* for packet waiting on tap */
};
typedef struct waitingdata
{ PIPELISTNODE link; /* for list use */
struct DosPacket *pkt; /* the packet we are waiting on */
union pktinfo pktinfo; /* data pertaining to the waiting request */
}
WAITINGDATA;
extern void StartPipeIO ( /* pipe, pkt, iotype */ );
extern void CheckWaiting ( /* pipe */ );
extern struct DosPacket *AllocPacket ( /* ReplyPort */ );
extern void FreePacket ( /* pkt */ );
extern void StartTapIO ( /* pkt, Type, Arg1, Arg2, Arg3, Handler */ );
extern void HandleTapReply ( /* pkt */ );
SHAR_EOF
cat << \SHAR_EOF > prelude_Mount
/* An example MOUNTLIST file enabling a 5" disk to be mounted
as DF1: and an interactive serial port mounted as AUX:
*/
DF1: Device = trackdisk.device
Unit = 1
Flags = 1
Surfaces = 2
BlocksPerTrack = 11
Reserved = 2
Interleave = 0
LowCyl = 0 ; HighCyl = 39
Buffers = 5
BufMemType = 3
#
/* This is provided as an example of an alternative type of
non-filing device mount. Please note that L:aux-handler
is not provided, and thus this mount does not work.
*/
AUX: Handler = L:aux-handler
Stacksize = 700
Priority = 5
#
P: Handler = L:pipe-handler
Stacksize = 3000
Priority = 5
#
SHAR_EOF