branch update for HEAD-2003021201
[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
62         //FIXME: instead of this, use SEH when available?
63         if (!Length || !ByteOffset)     {
64                 Status = STATUS_INVALID_PARAMETER;
65                 goto fail;
66         }
67
68         /*
69         BUGBUG: ObReferenceObjectByHandle fails if DesiredAccess=0 and mode=UserMode!
70         It should ONLY fail if we desire an access that conflict with granted access!
71         */
72         Status = ObReferenceObjectByHandle(
73                                          FileHandle,
74                                      FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to!
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         Irp->Overlay.AsynchronousParameters.UserApcRoutine = ApcRoutine;
121         Irp->Overlay.AsynchronousParameters.UserApcContext = ApcContext;
122
123         Irp->UserEvent = Event;
124         Irp->UserIosb = IoStatusBlock;
125         Irp->Tail.Overlay.Thread = PsGetCurrentThread();
126
127         StackPtr = IoGetNextIrpStackLocation(Irp);
128         StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
129         StackPtr->MinorFunction = IRP_MN_LOCK;
130         StackPtr->DeviceObject = DeviceObject;
131         StackPtr->FileObject = FileObject;
132         
133         if (ExclusiveLock) StackPtr->Flags |= SL_EXCLUSIVE_LOCK;
134         if (FailImmediatedly) StackPtr->Flags |= SL_FAIL_IMMEDIATELY;
135
136         LocalLength = ExAllocatePoolWithTag(
137                                                                         NonPagedPool,
138                                                                         sizeof(LARGE_INTEGER),
139                                                                         TAG_LOCK
140                                                                         );
141         if (!LocalLength){
142                 Status = STATUS_INSUFFICIENT_RESOURCES;
143                 goto fail;
144         }
145
146         *LocalLength = *Length;
147
148         StackPtr->Parameters.LockControl.Length = LocalLength;
149         StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
150         StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
151
152         IoSetCompletionRoutine(  
153                                         Irp,  
154                                         NtLockFileCompletionRoutine,  
155                                         LocalLength,  
156                                         TRUE,   
157                                         TRUE,  
158                                         TRUE  );
159
160         Status = IofCallDriver(DeviceObject, Irp);
161
162         if (Status == STATUS_PENDING && (FileObject->Flags & FO_SYNCHRONOUS_IO)) {
163
164                 Status = KeWaitForSingleObject(
165                                                         Event,
166                                                         Executive,
167                                                         ExGetPreviousMode() , 
168                                                         (FileObject->Flags & FO_ALERTABLE_IO) ? TRUE : FALSE,
169                                                         NULL
170                                                         );
171
172                 if (Status != STATUS_WAIT_0) {
173                         DPRINT1("NtLockFile -> KeWaitForSingleObject failed!\n");
174                         /*
175                         FIXME: should do some special processing here if alertable wait 
176                         was interupted by user apc or a thread alert (STATUS_ALERTED, STATUS_USER_APC)
177                         */
178                         return Status;   //set status to something else?
179                 }
180
181                 Status = LocalIoStatusBlock.Status;
182         }
183
184         if (FileObject->Flags & FO_SYNCHRONOUS_IO)
185                 *UserIoStatusBlock = LocalIoStatusBlock;
186
187         return Status;
188
189         fail:;
190
191         if (LocalLength) ExFreePool(LocalLength);
192         if (Irp) IoFreeIrp(Irp);
193         if (Event) ObDereferenceObject(Event);
194         if (FileObject) ObDereferenceObject(FileObject);
195
196         return Status;
197
198 }
199
200
201
202
203 NTSTATUS
204 STDCALL
205 NtUnlockFile (
206         IN      HANDLE                  FileHandle,
207         OUT     PIO_STATUS_BLOCK        UserIoStatusBlock,
208         IN      PLARGE_INTEGER          ByteOffset,
209         IN      PLARGE_INTEGER          Length,
210         OUT     PULONG                  Key             OPTIONAL
211         )
212 {
213         NTSTATUS Status;
214         PFILE_OBJECT FileObject = NULL;
215         PLARGE_INTEGER  LocalLength = NULL;
216         PIRP Irp  = NULL;
217         PIO_STACK_LOCATION StackPtr;
218         IO_STATUS_BLOCK         LocalIoStatusBlock;
219         PDEVICE_OBJECT  DeviceObject;
220
221         //FIXME: instead of this, use SEH when available
222         if (!Length || !ByteOffset)     {
223                 Status = STATUS_INVALID_PARAMETER;
224                 goto fail;
225         }
226
227         /*
228         BUGBUG: ObReferenceObjectByHandle fails if DesiredAccess=0 and mode=UserMode
229         It should ONLY fail if we desire an access that conflict with granted access!
230         */
231         Status = ObReferenceObjectByHandle(
232                                          FileHandle,
233                                      FILE_READ_DATA,//BUGBUG: have to use something...but shouldn't have to!
234                                      IoFileObjectType,
235                                      ExGetPreviousMode(),
236                                      (PVOID*)&FileObject,
237                                      NULL);
238
239         if (!NT_SUCCESS(Status)){
240                 goto fail;
241         }
242
243         DeviceObject = IoGetRelatedDeviceObject(FileObject);
244
245         Irp = IoAllocateIrp(
246                         DeviceObject->StackSize,
247                         TRUE
248                         );
249
250         if (Irp == NULL) {
251                 Status = STATUS_INSUFFICIENT_RESOURCES;
252                 goto fail;
253         }
254
255         Irp->UserIosb = &LocalIoStatusBlock;
256         Irp->Tail.Overlay.Thread = PsGetCurrentThread();
257
258         StackPtr = IoGetNextIrpStackLocation(Irp);
259         StackPtr->MajorFunction = IRP_MJ_LOCK_CONTROL;
260         StackPtr->MinorFunction = IRP_MN_UNLOCK_SINGLE;
261         StackPtr->DeviceObject = DeviceObject;
262         StackPtr->FileObject = FileObject;
263
264         LocalLength = ExAllocatePoolWithTag(
265                                                                         NonPagedPool,
266                                                                         sizeof(LARGE_INTEGER),
267                                                                         TAG_LOCK
268                                                                         );
269         if (!LocalLength){
270                 Status = STATUS_INSUFFICIENT_RESOURCES;
271                 goto fail;
272         }
273
274         *LocalLength = *Length;
275
276         StackPtr->Parameters.LockControl.Length = LocalLength;
277         StackPtr->Parameters.LockControl.ByteOffset = *ByteOffset;
278         StackPtr->Parameters.LockControl.Key = Key ? *Key : 0;
279
280         //allways syncronious
281         Status = IofCallDriver(DeviceObject, Irp);
282
283         *UserIoStatusBlock = LocalIoStatusBlock;
284
285         ExFreePool(LocalLength);
286
287         return Status;
288
289         fail:;
290
291         if (LocalLength) ExFreePool(LocalLength);
292         if (Irp) IoFreeIrp(Irp);
293         if (FileObject) ObDereferenceObject(FileObject);
294
295         return Status;
296 }