[NTOSKRNL]
[reactos.git] / ntoskrnl / fsrtl / filelock.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fsrtl/filelock.c
5 * PURPOSE: File Locking implementation for File System Drivers
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 PAGED_LOOKASIDE_LIST FsRtlFileLockLookasideList;
18
19 /* PRIVATE FUNCTIONS *********************************************************/
20
21 VOID
22 NTAPI
23 FsRtlCompleteLockIrpReal(IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteRoutine,
24 IN PVOID Context,
25 IN PIRP Irp,
26 IN NTSTATUS Status,
27 OUT PNTSTATUS NewStatus,
28 IN PFILE_OBJECT FileObject OPTIONAL)
29 {
30 /* Check if we have a complete routine */
31 if (CompleteRoutine)
32 {
33 /* Check if we have a file object */
34 if (FileObject) FileObject->LastLock = NULL;
35
36 /* Set the I/O Status and do completion */
37 Irp->IoStatus.Status = Status;
38 *NewStatus = CompleteRoutine(Context, Irp);
39 }
40 else
41 {
42 /* Otherwise do a normal I/O complete request */
43 FsRtlCompleteRequest(Irp, Status);
44 *NewStatus = Status;
45 }
46 }
47
48 /* PUBLIC FUNCTIONS **********************************************************/
49
50 /*
51 * @implemented
52 */
53 PFILE_LOCK_INFO
54 NTAPI
55 FsRtlGetNextFileLock(IN PFILE_LOCK FileLock,
56 IN BOOLEAN Restart)
57 {
58 KeBugCheck(FILE_SYSTEM);
59 return NULL;
60 }
61
62 /*
63 * @implemented
64 */
65 BOOLEAN
66 NTAPI
67 FsRtlPrivateLock(IN PFILE_LOCK FileLock,
68 IN PFILE_OBJECT FileObject,
69 IN PLARGE_INTEGER FileOffset,
70 IN PLARGE_INTEGER Length,
71 IN PEPROCESS Process,
72 IN ULONG Key,
73 IN BOOLEAN FailImmediately,
74 IN BOOLEAN ExclusiveLock,
75 OUT PIO_STATUS_BLOCK IoStatus,
76 IN PIRP Irp OPTIONAL,
77 IN PVOID Context OPTIONAL,
78 IN BOOLEAN AlreadySynchronized)
79 {
80 NTSTATUS Status;
81
82 static BOOLEAN Warn;
83 if (!Warn++) DPRINT1("FsRtlPrivateLock() is stubplemented!\n");
84
85 /* Initialize the lock, if necessary */
86 if (!FileLock->LockInformation)
87 {
88 DPRINT("LockInformation is uninitialized!\n");
89 }
90
91 /* Assume all is cool, and lock is set */
92 IoStatus->Status = STATUS_SUCCESS;
93
94 if (Irp)
95 {
96 /* Complete the request */
97 FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
98 Context,
99 Irp,
100 IoStatus->Status,
101 &Status,
102 FileObject);
103
104 /* Update the status */
105 IoStatus->Status = Status;
106 }
107
108 return TRUE;
109 }
110
111 /*
112 * @implemented
113 */
114 BOOLEAN
115 NTAPI
116 FsRtlCheckLockForReadAccess(IN PFILE_LOCK FileLock,
117 IN PIRP Irp)
118 {
119 KeBugCheck(FILE_SYSTEM);
120 return FALSE;
121 }
122
123 /*
124 * @implemented
125 */
126 BOOLEAN
127 NTAPI
128 FsRtlCheckLockForWriteAccess(IN PFILE_LOCK FileLock,
129 IN PIRP Irp)
130 {
131 KeBugCheck(FILE_SYSTEM);
132 return FALSE;
133 }
134
135 /*
136 * @implemented
137 */
138 BOOLEAN
139 NTAPI
140 FsRtlFastCheckLockForRead(IN PFILE_LOCK FileLock,
141 IN PLARGE_INTEGER FileOffset,
142 IN PLARGE_INTEGER Length,
143 IN ULONG Key,
144 IN PFILE_OBJECT FileObject,
145 IN PVOID Process)
146 {
147 KeBugCheck(FILE_SYSTEM);
148 return FALSE;
149 }
150
151 /*
152 * @implemented
153 */
154 BOOLEAN
155 NTAPI
156 FsRtlFastCheckLockForWrite(IN PFILE_LOCK FileLock,
157 IN PLARGE_INTEGER FileOffset,
158 IN PLARGE_INTEGER Length,
159 IN ULONG Key,
160 IN PFILE_OBJECT FileObject,
161 IN PVOID Process)
162 {
163 KeBugCheck(FILE_SYSTEM);
164 return FALSE;
165 }
166
167 /*
168 * @implemented
169 */
170 NTSTATUS
171 NTAPI
172 FsRtlFastUnlockSingle(IN PFILE_LOCK FileLock,
173 IN PFILE_OBJECT FileObject,
174 IN PLARGE_INTEGER FileOffset,
175 IN PLARGE_INTEGER Length,
176 IN PEPROCESS Process,
177 IN ULONG Key,
178 IN PVOID Context OPTIONAL,
179 IN BOOLEAN AlreadySynchronized)
180 {
181 static BOOLEAN Warn;
182 if (!Warn++) DPRINT1("FsRtlFastUnlockSingle() is stubplemented!\n");
183
184 return STATUS_SUCCESS;
185 }
186
187 /*
188 * @implemented
189 */
190 NTSTATUS
191 NTAPI
192 FsRtlFastUnlockAll(IN PFILE_LOCK FileLock,
193 IN PFILE_OBJECT FileObject,
194 IN PEPROCESS Process,
195 IN PVOID Context OPTIONAL)
196 {
197 KeBugCheck(FILE_SYSTEM);
198 return STATUS_UNSUCCESSFUL;
199 }
200
201 /*
202 * @implemented
203 */
204 NTSTATUS
205 NTAPI
206 FsRtlFastUnlockAllByKey(IN PFILE_LOCK FileLock,
207 IN PFILE_OBJECT FileObject,
208 IN PEPROCESS Process,
209 IN ULONG Key,
210 IN PVOID Context OPTIONAL)
211 {
212 KeBugCheck(FILE_SYSTEM);
213 return STATUS_UNSUCCESSFUL;
214 }
215
216 /*
217 * @implemented
218 */
219 NTSTATUS
220 NTAPI
221 FsRtlProcessFileLock(IN PFILE_LOCK FileLock,
222 IN PIRP Irp,
223 IN PVOID Context OPTIONAL)
224 {
225 PIO_STACK_LOCATION IoStackLocation;
226 NTSTATUS Status;
227 IO_STATUS_BLOCK IoStatusBlock;
228
229 /* Get the I/O Stack location */
230 IoStackLocation = IoGetCurrentIrpStackLocation(Irp);
231 ASSERT(IoStackLocation->MajorFunction == IRP_MJ_LOCK_CONTROL);
232
233 /* Clear the I/O status block and check what function this is */
234 IoStatusBlock.Information = 0;
235 switch(IoStackLocation->MinorFunction)
236 {
237 /* A lock */
238 case IRP_MN_LOCK:
239
240 /* Call the private lock routine */
241 FsRtlPrivateLock(FileLock,
242 IoStackLocation->FileObject,
243 &IoStackLocation->
244 Parameters.LockControl.ByteOffset,
245 IoStackLocation->Parameters.LockControl.Length,
246 IoGetRequestorProcess(Irp),
247 IoStackLocation->Parameters.LockControl.Key,
248 IoStackLocation->Flags & SL_FAIL_IMMEDIATELY,
249 IoStackLocation->Flags & SL_EXCLUSIVE_LOCK,
250 &IoStatusBlock,
251 Irp,
252 Context,
253 FALSE);
254 break;
255
256 /* A single unlock */
257 case IRP_MN_UNLOCK_SINGLE:
258
259 /* Call fast unlock */
260 IoStatusBlock.Status =
261 FsRtlFastUnlockSingle(FileLock,
262 IoStackLocation->FileObject,
263 &IoStackLocation->Parameters.LockControl.
264 ByteOffset,
265 IoStackLocation->Parameters.LockControl.
266 Length,
267 IoGetRequestorProcess(Irp),
268 IoStackLocation->Parameters.LockControl.
269 Key,
270 Context,
271 FALSE);
272
273 /* Complete the IRP */
274 FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
275 Context,
276 Irp,
277 IoStatusBlock.Status,
278 &Status,
279 NULL);
280 break;
281
282 /* Total unlock */
283 case IRP_MN_UNLOCK_ALL:
284
285 /* Do a fast unlock */
286 IoStatusBlock.Status = FsRtlFastUnlockAll(FileLock,
287 IoStackLocation->
288 FileObject,
289 IoGetRequestorProcess(Irp),
290 Context);
291
292 /* Complete the IRP */
293 FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
294 Context,
295 Irp,
296 IoStatusBlock.Status,
297 &Status,
298 NULL);
299 break;
300
301 /* Unlock by key */
302 case IRP_MN_UNLOCK_ALL_BY_KEY:
303
304 /* Do it */
305 IoStatusBlock.Status =
306 FsRtlFastUnlockAllByKey(FileLock,
307 IoStackLocation->FileObject,
308 IoGetRequestorProcess(Irp),
309 IoStackLocation->Parameters.
310 LockControl.Key,
311 Context);
312
313 /* Complete the IRP */
314 FsRtlCompleteLockIrpReal(FileLock->CompleteLockIrpRoutine,
315 Context,
316 Irp,
317 IoStatusBlock.Status,
318 &Status,
319 NULL);
320 break;
321
322 /* Invalid request */
323 default:
324
325 /* Complete it */
326 FsRtlCompleteRequest(Irp, STATUS_INVALID_DEVICE_REQUEST);
327 IoStatusBlock.Status = STATUS_INVALID_DEVICE_REQUEST;
328 break;
329 }
330
331 /* Return the status */
332 return IoStatusBlock.Status;
333 }
334
335 /*
336 * @implemented
337 */
338 VOID
339 NTAPI
340 FsRtlInitializeFileLock (IN PFILE_LOCK FileLock,
341 IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL,
342 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL)
343 {
344 /* Setup the lock */
345 FileLock->FastIoIsQuestionable = FALSE;
346 FileLock->CompleteLockIrpRoutine = CompleteLockIrpRoutine;
347 FileLock->UnlockRoutine = UnlockRoutine;
348 FileLock->LockInformation = NULL;
349 }
350
351 /*
352 * @implemented
353 */
354 VOID
355 NTAPI
356 FsRtlUninitializeFileLock(IN PFILE_LOCK FileLock)
357 {
358 return;
359 }
360
361 /*
362 * @implemented
363 */
364 PFILE_LOCK
365 NTAPI
366 FsRtlAllocateFileLock(IN PCOMPLETE_LOCK_IRP_ROUTINE CompleteLockIrpRoutine OPTIONAL,
367 IN PUNLOCK_ROUTINE UnlockRoutine OPTIONAL)
368 {
369 PFILE_LOCK FileLock;
370
371 /* Try to allocate it */
372 FileLock = ExAllocateFromPagedLookasideList(&FsRtlFileLockLookasideList);
373 if (FileLock)
374 {
375 /* Initialize it */
376 FsRtlInitializeFileLock(FileLock,
377 CompleteLockIrpRoutine,
378 UnlockRoutine);
379 }
380
381 /* Return the lock */
382 return FileLock;
383 }
384
385 /*
386 * @implemented
387 */
388 VOID
389 NTAPI
390 FsRtlFreeFileLock(IN PFILE_LOCK FileLock)
391 {
392 /* Uninitialize and free the lock */
393 FsRtlUninitializeFileLock(FileLock);
394 ExFreeToPagedLookasideList(&FsRtlFileLockLookasideList, FileLock);
395 }
396