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