2 * PROJECT: ReactOS Named Pipe FileSystem
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/filesystems/npfs/fsctrl.c
5 * PURPOSE: Named Pipe FileSystem I/O Controls
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
13 // File ID number for NPFS bugchecking support
14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_FSCTRL)
16 /* GLOBALS ********************************************************************/
18 IO_STATUS_BLOCK NpUserIoStatusBlock
;
20 /* FUNCTIONS ******************************************************************/
24 NpInternalTransceive(IN PDEVICE_OBJECT DeviceObject
,
29 return STATUS_NOT_IMPLEMENTED
;
34 NpInternalRead(IN PDEVICE_OBJECT DeviceObject
,
40 return STATUS_NOT_IMPLEMENTED
;
45 NpInternalWrite(IN PDEVICE_OBJECT DeviceObject
,
50 return STATUS_NOT_IMPLEMENTED
;
55 NpQueryClientProcess(IN PDEVICE_OBJECT DeviceObject
,
59 return STATUS_NOT_IMPLEMENTED
;
64 NpSetClientProcess(IN PDEVICE_OBJECT DeviceObject
,
68 return STATUS_NOT_IMPLEMENTED
;
73 NpAssignEvent(IN PDEVICE_OBJECT DeviceObject
,
77 return STATUS_NOT_IMPLEMENTED
;
82 NpQueryEvent(IN PDEVICE_OBJECT DeviceObject
,
86 return STATUS_NOT_IMPLEMENTED
;
91 NpImpersonate(IN PDEVICE_OBJECT DeviceObject
,
97 NODE_TYPE_CODE NodeTypeCode
;
98 PIO_STACK_LOCATION IoStack
;
101 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
103 NodeTypeCode
= NpDecodeFileObject(IoStack
->FileObject
, NULL
, &Ccb
, &NamedPipeEnd
);
104 if (NodeTypeCode
== NPFS_NTC_CCB
)
106 if (NamedPipeEnd
== FILE_PIPE_SERVER_END
)
108 Status
= NpImpersonateClientContext(Ccb
);
112 Status
= STATUS_ILLEGAL_FUNCTION
;
121 NpDisconnect(IN PDEVICE_OBJECT DeviceObject
,
128 NODE_TYPE_CODE NodeTypeCode
;
129 PIO_STACK_LOCATION IoStack
;
132 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
134 NodeTypeCode
= NpDecodeFileObject(IoStack
->FileObject
, NULL
, &Ccb
, &NamedPipeEnd
);
135 if (NodeTypeCode
== NPFS_NTC_CCB
)
137 if (NamedPipeEnd
== FILE_PIPE_SERVER_END
)
139 ExAcquireResourceExclusiveLite(&Ccb
->NonPagedCcb
->Lock
, TRUE
);
141 Status
= NpSetDisconnectedPipeState(Ccb
, List
);
143 NpUninitializeSecurity(Ccb
);
145 ExReleaseResourceLite(&Ccb
->NonPagedCcb
->Lock
);
149 Status
= STATUS_ILLEGAL_FUNCTION
;
154 Status
= STATUS_PIPE_DISCONNECTED
;
162 NpListen(IN PDEVICE_OBJECT DeviceObject
,
169 NODE_TYPE_CODE NodeTypeCode
;
170 PIO_STACK_LOCATION IoStack
;
173 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
175 NodeTypeCode
= NpDecodeFileObject(IoStack
->FileObject
, NULL
, &Ccb
, &NamedPipeEnd
);
176 if (NodeTypeCode
== NPFS_NTC_CCB
)
178 if (NamedPipeEnd
== FILE_PIPE_SERVER_END
)
180 ExAcquireResourceExclusiveLite(&Ccb
->NonPagedCcb
->Lock
, TRUE
);
182 Status
= NpSetListeningPipeState(Ccb
, Irp
, List
);
184 NpUninitializeSecurity(Ccb
);
186 ExReleaseResourceLite(&Ccb
->NonPagedCcb
->Lock
);
190 Status
= STATUS_ILLEGAL_FUNCTION
;
195 Status
= STATUS_ILLEGAL_FUNCTION
;
203 NpPeek(IN PDEVICE_OBJECT DeviceObject
,
207 PIO_STACK_LOCATION IoStack
;
212 PFILE_PIPE_PEEK_BUFFER PeekBuffer
;
213 PNP_DATA_QUEUE DataQueue
;
214 ULONG_PTR BytesPeeked
;
215 IO_STATUS_BLOCK IoStatus
;
217 PNP_DATA_QUEUE_ENTRY DataEntry
;
220 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
221 OutputLength
= IoStack
->Parameters
.FileSystemControl
.OutputBufferLength
;
222 Type
= NpDecodeFileObject(IoStack
->FileObject
, NULL
, &Ccb
, &NamedPipeEnd
);
226 return STATUS_PIPE_DISCONNECTED
;
229 if ((Type
!= NPFS_NTC_CCB
) &&
230 (OutputLength
< FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
)))
232 return STATUS_INVALID_PARAMETER
;
235 PeekBuffer
= (PFILE_PIPE_PEEK_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
236 if (NamedPipeEnd
!= FILE_PIPE_CLIENT_END
)
238 if (NamedPipeEnd
!= FILE_PIPE_SERVER_END
)
240 NpBugCheck(NamedPipeEnd
, 0, 0);
243 DataQueue
= &Ccb
->DataQueue
[FILE_PIPE_INBOUND
];
247 DataQueue
= &Ccb
->DataQueue
[FILE_PIPE_OUTBOUND
];
250 if (Ccb
->NamedPipeState
!= FILE_PIPE_CONNECTED_STATE
)
252 if (Ccb
->NamedPipeState
!= FILE_PIPE_CLOSING_STATE
)
254 return STATUS_INVALID_PIPE_STATE
;
257 if (DataQueue
->QueueState
!= WriteEntries
)
259 return STATUS_PIPE_BROKEN
;
263 PeekBuffer
->NamedPipeState
= 0;
264 PeekBuffer
->ReadDataAvailable
= 0;
265 PeekBuffer
->NumberOfMessages
= 0;
266 PeekBuffer
->MessageLength
= 0;
267 PeekBuffer
->NamedPipeState
= Ccb
->NamedPipeState
;
268 BytesPeeked
= FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
);
270 if (DataQueue
->QueueState
== WriteEntries
)
272 DataEntry
= CONTAINING_RECORD(DataQueue
->Queue
.Flink
,
275 ASSERT((DataEntry
->DataEntryType
== Buffered
) || (DataEntry
->DataEntryType
== Unbuffered
));
277 PeekBuffer
->ReadDataAvailable
= DataQueue
->BytesInQueue
- DataQueue
->ByteOffset
;
278 if (Ccb
->Fcb
->NamedPipeType
== FILE_PIPE_MESSAGE_TYPE
)
280 PeekBuffer
->NumberOfMessages
= DataQueue
->EntriesInQueue
;
281 PeekBuffer
->MessageLength
= DataEntry
->DataSize
- DataQueue
->ByteOffset
;
284 if (OutputLength
== FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
))
286 Status
= PeekBuffer
->ReadDataAvailable
? STATUS_BUFFER_OVERFLOW
: STATUS_SUCCESS
;
290 IoStatus
= NpReadDataQueue(DataQueue
,
294 OutputLength
- FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER
, Data
),
295 Ccb
->Fcb
->NamedPipeType
== FILE_PIPE_MESSAGE_TYPE
,
298 Status
= IoStatus
.Status
;
299 BytesPeeked
+= IoStatus
.Information
;
304 Status
= STATUS_SUCCESS
;
307 Irp
->IoStatus
.Information
= BytesPeeked
;
313 NpCompleteTransceiveIrp(IN PDEVICE_OBJECT DeviceObject
,
319 if (Irp
->AssociatedIrp
.SystemBuffer
)
321 ExFreePool(Irp
->AssociatedIrp
.SystemBuffer
);
325 return STATUS_MORE_PROCESSING_REQUIRED
;
330 NpTransceive(IN PDEVICE_OBJECT DeviceObject
,
334 PIO_STACK_LOCATION IoStack
;
335 PVOID InBuffer
, OutBuffer
;
336 ULONG InLength
, OutLength
, BytesWritten
;
337 NODE_TYPE_CODE NodeTypeCode
;
340 PNP_NONPAGED_CCB NonPagedCcb
;
341 PNP_DATA_QUEUE ReadQueue
, WriteQueue
;
342 PNP_EVENT_BUFFER EventBuffer
;
347 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
348 InLength
= IoStack
->Parameters
.FileSystemControl
.InputBufferLength
;
349 InBuffer
= IoStack
->Parameters
.FileSystemControl
.Type3InputBuffer
;
350 OutLength
= IoStack
->Parameters
.FileSystemControl
.OutputBufferLength
;
351 OutBuffer
= Irp
->UserBuffer
;
353 if (Irp
->RequestorMode
== UserMode
)
357 ProbeForRead(InBuffer
, InLength
, sizeof(CHAR
));
358 ProbeForWrite(OutBuffer
, OutLength
, sizeof(CHAR
));
360 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
362 _SEH2_YIELD(return _SEH2_GetExceptionCode());
367 NodeTypeCode
= NpDecodeFileObject(IoStack
->FileObject
, NULL
, &Ccb
, &NamedPipeEnd
);
368 if (NodeTypeCode
!= NPFS_NTC_CCB
)
370 return STATUS_PIPE_DISCONNECTED
;
373 NonPagedCcb
= Ccb
->NonPagedCcb
;
374 ExAcquireResourceExclusiveLite(&NonPagedCcb
->Lock
, TRUE
);
376 if (Ccb
->NamedPipeState
!= FILE_PIPE_CONNECTED_STATE
)
378 Status
= STATUS_INVALID_PIPE_STATE
;
382 if (NamedPipeEnd
!= FILE_PIPE_CLIENT_END
)
384 if (NamedPipeEnd
!= FILE_PIPE_SERVER_END
)
386 NpBugCheck(NamedPipeEnd
, 0, 0);
388 ReadQueue
= &Ccb
->DataQueue
[FILE_PIPE_INBOUND
];
389 WriteQueue
= &Ccb
->DataQueue
[FILE_PIPE_OUTBOUND
];
393 ReadQueue
= &Ccb
->DataQueue
[FILE_PIPE_OUTBOUND
];
394 WriteQueue
= &Ccb
->DataQueue
[FILE_PIPE_INBOUND
];
397 EventBuffer
= NonPagedCcb
->EventBuffer
[NamedPipeEnd
];
399 if (Ccb
->Fcb
->NamedPipeConfiguration
!= FILE_PIPE_FULL_DUPLEX
||
400 Ccb
->ReadMode
[NamedPipeEnd
] != FILE_PIPE_MESSAGE_MODE
)
402 Status
= STATUS_INVALID_PIPE_STATE
;
406 if (ReadQueue
->QueueState
!= Empty
)
408 Status
= STATUS_PIPE_BUSY
;
412 Status
= NpWriteDataQueue(WriteQueue
,
416 Ccb
->Fcb
->NamedPipeType
,
420 Irp
->Tail
.Overlay
.Thread
,
422 if (Status
== STATUS_MORE_PROCESSING_REQUIRED
)
424 ASSERT(WriteQueue
->QueueState
!= ReadEntries
);
425 NewIrp
= IoAllocateIrp(DeviceObject
->StackSize
, TRUE
);
428 Status
= STATUS_INSUFFICIENT_RESOURCES
;
432 IoSetCompletionRoutine(Irp
, NpCompleteTransceiveIrp
, NULL
, TRUE
, TRUE
, TRUE
);
436 NewIrp
->AssociatedIrp
.SystemBuffer
= ExAllocatePoolWithQuotaTag(PagedPool
| POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
438 NPFS_WRITE_BLOCK_TAG
);
439 if (!NewIrp
->AssociatedIrp
.SystemBuffer
)
442 Status
= STATUS_INSUFFICIENT_RESOURCES
;
448 RtlCopyMemory(NewIrp
->AssociatedIrp
.SystemBuffer
,
449 (PVOID
)((ULONG_PTR
)InBuffer
+ InLength
- BytesWritten
),
452 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
454 Status
= _SEH2_GetExceptionCode();
455 _SEH2_YIELD(goto Quickie
);
461 NewIrp
->AssociatedIrp
.SystemBuffer
= NULL
;
464 IoStack
= IoGetNextIrpStackLocation(NewIrp
);
465 IoSetNextIrpStackLocation(NewIrp
);
467 NewIrp
->Tail
.Overlay
.Thread
= Irp
->Tail
.Overlay
.Thread
;
468 NewIrp
->IoStatus
.Information
= BytesWritten
;
470 IoStack
->Parameters
.Read
.Length
= BytesWritten
;
471 IoStack
->MajorFunction
= IRP_MJ_WRITE
;
473 if (BytesWritten
> 0) NewIrp
->Flags
= IRP_DEALLOCATE_BUFFER
| IRP_BUFFERED_IO
;
474 NewIrp
->UserIosb
= &NpUserIoStatusBlock
;
476 Status
= NpAddDataQueueEntry(NamedPipeEnd
,
485 if (Status
!= STATUS_PENDING
)
487 NewIrp
->IoStatus
.Status
= Status
;
488 InsertTailList(List
, &NewIrp
->Tail
.Overlay
.ListEntry
);
492 if (!NT_SUCCESS(Status
)) goto Quickie
;
494 if (EventBuffer
) KeSetEvent(EventBuffer
->Event
, IO_NO_INCREMENT
, FALSE
);
495 ASSERT(ReadQueue
->QueueState
== Empty
);
496 Status
= NpAddDataQueueEntry(NamedPipeEnd
,
505 if (NT_SUCCESS(Status
))
507 if (EventBuffer
) KeSetEvent(EventBuffer
->Event
, IO_NO_INCREMENT
, FALSE
);
511 ExReleaseResourceLite(&Ccb
->NonPagedCcb
->Lock
);
517 NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject
,
520 PIO_STACK_LOCATION IoStack
;
521 ULONG InLength
, NameLength
;
522 UNICODE_STRING SourceString
, Prefix
;
525 PFILE_PIPE_WAIT_FOR_BUFFER Buffer
;
527 NODE_TYPE_CODE NodeTypeCode
;
528 PLIST_ENTRY NextEntry
;
530 PWCHAR OriginalBuffer
;
533 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
534 InLength
= IoStack
->Parameters
.FileSystemControl
.InputBufferLength
;
536 SourceString
.Buffer
= NULL
;
538 if (NpDecodeFileObject(IoStack
->FileObject
,
541 &NamedPipeEnd
) != NPFS_NTC_ROOT_DCB
)
543 Status
= STATUS_ILLEGAL_FUNCTION
;
547 Buffer
= (PFILE_PIPE_WAIT_FOR_BUFFER
)Irp
->AssociatedIrp
.SystemBuffer
;
548 if (InLength
< sizeof(*Buffer
))
550 Status
= STATUS_INVALID_PARAMETER
;
554 NameLength
= Buffer
->NameLength
;
555 if ((NameLength
> (0xFFFF - sizeof(UNICODE_NULL
))) ||
556 ((NameLength
+ FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER
, Name
)) > InLength
))
558 Status
= STATUS_INVALID_PARAMETER
;
562 SourceString
.Length
= (USHORT
)NameLength
+ sizeof(OBJ_NAME_PATH_SEPARATOR
);
563 SourceString
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
565 NPFS_WRITE_BLOCK_TAG
);
566 if (!SourceString
.Buffer
)
568 Status
= STATUS_INSUFFICIENT_RESOURCES
;
572 SourceString
.Buffer
[0] = OBJ_NAME_PATH_SEPARATOR
;
573 RtlCopyMemory(&SourceString
.Buffer
[1], Buffer
->Name
, Buffer
->NameLength
);
575 Status
= STATUS_SUCCESS
;
576 OriginalBuffer
= SourceString
.Buffer
;
577 //Status = NpTranslateAlias(&SourceString);
578 if (!NT_SUCCESS(Status
)) goto Quickie
;
580 Fcb
= NpFindPrefix(&SourceString
, TRUE
, &Prefix
);
581 Fcb
= (PNP_FCB
)((ULONG_PTR
)Fcb
& ~1);
583 NodeTypeCode
= Fcb
? Fcb
->NodeType
: 0;
584 if (NodeTypeCode
!= NPFS_NTC_FCB
)
586 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
590 for (NextEntry
= Fcb
->CcbList
.Flink
;
591 NextEntry
!= &Fcb
->CcbList
;
592 NextEntry
= NextEntry
->Flink
)
594 Ccb
= CONTAINING_RECORD(NextEntry
, NP_CCB
, CcbEntry
);
595 if (Ccb
->NamedPipeState
== FILE_PIPE_LISTENING_STATE
) break;
598 if (NextEntry
!= &Fcb
->CcbList
)
600 Status
= STATUS_SUCCESS
;
604 Status
= NpAddWaiter(&NpVcb
->WaitQueue
,
607 OriginalBuffer
== SourceString
.Buffer
?
608 NULL
: &SourceString
);
612 if (SourceString
.Buffer
) ExFreePool(SourceString
.Buffer
);
618 NpCommonFileSystemControl(IN PDEVICE_OBJECT DeviceObject
,
622 BOOLEAN Overflow
= FALSE
;
623 LIST_ENTRY DeferredList
;
627 InitializeListHead(&DeferredList
);
628 Fsctl
= IoGetCurrentIrpStackLocation(Irp
)->Parameters
.FileSystemControl
.FsControlCode
;
632 case FSCTL_PIPE_PEEK
:
633 NpAcquireExclusiveVcb();
634 Status
= NpPeek(DeviceObject
, Irp
, &DeferredList
);
637 case FSCTL_PIPE_INTERNAL_WRITE
:
638 NpAcquireSharedVcb();
639 Status
= NpInternalWrite(DeviceObject
, Irp
, &DeferredList
);
642 case FSCTL_PIPE_TRANSCEIVE
:
643 NpAcquireSharedVcb();
644 Status
= NpTransceive(DeviceObject
, Irp
, &DeferredList
);
647 case FSCTL_PIPE_INTERNAL_TRANSCEIVE
:
648 NpAcquireSharedVcb();
649 Status
= NpInternalTransceive(DeviceObject
, Irp
, &DeferredList
);
652 case FSCTL_PIPE_INTERNAL_READ_OVFLOW
:
656 case FSCTL_PIPE_INTERNAL_READ
:
657 NpAcquireSharedVcb();
658 Status
= NpInternalRead(DeviceObject
, Irp
, Overflow
, &DeferredList
);
661 case FSCTL_PIPE_QUERY_CLIENT_PROCESS
:
663 NpAcquireSharedVcb();
664 Status
= NpQueryClientProcess(DeviceObject
, Irp
);
667 case FSCTL_PIPE_ASSIGN_EVENT
:
669 NpAcquireExclusiveVcb();
670 Status
= NpAssignEvent(DeviceObject
, Irp
);
673 case FSCTL_PIPE_DISCONNECT
:
675 NpAcquireExclusiveVcb();
676 Status
= NpDisconnect(DeviceObject
, Irp
, &DeferredList
);
679 case FSCTL_PIPE_LISTEN
:
681 NpAcquireSharedVcb();
682 Status
= NpListen(DeviceObject
, Irp
, &DeferredList
);
685 case FSCTL_PIPE_QUERY_EVENT
:
687 NpAcquireExclusiveVcb();
688 Status
= NpQueryEvent(DeviceObject
, Irp
);
691 case FSCTL_PIPE_WAIT
:
693 NpAcquireExclusiveVcb();
694 Status
= NpWaitForNamedPipe(DeviceObject
, Irp
);
697 case FSCTL_PIPE_IMPERSONATE
:
699 NpAcquireExclusiveVcb();
700 Status
= NpImpersonate(DeviceObject
, Irp
);
703 case FSCTL_PIPE_SET_CLIENT_PROCESS
:
704 NpAcquireExclusiveVcb();
705 Status
= NpSetClientProcess(DeviceObject
, Irp
);
709 return STATUS_NOT_SUPPORTED
;
713 NpCompleteDeferredIrps(&DeferredList
);
720 NpFsdFileSystemControl(IN PDEVICE_OBJECT DeviceObject
,
726 FsRtlEnterFileSystem();
728 Status
= NpCommonFileSystemControl(DeviceObject
, Irp
);
730 FsRtlExitFileSystem();
732 if (Status
!= STATUS_PENDING
)
734 Irp
->IoStatus
.Status
= Status
;
735 IoCompleteRequest(Irp
, IO_NAMED_PIPE_INCREMENT
);