[SHELL-EXPERIMENTS]
[reactos.git] / drivers / filesystems / npfs / statesup.c
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
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 FsRtlExitFileSystem();
31 NpReleaseVcb();
32
33 Irp->IoStatus.Status = STATUS_CANCELLED;
34 IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
35 }
36
37 NTSTATUS
38 NTAPI
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
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
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
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 */