xref: /reactos/drivers/filesystems/udfs/misc.cpp (revision 84344399)
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: Misc.cpp
9 
10  Module: UDF File System Driver (Kernel mode execution only)
11 
12  Description:
13    This file contains some miscellaneous support routines.
14 
15 */
16 
17 #include            "udffs.h"
18 // define the file specific bug-check id
19 #define         UDF_BUG_CHECK_ID                UDF_FILE_MISC
20 
21 #include            <stdio.h>
22 
23 //CCHAR   DefLetter[] = {""};
24 
25 /*
26 
27  Function: UDFInitializeZones()
28 
29  Description:
30    Allocates some memory for global zones used to allocate FSD structures.
31    Either all memory will be allocated or we will back out gracefully.
32 
33  Expected Interrupt Level (for execution) :
34 
35   IRQL_PASSIVE_LEVEL
36 
37  Return Value: STATUS_SUCCESS/Error
38 
39 */
40 NTSTATUS
41 UDFInitializeZones(VOID)
42 {
43     NTSTATUS            RC = STATUS_SUCCESS;
44     uint32              SizeOfZone = UDFGlobalData.DefaultZoneSizeInNumStructs;
45     uint32              SizeOfObjectNameZone = 0;
46     uint32              SizeOfCCBZone = 0;
47 //    uint32              SizeOfFCBZone = 0;
48     uint32              SizeOfIrpContextZone = 0;
49 //    uint32              SizeOfFileInfoZone = 0;
50 
51     _SEH2_TRY {
52 
53         // initialize the spinlock protecting the zones
54         KeInitializeSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock));
55 
56         // determine memory requirements
57         switch (MmQuerySystemSize()) {
58         case MmMediumSystem:
59             SizeOfObjectNameZone = (4 * SizeOfZone * UDFQuadAlign(sizeof(UDFObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
60             SizeOfCCBZone = (4 * SizeOfZone * UDFQuadAlign(sizeof(UDFCCB))) + sizeof(ZONE_SEGMENT_HEADER);
61             SizeOfIrpContextZone = (4 * SizeOfZone * UDFQuadAlign(sizeof(UDFIrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
62             UDFGlobalData.MaxDelayedCloseCount = 24;
63             UDFGlobalData.MinDelayedCloseCount = 6;
64             UDFGlobalData.MaxDirDelayedCloseCount = 8;
65             UDFGlobalData.MinDirDelayedCloseCount = 2;
66             UDFGlobalData.WCacheMaxFrames = 8*4;
67             UDFGlobalData.WCacheMaxBlocks = 16*64;
68             UDFGlobalData.WCacheBlocksPerFrameSh = 8;
69             UDFGlobalData.WCacheFramesToKeepFree = 4;
70             break;
71         case MmLargeSystem:
72             SizeOfObjectNameZone = (8 * SizeOfZone * UDFQuadAlign(sizeof(UDFObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
73             SizeOfCCBZone = (8 * SizeOfZone * UDFQuadAlign(sizeof(UDFCCB))) + sizeof(ZONE_SEGMENT_HEADER);
74             SizeOfIrpContextZone = (8 * SizeOfZone * UDFQuadAlign(sizeof(UDFIrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
75             UDFGlobalData.MaxDelayedCloseCount = 72;
76             UDFGlobalData.MinDelayedCloseCount = 18;
77             UDFGlobalData.MaxDirDelayedCloseCount = 24;
78             UDFGlobalData.MinDirDelayedCloseCount = 6;
79             UDFGlobalData.WCacheMaxFrames = 2*16*4;
80             UDFGlobalData.WCacheMaxBlocks = 2*16*64;
81             UDFGlobalData.WCacheBlocksPerFrameSh = 8;
82             UDFGlobalData.WCacheFramesToKeepFree = 8;
83             break;
84         case MmSmallSystem:
85         default:
86             SizeOfObjectNameZone = (2 * SizeOfZone * UDFQuadAlign(sizeof(UDFObjectName))) + sizeof(ZONE_SEGMENT_HEADER);
87             SizeOfCCBZone = (2 * SizeOfZone * UDFQuadAlign(sizeof(UDFCCB))) + sizeof(ZONE_SEGMENT_HEADER);
88             SizeOfIrpContextZone = (2 * SizeOfZone * UDFQuadAlign(sizeof(UDFIrpContext))) + sizeof(ZONE_SEGMENT_HEADER);
89             UDFGlobalData.MaxDelayedCloseCount = 8;
90             UDFGlobalData.MinDelayedCloseCount = 2;
91             UDFGlobalData.MaxDirDelayedCloseCount = 6;
92             UDFGlobalData.MinDirDelayedCloseCount = 1;
93             UDFGlobalData.WCacheMaxFrames = 8*4/2;
94             UDFGlobalData.WCacheMaxBlocks = 16*64/2;
95             UDFGlobalData.WCacheBlocksPerFrameSh = 8;
96             UDFGlobalData.WCacheFramesToKeepFree = 2;
97         }
98 
99         // typical NT methodology (at least until *someone* exposed the "difference" between a server and workstation ;-)
100         if (MmIsThisAnNtAsSystem()) {
101             SizeOfObjectNameZone *= UDF_NTAS_MULTIPLE;
102             SizeOfCCBZone *= UDF_NTAS_MULTIPLE;
103             SizeOfIrpContextZone *= UDF_NTAS_MULTIPLE;
104         }
105 
106         // allocate memory for each of the zones and initialize the zones ...
107         if (!(UDFGlobalData.ObjectNameZone = DbgAllocatePool(NonPagedPool, SizeOfObjectNameZone))) {
108             RC = STATUS_INSUFFICIENT_RESOURCES;
109             try_return(RC);
110         }
111 
112         if (!(UDFGlobalData.CCBZone = DbgAllocatePool(NonPagedPool, SizeOfCCBZone))) {
113             RC = STATUS_INSUFFICIENT_RESOURCES;
114             try_return(RC);
115         }
116 
117         if (!(UDFGlobalData.IrpContextZone = DbgAllocatePool(NonPagedPool, SizeOfIrpContextZone))) {
118             RC = STATUS_INSUFFICIENT_RESOURCES;
119             try_return(RC);
120         }
121 
122         // initialize each of the zone headers ...
123         if (!NT_SUCCESS(RC = ExInitializeZone(&(UDFGlobalData.ObjectNameZoneHeader),
124                     UDFQuadAlign(sizeof(UDFObjectName)),
125                     UDFGlobalData.ObjectNameZone, SizeOfObjectNameZone))) {
126             // failed the initialization, leave ...
127             try_return(RC);
128         }
129 
130         if (!NT_SUCCESS(RC = ExInitializeZone(&(UDFGlobalData.CCBZoneHeader),
131                     UDFQuadAlign(sizeof(UDFCCB)),
132                     UDFGlobalData.CCBZone,
133                     SizeOfCCBZone))) {
134             // failed the initialization, leave ...
135             try_return(RC);
136         }
137 
138         if (!NT_SUCCESS(RC = ExInitializeZone(&(UDFGlobalData.IrpContextZoneHeader),
139                     UDFQuadAlign(sizeof(UDFIrpContext)),
140                     UDFGlobalData.IrpContextZone,
141                     SizeOfIrpContextZone))) {
142             // failed the initialization, leave ...
143             try_return(RC);
144         }
145 
146 try_exit:   NOTHING;
147 
148     } _SEH2_FINALLY {
149         if (!NT_SUCCESS(RC)) {
150             // invoke the destroy routine now ...
151             UDFDestroyZones();
152         } else {
153             // mark the fact that we have allocated zones ...
154             UDFSetFlag(UDFGlobalData.UDFFlags, UDF_DATA_FLAGS_ZONES_INITIALIZED);
155         }
156     } _SEH2_END;
157 
158     return(RC);
159 }
160 
161 
162 /*************************************************************************
163 *
164 * Function: UDFDestroyZones()
165 *
166 * Description:
167 *   Free up the previously allocated memory. NEVER do this once the
168 *   driver has been successfully loaded.
169 *
170 * Expected Interrupt Level (for execution) :
171 *
172 *  IRQL_PASSIVE_LEVEL
173 *
174 * Return Value: None
175 *
176 *************************************************************************/
177 VOID UDFDestroyZones(VOID)
178 {
179 //    BrutePoint();
180 
181     _SEH2_TRY {
182         // free up each of the pools
183         if(UDFGlobalData.ObjectNameZone) {
184             DbgFreePool(UDFGlobalData.ObjectNameZone);
185             UDFGlobalData.ObjectNameZone = NULL;
186         }
187         if(UDFGlobalData.CCBZone) {
188             DbgFreePool(UDFGlobalData.CCBZone);
189             UDFGlobalData.CCBZone = NULL;
190         }
191         if(UDFGlobalData.IrpContextZone) {
192             DbgFreePool(UDFGlobalData.IrpContextZone);
193             UDFGlobalData.IrpContextZone = NULL;
194         }
195 
196 //try_exit: NOTHING;
197 
198     } _SEH2_FINALLY {
199         UDFGlobalData.UDFFlags &= ~UDF_DATA_FLAGS_ZONES_INITIALIZED;
200     } _SEH2_END;
201 
202     return;
203 }
204 
205 
206 /*************************************************************************
207 *
208 * Function: UDFIsIrpTopLevel()
209 *
210 * Description:
211 *   Helps the FSD determine who the "top level" caller is for this
212 *   request. A request can originate directly from a user process
213 *   (in which case, the "top level" will be NULL when this routine
214 *   is invoked), OR the user may have originated either from the NT
215 *   Cache Manager/VMM ("top level" may be set), or this could be a
216 *   recursion into our code in which we would have set the "top level"
217 *   field the last time around.
218 *
219 * Expected Interrupt Level (for execution) :
220 *
221 *  whatever level a particular dispatch routine is invoked at.
222 *
223 * Return Value: TRUE/FALSE (TRUE if top level was NULL when routine invoked)
224 *
225 *************************************************************************/
226 BOOLEAN
227 __fastcall
228 UDFIsIrpTopLevel(
229     PIRP            Irp)            // the IRP sent to our dispatch routine
230 {
231     if(!IoGetTopLevelIrp()) {
232         // OK, so we can set ourselves to become the "top level" component
233         IoSetTopLevelIrp(Irp);
234         return TRUE;
235     }
236     return FALSE;
237 }
238 
239 
240 /*************************************************************************
241 *
242 * Function: UDFExceptionFilter()
243 *
244 * Description:
245 *   This routines allows the driver to determine whether the exception
246 *   is an "allowed" exception i.e. one we should not-so-quietly consume
247 *   ourselves, or one which should be propagated onwards in which case
248 *   we will most likely bring down the machine.
249 *
250 *   This routine employs the services of FsRtlIsNtstatusExpected(). This
251 *   routine returns a BOOLEAN result. A RC of FALSE will cause us to return
252 *   EXCEPTION_CONTINUE_SEARCH which will probably cause a panic.
253 *   The FsRtl.. routine returns FALSE iff exception values are (currently) :
254 *       STATUS_DATATYPE_MISALIGNMENT    ||  STATUS_ACCESS_VIOLATION ||
255 *       STATUS_ILLEGAL_INSTRUCTION  ||  STATUS_INSTRUCTION_MISALIGNMENT
256 *
257 * Expected Interrupt Level (for execution) :
258 *
259 *  ?
260 *
261 * Return Value: EXCEPTION_EXECUTE_HANDLER/EXECEPTION_CONTINUE_SEARCH
262 *
263 *************************************************************************/
264 long
265 UDFExceptionFilter(
266     PtrUDFIrpContext    PtrIrpContext,
267     PEXCEPTION_POINTERS PtrExceptionPointers
268     )
269 {
270     long                            ReturnCode = EXCEPTION_EXECUTE_HANDLER;
271     NTSTATUS                        ExceptionCode = STATUS_SUCCESS;
272 #if defined UDF_DBG || defined PRINT_ALWAYS
273     ULONG i;
274 
275     UDFPrint(("UDFExceptionFilter\n"));
276     UDFPrint(("    Ex. Code: %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionCode));
277     UDFPrint(("    Ex. Addr: %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionAddress));
278     UDFPrint(("    Ex. Flag: %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionFlags));
279     UDFPrint(("    Ex. Pnum: %x\n",PtrExceptionPointers->ExceptionRecord->NumberParameters));
280     for(i=0;i<PtrExceptionPointers->ExceptionRecord->NumberParameters;i++) {
281         UDFPrint(("       %x\n",PtrExceptionPointers->ExceptionRecord->ExceptionInformation[i]));
282     }
283 #ifdef _X86_
284     UDFPrint(("Exception context:\n"));
285     if(PtrExceptionPointers->ContextRecord->ContextFlags & CONTEXT_INTEGER) {
286         UDFPrint(("EAX=%8.8x   ",PtrExceptionPointers->ContextRecord->Eax));
287         UDFPrint(("EBX=%8.8x   ",PtrExceptionPointers->ContextRecord->Ebx));
288         UDFPrint(("ECX=%8.8x   ",PtrExceptionPointers->ContextRecord->Ecx));
289         UDFPrint(("EDX=%8.8x\n",PtrExceptionPointers->ContextRecord->Edx));
290 
291         UDFPrint(("ESI=%8.8x   ",PtrExceptionPointers->ContextRecord->Esi));
292         UDFPrint(("EDI=%8.8x   ",PtrExceptionPointers->ContextRecord->Edi));
293     }
294     if(PtrExceptionPointers->ContextRecord->ContextFlags & CONTEXT_CONTROL) {
295         UDFPrint(("EBP=%8.8x   ",PtrExceptionPointers->ContextRecord->Esp));
296         UDFPrint(("ESP=%8.8x\n",PtrExceptionPointers->ContextRecord->Ebp));
297 
298         UDFPrint(("EIP=%8.8x\n",PtrExceptionPointers->ContextRecord->Eip));
299     }
300 //    UDFPrint(("Flags: %s %s    ",PtrExceptionPointers->ContextRecord->Eip));
301 #endif //_X86_
302 
303 #endif // UDF_DBG
304 
305     // figure out the exception code
306     ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionCode;
307 
308     if ((ExceptionCode == STATUS_IN_PAGE_ERROR) && (PtrExceptionPointers->ExceptionRecord->NumberParameters >= 3)) {
309         ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionInformation[2];
310     }
311 
312     if (PtrIrpContext) {
313         PtrIrpContext->SavedExceptionCode = ExceptionCode;
314         UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_EXCEPTION);
315     }
316 
317     // check if we should propagate this exception or not
318     if (!(FsRtlIsNtstatusExpected(ExceptionCode))) {
319 
320         // better free up the IrpContext now ...
321         if (PtrIrpContext) {
322             UDFPrint(("    UDF Driver internal error\n"));
323             BrutePoint();
324         } else {
325             // we are not ok, propagate this exception.
326             //  NOTE: we will bring down the machine ...
327             ReturnCode = EXCEPTION_CONTINUE_SEARCH;
328         }
329     }
330 
331 
332     // return the appropriate code
333     return(ReturnCode);
334 } // end UDFExceptionFilter()
335 
336 
337 /*************************************************************************
338 *
339 * Function: UDFExceptionHandler()
340 *
341 * Description:
342 *   One of the routines in the FSD or in the modules we invoked encountered
343 *   an exception. We have decided that we will "handle" the exception.
344 *   Therefore we will prevent the machine from a panic ...
345 *   You can do pretty much anything you choose to in your commercial
346 *   driver at this point to ensure a graceful exit. In the UDF
347 *   driver, We shall simply free up the IrpContext (if any), set the
348 *   error code in the IRP and complete the IRP at this time ...
349 *
350 * Expected Interrupt Level (for execution) :
351 *
352 *  ?
353 *
354 * Return Value: Error code
355 *
356 *************************************************************************/
357 NTSTATUS
358 UDFExceptionHandler(
359     PtrUDFIrpContext PtrIrpContext,
360     PIRP             Irp
361     )
362 {
363 //    NTSTATUS                        RC;
364     NTSTATUS            ExceptionCode = STATUS_INSUFFICIENT_RESOURCES;
365     PDEVICE_OBJECT      Device;
366     PVPB Vpb;
367     PETHREAD Thread;
368 
369     UDFPrint(("UDFExceptionHandler \n"));
370 
371 //    ASSERT(Irp);
372 
373     if (!Irp) {
374         UDFPrint(("  !Irp, return\n"));
375         ASSERT(!PtrIrpContext);
376         return ExceptionCode;
377     }
378     // If it was a queued close (or something like this) then we need not
379     // completing it because of MUST_SUCCEED requirement.
380 
381     if (PtrIrpContext) {
382         ExceptionCode = PtrIrpContext->SavedExceptionCode;
383         // Free irp context here
384 //        UDFReleaseIrpContext(PtrIrpContext);
385     } else {
386         UDFPrint(("  complete Irp and return\n"));
387         // must be insufficient resources ...?
388         ExceptionCode = STATUS_INSUFFICIENT_RESOURCES;
389         Irp->IoStatus.Status = ExceptionCode;
390         Irp->IoStatus.Information = 0;
391         // complete the IRP
392         IoCompleteRequest(Irp, IO_NO_INCREMENT);
393 
394         return ExceptionCode;
395     }
396 
397     //  Check if we are posting this request.  One of the following must be true
398     //  if we are to post a request.
399     //
400     //      - Status code is STATUS_CANT_WAIT and the request is asynchronous
401     //          or we are forcing this to be posted.
402     //
403     //      - Status code is STATUS_VERIFY_REQUIRED and we are at APC level
404     //          or higher.  Can't wait for IO in the verify path in this case.
405     //
406     //  Set the MORE_PROCESSING flag in the IrpContext to keep if from being
407     //  deleted if this is a retryable condition.
408 
409     if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
410         if (KeGetCurrentIrql() >= APC_LEVEL) {
411             UDFPrint(("  use UDFPostRequest()\n"));
412             ExceptionCode = UDFPostRequest( PtrIrpContext, Irp );
413         }
414     }
415 
416     //  If we posted the request or our caller will retry then just return here.
417     if ((ExceptionCode == STATUS_PENDING) ||
418         (ExceptionCode == STATUS_CANT_WAIT)) {
419 
420         UDFPrint(("  STATUS_PENDING/STATUS_CANT_WAIT, return\n"));
421         return ExceptionCode;
422     }
423 
424     //  Store this error into the Irp for posting back to the Io system.
425     Irp->IoStatus.Status = ExceptionCode;
426     if (IoIsErrorUserInduced( ExceptionCode )) {
427 
428         //  Check for the various error conditions that can be caused by,
429         //  and possibly resolved my the user.
430         if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
431 
432             //  Now we are at the top level file system entry point.
433             //
434             //  If we have already posted this request then the device to
435             //  verify is in the original thread.  Find this via the Irp.
436             Device = IoGetDeviceToVerify( Irp->Tail.Overlay.Thread );
437             IoSetDeviceToVerify( Irp->Tail.Overlay.Thread, NULL );
438 
439             //  If there is no device in that location then check in the
440             //  current thread.
441             if (Device == NULL) {
442 
443                 Device = IoGetDeviceToVerify( PsGetCurrentThread() );
444                 IoSetDeviceToVerify( PsGetCurrentThread(), NULL );
445 
446                 ASSERT( Device != NULL );
447 
448                 //  Let's not BugCheck just because the driver screwed up.
449                 if (Device == NULL) {
450 
451                     UDFPrint(("  Device == NULL, return\n"));
452                     ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR;
453                     Irp->IoStatus.Status = ExceptionCode;
454                     Irp->IoStatus.Information = 0;
455                     // complete the IRP
456                     IoCompleteRequest(Irp, IO_NO_INCREMENT);
457 
458                     UDFReleaseIrpContext(PtrIrpContext);
459 
460                     return ExceptionCode;
461                 }
462             }
463 
464             UDFPrint(("  use UDFPerformVerify()\n"));
465             //  UDFPerformVerify() will do the right thing with the Irp.
466             //  If we return STATUS_CANT_WAIT then the current thread
467             //  can retry the request.
468             return UDFPerformVerify( PtrIrpContext, Irp, Device );
469         }
470 
471         //
472         //  The other user induced conditions generate an error unless
473         //  they have been disabled for this request.
474         //
475 
476         if (FlagOn( PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_FLAG_DISABLE_POPUPS )) {
477 
478             UDFPrint(("  DISABLE_POPUPS, complete Irp and return\n"));
479             Irp->IoStatus.Status = ExceptionCode;
480             Irp->IoStatus.Information = 0;
481             // complete the IRP
482             IoCompleteRequest(Irp, IO_NO_INCREMENT);
483 
484             UDFReleaseIrpContext(PtrIrpContext);
485             return ExceptionCode;
486         } else {
487 
488             //  Generate a pop-up
489             if (IoGetCurrentIrpStackLocation( Irp )->FileObject != NULL) {
490 
491                 Vpb = IoGetCurrentIrpStackLocation( Irp )->FileObject->Vpb;
492             } else {
493 
494                 Vpb = NULL;
495             }
496             //  The device to verify is either in my thread local storage
497             //  or that of the thread that owns the Irp.
498             Thread = Irp->Tail.Overlay.Thread;
499             Device = IoGetDeviceToVerify( Thread );
500 
501             if (Device == NULL) {
502 
503                 Thread = PsGetCurrentThread();
504                 Device = IoGetDeviceToVerify( Thread );
505                 ASSERT( Device != NULL );
506 
507                 //  Let's not BugCheck just because the driver screwed up.
508                 if (Device == NULL) {
509                     UDFPrint(("  Device == NULL, return(2)\n"));
510                     Irp->IoStatus.Status = ExceptionCode;
511                     Irp->IoStatus.Information = 0;
512                     // complete the IRP
513                     IoCompleteRequest(Irp, IO_NO_INCREMENT);
514 
515                     UDFReleaseIrpContext(PtrIrpContext);
516 
517                     return ExceptionCode;
518                 }
519             }
520 
521             //  This routine actually causes the pop-up.  It usually
522             //  does this by queuing an APC to the callers thread,
523             //  but in some cases it will complete the request immediately,
524             //  so it is very important to IoMarkIrpPending() first.
525             IoMarkIrpPending( Irp );
526             IoRaiseHardError( Irp, Vpb, Device );
527 
528             //  We will be handing control back to the caller here, so
529             //  reset the saved device object.
530 
531             UDFPrint(("  use IoSetDeviceToVerify()\n"));
532             IoSetDeviceToVerify( Thread, NULL );
533             //  The Irp will be completed by Io or resubmitted.  In either
534             //  case we must clean up the IrpContext here.
535 
536             UDFReleaseIrpContext(PtrIrpContext);
537             return STATUS_PENDING;
538         }
539     }
540 
541     // If it was a normal request from IOManager then complete it
542     if (Irp) {
543         UDFPrint(("  complete Irp\n"));
544         // set the error code in the IRP
545         Irp->IoStatus.Status = ExceptionCode;
546         Irp->IoStatus.Information = 0;
547 
548         // complete the IRP
549         IoCompleteRequest(Irp, IO_NO_INCREMENT);
550 
551         UDFReleaseIrpContext(PtrIrpContext);
552     }
553 
554     UDFPrint(("  return from exception handler with code %x\n", ExceptionCode));
555     return(ExceptionCode);
556 } // end UDFExceptionHandler()
557 
558 /*************************************************************************
559 *
560 * Function: UDFLogEvent()
561 *
562 * Description:
563 *   Log a message in the NT Event Log. This is a rather simplistic log
564 *   methodology since we can potentially utilize the event log to
565 *   provide a lot of information to the user (and you should too!)
566 *
567 * Expected Interrupt Level (for execution) :
568 *
569 *  IRQL_PASSIVE_LEVEL
570 *
571 * Return Value: None
572 *
573 *************************************************************************/
574 VOID
575 UDFLogEvent(
576     NTSTATUS UDFEventLogId,      // the UDF private message id
577     NTSTATUS RC)                 // any NT error code we wish to log ...
578 {
579     _SEH2_TRY {
580 
581         // Implement a call to IoAllocateErrorLogEntry() followed by a call
582         // to IoWriteErrorLogEntry(). You should note that the call to IoWriteErrorLogEntry()
583         // will free memory for the entry once the write completes (which in actuality
584         // is an asynchronous operation).
585 
586     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
587         // nothing really we can do here, just do not wish to crash ...
588         NOTHING;
589     } _SEH2_END;
590 
591     return;
592 } // end UDFLogEvent()
593 
594 
595 /*************************************************************************
596 *
597 * Function: UDFAllocateObjectName()
598 *
599 * Description:
600 *   Allocate a new ObjectName structure to represent an open on-disk object.
601 *   Also initialize the ObjectName structure to NULL.
602 *
603 * Expected Interrupt Level (for execution) :
604 *
605 *  IRQL_PASSIVE_LEVEL
606 *
607 * Return Value: A pointer to the ObjectName structure OR NULL.
608 *
609 *************************************************************************/
610 PtrUDFObjectName
611 UDFAllocateObjectName(VOID)
612 {
613     PtrUDFObjectName            PtrObjectName = NULL;
614     BOOLEAN                     AllocatedFromZone = TRUE;
615     KIRQL                       CurrentIrql;
616 
617     // first, __try to allocate out of the zone
618     KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
619     if (!ExIsFullZone(&(UDFGlobalData.ObjectNameZoneHeader))) {
620         // we have enough memory
621         PtrObjectName = (PtrUDFObjectName)ExAllocateFromZone(&(UDFGlobalData.ObjectNameZoneHeader));
622 
623         // release the spinlock
624         KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
625     } else {
626         // release the spinlock
627         KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
628 
629         // if we failed to obtain from the zone, get it directly from the VMM
630         PtrObjectName = (PtrUDFObjectName)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFObjectName)));
631         AllocatedFromZone = FALSE;
632     }
633 
634     if (!PtrObjectName) {
635         return NULL;
636     }
637 
638     // zero out the allocated memory block
639     RtlZeroMemory(PtrObjectName, UDFQuadAlign(sizeof(UDFObjectName)));
640 
641     // set up some fields ...
642     PtrObjectName->NodeIdentifier.NodeType  = UDF_NODE_TYPE_OBJECT_NAME;
643     PtrObjectName->NodeIdentifier.NodeSize  = UDFQuadAlign(sizeof(UDFObjectName));
644 
645 
646     if (!AllocatedFromZone) {
647         UDFSetFlag(PtrObjectName->ObjectNameFlags, UDF_OBJ_NAME_NOT_FROM_ZONE);
648     }
649 
650     return(PtrObjectName);
651 } // end UDFAllocateObjectName()
652 
653 
654 /*************************************************************************
655 *
656 * Function: UDFReleaseObjectName()
657 *
658 * Description:
659 *   Deallocate a previously allocated structure.
660 *
661 * Expected Interrupt Level (for execution) :
662 *
663 *  IRQL_PASSIVE_LEVEL
664 *
665 * Return Value: None
666 *
667 *************************************************************************/
668 VOID
669 __fastcall
670 UDFReleaseObjectName(
671     PtrUDFObjectName PtrObjectName)
672 {
673     KIRQL            CurrentIrql;
674 
675     ASSERT(PtrObjectName);
676 
677     // give back memory either to the zone or to the VMM
678     if (!(PtrObjectName->ObjectNameFlags & UDF_OBJ_NAME_NOT_FROM_ZONE)) {
679         // back to the zone
680         KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
681         ExFreeToZone(&(UDFGlobalData.ObjectNameZoneHeader), PtrObjectName);
682         KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
683     } else {
684         MyFreePool__(PtrObjectName);
685     }
686 
687     return;
688 } // end UDFReleaseObjectName()
689 
690 
691 /*************************************************************************
692 *
693 * Function: UDFAllocateCCB()
694 *
695 * Description:
696 *   Allocate a new CCB structure to represent an open on-disk object.
697 *   Also initialize the CCB structure to NULL.
698 *
699 * Expected Interrupt Level (for execution) :
700 *
701 *  IRQL_PASSIVE_LEVEL
702 *
703 * Return Value: A pointer to the CCB structure OR NULL.
704 *
705 *************************************************************************/
706 PtrUDFCCB
707 UDFAllocateCCB(VOID)
708 {
709     PtrUDFCCB                   Ccb = NULL;
710     BOOLEAN                     AllocatedFromZone = TRUE;
711     KIRQL                       CurrentIrql;
712 
713     // first, __try to allocate out of the zone
714     KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
715     if (!ExIsFullZone(&(UDFGlobalData.CCBZoneHeader))) {
716         // we have enough memory
717         Ccb = (PtrUDFCCB)ExAllocateFromZone(&(UDFGlobalData.CCBZoneHeader));
718 
719         // release the spinlock
720         KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
721     } else {
722         // release the spinlock
723         KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
724 
725         // if we failed to obtain from the zone, get it directly from the VMM
726         Ccb = (PtrUDFCCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFCCB)));
727         AllocatedFromZone = FALSE;
728 //        UDFPrint(("    CCB allocated @%x\n",Ccb));
729     }
730 
731     if (!Ccb) {
732         return NULL;
733     }
734 
735     // zero out the allocated memory block
736     RtlZeroMemory(Ccb, UDFQuadAlign(sizeof(UDFCCB)));
737 
738     // set up some fields ...
739     Ccb->NodeIdentifier.NodeType = UDF_NODE_TYPE_CCB;
740     Ccb->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFCCB));
741 
742 
743     if (!AllocatedFromZone) {
744         UDFSetFlag(Ccb->CCBFlags, UDF_CCB_NOT_FROM_ZONE);
745     }
746 
747     UDFPrint(("UDFAllocateCCB: %x\n", Ccb));
748     return(Ccb);
749 } // end UDFAllocateCCB()
750 
751 
752 /*************************************************************************
753 *
754 * Function: UDFReleaseCCB()
755 *
756 * Description:
757 *   Deallocate a previously allocated structure.
758 *
759 * Expected Interrupt Level (for execution) :
760 *
761 *  IRQL_PASSIVE_LEVEL
762 *
763 * Return Value: None
764 *
765 *************************************************************************/
766 VOID
767 __fastcall
768 UDFReleaseCCB(
769     PtrUDFCCB Ccb
770     )
771 {
772     KIRQL   CurrentIrql;
773 
774     ASSERT(Ccb);
775 
776     UDFPrint(("UDFReleaseCCB: %x\n", Ccb));
777     // give back memory either to the zone or to the VMM
778     if(!(Ccb->CCBFlags & UDF_CCB_NOT_FROM_ZONE)) {
779         // back to the zone
780         KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
781         ExFreeToZone(&(UDFGlobalData.CCBZoneHeader), Ccb);
782         KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
783     } else {
784         MyFreePool__(Ccb);
785     }
786 
787     return;
788 } // end UDFReleaseCCB()
789 
790 /*
791   Function: UDFCleanupCCB()
792 
793   Description:
794     Cleanup and deallocate a previously allocated structure.
795 
796   Expected Interrupt Level (for execution) :
797 
798    IRQL_PASSIVE_LEVEL
799 
800   Return Value: None
801 
802 */
803 VOID
804 __fastcall
805 UDFCleanUpCCB(
806     PtrUDFCCB Ccb)
807 {
808 //    ASSERT(Ccb);
809     if(!Ccb) return; // probably, we havn't allocated it...
810     ASSERT(Ccb->NodeIdentifier.NodeType == UDF_NODE_TYPE_CCB);
811 
812     _SEH2_TRY {
813         if(Ccb->Fcb) {
814             UDFTouch(&(Ccb->Fcb->CcbListResource));
815             UDFAcquireResourceExclusive(&(Ccb->Fcb->CcbListResource),TRUE);
816             RemoveEntryList(&(Ccb->NextCCB));
817             UDFReleaseResource(&(Ccb->Fcb->CcbListResource));
818         } else {
819             BrutePoint();
820         }
821 
822         if (Ccb->DirectorySearchPattern) {
823             if (Ccb->DirectorySearchPattern->Buffer) {
824                 MyFreePool__(Ccb->DirectorySearchPattern->Buffer);
825                 Ccb->DirectorySearchPattern->Buffer = NULL;
826             }
827 
828             MyFreePool__(Ccb->DirectorySearchPattern);
829             Ccb->DirectorySearchPattern = NULL;
830         }
831 
832         UDFReleaseCCB(Ccb);
833     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
834         BrutePoint();
835     } _SEH2_END;
836 } // end UDFCleanUpCCB()
837 
838 /*************************************************************************
839 *
840 * Function: UDFAllocateFCB()
841 *
842 * Description:
843 *   Allocate a new FCB structure to represent an open on-disk object.
844 *   Also initialize the FCB structure to NULL.
845 *
846 * Expected Interrupt Level (for execution) :
847 *
848 *  IRQL_PASSIVE_LEVEL
849 *
850 * Return Value: A pointer to the FCB structure OR NULL.
851 *
852 *************************************************************************/
853 PtrUDFFCB
854 UDFAllocateFCB(VOID)
855 {
856     PtrUDFFCB                   Fcb = NULL;
857 
858     Fcb = (PtrUDFFCB)MyAllocatePool__(UDF_FCB_MT, UDFQuadAlign(sizeof(UDFFCB)));
859 
860     if (!Fcb) {
861         return NULL;
862     }
863 
864     // zero out the allocated memory block
865     RtlZeroMemory(Fcb, UDFQuadAlign(sizeof(UDFFCB)));
866 
867     // set up some fields ...
868     Fcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_FCB;
869     Fcb->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFFCB));
870 
871     UDFPrint(("UDFAllocateFCB: %x\n", Fcb));
872     return(Fcb);
873 } // end UDFAllocateFCB()
874 
875 
876 /*************************************************************************
877 *
878 * Function: UDFReleaseFCB()
879 *
880 * Description:
881 *   Deallocate a previously allocated structure.
882 *
883 * Expected Interrupt Level (for execution) :
884 *
885 *  IRQL_PASSIVE_LEVEL
886 *
887 * Return Value: None
888 *
889 *************************************************************************/
890 /*VOID
891 UDFReleaseFCB(
892     PtrUDFFCB Fcb
893     )
894 {
895     ASSERT(Fcb);
896 
897     MyFreePool__(Fcb);
898 
899     return;
900 }*/
901 
902 /*************************************************************************
903 *
904 *
905 *************************************************************************/
906 VOID
907 __fastcall
908 UDFCleanUpFCB(
909     PtrUDFFCB Fcb
910     )
911 {
912     UDFPrint(("UDFCleanUpFCB: %x\n", Fcb));
913     if(!Fcb) return;
914 
915     ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB);
916 
917     _SEH2_TRY {
918         // Deinitialize FCBName field
919         if (Fcb->FCBName) {
920             if(Fcb->FCBName->ObjectName.Buffer) {
921                 MyFreePool__(Fcb->FCBName->ObjectName.Buffer);
922                 Fcb->FCBName->ObjectName.Buffer = NULL;
923 #ifdef UDF_DBG
924                 Fcb->FCBName->ObjectName.Length =
925                 Fcb->FCBName->ObjectName.MaximumLength = 0;
926 #endif
927             }
928 #ifdef UDF_DBG
929             else {
930                 UDFPrint(("UDF: Fcb has invalid FCBName Buffer\n"));
931                 BrutePoint();
932             }
933 #endif
934             UDFReleaseObjectName(Fcb->FCBName);
935             Fcb->FCBName = NULL;
936         }
937 #ifdef UDF_DBG
938         else {
939             UDFPrint(("UDF: Fcb has invalid FCBName field\n"));
940             BrutePoint();
941         }
942 #endif
943 
944 
945         // begin transaction {
946         UDFTouch(&(Fcb->Vcb->FcbListResource));
947         UDFAcquireResourceExclusive(&(Fcb->Vcb->FcbListResource), TRUE);
948         // Remove this FCB from list of all FCB in VCB
949         RemoveEntryList(&(Fcb->NextFCB));
950         UDFReleaseResource(&(Fcb->Vcb->FcbListResource));
951         // } end transaction
952 
953         if(Fcb->FCBFlags & UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE)
954             UDFDeleteResource(&(Fcb->CcbListResource));
955 
956         // Free memory
957         UDFReleaseFCB(Fcb);
958     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
959         BrutePoint();
960     } _SEH2_END;
961 } // end UDFCleanUpFCB()
962 
963 #ifdef UDF_DBG
964 ULONG IrpContextCounter = 0;
965 #endif //UDF_DBG
966 
967 /*************************************************************************
968 *
969 * Function: UDFAllocateIrpContext()
970 *
971 * Description:
972 *   The UDF FSD creates an IRP context for each request received. This
973 *   routine simply allocates (and initializes to NULL) a UDFIrpContext
974 *   structure.
975 *   Most of the fields in the context structure are then initialized here.
976 *
977 * Expected Interrupt Level (for execution) :
978 *
979 *  IRQL_PASSIVE_LEVEL
980 *
981 * Return Value: A pointer to the IrpContext structure OR NULL.
982 *
983 *************************************************************************/
984 PtrUDFIrpContext
985 UDFAllocateIrpContext(
986     PIRP           Irp,
987     PDEVICE_OBJECT PtrTargetDeviceObject
988     )
989 {
990     PtrUDFIrpContext            PtrIrpContext = NULL;
991     BOOLEAN                     AllocatedFromZone = TRUE;
992     KIRQL                       CurrentIrql;
993     PIO_STACK_LOCATION          IrpSp = NULL;
994 
995     // first, __try to allocate out of the zone
996     KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
997     if (!ExIsFullZone(&(UDFGlobalData.IrpContextZoneHeader))) {
998         // we have enough memory
999         PtrIrpContext = (PtrUDFIrpContext)ExAllocateFromZone(&(UDFGlobalData.IrpContextZoneHeader));
1000 
1001         // release the spinlock
1002         KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
1003     } else {
1004         // release the spinlock
1005         KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
1006 
1007         // if we failed to obtain from the zone, get it directly from the VMM
1008         PtrIrpContext = (PtrUDFIrpContext)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFIrpContext)));
1009         AllocatedFromZone = FALSE;
1010     }
1011 
1012     // if we could not obtain the required memory, bug-check.
1013     //  Do NOT do this in your commercial driver, instead handle    the error gracefully ...
1014     if (!PtrIrpContext) {
1015         return NULL;
1016     }
1017 
1018 #ifdef UDF_DBG
1019     IrpContextCounter++;
1020 #endif //UDF_DBG
1021 
1022     // zero out the allocated memory block
1023     RtlZeroMemory(PtrIrpContext, UDFQuadAlign(sizeof(UDFIrpContext)));
1024 
1025     // set up some fields ...
1026     PtrIrpContext->NodeIdentifier.NodeType  = UDF_NODE_TYPE_IRP_CONTEXT;
1027     PtrIrpContext->NodeIdentifier.NodeSize  = UDFQuadAlign(sizeof(UDFIrpContext));
1028 
1029 
1030     PtrIrpContext->Irp = Irp;
1031     PtrIrpContext->TargetDeviceObject = PtrTargetDeviceObject;
1032 
1033     // copy over some fields from the IRP and set appropriate flag values
1034     if (Irp) {
1035         IrpSp = IoGetCurrentIrpStackLocation(Irp);
1036         ASSERT(IrpSp);
1037 
1038         PtrIrpContext->MajorFunction = IrpSp->MajorFunction;
1039         PtrIrpContext->MinorFunction = IrpSp->MinorFunction;
1040 
1041         // Often, a FSD cannot honor a request for asynchronous processing
1042         // of certain critical requests. For example, a "close" request on
1043         // a file object can typically never be deferred. Therefore, do not
1044         // be surprised if sometimes our FSD (just like all other FSD
1045         // implementations on the Windows NT system) has to override the flag
1046         // below.
1047         if (IrpSp->FileObject == NULL) {
1048             PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
1049         } else {
1050             if (IoIsOperationSynchronous(Irp)) {
1051                 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
1052             }
1053         }
1054     }
1055 
1056     if (!AllocatedFromZone) {
1057         UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_NOT_FROM_ZONE);
1058     }
1059 
1060     // Are we top-level ? This information is used by the dispatching code
1061     // later (and also by the FSD dispatch routine)
1062     if (IoGetTopLevelIrp() != Irp) {
1063         // We are not top-level. Note this fact in the context structure
1064         UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_NOT_TOP_LEVEL);
1065     }
1066 
1067     return(PtrIrpContext);
1068 } // end UDFAllocateIrpContext()
1069 
1070 
1071 /*************************************************************************
1072 *
1073 * Function: UDFReleaseIrpContext()
1074 *
1075 * Description:
1076 *   Deallocate a previously allocated structure.
1077 *
1078 * Expected Interrupt Level (for execution) :
1079 *
1080 *  IRQL_PASSIVE_LEVEL
1081 *
1082 * Return Value: None
1083 *
1084 *************************************************************************/
1085 VOID
1086 UDFReleaseIrpContext(
1087     PtrUDFIrpContext    PtrIrpContext)
1088 {
1089     if(!PtrIrpContext) return;
1090 //    ASSERT(PtrIrpContext);
1091 
1092 #ifdef UDF_DBG
1093     IrpContextCounter--;
1094 #endif //UDF_DBG
1095 
1096     // give back memory either to the zone or to the VMM
1097     if (!(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_FROM_ZONE)) {
1098         // back to the zone
1099         KIRQL                           CurrentIrql;
1100 
1101         KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
1102         ExFreeToZone(&(UDFGlobalData.IrpContextZoneHeader), PtrIrpContext);
1103         KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
1104     } else {
1105         MyFreePool__(PtrIrpContext);
1106     }
1107 
1108     return;
1109 } // end UDFReleaseIrpContext()
1110 
1111 
1112 /*************************************************************************
1113 *
1114 * Function: UDFPostRequest()
1115 *
1116 * Description:
1117 *   Queue up a request for deferred processing (in the context of a system
1118 *   worker thread). The caller must have locked the user buffer (if required)
1119 *
1120 * Expected Interrupt Level (for execution) :
1121 *
1122 *  IRQL_PASSIVE_LEVEL
1123 *
1124 * Return Value: STATUS_PENDING
1125 *
1126 *************************************************************************/
1127 NTSTATUS
1128 UDFPostRequest(
1129     IN PtrUDFIrpContext PtrIrpContext,
1130     IN PIRP             Irp
1131     )
1132 {
1133     KIRQL SavedIrql;
1134 //    PIO_STACK_LOCATION IrpSp;
1135     PVCB Vcb;
1136 
1137 //    IrpSp = IoGetCurrentIrpStackLocation(Irp);
1138 
1139 /*
1140     if(Vcb->StopOverflowQueue) {
1141         if(Irp) {
1142             Irp->IoStatus.Status = STATUS_WRONG_VOLUME;
1143             Irp->IoStatus.Information = 0;
1144             IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1145         }
1146         UDFReleaseIrpContext(PtrIrpContext);
1147         return STATUS_WRONG_VOLUME;
1148     }
1149 */
1150     // mark the IRP pending if this is not double post
1151     if(Irp)
1152         IoMarkIrpPending(Irp);
1153 
1154     Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
1155     KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql);
1156 
1157     if ( Vcb->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
1158 
1159         //  We cannot currently respond to this IRP so we'll just enqueue it
1160         //  to the overflow queue on the volume.
1161         //  Note: we just reuse LIST_ITEM field inside WorkQueueItem, this
1162         //  doesn't matter to regular processing of WorkItems.
1163         InsertTailList( &(Vcb->OverflowQueue),
1164                         &(PtrIrpContext->WorkQueueItem.List) );
1165         Vcb->OverflowQueueCount++;
1166         KeReleaseSpinLock( &(Vcb->OverflowQueueSpinLock), SavedIrql );
1167 
1168     } else {
1169 
1170         //  We are going to send this Irp to an ex worker thread so up
1171         //  the count.
1172         Vcb->PostedRequestCount++;
1173 
1174         KeReleaseSpinLock( &(Vcb->OverflowQueueSpinLock), SavedIrql );
1175 
1176         // queue up the request
1177         ExInitializeWorkItem(&(PtrIrpContext->WorkQueueItem), UDFCommonDispatch, PtrIrpContext);
1178 
1179         ExQueueWorkItem(&(PtrIrpContext->WorkQueueItem), CriticalWorkQueue);
1180     //    ExQueueWorkItem(&(PtrIrpContext->WorkQueueItem), DelayedWorkQueue);
1181 
1182     }
1183 
1184     // return status pending
1185     return STATUS_PENDING;
1186 } // end UDFPostRequest()
1187 
1188 
1189 /*************************************************************************
1190 *
1191 * Function: UDFCommonDispatch()
1192 *
1193 * Description:
1194 *   The common dispatch routine invoked in the context of a system worker
1195 *   thread. All we do here is pretty much case off the major function
1196 *   code and invoke the appropriate FSD dispatch routine for further
1197 *   processing.
1198 *
1199 * Expected Interrupt Level (for execution) :
1200 *
1201 *   IRQL PASSIVE_LEVEL
1202 *
1203 * Return Value: None
1204 *
1205 *************************************************************************/
1206 VOID
1207 NTAPI
1208 UDFCommonDispatch(
1209     IN PVOID Context   // actually is a pointer to IRPContext structure
1210     )
1211 {
1212     NTSTATUS         RC = STATUS_SUCCESS;
1213     PtrUDFIrpContext PtrIrpContext = NULL;
1214     PIRP             Irp = NULL;
1215     PVCB             Vcb;
1216     KIRQL            SavedIrql;
1217     PLIST_ENTRY      Entry;
1218     BOOLEAN          SpinLock = FALSE;
1219 
1220     // The context must be a pointer to an IrpContext structure
1221     PtrIrpContext = (PtrUDFIrpContext)Context;
1222 
1223     // Assert that the Context is legitimate
1224     if ( !PtrIrpContext ||
1225          (PtrIrpContext->NodeIdentifier.NodeType != UDF_NODE_TYPE_IRP_CONTEXT) ||
1226          (PtrIrpContext->NodeIdentifier.NodeSize != UDFQuadAlign(sizeof(UDFIrpContext))) /*||
1227         !(PtrIrpContext->Irp)*/) {
1228         UDFPrint(("    Invalid Context\n"));
1229         BrutePoint();
1230         return;
1231     }
1232 
1233     Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
1234     ASSERT(Vcb);
1235 
1236     UDFPrint(("  *** Thr: %x  ThCnt: %x  QCnt: %x  Started!\n", PsGetCurrentThread(), Vcb->PostedRequestCount, Vcb->OverflowQueueCount));
1237 
1238     while(TRUE) {
1239 
1240         UDFPrint(("    Next IRP\n"));
1241         FsRtlEnterFileSystem();
1242 
1243         //  Get a pointer to the IRP structure
1244         // in some cases we can get Zero pointer to Irp
1245         Irp = PtrIrpContext->Irp;
1246         // Now, check if the FSD was top level when the IRP was originally invoked
1247         // and set the thread context (for the worker thread) appropriately
1248         if (PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_TOP_LEVEL) {
1249             // The FSD is not top level for the original request
1250             // Set a constant value in TLS to reflect this fact
1251             IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP);
1252         } else {
1253             IoSetTopLevelIrp(Irp);
1254         }
1255 
1256         // Since the FSD routine will now be invoked in the context of this worker
1257         // thread, we should inform the FSD that it is perfectly OK to block in
1258         // the context of this thread
1259         PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
1260 
1261         _SEH2_TRY {
1262 
1263             // Pre-processing has been completed; check the Major Function code value
1264             // either in the IrpContext (copied from the IRP), or directly from the
1265             //  IRP itself (we will need a pointer to the stack location to do that),
1266             //  Then, switch based on the value on the Major Function code
1267             UDFPrint(("  *** MJ: %x, Thr: %x\n", PtrIrpContext->MajorFunction, PsGetCurrentThread()));
1268             switch (PtrIrpContext->MajorFunction) {
1269             case IRP_MJ_CREATE:
1270                 // Invoke the common create routine
1271                 RC = UDFCommonCreate(PtrIrpContext, Irp);
1272                 break;
1273             case IRP_MJ_READ:
1274                 // Invoke the common read routine
1275                 RC = UDFCommonRead(PtrIrpContext, Irp);
1276                 break;
1277 #ifndef UDF_READ_ONLY_BUILD
1278             case IRP_MJ_WRITE:
1279                 // Invoke the common write routine
1280                 RC = UDFCommonWrite(PtrIrpContext, Irp);
1281                 break;
1282 #endif //UDF_READ_ONLY_BUILD
1283             case IRP_MJ_CLEANUP:
1284                 // Invoke the common cleanup routine
1285                 RC = UDFCommonCleanup(PtrIrpContext, Irp);
1286                 break;
1287             case IRP_MJ_CLOSE:
1288                 // Invoke the common close routine
1289                 RC = UDFCommonClose(PtrIrpContext, Irp);
1290                 break;
1291             case IRP_MJ_DIRECTORY_CONTROL:
1292                 // Invoke the common directory control routine
1293                 RC = UDFCommonDirControl(PtrIrpContext, Irp);
1294                 break;
1295             case IRP_MJ_QUERY_INFORMATION:
1296 #ifndef UDF_READ_ONLY_BUILD
1297             case IRP_MJ_SET_INFORMATION:
1298 #endif //UDF_READ_ONLY_BUILD
1299                 // Invoke the common query/set information routine
1300                 RC = UDFCommonFileInfo(PtrIrpContext, Irp);
1301                 break;
1302             case IRP_MJ_QUERY_VOLUME_INFORMATION:
1303                 // Invoke the common query volume routine
1304                 RC = UDFCommonQueryVolInfo(PtrIrpContext, Irp);
1305                 break;
1306 #ifndef UDF_READ_ONLY_BUILD
1307             case IRP_MJ_SET_VOLUME_INFORMATION:
1308                 // Invoke the common query volume routine
1309                 RC = UDFCommonSetVolInfo(PtrIrpContext, Irp);
1310                 break;
1311 #endif //UDF_READ_ONLY_BUILD
1312 #ifdef UDF_HANDLE_EAS
1313 /*            case IRP_MJ_QUERY_EA:
1314                 // Invoke the common query EAs routine
1315                 RC = UDFCommonGetExtendedAttr(PtrIrpContext, Irp);
1316                 break;
1317             case IRP_MJ_SET_EA:
1318                 // Invoke the common set EAs routine
1319                 RC = UDFCommonSetExtendedAttr(PtrIrpContext, Irp);
1320                 break;*/
1321 #endif // UDF_HANDLE_EAS
1322 #ifdef UDF_ENABLE_SECURITY
1323             case IRP_MJ_QUERY_SECURITY:
1324                 // Invoke the common query Security routine
1325                 RC = UDFCommonGetSecurity(PtrIrpContext, Irp);
1326                 break;
1327 #ifndef UDF_READ_ONLY_BUILD
1328             case IRP_MJ_SET_SECURITY:
1329                 // Invoke the common set Security routine
1330                 RC = UDFCommonSetSecurity(PtrIrpContext, Irp);
1331                 break;
1332 #endif //UDF_READ_ONLY_BUILD
1333 #endif // UDF_ENABLE_SECURITY
1334             // Continue with the remaining possible dispatch routines below ...
1335             default:
1336                 UDFPrint(("  unhandled *** MJ: %x, Thr: %x\n", PtrIrpContext->MajorFunction, PsGetCurrentThread()));
1337                 // This is the case where we have an invalid major function
1338                 Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
1339                 Irp->IoStatus.Information = 0;
1340 
1341                 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1342                 // Free up the Irp Context
1343                 UDFReleaseIrpContext(PtrIrpContext);
1344                 break;
1345             }
1346 
1347             // Note: PtrIrpContext is invalid here
1348             UDFPrint(("  *** Thr: %x  Done!\n", PsGetCurrentThread()));
1349 
1350         } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
1351 
1352             RC = UDFExceptionHandler(PtrIrpContext, Irp);
1353 
1354             UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
1355         }  _SEH2_END;
1356 
1357         // Enable preemption
1358         FsRtlExitFileSystem();
1359 
1360         // Ensure that the "top-level" field is cleared
1361         IoSetTopLevelIrp(NULL);
1362 
1363         //  If there are any entries on this volume's overflow queue, service
1364         //  them.
1365         if(!Vcb) {
1366             BrutePoint();
1367             break;
1368         }
1369 
1370         KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql);
1371         SpinLock = TRUE;
1372         if(!Vcb->OverflowQueueCount)
1373             break;
1374 
1375         Vcb->OverflowQueueCount--;
1376         Entry = RemoveHeadList(&Vcb->OverflowQueue);
1377         KeReleaseSpinLock(&(Vcb->OverflowQueueSpinLock), SavedIrql);
1378         SpinLock = FALSE;
1379 
1380         PtrIrpContext = CONTAINING_RECORD( Entry,
1381                                         UDFIrpContext,
1382                                         WorkQueueItem.List );
1383     }
1384 
1385     if(!SpinLock)
1386         KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql);
1387     Vcb->PostedRequestCount--;
1388     KeReleaseSpinLock(&(Vcb->OverflowQueueSpinLock), SavedIrql);
1389 
1390     UDFPrint(("  *** Thr: %x  ThCnt: %x  QCnt: %x  Terminated!\n", PsGetCurrentThread(), Vcb->PostedRequestCount, Vcb->OverflowQueueCount));
1391 
1392     return;
1393 } // end UDFCommonDispatch()
1394 
1395 
1396 /*************************************************************************
1397 *
1398 * Function: UDFInitializeVCB()
1399 *
1400 * Description:
1401 *   Perform the initialization for a VCB structure.
1402 *
1403 * Expected Interrupt Level (for execution) :
1404 *
1405 *   IRQL PASSIVE_LEVEL
1406 *
1407 * Return Value: status
1408 *
1409 *************************************************************************/
1410 NTSTATUS
1411 UDFInitializeVCB(
1412     IN PDEVICE_OBJECT PtrVolumeDeviceObject,
1413     IN PDEVICE_OBJECT PtrTargetDeviceObject,
1414     IN PVPB           PtrVPB
1415     )
1416 {
1417     NTSTATUS RC = STATUS_SUCCESS;
1418     PVCB     Vcb = NULL;
1419     SHORT    i;
1420 
1421     BOOLEAN VCBResourceInit     = FALSE;
1422     BOOLEAN BitMapResource1Init = FALSE;
1423     BOOLEAN FcbListResourceInit = FALSE;
1424     BOOLEAN FileIdResourceInit  = FALSE;
1425     BOOLEAN DlocResourceInit    = FALSE;
1426     BOOLEAN DlocResource2Init   = FALSE;
1427     BOOLEAN FlushResourceInit   = FALSE;
1428     BOOLEAN PreallocResourceInit= FALSE;
1429     BOOLEAN IoResourceInit      = FALSE;
1430 
1431     Vcb = (PVCB)(PtrVolumeDeviceObject->DeviceExtension);
1432 
1433     _SEH2_TRY {
1434     // Zero it out (typically this has already been done by the I/O
1435     // Manager but it does not hurt to do it again)!
1436     RtlZeroMemory(Vcb, sizeof(VCB));
1437 
1438     // Initialize the signature fields
1439     Vcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_VCB;
1440     Vcb->NodeIdentifier.NodeSize = sizeof(VCB);
1441 
1442     // Initialize the ERESOURCE object.
1443     RC = UDFInitializeResourceLite(&(Vcb->VCBResource));
1444     if(!NT_SUCCESS(RC))
1445         try_return(RC);
1446     VCBResourceInit = TRUE;
1447 
1448     RC = UDFInitializeResourceLite(&(Vcb->BitMapResource1));
1449     if(!NT_SUCCESS(RC))
1450         try_return(RC);
1451     BitMapResource1Init = TRUE;
1452 
1453     RC = UDFInitializeResourceLite(&(Vcb->FcbListResource));
1454     if(!NT_SUCCESS(RC))
1455         try_return(RC);
1456     FcbListResourceInit = TRUE;
1457 
1458     RC = UDFInitializeResourceLite(&(Vcb->FileIdResource));
1459     if(!NT_SUCCESS(RC))
1460         try_return(RC);
1461     FileIdResourceInit = TRUE;
1462 
1463     RC = UDFInitializeResourceLite(&(Vcb->DlocResource));
1464     if(!NT_SUCCESS(RC))
1465         try_return(RC);
1466     DlocResourceInit = TRUE;
1467 
1468     RC = UDFInitializeResourceLite(&(Vcb->DlocResource2));
1469     if(!NT_SUCCESS(RC))
1470         try_return(RC);
1471     DlocResource2Init = TRUE;
1472 
1473     RC = UDFInitializeResourceLite(&(Vcb->FlushResource));
1474     if(!NT_SUCCESS(RC))
1475         try_return(RC);
1476     FlushResourceInit = TRUE;
1477 
1478     RC = UDFInitializeResourceLite(&(Vcb->PreallocResource));
1479     if(!NT_SUCCESS(RC))
1480         try_return(RC);
1481     PreallocResourceInit = TRUE;
1482 
1483     RC = UDFInitializeResourceLite(&(Vcb->IoResource));
1484     if(!NT_SUCCESS(RC))
1485         try_return(RC);
1486     IoResourceInit = TRUE;
1487 
1488 //    RC = UDFInitializeResourceLite(&(Vcb->DelayedCloseResource));
1489 //    ASSERT(NT_SUCCESS(RC));
1490 
1491     // Allocate buffer for statistics
1492     Vcb->Statistics = (PFILE_SYSTEM_STATISTICS)MyAllocatePool__(NonPagedPool, sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors );
1493     if(!Vcb->Statistics)
1494         try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
1495     RtlZeroMemory( Vcb->Statistics, sizeof(FILE_SYSTEM_STATISTICS) * KeNumberProcessors );
1496     for (i=0; i < (KeNumberProcessors); i++) {
1497         Vcb->Statistics[i].Common.FileSystemType = FILESYSTEM_STATISTICS_TYPE_NTFS;
1498         Vcb->Statistics[i].Common.Version = 1;
1499         Vcb->Statistics[i].Common.SizeOfCompleteStructure =
1500             sizeof(FILE_SYSTEM_STATISTICS);
1501     }
1502 
1503     // We know the target device object.
1504     // Note that this is not neccessarily a pointer to the actual
1505     // physical/virtual device on which the logical volume should
1506     // be mounted. This is actually a pointer to either the actual
1507     // (real) device or to any device object that may have been
1508     // attached to it. Any IRPs that we send down should be sent to this
1509     // device object. However, the "real" physical/virtual device object
1510     // on which we perform our mount operation can be determined from the
1511     // RealDevice field in the VPB sent to us.
1512     Vcb->TargetDeviceObject = PtrTargetDeviceObject;
1513 
1514     // We also have a pointer to the newly created device object representing
1515     // this logical volume (remember that this VCB structure is simply an
1516     // extension of the created device object).
1517     Vcb->VCBDeviceObject = PtrVolumeDeviceObject;
1518 
1519     // We also have the VPB pointer. This was obtained from the
1520     // Parameters.MountVolume.Vpb field in the current I/O stack location
1521     // for the mount IRP.
1522     Vcb->Vpb = PtrVPB;
1523     // Target Vcb field in Vcb onto itself. This required for check in
1524     // open/lock/unlock volume dispatch poits
1525     Vcb->Vcb=Vcb;
1526 
1527     //  Set the removable media flag based on the real device's
1528     //  characteristics
1529     if (PtrVPB->RealDevice->Characteristics & FILE_REMOVABLE_MEDIA) {
1530         Vcb->VCBFlags |= UDF_VCB_FLAGS_REMOVABLE_MEDIA;
1531     }
1532 
1533     // Initialize the list anchor (head) for some lists in this VCB.
1534     InitializeListHead(&(Vcb->NextFCB));
1535     InitializeListHead(&(Vcb->NextNotifyIRP));
1536     InitializeListHead(&(Vcb->VolumeOpenListHead));
1537 
1538     //  Initialize the overflow queue for the volume
1539     Vcb->OverflowQueueCount = 0;
1540     InitializeListHead(&(Vcb->OverflowQueue));
1541 
1542     Vcb->PostedRequestCount = 0;
1543     KeInitializeSpinLock(&(Vcb->OverflowQueueSpinLock));
1544 
1545     // Initialize the notify IRP list mutex
1546     FsRtlNotifyInitializeSync(&(Vcb->NotifyIRPMutex));
1547 
1548     // Intilize NtRequiredFCB for this VCB
1549     Vcb->NTRequiredFCB = (PtrUDFNTRequiredFCB)MyAllocatePool__(NonPagedPool, UDFQuadAlign(sizeof(UDFNTRequiredFCB)));
1550     if(!Vcb->NTRequiredFCB)
1551         try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
1552     RtlZeroMemory(Vcb->NTRequiredFCB, UDFQuadAlign(sizeof(UDFNTRequiredFCB)));
1553 
1554     // Set the initial file size values appropriately. Note that our FSD may
1555     // wish to guess at the initial amount of information we would like to
1556     // read from the disk until we have really determined that this a valid
1557     // logical volume (on disk) that we wish to mount.
1558     // Vcb->FileSize = Vcb->AllocationSize = ??
1559 
1560     // We do not want to bother with valid data length callbacks
1561     // from the Cache Manager for the file stream opened for volume metadata
1562     // information
1563     Vcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart = 0x7FFFFFFFFFFFFFFFULL;
1564 
1565     Vcb->VolumeLockPID = -1;
1566 
1567     Vcb->VCBOpenCount = 1;
1568 
1569     Vcb->WCacheMaxBlocks        = UDFGlobalData.WCacheMaxBlocks;
1570     Vcb->WCacheMaxFrames        = UDFGlobalData.WCacheMaxFrames;
1571     Vcb->WCacheBlocksPerFrameSh = UDFGlobalData.WCacheBlocksPerFrameSh;
1572     Vcb->WCacheFramesToKeepFree = UDFGlobalData.WCacheFramesToKeepFree;
1573 
1574     // Create a stream file object for this volume.
1575     //Vcb->PtrStreamFileObject = IoCreateStreamFileObject(NULL,
1576     //                                            Vcb->Vpb->RealDevice);
1577     //ASSERT(Vcb->PtrStreamFileObject);
1578 
1579     // Initialize some important fields in the newly created file object.
1580     //Vcb->PtrStreamFileObject->FsContext = (PVOID)Vcb;
1581     //Vcb->PtrStreamFileObject->FsContext2 = NULL;
1582     //Vcb->PtrStreamFileObject->SectionObjectPointer = &(Vcb->SectionObject);
1583 
1584     //Vcb->PtrStreamFileObject->Vpb = PtrVPB;
1585 
1586     // Link this chap onto the global linked list of all VCB structures.
1587     // We consider that GlobalDataResource was acquired in past
1588     UDFAcquireResourceExclusive(&(UDFGlobalData.GlobalDataResource), TRUE);
1589     InsertTailList(&(UDFGlobalData.VCBQueue), &(Vcb->NextVCB));
1590 
1591     Vcb->TargetDevName.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, sizeof(MOUNTDEV_NAME));
1592     if(!Vcb->TargetDevName.Buffer)
1593         try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
1594 
1595     RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME /*IOCTL_MOUNTDEV_QUERY_DEVICE_NAME*/, Vcb->TargetDeviceObject,
1596                     NULL,0,
1597                     (PVOID)(Vcb->TargetDevName.Buffer),sizeof(MOUNTDEV_NAME),
1598                     FALSE, NULL);
1599     if(!NT_SUCCESS(RC)) {
1600 
1601         if(RC == STATUS_BUFFER_OVERFLOW) {
1602             if(!MyReallocPool__((PCHAR)(Vcb->TargetDevName.Buffer), sizeof(MOUNTDEV_NAME),
1603                              (PCHAR*)&(Vcb->TargetDevName.Buffer), Vcb->TargetDevName.Buffer[0]+sizeof(MOUNTDEV_NAME)) ) {
1604                 goto Kill_DevName_buffer;
1605             }
1606 
1607             RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME /*IOCTL_MOUNTDEV_QUERY_DEVICE_NAME*/, Vcb->TargetDeviceObject,
1608                             NULL,0,
1609                             (PVOID)(Vcb->TargetDevName.Buffer), Vcb->TargetDevName.Buffer[0]+sizeof(MOUNTDEV_NAME),
1610                             FALSE, NULL);
1611             if(!NT_SUCCESS(RC))
1612                 goto Kill_DevName_buffer;
1613 
1614         } else {
1615 Kill_DevName_buffer:
1616             if(!MyReallocPool__((PCHAR)Vcb->TargetDevName.Buffer, sizeof(MOUNTDEV_NAME),
1617                                 (PCHAR*)&(Vcb->TargetDevName.Buffer), sizeof(REG_NAMELESS_DEV)))
1618                 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
1619             RtlCopyMemory(Vcb->TargetDevName.Buffer, REG_NAMELESS_DEV, sizeof(REG_NAMELESS_DEV));
1620             Vcb->TargetDevName.Length = sizeof(REG_NAMELESS_DEV)-sizeof(WCHAR);
1621             Vcb->TargetDevName.MaximumLength = sizeof(REG_NAMELESS_DEV);
1622             goto read_reg;
1623         }
1624     }
1625 
1626     Vcb->TargetDevName.MaximumLength =
1627     (Vcb->TargetDevName.Length = Vcb->TargetDevName.Buffer[0]) + sizeof(WCHAR);
1628     RtlMoveMemory((PVOID)(Vcb->TargetDevName.Buffer), (PVOID)(Vcb->TargetDevName.Buffer+1), Vcb->TargetDevName.Buffer[0]);
1629     Vcb->TargetDevName.Buffer[i = (SHORT)(Vcb->TargetDevName.Length/sizeof(WCHAR))] = 0;
1630 
1631     for(;i>=0;i--) {
1632         if(Vcb->TargetDevName.Buffer[i] == L'\\') {
1633 
1634             Vcb->TargetDevName.Length -= i*sizeof(WCHAR);
1635             RtlMoveMemory((PVOID)(Vcb->TargetDevName.Buffer), (PVOID)(Vcb->TargetDevName.Buffer+i), Vcb->TargetDevName.Length);
1636             Vcb->TargetDevName.Buffer[Vcb->TargetDevName.Length/sizeof(WCHAR)] = 0;
1637             break;
1638         }
1639     }
1640 
1641     UDFPrint(("  TargetDevName: %S\n", Vcb->TargetDevName.Buffer));
1642 
1643     // Initialize caching for the stream file object.
1644     //CcInitializeCacheMap(Vcb->PtrStreamFileObject, (PCC_FILE_SIZES)(&(Vcb->AllocationSize)),
1645     //                            TRUE,       // We will use pinned access.
1646     //                            &(UDFGlobalData.CacheMgrCallBacks), Vcb);
1647 
1648 read_reg:
1649 
1650     UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
1651 
1652     // Mark the fact that this VCB structure is initialized.
1653     Vcb->VCBFlags |= UDF_VCB_FLAGS_VCB_INITIALIZED;
1654 
1655     RC = STATUS_SUCCESS;
1656 
1657 try_exit:   NOTHING;
1658 
1659     } _SEH2_FINALLY {
1660 
1661         if(!NT_SUCCESS(RC)) {
1662             if(Vcb->TargetDevName.Buffer)
1663                 MyFreePool__(Vcb->TargetDevName.Buffer);
1664             if(Vcb->NTRequiredFCB)
1665                 MyFreePool__(Vcb->NTRequiredFCB);
1666             if(Vcb->Statistics)
1667                 MyFreePool__(Vcb->Statistics);
1668 
1669             if(VCBResourceInit)
1670                 UDFDeleteResource(&(Vcb->VCBResource));
1671             if(BitMapResource1Init)
1672                 UDFDeleteResource(&(Vcb->BitMapResource1));
1673             if(FcbListResourceInit)
1674                 UDFDeleteResource(&(Vcb->FcbListResource));
1675             if(FileIdResourceInit)
1676                 UDFDeleteResource(&(Vcb->FileIdResource));
1677             if(DlocResourceInit)
1678                 UDFDeleteResource(&(Vcb->DlocResource));
1679             if(DlocResource2Init)
1680                 UDFDeleteResource(&(Vcb->DlocResource2));
1681             if(FlushResourceInit)
1682                 UDFDeleteResource(&(Vcb->FlushResource));
1683             if(PreallocResourceInit)
1684                 UDFDeleteResource(&(Vcb->PreallocResource));
1685             if(IoResourceInit)
1686                 UDFDeleteResource(&(Vcb->IoResource));
1687         }
1688     } _SEH2_END;
1689 
1690     return RC;
1691 } // end UDFInitializeVCB()
1692 
1693 UDFFSD_MEDIA_TYPE
1694 UDFGetMediaClass(
1695     PVCB Vcb
1696     )
1697 {
1698     switch(Vcb->FsDeviceType) {
1699     case FILE_DEVICE_CD_ROM_FILE_SYSTEM:
1700         if(Vcb->VCBFlags & (UDF_VCB_FLAGS_VOLUME_READ_ONLY |
1701                             UDF_VCB_FLAGS_MEDIA_READ_ONLY))
1702             return MediaCdrom;
1703         if(Vcb->CDR_Mode)
1704             return MediaCdr;
1705         if((Vcb->MediaType >= MediaType_UnknownSize_CDR) &&
1706            (Vcb->MediaType < MediaType_UnknownSize_CDRW)) {
1707             return MediaCdr;
1708         }
1709         if((Vcb->MediaType >= MediaType_UnknownSize_CDRW) &&
1710            (Vcb->MediaType < MediaType_UnknownSize_Unknown)) {
1711             return MediaCdrw;
1712         }
1713         if(Vcb->MediaClassEx == CdMediaClass_CDR) {
1714             return MediaCdr;
1715         }
1716         if(Vcb->MediaClassEx == CdMediaClass_DVDR ||
1717            Vcb->MediaClassEx == CdMediaClass_DVDpR ||
1718            Vcb->MediaClassEx == CdMediaClass_HD_DVDR ||
1719            Vcb->MediaClassEx == CdMediaClass_BDR) {
1720             return MediaDvdr;
1721         }
1722         if(Vcb->MediaClassEx == CdMediaClass_CDRW) {
1723             return MediaCdrw;
1724         }
1725         if(Vcb->MediaClassEx == CdMediaClass_DVDRW ||
1726            Vcb->MediaClassEx == CdMediaClass_DVDpRW ||
1727            Vcb->MediaClassEx == CdMediaClass_DVDRAM ||
1728            Vcb->MediaClassEx == CdMediaClass_HD_DVDRW ||
1729            Vcb->MediaClassEx == CdMediaClass_HD_DVDRAM ||
1730            Vcb->MediaClassEx == CdMediaClass_BDRE) {
1731             return MediaDvdrw;
1732         }
1733         //
1734         if(Vcb->MediaClassEx == CdMediaClass_CDROM ||
1735            Vcb->MediaClassEx == CdMediaClass_DVDROM ||
1736            Vcb->MediaClassEx == CdMediaClass_HD_DVDROM ||
1737            Vcb->MediaClassEx == CdMediaClass_BDROM) {
1738             return MediaCdrom;
1739         }
1740         return MediaCdrom;
1741 #ifdef UDF_HDD_SUPPORT
1742     case FILE_DEVICE_DISK_FILE_SYSTEM:
1743         if(Vcb->TargetDeviceObject->Characteristics & FILE_FLOPPY_DISKETTE)
1744             return MediaFloppy;
1745         if(Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1746             return MediaZip;
1747         return MediaHdd;
1748 #endif //UDF_HDD_SUPPORT
1749     }
1750     return MediaUnknown;
1751 } // end UDFGetMediaClass()
1752 
1753 typedef ULONG
1754 (*ptrUDFGetParameter)(
1755     IN PVCB Vcb,
1756     IN PCWSTR Name,
1757     IN ULONG DefValue
1758     );
1759 
1760 VOID
1761 UDFUpdateCompatOption(
1762     PVCB Vcb,
1763     BOOLEAN Update,
1764     BOOLEAN UseCfg,
1765     PCWSTR Name,
1766     ULONG Flag,
1767     BOOLEAN Default
1768     )
1769 {
1770     ptrUDFGetParameter UDFGetParameter = UseCfg ? UDFGetCfgParameter : UDFGetRegParameter;
1771 
1772     if(UDFGetParameter(Vcb, Name, Update ? ((Vcb->CompatFlags & Flag) ? TRUE : FALSE) : Default)) {
1773         Vcb->CompatFlags |= Flag;
1774     } else {
1775         Vcb->CompatFlags &= ~Flag;
1776     }
1777 } // end UDFUpdateCompatOption()
1778 
1779 VOID
1780 UDFReadRegKeys(
1781     PVCB Vcb,
1782     BOOLEAN Update,
1783     BOOLEAN UseCfg
1784     )
1785 {
1786     ULONG mult = 1;
1787     ptrUDFGetParameter UDFGetParameter = UseCfg ? UDFGetCfgParameter : UDFGetRegParameter;
1788 
1789     Vcb->DefaultRegName = UDFMediaClassName[(ULONG)UDFGetMediaClass(Vcb)].ClassName;
1790 
1791     // Should we use Extended FE by default ?
1792     Vcb->UseExtendedFE = (UCHAR)UDFGetParameter(Vcb, REG_USEEXTENDEDFE_NAME,
1793         Update ? Vcb->UseExtendedFE : FALSE);
1794     if(Vcb->UseExtendedFE != TRUE) Vcb->UseExtendedFE = FALSE;
1795     // What type of AllocDescs should we use
1796     Vcb->DefaultAllocMode = (USHORT)UDFGetParameter(Vcb, REG_DEFALLOCMODE_NAME,
1797         Update ? Vcb->DefaultAllocMode : ICB_FLAG_AD_SHORT);
1798     if(Vcb->DefaultAllocMode > ICB_FLAG_AD_LONG) Vcb->DefaultAllocMode = ICB_FLAG_AD_SHORT;
1799     // Default UID & GID to be set on newly created files
1800     Vcb->DefaultUID = UDFGetParameter(Vcb, UDF_DEFAULT_UID_NAME, Update ? Vcb->DefaultUID : -1);
1801     Vcb->DefaultGID = UDFGetParameter(Vcb, UDF_DEFAULT_GID_NAME, Update ? Vcb->DefaultGID : -1);
1802     // FE allocation charge for plain Dirs
1803     Vcb->FECharge = UDFGetParameter(Vcb, UDF_FE_CHARGE_NAME, Update ? Vcb->FECharge : 0);
1804     if(!Vcb->FECharge)
1805         Vcb->FECharge = UDF_DEFAULT_FE_CHARGE;
1806     // FE allocation charge for Stream Dirs (SDir)
1807     Vcb->FEChargeSDir = UDFGetParameter(Vcb, UDF_FE_CHARGE_SDIR_NAME,
1808         Update ? Vcb->FEChargeSDir : 0);
1809     if(!Vcb->FEChargeSDir)
1810         Vcb->FEChargeSDir = UDF_DEFAULT_FE_CHARGE_SDIR;
1811     // How many Deleted entries should contain Directory to make us
1812     // start packing it.
1813     Vcb->PackDirThreshold = UDFGetParameter(Vcb, UDF_DIR_PACK_THRESHOLD_NAME,
1814         Update ? Vcb->PackDirThreshold : 0);
1815     if(Vcb->PackDirThreshold == 0xffffffff)
1816         Vcb->PackDirThreshold = UDF_DEFAULT_DIR_PACK_THRESHOLD;
1817     // The binary exponent for the number of Pages to be read-ahead'ed
1818     // This information would be sent to System Cache Manager
1819     if(!Update) {
1820         Vcb->SystemCacheGran = (1 << UDFGetParameter(Vcb, UDF_READAHEAD_GRAN_NAME, 0)) * PAGE_SIZE;
1821         if(!Vcb->SystemCacheGran)
1822             Vcb->SystemCacheGran = UDF_DEFAULT_READAHEAD_GRAN;
1823     }
1824     // Timeouts for FreeSpaceBitMap & TheWholeDirTree flushes
1825     Vcb->BM_FlushPriod = UDFGetParameter(Vcb, UDF_BM_FLUSH_PERIOD_NAME,
1826         Update ? Vcb->BM_FlushPriod : 0);
1827     if(!Vcb->BM_FlushPriod) {
1828         Vcb->BM_FlushPriod = UDF_DEFAULT_BM_FLUSH_TIMEOUT;
1829     } else
1830     if(Vcb->BM_FlushPriod == (ULONG)-1) {
1831         Vcb->BM_FlushPriod = 0;
1832     }
1833     Vcb->Tree_FlushPriod = UDFGetParameter(Vcb, UDF_TREE_FLUSH_PERIOD_NAME,
1834         Update ? Vcb->Tree_FlushPriod : 0);
1835     if(!Vcb->Tree_FlushPriod) {
1836         Vcb->Tree_FlushPriod = UDF_DEFAULT_TREE_FLUSH_TIMEOUT;
1837     } else
1838     if(Vcb->Tree_FlushPriod == (ULONG)-1) {
1839         Vcb->Tree_FlushPriod = 0;
1840     }
1841     Vcb->SkipCountLimit = UDFGetParameter(Vcb, UDF_NO_UPDATE_PERIOD_NAME,
1842         Update ? Vcb->SkipCountLimit : 0);
1843     if(!Vcb->SkipCountLimit)
1844         Vcb->SkipCountLimit = -1;
1845 
1846     Vcb->SkipEjectCountLimit = UDFGetParameter(Vcb, UDF_NO_EJECT_PERIOD_NAME,
1847         Update ? Vcb->SkipEjectCountLimit : 3);
1848 
1849     if(!Update) {
1850         // How many threads are allowed to sodomize Disc simultaneously on each CPU
1851         Vcb->ThreadsPerCpu = UDFGetParameter(Vcb, UDF_FSP_THREAD_PER_CPU_NAME,
1852             Update ? Vcb->ThreadsPerCpu : 2);
1853         if(Vcb->ThreadsPerCpu < 2)
1854             Vcb->ThreadsPerCpu = UDF_DEFAULT_FSP_THREAD_PER_CPU;
1855     }
1856     // The mimimum FileSize increment when we'll decide not to allocate
1857     // on-disk space.
1858     Vcb->SparseThreshold = UDFGetParameter(Vcb, UDF_SPARSE_THRESHOLD_NAME,
1859         Update ? Vcb->SparseThreshold : 0);
1860     if(!Vcb->SparseThreshold)
1861         Vcb->SparseThreshold = UDF_DEFAULT_SPARSE_THRESHOLD;
1862     // This option is used to VERIFY all the data written. It decreases performance
1863     Vcb->VerifyOnWrite = UDFGetParameter(Vcb, UDF_VERIFY_ON_WRITE_NAME,
1864         Update ? Vcb->VerifyOnWrite : FALSE) ? TRUE : FALSE;
1865 
1866 #ifndef UDF_READ_ONLY_BUILD
1867     // Should we update AttrFileTime on Attr changes
1868     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_TIMES_ATTR, UDF_VCB_IC_UPDATE_ATTR_TIME, FALSE);
1869     // Should we update ModifyFileTime on Writes changes
1870     // It also affects ARCHIVE bit setting on write operations
1871     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_TIMES_MOD, UDF_VCB_IC_UPDATE_MODIFY_TIME, FALSE);
1872     // Should we update AccessFileTime on Exec & so on.
1873     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_TIMES_ACCS, UDF_VCB_IC_UPDATE_ACCESS_TIME, FALSE);
1874     // Should we update Archive bit
1875     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_ATTR_ARCH, UDF_VCB_IC_UPDATE_ARCH_BIT, FALSE);
1876     // Should we update Dir's Times & Attrs on Modify
1877     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_DIR_TIMES_ATTR_W, UDF_VCB_IC_UPDATE_DIR_WRITE, FALSE);
1878     // Should we update Dir's Times & Attrs on Access
1879     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_UPDATE_DIR_TIMES_ATTR_R, UDF_VCB_IC_UPDATE_DIR_READ, FALSE);
1880     // Should we allow user to write into Read-Only Directory
1881     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_ALLOW_WRITE_IN_RO_DIR, UDF_VCB_IC_WRITE_IN_RO_DIR, TRUE);
1882     // Should we allow user to change Access Time for unchanged Directory
1883     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_ALLOW_UPDATE_TIMES_ACCS_UCHG_DIR, UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME, FALSE);
1884 #endif //UDF_READ_ONLY_BUILD
1885     // Should we record Allocation Descriptors in W2k-compatible form
1886     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_W2K_COMPAT_ALLOC_DESCS, UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS, TRUE);
1887     // Should we read LONG_ADs with invalid PartitionReferenceNumber (generated by Nero Instant Burner)
1888     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_INSTANT_COMPAT_ALLOC_DESCS, UDF_VCB_IC_INSTANT_COMPAT_ALLOC_DESCS, TRUE);
1889     // Should we make a copy of VolumeLabel in LVD
1890     // usually only PVD is updated
1891     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_W2K_COMPAT_VLABEL, UDF_VCB_IC_W2K_COMPAT_VLABEL, TRUE);
1892     // Should we handle or ignore HW_RO flag
1893     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_HANDLE_HW_RO, UDF_VCB_IC_HW_RO, FALSE);
1894     // Should we handle or ignore SOFT_RO flag
1895     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_HANDLE_SOFT_RO, UDF_VCB_IC_SOFT_RO, TRUE);
1896 
1897     // Check if we should generate UDF-style or OS-style DOS-names
1898     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_OS_NATIVE_DOS_NAME, UDF_VCB_IC_OS_NATIVE_DOS_NAME, FALSE);
1899 #ifndef UDF_READ_ONLY_BUILD
1900     // should we force FO_WRITE_THROUGH on removable media
1901     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_FORCE_WRITE_THROUGH_NAME, UDF_VCB_IC_FORCE_WRITE_THROUGH,
1902                           (Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) ? TRUE : FALSE
1903                          );
1904 #endif //UDF_READ_ONLY_BUILD
1905     // Should we ignore FO_SEQUENTIAL_ONLY
1906     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_IGNORE_SEQUENTIAL_IO, UDF_VCB_IC_IGNORE_SEQUENTIAL_IO, FALSE);
1907 // Force Read-only mounts
1908 #ifndef UDF_READ_ONLY_BUILD
1909     UDFUpdateCompatOption(Vcb, Update, UseCfg, UDF_FORCE_HW_RO, UDF_VCB_IC_FORCE_HW_RO, FALSE);
1910 #else //UDF_READ_ONLY_BUILD
1911     Vcb->CompatFlags |= UDF_VCB_IC_FORCE_HW_RO;
1912 #endif //UDF_READ_ONLY_BUILD
1913     // Check if we should send FLUSH request for File/Dir down to
1914     // underlaying driver
1915     if(UDFGetParameter(Vcb, UDF_FLUSH_MEDIA,Update ? Vcb->FlushMedia : FALSE)) {
1916         Vcb->FlushMedia = TRUE;
1917     } else {
1918         Vcb->FlushMedia = FALSE;
1919     }
1920     // compare data from packet with data to be writen there
1921     // before physical writing
1922     if(!UDFGetParameter(Vcb, UDF_COMPARE_BEFORE_WRITE, Update ? Vcb->DoNotCompareBeforeWrite : FALSE)) {
1923         Vcb->DoNotCompareBeforeWrite = TRUE;
1924     } else {
1925         Vcb->DoNotCompareBeforeWrite = FALSE;
1926     }
1927     if(!Update)  {
1928         if(UDFGetParameter(Vcb, UDF_CHAINED_IO, TRUE)) {
1929             Vcb->CacheChainedIo = TRUE;
1930         }
1931 
1932         if(UDFGetParameter(Vcb, UDF_FORCE_MOUNT_ALL, FALSE)) {
1933             Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK;
1934         }
1935         // Should we show Blank.Cd file on damaged/unformatted,
1936         // but UDF-compatible disks
1937         Vcb->ShowBlankCd = (UCHAR)UDFGetParameter(Vcb, UDF_SHOW_BLANK_CD, FALSE);
1938         if(Vcb->ShowBlankCd) {
1939             Vcb->CompatFlags |= UDF_VCB_IC_SHOW_BLANK_CD;
1940             if(Vcb->ShowBlankCd > 2) {
1941                 Vcb->ShowBlankCd = 2;
1942             }
1943         }
1944         // Should we wait util CD device return from
1945         // Becoming Ready state
1946         if(UDFGetParameter(Vcb, UDF_WAIT_CD_SPINUP, TRUE)) {
1947             Vcb->CompatFlags |= UDF_VCB_IC_WAIT_CD_SPINUP;
1948         }
1949         // Should we remenber bad VDS locations during mount
1950         // Caching will improve mount performance on bad disks, but
1951         // will degrade mauntability of unreliable discs
1952         if(UDFGetParameter(Vcb, UDF_CACHE_BAD_VDS, TRUE)) {
1953             Vcb->CompatFlags |= UDF_VCB_IC_CACHE_BAD_VDS;
1954         }
1955 
1956         // Set partitially damaged volume mount mode
1957         Vcb->PartitialDamagedVolumeAction = (UCHAR)UDFGetParameter(Vcb, UDF_PART_DAMAGED_BEHAVIOR, UDF_PART_DAMAGED_RW);
1958         if(Vcb->PartitialDamagedVolumeAction > 2) {
1959             Vcb->PartitialDamagedVolumeAction = UDF_PART_DAMAGED_RW;
1960         }
1961 
1962         // Set partitially damaged volume mount mode
1963         Vcb->NoFreeRelocationSpaceVolumeAction = (UCHAR)UDFGetParameter(Vcb, UDF_NO_SPARE_BEHAVIOR, UDF_PART_DAMAGED_RW);
1964         if(Vcb->NoFreeRelocationSpaceVolumeAction > 1) {
1965             Vcb->NoFreeRelocationSpaceVolumeAction = UDF_PART_DAMAGED_RW;
1966         }
1967 
1968         // Set dirty volume mount mode
1969         if(UDFGetParameter(Vcb, UDF_DIRTY_VOLUME_BEHAVIOR, UDF_PART_DAMAGED_RO)) {
1970             Vcb->CompatFlags |= UDF_VCB_IC_DIRTY_RO;
1971         }
1972 
1973         mult = UDFGetParameter(Vcb, UDF_CACHE_SIZE_MULTIPLIER, 1);
1974         if(!mult) mult = 1;
1975         Vcb->WCacheMaxBlocks *= mult;
1976         Vcb->WCacheMaxFrames *= mult;
1977 
1978         if(UDFGetParameter(Vcb, UDF_USE_EJECT_BUTTON, TRUE)) {
1979             Vcb->UseEvent = TRUE;
1980         }
1981     }
1982     return;
1983 } // end UDFReadRegKeys()
1984 
1985 ULONG
1986 UDFGetRegParameter(
1987     IN PVCB Vcb,
1988     IN PCWSTR Name,
1989     IN ULONG DefValue
1990     )
1991 {
1992     return UDFRegCheckParameterValue(&(UDFGlobalData.SavedRegPath),
1993                                      Name,
1994                                      Vcb ? &(Vcb->TargetDevName) : NULL,
1995                                      Vcb ? Vcb->DefaultRegName : NULL,
1996                                      DefValue);
1997 } // end UDFGetRegParameter()
1998 
1999 ULONG
2000 UDFGetCfgParameter(
2001     IN PVCB Vcb,
2002     IN PCWSTR Name,
2003     IN ULONG DefValue
2004     )
2005 {
2006     ULONG len;
2007     CHAR NameA[128];
2008     ULONG ret_val=0;
2009     CHAR a;
2010     BOOLEAN wait_name=TRUE;
2011     BOOLEAN wait_val=FALSE;
2012     BOOLEAN wait_nl=FALSE;
2013     ULONG radix=10;
2014     ULONG i;
2015 
2016     PUCHAR Cfg    = Vcb->Cfg;
2017     ULONG  Length = Vcb->CfgLength;
2018 
2019     if(!Cfg || !Length)
2020         return DefValue;
2021 
2022     len = wcslen(Name);
2023     if(len >= sizeof(NameA))
2024         return DefValue;
2025     sprintf(NameA, "%S", Name);
2026 
2027     for(i=0; i<Length; i++) {
2028         a=Cfg[i];
2029         switch(a) {
2030         case '\n':
2031         case '\r':
2032         case ',':
2033             if(wait_val)
2034                 return DefValue;
2035             continue;
2036         case ';':
2037         case '#':
2038         case '[': // ignore sections for now, treat as comment
2039             if(!wait_name)
2040                 return DefValue;
2041             wait_nl = TRUE;
2042             continue;
2043         case '=':
2044             if(!wait_val)
2045                 return DefValue;
2046             continue;
2047         case ' ':
2048         case '\t':
2049             continue;
2050         default:
2051             if(wait_nl)
2052                 continue;
2053         }
2054         if(wait_name) {
2055             if(i+len+2 > Length)
2056                 return DefValue;
2057             if(RtlCompareMemory(Cfg+i, NameA, len) == len) {
2058                 a=Cfg[i+len];
2059                 switch(a) {
2060                 case '\n':
2061                 case '\r':
2062                 case ',':
2063                 case ';':
2064                 case '#':
2065                     return DefValue;
2066                 case '=':
2067                 case ' ':
2068                 case '\t':
2069                     break;
2070                 default:
2071                     wait_nl = TRUE;
2072                     wait_val = FALSE;
2073                     i+=len;
2074                     continue;
2075                 }
2076                 wait_name = FALSE;
2077                 wait_nl = FALSE;
2078                 wait_val = TRUE;
2079                 i+=len;
2080 
2081             } else {
2082                 wait_nl = TRUE;
2083             }
2084             continue;
2085         }
2086         if(wait_val) {
2087             if(i+3 > Length) {
2088                 if(a=='0' && Cfg[i+1]=='x') {
2089                     i+=2;
2090                     radix=16;
2091                 }
2092             }
2093             if(i >= Length) {
2094                 return DefValue;
2095             }
2096             while(i<Length) {
2097                 a=Cfg[i];
2098                 switch(a) {
2099                 case '\n':
2100                 case '\r':
2101                 case ' ':
2102                 case '\t':
2103                 case ',':
2104                 case ';':
2105                 case '#':
2106                     if(wait_val)
2107                         return DefValue;
2108                     return ret_val;
2109                 }
2110                 if(a >= '0' && a <= '9') {
2111                     a -= '0';
2112                 } else {
2113                     if(radix != 16)
2114                         return DefValue;
2115                     if(a >= 'a' && a <= 'f') {
2116                         a -= 'a';
2117                     } else
2118                     if(a >= 'A' && a <= 'F') {
2119                         a -= 'A';
2120                     } else {
2121                         return DefValue;
2122                     }
2123                     a += 0x0a;
2124                 }
2125                 ret_val = ret_val*radix + a;
2126                 wait_val = FALSE;
2127                 i++;
2128             }
2129             return ret_val;
2130         }
2131     }
2132     return DefValue;
2133 
2134 } // end UDFGetCfgParameter()
2135 
2136 VOID
2137 UDFReleaseVCB(
2138     PVCB  Vcb
2139     )
2140 {
2141     LARGE_INTEGER delay;
2142     UDFPrint(("UDFReleaseVCB\n"));
2143 
2144     delay.QuadPart = -500000; // 0.05 sec
2145     while(Vcb->PostedRequestCount) {
2146         UDFPrint(("UDFReleaseVCB: PostedRequestCount = %d\n", Vcb->PostedRequestCount));
2147         // spin until all queues IRPs are processed
2148         KeDelayExecutionThread(KernelMode, FALSE, &delay);
2149         delay.QuadPart -= 500000; // grow delay 0.05 sec
2150     }
2151 
2152     _SEH2_TRY {
2153         UDFPrint(("UDF: Flushing buffers\n"));
2154         UDFVRelease(Vcb);
2155         WCacheFlushAll__(&(Vcb->FastCache),Vcb);
2156         WCacheRelease__(&(Vcb->FastCache));
2157 
2158     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2159         BrutePoint();
2160     } _SEH2_END;
2161 
2162 #ifdef UDF_DBG
2163     _SEH2_TRY {
2164         if (!ExIsResourceAcquiredShared(&UDFGlobalData.GlobalDataResource)) {
2165             UDFPrint(("UDF: attempt to access to not protected data\n"));
2166             UDFPrint(("UDF: UDFGlobalData\n"));
2167             BrutePoint();
2168         }
2169     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2170         BrutePoint();
2171     } _SEH2_END;
2172 #endif
2173 
2174     _SEH2_TRY {
2175         RemoveEntryList(&(Vcb->NextVCB));
2176     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2177         BrutePoint();
2178     } _SEH2_END;
2179 
2180 /*    _SEH2_TRY {
2181         if(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT)
2182             KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, NULL);
2183             Vcb->VCBFlags &= ~UDF_VCB_FLAGS_STOP_WAITER_EVENT;
2184     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2185         BrutePoint();
2186     }*/
2187 
2188     _SEH2_TRY {
2189         UDFPrint(("UDF: Delete resources\n"));
2190         UDFDeleteResource(&(Vcb->VCBResource));
2191         UDFDeleteResource(&(Vcb->BitMapResource1));
2192         UDFDeleteResource(&(Vcb->FcbListResource));
2193         UDFDeleteResource(&(Vcb->FileIdResource));
2194         UDFDeleteResource(&(Vcb->DlocResource));
2195         UDFDeleteResource(&(Vcb->DlocResource2));
2196         UDFDeleteResource(&(Vcb->FlushResource));
2197         UDFDeleteResource(&(Vcb->PreallocResource));
2198         UDFDeleteResource(&(Vcb->IoResource));
2199     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2200         BrutePoint();
2201     } _SEH2_END;
2202 
2203     _SEH2_TRY {
2204         UDFPrint(("UDF: Cleanup VCB\n"));
2205         ASSERT(IsListEmpty(&(Vcb->NextNotifyIRP)));
2206         FsRtlNotifyUninitializeSync(&(Vcb->NotifyIRPMutex));
2207         UDFCleanupVCB(Vcb);
2208     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2209         BrutePoint();
2210     } _SEH2_END;
2211 
2212     _SEH2_TRY {
2213         UDFPrint(("UDF: Delete DO\n"));
2214         IoDeleteDevice(Vcb->VCBDeviceObject);
2215     } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2216         BrutePoint();
2217     } _SEH2_END;
2218 
2219 } // end UDFReleaseVCB()
2220 
2221 /*
2222     Read DWORD from Registry
2223 */
2224 ULONG
2225 UDFRegCheckParameterValue(
2226     IN PUNICODE_STRING RegistryPath,
2227     IN PCWSTR Name,
2228     IN PUNICODE_STRING PtrVolumePath,
2229     IN PCWSTR DefaultPath,
2230     IN ULONG DefValue
2231     )
2232 {
2233     NTSTATUS          status;
2234 
2235     ULONG             val = DefValue;
2236 
2237     UNICODE_STRING    paramStr;
2238     UNICODE_STRING    defaultParamStr;
2239     UNICODE_STRING    paramPathUnknownStr;
2240 
2241     UNICODE_STRING    paramSuffix;
2242     UNICODE_STRING    paramPath;
2243     UNICODE_STRING    paramPathUnknown;
2244     UNICODE_STRING    paramDevPath;
2245     UNICODE_STRING    defaultParamPath;
2246 
2247     _SEH2_TRY {
2248 
2249         paramPath.Buffer = NULL;
2250         paramDevPath.Buffer = NULL;
2251         paramPathUnknown.Buffer = NULL;
2252         defaultParamPath.Buffer = NULL;
2253 
2254         // First append \Parameters to the passed in registry path
2255         // Note, RtlInitUnicodeString doesn't allocate memory
2256         RtlInitUnicodeString(&paramStr, L"\\Parameters");
2257         RtlInitUnicodeString(&paramPath, NULL);
2258 
2259         RtlInitUnicodeString(&paramPathUnknownStr, REG_DEFAULT_UNKNOWN);
2260         RtlInitUnicodeString(&paramPathUnknown, NULL);
2261 
2262         paramPathUnknown.MaximumLength = RegistryPath->Length + paramPathUnknownStr.Length + paramStr.Length + sizeof(WCHAR);
2263         paramPath.MaximumLength = RegistryPath->Length + paramStr.Length + sizeof(WCHAR);
2264 
2265         paramPath.Buffer = (PWCH)MyAllocatePool__(PagedPool, paramPath.MaximumLength);
2266         if(!paramPath.Buffer) {
2267             UDFPrint(("UDFCheckRegValue: couldn't allocate paramPath\n"));
2268             try_return(val = DefValue);
2269         }
2270         paramPathUnknown.Buffer = (PWCH)MyAllocatePool__(PagedPool, paramPathUnknown.MaximumLength);
2271         if(!paramPathUnknown.Buffer) {
2272             UDFPrint(("UDFCheckRegValue: couldn't allocate paramPathUnknown\n"));
2273             try_return(val = DefValue);
2274         }
2275 
2276         RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength);
2277         status = RtlAppendUnicodeToString(&paramPath, RegistryPath->Buffer);
2278         if(!NT_SUCCESS(status)) {
2279             try_return(val = DefValue);
2280         }
2281         status = RtlAppendUnicodeToString(&paramPath, paramStr.Buffer);
2282         if(!NT_SUCCESS(status)) {
2283             try_return(val = DefValue);
2284         }
2285         UDFPrint(("UDFCheckRegValue: (1) |%S|\n", paramPath.Buffer));
2286 
2287         RtlZeroMemory(paramPathUnknown.Buffer, paramPathUnknown.MaximumLength);
2288         status = RtlAppendUnicodeToString(&paramPathUnknown, RegistryPath->Buffer);
2289         if(!NT_SUCCESS(status)) {
2290             try_return(val = DefValue);
2291         }
2292         status = RtlAppendUnicodeToString(&paramPathUnknown, paramStr.Buffer);
2293         if(!NT_SUCCESS(status)) {
2294             try_return(val = DefValue);
2295         }
2296         status = RtlAppendUnicodeToString(&paramPathUnknown, paramPathUnknownStr.Buffer);
2297         if(!NT_SUCCESS(status)) {
2298             try_return(val = DefValue);
2299         }
2300         UDFPrint(("UDFCheckRegValue: (2) |%S|\n", paramPathUnknown.Buffer));
2301 
2302         // First append \Parameters\Default_XXX to the passed in registry path
2303         if(DefaultPath) {
2304             RtlInitUnicodeString(&defaultParamStr, DefaultPath);
2305             RtlInitUnicodeString(&defaultParamPath, NULL);
2306             defaultParamPath.MaximumLength = paramPath.Length + defaultParamStr.Length + sizeof(WCHAR);
2307             defaultParamPath.Buffer = (PWCH)MyAllocatePool__(PagedPool, defaultParamPath.MaximumLength);
2308             if(!defaultParamPath.Buffer) {
2309                 UDFPrint(("UDFCheckRegValue: couldn't allocate defaultParamPath\n"));
2310                 try_return(val = DefValue);
2311             }
2312 
2313             RtlZeroMemory(defaultParamPath.Buffer, defaultParamPath.MaximumLength);
2314             status = RtlAppendUnicodeToString(&defaultParamPath, paramPath.Buffer);
2315             if(!NT_SUCCESS(status)) {
2316                 try_return(val = DefValue);
2317             }
2318             status = RtlAppendUnicodeToString(&defaultParamPath, defaultParamStr.Buffer);
2319             if(!NT_SUCCESS(status)) {
2320                 try_return(val = DefValue);
2321             }
2322             UDFPrint(("UDFCheckRegValue: (3) |%S|\n", defaultParamPath.Buffer));
2323         }
2324 
2325         if(PtrVolumePath) {
2326             paramSuffix = *PtrVolumePath;
2327         } else {
2328             RtlInitUnicodeString(&paramSuffix, NULL);
2329         }
2330 
2331         RtlInitUnicodeString(&paramDevPath, NULL);
2332         // now build the device specific path
2333         paramDevPath.MaximumLength = paramPath.Length + paramSuffix.Length + sizeof(WCHAR);
2334         paramDevPath.Buffer = (PWCH)MyAllocatePool__(PagedPool, paramDevPath.MaximumLength);
2335         if(!paramDevPath.Buffer) {
2336             try_return(val = DefValue);
2337         }
2338 
2339         RtlZeroMemory(paramDevPath.Buffer, paramDevPath.MaximumLength);
2340         status = RtlAppendUnicodeToString(&paramDevPath, paramPath.Buffer);
2341         if(!NT_SUCCESS(status)) {
2342             try_return(val = DefValue);
2343         }
2344         if(paramSuffix.Buffer) {
2345             status = RtlAppendUnicodeToString(&paramDevPath, paramSuffix.Buffer);
2346             if(!NT_SUCCESS(status)) {
2347                 try_return(val = DefValue);
2348             }
2349         }
2350 
2351         UDFPrint(( " Parameter = %ws\n", Name));
2352 
2353         {
2354             HKEY hk = NULL;
2355             status = RegTGetKeyHandle(NULL, RegistryPath->Buffer, &hk);
2356             if(NT_SUCCESS(status)) {
2357                 RegTCloseKeyHandle(hk);
2358             }
2359         }
2360 
2361 
2362         // *** Read GLOBAL_DEFAULTS from
2363         // "\DwUdf\Parameters_Unknown\"
2364 
2365         status = RegTGetDwordValue(NULL, paramPath.Buffer, Name, &val);
2366 
2367         // *** Read DEV_CLASS_SPEC_DEFAULTS (if any) from
2368         // "\DwUdf\Parameters_%DevClass%\"
2369 
2370         if(DefaultPath) {
2371             status = RegTGetDwordValue(NULL, defaultParamPath.Buffer, Name, &val);
2372         }
2373 
2374         // *** Read DEV_SPEC_PARAMS from (if device supports GetDevName)
2375         // "\DwUdf\Parameters\%DevName%\"
2376 
2377         status = RegTGetDwordValue(NULL, paramDevPath.Buffer, Name, &val);
2378 
2379 try_exit:   NOTHING;
2380 
2381     } _SEH2_FINALLY {
2382 
2383         if(DefaultPath && defaultParamPath.Buffer) {
2384             MyFreePool__(defaultParamPath.Buffer);
2385         }
2386         if(paramPath.Buffer) {
2387             MyFreePool__(paramPath.Buffer);
2388         }
2389         if(paramDevPath.Buffer) {
2390             MyFreePool__(paramDevPath.Buffer);
2391         }
2392         if(paramPathUnknown.Buffer) {
2393             MyFreePool__(paramPathUnknown.Buffer);
2394         }
2395     } _SEH2_END;
2396 
2397     UDFPrint(( "UDFCheckRegValue: %ws for drive %s is %x\n\n", Name, PtrVolumePath, val));
2398     return val;
2399 } // end UDFRegCheckParameterValue()
2400 
2401 /*
2402 Routine Description:
2403     This routine is called to initialize an IrpContext for the current
2404     UDFFS request.  The IrpContext is on the stack and we need to initialize
2405     it for the current request.  The request is a close operation.
2406 
2407 Arguments:
2408 
2409     IrpContext - IrpContext to initialize.
2410 
2411     IrpContextLite - source for initialization
2412 
2413 Return Value:
2414 
2415     None
2416 
2417 */
2418 VOID
2419 UDFInitializeIrpContextFromLite(
2420     OUT PtrUDFIrpContext    *IrpContext,
2421     IN PtrUDFIrpContextLite IrpContextLite
2422     )
2423 {
2424     (*IrpContext) = UDFAllocateIrpContext(NULL, IrpContextLite->RealDevice);
2425     //  Zero and then initialize the structure.
2426 
2427     //  Major/Minor Function codes
2428     (*IrpContext)->MajorFunction = IRP_MJ_CLOSE;
2429     (*IrpContext)->Fcb = IrpContextLite->Fcb;
2430     (*IrpContext)->TreeLength = IrpContextLite->TreeLength;
2431     (*IrpContext)->IrpContextFlags |= (IrpContextLite->IrpContextFlags & ~UDF_IRP_CONTEXT_NOT_FROM_ZONE);
2432 
2433     //  Set the wait parameter
2434     UDFSetFlag( (*IrpContext)->IrpContextFlags, UDF_IRP_CONTEXT_CAN_BLOCK );
2435 
2436     return;
2437 } // end UDFInitializeIrpContextFromLite()
2438 
2439 /*
2440 Routine Description:
2441     This routine is called to initialize an IrpContext for the current
2442     UDFFS request.  The IrpContext is on the stack and we need to initialize
2443     it for the current request.  The request is a close operation.
2444 
2445 Arguments:
2446 
2447     IrpContext - IrpContext to initialize.
2448 
2449     IrpContextLite - source for initialization
2450 
2451 Return Value:
2452 
2453     None
2454 
2455 */
2456 NTSTATUS
2457 UDFInitializeIrpContextLite(
2458     OUT PtrUDFIrpContextLite *IrpContextLite,
2459     IN PtrUDFIrpContext    IrpContext,
2460     IN PtrUDFFCB           Fcb
2461     )
2462 {
2463     PtrUDFIrpContextLite LocalIrpContextLite = (PtrUDFIrpContextLite)MyAllocatePool__(NonPagedPool,sizeof(UDFIrpContextLite));
2464     if(!LocalIrpContextLite)
2465         return STATUS_INSUFFICIENT_RESOURCES;
2466     //  Zero and then initialize the structure.
2467     RtlZeroMemory( LocalIrpContextLite, sizeof( UDFIrpContextLite ));
2468 
2469     LocalIrpContextLite->NodeIdentifier.NodeType  = UDF_NODE_TYPE_IRP_CONTEXT_LITE;
2470     LocalIrpContextLite->NodeIdentifier.NodeSize  = sizeof(UDFIrpContextLite);
2471 
2472     LocalIrpContextLite->Fcb = Fcb;
2473     LocalIrpContextLite->TreeLength = IrpContext->TreeLength;
2474     //  Copy RealDevice for workque algorithms.
2475     LocalIrpContextLite->RealDevice = IrpContext->TargetDeviceObject;
2476     LocalIrpContextLite->IrpContextFlags = IrpContext->IrpContextFlags;
2477     *IrpContextLite = LocalIrpContextLite;
2478 
2479     return STATUS_SUCCESS;
2480 } // end UDFInitializeIrpContextLite()
2481 
2482 NTSTATUS
2483 NTAPI
2484 UDFQuerySetEA(
2485     PDEVICE_OBJECT DeviceObject,       // the logical volume device object
2486     PIRP           Irp                 // I/O Request Packet
2487     )
2488 {
2489     NTSTATUS         RC = STATUS_SUCCESS;
2490 //    PtrUDFIrpContext PtrIrpContext = NULL;
2491     BOOLEAN          AreWeTopLevel = FALSE;
2492 
2493     UDFPrint(("UDFQuerySetEA: \n"));
2494 
2495     FsRtlEnterFileSystem();
2496     ASSERT(DeviceObject);
2497     ASSERT(Irp);
2498 
2499     // set the top level context
2500     AreWeTopLevel = UDFIsIrpTopLevel(Irp);
2501 
2502     RC = STATUS_EAS_NOT_SUPPORTED;
2503     Irp->IoStatus.Status = RC;
2504     Irp->IoStatus.Information = 0;
2505     // complete the IRP
2506     IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2507 
2508     if(AreWeTopLevel) {
2509         IoSetTopLevelIrp(NULL);
2510     }
2511 
2512     FsRtlExitFileSystem();
2513 
2514     return(RC);
2515 } // end UDFQuerySetEA()
2516 
2517 ULONG
2518 UDFIsResourceAcquired(
2519     IN PERESOURCE Resource
2520     )
2521 {
2522     ULONG ReAcqRes =
2523         ExIsResourceAcquiredExclusiveLite(Resource) ? 1 :
2524         (ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0);
2525     return ReAcqRes;
2526 } // end UDFIsResourceAcquired()
2527 
2528 BOOLEAN
2529 UDFAcquireResourceExclusiveWithCheck(
2530     IN PERESOURCE Resource
2531     )
2532 {
2533     ULONG ReAcqRes =
2534         ExIsResourceAcquiredExclusiveLite(Resource) ? 1 :
2535         (ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0);
2536     if(ReAcqRes) {
2537         UDFPrint(("UDFAcquireResourceExclusiveWithCheck: ReAcqRes, %x\n", ReAcqRes));
2538     } else {
2539 //        BrutePoint();
2540     }
2541 
2542     if(ReAcqRes == 1) {
2543         // OK
2544     } else
2545     if(ReAcqRes == 2) {
2546         UDFPrint(("UDFAcquireResourceExclusiveWithCheck: !!! Shared !!!\n"));
2547         //BrutePoint();
2548     } else {
2549         UDFAcquireResourceExclusive(Resource, TRUE);
2550         return TRUE;
2551     }
2552     return FALSE;
2553 } // end UDFAcquireResourceExclusiveWithCheck()
2554 
2555 BOOLEAN
2556 UDFAcquireResourceSharedWithCheck(
2557     IN PERESOURCE Resource
2558     )
2559 {
2560     ULONG ReAcqRes =
2561         ExIsResourceAcquiredExclusiveLite(Resource) ? 1 :
2562         (ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0);
2563     if(ReAcqRes) {
2564         UDFPrint(("UDFAcquireResourceSharedWithCheck: ReAcqRes, %x\n", ReAcqRes));
2565 /*    } else {
2566         BrutePoint();*/
2567     }
2568 
2569     if(ReAcqRes == 2) {
2570         // OK
2571     } else
2572     if(ReAcqRes == 1) {
2573         UDFPrint(("UDFAcquireResourceSharedWithCheck: Exclusive\n"));
2574         //BrutePoint();
2575     } else {
2576         UDFAcquireResourceShared(Resource, TRUE);
2577         return TRUE;
2578     }
2579     return FALSE;
2580 } // end UDFAcquireResourceSharedWithCheck()
2581 
2582 NTSTATUS
2583 UDFWCacheErrorHandler(
2584     IN PVOID Context,
2585     IN PWCACHE_ERROR_CONTEXT ErrorInfo
2586     )
2587 {
2588     InterlockedIncrement((PLONG)&(((PVCB)Context)->IoErrorCounter));
2589     return ErrorInfo->Status;
2590 }
2591 
2592 #include "Include/misc_common.cpp"
2593 #include "Include/regtools.cpp"
2594 
2595