:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / drivers / fs / np / rw.c
1 /* $Id$
2  *
3  * COPYRIGHT:  See COPYING in the top level directory
4  * PROJECT:    ReactOS kernel
5  * FILE:       services/fs/np/rw.c
6  * PURPOSE:    Named pipe filesystem
7  * PROGRAMMER: David Welch <welch@cwcom.net>
8  */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ddk/ntddk.h>
13 #include "npfs.h"
14
15 #define NDEBUG
16 #include <debug.h>
17
18
19 /* FUNCTIONS *****************************************************************/
20
21 static inline PNPFS_PIPE_DATA
22 NpfsAllocatePipeData(PVOID Data,
23                      ULONG Size)
24 {
25   PNPFS_PIPE_DATA PipeData;
26
27   PipeData = ExAllocateFromNPagedLookasideList(&NpfsPipeDataLookasideList);
28   if (!PipeData)
29     {
30       return NULL;
31     }
32
33   PipeData->Data = Data;
34   PipeData->Size = Size;
35   PipeData->Offset = 0;
36
37   return PipeData;
38 }
39
40
41 static inline PNPFS_PIPE_DATA
42 NpfsInitializePipeData(
43   PVOID Data,
44   ULONG Size)
45 {
46   PNPFS_PIPE_DATA PipeData;
47   PVOID Buffer;
48
49   Buffer = ExAllocatePool(NonPagedPool, Size);
50   if (!Buffer)
51   {
52     return NULL;
53   }
54
55   RtlMoveMemory(Buffer, Data, Size);
56
57   PipeData = NpfsAllocatePipeData(Buffer, Size);
58   if (!PipeData)
59   {
60     ExFreePool(Buffer);
61   }
62
63   return PipeData;
64 }
65
66
67 NTSTATUS STDCALL
68 NpfsRead(PDEVICE_OBJECT DeviceObject, PIRP Irp)
69 {
70   PIO_STACK_LOCATION IoStack;
71   PFILE_OBJECT FileObject;
72   NTSTATUS Status;
73   PNPFS_DEVICE_EXTENSION DeviceExt;
74   PWSTR PipeName;
75   KIRQL OldIrql;
76   PLIST_ENTRY CurrentEntry;
77   PNPFS_PIPE_DATA Current;
78   ULONG Information;
79   PNPFS_FCB Fcb;
80   PNPFS_FCB ReadFcb;
81   PNPFS_PIPE Pipe;
82   ULONG Length;
83   PVOID Buffer;
84   ULONG CopyLength;
85
86   DPRINT("NpfsRead(DeviceObject %p  Irp %p)\n", DeviceObject, Irp);
87   
88   DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
89   IoStack = IoGetCurrentIrpStackLocation(Irp);
90   FileObject = IoStack->FileObject;
91   Fcb = FileObject->FsContext;
92   Pipe = Fcb->Pipe;
93   ReadFcb = Fcb->OtherSide;
94
95   if (ReadFcb == NULL)
96     {
97       DPRINT("Pipe is NOT connected!\n");
98       Status = STATUS_UNSUCCESSFUL;
99       Information = 0;
100       goto done;
101     }
102
103   if (Irp->MdlAddress == NULL)
104     {
105       DPRINT("Irp->MdlAddress == NULL\n");
106       Status = STATUS_UNSUCCESSFUL;
107       Information = 0;
108       goto done;
109     }
110
111   Status = STATUS_SUCCESS;
112   Length = IoStack->Parameters.Read.Length;
113   Information = 0;
114
115   Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
116   DPRINT("Length %d Buffer %x\n",Length,Buffer);
117
118   KeAcquireSpinLock(&ReadFcb->DataListLock, &OldIrql);
119   while (1)
120   {
121      /* FIXME: check if in blocking mode */
122      if (IsListEmpty(&ReadFcb->DataListHead))
123      {
124         KeResetEvent(&Fcb->ReadEvent);
125         KeReleaseSpinLock(&ReadFcb->DataListLock, OldIrql);
126         if (Information > 0)
127         {
128            Status = STATUS_SUCCESS;
129            goto done;
130         }
131         if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
132         {
133            Status = STATUS_PIPE_BROKEN;
134            goto done;
135         }
136         /* Wait for ReadEvent to become signaled */
137         DPRINT("Waiting for readable data (%S)\n", Pipe->PipeName.Buffer);
138         Status = KeWaitForSingleObject(&Fcb->ReadEvent,
139                                        UserRequest,
140                                        KernelMode,
141                                        FALSE,
142                                        NULL);
143         DPRINT("Finished waiting (%S)! Status: %x\n", Pipe->PipeName.Buffer, Status);
144         KeAcquireSpinLock(&ReadFcb->DataListLock, &OldIrql);
145      }
146
147      if (Pipe->PipeReadMode == FILE_PIPE_BYTE_STREAM_MODE)
148      {
149         DPRINT("Byte stream mode\n");
150
151         /* Byte stream mode */
152         CurrentEntry = NULL;
153         while (Length > 0 && !IsListEmpty(&ReadFcb->DataListHead))
154         {
155            CurrentEntry = RemoveHeadList(&ReadFcb->DataListHead);
156            Current = CONTAINING_RECORD(CurrentEntry, NPFS_PIPE_DATA, ListEntry);
157
158            DPRINT("Took pipe data at %p off the queue\n", Current);
159
160            CopyLength = RtlMin(Current->Size, Length);
161            RtlCopyMemory(Buffer,
162                          ((PVOID)((PVOID)Current->Data + Current->Offset)),
163                          CopyLength);
164            Buffer += CopyLength;
165            Length -= CopyLength;
166            Information += CopyLength;
167
168            /* Update the data buffer */
169            Current->Offset += CopyLength;
170            Current->Size -= CopyLength;
171            if (Current->Size == 0)
172            {
173                NpfsFreePipeData(Current);
174                CurrentEntry = NULL;
175            }
176         }
177
178         if (CurrentEntry && Current->Size > 0)
179         {
180            DPRINT("Putting pipe data at %p back in queue\n", Current);
181
182            /* The caller's buffer could not contain the complete message,
183               so put it back on the queue */
184            InsertHeadList(&ReadFcb->DataListHead, &Current->ListEntry);
185         }
186
187         if (Length == 0)
188         {
189            break;
190         }
191      }
192      else
193      {
194         DPRINT("Message mode\n");
195
196         /* Message mode */
197         if (!IsListEmpty(&ReadFcb->DataListHead))
198         {
199            CurrentEntry = RemoveHeadList(&ReadFcb->DataListHead);
200            Current = CONTAINING_RECORD(CurrentEntry, NPFS_PIPE_DATA, ListEntry);
201
202            DPRINT("Took pipe data at %p off the queue\n", Current);
203
204            /* Truncate the message if the receive buffer is too small */
205            CopyLength = RtlMin(Current->Size, Length);
206            RtlCopyMemory(Buffer, Current->Data, CopyLength);
207            Information = CopyLength;
208
209            Current->Offset += CopyLength;
210            NpfsFreePipeData(Current);
211         }
212         if (Information > 0)
213         {
214            break;
215         }
216      }
217   }
218   /* reset ReaderEvent */
219   KeReleaseSpinLock(&ReadFcb->DataListLock, OldIrql);
220
221
222 done:
223   Irp->IoStatus.Status = Status;
224   Irp->IoStatus.Information = Information;
225
226   IoCompleteRequest(Irp, IO_NO_INCREMENT);
227
228   return(Status);
229 }
230
231
232 NTSTATUS STDCALL
233 NpfsWrite(PDEVICE_OBJECT DeviceObject,
234           PIRP Irp)
235 {
236   PIO_STACK_LOCATION IoStack;
237   PFILE_OBJECT FileObject;
238   PNPFS_FCB Fcb = NULL;
239   PNPFS_PIPE Pipe = NULL;
240   PUCHAR Buffer;
241   NTSTATUS Status = STATUS_SUCCESS;
242   ULONG Length;
243   ULONG Offset;
244   KIRQL OldIrql;
245   PNPFS_PIPE_DATA PipeData;
246
247   DPRINT("NpfsWrite()\n");
248
249   IoStack = IoGetCurrentIrpStackLocation(Irp);
250   FileObject = IoStack->FileObject;
251   DPRINT("FileObject %p\n", FileObject);
252   DPRINT("Pipe name %wZ\n", &FileObject->FileName);
253
254   Fcb = FileObject->FsContext;
255   Pipe = Fcb->Pipe;
256
257   Length = IoStack->Parameters.Write.Length;
258   Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
259
260   if (Irp->MdlAddress == NULL)
261     {
262       DbgPrint ("Irp->MdlAddress == NULL\n");
263       Status = STATUS_UNSUCCESSFUL;
264       Length = 0;
265       goto done;
266     }
267
268   if (Fcb->OtherSide == NULL)
269     {
270       DPRINT("Pipe is NOT connected!\n");
271       Status = STATUS_UNSUCCESSFUL;
272       Length = 0;
273       goto done;
274     }
275
276   Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
277   DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
278
279   PipeData = NpfsInitializePipeData(Buffer, Length);
280   if (PipeData)
281     {
282       DPRINT("Attaching pipe data at %p (%d bytes)\n", PipeData, Length);
283
284       KeAcquireSpinLock(&Fcb->DataListLock, &OldIrql);
285       InsertTailList(&Fcb->DataListHead, &PipeData->ListEntry);
286
287       /* signal the readers ReadEvent */
288       KeSetEvent(&Fcb->OtherSide->ReadEvent, IO_NO_INCREMENT, FALSE);
289
290       KeReleaseSpinLock(&Fcb->DataListLock, OldIrql);
291
292     }
293   else
294     {
295       Length = 0;
296       Status = STATUS_INSUFFICIENT_RESOURCES;
297     }
298
299 done:
300   Irp->IoStatus.Status = Status;
301   Irp->IoStatus.Information = Length;
302   
303   IoCompleteRequest(Irp, IO_NO_INCREMENT);
304   
305   return(Status);
306 }
307
308 /* EOF */