- Make ROS buildable with GCC 4.1
[reactos.git] / reactos / drivers / filesystems / 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 break;
186 default:
187 KEBUGCHECK(0);
188 }
189 ExReleaseFastMutex(&Fcb->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_FCB Fcb;
298 PNPFS_CONTEXT Context;
299 KEVENT Event;
300 ULONG Length;
301 ULONG Information;
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 Fcb = FileObject->FsContext;
319 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
320
321 if (Fcb->Data == NULL)
322 {
323 DPRINT1("Pipe is NOT readable!\n");
324 Status = STATUS_UNSUCCESSFUL;
325 Irp->IoStatus.Information = 0;
326 goto done;
327 }
328
329 ExAcquireFastMutex(&Fcb->DataListLock);
330
331 if (IoIsOperationSynchronous(Irp))
332 {
333 InsertTailList(&Fcb->ReadRequestListHead, &Context->ListEntry);
334 if (Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
335 {
336 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
337 Context->WaitEvent = &Event;
338 ExReleaseFastMutex(&Fcb->DataListLock);
339 Status = KeWaitForSingleObject(&Event,
340 Executive,
341 KernelMode,
342 FALSE,
343 NULL);
344 if (!NT_SUCCESS(Status))
345 {
346 KEBUGCHECK(0);
347 }
348 ExAcquireFastMutex(&Fcb->DataListLock);
349 }
350 Irp->IoStatus.Information = 0;
351 }
352 else
353 {
354 KIRQL oldIrql;
355 if (IsListEmpty(&Fcb->ReadRequestListHead) ||
356 Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
357 {
358 /* this is a new request */
359 Irp->IoStatus.Information = 0;
360 Context->WaitEvent = &Fcb->ReadEvent;
361 InsertTailList(&Fcb->ReadRequestListHead, &Context->ListEntry);
362 if (Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
363 {
364 /* there was already a request on the list */
365 IoAcquireCancelSpinLock(&oldIrql);
366 if (Irp->Cancel)
367 {
368 IoReleaseCancelSpinLock(oldIrql);
369 RemoveEntryList(&Context->ListEntry);
370 ExReleaseFastMutex(&Fcb->DataListLock);
371 Status = STATUS_CANCELLED;
372 goto done;
373 }
374 (void)IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
375 IoReleaseCancelSpinLock(oldIrql);
376 ExReleaseFastMutex(&Fcb->DataListLock);
377 IoMarkIrpPending(Irp);
378 Status = STATUS_PENDING;
379 goto done;
380 }
381 }
382 }
383
384 while (1)
385 {
386 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
387 Information = Irp->IoStatus.Information;
388 Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length;
389 ASSERT (Information <= Length);
390 Buffer = (PVOID)((ULONG_PTR)Buffer + Information);
391 Length -= Information;
392 Status = STATUS_SUCCESS;
393
394 while (1)
395 {
396 if (Fcb->ReadDataAvailable == 0)
397 {
398 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
399 {
400 ASSERT(Fcb->OtherSide != NULL);
401 KeSetEvent(&Fcb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
402 }
403 if (Information > 0 &&
404 (Fcb->Pipe->ReadMode != FILE_PIPE_BYTE_STREAM_MODE ||
405 Fcb->PipeState != FILE_PIPE_CONNECTED_STATE))
406 {
407 break;
408 }
409 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
410 {
411 DPRINT("PipeState: %x\n", Fcb->PipeState);
412 Status = STATUS_PIPE_BROKEN;
413 break;
414 }
415 ExReleaseFastMutex(&Fcb->DataListLock);
416 if (IoIsOperationSynchronous(Irp))
417 {
418 /* Wait for ReadEvent to become signaled */
419
420 DPRINT("Waiting for readable data (%wZ)\n", &Fcb->Pipe->PipeName);
421 Status = KeWaitForSingleObject(&Fcb->ReadEvent,
422 UserRequest,
423 KernelMode,
424 FALSE,
425 NULL);
426 DPRINT("Finished waiting (%wZ)! Status: %x\n", &Fcb->Pipe->PipeName, Status);
427 ExAcquireFastMutex(&Fcb->DataListLock);
428 }
429 else
430 {
431 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
432
433 Context->WaitEvent = &Fcb->ReadEvent;
434 Status = NpfsAddWaitingReadWriteRequest(DeviceObject, Irp);
435
436 if (NT_SUCCESS(Status))
437 {
438 Status = STATUS_PENDING;
439 }
440 ExAcquireFastMutex(&Fcb->DataListLock);
441 break;
442 }
443 }
444 ASSERT(IoGetCurrentIrpStackLocation(Irp)->FileObject != NULL);
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 */