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 *****************************************************************/
19 VOID
HexDump(PUCHAR Buffer
, ULONG Length
)
23 const char Hex
[] = "0123456789ABCDEF";
26 DbgPrint("---------------\n");
28 for (i
= 0; i
< Length
; i
+= 16)
30 memset(Line
, ' ', 64);
33 for (j
= 0; j
< 16 && j
+ i
< Length
; j
++)
36 Line
[3*j
+ 0] = Hex
[ch
>> 4];
37 Line
[3*j
+ 1] = Hex
[ch
& 0x0f];
38 Line
[48 + j
] = isprint(ch
) ? ch
: '.';
40 DbgPrint("%s\n", Line
);
42 DbgPrint("---------------\n");
45 static DRIVER_CANCEL NpfsReadWriteCancelRoutine
;
47 NpfsReadWriteCancelRoutine(IN PDEVICE_OBJECT DeviceObject
,
50 PNPFS_CONTEXT Context
;
51 PNPFS_DEVICE_EXTENSION DeviceExt
;
52 PIO_STACK_LOCATION IoStack
;
54 BOOLEAN Complete
= FALSE
;
56 DPRINT("NpfsReadWriteCancelRoutine(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
58 IoReleaseCancelSpinLock(Irp
->CancelIrql
);
60 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
61 DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
62 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
63 Ccb
= IoStack
->FileObject
->FsContext2
;
65 KeLockMutex(&DeviceExt
->PipeListLock
);
66 ExAcquireFastMutex(&Ccb
->DataListLock
);
67 switch(IoStack
->MajorFunction
)
70 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
72 /* we are not the first in the list, remove an complete us */
73 RemoveEntryList(&Context
->ListEntry
);
78 KeSetEvent(&Ccb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
84 ExReleaseFastMutex(&Ccb
->DataListLock
);
85 KeUnlockMutex(&DeviceExt
->PipeListLock
);
88 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
89 Irp
->IoStatus
.Information
= 0;
90 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
95 NpfsWaiterThread(PVOID InitContext
)
97 PNPFS_THREAD_CONTEXT ThreadContext
= (PNPFS_THREAD_CONTEXT
) InitContext
;
103 BOOLEAN Terminate
= FALSE
;
104 BOOLEAN Cancel
= FALSE
;
105 PIO_STACK_LOCATION IoStack
= NULL
;
106 PNPFS_CONTEXT Context
;
107 PNPFS_CONTEXT NextContext
;
110 KeLockMutex(&ThreadContext
->DeviceExt
->PipeListLock
);
114 CurrentCount
= ThreadContext
->Count
;
115 KeUnlockMutex(&ThreadContext
->DeviceExt
->PipeListLock
);
120 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
121 Irp
->IoStatus
.Information
= 0;
122 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
126 switch (IoStack
->MajorFunction
)
129 NpfsRead(IoStack
->DeviceObject
, Irp
);
140 Status
= KeWaitForMultipleObjects(CurrentCount
,
141 ThreadContext
->WaitObjectArray
,
147 ThreadContext
->WaitBlockArray
);
148 if (!NT_SUCCESS(Status
))
152 KeLockMutex(&ThreadContext
->DeviceExt
->PipeListLock
);
153 Count
= Status
- STATUS_SUCCESS
;
154 ASSERT (Count
< CurrentCount
);
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
];
163 Cancel
= (NULL
== IoSetCancelRoutine(Irp
, NULL
));
164 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
165 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
169 Ccb
= IoStack
->FileObject
->FsContext2
;
170 ExAcquireFastMutex(&Ccb
->DataListLock
);
171 RemoveEntryList(&Context
->ListEntry
);
172 switch (IoStack
->MajorFunction
)
175 if (!IsListEmpty(&Ccb
->ReadRequestListHead
))
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
--;
189 ExReleaseFastMutex(&Ccb
->DataListLock
);
194 /* someone has add a new wait request */
197 if (ThreadContext
->Count
== 1 && ThreadContext
->DeviceExt
->EmptyWaiterCount
>= MAXIMUM_WAIT_OBJECTS
)
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;
205 ExFreePool(ThreadContext
);
209 NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject
,
212 PLIST_ENTRY ListEntry
;
213 PNPFS_THREAD_CONTEXT ThreadContext
= NULL
;
218 PNPFS_CONTEXT Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
219 PNPFS_DEVICE_EXTENSION DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
221 DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
223 KeLockMutex(&DeviceExt
->PipeListLock
);
225 ListEntry
= DeviceExt
->ThreadListHead
.Flink
;
226 while (ListEntry
!= &DeviceExt
->ThreadListHead
)
228 ThreadContext
= CONTAINING_RECORD(ListEntry
, NPFS_THREAD_CONTEXT
, ListEntry
);
229 if (ThreadContext
->Count
< MAXIMUM_WAIT_OBJECTS
)
233 ListEntry
= ListEntry
->Flink
;
235 if (ListEntry
== &DeviceExt
->ThreadListHead
)
237 ThreadContext
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_THREAD_CONTEXT
));
238 if (ThreadContext
== NULL
)
240 KeUnlockMutex(&DeviceExt
->PipeListLock
);
241 return STATUS_NO_MEMORY
;
243 ThreadContext
->DeviceExt
= DeviceExt
;
244 KeInitializeEvent(&ThreadContext
->Event
, SynchronizationEvent
, FALSE
);
245 ThreadContext
->Count
= 1;
246 ThreadContext
->WaitObjectArray
[0] = &ThreadContext
->Event
;
249 DPRINT("Creating a new system thread for waiting read/write requests\n");
251 Status
= PsCreateSystemThread(&hThread
,
257 (PVOID
)ThreadContext
);
258 if (!NT_SUCCESS(Status
))
260 ExFreePool(ThreadContext
);
261 KeUnlockMutex(&DeviceExt
->PipeListLock
);
264 InsertHeadList(&DeviceExt
->ThreadListHead
, &ThreadContext
->ListEntry
);
265 DeviceExt
->EmptyWaiterCount
+= MAXIMUM_WAIT_OBJECTS
- 1;
267 IoMarkIrpPending(Irp
);
269 IoAcquireCancelSpinLock(&oldIrql
);
272 IoReleaseCancelSpinLock(oldIrql
);
273 Status
= STATUS_CANCELLED
;
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
;
286 KeUnlockMutex(&DeviceExt
->PipeListLock
);
291 NpfsRead(IN PDEVICE_OBJECT DeviceObject
,
294 PFILE_OBJECT FileObject
;
296 NTSTATUS OriginalStatus
= STATUS_SUCCESS
;
298 PNPFS_CONTEXT Context
;
301 ULONG Information
= 0;
302 ULONG CopyLength
= 0;
304 BOOLEAN IsOriginalRequest
= TRUE
;
307 DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
309 if (Irp
->MdlAddress
== NULL
)
311 DPRINT("Irp->MdlAddress == NULL\n");
312 Status
= STATUS_UNSUCCESSFUL
;
313 Irp
->IoStatus
.Information
= 0;
317 FileObject
= IoGetCurrentIrpStackLocation(Irp
)->FileObject
;
318 DPRINT("FileObject %p\n", FileObject
);
319 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
320 Ccb
= FileObject
->FsContext2
;
321 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
323 if ((Ccb
->OtherSide
) && (Ccb
->OtherSide
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
) && (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
))
325 DPRINT("Both Client and Server are disconnected!\n");
326 Status
= STATUS_PIPE_DISCONNECTED
;
327 Irp
->IoStatus
.Information
= 0;
332 if ((Ccb
->OtherSide
== NULL
) && (Ccb
->ReadDataAvailable
== 0))
334 if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
336 DPRINT("File pipe broken\n");
337 Status
= STATUS_PIPE_BROKEN
;
339 else if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
340 Status
= STATUS_PIPE_LISTENING
;
341 else if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
342 Status
= STATUS_PIPE_DISCONNECTED
;
344 Status
= STATUS_UNSUCCESSFUL
;
345 Irp
->IoStatus
.Information
= 0;
349 if (Ccb
->Data
== NULL
)
351 DPRINT("Pipe is NOT readable!\n");
352 Status
= STATUS_UNSUCCESSFUL
;
353 Irp
->IoStatus
.Information
= 0;
357 ExAcquireFastMutex(&Ccb
->DataListLock
);
359 if (IoIsOperationSynchronous(Irp
))
361 InsertTailList(&Ccb
->ReadRequestListHead
, &Context
->ListEntry
);
362 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
364 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
365 Context
->WaitEvent
= &Event
;
366 ExReleaseFastMutex(&Ccb
->DataListLock
);
367 Status
= KeWaitForSingleObject(&Event
,
372 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
))
374 Status
= STATUS_CANCELLED
;
377 if (!NT_SUCCESS(Status
))
381 ExAcquireFastMutex(&Ccb
->DataListLock
);
383 Irp
->IoStatus
.Information
= 0;
388 if (IsListEmpty(&Ccb
->ReadRequestListHead
) ||
389 Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
391 /* this is a new request */
392 Irp
->IoStatus
.Information
= 0;
393 Context
->WaitEvent
= &Ccb
->ReadEvent
;
394 InsertTailList(&Ccb
->ReadRequestListHead
, &Context
->ListEntry
);
395 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
397 /* there was already a request on the list */
398 IoAcquireCancelSpinLock(&oldIrql
);
401 IoReleaseCancelSpinLock(oldIrql
);
402 RemoveEntryList(&Context
->ListEntry
);
403 ExReleaseFastMutex(&Ccb
->DataListLock
);
404 Status
= STATUS_CANCELLED
;
407 (void)IoSetCancelRoutine(Irp
, NpfsReadWriteCancelRoutine
);
408 IoReleaseCancelSpinLock(oldIrql
);
409 ExReleaseFastMutex(&Ccb
->DataListLock
);
410 IoMarkIrpPending(Irp
);
411 Status
= STATUS_PENDING
;
419 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
420 Information
= Irp
->IoStatus
.Information
;
421 Length
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
;
422 ASSERT (Information
<= Length
);
423 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Information
);
424 Length
-= Information
;
425 Status
= STATUS_SUCCESS
;
429 if (Ccb
->ReadDataAvailable
== 0)
431 ULONG ConnectionSideReadMode
;
433 if (Ccb
->PipeEnd
== FILE_PIPE_CLIENT_END
) ConnectionSideReadMode
=Ccb
->Fcb
->ClientReadMode
;
434 else ConnectionSideReadMode
= Ccb
->Fcb
->ServerReadMode
;
436 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->OtherSide
))
438 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
440 if (Information
> 0 &&
441 (ConnectionSideReadMode
!= FILE_PIPE_BYTE_STREAM_MODE
||
442 Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
))
446 if ((Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
) && (Ccb
->ReadDataAvailable
== 0))
448 DPRINT("PipeState: %x\n", Ccb
->PipeState
);
449 Status
= STATUS_PIPE_BROKEN
;
452 ExReleaseFastMutex(&Ccb
->DataListLock
);
454 if (IoIsOperationSynchronous(Irp
))
456 /* Wait for ReadEvent to become signaled */
458 DPRINT("Waiting for readable data (%wZ)\n", &Ccb
->Fcb
->PipeName
);
459 Status
= KeWaitForSingleObject(&Ccb
->ReadEvent
,
464 DPRINT("Finished waiting (%wZ)! Status: %x\n", &Ccb
->Fcb
->PipeName
, Status
);
466 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
))
468 Status
= STATUS_CANCELLED
;
471 if (!NT_SUCCESS(Status
))
475 ExAcquireFastMutex(&Ccb
->DataListLock
);
479 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
481 Context
->WaitEvent
= &Ccb
->ReadEvent
;
482 Status
= NpfsAddWaitingReadWriteRequest(DeviceObject
, Irp
);
484 if (NT_SUCCESS(Status
))
486 Status
= STATUS_PENDING
;
489 ExAcquireFastMutex(&Ccb
->DataListLock
);
493 ASSERT(IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
);
495 /* If the pipe type and read mode are both byte stream */
496 if (Ccb
->Fcb
->PipeType
== FILE_PIPE_BYTE_STREAM_TYPE
)
498 DPRINT("Byte stream mode: Ccb->Data %x\n", Ccb
->Data
);
499 /* Byte stream mode */
500 while (Length
> 0 && Ccb
->ReadDataAvailable
> 0)
502 CopyLength
= min(Ccb
->ReadDataAvailable
, Length
);
503 if ((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
<= (ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
)
505 memcpy(Buffer
, Ccb
->ReadPtr
, CopyLength
);
506 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
);
507 if (Ccb
->ReadPtr
== (PVOID
)((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
))
509 Ccb
->ReadPtr
= Ccb
->Data
;
514 TempLength
= (ULONG
)((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
- (ULONG_PTR
)Ccb
->ReadPtr
);
515 memcpy(Buffer
, Ccb
->ReadPtr
, TempLength
);
516 memcpy((PVOID
)((ULONG_PTR
)Buffer
+ TempLength
), Ccb
->Data
, CopyLength
- TempLength
);
517 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->Data
+ CopyLength
- TempLength
);
520 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CopyLength
);
521 Length
-= CopyLength
;
522 Information
+= CopyLength
;
524 Ccb
->ReadDataAvailable
-= CopyLength
;
525 Ccb
->WriteQuotaAvailable
+= CopyLength
;
528 if ((Length
== 0) || (Ccb
->ReadDataAvailable
== 0))
530 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->OtherSide
))
532 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
534 KeResetEvent(&Ccb
->ReadEvent
);
538 else if (Ccb
->Fcb
->PipeType
== FILE_PIPE_MESSAGE_TYPE
)
540 DPRINT("Message mode: Ccb>Data %x\n", Ccb
->Data
);
542 /* Check if buffer is full and the read pointer is not at the start of the buffer */
543 if ((Ccb
->WriteQuotaAvailable
== 0) && (Ccb
->ReadPtr
> Ccb
->Data
))
545 Ccb
->WriteQuotaAvailable
+= (ULONG_PTR
)Ccb
->ReadPtr
- (ULONG_PTR
)Ccb
->Data
;
546 memcpy(Ccb
->Data
, Ccb
->ReadPtr
, (ULONG_PTR
)Ccb
->WritePtr
- (ULONG_PTR
)Ccb
->ReadPtr
);
547 Ccb
->WritePtr
= (PVOID
)((ULONG_PTR
)Ccb
->WritePtr
- ((ULONG_PTR
)Ccb
->ReadPtr
- (ULONG_PTR
)Ccb
->Data
));
548 Ccb
->ReadPtr
= Ccb
->Data
;
549 ASSERT((ULONG_PTR
)Ccb
->WritePtr
< ((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
));
550 ASSERT(Ccb
->WritePtr
>= Ccb
->Data
);
553 /* For Message mode, the Message length is stored in the buffer preceeding the Message. */
554 if (Ccb
->ReadDataAvailable
)
556 ULONG NextMessageLength
= 0;
558 /*First get the size of the message */
559 memcpy(&NextMessageLength
, Ccb
->ReadPtr
, sizeof(NextMessageLength
));
561 if ((NextMessageLength
== 0) || (NextMessageLength
> Ccb
->ReadDataAvailable
))
563 DPRINT1("Possible memory corruption.\n");
564 HexDump(Ccb
->Data
, (ULONG_PTR
)Ccb
->WritePtr
- (ULONG_PTR
)Ccb
->Data
);
568 /* Use the smaller value */
569 CopyLength
= min(NextMessageLength
, Length
);
570 ASSERT(CopyLength
> 0);
571 ASSERT(CopyLength
<= Ccb
->ReadDataAvailable
);
572 /* retrieve the message from the buffer */
573 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ sizeof(NextMessageLength
)), CopyLength
);
575 if (Ccb
->ReadDataAvailable
> CopyLength
)
577 if (CopyLength
< NextMessageLength
)
578 /* Client only requested part of the message */
580 /* Calculate the remaining message new size */
581 ULONG NewMessageSize
= NextMessageLength
-CopyLength
;
583 /* Update ReadPtr to point to new Message size location */
584 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
);
586 /* Write a new Message size to buffer for the part of the message still there */
587 memcpy(Ccb
->ReadPtr
, &NewMessageSize
, sizeof(NewMessageSize
));
590 /* Client wanted the entire message */
592 /* Update ReadPtr to point to next message size */
593 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
+ sizeof(CopyLength
));
598 /* This was the last Message, so just zero start of buffer for safety sake */
599 memset(Ccb
->Data
, 0, NextMessageLength
+ sizeof(NextMessageLength
));
601 /* Reset to MaxDataLength as partial message retrievals dont
602 give the length back to Quota */
603 Ccb
->WriteQuotaAvailable
= Ccb
->MaxDataLength
;
605 /* reset read and write pointer to beginning of buffer */
606 Ccb
->WritePtr
= Ccb
->Data
;
607 Ccb
->ReadPtr
= Ccb
->Data
;
610 DPRINT("Length %d Buffer %x\n",CopyLength
,Buffer
);
611 HexDump((PUCHAR
)Buffer
, CopyLength
);
614 Information
+= CopyLength
;
616 Ccb
->ReadDataAvailable
-= CopyLength
;
618 if ((ULONG
)Ccb
->WriteQuotaAvailable
> (ULONG
)Ccb
->MaxDataLength
) ASSERT(FALSE
);
623 ULONG ConnectionSideReadMode
;
625 if (Ccb
->PipeEnd
== FILE_PIPE_CLIENT_END
) ConnectionSideReadMode
=Ccb
->Fcb
->ClientReadMode
;
626 else ConnectionSideReadMode
= Ccb
->Fcb
->ServerReadMode
;
628 if ((ConnectionSideReadMode
== FILE_PIPE_BYTE_STREAM_MODE
) && (Ccb
->ReadDataAvailable
) && (Length
> CopyLength
))
630 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CopyLength
);
631 Length
-= CopyLength
;
635 KeResetEvent(&Ccb
->ReadEvent
);
637 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->WriteQuotaAvailable
> 0) && (Ccb
->OtherSide
))
639 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
647 DPRINT1("Unhandled Pipe Mode!\n");
651 Irp
->IoStatus
.Information
= Information
;
652 Irp
->IoStatus
.Status
= Status
;
654 ASSERT(IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
);
656 if (Status
== STATUS_CANCELLED
)
659 if (IoIsOperationSynchronous(Irp
))
661 RemoveEntryList(&Context
->ListEntry
);
662 if (!IsListEmpty(&Ccb
->ReadRequestListHead
))
664 Context
= CONTAINING_RECORD(Ccb
->ReadRequestListHead
.Flink
, NPFS_CONTEXT
, ListEntry
);
665 KeSetEvent(Context
->WaitEvent
, IO_NO_INCREMENT
, FALSE
);
667 ExReleaseFastMutex(&Ccb
->DataListLock
);
668 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
670 DPRINT("NpfsRead done (Status %lx)\n", Status
);
677 if (IsOriginalRequest
)
679 IsOriginalRequest
= FALSE
;
680 OriginalStatus
= Status
;
682 if (Status
== STATUS_PENDING
)
684 ExReleaseFastMutex(&Ccb
->DataListLock
);
685 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus
);
686 return OriginalStatus
;
688 RemoveEntryList(&Context
->ListEntry
);
689 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
690 if (IsListEmpty(&Ccb
->ReadRequestListHead
))
692 ExReleaseFastMutex(&Ccb
->DataListLock
);
693 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus
);
694 return OriginalStatus
;
697 IoAcquireCancelSpinLock(&oldIrql
);
698 Context
= CONTAINING_RECORD(Ccb
->ReadRequestListHead
.Flink
, NPFS_CONTEXT
, ListEntry
);
700 Irp
= CONTAINING_RECORD(Context
, IRP
, Tail
.Overlay
.DriverContext
);
701 /* Verify the Irp wasnt cancelled */
704 IoReleaseCancelSpinLock(oldIrql
);
705 RemoveEntryList(&Context
->ListEntry
);
706 ExReleaseFastMutex(&Ccb
->DataListLock
);
707 Status
= STATUS_CANCELLED
;
710 /* The Irp will now be handled, so remove the CancelRoutine */
711 (void)IoSetCancelRoutine(Irp
, NULL
);
712 IoReleaseCancelSpinLock(oldIrql
);
717 Irp
->IoStatus
.Status
= Status
;
719 if (Status
!= STATUS_PENDING
)
721 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
723 DPRINT("NpfsRead done (Status %lx)\n", Status
);
729 NpfsWrite(PDEVICE_OBJECT DeviceObject
,
732 PIO_STACK_LOCATION IoStack
;
733 PFILE_OBJECT FileObject
;
734 PNPFS_FCB Fcb
= NULL
;
735 PNPFS_CCB Ccb
= NULL
;
738 NTSTATUS Status
= STATUS_SUCCESS
;
745 DPRINT("NpfsWrite()\n");
747 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
748 FileObject
= IoStack
->FileObject
;
749 DPRINT("FileObject %p\n", FileObject
);
750 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
752 Ccb
= FileObject
->FsContext2
;
753 ReaderCcb
= Ccb
->OtherSide
;
756 Length
= IoStack
->Parameters
.Write
.Length
;
757 Offset
= IoStack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
760 if (Irp
->MdlAddress
== NULL
)
762 DPRINT("Irp->MdlAddress == NULL\n");
763 Status
= STATUS_UNSUCCESSFUL
;
768 if ((ReaderCcb
== NULL
) || (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
))
770 DPRINT("Pipe is NOT connected!\n");
771 if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
772 Status
= STATUS_PIPE_LISTENING
;
773 else if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
774 Status
= STATUS_PIPE_DISCONNECTED
;
776 Status
= STATUS_UNSUCCESSFUL
;
781 if (ReaderCcb
->Data
== NULL
)
783 DPRINT("Pipe is NOT writable!\n");
784 Status
= STATUS_UNSUCCESSFUL
;
789 Status
= STATUS_SUCCESS
;
790 Buffer
= MmGetSystemAddressForMdl (Irp
->MdlAddress
);
792 ExAcquireFastMutex(&ReaderCcb
->DataListLock
);
795 DPRINT("Length %d Buffer %x Offset %x\n",Length
,Buffer
,Offset
);
796 HexDump(Buffer
, Length
);
801 if ((ReaderCcb
->WriteQuotaAvailable
== 0))
803 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
804 if (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
806 Status
= STATUS_PIPE_BROKEN
;
807 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
810 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
812 DPRINT("Write Waiting for buffer space (%S)\n", Fcb
->PipeName
.Buffer
);
813 Status
= KeWaitForSingleObject(&Ccb
->WriteEvent
,
818 DPRINT("Write Finished waiting (%S)! Status: %x\n", Fcb
->PipeName
.Buffer
, Status
);
820 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
))
822 Status
= STATUS_CANCELLED
;
825 if (!NT_SUCCESS(Status
))
830 * It's possible that the event was signaled because the
831 * other side of pipe was closed.
833 if (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
835 DPRINT("PipeState: %x\n", Ccb
->PipeState
);
836 Status
= STATUS_PIPE_BROKEN
;
839 /* Check that the pipe has not been closed */
840 if (ReaderCcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
)
842 /* If the other side is valid, fire event */
845 KeResetEvent(&Ccb
->WriteEvent
);
847 Status
= STATUS_PIPE_BROKEN
;
850 ExAcquireFastMutex(&ReaderCcb
->DataListLock
);
853 if (Ccb
->Fcb
->PipeType
== FILE_PIPE_BYTE_STREAM_TYPE
)
855 DPRINT("Byte stream mode: Ccb->Data %x, Ccb->WritePtr %x\n", ReaderCcb
->Data
, ReaderCcb
->WritePtr
);
857 while (Length
> 0 && ReaderCcb
->WriteQuotaAvailable
> 0)
859 CopyLength
= min(Length
, ReaderCcb
->WriteQuotaAvailable
);
861 if ((ULONG_PTR
)ReaderCcb
->WritePtr
+ CopyLength
<= (ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
)
863 memcpy(ReaderCcb
->WritePtr
, Buffer
, CopyLength
);
864 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ CopyLength
);
865 if ((ULONG_PTR
)ReaderCcb
->WritePtr
== (ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
)
867 ReaderCcb
->WritePtr
= ReaderCcb
->Data
;
873 TempLength
= (ULONG
)((ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
-
874 (ULONG_PTR
)ReaderCcb
->WritePtr
);
876 memcpy(ReaderCcb
->WritePtr
, Buffer
, TempLength
);
877 memcpy(ReaderCcb
->Data
, Buffer
+ TempLength
, CopyLength
- TempLength
);
878 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->Data
+ CopyLength
- TempLength
);
881 Buffer
+= CopyLength
;
882 Length
-= CopyLength
;
883 Information
+= CopyLength
;
885 ReaderCcb
->ReadDataAvailable
+= CopyLength
;
886 ReaderCcb
->WriteQuotaAvailable
-= CopyLength
;
891 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
892 KeResetEvent(&Ccb
->WriteEvent
);
896 else if (Ccb
->Fcb
->PipeType
== FILE_PIPE_MESSAGE_TYPE
)
898 /* For Message Type Pipe, the Pipes memory will be used to store the size of each message */
899 DPRINT("Message mode: Ccb->Data %x, Ccb->WritePtr %x\n",ReaderCcb
->Data
, ReaderCcb
->WritePtr
);
902 /* Verify the WritePtr is still inside the buffer */
903 if (((ULONG_PTR
)ReaderCcb
->WritePtr
> ((ULONG_PTR
)ReaderCcb
->Data
+ (ULONG_PTR
)ReaderCcb
->MaxDataLength
)) ||
904 ((ULONG_PTR
)ReaderCcb
->WritePtr
< (ULONG_PTR
)ReaderCcb
->Data
))
906 DPRINT1("NPFS is writing out of its buffer. Report to developer!\n");
907 DPRINT1("ReaderCcb->WritePtr %x, ReaderCcb->Data %x, ReaderCcb->MaxDataLength %lu\n",
908 ReaderCcb
->WritePtr
, ReaderCcb
->Data
, ReaderCcb
->MaxDataLength
);
912 CopyLength
= min(Length
, ReaderCcb
->WriteQuotaAvailable
- sizeof(ULONG
));
913 if (CopyLength
> ReaderCcb
->WriteQuotaAvailable
)
915 DPRINT1("Writing %lu byte to pipe would overflow as only %lu bytes are available\n",
916 CopyLength
, ReaderCcb
->WriteQuotaAvailable
);
920 /* First Copy the Length of the message into the pipes buffer */
921 memcpy(ReaderCcb
->WritePtr
, &CopyLength
, sizeof(CopyLength
));
923 /* Now the user buffer itself */
924 memcpy((PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ sizeof(CopyLength
)), Buffer
, CopyLength
);
926 /* Update the write pointer */
927 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ sizeof(CopyLength
) + CopyLength
);
929 Information
+= CopyLength
;
931 ReaderCcb
->ReadDataAvailable
+= CopyLength
;
933 ReaderCcb
->WriteQuotaAvailable
-= (CopyLength
+ sizeof(ULONG
));
935 if ((ULONG_PTR
)ReaderCcb
->WriteQuotaAvailable
> (ULONG
)ReaderCcb
->MaxDataLength
)
937 DPRINT1("QuotaAvailable is greater than buffer size!\n");
944 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
945 KeResetEvent(&Ccb
->WriteEvent
);
951 DPRINT1("Unhandled Pipe Type Mode and Read Write Mode!\n");
956 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
959 Irp
->IoStatus
.Status
= Status
;
960 Irp
->IoStatus
.Information
= Information
;
962 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
964 DPRINT("NpfsWrite done (Status %lx)\n", Status
);