xref: /reactos/drivers/filesystems/npfs/fsctrl.c (revision d7fd62d4)
1 /*
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
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include "npfs.h"
12 
13 // File ID number for NPFS bugchecking support
14 #define NPFS_BUGCHECK_FILE_ID   (NPFS_BUGCHECK_FSCTRL)
15 
16 /* GLOBALS ********************************************************************/
17 
18 IO_STATUS_BLOCK NpUserIoStatusBlock;
19 
20 /* FUNCTIONS ******************************************************************/
21 
22 NTSTATUS
23 NTAPI
24 NpInternalTransceive(IN PDEVICE_OBJECT DeviceObject,
25                      IN PIRP Irp,
26                      IN PLIST_ENTRY List)
27 {
28     UNIMPLEMENTED;
29     return STATUS_NOT_IMPLEMENTED;
30 }
31 
32 NTSTATUS
33 NTAPI
34 NpInternalRead(IN PDEVICE_OBJECT DeviceObject,
35                IN PIRP Irp,
36                IN BOOLEAN Overflow,
37                IN PLIST_ENTRY List)
38 {
39     UNIMPLEMENTED;
40     return STATUS_NOT_IMPLEMENTED;
41 }
42 
43 NTSTATUS
44 NTAPI
45 NpInternalWrite(IN PDEVICE_OBJECT DeviceObject,
46                 IN PIRP Irp,
47                 IN PLIST_ENTRY List)
48 {
49     UNIMPLEMENTED;
50     return STATUS_NOT_IMPLEMENTED;
51 }
52 
53 NTSTATUS
54 NTAPI
55 NpQueryClientProcess(IN PDEVICE_OBJECT DeviceObject,
56                    IN PIRP Irp)
57 {
58     PIO_STACK_LOCATION IoStackLocation;
59     NODE_TYPE_CODE NodeTypeCode;
60     PNP_CCB Ccb;
61     PNP_CLIENT_PROCESS ClientSession, QueryBuffer;
62     ULONG Length;
63     PAGED_CODE();
64 
65     /* Get the current stack location */
66     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
67 
68     /* Decode the file object and check the node type */
69     NodeTypeCode = NpDecodeFileObject(IoStackLocation->FileObject, 0, &Ccb, 0);
70     if (NodeTypeCode != NPFS_NTC_CCB)
71     {
72         return STATUS_PIPE_DISCONNECTED;
73     }
74 
75     /* Get the length of the query buffer */
76     Length = IoStackLocation->Parameters.QueryFile.Length;
77     if (Length < 8)
78     {
79         return STATUS_INVALID_PARAMETER;
80     }
81 
82     QueryBuffer = Irp->AssociatedIrp.SystemBuffer;
83 
84     /* Lock the Ccb */
85     ExAcquireResourceExclusiveLite(&Ccb->NonPagedCcb->Lock, TRUE);
86 
87     /* Get the CCBs client session and check if it's set */
88     ClientSession = Ccb->ClientSession;
89     if (ClientSession != NULL)
90     {
91         /* Copy first 2 fields */
92         QueryBuffer->Unknown = ClientSession->Unknown;
93         QueryBuffer->Process = ClientSession->Process;
94     }
95     else
96     {
97         /* Copy the process from the CCB */
98         QueryBuffer->Unknown = NULL;
99         QueryBuffer->Process = Ccb->Process;
100     }
101 
102     /* Does the caller provide a large enough buffer for the full data? */
103     if (Length >= sizeof(NP_CLIENT_PROCESS))
104     {
105         Irp->IoStatus.Information = sizeof(NP_CLIENT_PROCESS);
106 
107         /* Do we have a ClientSession structure? */
108         if (ClientSession != NULL)
109         {
110             /* Copy length and the data */
111             QueryBuffer->DataLength = ClientSession->DataLength;
112             RtlCopyMemory(QueryBuffer->Buffer,
113                           ClientSession->Buffer,
114                           ClientSession->DataLength);
115 
116             /* NULL terminate the buffer */
117             NT_ASSERT(QueryBuffer->DataLength <= 30);
118             QueryBuffer->Buffer[QueryBuffer->DataLength / sizeof(WCHAR)] = 0;
119         }
120         else
121         {
122             /* No data */
123             QueryBuffer->DataLength = 0;
124             QueryBuffer->Buffer[0] = 0;
125         }
126     }
127     else
128     {
129         Irp->IoStatus.Information = FIELD_OFFSET(NP_CLIENT_PROCESS, DataLength);
130     }
131 
132     /* Unlock the Ccb */
133     ExReleaseResourceLite(&Ccb->NonPagedCcb->Lock);
134 
135     return STATUS_SUCCESS;
136 }
137 
138 NTSTATUS
139 NTAPI
140 NpSetClientProcess(IN PDEVICE_OBJECT DeviceObject,
141                    IN PIRP Irp)
142 {
143     PIO_STACK_LOCATION IoStackLocation;
144     NODE_TYPE_CODE NodeTypeCode;
145     PNP_CCB Ccb;
146     ULONG Length;
147     PNP_CLIENT_PROCESS InputBuffer, ClientSession, OldClientSession;
148     PAGED_CODE();
149 
150     /* Get the current stack location */
151     IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
152 
153     /* Only kernel calls are allowed! */
154     if (IoStackLocation->MinorFunction != IRP_MN_KERNEL_CALL)
155     {
156         return STATUS_ACCESS_DENIED;
157     }
158 
159     /* Decode the file object and check the node type */
160     NodeTypeCode = NpDecodeFileObject(IoStackLocation->FileObject, 0, &Ccb, 0);
161     if (NodeTypeCode != NPFS_NTC_CCB)
162     {
163         return STATUS_PIPE_DISCONNECTED;
164     }
165 
166     /* Get the length of the query buffer and check if it's valid */
167     Length = IoStackLocation->Parameters.QueryFile.Length;
168     if (Length != sizeof(NP_CLIENT_PROCESS))
169     {
170         return STATUS_INVALID_PARAMETER;
171     }
172 
173     /* Get the buffer and check if the data Length is valid */
174     InputBuffer = Irp->AssociatedIrp.SystemBuffer;
175     if (InputBuffer->DataLength > 30)
176     {
177         return STATUS_INVALID_PARAMETER;
178     }
179 
180     /* Allocate a new structure */
181     ClientSession = ExAllocatePoolWithQuotaTag(PagedPool,
182                                                sizeof(NP_CLIENT_PROCESS),
183                                                'iFpN');
184 
185     /* Copy the full input buffer */
186     RtlCopyMemory(ClientSession, InputBuffer, sizeof(NP_CLIENT_PROCESS));
187 
188     /* Lock the Ccb */
189     ExAcquireResourceExclusiveLite(&Ccb->NonPagedCcb->Lock, TRUE);
190 
191     /* Get the old ClientSession and set the new */
192     OldClientSession = Ccb->ClientSession;
193     Ccb->ClientSession = ClientSession;
194 
195     /* Copy the process to the CCB */
196     Ccb->Process = ClientSession->Process;
197 
198     /* Unlock the Ccb */
199     ExReleaseResourceLite(&Ccb->NonPagedCcb->Lock);
200 
201     /* Check if there was already a ClientSession */
202     if (OldClientSession != NULL)
203     {
204         /* Free it */
205         ExFreePoolWithTag(OldClientSession, 'iFpN');
206     }
207 
208     return STATUS_SUCCESS;
209 }
210 
211 NTSTATUS
212 NTAPI
213 NpAssignEvent(IN PDEVICE_OBJECT DeviceObject,
214               IN PIRP Irp)
215 {
216     UNIMPLEMENTED;
217     return STATUS_NOT_IMPLEMENTED;
218 }
219 
220 NTSTATUS
221 NTAPI
222 NpQueryEvent(IN PDEVICE_OBJECT DeviceObject,
223              IN PIRP Irp)
224 {
225     UNIMPLEMENTED;
226     return STATUS_NOT_IMPLEMENTED;
227 }
228 
229 NTSTATUS
230 NTAPI
231 NpImpersonate(IN PDEVICE_OBJECT DeviceObject,
232               IN PIRP Irp)
233 {
234     ULONG NamedPipeEnd;
235     PNP_CCB Ccb;
236     NTSTATUS Status;
237     NODE_TYPE_CODE NodeTypeCode;
238     PIO_STACK_LOCATION IoStack;
239     PAGED_CODE();
240 
241     IoStack = IoGetCurrentIrpStackLocation(Irp);
242 
243     NodeTypeCode = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
244     if (NodeTypeCode == NPFS_NTC_CCB && NamedPipeEnd == FILE_PIPE_SERVER_END)
245     {
246         Status = NpImpersonateClientContext(Ccb);
247     }
248     else
249     {
250         Status = STATUS_ILLEGAL_FUNCTION;
251     }
252 
253     return Status;
254 }
255 
256 NTSTATUS
257 NTAPI
258 NpDisconnect(IN PDEVICE_OBJECT DeviceObject,
259              IN PIRP Irp,
260              IN PLIST_ENTRY List)
261 {
262     ULONG NamedPipeEnd;
263     PNP_CCB Ccb;
264     NTSTATUS Status;
265     NODE_TYPE_CODE NodeTypeCode;
266     PIO_STACK_LOCATION IoStack;
267     PAGED_CODE();
268 
269     IoStack = IoGetCurrentIrpStackLocation(Irp);
270 
271     NodeTypeCode = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
272     if (NodeTypeCode == NPFS_NTC_CCB)
273     {
274         if (NamedPipeEnd == FILE_PIPE_SERVER_END)
275         {
276             ExAcquireResourceExclusiveLite(&Ccb->NonPagedCcb->Lock, TRUE);
277 
278             Status = NpSetDisconnectedPipeState(Ccb, List);
279 
280             NpUninitializeSecurity(Ccb);
281 
282             ExReleaseResourceLite(&Ccb->NonPagedCcb->Lock);
283         }
284         else
285         {
286             Status = STATUS_ILLEGAL_FUNCTION;
287         }
288     }
289     else
290     {
291         Status = STATUS_PIPE_DISCONNECTED;
292     }
293 
294     return Status;
295 }
296 
297 NTSTATUS
298 NTAPI
299 NpListen(IN PDEVICE_OBJECT DeviceObject,
300          IN PIRP Irp,
301          IN PLIST_ENTRY List)
302 {
303     ULONG NamedPipeEnd;
304     PNP_CCB Ccb;
305     NTSTATUS Status;
306     NODE_TYPE_CODE NodeTypeCode;
307     PIO_STACK_LOCATION IoStack;
308     PAGED_CODE();
309 
310     IoStack = IoGetCurrentIrpStackLocation(Irp);
311 
312     NodeTypeCode = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
313     if (NodeTypeCode == NPFS_NTC_CCB)
314     {
315         if (NamedPipeEnd == FILE_PIPE_SERVER_END)
316         {
317             ExAcquireResourceExclusiveLite(&Ccb->NonPagedCcb->Lock, TRUE);
318 
319             Status = NpSetListeningPipeState(Ccb, Irp, List);
320 
321             NpUninitializeSecurity(Ccb);
322 
323             ExReleaseResourceLite(&Ccb->NonPagedCcb->Lock);
324         }
325         else
326         {
327             Status = STATUS_ILLEGAL_FUNCTION;
328         }
329     }
330     else
331     {
332         Status = STATUS_ILLEGAL_FUNCTION;
333     }
334 
335     return Status;
336 }
337 
338 NTSTATUS
339 NTAPI
340 NpPeek(IN PDEVICE_OBJECT DeviceObject,
341        IN PIRP Irp,
342        IN PLIST_ENTRY List)
343 {
344     PIO_STACK_LOCATION IoStack;
345     NODE_TYPE_CODE Type;
346     ULONG OutputLength;
347     ULONG NamedPipeEnd;
348     PNP_CCB Ccb;
349     PFILE_PIPE_PEEK_BUFFER PeekBuffer;
350     PNP_DATA_QUEUE DataQueue;
351     ULONG_PTR BytesPeeked;
352     IO_STATUS_BLOCK IoStatus;
353     NTSTATUS Status;
354     PNP_DATA_QUEUE_ENTRY DataEntry;
355     PAGED_CODE();
356 
357     IoStack = IoGetCurrentIrpStackLocation(Irp);
358     OutputLength = IoStack->Parameters.FileSystemControl.OutputBufferLength;
359     Type = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
360 
361     if (!Type)
362     {
363         return STATUS_PIPE_DISCONNECTED;
364     }
365 
366     if ((Type != NPFS_NTC_CCB) &&
367         (OutputLength < FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data)))
368     {
369         return STATUS_INVALID_PARAMETER;
370     }
371 
372     PeekBuffer = Irp->AssociatedIrp.SystemBuffer;
373     if (NamedPipeEnd != FILE_PIPE_CLIENT_END)
374     {
375         if (NamedPipeEnd != FILE_PIPE_SERVER_END)
376         {
377             NpBugCheck(NamedPipeEnd, 0, 0);
378         }
379 
380         DataQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
381     }
382     else
383     {
384         DataQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
385     }
386 
387     if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE)
388     {
389         if (Ccb->NamedPipeState != FILE_PIPE_CLOSING_STATE)
390         {
391             return STATUS_INVALID_PIPE_STATE;
392         }
393 
394         if (DataQueue->QueueState != WriteEntries)
395         {
396             return STATUS_PIPE_BROKEN;
397         }
398     }
399 
400     PeekBuffer->NamedPipeState = 0;
401     PeekBuffer->ReadDataAvailable = 0;
402     PeekBuffer->NumberOfMessages = 0;
403     PeekBuffer->MessageLength = 0;
404     PeekBuffer->NamedPipeState = Ccb->NamedPipeState;
405     BytesPeeked = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data);
406 
407     if (DataQueue->QueueState == WriteEntries)
408     {
409         DataEntry = CONTAINING_RECORD(DataQueue->Queue.Flink,
410                                       NP_DATA_QUEUE_ENTRY,
411                                       QueueEntry);
412         ASSERT((DataEntry->DataEntryType == Buffered) || (DataEntry->DataEntryType == Unbuffered));
413 
414         PeekBuffer->ReadDataAvailable = DataQueue->BytesInQueue - DataQueue->ByteOffset;
415         if (Ccb->Fcb->NamedPipeType == FILE_PIPE_MESSAGE_TYPE)
416         {
417             PeekBuffer->NumberOfMessages = DataQueue->EntriesInQueue;
418             PeekBuffer->MessageLength = DataEntry->DataSize - DataQueue->ByteOffset;
419         }
420 
421         if (OutputLength == FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data))
422         {
423             Status = PeekBuffer->ReadDataAvailable ? STATUS_BUFFER_OVERFLOW : STATUS_SUCCESS;
424         }
425         else
426         {
427             IoStatus = NpReadDataQueue(DataQueue,
428                                        TRUE,
429                                        FALSE,
430                                        PeekBuffer->Data,
431                                        OutputLength - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data),
432                                        Ccb->Fcb->NamedPipeType == FILE_PIPE_MESSAGE_TYPE,
433                                        Ccb,
434                                        List);
435             Status = IoStatus.Status;
436             BytesPeeked += IoStatus.Information;
437         }
438     }
439     else
440     {
441         Status = STATUS_SUCCESS;
442     }
443 
444     Irp->IoStatus.Information = BytesPeeked;
445     return Status;
446 }
447 
448 NTSTATUS
449 NTAPI
450 NpCompleteTransceiveIrp(IN PDEVICE_OBJECT DeviceObject,
451                         IN PIRP Irp,
452                         IN PVOID Context)
453 {
454     PAGED_CODE();
455 
456     if (Irp->AssociatedIrp.SystemBuffer)
457     {
458         ExFreePool(Irp->AssociatedIrp.SystemBuffer);
459     }
460 
461     IoFreeIrp(Irp);
462     return STATUS_MORE_PROCESSING_REQUIRED;
463 }
464 
465 NTSTATUS
466 NTAPI
467 NpTransceive(IN PDEVICE_OBJECT DeviceObject,
468              IN PIRP Irp,
469              IN PLIST_ENTRY List)
470 {
471     PIO_STACK_LOCATION IoStack;
472     PVOID InBuffer, OutBuffer;
473     ULONG InLength, OutLength, BytesWritten;
474     NODE_TYPE_CODE NodeTypeCode;
475     PNP_CCB Ccb;
476     ULONG NamedPipeEnd;
477     PNP_NONPAGED_CCB NonPagedCcb;
478     PNP_DATA_QUEUE ReadQueue, WriteQueue;
479     PNP_EVENT_BUFFER EventBuffer;
480     NTSTATUS Status;
481     PIRP NewIrp;
482     PAGED_CODE();
483 
484     IoStack = IoGetCurrentIrpStackLocation(Irp);
485     InLength = IoStack->Parameters.FileSystemControl.InputBufferLength;
486     InBuffer = IoStack->Parameters.FileSystemControl.Type3InputBuffer;
487     OutLength = IoStack->Parameters.FileSystemControl.OutputBufferLength;
488     OutBuffer = Irp->UserBuffer;
489 
490     if (Irp->RequestorMode == UserMode)
491     {
492         _SEH2_TRY
493         {
494             ProbeForRead(InBuffer, InLength, sizeof(CHAR));
495             ProbeForWrite(OutBuffer, OutLength, sizeof(CHAR));
496         }
497         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
498         {
499             _SEH2_YIELD(return _SEH2_GetExceptionCode());
500         }
501         _SEH2_END;
502     }
503 
504     NodeTypeCode = NpDecodeFileObject(IoStack->FileObject, NULL, &Ccb, &NamedPipeEnd);
505     if (NodeTypeCode != NPFS_NTC_CCB)
506     {
507         return STATUS_PIPE_DISCONNECTED;
508     }
509 
510     NonPagedCcb = Ccb->NonPagedCcb;
511     ExAcquireResourceExclusiveLite(&NonPagedCcb->Lock, TRUE);
512 
513     if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE)
514     {
515         Status = STATUS_INVALID_PIPE_STATE;
516         goto Quickie;
517     }
518 
519     if (NamedPipeEnd != FILE_PIPE_CLIENT_END)
520     {
521         if (NamedPipeEnd != FILE_PIPE_SERVER_END)
522         {
523             NpBugCheck(NamedPipeEnd, 0, 0);
524         }
525         ReadQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
526         WriteQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
527     }
528     else
529     {
530         ReadQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
531         WriteQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
532     }
533 
534     EventBuffer = NonPagedCcb->EventBuffer[NamedPipeEnd];
535 
536     if (Ccb->Fcb->NamedPipeConfiguration != FILE_PIPE_FULL_DUPLEX ||
537         Ccb->ReadMode[NamedPipeEnd] != FILE_PIPE_MESSAGE_MODE)
538     {
539         Status = STATUS_INVALID_PIPE_STATE;
540         goto Quickie;
541     }
542 
543     if (ReadQueue->QueueState != Empty)
544     {
545         Status = STATUS_PIPE_BUSY;
546         goto Quickie;
547     }
548 
549     Status = NpWriteDataQueue(WriteQueue,
550                               FILE_PIPE_MESSAGE_MODE,
551                               InBuffer,
552                               InLength,
553                               Ccb->Fcb->NamedPipeType,
554                               &BytesWritten,
555                               Ccb,
556                               NamedPipeEnd,
557                               Irp->Tail.Overlay.Thread,
558                               List);
559     if (Status == STATUS_MORE_PROCESSING_REQUIRED)
560     {
561         ASSERT(WriteQueue->QueueState != ReadEntries);
562         NewIrp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
563         if (!NewIrp)
564         {
565             Status = STATUS_INSUFFICIENT_RESOURCES;
566             goto Quickie;
567         }
568 
569         IoSetCompletionRoutine(NewIrp, NpCompleteTransceiveIrp, NULL, TRUE, TRUE, TRUE);
570 
571         if (BytesWritten)
572         {
573             NewIrp->AssociatedIrp.SystemBuffer = ExAllocatePoolWithQuotaTag(PagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
574                                                                             BytesWritten,
575                                                                             NPFS_WRITE_BLOCK_TAG);
576             if (!NewIrp->AssociatedIrp.SystemBuffer)
577             {
578                 IoFreeIrp(NewIrp);
579                 Status = STATUS_INSUFFICIENT_RESOURCES;
580                 goto Quickie;
581             }
582 
583             _SEH2_TRY
584             {
585                 RtlCopyMemory(NewIrp->AssociatedIrp.SystemBuffer,
586                               (PVOID)((ULONG_PTR)InBuffer + InLength - BytesWritten),
587                               BytesWritten);
588             }
589             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
590             {
591                 Status = _SEH2_GetExceptionCode();
592                 _SEH2_YIELD(goto Quickie);
593             }
594             _SEH2_END;
595         }
596         else
597         {
598             NewIrp->AssociatedIrp.SystemBuffer = NULL;
599         }
600 
601         IoStack = IoGetNextIrpStackLocation(NewIrp);
602         IoSetNextIrpStackLocation(NewIrp);
603 
604         NewIrp->Tail.Overlay.Thread = Irp->Tail.Overlay.Thread;
605         NewIrp->IoStatus.Information = BytesWritten;
606 
607         IoStack->Parameters.Write.Length = BytesWritten;
608         IoStack->MajorFunction = IRP_MJ_WRITE;
609 
610         if (BytesWritten > 0) NewIrp->Flags = IRP_DEALLOCATE_BUFFER | IRP_BUFFERED_IO;
611         NewIrp->UserIosb = &NpUserIoStatusBlock;
612 
613         Status = NpAddDataQueueEntry(NamedPipeEnd,
614                                      Ccb,
615                                      WriteQueue,
616                                      WriteEntries,
617                                      Unbuffered,
618                                      BytesWritten,
619                                      NewIrp,
620                                      NULL,
621                                      0);
622         if (Status != STATUS_PENDING)
623         {
624             NewIrp->IoStatus.Status = Status;
625             InsertTailList(List, &NewIrp->Tail.Overlay.ListEntry);
626         }
627     }
628 
629     if (!NT_SUCCESS(Status)) goto Quickie;
630 
631     if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE);
632     ASSERT(ReadQueue->QueueState == Empty);
633     Status = NpAddDataQueueEntry(NamedPipeEnd,
634                                  Ccb,
635                                  ReadQueue,
636                                  ReadEntries,
637                                  Buffered,
638                                  OutLength,
639                                  Irp,
640                                  NULL,
641                                  0);
642     if (NT_SUCCESS(Status))
643     {
644         if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE);
645     }
646 
647 Quickie:
648     ExReleaseResourceLite(&Ccb->NonPagedCcb->Lock);
649     return Status;
650 }
651 
652 NTSTATUS
653 NTAPI
654 NpWaitForNamedPipe(IN PDEVICE_OBJECT DeviceObject,
655                    IN PIRP Irp)
656 {
657     PIO_STACK_LOCATION IoStack;
658     ULONG InLength, NameLength;
659     UNICODE_STRING SourceString, Prefix;
660     ULONG NamedPipeEnd;
661     PNP_CCB Ccb;
662     PFILE_PIPE_WAIT_FOR_BUFFER Buffer;
663     NTSTATUS Status;
664     NODE_TYPE_CODE NodeTypeCode;
665     PLIST_ENTRY NextEntry;
666     PNP_FCB Fcb;
667     PWCHAR OriginalBuffer;
668     PAGED_CODE();
669 
670     IoStack = IoGetCurrentIrpStackLocation(Irp);
671     InLength = IoStack->Parameters.FileSystemControl.InputBufferLength;
672 
673     SourceString.Buffer = NULL;
674 
675     if (NpDecodeFileObject(IoStack->FileObject,
676                            NULL,
677                            &Ccb,
678                            &NamedPipeEnd) != NPFS_NTC_ROOT_DCB)
679     {
680         Status = STATUS_ILLEGAL_FUNCTION;
681         goto Quickie;
682     }
683 
684     Buffer = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
685     if (InLength < sizeof(*Buffer))
686     {
687         Status = STATUS_INVALID_PARAMETER;
688         goto Quickie;
689     }
690 
691     NameLength = Buffer->NameLength;
692     if ((NameLength > (0xFFFF - sizeof(UNICODE_NULL))) ||
693         ((NameLength + FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name)) > InLength))
694     {
695         Status = STATUS_INVALID_PARAMETER;
696         goto Quickie;
697     }
698 
699     SourceString.Length = (USHORT)NameLength + sizeof(OBJ_NAME_PATH_SEPARATOR);
700     SourceString.Buffer = ExAllocatePoolWithTag(PagedPool,
701                                                 SourceString.Length,
702                                                 NPFS_WRITE_BLOCK_TAG);
703     if (!SourceString.Buffer)
704     {
705         Status = STATUS_INSUFFICIENT_RESOURCES;
706         goto Quickie;
707     }
708 
709     SourceString.Buffer[0] = OBJ_NAME_PATH_SEPARATOR;
710     RtlCopyMemory(&SourceString.Buffer[1], Buffer->Name, Buffer->NameLength);
711 
712     Status = STATUS_SUCCESS;
713     OriginalBuffer = SourceString.Buffer;
714     //Status = NpTranslateAlias(&SourceString);
715     if (!NT_SUCCESS(Status)) goto Quickie;
716 
717     Fcb = NpFindPrefix(&SourceString, 1, &Prefix);
718     Fcb = (PNP_FCB)((ULONG_PTR)Fcb & ~1);
719 
720     NodeTypeCode = Fcb ? Fcb->NodeType : 0;
721     if (NodeTypeCode != NPFS_NTC_FCB)
722     {
723         Status = STATUS_OBJECT_NAME_NOT_FOUND;
724         goto Quickie;
725     }
726 
727     for (NextEntry = Fcb->CcbList.Flink;
728          NextEntry != &Fcb->CcbList;
729          NextEntry = NextEntry->Flink)
730     {
731         Ccb = CONTAINING_RECORD(NextEntry, NP_CCB, CcbEntry);
732         if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) break;
733     }
734 
735     if (NextEntry != &Fcb->CcbList)
736     {
737         Status = STATUS_SUCCESS;
738     }
739     else
740     {
741         Status = NpAddWaiter(&NpVcb->WaitQueue,
742                              Fcb->Timeout,
743                              Irp,
744                              OriginalBuffer == SourceString.Buffer ?
745                              NULL : &SourceString);
746     }
747 
748 Quickie:
749     if (SourceString.Buffer) ExFreePool(SourceString.Buffer);
750     return Status;
751 }
752 
753 NTSTATUS
754 NTAPI
755 NpCommonFileSystemControl(IN PDEVICE_OBJECT DeviceObject,
756                           IN PIRP Irp)
757 {
758     ULONG Fsctl;
759     BOOLEAN Overflow = FALSE;
760     LIST_ENTRY DeferredList;
761     NTSTATUS Status;
762     PAGED_CODE();
763 
764     InitializeListHead(&DeferredList);
765     Fsctl = IoGetCurrentIrpStackLocation(Irp)->Parameters.FileSystemControl.FsControlCode;
766 
767     switch (Fsctl)
768     {
769         case FSCTL_PIPE_PEEK:
770             NpAcquireExclusiveVcb();
771             Status = NpPeek(DeviceObject, Irp, &DeferredList);
772             break;
773 
774         case FSCTL_PIPE_INTERNAL_WRITE:
775             NpAcquireSharedVcb();
776             Status = NpInternalWrite(DeviceObject, Irp, &DeferredList);
777             break;
778 
779         case FSCTL_PIPE_TRANSCEIVE:
780             NpAcquireSharedVcb();
781             Status = NpTransceive(DeviceObject, Irp, &DeferredList);
782             break;
783 
784         case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
785             NpAcquireSharedVcb();
786             Status = NpInternalTransceive(DeviceObject, Irp, &DeferredList);
787             break;
788 
789         case FSCTL_PIPE_INTERNAL_READ_OVFLOW:
790             Overflow = TRUE;
791             // on purpose
792 
793         case FSCTL_PIPE_INTERNAL_READ:
794             NpAcquireSharedVcb();
795             Status = NpInternalRead(DeviceObject, Irp, Overflow, &DeferredList);
796             break;
797 
798         case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
799 
800             NpAcquireSharedVcb();
801             Status = NpQueryClientProcess(DeviceObject, Irp);
802             break;
803 
804         case FSCTL_PIPE_ASSIGN_EVENT:
805 
806             NpAcquireExclusiveVcb();
807             Status = NpAssignEvent(DeviceObject, Irp);
808             break;
809 
810         case FSCTL_PIPE_DISCONNECT:
811 
812             NpAcquireExclusiveVcb();
813             Status = NpDisconnect(DeviceObject, Irp, &DeferredList);
814             break;
815 
816         case FSCTL_PIPE_LISTEN:
817 
818             NpAcquireSharedVcb();
819             Status = NpListen(DeviceObject, Irp, &DeferredList);
820             break;
821 
822         case FSCTL_PIPE_QUERY_EVENT:
823 
824             NpAcquireExclusiveVcb();
825             Status = NpQueryEvent(DeviceObject, Irp);
826             break;
827 
828         case FSCTL_PIPE_WAIT:
829 
830             NpAcquireExclusiveVcb();
831             Status = NpWaitForNamedPipe(DeviceObject, Irp);
832             break;
833 
834         case FSCTL_PIPE_IMPERSONATE:
835 
836             NpAcquireExclusiveVcb();
837             Status = NpImpersonate(DeviceObject, Irp);
838             break;
839 
840         case FSCTL_PIPE_SET_CLIENT_PROCESS:
841             NpAcquireExclusiveVcb();
842             Status = NpSetClientProcess(DeviceObject, Irp);
843             break;
844 
845         default:
846             return STATUS_NOT_SUPPORTED;
847     }
848 
849     NpReleaseVcb();
850     NpCompleteDeferredIrps(&DeferredList);
851 
852     return Status;
853 }
854 
855 NTSTATUS
856 NTAPI
857 NpFsdFileSystemControl(IN PDEVICE_OBJECT DeviceObject,
858                        IN PIRP Irp)
859 {
860     NTSTATUS Status;
861     PAGED_CODE();
862 
863     FsRtlEnterFileSystem();
864 
865     Status = NpCommonFileSystemControl(DeviceObject, Irp);
866 
867     FsRtlExitFileSystem();
868 
869     if (Status != STATUS_PENDING)
870     {
871         Irp->IoStatus.Status = Status;
872         IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
873     }
874 
875     return Status;
876 }
877 
878 /* EOF */
879