0bb9b964eb2216190d7962fa257cf043a28c4d55
[reactos.git] / ntoskrnl / io / iocomp.c
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/ke/iocomp.c
5  * PURPOSE:         
6  * PROGRAMMER:      David Welch (welch@mcmail.com)
7  * UPDATE HISTORY:
8  *                  Created 22/05/98
9                     Changed NtQueryIoCompletion 
10  */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <limits.h>
15 #include <ddk/ntddk.h>
16 #include <ntos/synch.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 #define IOC_TAG   TAG('I', 'O', 'C', 'T')   
22
23 POBJECT_TYPE ExIoCompletionType;
24
25 NPAGED_LOOKASIDE_LIST  IoCompletionPacketLookaside;
26
27 static GENERIC_MAPPING ExIoCompletionMapping = 
28 {
29    STANDARD_RIGHTS_READ | IO_COMPLETION_QUERY_STATE,
30    STANDARD_RIGHTS_WRITE | IO_COMPLETION_MODIFY_STATE,
31    STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE,
32    IO_COMPLETION_ALL_ACCESS
33 };
34
35 /* FUNCTIONS *****************************************************************/
36
37 NTSTATUS 
38 STDCALL
39 NtpCreateIoCompletion(
40    PVOID                ObjectBody,
41    PVOID                Parent,
42    PWSTR                RemainingPath,
43    POBJECT_ATTRIBUTES   ObjectAttributes
44    )
45 {
46    DPRINT("NtpCreateIoCompletion(ObjectBody %x, Parent %x, RemainingPath %S)\n",
47       ObjectBody, Parent, RemainingPath);
48
49    if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
50    {
51       return STATUS_UNSUCCESSFUL;
52    }
53
54    return STATUS_SUCCESS;
55 }
56
57 VOID STDCALL
58 NtpDeleteIoCompletion(PVOID ObjectBody)
59 {
60    PKQUEUE Queue = ObjectBody;
61
62    DPRINT("NtpDeleteIoCompletion()\n");
63
64    KeRundownQueue(Queue);
65 }
66
67
68 VOID 
69 NtInitializeIoCompletionImplementation(VOID)
70 {
71    ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
72    
73    RtlCreateUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion");
74    
75    ExIoCompletionType->Tag = IOC_TAG;
76    ExIoCompletionType->MaxObjects = ULONG_MAX;
77    ExIoCompletionType->MaxHandles = ULONG_MAX;
78    ExIoCompletionType->TotalObjects = 0;
79    ExIoCompletionType->TotalHandles = 0;
80    ExIoCompletionType->PagedPoolCharge = 0;
81    ExIoCompletionType->NonpagedPoolCharge = sizeof(KQUEUE);
82    ExIoCompletionType->Mapping = &ExIoCompletionMapping;
83    ExIoCompletionType->Dump = NULL;
84    ExIoCompletionType->Open = NULL;
85    ExIoCompletionType->Close = NULL;
86    ExIoCompletionType->Delete = NtpDeleteIoCompletion;
87    ExIoCompletionType->Parse = NULL;
88    ExIoCompletionType->Security = NULL;
89    ExIoCompletionType->QueryName = NULL;
90    ExIoCompletionType->OkayToClose = NULL;
91    ExIoCompletionType->Create = NtpCreateIoCompletion;
92    ExIoCompletionType->DuplicationNotify = NULL;
93
94    ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside,
95                                    NULL,
96                                    NULL,
97                                    0,
98                                    sizeof(IO_COMPLETION_PACKET),
99                                    IOC_TAG,
100                                    0);
101 }
102
103
104 NTSTATUS
105 STDCALL
106 NtCreateIoCompletion(
107    OUT PHANDLE             IoCompletionHandle,
108    IN  ACCESS_MASK         DesiredAccess,
109    IN  POBJECT_ATTRIBUTES  ObjectAttributes,
110    IN  ULONG               NumberOfConcurrentThreads
111    )
112 {
113    PKQUEUE     Queue;
114    NTSTATUS    Status;
115    
116    Status = ObCreateObject(IoCompletionHandle,
117                            DesiredAccess,
118                            ObjectAttributes,
119                            ExIoCompletionType,
120                            (PVOID*)&Queue);
121
122    if (NT_SUCCESS(Status))
123    {
124       (void) KeInitializeQueue(Queue, NumberOfConcurrentThreads);
125       ObDereferenceObject(Queue);
126    }
127
128    return Status;
129    /*
130
131   CompletionPort = NULL OR ExistingCompletionPort
132
133   */
134  
135
136 }
137
138 /*
139 DesiredAccess:
140 ZERO
141 IO_COMPLETION_QUERY_STATE Query access
142 IO_COMPLETION_MODIFY_STATE Modify access
143 IO_COMPLETION_ALL_ACCESS All of the preceding + STANDARD_RIGHTS_ALL
144
145 ObjectAttributes
146 OBJ_OPENLINK and OBJ_PERMANENT are not valid attributes
147
148 Return Value
149 STATUS_SUCCESS or an error status, such as STATUS_ACCESS_DENIED or
150 STATUS_OBJECT_NAME_NOT_FOUND.
151 */
152 NTSTATUS
153 STDCALL
154 NtOpenIoCompletion(
155    OUT PHANDLE             IoCompletionHandle,
156    IN  ACCESS_MASK         DesiredAccess,
157    IN  POBJECT_ATTRIBUTES  ObjectAttributes
158    )
159 {
160    NTSTATUS Status;
161    
162    Status = ObOpenObjectByName(ObjectAttributes,
163                                ExIoCompletionType,
164                                NULL,
165                                UserMode,
166                                DesiredAccess,
167                                NULL,
168                                IoCompletionHandle);  //<- ???
169    
170    return Status;
171 }
172
173
174 NTSTATUS
175 STDCALL
176 NtQueryIoCompletion(
177    IN  HANDLE                          IoCompletionHandle,
178    IN  IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
179    OUT PVOID                           IoCompletionInformation,
180    IN  ULONG                           IoCompletionInformationLength,
181    OUT PULONG                          ResultLength OPTIONAL
182    )
183 {
184    PKQUEUE  Queue;
185    NTSTATUS Status;
186
187    if (IoCompletionInformationClass != IoCompletionBasicInformation)
188    {
189       return STATUS_INVALID_INFO_CLASS;
190    }
191    if (IoCompletionInformationLength < sizeof(IO_COMPLETION_BASIC_INFORMATION))
192    {
193       return STATUS_INFO_LENGTH_MISMATCH;
194    }
195
196    Status = ObReferenceObjectByHandle( IoCompletionHandle,
197                                        IO_COMPLETION_QUERY_STATE,
198                                        ExIoCompletionType,
199                                        UserMode,
200                                        (PVOID*)&Queue,
201                                        NULL);
202    if (NT_SUCCESS(Status))
203    {
204       ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->SignalState = 
205          Queue->Header.SignalState;
206
207       ObDereferenceObject(Queue);
208
209       if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
210    }
211
212    return Status;
213 }
214
215
216 /*
217  * Dequeues an I/O completion message from an I/O completion object
218  */
219 NTSTATUS
220 STDCALL
221 NtRemoveIoCompletion(
222    IN  HANDLE           IoCompletionHandle,
223    OUT PULONG           CompletionKey,
224    OUT PULONG           CompletionValue,
225    OUT PIO_STATUS_BLOCK IoStatusBlock,
226    IN  PLARGE_INTEGER   Timeout OPTIONAL
227    )
228 {
229    PKQUEUE  Queue;
230    NTSTATUS Status;
231       
232    Status = ObReferenceObjectByHandle( IoCompletionHandle,
233                                        IO_COMPLETION_MODIFY_STATE,
234                                        ExIoCompletionType,
235                                        UserMode,
236                                        (PVOID*)&Queue,
237                                        NULL);
238    if (NT_SUCCESS(Status))
239    {
240       PIO_COMPLETION_PACKET   Packet;
241       PLIST_ENTRY             ListEntry;
242
243       /*
244       Try 2 remove packet from queue. Wait (optionaly) if
245       no packet in queue or max num of threads allready running.
246       */
247       ListEntry = KeRemoveQueue(Queue, UserMode, Timeout );
248
249       ObDereferenceObject(Queue);
250
251       Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
252
253       if (CompletionKey) *CompletionKey = Packet->Key;
254       if (CompletionValue) *CompletionValue = Packet->Overlapped;
255       if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus;
256
257       ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
258    }
259
260    return Status;
261 }
262
263
264 /*
265 ASSOSIERT MED FOB's IoCompletionContext
266
267 typedef struct _IO_COMPLETION_CONTEXT {
268         PVOID Port; 
269         ULONG Key; 
270 } IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT;
271
272 */
273
274
275 /*
276  * Queues an I/O completion message to an I/O completion object
277  */
278 NTSTATUS
279 STDCALL
280 NtSetIoCompletion(
281    IN HANDLE   IoCompletionPortHandle,
282    IN ULONG    CompletionKey,
283    IN ULONG    CompletionValue,
284    IN NTSTATUS CompletionStatus,
285    IN ULONG    CompletionInformation
286    )
287 {
288    NTSTATUS                Status;
289    PKQUEUE                 Queue;
290
291    Status = ObReferenceObjectByHandle( IoCompletionPortHandle,
292                                        IO_COMPLETION_MODIFY_STATE,
293                                        ExIoCompletionType,
294                                        UserMode,
295                                        (PVOID*)&Queue,
296                                        NULL);
297    if (NT_SUCCESS(Status))
298    {
299       PIO_COMPLETION_PACKET   Packet;
300
301       Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside);
302
303       Packet->Key = CompletionKey;
304       Packet->Overlapped = CompletionValue;
305       Packet->IoStatus.Status = CompletionStatus;
306       Packet->IoStatus.Information = CompletionInformation;
307    
308       KeInsertQueue(Queue, &Packet->ListEntry);
309       ObDereferenceObject(Queue);
310    }
311
312    return Status;
313 }