dtpic.mui: added MUI4 attributes. (Only attribute
[AROS.git] / workbench / fs / pipe / pipecreate.c
blob00a052dc62db31e6cc0f9dfee63cd1773f55d0af
1 /****************************************************************************
2 ** File: pipecreate.c
3 ** Program: pipe-handler - an AmigaDOS handler for named pipes
4 ** Version: 1.1
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 lock initialization to OpenPipe()
11 ** for locks on individual pipes.
12 ** 12-Feb-87 Fixed bug in OpenPipe(): previously ignored
13 ** lock passed in packet. Bug uncovered when
14 ** pipes became lockable, and thus assignable.
15 ** 26-Mar-87 Fixed bug in ClosePipe(): not closing r/w
16 ** mode properly (extraneous else).
19 #include <libraries/dos.h>
20 #include <libraries/dosextens.h>
21 #include <libraries/filehandler.h>
22 #include <exec/exec.h>
24 #include "pipelists.h"
25 #include "pipename.h"
26 #include "pipebuf.h"
27 #include "pipecreate.h"
28 #include "pipesched.h"
29 #include "pipe-handler.h"
31 #if PIPEDIR
32 # include "pipedir.h"
33 #endif /* PIPEDIR */
35 #ifdef DEBUG
36 # include "pipedebug.h"
37 #endif /* DEBUG */
41 /*---------------------------------------------------------------------------
42 ** pipecreate.c
43 ** ------------
44 ** This module handles opens and closes for pipes.
46 ** Visible Functions
47 ** -----------------
48 ** void OpenPipe (pkt, tapfh)
49 ** void ClosePipe (pkt)
50 ** void DiscardPipe (pipe)
52 ** Macros (in pipecreate.h)
53 ** ------------------------
54 ** - none -
56 ** Local Functions
57 ** ---------------
58 ** int TapFormsLoop (tapfh, pipe)
59 ** void OpenTap (pkt, tapname)
60 ** void CloseTap (tapfh)
65 /*---------------------------------------------------------------------------
66 ** OpenPipe() handles open requests. The DosPacket from the client and the
67 ** filehandle of the tap are sent. If tapfh is 0, but the name sent
68 ** indicates a tap is desired (see ParsePipeName() in pipename.c), then
69 ** an OpenTap() request is initiated and OpenPipe() is immediately exited.
70 ** Later, when the request returns (to HandleTapReply()), OpenPipe() is
71 ** called again with the same client packet and the newly returned tapfh.
72 ** If tapfh is nonzero, or if it is zero but no tap is desired, then
73 ** the an attempt to open the pipe is made. If a existent pipe with a tap is
74 ** to be opened and a new tapfh is given, the old tap is closed.
75 ** If the name's syntax is incorrect, then the request is returned
76 ** unsuccessful. Otherwise, if the pipe named by the request does not
77 ** already exist, a new pipe is created (if there is enough memory).
78 ** If it does exist, but it is already open for the mode requested, an error
79 ** is returned (a maximum of one reader and one writer is allowed).
80 ** A successful open returns the client's filehandle with its Arg1 field
81 ** pointing to a PIPEKEY, which in turn identifies the pipe and open mode.
82 ** Unless an OpenTap() is required, the packet is returned to the cleint
83 ** by this function. If an OpenTap() is required, it will be returned by the
84 ** the later call to this function when the tap open request is returned.
85 ** Note: the code which checks if the lock sent in the packet relies on
86 ** the fact that the pipe-handler does not allow subdirectories. If a lock
87 ** on a pipe is passed in, then that pipe is opened. Otherwise, the name is
88 ** parsed without reference to the lock.
91 static int TapFormsLoop(BPTR tapfh, PIPEDATA *pipe);
92 static void CloseTap(BPTR tapfh);
93 static void OpenTap(struct DosPacket *pkt,const char *tapname);
95 void OpenPipe (pkt, tapfh)
97 struct DosPacket *pkt;
98 BPTR tapfh;
101 LONG openmode;
102 struct FileHandle *handle;
103 struct FileLock *lock;
104 char *pipename = NULL, *tapname = NULL;
105 ULONG pipesize;
106 PIPEKEY *pipekey = NULL;
107 PIPEDATA *pipe = NULL;
110 pkt->dp_Res1= 0; /* error, for now */
112 if (! ParsePipeName (BPTRtoCptr (pkt->dp_Arg3), &pipename, &pipesize, &tapname))
113 { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
114 goto OPENREPLY;
117 if ( (tapfh == 0) && (tapname != NULL) && (tapname[0] != '\0') )
118 { OpenTap (pkt, tapname); /* start tap open request */
119 return; /* HandleTapReply() re-calls when request returns */
122 openmode= pkt->dp_Type;
123 lock= (struct FileLock *) BPTRtoCptr (pkt->dp_Arg2);
124 pipe= NULL;
126 if ( (lock == NULL) || ((pipe= (PIPEDATA *) lock->fl_Key) == NULL) )
127 { if (pipename[0] == '\0')
128 #if AUTONAME
129 pipename= get_autoname ((openmode == MODE_NEWFILE) || (openmode == MODE_READWRITE));
130 #else /* !AUTONAME */
131 { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
132 goto OPENREPLY;
134 #endif /* AUTONAME */
135 if (AUTONAME_STAR && pipename[0] == '*' && pipename[1] == 0) {
136 pipename= get_autoname ((openmode == MODE_NEWFILE) || (openmode == MODE_READWRITE));
139 pipe= FindPipe (pipename);
141 else /* packet's lock was on the pipe */
142 { if (pipename[0] != '\0')
143 { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
144 goto OPENREPLY;
147 pipename= pipe->name;
151 handle= (struct FileHandle *) BPTRtoCptr (pkt->dp_Arg1);
153 if ((pipekey= (PIPEKEY *) AllocMem (sizeof (PIPEKEY), ALLOCMEM_FLAGS)) == NULL)
154 { pkt->dp_Res2= ERROR_NO_FREE_STORE;
155 goto OPENREPLY;
159 if (pipe == NULL) /* then PIPE NOT FOUND */
160 { if (openmode == MODE_READONLY)
161 { pkt->dp_Res2= ERROR_OBJECT_NOT_FOUND;
162 goto OPENREPLY;
165 pkt->dp_Res2= ERROR_NO_FREE_STORE; /* in case of AllocMem error */
167 if ((pipe= (PIPEDATA *) AllocMem (sizeof (PIPEDATA), ALLOCMEM_FLAGS)) == NULL)
168 goto OPENMEMERR1;
170 if ((pipe->buf= AllocPipebuf (pipesize)) == NULL)
171 goto OPENMEMERR2;
173 if ((pipe->lock= (struct FileLock *) AllocMem (sizeof (struct FileLock), ALLOCMEM_FLAGS)) == NULL)
174 { FreePipebuf (pipe->buf);
175 OPENMEMERR2:
176 FreeMem (pipe, sizeof (PIPEDATA));
177 OPENMEMERR1:
178 goto OPENREPLY;
181 l_strcpy (pipe->name, pipename);
183 pipekey->pipe= pipe;
184 pipekey->openmode= openmode;
186 if (openmode == MODE_READONLY)
187 { pipekey->iotype= PIPEREAD;
188 pipe->flags |= OPEN_FOR_READ;
190 else if (openmode == MODE_NEWFILE)
191 { pipekey->iotype= PIPEWRITE;
192 pipe->flags= OPEN_FOR_WRITE;
194 else /* MODE_READWRITE */
195 { pipekey->iotype= PIPERW;
196 pipe->flags= (OPEN_FOR_READ | OPEN_FOR_WRITE);
199 InitList (&pipe->readerlist);
200 InitList (&pipe->writerlist);
202 pipe->tapfh= tapfh;
204 #if PIPEDIR
205 pipe->lockct= 0;
206 InitLock (pipe->lock, pipe);
207 #endif /* PIPEDIR */
209 InsertTail (&pipelist, pipe); /* at tail for directory's sake */
211 #ifdef DEBUG
212 OS ("*** created pipe '"); OS (pipe->name);
213 OS ("' [buflen "); OL (pipe->buf->len); OS ("]\n");
214 #endif /* DEBUG */
216 else /* PIPE WAS FOUND */
217 { if (TapFormsLoop (tapfh, pipe))
218 { pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
219 goto OPENREPLY;
222 pipekey->pipe= pipe;
223 pipekey->openmode= openmode;
225 pkt->dp_Res2= ERROR_OBJECT_IN_USE; /* in case of openmode error */
227 if (openmode == MODE_READONLY)
228 { if (pipe->flags & OPEN_FOR_READ)
229 goto OPENREPLY;
231 pipekey->iotype= PIPEREAD;
232 pipe->flags |= OPEN_FOR_READ;
234 else if (openmode == MODE_NEWFILE)
235 { if (pipe->flags & OPEN_FOR_WRITE)
236 goto OPENREPLY;
238 pipekey->iotype= PIPEWRITE;
239 pipe->flags |= OPEN_FOR_WRITE;
241 else /* MODE_READWRITE */
242 { if (pipe->flags & (OPEN_FOR_READ | OPEN_FOR_WRITE))
243 goto OPENREPLY;
245 pipekey->iotype= PIPERW;
246 pipe->flags= (OPEN_FOR_READ | OPEN_FOR_WRITE);
249 if (tapfh != 0)
250 { if (pipe->tapfh != 0)
251 CloseTap (pipe->tapfh); /* close old tap first */
253 pipe->tapfh= tapfh;
258 handle->fh_Arg1= (IPTR) pipekey; /* for identification on Read, Write, Close */
259 pkt->dp_Res1= 1;
260 pkt->dp_Res2= 0; /* for successful open */
263 OPENREPLY:
264 if (pkt->dp_Res1 == 0) /* then there was an error */
265 { if (pipekey != NULL)
266 FreeMem (pipekey, sizeof (PIPEKEY));
268 if (tapfh != 0)
269 CloseTap (tapfh);
271 #if PIPEDIR
272 else
273 SetPipeDate (pipe);
274 #endif /* PIPEDIR */
276 QuickReplyPkt(pkt);
281 /*---------------------------------------------------------------------------
282 ** This routine checks for "the old loop in the pipe trick" (86). If the
283 ** handler has a loop through its tap, the handler will endlessly pass
284 ** packets to itself. This would be disastrous if the handler is running at
285 ** high priority.
288 static int TapFormsLoop (tapfh, pipe)
290 BPTR tapfh;
291 PIPEDATA *pipe;
293 { struct FileHandle *handle;
294 PIPEKEY *tapkey;
295 PIPEDATA *tappipe;
296 int numchecks; /* protection */
299 for (numchecks= 0; ((tapfh != 0) && (numchecks < 10000)); ++numchecks)
300 { handle= (struct FileHandle *) BPTRtoCptr (tapfh);
302 if (handle->fh_Type == PipePort) /* then the tap is a pipe, too */
303 { if ( ((tapkey= (PIPEKEY *) handle->fh_Arg1) == NULL) ||
304 ((tappipe= tapkey->pipe) == NULL) )
305 return FALSE;
307 if (tappipe == pipe)
308 return TRUE;
310 tapfh= tappipe->tapfh;
312 else
313 return FALSE;
316 return FALSE;
321 /*---------------------------------------------------------------------------
322 ** The previous open performed on a pipe is terminated. The PIPEKEY
323 ** allocated for the client when the pipe was opened is freed. Then,
324 ** CheckWaiting() is called -- it will discard the pipe if it becomes empty
325 ** and is not opened for read or write.
328 void ClosePipe (pkt)
330 struct DosPacket *pkt;
332 { PIPEKEY *pipekey;
333 PIPEDATA *pipe;
334 void DeletePipe();
337 pipekey= (PIPEKEY *) pkt->dp_Arg1;
338 pipe= pipekey->pipe;
340 if ((pipekey->iotype == PIPEREAD) || (pipekey->iotype == PIPERW))
341 pipe->flags &= ~OPEN_FOR_READ;
343 if ((pipekey->iotype == PIPEWRITE) || (pipekey->iotype == PIPERW))
344 pipe->flags &= ~OPEN_FOR_WRITE;
346 FreeMem (pipekey, sizeof (PIPEKEY));
348 CheckWaiting (pipe); /* will discard if empty */
350 pkt->dp_Res1= 1;
351 pkt->dp_Res2= 0;
353 QuickReplyPkt (pkt);
358 /*---------------------------------------------------------------------------
359 ** Remove a pipe from the pipe list and release its memory. The pipe is
360 ** assumed empty and having no clients.
363 void DiscardPipe (pipe)
365 PIPEDATA *pipe;
368 #ifdef DEBUG
369 OS ("*** discarding pipe '"); OS (pipe->name); OS ("'\n");
370 #endif /* DEBUG */
372 Delete (&pipelist, pipe);
374 FreePipebuf (pipe->buf);
375 FreeMem (pipe->lock, sizeof (struct FileLock));
377 if (pipe->tapfh != 0)
378 CloseTap (pipe->tapfh);
380 FreeMem (pipe, sizeof (PIPEDATA));
385 /*---------------------------------------------------------------------------
386 ** An open request for a tap is performed. A WAITINGDATA structure is
387 ** allocated to hold the client packet until later. HandleTapReply() will
388 ** deal with the reply and, if successful, re-call OpenPipe().
391 static void OpenTap (pkt, tapname)
393 struct DosPacket *pkt;
394 const char *tapname;
396 { char *Bname;
397 struct FileHandle *handle;
398 WAITINGDATA *wd;
399 struct DosPacket *tappkt;
400 struct MsgPort *Handler;
401 struct FileLock *Lock;
402 void StartTapIO();
405 if ( (tapname == NULL) ||
406 ((Bname= (char *) AllocMem (OPENTAP_STRSIZE, ALLOCMEM_FLAGS)) == NULL) )
407 goto OPENTAPERR;
409 if ((handle= (struct FileHandle *) AllocMem (sizeof (struct FileHandle), (ALLOCMEM_FLAGS | MEMF_CLEAR))) == NULL)
410 goto OPENTAPERR1;
412 if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL)
413 goto OPENTAPERR2;
415 if ((tappkt= AllocPacket (TapReplyPort)) == NULL)
416 goto OPENTAPERR3;
418 if ((Handler= DeviceProc (tapname)) == NULL)
419 { FreePacket (tappkt);
420 OPENTAPERR3:
421 FreeMem (wd, sizeof (WAITINGDATA));
422 OPENTAPERR2:
423 FreeMem (handle, sizeof (struct FileHandle));
424 OPENTAPERR1:
425 FreeMem (Bname, OPENTAP_STRSIZE);
426 OPENTAPERR:
427 pkt->dp_Res1= 0;
428 pkt->dp_Res2= ERROR_INVALID_COMPONENT_NAME;
429 QuickReplyPkt (pkt);
430 return;
433 Lock= (struct FileLock *) IoErr ();
434 CstrtoBSTR (tapname, Bname, OPENTAP_STRSIZE);
436 handle->fh_Pos= -1;
437 handle->fh_End= -1;
438 handle->fh_Type= Handler; /* initialize file handle */
440 wd->pkt= tappkt;
441 wd->pktinfo.tapwait.clientpkt= pkt;
442 wd->pktinfo.tapwait.handle= handle; /* for HandleTapReply() */
444 StartTapIO ( tappkt, ACTION_FINDOUTPUT,
445 CptrtoBPTR (handle), CptrtoBPTR (Lock), CptrtoBPTR (Bname),
446 Handler );
448 InsertHead (&tapwaitlist, wd);
453 /*---------------------------------------------------------------------------
454 ** A close request for a tap filehandle is initiated. When HandleTapReply()
455 ** gets the reply, it merely discards it.
458 static void CloseTap (tapfh)
460 BPTR tapfh;
462 { struct FileHandle *taphandle;
463 struct DosPacket *tappkt;
464 WAITINGDATA *wd;
465 void StartTapIO();
468 taphandle= (struct FileHandle *) BPTRtoCptr (tapfh);
470 if ((tappkt= AllocPacket (TapReplyPort)) == NULL)
471 goto CLOSETAPERR;
473 if ((wd= (WAITINGDATA *) AllocMem (sizeof (WAITINGDATA), ALLOCMEM_FLAGS)) == NULL)
474 { FreePacket (tappkt);
475 CLOSETAPERR:
476 FreeMem (taphandle, sizeof (struct FileHandle));
477 #ifdef DEBUG
478 OS ("!!! ERROR - CloseTap() failed\n");
479 #endif /* DEBUG */
480 return;
483 wd->pkt= tappkt;
484 /* don't need ...tapwait.clientpkt */
485 wd->pktinfo.tapwait.handle= taphandle; /* for HandleTapReply() */
487 StartTapIO ( tappkt, ACTION_END,
488 taphandle->fh_Arg1, 0, 0,
489 taphandle->fh_Type );
491 InsertHead (&tapwaitlist, wd);