xref: /reactos/drivers/filesystems/npfs/statesup.c (revision c2c66aff)
1 /*
2  * PROJECT:     ReactOS Named Pipe FileSystem
3  * LICENSE:     BSD - See COPYING.ARM in the top level directory
4  * FILE:        drivers/filesystems/npfs/statesup.c
5  * PURPOSE:     Pipes State Support
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_STATESUP)
15 
16 /* FUNCTIONS ******************************************************************/
17 
18 VOID
19 NTAPI
NpCancelListeningQueueIrp(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)20 NpCancelListeningQueueIrp(IN PDEVICE_OBJECT DeviceObject,
21                           IN PIRP Irp)
22 {
23     IoReleaseCancelSpinLock(Irp->CancelIrql);
24 
25     FsRtlEnterFileSystem();
26     NpAcquireExclusiveVcb();
27 
28     RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
29 
30     NpReleaseVcb();
31     FsRtlExitFileSystem();
32 
33     Irp->IoStatus.Status = STATUS_CANCELLED;
34     IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
35 }
36 
37 NTSTATUS
38 NTAPI
NpSetConnectedPipeState(IN PNP_CCB Ccb,IN PFILE_OBJECT FileObject,IN PLIST_ENTRY List)39 NpSetConnectedPipeState(IN PNP_CCB Ccb,
40                         IN PFILE_OBJECT FileObject,
41                         IN PLIST_ENTRY List)
42 {
43     PLIST_ENTRY NextEntry;
44     PIRP Irp;
45 
46     ASSERT(Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE);
47 
48     Ccb->ReadMode[FILE_PIPE_CLIENT_END] = FILE_PIPE_BYTE_STREAM_MODE;
49     Ccb->CompletionMode[FILE_PIPE_CLIENT_END] = FILE_PIPE_QUEUE_OPERATION;
50     Ccb->NamedPipeState = FILE_PIPE_CONNECTED_STATE;
51     Ccb->FileObject[FILE_PIPE_CLIENT_END] = FileObject;
52 
53     NpSetFileObject(FileObject, Ccb, Ccb->NonPagedCcb, FALSE);
54 
55     while (!IsListEmpty(&Ccb->IrpList))
56     {
57         NextEntry = RemoveHeadList(&Ccb->IrpList);
58 
59         Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
60 
61         if (IoSetCancelRoutine(Irp, NULL))
62         {
63             Irp->IoStatus.Status = STATUS_SUCCESS;
64             InsertTailList(List, NextEntry);
65         }
66         else
67         {
68             InitializeListHead(NextEntry);
69         }
70     }
71 
72     return STATUS_SUCCESS;
73 }
74 
75 NTSTATUS
76 NTAPI
NpSetDisconnectedPipeState(IN PNP_CCB Ccb,IN PLIST_ENTRY List)77 NpSetDisconnectedPipeState(IN PNP_CCB Ccb,
78                            IN PLIST_ENTRY List)
79 {
80     PIRP Irp;
81     PNP_NONPAGED_CCB NonPagedCcb;
82     NTSTATUS Status;
83     PLIST_ENTRY NextEntry;
84     PNP_EVENT_BUFFER EventBuffer;
85 
86     NonPagedCcb = Ccb->NonPagedCcb;
87 
88     switch (Ccb->NamedPipeState)
89     {
90         case FILE_PIPE_DISCONNECTED_STATE:
91             Status = STATUS_PIPE_DISCONNECTED;
92             break;
93 
94         case FILE_PIPE_LISTENING_STATE:
95             while (!IsListEmpty(&Ccb->IrpList))
96             {
97                 NextEntry = RemoveHeadList(&Ccb->IrpList);
98 
99                 Irp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
100 
101                 if (IoSetCancelRoutine(Irp, NULL))
102                 {
103                     Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED;
104                     InsertTailList(List, NextEntry);
105                 }
106                 else
107                 {
108                     InitializeListHead(NextEntry);
109                 }
110             }
111 
112             Status = STATUS_SUCCESS;
113             break;
114 
115         case FILE_PIPE_CONNECTED_STATE:
116 
117             EventBuffer = NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END];
118 
119             while (Ccb->DataQueue[FILE_PIPE_INBOUND].QueueState != Empty)
120             {
121                 Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_INBOUND], FALSE, List);
122                 if (Irp)
123                 {
124                     Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED;
125                     InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
126                 }
127             }
128 
129             while (Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState != Empty)
130             {
131                 Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_OUTBOUND], FALSE, List);
132                 if (Irp)
133                 {
134                     Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED;
135                     InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
136                 }
137             }
138 
139             if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE);
140 
141             // drop down on purpose... queue will be empty so flush code is nop
142             ASSERT(Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState == Empty);
143 
144         case FILE_PIPE_CLOSING_STATE:
145 
146             EventBuffer = NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END];
147 
148             while (Ccb->DataQueue[FILE_PIPE_INBOUND].QueueState != Empty)
149             {
150                 Irp = NpRemoveDataQueueEntry(&Ccb->DataQueue[FILE_PIPE_INBOUND], FALSE, List);
151                 if (Irp)
152                 {
153                     Irp->IoStatus.Status = STATUS_PIPE_DISCONNECTED;
154                     InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
155                 }
156             }
157 
158             ASSERT(Ccb->DataQueue[FILE_PIPE_OUTBOUND].QueueState == Empty);
159 
160             NpDeleteEventTableEntry(&NpVcb->EventTable, EventBuffer);
161             NonPagedCcb->EventBuffer[FILE_PIPE_CLIENT_END] = NULL;
162 
163             NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE);
164             Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
165 
166             NpUninitializeSecurity(Ccb);
167 
168             if (Ccb->ClientSession)
169             {
170                 ExFreePool(Ccb->ClientSession);
171                 Ccb->ClientSession = NULL;
172             }
173 
174             Status = STATUS_SUCCESS;
175             break;
176 
177         default:
178             NpBugCheck(Ccb->NamedPipeState, 0, 0);
179             break;
180     }
181 
182     Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE;
183     return Status;
184 }
185 
186 NTSTATUS
187 NTAPI
NpSetListeningPipeState(IN PNP_CCB Ccb,IN PIRP Irp,IN PLIST_ENTRY List)188 NpSetListeningPipeState(IN PNP_CCB Ccb,
189                         IN PIRP Irp,
190                         IN PLIST_ENTRY List)
191 {
192     NTSTATUS Status;
193 
194     switch (Ccb->NamedPipeState)
195     {
196         case FILE_PIPE_DISCONNECTED_STATE:
197 
198             Status = NpCancelWaiter(&NpVcb->WaitQueue,
199                                     &Ccb->Fcb->FullName,
200                                     STATUS_SUCCESS,
201                                     List);
202             if (!NT_SUCCESS(Status)) return Status;
203 
204         //
205         // Drop down on purpose
206         //
207 
208         case FILE_PIPE_LISTENING_STATE:
209 
210             if (Ccb->CompletionMode[FILE_PIPE_SERVER_END] == FILE_PIPE_COMPLETE_OPERATION)
211             {
212                 Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE;
213                 return STATUS_PIPE_LISTENING;
214             }
215 
216             IoSetCancelRoutine(Irp, NpCancelListeningQueueIrp);
217             if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
218             {
219                 return STATUS_CANCELLED;
220             }
221 
222             Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE;
223             IoMarkIrpPending(Irp);
224             InsertTailList(&Ccb->IrpList, &Irp->Tail.Overlay.ListEntry);
225             return STATUS_PENDING;
226 
227         case FILE_PIPE_CONNECTED_STATE:
228             Status = STATUS_PIPE_CONNECTED;
229             break;
230 
231         case FILE_PIPE_CLOSING_STATE:
232             Status = STATUS_PIPE_CLOSING;
233             break;
234 
235         default:
236             NpBugCheck(Ccb->NamedPipeState, 0, 0);
237             break;
238     }
239 
240     return Status;
241 }
242 
243 NTSTATUS
244 NTAPI
NpSetClosingPipeState(IN PNP_CCB Ccb,IN PIRP Irp,IN ULONG NamedPipeEnd,IN PLIST_ENTRY List)245 NpSetClosingPipeState(IN PNP_CCB Ccb,
246                       IN PIRP Irp,
247                       IN ULONG NamedPipeEnd,
248                       IN PLIST_ENTRY List)
249 {
250     PNP_NONPAGED_CCB NonPagedCcb;
251     PNP_FCB Fcb;
252     PLIST_ENTRY NextEntry;
253     PNP_DATA_QUEUE ReadQueue, WriteQueue, DataQueue;
254     PNP_EVENT_BUFFER EventBuffer;
255     PIRP ListIrp;
256 
257     NonPagedCcb = Ccb->NonPagedCcb;
258     Fcb = Ccb->Fcb;
259 
260     switch (Ccb->NamedPipeState)
261     {
262         case FILE_PIPE_LISTENING_STATE:
263 
264             ASSERT(NamedPipeEnd == FILE_PIPE_SERVER_END);
265 
266             while (!IsListEmpty(&Ccb->IrpList))
267             {
268                 NextEntry = RemoveHeadList(&Ccb->IrpList);
269 
270                 ListIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
271 
272                 if (IoSetCancelRoutine(ListIrp, NULL))
273                 {
274                     ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
275                     InsertTailList(List, NextEntry);
276                 }
277                 else
278                 {
279                     InitializeListHead(NextEntry);
280                 }
281             }
282 
283             // Drop on purpose
284 
285         case FILE_PIPE_DISCONNECTED_STATE:
286 
287             ASSERT(NamedPipeEnd == FILE_PIPE_SERVER_END);
288 
289             NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE);
290             Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;
291 
292             NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE);
293             Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
294 
295             NpDeleteCcb(Ccb, List);
296             if (!Fcb->CurrentInstances) NpDeleteFcb(Fcb, List);
297             break;
298 
299         case FILE_PIPE_CLOSING_STATE:
300 
301             if (NamedPipeEnd == FILE_PIPE_SERVER_END)
302             {
303                 DataQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
304             }
305             else
306             {
307                 DataQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
308             }
309 
310             NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE);
311             Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;
312 
313             NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE);
314             Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
315 
316             while (DataQueue->QueueState != Empty)
317             {
318                 ListIrp = NpRemoveDataQueueEntry(DataQueue, FALSE, List);
319                 if (ListIrp)
320                 {
321                     ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
322                     InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry);
323                 }
324             }
325 
326             NpUninitializeSecurity(Ccb);
327 
328             if (Ccb->ClientSession)
329             {
330                 ExFreePool(Ccb->ClientSession);
331                 Ccb->ClientSession = NULL;
332             }
333 
334             NpDeleteCcb(Ccb, List);
335             if (!Fcb->CurrentInstances) NpDeleteFcb(Fcb, List);
336             break;
337 
338         case FILE_PIPE_CONNECTED_STATE:
339 
340             if (NamedPipeEnd == FILE_PIPE_SERVER_END)
341             {
342                 ReadQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
343                 WriteQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
344 
345                 NpSetFileObject(Ccb->FileObject[FILE_PIPE_SERVER_END], NULL, NULL, TRUE);
346                 Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;
347             }
348             else
349             {
350                 ReadQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
351                 WriteQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
352 
353                 NpSetFileObject(Ccb->FileObject[FILE_PIPE_CLIENT_END], NULL, NULL, FALSE);
354                 Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
355             }
356 
357             EventBuffer = NonPagedCcb->EventBuffer[NamedPipeEnd];
358 
359             Ccb->NamedPipeState = FILE_PIPE_CLOSING_STATE;
360 
361             while (ReadQueue->QueueState != Empty)
362             {
363                 ListIrp = NpRemoveDataQueueEntry(ReadQueue, FALSE, List);
364                 if (ListIrp)
365                 {
366                     ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
367                     InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry);
368                 }
369             }
370 
371             while (WriteQueue->QueueState == ReadEntries)
372             {
373                 ListIrp = NpRemoveDataQueueEntry(WriteQueue, FALSE, List);
374                 if (ListIrp)
375                 {
376                     ListIrp->IoStatus.Status = STATUS_PIPE_BROKEN;
377                     InsertTailList(List, &ListIrp->Tail.Overlay.ListEntry);
378                 }
379             }
380 
381             if (EventBuffer) KeSetEvent(EventBuffer->Event, IO_NO_INCREMENT, FALSE);
382             break;
383 
384         default:
385             NpBugCheck(Ccb->NamedPipeState, 0, 0);
386             break;
387     }
388     return STATUS_SUCCESS;
389 }
390 
391 /* EOF */
392