5f8f739b7451c08396bcbdf76a70f345f2f88c94
[reactos.git] / reactos / drivers / filesystems / npfs_new / datasup.c
1 /*
2 * PROJECT: ReactOS Named Pipe FileSystem
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/filesystems/npfs/datasup.c
5 * PURPOSE: Data Queues Support
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "npfs.h"
12
13 /* FUNCTIONS ******************************************************************/
14
15 NTSTATUS
16 NTAPI
17 NpUninitializeDataQueue(IN PNP_DATA_QUEUE DataQueue)
18 {
19 PAGED_CODE();
20
21 ASSERT(DataQueue->QueueState == Empty);
22
23 RtlZeroMemory(DataQueue, sizeof(*DataQueue));
24 return STATUS_SUCCESS;
25 }
26
27 NTSTATUS
28 NTAPI
29 NpInitializeDataQueue(IN PNP_DATA_QUEUE DataQueue,
30 IN ULONG Quota)
31 {
32 PAGED_CODE();
33
34 DataQueue->BytesInQueue = 0;
35 DataQueue->EntriesInQueue = 0;
36 DataQueue->QuotaUsed = 0;
37 DataQueue->ByteOffset = 0;
38 DataQueue->QueueState = Empty;
39 DataQueue->Quota = Quota;
40 InitializeListHead(&DataQueue->Queue);
41 return STATUS_SUCCESS;
42 }
43
44 VOID
45 NTAPI
46 NpCompleteStalledWrites(IN PNP_DATA_QUEUE DataQueue,
47 IN PLIST_ENTRY List)
48 {
49 ULONG QuotaLeft, ByteOffset, DataLeft, NewQuotaLeft;
50 PNP_DATA_QUEUE_ENTRY DataQueueEntry;
51 PIRP Irp;
52 PLIST_ENTRY NextEntry;
53
54 QuotaLeft = DataQueue->Quota - DataQueue->QuotaUsed;
55 ByteOffset = DataQueue->ByteOffset;
56
57 NextEntry = DataQueue->Queue.Flink;
58 while (NextEntry != &DataQueue->Queue)
59 {
60 if (!QuotaLeft) break;
61
62 DataQueueEntry = CONTAINING_RECORD(NextEntry, NP_DATA_QUEUE_ENTRY, Irp);
63
64 Irp = DataQueueEntry->Irp;
65
66 if ((DataQueueEntry->DataEntryType == 0) && (Irp))
67 {
68 DataLeft = DataQueueEntry->DataSize - ByteOffset;
69
70 if (DataQueueEntry->QuotaInEntry < DataLeft)
71 {
72 NewQuotaLeft = DataLeft - DataQueueEntry->QuotaInEntry;
73 if (NewQuotaLeft > QuotaLeft) NewQuotaLeft = QuotaLeft;
74
75 QuotaLeft -= NewQuotaLeft;
76 DataQueueEntry->QuotaInEntry += NewQuotaLeft;
77
78 if (DataQueueEntry->QuotaInEntry == DataLeft &&
79 IoSetCancelRoutine(Irp, NULL))
80 {
81 DataQueueEntry->Irp = NULL;
82
83 Irp->IoStatus.Status = 0;
84 Irp->IoStatus.Information = DataQueueEntry->DataSize;
85
86 InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
87 }
88 }
89 }
90
91 NextEntry = NextEntry->Flink;
92 ByteOffset = 0;
93 }
94
95 DataQueue->QuotaUsed = DataQueue->Quota - QuotaLeft;
96 }
97
98 PIRP
99 NTAPI
100 NpRemoveDataQueueEntry(IN PNP_DATA_QUEUE DataQueue,
101 IN BOOLEAN Flag,
102 IN PLIST_ENTRY List)
103 {
104 PIRP Irp;
105 PNP_DATA_QUEUE_ENTRY QueueEntry;
106 BOOLEAN HasWrites;
107
108 if (DataQueue->QueueState == Empty)
109 {
110 Irp = NULL;
111 ASSERT(IsListEmpty(&DataQueue->Queue));
112 ASSERT(DataQueue->EntriesInQueue == 0);
113 ASSERT(DataQueue->BytesInQueue == 0);
114 ASSERT(DataQueue->QuotaUsed == 0);
115 }
116 else
117 {
118 QueueEntry = CONTAINING_RECORD(RemoveHeadList(&DataQueue->Queue),
119 NP_DATA_QUEUE_ENTRY,
120 QueueEntry);
121
122 DataQueue->BytesInQueue -= QueueEntry->DataSize;
123 --DataQueue->EntriesInQueue;
124
125 HasWrites = 1;
126 if (!DataQueue->QueueState != WriteEntries || DataQueue->QuotaUsed < DataQueue->Quota || !QueueEntry->QuotaInEntry)
127 {
128 HasWrites = 0;
129 }
130
131 DataQueue->QuotaUsed -= QueueEntry->QuotaInEntry;
132
133 if (DataQueue->Queue.Flink == &DataQueue->Queue)
134 {
135 DataQueue->QueueState = Empty;
136 HasWrites = 0;
137 }
138
139 Irp = QueueEntry->Irp;
140 NpFreeClientSecurityContext(QueueEntry->ClientSecurityContext);
141
142 if (Irp && IoSetCancelRoutine(Irp, NULL))
143 {
144 Irp->Tail.Overlay.DriverContext[3] = NULL;
145 }
146
147 ExFreePool(QueueEntry);
148
149 if (Flag)
150 {
151 NpGetNextRealDataQueueEntry(DataQueue, List);
152 }
153
154 if (HasWrites)
155 {
156 NpCompleteStalledWrites(DataQueue, List);
157 }
158 }
159
160 DataQueue->ByteOffset = 0;
161 return Irp;
162 }
163
164 PNP_DATA_QUEUE_ENTRY
165 NTAPI
166 NpGetNextRealDataQueueEntry(IN PNP_DATA_QUEUE DataQueue,
167 IN PLIST_ENTRY List)
168 {
169 PNP_DATA_QUEUE_ENTRY DataEntry;
170 ULONG Type;
171 PIRP Irp;
172 PLIST_ENTRY NextEntry;
173 PAGED_CODE();
174
175 DataEntry = NULL;
176
177 NextEntry = DataQueue->Queue.Flink;
178 while (NextEntry != &DataQueue->Queue)
179 {
180 DataEntry = CONTAINING_RECORD(NextEntry, NP_DATA_QUEUE_ENTRY, QueueEntry);
181
182 Type = DataEntry->DataEntryType;
183 if (Type == Buffered || Type == Unbuffered) break;
184
185 Irp = NpRemoveDataQueueEntry(DataQueue, FALSE, List);
186 if (Irp)
187 {
188 Irp->IoStatus.Status = STATUS_SUCCESS;
189 InsertTailList(List, &Irp->Tail.Overlay.ListEntry);
190 }
191 }
192
193 return DataEntry;
194 }
195
196 VOID
197 NTAPI
198 NpCancelDataQueueIrp(IN PDEVICE_OBJECT DeviceObject,
199 IN PIRP Irp)
200 {
201 PNP_DATA_QUEUE DataQueue;
202 PNP_DATA_QUEUE_ENTRY DataEntry;
203 LIST_ENTRY DeferredList;
204 PSECURITY_CLIENT_CONTEXT ClientSecurityContext;
205 BOOLEAN CompleteWrites, FirstEntry;
206
207 if (DeviceObject) IoReleaseCancelSpinLock(Irp->CancelIrql);
208
209 InitializeListHead(&DeferredList);
210
211 DataQueue = (PNP_DATA_QUEUE)Irp->Tail.Overlay.DriverContext[2];
212 ClientSecurityContext = NULL;
213
214 if (DeviceObject)
215 {
216 FsRtlEnterFileSystem();
217 NpAcquireExclusiveVcb();
218 }
219
220 DataEntry = (PNP_DATA_QUEUE_ENTRY)Irp->Tail.Overlay.DriverContext[3];
221 if (DataEntry)
222 {
223 if (DataEntry->QueueEntry.Blink == &DataQueue->Queue)
224 {
225 DataQueue->ByteOffset = 0;
226 FirstEntry = 1;
227 }
228 else
229 {
230 FirstEntry = 0;
231 }
232
233 RemoveEntryList(&DataEntry->QueueEntry);
234
235 ClientSecurityContext = DataEntry->ClientSecurityContext;
236
237 CompleteWrites = 1;
238 if (!DataQueue->QueueState != WriteEntries || DataQueue->QuotaUsed < DataQueue->Quota || !DataEntry->QuotaInEntry)
239 {
240 CompleteWrites = 0;
241 }
242
243 DataQueue->BytesInQueue -= DataEntry->DataSize;
244 DataQueue->QuotaUsed -= DataEntry->QuotaInEntry;
245 --DataQueue->EntriesInQueue;
246
247 if (DataQueue->Queue.Flink == &DataQueue->Queue)
248 {
249 DataQueue->QueueState = Empty;
250 ASSERT(DataQueue->BytesInQueue == 0);
251 ASSERT(DataQueue->EntriesInQueue == 0);
252 ASSERT(DataQueue->QuotaUsed == 0);
253 }
254 else
255 {
256 if (FirstEntry)
257 {
258 NpGetNextRealDataQueueEntry(DataQueue, &DeferredList);
259 }
260 if (CompleteWrites)
261 {
262 NpCompleteStalledWrites(DataQueue, &DeferredList);
263 }
264 }
265 }
266
267 if (DeviceObject)
268 {
269 NpReleaseVcb();
270 FsRtlExitFileSystem();
271 }
272
273 if (DataEntry) ExFreePool(DataEntry);
274
275 NpFreeClientSecurityContext(ClientSecurityContext);
276 Irp->IoStatus.Status = STATUS_CANCELLED;
277 IoCompleteRequest(Irp, IO_NAMED_PIPE_INCREMENT);
278
279 NpCompleteDeferredIrps(&DeferredList);
280 }
281
282 NTSTATUS
283 NTAPI
284 NpAddDataQueueEntry(IN ULONG NamedPipeEnd,
285 IN PNP_CCB Ccb,
286 IN PNP_DATA_QUEUE DataQueue,
287 IN ULONG Who,
288 IN ULONG Type,
289 IN ULONG DataSize,
290 IN PIRP Irp,
291 IN PVOID Buffer,
292 IN ULONG ByteOffset)
293 {
294 NTSTATUS Status;
295 PNP_DATA_QUEUE_ENTRY DataEntry;
296 SIZE_T EntrySize;
297 ULONG QuotaInEntry;
298 PSECURITY_CLIENT_CONTEXT ClientContext;
299 BOOLEAN HasSpace;
300
301 ClientContext = NULL;
302 ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
303
304 Status = STATUS_SUCCESS;
305
306 if ((Type != 2) && (Who == WriteEntries))
307 {
308 Status = NpGetClientSecurityContext(NamedPipeEnd,
309 Ccb,
310 Irp ? Irp->Tail.Overlay.Thread :
311 PsGetCurrentThread(),
312 &ClientContext);
313 if (!NT_SUCCESS(Status))
314 {
315 return Status;
316 }
317 }
318
319 switch (Type)
320 {
321 case Unbuffered:
322 case 2:
323 case 3:
324
325 ASSERT(Irp != NULL);
326 DataEntry = ExAllocatePoolWithQuotaTag(NonPagedPool,
327 sizeof(*DataEntry),
328 NPFS_DATA_ENTRY_TAG);
329 if (!DataEntry)
330 {
331 NpFreeClientSecurityContext(ClientContext);
332 return STATUS_INSUFFICIENT_RESOURCES;
333 }
334
335 DataEntry->DataEntryType = Type;
336 DataEntry->QuotaInEntry = 0;
337 DataEntry->Irp = Irp;
338 DataEntry->DataSize = DataSize;
339 DataEntry->ClientSecurityContext = ClientContext;
340 ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
341 Status = STATUS_PENDING;
342 break;
343
344 case Buffered:
345
346 EntrySize = sizeof(*DataEntry);
347 if (Who != ReadEntries)
348 {
349 EntrySize += DataSize;
350 if (EntrySize < DataSize)
351 {
352 NpFreeClientSecurityContext(ClientContext);
353 return STATUS_INVALID_PARAMETER;
354 }
355 }
356
357 QuotaInEntry = DataSize - ByteOffset;
358 if (DataQueue->Quota - DataQueue->QuotaUsed < QuotaInEntry)
359 {
360 QuotaInEntry = DataQueue->Quota - DataQueue->QuotaUsed;
361 HasSpace = TRUE;
362 }
363 else
364 {
365 HasSpace = FALSE;
366 }
367
368 DataEntry = ExAllocatePoolWithQuotaTag(NonPagedPool,
369 EntrySize,
370 NPFS_DATA_ENTRY_TAG);
371 if (!DataEntry)
372 {
373 NpFreeClientSecurityContext(ClientContext);
374 return STATUS_INSUFFICIENT_RESOURCES;
375 }
376
377 DataEntry->QuotaInEntry = QuotaInEntry;
378 DataEntry->Irp = Irp;
379 DataEntry->DataEntryType = Buffered;
380 DataEntry->ClientSecurityContext = ClientContext;
381 DataEntry->DataSize = DataSize;
382
383 if (Who == ReadEntries)
384 {
385 ASSERT(Irp);
386
387 Status = STATUS_PENDING;
388 ASSERT((DataQueue->QueueState == Empty) ||
389 (DataQueue->QueueState == Who));
390 }
391 else
392 {
393 _SEH2_TRY
394 {
395 RtlCopyMemory(DataEntry + 1,
396 Irp ? Irp->UserBuffer: Buffer,
397 DataSize);
398 }
399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
400 {
401 NpFreeClientSecurityContext(ClientContext);
402 return _SEH2_GetExceptionCode();
403 }
404 _SEH2_END;
405
406 if (HasSpace && Irp)
407 {
408 Status = STATUS_PENDING;
409 }
410 else
411 {
412 DataEntry->Irp = NULL;
413 Status = STATUS_SUCCESS;
414 }
415
416 ASSERT((DataQueue->QueueState == Empty) ||
417 (DataQueue->QueueState == Who));
418 }
419 break;
420
421 default:
422 ASSERT(FALSE);
423 NpFreeClientSecurityContext(ClientContext);
424 return STATUS_INVALID_PARAMETER;
425 }
426
427 ASSERT((DataQueue->QueueState == Empty) || (DataQueue->QueueState == Who));
428 if (DataQueue->QueueState == Empty)
429 {
430 ASSERT(DataQueue->BytesInQueue == 0);
431 ASSERT(DataQueue->EntriesInQueue == 0);
432 ASSERT(IsListEmpty (&DataQueue->Queue));
433 }
434 else
435 {
436 ASSERT(DataQueue->QueueState == Who);
437 ASSERT(DataQueue->QueueState != Empty);
438 ASSERT(DataQueue->EntriesInQueue != 0);
439 }
440
441 DataQueue->QuotaUsed += DataEntry->QuotaInEntry;
442 DataQueue->QueueState = Who;
443 DataQueue->BytesInQueue += DataEntry->DataSize;
444 DataQueue->EntriesInQueue++;
445
446 if (ByteOffset)
447 {
448 DataQueue->ByteOffset = ByteOffset;
449 ASSERT(Who == WriteEntries);
450 ASSERT(ByteOffset < DataEntry->DataSize);
451 ASSERT(DataQueue->EntriesInQueue == 1);
452 }
453
454 InsertTailList(&DataQueue->Queue, &DataEntry->QueueEntry);
455
456 if (Status == STATUS_PENDING)
457 {
458 IoMarkIrpPending(Irp);
459 Irp->Tail.Overlay.DriverContext[2] = DataQueue;
460 Irp->Tail.Overlay.DriverContext[3] = DataEntry;
461
462 IoSetCancelRoutine(Irp, NpCancelDataQueueIrp);
463
464 if ((Irp->Cancel) && (IoSetCancelRoutine(Irp, NULL)))
465 {
466 NpCancelDataQueueIrp(NULL, Irp);
467 }
468 }
469
470 return Status;
471 }
472
473 /* EOF */