- Set a default PCM volume so that something can be heard when driver is
[AROS.git] / workbench / devs / pipefs_handler.c
blobf70c5ba277f5e05bc301c4c2a4fea0d9dc904521
1 /*
2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #define DEBUG 0
7 #include <aros/debug.h>
9 #include <exec/errors.h>
10 #include <exec/resident.h>
11 #include <exec/memory.h>
12 #include <exec/semaphores.h>
13 #include <exec/lists.h>
14 #include <exec/nodes.h>
15 #include <proto/exec.h>
16 #include <utility/tagitem.h>
17 #include <dos/dosextens.h>
18 #include <dos/filesystem.h>
19 #include <proto/dos.h>
20 #include <aros/symbolsets.h>
21 #include <aros/asmcall.h>
22 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
23 #include "pipefs_handler_gcc.h"
24 #endif
26 #include LC_LIBDEFS_FILE
28 #include <string.h>
29 #include <stddef.h>
31 AROS_UFP3(LONG, pipefsproc,
32 AROS_UFPA(char *,argstr,A0),
33 AROS_UFPA(ULONG,argsize,D0),
34 AROS_UFPA(struct ExecBase *,SysBase,A6));
36 struct pipefsmessage
38 struct Message msg;
39 struct IOFileSys *iofs;
40 LONG curlen;
43 struct dirnode
45 struct MinNode node;
46 struct dirnode *parent; /* Parent directory */
47 STRPTR name;
48 LONG type;
49 struct DateStamp datestamp;
50 ULONG numusers;
51 struct List files;
54 struct filenode
56 struct MinNode node;
57 struct dirnode *parent;
58 STRPTR name;
59 LONG type;
60 struct DateStamp datestamp;
61 ULONG numusers; /* Number of actual users of this pipe */
62 ULONG numwriters; /* Num of actual writers */
63 ULONG numreaders; /* Num of actual readers */
64 struct List waitinglist; /* List of files waiting for a reader or a writer to become available */
65 struct List pendingwrites; /* List of pending write requestes */
66 struct List pendingreads; /* List of pending read requestes */
67 ULONG flags; /* See below */
70 /* Flags for filenodes */
71 #define FNF_DELETEONCLOSE 1 /* Specify this flag when you want a pipe to be deleted
72 when it's closed. Useful for unnamed pipes */
73 struct usernode
75 struct filenode *fn;
76 ULONG mode;
79 static size_t LenFirstPart (CONST_STRPTR path);
80 static struct filenode *FindFile (struct pipefsbase *pipefsbase, struct dirnode **dn_ptr, CONST_STRPTR path);
81 static struct filenode *GetFile (struct pipefsbase *pipefsbase, CONST_STRPTR filename, struct dirnode *dn, ULONG mode, ULONG *err);
82 static ULONG SendRequest (struct pipefsbase *pipefsbase, struct IOFileSys *iofs, BOOL abort);
83 static STRPTR StrDup (struct pipefsbase *pipefsbase, CONST_STRPTR str);
86 static int GM_UNIQUENAME(Init)(LIBBASETYPEPTR pipefsbase)
88 DOSBase = (struct DosLibrary *)OpenLibrary("dos.library",39);
90 if(DOSBase)
92 struct TagItem taglist[]=
94 {NP_Entry, (IPTR)pipefsproc},
95 {NP_Name, (IPTR)"pipefs.handler process"},
96 {NP_UserData, (IPTR)pipefsbase},
97 {TAG_DONE, 0}
100 pipefsbase->proc = CreateNewProc(taglist);
102 if (pipefsbase->proc)
103 return TRUE;
105 CloseLibrary((struct Library *)DOSBase);
108 return FALSE;
111 static int GM_UNIQUENAME(Open)
113 LIBBASETYPEPTR pipefsbase,
114 struct IOFileSys *iofs,
115 ULONG unitnum,
116 ULONG flags
119 struct usernode *un;
120 struct dirnode *dn;
122 /* Mark Message as recently used. */
123 iofs->IOFS.io_Message.mn_Node.ln_Type=NT_REPLYMSG;
125 /* Build a fake usernode */
126 un = AllocVec(sizeof(*un),MEMF_PUBLIC|MEMF_CLEAR);
127 if(un)
129 dn = AllocVec(sizeof(*dn),MEMF_PUBLIC|MEMF_CLEAR);
130 if (dn)
132 dn->type = ST_ROOT;
133 dn->name = iofs->io_Union.io_OpenDevice.io_DosName;
134 dn->parent = NULL;
136 NEWLIST(&dn->files);
137 DateStamp(&dn->datestamp);
139 un->fn = (struct filenode *)dn;
140 iofs->IOFS.io_Unit=(struct Unit *)un;
141 iofs->IOFS.io_Device=&pipefsbase->device;
143 iofs->IOFS.io_Error=0;
145 return TRUE;
148 FreeVec(un);
151 iofs->io_DosError=ERROR_NO_FREE_STORE;
153 iofs->IOFS.io_Error=IOERR_OPENFAIL;
155 return FALSE;
158 static int GM_UNIQUENAME(Close)
160 LIBBASETYPEPTR pipefsbase,
161 struct IOFileSys *iofs
164 struct usernode *un;
165 struct dirnode *dn;
167 un = (struct usernode *)iofs->IOFS.io_Unit;
168 dn = (struct dirnode *)un->fn;
170 if(!IsListEmpty(&dn->files))
172 iofs->io_DosError=ERROR_OBJECT_IN_USE;
173 return FALSE;
176 FreeVec(dn);
177 FreeVec(un);
179 iofs->io_DosError=0;
181 return TRUE;
184 static int GM_UNIQUENAME(Expunge)(LIBBASETYPEPTR pipefsbase)
187 This function is single-threaded by exec by calling Forbid.
188 Never break the Forbid() or strange things might happen.
191 SendRequest(pipefsbase, NULL, TRUE);
193 /* Free all resources */
194 CloseLibrary((struct Library *)pipefsbase->dosbase);
196 return TRUE;
199 AROS_LH1(void, beginio,
200 AROS_LHA(struct IOFileSys *, iofs, A1),
201 struct pipefsbase *, pipefsbase, 5, Pipefs)
203 AROS_LIBFUNC_INIT
204 LONG error=0;
205 BOOL enqueued = FALSE;
207 D(bug("COMMAND %d\n", iofs->IOFS.io_Command));
208 switch(iofs->IOFS.io_Command)
210 case FSA_OPEN:
211 case FSA_OPEN_FILE:
212 case FSA_PIPE:
213 case FSA_EXAMINE:
214 case FSA_EXAMINE_NEXT:
215 case FSA_READ:
216 case FSA_WRITE:
217 case FSA_CLOSE:
218 case FSA_CREATE_DIR:
219 case FSA_DELETE_OBJECT:
220 case FSA_FILE_MODE:
221 error = SendRequest(pipefsbase, iofs, FALSE);
222 enqueued = !error;
223 break;
225 case FSA_SEEK:
226 error = ERROR_SEEK_ERROR;
227 break;
228 case FSA_IS_FILESYSTEM:
229 iofs->io_Union.io_IS_FILESYSTEM.io_IsFilesystem = TRUE;
230 break;
231 case FSA_SET_FILE_SIZE:
232 case FSA_EXAMINE_ALL:
233 case FSA_CREATE_HARDLINK:
234 case FSA_CREATE_SOFTLINK:
235 case FSA_RENAME:
236 error = ERROR_NOT_IMPLEMENTED;
237 break;
239 default:
240 error = ERROR_ACTION_NOT_KNOWN;
241 break;
244 /* Set error code */
245 iofs->io_DosError=error;
247 /* If the quick bit is not set and the request hasn't been redirected
248 send the message to the port
250 if(!(iofs->IOFS.io_Flags&IOF_QUICK) && !enqueued)
251 ReplyMsg(&iofs->IOFS.io_Message);
253 AROS_LIBFUNC_EXIT
256 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
257 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
258 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
259 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge), 0)
261 AROS_LH1(LONG, abortio,
262 AROS_LHA(struct IOFileSys *, iofs, A1),
263 struct pipefsbase *, pipefsbase, 6, Pipefs)
265 AROS_LIBFUNC_INIT
267 return SendRequest(pipefsbase, iofs, TRUE);
269 AROS_LIBFUNC_EXIT
272 static ULONG SendRequest(struct pipefsbase *pipefsbase, struct IOFileSys *iofs, BOOL abort)
274 struct pipefsmessage *msg = AllocVec(sizeof(*msg), MEMF_PUBLIC);
276 if (msg)
278 msg->msg.mn_Node.ln_Type = NT_MESSAGE;
279 msg->msg.mn_Node.ln_Name = "PIPEFSMSG";
280 msg->msg.mn_Length = sizeof(struct pipefsmessage);
281 msg->iofs = iofs;
282 msg->curlen = abort;
284 if (iofs)
286 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_MESSAGE;
287 iofs->IOFS.io_Flags &= ~IOF_QUICK;
290 PutMsg(&pipefsbase->proc->pr_MsgPort, (struct Message *)msg);
292 return 0;
295 return ERROR_NO_FREE_STORE;
298 /* The helper process */
300 #define SendBack(msg, err) \
302 msg->iofs->io_DosError = err; \
303 ReplyMsg(&(msg)->iofs->IOFS.io_Message); \
304 FreeVec(msg); \
307 static STRPTR StrDup(struct pipefsbase *pipefsbase, CONST_STRPTR str)
309 size_t len = strlen(str)+1;
310 STRPTR ret = AllocVec(len, MEMF_ANY);
312 if (ret)
313 CopyMem(str, ret, len);
315 return ret;
319 Return the len of the first part in the path.
321 EXAMPLE
322 LenFirstPart("yyy/xxx") would return 3
323 LenFirstPart("xxxx") would return 4
326 static size_t LenFirstPart(CONST_STRPTR path)
328 size_t len = 0;
330 for (; path[0] && path[0] != '/'; path++, len++);
332 return len;
335 static struct filenode *FindFile(struct pipefsbase *pipefsbase, struct dirnode **dn_ptr, CONST_STRPTR path)
337 #define dn (*dn_ptr)
339 size_t len;
340 CONST_STRPTR nextpart;
341 struct filenode *fn;
343 while (path[0] == '/' && dn)
345 dn = dn->parent;
346 path++;
349 if (!dn) return NULL;
351 if (!path[0]) return (struct filenode *)dn;
353 if (dn->type <= 0)
355 D(bug("User wants %S to be a directory, but it's a file.\n", dn->name));
356 dn = NULL;
357 return NULL;
360 len = LenFirstPart(path);
361 nextpart = &path[len];
362 fn = (struct filenode *)GetHead(&dn->files);
364 D(bug("Searching for %.*S.\n", len, path));
366 while (fn) {
367 if (fn->name != NULL) {
368 D(bug("Comparing %S with %.*S.\n", fn->name, len, path));
369 if (strlen(fn->name) == len && strncasecmp(fn->name, path, len) == 0)
370 break;
372 fn = (struct filenode *)GetSucc((struct Node *)fn);
375 if (fn)
377 if (nextpart[0] == '/') nextpart++;
379 dn = (struct dirnode *)fn;
380 fn = FindFile(pipefsbase, &dn, nextpart);
383 return fn;
385 #undef dn
388 static struct filenode *NewFileNode(struct pipefsbase *pipefsbase, STRPTR filename, ULONG flags, struct dirnode *dn, ULONG *err)
390 struct filenode *fn;
392 fn = AllocVec(sizeof(*fn), MEMF_PUBLIC|MEMF_CLEAR);
393 if (fn)
395 if (filename == NULL || (fn->name = StrDup(pipefsbase, filename)) != NULL) {
396 fn->type = ST_PIPEFILE;
398 DateStamp(&fn->datestamp);
399 NEWLIST(&fn->waitinglist);
400 NEWLIST(&fn->pendingwrites);
401 NEWLIST(&fn->pendingreads);
403 fn->parent = dn;
404 fn->flags = flags;
406 AddTail(&dn->files, (struct Node *)fn);
407 D(bug("New file created and added to the list\n"));
409 return fn;
412 FreeVec(fn);
415 D(bug("AllocVec Failed. No more memory available\n"));
416 *err = ERROR_NO_FREE_STORE;
417 return NULL;
420 static struct filenode *GetFile(struct pipefsbase *pipefsbase, CONST_STRPTR filename, struct dirnode *dn, ULONG mode, ULONG *err)
422 struct filenode *fn;
424 D(bug("User wants to open file %S.\n", filename));
425 D(bug("Current directory is %S\n", dn->name));
427 if (dn && !dn->parent && strcmp(filename, "__UNNAMED__") == 0)
429 return NewFileNode(pipefsbase, "__UNNAMED__", FNF_DELETEONCLOSE, dn, err);
432 fn = FindFile(pipefsbase, &dn, filename);
433 if (!fn)
435 D(bug("The file couldn't be found.\n"));
437 if (dn && mode&FMF_CREATE)
439 D(bug("But the user wants it to be created.\n"));
441 return NewFileNode(pipefsbase, FilePart(filename), 0, dn, err);
443 else
445 *err = ERROR_OBJECT_NOT_FOUND;
449 if (fn && fn->type > 0 && mode&(FMF_WRITE|FMF_READ))
451 D(bug("The file is a directory, cannot be open for reading/writing\n"));
452 *err = ERROR_OBJECT_WRONG_TYPE;
453 return NULL;
456 return fn;
459 #undef SysBase
460 #ifndef kprintf
461 struct ExecBase *SysBase;
462 #else
463 # define SysBase _SysBase
464 #endif
467 AROS_UFH3(LONG, pipefsproc,
468 AROS_UFHA(char *,argstr,A0),
469 AROS_UFHA(ULONG,argsize,D0),
470 AROS_UFHA(struct ExecBase *,_SysBase,A6))
472 AROS_USERFUNC_INIT
474 struct Process *me;
475 struct pipefsbase *pipefsbase;
476 struct pipefsmessage *msg;
477 struct usernode *un;
478 struct filenode *fn;
479 BOOL cont = TRUE;
481 SysBase = _SysBase;
483 me = (struct Process *)FindTask(0);
484 pipefsbase = me->pr_Task.tc_UserData;
489 WaitPort(&(me->pr_MsgPort));
491 while
493 (msg =(struct pipefsmessage *)GetMsg(&(me->pr_MsgPort))) &&
494 (cont = (msg->iofs != 0))
497 D(bug("Message received.\n"));
499 un = (struct usernode *)msg->iofs->IOFS.io_Unit;
500 fn = un->fn;
502 if (msg->curlen) /* This field is abused too see whethet the user wants to abort the request */
504 struct pipefsmessage *msg2;
505 BOOL found = FALSE;
507 D(bug("The user wants to abort this request.\n"));
509 ForeachNode(&fn->waitinglist, msg2)
511 if (msg2->iofs == msg->iofs)
513 found = TRUE;
515 fn->numusers--;
516 if (un->mode & FMF_WRITE)
517 fn->numwriters--;
518 if (un->mode & FMF_READ)
519 fn->numreaders--;
521 FreeVec(un);
523 break;
526 if (!found && (un->mode & FMF_WRITE))
528 ForeachNode(&fn->pendingwrites, msg2)
530 if (msg2->iofs == msg->iofs)
532 found = TRUE;
533 break;
537 if (!found && (un->mode & FMF_READ))
539 ForeachNode(&fn->pendingreads, msg2)
541 if (msg2->iofs == msg->iofs)
543 found = TRUE;
544 break;
549 if (found)
551 D(bug("Aborting the request.\n"));
552 Remove((struct Node *)msg2);
553 msg2->iofs->IOFS.io_Error = IOERR_ABORTED;
554 SendBack(msg2, ERROR_INTERRUPTED);
556 else
558 D(bug("There was no I/O in process for this request.\n"));
561 FreeVec(msg);
562 continue;
565 switch (msg->iofs->IOFS.io_Command)
567 case FSA_OPEN:
568 msg->iofs->io_Union.io_OPEN.io_FileMode &= ~(FMF_WRITE|FMF_READ);
569 /* Fall through */
570 case FSA_OPEN_FILE:
572 struct usernode *un;
573 BOOL stillwaiting;
574 ULONG err;
576 D(bug("Command is OPEN\n"));
579 I would have liked to put this AFTER GetFile(),
580 but then it would have been really difficult to
581 undo what's done in GetFile() if the following AllocVec()
582 failed...
584 un = AllocVec(sizeof(*un), MEMF_PUBLIC);
585 if (!un)
587 SendBack(msg, ERROR_NO_FREE_STORE);
588 continue;
591 un->mode = msg->iofs->io_Union.io_OPEN.io_FileMode;
593 fn = GetFile(pipefsbase, msg->iofs->io_Union.io_OPEN.io_Filename, (struct dirnode *)fn, un->mode, &err);
594 if (!fn)
596 FreeVec(un);
597 SendBack(msg, err);
598 continue;
601 D(bug("File requested found.\n"));
602 D(bug("The requested file is %s.\n",
603 fn->type <= 0 ?
604 "a pipe":
605 "a directory"));
607 msg->iofs->IOFS.io_Unit = (struct Unit *)un;
608 fn->numusers++;
609 un->fn = fn;
611 if (fn->type > 0)
613 SendBack(msg, 0);
614 continue;
617 stillwaiting = !fn->numwriters || !fn->numreaders;
619 if (un->mode == FMF_MODE_OLDFILE) un->mode &= ~FMF_WRITE;
620 if (un->mode == FMF_MODE_NEWFILE) un->mode &= ~FMF_READ;
622 if (un->mode & FMF_READ)
624 D(bug("User wants to read. "));
625 fn->numreaders++;
627 if (un->mode & FMF_WRITE)
629 D(bug("User wants to write. "));
630 fn->numwriters++;
633 D(bug("There are %d readers and %d writers at the moment\n", fn->numreaders, fn->numwriters));
635 if (!fn->numwriters || !fn->numreaders)
637 if (un->mode&(FMF_WRITE|FMF_READ) && !(un->mode&FMF_NONBLOCK))
640 If we're lacking of writers or readers
641 then add this message to a waiting list.
643 D(bug("There are no %s at the moment, so this %s must wait\n",
644 fn->numwriters?"readers":"writers",
645 fn->numwriters?"writer":"reader"));
647 AddTail(&fn->waitinglist, (struct Node *)msg);
649 else
650 SendBack(msg, 0);
652 else
654 if (stillwaiting)
657 Else wake up all the ones that were still waiting
659 struct pipefsmessage *msg;
661 D(bug("Finally there are enough readers and writers! "
662 "Wake up all of them\n"));
664 while ((msg = (struct pipefsmessage *)RemHead(&fn->waitinglist)))
665 SendBack(msg, 0);
667 SendBack(msg, 0);
670 continue;
673 case FSA_PIPE: {
674 struct usernode *reader, *writer;
675 LONG err;
677 D(bug("Command is FSA_PIPE\n"));
679 if ((reader = AllocVec(sizeof(struct usernode), MEMF_PUBLIC)) == NULL) {
680 SendBack(msg, ERROR_NO_FREE_STORE);
681 continue;
683 if ((writer = AllocVec(sizeof(struct usernode), MEMF_PUBLIC)) == NULL) {
684 SendBack(msg, ERROR_NO_FREE_STORE);
685 continue;
688 fn = NewFileNode(pipefsbase, NULL, FNF_DELETEONCLOSE, (struct dirnode *) fn, &err);
689 if (fn == NULL) {
690 FreeVec(reader);
691 FreeVec(writer);
692 SendBack(msg, err);
693 continue;
696 msg->iofs->IOFS.io_Unit = (struct Unit *) reader;
697 msg->iofs->io_Union.io_PIPE.io_Writer = (struct Unit *) writer;
699 reader->fn = writer->fn = fn;
700 fn->numusers = 2;
702 reader->mode = FMF_READ;
703 fn->numreaders++;
705 writer->mode = FMF_WRITE;
706 fn->numwriters++;
708 SendBack(msg, 0);
710 continue;
713 case FSA_CLOSE:
714 D(bug("Command is FSA_CLOSE\n"));
716 if (un->mode & FMF_READ)
718 D(bug("User was a reader. "));
719 fn->numreaders--;
720 D(bug("There are %d readers at the moment\n", fn->numreaders));
721 if (!fn->numreaders)
723 struct pipefsmessage *msg;
725 D(bug("There are no readers anymore. %s\n",
726 IsListEmpty(&fn->pendingwrites) ?
727 "There are no pending writes" :
728 "Reply to all the waiting writers"));
730 while ((msg = (struct pipefsmessage *)RemHead(&fn->pendingwrites)))
731 SendBack(msg, 0);
734 if (un->mode & FMF_WRITE)
736 D(bug("User was a writer. "));
737 fn->numwriters--;
738 D(bug("There are %d writers at the moment\n", fn->numwriters));
740 if (!fn->numwriters)
742 struct pipefsmessage *msg;
744 D(bug("There are no writers anymore. %s\n",
745 IsListEmpty(&fn->pendingreads) ?
746 "There are no pending reads" :
747 "Reply to all the waiting readers"));
748 while ((msg = (struct pipefsmessage *)RemHead(&fn->pendingreads)))
750 msg->iofs->io_Union.io_READ_WRITE.io_Length =
751 msg->iofs->io_Union.io_READ_WRITE.io_Length - msg->curlen;
752 SendBack(msg, 0);
757 un->fn->numusers--;
759 if (!un->fn->numusers && un->fn->type <= 0 && (un->fn->flags & FNF_DELETEONCLOSE))
761 Remove((struct Node *)fn);
762 if (fn->name != NULL)
763 FreeVec(fn->name);
764 FreeVec(fn);
767 FreeVec(un);
768 SendBack(msg, 0);
770 continue;
771 case FSA_EXAMINE:
773 struct ExAllData *ead = msg->iofs->io_Union.io_EXAMINE.io_ead;
774 const ULONG type = msg->iofs->io_Union.io_EXAMINE.io_Mode;
775 const ULONG size = msg->iofs->io_Union.io_EXAMINE.io_Size;
776 STRPTR next, end;
778 static const ULONG sizes[]=
781 offsetof(struct ExAllData,ed_Type),
782 offsetof(struct ExAllData,ed_Size),
783 offsetof(struct ExAllData,ed_Prot),
784 offsetof(struct ExAllData,ed_Days),
785 offsetof(struct ExAllData,ed_Comment),
786 offsetof(struct ExAllData,ed_OwnerUID),
787 sizeof(struct ExAllData)
790 D(bug("Command is EXAMINE\n"));
792 if (fn->name == NULL) {
793 SendBack(msg, ERROR_OBJECT_NOT_FOUND);
794 continue;
797 D(bug("Examining file %S\n", fn->name));
799 if (type > ED_OWNER)
801 D(bug("The user requested an invalid type\n"));
802 SendBack(msg, ERROR_BAD_NUMBER);
803 continue;
806 next = (STRPTR)ead + sizes[type];
807 end = (STRPTR)ead + size;
809 if(next>end) /* > is correct. Not >= */
811 SendBack(msg, ERROR_BUFFER_OVERFLOW);
812 continue;
815 if (fn->type > 0)
817 msg->iofs->io_DirPos = (LONG)GetHead(&((struct dirnode *)fn)->files);
819 else
821 msg->iofs->io_DirPos = (LONG)fn;
824 switch(type)
826 case ED_OWNER:
827 ead->ed_OwnerUID = 0;
828 ead->ed_OwnerGID = 0;
830 /* Fall through */
831 case ED_COMMENT:
832 ead->ed_Comment = NULL;
834 /* Fall through */
835 case ED_DATE:
836 ead->ed_Days = fn->datestamp.ds_Days;
837 ead->ed_Mins = fn->datestamp.ds_Minute;
838 ead->ed_Ticks = fn->datestamp.ds_Tick;
840 /* Fall through */
841 case ED_PROTECTION:
842 ead->ed_Prot = 0;
844 /* Fall through */
845 case ED_SIZE:
846 ead->ed_Size = 0;
848 /* Fall through */
849 case ED_TYPE:
850 ead->ed_Type = fn->type;
852 /* Fall through */
853 case ED_NAME:
855 STRPTR name = fn->name;
856 ead->ed_Name = next;
858 for (;;)
860 if (next >= end)
862 SendBack(msg, ERROR_BUFFER_OVERFLOW);
863 continue;
866 if (!(*next++ = *name++))
868 break;
874 ead->ed_Next = (struct ExAllData *)(((IPTR)next + AROS_PTRALIGN - 1) & ~(AROS_PTRALIGN - 1));
876 SendBack(msg, 0);
877 continue;
879 case FSA_EXAMINE_NEXT:
881 struct FileInfoBlock *fib = msg->iofs->io_Union.io_EXAMINE_NEXT.io_fib;
882 struct filenode *fn = (struct filenode *)fib->fib_DiskKey;
884 D(bug("Command is EXAMINE_NEXT\n"));
886 if (!fn)
888 D(bug("There are no more entries in this directory\n"));
889 SendBack(msg, ERROR_NO_MORE_ENTRIES);
890 continue;
893 if (fn->name == NULL) {
894 SendBack(msg, ERROR_OBJECT_NOT_FOUND);
895 continue;
898 D(bug("Current directory is %S. Current file is %S\n", fn->parent->name, fn->name));
900 fib->fib_OwnerUID = 0;
901 fib->fib_OwnerGID = 0;
902 fib->fib_Date.ds_Days = fn->datestamp.ds_Days;
903 fib->fib_Date.ds_Minute = fn->datestamp.ds_Minute;
904 fib->fib_Date.ds_Tick = fn->datestamp.ds_Tick;
905 fib->fib_Protection = 0;
906 fib->fib_Size = 0;
907 fib->fib_DirEntryType = fn->type;
909 strncpy(fib->fib_FileName, fn->name, MAXFILENAMELENGTH - 1);
910 fib->fib_Comment[0] = '\0';
912 fib->fib_DiskKey = (IPTR)GetSucc(fn);
913 SendBack(msg, 0);
915 continue;
917 case FSA_CREATE_DIR:
919 CONST_STRPTR filename = msg->iofs->io_Union.io_CREATE_DIR.io_Filename;
920 struct dirnode *parent = (struct dirnode *)fn;
921 struct dirnode *dn;
923 D(bug("Command is FSA_CREATE_DIR\n"));
924 D(bug("Current directory is %S\n", parent->name));
925 D(bug("User wants to create directory %S\n", filename));
927 dn = (struct dirnode *)FindFile(pipefsbase, &parent, filename);
928 if (dn)
930 D(bug("The object %S already exists\n", filename));
931 SendBack(msg, ERROR_OBJECT_EXISTS);
932 continue;
934 else
935 if (!parent)
937 D(bug("The path is not valid.\n"));
938 SendBack(msg, ERROR_OBJECT_NOT_FOUND);
939 continue;
944 !(un = AllocVec(sizeof(*un), MEMF_PUBLIC)) ||
945 !(dn = AllocVec(sizeof(*dn), MEMF_PUBLIC)) ||
946 !(dn->name = StrDup(pipefsbase, filename))
949 SendBack(msg, ERROR_NO_FREE_STORE);
950 continue;
953 D(bug("Ok, there's room for this directory.\n"));
954 AddTail(&parent->files, (struct Node *)dn);
955 dn->parent = parent;
956 dn->numusers = 0;
957 dn->type = ST_USERDIR;
958 NEWLIST(&dn->files);
959 DateStamp(&dn->datestamp);
961 un->fn = (struct filenode *)dn;
962 un->mode = 0;
963 msg->iofs->IOFS.io_Unit = (struct Unit *)un;
965 SendBack(msg, 0);
966 continue;
968 case FSA_FILE_MODE:
969 D(bug("Command is FSA_FILE_MODE\n"));
970 D(bug("Current mode is 0x%08x\n", un->mode));
972 un->mode &= ~msg->iofs->io_Union.io_FILE_MODE.io_Mask;
973 un->mode |= msg->iofs->io_Union.io_FILE_MODE.io_FileMode;
975 D(bug("New mode is 0x%08x\n", un->mode));
977 SendBack(msg, 0);
978 continue;
979 case FSA_DELETE_OBJECT:
981 CONST_STRPTR filename = msg->iofs->io_Union.io_DELETE_OBJECT.io_Filename;
982 struct dirnode *dn = (struct dirnode *)fn;
984 if (fn->name == NULL) {
985 SendBack(msg, ERROR_OBJECT_NOT_FOUND);
986 continue;
989 D(bug("Command is FSA_DELETE_OBJECT\n"));
990 D(bug("Current directory is %S\n", fn->name));
991 D(bug("User wants to delete the object %S\n", filename));
993 fn = FindFile(pipefsbase, &dn, filename);
994 if (!fn)
996 D(bug("The object doesn't exist\n"));
997 SendBack(msg, ERROR_OBJECT_NOT_FOUND);
998 continue;
1000 if (fn->type == ST_ROOT)
1002 D(bug("The object is the root directory. Cannot be deleted\n"));
1003 SendBack(msg, ERROR_OBJECT_WRONG_TYPE);
1004 continue;
1006 if (fn->numusers)
1008 D(bug("The object is in use, cannot be deleted\n"));
1009 SendBack(msg, ERROR_OBJECT_IN_USE);
1010 continue;
1012 if (fn->type > 0 && !IsListEmpty(&((struct dirnode *)fn)->files))
1014 D(bug("The object is a directory, but is not empty, thus cannot be deleted\n"));
1015 SendBack(msg, ERROR_DIRECTORY_NOT_EMPTY);
1016 continue;
1019 D(bug("Removing the object from it's parent directory\n"));
1021 Remove((struct Node *)fn);
1022 FreeVec(fn->name);
1023 FreeVec(fn);
1025 SendBack(msg, 0);
1026 continue;
1028 case FSA_WRITE:
1029 D(bug("Command is FSA_WRITE. "));
1030 if (!(un->mode & FMF_WRITE))
1032 D(bug("User doesn't have permission to write.\n"));
1033 SendBack(msg, ERROR_BAD_STREAM_NAME);
1034 continue;
1036 if (!fn->numreaders)
1038 D(bug("There are no more readers: PIPE BROKEN.\n"));
1039 SendBack(msg, ERROR_BROKEN_PIPE);
1040 continue;
1042 if (un->mode & FMF_NONBLOCK && IsListEmpty(&fn->pendingreads))
1044 D(bug("There are no pending reads and the pipe is in nonblocking mode, so return EWOULDBLOCK\n"));
1045 SendBack(msg, ERROR_WOULD_BLOCK);
1046 continue;
1049 D(bug("Enqueing the message\n"));
1050 msg->curlen = msg->iofs->io_Union.io_READ_WRITE.io_Length;
1051 AddTail(&fn->pendingwrites, (struct Node *)msg);
1052 break;
1053 case FSA_READ:
1054 D(bug("Command is FSA_READ. "));
1055 if (!(un->mode & FMF_READ))
1057 D(bug("User doesn't have permission to read.\n"));
1058 SendBack(msg, ERROR_BAD_STREAM_NAME);
1059 continue;
1061 if (!fn->numwriters)
1063 D(bug("There's no data to read: send EOF\n"));
1064 msg->iofs->io_Union.io_READ_WRITE.io_Length = 0;
1065 SendBack(msg, 0);
1066 continue;
1068 if (un->mode & FMF_NONBLOCK && IsListEmpty(&fn->pendingwrites))
1070 D(bug("There are no pending writes and the pipe is in nonblocking mode, so return EWOULDBLOCK\n"));
1071 SendBack(msg, ERROR_WOULD_BLOCK);
1072 continue;
1075 D(bug("Enqueing the message\n"));
1076 msg->curlen = msg->iofs->io_Union.io_READ_WRITE.io_Length;
1077 AddTail(&fn->pendingreads, (struct Node *)msg);
1078 break;
1081 while (!IsListEmpty(&fn->pendingwrites) && !IsListEmpty(&fn->pendingreads))
1083 struct pipefsmessage *rmsg = (struct pipefsmessage *)RemHead(&fn->pendingreads);
1084 struct pipefsmessage *wmsg = (struct pipefsmessage *)RemHead(&fn->pendingwrites);
1086 ULONG len = (rmsg->curlen > wmsg->curlen) ?
1087 wmsg->curlen : rmsg->curlen;
1089 D(bug("Writer len = %d - Reader len = %d. Copying %d bytes\n",
1090 wmsg->curlen, rmsg->curlen, len));
1092 CopyMem
1094 wmsg->iofs->io_Union.io_READ_WRITE.io_Buffer +
1095 wmsg->iofs->io_Union.io_READ_WRITE.io_Length -
1096 wmsg->curlen,
1098 rmsg->iofs->io_Union.io_READ_WRITE.io_Buffer +
1099 rmsg->iofs->io_Union.io_READ_WRITE.io_Length -
1100 rmsg->curlen,
1105 wmsg->curlen -= len;
1106 rmsg->curlen -= len;
1108 D(bug("Writer curlen is now %d - Reader curlen is now %d\n",
1109 wmsg->curlen, rmsg->curlen));
1111 if (!wmsg->curlen)
1113 D(bug("Writer: finished its job.\n"));
1114 SendBack(wmsg, 0);
1116 else
1118 D(bug("Writer: not finished yet. Enqueueing the request again.\n"));
1119 AddTail(&fn->pendingwrites, (struct Node *)wmsg);
1122 if (!rmsg->curlen)
1124 D(bug("Reader: finished its job.\n"));
1125 SendBack(rmsg, 0);
1127 else
1130 ((struct usernode *)rmsg->iofs->IOFS.io_Unit)->mode & FMF_NONBLOCK &&
1131 rmsg->iofs->io_Union.io_READ_WRITE.io_Length > wmsg->iofs->io_Union.io_READ_WRITE.io_Length
1134 D(bug("Reader: wants to read more data than it's actually available, but since it's in nonblocking mode return anyway\n"));
1135 rmsg->iofs->io_Union.io_READ_WRITE.io_Length = len;
1136 SendBack(rmsg, 0);
1138 else
1140 D(bug("Reader: not finished yet. Enqueueing the request again.\n"));
1141 AddTail(&fn->pendingreads, (struct Node *)rmsg);
1145 D(bug("Coming back to wait for a new message\n"));
1147 } while (cont);
1149 return 0;
1151 AROS_USERFUNC_EXIT