1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
3 // All rights reserved
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
6 /*************************************************************************
7 *
8 * File: LockCtrl.cpp.cpp
9 *
10 * Module: UDF File System Driver (Kernel mode execution only)
11 *
12 * Description:
13 * Contains code to handle the "byte-range locking" dispatch entry point.
14 *
15 *************************************************************************/
16
17 #include "udffs.h"
18
19 // define the file specific bug-check id
20 #define UDF_BUG_CHECK_ID UDF_FILE_SHUTDOWN
21
22
23 /*************************************************************************
24 *
25 * Function: UDFLockControl()
26 *
27 * Description:
28 *
29 * Expected Interrupt Level (for execution) :
30 *
31 * IRQL_PASSIVE_LEVEL
32 *
33 * Return Value: Irrelevant.
34 *
35 *************************************************************************/
36 NTSTATUS
37 NTAPI
UDFLockControl(IN PDEVICE_OBJECT DeviceObject,IN PIRP Irp)38 UDFLockControl(
39 IN PDEVICE_OBJECT DeviceObject, // the logical volume device object
40 IN PIRP Irp) // I/O Request Packet
41 {
42 NTSTATUS RC = STATUS_SUCCESS;
43 PtrUDFIrpContext PtrIrpContext = NULL;
44 BOOLEAN AreWeTopLevel = FALSE;
45
46 UDFPrint(("UDFLockControl\n"));
47 // BrutePoint();
48
49 FsRtlEnterFileSystem();
50 ASSERT(DeviceObject);
51 ASSERT(Irp);
52
53 // set the top level context
54 AreWeTopLevel = UDFIsIrpTopLevel(Irp);
55 // Call the common Lock Control routine, with blocking allowed if
56 // synchronous
57 _SEH2_TRY {
58
59 // get an IRP context structure and issue the request
60 PtrIrpContext = UDFAllocateIrpContext(Irp, DeviceObject);
61 if(PtrIrpContext) {
62 RC = UDFCommonLockControl(PtrIrpContext, Irp);
63 } else {
64 RC = STATUS_INSUFFICIENT_RESOURCES;
65 Irp->IoStatus.Status = RC;
66 Irp->IoStatus.Information = 0;
67 // complete the IRP
68 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
69 }
70
71 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
72
73 RC = UDFExceptionHandler(PtrIrpContext, Irp);
74
75 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
76 } _SEH2_END;
77
78 if (AreWeTopLevel) {
79 IoSetTopLevelIrp(NULL);
80 }
81
82 FsRtlExitFileSystem();
83
84 return(RC);
85 } // end UDFLockControl()
86
87
88 /*************************************************************************
89 *
90 * Function: UDFCommonLockControl()
91 *
92 * Description:
93 * This is the common routine for doing Lock control operations called
94 * by both the fsd and fsp threads
95 *
96 * Expected Interrupt Level (for execution) :
97 *
98 * IRQL_PASSIVE_LEVEL
99 *
100 * Return Value: Irrelevant
101 *
102 *************************************************************************/
103 NTSTATUS
104 NTAPI
UDFCommonLockControl(IN PtrUDFIrpContext PtrIrpContext,IN PIRP Irp)105 UDFCommonLockControl(
106 IN PtrUDFIrpContext PtrIrpContext,
107 IN PIRP Irp)
108 {
109 NTSTATUS RC = STATUS_SUCCESS;
110 PIO_STACK_LOCATION IrpSp = NULL;
111 //IO_STATUS_BLOCK LocalIoStatus;
112 // BOOLEAN CompleteRequest = FALSE;
113 BOOLEAN PostRequest = FALSE;
114 BOOLEAN CanWait = FALSE;
115 PtrUDFNTRequiredFCB NtReqFcb = NULL;
116 BOOLEAN AcquiredFCB = FALSE;
117 PFILE_OBJECT FileObject = NULL;
118 PtrUDFFCB Fcb = NULL;
119 PtrUDFCCB Ccb = NULL;
120
121 UDFPrint(("UDFCommonLockControl\n"));
122
123 _SEH2_TRY {
124 // First, get a pointer to the current I/O stack location.
125 IrpSp = IoGetCurrentIrpStackLocation(Irp);
126 ASSERT(IrpSp);
127
128 FileObject = IrpSp->FileObject;
129 ASSERT(FileObject);
130
131 // Get the FCB and CCB pointers.
132 Ccb = (PtrUDFCCB)(FileObject->FsContext2);
133 ASSERT(Ccb);
134 Fcb = Ccb->Fcb;
135 ASSERT(Fcb);
136 // Validate the sent-in FCB
137 if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
138 (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
139
140 // CompleteRequest = TRUE;
141 try_return(RC = STATUS_INVALID_PARAMETER);
142 }
143
144 NtReqFcb = Fcb->NTRequiredFCB;
145 CanWait = ((PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_CAN_BLOCK) ? TRUE : FALSE);
146
147 // Acquire the FCB resource shared
148 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
149 if (!UDFAcquireResourceExclusive(&(NtReqFcb->MainResource), CanWait)) {
150 PostRequest = TRUE;
151 try_return(RC = STATUS_PENDING);
152 }
153 AcquiredFCB = TRUE;
154
155 RC = FsRtlProcessFileLock(&(NtReqFcb->FileLock), Irp, NULL);
156 // CompleteRequest = TRUE;
157
158 try_exit: NOTHING;
159
160 } _SEH2_FINALLY {
161
162 // Release the FCB resources if acquired.
163 if (AcquiredFCB) {
164 UDF_CHECK_PAGING_IO_RESOURCE(NtReqFcb);
165 UDFReleaseResource(&(NtReqFcb->MainResource));
166 AcquiredFCB = FALSE;
167 }
168 if (PostRequest) {
169 // Perform appropriate post related processing here
170 RC = UDFPostRequest(PtrIrpContext, Irp);
171 } else
172 if(!_SEH2_AbnormalTermination()) {
173 // Simply free up the IrpContext since the IRP has been queued or
174 // Completed by FsRtlProcessFileLock
175 UDFReleaseIrpContext(PtrIrpContext);
176 }
177 } _SEH2_END; // end of "__finally" processing
178
179 return(RC);
180 } // end UDFCommonLockControl()
181
182
183 /*
184 Routine Description:
185 This is a call back routine for doing the fast lock call.
186 Arguments:
187 FileObject - Supplies the file object used in this operation
188 FileOffset - Supplies the file offset used in this operation
189 Length - Supplies the length used in this operation
190 ProcessId - Supplies the process ID used in this operation
191 Key - Supplies the key used in this operation
192 FailImmediately - Indicates if the request should fail immediately
193 if the lock cannot be granted.
194 ExclusiveLock - Indicates if this is a request for an exclusive or
195 shared lock
196 IoStatus - Receives the Status if this operation is successful
197
198 Return Value:
199 BOOLEAN - TRUE if this operation completed and FALSE if caller
200 needs to take the long route.
201 */
202
203 BOOLEAN
204 NTAPI
UDFFastLock(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN PLARGE_INTEGER Length,PEPROCESS ProcessId,ULONG Key,BOOLEAN FailImmediately,BOOLEAN ExclusiveLock,OUT PIO_STATUS_BLOCK IoStatus,IN PDEVICE_OBJECT DeviceObject)205 UDFFastLock (
206 IN PFILE_OBJECT FileObject,
207 IN PLARGE_INTEGER FileOffset,
208 IN PLARGE_INTEGER Length,
209 PEPROCESS ProcessId,
210 ULONG Key,
211 BOOLEAN FailImmediately,
212 BOOLEAN ExclusiveLock,
213 OUT PIO_STATUS_BLOCK IoStatus,
214 IN PDEVICE_OBJECT DeviceObject
215 )
216 {
217 BOOLEAN Results = FALSE;
218
219 // BOOLEAN AcquiredFCB = FALSE;
220 PtrUDFFCB Fcb = NULL;
221 PtrUDFCCB Ccb = NULL;
222
223 UDFPrint(("UDFFastLock\n"));
224 // Decode the type of file object we're being asked to process and make
225 // sure it is only a user file open.
226
227
228 // Get the FCB and CCB pointers.
229 Ccb = (PtrUDFCCB)(FileObject->FsContext2);
230 ASSERT(Ccb);
231 Fcb = Ccb->Fcb;
232 ASSERT(Fcb);
233 // Validate the sent-in FCB
234 if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
235 (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
236
237 IoStatus->Status = STATUS_INVALID_PARAMETER;
238 IoStatus->Information = 0;
239 return TRUE;
240 }
241
242 // Acquire exclusive access to the Fcb this operation can always wait
243
244 FsRtlEnterFileSystem();
245
246 // BUGBUG: kenr
247 // (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE );
248
249 _SEH2_TRY {
250
251 // We check whether we can proceed
252 // based on the state of the file oplocks.
253
254 // Now call the FsRtl routine to do the actual processing of the
255 // Lock request
256 if ((Results = FsRtlFastLock( &(Fcb->NTRequiredFCB->FileLock),
257 FileObject,
258 FileOffset,
259 Length,
260 ProcessId,
261 Key,
262 FailImmediately,
263 ExclusiveLock,
264 IoStatus,
265 NULL,
266 FALSE ))) {
267
268 // Set the flag indicating if Fast I/O is possible
269 Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);
270 }
271
272 //try_exit: NOTHING;
273 } _SEH2_FINALLY {
274
275 // Release the Fcb, and return to our caller
276
277 // BUGBUG: kenr
278 // UDFReleaseResource( (Fcb)->Header.Resource );
279
280 FsRtlExitFileSystem();
281
282 } _SEH2_END;
283
284 return Results;
285 } // end UDFFastLock()
286
287
288 /*
289 Routine Description:
290
291 This is a call back routine for doing the fast unlock single call.
292
293 Arguments:
294
295 FileObject - Supplies the file object used in this operation
296 FileOffset - Supplies the file offset used in this operation
297 Length - Supplies the length used in this operation
298 ProcessId - Supplies the process ID used in this operation
299 Key - Supplies the key used in this operation
300 Status - Receives the Status if this operation is successful
301
302 Return Value:
303
304 BOOLEAN - TRUE if this operation completed and FALSE if caller
305 needs to take the long route.
306 */
307 BOOLEAN
308 NTAPI
UDFFastUnlockSingle(IN PFILE_OBJECT FileObject,IN PLARGE_INTEGER FileOffset,IN PLARGE_INTEGER Length,PEPROCESS ProcessId,ULONG Key,OUT PIO_STATUS_BLOCK IoStatus,IN PDEVICE_OBJECT DeviceObject)309 UDFFastUnlockSingle(
310 IN PFILE_OBJECT FileObject,
311 IN PLARGE_INTEGER FileOffset,
312 IN PLARGE_INTEGER Length,
313 PEPROCESS ProcessId,
314 ULONG Key,
315 OUT PIO_STATUS_BLOCK IoStatus,
316 IN PDEVICE_OBJECT DeviceObject
317 )
318
319 {
320 BOOLEAN Results = FALSE;
321
322 // BOOLEAN AcquiredFCB = FALSE;
323 PtrUDFFCB Fcb = NULL;
324 PtrUDFCCB Ccb = NULL;
325
326 UDFPrint(("UDFFastUnlockSingle\n"));
327 // Decode the type of file object we're being asked to process and make
328 // sure it is only a user file open.
329
330 IoStatus->Information = 0;
331
332 // Get the FCB and CCB pointers.
333 Ccb = (PtrUDFCCB)(FileObject->FsContext2);
334 ASSERT(Ccb);
335 Fcb = Ccb->Fcb;
336 ASSERT(Fcb);
337 // Validate the sent-in FCB
338 if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
339 (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
340
341 IoStatus->Status = STATUS_INVALID_PARAMETER;
342 return TRUE;
343 }
344
345 // Acquire exclusive access to the Fcb this operation can always wait
346
347 FsRtlEnterFileSystem();
348
349 // BUGBUG: kenr
350 // (VOID) ExAcquireResourceShared( Fcb->Header.Resource, TRUE );
351
352 _SEH2_TRY {
353
354 // We check whether we can proceed
355 // based on the state of the file oplocks.
356
357 // Now call the FsRtl routine to do the actual processing of the
358 // Lock request
359 Results = TRUE;
360 IoStatus->Status = FsRtlFastUnlockSingle( &(Fcb->NTRequiredFCB->FileLock),
361 FileObject,
362 FileOffset,
363 Length,
364 ProcessId,
365 Key,
366 NULL,
367 FALSE );
368 // Set the flag indicating if Fast I/O is possible
369 Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible(Fcb);
370
371 //try_exit: NOTHING;
372 } _SEH2_FINALLY {
373
374 // Release the Fcb, and return to our caller
375
376 // BUGBUG: kenr
377 // UDFReleaseResource( (Fcb)->Header.Resource );
378
379 FsRtlExitFileSystem();
380
381 } _SEH2_END;
382
383 return Results;
384 } // end UDFFastUnlockSingle()
385
386
387 /*
388 Routine Description:
389
390 This is a call back routine for doing the fast unlock all call.
391
392 Arguments:
393 FileObject - Supplies the file object used in this operation
394 ProcessId - Supplies the process ID used in this operation
395 Status - Receives the Status if this operation is successful
396
397 Return Value:
398
399 BOOLEAN - TRUE if this operation completed and FALSE if caller
400 needs to take the long route.
401 */
402 BOOLEAN
403 NTAPI
UDFFastUnlockAll(IN PFILE_OBJECT FileObject,PEPROCESS ProcessId,OUT PIO_STATUS_BLOCK IoStatus,IN PDEVICE_OBJECT DeviceObject)404 UDFFastUnlockAll(
405 IN PFILE_OBJECT FileObject,
406 PEPROCESS ProcessId,
407 OUT PIO_STATUS_BLOCK IoStatus,
408 IN PDEVICE_OBJECT DeviceObject
409 )
410
411 {
412 BOOLEAN Results = FALSE;
413
414 // BOOLEAN AcquiredFCB = FALSE;
415 PtrUDFFCB Fcb = NULL;
416 PtrUDFCCB Ccb = NULL;
417
418 UDFPrint(("UDFFastUnlockAll\n"));
419
420 IoStatus->Information = 0;
421 // Decode the type of file object we're being asked to process and make
422 // sure it is only a user file open.
423
424 // Get the FCB and CCB pointers.
425 Ccb = (PtrUDFCCB)(FileObject->FsContext2);
426 ASSERT(Ccb);
427 Fcb = Ccb->Fcb;
428 ASSERT(Fcb);
429 // Validate the sent-in FCB
430 if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
431 (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
432
433 IoStatus->Status = STATUS_INVALID_PARAMETER;
434 return TRUE;
435 }
436
437 // Acquire shared access to the Fcb this operation can always wait
438
439 FsRtlEnterFileSystem();
440
441 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
442 UDFAcquireResourceShared( &(Fcb->NTRequiredFCB->MainResource),TRUE );
443
444 _SEH2_TRY {
445
446 // We check whether we can proceed
447 // based on the state of the file oplocks.
448
449 // Now call the FsRtl routine to do the actual processing of the
450 // Lock request
451 Results = TRUE;
452 IoStatus->Status = FsRtlFastUnlockAll( &(Fcb->NTRequiredFCB->FileLock),
453 FileObject,
454 ProcessId,
455 NULL );
456
457 // Set the flag indicating if Fast I/O is questionable
458
459 Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible( Fcb );
460
461 //try_exit: NOTHING;
462 } _SEH2_FINALLY {
463
464 // Release the Fcb, and return to our caller
465
466 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
467 UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource));
468 FsRtlExitFileSystem();
469
470 } _SEH2_END;
471
472 return Results;
473 } // end UDFFastUnlockAll()
474
475
476 /*
477 Routine Description:
478
479 This is a call back routine for doing the fast unlock all call.
480
481 Arguments:
482 FileObject - Supplies the file object used in this operation
483 ProcessId - Supplies the process ID used in this operation
484 Status - Receives the Status if this operation is successful
485
486 Return Value:
487
488 BOOLEAN - TRUE if this operation completed and FALSE if caller
489 needs to take the long route.
490 */
491
492 BOOLEAN
493 NTAPI
UDFFastUnlockAllByKey(IN PFILE_OBJECT FileObject,PEPROCESS ProcessId,ULONG Key,OUT PIO_STATUS_BLOCK IoStatus,IN PDEVICE_OBJECT DeviceObject)494 UDFFastUnlockAllByKey(
495 IN PFILE_OBJECT FileObject,
496 PEPROCESS ProcessId,
497 ULONG Key,
498 OUT PIO_STATUS_BLOCK IoStatus,
499 IN PDEVICE_OBJECT DeviceObject
500 )
501
502 {
503 BOOLEAN Results = FALSE;
504
505 // BOOLEAN AcquiredFCB = FALSE;
506 PtrUDFFCB Fcb = NULL;
507 PtrUDFCCB Ccb = NULL;
508
509 UDFPrint(("UDFFastUnlockAllByKey\n"));
510
511 IoStatus->Information = 0;
512 // Decode the type of file object we're being asked to process and make
513 // sure it is only a user file open.
514
515 // Get the FCB and CCB pointers.
516 Ccb = (PtrUDFCCB)(FileObject->FsContext2);
517 ASSERT(Ccb);
518 Fcb = Ccb->Fcb;
519 ASSERT(Fcb);
520 // Validate the sent-in FCB
521 if ( (Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_VCB) ||
522 (Fcb->FCBFlags & UDF_FCB_DIRECTORY)) {
523
524 IoStatus->Status = STATUS_INVALID_PARAMETER;
525 return TRUE;
526 }
527
528 // Acquire shared access to the Fcb this operation can always wait
529
530 FsRtlEnterFileSystem();
531
532 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
533 UDFAcquireResourceShared( &(Fcb->NTRequiredFCB->MainResource),TRUE );
534
535 _SEH2_TRY {
536
537 // We check whether we can proceed
538 // based on the state of the file oplocks.
539
540 // Now call the FsRtl routine to do the actual processing of the
541 // Lock request
542 Results = TRUE;
543 IoStatus->Status = FsRtlFastUnlockAllByKey( &(Fcb->NTRequiredFCB->FileLock),
544 FileObject,
545 ProcessId,
546 Key,
547 NULL );
548
549 // Set the flag indicating if Fast I/O is possible
550
551 Fcb->NTRequiredFCB->CommonFCBHeader.IsFastIoPossible = UDFIsFastIoPossible( Fcb );
552
553 //try_exit: NOTHING;
554 } _SEH2_FINALLY {
555
556 // Release the Fcb, and return to our caller
557
558 UDF_CHECK_PAGING_IO_RESOURCE(Fcb->NTRequiredFCB);
559 UDFReleaseResource(&(Fcb->NTRequiredFCB->MainResource));
560 FsRtlExitFileSystem();
561
562 } _SEH2_END;
563
564 return Results;
565 } // end UDFFastUnlockAllByKey()
566