[FS_REC]
[reactos.git] / reactos / drivers / filesystems / npfs / waitsup.c
1 /*
2 * PROJECT: ReactOS Named Pipe FileSystem
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/filesystems/npfs/waitsup.c
5 * PURPOSE: Pipes Waiting 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_WAITSUP)
15
16 /* FUNCTIONS ******************************************************************/
17
18 VOID
19 NTAPI
20 NpCancelWaitQueueIrp(IN PDEVICE_OBJECT DeviceObject,
21 IN PIRP Irp)
22 {
23 KIRQL OldIrql;
24 PNP_WAIT_QUEUE_ENTRY WaitEntry;
25 PNP_WAIT_QUEUE WaitQueue;
26
27 IoReleaseCancelSpinLock(Irp->CancelIrql);
28
29 WaitQueue = (PNP_WAIT_QUEUE)Irp->Tail.Overlay.DriverContext[0];
30
31 KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
32
33 WaitEntry = (PNP_WAIT_QUEUE_ENTRY)Irp->Tail.Overlay.DriverContext[1];
34 if (WaitEntry)
35 {
36 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
37 if (!KeCancelTimer(&WaitEntry->Timer))
38 {
39 WaitEntry->Irp = NULL;
40 WaitEntry = NULL;
41 }
42 }
43
44 KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
45
46 if (WaitEntry)
47 {
48 ObDereferenceObject(WaitEntry->FileObject);
49 ExFreePool(WaitEntry);
50 }
51
52 Irp->IoStatus.Information = 0;
53 Irp->IoStatus.Status = STATUS_CANCELLED;
54 IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
55 }
56
57 VOID
58 NTAPI
59 NpTimerDispatch(IN PKDPC Dpc,
60 IN PVOID Context,
61 IN PVOID Argument1,
62 IN PVOID Argument2)
63 {
64 PIRP Irp;
65 KIRQL OldIrql;
66 PNP_WAIT_QUEUE_ENTRY WaitEntry = Context;
67
68 KeAcquireSpinLock(&WaitEntry->WaitQueue->WaitLock, &OldIrql);
69
70 Irp = WaitEntry->Irp;
71 if (Irp)
72 {
73 RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
74
75 if (!IoSetCancelRoutine(Irp, NULL))
76 {
77 Irp->Tail.Overlay.DriverContext[1] = NULL;
78 Irp = NULL;
79 }
80 }
81
82 KeReleaseSpinLock(&WaitEntry->WaitQueue->WaitLock, OldIrql);
83
84 if (Irp)
85 {
86 Irp->IoStatus.Status = STATUS_IO_TIMEOUT;
87 IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
88 }
89
90 ObDereferenceObject(WaitEntry->FileObject);
91 ExFreePool(WaitEntry);
92 }
93
94 VOID
95 NTAPI
96 NpInitializeWaitQueue(IN PNP_WAIT_QUEUE WaitQueue)
97 {
98 InitializeListHead(&WaitQueue->WaitList);
99 KeInitializeSpinLock(&WaitQueue->WaitLock);
100 }
101
102 NTSTATUS
103 NTAPI
104 NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue,
105 IN PUNICODE_STRING PipeName,
106 IN NTSTATUS Status,
107 IN PLIST_ENTRY List)
108 {
109 UNICODE_STRING DestinationString;
110 KIRQL OldIrql;
111 PWCHAR Buffer;
112 PLIST_ENTRY NextEntry;
113 PNP_WAIT_QUEUE_ENTRY WaitEntry, Linkage;
114 PIRP WaitIrp;
115 PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
116 ULONG i, NameLength;
117
118 Linkage = NULL;
119
120 Buffer = ExAllocatePoolWithTag(NonPagedPool,
121 PipeName->Length,
122 NPFS_WAIT_BLOCK_TAG);
123 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
124
125 RtlInitEmptyUnicodeString(&DestinationString, Buffer, PipeName->Length);
126 RtlUpcaseUnicodeString(&DestinationString, PipeName, FALSE);
127
128 KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
129
130 for (NextEntry = WaitQueue->WaitList.Flink;
131 NextEntry != &WaitQueue->WaitList;
132 NextEntry = NextEntry->Flink)
133 {
134 WaitIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
135 WaitEntry = WaitIrp->Tail.Overlay.DriverContext[1];
136
137 if (WaitEntry->AliasName.Length)
138 {
139 ASSERT(FALSE);
140 if (DestinationString.Length == WaitEntry->AliasName.Length)
141 {
142 if (RtlCompareMemory(WaitEntry->AliasName.Buffer,
143 DestinationString.Buffer,
144 DestinationString.Length) ==
145 DestinationString.Length)
146 {
147 CancelWait:
148 RemoveEntryList(&WaitIrp->Tail.Overlay.ListEntry);
149 if (KeCancelTimer(&WaitEntry->Timer))
150 {
151 WaitEntry->WaitQueue = (PNP_WAIT_QUEUE)Linkage;
152 Linkage = WaitEntry;
153 }
154 else
155 {
156 WaitEntry->Irp = NULL;
157 WaitIrp->Tail.Overlay.DriverContext[1] = NULL;
158 }
159
160 if (IoSetCancelRoutine(WaitIrp, NULL))
161 {
162 WaitIrp->IoStatus.Information = 0;
163 WaitIrp->IoStatus.Status = Status;
164 InsertTailList(List, &WaitIrp->Tail.Overlay.ListEntry);
165 }
166 else
167 {
168 WaitIrp->Tail.Overlay.DriverContext[1] = NULL;
169 }
170 }
171 }
172 }
173 else
174 {
175 WaitBuffer = WaitIrp->AssociatedIrp.SystemBuffer;
176
177 if (WaitBuffer->NameLength + sizeof(WCHAR) == DestinationString.Length)
178 {
179 NameLength = WaitBuffer->NameLength / sizeof(WCHAR);
180 for (i = 0; i < NameLength; i++)
181 {
182 if (WaitBuffer->Name[i] != DestinationString.Buffer[i + 1]) break;
183 }
184
185 if (i >= NameLength) goto CancelWait;
186 }
187 }
188 }
189
190 KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
191
192 ExFreePool(DestinationString.Buffer);
193
194 while (Linkage)
195 {
196 WaitEntry = Linkage;
197 Linkage = (PNP_WAIT_QUEUE_ENTRY)Linkage->WaitQueue;
198 ObDereferenceObject(WaitEntry->FileObject);
199 ExFreePool(WaitEntry);
200 }
201
202 return STATUS_SUCCESS;
203 }
204
205 NTSTATUS
206 NTAPI
207 NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
208 IN LARGE_INTEGER WaitTime,
209 IN PIRP Irp,
210 IN PUNICODE_STRING AliasName)
211 {
212 PIO_STACK_LOCATION IoStack;
213 KIRQL OldIrql;
214 NTSTATUS Status;
215 PNP_WAIT_QUEUE_ENTRY WaitEntry;
216 PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
217 LARGE_INTEGER DueTime;
218 ULONG i;
219
220 IoStack = IoGetCurrentIrpStackLocation(Irp);
221
222 WaitEntry = ExAllocatePoolWithQuotaTag(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
223 sizeof(*WaitEntry),
224 NPFS_WRITE_BLOCK_TAG);
225 if (!WaitEntry)
226 {
227 return STATUS_INSUFFICIENT_RESOURCES;
228 }
229
230 KeInitializeDpc(&WaitEntry->Dpc, NpTimerDispatch, WaitEntry);
231 KeInitializeTimer(&WaitEntry->Timer);
232
233 if (AliasName)
234 {
235 WaitEntry->AliasName = *AliasName;
236 }
237 else
238 {
239 WaitEntry->AliasName.Length = 0;
240 WaitEntry->AliasName.Buffer = NULL;
241 }
242
243 WaitEntry->WaitQueue = WaitQueue;
244 WaitEntry->Irp = Irp;
245
246 WaitBuffer = (PFILE_PIPE_WAIT_FOR_BUFFER)Irp->AssociatedIrp.SystemBuffer;
247 if (WaitBuffer->TimeoutSpecified)
248 {
249 DueTime = WaitBuffer->Timeout;
250 }
251 else
252 {
253 DueTime = WaitTime;
254 }
255
256 for (i = 0; i < WaitBuffer->NameLength / sizeof(WCHAR); i++)
257 {
258 WaitBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitBuffer->Name[i]);
259 }
260
261 Irp->Tail.Overlay.DriverContext[0] = WaitQueue;
262 Irp->Tail.Overlay.DriverContext[1] = WaitEntry;
263
264 KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
265
266 IoSetCancelRoutine(Irp, NpCancelWaitQueueIrp);
267
268 if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
269 {
270 Status = STATUS_CANCELLED;
271 }
272 else
273 {
274 InsertTailList(&WaitQueue->WaitList, &Irp->Tail.Overlay.ListEntry);
275
276 IoMarkIrpPending(Irp);
277 Status = STATUS_PENDING;
278
279 WaitEntry->FileObject = IoStack->FileObject;
280 ObReferenceObject(WaitEntry->FileObject);
281
282 KeSetTimer(&WaitEntry->Timer, DueTime, &WaitEntry->Dpc);
283 WaitEntry = NULL;
284
285 }
286
287 KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
288 if (WaitEntry) ExFreePool(WaitEntry);
289
290 return Status;
291 }
292
293 /* EOF */