Do only signal the other side of the pipe if the pipe is connected.
[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 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
106 {
107 KeSetEvent(&WriterFcb->Event, IO_NO_INCREMENT, FALSE);
108 }
109 KeReleaseSpinLock(&Fcb->DataListLock, OldIrql);
110 if (Information > 0)
111 {
112 Status = STATUS_SUCCESS;
113 goto done;
114 }
115
116 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
117 {
118 DPRINT("PipeState: %x\n", Fcb->PipeState);
119 Status = STATUS_PIPE_BROKEN;
120 goto done;
121 }
122
123 /* Wait for ReadEvent to become signaled */
124 DPRINT("Waiting for readable data (%S)\n", Pipe->PipeName.Buffer);
125 Status = KeWaitForSingleObject(&Fcb->Event,
126 UserRequest,
127 KernelMode,
128 FALSE,
129 NULL);
130 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe->PipeName.Buffer, Status);
131
132 KeAcquireSpinLock(&Fcb->DataListLock, &OldIrql);
133 }
134
135 if (Pipe->ReadMode == FILE_PIPE_BYTE_STREAM_MODE)
136 {
137 DPRINT("Byte stream mode\n");
138 /* Byte stream mode */
139 while (Length > 0 && Fcb->ReadDataAvailable > 0)
140 {
141 CopyLength = RtlRosMin(Fcb->ReadDataAvailable, Length);
142 if (Fcb->ReadPtr + CopyLength <= Fcb->Data + Fcb->MaxDataLength)
143 {
144 memcpy(Buffer, Fcb->ReadPtr, CopyLength);
145 Fcb->ReadPtr += CopyLength;
146 if (Fcb->ReadPtr == Fcb->Data + Fcb->MaxDataLength)
147 {
148 Fcb->ReadPtr = Fcb->Data;
149 }
150 }
151 else
152 {
153 TempLength = Fcb->Data + Fcb->MaxDataLength - Fcb->ReadPtr;
154 memcpy(Buffer, Fcb->ReadPtr, TempLength);
155 memcpy(Buffer + TempLength, Fcb->Data, CopyLength - TempLength);
156 Fcb->ReadPtr = Fcb->Data + CopyLength - TempLength;
157 }
158
159 Buffer += CopyLength;
160 Length -= CopyLength;
161 Information += CopyLength;
162
163 Fcb->ReadDataAvailable -= CopyLength;
164 Fcb->WriteQuotaAvailable += CopyLength;
165 }
166
167 if (Length == 0)
168 {
169 KeSetEvent(&WriterFcb->Event, IO_NO_INCREMENT, FALSE);
170 break;
171 }
172 }
173 else
174 {
175 DPRINT("Message mode\n");
176
177 /* Message mode */
178 if (Fcb->ReadDataAvailable)
179 {
180 /* Truncate the message if the receive buffer is too small */
181 CopyLength = RtlRosMin(Fcb->ReadDataAvailable, Length);
182 memcpy(Buffer, Fcb->Data, CopyLength);
183
184 #ifndef NDEBUG
185 DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
186 HexDump((PUCHAR)Buffer, CopyLength);
187 #endif
188
189 Information = CopyLength;
190 Fcb->ReadDataAvailable = 0;
191 Fcb->WriteQuotaAvailable = Fcb->MaxDataLength;
192 }
193
194 if (Information > 0)
195 {
196 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
197 {
198 KeSetEvent(&WriterFcb->Event, IO_NO_INCREMENT, FALSE);
199 }
200 break;
201 }
202 }
203 }
204
205 KeReleaseSpinLock(&Fcb->DataListLock, OldIrql);
206
207 done:
208 Irp->IoStatus.Status = Status;
209 Irp->IoStatus.Information = Information;
210
211 IoCompleteRequest(Irp, IO_NO_INCREMENT);
212
213 DPRINT("NpfsRead done (Status %lx)\n", Status);
214
215 return Status;
216 }
217
218
219 NTSTATUS STDCALL
220 NpfsWrite(PDEVICE_OBJECT DeviceObject,
221 PIRP Irp)
222 {
223 PIO_STACK_LOCATION IoStack;
224 PFILE_OBJECT FileObject;
225 PNPFS_FCB Fcb = NULL;
226 PNPFS_FCB ReaderFcb;
227 PNPFS_PIPE Pipe = NULL;
228 PUCHAR Buffer;
229 NTSTATUS Status = STATUS_SUCCESS;
230 ULONG Length;
231 ULONG Offset;
232 KIRQL OldIrql;
233 ULONG Information;
234 ULONG CopyLength;
235 ULONG TempLength;
236
237 DPRINT("NpfsWrite()\n");
238
239 IoStack = IoGetCurrentIrpStackLocation(Irp);
240 FileObject = IoStack->FileObject;
241 DPRINT("FileObject %p\n", FileObject);
242 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
243
244 Fcb = FileObject->FsContext;
245 ReaderFcb = Fcb->OtherSide;
246 Pipe = Fcb->Pipe;
247
248 Length = IoStack->Parameters.Write.Length;
249 Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
250 Information = 0;
251
252 if (Irp->MdlAddress == NULL)
253 {
254 DPRINT("Irp->MdlAddress == NULL\n");
255 Status = STATUS_UNSUCCESSFUL;
256 Length = 0;
257 goto done;
258 }
259
260 if (ReaderFcb == NULL)
261 {
262 DPRINT("Pipe is NOT connected!\n");
263 if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
264 Status = STATUS_PIPE_LISTENING;
265 else if (Fcb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
266 Status = STATUS_PIPE_DISCONNECTED;
267 else
268 Status = STATUS_UNSUCCESSFUL;
269 Length = 0;
270 goto done;
271 }
272
273 if (ReaderFcb->Data == NULL)
274 {
275 DPRINT("Pipe is NOT writable!\n");
276 Status = STATUS_UNSUCCESSFUL;
277 Length = 0;
278 goto done;
279 }
280
281 Status = STATUS_SUCCESS;
282 Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
283
284 KeAcquireSpinLock(&ReaderFcb->DataListLock, &OldIrql);
285 #ifndef NDEBUG
286 DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
287 HexDump(Buffer, Length);
288 #endif
289
290 while(1)
291 {
292 if (ReaderFcb->WriteQuotaAvailable == 0)
293 {
294 KeResetEvent(&Fcb->Event);
295 KeSetEvent(&ReaderFcb->Event, IO_NO_INCREMENT, FALSE);
296 KeReleaseSpinLock(&ReaderFcb->DataListLock, OldIrql);
297 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
298 {
299 Status = STATUS_PIPE_BROKEN;
300 goto done;
301 }
302
303 DPRINT("Waiting for buffer space (%S)\n", Pipe->PipeName.Buffer);
304 Status = KeWaitForSingleObject(&Fcb->Event,
305 UserRequest,
306 KernelMode,
307 FALSE,
308 NULL);
309 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe->PipeName.Buffer, Status);
310
311 /*
312 * It's possible that the event was signaled because the
313 * other side of pipe was closed.
314 */
315 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
316 {
317 DPRINT("PipeState: %x\n", Fcb->PipeState);
318 Status = STATUS_PIPE_BROKEN;
319 goto done;
320 }
321 KeAcquireSpinLock(&ReaderFcb->DataListLock, &OldIrql);
322 }
323
324 if (Pipe->WriteMode == FILE_PIPE_BYTE_STREAM_MODE)
325 {
326 DPRINT("Byte stream mode\n");
327 while (Length > 0 && ReaderFcb->WriteQuotaAvailable > 0)
328 {
329 CopyLength = RtlRosMin(Length, ReaderFcb->WriteQuotaAvailable);
330 if (ReaderFcb->WritePtr + CopyLength <= ReaderFcb->Data + ReaderFcb->MaxDataLength)
331 {
332 memcpy(ReaderFcb->WritePtr, Buffer, CopyLength);
333 ReaderFcb->WritePtr += CopyLength;
334 if (ReaderFcb->WritePtr == ReaderFcb->Data + ReaderFcb->MaxDataLength)
335 {
336 ReaderFcb->WritePtr = ReaderFcb->Data;
337 }
338 }
339 else
340 {
341 TempLength = ReaderFcb->Data + ReaderFcb->MaxDataLength - ReaderFcb->WritePtr;
342 memcpy(ReaderFcb->WritePtr, Buffer, TempLength);
343 memcpy(ReaderFcb->Data, Buffer + TempLength, CopyLength - TempLength);
344 ReaderFcb->WritePtr = ReaderFcb->Data + CopyLength - TempLength;
345 }
346
347 Buffer += CopyLength;
348 Length -= CopyLength;
349 Information += CopyLength;
350
351 ReaderFcb->ReadDataAvailable += CopyLength;
352 ReaderFcb->WriteQuotaAvailable -= CopyLength;
353 }
354
355 if (Length == 0)
356 {
357 KeSetEvent(&ReaderFcb->Event, IO_NO_INCREMENT, FALSE);
358 break;
359 }
360 }
361 else
362 {
363 DPRINT("Message mode\n");
364 if (Length > 0)
365 {
366 CopyLength = RtlRosMin(Length, ReaderFcb->WriteQuotaAvailable);
367 memcpy(ReaderFcb->Data, Buffer, CopyLength);
368
369 Information = CopyLength;
370 ReaderFcb->ReadDataAvailable = CopyLength;
371 ReaderFcb->WriteQuotaAvailable = 0;
372 }
373
374 if (Information > 0)
375 {
376 KeSetEvent(&ReaderFcb->Event, IO_NO_INCREMENT, FALSE);
377 break;
378 }
379 }
380 }
381
382 KeReleaseSpinLock(&ReaderFcb->DataListLock, OldIrql);
383
384 done:
385 Irp->IoStatus.Status = Status;
386 Irp->IoStatus.Information = Information;
387
388 IoCompleteRequest(Irp, IO_NO_INCREMENT);
389
390 DPRINT("NpfsWrite done (Status %lx)\n", Status);
391
392 return Status;
393 }
394
395 /* EOF */