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
9 /* INCLUDES *******************************************************************/
13 // File ID number for NPFS bugchecking support
14 #define NPFS_BUGCHECK_FILE_ID (NPFS_BUGCHECK_DATASUP)
16 /* FUNCTIONS ******************************************************************/
20 NpUninitializeDataQueue(IN PNP_DATA_QUEUE DataQueue
)
24 ASSERT(DataQueue
->QueueState
== Empty
);
26 RtlZeroMemory(DataQueue
, sizeof(*DataQueue
));
27 return STATUS_SUCCESS
;
32 NpInitializeDataQueue(IN PNP_DATA_QUEUE DataQueue
,
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
;
49 NpCompleteStalledWrites(IN PNP_DATA_QUEUE DataQueue
,
52 ULONG QuotaLeft
, ByteOffset
, DataLeft
, NewQuotaLeft
;
53 PNP_DATA_QUEUE_ENTRY DataQueueEntry
;
55 PLIST_ENTRY NextEntry
;
57 QuotaLeft
= DataQueue
->Quota
- DataQueue
->QuotaUsed
;
58 ByteOffset
= DataQueue
->ByteOffset
;
60 NextEntry
= DataQueue
->Queue
.Flink
;
61 while (NextEntry
!= &DataQueue
->Queue
)
63 if (!QuotaLeft
) break;
65 DataQueueEntry
= CONTAINING_RECORD(NextEntry
,
69 Irp
= DataQueueEntry
->Irp
;
71 if ((DataQueueEntry
->DataEntryType
== Buffered
) && (Irp
))
73 DataLeft
= DataQueueEntry
->DataSize
- ByteOffset
;
75 if (DataQueueEntry
->QuotaInEntry
< DataLeft
)
77 NewQuotaLeft
= DataLeft
- DataQueueEntry
->QuotaInEntry
;
78 if (NewQuotaLeft
> QuotaLeft
) NewQuotaLeft
= QuotaLeft
;
80 QuotaLeft
-= NewQuotaLeft
;
81 DataQueueEntry
->QuotaInEntry
+= NewQuotaLeft
;
83 if (DataQueueEntry
->QuotaInEntry
== DataLeft
&&
84 IoSetCancelRoutine(Irp
, NULL
))
86 DataQueueEntry
->Irp
= NULL
;
88 Irp
->IoStatus
.Status
= 0;
89 Irp
->IoStatus
.Information
= DataQueueEntry
->DataSize
;
91 InsertTailList(List
, &Irp
->Tail
.Overlay
.ListEntry
);
96 NextEntry
= NextEntry
->Flink
;
100 DataQueue
->QuotaUsed
= DataQueue
->Quota
- QuotaLeft
;
105 NpRemoveDataQueueEntry(IN PNP_DATA_QUEUE DataQueue
,
110 PNP_DATA_QUEUE_ENTRY QueueEntry
;
113 if (DataQueue
->QueueState
== Empty
)
116 ASSERT(IsListEmpty(&DataQueue
->Queue
));
117 ASSERT(DataQueue
->EntriesInQueue
== 0);
118 ASSERT(DataQueue
->BytesInQueue
== 0);
119 ASSERT(DataQueue
->QuotaUsed
== 0);
123 QueueEntry
= CONTAINING_RECORD(RemoveHeadList(&DataQueue
->Queue
),
127 DataQueue
->BytesInQueue
-= QueueEntry
->DataSize
;
128 --DataQueue
->EntriesInQueue
;
131 if (DataQueue
->QueueState
!= WriteEntries
||
132 DataQueue
->QuotaUsed
< DataQueue
->Quota
||
133 !QueueEntry
->QuotaInEntry
)
138 DataQueue
->QuotaUsed
-= QueueEntry
->QuotaInEntry
;
140 if (IsListEmpty(&DataQueue
->Queue
))
142 DataQueue
->QueueState
= Empty
;
146 Irp
= QueueEntry
->Irp
;
147 NpFreeClientSecurityContext(QueueEntry
->ClientSecurityContext
);
149 if (Irp
&& IoSetCancelRoutine(Irp
, NULL
))
151 Irp
->Tail
.Overlay
.DriverContext
[3] = NULL
;
154 ExFreePool(QueueEntry
);
158 NpGetNextRealDataQueueEntry(DataQueue
, List
);
163 NpCompleteStalledWrites(DataQueue
, List
);
167 DataQueue
->ByteOffset
= 0;
173 NpGetNextRealDataQueueEntry(IN PNP_DATA_QUEUE DataQueue
,
176 PNP_DATA_QUEUE_ENTRY DataEntry
;
179 PLIST_ENTRY NextEntry
;
182 for (NextEntry
= DataQueue
->Queue
.Flink
;
183 NextEntry
!= &DataQueue
->Queue
;
184 NextEntry
= DataQueue
->Queue
.Flink
)
186 DataEntry
= CONTAINING_RECORD(NextEntry
,
190 Type
= DataEntry
->DataEntryType
;
191 if (Type
== Buffered
|| Type
== Unbuffered
) break;
193 Irp
= NpRemoveDataQueueEntry(DataQueue
, FALSE
, List
);
196 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
197 InsertTailList(List
, &Irp
->Tail
.Overlay
.ListEntry
);
206 NpCancelDataQueueIrp(IN PDEVICE_OBJECT DeviceObject
,
209 PNP_DATA_QUEUE DataQueue
;
210 PNP_DATA_QUEUE_ENTRY DataEntry
;
211 LIST_ENTRY DeferredList
;
212 PSECURITY_CLIENT_CONTEXT ClientSecurityContext
;
213 BOOLEAN CompleteWrites
, FirstEntry
;
215 if (DeviceObject
) IoReleaseCancelSpinLock(Irp
->CancelIrql
);
217 InitializeListHead(&DeferredList
);
219 DataQueue
= (PNP_DATA_QUEUE
)Irp
->Tail
.Overlay
.DriverContext
[2];
220 ClientSecurityContext
= NULL
;
224 FsRtlEnterFileSystem();
225 NpAcquireExclusiveVcb();
228 DataEntry
= Irp
->Tail
.Overlay
.DriverContext
[3];
231 if (DataEntry
->QueueEntry
.Blink
== &DataQueue
->Queue
)
233 DataQueue
->ByteOffset
= 0;
241 RemoveEntryList(&DataEntry
->QueueEntry
);
243 ClientSecurityContext
= DataEntry
->ClientSecurityContext
;
245 CompleteWrites
= TRUE
;
246 if (DataQueue
->QueueState
!= WriteEntries
||
247 DataQueue
->QuotaUsed
< DataQueue
->Quota
||
248 !DataEntry
->QuotaInEntry
)
250 CompleteWrites
= FALSE
;
253 DataQueue
->BytesInQueue
-= DataEntry
->DataSize
;
254 DataQueue
->QuotaUsed
-= DataEntry
->QuotaInEntry
;
255 --DataQueue
->EntriesInQueue
;
257 if (IsListEmpty(&DataQueue
->Queue
))
259 DataQueue
->QueueState
= Empty
;
260 ASSERT(DataQueue
->BytesInQueue
== 0);
261 ASSERT(DataQueue
->EntriesInQueue
== 0);
262 ASSERT(DataQueue
->QuotaUsed
== 0);
268 NpGetNextRealDataQueueEntry(DataQueue
, &DeferredList
);
272 NpCompleteStalledWrites(DataQueue
, &DeferredList
);
280 FsRtlExitFileSystem();
283 if (DataEntry
) ExFreePool(DataEntry
);
285 NpFreeClientSecurityContext(ClientSecurityContext
);
286 Irp
->IoStatus
.Status
= STATUS_CANCELLED
;
287 IoCompleteRequest(Irp
, IO_NAMED_PIPE_INCREMENT
);
289 NpCompleteDeferredIrps(&DeferredList
);
294 NpAddDataQueueEntry(IN ULONG NamedPipeEnd
,
296 IN PNP_DATA_QUEUE DataQueue
,
305 PNP_DATA_QUEUE_ENTRY DataEntry
;
308 PSECURITY_CLIENT_CONTEXT ClientContext
;
311 ClientContext
= NULL
;
312 ASSERT((DataQueue
->QueueState
== Empty
) || (DataQueue
->QueueState
== Who
));
314 Status
= STATUS_SUCCESS
;
316 if ((Type
!= 2) && (Who
== WriteEntries
))
318 Status
= NpGetClientSecurityContext(NamedPipeEnd
,
320 Irp
? Irp
->Tail
.Overlay
.Thread
:
321 PsGetCurrentThread(),
323 if (!NT_SUCCESS(Status
))
336 DataEntry
= ExAllocatePoolWithQuotaTag(NonPagedPool
| POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
338 NPFS_DATA_ENTRY_TAG
);
341 NpFreeClientSecurityContext(ClientContext
);
342 return STATUS_INSUFFICIENT_RESOURCES
;
345 DataEntry
->DataEntryType
= Type
;
346 DataEntry
->QuotaInEntry
= 0;
347 DataEntry
->Irp
= Irp
;
348 DataEntry
->DataSize
= DataSize
;
349 DataEntry
->ClientSecurityContext
= ClientContext
;
350 ASSERT((DataQueue
->QueueState
== Empty
) || (DataQueue
->QueueState
== Who
));
351 Status
= STATUS_PENDING
;
356 EntrySize
= sizeof(*DataEntry
);
357 if (Who
!= ReadEntries
)
359 EntrySize
+= DataSize
;
360 if (EntrySize
< DataSize
)
362 NpFreeClientSecurityContext(ClientContext
);
363 return STATUS_INVALID_PARAMETER
;
367 QuotaInEntry
= DataSize
- ByteOffset
;
368 if (DataQueue
->Quota
- DataQueue
->QuotaUsed
< QuotaInEntry
)
370 QuotaInEntry
= DataQueue
->Quota
- DataQueue
->QuotaUsed
;
378 DataEntry
= ExAllocatePoolWithQuotaTag(NonPagedPool
| POOL_QUOTA_FAIL_INSTEAD_OF_RAISE
,
380 NPFS_DATA_ENTRY_TAG
);
383 NpFreeClientSecurityContext(ClientContext
);
384 return STATUS_INSUFFICIENT_RESOURCES
;
387 DataEntry
->QuotaInEntry
= QuotaInEntry
;
388 DataEntry
->Irp
= Irp
;
389 DataEntry
->DataEntryType
= Buffered
;
390 DataEntry
->ClientSecurityContext
= ClientContext
;
391 DataEntry
->DataSize
= DataSize
;
393 if (Who
== ReadEntries
)
397 Status
= STATUS_PENDING
;
398 ASSERT((DataQueue
->QueueState
== Empty
) ||
399 (DataQueue
->QueueState
== Who
));
405 RtlCopyMemory(DataEntry
+ 1,
406 Irp
? Irp
->UserBuffer
: Buffer
,
409 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
411 NpFreeClientSecurityContext(ClientContext
);
412 _SEH2_YIELD(return _SEH2_GetExceptionCode());
418 Status
= STATUS_PENDING
;
422 DataEntry
->Irp
= NULL
;
423 Status
= STATUS_SUCCESS
;
426 ASSERT((DataQueue
->QueueState
== Empty
) ||
427 (DataQueue
->QueueState
== Who
));
433 NpFreeClientSecurityContext(ClientContext
);
434 return STATUS_INVALID_PARAMETER
;
437 ASSERT((DataQueue
->QueueState
== Empty
) || (DataQueue
->QueueState
== Who
));
438 if (DataQueue
->QueueState
== Empty
)
440 ASSERT(DataQueue
->BytesInQueue
== 0);
441 ASSERT(DataQueue
->EntriesInQueue
== 0);
442 ASSERT(IsListEmpty(&DataQueue
->Queue
));
446 ASSERT(DataQueue
->QueueState
== Who
);
447 ASSERT(DataQueue
->QueueState
!= Empty
);
448 ASSERT(DataQueue
->EntriesInQueue
!= 0);
451 DataQueue
->QuotaUsed
+= DataEntry
->QuotaInEntry
;
452 DataQueue
->QueueState
= Who
;
453 DataQueue
->BytesInQueue
+= DataEntry
->DataSize
;
454 DataQueue
->EntriesInQueue
++;
458 DataQueue
->ByteOffset
= ByteOffset
;
459 ASSERT(Who
== WriteEntries
);
460 ASSERT(ByteOffset
< DataEntry
->DataSize
);
461 ASSERT(DataQueue
->EntriesInQueue
== 1);
464 InsertTailList(&DataQueue
->Queue
, &DataEntry
->QueueEntry
);
466 if (Status
== STATUS_PENDING
)
468 IoMarkIrpPending(Irp
);
469 Irp
->Tail
.Overlay
.DriverContext
[2] = DataQueue
;
470 Irp
->Tail
.Overlay
.DriverContext
[3] = DataEntry
;
472 IoSetCancelRoutine(Irp
, NpCancelDataQueueIrp
);
474 if ((Irp
->Cancel
) && (IoSetCancelRoutine(Irp
, NULL
)))
476 NpCancelDataQueueIrp(NULL
, Irp
);