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
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
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
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
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
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
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