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
= 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 */
198 ThreadContext
->Vcb
->EmptyWaiterCount
-= MAXIMUM_WAIT_OBJECTS
- 1;
199 RemoveEntryList(&ThreadContext
->ListEntry
);
200 KeUnlockMutex(&ThreadContext
->Vcb
->PipeListLock
);
201 ExFreePoolWithTag(ThreadContext
, TAG_NPFS_THREAD_CONTEXT
);
208 NpfsAddWaitingReadWriteRequest(IN PDEVICE_OBJECT DeviceObject
,
211 PLIST_ENTRY ListEntry
;
212 PNPFS_THREAD_CONTEXT ThreadContext
= NULL
;
213 PNPFS_CONTEXT Context
;
219 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
220 Vcb
= (PNPFS_VCB
)DeviceObject
->DeviceExtension
;
222 DPRINT("NpfsAddWaitingReadWriteRequest(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
224 KeLockMutex(&Vcb
->PipeListLock
);
226 ListEntry
= Vcb
->ThreadListHead
.Flink
;
227 while (ListEntry
!= &Vcb
->ThreadListHead
)
229 ThreadContext
= CONTAINING_RECORD(ListEntry
, NPFS_THREAD_CONTEXT
, ListEntry
);
230 if (ThreadContext
->Count
< MAXIMUM_WAIT_OBJECTS
)
234 ListEntry
= ListEntry
->Flink
;
237 if (ListEntry
== &Vcb
->ThreadListHead
)
239 ThreadContext
= ExAllocatePoolWithTag(NonPagedPool
,
240 sizeof(NPFS_THREAD_CONTEXT
),
241 TAG_NPFS_THREAD_CONTEXT
);
242 if (ThreadContext
== NULL
)
244 KeUnlockMutex(&Vcb
->PipeListLock
);
245 return STATUS_NO_MEMORY
;
248 ThreadContext
->Vcb
= Vcb
;
249 KeInitializeEvent(&ThreadContext
->Event
, SynchronizationEvent
, FALSE
);
250 ThreadContext
->Count
= 1;
251 ThreadContext
->WaitObjectArray
[0] = &ThreadContext
->Event
;
253 DPRINT("Creating a new system thread for waiting read/write requests\n");
255 Status
= PsCreateSystemThread(&hThread
,
261 (PVOID
)ThreadContext
);
262 if (!NT_SUCCESS(Status
))
264 ExFreePoolWithTag(ThreadContext
, TAG_NPFS_THREAD_CONTEXT
);
265 KeUnlockMutex(&Vcb
->PipeListLock
);
269 InsertHeadList(&Vcb
->ThreadListHead
, &ThreadContext
->ListEntry
);
270 Vcb
->EmptyWaiterCount
+= MAXIMUM_WAIT_OBJECTS
- 1;
272 IoMarkIrpPending(Irp
);
274 IoAcquireCancelSpinLock(&oldIrql
);
277 IoReleaseCancelSpinLock(oldIrql
);
278 Status
= STATUS_CANCELLED
;
282 (void)IoSetCancelRoutine(Irp
, NpfsReadWriteCancelRoutine
);
283 IoReleaseCancelSpinLock(oldIrql
);
284 ThreadContext
->WaitObjectArray
[ThreadContext
->Count
] = Context
->WaitEvent
;
285 ThreadContext
->WaitIrpArray
[ThreadContext
->Count
] = Irp
;
286 ThreadContext
->Count
++;
287 Vcb
->EmptyWaiterCount
--;
288 KeSetEvent(&ThreadContext
->Event
, IO_NO_INCREMENT
, FALSE
);
289 Status
= STATUS_SUCCESS
;
291 KeUnlockMutex(&Vcb
->PipeListLock
);
296 NpfsRead(IN PDEVICE_OBJECT DeviceObject
,
299 PFILE_OBJECT FileObject
;
301 NTSTATUS OriginalStatus
= STATUS_SUCCESS
;
303 PNPFS_CONTEXT Context
;
306 ULONG Information
= 0;
307 ULONG CopyLength
= 0;
309 BOOLEAN IsOriginalRequest
= TRUE
;
312 DPRINT("NpfsRead(DeviceObject %p, Irp %p)\n", DeviceObject
, Irp
);
314 FileObject
= IoGetCurrentIrpStackLocation(Irp
)->FileObject
;
315 DPRINT("FileObject %p\n", FileObject
);
316 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
317 Ccb
= FileObject
->FsContext2
;
319 /* Fail, if the CCB is not a pipe CCB */
320 if (Ccb
->Type
!= CCB_PIPE
)
322 DPRINT("Not a pipe!\n");
323 Status
= STATUS_INVALID_PARAMETER
;
324 Irp
->IoStatus
.Information
= 0;
328 if (Irp
->MdlAddress
== NULL
)
330 DPRINT("Irp->MdlAddress == NULL\n");
331 Status
= STATUS_UNSUCCESSFUL
;
332 Irp
->IoStatus
.Information
= 0;
336 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
338 if ((Ccb
->OtherSide
) && (Ccb
->OtherSide
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
) && (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
))
340 DPRINT("Both Client and Server are disconnected!\n");
341 Status
= STATUS_PIPE_DISCONNECTED
;
342 Irp
->IoStatus
.Information
= 0;
347 if ((Ccb
->OtherSide
== NULL
) && (Ccb
->ReadDataAvailable
== 0))
349 if (Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
)
350 Status
= STATUS_PIPE_BROKEN
;
351 else if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
352 Status
= STATUS_PIPE_LISTENING
;
353 else if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
354 Status
= STATUS_PIPE_DISCONNECTED
;
356 Status
= STATUS_UNSUCCESSFUL
;
357 Irp
->IoStatus
.Information
= 0;
361 if (Ccb
->Data
== NULL
)
363 DPRINT("Pipe is NOT readable!\n");
364 Status
= STATUS_UNSUCCESSFUL
;
365 Irp
->IoStatus
.Information
= 0;
369 ExAcquireFastMutex(&Ccb
->DataListLock
);
371 if (IoIsOperationSynchronous(Irp
))
373 InsertTailList(&Ccb
->ReadRequestListHead
, &Context
->ListEntry
);
374 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
376 KeInitializeEvent(&Event
, SynchronizationEvent
, FALSE
);
377 Context
->WaitEvent
= &Event
;
378 ExReleaseFastMutex(&Ccb
->DataListLock
);
379 KeWaitForSingleObject(&Event
,
384 ExAcquireFastMutex(&Ccb
->DataListLock
);
386 Irp
->IoStatus
.Information
= 0;
391 if (IsListEmpty(&Ccb
->ReadRequestListHead
) ||
392 Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
394 /* this is a new request */
395 Irp
->IoStatus
.Information
= 0;
396 KeResetEvent(&Ccb
->ReadEvent
);
397 Context
->WaitEvent
= &Ccb
->ReadEvent
;
398 InsertTailList(&Ccb
->ReadRequestListHead
, &Context
->ListEntry
);
399 if (Ccb
->ReadRequestListHead
.Flink
!= &Context
->ListEntry
)
401 /* there was already a request on the list */
402 IoAcquireCancelSpinLock(&oldIrql
);
405 IoReleaseCancelSpinLock(oldIrql
);
406 RemoveEntryList(&Context
->ListEntry
);
407 ExReleaseFastMutex(&Ccb
->DataListLock
);
408 Status
= STATUS_CANCELLED
;
411 (void)IoSetCancelRoutine(Irp
, NpfsReadWriteCancelRoutine
);
412 IoReleaseCancelSpinLock(oldIrql
);
413 ExReleaseFastMutex(&Ccb
->DataListLock
);
414 IoMarkIrpPending(Irp
);
415 Status
= STATUS_PENDING
;
423 Buffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
,
425 Information
= Irp
->IoStatus
.Information
;
426 Length
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.Read
.Length
;
427 ASSERT(Information
<= Length
);
428 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ Information
);
429 Length
-= Information
;
430 Status
= STATUS_SUCCESS
;
434 if (Ccb
->ReadDataAvailable
== 0)
436 ULONG ConnectionSideReadMode
;
438 if (Ccb
->PipeEnd
== FILE_PIPE_CLIENT_END
) ConnectionSideReadMode
=Ccb
->Fcb
->ClientReadMode
;
439 else ConnectionSideReadMode
= Ccb
->Fcb
->ServerReadMode
;
441 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->OtherSide
))
443 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
445 if (Information
> 0 &&
446 (ConnectionSideReadMode
!= FILE_PIPE_BYTE_STREAM_MODE
||
447 Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
))
451 ASSERT(Ccb
->ReadDataAvailable
== 0);
452 if ((Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
) || (!Ccb
->OtherSide
))
454 DPRINT("PipeState: %x\n", Ccb
->PipeState
);
455 Status
= STATUS_PIPE_BROKEN
;
458 KeResetEvent(&Ccb
->ReadEvent
);
459 ExReleaseFastMutex(&Ccb
->DataListLock
);
461 if (IoIsOperationSynchronous(Irp
))
463 /* Wait for ReadEvent to become signaled */
465 DPRINT("Waiting for readable data (%wZ)\n", &Ccb
->Fcb
->PipeName
);
466 Status
= KeWaitForSingleObject(&Ccb
->ReadEvent
,
469 (FileObject
->Flags
& FO_ALERTABLE_IO
) != 0,
471 DPRINT("Finished waiting (%wZ)! Status: %lx\n", &Ccb
->Fcb
->PipeName
, Status
);
473 ExAcquireFastMutex(&Ccb
->DataListLock
);
475 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
) || (Status
== STATUS_ALERTED
))
477 Status
= STATUS_CANCELLED
;
480 if (!NT_SUCCESS(Status
))
487 Context
= (PNPFS_CONTEXT
)&Irp
->Tail
.Overlay
.DriverContext
;
489 Context
->WaitEvent
= &Ccb
->ReadEvent
;
490 Status
= NpfsAddWaitingReadWriteRequest(DeviceObject
, Irp
);
492 if (NT_SUCCESS(Status
))
494 Status
= STATUS_PENDING
;
497 ExAcquireFastMutex(&Ccb
->DataListLock
);
501 ASSERT(IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
);
503 /* If the pipe type and read mode are both byte stream */
504 if (Ccb
->Fcb
->PipeType
== FILE_PIPE_BYTE_STREAM_TYPE
)
506 DPRINT("Byte stream mode: Ccb->Data %p\n", Ccb
->Data
);
507 /* Byte stream mode */
508 while (Length
> 0 && Ccb
->ReadDataAvailable
> 0)
510 CopyLength
= min(Ccb
->ReadDataAvailable
, Length
);
511 if ((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
<= (ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
)
513 memcpy(Buffer
, Ccb
->ReadPtr
, CopyLength
);
514 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
);
515 if (Ccb
->ReadPtr
== (PVOID
)((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
))
517 Ccb
->ReadPtr
= Ccb
->Data
;
522 TempLength
= (ULONG
)((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
- (ULONG_PTR
)Ccb
->ReadPtr
);
523 memcpy(Buffer
, Ccb
->ReadPtr
, TempLength
);
524 memcpy((PVOID
)((ULONG_PTR
)Buffer
+ TempLength
), Ccb
->Data
, CopyLength
- TempLength
);
525 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->Data
+ CopyLength
- TempLength
);
528 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CopyLength
);
529 Length
-= CopyLength
;
530 Information
+= CopyLength
;
532 Ccb
->ReadDataAvailable
-= CopyLength
;
533 Ccb
->WriteQuotaAvailable
+= CopyLength
;
536 if ((Length
== 0) || (Ccb
->ReadDataAvailable
== 0))
538 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->OtherSide
))
540 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
545 else if (Ccb
->Fcb
->PipeType
== FILE_PIPE_MESSAGE_TYPE
)
547 DPRINT("Message mode: Ccb>Data %p\n", Ccb
->Data
);
549 /* Check if buffer is full and the read pointer is not at the start of the buffer */
550 if ((Ccb
->WriteQuotaAvailable
== 0) && (Ccb
->ReadPtr
> Ccb
->Data
))
552 Ccb
->WriteQuotaAvailable
+= (ULONG_PTR
)Ccb
->ReadPtr
- (ULONG_PTR
)Ccb
->Data
;
553 memcpy(Ccb
->Data
, Ccb
->ReadPtr
, (ULONG_PTR
)Ccb
->WritePtr
- (ULONG_PTR
)Ccb
->ReadPtr
);
554 Ccb
->WritePtr
= (PVOID
)((ULONG_PTR
)Ccb
->WritePtr
- ((ULONG_PTR
)Ccb
->ReadPtr
- (ULONG_PTR
)Ccb
->Data
));
555 Ccb
->ReadPtr
= Ccb
->Data
;
556 ASSERT((ULONG_PTR
)Ccb
->WritePtr
< ((ULONG_PTR
)Ccb
->Data
+ Ccb
->MaxDataLength
));
557 ASSERT(Ccb
->WritePtr
>= Ccb
->Data
);
560 /* For Message mode, the Message length is stored in the buffer preceeding the Message. */
561 if (Ccb
->ReadDataAvailable
)
563 ULONG NextMessageLength
= 0;
565 /* First get the size of the message */
566 memcpy(&NextMessageLength
, Ccb
->ReadPtr
, sizeof(NextMessageLength
));
568 if ((NextMessageLength
== 0) || (NextMessageLength
> Ccb
->ReadDataAvailable
))
570 DPRINT1("Possible memory corruption.\n");
571 HexDump(Ccb
->Data
, (ULONG_PTR
)Ccb
->WritePtr
- (ULONG_PTR
)Ccb
->Data
);
575 /* Use the smaller value */
576 CopyLength
= min(NextMessageLength
, Length
);
577 ASSERT(CopyLength
> 0);
578 ASSERT(CopyLength
<= Ccb
->ReadDataAvailable
);
579 /* retrieve the message from the buffer */
580 memcpy(Buffer
, (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ sizeof(NextMessageLength
)), CopyLength
);
582 if (Ccb
->ReadDataAvailable
> CopyLength
)
584 if (CopyLength
< NextMessageLength
)
585 /* Client only requested part of the message */
587 /* Calculate the remaining message new size */
588 ULONG NewMessageSize
= NextMessageLength
- CopyLength
;
590 /* Update ReadPtr to point to new Message size location */
591 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
);
593 /* Write a new Message size to buffer for the part of the message still there */
594 memcpy(Ccb
->ReadPtr
, &NewMessageSize
, sizeof(NewMessageSize
));
597 /* Client wanted the entire message */
599 /* Update ReadPtr to point to next message size */
600 Ccb
->ReadPtr
= (PVOID
)((ULONG_PTR
)Ccb
->ReadPtr
+ CopyLength
+ sizeof(CopyLength
));
605 /* This was the last Message, so just zero start of buffer for safety sake */
606 memset(Ccb
->Data
, 0, NextMessageLength
+ sizeof(NextMessageLength
));
608 /* Reset to MaxDataLength as partial message retrievals dont
609 give the length back to Quota */
610 Ccb
->WriteQuotaAvailable
= Ccb
->MaxDataLength
;
612 /* reset read and write pointer to beginning of buffer */
613 Ccb
->WritePtr
= Ccb
->Data
;
614 Ccb
->ReadPtr
= Ccb
->Data
;
617 DPRINT("Length %d Buffer %x\n", CopyLength
, Buffer
);
618 HexDump((PUCHAR
)Buffer
, CopyLength
);
621 Information
+= CopyLength
;
623 Ccb
->ReadDataAvailable
-= CopyLength
;
625 ASSERT(Ccb
->WriteQuotaAvailable
<= Ccb
->MaxDataLength
);
630 ULONG ConnectionSideReadMode
;
632 if (Ccb
->PipeEnd
== FILE_PIPE_CLIENT_END
) ConnectionSideReadMode
=Ccb
->Fcb
->ClientReadMode
;
633 else ConnectionSideReadMode
= Ccb
->Fcb
->ServerReadMode
;
635 if ((ConnectionSideReadMode
== FILE_PIPE_BYTE_STREAM_MODE
) && (Ccb
->ReadDataAvailable
) && (Length
> CopyLength
))
637 Buffer
= (PVOID
)((ULONG_PTR
)Buffer
+ CopyLength
);
638 Length
-= CopyLength
;
642 if ((Ccb
->PipeState
== FILE_PIPE_CONNECTED_STATE
) && (Ccb
->WriteQuotaAvailable
> 0) && (Ccb
->OtherSide
))
644 KeSetEvent(&Ccb
->OtherSide
->WriteEvent
, IO_NO_INCREMENT
, FALSE
);
652 DPRINT1("Unhandled Pipe Mode!\n");
656 Irp
->IoStatus
.Information
= Information
;
657 Irp
->IoStatus
.Status
= Status
;
659 ASSERT(IoGetCurrentIrpStackLocation(Irp
)->FileObject
!= NULL
);
661 if (IoIsOperationSynchronous(Irp
))
663 RemoveEntryList(&Context
->ListEntry
);
664 if (!IsListEmpty(&Ccb
->ReadRequestListHead
))
666 Context
= CONTAINING_RECORD(Ccb
->ReadRequestListHead
.Flink
, NPFS_CONTEXT
, ListEntry
);
667 KeSetEvent(Context
->WaitEvent
, IO_NO_INCREMENT
, FALSE
);
669 ExReleaseFastMutex(&Ccb
->DataListLock
);
670 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
672 DPRINT("NpfsRead done (Status %lx)\n", Status
);
679 if (IsOriginalRequest
)
681 IsOriginalRequest
= FALSE
;
682 OriginalStatus
= Status
;
684 if (Status
== STATUS_PENDING
)
686 ExReleaseFastMutex(&Ccb
->DataListLock
);
687 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus
);
688 return OriginalStatus
;
690 RemoveEntryList(&Context
->ListEntry
);
691 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
692 if (IsListEmpty(&Ccb
->ReadRequestListHead
))
694 ExReleaseFastMutex(&Ccb
->DataListLock
);
695 DPRINT("NpfsRead done (Status %lx)\n", OriginalStatus
);
696 return OriginalStatus
;
699 IoAcquireCancelSpinLock(&oldIrql
);
700 Context
= CONTAINING_RECORD(Ccb
->ReadRequestListHead
.Flink
, NPFS_CONTEXT
, ListEntry
);
702 Irp
= CONTAINING_RECORD(Context
, IRP
, Tail
.Overlay
.DriverContext
);
703 /* Verify the Irp wasnt cancelled */
706 IoReleaseCancelSpinLock(oldIrql
);
707 RemoveEntryList(&Context
->ListEntry
);
708 ExReleaseFastMutex(&Ccb
->DataListLock
);
709 Status
= STATUS_CANCELLED
;
712 /* The Irp will now be handled, so remove the CancelRoutine */
713 (void)IoSetCancelRoutine(Irp
, NULL
);
714 IoReleaseCancelSpinLock(oldIrql
);
719 Irp
->IoStatus
.Status
= Status
;
721 if (Status
!= STATUS_PENDING
)
723 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
725 DPRINT("NpfsRead done (Status %lx)\n", Status
);
731 NpfsWrite(PDEVICE_OBJECT DeviceObject
,
734 PIO_STACK_LOCATION IoStack
;
735 PFILE_OBJECT FileObject
;
736 PNPFS_FCB Fcb
= NULL
;
737 PNPFS_CCB Ccb
= NULL
;
740 NTSTATUS Status
= STATUS_SUCCESS
;
743 ULONG Information
= 0;
747 UNREFERENCED_PARAMETER(DeviceObject
);
749 DPRINT("NpfsWrite()\n");
751 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
752 FileObject
= IoStack
->FileObject
;
753 DPRINT("FileObject %p\n", FileObject
);
754 DPRINT("Pipe name %wZ\n", &FileObject
->FileName
);
756 Ccb
= FileObject
->FsContext2
;
758 /* Fail, if the CCB is not a pipe CCB */
759 if (Ccb
->Type
!= CCB_PIPE
)
761 DPRINT("Not a pipe!\n");
762 Status
= STATUS_INVALID_PARAMETER
;
767 ReaderCcb
= Ccb
->OtherSide
;
770 Length
= IoStack
->Parameters
.Write
.Length
;
771 Offset
= IoStack
->Parameters
.Write
.ByteOffset
.u
.LowPart
;
773 if (Irp
->MdlAddress
== NULL
)
775 DPRINT("Irp->MdlAddress == NULL\n");
776 Status
= STATUS_UNSUCCESSFUL
;
781 if ((ReaderCcb
== NULL
) || (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
))
783 DPRINT("Pipe is NOT connected!\n");
784 if (Ccb
->PipeState
== FILE_PIPE_LISTENING_STATE
)
785 Status
= STATUS_PIPE_LISTENING
;
786 else if (Ccb
->PipeState
== FILE_PIPE_DISCONNECTED_STATE
)
787 Status
= STATUS_PIPE_DISCONNECTED
;
789 Status
= STATUS_UNSUCCESSFUL
;
794 if (ReaderCcb
->Data
== NULL
)
796 DPRINT("Pipe is NOT writable!\n");
797 Status
= STATUS_UNSUCCESSFUL
;
802 Status
= STATUS_SUCCESS
;
803 Buffer
= MmGetSystemAddressForMdlSafe(Irp
->MdlAddress
, NormalPagePriority
);
807 DPRINT("MmGetSystemAddressForMdlSafe failed\n");
808 Status
= STATUS_INSUFFICIENT_RESOURCES
;
814 ExAcquireFastMutex(&ReaderCcb
->DataListLock
);
816 DPRINT("Length %lu Buffer %p Offset %lu\n", Length
, Buffer
, Offset
);
819 HexDump(Buffer
, Length
);
824 if (ReaderCcb
->WriteQuotaAvailable
== 0)
826 if (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
|| !Ccb
->OtherSide
)
828 Status
= STATUS_PIPE_BROKEN
;
829 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
832 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
833 KeResetEvent(&Ccb
->WriteEvent
);
834 ExReleaseFastMutex(&ReaderCcb
->DataListLock
);
836 DPRINT("Write Waiting for buffer space (%wZ)\n", &Fcb
->PipeName
);
837 Status
= KeWaitForSingleObject(&Ccb
->WriteEvent
,
840 (FileObject
->Flags
& FO_ALERTABLE_IO
) != 0,
842 DPRINT("Write Finished waiting (%wZ)! Status: %lx\n", &Fcb
->PipeName
, Status
);
844 if ((Status
== STATUS_USER_APC
) || (Status
== STATUS_KERNEL_APC
) || (Status
== STATUS_ALERTED
))
846 Status
= STATUS_CANCELLED
;
849 if (!NT_SUCCESS(Status
))
854 * It's possible that the event was signaled because the
855 * other side of pipe was closed.
857 if (Ccb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
|| !Ccb
->OtherSide
)
859 DPRINT("PipeState: %lx\n", Ccb
->PipeState
);
860 Status
= STATUS_PIPE_BROKEN
;
863 /* Check that the pipe has not been closed */
864 if (ReaderCcb
->PipeState
!= FILE_PIPE_CONNECTED_STATE
|| !ReaderCcb
->OtherSide
)
866 Status
= STATUS_PIPE_BROKEN
;
869 ExAcquireFastMutex(&ReaderCcb
->DataListLock
);
872 if (Ccb
->Fcb
->PipeType
== FILE_PIPE_BYTE_STREAM_TYPE
)
874 DPRINT("Byte stream mode: Ccb->Data %p, Ccb->WritePtr %p\n", ReaderCcb
->Data
, ReaderCcb
->WritePtr
);
876 while (Length
> 0 && ReaderCcb
->WriteQuotaAvailable
> 0)
878 CopyLength
= min(Length
, ReaderCcb
->WriteQuotaAvailable
);
880 if ((ULONG_PTR
)ReaderCcb
->WritePtr
+ CopyLength
<= (ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
)
882 memcpy(ReaderCcb
->WritePtr
, Buffer
, CopyLength
);
883 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ CopyLength
);
884 if ((ULONG_PTR
)ReaderCcb
->WritePtr
== (ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
)
886 ReaderCcb
->WritePtr
= ReaderCcb
->Data
;
892 TempLength
= (ULONG
)((ULONG_PTR
)ReaderCcb
->Data
+ ReaderCcb
->MaxDataLength
-
893 (ULONG_PTR
)ReaderCcb
->WritePtr
);
895 memcpy(ReaderCcb
->WritePtr
, Buffer
, TempLength
);
896 memcpy(ReaderCcb
->Data
, Buffer
+ TempLength
, CopyLength
- TempLength
);
897 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->Data
+ CopyLength
- TempLength
);
900 Buffer
+= CopyLength
;
901 Length
-= CopyLength
;
902 Information
+= CopyLength
;
904 ReaderCcb
->ReadDataAvailable
+= CopyLength
;
905 ReaderCcb
->WriteQuotaAvailable
-= CopyLength
;
910 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
914 else if (Ccb
->Fcb
->PipeType
== FILE_PIPE_MESSAGE_TYPE
)
916 /* For Message Type Pipe, the Pipes memory will be used to store the size of each message */
917 DPRINT("Message mode: Ccb->Data %p, Ccb->WritePtr %p\n", ReaderCcb
->Data
, ReaderCcb
->WritePtr
);
920 /* Verify the WritePtr is still inside the buffer */
921 if (((ULONG_PTR
)ReaderCcb
->WritePtr
> ((ULONG_PTR
)ReaderCcb
->Data
+ (ULONG_PTR
)ReaderCcb
->MaxDataLength
)) ||
922 ((ULONG_PTR
)ReaderCcb
->WritePtr
< (ULONG_PTR
)ReaderCcb
->Data
))
924 DPRINT1("NPFS is writing out of its buffer. Report to developer!\n");
925 DPRINT1("ReaderCcb->WritePtr %p, ReaderCcb->Data %p, ReaderCcb->MaxDataLength %lu\n",
926 ReaderCcb
->WritePtr
, ReaderCcb
->Data
, ReaderCcb
->MaxDataLength
);
930 CopyLength
= min(Length
, ReaderCcb
->WriteQuotaAvailable
- sizeof(ULONG
));
931 if (CopyLength
> ReaderCcb
->WriteQuotaAvailable
)
933 DPRINT1("Writing %lu byte to pipe would overflow as only %lu bytes are available\n",
934 CopyLength
, ReaderCcb
->WriteQuotaAvailable
);
938 /* First Copy the Length of the message into the pipes buffer */
939 memcpy(ReaderCcb
->WritePtr
, &CopyLength
, sizeof(CopyLength
));
941 /* Now the user buffer itself */
942 memcpy((PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ sizeof(CopyLength
)), Buffer
, CopyLength
);
944 /* Update the write pointer */
945 ReaderCcb
->WritePtr
= (PVOID
)((ULONG_PTR
)ReaderCcb
->WritePtr
+ sizeof(CopyLength
) + CopyLength
);
947 Information
+= CopyLength
;
949 ReaderCcb
->ReadDataAvailable
+= CopyLength
;
951 ReaderCcb
->WriteQuotaAvailable
-= (CopyLength
+ sizeof(ULONG
));
953 if ((ULONG_PTR
)ReaderCcb
->WriteQuotaAvailable
> (ULONG
)ReaderCcb
->MaxDataLength
)
955 DPRINT1("QuotaAvailable is greater than buffer size!\n");
962 KeSetEvent(&ReaderCcb
->ReadEvent
, IO_NO_INCREMENT
, FALSE
);
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
);