Moved tests into appropriate subdirs.
[AROS.git] / workbench / fs / pipe / pipe-handler.c
blob3bebdfa0916da46ea927397b820078c225d6d283
1 /****************************************************************************
2 ** File: pipe-handler.c
3 ** Program: pipe-handler - an AmigaDOS handler for named pipes
4 ** Version: 1.2
5 ** Author: Ed Puckett qix@mit-oz
6 **
7 ** Copyright 1987 by EpAc Software. All Rights Reserved.
8 **
9 ** History: 05-Jan-87 Original Version (1.0)
10 ** 07-Feb-87 Added shared locks for individual pipes.
11 ** PIPEDATA structure modified to include
12 ** a FileLock structure.
13 ** 07-Feb-87 Added #if's forautomatic pipe naming "feature"
14 ** for pipes specified with empty names.
15 ** 12-Feb-87 Added ParentDir packet handling.
16 ** 12-Feb-87 Fixed bug in OpenPipe() and PipeLock():
17 ** they previously ignored the lock passed in
18 ** packet. Bug uncovered when pipes became
19 ** lockable, and thus assignable.
20 ** 27-Mar-87 Added the case for PipeDupLock(). This was
21 ** missing in the original version!
22 ** 28-Mar-87 Added code to handler() to remove ':' from
23 ** end of handler name. This caused problems
24 ** with Examine(); it expects no ending ':'.
27 #include <libraries/dos.h>
28 #include <libraries/dosextens.h>
29 #include <libraries/filehandler.h>
30 #include <exec/exec.h>
32 #include <proto/exec.h>
33 #include <proto/dos.h>
34 #include <proto/alib.h>
36 #include "pipelists.h"
37 #include "pipename.h"
38 #include "pipebuf.h"
39 #include "pipecreate.h"
40 #include "pipesched.h"
41 #include "pipe-handler.h"
43 #if PIPEDIR
44 # include "pipedir.h"
45 #endif /* PIPEDIR */
47 #ifdef DEBUG
48 # include "pipedebug.h"
49 #endif /* DEBUG */
53 /*---------------------------------------------------------------------------
54 ** pipe-handler.c
55 ** --------------
56 ** This is the main module for the handler. Handlers are started with
57 ** register D1 containing a BPTR to a startup packet, which in turn contains
58 ** (BCPL) pointers to the name and DeviceNode. Since the entry, handler(),
59 ** expects a byte address of the startup packet, an assembly language startup
60 ** must be used to convert the BCPL pointer, and pass it on the stack.
62 ** Problems arise if a handler tries to do I/O via the DOS functions Open(),
63 ** Close(), Read() and Write(). DOS sends request packets to the handler
64 ** via its DOS port (the one whose address forms the process ID). This is
65 ** also the port used by the I/O functions. Therefore, if a request comes,
66 ** and then an Open() call is performed, DOS will send a request packet for
67 ** the open and erroneously pick up the request packet meant for the handler
68 ** as its reply. A crash ensues.
70 ** This is the reason for the I/O functions in pipedebug.c. They implement
71 ** the regular I/O calls, but use a different ReplyPort. With no debugging,
72 ** these functions are unneeded, since all of the handler's normal I/O is
73 ** performed asynchronously, using PutMsg().
75 ** An alternate solution is to patch the handler's Task field with a new port
76 ** instead of the handler's DOS port. This works, except that DOS always
77 ** sends the initial request packets to the DOS port (when the handler is
78 ** first started). This is probably because DeviceProc(), upon seeing that
79 ** the handler has not yet been loaded, returns the result from its call to
80 ** CreateProc() for the handler process. Only on subsequent calls to
81 ** DeviceProc() will the patched field be returned. The upshot of this is
82 ** that an alternate port can be used for handler requests, but there are
83 ** always an unspecified number that may come over the DOS port regardless.
84 ** Note that since not all handlers patch their Task field (because they want
85 ** to be restarted each time), DOS is doing the "right" thing, or at least
86 ** the best it can.
88 ** Visible Functions
89 ** -----------------
90 ** void handler (StartPkt)
91 ** PIPEDATA *FindPipe (name)
93 ** Macros (in pipe-handler.h)
94 ** --------------------------
95 ** BPTRtoCptr (Bp)
96 ** CptrtoBPTR (Cp)
97 ** QuickReplyPkt (pkt)
99 ** Local Functions
100 ** ---------------
101 ** struct DosPacket *QuickGetPkt (port)
106 /*---------------------------------------------------------------------------
107 ** HandlerName : passed as a BSTR in startup packet Arg1, our device name.
108 ** Everything from the ':' and beyond is removed.
109 ** Used by PipeExamine() for the handler's "directory" name.
111 ** DevNode : passed as a BPTR in startup packet Arg3. This is a pointer
112 ** to our DeviceNode entry in the system device list (DevInfo).
114 ** PipePort : our DOS MsgPort, as well as our process ID. See above for
115 ** notes about why we can't let DOS use this.
117 ** pipelist : the list of currently existing pipes. PIPEDATA nodes are
118 ** linked into this list.
120 ** tapwaitlist : the list of requests waiting on tap opens/closes/writes.
121 ** WAITINGDATA nodes are linked into this list. See pipesched.c
122 ** and pipecreate.c.
124 ** TapReplyPort : this is the MsgPort to which tap I/O replys are returned.
126 ** SysBase,
127 ** DOSBase : Standard system library pointers. Since we don't have the
128 ** usual startup code, we must initialize these ourselves.
130 ** PipeDate : If compiled with PIPEDIR true, the handler responds to some
131 ** directory-like actions. This is the date for the entire
132 ** handler, i.e., the directory date. The flag UPDATE_PIPEDATE
133 ** controls whether this date is updated with each pipe access
134 ** (true) or not (false). See SetPipeDate() and PipeExamine().
137 char HandlerName[30];
138 struct DeviceNode *DevNode = NULL;
139 struct MsgPort *PipePort = NULL;
141 PIPELISTHEADER pipelist;
143 PIPELISTHEADER tapwaitlist;
144 struct MsgPort *TapReplyPort = NULL;
146 #ifndef __AROS__
147 struct Library *SysBase = NULL;
148 #endif
149 struct DosLibrary *DOSBase = NULL;
151 #if PIPEDIR
152 struct DateStamp PipeDate;
153 #endif /* PIPEDIR */
155 static struct DosPacket *QuickGetPkt (register struct MsgPort *port);
158 /*---------------------------------------------------------------------------
159 ** Performs initialization, replies to startup packet, and dispatches
160 ** incoming request packets to the apropriate functions. The TapReplyPort is
161 ** also monitored for returning requests which were sent out by the handler.
162 ** These returned requests are routed to HandleTapReply().
163 ** Our DeviceNode Task field is patched with our process ID so that this
164 ** process is used for subsequent handler requests. The function exits only
165 ** if there is some initialization error.
168 void handler (StartPkt)
170 struct DosPacket *StartPkt;
172 { char *cp;
173 struct Task *Task;
174 ULONG PipeMask, TapReplyMask, WakeupMask, SigMask;
175 struct DosPacket *pkt;
177 #ifndef __AROS__
178 SysBase= AbsExecBase;
179 #endif
181 if ((DOSBase= (APTR)OpenLibrary (DOSNAME, 0)) == NULL)
182 goto QUIT;
184 BSTRtoCstr (BPTRtoCptr (StartPkt->dp_Arg1), HandlerName, sizeof (HandlerName));
185 for (cp= HandlerName; *cp != '\0'; ++cp)
186 if (*cp == ':') /* remainder of handler's first refernece follows */
187 { *cp= '\0';
188 break;
191 Task= FindTask (NULL);
192 PipePort= &((struct Process *)Task)->pr_MsgPort;
193 ((struct Process *) Task)->pr_CurrentDir= 0; /* initial file system root */
195 if ((TapReplyPort= CreatePort (NULL, PipePort->mp_Node.ln_Pri)) == NULL)
196 goto QUIT;
198 #ifdef DEBUG
199 if (! InitDebugIO (PipePort->mp_Node.ln_Pri))
200 goto QUIT;
201 #endif /* DEBUG */
204 PipeMask= (1L << PipePort->mp_SigBit);
205 TapReplyMask= (1L << TapReplyPort->mp_SigBit);
206 WakeupMask= (PipeMask | TapReplyMask);
208 DevNode= (struct DeviceNode *) BPTRtoCptr (StartPkt->dp_Arg3);
209 DevNode->dn_Task= PipePort;
211 InitList (&pipelist);
212 InitList (&tapwaitlist);
214 #if PIPEDIR
215 (void) DateStamp (&PipeDate);
216 #endif /* PIPEDIR */
218 StartPkt->dp_Res1 = DOSTRUE;
219 QuickReplyPkt (StartPkt);
222 LOOP:
223 SigMask= Wait (WakeupMask);
225 if (SigMask & TapReplyMask)
226 while ((pkt= QuickGetPkt (TapReplyPort)) != NULL)
227 HandleTapReply (pkt);
229 if (SigMask & PipeMask)
230 while ((pkt= QuickGetPkt (PipePort)) != NULL)
231 switch (pkt->dp_Type)
232 { case MODE_READWRITE:
233 #ifdef DEBUG
234 OS ("Open READWRITE packet received\n");
235 #endif /* DEBUG */
236 OpenPipe (pkt, 0);
237 break;
239 case MODE_READONLY: /* syn: MODE_OLDFILE, ACTION_FINDINPUT */
240 #ifdef DEBUG
241 OS ("Open READONLY packet received\n");
242 #endif /* DEBUG */
243 OpenPipe (pkt, 0);
244 break;
246 case MODE_NEWFILE: /* syn: ACTION_FINDOUTPUT */
247 #ifdef DEBUG
248 OS ("Open NEWFILE packet received\n");
249 #endif /* DEBUG */
250 OpenPipe (pkt, 0);
251 break;
253 case ACTION_END:
254 #ifdef DEBUG
255 OS ("Close packet received\n");
256 #endif /* DEBUG */
257 ClosePipe (pkt);
258 break;
260 case ACTION_READ:
261 #ifdef DEBUG
262 OS ("<<< Read packet received\n");
263 #endif /* DEBUG */
264 StartPipeIO (pkt, PIPEREAD);
265 break;
267 case ACTION_WRITE:
268 #ifdef DEBUG
269 OS (">>> Write packet received\n");
270 #endif /* DEBUG */
271 StartPipeIO (pkt, PIPEWRITE);
272 break;
274 #if PIPEDIR
275 case ACTION_LOCATE_OBJECT:
276 # ifdef DEBUG
277 OS ( "Lock packet received\n");
278 # endif /* DEBUG */
279 PipeLock (pkt);
280 break;
282 case ACTION_FH_FROM_LOCK:
283 # ifdef DEBUG
284 OS ( "FHFromLock packet received\n");
285 # endif /* DEBUG */
286 PipeFHFromLock (pkt);
287 break;
289 case ACTION_COPY_DIR:
290 # ifdef DEBUG
291 OS ( "DupLock packet received\n");
292 # endif /* DEBUG */
293 PipeDupLock (pkt);
294 break;
296 case ACTION_COPY_DIR_FH:
297 # ifdef DEBUG
298 OS ( "DupLockFH packet received\n");
299 # endif /* DEBUG */
300 PipeDupLockFH (pkt);
301 break;
303 case ACTION_FREE_LOCK:
304 # ifdef DEBUG
305 OS ( "UnLock packet received\n");
306 # endif /* DEBUG */
307 PipeUnLock (pkt);
308 break;
310 case ACTION_EXAMINE_OBJECT:
311 # ifdef DEBUG
312 OS ( "Examine packet received\n");
313 # endif /* DEBUG */
314 PipeExamine (pkt);
315 break;
317 case ACTION_EXAMINE_NEXT:
318 # ifdef DEBUG
319 OS ( "ExNext packet received\n");
320 # endif /* DEBUG */
321 PipeExNext (pkt);
322 break;
324 case ACTION_EXAMINE_FH:
325 # ifdef DEBUG
326 OS ( "ExFH packet received\n");
327 # endif /* DEBUG */
328 PipeExFH (pkt);
329 break;
331 case ACTION_PARENT:
332 # ifdef DEBUG
333 OS ( "ParentDir packet received\n");
334 # endif /* DEBUG */
335 PipeParentDir (pkt);
336 break;
338 case ACTION_PARENT_FH:
339 # ifdef DEBUG
340 OS ( "ParentFH packet received\n");
341 # endif /* DEBUG */
342 PipeParentFH (pkt);
343 break;
344 #endif /* PIPEDIR */
346 default:
347 #ifdef DEBUG
348 OS ("BAD packet received, type = "); OL (pkt->dp_Type); NL;
349 #endif /* DEBUG */
350 pkt->dp_Res1= 0;
351 pkt->dp_Res2= ERROR_ACTION_NOT_KNOWN;
352 QuickReplyPkt (pkt);
355 goto LOOP;
358 QUIT:
359 DevNode->dn_Task= NULL; /* bad if someone in process of accessing us . . . */
361 if (TapReplyPort != NULL)
362 FreeMem (TapReplyPort, sizeof (struct MsgPort)); /* signal bit won't matter */
364 #ifdef DEBUG
365 CleanupDebugIO ();
366 #endif /* DEBUG */
368 if (DOSBase != NULL)
369 CloseLibrary ((APTR)DOSBase);
374 /*---------------------------------------------------------------------------
375 ** Returns the DosPacket associated with the next message on "port", or NULL
376 ** if the port is empty. The message is removed from the port.
377 ** A related macro, QuickReplyPkt() is provided in pipe-handler.h.
379 static struct DosPacket *QuickGetPkt (port)
381 register struct MsgPort *port;
383 { register struct Message *msg;
385 return ((msg= GetMsg (port)) == NULL)
386 ? NULL
387 : (struct DosPacket *) msg->mn_Node.ln_Name;
392 /*---------------------------------------------------------------------------
393 ** Searches "pipelist" for a pipe whose name is "name". If found, a pointer
394 ** to the pipe returns. Otherwise, NULL returns.
397 PIPEDATA *FindPipe (name)
399 char *name;
401 { PIPEDATA *p;
402 char *cp;
405 for (p= (PIPEDATA *) FirstItem (&pipelist); p != NULL; p= (PIPEDATA *) NextItem (p))
406 { cp= strdiff (name, p->name);
408 if ((*cp == '\0') && (p->name[(const UBYTE *)cp - (const UBYTE *)name] == '\0'))
409 return p; /* same name */
412 return NULL; /* no match found */