[NPFS]
[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 = Irp->Tail.Overlay.DriverContext[0];
30
31 KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
32
33 WaitEntry = 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 static
103 BOOLEAN
104 NpEqualUnicodeString(IN PCUNICODE_STRING String1,
105 IN PCUNICODE_STRING String2)
106 {
107 SIZE_T EqualLength;
108
109 if (String1->Length != String2->Length)
110 return FALSE;
111
112 EqualLength = RtlCompareMemory(String1->Buffer,
113 String2->Buffer,
114 String1->Length);
115 return EqualLength == String1->Length;
116 }
117
118 NTSTATUS
119 NTAPI
120 NpCancelWaiter(IN PNP_WAIT_QUEUE WaitQueue,
121 IN PUNICODE_STRING PipePath,
122 IN NTSTATUS Status,
123 IN PLIST_ENTRY List)
124 {
125 UNICODE_STRING PipePathUpper;
126 KIRQL OldIrql;
127 PWCHAR Buffer;
128 PLIST_ENTRY NextEntry;
129 PNP_WAIT_QUEUE_ENTRY WaitEntry, Linkage;
130 PIRP WaitIrp;
131 PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
132 UNICODE_STRING WaitName, PipeName;
133
134 Linkage = NULL;
135
136 Buffer = ExAllocatePoolWithTag(NonPagedPool,
137 PipePath->Length,
138 NPFS_WAIT_BLOCK_TAG);
139 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
140
141 RtlInitEmptyUnicodeString(&PipePathUpper, Buffer, PipePath->Length);
142 RtlUpcaseUnicodeString(&PipePathUpper, PipePath, FALSE);
143
144 KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
145
146 NextEntry = WaitQueue->WaitList.Flink;
147 while (NextEntry != &WaitQueue->WaitList)
148 {
149 WaitIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
150 NextEntry = NextEntry->Flink;
151 WaitEntry = WaitIrp->Tail.Overlay.DriverContext[1];
152
153 if (WaitEntry->AliasName.Length)
154 {
155 ASSERT(FALSE);
156 /* We have an alias. Use that for comparison */
157 WaitName = WaitEntry->AliasName;
158 PipeName = PipePathUpper;
159 }
160 else
161 {
162 /* Use the name from the wait buffer to compare */
163 WaitBuffer = WaitIrp->AssociatedIrp.SystemBuffer;
164 WaitName.Buffer = WaitBuffer->Name;
165 WaitName.Length = WaitBuffer->NameLength;
166 WaitName.MaximumLength = WaitName.Length;
167
168 /* WaitName doesn't have a leading backslash,
169 * so skip the one in PipePathUpper for the comparison */
170 PipeName.Buffer = PipePathUpper.Buffer + 1;
171 PipeName.Length = PipePathUpper.Length - sizeof(WCHAR);
172 PipeName.MaximumLength = PipeName.Length;
173 }
174
175 /* Can't use RtlEqualUnicodeString with a spinlock held */
176 if (NpEqualUnicodeString(&WaitName, &PipeName))
177 {
178 /* Found a matching wait. Cancel it */
179 RemoveEntryList(&WaitIrp->Tail.Overlay.ListEntry);
180 if (KeCancelTimer(&WaitEntry->Timer))
181 {
182 WaitEntry->WaitQueue = (PNP_WAIT_QUEUE)Linkage;
183 Linkage = WaitEntry;
184 }
185 else
186 {
187 WaitEntry->Irp = NULL;
188 WaitIrp->Tail.Overlay.DriverContext[1] = NULL;
189 }
190
191 if (IoSetCancelRoutine(WaitIrp, NULL))
192 {
193 WaitIrp->IoStatus.Information = 0;
194 WaitIrp->IoStatus.Status = Status;
195 InsertTailList(List, &WaitIrp->Tail.Overlay.ListEntry);
196 }
197 else
198 {
199 WaitIrp->Tail.Overlay.DriverContext[1] = NULL;
200 }
201 }
202 }
203
204 KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
205
206 ExFreePoolWithTag(Buffer, NPFS_WAIT_BLOCK_TAG);
207
208 while (Linkage)
209 {
210 WaitEntry = Linkage;
211 Linkage = (PNP_WAIT_QUEUE_ENTRY)Linkage->WaitQueue;
212 ObDereferenceObject(WaitEntry->FileObject);
213 ExFreePool(WaitEntry);
214 }
215
216 return STATUS_SUCCESS;
217 }
218
219 NTSTATUS
220 NTAPI
221 NpAddWaiter(IN PNP_WAIT_QUEUE WaitQueue,
222 IN LARGE_INTEGER WaitTime,
223 IN PIRP Irp,
224 IN PUNICODE_STRING AliasName)
225 {
226 PIO_STACK_LOCATION IoStack;
227 KIRQL OldIrql;
228 NTSTATUS Status;
229 PNP_WAIT_QUEUE_ENTRY WaitEntry;
230 PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
231 LARGE_INTEGER DueTime;
232 ULONG i;
233
234 IoStack = IoGetCurrentIrpStackLocation(Irp);
235
236 WaitEntry = ExAllocatePoolWithQuotaTag(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
237 sizeof(*WaitEntry),
238 NPFS_WRITE_BLOCK_TAG);
239 if (!WaitEntry)
240 {
241 return STATUS_INSUFFICIENT_RESOURCES;
242 }
243
244 KeInitializeDpc(&WaitEntry->Dpc, NpTimerDispatch, WaitEntry);
245 KeInitializeTimer(&WaitEntry->Timer);
246
247 if (AliasName)
248 {
249 WaitEntry->AliasName = *AliasName;
250 }
251 else
252 {
253 WaitEntry->AliasName.Length = 0;
254 WaitEntry->AliasName.Buffer = NULL;
255 }
256
257 WaitEntry->WaitQueue = WaitQueue;
258 WaitEntry->Irp = Irp;
259
260 WaitBuffer = Irp->AssociatedIrp.SystemBuffer;
261 if (WaitBuffer->TimeoutSpecified)
262 {
263 DueTime = WaitBuffer->Timeout;
264 }
265 else
266 {
267 DueTime = WaitTime;
268 }
269
270 for (i = 0; i < WaitBuffer->NameLength / sizeof(WCHAR); i++)
271 {
272 WaitBuffer->Name[i] = RtlUpcaseUnicodeChar(WaitBuffer->Name[i]);
273 }
274
275 Irp->Tail.Overlay.DriverContext[0] = WaitQueue;
276 Irp->Tail.Overlay.DriverContext[1] = WaitEntry;
277
278 KeAcquireSpinLock(&WaitQueue->WaitLock, &OldIrql);
279
280 IoSetCancelRoutine(Irp, NpCancelWaitQueueIrp);
281
282 if (Irp->Cancel && IoSetCancelRoutine(Irp, NULL))
283 {
284 Status = STATUS_CANCELLED;
285 }
286 else
287 {
288 InsertTailList(&WaitQueue->WaitList, &Irp->Tail.Overlay.ListEntry);
289
290 IoMarkIrpPending(Irp);
291 Status = STATUS_PENDING;
292
293 WaitEntry->FileObject = IoStack->FileObject;
294 ObReferenceObject(WaitEntry->FileObject);
295
296 KeSetTimer(&WaitEntry->Timer, DueTime, &WaitEntry->Dpc);
297 WaitEntry = NULL;
298 }
299
300 KeReleaseSpinLock(&WaitQueue->WaitLock, OldIrql);
301 if (WaitEntry) ExFreePool(WaitEntry);
302
303 return Status;
304 }
305
306 /* EOF */