include npfs.h before debug.h - this fixes compilation with MSVC
[reactos.git] / reactos / 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 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_CCB Ccb;
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 Ccb = IoStack->FileObject->FsContext2;
64
65 KeLockMutex(&DeviceExt->PipeListLock);
66 ExAcquireFastMutex(&Ccb->DataListLock);
67 switch(IoStack->MajorFunction)
68 {
69 case IRP_MJ_READ:
70 if (Ccb->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(&Ccb->ReadEvent, IO_NO_INCREMENT, FALSE);
79 }
80 break;
81 default:
82 KEBUGCHECK(0);
83 }
84 ExReleaseFastMutex(&Ccb->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_CCB Ccb;
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 Ccb = IoStack->FileObject->FsContext2;
170 ExAcquireFastMutex(&Ccb->DataListLock);
171 RemoveEntryList(&Context->ListEntry);
172 switch (IoStack->MajorFunction)
173 {
174 case IRP_MJ_READ:
175 if (!IsListEmpty(&Ccb->ReadRequestListHead))
176 {
177 /* put the next request on the wait list */
178 NextContext = CONTAINING_RECORD(Ccb->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 break;
186 default:
187 KEBUGCHECK(0);
188 }
189 ExReleaseFastMutex(&Ccb->DataListLock);
190 }
191 }
192 else
193 {
194 /* someone has add a new wait request */
195 Irp = NULL;
196 }
197 if (ThreadContext->Count == 1 && ThreadContext->DeviceExt->EmptyWaiterCount >= MAXIMUM_WAIT_OBJECTS)
198 {
199 /* it exist an other thread with empty wait slots, we can remove our thread from the list */
200 RemoveEntryList(&ThreadContext->ListEntry);
201 ThreadContext->DeviceExt->EmptyWaiterCount -= MAXIMUM_WAIT_OBJECTS - 1;
202 Terminate = TRUE;
203 }
204 }
205 ExFreePool(ThreadContext);
206 }
207
208 static NTSTATUS
209 NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject,
210 IN PIRP Irp)
211 {
212 PLIST_ENTRY ListEntry;
213 PNPFS_THREAD_CONTEXT ThreadContext = NULL;
214 NTSTATUS Status;
215 HANDLE hThread;
216 KIRQL oldIrql;
217
218 PNPFS_CONTEXT Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
219 PNPFS_DEVICE_EXTENSION DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
220
221 DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
222
223 KeLockMutex(&DeviceExt->PipeListLock);
224
225 ListEntry = DeviceExt->ThreadListHead.Flink;
226 while (ListEntry != &DeviceExt->ThreadListHead)
227 {
228 ThreadContext = CONTAINING_RECORD(ListEntry, NPFS_THREAD_CONTEXT, ListEntry);
229 if (ThreadContext->Count < MAXIMUM_WAIT_OBJECTS)
230 {
231 break;
232 }
233 ListEntry = ListEntry->Flink;
234 }
235 if (ListEntry == &DeviceExt->ThreadListHead)
236 {
237 ThreadContext = ExAllocatePool(NonPagedPool, sizeof(NPFS_THREAD_CONTEXT));
238 if (ThreadContext == NULL)
239 {
240 KeUnlockMutex(&DeviceExt->PipeListLock);
241 return STATUS_NO_MEMORY;
242 }
243 ThreadContext->DeviceExt = DeviceExt;
244 KeInitializeEvent(&ThreadContext->Event, SynchronizationEvent, FALSE);
245 ThreadContext->Count = 1;
246 ThreadContext->WaitObjectArray[0] = &ThreadContext->Event;
247
248
249 DPRINT("Creating a new system thread for waiting read/write requests\n");
250
251 Status = PsCreateSystemThread(&hThread,
252 THREAD_ALL_ACCESS,
253 NULL,
254 NULL,
255 NULL,
256 NpfsWaiterThread,
257 (PVOID)ThreadContext);
258 if (!NT_SUCCESS(Status))
259 {
260 ExFreePool(ThreadContext);
261 KeUnlockMutex(&DeviceExt->PipeListLock);
262 return Status;
263 }
264 InsertHeadList(&DeviceExt->ThreadListHead, &ThreadContext->ListEntry);
265 DeviceExt->EmptyWaiterCount += MAXIMUM_WAIT_OBJECTS - 1;
266 }
267 IoMarkIrpPending(Irp);
268
269 IoAcquireCancelSpinLock(&oldIrql);
270 if (Irp->Cancel)
271 {
272 IoReleaseCancelSpinLock(oldIrql);
273 Status = STATUS_CANCELLED;
274 }
275 else
276 {
277 (void)IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
278 IoReleaseCancelSpinLock(oldIrql);
279 ThreadContext->WaitObjectArray[ThreadContext->Count] = Context->WaitEvent;
280 ThreadContext->WaitIrpArray[ThreadContext->Count] = Irp;
281 ThreadContext->Count++;
282 DeviceExt->EmptyWaiterCount--;
283 KeSetEvent(&ThreadContext->Event, IO_NO_INCREMENT, FALSE);
284 Status = STATUS_SUCCESS;
285 }
286 KeUnlockMutex(&DeviceExt->PipeListLock);
287 return Status;
288 }
289
290 NTSTATUS STDCALL
291 NpfsRead(IN PDEVICE_OBJECT DeviceObject,
292 IN PIRP Irp)
293 {
294 PFILE_OBJECT FileObject;
295 NTSTATUS Status;
296 NTSTATUS OriginalStatus = STATUS_SUCCESS;
297 PNPFS_CCB Ccb;
298 PNPFS_CONTEXT Context;
299 KEVENT Event;
300 ULONG Length;
301 ULONG Information = 0;
302 ULONG CopyLength;
303 ULONG TempLength;
304 BOOLEAN IsOriginalRequest = TRUE;
305 PVOID Buffer;
306
307 DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
308
309 if (Irp->MdlAddress == NULL)
310 {
311 DPRINT("Irp->MdlAddress == NULL\n");
312 Status = STATUS_UNSUCCESSFUL;
313 Irp->IoStatus.Information = 0;
314 goto done;
315 }
316
317 FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
318 Ccb = FileObject->FsContext2;
319 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
320
321 if (Ccb->OtherSide == NULL)
322 {
323 DPRINT("Pipe is NOT connected!\n");
324 if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
325 Status = STATUS_PIPE_LISTENING;
326 else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
327 Status = STATUS_PIPE_DISCONNECTED;
328 else
329 Status = STATUS_UNSUCCESSFUL;
330 Irp->IoStatus.Information = 0;
331 goto done;
332 }
333
334 if (Ccb->Data == NULL)
335 {
336 DPRINT1("Pipe is NOT readable!\n");
337 Status = STATUS_UNSUCCESSFUL;
338 Irp->IoStatus.Information = 0;
339 goto done;
340 }
341
342 ExAcquireFastMutex(&Ccb->DataListLock);
343
344 if (IoIsOperationSynchronous(Irp))
345 {
346 InsertTailList(&Ccb->ReadRequestListHead, &Context->ListEntry);
347 if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
348 {
349 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
350 Context->WaitEvent = &Event;
351 ExReleaseFastMutex(&Ccb->DataListLock);
352 Status = KeWaitForSingleObject(&Event,
353 Executive,
354 KernelMode,
355 FALSE,
356 NULL);
357 if (!NT_SUCCESS(Status))
358 {
359 KEBUGCHECK(0);
360 }
361 ExAcquireFastMutex(&Ccb->DataListLock);
362 }
363 Irp->IoStatus.Information = 0;
364 }
365 else
366 {
367 KIRQL oldIrql;
368 if (IsListEmpty(&Ccb->ReadRequestListHead) ||
369 Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
370 {
371 /* this is a new request */
372 Irp->IoStatus.Information = 0;
373 Context->WaitEvent = &Ccb->ReadEvent;
374 InsertTailList(&Ccb->ReadRequestListHead, &Context->ListEntry);
375 if (Ccb->ReadRequestListHead.Flink != &Context->ListEntry)
376 {
377 /* there was already a request on the list */
378 IoAcquireCancelSpinLock(&oldIrql);
379 if (Irp->Cancel)
380 {
381 IoReleaseCancelSpinLock(oldIrql);
382 RemoveEntryList(&Context->ListEntry);
383 ExReleaseFastMutex(&Ccb->DataListLock);
384 Status = STATUS_CANCELLED;
385 goto done;
386 }
387 (void)IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
388 IoReleaseCancelSpinLock(oldIrql);
389 ExReleaseFastMutex(&Ccb->DataListLock);
390 IoMarkIrpPending(Irp);
391 Status = STATUS_PENDING;
392 goto done;
393 }
394 }
395 }
396
397 while (1)
398 {
399 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
400 Information = Irp->IoStatus.Information;
401 Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length;
402 ASSERT (Information <= Length);
403 Buffer = (PVOID)((ULONG_PTR)Buffer + Information);
404 Length -= Information;
405 Status = STATUS_SUCCESS;
406
407 while (1)
408 {
409 if (Ccb->ReadDataAvailable == 0)
410 {
411 if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
412 {
413 ASSERT(Ccb->OtherSide != NULL);
414 KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
415 }
416 if (Information > 0 &&
417 (Ccb->Fcb->ReadMode != FILE_PIPE_BYTE_STREAM_MODE ||
418 Ccb->PipeState != FILE_PIPE_CONNECTED_STATE))
419 {
420 break;
421 }
422 if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
423 {
424 DPRINT("PipeState: %x\n", Ccb->PipeState);
425 Status = STATUS_PIPE_BROKEN;
426 break;
427 }
428 ExReleaseFastMutex(&Ccb->DataListLock);
429 if (IoIsOperationSynchronous(Irp))
430 {
431 /* Wait for ReadEvent to become signaled */
432
433 DPRINT("Waiting for readable data (%wZ)\n", &Ccb->Fcb->PipeName);
434 Status = KeWaitForSingleObject(&Ccb->ReadEvent,
435 UserRequest,
436 KernelMode,
437 FALSE,
438 NULL);
439 DPRINT("Finished waiting (%wZ)! Status: %x\n", &Ccb->Fcb->PipeName, Status);
440 ExAcquireFastMutex(&Ccb->DataListLock);
441 }
442 else
443 {
444 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
445
446 Context->WaitEvent = &Ccb->ReadEvent;
447 Status = NpfsAddWaitingReadWriteRequest(DeviceObject, Irp);
448
449 if (NT_SUCCESS(Status))
450 {
451 Status = STATUS_PENDING;
452 }
453 ExAcquireFastMutex(&Ccb->DataListLock);
454 break;
455 }
456 }
457 ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
458 if (Ccb->Fcb->ReadMode == FILE_PIPE_BYTE_STREAM_MODE)
459 {
460 DPRINT("Byte stream mode\n");
461 /* Byte stream mode */
462 while (Length > 0 && Ccb->ReadDataAvailable > 0)
463 {
464 CopyLength = min(Ccb->ReadDataAvailable, Length);
465 if ((ULONG_PTR)Ccb->ReadPtr + CopyLength <= (ULONG_PTR)Ccb->Data + Ccb->MaxDataLength)
466 {
467 memcpy(Buffer, Ccb->ReadPtr, CopyLength);
468 Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->ReadPtr + CopyLength);
469 if (Ccb->ReadPtr == (PVOID)((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength))
470 {
471 Ccb->ReadPtr = Ccb->Data;
472 }
473 }
474 else
475 {
476 TempLength = (ULONG)((ULONG_PTR)Ccb->Data + Ccb->MaxDataLength - (ULONG_PTR)Ccb->ReadPtr);
477 memcpy(Buffer, Ccb->ReadPtr, TempLength);
478 memcpy((PVOID)((ULONG_PTR)Buffer + TempLength), Ccb->Data, CopyLength - TempLength);
479 Ccb->ReadPtr = (PVOID)((ULONG_PTR)Ccb->Data + CopyLength - TempLength);
480 }
481
482 Buffer = (PVOID)((ULONG_PTR)Buffer + CopyLength);
483 Length -= CopyLength;
484 Information += CopyLength;
485
486 Ccb->ReadDataAvailable -= CopyLength;
487 Ccb->WriteQuotaAvailable += CopyLength;
488 }
489
490 if (Length == 0)
491 {
492 if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
493 {
494 KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
495 }
496 KeResetEvent(&Ccb->ReadEvent);
497 break;
498 }
499 }
500 else
501 {
502 DPRINT("Message mode\n");
503
504 /* Message mode */
505 if (Ccb->ReadDataAvailable)
506 {
507 /* Truncate the message if the receive buffer is too small */
508 CopyLength = min(Ccb->ReadDataAvailable, Length);
509 memcpy(Buffer, Ccb->Data, CopyLength);
510
511 #ifndef NDEBUG
512 DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
513 HexDump((PUCHAR)Buffer, CopyLength);
514 #endif
515
516 Information = CopyLength;
517
518 if (Ccb->ReadDataAvailable > Length)
519 {
520 memmove(Ccb->Data, (PVOID)((ULONG_PTR)Ccb->Data + Length),
521 Ccb->ReadDataAvailable - Length);
522 Ccb->ReadDataAvailable -= Length;
523 Status = STATUS_MORE_ENTRIES;
524 }
525 else
526 {
527 KeResetEvent(&Ccb->ReadEvent);
528 if (Ccb->PipeState == FILE_PIPE_CONNECTED_STATE)
529 {
530 KeSetEvent(&Ccb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
531 }
532 Ccb->ReadDataAvailable = 0;
533 Ccb->WriteQuotaAvailable = Ccb->MaxDataLength;
534 }
535 }
536
537 if (Information > 0)
538 {
539 break;
540 }
541 }
542 }
543 Irp->IoStatus.Information = Information;
544 Irp->IoStatus.Status = Status;
545
546 ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
547
548 if (IoIsOperationSynchronous(Irp))
549 {
550 RemoveEntryList(&Context->ListEntry);
551 if (!IsListEmpty(&Ccb->ReadRequestListHead))
552 {
553 Context = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
554 KeSetEvent(Context->WaitEvent, IO_NO_INCREMENT, FALSE);
555 }
556 ExReleaseFastMutex(&Ccb->DataListLock);
557 IoCompleteRequest(Irp, IO_NO_INCREMENT);
558
559 DPRINT("NpfsRead done (Status %lx)\n", Status);
560 return Status;
561 }
562 else
563 {
564 if (IsOriginalRequest)
565 {
566 IsOriginalRequest = FALSE;
567 OriginalStatus = Status;
568 }
569 if (Status == STATUS_PENDING)
570 {
571 ExReleaseFastMutex(&Ccb->DataListLock);
572 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
573 return OriginalStatus;
574 }
575 RemoveEntryList(&Context->ListEntry);
576 IoCompleteRequest(Irp, IO_NO_INCREMENT);
577 if (IsListEmpty(&Ccb->ReadRequestListHead))
578 {
579 ExReleaseFastMutex(&Ccb->DataListLock);
580 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
581 return OriginalStatus;
582 }
583 Context = CONTAINING_RECORD(Ccb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
584 Irp = CONTAINING_RECORD(Context, IRP, Tail.Overlay.DriverContext);
585 }
586 }
587
588 done:
589 Irp->IoStatus.Status = Status;
590
591 if (Status != STATUS_PENDING)
592 {
593 IoCompleteRequest(Irp, IO_NO_INCREMENT);
594 }
595 DPRINT("NpfsRead done (Status %lx)\n", Status);
596
597 return Status;
598 }
599
600 NTSTATUS STDCALL
601 NpfsWrite(PDEVICE_OBJECT DeviceObject,
602 PIRP Irp)
603 {
604 PIO_STACK_LOCATION IoStack;
605 PFILE_OBJECT FileObject;
606 PNPFS_FCB Fcb = NULL;
607 PNPFS_CCB Ccb = NULL;
608 PNPFS_CCB ReaderCcb;
609 PUCHAR Buffer;
610 NTSTATUS Status = STATUS_SUCCESS;
611 ULONG Length;
612 ULONG Offset;
613 ULONG Information;
614 ULONG CopyLength;
615 ULONG TempLength;
616
617 DPRINT("NpfsWrite()\n");
618
619 IoStack = IoGetCurrentIrpStackLocation(Irp);
620 FileObject = IoStack->FileObject;
621 DPRINT("FileObject %p\n", FileObject);
622 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
623
624 Ccb = FileObject->FsContext2;
625 ReaderCcb = Ccb->OtherSide;
626 Fcb = Ccb->Fcb;
627
628 Length = IoStack->Parameters.Write.Length;
629 Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
630 Information = 0;
631
632 if (Irp->MdlAddress == NULL)
633 {
634 DPRINT("Irp->MdlAddress == NULL\n");
635 Status = STATUS_UNSUCCESSFUL;
636 Length = 0;
637 goto done;
638 }
639
640 if (ReaderCcb == NULL)
641 {
642 DPRINT("Pipe is NOT connected!\n");
643 if (Ccb->PipeState == FILE_PIPE_LISTENING_STATE)
644 Status = STATUS_PIPE_LISTENING;
645 else if (Ccb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
646 Status = STATUS_PIPE_DISCONNECTED;
647 else
648 Status = STATUS_UNSUCCESSFUL;
649 Length = 0;
650 goto done;
651 }
652
653 if (ReaderCcb->Data == NULL)
654 {
655 DPRINT("Pipe is NOT writable!\n");
656 Status = STATUS_UNSUCCESSFUL;
657 Length = 0;
658 goto done;
659 }
660
661 Status = STATUS_SUCCESS;
662 Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
663
664 ExAcquireFastMutex(&ReaderCcb->DataListLock);
665 #ifndef NDEBUG
666 DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
667 HexDump(Buffer, Length);
668 #endif
669
670 while(1)
671 {
672 if (ReaderCcb->WriteQuotaAvailable == 0)
673 {
674 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
675 if (Ccb->PipeState != FILE_PIPE_CONNECTED_STATE)
676 {
677 Status = STATUS_PIPE_BROKEN;
678 ExReleaseFastMutex(&ReaderCcb->DataListLock);
679 goto done;
680 }
681 ExReleaseFastMutex(&ReaderCcb->DataListLock);
682
683 DPRINT("Waiting for buffer space (%S)\n", Fcb->PipeName.Buffer);
684 Status = KeWaitForSingleObject(&Ccb->WriteEvent,
685 UserRequest,
686 KernelMode,
687 FALSE,
688 NULL);
689 DPRINT("Finished waiting (%S)! Status: %x\n", Fcb->PipeName.Buffer, Status);
690
691 ExAcquireFastMutex(&ReaderCcb->DataListLock);
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
705 if (Fcb->WriteMode == FILE_PIPE_BYTE_STREAM_MODE)
706 {
707 DPRINT("Byte stream mode\n");
708 while (Length > 0 && ReaderCcb->WriteQuotaAvailable > 0)
709 {
710 CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable);
711 if ((ULONG_PTR)ReaderCcb->WritePtr + CopyLength <= (ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength)
712 {
713 memcpy(ReaderCcb->WritePtr, Buffer, CopyLength);
714 ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->WritePtr + CopyLength);
715 if ((ULONG_PTR)ReaderCcb->WritePtr == (ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength)
716 {
717 ReaderCcb->WritePtr = ReaderCcb->Data;
718 }
719 }
720 else
721 {
722 TempLength = (ULONG)((ULONG_PTR)ReaderCcb->Data + ReaderCcb->MaxDataLength - (ULONG_PTR)ReaderCcb->WritePtr);
723 memcpy(ReaderCcb->WritePtr, Buffer, TempLength);
724 memcpy(ReaderCcb->Data, Buffer + TempLength, CopyLength - TempLength);
725 ReaderCcb->WritePtr = (PVOID)((ULONG_PTR)ReaderCcb->Data + CopyLength - TempLength);
726 }
727
728 Buffer += CopyLength;
729 Length -= CopyLength;
730 Information += CopyLength;
731
732 ReaderCcb->ReadDataAvailable += CopyLength;
733 ReaderCcb->WriteQuotaAvailable -= CopyLength;
734 }
735
736 if (Length == 0)
737 {
738 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
739 KeResetEvent(&Ccb->WriteEvent);
740 break;
741 }
742 }
743 else
744 {
745 DPRINT("Message mode\n");
746 if (Length > 0)
747 {
748 CopyLength = min(Length, ReaderCcb->WriteQuotaAvailable);
749 memcpy(ReaderCcb->Data, Buffer, CopyLength);
750
751 Information = CopyLength;
752 ReaderCcb->ReadDataAvailable = CopyLength;
753 ReaderCcb->WriteQuotaAvailable = 0;
754 }
755
756 if (Information > 0)
757 {
758 KeSetEvent(&ReaderCcb->ReadEvent, IO_NO_INCREMENT, FALSE);
759 KeResetEvent(&Ccb->WriteEvent);
760 break;
761 }
762 }
763 }
764
765 ExReleaseFastMutex(&ReaderCcb->DataListLock);
766
767 done:
768 Irp->IoStatus.Status = Status;
769 Irp->IoStatus.Information = Information;
770
771 IoCompleteRequest(Irp, IO_NO_INCREMENT);
772
773 DPRINT("NpfsWrite done (Status %lx)\n", Status);
774
775 return Status;
776 }
777
778 /* EOF */