+sanity check of NULL IoGetCurrentIrpStackLocation(Irp)->FileObject
[reactos.git] / ntoskrnl / io / irp.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/io/irp.c
6  * PURPOSE:         Handle IRPs
7  * PROGRAMMER:      David Welch (welch@mcmail.com)
8  * UPDATE HISTORY: 
9  *                  24/05/98: Created 
10  */
11
12 /* NOTES *******************************************************************
13  * 
14  * Layout of an IRP 
15  * 
16  *             ################
17  *             #    Headers   #
18  *             ################
19  *             #              #
20  *             #   Variable   #
21  *             # length list  #
22  *             # of io stack  #
23  *             #  locations   #
24  *             #              #
25  *             ################
26  * 
27  * 
28  * 
29  */
30
31 /* INCLUDES ****************************************************************/
32
33 #include <ddk/ntddk.h>
34 #include <internal/io.h>
35 #include <internal/ps.h>
36 #include <internal/pool.h>
37
38 #define NDEBUG
39 #include <internal/debug.h>
40
41 /* GLOBALS *******************************************************************/
42
43 #define TAG_IRP     TAG('I', 'R', 'P', ' ')
44
45
46 /* FUNCTIONS ****************************************************************/
47
48
49 VOID STDCALL
50 IoFreeIrp(PIRP Irp)
51 /*
52  * FUNCTION: Releases a caller allocated irp
53  * ARGUMENTS:
54  *      Irp = Irp to free
55  */
56 {
57   ExFreePool(Irp);
58 }
59
60 #ifndef LIBCAPTIVE
61
62 PIRP STDCALL
63 IoMakeAssociatedIrp(PIRP Irp,
64                     CCHAR StackSize)
65 /*
66  * FUNCTION: Allocates and initializes an irp to associated with a master irp
67  * ARGUMENTS:
68  *       Irp = Master irp
69  *       StackSize = Number of stack locations to be allocated in the irp
70  * RETURNS: The irp allocated
71  */
72 {
73   PIRP AssocIrp;
74   
75   AssocIrp = IoAllocateIrp(StackSize,FALSE);
76   UNIMPLEMENTED;
77   return NULL;
78 }
79
80 #endif /* LIBCAPTIVE */
81
82 VOID STDCALL
83 IoInitializeIrp(PIRP Irp,
84                 USHORT PacketSize,
85                 CCHAR StackSize)
86 /*
87  * FUNCTION: Initalizes an irp allocated by the caller
88  * ARGUMENTS:
89  *          Irp = IRP to initalize
90  *          PacketSize = Size in bytes of the IRP
91  *          StackSize = Number of stack locations in the IRP
92  */
93 {
94   assert(Irp != NULL);
95
96   memset(Irp, 0, PacketSize);
97   Irp->Type = IO_TYPE_IRP;
98   Irp->Size = PacketSize;
99   Irp->StackCount = StackSize;
100   Irp->CurrentLocation = StackSize;
101   Irp->Tail.Overlay.CurrentStackLocation = &Irp->Stack[(ULONG)StackSize];
102 }
103
104
105 NTSTATUS FASTCALL
106 IofCallDriver(PDEVICE_OBJECT DeviceObject,
107               PIRP Irp)
108 /*
109   * FUNCTION: Sends an IRP to the next lower driver
110  */
111 {
112   PDRIVER_OBJECT DriverObject;
113   PIO_STACK_LOCATION Param;
114   
115   DPRINT("IofCallDriver(DeviceObject %x, Irp %x)\n",DeviceObject,Irp);
116   
117   assert(Irp);
118   assert(DeviceObject);
119
120   DriverObject = DeviceObject->DriverObject;
121
122   assert(DriverObject);
123
124   IoSetNextIrpStackLocation(Irp);
125   Param = IoGetCurrentIrpStackLocation(Irp);
126
127   DPRINT("IrpSp 0x%X\n", Param);
128   
129   Param->DeviceObject = DeviceObject;
130
131   DPRINT("MajorFunction %d\n", Param->MajorFunction);
132   DPRINT("DriverObject->MajorFunction[Param->MajorFunction] %x\n",
133     DriverObject->MajorFunction[Param->MajorFunction]);
134
135   if (!DriverObject->MajorFunction[Param->MajorFunction])
136     KeBugCheck(0);
137   return DriverObject->MajorFunction[Param->MajorFunction](DeviceObject, Irp);
138 }
139
140
141 NTSTATUS
142 STDCALL
143 IoCallDriver (PDEVICE_OBJECT DeviceObject, PIRP Irp)
144 {
145   return(IofCallDriver(DeviceObject,
146                        Irp));
147 }
148
149
150 PIRP STDCALL
151 IoAllocateIrp(CCHAR StackSize,
152               BOOLEAN ChargeQuota)
153 /*
154  * FUNCTION: Allocates an IRP
155  * ARGUMENTS:
156  *          StackSize = the size of the stack required for the irp
157  *          ChargeQuota = Charge allocation to current threads quota
158  * RETURNS: Irp allocated
159  */
160 {
161   PIRP Irp;
162
163 #if 0
164   DbgPrint("IoAllocateIrp(StackSize %d ChargeQuota %d)\n",
165            StackSize,
166            ChargeQuota);
167   KeDumpStackFrames(0,8);
168 #endif
169   
170   if (ChargeQuota)
171     {
172 //      Irp = ExAllocatePoolWithQuota(NonPagedPool,IoSizeOfIrp(StackSize));
173       Irp = ExAllocatePoolWithTag(NonPagedPool,
174                                   IoSizeOfIrp(StackSize),
175                                   TAG_IRP);
176     }
177   else
178     {
179       Irp = ExAllocatePoolWithTag(NonPagedPool,
180                                   IoSizeOfIrp(StackSize),
181                                   TAG_IRP);
182     }
183
184   if (Irp==NULL)
185     {
186       return(NULL);
187     }
188
189   IoInitializeIrp(Irp,
190                   IoSizeOfIrp(StackSize),
191                   StackSize);
192
193 //  DPRINT("Irp %x Irp->StackPtr %d\n", Irp, Irp->CurrentLocation);
194
195   return(Irp);
196 }
197
198 #ifndef LIBCAPTIVE
199
200 VOID STDCALL
201 IopCompleteRequest(struct _KAPC* Apc,
202                    PKNORMAL_ROUTINE* NormalRoutine,
203                    PVOID* NormalContext,
204                    PVOID* SystemArgument1,
205                    PVOID* SystemArgument2)
206 {
207   DPRINT("IopCompleteRequest(Apc %x, SystemArgument1 %x, (*SystemArgument1) %x\n",
208          Apc,
209          SystemArgument1,
210          *SystemArgument1);
211   IoSecondStageCompletion((PIRP)(*SystemArgument1),
212                           (KPRIORITY)(*SystemArgument2));
213 }
214
215 #endif /* LIBCAPTIVE */
216
217 VOID FASTCALL
218 IofCompleteRequest(PIRP Irp,
219                    CCHAR PriorityBoost)
220 /*
221  * FUNCTION: Indicates the caller has finished all processing for a given
222  * I/O request and is returning the given IRP to the I/O manager
223  * ARGUMENTS:
224  *         Irp = Irp to be cancelled
225  *         PriorityBoost = Increment by which to boost the priority of the
226  *                         thread making the request
227  */
228 {
229    ULONG             i;
230    NTSTATUS          Status;
231    PDEVICE_OBJECT    DeviceObject;
232
233    DPRINT("IoCompleteRequest(Irp %x, PriorityBoost %d) Event %x THread %x\n",
234       Irp,PriorityBoost, Irp->UserEvent, PsGetCurrentThread());
235
236    assert(Irp->CancelRoutine == NULL);
237    assert(Irp->IoStatus.Status != STATUS_PENDING);
238
239    if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
240    {
241       Irp->PendingReturned = TRUE;
242    }
243
244    for (i=Irp->CurrentLocation;i<(ULONG)Irp->StackCount;i++)
245    {
246       /*
247       Completion routines expect the current irp stack location to be the same as when
248       IoSetCompletionRoutine was called to set them. A side effect is that completion
249       routines set by highest level drivers without their own stack location will receive
250       an invalid current stack location (at least it should be considered as invalid).
251       Since the DeviceObject argument passed is taken from the current stack, this value
252       is also invalid (NULL).
253       */
254       if (Irp->CurrentLocation < Irp->StackCount - 1)
255       {
256          IoSetPreviousIrpStackLocation(Irp);
257          DeviceObject = IoGetCurrentIrpStackLocation(Irp)->DeviceObject;
258       }
259       else
260       {
261          DeviceObject = NULL;
262       }
263
264       if (Irp->Stack[i].CompletionRoutine != NULL &&
265          ((NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_SUCCESS)) ||
266          (!NT_SUCCESS(Irp->IoStatus.Status) && (Irp->Stack[i].Control & SL_INVOKE_ON_ERROR)) ||
267          (Irp->Cancel && (Irp->Stack[i].Control & SL_INVOKE_ON_CANCEL))))
268       {
269          Status = Irp->Stack[i].CompletionRoutine(DeviceObject,
270                                                   Irp,
271                                                   Irp->Stack[i].CompletionContext);
272
273          if (Status == STATUS_MORE_PROCESSING_REQUIRED)
274          {
275             if (Irp->UserIosb)
276                {
277                   *Irp->UserIosb=Irp->IoStatus;
278                }
279             return;
280          }
281       }
282    
283       if (IoGetCurrentIrpStackLocation(Irp)->Control & SL_PENDING_RETURNED)
284       {
285          Irp->PendingReturned = TRUE;
286       }
287    }
288
289    if (Irp->PendingReturned)
290      {
291         DPRINT("Dispatching APC\n");
292 #ifndef LIBCAPTIVE
293         KeInitializeApc(&Irp->Tail.Apc,
294                         &Irp->Tail.Overlay.Thread->Tcb,
295                         0,
296                         IopCompleteRequest,
297                         NULL,
298                         (PKNORMAL_ROUTINE)
299                         NULL,
300                         KernelMode,
301                         NULL);
302         KeInsertQueueApc(&Irp->Tail.Apc,
303                          (PVOID)Irp,
304                          (PVOID)(ULONG)PriorityBoost,
305                          KernelMode);
306         DPRINT("Finished dispatching APC\n");
307 #else /* !LIBCAPTIVE */
308         KeBugCheck(0);
309 #endif /* !LIBCAPTIVE */
310      }
311    else
312      {
313         DPRINT("Calling completion routine directly\n");
314         IoSecondStageCompletion(Irp,PriorityBoost);
315         DPRINT("Finished completition routine\n");
316      }
317 }
318
319
320 VOID STDCALL
321 IoCompleteRequest(PIRP Irp,
322                   CCHAR PriorityBoost)
323 {
324   IofCompleteRequest(Irp,
325                      PriorityBoost);
326 }
327
328
329 /**********************************************************************
330  * NAME                                                 EXPORTED
331  *      IoIsOperationSynchronous@4
332  *
333  * DESCRIPTION
334  *      Check if the I/O operation associated with the given IRP
335  *      is synchronous.
336  *
337  * ARGUMENTS
338  *      Irp     Packet to check.
339  *
340  * RETURN VALUE
341  *      TRUE if Irp's operation is synchronous; otherwise FALSE.
342  */
343 BOOLEAN STDCALL
344 IoIsOperationSynchronous(IN PIRP Irp)
345 {
346   PFILE_OBJECT FileObject = NULL;
347   ULONG Flags = 0;
348
349   /* Check the FILE_OBJECT's flags first. */
350   FileObject = IoGetCurrentIrpStackLocation(Irp)->FileObject;
351   if (FileObject == NULL)
352     KeBugCheck(0);
353   if (!(FO_SYNCHRONOUS_IO & FileObject->Flags))
354     {
355       /* Check IRP's flags. */
356       Flags = Irp->Flags;
357       if (!((IRP_SYNCHRONOUS_API | IRP_SYNCHRONOUS_PAGING_IO) & Flags))
358         {
359 #ifdef LIBCAPTIVE
360           /* libcaptive is fully single-thread/single-process synchronous model. */
361           return TRUE;
362 #endif /* LIBCAPTIVE */
363           return(FALSE);
364         }
365     }
366
367   /* Check more IRP's flags. */
368   Flags = Irp->Flags;
369   if (!(IRP_PAGING_IO & Flags)
370       || (IRP_SYNCHRONOUS_PAGING_IO & Flags))
371     {
372       return(TRUE);
373     }
374
375   /* Otherwise, it is an asynchronous operation. */
376 #ifdef LIBCAPTIVE
377   /* libcaptive is fully single-thread/single-process synchronous model. */
378   return TRUE;
379 #endif /* LIBCAPTIVE */
380   return(FALSE);
381 }
382
383 #ifndef LIBCAPTIVE
384
385 VOID STDCALL
386 IoEnqueueIrp(IN PIRP Irp)
387 {
388   UNIMPLEMENTED;
389 }
390
391 #endif /* LIBCAPTIVE */
392
393 VOID STDCALL
394 IoSetTopLevelIrp(IN PIRP Irp)
395 {
396   PETHREAD Thread;
397
398   Thread = PsGetCurrentThread();
399   Thread->TopLevelIrp->TopLevelIrp = Irp;
400 }
401
402
403 PIRP STDCALL
404 IoGetTopLevelIrp(VOID)
405 {
406   return(PsGetCurrentThread()->TopLevelIrp->TopLevelIrp);
407 }
408
409 #ifndef LIBCAPTIVE
410
411 VOID STDCALL
412 IoQueueThreadIrp(IN PIRP Irp)
413 {
414   UNIMPLEMENTED;
415 }
416
417 /*
418 NTSTATUS
419 STDCALL
420 IoSetDeviceInterfaceState(IN PUNICODE_STRING SymbolicLinkName, IN BOOLEAN Enable)
421 {
422   UNIMPLEMENTED;
423         return 0;
424 }
425
426 NTSTATUS
427 STDCALL
428 IoGetDeviceProperty(
429   IN PDEVICE_OBJECT DeviceObject,
430   IN DEVICE_REGISTRY_PROPERTY DeviceProperty,
431   IN ULONG BufferLength,
432   OUT PVOID PropertyBuffer,
433   OUT PULONG ResultLength)
434 {
435   UNIMPLEMENTED;
436         return 0;
437 }
438
439 NTSTATUS
440 STDCALL
441 IoOpenDeviceRegistryKey(
442   IN PDEVICE_OBJECT DeviceObject,
443   IN ULONG DevInstKeyType,
444   IN ACCESS_MASK DesiredAccess,
445   OUT PHANDLE DevInstRegKey)
446 {
447   UNIMPLEMENTED;
448         return 0;
449 }
450  */
451
452 #endif /* LIBCAPTIVE */
453
454 /* EOF */