2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: drivers/filesystems/npfs/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 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 Vcb
= (PNPFS_VCB
)DeviceObject
->DeviceExtension
;
64 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
65 Ccb
= IoStack
->FileObject
->FsContext2
;
67 KeLockMutex(&Vcb
->PipeListLock
);
68 ExAcquireFastMutex(&Ccb
->DataListLock
);
69 switch(IoStack
->MajorFunction
)
72 ListEntry
= Vcb
->ThreadListHead
.Flink
;
73 while (ListEntry
!= &Vcb
->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(&Vcb
->PipeListLock
);
100 ListEntry
= ListEntry
->Flink
;
103 RemoveEntryList(&Context
->ListEntry
);
105 ExReleaseFastMutex(&Ccb
->DataListLock
);
106 KeUnlockMutex(&Vcb
->PipeListLock
);
108 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
109 Irp
->IoStatus
.Information
= 0;
111 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
118 static KSTART_ROUTINE NpfsWaiterThread
;
120 NpfsWaiterThread(PVOID InitContext
)
122 PNPFS_THREAD_CONTEXT ThreadContext
= (PNPFS_THREAD_CONTEXT
) InitContext
;
127 PIO_STACK_LOCATION IoStack
= NULL
;
130 KeLockMutex(&ThreadContext
->Vcb
->PipeListLock
);
134 CurrentCount
= ThreadContext
->Count
;
135 KeUnlockMutex(&ThreadContext
->Vcb
->PipeListLock
);
136 IoAcquireCancelSpinLock(&OldIrql
);
137 if (Irp
&& IoSetCancelRoutine(Irp
, NULL
) != NULL
)
139 IoReleaseCancelSpinLock(OldIrql
);
140 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
141 switch (IoStack
->MajorFunction
)
144 NpfsRead(IoStack
->DeviceObject
, Irp
);
152 IoReleaseCancelSpinLock(OldIrql
);
154 Status
= KeWaitForMultipleObjects(CurrentCount
,
155 ThreadContext
->WaitObjectArray
,
161 ThreadContext
->WaitBlockArray
);
162 if (!NT_SUCCESS(Status
))
166 KeLockMutex(&ThreadContext
->Vcb
->PipeListLock
);
167 Count
= Status
- STATUS_WAIT_0
;
168 ASSERT (Count
< CurrentCount
);
171 Irp
= ThreadContext
->WaitIrpArray
[Count
];
172 ThreadContext
->Count
--;
173 ThreadContext
->Vcb
->EmptyWaiterCount
++;
174 ThreadContext
->WaitObjectArray
[Count
] = ThreadContext
->WaitObjectArray
[ThreadContext
->Count
];
175 ThreadContext
->WaitIrpArray
[Count
] = ThreadContext
->WaitIrpArray
[ThreadContext
->Count
];
179 /* someone has added a new wait request or cancelled an old one */
182 /* Look for cancelled requests */
183 for (i
= 1; i
< ThreadContext
->Count
; i
++)
185 if (ThreadContext
->WaitIrpArray
[i
] == NULL
)
187 ThreadContext
->Count
--;
188 ThreadContext
->Vcb
->EmptyWaiterCount
++;
189 ThreadContext
->WaitObjectArray
[i
] = ThreadContext
->WaitObjectArray
[ThreadContext
->Count
];
190 ThreadContext
->WaitIrpArray
[i
] = ThreadContext
->WaitIrpArray
[ThreadContext
->Count
];
194 if (ThreadContext
->Count
== 1 && ThreadContext
->Vcb
->EmptyWaiterCount
>= MAXIMUM_WAIT_OBJECTS
)
196 /* there is another thread with empty wait slots, we can remove our thread from the list */
197 RemoveEntryList(&ThreadContext
->ListEntry
);
198 ExFreePoolWithTag(ThreadContext
, TAG_NPFS_THREAD_CONTEXT
);
199 KeUnlockMutex(&ThreadContext
->Vcb
->PipeListLock
);
206 NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject
,
209 PLIST_ENTRY ListEntry
;
210 PNPFS_THREAD_CONTEXT ThreadContext
= NULL
;
211 PNPFS_CONTEXT Context
;
217 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
218 Vcb
= (PNPFS_VCB
)DeviceObject
->DeviceExtension
;
220 DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
222 KeLockMutex(&Vcb
->PipeListLock
);
224 ListEntry
= Vcb
->ThreadListHead
.Flink
;
225 while (ListEntry
!= &Vcb
->ThreadListHead
)
227 ThreadContext
= CONTAINING_RECORD(ListEntry
, NPFS_THREAD_CONTEXT
, ListEntry
);
228 if (ThreadContext
->Count
< MAXIMUM_WAIT_OBJECTS
)
232 ListEntry
= ListEntry
->Flink
;
235 if (ListEntry
== &Vcb
->ThreadListHead
)
237 ThreadContext
= ExAllocatePoolWithTag(NonPagedPool
,
238 sizeof(NPFS_THREAD_CONTEXT
),
239 TAG_NPFS_THREAD_CONTEXT
);
240 if (ThreadContext
== NULL
)
242 KeUnlockMutex(&Vcb
->PipeListLock
);
243 return STATUS_NO_MEMORY
;
246 ThreadContext
->Vcb
= Vcb
;
247 KeInitializeEvent(&ThreadContext
->Event
, SynchronizationEvent
, FALSE
);
248 ThreadContext
->Count
= 1;
249 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 ExFreePoolWithTag(ThreadContext
, TAG_NPFS_THREAD_CONTEXT
);
263 KeUnlockMutex(&Vcb
->PipeListLock
);
267 InsertHeadList(&Vcb
->ThreadListHead
, &ThreadContext
->ListEntry
);
268 Vcb
->EmptyWaiterCount
+= MAXIMUM_WAIT_OBJECTS
- 1;
270 IoMarkIrpPending(Irp
);
272 IoAcquireCancelSpinLock(&oldIrql
);
275 IoReleaseCancelSpinLock(oldIrql
);
276 Status
= STATUS_CANCELLED
;
280 (void)IoSetCancelRoutine(Irp
, NpfsReadWriteCancelRoutine
);
281 IoReleaseCancelSpinLock(oldIrql
);
282 ThreadContext
->WaitObjectArray
[ThreadContext
->Count
] = Context
->WaitEvent
;
283 ThreadContext
->WaitIrpArray
[ThreadContext
->Count
] = Irp
;
284 ThreadContext
->Count
++;
285 Vcb
->EmptyWaiterCount
--;
286 KeSetEvent(&ThreadContext
->Event
, IO_NO_INCREMENT
, FALSE
);
287 Status
= STATUS_SUCCESS
;
289 KeUnlockMutex(&Vcb
->PipeListLock
);
294 NpfsRead(IN PDEVICE_OBJECT DeviceObject
,
297 PFILE_OBJECT FileObject
;
299 NTSTATUS OriginalStatus
= STATUS_SUCCESS
;
301 PNPFS_CONTEXT Context
;
304 ULONG Information
= 0;
305 ULONG CopyLength
= 0;
307 BOOLEAN IsOriginalRequest
= TRUE
;
310 DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
312 FileObject
= IoGetCurrentIrpStackLocation(Irp
)->FileObject
;
313 DPRINT("FileObject %p\n", FileObject
);
314 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
315 Ccb
= FileObject
->FsContext2
;
317 /* Fail, if the CCB is not a pipe CCB */
318 if (Ccb
->Type
!= CCB_PIPE
)
320 DPRINT("Not a pipe!\n");
321 Status
= STATUS_INVALID_PARAMETER
;
322 Irp
->IoStatus
.Information
= 0;
326 if (Irp
->MdlAddress
== NULL
)
328 DPRINT("Irp->MdlAddress == NULL\n");
329 Status
= STATUS_UNSUCCESSFUL
;
330 Irp
->IoStatus
.Information
= 0;
334 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
336 if ((Ccb
->OtherSide
) && (Ccb
->OtherSide
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
) && (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
))
338 DPRINT("Both Client and Server are disconnected!\n");
339 Status
= STATUS_PIPE_DISCONNECTED
;
340 Irp
->IoStatus
.Information
= 0;
345 if ((Ccb
->OtherSide
== NULL
) && (Ccb
->ReadDataAvailable
== 0))
347 if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
348 Status
= STATUS_PIPE_BROKEN
;
349 else if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
350 Status
= STATUS_PIPE_LISTENING
;
351 else if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
352 Status
= STATUS_PIPE_DISCONNECTED
;
354 Status
= STATUS_UNSUCCESSFUL
;
355 Irp
->IoStatus
.Information
= 0;
359 if (Ccb
->Data
== NULL
)
361 DPRINT("Pipe is NOT readable!\n");
362 Status
= STATUS_UNSUCCESSFUL
;
363 Irp
->IoStatus
.Information
= 0;
367 ExAcquireFastMutex(&Ccb
->DataListLock
);
369 if (IoIsOperationSynchronous(Irp
))
371 InsertTailList(&Ccb
->ReadRequestListHead
, &Context
->ListEntry
);
372 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
374 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
375 Context
->WaitEvent
= &Event
;
376 ExReleaseFastMutex(&Ccb
->DataListLock
);
377 KeWaitForSingleObject(&Event
,
382 ExAcquireFastMutex(&Ccb
->DataListLock
);
384 Irp
->IoStatus
.Information
= 0;
389 if (IsListEmpty(&Ccb
->ReadRequestListHead
) ||
390 Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
392 /* this is a new request */
393 Irp
->IoStatus
.Information
= 0;
394 Context
->WaitEvent
= &Ccb
->ReadEvent
;
395 InsertTailList(&Ccb
->ReadRequestListHead
, &Context
->ListEntry
);
396 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
398 /* there was already a request on the list */
399 IoAcquireCancelSpinLock(&oldIrql
);
402 IoReleaseCancelSpinLock(oldIrql
);
403 RemoveEntryList(&Context
->ListEntry
);
404 ExReleaseFastMutex(&Ccb
->DataListLock
);
405 Status
= STATUS_CANCELLED
;
408 (void)IoSetCancelRoutine(Irp
, NpfsReadWriteCancelRoutine
);
409 IoReleaseCancelSpinLock(oldIrql
);
410 ExReleaseFastMutex(&Ccb
->DataListLock
);
411 IoMarkIrpPending(Irp
);
412 Status
= STATUS_PENDING
;
420 Buffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
,
422 Information
= Irp
->IoStatus
.Information
;
423 Length
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
;
424 ASSERT(Information
<= Length
);
425 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Information
);
426 Length
-= Information
;
427 Status
= STATUS_SUCCESS
;
431 if (Ccb
->ReadDataAvailable
== 0)
433 ULONG ConnectionSideReadMode
;
435 if (Ccb
->PipeEnd
== FILE_PIPE_CLIENT_END
) ConnectionSideReadMode
=Ccb
->Fcb
->ClientReadMode
;
436 else ConnectionSideReadMode
= Ccb
->Fcb
->ServerReadMode
;
438 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->OtherSide
))
440 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
442 if (Information
> 0 &&
443 (ConnectionSideReadMode
!= FILE_PIPE_BYTE_STREAM_MODE
||
444 Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
))
448 ASSERT(Ccb
->ReadDataAvailable
== 0);
449 if ((Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
) || (!Ccb
->OtherSide
))
451 DPRINT("PipeState: %x\n", Ccb
->PipeState
);
452 Status
= STATUS_PIPE_BROKEN
;
455 ExReleaseFastMutex(&Ccb
->DataListLock
);
457 if (IoIsOperationSynchronous(Irp
))
459 /* Wait for ReadEvent to become signaled */
461 DPRINT("Waiting for readable data (%wZ)\n", &Ccb
->Fcb
->PipeName
);
462 Status
= KeWaitForSingleObject(&Ccb
->ReadEvent
,
465 (FileObject
->Flags
& FO_ALERTABLE_IO
) != 0,
467 DPRINT("Finished waiting (%wZ)! Status: %lx\n", &Ccb
->Fcb
->PipeName
, Status
);
469 ExAcquireFastMutex(&Ccb
->DataListLock
);
471 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
) || (Status
== STATUS_ALERTED
))
473 Status
= STATUS_CANCELLED
;
476 if (!NT_SUCCESS(Status
))
483 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
485 Context
->WaitEvent
= &Ccb
->ReadEvent
;
486 Status
= NpfsAddWaitingReadWriteRequest(DeviceObject
, Irp
);
488 if (NT_SUCCESS(Status
))
490 Status
= STATUS_PENDING
;
493 ExAcquireFastMutex(&Ccb
->DataListLock
);
497 ASSERT(IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
);
499 /* If the pipe type and read mode are both byte stream */
500 if (Ccb
->Fcb
->PipeType
== FILE_PIPE_BYTE_STREAM_TYPE
)
502 DPRINT("Byte stream mode: Ccb->Data %x\n", Ccb
->Data
);
503 /* Byte stream mode */
504 while (Length
> 0 && Ccb
->ReadDataAvailable
> 0)
506 CopyLength
= min(Ccb
->ReadDataAvailable
, Length
);
507 if ((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
<= (ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
)
509 memcpy(Buffer
, Ccb
->ReadPtr
, CopyLength
);
510 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
);
511 if (Ccb
->ReadPtr
== (PVOID
)((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
))
513 Ccb
->ReadPtr
= Ccb
->Data
;
518 TempLength
= (ULONG
)((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
- (ULONG_PTR
)Ccb
->ReadPtr
);
519 memcpy(Buffer
, Ccb
->ReadPtr
, TempLength
);
520 memcpy((PVOID
)((ULONG_PTR
)Buffer
+ TempLength
), Ccb
->Data
, CopyLength
- TempLength
);
521 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->Data
+ CopyLength
- TempLength
);
524 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CopyLength
);
525 Length
-= CopyLength
;
526 Information
+= CopyLength
;
528 Ccb
->ReadDataAvailable
-= CopyLength
;
529 Ccb
->WriteQuotaAvailable
+= CopyLength
;
532 if ((Length
== 0) || (Ccb
->ReadDataAvailable
== 0))
534 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->OtherSide
))
536 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
538 KeResetEvent(&Ccb
->ReadEvent
);
542 else if (Ccb
->Fcb
->PipeType
== FILE_PIPE_MESSAGE_TYPE
)
544 DPRINT("Message mode: Ccb>Data %x\n", Ccb
->Data
);
546 /* Check if buffer is full and the read pointer is not at the start of the buffer */
547 if ((Ccb
->WriteQuotaAvailable
== 0) && (Ccb
->ReadPtr
> Ccb
->Data
))
549 Ccb
->WriteQuotaAvailable
+= (ULONG_PTR
)Ccb
->ReadPtr
- (ULONG_PTR
)Ccb
->Data
;
550 memcpy(Ccb
->Data
, Ccb
->ReadPtr
, (ULONG_PTR
)Ccb
->WritePtr
- (ULONG_PTR
)Ccb
->ReadPtr
);
551 Ccb
->WritePtr
= (PVOID
)((ULONG_PTR
)Ccb
->WritePtr
- ((ULONG_PTR
)Ccb
->ReadPtr
- (ULONG_PTR
)Ccb
->Data
));
552 Ccb
->ReadPtr
= Ccb
->Data
;
553 ASSERT((ULONG_PTR
)Ccb
->WritePtr
< ((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
));
554 ASSERT(Ccb
->WritePtr
>= Ccb
->Data
);
557 /* For Message mode, the Message length is stored in the buffer preceeding the Message. */
558 if (Ccb
->ReadDataAvailable
)
560 ULONG NextMessageLength
= 0;
562 /* First get the size of the message */
563 memcpy(&NextMessageLength
, Ccb
->ReadPtr
, sizeof(NextMessageLength
));
565 if ((NextMessageLength
== 0) || (NextMessageLength
> Ccb
->ReadDataAvailable
))
567 DPRINT1("Possible memory corruption.\n");
568 HexDump(Ccb
->Data
, (ULONG_PTR
)Ccb
->WritePtr
- (ULONG_PTR
)Ccb
->Data
);
572 /* Use the smaller value */
573 CopyLength
= min(NextMessageLength
, Length
);
574 ASSERT(CopyLength
> 0);
575 ASSERT(CopyLength
<= Ccb
->ReadDataAvailable
);
576 /* retrieve the message from the buffer */
577 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ sizeof(NextMessageLength
)), CopyLength
);
579 if (Ccb
->ReadDataAvailable
> CopyLength
)
581 if (CopyLength
< NextMessageLength
)
582 /* Client only requested part of the message */
584 /* Calculate the remaining message new size */
585 ULONG NewMessageSize
= NextMessageLength
- CopyLength
;
587 /* Update ReadPtr to point to new Message size location */
588 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
);
590 /* Write a new Message size to buffer for the part of the message still there */
591 memcpy(Ccb
->ReadPtr
, &NewMessageSize
, sizeof(NewMessageSize
));
594 /* Client wanted the entire message */
596 /* Update ReadPtr to point to next message size */
597 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
+ sizeof(CopyLength
));
602 /* This was the last Message, so just zero start of buffer for safety sake */
603 memset(Ccb
->Data
, 0, NextMessageLength
+ sizeof(NextMessageLength
));
605 /* Reset to MaxDataLength as partial message retrievals dont
606 give the length back to Quota */
607 Ccb
->WriteQuotaAvailable
= Ccb
->MaxDataLength
;
609 /* reset read and write pointer to beginning of buffer */
610 Ccb
->WritePtr
= Ccb
->Data
;
611 Ccb
->ReadPtr
= Ccb
->Data
;
614 DPRINT("Length %d Buffer %x\n",CopyLength
,Buffer
);
615 HexDump((PUCHAR
)Buffer
, CopyLength
);
618 Information
+= CopyLength
;
620 Ccb
->ReadDataAvailable
-= CopyLength
;
622 ASSERT(Ccb
->WriteQuotaAvailable
<= Ccb
->MaxDataLength
);
627 ULONG ConnectionSideReadMode
;
629 if (Ccb
->PipeEnd
== FILE_PIPE_CLIENT_END
) ConnectionSideReadMode
=Ccb
->Fcb
->ClientReadMode
;
630 else ConnectionSideReadMode
= Ccb
->Fcb
->ServerReadMode
;
632 if ((ConnectionSideReadMode
== FILE_PIPE_BYTE_STREAM_MODE
) && (Ccb
->ReadDataAvailable
) && (Length
> CopyLength
))
634 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CopyLength
);
635 Length
-= CopyLength
;
639 KeResetEvent(&Ccb
->ReadEvent
);
641 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->WriteQuotaAvailable
> 0) && (Ccb
->OtherSide
))
643 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
651 DPRINT1("Unhandled Pipe Mode!\n");
655 Irp
->IoStatus
.Information
= Information
;
656 Irp
->IoStatus
.Status
= Status
;
658 ASSERT(IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
);
660 if (IoIsOperationSynchronous(Irp
))
662 RemoveEntryList(&Context
->ListEntry
);
663 if (!IsListEmpty(&Ccb
->ReadRequestListHead
))
665 Context
= CONTAINING_RECORD(Ccb
->ReadRequestListHead
.Flink
, NPFS_CONTEXT
, ListEntry
);
666 KeSetEvent(Context
->WaitEvent
, IO_NO_INCREMENT
, FALSE
);
668 ExReleaseFastMutex(&Ccb
->DataListLock
);
669 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
671 DPRINT("NpfsRead done (Status %lx)\n", Status
);
678 if (IsOriginalRequest
)
680 IsOriginalRequest
= FALSE
;
681 OriginalStatus
= Status
;
683 if (Status
== STATUS_PENDING
)
685 ExReleaseFastMutex(&Ccb
->DataListLock
);
686 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus
);
687 return OriginalStatus
;
689 RemoveEntryList(&Context
->ListEntry
);
690 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
691 if (IsListEmpty(&Ccb
->ReadRequestListHead
))
693 ExReleaseFastMutex(&Ccb
->DataListLock
);
694 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus
);
695 return OriginalStatus
;
698 IoAcquireCancelSpinLock(&oldIrql
);
699 Context
= CONTAINING_RECORD(Ccb
->ReadRequestListHead
.Flink
, NPFS_CONTEXT
, ListEntry
);
701 Irp
= CONTAINING_RECORD(Context
, IRP
, Tail
.Overlay
.DriverContext
);
702 /* Verify the Irp wasnt cancelled */
705 IoReleaseCancelSpinLock(oldIrql
);
706 RemoveEntryList(&Context
->ListEntry
);
707 ExReleaseFastMutex(&Ccb
->DataListLock
);
708 Status
= STATUS_CANCELLED
;
711 /* The Irp will now be handled, so remove the CancelRoutine */
712 (void)IoSetCancelRoutine(Irp
, NULL
);
713 IoReleaseCancelSpinLock(oldIrql
);
718 Irp
->IoStatus
.Status
= Status
;
720 if (Status
!= STATUS_PENDING
)
722 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
724 DPRINT("NpfsRead done (Status %lx)\n", Status
);
730 NpfsWrite(PDEVICE_OBJECT DeviceObject
,
733 PIO_STACK_LOCATION IoStack
;
734 PFILE_OBJECT FileObject
;
735 PNPFS_FCB Fcb
= NULL
;
736 PNPFS_CCB Ccb
= NULL
;
739 NTSTATUS Status
= STATUS_SUCCESS
;
742 ULONG Information
= 0;
746 UNREFERENCED_PARAMETER(DeviceObject
);
748 DPRINT("NpfsWrite()\n");
750 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
751 FileObject
= IoStack
->FileObject
;
752 DPRINT("FileObject %p\n", FileObject
);
753 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
755 Ccb
= FileObject
->FsContext2
;
757 /* Fail, if the CCB is not a pipe CCB */
758 if (Ccb
->Type
!= CCB_PIPE
)
760 DPRINT("Not a pipe!\n");
761 Status
= STATUS_INVALID_PARAMETER
;
766 ReaderCcb
= Ccb
->OtherSide
;
769 Length
= IoStack
->Parameters
.Write
.Length
;
770 Offset
= IoStack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
772 if (Irp
->MdlAddress
== NULL
)
774 DPRINT("Irp->MdlAddress == NULL\n");
775 Status
= STATUS_UNSUCCESSFUL
;
780 if ((ReaderCcb
== NULL
) || (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
))
782 DPRINT("Pipe is NOT connected!\n");
783 if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
784 Status
= STATUS_PIPE_LISTENING
;
785 else if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
786 Status
= STATUS_PIPE_DISCONNECTED
;
788 Status
= STATUS_UNSUCCESSFUL
;
793 if (ReaderCcb
->Data
== NULL
)
795 DPRINT("Pipe is NOT writable!\n");
796 Status
= STATUS_UNSUCCESSFUL
;
801 Status
= STATUS_SUCCESS
;
802 Buffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
806 DPRINT("MmGetSystemAddressForMdlSafe failed\n");
807 Status
= STATUS_INSUFFICIENT_RESOURCES
;
813 ExAcquireFastMutex(&ReaderCcb
->DataListLock
);
815 DPRINT("Length %d Buffer %x Offset %x\n",Length
,Buffer
,Offset
);
818 HexDump(Buffer
, Length
);
823 if (ReaderCcb
->WriteQuotaAvailable
== 0)
825 if (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
|| !Ccb
->OtherSide
)
827 Status
= STATUS_PIPE_BROKEN
;
828 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
831 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
832 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
834 DPRINT("Write Waiting for buffer space (%wZ)\n", &Fcb
->PipeName
);
835 Status
= KeWaitForSingleObject(&Ccb
->WriteEvent
,
838 (FileObject
->Flags
& FO_ALERTABLE_IO
) != 0,
840 DPRINT("Write Finished waiting (%wZ)! Status: %lx\n", &Fcb
->PipeName
, Status
);
842 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
) || (Status
== STATUS_ALERTED
))
844 Status
= STATUS_CANCELLED
;
847 if (!NT_SUCCESS(Status
))
852 * It's possible that the event was signaled because the
853 * other side of pipe was closed.
855 if (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
|| !Ccb
->OtherSide
)
857 DPRINT("PipeState: %x\n", Ccb
->PipeState
);
858 Status
= STATUS_PIPE_BROKEN
;
861 /* Check that the pipe has not been closed */
862 if (ReaderCcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
|| !ReaderCcb
->OtherSide
)
864 Status
= STATUS_PIPE_BROKEN
;
867 ExAcquireFastMutex(&ReaderCcb
->DataListLock
);
870 if (Ccb
->Fcb
->PipeType
== FILE_PIPE_BYTE_STREAM_TYPE
)
872 DPRINT("Byte stream mode: Ccb->Data %x, Ccb->WritePtr %x\n", ReaderCcb
->Data
, ReaderCcb
->WritePtr
);
874 while (Length
> 0 && ReaderCcb
->WriteQuotaAvailable
> 0)
876 CopyLength
= min(Length
, ReaderCcb
->WriteQuotaAvailable
);
878 if ((ULONG_PTR
)ReaderCcb
->WritePtr
+ CopyLength
<= (ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
)
880 memcpy(ReaderCcb
->WritePtr
, Buffer
, CopyLength
);
881 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ CopyLength
);
882 if ((ULONG_PTR
)ReaderCcb
->WritePtr
== (ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
)
884 ReaderCcb
->WritePtr
= ReaderCcb
->Data
;
890 TempLength
= (ULONG
)((ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
-
891 (ULONG_PTR
)ReaderCcb
->WritePtr
);
893 memcpy(ReaderCcb
->WritePtr
, Buffer
, TempLength
);
894 memcpy(ReaderCcb
->Data
, Buffer
+ TempLength
, CopyLength
- TempLength
);
895 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->Data
+ CopyLength
- TempLength
);
898 Buffer
+= CopyLength
;
899 Length
-= CopyLength
;
900 Information
+= CopyLength
;
902 ReaderCcb
->ReadDataAvailable
+= CopyLength
;
903 ReaderCcb
->WriteQuotaAvailable
-= CopyLength
;
908 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
909 KeResetEvent(&Ccb
->WriteEvent
);
913 else if (Ccb
->Fcb
->PipeType
== FILE_PIPE_MESSAGE_TYPE
)
915 /* For Message Type Pipe, the Pipes memory will be used to store the size of each message */
916 DPRINT("Message mode: Ccb->Data %x, Ccb->WritePtr %x\n",ReaderCcb
->Data
, ReaderCcb
->WritePtr
);
919 /* Verify the WritePtr is still inside the buffer */
920 if (((ULONG_PTR
)ReaderCcb
->WritePtr
> ((ULONG_PTR
)ReaderCcb
->Data
+ (ULONG_PTR
)ReaderCcb
->MaxDataLength
)) ||
921 ((ULONG_PTR
)ReaderCcb
->WritePtr
< (ULONG_PTR
)ReaderCcb
->Data
))
923 DPRINT1("NPFS is writing out of its buffer. Report to developer!\n");
924 DPRINT1("ReaderCcb->WritePtr %x, ReaderCcb->Data %x, ReaderCcb->MaxDataLength %lu\n",
925 ReaderCcb
->WritePtr
, ReaderCcb
->Data
, ReaderCcb
->MaxDataLength
);
929 CopyLength
= min(Length
, ReaderCcb
->WriteQuotaAvailable
- sizeof(ULONG
));
930 if (CopyLength
> ReaderCcb
->WriteQuotaAvailable
)
932 DPRINT1("Writing %lu byte to pipe would overflow as only %lu bytes are available\n",
933 CopyLength
, ReaderCcb
->WriteQuotaAvailable
);
937 /* First Copy the Length of the message into the pipes buffer */
938 memcpy(ReaderCcb
->WritePtr
, &CopyLength
, sizeof(CopyLength
));
940 /* Now the user buffer itself */
941 memcpy((PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ sizeof(CopyLength
)), Buffer
, CopyLength
);
943 /* Update the write pointer */
944 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ sizeof(CopyLength
) + CopyLength
);
946 Information
+= CopyLength
;
948 ReaderCcb
->ReadDataAvailable
+= CopyLength
;
950 ReaderCcb
->WriteQuotaAvailable
-= (CopyLength
+ sizeof(ULONG
));
952 if ((ULONG_PTR
)ReaderCcb
->WriteQuotaAvailable
> (ULONG
)ReaderCcb
->MaxDataLength
)
954 DPRINT1("QuotaAvailable is greater than buffer size!\n");
961 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
962 KeResetEvent(&Ccb
->WriteEvent
);
968 DPRINT1("Unhandled Pipe Type Mode and Read Write Mode!\n");
973 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
976 Irp
->IoStatus
.Status
= Status
;
977 Irp
->IoStatus
.Information
= Information
;
979 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
981 DPRINT("NpfsWrite done (Status %lx)\n", Status
);