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