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>
10 /* INCLUDES ******************************************************************/
17 /* FUNCTIONS *****************************************************************/
20 VOID
HexDump(PUCHAR Buffer
, ULONG Length
)
24 const char Hex
[] = "0123456789ABCDEF";
27 DbgPrint("---------------\n");
29 for (i
= 0; i
< Length
; i
+= 16)
31 memset(Line
, ' ', 64);
34 for (j
= 0; j
< 16 && j
+ i
< Length
; j
++)
37 Line
[3*j
+ 0] = Hex
[ch
>> 4];
38 Line
[3*j
+ 1] = Hex
[ch
& 0x0f];
39 Line
[48 + j
] = isprint(ch
) ? ch
: '.';
41 DbgPrint("%s\n", Line
);
43 DbgPrint("---------------\n");
47 static DRIVER_CANCEL NpfsReadWriteCancelRoutine
;
49 NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject
,
52 PNPFS_CONTEXT Context
;
53 PNPFS_DEVICE_EXTENSION DeviceExt
;
54 PIO_STACK_LOCATION IoStack
;
56 BOOLEAN Complete
= FALSE
;
58 DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
60 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
62 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
63 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
64 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
65 Ccb
= IoStack
->FileObject
->FsContext2
;
67 KeLockMutex(&DeviceExt
->PipeListLock
);
68 ExAcquireFastMutex(&Ccb
->DataListLock
);
69 switch(IoStack
->MajorFunction
)
72 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
74 /* we are not the first in the list, remove an complete us */
75 RemoveEntryList(&Context
->ListEntry
);
80 KeSetEvent(&Ccb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
86 ExReleaseFastMutex(&Ccb
->DataListLock
);
87 KeUnlockMutex(&DeviceExt
->PipeListLock
);
90 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
91 Irp
->IoStatus
.Information
= 0;
92 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
97 NpfsWaiterThread(PVOID InitContext
)
99 PNPFS_THREAD_CONTEXT ThreadContext
= (PNPFS_THREAD_CONTEXT
) InitContext
;
105 BOOLEAN Terminate
= FALSE
;
106 BOOLEAN Cancel
= FALSE
;
107 PIO_STACK_LOCATION IoStack
= NULL
;
108 PNPFS_CONTEXT Context
;
109 PNPFS_CONTEXT NextContext
;
112 KeLockMutex(&ThreadContext
->DeviceExt
->PipeListLock
);
116 CurrentCount
= ThreadContext
->Count
;
117 KeUnlockMutex(&ThreadContext
->DeviceExt
->PipeListLock
);
122 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
123 Irp
->IoStatus
.Information
= 0;
124 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
128 switch (IoStack
->MajorFunction
)
131 NpfsRead(IoStack
->DeviceObject
, Irp
);
142 Status
= KeWaitForMultipleObjects(CurrentCount
,
143 ThreadContext
->WaitObjectArray
,
149 ThreadContext
->WaitBlockArray
);
150 if (!NT_SUCCESS(Status
))
154 KeLockMutex(&ThreadContext
->DeviceExt
->PipeListLock
);
155 Count
= Status
- STATUS_SUCCESS
;
156 ASSERT (Count
< CurrentCount
);
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
];
165 Cancel
= (NULL
== IoSetCancelRoutine(Irp
, NULL
));
166 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
167 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
171 Ccb
= IoStack
->FileObject
->FsContext2
;
172 ExAcquireFastMutex(&Ccb
->DataListLock
);
173 RemoveEntryList(&Context
->ListEntry
);
174 switch (IoStack
->MajorFunction
)
177 if (!IsListEmpty(&Ccb
->ReadRequestListHead
))
179 /* put the next request on the wait list */
180 NextContext
= CONTAINING_RECORD(Ccb
->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
--;
191 ExReleaseFastMutex(&Ccb
->DataListLock
);
196 /* someone has add a new wait request */
199 if (ThreadContext
->Count
== 1 && ThreadContext
->DeviceExt
->EmptyWaiterCount
>= MAXIMUM_WAIT_OBJECTS
)
201 /* it exist an other thread with empty wait slots, we can remove our thread from the list */
202 RemoveEntryList(&ThreadContext
->ListEntry
);
203 ThreadContext
->DeviceExt
->EmptyWaiterCount
-= MAXIMUM_WAIT_OBJECTS
- 1;
207 ExFreePool(ThreadContext
);
211 NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject
,
214 PLIST_ENTRY ListEntry
;
215 PNPFS_THREAD_CONTEXT ThreadContext
= NULL
;
220 PNPFS_CONTEXT Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
221 PNPFS_DEVICE_EXTENSION DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
223 DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
225 KeLockMutex(&DeviceExt
->PipeListLock
);
227 ListEntry
= DeviceExt
->ThreadListHead
.Flink
;
228 while (ListEntry
!= &DeviceExt
->ThreadListHead
)
230 ThreadContext
= CONTAINING_RECORD(ListEntry
, NPFS_THREAD_CONTEXT
, ListEntry
);
231 if (ThreadContext
->Count
< MAXIMUM_WAIT_OBJECTS
)
235 ListEntry
= ListEntry
->Flink
;
237 if (ListEntry
== &DeviceExt
->ThreadListHead
)
239 ThreadContext
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_THREAD_CONTEXT
));
240 if (ThreadContext
== NULL
)
242 KeUnlockMutex(&DeviceExt
->PipeListLock
);
243 return STATUS_NO_MEMORY
;
245 ThreadContext
->DeviceExt
= DeviceExt
;
246 KeInitializeEvent(&ThreadContext
->Event
, SynchronizationEvent
, FALSE
);
247 ThreadContext
->Count
= 1;
248 ThreadContext
->WaitObjectArray
[0] = &ThreadContext
->Event
;
251 DPRINT("Creating a new system thread for waiting read/write requests\n");
253 Status
= PsCreateSystemThread(&hThread
,
259 (PVOID
)ThreadContext
);
260 if (!NT_SUCCESS(Status
))
262 ExFreePool(ThreadContext
);
263 KeUnlockMutex(&DeviceExt
->PipeListLock
);
266 InsertHeadList(&DeviceExt
->ThreadListHead
, &ThreadContext
->ListEntry
);
267 DeviceExt
->EmptyWaiterCount
+= MAXIMUM_WAIT_OBJECTS
- 1;
269 IoMarkIrpPending(Irp
);
271 IoAcquireCancelSpinLock(&oldIrql
);
274 IoReleaseCancelSpinLock(oldIrql
);
275 Status
= STATUS_CANCELLED
;
279 (void)IoSetCancelRoutine(Irp
, NpfsReadWriteCancelRoutine
);
280 IoReleaseCancelSpinLock(oldIrql
);
281 ThreadContext
->WaitObjectArray
[ThreadContext
->Count
] = Context
->WaitEvent
;
282 ThreadContext
->WaitIrpArray
[ThreadContext
->Count
] = Irp
;
283 ThreadContext
->Count
++;
284 DeviceExt
->EmptyWaiterCount
--;
285 KeSetEvent(&ThreadContext
->Event
, IO_NO_INCREMENT
, FALSE
);
286 Status
= STATUS_SUCCESS
;
288 KeUnlockMutex(&DeviceExt
->PipeListLock
);
293 NpfsRead(IN PDEVICE_OBJECT DeviceObject
,
296 PFILE_OBJECT FileObject
;
298 NTSTATUS OriginalStatus
= STATUS_SUCCESS
;
300 PNPFS_CONTEXT Context
;
303 ULONG Information
= 0;
304 ULONG CopyLength
= 0;
306 BOOLEAN IsOriginalRequest
= TRUE
;
309 DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
311 if (Irp
->MdlAddress
== NULL
)
313 DPRINT("Irp->MdlAddress == NULL\n");
314 Status
= STATUS_UNSUCCESSFUL
;
315 Irp
->IoStatus
.Information
= 0;
319 FileObject
= IoGetCurrentIrpStackLocation(Irp
)->FileObject
;
320 DPRINT("FileObject %p\n", FileObject
);
321 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
322 Ccb
= FileObject
->FsContext2
;
323 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
325 if ((Ccb
->OtherSide
== NULL
) && (Ccb
->ReadDataAvailable
== 0))
327 /* Its ok if the other side has been Disconnect, but if we have data still in the buffer
328 , need to still be able to read it. Currently this is a HAXXXX */
329 DPRINT("Pipe no longer connected and no data exist in buffer. Ok to close pipe\n");
330 if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
331 Status
= STATUS_PIPE_LISTENING
;
332 else if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
333 Status
= STATUS_PIPE_DISCONNECTED
;
335 Status
= STATUS_UNSUCCESSFUL
;
336 Irp
->IoStatus
.Information
= 0;
340 if (Ccb
->Data
== NULL
)
342 DPRINT1("Pipe is NOT readable!\n");
343 Status
= STATUS_UNSUCCESSFUL
;
344 Irp
->IoStatus
.Information
= 0;
348 ExAcquireFastMutex(&Ccb
->DataListLock
);
350 if (IoIsOperationSynchronous(Irp
))
352 InsertTailList(&Ccb
->ReadRequestListHead
, &Context
->ListEntry
);
353 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
355 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
356 Context
->WaitEvent
= &Event
;
357 ExReleaseFastMutex(&Ccb
->DataListLock
);
358 Status
= KeWaitForSingleObject(&Event
,
364 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
))
366 Status
= STATUS_CANCELLED
;
369 if (!NT_SUCCESS(Status
))
373 ExAcquireFastMutex(&Ccb
->DataListLock
);
375 Irp
->IoStatus
.Information
= 0;
380 if (IsListEmpty(&Ccb
->ReadRequestListHead
) ||
381 Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
383 /* this is a new request */
384 Irp
->IoStatus
.Information
= 0;
385 Context
->WaitEvent
= &Ccb
->ReadEvent
;
386 InsertTailList(&Ccb
->ReadRequestListHead
, &Context
->ListEntry
);
387 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
389 /* there was already a request on the list */
390 IoAcquireCancelSpinLock(&oldIrql
);
393 IoReleaseCancelSpinLock(oldIrql
);
394 RemoveEntryList(&Context
->ListEntry
);
395 ExReleaseFastMutex(&Ccb
->DataListLock
);
396 Status
= STATUS_CANCELLED
;
399 (void)IoSetCancelRoutine(Irp
, NpfsReadWriteCancelRoutine
);
400 IoReleaseCancelSpinLock(oldIrql
);
401 ExReleaseFastMutex(&Ccb
->DataListLock
);
402 IoMarkIrpPending(Irp
);
403 Status
= STATUS_PENDING
;
411 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
412 Information
= Irp
->IoStatus
.Information
;
413 Length
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
;
414 ASSERT (Information
<= Length
);
415 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Information
);
416 Length
-= Information
;
417 Status
= STATUS_SUCCESS
;
421 if (Ccb
->ReadDataAvailable
== 0)
423 if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
425 ASSERT(Ccb
->OtherSide
!= NULL
);
426 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
428 if (Information
> 0 &&
429 (Ccb
->Fcb
->ReadMode
!= FILE_PIPE_BYTE_STREAM_MODE
||
430 Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
))
434 if ((Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
) && (Ccb
->ReadDataAvailable
== 0))
436 DPRINT("PipeState: %x\n", Ccb
->PipeState
);
437 Status
= STATUS_PIPE_BROKEN
;
440 ExReleaseFastMutex(&Ccb
->DataListLock
);
442 if (IoIsOperationSynchronous(Irp
))
444 /* Wait for ReadEvent to become signaled */
446 DPRINT("Waiting for readable data (%wZ)\n", &Ccb
->Fcb
->PipeName
);
447 Status
= KeWaitForSingleObject(&Ccb
->ReadEvent
,
452 DPRINT("Finished waiting (%wZ)! Status: %x\n", &Ccb
->Fcb
->PipeName
, Status
);
454 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
))
456 Status
= STATUS_CANCELLED
;
459 if (!NT_SUCCESS(Status
))
463 ExAcquireFastMutex(&Ccb
->DataListLock
);
467 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
469 Context
->WaitEvent
= &Ccb
->ReadEvent
;
471 Status
= NpfsAddWaitingReadWriteRequest(DeviceObject
, Irp
);
473 if (NT_SUCCESS(Status
))
475 Status
= STATUS_PENDING
;
478 ExAcquireFastMutex(&Ccb
->DataListLock
);
482 ASSERT(IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
);
483 if (Ccb
->Fcb
->ReadMode
== FILE_PIPE_BYTE_STREAM_MODE
)
485 DPRINT("Byte stream mode\n");
486 /* Byte stream mode */
487 while (Length
> 0 && Ccb
->ReadDataAvailable
> 0)
489 CopyLength
= min(Ccb
->ReadDataAvailable
, Length
);
490 if ((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
<= (ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
)
492 memcpy(Buffer
, Ccb
->ReadPtr
, CopyLength
);
493 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
);
494 if (Ccb
->ReadPtr
== (PVOID
)((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
))
496 Ccb
->ReadPtr
= Ccb
->Data
;
501 TempLength
= (ULONG
)((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
- (ULONG_PTR
)Ccb
->ReadPtr
);
502 memcpy(Buffer
, Ccb
->ReadPtr
, TempLength
);
503 memcpy((PVOID
)((ULONG_PTR
)Buffer
+ TempLength
), Ccb
->Data
, CopyLength
- TempLength
);
504 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->Data
+ CopyLength
- TempLength
);
507 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CopyLength
);
508 Length
-= CopyLength
;
509 Information
+= CopyLength
;
511 Ccb
->ReadDataAvailable
-= CopyLength
;
512 Ccb
->WriteQuotaAvailable
+= CopyLength
;
515 if ((Length
== 0) || (Ccb
->ReadDataAvailable
== 0))
517 if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
519 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
521 KeResetEvent(&Ccb
->ReadEvent
);
527 DPRINT("Message mode\n");
529 /* For Message mode, the Message length will be stored in the buffer preceeding the Message. */
530 if (Ccb
->ReadDataAvailable
)
532 ULONG NextMessageLength
=0;
533 //HexDump(Ccb->Data, (ULONG)Ccb->WritePtr - (ULONG)Ccb->Data);
534 /*First get the size of the message */
535 memcpy(&NextMessageLength
, Ccb
->Data
, sizeof(NextMessageLength
));
536 if ((NextMessageLength
== 0) || (NextMessageLength
> Ccb
->ReadDataAvailable
))
538 DPRINT1("This should never happen! Possible memory corruption.\n");
540 HexDump(Ccb
->Data
, (ULONG
)Ccb
->WritePtr
- (ULONG
)Ccb
->Data
);
545 /* Use the smaller value */
547 CopyLength
= min(NextMessageLength
, Length
);
549 /* retrieve the message from the buffer */
550 memcpy(Buffer
, (PVOID
)((ULONG
)Ccb
->Data
+ sizeof(NextMessageLength
)), CopyLength
);
553 if (Ccb
->ReadDataAvailable
> CopyLength
)
555 if (CopyLength
< NextMessageLength
)
557 /* Client only requested part of the message */
559 /* Calculate the remaining message new size */
560 ULONG NewMessageSize
= NextMessageLength
-CopyLength
;
562 /* Write a new Message size to buffer for the part of the message still there */
563 memcpy(Ccb
->Data
, &NewMessageSize
, sizeof(NewMessageSize
));
565 /* Move the memory starting from end of partial Message just retrieved */
566 memmove((PVOID
)((ULONG_PTR
)Ccb
->Data
+ sizeof(NewMessageSize
)),
567 (PVOID
)((ULONG_PTR
) Ccb
->Data
+ CopyLength
+ sizeof(NewMessageSize
)),
568 (ULONG
)Ccb
->WritePtr
- ((ULONG
)Ccb
->Data
+ sizeof(NewMessageSize
)) - CopyLength
);
570 /* Update the write pointer */
571 Ccb
->WritePtr
= (PVOID
)((ULONG
)Ccb
->WritePtr
- CopyLength
);
573 /* Add CopyLength only to WriteQuotaAvailable as the
574 Message Size was replaced in the buffer */
575 Ccb
->WriteQuotaAvailable
+= CopyLength
;
579 /* Client wanted the entire message */
581 /* Move the memory starting from the next Message just retrieved */
583 (PVOID
)((ULONG_PTR
) Ccb
->Data
+ NextMessageLength
+ sizeof(NextMessageLength
)),
584 (ULONG
)Ccb
->WritePtr
- (ULONG
)Ccb
->Data
- NextMessageLength
- sizeof(NextMessageLength
));
586 /* Update the write pointer */
587 Ccb
->WritePtr
= (PVOID
)((ULONG
)Ccb
->WritePtr
- NextMessageLength
);
589 /* Add both the message length and the header to the WriteQuotaAvailable
590 as they both were removed */
591 Ccb
->WriteQuotaAvailable
+= (CopyLength
+ sizeof(NextMessageLength
));
596 /* This was the last Message, so just zero this messages for safety sake */
597 memset(Ccb
->Data
,0,NextMessageLength
+ sizeof(NextMessageLength
));
599 /* reset the write pointer to beginning of buffer */
600 Ccb
->WritePtr
= Ccb
->Data
;
602 /* Add both the message length and the header to the WriteQuotaAvailable
603 as they both were removed */
604 Ccb
->WriteQuotaAvailable
+= (CopyLength
+ sizeof(ULONG
));
606 KeResetEvent(&Ccb
->ReadEvent
);
607 if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
609 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
613 DPRINT("Length %d Buffer %x\n",CopyLength
,Buffer
);
614 HexDump((PUCHAR
)Buffer
, CopyLength
);
617 Information
+= CopyLength
;
619 Ccb
->ReadDataAvailable
-= CopyLength
;
621 if ((ULONG
)Ccb
->WriteQuotaAvailable
> (ULONG
)Ccb
->MaxDataLength
) ASSERT(FALSE
);
630 Irp
->IoStatus
.Information
= Information
;
631 Irp
->IoStatus
.Status
= Status
;
633 ASSERT(IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
);
635 if (IoIsOperationSynchronous(Irp
))
637 RemoveEntryList(&Context
->ListEntry
);
638 if (!IsListEmpty(&Ccb
->ReadRequestListHead
))
640 Context
= CONTAINING_RECORD(Ccb
->ReadRequestListHead
.Flink
, NPFS_CONTEXT
, ListEntry
);
641 KeSetEvent(Context
->WaitEvent
, IO_NO_INCREMENT
, FALSE
);
643 ExReleaseFastMutex(&Ccb
->DataListLock
);
644 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
646 DPRINT("NpfsRead done (Status %lx)\n", Status
);
651 if (IsOriginalRequest
)
653 IsOriginalRequest
= FALSE
;
654 OriginalStatus
= Status
;
656 if (Status
== STATUS_PENDING
)
658 ExReleaseFastMutex(&Ccb
->DataListLock
);
659 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus
);
660 return OriginalStatus
;
662 RemoveEntryList(&Context
->ListEntry
);
663 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
664 if (IsListEmpty(&Ccb
->ReadRequestListHead
))
666 ExReleaseFastMutex(&Ccb
->DataListLock
);
667 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus
);
668 return OriginalStatus
;
670 Context
= CONTAINING_RECORD(Ccb
->ReadRequestListHead
.Flink
, NPFS_CONTEXT
, ListEntry
);
671 Irp
= CONTAINING_RECORD(Context
, IRP
, Tail
.Overlay
.DriverContext
);
676 Irp
->IoStatus
.Status
= Status
;
678 if (Status
!= STATUS_PENDING
)
680 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
682 DPRINT("NpfsRead done (Status %lx)\n", Status
);
688 NpfsWrite(PDEVICE_OBJECT DeviceObject
,
691 PIO_STACK_LOCATION IoStack
;
692 PFILE_OBJECT FileObject
;
693 PNPFS_FCB Fcb
= NULL
;
694 PNPFS_CCB Ccb
= NULL
;
697 NTSTATUS Status
= STATUS_SUCCESS
;
704 DPRINT("NpfsWrite()\n");
706 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
707 FileObject
= IoStack
->FileObject
;
708 DPRINT("FileObject %p\n", FileObject
);
709 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
711 Ccb
= FileObject
->FsContext2
;
712 ReaderCcb
= Ccb
->OtherSide
;
715 Length
= IoStack
->Parameters
.Write
.Length
;
716 Offset
= IoStack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
719 if (Irp
->MdlAddress
== NULL
)
721 DPRINT1("Irp->MdlAddress == NULL\n");
722 Status
= STATUS_UNSUCCESSFUL
;
727 if (ReaderCcb
== NULL
)
729 DPRINT1("Pipe is NOT connected!\n");
730 if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
731 Status
= STATUS_PIPE_LISTENING
;
732 else if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
733 Status
= STATUS_PIPE_DISCONNECTED
;
735 Status
= STATUS_UNSUCCESSFUL
;
740 if (ReaderCcb
->Data
== NULL
)
742 DPRINT1("Pipe is NOT writable!\n");
743 Status
= STATUS_UNSUCCESSFUL
;
748 Status
= STATUS_SUCCESS
;
749 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
751 ExAcquireFastMutex(&ReaderCcb
->DataListLock
);
753 DPRINT("Length %d Buffer %x Offset %x\n",Length
,Buffer
,Offset
);
754 HexDump(Buffer
, Length
);
759 if ((ReaderCcb
->WriteQuotaAvailable
== 0))
761 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
762 if (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
764 Status
= STATUS_PIPE_BROKEN
;
765 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
768 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
770 DPRINT("Write Waiting for buffer space (%S)\n", Fcb
->PipeName
.Buffer
);
771 Status
= KeWaitForSingleObject(&Ccb
->WriteEvent
,
776 DPRINT("Write Finished waiting (%S)! Status: %x\n", Fcb
->PipeName
.Buffer
, Status
);
777 ExAcquireFastMutex(&ReaderCcb
->DataListLock
);
778 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
))
780 Status
= STATUS_CANCELLED
;
783 if (!NT_SUCCESS(Status
))
788 * It's possible that the event was signaled because the
789 * other side of pipe was closed.
791 if (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
793 DPRINT("PipeState: %x\n", Ccb
->PipeState
);
794 Status
= STATUS_PIPE_BROKEN
;
795 // ExReleaseFastMutex(&ReaderCcb->DataListLock);
800 if (Fcb
->WriteMode
== FILE_PIPE_BYTE_STREAM_MODE
)
802 DPRINT("Byte stream mode\n");
804 while (Length
> 0 && ReaderCcb
->WriteQuotaAvailable
> 0)
806 CopyLength
= min(Length
, ReaderCcb
->WriteQuotaAvailable
);
808 if ((ULONG_PTR
)ReaderCcb
->WritePtr
+ CopyLength
<= (ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
)
810 memcpy(ReaderCcb
->WritePtr
, Buffer
, CopyLength
);
811 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ CopyLength
);
812 if ((ULONG_PTR
)ReaderCcb
->WritePtr
== (ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
)
814 ReaderCcb
->WritePtr
= ReaderCcb
->Data
;
819 TempLength
= (ULONG
)((ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
- (ULONG_PTR
)ReaderCcb
->WritePtr
);
820 memcpy(ReaderCcb
->WritePtr
, Buffer
, TempLength
);
821 memcpy(ReaderCcb
->Data
, Buffer
+ TempLength
, CopyLength
- TempLength
);
822 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->Data
+ CopyLength
- TempLength
);
825 Buffer
+= CopyLength
;
826 Length
-= CopyLength
;
827 Information
+= CopyLength
;
829 ReaderCcb
->ReadDataAvailable
+= CopyLength
;
830 ReaderCcb
->WriteQuotaAvailable
-= CopyLength
;
835 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
836 KeResetEvent(&Ccb
->WriteEvent
);
842 /* For Message Type Pipe, the Pipes memory will be used to store the size of each message */
843 /* FIXME: Check and verify ReadMode ByteStream */
847 /* Verify the WritePtr is still inside the buffer */
848 if (((ULONG
)ReaderCcb
->WritePtr
> ((ULONG
)ReaderCcb
->Data
+ (ULONG
)ReaderCcb
->MaxDataLength
)) ||
849 ((ULONG
)ReaderCcb
->WritePtr
< (ULONG
)ReaderCcb
->Data
))
851 DPRINT1("NPFS is writing out of its buffer. Report to developer!\n");
852 DPRINT1("ReaderCcb->WritePtr %x, ReaderCcb->Data %x, ReaderCcb->MaxDataLength%d\n",
853 ReaderCcb
->WritePtr
,ReaderCcb
->Data
,ReaderCcb
->MaxDataLength
);
857 CopyLength
= min(Length
, ReaderCcb
->WriteQuotaAvailable
- sizeof(ULONG
));
859 /* First Copy the Length of the message into the pipes buffer */
860 memcpy(ReaderCcb
->WritePtr
, &CopyLength
, sizeof(CopyLength
));
862 /* Now the user buffer itself */
863 memcpy((PVOID
)((ULONG
)ReaderCcb
->WritePtr
+ sizeof(CopyLength
)), Buffer
, CopyLength
);
865 /* Update the write pointer */
866 ReaderCcb
->WritePtr
= (PVOID
)((ULONG
)ReaderCcb
->WritePtr
+ sizeof(CopyLength
) + CopyLength
);
868 Information
+= CopyLength
;
870 ReaderCcb
->ReadDataAvailable
+= CopyLength
;
872 ReaderCcb
->WriteQuotaAvailable
-= (CopyLength
+ sizeof(ULONG
));
874 if ((ULONG
)ReaderCcb
->WriteQuotaAvailable
> (ULONG
)ReaderCcb
->MaxDataLength
)
876 DPRINT1("QuotaAvailable is greater than buffer size!\n");
883 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
884 KeResetEvent(&Ccb
->WriteEvent
);
890 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
893 Irp
->IoStatus
.Status
= Status
;
894 Irp
->IoStatus
.Information
= Information
;
896 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
898 DPRINT("NpfsWrite done (Status %lx)\n", Status
);