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 PLIST_ENTRY ListEntry
;
55 PNPFS_THREAD_CONTEXT ThreadContext
;
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 ListEntry
= DeviceExt
->ThreadListHead
.Flink
;
73 while (ListEntry
!= &DeviceExt
->ThreadListHead
)
75 ThreadContext
= CONTAINING_RECORD(ListEntry
, NPFS_THREAD_CONTEXT
, ListEntry
);
76 /* Real events start at index 1 */
77 for (i
= 1; i
< ThreadContext
->Count
; i
++)
79 if (ThreadContext
->WaitIrpArray
[i
] == Irp
)
81 ASSERT(ThreadContext
->WaitObjectArray
[i
] == Context
->WaitEvent
);
83 ThreadContext
->WaitIrpArray
[i
] = NULL
;
85 RemoveEntryList(&Context
->ListEntry
);
87 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
88 Irp
->IoStatus
.Information
= 0;
90 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
92 KeSetEvent(&ThreadContext
->Event
, IO_NO_INCREMENT
, FALSE
);
94 ExReleaseFastMutex(&Ccb
->DataListLock
);
95 KeUnlockMutex(&DeviceExt
->PipeListLock
);
100 ListEntry
= ListEntry
->Flink
;
103 RemoveEntryList(&Context
->ListEntry
);
105 ExReleaseFastMutex(&Ccb
->DataListLock
);
106 KeUnlockMutex(&DeviceExt
->PipeListLock
);
108 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
109 Irp
->IoStatus
.Information
= 0;
111 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
119 NpfsWaiterThread(PVOID InitContext
)
121 PNPFS_THREAD_CONTEXT ThreadContext
= (PNPFS_THREAD_CONTEXT
) InitContext
;
126 PIO_STACK_LOCATION IoStack
= NULL
;
129 KeLockMutex(&ThreadContext
->DeviceExt
->PipeListLock
);
133 CurrentCount
= ThreadContext
->Count
;
134 KeUnlockMutex(&ThreadContext
->DeviceExt
->PipeListLock
);
135 IoAcquireCancelSpinLock(&OldIrql
);
136 if (Irp
&& IoSetCancelRoutine(Irp
, NULL
) != NULL
)
138 IoReleaseCancelSpinLock(OldIrql
);
139 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
140 switch (IoStack
->MajorFunction
)
143 NpfsRead(IoStack
->DeviceObject
, Irp
);
151 IoReleaseCancelSpinLock(OldIrql
);
153 Status
= KeWaitForMultipleObjects(CurrentCount
,
154 ThreadContext
->WaitObjectArray
,
160 ThreadContext
->WaitBlockArray
);
161 if (!NT_SUCCESS(Status
))
165 KeLockMutex(&ThreadContext
->DeviceExt
->PipeListLock
);
166 Count
= Status
- STATUS_WAIT_0
;
167 ASSERT (Count
< CurrentCount
);
170 Irp
= ThreadContext
->WaitIrpArray
[Count
];
171 ThreadContext
->Count
--;
172 ThreadContext
->DeviceExt
->EmptyWaiterCount
++;
173 ThreadContext
->WaitObjectArray
[Count
] = ThreadContext
->WaitObjectArray
[ThreadContext
->Count
];
174 ThreadContext
->WaitIrpArray
[Count
] = ThreadContext
->WaitIrpArray
[ThreadContext
->Count
];
178 /* someone has add a new wait request or cancelled an old one */
181 /* Look for cancelled requests */
182 for (i
= 1; i
< ThreadContext
->Count
; i
++)
184 if (ThreadContext
->WaitIrpArray
[i
] == NULL
)
186 ThreadContext
->Count
--;
187 ThreadContext
->DeviceExt
->EmptyWaiterCount
++;
188 ThreadContext
->WaitObjectArray
[i
] = ThreadContext
->WaitObjectArray
[ThreadContext
->Count
];
189 ThreadContext
->WaitIrpArray
[i
] = ThreadContext
->WaitIrpArray
[ThreadContext
->Count
];
193 if (ThreadContext
->Count
== 1 && ThreadContext
->DeviceExt
->EmptyWaiterCount
>= MAXIMUM_WAIT_OBJECTS
)
195 /* it exist an other thread with empty wait slots, we can remove our thread from the list */
196 RemoveEntryList(&ThreadContext
->ListEntry
);
197 ThreadContext
->DeviceExt
->EmptyWaiterCount
-= MAXIMUM_WAIT_OBJECTS
- 1;
198 KeUnlockMutex(&ThreadContext
->DeviceExt
->PipeListLock
);
202 ExFreePool(ThreadContext
);
206 NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject
,
209 PLIST_ENTRY ListEntry
;
210 PNPFS_THREAD_CONTEXT ThreadContext
= NULL
;
215 PNPFS_CONTEXT Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
216 PNPFS_DEVICE_EXTENSION DeviceExt
= (PNPFS_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
218 DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
220 KeLockMutex(&DeviceExt
->PipeListLock
);
222 ListEntry
= DeviceExt
->ThreadListHead
.Flink
;
223 while (ListEntry
!= &DeviceExt
->ThreadListHead
)
225 ThreadContext
= CONTAINING_RECORD(ListEntry
, NPFS_THREAD_CONTEXT
, ListEntry
);
226 if (ThreadContext
->Count
< MAXIMUM_WAIT_OBJECTS
)
230 ListEntry
= ListEntry
->Flink
;
232 if (ListEntry
== &DeviceExt
->ThreadListHead
)
234 ThreadContext
= ExAllocatePool(NonPagedPool
, sizeof(NPFS_THREAD_CONTEXT
));
235 if (ThreadContext
== NULL
)
237 KeUnlockMutex(&DeviceExt
->PipeListLock
);
238 return STATUS_NO_MEMORY
;
240 ThreadContext
->DeviceExt
= DeviceExt
;
241 KeInitializeEvent(&ThreadContext
->Event
, SynchronizationEvent
, FALSE
);
242 ThreadContext
->Count
= 1;
243 ThreadContext
->WaitObjectArray
[0] = &ThreadContext
->Event
;
246 DPRINT("Creating a new system thread for waiting read/write requests\n");
248 Status
= PsCreateSystemThread(&hThread
,
254 (PVOID
)ThreadContext
);
255 if (!NT_SUCCESS(Status
))
257 ExFreePool(ThreadContext
);
258 KeUnlockMutex(&DeviceExt
->PipeListLock
);
261 InsertHeadList(&DeviceExt
->ThreadListHead
, &ThreadContext
->ListEntry
);
262 DeviceExt
->EmptyWaiterCount
+= MAXIMUM_WAIT_OBJECTS
- 1;
264 IoMarkIrpPending(Irp
);
266 IoAcquireCancelSpinLock(&oldIrql
);
269 IoReleaseCancelSpinLock(oldIrql
);
270 Status
= STATUS_CANCELLED
;
274 (void)IoSetCancelRoutine(Irp
, NpfsReadWriteCancelRoutine
);
275 IoReleaseCancelSpinLock(oldIrql
);
276 ThreadContext
->WaitObjectArray
[ThreadContext
->Count
] = Context
->WaitEvent
;
277 ThreadContext
->WaitIrpArray
[ThreadContext
->Count
] = Irp
;
278 ThreadContext
->Count
++;
279 DeviceExt
->EmptyWaiterCount
--;
280 KeSetEvent(&ThreadContext
->Event
, IO_NO_INCREMENT
, FALSE
);
281 Status
= STATUS_SUCCESS
;
283 KeUnlockMutex(&DeviceExt
->PipeListLock
);
288 NpfsRead(IN PDEVICE_OBJECT DeviceObject
,
291 PFILE_OBJECT FileObject
;
293 NTSTATUS OriginalStatus
= STATUS_SUCCESS
;
295 PNPFS_CONTEXT Context
;
298 ULONG Information
= 0;
299 ULONG CopyLength
= 0;
301 BOOLEAN IsOriginalRequest
= TRUE
;
304 DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
306 if (Irp
->MdlAddress
== NULL
)
308 DPRINT("Irp->MdlAddress == NULL\n");
309 Status
= STATUS_UNSUCCESSFUL
;
310 Irp
->IoStatus
.Information
= 0;
314 FileObject
= IoGetCurrentIrpStackLocation(Irp
)->FileObject
;
315 DPRINT("FileObject %p\n", FileObject
);
316 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
317 Ccb
= FileObject
->FsContext2
;
318 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
320 if ((Ccb
->OtherSide
) && (Ccb
->OtherSide
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
) && (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
))
322 DPRINT("Both Client and Server are disconnected!\n");
323 Status
= STATUS_PIPE_DISCONNECTED
;
324 Irp
->IoStatus
.Information
= 0;
329 if ((Ccb
->OtherSide
== NULL
) && (Ccb
->ReadDataAvailable
== 0))
331 if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
332 Status
= STATUS_PIPE_BROKEN
;
333 else if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
334 Status
= STATUS_PIPE_LISTENING
;
335 else if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
336 Status
= STATUS_PIPE_DISCONNECTED
;
338 Status
= STATUS_UNSUCCESSFUL
;
339 Irp
->IoStatus
.Information
= 0;
343 if (Ccb
->Data
== NULL
)
345 DPRINT("Pipe is NOT readable!\n");
346 Status
= STATUS_UNSUCCESSFUL
;
347 Irp
->IoStatus
.Information
= 0;
351 ExAcquireFastMutex(&Ccb
->DataListLock
);
353 if (IoIsOperationSynchronous(Irp
))
355 InsertTailList(&Ccb
->ReadRequestListHead
, &Context
->ListEntry
);
356 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
358 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
359 Context
->WaitEvent
= &Event
;
360 ExReleaseFastMutex(&Ccb
->DataListLock
);
361 Status
= KeWaitForSingleObject(&Event
,
366 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
))
368 Status
= STATUS_CANCELLED
;
371 if (!NT_SUCCESS(Status
))
375 ExAcquireFastMutex(&Ccb
->DataListLock
);
377 Irp
->IoStatus
.Information
= 0;
382 if (IsListEmpty(&Ccb
->ReadRequestListHead
) ||
383 Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
385 /* this is a new request */
386 Irp
->IoStatus
.Information
= 0;
387 Context
->WaitEvent
= &Ccb
->ReadEvent
;
388 InsertTailList(&Ccb
->ReadRequestListHead
, &Context
->ListEntry
);
389 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
391 /* there was already a request on the list */
392 IoAcquireCancelSpinLock(&oldIrql
);
395 IoReleaseCancelSpinLock(oldIrql
);
396 RemoveEntryList(&Context
->ListEntry
);
397 ExReleaseFastMutex(&Ccb
->DataListLock
);
398 Status
= STATUS_CANCELLED
;
401 (void)IoSetCancelRoutine(Irp
, NpfsReadWriteCancelRoutine
);
402 IoReleaseCancelSpinLock(oldIrql
);
403 ExReleaseFastMutex(&Ccb
->DataListLock
);
404 IoMarkIrpPending(Irp
);
405 Status
= STATUS_PENDING
;
413 Buffer
= MmGetSystemAddressForMdl(Irp
->MdlAddress
);
414 Information
= Irp
->IoStatus
.Information
;
415 Length
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
;
416 ASSERT (Information
<= Length
);
417 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Information
);
418 Length
-= Information
;
419 Status
= STATUS_SUCCESS
;
423 if (Ccb
->ReadDataAvailable
== 0)
425 ULONG ConnectionSideReadMode
;
427 if (Ccb
->PipeEnd
== FILE_PIPE_CLIENT_END
) ConnectionSideReadMode
=Ccb
->Fcb
->ClientReadMode
;
428 else ConnectionSideReadMode
= Ccb
->Fcb
->ServerReadMode
;
430 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->OtherSide
))
432 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
434 if (Information
> 0 &&
435 (ConnectionSideReadMode
!= FILE_PIPE_BYTE_STREAM_MODE
||
436 Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
))
440 if (((Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
) || (!Ccb
->OtherSide
)) && (Ccb
->ReadDataAvailable
== 0))
442 DPRINT("PipeState: %x\n", Ccb
->PipeState
);
443 Status
= STATUS_PIPE_BROKEN
;
446 ExReleaseFastMutex(&Ccb
->DataListLock
);
448 if (IoIsOperationSynchronous(Irp
))
450 /* Wait for ReadEvent to become signaled */
452 DPRINT("Waiting for readable data (%wZ)\n", &Ccb
->Fcb
->PipeName
);
453 Status
= KeWaitForSingleObject(&Ccb
->ReadEvent
,
458 DPRINT("Finished waiting (%wZ)! Status: %x\n", &Ccb
->Fcb
->PipeName
, Status
);
460 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
))
462 Status
= STATUS_CANCELLED
;
465 if (!NT_SUCCESS(Status
))
469 ExAcquireFastMutex(&Ccb
->DataListLock
);
473 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
475 Context
->WaitEvent
= &Ccb
->ReadEvent
;
476 Status
= NpfsAddWaitingReadWriteRequest(DeviceObject
, Irp
);
478 if (NT_SUCCESS(Status
))
480 Status
= STATUS_PENDING
;
483 ExAcquireFastMutex(&Ccb
->DataListLock
);
487 ASSERT(IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
);
489 /* If the pipe type and read mode are both byte stream */
490 if (Ccb
->Fcb
->PipeType
== FILE_PIPE_BYTE_STREAM_TYPE
)
492 DPRINT("Byte stream mode: Ccb->Data %x\n", Ccb
->Data
);
493 /* Byte stream mode */
494 while (Length
> 0 && Ccb
->ReadDataAvailable
> 0)
496 CopyLength
= min(Ccb
->ReadDataAvailable
, Length
);
497 if ((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
<= (ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
)
499 memcpy(Buffer
, Ccb
->ReadPtr
, CopyLength
);
500 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
);
501 if (Ccb
->ReadPtr
== (PVOID
)((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
))
503 Ccb
->ReadPtr
= Ccb
->Data
;
508 TempLength
= (ULONG
)((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
- (ULONG_PTR
)Ccb
->ReadPtr
);
509 memcpy(Buffer
, Ccb
->ReadPtr
, TempLength
);
510 memcpy((PVOID
)((ULONG_PTR
)Buffer
+ TempLength
), Ccb
->Data
, CopyLength
- TempLength
);
511 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->Data
+ CopyLength
- TempLength
);
514 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CopyLength
);
515 Length
-= CopyLength
;
516 Information
+= CopyLength
;
518 Ccb
->ReadDataAvailable
-= CopyLength
;
519 Ccb
->WriteQuotaAvailable
+= CopyLength
;
522 if ((Length
== 0) || (Ccb
->ReadDataAvailable
== 0))
524 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->OtherSide
))
526 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
528 KeResetEvent(&Ccb
->ReadEvent
);
532 else if (Ccb
->Fcb
->PipeType
== FILE_PIPE_MESSAGE_TYPE
)
534 DPRINT("Message mode: Ccb>Data %x\n", Ccb
->Data
);
536 /* Check if buffer is full and the read pointer is not at the start of the buffer */
537 if ((Ccb
->WriteQuotaAvailable
== 0) && (Ccb
->ReadPtr
> Ccb
->Data
))
539 Ccb
->WriteQuotaAvailable
+= (ULONG_PTR
)Ccb
->ReadPtr
- (ULONG_PTR
)Ccb
->Data
;
540 memcpy(Ccb
->Data
, Ccb
->ReadPtr
, (ULONG_PTR
)Ccb
->WritePtr
- (ULONG_PTR
)Ccb
->ReadPtr
);
541 Ccb
->WritePtr
= (PVOID
)((ULONG_PTR
)Ccb
->WritePtr
- ((ULONG_PTR
)Ccb
->ReadPtr
- (ULONG_PTR
)Ccb
->Data
));
542 Ccb
->ReadPtr
= Ccb
->Data
;
543 ASSERT((ULONG_PTR
)Ccb
->WritePtr
< ((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
));
544 ASSERT(Ccb
->WritePtr
>= Ccb
->Data
);
547 /* For Message mode, the Message length is stored in the buffer preceeding the Message. */
548 if (Ccb
->ReadDataAvailable
)
550 ULONG NextMessageLength
= 0;
552 /*First get the size of the message */
553 memcpy(&NextMessageLength
, Ccb
->ReadPtr
, sizeof(NextMessageLength
));
555 if ((NextMessageLength
== 0) || (NextMessageLength
> Ccb
->ReadDataAvailable
))
557 DPRINT1("Possible memory corruption.\n");
558 HexDump(Ccb
->Data
, (ULONG_PTR
)Ccb
->WritePtr
- (ULONG_PTR
)Ccb
->Data
);
562 /* Use the smaller value */
563 CopyLength
= min(NextMessageLength
, Length
);
564 ASSERT(CopyLength
> 0);
565 ASSERT(CopyLength
<= Ccb
->ReadDataAvailable
);
566 /* retrieve the message from the buffer */
567 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ sizeof(NextMessageLength
)), CopyLength
);
569 if (Ccb
->ReadDataAvailable
> CopyLength
)
571 if (CopyLength
< NextMessageLength
)
572 /* Client only requested part of the message */
574 /* Calculate the remaining message new size */
575 ULONG NewMessageSize
= NextMessageLength
-CopyLength
;
577 /* Update ReadPtr to point to new Message size location */
578 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
);
580 /* Write a new Message size to buffer for the part of the message still there */
581 memcpy(Ccb
->ReadPtr
, &NewMessageSize
, sizeof(NewMessageSize
));
584 /* Client wanted the entire message */
586 /* Update ReadPtr to point to next message size */
587 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
+ sizeof(CopyLength
));
592 /* This was the last Message, so just zero start of buffer for safety sake */
593 memset(Ccb
->Data
, 0, NextMessageLength
+ sizeof(NextMessageLength
));
595 /* Reset to MaxDataLength as partial message retrievals dont
596 give the length back to Quota */
597 Ccb
->WriteQuotaAvailable
= Ccb
->MaxDataLength
;
599 /* reset read and write pointer to beginning of buffer */
600 Ccb
->WritePtr
= Ccb
->Data
;
601 Ccb
->ReadPtr
= Ccb
->Data
;
604 DPRINT("Length %d Buffer %x\n",CopyLength
,Buffer
);
605 HexDump((PUCHAR
)Buffer
, CopyLength
);
608 Information
+= CopyLength
;
610 Ccb
->ReadDataAvailable
-= CopyLength
;
612 if ((ULONG
)Ccb
->WriteQuotaAvailable
> (ULONG
)Ccb
->MaxDataLength
) ASSERT(FALSE
);
617 ULONG ConnectionSideReadMode
;
619 if (Ccb
->PipeEnd
== FILE_PIPE_CLIENT_END
) ConnectionSideReadMode
=Ccb
->Fcb
->ClientReadMode
;
620 else ConnectionSideReadMode
= Ccb
->Fcb
->ServerReadMode
;
622 if ((ConnectionSideReadMode
== FILE_PIPE_BYTE_STREAM_MODE
) && (Ccb
->ReadDataAvailable
) && (Length
> CopyLength
))
624 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CopyLength
);
625 Length
-= CopyLength
;
629 KeResetEvent(&Ccb
->ReadEvent
);
631 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->WriteQuotaAvailable
> 0) && (Ccb
->OtherSide
))
633 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
641 DPRINT1("Unhandled Pipe Mode!\n");
645 Irp
->IoStatus
.Information
= Information
;
646 Irp
->IoStatus
.Status
= Status
;
648 ASSERT(IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
);
650 if (Status
== STATUS_CANCELLED
)
653 if (IoIsOperationSynchronous(Irp
))
655 RemoveEntryList(&Context
->ListEntry
);
656 if (!IsListEmpty(&Ccb
->ReadRequestListHead
))
658 Context
= CONTAINING_RECORD(Ccb
->ReadRequestListHead
.Flink
, NPFS_CONTEXT
, ListEntry
);
659 KeSetEvent(Context
->WaitEvent
, IO_NO_INCREMENT
, FALSE
);
661 ExReleaseFastMutex(&Ccb
->DataListLock
);
662 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
664 DPRINT("NpfsRead done (Status %lx)\n", Status
);
671 if (IsOriginalRequest
)
673 IsOriginalRequest
= FALSE
;
674 OriginalStatus
= Status
;
676 if (Status
== STATUS_PENDING
)
678 ExReleaseFastMutex(&Ccb
->DataListLock
);
679 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus
);
680 return OriginalStatus
;
682 RemoveEntryList(&Context
->ListEntry
);
683 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
684 if (IsListEmpty(&Ccb
->ReadRequestListHead
))
686 ExReleaseFastMutex(&Ccb
->DataListLock
);
687 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus
);
688 return OriginalStatus
;
691 IoAcquireCancelSpinLock(&oldIrql
);
692 Context
= CONTAINING_RECORD(Ccb
->ReadRequestListHead
.Flink
, NPFS_CONTEXT
, ListEntry
);
694 Irp
= CONTAINING_RECORD(Context
, IRP
, Tail
.Overlay
.DriverContext
);
695 /* Verify the Irp wasnt cancelled */
698 IoReleaseCancelSpinLock(oldIrql
);
699 RemoveEntryList(&Context
->ListEntry
);
700 ExReleaseFastMutex(&Ccb
->DataListLock
);
701 Status
= STATUS_CANCELLED
;
704 /* The Irp will now be handled, so remove the CancelRoutine */
705 (void)IoSetCancelRoutine(Irp
, NULL
);
706 IoReleaseCancelSpinLock(oldIrql
);
711 Irp
->IoStatus
.Status
= Status
;
713 if (Status
!= STATUS_PENDING
)
715 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
717 DPRINT("NpfsRead done (Status %lx)\n", Status
);
723 NpfsWrite(PDEVICE_OBJECT DeviceObject
,
726 PIO_STACK_LOCATION IoStack
;
727 PFILE_OBJECT FileObject
;
728 PNPFS_FCB Fcb
= NULL
;
729 PNPFS_CCB Ccb
= NULL
;
732 NTSTATUS Status
= STATUS_SUCCESS
;
739 DPRINT("NpfsWrite()\n");
741 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
742 FileObject
= IoStack
->FileObject
;
743 DPRINT("FileObject %p\n", FileObject
);
744 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
746 Ccb
= FileObject
->FsContext2
;
747 ReaderCcb
= Ccb
->OtherSide
;
750 Length
= IoStack
->Parameters
.Write
.Length
;
751 Offset
= IoStack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
754 if (Irp
->MdlAddress
== NULL
)
756 DPRINT("Irp->MdlAddress == NULL\n");
757 Status
= STATUS_UNSUCCESSFUL
;
762 if ((ReaderCcb
== NULL
) || (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
))
764 DPRINT("Pipe is NOT connected!\n");
765 if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
766 Status
= STATUS_PIPE_LISTENING
;
767 else if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
768 Status
= STATUS_PIPE_DISCONNECTED
;
770 Status
= STATUS_UNSUCCESSFUL
;
775 if (ReaderCcb
->Data
== NULL
)
777 DPRINT("Pipe is NOT writable!\n");
778 Status
= STATUS_UNSUCCESSFUL
;
783 Status
= STATUS_SUCCESS
;
784 Buffer
= MmGetSystemAddressForMdlSafe (Irp
->MdlAddress
, NormalPagePriority
);
788 DPRINT("MmGetSystemAddressForMdlSafe failed\n");
789 Status
= STATUS_INSUFFICIENT_RESOURCES
;
795 ExAcquireFastMutex(&ReaderCcb
->DataListLock
);
798 DPRINT("Length %d Buffer %x Offset %x\n",Length
,Buffer
,Offset
);
799 HexDump(Buffer
, Length
);
804 if ((ReaderCcb
->WriteQuotaAvailable
== 0))
806 if (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
|| !Ccb
->OtherSide
)
808 Status
= STATUS_PIPE_BROKEN
;
809 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
812 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
813 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
815 DPRINT("Write Waiting for buffer space (%S)\n", Fcb
->PipeName
.Buffer
);
816 Status
= KeWaitForSingleObject(&Ccb
->WriteEvent
,
821 DPRINT("Write Finished waiting (%S)! Status: %x\n", Fcb
->PipeName
.Buffer
, Status
);
823 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
))
825 Status
= STATUS_CANCELLED
;
828 if (!NT_SUCCESS(Status
))
833 * It's possible that the event was signaled because the
834 * other side of pipe was closed.
836 if (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
|| !Ccb
->OtherSide
)
838 DPRINT("PipeState: %x\n", Ccb
->PipeState
);
839 Status
= STATUS_PIPE_BROKEN
;
842 /* Check that the pipe has not been closed */
843 if (ReaderCcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
|| !ReaderCcb
->OtherSide
)
845 Status
= STATUS_PIPE_BROKEN
;
848 ExAcquireFastMutex(&ReaderCcb
->DataListLock
);
851 if (Ccb
->Fcb
->PipeType
== FILE_PIPE_BYTE_STREAM_TYPE
)
853 DPRINT("Byte stream mode: Ccb->Data %x, Ccb->WritePtr %x\n", ReaderCcb
->Data
, ReaderCcb
->WritePtr
);
855 while (Length
> 0 && ReaderCcb
->WriteQuotaAvailable
> 0)
857 CopyLength
= min(Length
, ReaderCcb
->WriteQuotaAvailable
);
859 if ((ULONG_PTR
)ReaderCcb
->WritePtr
+ CopyLength
<= (ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
)
861 memcpy(ReaderCcb
->WritePtr
, Buffer
, CopyLength
);
862 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ CopyLength
);
863 if ((ULONG_PTR
)ReaderCcb
->WritePtr
== (ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
)
865 ReaderCcb
->WritePtr
= ReaderCcb
->Data
;
871 TempLength
= (ULONG
)((ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
-
872 (ULONG_PTR
)ReaderCcb
->WritePtr
);
874 memcpy(ReaderCcb
->WritePtr
, Buffer
, TempLength
);
875 memcpy(ReaderCcb
->Data
, Buffer
+ TempLength
, CopyLength
- TempLength
);
876 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->Data
+ CopyLength
- TempLength
);
879 Buffer
+= CopyLength
;
880 Length
-= CopyLength
;
881 Information
+= CopyLength
;
883 ReaderCcb
->ReadDataAvailable
+= CopyLength
;
884 ReaderCcb
->WriteQuotaAvailable
-= CopyLength
;
889 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
890 KeResetEvent(&Ccb
->WriteEvent
);
894 else if (Ccb
->Fcb
->PipeType
== FILE_PIPE_MESSAGE_TYPE
)
896 /* For Message Type Pipe, the Pipes memory will be used to store the size of each message */
897 DPRINT("Message mode: Ccb->Data %x, Ccb->WritePtr %x\n",ReaderCcb
->Data
, ReaderCcb
->WritePtr
);
900 /* Verify the WritePtr is still inside the buffer */
901 if (((ULONG_PTR
)ReaderCcb
->WritePtr
> ((ULONG_PTR
)ReaderCcb
->Data
+ (ULONG_PTR
)ReaderCcb
->MaxDataLength
)) ||
902 ((ULONG_PTR
)ReaderCcb
->WritePtr
< (ULONG_PTR
)ReaderCcb
->Data
))
904 DPRINT1("NPFS is writing out of its buffer. Report to developer!\n");
905 DPRINT1("ReaderCcb->WritePtr %x, ReaderCcb->Data %x, ReaderCcb->MaxDataLength %lu\n",
906 ReaderCcb
->WritePtr
, ReaderCcb
->Data
, ReaderCcb
->MaxDataLength
);
910 CopyLength
= min(Length
, ReaderCcb
->WriteQuotaAvailable
- sizeof(ULONG
));
911 if (CopyLength
> ReaderCcb
->WriteQuotaAvailable
)
913 DPRINT1("Writing %lu byte to pipe would overflow as only %lu bytes are available\n",
914 CopyLength
, ReaderCcb
->WriteQuotaAvailable
);
918 /* First Copy the Length of the message into the pipes buffer */
919 memcpy(ReaderCcb
->WritePtr
, &CopyLength
, sizeof(CopyLength
));
921 /* Now the user buffer itself */
922 memcpy((PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ sizeof(CopyLength
)), Buffer
, CopyLength
);
924 /* Update the write pointer */
925 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ sizeof(CopyLength
) + CopyLength
);
927 Information
+= CopyLength
;
929 ReaderCcb
->ReadDataAvailable
+= CopyLength
;
931 ReaderCcb
->WriteQuotaAvailable
-= (CopyLength
+ sizeof(ULONG
));
933 if ((ULONG_PTR
)ReaderCcb
->WriteQuotaAvailable
> (ULONG
)ReaderCcb
->MaxDataLength
)
935 DPRINT1("QuotaAvailable is greater than buffer size!\n");
942 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
943 KeResetEvent(&Ccb
->WriteEvent
);
949 DPRINT1("Unhandled Pipe Type Mode and Read Write Mode!\n");
954 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
957 Irp
->IoStatus
.Status
= Status
;
958 Irp
->IoStatus
.Information
= Information
;
960 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
962 DPRINT("NpfsWrite done (Status %lx)\n", Status
);