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