f7ff3a5b0b1e1c8e9b011116235b23fb7318ad57
[reactos.git] / reactos / drivers / fs / np / rw.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: drivers/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 <rosrtl/minmax.h>
14 #include "npfs.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* FUNCTIONS *****************************************************************/
20
21 #ifndef NDEBUG
22 VOID HexDump(PUCHAR Buffer, ULONG Length)
23 {
24 CHAR Line[65];
25 UCHAR ch;
26 const char Hex[] = "0123456789ABCDEF";
27 int i, j;
28
29 DbgPrint("---------------\n");
30
31 for (i = 0; i < ROUND_UP(Length, 16); i+= 16)
32 {
33 memset(Line, ' ', 64);
34 Line[64] = 0;
35
36 for (j = 0; j < 16 && j + i < Length; j++)
37 {
38 ch = Buffer[i + j];
39 Line[3*j + 0] = Hex[ch >> 4];
40 Line[3*j + 1] = Hex[ch & 0x0f];
41 Line[48 + j] = isprint(ch) ? ch : '.';
42 }
43 DbgPrint("%s\n", Line);
44 }
45 DbgPrint("---------------\n");
46 }
47 #endif
48
49
50 NTSTATUS STDCALL
51 NpfsRead(PDEVICE_OBJECT DeviceObject,
52 PIRP Irp)
53 {
54 PIO_STACK_LOCATION IoStack;
55 PFILE_OBJECT FileObject;
56 NTSTATUS Status;
57 PNPFS_DEVICE_EXTENSION DeviceExt;
58 KIRQL OldIrql;
59 ULONG Information;
60 PNPFS_FCB Fcb;
61 PNPFS_FCB WriterFcb;
62 PNPFS_PIPE Pipe;
63 ULONG Length;
64 PVOID Buffer;
65 ULONG CopyLength;
66 ULONG TempLength;
67
68 DPRINT("NpfsRead(DeviceObject %p Irp %p)\n", DeviceObject, Irp);
69
70 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
71 IoStack = IoGetCurrentIrpStackLocation(Irp);
72 FileObject = IoStack->FileObject;
73 Fcb = FileObject->FsContext;
74 Pipe = Fcb->Pipe;
75 WriterFcb = Fcb->OtherSide;
76
77 if (Irp->MdlAddress == NULL)
78 {
79 DPRINT("Irp->MdlAddress == NULL\n");
80 Status = STATUS_UNSUCCESSFUL;
81 Information = 0;
82 goto done;
83 }
84
85 if (Fcb->Data == NULL)
86 {
87 DPRINT("Pipe is NOT readable!\n");
88 Status = STATUS_UNSUCCESSFUL;
89 Information = 0;
90 goto done;
91 }
92
93 Status = STATUS_SUCCESS;
94 Length = IoStack->Parameters.Read.Length;
95 Information = 0;
96
97 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
98 KeAcquireSpinLock(&Fcb->DataListLock, &OldIrql);
99 while (1)
100 {
101 /* FIXME: check if in blocking mode */
102 if (Fcb->ReadDataAvailable == 0)
103 {
104 KeResetEvent(&Fcb->Event);
105 KeSetEvent(&WriterFcb->Event, IO_NO_INCREMENT, FALSE);
106 KeReleaseSpinLock(&Fcb->DataListLock, OldIrql);
107 if (Information > 0)
108 {
109 Status = STATUS_SUCCESS;
110 goto done;
111 }
112
113 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
114 {
115 DPRINT("PipeState: %x\n", Fcb->PipeState);
116 Status = STATUS_PIPE_BROKEN;
117 goto done;
118 }
119
120 /* Wait for ReadEvent to become signaled */
121 DPRINT("Waiting for readable data (%S)\n", Pipe->PipeName.Buffer);
122 Status = KeWaitForSingleObject(&Fcb->Event,
123 UserRequest,
124 KernelMode,
125 FALSE,
126 NULL);
127 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe->PipeName.Buffer, Status);
128
129 KeAcquireSpinLock(&Fcb->DataListLock, &OldIrql);
130 }
131
132 if (Pipe->ReadMode == FILE_PIPE_BYTE_STREAM_MODE)
133 {
134 DPRINT("Byte stream mode\n");
135 /* Byte stream mode */
136 while (Length > 0 && Fcb->ReadDataAvailable > 0)
137 {
138 CopyLength = RtlRosMin(Fcb->ReadDataAvailable, Length);
139 if (Fcb->ReadPtr + CopyLength <= Fcb->Data + Fcb->MaxDataLength)
140 {
141 memcpy(Buffer, Fcb->ReadPtr, CopyLength);
142 Fcb->ReadPtr += CopyLength;
143 if (Fcb->ReadPtr == Fcb->Data + Fcb->MaxDataLength)
144 {
145 Fcb->ReadPtr = Fcb->Data;
146 }
147 }
148 else
149 {
150 TempLength = Fcb->Data + Fcb->MaxDataLength - Fcb->ReadPtr;
151 memcpy(Buffer, Fcb->ReadPtr, TempLength);
152 memcpy(Buffer + TempLength, Fcb->Data, CopyLength - TempLength);
153 Fcb->ReadPtr = Fcb->Data + CopyLength - TempLength;
154 }
155
156 Buffer += CopyLength;
157 Length -= CopyLength;
158 Information += CopyLength;
159
160 Fcb->ReadDataAvailable -= CopyLength;
161 Fcb->WriteQuotaAvailable += CopyLength;
162 }
163
164 if (Length == 0)
165 {
166 KeSetEvent(&WriterFcb->Event, IO_NO_INCREMENT, FALSE);
167 break;
168 }
169 }
170 else
171 {
172 DPRINT("Message mode\n");
173
174 /* Message mode */
175 if (Fcb->ReadDataAvailable)
176 {
177 /* Truncate the message if the receive buffer is too small */
178 CopyLength = RtlRosMin(Fcb->ReadDataAvailable, Length);
179 memcpy(Buffer, Fcb->Data, CopyLength);
180
181 #ifndef NDEBUG
182 DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
183 HexDump((PUCHAR)Buffer, CopyLength);
184 #endif
185
186 Information = CopyLength;
187 Fcb->ReadDataAvailable = 0;
188 Fcb->WriteQuotaAvailable = Fcb->MaxDataLength;
189 }
190
191 if (Information > 0)
192 {
193 KeSetEvent(&WriterFcb->Event, IO_NO_INCREMENT, FALSE);
194 break;
195 }
196 }
197 }
198
199 KeReleaseSpinLock(&Fcb->DataListLock, OldIrql);
200
201 done:
202 Irp->IoStatus.Status = Status;
203 Irp->IoStatus.Information = Information;
204
205 IoCompleteRequest(Irp, IO_NO_INCREMENT);
206
207 DPRINT("NpfsRead done (Status %lx)\n", Status);
208
209 return Status;
210 }
211
212
213 NTSTATUS STDCALL
214 NpfsWrite(PDEVICE_OBJECT DeviceObject,
215 PIRP Irp)
216 {
217 PIO_STACK_LOCATION IoStack;
218 PFILE_OBJECT FileObject;
219 PNPFS_FCB Fcb = NULL;
220 PNPFS_FCB ReaderFcb;
221 PNPFS_PIPE Pipe = NULL;
222 PUCHAR Buffer;
223 NTSTATUS Status = STATUS_SUCCESS;
224 ULONG Length;
225 ULONG Offset;
226 KIRQL OldIrql;
227 ULONG Information;
228 ULONG CopyLength;
229 ULONG TempLength;
230
231 DPRINT("NpfsWrite()\n");
232
233 IoStack = IoGetCurrentIrpStackLocation(Irp);
234 FileObject = IoStack->FileObject;
235 DPRINT("FileObject %p\n", FileObject);
236 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
237
238 Fcb = FileObject->FsContext;
239 ReaderFcb = Fcb->OtherSide;
240 Pipe = Fcb->Pipe;
241
242 Length = IoStack->Parameters.Write.Length;
243 Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
244 Information = 0;
245
246 if (Irp->MdlAddress == NULL)
247 {
248 DPRINT("Irp->MdlAddress == NULL\n");
249 Status = STATUS_UNSUCCESSFUL;
250 Length = 0;
251 goto done;
252 }
253
254 if (ReaderFcb == NULL)
255 {
256 DPRINT("Pipe is NOT connected!\n");
257 if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
258 Status = STATUS_PIPE_LISTENING;
259 else if (Fcb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
260 Status = STATUS_PIPE_DISCONNECTED;
261 else
262 Status = STATUS_UNSUCCESSFUL;
263 Length = 0;
264 goto done;
265 }
266
267 if (ReaderFcb->Data == NULL)
268 {
269 DPRINT("Pipe is NOT writable!\n");
270 Status = STATUS_UNSUCCESSFUL;
271 Length = 0;
272 goto done;
273 }
274
275 Status = STATUS_SUCCESS;
276 Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
277
278 KeAcquireSpinLock(&ReaderFcb->DataListLock, &OldIrql);
279 #ifndef NDEBUG
280 DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
281 HexDump(Buffer, Length);
282 #endif
283
284 while(1)
285 {
286 if (ReaderFcb->WriteQuotaAvailable == 0)
287 {
288 KeResetEvent(&Fcb->Event);
289 KeSetEvent(&ReaderFcb->Event, IO_NO_INCREMENT, FALSE);
290 KeReleaseSpinLock(&ReaderFcb->DataListLock, OldIrql);
291 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
292 {
293 Status = STATUS_PIPE_BROKEN;
294 goto done;
295 }
296
297 DPRINT("Waiting for buffer space (%S)\n", Pipe->PipeName.Buffer);
298 Status = KeWaitForSingleObject(&Fcb->Event,
299 UserRequest,
300 KernelMode,
301 FALSE,
302 NULL);
303 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe->PipeName.Buffer, Status);
304
305 /*
306 * It's possible that the event was signaled because the
307 * other side of pipe was closed.
308 */
309 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
310 {
311 DPRINT("PipeState: %x\n", Fcb->PipeState);
312 Status = STATUS_PIPE_BROKEN;
313 goto done;
314 }
315 KeAcquireSpinLock(&ReaderFcb->DataListLock, &OldIrql);
316 }
317
318 if (Pipe->WriteMode == FILE_PIPE_BYTE_STREAM_MODE)
319 {
320 DPRINT("Byte stream mode\n");
321 while (Length > 0 && ReaderFcb->WriteQuotaAvailable > 0)
322 {
323 CopyLength = RtlRosMin(Length, ReaderFcb->WriteQuotaAvailable);
324 if (ReaderFcb->WritePtr + CopyLength <= ReaderFcb->Data + ReaderFcb->MaxDataLength)
325 {
326 memcpy(ReaderFcb->WritePtr, Buffer, CopyLength);
327 ReaderFcb->WritePtr += CopyLength;
328 if (ReaderFcb->WritePtr == ReaderFcb->Data + ReaderFcb->MaxDataLength)
329 {
330 ReaderFcb->WritePtr = ReaderFcb->Data;
331 }
332 }
333 else
334 {
335 TempLength = ReaderFcb->Data + ReaderFcb->MaxDataLength - ReaderFcb->WritePtr;
336 memcpy(ReaderFcb->WritePtr, Buffer, TempLength);
337 memcpy(ReaderFcb->Data, Buffer + TempLength, CopyLength - TempLength);
338 ReaderFcb->WritePtr = ReaderFcb->Data + CopyLength - TempLength;
339 }
340
341 Buffer += CopyLength;
342 Length -= CopyLength;
343 Information += CopyLength;
344
345 ReaderFcb->ReadDataAvailable += CopyLength;
346 ReaderFcb->WriteQuotaAvailable -= CopyLength;
347 }
348
349 if (Length == 0)
350 {
351 KeSetEvent(&ReaderFcb->Event, IO_NO_INCREMENT, FALSE);
352 break;
353 }
354 }
355 else
356 {
357 DPRINT("Message mode\n");
358 if (Length > 0)
359 {
360 CopyLength = RtlRosMin(Length, ReaderFcb->WriteQuotaAvailable);
361 memcpy(ReaderFcb->Data, Buffer, CopyLength);
362
363 Information = CopyLength;
364 ReaderFcb->ReadDataAvailable = CopyLength;
365 ReaderFcb->WriteQuotaAvailable = 0;
366 }
367
368 if (Information > 0)
369 {
370 KeSetEvent(&ReaderFcb->Event, IO_NO_INCREMENT, FALSE);
371 break;
372 }
373 }
374 }
375
376 KeReleaseSpinLock(&ReaderFcb->DataListLock, OldIrql);
377
378 done:
379 Irp->IoStatus.Status = Status;
380 Irp->IoStatus.Information = Information;
381
382 IoCompleteRequest(Irp, IO_NO_INCREMENT);
383
384 DPRINT("NpfsWrite done (Status %lx)\n", Status);
385
386 return Status;
387 }
388
389 /* EOF */