branch update for HEAD-2003050101
[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 NTSTATUS
38 STDCALL
39 NtLockFile (
40         IN      HANDLE                  FileHandle,
41         IN      HANDLE                  EventHandle             OPTIONAL,
42         IN      PIO_APC_ROUTINE         ApcRoutine      OPTIONAL,
43         IN      PVOID                   ApcContext      OPTIONAL,
44         OUT     PIO_STATUS_BLOCK        UserIoStatusBlock,
45         IN      PLARGE_INTEGER          ByteOffset,
46         IN      PLARGE_INTEGER          Length,
47         IN      PULONG                  Key,
48         IN      BOOLEAN                 FailImmediatedly,
49         IN      BOOLEAN                 ExclusiveLock
50         )
51 {
52         NTSTATUS Status;
53         PFILE_OBJECT FileObject = NULL;
54         PLARGE_INTEGER  LocalLength = NULL;
55         PKEVENT Event = NULL;
56         PIRP Irp = NULL;
57         PIO_STACK_LOCATION StackPtr;
58         IO_STATUS_BLOCK         LocalIoStatusBlock;
59         PIO_STATUS_BLOCK IoStatusBlock;
60         PDEVICE_OBJECT  DeviceObject;
61    ULONG FobFlags;
62
63         //FIXME: instead of this, use SEH when available?
64         if (!Length || !ByteOffset)     {
65                 Status = STATUS_INVALID_PARAMETER;
66                 goto fail;
67         }
68
69         Status = ObReferenceObjectByHandle(
70                                          FileHandle,
71                                      0,
72                                      IoFileObjectType,
73                                      ExGetPreviousMode(),
74                                      (PVOID*)&FileObject,
75                                      NULL);
76
77         if (!NT_SUCCESS(Status)){
78                 goto fail;
79         }
80
81         DeviceObject = IoGetRelatedDeviceObject(FileObject);
82
83         Irp = IoAllocateIrp(
84                         DeviceObject->StackSize,
85                         TRUE
86                         );
87
88         if (Irp == NULL) {
89                 Status = STATUS_INSUFFICIENT_RESOURCES;
90                 goto fail;
91         }
92
93         if (EventHandle != NULL && !FailImmediatedly) {
94                  Status = ObReferenceObjectByHandle(
95                                          EventHandle,
96                                          SYNCHRONIZE,
97                                          ExEventObjectType,
98                                          ExGetPreviousMode(),
99                                          (PVOID*)&Event,
100                                          NULL);
101
102                 if (!NT_SUCCESS(Status)) {
103                         goto fail;
104                 }
105
106         }       
107         else {
108                 Event = &FileObject->Event;
109                 KeResetEvent(Event);
110         }
111
112         if ((FileObject->Flags & FO_SYNCHRONOUS_IO) || FailImmediatedly)
113                 IoStatusBlock = &LocalIoStatusBlock;
114         else
115                 IoStatusBlock = UserIoStatusBlock;
116
117         Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
118         Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
119
120         Irp->UserEvent = Event;
121         Irp->UserIosb = IoStatusBlock;
122         Irp->Tail.Overlay.Thread = PsGetCurrentThread();
123
124         StackPtr = IoGetNextIrpStackLocation(Irp);
125         StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
126         StackPtr->MinorFunction = IRP_MN_LOCK;
127         StackPtr->FileObject = FileObject;
128         
129         if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
130         if (FailImmediatedly) StackPtr->Flags |= SL_FAIL_IMMEDIATELY;
131
132         LocalLength = ExAllocatePoolWithTag(
133                                                                         NonPagedPool,
134                                                                         sizeof(LARGE_INTEGER),
135                                                                         TAG_LOCK
136                                                                         );
137         if (!LocalLength){
138                 Status = STATUS_INSUFFICIENT_RESOURCES;
139                 goto fail;
140         }
141
142         *LocalLength = *Length;
143
144         StackPtr->Parameters.LockControl.Length = LocalLength;
145         StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
146         StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
147
148         IoSetCompletionRoutine(  
149                                         Irp,  
150                                         NtLockFileCompletionRoutine,  
151                                         LocalLength,  
152                                         TRUE,   
153                                         TRUE,  
154                                         TRUE  );
155
156    //can't touch FileObject after IoCallDriver since it might be freed
157    FobFlags = FileObject->Flags;
158         Status = IofCallDriver(DeviceObject, Irp);
159
160    if (Status == STATUS_PENDING && (FobFlags & FO_SYNCHRONOUS_IO)) {
161
162                 Status = KeWaitForSingleObject(
163                                                         Event,
164                                                         Executive,
165                                                         ExGetPreviousMode() , 
166                      (FobFlags & FO_ALERTABLE_IO) ? TRUE : FALSE,
167                                                         NULL
168                                                         );
169
170                 if (Status != STATUS_WAIT_0) {
171                         DPRINT1("NtLockFile -> KeWaitForSingleObject failed!\n");
172                         /*
173                         FIXME: should do some special processing here if alertable wait 
174                         was interupted by user apc or a thread alert (STATUS_ALERTED, STATUS_USER_APC)
175                         */
176                         return Status;   //set status to something else?
177                 }
178
179                 Status = LocalIoStatusBlock.Status;
180         }
181
182    if (FobFlags & FO_SYNCHRONOUS_IO)
183                 *UserIoStatusBlock = LocalIoStatusBlock;
184
185         return Status;
186
187         fail:;
188
189         if (LocalLength) ExFreePool(LocalLength);
190         if (Irp) IoFreeIrp(Irp);
191         if (Event) ObDereferenceObject(Event);
192         if (FileObject) ObDereferenceObject(FileObject);
193
194         return Status;
195
196 }
197
198
199
200
201 NTSTATUS
202 STDCALL
203 NtUnlockFile (
204         IN      HANDLE                  FileHandle,
205         OUT     PIO_STATUS_BLOCK        UserIoStatusBlock,
206         IN      PLARGE_INTEGER          ByteOffset,
207         IN      PLARGE_INTEGER          Length,
208         OUT     PULONG                  Key             OPTIONAL
209         )
210 {
211         NTSTATUS Status;
212         PFILE_OBJECT FileObject = NULL;
213         PLARGE_INTEGER  LocalLength = NULL;
214         PIRP Irp  = NULL;
215         PIO_STACK_LOCATION StackPtr;
216         IO_STATUS_BLOCK         LocalIoStatusBlock;
217         PDEVICE_OBJECT  DeviceObject;
218
219         //FIXME: instead of this, use SEH when available
220         if (!Length || !ByteOffset)     {
221                 Status = STATUS_INVALID_PARAMETER;
222                 goto fail;
223         }
224
225         /*
226         BUGBUG: ObReferenceObjectByHandle fails if DesiredAccess=0 and mode=UserMode
227         It should ONLY fail if we desire an access that conflict with granted access!
228         */
229         Status = ObReferenceObjectByHandle(
230                                          FileHandle,
231                                      FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to!
232                                      IoFileObjectType,
233                                      ExGetPreviousMode(),
234                                      (PVOID*)&FileObject,
235                                      NULL);
236
237         if (!NT_SUCCESS(Status)){
238                 goto fail;
239         }
240
241         DeviceObject = IoGetRelatedDeviceObject(FileObject);
242
243         Irp = IoAllocateIrp(
244                         DeviceObject->StackSize,
245                         TRUE
246                         );
247
248         if (Irp == NULL) {
249                 Status = STATUS_INSUFFICIENT_RESOURCES;
250                 goto fail;
251         }
252
253         Irp->UserIosb = &LocalIoStatusBlock;
254         Irp->Tail.Overlay.Thread = PsGetCurrentThread();
255
256         StackPtr = IoGetNextIrpStackLocation(Irp);
257         StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
258         StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
259         StackPtr->DeviceObject = DeviceObject;
260         StackPtr->FileObject = FileObject;
261
262         LocalLength = ExAllocatePoolWithTag(
263                                                                         NonPagedPool,
264                                                                         sizeof(LARGE_INTEGER),
265                                                                         TAG_LOCK
266                                                                         );
267         if (!LocalLength){
268                 Status = STATUS_INSUFFICIENT_RESOURCES;
269                 goto fail;
270         }
271
272         *LocalLength = *Length;
273
274         StackPtr->Parameters.LockControl.Length = LocalLength;
275         StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
276         StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
277
278         //allways syncronious
279         Status = IofCallDriver(DeviceObject, Irp);
280
281         *UserIoStatusBlock = LocalIoStatusBlock;
282
283         ExFreePool(LocalLength);
284
285         return Status;
286
287         fail:;
288
289         if (LocalLength) ExFreePool(LocalLength);
290         if (Irp) IoFreeIrp(Irp);
291         if (FileObject) ObDereferenceObject(FileObject);
292
293         return Status;
294 }