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