2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
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"
26 #include LC_LIBDEFS_FILE
31 AROS_UFP3(LONG
, pipefsproc
,
32 AROS_UFPA(char *,argstr
,A0
),
33 AROS_UFPA(ULONG
,argsize
,D0
),
34 AROS_UFPA(struct ExecBase
*,SysBase
,A6
));
39 struct IOFileSys
*iofs
;
46 struct dirnode
*parent
; /* Parent directory */
49 struct DateStamp datestamp
;
57 struct dirnode
*parent
;
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 */
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);
92 struct TagItem taglist
[]=
94 {NP_Entry
, (IPTR
)pipefsproc
},
95 {NP_Name
, (IPTR
)"pipefs.handler process"},
96 {NP_UserData
, (IPTR
)pipefsbase
},
100 pipefsbase
->proc
= CreateNewProc(taglist
);
102 if (pipefsbase
->proc
)
105 CloseLibrary((struct Library
*)DOSBase
);
111 static int GM_UNIQUENAME(Open
)
113 LIBBASETYPEPTR pipefsbase
,
114 struct IOFileSys
*iofs
,
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
);
129 dn
= AllocVec(sizeof(*dn
),MEMF_PUBLIC
|MEMF_CLEAR
);
133 dn
->name
= iofs
->io_Union
.io_OpenDevice
.io_DosName
;
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;
151 iofs
->io_DosError
=ERROR_NO_FREE_STORE
;
153 iofs
->IOFS
.io_Error
=IOERR_OPENFAIL
;
158 static int GM_UNIQUENAME(Close
)
160 LIBBASETYPEPTR pipefsbase
,
161 struct IOFileSys
*iofs
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
;
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
);
199 AROS_LH1(void, beginio
,
200 AROS_LHA(struct IOFileSys
*, iofs
, A1
),
201 struct pipefsbase
*, pipefsbase
, 5, Pipefs
)
205 BOOL enqueued
= FALSE
;
207 D(bug("COMMAND %d\n", iofs
->IOFS
.io_Command
));
208 switch(iofs
->IOFS
.io_Command
)
213 case FSA_EXAMINE_NEXT
:
218 case FSA_DELETE_OBJECT
:
220 error
= SendRequest(pipefsbase
, iofs
, FALSE
);
225 error
= ERROR_SEEK_ERROR
;
227 case FSA_IS_FILESYSTEM
:
228 iofs
->io_Union
.io_IS_FILESYSTEM
.io_IsFilesystem
= TRUE
;
230 case FSA_SET_FILE_SIZE
:
231 case FSA_EXAMINE_ALL
:
232 case FSA_CREATE_HARDLINK
:
233 case FSA_CREATE_SOFTLINK
:
235 error
= ERROR_NOT_IMPLEMENTED
;
239 error
= ERROR_ACTION_NOT_KNOWN
;
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
);
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
)
266 return SendRequest(pipefsbase
, iofs
, TRUE
);
271 static ULONG
SendRequest(struct pipefsbase
*pipefsbase
, struct IOFileSys
*iofs
, BOOL abort
)
273 struct pipefsmessage
*msg
= AllocVec(sizeof(*msg
), MEMF_PUBLIC
);
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
);
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
);
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); \
306 static STRPTR
StrDup(struct pipefsbase
*pipefsbase
, STRPTR str
)
308 size_t len
= strlen(str
)+1;
309 STRPTR ret
= AllocVec(len
, MEMF_ANY
);
312 CopyMem(str
, ret
, len
);
318 Return the len of the first part in the path.
321 LenFirstPart("yyy/xxx") would return 3
322 LenFirstPart("xxxx") would return 4
325 static size_t LenFirstPart(STRPTR path
)
329 for (; path
[0] && path
[0] != '/'; path
++, len
++);
334 static struct filenode
*FindFile(struct pipefsbase
*pipefsbase
, struct dirnode
**dn_ptr
, STRPTR path
)
342 while (path
[0] == '/' && dn
)
348 if (!dn
) return NULL
;
350 if (!path
[0]) return (struct filenode
*)dn
;
354 D(bug("User wants %S to be a directory, but it's a file.\n", dn
->name
));
359 len
= LenFirstPart(path
);
360 nextpart
= &path
[len
];
361 fn
= (struct filenode
*)GetHead(&dn
->files
);
363 D(bug("Searching for %.*S.\n", len
, path
));
367 D(bug("Comparing %S with %.*S.\n", fn
->name
, len
, path
));
370 strlen(fn
->name
) == len
&&
371 strncasecmp(fn
->name
, path
, len
) == 0
376 fn
= (struct filenode
*)GetSucc((struct Node
*)fn
);
381 if (nextpart
[0] == '/') nextpart
++;
383 dn
= (struct dirnode
*)fn
;
384 fn
= FindFile(pipefsbase
, &dn
, nextpart
);
392 static struct filenode
*NewFileNode(struct pipefsbase
*pipefsbase
, STRPTR filename
, ULONG flags
, struct dirnode
*dn
, ULONG
*err
)
396 fn
= AllocVec(sizeof(*fn
), MEMF_PUBLIC
|MEMF_CLEAR
);
399 fn
->name
= StrDup(pipefsbase
, filename
);
403 fn
->type
= ST_PIPEFILE
;
405 DateStamp(&fn
->datestamp
);
406 NEWLIST(&fn
->waitinglist
);
407 NEWLIST(&fn
->pendingwrites
);
408 NEWLIST(&fn
->pendingreads
);
413 AddTail(&dn
->files
, (struct Node
*)fn
);
414 D(bug("New file created and added to the list\n"));
422 D(bug("AllocVec Failed. No more memory available\n"));
423 *err
= ERROR_NO_FREE_STORE
;
427 static struct filenode
*GetFile(struct pipefsbase
*pipefsbase
, STRPTR filename
, struct dirnode
*dn
, ULONG mode
, ULONG
*err
)
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
);
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
);
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
;
468 struct ExecBase
*SysBase
;
470 # define SysBase _SysBase
474 AROS_UFH3(LONG
, pipefsproc
,
475 AROS_UFHA(char *,argstr
,A0
),
476 AROS_UFHA(ULONG
,argsize
,D0
),
477 AROS_UFHA(struct ExecBase
*,_SysBase
,A6
))
482 struct pipefsbase
*pipefsbase
;
483 struct pipefsmessage
*msg
;
490 me
= (struct Process
*)FindTask(0);
491 pipefsbase
= me
->pr_Task
.tc_UserData
;
496 WaitPort(&(me
->pr_MsgPort
));
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
;
509 if (msg
->curlen
) /* This field is abused too see whethet the user wants to abort the request */
511 struct pipefsmessage
*msg2
;
514 D(bug("The user wants to abort this request.\n"));
516 ForeachNode(&fn
->waitinglist
, msg2
)
518 if (msg2
->iofs
== msg
->iofs
)
523 if (un
->mode
& FMF_WRITE
)
525 if (un
->mode
& FMF_READ
)
533 if (!found
&& (un
->mode
& FMF_WRITE
))
535 ForeachNode(&fn
->pendingwrites
, msg2
)
537 if (msg2
->iofs
== msg
->iofs
)
544 if (!found
&& (un
->mode
& FMF_READ
))
546 ForeachNode(&fn
->pendingreads
, msg2
)
548 if (msg2
->iofs
== msg
->iofs
)
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
);
565 D(bug("There was no I/O in process for this request.\n"));
572 switch (msg
->iofs
->IOFS
.io_Command
)
575 msg
->iofs
->io_Union
.io_OPEN
.io_FileMode
&= ~(FMF_WRITE
|FMF_READ
);
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()
591 un
= AllocVec(sizeof(*un
), MEMF_PUBLIC
);
594 SendBack(msg
, ERROR_NO_FREE_STORE
);
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
);
608 D(bug("File requested found.\n"));
609 D(bug("The requested file is %s.\n",
614 msg
->iofs
->IOFS
.io_Unit
= (struct Unit
*)un
;
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. "));
634 if (un
->mode
& FMF_WRITE
)
636 D(bug("User wants to write. "));
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
);
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
)))
680 D(bug("Command is FSA_CLOSE\n"));
682 if (un
->mode
& FMF_READ
)
684 D(bug("User was a reader. "));
686 D(bug("There are %d readers at the moment\n", 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
)))
700 if (un
->mode
& FMF_WRITE
)
702 D(bug("User was a writer. "));
704 D(bug("There are %d writers at the moment\n", 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
;
725 if (!un
->fn
->numusers
&& un
->fn
->type
<= 0 && (un
->fn
->flags
& FNF_DELETEONCLOSE
))
727 Remove((struct Node
*)fn
);
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
;
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
));
760 D(bug("The user requested an invalid type\n"));
761 SendBack(msg
, ERROR_BAD_NUMBER
);
765 next
= (STRPTR
)ead
+ sizes
[type
];
766 end
= (STRPTR
)ead
+ size
;
768 if(next
>end
) /* > is correct. Not >= */
770 SendBack(msg
, ERROR_BUFFER_OVERFLOW
);
776 msg
->iofs
->io_DirPos
= (LONG
)GetHead(&((struct dirnode
*)fn
)->files
);
780 msg
->iofs
->io_DirPos
= (LONG
)fn
;
786 ead
->ed_OwnerUID
= 0;
787 ead
->ed_OwnerGID
= 0;
791 ead
->ed_Comment
= NULL
;
795 ead
->ed_Days
= fn
->datestamp
.ds_Days
;
796 ead
->ed_Mins
= fn
->datestamp
.ds_Minute
;
797 ead
->ed_Ticks
= fn
->datestamp
.ds_Tick
;
809 ead
->ed_Type
= fn
->type
;
814 STRPTR name
= fn
->name
;
821 SendBack(msg
, ERROR_BUFFER_OVERFLOW
);
825 if (!(*next
++ = *name
++))
833 ead
->ed_Next
= (struct ExAllData
*)(((IPTR
)next
+ AROS_PTRALIGN
- 1) & ~(AROS_PTRALIGN
- 1));
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"));
847 D(bug("There are no more entries in this directory\n"));
848 SendBack(msg
, ERROR_NO_MORE_ENTRIES
);
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;
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
);
873 STRPTR filename
= msg
->iofs
->io_Union
.io_CREATE_DIR
.io_Filename
;
874 struct dirnode
*parent
= (struct dirnode
*)fn
;
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
);
884 D(bug("The object %S already exists\n", filename
));
885 SendBack(msg
, ERROR_OBJECT_EXISTS
);
891 D(bug("The path is not valid.\n"));
892 SendBack(msg
, ERROR_OBJECT_NOT_FOUND
);
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
);
907 D(bug("Ok, there's room for this directory.\n"));
908 AddTail(&parent
->files
, (struct Node
*)dn
);
911 dn
->type
= ST_USERDIR
;
913 DateStamp(&dn
->datestamp
);
915 un
->fn
= (struct filenode
*)dn
;
917 msg
->iofs
->IOFS
.io_Unit
= (struct Unit
*)un
;
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
));
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
);
945 D(bug("The object doesn't exist\n"));
946 SendBack(msg
, ERROR_OBJECT_NOT_FOUND
);
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
);
957 D(bug("The object is in use, cannot be deleted\n"));
958 SendBack(msg
, ERROR_OBJECT_IN_USE
);
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
);
968 D(bug("Removing the object from it's parent directory\n"));
970 Remove((struct Node
*)fn
);
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
);
987 D(bug("There are no more readers: PIPE BROKEN.\n"));
988 SendBack(msg
, ERROR_BROKEN_PIPE
);
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
);
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
);
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
);
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;
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
);
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
);
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
));
1043 wmsg
->iofs
->io_Union
.io_READ_WRITE
.io_Buffer
+
1044 wmsg
->iofs
->io_Union
.io_READ_WRITE
.io_Length
-
1047 rmsg
->iofs
->io_Union
.io_READ_WRITE
.io_Buffer
+
1048 rmsg
->iofs
->io_Union
.io_READ_WRITE
.io_Length
-
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
));
1062 D(bug("Writer: finished its job.\n"));
1067 D(bug("Writer: not finished yet. Enqueueing the request again.\n"));
1068 AddTail(&fn
->pendingwrites
, (struct Node
*)wmsg
);
1073 D(bug("Reader: finished its job.\n"));
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
;
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"));