Commit of the rest of Gunnars file locking patch.
[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 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 }