update for HEAD-2003091401
[reactos.git] / ntoskrnl / io / lock.c
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/ke/bug.c
5  * PURPOSE:         Graceful system shutdown if a bug is detected
6  * PROGRAMMER:      David Welch (welch@mcmail.com)
7  * UPDATE HISTORY:
8  *                  Created 22/05/98
9  */
10
11 /* INCLUDES *****************************************************************/
12
13
14 #include <ddk/ntddk.h>
15
16 #define NDEBUG
17 #include <internal/debug.h>
18
19
20 #define TAG_LOCK                        TAG('F','l','c','k')
21
22 /* FUNCTIONS *****************************************************************/
23
24 NTSTATUS
25 STDCALL
26   NtLockFileCompletionRoutine(
27     IN PDEVICE_OBJECT  DeviceObject,
28     IN PIRP  Irp,
29     IN PVOID  Context
30     )
31 {
32         ExFreePool(Context);
33         return STATUS_SUCCESS;
34         //FIXME: should I call IoFreeIrp and return STATUS_MORE_PROCESSING_REQUIRED?
35 }
36
37 /*
38  * @unimplemented
39  */
40 NTSTATUS
41 STDCALL
42 NtLockFile (
43         IN      HANDLE                  FileHandle,
44         IN      HANDLE                  EventHandle             OPTIONAL,
45         IN      PIO_APC_ROUTINE         ApcRoutine      OPTIONAL,
46         IN      PVOID                   ApcContext      OPTIONAL,
47         OUT     PIO_STATUS_BLOCK        UserIoStatusBlock,
48         IN      PLARGE_INTEGER          ByteOffset,
49         IN      PLARGE_INTEGER          Length,
50         IN      PULONG                  Key,
51         IN      BOOLEAN                 FailImmediatedly,
52         IN      BOOLEAN                 ExclusiveLock
53         )
54 {
55         NTSTATUS Status;
56         PFILE_OBJECT FileObject = NULL;
57         PLARGE_INTEGER  LocalLength = NULL;
58         PKEVENT Event = NULL;
59         PIRP Irp = NULL;
60         PEXTENDED_IO_STACK_LOCATION StackPtr;
61         IO_STATUS_BLOCK         LocalIoStatusBlock;
62         PIO_STATUS_BLOCK IoStatusBlock;
63         PDEVICE_OBJECT  DeviceObject;
64    ULONG FobFlags;
65
66         //FIXME: instead of this, use SEH when available?
67         if (!Length || !ByteOffset)     {
68                 Status = STATUS_INVALID_PARAMETER;
69                 goto fail;
70         }
71
72         Status = ObReferenceObjectByHandle(
73                                          FileHandle,
74                                      0,
75                                      IoFileObjectType,
76                                      ExGetPreviousMode(),
77                                      (PVOID*)&FileObject,
78                                      NULL);
79
80         if (!NT_SUCCESS(Status)){
81                 goto fail;
82         }
83
84         DeviceObject = IoGetRelatedDeviceObject(FileObject);
85
86         Irp = IoAllocateIrp(
87                         DeviceObject->StackSize,
88                         TRUE
89                         );
90
91         if (Irp == NULL) {
92                 Status = STATUS_INSUFFICIENT_RESOURCES;
93                 goto fail;
94         }
95
96         if (EventHandle != NULL && !FailImmediatedly) {
97                  Status = ObReferenceObjectByHandle(
98                                          EventHandle,
99                                          SYNCHRONIZE,
100                                          ExEventObjectType,
101                                          ExGetPreviousMode(),
102                                          (PVOID*)&Event,
103                                          NULL);
104
105                 if (!NT_SUCCESS(Status)) {
106                         goto fail;
107                 }
108
109         }       
110         else {
111                 Event = &FileObject->Event;
112                 KeResetEvent(Event);
113         }
114
115         if ((FileObject->Flags & FO_SYNCHRONOUS_IO) || FailImmediatedly)
116                 IoStatusBlock = &LocalIoStatusBlock;
117         else
118                 IoStatusBlock = UserIoStatusBlock;
119
120    //trigger FileObject/Event dereferencing
121    Irp->Tail.Overlay.OriginalFileObject = FileObject;
122
123         Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
124         Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
125
126         Irp->UserEvent = Event;
127         Irp->UserIosb = IoStatusBlock;
128         Irp->Tail.Overlay.Thread = PsGetCurrentThread();
129
130         StackPtr = (PEXTENDED_IO_STACK_LOCATION) IoGetNextIrpStackLocation(Irp);
131         StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
132         StackPtr->MinorFunction = IRP_MN_LOCK;
133         StackPtr->FileObject = FileObject;
134         
135         if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
136         if (FailImmediatedly) StackPtr->Flags |= SL_FAIL_IMMEDIATELY;
137
138         LocalLength = ExAllocatePoolWithTag(
139                                                                         NonPagedPool,
140                                                                         sizeof(LARGE_INTEGER),
141                                                                         TAG_LOCK
142                                                                         );
143         if (!LocalLength){
144                 Status = STATUS_INSUFFICIENT_RESOURCES;
145                 goto fail;
146         }
147
148         *LocalLength = *Length;
149
150         StackPtr->Parameters.LockControl.Length = LocalLength;
151         StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
152         StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
153         
154         IoSetCompletionRoutine(  
155                                         Irp,  
156                                         NtLockFileCompletionRoutine,  
157                                         LocalLength,  
158                                         TRUE,   
159                                         TRUE,  
160                                         TRUE  );
161
162    //can't touch FileObject after IoCallDriver since it might be freed
163    FobFlags = FileObject->Flags;
164         Status = IofCallDriver(DeviceObject, Irp);
165
166    if (Status == STATUS_PENDING && (FobFlags & FO_SYNCHRONOUS_IO)) {
167
168                 Status = KeWaitForSingleObject(
169                                                         Event,
170                                                         Executive,
171                                                         ExGetPreviousMode() , 
172                      (FobFlags & FO_ALERTABLE_IO) ? TRUE : FALSE,
173                                                         NULL
174                                                         );
175
176                 if (Status != STATUS_WAIT_0) {
177                         DPRINT1("NtLockFile -> KeWaitForSingleObject failed!\n");
178                         /*
179                         FIXME: should do some special processing here if alertable wait 
180                         was interupted by user apc or a thread alert (STATUS_ALERTED, STATUS_USER_APC)
181                         */
182                         return Status;   //set status to something else?
183                 }
184
185                 Status = LocalIoStatusBlock.Status;
186         }
187
188    if (FobFlags & FO_SYNCHRONOUS_IO)
189                 *UserIoStatusBlock = LocalIoStatusBlock;
190
191         return Status;
192
193         fail:;
194
195         if (LocalLength) ExFreePool(LocalLength);
196         if (Irp) IoFreeIrp(Irp);
197         if (Event) ObDereferenceObject(Event);
198         if (FileObject) ObDereferenceObject(FileObject);
199
200         return Status;
201
202 }
203
204
205
206
207 /*
208  * @unimplemented
209  */
210 NTSTATUS
211 STDCALL
212 NtUnlockFile (
213         IN      HANDLE                  FileHandle,
214         OUT     PIO_STATUS_BLOCK        UserIoStatusBlock,
215         IN      PLARGE_INTEGER          ByteOffset,
216         IN      PLARGE_INTEGER          Length,
217         OUT     PULONG                  Key             OPTIONAL
218         )
219 {
220         NTSTATUS Status;
221         PFILE_OBJECT FileObject = NULL;
222         PLARGE_INTEGER  LocalLength = NULL;
223         PIRP Irp  = NULL;
224         PEXTENDED_IO_STACK_LOCATION StackPtr;
225         IO_STATUS_BLOCK         LocalIoStatusBlock;
226         PDEVICE_OBJECT  DeviceObject;
227
228         //FIXME: instead of this, use SEH when available
229         if (!Length || !ByteOffset)     {
230                 Status = STATUS_INVALID_PARAMETER;
231                 goto fail;
232         }
233
234         /*
235         BUGBUG: ObReferenceObjectByHandle fails if DesiredAccess=0 and mode=UserMode
236         It should ONLY fail if we desire an access that conflict with granted access!
237         */
238         Status = ObReferenceObjectByHandle(
239                                          FileHandle,
240                                      FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to!
241                                      IoFileObjectType,
242                                      ExGetPreviousMode(),
243                                      (PVOID*)&FileObject,
244                                      NULL);
245
246         if (!NT_SUCCESS(Status)){
247                 goto fail;
248         }
249
250         DeviceObject = IoGetRelatedDeviceObject(FileObject);
251
252         Irp = IoAllocateIrp(
253                         DeviceObject->StackSize,
254                         TRUE
255                         );
256
257         if (Irp == NULL) {
258                 Status = STATUS_INSUFFICIENT_RESOURCES;
259                 goto fail;
260         }
261
262    //trigger FileObject/Event dereferencing
263    Irp->Tail.Overlay.OriginalFileObject = FileObject;
264
265         Irp->UserIosb = &LocalIoStatusBlock;
266         Irp->Tail.Overlay.Thread = PsGetCurrentThread();
267
268         StackPtr = (PEXTENDED_IO_STACK_LOCATION) IoGetNextIrpStackLocation(Irp);
269         StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
270         StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
271         StackPtr->DeviceObject = DeviceObject;
272         StackPtr->FileObject = FileObject;
273
274         LocalLength = ExAllocatePoolWithTag(
275                                                                         NonPagedPool,
276                                                                         sizeof(LARGE_INTEGER),
277                                                                         TAG_LOCK
278                                                                         );
279         if (!LocalLength){
280                 Status = STATUS_INSUFFICIENT_RESOURCES;
281                 goto fail;
282         }
283
284         *LocalLength = *Length;
285
286         StackPtr->Parameters.LockControl.Length = LocalLength;
287         StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
288         StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
289
290         //allways syncronious
291         Status = IofCallDriver(DeviceObject, Irp);
292
293         *UserIoStatusBlock = LocalIoStatusBlock;
294
295         ExFreePool(LocalLength);
296
297         return Status;
298
299         fail:;
300
301         if (LocalLength) ExFreePool(LocalLength);
302         if (Irp) IoFreeIrp(Irp);
303         if (FileObject) ObDereferenceObject(FileObject);
304
305         return Status;
306 }