0676d42d34573ea3701446860f65e8158899c775
[reactos.git] / reactos / drivers / fs / np / rw.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/fs/np/rw.c
5 * PURPOSE: Named pipe filesystem
6 * PROGRAMMER: David Welch <welch@cwcom.net>
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #define NDEBUG
12 #include <debug.h>
13
14 #include "npfs.h"
15
16 /* FUNCTIONS *****************************************************************/
17
18 #ifndef NDEBUG
19 VOID HexDump(PUCHAR Buffer, ULONG Length)
20 {
21 CHAR Line[65];
22 UCHAR ch;
23 const char Hex[] = "0123456789ABCDEF";
24 int i, j;
25
26 DbgPrint("---------------\n");
27
28 for (i = 0; i < Length; i+= 16)
29 {
30 memset(Line, ' ', 64);
31 Line[64] = 0;
32
33 for (j = 0; j < 16 && j + i < Length; j++)
34 {
35 ch = Buffer[i + j];
36 Line[3*j + 0] = Hex[ch >> 4];
37 Line[3*j + 1] = Hex[ch & 0x0f];
38 Line[48 + j] = isprint(ch) ? ch : '.';
39 }
40 DbgPrint("%s\n", Line);
41 }
42 DbgPrint("---------------\n");
43 }
44 #endif
45
46 static VOID STDCALL
47 NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
48 IN PIRP Irp)
49 {
50 PNPFS_CONTEXT Context;
51 PNPFS_DEVICE_EXTENSION DeviceExt;
52 PIO_STACK_LOCATION IoStack;
53 PNPFS_FCB Fcb;
54 BOOLEAN Complete = FALSE;
55
56 DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %x, Irp %x)\n", DeviceObject, Irp);
57
58 IoReleaseCancelSpinLock(Irp->CancelIrql);
59
60 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
61 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
62 IoStack = IoGetCurrentIrpStackLocation(Irp);
63 Fcb = IoStack->FileObject->FsContext;
64
65 KeLockMutex(&DeviceExt->PipeListLock);
66 ExAcquireFastMutex(&Fcb->DataListLock);
67 switch(IoStack->MajorFunction)
68 {
69 case IRP_MJ_READ:
70 if (Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
71 {
72 /* we are not the first in the list, remove an complete us */
73 RemoveEntryList(&Context->ListEntry);
74 Complete = TRUE;
75 }
76 else
77 {
78 KeSetEvent(&Fcb->ReadEvent, IO_NO_INCREMENT, FALSE);
79 }
80 break;
81 default:
82 KEBUGCHECK(0);
83 }
84 ExReleaseFastMutex(&Fcb->DataListLock);
85 KeUnlockMutex(&DeviceExt->PipeListLock);
86 if (Complete)
87 {
88 Irp->IoStatus.Status = STATUS_CANCELLED;
89 Irp->IoStatus.Information = 0;
90 IoCompleteRequest(Irp, IO_NO_INCREMENT);
91 }
92 }
93
94 static VOID STDCALL
95 NpfsWaiterThread(PVOID InitContext)
96 {
97 PNPFS_THREAD_CONTEXT ThreadContext = (PNPFS_THREAD_CONTEXT) InitContext;
98 ULONG CurrentCount;
99 ULONG Count = 0;
100 PIRP Irp = NULL;
101 PIRP NextIrp;
102 NTSTATUS Status;
103 BOOLEAN Terminate = FALSE;
104 BOOLEAN Cancel = FALSE;
105 PIO_STACK_LOCATION IoStack = NULL;
106 PNPFS_CONTEXT Context;
107 PNPFS_CONTEXT NextContext;
108 PNPFS_FCB Fcb;
109
110 KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
111
112 while (1)
113 {
114 CurrentCount = ThreadContext->Count;
115 KeUnlockMutex(&ThreadContext->DeviceExt->PipeListLock);
116 if (Irp)
117 {
118 if (Cancel)
119 {
120 Irp->IoStatus.Status = STATUS_CANCELLED;
121 Irp->IoStatus.Information = 0;
122 IoCompleteRequest(Irp, IO_NO_INCREMENT);
123 }
124 else
125 {
126 switch (IoStack->MajorFunction)
127 {
128 case IRP_MJ_READ:
129 NpfsRead(IoStack->DeviceObject, Irp);
130 break;
131 default:
132 KEBUGCHECK(0);
133 }
134 }
135 }
136 if (Terminate)
137 {
138 break;
139 }
140 Status = KeWaitForMultipleObjects(CurrentCount,
141 ThreadContext->WaitObjectArray,
142 WaitAny,
143 Executive,
144 KernelMode,
145 FALSE,
146 NULL,
147 ThreadContext->WaitBlockArray);
148 if (!NT_SUCCESS(Status))
149 {
150 KEBUGCHECK(0);
151 }
152 KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
153 Count = Status - STATUS_SUCCESS;
154 ASSERT (Count < CurrentCount);
155 if (Count > 0)
156 {
157 Irp = ThreadContext->WaitIrpArray[Count];
158 ThreadContext->Count--;
159 ThreadContext->DeviceExt->EmptyWaiterCount++;
160 ThreadContext->WaitObjectArray[Count] = ThreadContext->WaitObjectArray[ThreadContext->Count];
161 ThreadContext->WaitIrpArray[Count] = ThreadContext->WaitIrpArray[ThreadContext->Count];
162
163 Cancel = (NULL == IoSetCancelRoutine(Irp, NULL));
164 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
165 IoStack = IoGetCurrentIrpStackLocation(Irp);
166
167 if (Cancel)
168 {
169 Fcb = IoStack->FileObject->FsContext;
170 ExAcquireFastMutex(&Fcb->DataListLock);
171 RemoveEntryList(&Context->ListEntry);
172 switch (IoStack->MajorFunction)
173 {
174 case IRP_MJ_READ:
175 if (!IsListEmpty(&Fcb->ReadRequestListHead))
176 {
177 /* put the next request on the wait list */
178 NextContext = CONTAINING_RECORD(Fcb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
179 ThreadContext->WaitObjectArray[ThreadContext->Count] = NextContext->WaitEvent;
180 NextIrp = CONTAINING_RECORD(NextContext, IRP, Tail.Overlay.DriverContext);
181 ThreadContext->WaitIrpArray[ThreadContext->Count] = NextIrp;
182 ThreadContext->Count++;
183 ThreadContext->DeviceExt->EmptyWaiterCount--;
184 }
185 KeUnlockMutex(&ThreadContext->DeviceExt->PipeListLock);
186 break;
187 default:
188 KEBUGCHECK(0);
189 }
190 ExReleaseFastMutex(&Fcb->DataListLock);
191 }
192 }
193 else
194 {
195 /* someone has add a new wait request */
196 Irp = NULL;
197 }
198 if (ThreadContext->Count == 1 && ThreadContext->DeviceExt->EmptyWaiterCount >= MAXIMUM_WAIT_OBJECTS)
199 {
200 /* it exist an other thread with empty wait slots, we can remove our thread from the list */
201 RemoveEntryList(&ThreadContext->ListEntry);
202 ThreadContext->DeviceExt->EmptyWaiterCount -= MAXIMUM_WAIT_OBJECTS - 1;
203 Terminate = TRUE;
204 }
205 }
206 ExFreePool(ThreadContext);
207 }
208
209 static NTSTATUS
210 NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject,
211 IN PIRP Irp)
212 {
213 PLIST_ENTRY ListEntry;
214 PNPFS_THREAD_CONTEXT ThreadContext = NULL;
215 NTSTATUS Status;
216 HANDLE hThread;
217 KIRQL oldIrql;
218
219 PNPFS_CONTEXT Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
220 PNPFS_DEVICE_EXTENSION DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
221
222 DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
223
224 KeLockMutex(&DeviceExt->PipeListLock);
225
226 ListEntry = DeviceExt->ThreadListHead.Flink;
227 while (ListEntry != &DeviceExt->ThreadListHead)
228 {
229 ThreadContext = CONTAINING_RECORD(ListEntry, NPFS_THREAD_CONTEXT, ListEntry);
230 if (ThreadContext->Count < MAXIMUM_WAIT_OBJECTS)
231 {
232 break;
233 }
234 ListEntry = ListEntry->Flink;
235 }
236 if (ListEntry == &DeviceExt->ThreadListHead)
237 {
238 ThreadContext = ExAllocatePool(NonPagedPool, sizeof(NPFS_THREAD_CONTEXT));
239 if (ThreadContext == NULL)
240 {
241 KeUnlockMutex(&DeviceExt->PipeListLock);
242 return STATUS_NO_MEMORY;
243 }
244 ThreadContext->DeviceExt = DeviceExt;
245 KeInitializeEvent(&ThreadContext->Event, SynchronizationEvent, FALSE);
246 ThreadContext->Count = 1;
247 ThreadContext->WaitObjectArray[0] = &ThreadContext->Event;
248
249
250 DPRINT("Creating a new system thread for waiting read/write requests\n");
251
252 Status = PsCreateSystemThread(&hThread,
253 THREAD_ALL_ACCESS,
254 NULL,
255 NULL,
256 NULL,
257 NpfsWaiterThread,
258 (PVOID)ThreadContext);
259 if (!NT_SUCCESS(Status))
260 {
261 ExFreePool(ThreadContext);
262 KeUnlockMutex(&DeviceExt->PipeListLock);
263 return Status;
264 }
265 InsertHeadList(&DeviceExt->ThreadListHead, &ThreadContext->ListEntry);
266 DeviceExt->EmptyWaiterCount += MAXIMUM_WAIT_OBJECTS - 1;
267 }
268 IoMarkIrpPending(Irp);
269
270 IoAcquireCancelSpinLock(&oldIrql);
271 if (Irp->Cancel)
272 {
273 IoReleaseCancelSpinLock(oldIrql);
274 Status = STATUS_CANCELLED;
275 }
276 else
277 {
278 IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
279 IoReleaseCancelSpinLock(oldIrql);
280 ThreadContext->WaitObjectArray[ThreadContext->Count] = Context->WaitEvent;
281 ThreadContext->WaitIrpArray[ThreadContext->Count] = Irp;
282 ThreadContext->Count++;
283 DeviceExt->EmptyWaiterCount--;
284 KeSetEvent(&ThreadContext->Event, IO_NO_INCREMENT, FALSE);
285 Status = STATUS_SUCCESS;
286 }
287 KeUnlockMutex(&DeviceExt->PipeListLock);
288 return Status;
289 }
290
291 NTSTATUS STDCALL
292 NpfsRead(IN PDEVICE_OBJECT DeviceObject,
293 IN PIRP Irp)
294 {
295 PFILE_OBJECT FileObject;
296 NTSTATUS Status;
297 NTSTATUS OriginalStatus = STATUS_SUCCESS;
298 PNPFS_FCB Fcb;
299 PNPFS_CONTEXT Context;
300 KEVENT Event;
301 ULONG Length;
302 ULONG Information;
303 ULONG CopyLength;
304 ULONG TempLength;
305 BOOLEAN IsOriginalRequest = TRUE;
306 PVOID Buffer;
307
308 DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
309
310 if (Irp->MdlAddress == NULL)
311 {
312 DPRINT("Irp->MdlAddress == NULL\n");
313 Status = STATUS_UNSUCCESSFUL;
314 Irp->IoStatus.Information = 0;
315 goto done;
316 }
317
318 FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
319 Fcb = FileObject->FsContext;
320 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
321
322 if (Fcb->Data == NULL)
323 {
324 DPRINT1("Pipe is NOT readable!\n");
325 Status = STATUS_UNSUCCESSFUL;
326 Irp->IoStatus.Information = 0;
327 goto done;
328 }
329
330 ExAcquireFastMutex(&Fcb->DataListLock);
331
332 if (IoIsOperationSynchronous(Irp))
333 {
334 InsertTailList(&Fcb->ReadRequestListHead, &Context->ListEntry);
335 if (Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
336 {
337 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
338 Context->WaitEvent = &Event;
339 ExReleaseFastMutex(&Fcb->DataListLock);
340 Status = KeWaitForSingleObject(&Event,
341 Executive,
342 KernelMode,
343 FALSE,
344 NULL);
345 if (!NT_SUCCESS(Status))
346 {
347 KEBUGCHECK(0);
348 }
349 ExAcquireFastMutex(&Fcb->DataListLock);
350 }
351 Irp->IoStatus.Information = 0;
352 }
353 else
354 {
355 KIRQL oldIrql;
356 if (IsListEmpty(&Fcb->ReadRequestListHead) ||
357 Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
358 {
359 /* this is a new request */
360 Irp->IoStatus.Information = 0;
361 Context->WaitEvent = &Fcb->ReadEvent;
362 InsertTailList(&Fcb->ReadRequestListHead, &Context->ListEntry);
363 if (Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
364 {
365 /* there was already a request on the list */
366 IoAcquireCancelSpinLock(&oldIrql);
367 if (Irp->Cancel)
368 {
369 IoReleaseCancelSpinLock(oldIrql);
370 RemoveEntryList(&Context->ListEntry);
371 ExReleaseFastMutex(&Fcb->DataListLock);
372 Status = STATUS_CANCELLED;
373 goto done;
374 }
375 IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
376 IoReleaseCancelSpinLock(oldIrql);
377 ExReleaseFastMutex(&Fcb->DataListLock);
378 IoMarkIrpPending(Irp);
379 Status = STATUS_PENDING;
380 goto done;
381 }
382 }
383 }
384
385 while (1)
386 {
387 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
388 Information = Irp->IoStatus.Information;
389 Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length;
390 ASSERT (Information <= Length);
391 Buffer = (PVOID)((ULONG_PTR)Buffer + Information);
392 Length -= Information;
393 Status = STATUS_SUCCESS;
394
395 while (1)
396 {
397 if (Fcb->ReadDataAvailable == 0)
398 {
399 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
400 {
401 ASSERT(Fcb->OtherSide != NULL);
402 KeSetEvent(&Fcb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
403 }
404 if (Information > 0 &&
405 (Fcb->Pipe->ReadMode != FILE_PIPE_BYTE_STREAM_MODE ||
406 Fcb->PipeState != FILE_PIPE_CONNECTED_STATE))
407 {
408 break;
409 }
410 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
411 {
412 DPRINT("PipeState: %x\n", Fcb->PipeState);
413 Status = STATUS_PIPE_BROKEN;
414 break;
415 }
416 ExReleaseFastMutex(&Fcb->DataListLock);
417 if (IoIsOperationSynchronous(Irp))
418 {
419 /* Wait for ReadEvent to become signaled */
420
421 DPRINT("Waiting for readable data (%wZ)\n", &Fcb->Pipe->PipeName);
422 Status = KeWaitForSingleObject(&Fcb->ReadEvent,
423 UserRequest,
424 KernelMode,
425 FALSE,
426 NULL);
427 DPRINT("Finished waiting (%wZ)! Status: %x\n", &Fcb->Pipe->PipeName, Status);
428 ExAcquireFastMutex(&Fcb->DataListLock);
429 }
430 else
431 {
432 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
433
434 Context->WaitEvent = &Fcb->ReadEvent;
435 Status = NpfsAddWaitingReadWriteRequest(DeviceObject, Irp);
436
437 if (NT_SUCCESS(Status))
438 {
439 Status = STATUS_PENDING;
440 }
441 ExAcquireFastMutex(&Fcb->DataListLock);
442 break;
443 }
444 }
445 if (Fcb->Pipe->ReadMode == FILE_PIPE_BYTE_STREAM_MODE)
446 {
447 DPRINT("Byte stream mode\n");
448 /* Byte stream mode */
449 while (Length > 0 && Fcb->ReadDataAvailable > 0)
450 {
451 CopyLength = min(Fcb->ReadDataAvailable, Length);
452 if ((ULONG_PTR)Fcb->ReadPtr + CopyLength <= (ULONG_PTR)Fcb->Data + Fcb->MaxDataLength)
453 {
454 memcpy(Buffer, Fcb->ReadPtr, CopyLength);
455 Fcb->ReadPtr = (PVOID)((ULONG_PTR)Fcb->ReadPtr + CopyLength);
456 if (Fcb->ReadPtr == (PVOID)((ULONG_PTR)Fcb->Data + Fcb->MaxDataLength))
457 {
458 Fcb->ReadPtr = Fcb->Data;
459 }
460 }
461 else
462 {
463 TempLength = (ULONG)((ULONG_PTR)Fcb->Data + Fcb->MaxDataLength - (ULONG_PTR)Fcb->ReadPtr);
464 memcpy(Buffer, Fcb->ReadPtr, TempLength);
465 memcpy((PVOID)((ULONG_PTR)Buffer + TempLength), Fcb->Data, CopyLength - TempLength);
466 Fcb->ReadPtr = (PVOID)((ULONG_PTR)Fcb->Data + CopyLength - TempLength);
467 }
468
469 Buffer = (PVOID)((ULONG_PTR)Buffer + CopyLength);
470 Length -= CopyLength;
471 Information += CopyLength;
472
473 Fcb->ReadDataAvailable -= CopyLength;
474 Fcb->WriteQuotaAvailable += CopyLength;
475 }
476
477 if (Length == 0)
478 {
479 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
480 {
481 KeSetEvent(&Fcb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
482 }
483 KeResetEvent(&Fcb->ReadEvent);
484 break;
485 }
486 }
487 else
488 {
489 DPRINT("Message mode\n");
490
491 /* Message mode */
492 if (Fcb->ReadDataAvailable)
493 {
494 /* Truncate the message if the receive buffer is too small */
495 CopyLength = min(Fcb->ReadDataAvailable, Length);
496 memcpy(Buffer, Fcb->Data, CopyLength);
497
498 #ifndef NDEBUG
499 DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
500 HexDump((PUCHAR)Buffer, CopyLength);
501 #endif
502
503 Information = CopyLength;
504
505 if (Fcb->ReadDataAvailable > Length)
506 {
507 memmove(Fcb->Data, (PVOID)((ULONG_PTR)Fcb->Data + Length),
508 Fcb->ReadDataAvailable - Length);
509 Fcb->ReadDataAvailable -= Length;
510 Status = STATUS_MORE_ENTRIES;
511 }
512 else
513 {
514 KeResetEvent(&Fcb->ReadEvent);
515 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
516 {
517 KeSetEvent(&Fcb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
518 }
519 Fcb->ReadDataAvailable = 0;
520 Fcb->WriteQuotaAvailable = Fcb->MaxDataLength;
521 }
522 }
523
524 if (Information > 0)
525 {
526 break;
527 }
528 }
529 }
530 Irp->IoStatus.Information = Information;
531 Irp->IoStatus.Status = Status;
532
533 ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
534
535 if (IoIsOperationSynchronous(Irp))
536 {
537 RemoveEntryList(&Context->ListEntry);
538 if (!IsListEmpty(&Fcb->ReadRequestListHead))
539 {
540 Context = CONTAINING_RECORD(Fcb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
541 KeSetEvent(Context->WaitEvent, IO_NO_INCREMENT, FALSE);
542 }
543 ExReleaseFastMutex(&Fcb->DataListLock);
544 IoCompleteRequest(Irp, IO_NO_INCREMENT);
545
546 DPRINT("NpfsRead done (Status %lx)\n", Status);
547 return Status;
548 }
549 else
550 {
551 if (IsOriginalRequest)
552 {
553 IsOriginalRequest = FALSE;
554 OriginalStatus = Status;
555 }
556 if (Status == STATUS_PENDING)
557 {
558 ExReleaseFastMutex(&Fcb->DataListLock);
559 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
560 return OriginalStatus;
561 }
562 RemoveEntryList(&Context->ListEntry);
563 IoCompleteRequest(Irp, IO_NO_INCREMENT);
564 if (IsListEmpty(&Fcb->ReadRequestListHead))
565 {
566 ExReleaseFastMutex(&Fcb->DataListLock);
567 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
568 return OriginalStatus;
569 }
570 Context = CONTAINING_RECORD(Fcb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
571 Irp = CONTAINING_RECORD(Context, IRP, Tail.Overlay.DriverContext);
572 }
573 }
574
575 done:
576 Irp->IoStatus.Status = Status;
577
578 if (Status != STATUS_PENDING)
579 {
580 IoCompleteRequest(Irp, IO_NO_INCREMENT);
581 }
582 DPRINT("NpfsRead done (Status %lx)\n", Status);
583
584 return Status;
585 }
586
587 NTSTATUS STDCALL
588 NpfsWrite(PDEVICE_OBJECT DeviceObject,
589 PIRP Irp)
590 {
591 PIO_STACK_LOCATION IoStack;
592 PFILE_OBJECT FileObject;
593 PNPFS_FCB Fcb = NULL;
594 PNPFS_FCB ReaderFcb;
595 PNPFS_PIPE Pipe = NULL;
596 PUCHAR Buffer;
597 NTSTATUS Status = STATUS_SUCCESS;
598 ULONG Length;
599 ULONG Offset;
600 ULONG Information;
601 ULONG CopyLength;
602 ULONG TempLength;
603
604 DPRINT("NpfsWrite()\n");
605
606 IoStack = IoGetCurrentIrpStackLocation(Irp);
607 FileObject = IoStack->FileObject;
608 DPRINT("FileObject %p\n", FileObject);
609 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
610
611 Fcb = FileObject->FsContext;
612 ReaderFcb = Fcb->OtherSide;
613 Pipe = Fcb->Pipe;
614
615 Length = IoStack->Parameters.Write.Length;
616 Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
617 Information = 0;
618
619 if (Irp->MdlAddress == NULL)
620 {
621 DPRINT("Irp->MdlAddress == NULL\n");
622 Status = STATUS_UNSUCCESSFUL;
623 Length = 0;
624 goto done;
625 }
626
627 if (ReaderFcb == NULL)
628 {
629 DPRINT("Pipe is NOT connected!\n");
630 if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
631 Status = STATUS_PIPE_LISTENING;
632 else if (Fcb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
633 Status = STATUS_PIPE_DISCONNECTED;
634 else
635 Status = STATUS_UNSUCCESSFUL;
636 Length = 0;
637 goto done;
638 }
639
640 if (ReaderFcb->Data == NULL)
641 {
642 DPRINT("Pipe is NOT writable!\n");
643 Status = STATUS_UNSUCCESSFUL;
644 Length = 0;
645 goto done;
646 }
647
648 Status = STATUS_SUCCESS;
649 Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
650
651 ExAcquireFastMutex(&ReaderFcb->DataListLock);
652 #ifndef NDEBUG
653 DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
654 HexDump(Buffer, Length);
655 #endif
656
657 while(1)
658 {
659 if (ReaderFcb->WriteQuotaAvailable == 0)
660 {
661 KeSetEvent(&ReaderFcb->ReadEvent, IO_NO_INCREMENT, FALSE);
662 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
663 {
664 Status = STATUS_PIPE_BROKEN;
665 ExReleaseFastMutex(&ReaderFcb->DataListLock);
666 goto done;
667 }
668 ExReleaseFastMutex(&ReaderFcb->DataListLock);
669
670 DPRINT("Waiting for buffer space (%S)\n", Pipe->PipeName.Buffer);
671 Status = KeWaitForSingleObject(&Fcb->WriteEvent,
672 UserRequest,
673 KernelMode,
674 FALSE,
675 NULL);
676 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe->PipeName.Buffer, Status);
677
678 ExAcquireFastMutex(&ReaderFcb->DataListLock);
679 /*
680 * It's possible that the event was signaled because the
681 * other side of pipe was closed.
682 */
683 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
684 {
685 DPRINT("PipeState: %x\n", Fcb->PipeState);
686 Status = STATUS_PIPE_BROKEN;
687 ExReleaseFastMutex(&ReaderFcb->DataListLock);
688 goto done;
689 }
690 }
691
692 if (Pipe->WriteMode == FILE_PIPE_BYTE_STREAM_MODE)
693 {
694 DPRINT("Byte stream mode\n");
695 while (Length > 0 && ReaderFcb->WriteQuotaAvailable > 0)
696 {
697 CopyLength = min(Length, ReaderFcb->WriteQuotaAvailable);
698 if ((ULONG_PTR)ReaderFcb->WritePtr + CopyLength <= (ULONG_PTR)ReaderFcb->Data + ReaderFcb->MaxDataLength)
699 {
700 memcpy(ReaderFcb->WritePtr, Buffer, CopyLength);
701 ReaderFcb->WritePtr = (PVOID)((ULONG_PTR)ReaderFcb->WritePtr + CopyLength);
702 if ((ULONG_PTR)ReaderFcb->WritePtr == (ULONG_PTR)ReaderFcb->Data + ReaderFcb->MaxDataLength)
703 {
704 ReaderFcb->WritePtr = ReaderFcb->Data;
705 }
706 }
707 else
708 {
709 TempLength = (ULONG)((ULONG_PTR)ReaderFcb->Data + ReaderFcb->MaxDataLength - (ULONG_PTR)ReaderFcb->WritePtr);
710 memcpy(ReaderFcb->WritePtr, Buffer, TempLength);
711 memcpy(ReaderFcb->Data, Buffer + TempLength, CopyLength - TempLength);
712 ReaderFcb->WritePtr = (PVOID)((ULONG_PTR)ReaderFcb->Data + CopyLength - TempLength);
713 }
714
715 Buffer += CopyLength;
716 Length -= CopyLength;
717 Information += CopyLength;
718
719 ReaderFcb->ReadDataAvailable += CopyLength;
720 ReaderFcb->WriteQuotaAvailable -= CopyLength;
721 }
722
723 if (Length == 0)
724 {
725 KeSetEvent(&ReaderFcb->ReadEvent, IO_NO_INCREMENT, FALSE);
726 KeResetEvent(&Fcb->WriteEvent);
727 break;
728 }
729 }
730 else
731 {
732 DPRINT("Message mode\n");
733 if (Length > 0)
734 {
735 CopyLength = min(Length, ReaderFcb->WriteQuotaAvailable);
736 memcpy(ReaderFcb->Data, Buffer, CopyLength);
737
738 Information = CopyLength;
739 ReaderFcb->ReadDataAvailable = CopyLength;
740 ReaderFcb->WriteQuotaAvailable = 0;
741 }
742
743 if (Information > 0)
744 {
745 KeSetEvent(&ReaderFcb->ReadEvent, IO_NO_INCREMENT, FALSE);
746 KeResetEvent(&Fcb->WriteEvent);
747 break;
748 }
749 }
750 }
751
752 ExReleaseFastMutex(&ReaderFcb->DataListLock);
753
754 done:
755 Irp->IoStatus.Status = Status;
756 Irp->IoStatus.Information = Information;
757
758 IoCompleteRequest(Irp, IO_NO_INCREMENT);
759
760 DPRINT("NpfsWrite done (Status %lx)\n", Status);
761
762 return Status;
763 }
764
765 /* EOF */