New bitmap method SetRGBConversionFunction which can be used to
[tangerine.git] / workbench / devs / pipefs_handler.c
blob8ccae9e0ec08de90f63f755adba007f0157f0108
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 (STRPTR path);
80 static struct filenode *FindFile (struct pipefsbase *pipefsbase, struct dirnode **dn_ptr, STRPTR path);
81 static struct filenode *GetFile (struct pipefsbase *pipefsbase, 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, 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_EXAMINE:
213 case FSA_EXAMINE_NEXT:
214 case FSA_READ:
215 case FSA_WRITE:
216 case FSA_CLOSE:
217 case FSA_CREATE_DIR:
218 case FSA_DELETE_OBJECT:
219 case FSA_FILE_MODE:
220 error = SendRequest(pipefsbase, iofs, FALSE);
221 enqueued = !error;
222 break;
224 case FSA_SEEK:
225 error = ERROR_SEEK_ERROR;
226 break;
227 case FSA_IS_FILESYSTEM:
228 iofs->io_Union.io_IS_FILESYSTEM.io_IsFilesystem = TRUE;
229 break;
230 case FSA_SET_FILE_SIZE:
231 case FSA_EXAMINE_ALL:
232 case FSA_CREATE_HARDLINK:
233 case FSA_CREATE_SOFTLINK:
234 case FSA_RENAME:
235 error = ERROR_NOT_IMPLEMENTED;
236 break;
238 default:
239 error = ERROR_ACTION_NOT_KNOWN;
240 break;
243 /* Set error code */
244 iofs->io_DosError=error;
246 /* If the quick bit is not set and the request hasn't been redirected
247 send the message to the port
249 if(!(iofs->IOFS.io_Flags&IOF_QUICK) && !enqueued)
250 ReplyMsg(&iofs->IOFS.io_Message);
252 AROS_LIBFUNC_EXIT
255 ADD2INITLIB(GM_UNIQUENAME(Init), 0)
256 ADD2OPENDEV(GM_UNIQUENAME(Open), 0)
257 ADD2CLOSEDEV(GM_UNIQUENAME(Close), 0)
258 ADD2EXPUNGELIB(GM_UNIQUENAME(Expunge), 0)
260 AROS_LH1(LONG, abortio,
261 AROS_LHA(struct IOFileSys *, iofs, A1),
262 struct pipefsbase *, pipefsbase, 6, Pipefs)
264 AROS_LIBFUNC_INIT
266 return SendRequest(pipefsbase, iofs, TRUE);
268 AROS_LIBFUNC_EXIT
271 static ULONG SendRequest(struct pipefsbase *pipefsbase, struct IOFileSys *iofs, BOOL abort)
273 struct pipefsmessage *msg = AllocVec(sizeof(*msg), MEMF_PUBLIC);
275 if (msg)
277 msg->msg.mn_Node.ln_Type = NT_MESSAGE;
278 msg->msg.mn_Node.ln_Name = "PIPEFSMSG";
279 msg->msg.mn_Length = sizeof(struct pipefsmessage);
280 msg->iofs = iofs;
281 msg->curlen = abort;
283 if (iofs)
285 iofs->IOFS.io_Message.mn_Node.ln_Type = NT_MESSAGE;
286 iofs->IOFS.io_Flags &= ~IOF_QUICK;
289 PutMsg(&pipefsbase->proc->pr_MsgPort, (struct Message *)msg);
291 return 0;
294 return ERROR_NO_FREE_STORE;
297 /* The helper process */
299 #define SendBack(msg, err) \
301 msg->iofs->io_DosError = err; \
302 ReplyMsg(&(msg)->iofs->IOFS.io_Message); \
303 FreeVec(msg); \
306 static STRPTR StrDup(struct pipefsbase *pipefsbase, STRPTR str)
308 size_t len = strlen(str)+1;
309 STRPTR ret = AllocVec(len, MEMF_ANY);
311 if (ret)
312 CopyMem(str, ret, len);
314 return ret;
318 Return the len of the first part in the path.
320 EXAMPLE
321 LenFirstPart("yyy/xxx") would return 3
322 LenFirstPart("xxxx") would return 4
325 static size_t LenFirstPart(STRPTR path)
327 size_t len = 0;
329 for (; path[0] && path[0] != '/'; path++, len++);
331 return len;
334 static struct filenode *FindFile(struct pipefsbase *pipefsbase, struct dirnode **dn_ptr, STRPTR path)
336 #define dn (*dn_ptr)
338 size_t len;
339 STRPTR nextpart;
340 struct filenode *fn;
342 while (path[0] == '/' && dn)
344 dn = dn->parent;
345 path++;
348 if (!dn) return NULL;
350 if (!path[0]) return (struct filenode *)dn;
352 if (dn->type <= 0)
354 D(bug("User wants %S to be a directory, but it's a file.\n", dn->name));
355 dn = NULL;
356 return NULL;
359 len = LenFirstPart(path);
360 nextpart = &path[len];
361 fn = (struct filenode *)GetHead(&dn->files);
363 D(bug("Searching for %.*S.\n", len, path));
365 while (fn)
367 D(bug("Comparing %S with %.*S.\n", fn->name, len, path));
370 strlen(fn->name) == len &&
371 strncasecmp(fn->name, path, len) == 0
374 break;
376 fn = (struct filenode *)GetSucc((struct Node *)fn);
379 if (fn)
381 if (nextpart[0] == '/') nextpart++;
383 dn = (struct dirnode *)fn;
384 fn = FindFile(pipefsbase, &dn, nextpart);
387 return fn;
389 #undef dn
392 static struct filenode *NewFileNode(struct pipefsbase *pipefsbase, STRPTR filename, ULONG flags, struct dirnode *dn, ULONG *err)
394 struct filenode *fn;
396 fn = AllocVec(sizeof(*fn), MEMF_PUBLIC|MEMF_CLEAR);
397 if (fn)
399 fn->name = StrDup(pipefsbase, filename);
401 if (fn->name)
403 fn->type = ST_PIPEFILE;
405 DateStamp(&fn->datestamp);
406 NEWLIST(&fn->waitinglist);
407 NEWLIST(&fn->pendingwrites);
408 NEWLIST(&fn->pendingreads);
410 fn->parent = dn;
411 fn->flags = flags;
413 AddTail(&dn->files, (struct Node *)fn);
414 D(bug("New file created and added to the list\n"));
416 return fn;
419 FreeVec(fn);
422 D(bug("AllocVec Failed. No more memory available\n"));
423 *err = ERROR_NO_FREE_STORE;
424 return NULL;
427 static struct filenode *GetFile(struct pipefsbase *pipefsbase, STRPTR filename, struct dirnode *dn, ULONG mode, ULONG *err)
429 struct filenode *fn;
431 D(bug("User wants to open file %S.\n", filename));
432 D(bug("Current directory is %S\n", dn->name));
434 if (dn && !dn->parent && strcmp(filename, "__UNNAMED__") == 0)
436 return NewFileNode(pipefsbase, "__UNNAMED__", FNF_DELETEONCLOSE, dn, err);
439 fn = FindFile(pipefsbase, &dn, filename);
440 if (!fn)
442 D(bug("The file couldn't be found.\n"));
444 if (dn && mode&FMF_CREATE)
446 D(bug("But the user wants it to be created.\n"));
448 return NewFileNode(pipefsbase, FilePart(filename), 0, dn, err);
450 else
452 *err = ERROR_OBJECT_NOT_FOUND;
456 if (fn && fn->type > 0 && mode&(FMF_WRITE|FMF_READ))
458 D(bug("The file is a directory, cannot be open for reading/writing\n"));
459 *err = ERROR_OBJECT_WRONG_TYPE;
460 return NULL;
463 return fn;
466 #undef SysBase
467 #ifndef kprintf
468 struct ExecBase *SysBase;
469 #else
470 # define SysBase _SysBase
471 #endif
474 AROS_UFH3(LONG, pipefsproc,
475 AROS_UFHA(char *,argstr,A0),
476 AROS_UFHA(ULONG,argsize,D0),
477 AROS_UFHA(struct ExecBase *,_SysBase,A6))
479 AROS_USERFUNC_INIT
481 struct Process *me;
482 struct pipefsbase *pipefsbase;
483 struct pipefsmessage *msg;
484 struct usernode *un;
485 struct filenode *fn;
486 BOOL cont = TRUE;
488 SysBase = _SysBase;
490 me = (struct Process *)FindTask(0);
491 pipefsbase = me->pr_Task.tc_UserData;
496 WaitPort(&(me->pr_MsgPort));
498 while
500 (msg =(struct pipefsmessage *)GetMsg(&(me->pr_MsgPort))) &&
501 (cont = (msg->iofs != 0))
504 D(bug("Message received.\n"));
506 un = (struct usernode *)msg->iofs->IOFS.io_Unit;
507 fn = un->fn;
509 if (msg->curlen) /* This field is abused too see whethet the user wants to abort the request */
511 struct pipefsmessage *msg2;
512 BOOL found = FALSE;
514 D(bug("The user wants to abort this request.\n"));
516 ForeachNode(&fn->waitinglist, msg2)
518 if (msg2->iofs == msg->iofs)
520 found = TRUE;
522 fn->numusers--;
523 if (un->mode & FMF_WRITE)
524 fn->numwriters--;
525 if (un->mode & FMF_READ)
526 fn->numreaders--;
528 FreeVec(un);
530 break;
533 if (!found && (un->mode & FMF_WRITE))
535 ForeachNode(&fn->pendingwrites, msg2)
537 if (msg2->iofs == msg->iofs)
539 found = TRUE;
540 break;
544 if (!found && (un->mode & FMF_READ))
546 ForeachNode(&fn->pendingreads, msg2)
548 if (msg2->iofs == msg->iofs)
550 found = TRUE;
551 break;
556 if (found)
558 D(bug("Aborting the request.\n"));
559 Remove((struct Node *)msg2);
560 msg2->iofs->IOFS.io_Error = IOERR_ABORTED;
561 SendBack(msg2, ERROR_INTERRUPTED);
563 else
565 D(bug("There was no I/O in process for this request.\n"));
568 FreeVec(msg);
569 continue;
572 switch (msg->iofs->IOFS.io_Command)
574 case FSA_OPEN:
575 msg->iofs->io_Union.io_OPEN.io_FileMode &= ~(FMF_WRITE|FMF_READ);
576 /* Fall through */
577 case FSA_OPEN_FILE:
579 struct usernode *un;
580 BOOL stillwaiting;
581 ULONG err;
583 D(bug("Command is OPEN\n"));
586 I would have liked to put this AFTER GetFile(),
587 but then it would have been really difficult to
588 undo what's done in GetFile() if the following AllocVec()
589 failed...
591 un = AllocVec(sizeof(*un), MEMF_PUBLIC);
592 if (!un)
594 SendBack(msg, ERROR_NO_FREE_STORE);
595 continue;
598 un->mode = msg->iofs->io_Union.io_OPEN.io_FileMode;
600 fn = GetFile(pipefsbase, msg->iofs->io_Union.io_OPEN.io_Filename, (struct dirnode *)fn, un->mode, &err);
601 if (!fn)
603 FreeVec(un);
604 SendBack(msg, err);
605 continue;
608 D(bug("File requested found.\n"));
609 D(bug("The requested file is %s.\n",
610 fn->type <= 0 ?
611 "a pipe":
612 "a directory"));
614 msg->iofs->IOFS.io_Unit = (struct Unit *)un;
615 fn->numusers++;
616 un->fn = fn;
618 if (fn->type > 0)
620 SendBack(msg, 0);
621 continue;
624 stillwaiting = !fn->numwriters || !fn->numreaders;
626 if (un->mode == FMF_MODE_OLDFILE) un->mode &= ~FMF_WRITE;
627 if (un->mode == FMF_MODE_NEWFILE) un->mode &= ~FMF_READ;
629 if (un->mode & FMF_READ)
631 D(bug("User wants to read. "));
632 fn->numreaders++;
634 if (un->mode & FMF_WRITE)
636 D(bug("User wants to write. "));
637 fn->numwriters++;
640 D(bug("There are %d readers and %d writers at the moment\n", fn->numreaders, fn->numwriters));
642 if (!fn->numwriters || !fn->numreaders)
644 if (un->mode&(FMF_WRITE|FMF_READ) && !(un->mode&FMF_NONBLOCK))
647 If we're lacking of writers or readers
648 then add this message to a waiting list.
650 D(bug("There are no %s at the moment, so this %s must wait\n",
651 fn->numwriters?"readers":"writers",
652 fn->numwriters?"writer":"reader"));
654 AddTail(&fn->waitinglist, (struct Node *)msg);
656 else
657 SendBack(msg, 0);
659 else
661 if (stillwaiting)
664 Else wake up all the ones that were still waiting
666 struct pipefsmessage *msg;
668 D(bug("Finally there are enough readers and writers! "
669 "Wake up all of them\n"));
671 while ((msg = (struct pipefsmessage *)RemHead(&fn->waitinglist)))
672 SendBack(msg, 0);
674 SendBack(msg, 0);
677 continue;
679 case FSA_CLOSE:
680 D(bug("Command is FSA_CLOSE\n"));
682 if (un->mode & FMF_READ)
684 D(bug("User was a reader. "));
685 fn->numreaders--;
686 D(bug("There are %d readers at the moment\n", fn->numreaders));
687 if (!fn->numreaders)
689 struct pipefsmessage *msg;
691 D(bug("There are no readers anymore. %s\n",
692 IsListEmpty(&fn->pendingwrites) ?
693 "There are no pending writes" :
694 "Reply to all the waiting writers"));
696 while ((msg = (struct pipefsmessage *)RemHead(&fn->pendingwrites)))
697 SendBack(msg, 0);
700 if (un->mode & FMF_WRITE)
702 D(bug("User was a writer. "));
703 fn->numwriters--;
704 D(bug("There are %d writers at the moment\n", fn->numwriters));
706 if (!fn->numwriters)
708 struct pipefsmessage *msg;
710 D(bug("There are no writers anymore. %s\n",
711 IsListEmpty(&fn->pendingreads) ?
712 "There are no pending reads" :
713 "Reply to all the waiting readers"));
714 while ((msg = (struct pipefsmessage *)RemHead(&fn->pendingreads)))
716 msg->iofs->io_Union.io_READ_WRITE.io_Length =
717 msg->iofs->io_Union.io_READ_WRITE.io_Length - msg->curlen;
718 SendBack(msg, 0);
723 un->fn->numusers--;
725 if (!un->fn->numusers && un->fn->type <= 0 && (un->fn->flags & FNF_DELETEONCLOSE))
727 Remove((struct Node *)fn);
728 FreeVec(fn->name);
729 FreeVec(fn);
732 FreeVec(un);
733 SendBack(msg, 0);
735 continue;
736 case FSA_EXAMINE:
738 struct ExAllData *ead = msg->iofs->io_Union.io_EXAMINE.io_ead;
739 const ULONG type = msg->iofs->io_Union.io_EXAMINE.io_Mode;
740 const ULONG size = msg->iofs->io_Union.io_EXAMINE.io_Size;
741 STRPTR next, end;
743 static const ULONG sizes[]=
746 offsetof(struct ExAllData,ed_Type),
747 offsetof(struct ExAllData,ed_Size),
748 offsetof(struct ExAllData,ed_Prot),
749 offsetof(struct ExAllData,ed_Days),
750 offsetof(struct ExAllData,ed_Comment),
751 offsetof(struct ExAllData,ed_OwnerUID),
752 sizeof(struct ExAllData)
755 D(bug("Command is EXAMINE\n"));
756 D(bug("Examining file %S\n", fn->name));
758 if (type > ED_OWNER)
760 D(bug("The user requested an invalid type\n"));
761 SendBack(msg, ERROR_BAD_NUMBER);
762 continue;
765 next = (STRPTR)ead + sizes[type];
766 end = (STRPTR)ead + size;
768 if(next>end) /* > is correct. Not >= */
770 SendBack(msg, ERROR_BUFFER_OVERFLOW);
771 continue;
774 if (fn->type > 0)
776 msg->iofs->io_DirPos = (LONG)GetHead(&((struct dirnode *)fn)->files);
778 else
780 msg->iofs->io_DirPos = (LONG)fn;
783 switch(type)
785 case ED_OWNER:
786 ead->ed_OwnerUID = 0;
787 ead->ed_OwnerGID = 0;
789 /* Fall through */
790 case ED_COMMENT:
791 ead->ed_Comment = NULL;
793 /* Fall through */
794 case ED_DATE:
795 ead->ed_Days = fn->datestamp.ds_Days;
796 ead->ed_Mins = fn->datestamp.ds_Minute;
797 ead->ed_Ticks = fn->datestamp.ds_Tick;
799 /* Fall through */
800 case ED_PROTECTION:
801 ead->ed_Prot = 0;
803 /* Fall through */
804 case ED_SIZE:
805 ead->ed_Size = 0;
807 /* Fall through */
808 case ED_TYPE:
809 ead->ed_Type = fn->type;
811 /* Fall through */
812 case ED_NAME:
814 STRPTR name = fn->name;
815 ead->ed_Name = next;
817 for (;;)
819 if (next >= end)
821 SendBack(msg, ERROR_BUFFER_OVERFLOW);
822 continue;
825 if (!(*next++ = *name++))
827 break;
833 ead->ed_Next = (struct ExAllData *)(((IPTR)next + AROS_PTRALIGN - 1) & ~(AROS_PTRALIGN - 1));
835 SendBack(msg, 0);
836 continue;
838 case FSA_EXAMINE_NEXT:
840 struct FileInfoBlock *fib = msg->iofs->io_Union.io_EXAMINE_NEXT.io_fib;
841 struct filenode *fn = (struct filenode *)fib->fib_DiskKey;
843 D(bug("Command is EXAMINE_NEXT\n"));
845 if (!fn)
847 D(bug("There are no more entries in this directory\n"));
848 SendBack(msg, ERROR_NO_MORE_ENTRIES);
849 continue;
852 D(bug("Current directory is %S. Current file is %S\n", fn->parent->name, fn->name));
854 fib->fib_OwnerUID = 0;
855 fib->fib_OwnerGID = 0;
856 fib->fib_Date.ds_Days = fn->datestamp.ds_Days;
857 fib->fib_Date.ds_Minute = fn->datestamp.ds_Minute;
858 fib->fib_Date.ds_Tick = fn->datestamp.ds_Tick;
859 fib->fib_Protection = 0;
860 fib->fib_Size = 0;
861 fib->fib_DirEntryType = fn->type;
863 strncpy(fib->fib_FileName, fn->name, MAXFILENAMELENGTH - 1);
864 fib->fib_Comment[0] = '\0';
866 fib->fib_DiskKey = (LONG)GetSucc(fn);
867 SendBack(msg, 0);
869 continue;
871 case FSA_CREATE_DIR:
873 STRPTR filename = msg->iofs->io_Union.io_CREATE_DIR.io_Filename;
874 struct dirnode *parent = (struct dirnode *)fn;
875 struct dirnode *dn;
877 D(bug("Command is FSA_CREATE_DIR\n"));
878 D(bug("Current directory is %S\n", parent->name));
879 D(bug("User wants to create directory %S\n", filename));
881 dn = (struct dirnode *)FindFile(pipefsbase, &parent, filename);
882 if (dn)
884 D(bug("The object %S already exists\n", filename));
885 SendBack(msg, ERROR_OBJECT_EXISTS);
886 continue;
888 else
889 if (!parent)
891 D(bug("The path is not valid.\n"));
892 SendBack(msg, ERROR_OBJECT_NOT_FOUND);
893 continue;
898 !(un = AllocVec(sizeof(*un), MEMF_PUBLIC)) ||
899 !(dn = AllocVec(sizeof(*dn), MEMF_PUBLIC)) ||
900 !(dn->name = StrDup(pipefsbase, filename))
903 SendBack(msg, ERROR_NO_FREE_STORE);
904 continue;
907 D(bug("Ok, there's room for this directory.\n"));
908 AddTail(&parent->files, (struct Node *)dn);
909 dn->parent = parent;
910 dn->numusers = 0;
911 dn->type = ST_USERDIR;
912 NEWLIST(&dn->files);
913 DateStamp(&dn->datestamp);
915 un->fn = (struct filenode *)dn;
916 un->mode = 0;
917 msg->iofs->IOFS.io_Unit = (struct Unit *)un;
919 SendBack(msg, 0);
920 continue;
922 case FSA_FILE_MODE:
923 D(bug("Command is FSA_FILE_MODE\n"));
924 D(bug("Current mode is 0x%08x\n", un->mode));
926 un->mode &= ~msg->iofs->io_Union.io_FILE_MODE.io_Mask;
927 un->mode |= msg->iofs->io_Union.io_FILE_MODE.io_FileMode;
929 D(bug("New mode is 0x%08x\n", un->mode));
931 SendBack(msg, 0);
932 continue;
933 case FSA_DELETE_OBJECT:
935 STRPTR filename = msg->iofs->io_Union.io_DELETE_OBJECT.io_Filename;
936 struct dirnode *dn = (struct dirnode *)fn;
938 D(bug("Command is FSA_DELETE_OBJECT\n"));
939 D(bug("Current directory is %S\n", fn->name));
940 D(bug("User wants to delete the object %S\n", filename));
942 fn = FindFile(pipefsbase, &dn, filename);
943 if (!fn)
945 D(bug("The object doesn't exist\n"));
946 SendBack(msg, ERROR_OBJECT_NOT_FOUND);
947 continue;
949 if (fn->type == ST_ROOT)
951 D(bug("The object is the root directory. Cannot be deleted\n"));
952 SendBack(msg, ERROR_OBJECT_WRONG_TYPE);
953 continue;
955 if (fn->numusers)
957 D(bug("The object is in use, cannot be deleted\n"));
958 SendBack(msg, ERROR_OBJECT_IN_USE);
959 continue;
961 if (fn->type > 0 && !IsListEmpty(&((struct dirnode *)fn)->files))
963 D(bug("The object is a directory, but is not empty, thus cannot be deleted\n"));
964 SendBack(msg, ERROR_DIRECTORY_NOT_EMPTY);
965 continue;
968 D(bug("Removing the object from it's parent directory\n"));
970 Remove((struct Node *)fn);
971 FreeVec(fn->name);
972 FreeVec(fn);
974 SendBack(msg, 0);
975 continue;
977 case FSA_WRITE:
978 D(bug("Command is FSA_WRITE. "));
979 if (!(un->mode & FMF_WRITE))
981 D(bug("User doesn't have permission to write.\n"));
982 SendBack(msg, ERROR_BAD_STREAM_NAME);
983 continue;
985 if (!fn->numreaders)
987 D(bug("There are no more readers: PIPE BROKEN.\n"));
988 SendBack(msg, ERROR_BROKEN_PIPE);
989 continue;
991 if (un->mode & FMF_NONBLOCK && IsListEmpty(&fn->pendingreads))
993 D(bug("There are no pending reads and the pipe is in nonblocking mode, so return EWOULDBLOCK\n"));
994 SendBack(msg, ERROR_WOULD_BLOCK);
995 continue;
998 D(bug("Enqueing the message\n"));
999 msg->curlen = msg->iofs->io_Union.io_READ_WRITE.io_Length;
1000 AddTail(&fn->pendingwrites, (struct Node *)msg);
1001 break;
1002 case FSA_READ:
1003 D(bug("Command is FSA_READ. "));
1004 if (!(un->mode & FMF_READ))
1006 D(bug("User doesn't have permission to read.\n"));
1007 SendBack(msg, ERROR_BAD_STREAM_NAME);
1008 continue;
1010 if (!fn->numwriters)
1012 D(bug("There's no data to read: send EOF\n"));
1013 msg->iofs->io_Union.io_READ_WRITE.io_Length = 0;
1014 SendBack(msg, 0);
1015 continue;
1017 if (un->mode & FMF_NONBLOCK && IsListEmpty(&fn->pendingwrites))
1019 D(bug("There are no pending writes and the pipe is in nonblocking mode, so return EWOULDBLOCK\n"));
1020 SendBack(msg, ERROR_WOULD_BLOCK);
1021 continue;
1024 D(bug("Enqueing the message\n"));
1025 msg->curlen = msg->iofs->io_Union.io_READ_WRITE.io_Length;
1026 AddTail(&fn->pendingreads, (struct Node *)msg);
1027 break;
1030 while (!IsListEmpty(&fn->pendingwrites) && !IsListEmpty(&fn->pendingreads))
1032 struct pipefsmessage *rmsg = (struct pipefsmessage *)RemHead(&fn->pendingreads);
1033 struct pipefsmessage *wmsg = (struct pipefsmessage *)RemHead(&fn->pendingwrites);
1035 ULONG len = (rmsg->curlen > wmsg->curlen) ?
1036 wmsg->curlen : rmsg->curlen;
1038 D(bug("Writer len = %d - Reader len = %d. Copying %d bytes\n",
1039 wmsg->curlen, rmsg->curlen, len));
1041 CopyMem
1043 wmsg->iofs->io_Union.io_READ_WRITE.io_Buffer +
1044 wmsg->iofs->io_Union.io_READ_WRITE.io_Length -
1045 wmsg->curlen,
1047 rmsg->iofs->io_Union.io_READ_WRITE.io_Buffer +
1048 rmsg->iofs->io_Union.io_READ_WRITE.io_Length -
1049 rmsg->curlen,
1054 wmsg->curlen -= len;
1055 rmsg->curlen -= len;
1057 D(bug("Writer curlen is now %d - Reader curlen is now %d\n",
1058 wmsg->curlen, rmsg->curlen));
1060 if (!wmsg->curlen)
1062 D(bug("Writer: finished its job.\n"));
1063 SendBack(wmsg, 0);
1065 else
1067 D(bug("Writer: not finished yet. Enqueueing the request again.\n"));
1068 AddTail(&fn->pendingwrites, (struct Node *)wmsg);
1071 if (!rmsg->curlen)
1073 D(bug("Reader: finished its job.\n"));
1074 SendBack(rmsg, 0);
1076 else
1079 ((struct usernode *)rmsg->iofs->IOFS.io_Unit)->mode & FMF_NONBLOCK &&
1080 rmsg->iofs->io_Union.io_READ_WRITE.io_Length > wmsg->iofs->io_Union.io_READ_WRITE.io_Length
1083 D(bug("Reader: wants to read more data than it's actually available, but since it's in nonblocking mode return anyway\n"));
1084 rmsg->iofs->io_Union.io_READ_WRITE.io_Length = len;
1085 SendBack(rmsg, 0);
1087 else
1089 D(bug("Reader: not finished yet. Enqueueing the request again.\n"));
1090 AddTail(&fn->pendingreads, (struct Node *)rmsg);
1094 D(bug("Coming back to wait for a new message\n"));
1096 } while (cont);
1098 return 0;
1100 AROS_USERFUNC_EXIT