Build file system drivers w/ W32API headers.
[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 <rosrtl/minmax.h>
14 #include "npfs.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* FUNCTIONS *****************************************************************/
20
21 #ifndef NDEBUG
22 VOID HexDump(PUCHAR Buffer, ULONG Length)
23 {
24 CHAR Line[65];
25 UCHAR ch;
26 const char Hex[] = "0123456789ABCDEF";
27 int i, j;
28
29 DbgPrint("---------------\n");
30
31 for (i = 0; i < ROUND_UP(Length, 16); i+= 16)
32 {
33 memset(Line, ' ', 64);
34 Line[64] = 0;
35
36 for (j = 0; j < 16 && j + i < Length; j++)
37 {
38 ch = Buffer[i + j];
39 Line[3*j + 0] = Hex[ch >> 4];
40 Line[3*j + 1] = Hex[ch & 0x0f];
41 Line[48 + j] = isprint(ch) ? ch : '.';
42 }
43 DbgPrint("%s\n", Line);
44 }
45 DbgPrint("---------------\n");
46 }
47 #endif
48
49 static VOID STDCALL
50 NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject,
51 IN PIRP Irp)
52 {
53 PNPFS_CONTEXT Context;
54 PNPFS_DEVICE_EXTENSION DeviceExt;
55 PIO_STACK_LOCATION IoStack;
56 PNPFS_FCB Fcb;
57 BOOLEAN Complete = FALSE;
58
59 DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %x, Irp %x)\n", DeviceObject, Irp);
60
61 IoReleaseCancelSpinLock(Irp->CancelIrql);
62
63 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
64 DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
65 IoStack = IoGetCurrentIrpStackLocation(Irp);
66 Fcb = IoStack->FileObject->FsContext;
67
68 KeLockMutex(&DeviceExt->PipeListLock);
69 ExAcquireFastMutex(&Fcb->DataListLock);
70 switch(IoStack->MajorFunction)
71 {
72 case IRP_MJ_READ:
73 if (Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
74 {
75 /* we are not the first in the list, remove an complete us */
76 RemoveEntryList(&Context->ListEntry);
77 Complete = TRUE;
78 }
79 else
80 {
81 KeSetEvent(&Fcb->ReadEvent, IO_NO_INCREMENT, FALSE);
82 }
83 break;
84 default:
85 KEBUGCHECK(0);
86 }
87 ExReleaseFastMutex(&Fcb->DataListLock);
88 KeUnlockMutex(&DeviceExt->PipeListLock);
89 if (Complete)
90 {
91 Irp->IoStatus.Status = STATUS_CANCELLED;
92 Irp->IoStatus.Information = 0;
93 IoCompleteRequest(Irp, IO_NO_INCREMENT);
94 }
95 }
96
97 static VOID STDCALL
98 NpfsWaiterThread(PVOID InitContext)
99 {
100 PNPFS_THREAD_CONTEXT ThreadContext = (PNPFS_THREAD_CONTEXT) InitContext;
101 ULONG CurrentCount;
102 ULONG Count = 0;
103 PIRP Irp = NULL;
104 PIRP NextIrp;
105 NTSTATUS Status;
106 BOOLEAN Terminate = FALSE;
107 BOOLEAN Cancel = FALSE;
108 PIO_STACK_LOCATION IoStack = NULL;
109 PNPFS_CONTEXT Context;
110 PNPFS_CONTEXT NextContext;
111 PNPFS_FCB Fcb;
112
113 KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
114
115 while (1)
116 {
117 CurrentCount = ThreadContext->Count;
118 KeUnlockMutex(&ThreadContext->DeviceExt->PipeListLock);
119 if (Irp)
120 {
121 if (Cancel)
122 {
123 Irp->IoStatus.Status = STATUS_CANCELLED;
124 Irp->IoStatus.Information = 0;
125 IoCompleteRequest(Irp, IO_NO_INCREMENT);
126 }
127 else
128 {
129 switch (IoStack->MajorFunction)
130 {
131 case IRP_MJ_READ:
132 NpfsRead(IoStack->DeviceObject, Irp);
133 break;
134 default:
135 KEBUGCHECK(0);
136 }
137 }
138 }
139 if (Terminate)
140 {
141 break;
142 }
143 Status = KeWaitForMultipleObjects(CurrentCount,
144 ThreadContext->WaitObjectArray,
145 WaitAny,
146 Executive,
147 KernelMode,
148 FALSE,
149 NULL,
150 ThreadContext->WaitBlockArray);
151 if (!NT_SUCCESS(Status))
152 {
153 KEBUGCHECK(0);
154 }
155 KeLockMutex(&ThreadContext->DeviceExt->PipeListLock);
156 Count = Status - STATUS_SUCCESS;
157 ASSERT (Count < CurrentCount);
158 if (Count > 0)
159 {
160 Irp = ThreadContext->WaitIrpArray[Count];
161 ThreadContext->Count--;
162 ThreadContext->DeviceExt->EmptyWaiterCount++;
163 ThreadContext->WaitObjectArray[Count] = ThreadContext->WaitObjectArray[ThreadContext->Count];
164 ThreadContext->WaitIrpArray[Count] = ThreadContext->WaitIrpArray[ThreadContext->Count];
165
166 Cancel = (NULL == IoSetCancelRoutine(Irp, NULL));
167 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
168 IoStack = IoGetCurrentIrpStackLocation(Irp);
169
170 if (Cancel)
171 {
172 Fcb = IoStack->FileObject->FsContext;
173 ExAcquireFastMutex(&Fcb->DataListLock);
174 RemoveEntryList(&Context->ListEntry);
175 switch (IoStack->MajorFunction)
176 {
177 case IRP_MJ_READ:
178 if (!IsListEmpty(&Fcb->ReadRequestListHead))
179 {
180 /* put the next request on the wait list */
181 NextContext = CONTAINING_RECORD(Fcb->ReadRequestListHead.Flink, NPFS_CONTEXT, ListEntry);
182 ThreadContext->WaitObjectArray[ThreadContext->Count] = NextContext->WaitEvent;
183 NextIrp = CONTAINING_RECORD(NextContext, IRP, Tail.Overlay.DriverContext);
184 ThreadContext->WaitIrpArray[ThreadContext->Count] = NextIrp;
185 ThreadContext->Count++;
186 ThreadContext->DeviceExt->EmptyWaiterCount--;
187 }
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 KeUnlockMutex(&ThreadContext->DeviceExt->PipeListLock);
209 ExFreePool(ThreadContext);
210 }
211
212 static NTSTATUS
213 NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject,
214 IN PIRP Irp)
215 {
216 PLIST_ENTRY ListEntry;
217 PNPFS_THREAD_CONTEXT ThreadContext = NULL;
218 NTSTATUS Status;
219 HANDLE hThread;
220 KIRQL oldIrql;
221
222 PNPFS_CONTEXT Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
223 PNPFS_DEVICE_EXTENSION DeviceExt = (PNPFS_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
224
225 DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
226
227 KeLockMutex(&DeviceExt->PipeListLock);
228
229 ListEntry = DeviceExt->ThreadListHead.Flink;
230 while (ListEntry != &DeviceExt->ThreadListHead)
231 {
232 ThreadContext = CONTAINING_RECORD(ListEntry, NPFS_THREAD_CONTEXT, ListEntry);
233 if (ThreadContext->Count < MAXIMUM_WAIT_OBJECTS)
234 {
235 break;
236 }
237 ListEntry = ListEntry->Flink;
238 }
239 if (ListEntry == &DeviceExt->ThreadListHead)
240 {
241 ThreadContext = ExAllocatePool(NonPagedPool, sizeof(NPFS_THREAD_CONTEXT));
242 if (ThreadContext == NULL)
243 {
244 KeUnlockMutex(&DeviceExt->PipeListLock);
245 return STATUS_NO_MEMORY;
246 }
247 ThreadContext->DeviceExt = DeviceExt;
248 KeInitializeEvent(&ThreadContext->Event, SynchronizationEvent, FALSE);
249 ThreadContext->Count = 1;
250 ThreadContext->WaitObjectArray[0] = &ThreadContext->Event;
251
252
253 DPRINT("Creating a new system thread for waiting read/write requests\n");
254
255 Status = PsCreateSystemThread(&hThread,
256 THREAD_ALL_ACCESS,
257 NULL,
258 NULL,
259 NULL,
260 NpfsWaiterThread,
261 (PVOID)ThreadContext);
262 if (!NT_SUCCESS(Status))
263 {
264 ExFreePool(ThreadContext);
265 KeUnlockMutex(&DeviceExt->PipeListLock);
266 return Status;
267 }
268 InsertHeadList(&DeviceExt->ThreadListHead, &ThreadContext->ListEntry);
269 DeviceExt->EmptyWaiterCount += MAXIMUM_WAIT_OBJECTS - 1;
270 }
271 IoMarkIrpPending(Irp);
272
273 IoAcquireCancelSpinLock(&oldIrql);
274 if (Irp->Cancel)
275 {
276 IoReleaseCancelSpinLock(oldIrql);
277 Status = STATUS_CANCELLED;
278 }
279 else
280 {
281 IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
282 IoReleaseCancelSpinLock(oldIrql);
283 ThreadContext->WaitObjectArray[ThreadContext->Count] = Context->WaitEvent;
284 ThreadContext->WaitIrpArray[ThreadContext->Count] = Irp;
285 ThreadContext->Count++;
286 DeviceExt->EmptyWaiterCount--;
287 KeSetEvent(&ThreadContext->Event, IO_NO_INCREMENT, FALSE);
288 Status = STATUS_SUCCESS;
289 }
290 KeUnlockMutex(&DeviceExt->PipeListLock);
291 return Status;
292 }
293
294 NTSTATUS STDCALL
295 NpfsRead(IN PDEVICE_OBJECT DeviceObject,
296 IN PIRP Irp)
297 {
298 PFILE_OBJECT FileObject;
299 NTSTATUS Status;
300 NTSTATUS OriginalStatus = STATUS_SUCCESS;
301 PNPFS_FCB Fcb;
302 PNPFS_CONTEXT Context;
303 KEVENT Event;
304 ULONG Length;
305 ULONG Information;
306 ULONG CopyLength;
307 ULONG TempLength;
308 BOOLEAN IsOriginalRequest = TRUE;
309 PVOID Buffer;
310
311 DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject, Irp);
312
313 if (Irp->MdlAddress == NULL)
314 {
315 DPRINT("Irp->MdlAddress == NULL\n");
316 Status = STATUS_UNSUCCESSFUL;
317 Irp->IoStatus.Information = 0;
318 goto done;
319 }
320
321 FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
322 Fcb = FileObject->FsContext;
323 Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
324
325 if (Fcb->Data == NULL)
326 {
327 DPRINT1("Pipe is NOT readable!\n");
328 Status = STATUS_UNSUCCESSFUL;
329 Irp->IoStatus.Information = 0;
330 goto done;
331 }
332
333 ExAcquireFastMutex(&Fcb->DataListLock);
334
335 if (IoIsOperationSynchronous(Irp))
336 {
337 InsertTailList(&Fcb->ReadRequestListHead, &Context->ListEntry);
338 if (Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
339 {
340 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
341 Context->WaitEvent = &Event;
342 ExReleaseFastMutex(&Fcb->DataListLock);
343 Status = KeWaitForSingleObject(&Event,
344 Executive,
345 KernelMode,
346 FALSE,
347 NULL);
348 if (!NT_SUCCESS(Status))
349 {
350 KEBUGCHECK(0);
351 }
352 ExAcquireFastMutex(&Fcb->DataListLock);
353 }
354 Irp->IoStatus.Information = 0;
355 }
356 else
357 {
358 KIRQL oldIrql;
359 if (IsListEmpty(&Fcb->ReadRequestListHead) ||
360 Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
361 {
362 /* this is a new request */
363 Irp->IoStatus.Information = 0;
364 Context->WaitEvent = &Fcb->ReadEvent;
365 InsertTailList(&Fcb->ReadRequestListHead, &Context->ListEntry);
366 if (Fcb->ReadRequestListHead.Flink != &Context->ListEntry)
367 {
368 /* there was already a request on the list */
369 IoAcquireCancelSpinLock(&oldIrql);
370 if (Irp->Cancel)
371 {
372 IoReleaseCancelSpinLock(oldIrql);
373 RemoveEntryList(&Context->ListEntry);
374 ExReleaseFastMutex(&Fcb->DataListLock);
375 Status = STATUS_CANCELLED;
376 goto done;
377 }
378 IoSetCancelRoutine(Irp, NpfsReadWriteCancelRoutine);
379 IoReleaseCancelSpinLock(oldIrql);
380 ExReleaseFastMutex(&Fcb->DataListLock);
381 IoMarkIrpPending(Irp);
382 Status = STATUS_PENDING;
383 goto done;
384 }
385 }
386 }
387
388 while (1)
389 {
390 Buffer = MmGetSystemAddressForMdl(Irp->MdlAddress);
391 Information = Irp->IoStatus.Information;
392 Length = IoGetCurrentIrpStackLocation(Irp)->Parameters.Read.Length;
393 ASSERT (Information <= Length);
394 Buffer += Information;
395 Length -= Information;
396 Status = STATUS_SUCCESS;
397
398 while (1)
399 {
400 if (Fcb->ReadDataAvailable == 0)
401 {
402 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
403 {
404 KeSetEvent(&Fcb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
405 }
406 if (Information > 0 &&
407 (Fcb->Pipe->ReadMode != FILE_PIPE_BYTE_STREAM_MODE ||
408 Fcb->PipeState != FILE_PIPE_CONNECTED_STATE))
409 {
410 break;
411 }
412 if (Fcb->PipeState != FILE_PIPE_CONNECTED_STATE)
413 {
414 DPRINT("PipeState: %x\n", Fcb->PipeState);
415 Status = STATUS_PIPE_BROKEN;
416 break;
417 }
418 ExReleaseFastMutex(&Fcb->DataListLock);
419 if (IoIsOperationSynchronous(Irp))
420 {
421 /* Wait for ReadEvent to become signaled */
422
423 DPRINT("Waiting for readable data (%wZ)\n", &Fcb->Pipe->PipeName);
424 Status = KeWaitForSingleObject(&Fcb->ReadEvent,
425 UserRequest,
426 KernelMode,
427 FALSE,
428 NULL);
429 DPRINT("Finished waiting (%wZ)! Status: %x\n", &Fcb->Pipe->PipeName, Status);
430 ExAcquireFastMutex(&Fcb->DataListLock);
431 }
432 else
433 {
434 PNPFS_CONTEXT Context = (PNPFS_CONTEXT)&Irp->Tail.Overlay.DriverContext;
435
436 Context->WaitEvent = &Fcb->ReadEvent;
437 Status = NpfsAddWaitingReadWriteRequest(DeviceObject, Irp);
438
439 if (NT_SUCCESS(Status))
440 {
441 Status = STATUS_PENDING;
442 }
443 ExAcquireFastMutex(&Fcb->DataListLock);
444 break;
445 }
446 }
447 if (Fcb->Pipe->ReadMode == FILE_PIPE_BYTE_STREAM_MODE)
448 {
449 DPRINT("Byte stream mode\n");
450 /* Byte stream mode */
451 while (Length > 0 && Fcb->ReadDataAvailable > 0)
452 {
453 CopyLength = RtlRosMin(Fcb->ReadDataAvailable, Length);
454 if (Fcb->ReadPtr + CopyLength <= Fcb->Data + Fcb->MaxDataLength)
455 {
456 memcpy(Buffer, Fcb->ReadPtr, CopyLength);
457 Fcb->ReadPtr += CopyLength;
458 if (Fcb->ReadPtr == Fcb->Data + Fcb->MaxDataLength)
459 {
460 Fcb->ReadPtr = Fcb->Data;
461 }
462 }
463 else
464 {
465 TempLength = Fcb->Data + Fcb->MaxDataLength - Fcb->ReadPtr;
466 memcpy(Buffer, Fcb->ReadPtr, TempLength);
467 memcpy(Buffer + TempLength, Fcb->Data, CopyLength - TempLength);
468 Fcb->ReadPtr = Fcb->Data + CopyLength - TempLength;
469 }
470
471 Buffer += CopyLength;
472 Length -= CopyLength;
473 Information += CopyLength;
474
475 Fcb->ReadDataAvailable -= CopyLength;
476 Fcb->WriteQuotaAvailable += CopyLength;
477 }
478
479 if (Length == 0)
480 {
481 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
482 {
483 KeSetEvent(&Fcb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
484 }
485 KeResetEvent(&Fcb->ReadEvent);
486 break;
487 }
488 }
489 else
490 {
491 DPRINT("Message mode\n");
492
493 /* Message mode */
494 if (Fcb->ReadDataAvailable)
495 {
496 /* Truncate the message if the receive buffer is too small */
497 CopyLength = RtlRosMin(Fcb->ReadDataAvailable, Length);
498 memcpy(Buffer, Fcb->Data, CopyLength);
499
500 #ifndef NDEBUG
501 DPRINT("Length %d Buffer %x\n",CopyLength,Buffer);
502 HexDump((PUCHAR)Buffer, CopyLength);
503 #endif
504
505 Information = CopyLength;
506
507 if (Fcb->ReadDataAvailable > Length)
508 {
509 memmove(Fcb->Data, Fcb->Data + Length,
510 Fcb->ReadDataAvailable - Length);
511 Fcb->ReadDataAvailable -= Length;
512 Status = STATUS_MORE_ENTRIES;
513 }
514 else
515 {
516 KeResetEvent(&Fcb->ReadEvent);
517 if (Fcb->PipeState == FILE_PIPE_CONNECTED_STATE)
518 {
519 KeSetEvent(&Fcb->OtherSide->WriteEvent, IO_NO_INCREMENT, FALSE);
520 }
521 Fcb->ReadDataAvailable = 0;
522 Fcb->WriteQuotaAvailable = Fcb->MaxDataLength;
523 }
524 }
525
526 if (Information > 0)
527 {
528 break;
529 }
530 }
531 }
532 Irp->IoStatus.Information = Information;
533 Irp->IoStatus.Status = Status;
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 = RtlRosMin(Length, ReaderFcb->WriteQuotaAvailable);
698 if (ReaderFcb->WritePtr + CopyLength <= ReaderFcb->Data + ReaderFcb->MaxDataLength)
699 {
700 memcpy(ReaderFcb->WritePtr, Buffer, CopyLength);
701 ReaderFcb->WritePtr += CopyLength;
702 if (ReaderFcb->WritePtr == ReaderFcb->Data + ReaderFcb->MaxDataLength)
703 {
704 ReaderFcb->WritePtr = ReaderFcb->Data;
705 }
706 }
707 else
708 {
709 TempLength = ReaderFcb->Data + ReaderFcb->MaxDataLength - ReaderFcb->WritePtr;
710 memcpy(ReaderFcb->WritePtr, Buffer, TempLength);
711 memcpy(ReaderFcb->Data, Buffer + TempLength, CopyLength - TempLength);
712 ReaderFcb->WritePtr = 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 = RtlRosMin(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 */