Readd check that I accidently removed.
[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 < Length; 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 KeUnlockMutex(&ThreadContext->DeviceExt->PipeListLock);
188 break;
189 default:
190 KEBUGCHECK(0);
191 }
192 ExReleaseFastMutex(&Fcb->DataListLock);
193 }
194 }
195 else
196 {
197 /* someone has add a new wait request */
198 Irp = NULL;
199 }
200 if (ThreadContext->Count == 1 && ThreadContext->DeviceExt->EmptyWaiterCount >= MAXIMUM_WAIT_OBJECTS)
201 {
202 /* it exist an other thread with empty wait slots, we can remove our thread from the list */
203 RemoveEntryList(&ThreadContext->ListEntry);
204 ThreadContext->DeviceExt->EmptyWaiterCount -= MAXIMUM_WAIT_OBJECTS - 1;
205 Terminate = TRUE;
206 }
207 }
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 = (PVOID)((ULONG_PTR)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 DPRINT("PipeState: %x\n", Fcb->PipeState);
404 if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
405 Status = STATUS_PIPE_LISTENING;
406 else
407 Status = STATUS_PIPE_DISCONNECTED;
408 break;
409 }
410
411 ASSERT(Fcb->OtherSide != NULL);
412 KeSetEvent(&Fcb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
413
414 if (Information > 0 &&
415 Fcb->Pipe->ReadMode != FILE_PIPE_BYTE_STREAM_MODE)
416 {
417 break;
418 }
419
420 ExReleaseFastMutex(&Fcb->DataListLock);
421 if (IoIsOperationSynchronous(Irp))
422 {
423 /* Wait for ReadEvent to become signaled */
424
425 DPRINT("Waiting for readable data (%wZ)\n", &Fcb->Pipe->PipeName);
426 Status = KeWaitForSingleObject(&Fcb->ReadEvent,
427 UserRequest,
428 KernelMode,
429 FALSE,
430 NULL);
431 DPRINT("Finished waiting (%wZ)! Status: %x\n", &Fcb->Pipe->PipeName, Status);
432 ExAcquireFastMutex(&Fcb->DataListLock);
433 }
434 else
435 {
436 PNPFS_CONTEXT Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
437
438 Context->WaitEvent = &Fcb->ReadEvent;
439 Status = NpfsAddWaitingReadWriteRequest(DeviceObject, Irp);
440
441 if (NT_SUCCESS(Status))
442 {
443 Status = STATUS_PENDING;
444 }
445 ExAcquireFastMutex(&Fcb->DataListLock);
446 break;
447 }
448 }
449 if (Fcb->Pipe->ReadMode == FILE_PIPE_BYTE_STREAM_MODE)
450 {
451 DPRINT("Byte stream mode\n");
452 /* Byte stream mode */
453 while (Length > 0 && Fcb->ReadDataAvailable > 0)
454 {
455 CopyLength = min(Fcb->ReadDataAvailable, Length);
456 if ((ULONG_PTR)Fcb->ReadPtr + CopyLength <= (ULONG_PTR)Fcb->Data + Fcb->MaxDataLength)
457 {
458 memcpy(Buffer, Fcb->ReadPtr, CopyLength);
459 Fcb->ReadPtr = (PVOID)((ULONG_PTR)Fcb->ReadPtr + CopyLength);
460 if (Fcb->ReadPtr == (PVOID)((ULONG_PTR)Fcb->Data + Fcb->MaxDataLength))
461 {
462 Fcb->ReadPtr = Fcb->Data;
463 }
464 }
465 else
466 {
467 TempLength = (ULONG)((ULONG_PTR)Fcb->Data + Fcb->MaxDataLength - (ULONG_PTR)Fcb->ReadPtr);
468 memcpy(Buffer, Fcb->ReadPtr, TempLength);
469 memcpy((PVOID)((ULONG_PTR)Buffer + TempLength), Fcb->Data, CopyLength - TempLength);
470 Fcb->ReadPtr = (PVOID)((ULONG_PTR)Fcb->Data + CopyLength - TempLength);
471 }
472
473 Buffer = (PVOID)((ULONG_PTR)Buffer + CopyLength);
474 Length -= CopyLength;
475 Information += CopyLength;
476
477 Fcb->ReadDataAvailable -= CopyLength;
478 Fcb->WriteQuotaAvailable += CopyLength;
479 }
480
481 if (Length == 0)
482 {
483 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
484 {
485 KeSetEvent(&Fcb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
486 }
487 KeResetEvent(&Fcb->ReadEvent);
488 break;
489 }
490 }
491 else
492 {
493 DPRINT("Message mode\n");
494
495 /* Message mode */
496 if (Fcb->ReadDataAvailable)
497 {
498 /* Truncate the message if the receive buffer is too small */
499 CopyLength = min(Fcb->ReadDataAvailable, Length);
500 memcpy(Buffer, Fcb->Data, CopyLength);
501
502 #ifndef NDEBUG
503 DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
504 HexDump((PUCHAR)Buffer, CopyLength);
505 #endif
506
507 Information = CopyLength;
508
509 if (Fcb->ReadDataAvailable > Length)
510 {
511 memmove(Fcb->Data, (PVOID)((ULONG_PTR)Fcb->Data + Length),
512 Fcb->ReadDataAvailable - Length);
513 Fcb->ReadDataAvailable -= Length;
514 Status = STATUS_MORE_ENTRIES;
515 }
516 else
517 {
518 KeResetEvent(&Fcb->ReadEvent);
519 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
520 {
521 KeSetEvent(&Fcb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
522 }
523 Fcb->ReadDataAvailable = 0;
524 Fcb->WriteQuotaAvailable = Fcb->MaxDataLength;
525 }
526 }
527
528 if (Information > 0)
529 {
530 break;
531 }
532 }
533 }
534 Irp->IoStatus.Information = Information;
535 Irp->IoStatus.Status = Status;
536
537 if (IoIsOperationSynchronous(Irp))
538 {
539 RemoveEntryList(&Context->ListEntry);
540 if (!IsListEmpty(&Fcb->ReadRequestListHead))
541 {
542 Context = CONTAINING_RECORD(Fcb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
543 KeSetEvent(Context->WaitEvent, IO_NO_INCREMENT, FALSE);
544 }
545 ExReleaseFastMutex(&Fcb->DataListLock);
546 IoCompleteRequest(Irp, IO_NO_INCREMENT);
547
548 DPRINT("NpfsRead done (Status %lx)\n", Status);
549 return Status;
550 }
551 else
552 {
553 if (IsOriginalRequest)
554 {
555 IsOriginalRequest = FALSE;
556 OriginalStatus = Status;
557 }
558 if (Status == STATUS_PENDING)
559 {
560 ExReleaseFastMutex(&Fcb->DataListLock);
561 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
562 return OriginalStatus;
563 }
564 RemoveEntryList(&Context->ListEntry);
565 IoCompleteRequest(Irp, IO_NO_INCREMENT);
566 if (IsListEmpty(&Fcb->ReadRequestListHead))
567 {
568 ExReleaseFastMutex(&Fcb->DataListLock);
569 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus);
570 return OriginalStatus;
571 }
572 Context = CONTAINING_RECORD(Fcb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
573 Irp = CONTAINING_RECORD(Context, IRP, Tail.Overlay.DriverContext);
574 }
575 }
576
577 done:
578 Irp->IoStatus.Status = Status;
579
580 if (Status != STATUS_PENDING)
581 {
582 IoCompleteRequest(Irp, IO_NO_INCREMENT);
583 }
584 DPRINT("NpfsRead done (Status %lx)\n", Status);
585
586 return Status;
587 }
588
589 NTSTATUS STDCALL
590 NpfsWrite(PDEVICE_OBJECT DeviceObject,
591 PIRP Irp)
592 {
593 PIO_STACK_LOCATION IoStack;
594 PFILE_OBJECT FileObject;
595 PNPFS_FCB Fcb = NULL;
596 PNPFS_FCB ReaderFcb;
597 PNPFS_PIPE Pipe = NULL;
598 PUCHAR Buffer;
599 NTSTATUS Status = STATUS_SUCCESS;
600 ULONG Length;
601 ULONG Offset;
602 ULONG Information;
603 ULONG CopyLength;
604 ULONG TempLength;
605
606 DPRINT("NpfsWrite()\n");
607
608 IoStack = IoGetCurrentIrpStackLocation(Irp);
609 FileObject = IoStack->FileObject;
610 DPRINT("FileObject %p\n", FileObject);
611 DPRINT("Pipe name %wZ\n", &FileObject->FileName);
612
613 Fcb = FileObject->FsContext;
614 ReaderFcb = Fcb->OtherSide;
615 Pipe = Fcb->Pipe;
616
617 Length = IoStack->Parameters.Write.Length;
618 Offset = IoStack->Parameters.Write.ByteOffset.u.LowPart;
619 Information = 0;
620
621 if (Irp->MdlAddress == NULL)
622 {
623 DPRINT("Irp->MdlAddress == NULL\n");
624 Status = STATUS_UNSUCCESSFUL;
625 Length = 0;
626 goto done;
627 }
628
629 if (ReaderFcb == NULL)
630 {
631 DPRINT("Pipe is NOT connected!\n");
632 if (Fcb->PipeState == FILE_PIPE_LISTENING_STATE)
633 Status = STATUS_PIPE_LISTENING;
634 else if (Fcb->PipeState == FILE_PIPE_DISCONNECTED_STATE)
635 Status = STATUS_PIPE_DISCONNECTED;
636 else
637 Status = STATUS_UNSUCCESSFUL;
638 Length = 0;
639 goto done;
640 }
641
642 if (ReaderFcb->Data == NULL)
643 {
644 DPRINT("Pipe is NOT writable!\n");
645 Status = STATUS_UNSUCCESSFUL;
646 Length = 0;
647 goto done;
648 }
649
650 Status = STATUS_SUCCESS;
651 Buffer = MmGetSystemAddressForMdl (Irp->MdlAddress);
652
653 ExAcquireFastMutex(&ReaderFcb->DataListLock);
654 #ifndef NDEBUG
655 DPRINT("Length %d Buffer %x Offset %x\n",Length,Buffer,Offset);
656 HexDump(Buffer, Length);
657 #endif
658
659 while(1)
660 {
661 if (ReaderFcb->WriteQuotaAvailable == 0)
662 {
663 KeSetEvent(&ReaderFcb->ReadEvent, IO_NO_INCREMENT, FALSE);
664 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
665 {
666 Status = STATUS_PIPE_BROKEN;
667 ExReleaseFastMutex(&ReaderFcb->DataListLock);
668 goto done;
669 }
670 ExReleaseFastMutex(&ReaderFcb->DataListLock);
671
672 DPRINT("Waiting for buffer space (%S)\n", Pipe->PipeName.Buffer);
673 Status = KeWaitForSingleObject(&Fcb->WriteEvent,
674 UserRequest,
675 KernelMode,
676 FALSE,
677 NULL);
678 DPRINT("Finished waiting (%S)! Status: %x\n", Pipe->PipeName.Buffer, Status);
679
680 ExAcquireFastMutex(&ReaderFcb->DataListLock);
681 /*
682 * It's possible that the event was signaled because the
683 * other side of pipe was closed.
684 */
685 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
686 {
687 DPRINT("PipeState: %x\n", Fcb->PipeState);
688 Status = STATUS_PIPE_BROKEN;
689 ExReleaseFastMutex(&ReaderFcb->DataListLock);
690 goto done;
691 }
692 }
693
694 if (Pipe->WriteMode == FILE_PIPE_BYTE_STREAM_MODE)
695 {
696 DPRINT("Byte stream mode\n");
697 while (Length > 0 && ReaderFcb->WriteQuotaAvailable > 0)
698 {
699 CopyLength = min(Length, ReaderFcb->WriteQuotaAvailable);
700 if ((ULONG_PTR)ReaderFcb->WritePtr + CopyLength <= (ULONG_PTR)ReaderFcb->Data + ReaderFcb->MaxDataLength)
701 {
702 memcpy(ReaderFcb->WritePtr, Buffer, CopyLength);
703 ReaderFcb->WritePtr = (PVOID)((ULONG_PTR)ReaderFcb->WritePtr + CopyLength);
704 if ((ULONG_PTR)ReaderFcb->WritePtr == (ULONG_PTR)ReaderFcb->Data + ReaderFcb->MaxDataLength)
705 {
706 ReaderFcb->WritePtr = ReaderFcb->Data;
707 }
708 }
709 else
710 {
711 TempLength = (ULONG)((ULONG_PTR)ReaderFcb->Data + ReaderFcb->MaxDataLength - (ULONG_PTR)ReaderFcb->WritePtr);
712 memcpy(ReaderFcb->WritePtr, Buffer, TempLength);
713 memcpy(ReaderFcb->Data, Buffer + TempLength, CopyLength - TempLength);
714 ReaderFcb->WritePtr = (PVOID)((ULONG_PTR)ReaderFcb->Data + CopyLength - TempLength);
715 }
716
717 Buffer += CopyLength;
718 Length -= CopyLength;
719 Information += CopyLength;
720
721 ReaderFcb->ReadDataAvailable += CopyLength;
722 ReaderFcb->WriteQuotaAvailable -= CopyLength;
723 }
724
725 if (Length == 0)
726 {
727 KeSetEvent(&ReaderFcb->ReadEvent, IO_NO_INCREMENT, FALSE);
728 KeResetEvent(&Fcb->WriteEvent);
729 break;
730 }
731 }
732 else
733 {
734 DPRINT("Message mode\n");
735 if (Length > 0)
736 {
737 CopyLength = min(Length, ReaderFcb->WriteQuotaAvailable);
738 memcpy(ReaderFcb->Data, Buffer, CopyLength);
739
740 Information = CopyLength;
741 ReaderFcb->ReadDataAvailable = CopyLength;
742 ReaderFcb->WriteQuotaAvailable = 0;
743 }
744
745 if (Information > 0)
746 {
747 KeSetEvent(&ReaderFcb->ReadEvent, IO_NO_INCREMENT, FALSE);
748 KeResetEvent(&Fcb->WriteEvent);
749 break;
750 }
751 }
752 }
753
754 ExReleaseFastMutex(&ReaderFcb->DataListLock);
755
756 done:
757 Irp->IoStatus.Status = Status;
758 Irp->IoStatus.Information = Information;
759
760 IoCompleteRequest(Irp, IO_NO_INCREMENT);
761
762 DPRINT("NpfsWrite done (Status %lx)\n", Status);
763
764 return Status;
765 }
766
767 /* EOF */