1 ////////////////////////////////////////////////////////////////////
2 // Copyright (C) Alexander Telyatnikov, Ivan Keliukh, Yegor Anchishkin, SKIF Software, 1999-2013. Kiev, Ukraine
4 // This file was released under the GPLv2 on June 2015.
5 ////////////////////////////////////////////////////////////////////
10 Module: UDF File System Driver (Kernel mode execution only)
13 This file contains some miscellaneous support routines.
18 // define the file specific bug-check id
19 #define UDF_BUG_CHECK_ID UDF_FILE_MISC
23 //CCHAR DefLetter[] = {""};
27 Function: UDFInitializeZones()
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.
33 Expected Interrupt Level (for execution) :
37 Return Value: STATUS_SUCCESS/Error
41 UDFInitializeZones(VOID
)
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;
53 // initialize the spinlock protecting the zones
54 KeInitializeSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
));
56 // determine memory requirements
57 switch (MmQuerySystemSize()) {
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;
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;
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;
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
;
106 // allocate memory for each of the zones and initialize the zones ...
107 if (!(UDFGlobalData
.ObjectNameZone
= DbgAllocatePool(NonPagedPool
, SizeOfObjectNameZone
))) {
108 RC
= STATUS_INSUFFICIENT_RESOURCES
;
112 if (!(UDFGlobalData
.CCBZone
= DbgAllocatePool(NonPagedPool
, SizeOfCCBZone
))) {
113 RC
= STATUS_INSUFFICIENT_RESOURCES
;
117 if (!(UDFGlobalData
.IrpContextZone
= DbgAllocatePool(NonPagedPool
, SizeOfIrpContextZone
))) {
118 RC
= STATUS_INSUFFICIENT_RESOURCES
;
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 ...
130 if (!NT_SUCCESS(RC
= ExInitializeZone(&(UDFGlobalData
.CCBZoneHeader
),
131 UDFQuadAlign(sizeof(UDFCCB
)),
132 UDFGlobalData
.CCBZone
,
134 // failed the initialization, leave ...
138 if (!NT_SUCCESS(RC
= ExInitializeZone(&(UDFGlobalData
.IrpContextZoneHeader
),
139 UDFQuadAlign(sizeof(UDFIrpContext
)),
140 UDFGlobalData
.IrpContextZone
,
141 SizeOfIrpContextZone
))) {
142 // failed the initialization, leave ...
149 if (!NT_SUCCESS(RC
)) {
150 // invoke the destroy routine now ...
153 // mark the fact that we have allocated zones ...
154 UDFSetFlag(UDFGlobalData
.UDFFlags
, UDF_DATA_FLAGS_ZONES_INITIALIZED
);
162 /*************************************************************************
164 * Function: UDFDestroyZones()
167 * Free up the previously allocated memory. NEVER do this once the
168 * driver has been successfully loaded.
170 * Expected Interrupt Level (for execution) :
176 *************************************************************************/
177 VOID
UDFDestroyZones(VOID
)
182 // free up each of the pools
183 if(UDFGlobalData
.ObjectNameZone
) {
184 DbgFreePool(UDFGlobalData
.ObjectNameZone
);
185 UDFGlobalData
.ObjectNameZone
= NULL
;
187 if(UDFGlobalData
.CCBZone
) {
188 DbgFreePool(UDFGlobalData
.CCBZone
);
189 UDFGlobalData
.CCBZone
= NULL
;
191 if(UDFGlobalData
.IrpContextZone
) {
192 DbgFreePool(UDFGlobalData
.IrpContextZone
);
193 UDFGlobalData
.IrpContextZone
= NULL
;
199 UDFGlobalData
.UDFFlags
&= ~UDF_DATA_FLAGS_ZONES_INITIALIZED
;
206 /*************************************************************************
208 * Function: UDFIsIrpTopLevel()
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.
219 * Expected Interrupt Level (for execution) :
221 * whatever level a particular dispatch routine is invoked at.
223 * Return Value: TRUE/FALSE (TRUE if top level was NULL when routine invoked)
225 *************************************************************************/
229 PIRP Irp
) // the IRP sent to our dispatch routine
231 if(!IoGetTopLevelIrp()) {
232 // OK, so we can set ourselves to become the "top level" component
233 IoSetTopLevelIrp(Irp
);
240 /*************************************************************************
242 * Function: UDFExceptionFilter()
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.
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
257 * Expected Interrupt Level (for execution) :
261 * Return Value: EXCEPTION_EXECUTE_HANDLER/EXECEPTION_CONTINUE_SEARCH
263 *************************************************************************/
266 PtrUDFIrpContext PtrIrpContext
,
267 PEXCEPTION_POINTERS PtrExceptionPointers
270 long ReturnCode
= EXCEPTION_EXECUTE_HANDLER
;
271 NTSTATUS ExceptionCode
= STATUS_SUCCESS
;
272 #if defined UDF_DBG || defined PRINT_ALWAYS
275 KdPrint(("UDFExceptionFilter\n"));
276 KdPrint((" Ex. Code: %x\n",PtrExceptionPointers
->ExceptionRecord
->ExceptionCode
));
277 KdPrint((" Ex. Addr: %x\n",PtrExceptionPointers
->ExceptionRecord
->ExceptionAddress
));
278 KdPrint((" Ex. Flag: %x\n",PtrExceptionPointers
->ExceptionRecord
->ExceptionFlags
));
279 KdPrint((" Ex. Pnum: %x\n",PtrExceptionPointers
->ExceptionRecord
->NumberParameters
));
280 for(i
=0;i
<PtrExceptionPointers
->ExceptionRecord
->NumberParameters
;i
++) {
281 KdPrint((" %x\n",PtrExceptionPointers
->ExceptionRecord
->ExceptionInformation
[i
]));
283 KdPrint(("Exception context:\n"));
284 if(PtrExceptionPointers
->ContextRecord
->ContextFlags
& CONTEXT_INTEGER
) {
285 KdPrint(("EAX=%8.8x ",PtrExceptionPointers
->ContextRecord
->Eax
));
286 KdPrint(("EBX=%8.8x ",PtrExceptionPointers
->ContextRecord
->Ebx
));
287 KdPrint(("ECX=%8.8x ",PtrExceptionPointers
->ContextRecord
->Ecx
));
288 KdPrint(("EDX=%8.8x\n",PtrExceptionPointers
->ContextRecord
->Edx
));
290 KdPrint(("ESI=%8.8x ",PtrExceptionPointers
->ContextRecord
->Esi
));
291 KdPrint(("EDI=%8.8x ",PtrExceptionPointers
->ContextRecord
->Edi
));
293 if(PtrExceptionPointers
->ContextRecord
->ContextFlags
& CONTEXT_CONTROL
) {
294 KdPrint(("EBP=%8.8x ",PtrExceptionPointers
->ContextRecord
->Esp
));
295 KdPrint(("ESP=%8.8x\n",PtrExceptionPointers
->ContextRecord
->Ebp
));
297 KdPrint(("EIP=%8.8x\n",PtrExceptionPointers
->ContextRecord
->Eip
));
299 // KdPrint(("Flags: %s %s ",PtrExceptionPointers->ContextRecord->Eip));
303 // figure out the exception code
304 ExceptionCode
= PtrExceptionPointers
->ExceptionRecord
->ExceptionCode
;
306 if ((ExceptionCode
== STATUS_IN_PAGE_ERROR
) && (PtrExceptionPointers
->ExceptionRecord
->NumberParameters
>= 3)) {
307 ExceptionCode
= PtrExceptionPointers
->ExceptionRecord
->ExceptionInformation
[2];
311 PtrIrpContext
->SavedExceptionCode
= ExceptionCode
;
312 UDFSetFlag(PtrIrpContext
->IrpContextFlags
, UDF_IRP_CONTEXT_EXCEPTION
);
315 // check if we should propagate this exception or not
316 if (!(FsRtlIsNtstatusExpected(ExceptionCode
))) {
318 // better free up the IrpContext now ...
320 KdPrint((" UDF Driver internal error\n"));
323 // we are not ok, propagate this exception.
324 // NOTE: we will bring down the machine ...
325 ReturnCode
= EXCEPTION_CONTINUE_SEARCH
;
330 // return the appropriate code
332 } // end UDFExceptionFilter()
335 /*************************************************************************
337 * Function: UDFExceptionHandler()
340 * One of the routines in the FSD or in the modules we invoked encountered
341 * an exception. We have decided that we will "handle" the exception.
342 * Therefore we will prevent the machine from a panic ...
343 * You can do pretty much anything you choose to in your commercial
344 * driver at this point to ensure a graceful exit. In the UDF
345 * driver, We shall simply free up the IrpContext (if any), set the
346 * error code in the IRP and complete the IRP at this time ...
348 * Expected Interrupt Level (for execution) :
352 * Return Value: Error code
354 *************************************************************************/
357 PtrUDFIrpContext PtrIrpContext
,
362 NTSTATUS ExceptionCode
= STATUS_INSUFFICIENT_RESOURCES
;
363 PDEVICE_OBJECT Device
;
367 KdPrint(("UDFExceptionHandler \n"));
372 KdPrint((" !Irp, return\n"));
373 ASSERT(!PtrIrpContext
);
374 return ExceptionCode
;
376 // If it was a queued close (or something like this) then we need not
377 // completing it because of MUST_SUCCEED requirement.
380 ExceptionCode
= PtrIrpContext
->SavedExceptionCode
;
381 // Free irp context here
382 // UDFReleaseIrpContext(PtrIrpContext);
384 KdPrint((" complete Irp and return\n"));
385 // must be insufficient resources ...?
386 ExceptionCode
= STATUS_INSUFFICIENT_RESOURCES
;
387 Irp
->IoStatus
.Status
= ExceptionCode
;
388 Irp
->IoStatus
.Information
= 0;
390 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
392 return ExceptionCode
;
395 // Check if we are posting this request. One of the following must be true
396 // if we are to post a request.
398 // - Status code is STATUS_CANT_WAIT and the request is asynchronous
399 // or we are forcing this to be posted.
401 // - Status code is STATUS_VERIFY_REQUIRED and we are at APC level
402 // or higher. Can't wait for IO in the verify path in this case.
404 // Set the MORE_PROCESSING flag in the IrpContext to keep if from being
405 // deleted if this is a retryable condition.
407 if (ExceptionCode
== STATUS_VERIFY_REQUIRED
) {
408 if (KeGetCurrentIrql() >= APC_LEVEL
) {
409 KdPrint((" use UDFPostRequest()\n"));
410 ExceptionCode
= UDFPostRequest( PtrIrpContext
, Irp
);
414 // If we posted the request or our caller will retry then just return here.
415 if ((ExceptionCode
== STATUS_PENDING
) ||
416 (ExceptionCode
== STATUS_CANT_WAIT
)) {
418 KdPrint((" STATUS_PENDING/STATUS_CANT_WAIT, return\n"));
419 return ExceptionCode
;
422 // Store this error into the Irp for posting back to the Io system.
423 Irp
->IoStatus
.Status
= ExceptionCode
;
424 if (IoIsErrorUserInduced( ExceptionCode
)) {
426 // Check for the various error conditions that can be caused by,
427 // and possibly resolved my the user.
428 if (ExceptionCode
== STATUS_VERIFY_REQUIRED
) {
430 // Now we are at the top level file system entry point.
432 // If we have already posted this request then the device to
433 // verify is in the original thread. Find this via the Irp.
434 Device
= IoGetDeviceToVerify( Irp
->Tail
.Overlay
.Thread
);
435 IoSetDeviceToVerify( Irp
->Tail
.Overlay
.Thread
, NULL
);
437 // If there is no device in that location then check in the
439 if (Device
== NULL
) {
441 Device
= IoGetDeviceToVerify( PsGetCurrentThread() );
442 IoSetDeviceToVerify( PsGetCurrentThread(), NULL
);
444 ASSERT( Device
!= NULL
);
446 // Let's not BugCheck just because the driver screwed up.
447 if (Device
== NULL
) {
449 KdPrint((" Device == NULL, return\n"));
450 ExceptionCode
= STATUS_DRIVER_INTERNAL_ERROR
;
451 Irp
->IoStatus
.Status
= ExceptionCode
;
452 Irp
->IoStatus
.Information
= 0;
454 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
456 UDFReleaseIrpContext(PtrIrpContext
);
458 return ExceptionCode
;
462 KdPrint((" use UDFPerformVerify()\n"));
463 // UDFPerformVerify() will do the right thing with the Irp.
464 // If we return STATUS_CANT_WAIT then the current thread
465 // can retry the request.
466 return UDFPerformVerify( PtrIrpContext
, Irp
, Device
);
470 // The other user induced conditions generate an error unless
471 // they have been disabled for this request.
474 if (FlagOn( PtrIrpContext
->IrpContextFlags
, UDF_IRP_CONTEXT_FLAG_DISABLE_POPUPS
)) {
476 KdPrint((" DISABLE_POPUPS, complete Irp and return\n"));
477 Irp
->IoStatus
.Status
= ExceptionCode
;
478 Irp
->IoStatus
.Information
= 0;
480 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
482 UDFReleaseIrpContext(PtrIrpContext
);
483 return ExceptionCode
;
487 if (IoGetCurrentIrpStackLocation( Irp
)->FileObject
!= NULL
) {
489 Vpb
= IoGetCurrentIrpStackLocation( Irp
)->FileObject
->Vpb
;
494 // The device to verify is either in my thread local storage
495 // or that of the thread that owns the Irp.
496 Thread
= Irp
->Tail
.Overlay
.Thread
;
497 Device
= IoGetDeviceToVerify( Thread
);
499 if (Device
== NULL
) {
501 Thread
= PsGetCurrentThread();
502 Device
= IoGetDeviceToVerify( Thread
);
503 ASSERT( Device
!= NULL
);
505 // Let's not BugCheck just because the driver screwed up.
506 if (Device
== NULL
) {
507 KdPrint((" Device == NULL, return(2)\n"));
508 Irp
->IoStatus
.Status
= ExceptionCode
;
509 Irp
->IoStatus
.Information
= 0;
511 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
513 UDFReleaseIrpContext(PtrIrpContext
);
515 return ExceptionCode
;
519 // This routine actually causes the pop-up. It usually
520 // does this by queuing an APC to the callers thread,
521 // but in some cases it will complete the request immediately,
522 // so it is very important to IoMarkIrpPending() first.
523 IoMarkIrpPending( Irp
);
524 IoRaiseHardError( Irp
, Vpb
, Device
);
526 // We will be handing control back to the caller here, so
527 // reset the saved device object.
529 KdPrint((" use IoSetDeviceToVerify()\n"));
530 IoSetDeviceToVerify( Thread
, NULL
);
531 // The Irp will be completed by Io or resubmitted. In either
532 // case we must clean up the IrpContext here.
534 UDFReleaseIrpContext(PtrIrpContext
);
535 return STATUS_PENDING
;
539 // If it was a normal request from IOManager then complete it
541 KdPrint((" complete Irp\n"));
542 // set the error code in the IRP
543 Irp
->IoStatus
.Status
= ExceptionCode
;
544 Irp
->IoStatus
.Information
= 0;
547 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
549 UDFReleaseIrpContext(PtrIrpContext
);
552 KdPrint((" return from exception handler with code %x\n", ExceptionCode
));
553 return(ExceptionCode
);
554 } // end UDFExceptionHandler()
556 /*************************************************************************
558 * Function: UDFLogEvent()
561 * Log a message in the NT Event Log. This is a rather simplistic log
562 * methodology since we can potentially utilize the event log to
563 * provide a lot of information to the user (and you should too!)
565 * Expected Interrupt Level (for execution) :
571 *************************************************************************/
574 NTSTATUS UDFEventLogId
, // the UDF private message id
575 NTSTATUS RC
) // any NT error code we wish to log ...
579 // Implement a call to IoAllocateErrorLogEntry() followed by a call
580 // to IoWriteErrorLogEntry(). You should note that the call to IoWriteErrorLogEntry()
581 // will free memory for the entry once the write completes (which in actuality
582 // is an asynchronous operation).
584 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
585 // nothing really we can do here, just do not wish to crash ...
590 } // end UDFLogEvent()
593 /*************************************************************************
595 * Function: UDFAllocateObjectName()
598 * Allocate a new ObjectName structure to represent an open on-disk object.
599 * Also initialize the ObjectName structure to NULL.
601 * Expected Interrupt Level (for execution) :
605 * Return Value: A pointer to the ObjectName structure OR NULL.
607 *************************************************************************/
609 UDFAllocateObjectName(VOID
)
611 PtrUDFObjectName PtrObjectName
= NULL
;
612 BOOLEAN AllocatedFromZone
= TRUE
;
615 // first, __try to allocate out of the zone
616 KeAcquireSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), &CurrentIrql
);
617 if (!ExIsFullZone(&(UDFGlobalData
.ObjectNameZoneHeader
))) {
618 // we have enough memory
619 PtrObjectName
= (PtrUDFObjectName
)ExAllocateFromZone(&(UDFGlobalData
.ObjectNameZoneHeader
));
621 // release the spinlock
622 KeReleaseSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), CurrentIrql
);
624 // release the spinlock
625 KeReleaseSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), CurrentIrql
);
627 // if we failed to obtain from the zone, get it directly from the VMM
628 PtrObjectName
= (PtrUDFObjectName
)MyAllocatePool__(NonPagedPool
, UDFQuadAlign(sizeof(UDFObjectName
)));
629 AllocatedFromZone
= FALSE
;
632 if (!PtrObjectName
) {
636 // zero out the allocated memory block
637 RtlZeroMemory(PtrObjectName
, UDFQuadAlign(sizeof(UDFObjectName
)));
639 // set up some fields ...
640 PtrObjectName
->NodeIdentifier
.NodeType
= UDF_NODE_TYPE_OBJECT_NAME
;
641 PtrObjectName
->NodeIdentifier
.NodeSize
= UDFQuadAlign(sizeof(UDFObjectName
));
644 if (!AllocatedFromZone
) {
645 UDFSetFlag(PtrObjectName
->ObjectNameFlags
, UDF_OBJ_NAME_NOT_FROM_ZONE
);
648 return(PtrObjectName
);
649 } // end UDFAllocateObjectName()
652 /*************************************************************************
654 * Function: UDFReleaseObjectName()
657 * Deallocate a previously allocated structure.
659 * Expected Interrupt Level (for execution) :
665 *************************************************************************/
668 UDFReleaseObjectName(
669 PtrUDFObjectName PtrObjectName
)
673 ASSERT(PtrObjectName
);
675 // give back memory either to the zone or to the VMM
676 if (!(PtrObjectName
->ObjectNameFlags
& UDF_OBJ_NAME_NOT_FROM_ZONE
)) {
678 KeAcquireSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), &CurrentIrql
);
679 ExFreeToZone(&(UDFGlobalData
.ObjectNameZoneHeader
), PtrObjectName
);
680 KeReleaseSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), CurrentIrql
);
682 MyFreePool__(PtrObjectName
);
686 } // end UDFReleaseObjectName()
689 /*************************************************************************
691 * Function: UDFAllocateCCB()
694 * Allocate a new CCB structure to represent an open on-disk object.
695 * Also initialize the CCB structure to NULL.
697 * Expected Interrupt Level (for execution) :
701 * Return Value: A pointer to the CCB structure OR NULL.
703 *************************************************************************/
707 PtrUDFCCB Ccb
= NULL
;
708 BOOLEAN AllocatedFromZone
= TRUE
;
711 // first, __try to allocate out of the zone
712 KeAcquireSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), &CurrentIrql
);
713 if (!ExIsFullZone(&(UDFGlobalData
.CCBZoneHeader
))) {
714 // we have enough memory
715 Ccb
= (PtrUDFCCB
)ExAllocateFromZone(&(UDFGlobalData
.CCBZoneHeader
));
717 // release the spinlock
718 KeReleaseSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), CurrentIrql
);
720 // release the spinlock
721 KeReleaseSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), CurrentIrql
);
723 // if we failed to obtain from the zone, get it directly from the VMM
724 Ccb
= (PtrUDFCCB
)MyAllocatePool__(NonPagedPool
, UDFQuadAlign(sizeof(UDFCCB
)));
725 AllocatedFromZone
= FALSE
;
726 // KdPrint((" CCB allocated @%x\n",Ccb));
733 // zero out the allocated memory block
734 RtlZeroMemory(Ccb
, UDFQuadAlign(sizeof(UDFCCB
)));
736 // set up some fields ...
737 Ccb
->NodeIdentifier
.NodeType
= UDF_NODE_TYPE_CCB
;
738 Ccb
->NodeIdentifier
.NodeSize
= UDFQuadAlign(sizeof(UDFCCB
));
741 if (!AllocatedFromZone
) {
742 UDFSetFlag(Ccb
->CCBFlags
, UDF_CCB_NOT_FROM_ZONE
);
745 KdPrint(("UDFAllocateCCB: %x\n", Ccb
));
747 } // end UDFAllocateCCB()
750 /*************************************************************************
752 * Function: UDFReleaseCCB()
755 * Deallocate a previously allocated structure.
757 * Expected Interrupt Level (for execution) :
763 *************************************************************************/
774 KdPrint(("UDFReleaseCCB: %x\n", Ccb
));
775 // give back memory either to the zone or to the VMM
776 if(!(Ccb
->CCBFlags
& UDF_CCB_NOT_FROM_ZONE
)) {
778 KeAcquireSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), &CurrentIrql
);
779 ExFreeToZone(&(UDFGlobalData
.CCBZoneHeader
), Ccb
);
780 KeReleaseSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), CurrentIrql
);
786 } // end UDFReleaseCCB()
789 Function: UDFCleanupCCB()
792 Cleanup and deallocate a previously allocated structure.
794 Expected Interrupt Level (for execution) :
807 if(!Ccb
) return; // probably, we havn't allocated it...
808 ASSERT(Ccb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_CCB
);
812 UDFTouch(&(Ccb
->Fcb
->CcbListResource
));
813 UDFAcquireResourceExclusive(&(Ccb
->Fcb
->CcbListResource
),TRUE
);
814 RemoveEntryList(&(Ccb
->NextCCB
));
815 UDFReleaseResource(&(Ccb
->Fcb
->CcbListResource
));
820 if (Ccb
->DirectorySearchPattern
) {
821 if (Ccb
->DirectorySearchPattern
->Buffer
) {
822 MyFreePool__(Ccb
->DirectorySearchPattern
->Buffer
);
823 Ccb
->DirectorySearchPattern
->Buffer
= NULL
;
826 MyFreePool__(Ccb
->DirectorySearchPattern
);
827 Ccb
->DirectorySearchPattern
= NULL
;
831 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
834 } // end UDFCleanUpCCB()
836 /*************************************************************************
838 * Function: UDFAllocateFCB()
841 * Allocate a new FCB structure to represent an open on-disk object.
842 * Also initialize the FCB structure to NULL.
844 * Expected Interrupt Level (for execution) :
848 * Return Value: A pointer to the FCB structure OR NULL.
850 *************************************************************************/
854 PtrUDFFCB Fcb
= NULL
;
856 Fcb
= (PtrUDFFCB
)MyAllocatePool__(UDF_FCB_MT
, UDFQuadAlign(sizeof(UDFFCB
)));
862 // zero out the allocated memory block
863 RtlZeroMemory(Fcb
, UDFQuadAlign(sizeof(UDFFCB
)));
865 // set up some fields ...
866 Fcb
->NodeIdentifier
.NodeType
= UDF_NODE_TYPE_FCB
;
867 Fcb
->NodeIdentifier
.NodeSize
= UDFQuadAlign(sizeof(UDFFCB
));
869 KdPrint(("UDFAllocateFCB: %x\n", Fcb
));
871 } // end UDFAllocateFCB()
874 /*************************************************************************
876 * Function: UDFReleaseFCB()
879 * Deallocate a previously allocated structure.
881 * Expected Interrupt Level (for execution) :
887 *************************************************************************/
900 /*************************************************************************
903 *************************************************************************/
910 KdPrint(("UDFCleanUpFCB: %x\n", Fcb
));
913 ASSERT(Fcb
->NodeIdentifier
.NodeType
== UDF_NODE_TYPE_FCB
);
916 // Deinitialize FCBName field
918 if(Fcb
->FCBName
->ObjectName
.Buffer
) {
919 MyFreePool__(Fcb
->FCBName
->ObjectName
.Buffer
);
920 Fcb
->FCBName
->ObjectName
.Buffer
= NULL
;
922 Fcb
->FCBName
->ObjectName
.Length
=
923 Fcb
->FCBName
->ObjectName
.MaximumLength
= 0;
928 KdPrint(("UDF: Fcb has invalid FCBName Buffer\n"));
932 UDFReleaseObjectName(Fcb
->FCBName
);
937 KdPrint(("UDF: Fcb has invalid FCBName field\n"));
943 // begin transaction {
944 UDFTouch(&(Fcb
->Vcb
->FcbListResource
));
945 UDFAcquireResourceExclusive(&(Fcb
->Vcb
->FcbListResource
), TRUE
);
946 // Remove this FCB from list of all FCB in VCB
947 RemoveEntryList(&(Fcb
->NextFCB
));
948 UDFReleaseResource(&(Fcb
->Vcb
->FcbListResource
));
951 if(Fcb
->FCBFlags
& UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE
)
952 UDFDeleteResource(&(Fcb
->CcbListResource
));
956 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
959 } // end UDFCleanUpFCB()
962 ULONG IrpContextCounter
= 0;
965 /*************************************************************************
967 * Function: UDFAllocateIrpContext()
970 * The UDF FSD creates an IRP context for each request received. This
971 * routine simply allocates (and initializes to NULL) a UDFIrpContext
973 * Most of the fields in the context structure are then initialized here.
975 * Expected Interrupt Level (for execution) :
979 * Return Value: A pointer to the IrpContext structure OR NULL.
981 *************************************************************************/
983 UDFAllocateIrpContext(
985 PDEVICE_OBJECT PtrTargetDeviceObject
988 PtrUDFIrpContext PtrIrpContext
= NULL
;
989 BOOLEAN AllocatedFromZone
= TRUE
;
991 PIO_STACK_LOCATION IrpSp
= NULL
;
993 // first, __try to allocate out of the zone
994 KeAcquireSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), &CurrentIrql
);
995 if (!ExIsFullZone(&(UDFGlobalData
.IrpContextZoneHeader
))) {
996 // we have enough memory
997 PtrIrpContext
= (PtrUDFIrpContext
)ExAllocateFromZone(&(UDFGlobalData
.IrpContextZoneHeader
));
999 // release the spinlock
1000 KeReleaseSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), CurrentIrql
);
1002 // release the spinlock
1003 KeReleaseSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), CurrentIrql
);
1005 // if we failed to obtain from the zone, get it directly from the VMM
1006 PtrIrpContext
= (PtrUDFIrpContext
)MyAllocatePool__(NonPagedPool
, UDFQuadAlign(sizeof(UDFIrpContext
)));
1007 AllocatedFromZone
= FALSE
;
1010 // if we could not obtain the required memory, bug-check.
1011 // Do NOT do this in your commercial driver, instead handle the error gracefully ...
1012 if (!PtrIrpContext
) {
1017 IrpContextCounter
++;
1020 // zero out the allocated memory block
1021 RtlZeroMemory(PtrIrpContext
, UDFQuadAlign(sizeof(UDFIrpContext
)));
1023 // set up some fields ...
1024 PtrIrpContext
->NodeIdentifier
.NodeType
= UDF_NODE_TYPE_IRP_CONTEXT
;
1025 PtrIrpContext
->NodeIdentifier
.NodeSize
= UDFQuadAlign(sizeof(UDFIrpContext
));
1028 PtrIrpContext
->Irp
= Irp
;
1029 PtrIrpContext
->TargetDeviceObject
= PtrTargetDeviceObject
;
1031 // copy over some fields from the IRP and set appropriate flag values
1033 IrpSp
= IoGetCurrentIrpStackLocation(Irp
);
1036 PtrIrpContext
->MajorFunction
= IrpSp
->MajorFunction
;
1037 PtrIrpContext
->MinorFunction
= IrpSp
->MinorFunction
;
1039 // Often, a FSD cannot honor a request for asynchronous processing
1040 // of certain critical requests. For example, a "close" request on
1041 // a file object can typically never be deferred. Therefore, do not
1042 // be surprised if sometimes our FSD (just like all other FSD
1043 // implementations on the Windows NT system) has to override the flag
1045 if (IrpSp
->FileObject
== NULL
) {
1046 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_CAN_BLOCK
;
1048 if (IoIsOperationSynchronous(Irp
)) {
1049 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_CAN_BLOCK
;
1054 if (!AllocatedFromZone
) {
1055 UDFSetFlag(PtrIrpContext
->IrpContextFlags
, UDF_IRP_CONTEXT_NOT_FROM_ZONE
);
1058 // Are we top-level ? This information is used by the dispatching code
1059 // later (and also by the FSD dispatch routine)
1060 if (IoGetTopLevelIrp() != Irp
) {
1061 // We are not top-level. Note this fact in the context structure
1062 UDFSetFlag(PtrIrpContext
->IrpContextFlags
, UDF_IRP_CONTEXT_NOT_TOP_LEVEL
);
1065 return(PtrIrpContext
);
1066 } // end UDFAllocateIrpContext()
1069 /*************************************************************************
1071 * Function: UDFReleaseIrpContext()
1074 * Deallocate a previously allocated structure.
1076 * Expected Interrupt Level (for execution) :
1078 * IRQL_PASSIVE_LEVEL
1080 * Return Value: None
1082 *************************************************************************/
1084 UDFReleaseIrpContext(
1085 PtrUDFIrpContext PtrIrpContext
)
1087 if(!PtrIrpContext
) return;
1088 // ASSERT(PtrIrpContext);
1091 IrpContextCounter
--;
1094 // give back memory either to the zone or to the VMM
1095 if (!(PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_NOT_FROM_ZONE
)) {
1099 KeAcquireSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), &CurrentIrql
);
1100 ExFreeToZone(&(UDFGlobalData
.IrpContextZoneHeader
), PtrIrpContext
);
1101 KeReleaseSpinLock(&(UDFGlobalData
.ZoneAllocationSpinLock
), CurrentIrql
);
1103 MyFreePool__(PtrIrpContext
);
1107 } // end UDFReleaseIrpContext()
1110 /*************************************************************************
1112 * Function: UDFPostRequest()
1115 * Queue up a request for deferred processing (in the context of a system
1116 * worker thread). The caller must have locked the user buffer (if required)
1118 * Expected Interrupt Level (for execution) :
1120 * IRQL_PASSIVE_LEVEL
1122 * Return Value: STATUS_PENDING
1124 *************************************************************************/
1127 IN PtrUDFIrpContext PtrIrpContext
,
1132 // PIO_STACK_LOCATION IrpSp;
1135 // IrpSp = IoGetCurrentIrpStackLocation(Irp);
1138 if(Vcb->StopOverflowQueue) {
1140 Irp->IoStatus.Status = STATUS_WRONG_VOLUME;
1141 Irp->IoStatus.Information = 0;
1142 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1144 UDFReleaseIrpContext(PtrIrpContext);
1145 return STATUS_WRONG_VOLUME;
1148 // mark the IRP pending if this is not double post
1150 IoMarkIrpPending(Irp
);
1152 Vcb
= (PVCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
1153 KeAcquireSpinLock(&(Vcb
->OverflowQueueSpinLock
), &SavedIrql
);
1155 if ( Vcb
->PostedRequestCount
> FSP_PER_DEVICE_THRESHOLD
) {
1157 // We cannot currently respond to this IRP so we'll just enqueue it
1158 // to the overflow queue on the volume.
1159 // Note: we just reuse LIST_ITEM field inside WorkQueueItem, this
1160 // doesn't matter to regular processing of WorkItems.
1161 InsertTailList( &(Vcb
->OverflowQueue
),
1162 &(PtrIrpContext
->WorkQueueItem
.List
) );
1163 Vcb
->OverflowQueueCount
++;
1164 KeReleaseSpinLock( &(Vcb
->OverflowQueueSpinLock
), SavedIrql
);
1168 // We are going to send this Irp to an ex worker thread so up
1170 Vcb
->PostedRequestCount
++;
1172 KeReleaseSpinLock( &(Vcb
->OverflowQueueSpinLock
), SavedIrql
);
1174 // queue up the request
1175 ExInitializeWorkItem(&(PtrIrpContext
->WorkQueueItem
), (PWORKER_THREAD_ROUTINE
)UDFCommonDispatch
, PtrIrpContext
);
1177 ExQueueWorkItem(&(PtrIrpContext
->WorkQueueItem
), CriticalWorkQueue
);
1178 // ExQueueWorkItem(&(PtrIrpContext->WorkQueueItem), DelayedWorkQueue);
1182 // return status pending
1183 return STATUS_PENDING
;
1184 } // end UDFPostRequest()
1187 /*************************************************************************
1189 * Function: UDFCommonDispatch()
1192 * The common dispatch routine invoked in the context of a system worker
1193 * thread. All we do here is pretty much case off the major function
1194 * code and invoke the appropriate FSD dispatch routine for further
1197 * Expected Interrupt Level (for execution) :
1199 * IRQL PASSIVE_LEVEL
1201 * Return Value: None
1203 *************************************************************************/
1206 IN PVOID Context
// actually is a pointer to IRPContext structure
1209 NTSTATUS RC
= STATUS_SUCCESS
;
1210 PtrUDFIrpContext PtrIrpContext
= NULL
;
1215 BOOLEAN SpinLock
= FALSE
;
1217 // The context must be a pointer to an IrpContext structure
1218 PtrIrpContext
= (PtrUDFIrpContext
)Context
;
1220 // Assert that the Context is legitimate
1221 if ( !PtrIrpContext
||
1222 (PtrIrpContext
->NodeIdentifier
.NodeType
!= UDF_NODE_TYPE_IRP_CONTEXT
) ||
1223 (PtrIrpContext
->NodeIdentifier
.NodeSize
!= UDFQuadAlign(sizeof(UDFIrpContext
))) /*||
1224 !(PtrIrpContext->Irp)*/) {
1225 KdPrint((" Invalid Context\n"));
1230 Vcb
= (PVCB
)(PtrIrpContext
->TargetDeviceObject
->DeviceExtension
);
1233 KdPrint((" *** Thr: %x ThCnt: %x QCnt: %x Started!\n", PsGetCurrentThread(), Vcb
->PostedRequestCount
, Vcb
->OverflowQueueCount
));
1237 KdPrint((" Next IRP\n"));
1238 FsRtlEnterFileSystem();
1240 // Get a pointer to the IRP structure
1241 // in some cases we can get Zero pointer to Irp
1242 Irp
= PtrIrpContext
->Irp
;
1243 // Now, check if the FSD was top level when the IRP was originally invoked
1244 // and set the thread context (for the worker thread) appropriately
1245 if (PtrIrpContext
->IrpContextFlags
& UDF_IRP_CONTEXT_NOT_TOP_LEVEL
) {
1246 // The FSD is not top level for the original request
1247 // Set a constant value in TLS to reflect this fact
1248 IoSetTopLevelIrp((PIRP
)FSRTL_FSP_TOP_LEVEL_IRP
);
1250 IoSetTopLevelIrp(Irp
);
1253 // Since the FSD routine will now be invoked in the context of this worker
1254 // thread, we should inform the FSD that it is perfectly OK to block in
1255 // the context of this thread
1256 PtrIrpContext
->IrpContextFlags
|= UDF_IRP_CONTEXT_CAN_BLOCK
;
1260 // Pre-processing has been completed; check the Major Function code value
1261 // either in the IrpContext (copied from the IRP), or directly from the
1262 // IRP itself (we will need a pointer to the stack location to do that),
1263 // Then, switch based on the value on the Major Function code
1264 KdPrint((" *** MJ: %x, Thr: %x\n", PtrIrpContext
->MajorFunction
, PsGetCurrentThread()));
1265 switch (PtrIrpContext
->MajorFunction
) {
1267 // Invoke the common create routine
1268 RC
= UDFCommonCreate(PtrIrpContext
, Irp
);
1271 // Invoke the common read routine
1272 RC
= UDFCommonRead(PtrIrpContext
, Irp
);
1274 #ifndef UDF_READ_ONLY_BUILD
1276 // Invoke the common write routine
1277 RC
= UDFCommonWrite(PtrIrpContext
, Irp
);
1279 #endif //UDF_READ_ONLY_BUILD
1280 case IRP_MJ_CLEANUP
:
1281 // Invoke the common cleanup routine
1282 RC
= UDFCommonCleanup(PtrIrpContext
, Irp
);
1285 // Invoke the common close routine
1286 RC
= UDFCommonClose(PtrIrpContext
, Irp
);
1288 case IRP_MJ_DIRECTORY_CONTROL
:
1289 // Invoke the common directory control routine
1290 RC
= UDFCommonDirControl(PtrIrpContext
, Irp
);
1292 case IRP_MJ_QUERY_INFORMATION
:
1293 #ifndef UDF_READ_ONLY_BUILD
1294 case IRP_MJ_SET_INFORMATION
:
1295 #endif //UDF_READ_ONLY_BUILD
1296 // Invoke the common query/set information routine
1297 RC
= UDFCommonFileInfo(PtrIrpContext
, Irp
);
1299 case IRP_MJ_QUERY_VOLUME_INFORMATION
:
1300 // Invoke the common query volume routine
1301 RC
= UDFCommonQueryVolInfo(PtrIrpContext
, Irp
);
1303 #ifndef UDF_READ_ONLY_BUILD
1304 case IRP_MJ_SET_VOLUME_INFORMATION
:
1305 // Invoke the common query volume routine
1306 RC
= UDFCommonSetVolInfo(PtrIrpContext
, Irp
);
1308 #endif //UDF_READ_ONLY_BUILD
1309 #ifdef UDF_HANDLE_EAS
1310 /* case IRP_MJ_QUERY_EA:
1311 // Invoke the common query EAs routine
1312 RC = UDFCommonGetExtendedAttr(PtrIrpContext, Irp);
1315 // Invoke the common set EAs routine
1316 RC = UDFCommonSetExtendedAttr(PtrIrpContext, Irp);
1318 #endif // UDF_HANDLE_EAS
1319 #ifdef UDF_ENABLE_SECURITY
1320 case IRP_MJ_QUERY_SECURITY
:
1321 // Invoke the common query Security routine
1322 RC
= UDFCommonGetSecurity(PtrIrpContext
, Irp
);
1324 #ifndef UDF_READ_ONLY_BUILD
1325 case IRP_MJ_SET_SECURITY
:
1326 // Invoke the common set Security routine
1327 RC
= UDFCommonSetSecurity(PtrIrpContext
, Irp
);
1329 #endif //UDF_READ_ONLY_BUILD
1330 #endif // UDF_ENABLE_SECURITY
1331 // Continue with the remaining possible dispatch routines below ...
1333 KdPrint((" unhandled *** MJ: %x, Thr: %x\n", PtrIrpContext
->MajorFunction
, PsGetCurrentThread()));
1334 // This is the case where we have an invalid major function
1335 Irp
->IoStatus
.Status
= STATUS_INVALID_DEVICE_REQUEST
;
1336 Irp
->IoStatus
.Information
= 0;
1338 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
1339 // Free up the Irp Context
1340 UDFReleaseIrpContext(PtrIrpContext
);
1344 // Note: PtrIrpContext is invalid here
1345 KdPrint((" *** Thr: %x Done!\n", PsGetCurrentThread()));
1347 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext
, _SEH2_GetExceptionInformation())) {
1349 RC
= UDFExceptionHandler(PtrIrpContext
, Irp
);
1351 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR
, RC
);
1354 // Enable preemption
1355 FsRtlExitFileSystem();
1357 // Ensure that the "top-level" field is cleared
1358 IoSetTopLevelIrp(NULL
);
1360 // If there are any entries on this volume's overflow queue, service
1367 KeAcquireSpinLock(&(Vcb
->OverflowQueueSpinLock
), &SavedIrql
);
1369 if(!Vcb
->OverflowQueueCount
)
1372 Vcb
->OverflowQueueCount
--;
1373 Entry
= RemoveHeadList(&Vcb
->OverflowQueue
);
1374 KeReleaseSpinLock(&(Vcb
->OverflowQueueSpinLock
), SavedIrql
);
1377 PtrIrpContext
= CONTAINING_RECORD( Entry
,
1379 WorkQueueItem
.List
);
1383 KeAcquireSpinLock(&(Vcb
->OverflowQueueSpinLock
), &SavedIrql
);
1384 Vcb
->PostedRequestCount
--;
1385 KeReleaseSpinLock(&(Vcb
->OverflowQueueSpinLock
), SavedIrql
);
1387 KdPrint((" *** Thr: %x ThCnt: %x QCnt: %x Terminated!\n", PsGetCurrentThread(), Vcb
->PostedRequestCount
, Vcb
->OverflowQueueCount
));
1390 } // end UDFCommonDispatch()
1393 /*************************************************************************
1395 * Function: UDFInitializeVCB()
1398 * Perform the initialization for a VCB structure.
1400 * Expected Interrupt Level (for execution) :
1402 * IRQL PASSIVE_LEVEL
1404 * Return Value: status
1406 *************************************************************************/
1409 IN PDEVICE_OBJECT PtrVolumeDeviceObject
,
1410 IN PDEVICE_OBJECT PtrTargetDeviceObject
,
1414 NTSTATUS RC
= STATUS_SUCCESS
;
1418 BOOLEAN VCBResourceInit
= FALSE
;
1419 BOOLEAN BitMapResource1Init
= FALSE
;
1420 BOOLEAN FcbListResourceInit
= FALSE
;
1421 BOOLEAN FileIdResourceInit
= FALSE
;
1422 BOOLEAN DlocResourceInit
= FALSE
;
1423 BOOLEAN DlocResource2Init
= FALSE
;
1424 BOOLEAN FlushResourceInit
= FALSE
;
1425 BOOLEAN PreallocResourceInit
= FALSE
;
1426 BOOLEAN IoResourceInit
= FALSE
;
1428 Vcb
= (PVCB
)(PtrVolumeDeviceObject
->DeviceExtension
);
1431 // Zero it out (typically this has already been done by the I/O
1432 // Manager but it does not hurt to do it again)!
1433 RtlZeroMemory(Vcb
, sizeof(VCB
));
1435 // Initialize the signature fields
1436 Vcb
->NodeIdentifier
.NodeType
= UDF_NODE_TYPE_VCB
;
1437 Vcb
->NodeIdentifier
.NodeSize
= sizeof(VCB
);
1439 // Initialize the ERESOURCE object.
1440 RC
= UDFInitializeResourceLite(&(Vcb
->VCBResource
));
1443 VCBResourceInit
= TRUE
;
1445 RC
= UDFInitializeResourceLite(&(Vcb
->BitMapResource1
));
1448 BitMapResource1Init
= TRUE
;
1450 RC
= UDFInitializeResourceLite(&(Vcb
->FcbListResource
));
1453 FcbListResourceInit
= TRUE
;
1455 RC
= UDFInitializeResourceLite(&(Vcb
->FileIdResource
));
1458 FileIdResourceInit
= TRUE
;
1460 RC
= UDFInitializeResourceLite(&(Vcb
->DlocResource
));
1463 DlocResourceInit
= TRUE
;
1465 RC
= UDFInitializeResourceLite(&(Vcb
->DlocResource2
));
1468 DlocResource2Init
= TRUE
;
1470 RC
= UDFInitializeResourceLite(&(Vcb
->FlushResource
));
1473 FlushResourceInit
= TRUE
;
1475 RC
= UDFInitializeResourceLite(&(Vcb
->PreallocResource
));
1478 PreallocResourceInit
= TRUE
;
1480 RC
= UDFInitializeResourceLite(&(Vcb
->IoResource
));
1483 IoResourceInit
= TRUE
;
1485 // RC = UDFInitializeResourceLite(&(Vcb->DelayedCloseResource));
1486 // ASSERT(NT_SUCCESS(RC));
1488 // Allocate buffer for statistics
1489 Vcb
->Statistics
= (PFILE_SYSTEM_STATISTICS
)MyAllocatePool__(NonPagedPool
, sizeof(FILE_SYSTEM_STATISTICS
) * KeNumberProcessors
);
1490 if(!Vcb
->Statistics
)
1491 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
1492 RtlZeroMemory( Vcb
->Statistics
, sizeof(FILE_SYSTEM_STATISTICS
) * KeNumberProcessors
);
1493 for (i
=0; i
< (KeNumberProcessors
); i
++) {
1494 Vcb
->Statistics
[i
].Common
.FileSystemType
= FILESYSTEM_STATISTICS_TYPE_NTFS
;
1495 Vcb
->Statistics
[i
].Common
.Version
= 1;
1496 Vcb
->Statistics
[i
].Common
.SizeOfCompleteStructure
=
1497 sizeof(FILE_SYSTEM_STATISTICS
);
1500 // We know the target device object.
1501 // Note that this is not neccessarily a pointer to the actual
1502 // physical/virtual device on which the logical volume should
1503 // be mounted. This is actually a pointer to either the actual
1504 // (real) device or to any device object that may have been
1505 // attached to it. Any IRPs that we send down should be sent to this
1506 // device object. However, the "real" physical/virtual device object
1507 // on which we perform our mount operation can be determined from the
1508 // RealDevice field in the VPB sent to us.
1509 Vcb
->TargetDeviceObject
= PtrTargetDeviceObject
;
1511 // We also have a pointer to the newly created device object representing
1512 // this logical volume (remember that this VCB structure is simply an
1513 // extension of the created device object).
1514 Vcb
->VCBDeviceObject
= PtrVolumeDeviceObject
;
1516 // We also have the VPB pointer. This was obtained from the
1517 // Parameters.MountVolume.Vpb field in the current I/O stack location
1518 // for the mount IRP.
1520 // Target Vcb field in Vcb onto itself. This required for check in
1521 // open/lock/unlock volume dispatch poits
1524 // Set the removable media flag based on the real device's
1526 if (PtrVPB
->RealDevice
->Characteristics
& FILE_REMOVABLE_MEDIA
) {
1527 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_REMOVABLE_MEDIA
;
1530 // Initialize the list anchor (head) for some lists in this VCB.
1531 InitializeListHead(&(Vcb
->NextFCB
));
1532 InitializeListHead(&(Vcb
->NextNotifyIRP
));
1533 InitializeListHead(&(Vcb
->VolumeOpenListHead
));
1535 // Initialize the overflow queue for the volume
1536 Vcb
->OverflowQueueCount
= 0;
1537 InitializeListHead(&(Vcb
->OverflowQueue
));
1539 Vcb
->PostedRequestCount
= 0;
1540 KeInitializeSpinLock(&(Vcb
->OverflowQueueSpinLock
));
1542 // Initialize the notify IRP list mutex
1543 FsRtlNotifyInitializeSync(&(Vcb
->NotifyIRPMutex
));
1545 // Intilize NtRequiredFCB for this VCB
1546 Vcb
->NTRequiredFCB
= (PtrUDFNTRequiredFCB
)MyAllocatePool__(NonPagedPool
, UDFQuadAlign(sizeof(UDFNTRequiredFCB
)));
1547 if(!Vcb
->NTRequiredFCB
)
1548 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
1549 RtlZeroMemory(Vcb
->NTRequiredFCB
, UDFQuadAlign(sizeof(UDFNTRequiredFCB
)));
1551 // Set the initial file size values appropriately. Note that our FSD may
1552 // wish to guess at the initial amount of information we would like to
1553 // read from the disk until we have really determined that this a valid
1554 // logical volume (on disk) that we wish to mount.
1555 // Vcb->FileSize = Vcb->AllocationSize = ??
1557 // We do not want to bother with valid data length callbacks
1558 // from the Cache Manager for the file stream opened for volume metadata
1560 Vcb
->NTRequiredFCB
->CommonFCBHeader
.ValidDataLength
.QuadPart
= 0x7FFFFFFFFFFFFFFFULL
;
1562 Vcb
->VolumeLockPID
= -1;
1564 Vcb
->VCBOpenCount
= 1;
1566 Vcb
->WCacheMaxBlocks
= UDFGlobalData
.WCacheMaxBlocks
;
1567 Vcb
->WCacheMaxFrames
= UDFGlobalData
.WCacheMaxFrames
;
1568 Vcb
->WCacheBlocksPerFrameSh
= UDFGlobalData
.WCacheBlocksPerFrameSh
;
1569 Vcb
->WCacheFramesToKeepFree
= UDFGlobalData
.WCacheFramesToKeepFree
;
1571 // Create a stream file object for this volume.
1572 //Vcb->PtrStreamFileObject = IoCreateStreamFileObject(NULL,
1573 // Vcb->Vpb->RealDevice);
1574 //ASSERT(Vcb->PtrStreamFileObject);
1576 // Initialize some important fields in the newly created file object.
1577 //Vcb->PtrStreamFileObject->FsContext = (PVOID)Vcb;
1578 //Vcb->PtrStreamFileObject->FsContext2 = NULL;
1579 //Vcb->PtrStreamFileObject->SectionObjectPointer = &(Vcb->SectionObject);
1581 //Vcb->PtrStreamFileObject->Vpb = PtrVPB;
1583 // Link this chap onto the global linked list of all VCB structures.
1584 // We consider that GlobalDataResource was acquired in past
1585 UDFAcquireResourceExclusive(&(UDFGlobalData
.GlobalDataResource
), TRUE
);
1586 InsertTailList(&(UDFGlobalData
.VCBQueue
), &(Vcb
->NextVCB
));
1588 Vcb
->TargetDevName
.Buffer
= (PWCHAR
)MyAllocatePool__(NonPagedPool
, sizeof(MOUNTDEV_NAME
));
1589 if(!Vcb
->TargetDevName
.Buffer
)
1590 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
1592 RC
= UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME
/*IOCTL_MOUNTDEV_QUERY_DEVICE_NAME*/, Vcb
->TargetDeviceObject
,
1594 (PVOID
)(Vcb
->TargetDevName
.Buffer
),sizeof(MOUNTDEV_NAME
),
1596 if(!NT_SUCCESS(RC
)) {
1598 if(RC
== STATUS_BUFFER_OVERFLOW
) {
1599 if(!MyReallocPool__((PCHAR
)(Vcb
->TargetDevName
.Buffer
), sizeof(MOUNTDEV_NAME
),
1600 (PCHAR
*)&(Vcb
->TargetDevName
.Buffer
), Vcb
->TargetDevName
.Buffer
[0]+sizeof(MOUNTDEV_NAME
)) ) {
1601 goto Kill_DevName_buffer
;
1604 RC
= UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME
/*IOCTL_MOUNTDEV_QUERY_DEVICE_NAME*/, Vcb
->TargetDeviceObject
,
1606 (PVOID
)(Vcb
->TargetDevName
.Buffer
), Vcb
->TargetDevName
.Buffer
[0]+sizeof(MOUNTDEV_NAME
),
1609 goto Kill_DevName_buffer
;
1612 Kill_DevName_buffer
:
1613 if(!MyReallocPool__((PCHAR
)Vcb
->TargetDevName
.Buffer
, sizeof(MOUNTDEV_NAME
),
1614 (PCHAR
*)&(Vcb
->TargetDevName
.Buffer
), sizeof(REG_NAMELESS_DEV
)))
1615 try_return(RC
= STATUS_INSUFFICIENT_RESOURCES
);
1616 RtlCopyMemory(Vcb
->TargetDevName
.Buffer
, REG_NAMELESS_DEV
, sizeof(REG_NAMELESS_DEV
));
1617 Vcb
->TargetDevName
.Length
= sizeof(REG_NAMELESS_DEV
)-sizeof(WCHAR
);
1618 Vcb
->TargetDevName
.MaximumLength
= sizeof(REG_NAMELESS_DEV
);
1623 Vcb
->TargetDevName
.MaximumLength
=
1624 (Vcb
->TargetDevName
.Length
= Vcb
->TargetDevName
.Buffer
[0]) + sizeof(WCHAR
);
1625 RtlMoveMemory((PVOID
)(Vcb
->TargetDevName
.Buffer
), (PVOID
)(Vcb
->TargetDevName
.Buffer
+1), Vcb
->TargetDevName
.Buffer
[0]);
1626 Vcb
->TargetDevName
.Buffer
[i
= (SHORT
)(Vcb
->TargetDevName
.Length
/sizeof(WCHAR
))] = 0;
1629 if(Vcb
->TargetDevName
.Buffer
[i
] == L
'\\') {
1631 Vcb
->TargetDevName
.Length
-= i
*sizeof(WCHAR
);
1632 RtlMoveMemory((PVOID
)(Vcb
->TargetDevName
.Buffer
), (PVOID
)(Vcb
->TargetDevName
.Buffer
+i
), Vcb
->TargetDevName
.Length
);
1633 Vcb
->TargetDevName
.Buffer
[Vcb
->TargetDevName
.Length
/sizeof(WCHAR
)] = 0;
1638 KdPrint((" TargetDevName: %S\n", Vcb
->TargetDevName
.Buffer
));
1640 // Initialize caching for the stream file object.
1641 //CcInitializeCacheMap(Vcb->PtrStreamFileObject, (PCC_FILE_SIZES)(&(Vcb->AllocationSize)),
1642 // TRUE, // We will use pinned access.
1643 // &(UDFGlobalData.CacheMgrCallBacks), Vcb);
1647 UDFReleaseResource(&(UDFGlobalData
.GlobalDataResource
));
1649 // Mark the fact that this VCB structure is initialized.
1650 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_VCB_INITIALIZED
;
1652 RC
= STATUS_SUCCESS
;
1658 if(!NT_SUCCESS(RC
)) {
1659 if(Vcb
->TargetDevName
.Buffer
)
1660 MyFreePool__(Vcb
->TargetDevName
.Buffer
);
1661 if(Vcb
->NTRequiredFCB
)
1662 MyFreePool__(Vcb
->NTRequiredFCB
);
1664 MyFreePool__(Vcb
->Statistics
);
1667 UDFDeleteResource(&(Vcb
->VCBResource
));
1668 if(BitMapResource1Init
)
1669 UDFDeleteResource(&(Vcb
->BitMapResource1
));
1670 if(FcbListResourceInit
)
1671 UDFDeleteResource(&(Vcb
->FcbListResource
));
1672 if(FileIdResourceInit
)
1673 UDFDeleteResource(&(Vcb
->FileIdResource
));
1674 if(DlocResourceInit
)
1675 UDFDeleteResource(&(Vcb
->DlocResource
));
1676 if(DlocResource2Init
)
1677 UDFDeleteResource(&(Vcb
->DlocResource2
));
1678 if(FlushResourceInit
)
1679 UDFDeleteResource(&(Vcb
->FlushResource
));
1680 if(PreallocResourceInit
)
1681 UDFDeleteResource(&(Vcb
->PreallocResource
));
1683 UDFDeleteResource(&(Vcb
->IoResource
));
1688 } // end UDFInitializeVCB()
1695 switch(Vcb
->FsDeviceType
) {
1696 case FILE_DEVICE_CD_ROM_FILE_SYSTEM
:
1697 if(Vcb
->VCBFlags
& (UDF_VCB_FLAGS_VOLUME_READ_ONLY
|
1698 UDF_VCB_FLAGS_MEDIA_READ_ONLY
))
1702 if((Vcb
->MediaType
>= MediaType_UnknownSize_CDR
) &&
1703 (Vcb
->MediaType
< MediaType_UnknownSize_CDRW
)) {
1706 if((Vcb
->MediaType
>= MediaType_UnknownSize_CDRW
) &&
1707 (Vcb
->MediaType
< MediaType_UnknownSize_Unknown
)) {
1710 if(Vcb
->MediaClassEx
== CdMediaClass_CDR
) {
1713 if(Vcb
->MediaClassEx
== CdMediaClass_DVDR
||
1714 Vcb
->MediaClassEx
== CdMediaClass_DVDpR
||
1715 Vcb
->MediaClassEx
== CdMediaClass_HD_DVDR
||
1716 Vcb
->MediaClassEx
== CdMediaClass_BDR
) {
1719 if(Vcb
->MediaClassEx
== CdMediaClass_CDRW
) {
1722 if(Vcb
->MediaClassEx
== CdMediaClass_DVDRW
||
1723 Vcb
->MediaClassEx
== CdMediaClass_DVDpRW
||
1724 Vcb
->MediaClassEx
== CdMediaClass_DVDRAM
||
1725 Vcb
->MediaClassEx
== CdMediaClass_HD_DVDRW
||
1726 Vcb
->MediaClassEx
== CdMediaClass_HD_DVDRAM
||
1727 Vcb
->MediaClassEx
== CdMediaClass_BDRE
) {
1731 if(Vcb
->MediaClassEx
== CdMediaClass_CDROM
||
1732 Vcb
->MediaClassEx
== CdMediaClass_DVDROM
||
1733 Vcb
->MediaClassEx
== CdMediaClass_HD_DVDROM
||
1734 Vcb
->MediaClassEx
== CdMediaClass_BDROM
) {
1738 #ifdef UDF_HDD_SUPPORT
1739 case FILE_DEVICE_DISK_FILE_SYSTEM
:
1740 if(Vcb
->TargetDeviceObject
->Characteristics
& FILE_FLOPPY_DISKETTE
)
1742 if(Vcb
->TargetDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
)
1745 #endif //UDF_HDD_SUPPORT
1747 return MediaUnknown
;
1748 } // end UDFGetMediaClass()
1751 (*ptrUDFGetParameter
)(
1758 UDFUpdateCompatOption(
1767 ptrUDFGetParameter UDFGetParameter
= UseCfg
? UDFGetCfgParameter
: UDFGetRegParameter
;
1769 if(UDFGetParameter(Vcb
, Name
, Update
? ((Vcb
->CompatFlags
& Flag
) ? TRUE
: FALSE
) : Default
)) {
1770 Vcb
->CompatFlags
|= Flag
;
1772 Vcb
->CompatFlags
&= ~Flag
;
1774 } // end UDFUpdateCompatOption()
1784 ptrUDFGetParameter UDFGetParameter
= UseCfg
? UDFGetCfgParameter
: UDFGetRegParameter
;
1786 Vcb
->DefaultRegName
= UDFMediaClassName
[(ULONG
)UDFGetMediaClass(Vcb
)].ClassName
;
1788 // Should we use Extended FE by default ?
1789 Vcb
->UseExtendedFE
= (UCHAR
)UDFGetParameter(Vcb
, REG_USEEXTENDEDFE_NAME
,
1790 Update
? Vcb
->UseExtendedFE
: FALSE
);
1791 if(Vcb
->UseExtendedFE
!= TRUE
) Vcb
->UseExtendedFE
= FALSE
;
1792 // What type of AllocDescs should we use
1793 Vcb
->DefaultAllocMode
= (USHORT
)UDFGetParameter(Vcb
, REG_DEFALLOCMODE_NAME
,
1794 Update
? Vcb
->DefaultAllocMode
: ICB_FLAG_AD_SHORT
);
1795 if(Vcb
->DefaultAllocMode
> ICB_FLAG_AD_LONG
) Vcb
->DefaultAllocMode
= ICB_FLAG_AD_SHORT
;
1796 // Default UID & GID to be set on newly created files
1797 Vcb
->DefaultUID
= UDFGetParameter(Vcb
, UDF_DEFAULT_UID_NAME
, Update
? Vcb
->DefaultUID
: -1);
1798 Vcb
->DefaultGID
= UDFGetParameter(Vcb
, UDF_DEFAULT_GID_NAME
, Update
? Vcb
->DefaultGID
: -1);
1799 // FE allocation charge for plain Dirs
1800 Vcb
->FECharge
= UDFGetParameter(Vcb
, UDF_FE_CHARGE_NAME
, Update
? Vcb
->FECharge
: 0);
1802 Vcb
->FECharge
= UDF_DEFAULT_FE_CHARGE
;
1803 // FE allocation charge for Stream Dirs (SDir)
1804 Vcb
->FEChargeSDir
= UDFGetParameter(Vcb
, UDF_FE_CHARGE_SDIR_NAME
,
1805 Update
? Vcb
->FEChargeSDir
: 0);
1806 if(!Vcb
->FEChargeSDir
)
1807 Vcb
->FEChargeSDir
= UDF_DEFAULT_FE_CHARGE_SDIR
;
1808 // How many Deleted entries should contain Directory to make us
1809 // start packing it.
1810 Vcb
->PackDirThreshold
= UDFGetParameter(Vcb
, UDF_DIR_PACK_THRESHOLD_NAME
,
1811 Update
? Vcb
->PackDirThreshold
: 0);
1812 if(Vcb
->PackDirThreshold
== 0xffffffff)
1813 Vcb
->PackDirThreshold
= UDF_DEFAULT_DIR_PACK_THRESHOLD
;
1814 // The binary exponent for the number of Pages to be read-ahead'ed
1815 // This information would be sent to System Cache Manager
1817 Vcb
->SystemCacheGran
= (1 << UDFGetParameter(Vcb
, UDF_READAHEAD_GRAN_NAME
, 0)) * PAGE_SIZE
;
1818 if(!Vcb
->SystemCacheGran
)
1819 Vcb
->SystemCacheGran
= UDF_DEFAULT_READAHEAD_GRAN
;
1821 // Timeouts for FreeSpaceBitMap & TheWholeDirTree flushes
1822 Vcb
->BM_FlushPriod
= UDFGetParameter(Vcb
, UDF_BM_FLUSH_PERIOD_NAME
,
1823 Update
? Vcb
->BM_FlushPriod
: 0);
1824 if(!Vcb
->BM_FlushPriod
) {
1825 Vcb
->BM_FlushPriod
= UDF_DEFAULT_BM_FLUSH_TIMEOUT
;
1827 if(Vcb
->BM_FlushPriod
== (ULONG
)-1) {
1828 Vcb
->BM_FlushPriod
= 0;
1830 Vcb
->Tree_FlushPriod
= UDFGetParameter(Vcb
, UDF_TREE_FLUSH_PERIOD_NAME
,
1831 Update
? Vcb
->Tree_FlushPriod
: 0);
1832 if(!Vcb
->Tree_FlushPriod
) {
1833 Vcb
->Tree_FlushPriod
= UDF_DEFAULT_TREE_FLUSH_TIMEOUT
;
1835 if(Vcb
->Tree_FlushPriod
== (ULONG
)-1) {
1836 Vcb
->Tree_FlushPriod
= 0;
1838 Vcb
->SkipCountLimit
= UDFGetParameter(Vcb
, UDF_NO_UPDATE_PERIOD_NAME
,
1839 Update
? Vcb
->SkipCountLimit
: 0);
1840 if(!Vcb
->SkipCountLimit
)
1841 Vcb
->SkipCountLimit
= -1;
1843 Vcb
->SkipEjectCountLimit
= UDFGetParameter(Vcb
, UDF_NO_EJECT_PERIOD_NAME
,
1844 Update
? Vcb
->SkipEjectCountLimit
: 3);
1847 // How many threads are allowed to sodomize Disc simultaneously on each CPU
1848 Vcb
->ThreadsPerCpu
= UDFGetParameter(Vcb
, UDF_FSP_THREAD_PER_CPU_NAME
,
1849 Update
? Vcb
->ThreadsPerCpu
: 2);
1850 if(Vcb
->ThreadsPerCpu
< 2)
1851 Vcb
->ThreadsPerCpu
= UDF_DEFAULT_FSP_THREAD_PER_CPU
;
1853 // The mimimum FileSize increment when we'll decide not to allocate
1855 Vcb
->SparseThreshold
= UDFGetParameter(Vcb
, UDF_SPARSE_THRESHOLD_NAME
,
1856 Update
? Vcb
->SparseThreshold
: 0);
1857 if(!Vcb
->SparseThreshold
)
1858 Vcb
->SparseThreshold
= UDF_DEFAULT_SPARSE_THRESHOLD
;
1859 // This option is used to VERIFY all the data written. It decreases performance
1860 Vcb
->VerifyOnWrite
= UDFGetParameter(Vcb
, UDF_VERIFY_ON_WRITE_NAME
,
1861 Update
? Vcb
->VerifyOnWrite
: FALSE
) ? TRUE
: FALSE
;
1863 #ifndef UDF_READ_ONLY_BUILD
1864 // Should we update AttrFileTime on Attr changes
1865 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_UPDATE_TIMES_ATTR
, UDF_VCB_IC_UPDATE_ATTR_TIME
, FALSE
);
1866 // Should we update ModifyFileTime on Writes changes
1867 // It also affects ARCHIVE bit setting on write operations
1868 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_UPDATE_TIMES_MOD
, UDF_VCB_IC_UPDATE_MODIFY_TIME
, FALSE
);
1869 // Should we update AccessFileTime on Exec & so on.
1870 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_UPDATE_TIMES_ACCS
, UDF_VCB_IC_UPDATE_ACCESS_TIME
, FALSE
);
1871 // Should we update Archive bit
1872 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_UPDATE_ATTR_ARCH
, UDF_VCB_IC_UPDATE_ARCH_BIT
, FALSE
);
1873 // Should we update Dir's Times & Attrs on Modify
1874 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_UPDATE_DIR_TIMES_ATTR_W
, UDF_VCB_IC_UPDATE_DIR_WRITE
, FALSE
);
1875 // Should we update Dir's Times & Attrs on Access
1876 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_UPDATE_DIR_TIMES_ATTR_R
, UDF_VCB_IC_UPDATE_DIR_READ
, FALSE
);
1877 // Should we allow user to write into Read-Only Directory
1878 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_ALLOW_WRITE_IN_RO_DIR
, UDF_VCB_IC_WRITE_IN_RO_DIR
, TRUE
);
1879 // Should we allow user to change Access Time for unchanged Directory
1880 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_ALLOW_UPDATE_TIMES_ACCS_UCHG_DIR
, UDF_VCB_IC_UPDATE_UCHG_DIR_ACCESS_TIME
, FALSE
);
1881 #endif //UDF_READ_ONLY_BUILD
1882 // Should we record Allocation Descriptors in W2k-compatible form
1883 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_W2K_COMPAT_ALLOC_DESCS
, UDF_VCB_IC_W2K_COMPAT_ALLOC_DESCS
, TRUE
);
1884 // Should we read LONG_ADs with invalid PartitionReferenceNumber (generated by Nero Instant Burner)
1885 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_INSTANT_COMPAT_ALLOC_DESCS
, UDF_VCB_IC_INSTANT_COMPAT_ALLOC_DESCS
, TRUE
);
1886 // Should we make a copy of VolumeLabel in LVD
1887 // usually only PVD is updated
1888 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_W2K_COMPAT_VLABEL
, UDF_VCB_IC_W2K_COMPAT_VLABEL
, TRUE
);
1889 // Should we handle or ignore HW_RO flag
1890 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_HANDLE_HW_RO
, UDF_VCB_IC_HW_RO
, FALSE
);
1891 // Should we handle or ignore SOFT_RO flag
1892 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_HANDLE_SOFT_RO
, UDF_VCB_IC_SOFT_RO
, TRUE
);
1894 // Check if we should generate UDF-style or OS-style DOS-names
1895 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_OS_NATIVE_DOS_NAME
, UDF_VCB_IC_OS_NATIVE_DOS_NAME
, FALSE
);
1896 #ifndef UDF_READ_ONLY_BUILD
1897 // should we force FO_WRITE_THROUGH on removable media
1898 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_FORCE_WRITE_THROUGH_NAME
, UDF_VCB_IC_FORCE_WRITE_THROUGH
,
1899 (Vcb
->TargetDeviceObject
->Characteristics
& FILE_REMOVABLE_MEDIA
) ? TRUE
: FALSE
1901 #endif //UDF_READ_ONLY_BUILD
1902 // Should we ignore FO_SEQUENTIAL_ONLY
1903 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_IGNORE_SEQUENTIAL_IO
, UDF_VCB_IC_IGNORE_SEQUENTIAL_IO
, FALSE
);
1904 // Force Read-only mounts
1905 #ifndef UDF_READ_ONLY_BUILD
1906 UDFUpdateCompatOption(Vcb
, Update
, UseCfg
, UDF_FORCE_HW_RO
, UDF_VCB_IC_FORCE_HW_RO
, FALSE
);
1907 #else //UDF_READ_ONLY_BUILD
1908 Vcb
->CompatFlags
|= UDF_VCB_IC_FORCE_HW_RO
;
1909 #endif //UDF_READ_ONLY_BUILD
1910 // Check if we should send FLUSH request for File/Dir down to
1911 // underlaying driver
1912 if(UDFGetParameter(Vcb
, UDF_FLUSH_MEDIA
,Update
? Vcb
->FlushMedia
: FALSE
)) {
1913 Vcb
->FlushMedia
= TRUE
;
1915 Vcb
->FlushMedia
= FALSE
;
1917 // compare data from packet with data to be writen there
1918 // before physical writing
1919 if(!UDFGetParameter(Vcb
, UDF_COMPARE_BEFORE_WRITE
, Update
? Vcb
->DoNotCompareBeforeWrite
: FALSE
)) {
1920 Vcb
->DoNotCompareBeforeWrite
= TRUE
;
1922 Vcb
->DoNotCompareBeforeWrite
= FALSE
;
1925 if(UDFGetParameter(Vcb
, UDF_CHAINED_IO
, TRUE
)) {
1926 Vcb
->CacheChainedIo
= TRUE
;
1929 if(UDFGetParameter(Vcb
, UDF_FORCE_MOUNT_ALL
, FALSE
)) {
1930 Vcb
->VCBFlags
|= UDF_VCB_FLAGS_RAW_DISK
;
1932 // Should we show Blank.Cd file on damaged/unformatted,
1933 // but UDF-compatible disks
1934 Vcb
->ShowBlankCd
= (UCHAR
)UDFGetParameter(Vcb
, UDF_SHOW_BLANK_CD
, FALSE
);
1935 if(Vcb
->ShowBlankCd
) {
1936 Vcb
->CompatFlags
|= UDF_VCB_IC_SHOW_BLANK_CD
;
1937 if(Vcb
->ShowBlankCd
> 2) {
1938 Vcb
->ShowBlankCd
= 2;
1941 // Should we wait util CD device return from
1942 // Becoming Ready state
1943 if(UDFGetParameter(Vcb
, UDF_WAIT_CD_SPINUP
, TRUE
)) {
1944 Vcb
->CompatFlags
|= UDF_VCB_IC_WAIT_CD_SPINUP
;
1946 // Should we remenber bad VDS locations during mount
1947 // Caching will improve mount performance on bad disks, but
1948 // will degrade mauntability of unreliable discs
1949 if(UDFGetParameter(Vcb
, UDF_CACHE_BAD_VDS
, TRUE
)) {
1950 Vcb
->CompatFlags
|= UDF_VCB_IC_CACHE_BAD_VDS
;
1953 // Set partitially damaged volume mount mode
1954 Vcb
->PartitialDamagedVolumeAction
= (UCHAR
)UDFGetParameter(Vcb
, UDF_PART_DAMAGED_BEHAVIOR
, UDF_PART_DAMAGED_RW
);
1955 if(Vcb
->PartitialDamagedVolumeAction
> 2) {
1956 Vcb
->PartitialDamagedVolumeAction
= UDF_PART_DAMAGED_RW
;
1959 // Set partitially damaged volume mount mode
1960 Vcb
->NoFreeRelocationSpaceVolumeAction
= (UCHAR
)UDFGetParameter(Vcb
, UDF_NO_SPARE_BEHAVIOR
, UDF_PART_DAMAGED_RW
);
1961 if(Vcb
->NoFreeRelocationSpaceVolumeAction
> 1) {
1962 Vcb
->NoFreeRelocationSpaceVolumeAction
= UDF_PART_DAMAGED_RW
;
1965 // Set dirty volume mount mode
1966 if(UDFGetParameter(Vcb
, UDF_DIRTY_VOLUME_BEHAVIOR
, UDF_PART_DAMAGED_RO
)) {
1967 Vcb
->CompatFlags
|= UDF_VCB_IC_DIRTY_RO
;
1970 mult
= UDFGetParameter(Vcb
, UDF_CACHE_SIZE_MULTIPLIER
, 1);
1972 Vcb
->WCacheMaxBlocks
*= mult
;
1973 Vcb
->WCacheMaxFrames
*= mult
;
1975 if(UDFGetParameter(Vcb
, UDF_USE_EJECT_BUTTON
, TRUE
)) {
1976 Vcb
->UseEvent
= TRUE
;
1980 } // end UDFReadRegKeys()
1989 return UDFRegCheckParameterValue(&(UDFGlobalData
.SavedRegPath
),
1991 Vcb
? &(Vcb
->TargetDevName
) : NULL
,
1992 Vcb
? Vcb
->DefaultRegName
: NULL
,
1994 } // end UDFGetRegParameter()
2007 BOOLEAN wait_name
=TRUE
;
2008 BOOLEAN wait_val
=FALSE
;
2009 BOOLEAN wait_nl
=FALSE
;
2013 PUCHAR Cfg
= Vcb
->Cfg
;
2014 ULONG Length
= Vcb
->CfgLength
;
2020 if(len
>= sizeof(NameA
))
2022 sprintf(NameA
, "%S", Name
);
2024 for(i
=0; i
<Length
; i
++) {
2035 case '[': // ignore sections for now, treat as comment
2052 if(i
+len
+2 > Length
)
2054 if(RtlCompareMemory(Cfg
+i
, NameA
, len
) == len
) {
2085 if(a
=='0' && Cfg
[i
+1]=='x') {
2107 if(a
>= '0' && a
<= '9') {
2112 if(a
>= 'a' && a
<= 'f') {
2115 if(a
>= 'A' && a
<= 'F') {
2122 ret_val
= ret_val
*radix
+ a
;
2131 } // end UDFGetCfgParameter()
2138 LARGE_INTEGER delay
;
2139 KdPrint(("UDFReleaseVCB\n"));
2141 delay
.QuadPart
= -500000; // 0.05 sec
2142 while(Vcb
->PostedRequestCount
) {
2143 KdPrint(("UDFReleaseVCB: PostedRequestCount = %d\n", Vcb
->PostedRequestCount
));
2144 // spin until all queues IRPs are processed
2145 KeDelayExecutionThread(KernelMode
, FALSE
, &delay
);
2146 delay
.QuadPart
-= 500000; // grow delay 0.05 sec
2150 KdPrint(("UDF: Flushing buffers\n"));
2152 WCacheFlushAll__(&(Vcb
->FastCache
),Vcb
);
2153 WCacheRelease__(&(Vcb
->FastCache
));
2155 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
2161 if (!ExIsResourceAcquiredShared(&UDFGlobalData
.GlobalDataResource
)) {
2162 KdPrint(("UDF: attempt to access to not protected data\n"));
2163 KdPrint(("UDF: UDFGlobalData\n"));
2166 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
2172 RemoveEntryList(&(Vcb
->NextVCB
));
2173 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
2178 if(Vcb->VCBFlags & UDF_VCB_FLAGS_STOP_WAITER_EVENT)
2179 KeWaitForSingleObject(&(Vcb->WaiterStopped), Executive, KernelMode, FALSE, NULL);
2180 Vcb->VCBFlags &= ~UDF_VCB_FLAGS_STOP_WAITER_EVENT;
2181 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2186 KdPrint(("UDF: Delete resources\n"));
2187 UDFDeleteResource(&(Vcb
->VCBResource
));
2188 UDFDeleteResource(&(Vcb
->BitMapResource1
));
2189 UDFDeleteResource(&(Vcb
->FcbListResource
));
2190 UDFDeleteResource(&(Vcb
->FileIdResource
));
2191 UDFDeleteResource(&(Vcb
->DlocResource
));
2192 UDFDeleteResource(&(Vcb
->DlocResource2
));
2193 UDFDeleteResource(&(Vcb
->FlushResource
));
2194 UDFDeleteResource(&(Vcb
->PreallocResource
));
2195 UDFDeleteResource(&(Vcb
->IoResource
));
2196 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
2201 KdPrint(("UDF: Cleanup VCB\n"));
2202 ASSERT(IsListEmpty(&(Vcb
->NextNotifyIRP
)));
2203 FsRtlNotifyUninitializeSync(&(Vcb
->NotifyIRPMutex
));
2205 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
2210 KdPrint(("UDF: Delete DO\n"));
2211 IoDeleteDevice(Vcb
->VCBDeviceObject
);
2212 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
) {
2216 } // end UDFReleaseVCB()
2219 Read DWORD from Registry
2222 UDFRegCheckParameterValue(
2223 IN PUNICODE_STRING RegistryPath
,
2225 IN PUNICODE_STRING PtrVolumePath
,
2226 IN PCWSTR DefaultPath
,
2232 ULONG val
= DefValue
;
2234 UNICODE_STRING paramStr
;
2235 UNICODE_STRING defaultParamStr
;
2236 UNICODE_STRING paramPathUnknownStr
;
2238 UNICODE_STRING paramSuffix
;
2239 UNICODE_STRING paramPath
;
2240 UNICODE_STRING paramPathUnknown
;
2241 UNICODE_STRING paramDevPath
;
2242 UNICODE_STRING defaultParamPath
;
2246 paramPath
.Buffer
= NULL
;
2247 paramDevPath
.Buffer
= NULL
;
2248 paramPathUnknown
.Buffer
= NULL
;
2249 defaultParamPath
.Buffer
= NULL
;
2251 // First append \Parameters to the passed in registry path
2252 // Note, RtlInitUnicodeString doesn't allocate memory
2253 RtlInitUnicodeString(¶mStr
, L
"\\Parameters");
2254 RtlInitUnicodeString(¶mPath
, NULL
);
2256 RtlInitUnicodeString(¶mPathUnknownStr
, REG_DEFAULT_UNKNOWN
);
2257 RtlInitUnicodeString(¶mPathUnknown
, NULL
);
2259 paramPathUnknown
.MaximumLength
= RegistryPath
->Length
+ paramPathUnknownStr
.Length
+ paramStr
.Length
+ sizeof(WCHAR
);
2260 paramPath
.MaximumLength
= RegistryPath
->Length
+ paramStr
.Length
+ sizeof(WCHAR
);
2262 paramPath
.Buffer
= (PWCH
)MyAllocatePool__(PagedPool
, paramPath
.MaximumLength
);
2263 if(!paramPath
.Buffer
) {
2264 KdPrint(("UDFCheckRegValue: couldn't allocate paramPath\n"));
2265 try_return(val
= DefValue
);
2267 paramPathUnknown
.Buffer
= (PWCH
)MyAllocatePool__(PagedPool
, paramPathUnknown
.MaximumLength
);
2268 if(!paramPathUnknown
.Buffer
) {
2269 KdPrint(("UDFCheckRegValue: couldn't allocate paramPathUnknown\n"));
2270 try_return(val
= DefValue
);
2273 RtlZeroMemory(paramPath
.Buffer
, paramPath
.MaximumLength
);
2274 status
= RtlAppendUnicodeToString(¶mPath
, RegistryPath
->Buffer
);
2275 if(!NT_SUCCESS(status
)) {
2276 try_return(val
= DefValue
);
2278 status
= RtlAppendUnicodeToString(¶mPath
, paramStr
.Buffer
);
2279 if(!NT_SUCCESS(status
)) {
2280 try_return(val
= DefValue
);
2282 KdPrint(("UDFCheckRegValue: (1) |%S|\n", paramPath
.Buffer
));
2284 RtlZeroMemory(paramPathUnknown
.Buffer
, paramPathUnknown
.MaximumLength
);
2285 status
= RtlAppendUnicodeToString(¶mPathUnknown
, RegistryPath
->Buffer
);
2286 if(!NT_SUCCESS(status
)) {
2287 try_return(val
= DefValue
);
2289 status
= RtlAppendUnicodeToString(¶mPathUnknown
, paramStr
.Buffer
);
2290 if(!NT_SUCCESS(status
)) {
2291 try_return(val
= DefValue
);
2293 status
= RtlAppendUnicodeToString(¶mPathUnknown
, paramPathUnknownStr
.Buffer
);
2294 if(!NT_SUCCESS(status
)) {
2295 try_return(val
= DefValue
);
2297 KdPrint(("UDFCheckRegValue: (2) |%S|\n", paramPathUnknown
.Buffer
));
2299 // First append \Parameters\Default_XXX to the passed in registry path
2301 RtlInitUnicodeString(&defaultParamStr
, DefaultPath
);
2302 RtlInitUnicodeString(&defaultParamPath
, NULL
);
2303 defaultParamPath
.MaximumLength
= paramPath
.Length
+ defaultParamStr
.Length
+ sizeof(WCHAR
);
2304 defaultParamPath
.Buffer
= (PWCH
)MyAllocatePool__(PagedPool
, defaultParamPath
.MaximumLength
);
2305 if(!defaultParamPath
.Buffer
) {
2306 KdPrint(("UDFCheckRegValue: couldn't allocate defaultParamPath\n"));
2307 try_return(val
= DefValue
);
2310 RtlZeroMemory(defaultParamPath
.Buffer
, defaultParamPath
.MaximumLength
);
2311 status
= RtlAppendUnicodeToString(&defaultParamPath
, paramPath
.Buffer
);
2312 if(!NT_SUCCESS(status
)) {
2313 try_return(val
= DefValue
);
2315 status
= RtlAppendUnicodeToString(&defaultParamPath
, defaultParamStr
.Buffer
);
2316 if(!NT_SUCCESS(status
)) {
2317 try_return(val
= DefValue
);
2319 KdPrint(("UDFCheckRegValue: (3) |%S|\n", defaultParamPath
.Buffer
));
2323 paramSuffix
= *PtrVolumePath
;
2325 RtlInitUnicodeString(¶mSuffix
, NULL
);
2328 RtlInitUnicodeString(¶mDevPath
, NULL
);
2329 // now build the device specific path
2330 paramDevPath
.MaximumLength
= paramPath
.Length
+ paramSuffix
.Length
+ sizeof(WCHAR
);
2331 paramDevPath
.Buffer
= (PWCH
)MyAllocatePool__(PagedPool
, paramDevPath
.MaximumLength
);
2332 if(!paramDevPath
.Buffer
) {
2333 try_return(val
= DefValue
);
2336 RtlZeroMemory(paramDevPath
.Buffer
, paramDevPath
.MaximumLength
);
2337 status
= RtlAppendUnicodeToString(¶mDevPath
, paramPath
.Buffer
);
2338 if(!NT_SUCCESS(status
)) {
2339 try_return(val
= DefValue
);
2341 if(paramSuffix
.Buffer
) {
2342 status
= RtlAppendUnicodeToString(¶mDevPath
, paramSuffix
.Buffer
);
2343 if(!NT_SUCCESS(status
)) {
2344 try_return(val
= DefValue
);
2348 KdPrint(( " Parameter = %ws\n", Name
));
2352 status
= RegTGetKeyHandle(NULL
, RegistryPath
->Buffer
, &hk
);
2353 if(NT_SUCCESS(status
)) {
2354 RegTCloseKeyHandle(hk
);
2359 // *** Read GLOBAL_DEFAULTS from
2360 // "\DwUdf\Parameters_Unknown\"
2362 status
= RegTGetDwordValue(NULL
, paramPath
.Buffer
, Name
, &val
);
2364 // *** Read DEV_CLASS_SPEC_DEFAULTS (if any) from
2365 // "\DwUdf\Parameters_%DevClass%\"
2368 status
= RegTGetDwordValue(NULL
, defaultParamPath
.Buffer
, Name
, &val
);
2371 // *** Read DEV_SPEC_PARAMS from (if device supports GetDevName)
2372 // "\DwUdf\Parameters\%DevName%\"
2374 status
= RegTGetDwordValue(NULL
, paramDevPath
.Buffer
, Name
, &val
);
2380 if(DefaultPath
&& defaultParamPath
.Buffer
) {
2381 MyFreePool__(defaultParamPath
.Buffer
);
2383 if(paramPath
.Buffer
) {
2384 MyFreePool__(paramPath
.Buffer
);
2386 if(paramDevPath
.Buffer
) {
2387 MyFreePool__(paramDevPath
.Buffer
);
2389 if(paramPathUnknown
.Buffer
) {
2390 MyFreePool__(paramPathUnknown
.Buffer
);
2394 KdPrint(( "UDFCheckRegValue: %ws for drive %s is %x\n\n", Name
, PtrVolumePath
, val
));
2396 } // end UDFRegCheckParameterValue()
2399 Routine Description:
2400 This routine is called to initialize an IrpContext for the current
2401 UDFFS request. The IrpContext is on the stack and we need to initialize
2402 it for the current request. The request is a close operation.
2406 IrpContext - IrpContext to initialize.
2408 IrpContextLite - source for initialization
2416 UDFInitializeIrpContextFromLite(
2417 OUT PtrUDFIrpContext
*IrpContext
,
2418 IN PtrUDFIrpContextLite IrpContextLite
2421 (*IrpContext
) = UDFAllocateIrpContext(NULL
, IrpContextLite
->RealDevice
);
2422 // Zero and then initialize the structure.
2424 // Major/Minor Function codes
2425 (*IrpContext
)->MajorFunction
= IRP_MJ_CLOSE
;
2426 (*IrpContext
)->Fcb
= IrpContextLite
->Fcb
;
2427 (*IrpContext
)->TreeLength
= IrpContextLite
->TreeLength
;
2428 (*IrpContext
)->IrpContextFlags
|= (IrpContextLite
->IrpContextFlags
& ~UDF_IRP_CONTEXT_NOT_FROM_ZONE
);
2430 // Set the wait parameter
2431 UDFSetFlag( (*IrpContext
)->IrpContextFlags
, UDF_IRP_CONTEXT_CAN_BLOCK
);
2434 } // end UDFInitializeIrpContextFromLite()
2437 Routine Description:
2438 This routine is called to initialize an IrpContext for the current
2439 UDFFS request. The IrpContext is on the stack and we need to initialize
2440 it for the current request. The request is a close operation.
2444 IrpContext - IrpContext to initialize.
2446 IrpContextLite - source for initialization
2454 UDFInitializeIrpContextLite(
2455 OUT PtrUDFIrpContextLite
*IrpContextLite
,
2456 IN PtrUDFIrpContext IrpContext
,
2460 PtrUDFIrpContextLite LocalIrpContextLite
= (PtrUDFIrpContextLite
)MyAllocatePool__(NonPagedPool
,sizeof(UDFIrpContextLite
));
2461 if(!LocalIrpContextLite
)
2462 return STATUS_INSUFFICIENT_RESOURCES
;
2463 // Zero and then initialize the structure.
2464 RtlZeroMemory( LocalIrpContextLite
, sizeof( UDFIrpContextLite
));
2466 LocalIrpContextLite
->NodeIdentifier
.NodeType
= UDF_NODE_TYPE_IRP_CONTEXT_LITE
;
2467 LocalIrpContextLite
->NodeIdentifier
.NodeSize
= sizeof(UDFIrpContextLite
);
2469 LocalIrpContextLite
->Fcb
= Fcb
;
2470 LocalIrpContextLite
->TreeLength
= IrpContext
->TreeLength
;
2471 // Copy RealDevice for workque algorithms.
2472 LocalIrpContextLite
->RealDevice
= IrpContext
->TargetDeviceObject
;
2473 LocalIrpContextLite
->IrpContextFlags
= IrpContext
->IrpContextFlags
;
2474 *IrpContextLite
= LocalIrpContextLite
;
2476 return STATUS_SUCCESS
;
2477 } // end UDFInitializeIrpContextLite()
2482 PDEVICE_OBJECT DeviceObject
, // the logical volume device object
2483 PIRP Irp
// I/O Request Packet
2486 NTSTATUS RC
= STATUS_SUCCESS
;
2487 // PtrUDFIrpContext PtrIrpContext = NULL;
2488 BOOLEAN AreWeTopLevel
= FALSE
;
2490 KdPrint(("UDFQuerySetEA: \n"));
2492 FsRtlEnterFileSystem();
2493 ASSERT(DeviceObject
);
2496 // set the top level context
2497 AreWeTopLevel
= UDFIsIrpTopLevel(Irp
);
2499 RC
= STATUS_EAS_NOT_SUPPORTED
;
2500 Irp
->IoStatus
.Status
= RC
;
2501 Irp
->IoStatus
.Information
= 0;
2503 IoCompleteRequest(Irp
, IO_DISK_INCREMENT
);
2506 IoSetTopLevelIrp(NULL
);
2509 FsRtlExitFileSystem();
2512 } // end UDFQuerySetEA()
2515 UDFIsResourceAcquired(
2516 IN PERESOURCE Resource
2520 ExIsResourceAcquiredExclusiveLite(Resource
) ? 1 :
2521 (ExIsResourceAcquiredSharedLite(Resource
) ? 2 : 0);
2523 } // end UDFIsResourceAcquired()
2526 UDFAcquireResourceExclusiveWithCheck(
2527 IN PERESOURCE Resource
2531 ExIsResourceAcquiredExclusiveLite(Resource
) ? 1 :
2532 (ExIsResourceAcquiredSharedLite(Resource
) ? 2 : 0);
2534 KdPrint(("UDFAcquireResourceExclusiveWithCheck: ReAcqRes, %x\n", ReAcqRes
));
2543 KdPrint(("UDFAcquireResourceExclusiveWithCheck: !!! Shared !!!\n"));
2546 UDFAcquireResourceExclusive(Resource
, TRUE
);
2550 } // end UDFAcquireResourceExclusiveWithCheck()
2553 UDFAcquireResourceSharedWithCheck(
2554 IN PERESOURCE Resource
2558 ExIsResourceAcquiredExclusiveLite(Resource
) ? 1 :
2559 (ExIsResourceAcquiredSharedLite(Resource
) ? 2 : 0);
2561 KdPrint(("UDFAcquireResourceSharedWithCheck: ReAcqRes, %x\n", ReAcqRes
));
2570 KdPrint(("UDFAcquireResourceSharedWithCheck: Exclusive\n"));
2573 UDFAcquireResourceShared(Resource
, TRUE
);
2577 } // end UDFAcquireResourceSharedWithCheck()
2580 UDFWCacheErrorHandler(
2582 IN PWCACHE_ERROR_CONTEXT ErrorInfo
2585 InterlockedIncrement((PLONG
)&(((PVCB
)Context
)->IoErrorCounter
));
2586 return ErrorInfo
->Status
;
2589 #include "Include/misc_common.cpp"
2590 #include "Include/regtools.cpp"