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