Create a branch for network fixes.
[reactos.git] / drivers / filesystems / npfs / 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 #include "npfs.h"
12
13 #define NDEBUG
14 #include <debug.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 DRIVER_CANCEL NpfsReadWriteCancelRoutine;
47 static VOID STDCALL
48 NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
49 IN PIRP Irp)
50 {
51 PNPFS_CONTEXT Context;
52 PNPFS_DEVICE_EXTENSION DeviceExt;
53 PIO_STACK_LOCATION IoStack;
54 PNPFS_CCB Ccb;
55 BOOLEAN Complete = FALSE;
56
57 DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
58
59 IoReleaseCancelSpinLock(Irp->CancelIrql);
60
61 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
62 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
63 IoStack = IoGetCurrentIrpStackLocation(Irp);
64 Ccb = IoStack->FileObject->FsContext2;
65
66 KeLockMutex(&DeviceExt->PipeListLock);
67 ExAcquireFastMutex(&Ccb->DataListLock);
68 switch(IoStack->MajorFunction)
69 {
70 case IRP_MJ_READ:
71 if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
72 {
73 /* we are not the first in the list, remove an complete us */
74 RemoveEntryList(&Context->ListEntry);
75 Complete = TRUE;
76 }
77 else
78 {
79 KeSetEvent(&Ccb->ReadEvent, IO_NO_INCREMENT, FALSE);
80 }
81 break;
82 default:
83 KEBUGCHECK(0);
84 }
85 ExReleaseFastMutex(&Ccb->DataListLock);
86 KeUnlockMutex(&DeviceExt->PipeListLock);
87 if (Complete)
88 {
89 Irp->IoStatus.Status = STATUS_CANCELLED;
90 Irp->IoStatus.Information = 0;
91 IoCompleteRequest(Irp, IO_NO_INCREMENT);
92 }
93 }
94
95 static VOID STDCALL
96 NpfsWaiterThread(PVOID InitContext)
97 {
98 PNPFS_THREAD_CONTEXT ThreadContext = (PNPFS_THREAD_CONTEXT) InitContext;
99 ULONG CurrentCount;
100 ULONG Count = 0;
101 PIRP Irp = NULL;
102 PIRP NextIrp;
103 NTSTATUS Status;
104 BOOLEAN Terminate = FALSE;
105 BOOLEAN Cancel = FALSE;
106 PIO_STACK_LOCATION IoStack = NULL;
107 PNPFS_CONTEXT Context;
108 PNPFS_CONTEXT NextContext;
109 PNPFS_CCB Ccb;
110
111 KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
112
113 while (1)
114 {
115 CurrentCount = ThreadContext->Count;
116 KeUnlockMutex(&ThreadContext->DeviceExt->PipeListLock);
117 if (Irp)
118 {
119 if (Cancel)
120 {
121 Irp->IoStatus.Status = STATUS_CANCELLED;
122 Irp->IoStatus.Information = 0;
123 IoCompleteRequest(Irp, IO_NO_INCREMENT);
124 }
125 else
126 {
127 switch (IoStack->MajorFunction)
128 {
129 case IRP_MJ_READ:
130 NpfsRead(IoStack->DeviceObject, Irp);
131 break;
132 default:
133 KEBUGCHECK(0);
134 }
135 }
136 }
137 if (Terminate)
138 {
139 break;
140 }
141 Status = KeWaitForMultipleObjects(CurrentCount,
142 ThreadContext->WaitObjectArray,
143 WaitAny,
144 Executive,
145 KernelMode,
146 FALSE,
147 NULL,
148 ThreadContext->WaitBlockArray);
149 if (!NT_SUCCESS(Status))
150 {
151 KEBUGCHECK(0);
152 }
153 KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
154 Count = Status - STATUS_SUCCESS;
155 ASSERT (Count < CurrentCount);
156 if (Count > 0)
157 {
158 Irp = ThreadContext->WaitIrpArray[Count];
159 ThreadContext->Count--;
160 ThreadContext->DeviceExt->EmptyWaiterCount++;
161 ThreadContext->WaitObjectArray[Count] = ThreadContext->WaitObjectArray[ThreadContext->Count];
162 ThreadContext->WaitIrpArray[Count] = ThreadContext->WaitIrpArray[ThreadContext->Count];
163
164 Cancel = (NULL == IoSetCancelRoutine(Irp, NULL));
165 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
166 IoStack = IoGetCurrentIrpStackLocation(Irp);
167
168 if (Cancel)
169 {
170 Ccb = IoStack->FileObject->FsContext2;
171 ExAcquireFastMutex(&Ccb->DataListLock);
172 RemoveEntryList(&Context->ListEntry);
173 switch (IoStack->MajorFunction)
174 {
175 case IRP_MJ_READ:
176 if (!IsListEmpty(&Ccb->ReadRequestListHead))
177 {
178 /* put the next request on the wait list */
179 NextContext = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
180 ThreadContext->WaitObjectArray[ThreadContext->Count] = NextContext->WaitEvent;
181 NextIrp = CONTAINING_RECORD(NextContext, IRP, Tail.Overlay.DriverContext);
182 ThreadContext->WaitIrpArray[ThreadContext->Count] = NextIrp;
183 ThreadContext->Count++;
184 ThreadContext->DeviceExt->EmptyWaiterCount--;
185 }
186 break;
187 default:
188 KEBUGCHECK(0);
189 }
190 ExReleaseFastMutex(&Ccb->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 (void)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_CCB Ccb;
299 PNPFS_CONTEXT Context;
300 KEVENT Event;
301 ULONG Length;
302 ULONG Information = 0;
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 Ccb = FileObject->FsContext2;
320 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
321
322 if (Ccb->OtherSide == NULL)
323 {
324 DPRINT("Pipe is NOT connected!\n");
325 if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
326 Status = STATUS_PIPE_LISTENING;
327 else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
328 Status = STATUS_PIPE_DISCONNECTED;
329 else
330 Status = STATUS_UNSUCCESSFUL;
331 Irp->IoStatus.Information = 0;
332 goto done;
333 }
334
335 if (Ccb->Data == NULL)
336 {
337 DPRINT1("Pipe is NOT readable!\n");
338 Status = STATUS_UNSUCCESSFUL;
339 Irp->IoStatus.Information = 0;
340 goto done;
341 }
342
343 ExAcquireFastMutex(&Ccb->DataListLock);
344
345 if (IoIsOperationSynchronous(Irp))
346 {
347 InsertTailList(&Ccb->ReadRequestListHead, &Context->ListEntry);
348 if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
349 {
350 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
351 Context->WaitEvent = &Event;
352 ExReleaseFastMutex(&Ccb->DataListLock);
353 Status = KeWaitForSingleObject(&Event,
354 Executive,
355 KernelMode,
356 FALSE,
357 NULL);
358 if (!NT_SUCCESS(Status))
359 {
360 KEBUGCHECK(0);
361 }
362 ExAcquireFastMutex(&Ccb->DataListLock);
363 }
364 Irp->IoStatus.Information = 0;
365 }
366 else
367 {
368 KIRQL oldIrql;
369 if (IsListEmpty(&Ccb->ReadRequestListHead) ||
370 Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
371 {
372 /* this is a new request */
373 Irp->IoStatus.Information = 0;
374 Context->WaitEvent = &Ccb->ReadEvent;
375 InsertTailList(&Ccb->ReadRequestListHead, &Context->ListEntry);
376 if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
377 {
378 /* there was already a request on the list */
379 IoAcquireCancelSpinLock(&oldIrql);
380 if (Irp->Cancel)
381 {
382 IoReleaseCancelSpinLock(oldIrql);
383 RemoveEntryList(&Context->ListEntry);
384 ExReleaseFastMutex(&Ccb->DataListLock);
385 Status = STATUS_CANCELLED;
386 goto done;
387 }
388 (void)IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
389 IoReleaseCancelSpinLock(oldIrql);
390 ExReleaseFastMutex(&Ccb->DataListLock);
391 IoMarkIrpPending(Irp);
392 Status = STATUS_PENDING;
393 goto done;
394 }
395 }
396 }
397
398 while (1)
399 {
400 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
401 Information = Irp->IoStatus.Information;
402 Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length;
403 ASSERT (Information <= Length);
404 Buffer = (PVOID)((ULONG_PTR)Buffer + Information);
405 Length -= Information;
406 Status = STATUS_SUCCESS;
407
408 while (1)
409 {
410 if (Ccb->ReadDataAvailable == 0)
411 {
412 if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
413 {
414 ASSERT(Ccb->OtherSide != NULL);
415 KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
416 }
417 if (Information > 0 &&
418 (Ccb->Fcb->ReadMode != FILE_PIPE_BYTE_STREAM_MODE ||
419 Ccb->PipeState != FILE_PIPE_CONNECTED_STATE))
420 {
421 break;
422 }
423 if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
424 {
425 DPRINT("PipeState: %x\n", Ccb->PipeState);
426 Status = STATUS_PIPE_BROKEN;
427 break;
428 }
429 ExReleaseFastMutex(&Ccb->DataListLock);
430 if (IoIsOperationSynchronous(Irp))
431 {
432 /* Wait for ReadEvent to become signaled */
433
434 DPRINT("Waiting for readable data (%wZ)\n", &Ccb->Fcb->PipeName);
435 Status = KeWaitForSingleObject(&Ccb->ReadEvent,
436 UserRequest,
437 KernelMode,
438 FALSE,
439 NULL);
440 DPRINT("Finished waiting (%wZ)! Status: %x\n", &Ccb->Fcb->PipeName, Status);
441 ExAcquireFastMutex(&Ccb->DataListLock);
442 }
443 else
444 {
445 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
446
447 Context->WaitEvent = &Ccb->ReadEvent;
448 Status = NpfsAddWaitingReadWriteRequest(DeviceObject, Irp);
449
450 if (NT_SUCCESS(Status))
451 {
452 Status = STATUS_PENDING;
453 }
454 ExAcquireFastMutex(&Ccb->DataListLock);
455 break;
456 }
457 }
458 ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
459 if (Ccb->Fcb->ReadMode == FILE_PIPE_BYTE_STREAM_MODE)
460 {
461 DPRINT("Byte stream mode\n");
462 /* Byte stream mode */
463 while (Length > 0 && Ccb->ReadDataAvailable > 0)
464 {
465 CopyLength = min(Ccb->ReadDataAvailable, Length);
466 if ((ULONG_PTR)Ccb->ReadPtr + CopyLength <= (ULONG_PTR)Ccb->Data + Ccb->MaxDataLength)
467 {
468 memcpy(Buffer, Ccb->ReadPtr, CopyLength);
469 Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->ReadPtr + CopyLength);
470 if (Ccb->ReadPtr == (PVOID)((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength))
471 {
472 Ccb->ReadPtr = Ccb->Data;
473 }
474 }
475 else
476 {
477 TempLength = (ULONG)((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength - (ULONG_PTR)Ccb->ReadPtr);
478 memcpy(Buffer, Ccb->ReadPtr, TempLength);
479 memcpy((PVOID)((ULONG_PTR)Buffer + TempLength), Ccb->Data, CopyLength - TempLength);
480 Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->Data + CopyLength - TempLength);
481 }
482
483 Buffer = (PVOID)((ULONG_PTR)Buffer + CopyLength);
484 Length -= CopyLength;
485 Information += CopyLength;
486
487 Ccb->ReadDataAvailable -= CopyLength;
488 Ccb->WriteQuotaAvailable += CopyLength;
489 }
490
491 if (Length == 0)
492 {
493 if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
494 {
495 KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
496 }
497 KeResetEvent(&Ccb->ReadEvent);
498 break;
499 }
500 }
501 else
502 {
503 DPRINT("Message mode\n");
504
505 /* Message mode */
506 if (Ccb->ReadDataAvailable)
507 {
508 /* Truncate the message if the receive buffer is too small */
509 CopyLength = min(Ccb->ReadDataAvailable, Length);
510 memcpy(Buffer, Ccb->Data, CopyLength);
511
512 #ifndef NDEBUG
513 DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
514 HexDump((PUCHAR)Buffer, CopyLength);
515 #endif
516
517 Information = CopyLength;
518
519 if (Ccb->ReadDataAvailable > Length)
520 {
521 memmove(Ccb->Data, (PVOID)((ULONG_PTR)Ccb->Data + Length),
522 Ccb->ReadDataAvailable - Length);
523 Ccb->ReadDataAvailable -= Length;
524 Status = STATUS_MORE_ENTRIES;
525 }
526 else
527 {
528 KeResetEvent(&Ccb->ReadEvent);
529 if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
530 {
531 KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
532 }
533 Ccb->ReadDataAvailable = 0;
534 Ccb->WriteQuotaAvailable = Ccb->MaxDataLength;
535 }
536 }
537
538 if (Information > 0)
539 {
540 break;
541 }
542 }
543 }
544 Irp->IoStatus.Information = Information;
545 Irp->IoStatus.Status = Status;
546
547 ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
548
549 if (IoIsOperationSynchronous(Irp))
550 {
551 RemoveEntryList(&Context->ListEntry);
552 if (!IsListEmpty(&Ccb->ReadRequestListHead))
553 {
554 Context = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
555 KeSetEvent(Context->WaitEvent, IO_NO_INCREMENT, FALSE);
556 }
557 ExReleaseFastMutex(&Ccb->DataListLock);
558 IoCompleteRequest(Irp, IO_NO_INCREMENT);
559
560 DPRINT("NpfsRead done (Status %lx)\n", Status);
561 return Status;
562 }
563 else
564 {
565 if (IsOriginalRequest)
566 {
567 IsOriginalRequest = FALSE;
568 OriginalStatus = Status;
569 }
570 if (Status == STATUS_PENDING)
571 {
572 ExReleaseFastMutex(&Ccb->DataListLock);
573 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
574 return OriginalStatus;
575 }
576 RemoveEntryList(&Context->ListEntry);
577 IoCompleteRequest(Irp, IO_NO_INCREMENT);
578 if (IsListEmpty(&Ccb->ReadRequestListHead))
579 {
580 ExReleaseFastMutex(&Ccb->DataListLock);
581 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
582 return OriginalStatus;
583 }
584 Context = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
585 Irp = CONTAINING_RECORD(Context, IRP, Tail.Overlay.DriverContext);
586 }
587 }
588
589 done:
590 Irp->IoStatus.Status = Status;
591
592 if (Status != STATUS_PENDING)
593 {
594 IoCompleteRequest(Irp, IO_NO_INCREMENT);
595 }
596 DPRINT("NpfsRead done (Status %lx)\n", Status);
597
598 return Status;
599 }
600
601 NTSTATUS STDCALL
602 NpfsWrite(PDEVICE_OBJECT DeviceObject,
603 PIRP Irp)
604 {
605 PIO_STACK_LOCATION IoStack;
606 PFILE_OBJECT FileObject;
607 PNPFS_FCB Fcb = NULL;
608 PNPFS_CCB Ccb = NULL;
609 PNPFS_CCB ReaderCcb;
610 PUCHAR Buffer;
611 NTSTATUS Status = STATUS_SUCCESS;
612 ULONG Length;
613 ULONG Offset;
614 ULONG Information;
615 ULONG CopyLength;
616 ULONG TempLength;
617
618 DPRINT("NpfsWrite()\n");
619
620 IoStack = IoGetCurrentIrpStackLocation(Irp);
621 FileObject = IoStack->FileObject;
622 DPRINT("FileObject %p\n", FileObject);
623 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
624
625 Ccb = FileObject->FsContext2;
626 ReaderCcb = Ccb->OtherSide;
627 Fcb = Ccb->Fcb;
628
629 Length = IoStack->Parameters.Write.Length;
630 Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
631 Information = 0;
632
633 if (Irp->MdlAddress == NULL)
634 {
635 DPRINT("Irp->MdlAddress == NULL\n");
636 Status = STATUS_UNSUCCESSFUL;
637 Length = 0;
638 goto done;
639 }
640
641 if (ReaderCcb == NULL)
642 {
643 DPRINT("Pipe is NOT connected!\n");
644 if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
645 Status = STATUS_PIPE_LISTENING;
646 else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
647 Status = STATUS_PIPE_DISCONNECTED;
648 else
649 Status = STATUS_UNSUCCESSFUL;
650 Length = 0;
651 goto done;
652 }
653
654 if (ReaderCcb->Data == NULL)
655 {
656 DPRINT("Pipe is NOT writable!\n");
657 Status = STATUS_UNSUCCESSFUL;
658 Length = 0;
659 goto done;
660 }
661
662 Status = STATUS_SUCCESS;
663 Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
664
665 ExAcquireFastMutex(&ReaderCcb->DataListLock);
666 #ifndef NDEBUG
667 DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
668 HexDump(Buffer, Length);
669 #endif
670
671 while(1)
672 {
673 if (ReaderCcb->WriteQuotaAvailable == 0)
674 {
675 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
676 if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
677 {
678 Status = STATUS_PIPE_BROKEN;
679 ExReleaseFastMutex(&ReaderCcb->DataListLock);
680 goto done;
681 }
682 ExReleaseFastMutex(&ReaderCcb->DataListLock);
683
684 DPRINT("Waiting for buffer space (%S)\n", Fcb->PipeName.Buffer);
685 Status = KeWaitForSingleObject(&Ccb->WriteEvent,
686 UserRequest,
687 KernelMode,
688 FALSE,
689 NULL);
690 DPRINT("Finished waiting (%S)! Status: %x\n", Fcb->PipeName.Buffer, Status);
691
692 /*
693 * It's possible that the event was signaled because the
694 * other side of pipe was closed.
695 */
696 if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
697 {
698 DPRINT("PipeState: %x\n", Ccb->PipeState);
699 Status = STATUS_PIPE_BROKEN;
700 // ExReleaseFastMutex(&ReaderCcb->DataListLock);
701 goto done;
702 }
703
704 ExAcquireFastMutex(&ReaderCcb->DataListLock);
705 }
706
707 if (Fcb->WriteMode == FILE_PIPE_BYTE_STREAM_MODE)
708 {
709 DPRINT("Byte stream mode\n");
710 while (Length > 0 && ReaderCcb->WriteQuotaAvailable > 0)
711 {
712 CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable);
713 if ((ULONG_PTR)ReaderCcb->WritePtr + CopyLength <= (ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength)
714 {
715 memcpy(ReaderCcb->WritePtr, Buffer, CopyLength);
716 ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->WritePtr + CopyLength);
717 if ((ULONG_PTR)ReaderCcb->WritePtr == (ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength)
718 {
719 ReaderCcb->WritePtr = ReaderCcb->Data;
720 }
721 }
722 else
723 {
724 TempLength = (ULONG)((ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength - (ULONG_PTR)ReaderCcb->WritePtr);
725 memcpy(ReaderCcb->WritePtr, Buffer, TempLength);
726 memcpy(ReaderCcb->Data, Buffer + TempLength, CopyLength - TempLength);
727 ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->Data + CopyLength - TempLength);
728 }
729
730 Buffer += CopyLength;
731 Length -= CopyLength;
732 Information += CopyLength;
733
734 ReaderCcb->ReadDataAvailable += CopyLength;
735 ReaderCcb->WriteQuotaAvailable -= CopyLength;
736 }
737
738 if (Length == 0)
739 {
740 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
741 KeResetEvent(&Ccb->WriteEvent);
742 break;
743 }
744 }
745 else
746 {
747 DPRINT("Message mode\n");
748 if (Length > 0)
749 {
750 CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable);
751 memcpy(ReaderCcb->Data, Buffer, CopyLength);
752
753 Information = CopyLength;
754 ReaderCcb->ReadDataAvailable = CopyLength;
755 ReaderCcb->WriteQuotaAvailable = 0;
756 }
757
758 if (Information > 0)
759 {
760 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
761 KeResetEvent(&Ccb->WriteEvent);
762 break;
763 }
764 }
765 }
766
767 ExReleaseFastMutex(&ReaderCcb->DataListLock);
768
769 done:
770 Irp->IoStatus.Status = Status;
771 Irp->IoStatus.Information = Information;
772
773 IoCompleteRequest(Irp, IO_NO_INCREMENT);
774
775 DPRINT("NpfsWrite done (Status %lx)\n", Status);
776
777 return Status;
778 }
779
780 /* EOF */