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