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