d512ca8fbf66f676efa75b8eb795f47cd0b4bf97
[reactos.git] / reactos / drivers / filesystems / udfs / misc.cpp
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 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]));
282 }
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));
289
290 KdPrint(("ESI=%8.8x ",PtrExceptionPointers->ContextRecord->Esi));
291 KdPrint(("EDI=%8.8x ",PtrExceptionPointers->ContextRecord->Edi));
292 }
293 if(PtrExceptionPointers->ContextRecord->ContextFlags & CONTEXT_CONTROL) {
294 KdPrint(("EBP=%8.8x ",PtrExceptionPointers->ContextRecord->Esp));
295 KdPrint(("ESP=%8.8x\n",PtrExceptionPointers->ContextRecord->Ebp));
296
297 KdPrint(("EIP=%8.8x\n",PtrExceptionPointers->ContextRecord->Eip));
298 }
299 // KdPrint(("Flags: %s %s ",PtrExceptionPointers->ContextRecord->Eip));
300
301 #endif // UDF_DBG
302
303 // figure out the exception code
304 ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionCode;
305
306 if ((ExceptionCode == STATUS_IN_PAGE_ERROR) && (PtrExceptionPointers->ExceptionRecord->NumberParameters >= 3)) {
307 ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionInformation[2];
308 }
309
310 if (PtrIrpContext) {
311 PtrIrpContext->SavedExceptionCode = ExceptionCode;
312 UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_EXCEPTION);
313 }
314
315 // check if we should propagate this exception or not
316 if (!(FsRtlIsNtstatusExpected(ExceptionCode))) {
317
318 // better free up the IrpContext now ...
319 if (PtrIrpContext) {
320 KdPrint((" UDF Driver internal error\n"));
321 BrutePoint();
322 } else {
323 // we are not ok, propagate this exception.
324 // NOTE: we will bring down the machine ...
325 ReturnCode = EXCEPTION_CONTINUE_SEARCH;
326 }
327 }
328
329
330 // return the appropriate code
331 return(ReturnCode);
332 } // end UDFExceptionFilter()
333
334
335 /*************************************************************************
336 *
337 * Function: UDFExceptionHandler()
338 *
339 * Description:
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 ...
347 *
348 * Expected Interrupt Level (for execution) :
349 *
350 * ?
351 *
352 * Return Value: Error code
353 *
354 *************************************************************************/
355 NTSTATUS
356 UDFExceptionHandler(
357 PtrUDFIrpContext PtrIrpContext,
358 PIRP Irp
359 )
360 {
361 // NTSTATUS RC;
362 NTSTATUS ExceptionCode = STATUS_INSUFFICIENT_RESOURCES;
363 PDEVICE_OBJECT Device;
364 PVPB Vpb;
365 PETHREAD Thread;
366
367 KdPrint(("UDFExceptionHandler \n"));
368
369 // ASSERT(Irp);
370
371 if (!Irp) {
372 KdPrint((" !Irp, return\n"));
373 ASSERT(!PtrIrpContext);
374 return ExceptionCode;
375 }
376 // If it was a queued close (or something like this) then we need not
377 // completing it because of MUST_SUCCEED requirement.
378
379 if (PtrIrpContext) {
380 ExceptionCode = PtrIrpContext->SavedExceptionCode;
381 // Free irp context here
382 // UDFReleaseIrpContext(PtrIrpContext);
383 } else {
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;
389 // complete the IRP
390 IoCompleteRequest(Irp, IO_NO_INCREMENT);
391
392 return ExceptionCode;
393 }
394
395 // Check if we are posting this request. One of the following must be true
396 // if we are to post a request.
397 //
398 // - Status code is STATUS_CANT_WAIT and the request is asynchronous
399 // or we are forcing this to be posted.
400 //
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.
403 //
404 // Set the MORE_PROCESSING flag in the IrpContext to keep if from being
405 // deleted if this is a retryable condition.
406
407 if (ExceptionCode == STATUS_VERIFY_REQUIRED) {
408 if (KeGetCurrentIrql() >= APC_LEVEL) {
409 KdPrint((" use UDFPostRequest()\n"));
410 ExceptionCode = UDFPostRequest( PtrIrpContext, Irp );
411 }
412 }
413
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)) {
417
418 KdPrint((" STATUS_PENDING/STATUS_CANT_WAIT, return\n"));
419 return ExceptionCode;
420 }
421
422 // Store this error into the Irp for posting back to the Io system.
423 Irp->IoStatus.Status = ExceptionCode;
424 if (IoIsErrorUserInduced( ExceptionCode )) {
425
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) {
429
430 // Now we are at the top level file system entry point.
431 //
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 );
436
437 // If there is no device in that location then check in the
438 // current thread.
439 if (Device == NULL) {
440
441 Device = IoGetDeviceToVerify( PsGetCurrentThread() );
442 IoSetDeviceToVerify( PsGetCurrentThread(), NULL );
443
444 ASSERT( Device != NULL );
445
446 // Let's not BugCheck just because the driver screwed up.
447 if (Device == NULL) {
448
449 KdPrint((" Device == NULL, return\n"));
450 ExceptionCode = STATUS_DRIVER_INTERNAL_ERROR;
451 Irp->IoStatus.Status = ExceptionCode;
452 Irp->IoStatus.Information = 0;
453 // complete the IRP
454 IoCompleteRequest(Irp, IO_NO_INCREMENT);
455
456 UDFReleaseIrpContext(PtrIrpContext);
457
458 return ExceptionCode;
459 }
460 }
461
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 );
467 }
468
469 //
470 // The other user induced conditions generate an error unless
471 // they have been disabled for this request.
472 //
473
474 if (FlagOn( PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_FLAG_DISABLE_POPUPS )) {
475
476 KdPrint((" DISABLE_POPUPS, complete Irp and return\n"));
477 Irp->IoStatus.Status = ExceptionCode;
478 Irp->IoStatus.Information = 0;
479 // complete the IRP
480 IoCompleteRequest(Irp, IO_NO_INCREMENT);
481
482 UDFReleaseIrpContext(PtrIrpContext);
483 return ExceptionCode;
484 } else {
485
486 // Generate a pop-up
487 if (IoGetCurrentIrpStackLocation( Irp )->FileObject != NULL) {
488
489 Vpb = IoGetCurrentIrpStackLocation( Irp )->FileObject->Vpb;
490 } else {
491
492 Vpb = NULL;
493 }
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 );
498
499 if (Device == NULL) {
500
501 Thread = PsGetCurrentThread();
502 Device = IoGetDeviceToVerify( Thread );
503 ASSERT( Device != NULL );
504
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;
510 // complete the IRP
511 IoCompleteRequest(Irp, IO_NO_INCREMENT);
512
513 UDFReleaseIrpContext(PtrIrpContext);
514
515 return ExceptionCode;
516 }
517 }
518
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 );
525
526 // We will be handing control back to the caller here, so
527 // reset the saved device object.
528
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.
533
534 UDFReleaseIrpContext(PtrIrpContext);
535 return STATUS_PENDING;
536 }
537 }
538
539 // If it was a normal request from IOManager then complete it
540 if (Irp) {
541 KdPrint((" complete Irp\n"));
542 // set the error code in the IRP
543 Irp->IoStatus.Status = ExceptionCode;
544 Irp->IoStatus.Information = 0;
545
546 // complete the IRP
547 IoCompleteRequest(Irp, IO_NO_INCREMENT);
548
549 UDFReleaseIrpContext(PtrIrpContext);
550 }
551
552 KdPrint((" return from exception handler with code %x\n", ExceptionCode));
553 return(ExceptionCode);
554 } // end UDFExceptionHandler()
555
556 /*************************************************************************
557 *
558 * Function: UDFLogEvent()
559 *
560 * Description:
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!)
564 *
565 * Expected Interrupt Level (for execution) :
566 *
567 * IRQL_PASSIVE_LEVEL
568 *
569 * Return Value: None
570 *
571 *************************************************************************/
572 VOID
573 UDFLogEvent(
574 NTSTATUS UDFEventLogId, // the UDF private message id
575 NTSTATUS RC) // any NT error code we wish to log ...
576 {
577 _SEH2_TRY {
578
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).
583
584 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
585 // nothing really we can do here, just do not wish to crash ...
586 NOTHING;
587 } _SEH2_END;
588
589 return;
590 } // end UDFLogEvent()
591
592
593 /*************************************************************************
594 *
595 * Function: UDFAllocateObjectName()
596 *
597 * Description:
598 * Allocate a new ObjectName structure to represent an open on-disk object.
599 * Also initialize the ObjectName structure to NULL.
600 *
601 * Expected Interrupt Level (for execution) :
602 *
603 * IRQL_PASSIVE_LEVEL
604 *
605 * Return Value: A pointer to the ObjectName structure OR NULL.
606 *
607 *************************************************************************/
608 PtrUDFObjectName
609 UDFAllocateObjectName(VOID)
610 {
611 PtrUDFObjectName PtrObjectName = NULL;
612 BOOLEAN AllocatedFromZone = TRUE;
613 KIRQL CurrentIrql;
614
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));
620
621 // release the spinlock
622 KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
623 } else {
624 // release the spinlock
625 KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
626
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;
630 }
631
632 if (!PtrObjectName) {
633 return NULL;
634 }
635
636 // zero out the allocated memory block
637 RtlZeroMemory(PtrObjectName, UDFQuadAlign(sizeof(UDFObjectName)));
638
639 // set up some fields ...
640 PtrObjectName->NodeIdentifier.NodeType = UDF_NODE_TYPE_OBJECT_NAME;
641 PtrObjectName->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFObjectName));
642
643
644 if (!AllocatedFromZone) {
645 UDFSetFlag(PtrObjectName->ObjectNameFlags, UDF_OBJ_NAME_NOT_FROM_ZONE);
646 }
647
648 return(PtrObjectName);
649 } // end UDFAllocateObjectName()
650
651
652 /*************************************************************************
653 *
654 * Function: UDFReleaseObjectName()
655 *
656 * Description:
657 * Deallocate a previously allocated structure.
658 *
659 * Expected Interrupt Level (for execution) :
660 *
661 * IRQL_PASSIVE_LEVEL
662 *
663 * Return Value: None
664 *
665 *************************************************************************/
666 VOID
667 __fastcall
668 UDFReleaseObjectName(
669 PtrUDFObjectName PtrObjectName)
670 {
671 KIRQL CurrentIrql;
672
673 ASSERT(PtrObjectName);
674
675 // give back memory either to the zone or to the VMM
676 if (!(PtrObjectName->ObjectNameFlags & UDF_OBJ_NAME_NOT_FROM_ZONE)) {
677 // back to the zone
678 KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
679 ExFreeToZone(&(UDFGlobalData.ObjectNameZoneHeader), PtrObjectName);
680 KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
681 } else {
682 MyFreePool__(PtrObjectName);
683 }
684
685 return;
686 } // end UDFReleaseObjectName()
687
688
689 /*************************************************************************
690 *
691 * Function: UDFAllocateCCB()
692 *
693 * Description:
694 * Allocate a new CCB structure to represent an open on-disk object.
695 * Also initialize the CCB structure to NULL.
696 *
697 * Expected Interrupt Level (for execution) :
698 *
699 * IRQL_PASSIVE_LEVEL
700 *
701 * Return Value: A pointer to the CCB structure OR NULL.
702 *
703 *************************************************************************/
704 PtrUDFCCB
705 UDFAllocateCCB(VOID)
706 {
707 PtrUDFCCB Ccb = NULL;
708 BOOLEAN AllocatedFromZone = TRUE;
709 KIRQL CurrentIrql;
710
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));
716
717 // release the spinlock
718 KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
719 } else {
720 // release the spinlock
721 KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
722
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));
727 }
728
729 if (!Ccb) {
730 return NULL;
731 }
732
733 // zero out the allocated memory block
734 RtlZeroMemory(Ccb, UDFQuadAlign(sizeof(UDFCCB)));
735
736 // set up some fields ...
737 Ccb->NodeIdentifier.NodeType = UDF_NODE_TYPE_CCB;
738 Ccb->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFCCB));
739
740
741 if (!AllocatedFromZone) {
742 UDFSetFlag(Ccb->CCBFlags, UDF_CCB_NOT_FROM_ZONE);
743 }
744
745 KdPrint(("UDFAllocateCCB: %x\n", Ccb));
746 return(Ccb);
747 } // end UDFAllocateCCB()
748
749
750 /*************************************************************************
751 *
752 * Function: UDFReleaseCCB()
753 *
754 * Description:
755 * Deallocate a previously allocated structure.
756 *
757 * Expected Interrupt Level (for execution) :
758 *
759 * IRQL_PASSIVE_LEVEL
760 *
761 * Return Value: None
762 *
763 *************************************************************************/
764 VOID
765 __fastcall
766 UDFReleaseCCB(
767 PtrUDFCCB Ccb
768 )
769 {
770 KIRQL CurrentIrql;
771
772 ASSERT(Ccb);
773
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)) {
777 // back to the zone
778 KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
779 ExFreeToZone(&(UDFGlobalData.CCBZoneHeader), Ccb);
780 KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
781 } else {
782 MyFreePool__(Ccb);
783 }
784
785 return;
786 } // end UDFReleaseCCB()
787
788 /*
789 Function: UDFCleanupCCB()
790
791 Description:
792 Cleanup and deallocate a previously allocated structure.
793
794 Expected Interrupt Level (for execution) :
795
796 IRQL_PASSIVE_LEVEL
797
798 Return Value: None
799
800 */
801 VOID
802 __fastcall
803 UDFCleanUpCCB(
804 PtrUDFCCB Ccb)
805 {
806 // ASSERT(Ccb);
807 if(!Ccb) return; // probably, we havn't allocated it...
808 ASSERT(Ccb->NodeIdentifier.NodeType == UDF_NODE_TYPE_CCB);
809
810 _SEH2_TRY {
811 if(Ccb->Fcb) {
812 UDFTouch(&(Ccb->Fcb->CcbListResource));
813 UDFAcquireResourceExclusive(&(Ccb->Fcb->CcbListResource),TRUE);
814 RemoveEntryList(&(Ccb->NextCCB));
815 UDFReleaseResource(&(Ccb->Fcb->CcbListResource));
816 } else {
817 BrutePoint();
818 }
819
820 if (Ccb->DirectorySearchPattern) {
821 if (Ccb->DirectorySearchPattern->Buffer) {
822 MyFreePool__(Ccb->DirectorySearchPattern->Buffer);
823 Ccb->DirectorySearchPattern->Buffer = NULL;
824 }
825
826 MyFreePool__(Ccb->DirectorySearchPattern);
827 Ccb->DirectorySearchPattern = NULL;
828 }
829
830 UDFReleaseCCB(Ccb);
831 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
832 BrutePoint();
833 } _SEH2_END;
834 } // end UDFCleanUpCCB()
835
836 /*************************************************************************
837 *
838 * Function: UDFAllocateFCB()
839 *
840 * Description:
841 * Allocate a new FCB structure to represent an open on-disk object.
842 * Also initialize the FCB structure to NULL.
843 *
844 * Expected Interrupt Level (for execution) :
845 *
846 * IRQL_PASSIVE_LEVEL
847 *
848 * Return Value: A pointer to the FCB structure OR NULL.
849 *
850 *************************************************************************/
851 PtrUDFFCB
852 UDFAllocateFCB(VOID)
853 {
854 PtrUDFFCB Fcb = NULL;
855
856 Fcb = (PtrUDFFCB)MyAllocatePool__(UDF_FCB_MT, UDFQuadAlign(sizeof(UDFFCB)));
857
858 if (!Fcb) {
859 return NULL;
860 }
861
862 // zero out the allocated memory block
863 RtlZeroMemory(Fcb, UDFQuadAlign(sizeof(UDFFCB)));
864
865 // set up some fields ...
866 Fcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_FCB;
867 Fcb->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFFCB));
868
869 KdPrint(("UDFAllocateFCB: %x\n", Fcb));
870 return(Fcb);
871 } // end UDFAllocateFCB()
872
873
874 /*************************************************************************
875 *
876 * Function: UDFReleaseFCB()
877 *
878 * Description:
879 * Deallocate a previously allocated structure.
880 *
881 * Expected Interrupt Level (for execution) :
882 *
883 * IRQL_PASSIVE_LEVEL
884 *
885 * Return Value: None
886 *
887 *************************************************************************/
888 /*VOID
889 UDFReleaseFCB(
890 PtrUDFFCB Fcb
891 )
892 {
893 ASSERT(Fcb);
894
895 MyFreePool__(Fcb);
896
897 return;
898 }*/
899
900 /*************************************************************************
901 *
902 *
903 *************************************************************************/
904 VOID
905 __fastcall
906 UDFCleanUpFCB(
907 PtrUDFFCB Fcb
908 )
909 {
910 KdPrint(("UDFCleanUpFCB: %x\n", Fcb));
911 if(!Fcb) return;
912
913 ASSERT(Fcb->NodeIdentifier.NodeType == UDF_NODE_TYPE_FCB);
914
915 _SEH2_TRY {
916 // Deinitialize FCBName field
917 if (Fcb->FCBName) {
918 if(Fcb->FCBName->ObjectName.Buffer) {
919 MyFreePool__(Fcb->FCBName->ObjectName.Buffer);
920 Fcb->FCBName->ObjectName.Buffer = NULL;
921 #ifdef UDF_DBG
922 Fcb->FCBName->ObjectName.Length =
923 Fcb->FCBName->ObjectName.MaximumLength = 0;
924 #endif
925 }
926 #ifdef UDF_DBG
927 else {
928 KdPrint(("UDF: Fcb has invalid FCBName Buffer\n"));
929 BrutePoint();
930 }
931 #endif
932 UDFReleaseObjectName(Fcb->FCBName);
933 Fcb->FCBName = NULL;
934 }
935 #ifdef UDF_DBG
936 else {
937 KdPrint(("UDF: Fcb has invalid FCBName field\n"));
938 BrutePoint();
939 }
940 #endif
941
942
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));
949 // } end transaction
950
951 if(Fcb->FCBFlags & UDF_FCB_INITIALIZED_CCB_LIST_RESOURCE)
952 UDFDeleteResource(&(Fcb->CcbListResource));
953
954 // Free memory
955 UDFReleaseFCB(Fcb);
956 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
957 BrutePoint();
958 } _SEH2_END;
959 } // end UDFCleanUpFCB()
960
961 #ifdef UDF_DBG
962 ULONG IrpContextCounter = 0;
963 #endif //UDF_DBG
964
965 /*************************************************************************
966 *
967 * Function: UDFAllocateIrpContext()
968 *
969 * Description:
970 * The UDF FSD creates an IRP context for each request received. This
971 * routine simply allocates (and initializes to NULL) a UDFIrpContext
972 * structure.
973 * Most of the fields in the context structure are then initialized here.
974 *
975 * Expected Interrupt Level (for execution) :
976 *
977 * IRQL_PASSIVE_LEVEL
978 *
979 * Return Value: A pointer to the IrpContext structure OR NULL.
980 *
981 *************************************************************************/
982 PtrUDFIrpContext
983 UDFAllocateIrpContext(
984 PIRP Irp,
985 PDEVICE_OBJECT PtrTargetDeviceObject
986 )
987 {
988 PtrUDFIrpContext PtrIrpContext = NULL;
989 BOOLEAN AllocatedFromZone = TRUE;
990 KIRQL CurrentIrql;
991 PIO_STACK_LOCATION IrpSp = NULL;
992
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));
998
999 // release the spinlock
1000 KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
1001 } else {
1002 // release the spinlock
1003 KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
1004
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;
1008 }
1009
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) {
1013 return NULL;
1014 }
1015
1016 #ifdef UDF_DBG
1017 IrpContextCounter++;
1018 #endif //UDF_DBG
1019
1020 // zero out the allocated memory block
1021 RtlZeroMemory(PtrIrpContext, UDFQuadAlign(sizeof(UDFIrpContext)));
1022
1023 // set up some fields ...
1024 PtrIrpContext->NodeIdentifier.NodeType = UDF_NODE_TYPE_IRP_CONTEXT;
1025 PtrIrpContext->NodeIdentifier.NodeSize = UDFQuadAlign(sizeof(UDFIrpContext));
1026
1027
1028 PtrIrpContext->Irp = Irp;
1029 PtrIrpContext->TargetDeviceObject = PtrTargetDeviceObject;
1030
1031 // copy over some fields from the IRP and set appropriate flag values
1032 if (Irp) {
1033 IrpSp = IoGetCurrentIrpStackLocation(Irp);
1034 ASSERT(IrpSp);
1035
1036 PtrIrpContext->MajorFunction = IrpSp->MajorFunction;
1037 PtrIrpContext->MinorFunction = IrpSp->MinorFunction;
1038
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
1044 // below.
1045 if (IrpSp->FileObject == NULL) {
1046 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
1047 } else {
1048 if (IoIsOperationSynchronous(Irp)) {
1049 PtrIrpContext->IrpContextFlags |= UDF_IRP_CONTEXT_CAN_BLOCK;
1050 }
1051 }
1052 }
1053
1054 if (!AllocatedFromZone) {
1055 UDFSetFlag(PtrIrpContext->IrpContextFlags, UDF_IRP_CONTEXT_NOT_FROM_ZONE);
1056 }
1057
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);
1063 }
1064
1065 return(PtrIrpContext);
1066 } // end UDFAllocateIrpContext()
1067
1068
1069 /*************************************************************************
1070 *
1071 * Function: UDFReleaseIrpContext()
1072 *
1073 * Description:
1074 * Deallocate a previously allocated structure.
1075 *
1076 * Expected Interrupt Level (for execution) :
1077 *
1078 * IRQL_PASSIVE_LEVEL
1079 *
1080 * Return Value: None
1081 *
1082 *************************************************************************/
1083 VOID
1084 UDFReleaseIrpContext(
1085 PtrUDFIrpContext PtrIrpContext)
1086 {
1087 if(!PtrIrpContext) return;
1088 // ASSERT(PtrIrpContext);
1089
1090 #ifdef UDF_DBG
1091 IrpContextCounter--;
1092 #endif //UDF_DBG
1093
1094 // give back memory either to the zone or to the VMM
1095 if (!(PtrIrpContext->IrpContextFlags & UDF_IRP_CONTEXT_NOT_FROM_ZONE)) {
1096 // back to the zone
1097 KIRQL CurrentIrql;
1098
1099 KeAcquireSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), &CurrentIrql);
1100 ExFreeToZone(&(UDFGlobalData.IrpContextZoneHeader), PtrIrpContext);
1101 KeReleaseSpinLock(&(UDFGlobalData.ZoneAllocationSpinLock), CurrentIrql);
1102 } else {
1103 MyFreePool__(PtrIrpContext);
1104 }
1105
1106 return;
1107 } // end UDFReleaseIrpContext()
1108
1109
1110 /*************************************************************************
1111 *
1112 * Function: UDFPostRequest()
1113 *
1114 * Description:
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)
1117 *
1118 * Expected Interrupt Level (for execution) :
1119 *
1120 * IRQL_PASSIVE_LEVEL
1121 *
1122 * Return Value: STATUS_PENDING
1123 *
1124 *************************************************************************/
1125 NTSTATUS
1126 UDFPostRequest(
1127 IN PtrUDFIrpContext PtrIrpContext,
1128 IN PIRP Irp
1129 )
1130 {
1131 KIRQL SavedIrql;
1132 // PIO_STACK_LOCATION IrpSp;
1133 PVCB Vcb;
1134
1135 // IrpSp = IoGetCurrentIrpStackLocation(Irp);
1136
1137 /*
1138 if(Vcb->StopOverflowQueue) {
1139 if(Irp) {
1140 Irp->IoStatus.Status = STATUS_WRONG_VOLUME;
1141 Irp->IoStatus.Information = 0;
1142 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
1143 }
1144 UDFReleaseIrpContext(PtrIrpContext);
1145 return STATUS_WRONG_VOLUME;
1146 }
1147 */
1148 // mark the IRP pending if this is not double post
1149 if(Irp)
1150 IoMarkIrpPending(Irp);
1151
1152 Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
1153 KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql);
1154
1155 if ( Vcb->PostedRequestCount > FSP_PER_DEVICE_THRESHOLD) {
1156
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 );
1165
1166 } else {
1167
1168 // We are going to send this Irp to an ex worker thread so up
1169 // the count.
1170 Vcb->PostedRequestCount++;
1171
1172 KeReleaseSpinLock( &(Vcb->OverflowQueueSpinLock), SavedIrql );
1173
1174 // queue up the request
1175 ExInitializeWorkItem(&(PtrIrpContext->WorkQueueItem), (PWORKER_THREAD_ROUTINE)UDFCommonDispatch, PtrIrpContext);
1176
1177 ExQueueWorkItem(&(PtrIrpContext->WorkQueueItem), CriticalWorkQueue);
1178 // ExQueueWorkItem(&(PtrIrpContext->WorkQueueItem), DelayedWorkQueue);
1179
1180 }
1181
1182 // return status pending
1183 return STATUS_PENDING;
1184 } // end UDFPostRequest()
1185
1186
1187 /*************************************************************************
1188 *
1189 * Function: UDFCommonDispatch()
1190 *
1191 * Description:
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
1195 * processing.
1196 *
1197 * Expected Interrupt Level (for execution) :
1198 *
1199 * IRQL PASSIVE_LEVEL
1200 *
1201 * Return Value: None
1202 *
1203 *************************************************************************/
1204 VOID
1205 UDFCommonDispatch(
1206 IN PVOID Context // actually is a pointer to IRPContext structure
1207 )
1208 {
1209 NTSTATUS RC = STATUS_SUCCESS;
1210 PtrUDFIrpContext PtrIrpContext = NULL;
1211 PIRP Irp = NULL;
1212 PVCB Vcb;
1213 KIRQL SavedIrql;
1214 PLIST_ENTRY Entry;
1215 BOOLEAN SpinLock = FALSE;
1216
1217 // The context must be a pointer to an IrpContext structure
1218 PtrIrpContext = (PtrUDFIrpContext)Context;
1219
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"));
1226 BrutePoint();
1227 return;
1228 }
1229
1230 Vcb = (PVCB)(PtrIrpContext->TargetDeviceObject->DeviceExtension);
1231 ASSERT(Vcb);
1232
1233 KdPrint((" *** Thr: %x ThCnt: %x QCnt: %x Started!\n", PsGetCurrentThread(), Vcb->PostedRequestCount, Vcb->OverflowQueueCount));
1234
1235 while(TRUE) {
1236
1237 KdPrint((" Next IRP\n"));
1238 FsRtlEnterFileSystem();
1239
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);
1249 } else {
1250 IoSetTopLevelIrp(Irp);
1251 }
1252
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;
1257
1258 _SEH2_TRY {
1259
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) {
1266 case IRP_MJ_CREATE:
1267 // Invoke the common create routine
1268 RC = UDFCommonCreate(PtrIrpContext, Irp);
1269 break;
1270 case IRP_MJ_READ:
1271 // Invoke the common read routine
1272 RC = UDFCommonRead(PtrIrpContext, Irp);
1273 break;
1274 #ifndef UDF_READ_ONLY_BUILD
1275 case IRP_MJ_WRITE:
1276 // Invoke the common write routine
1277 RC = UDFCommonWrite(PtrIrpContext, Irp);
1278 break;
1279 #endif //UDF_READ_ONLY_BUILD
1280 case IRP_MJ_CLEANUP:
1281 // Invoke the common cleanup routine
1282 RC = UDFCommonCleanup(PtrIrpContext, Irp);
1283 break;
1284 case IRP_MJ_CLOSE:
1285 // Invoke the common close routine
1286 RC = UDFCommonClose(PtrIrpContext, Irp);
1287 break;
1288 case IRP_MJ_DIRECTORY_CONTROL:
1289 // Invoke the common directory control routine
1290 RC = UDFCommonDirControl(PtrIrpContext, Irp);
1291 break;
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);
1298 break;
1299 case IRP_MJ_QUERY_VOLUME_INFORMATION:
1300 // Invoke the common query volume routine
1301 RC = UDFCommonQueryVolInfo(PtrIrpContext, Irp);
1302 break;
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);
1307 break;
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);
1313 break;
1314 case IRP_MJ_SET_EA:
1315 // Invoke the common set EAs routine
1316 RC = UDFCommonSetExtendedAttr(PtrIrpContext, Irp);
1317 break;*/
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);
1323 break;
1324 #ifndef UDF_READ_ONLY_BUILD
1325 case IRP_MJ_SET_SECURITY:
1326 // Invoke the common set Security routine
1327 RC = UDFCommonSetSecurity(PtrIrpContext, Irp);
1328 break;
1329 #endif //UDF_READ_ONLY_BUILD
1330 #endif // UDF_ENABLE_SECURITY
1331 // Continue with the remaining possible dispatch routines below ...
1332 default:
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;
1337
1338 IoCompleteRequest(Irp, IO_NO_INCREMENT);
1339 // Free up the Irp Context
1340 UDFReleaseIrpContext(PtrIrpContext);
1341 break;
1342 }
1343
1344 // Note: PtrIrpContext is invalid here
1345 KdPrint((" *** Thr: %x Done!\n", PsGetCurrentThread()));
1346
1347 } _SEH2_EXCEPT(UDFExceptionFilter(PtrIrpContext, _SEH2_GetExceptionInformation())) {
1348
1349 RC = UDFExceptionHandler(PtrIrpContext, Irp);
1350
1351 UDFLogEvent(UDF_ERROR_INTERNAL_ERROR, RC);
1352 } _SEH2_END;
1353
1354 // Enable preemption
1355 FsRtlExitFileSystem();
1356
1357 // Ensure that the "top-level" field is cleared
1358 IoSetTopLevelIrp(NULL);
1359
1360 // If there are any entries on this volume's overflow queue, service
1361 // them.
1362 if(!Vcb) {
1363 BrutePoint();
1364 break;
1365 }
1366
1367 KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql);
1368 SpinLock = TRUE;
1369 if(!Vcb->OverflowQueueCount)
1370 break;
1371
1372 Vcb->OverflowQueueCount--;
1373 Entry = RemoveHeadList(&Vcb->OverflowQueue);
1374 KeReleaseSpinLock(&(Vcb->OverflowQueueSpinLock), SavedIrql);
1375 SpinLock = FALSE;
1376
1377 PtrIrpContext = CONTAINING_RECORD( Entry,
1378 UDFIrpContext,
1379 WorkQueueItem.List );
1380 }
1381
1382 if(!SpinLock)
1383 KeAcquireSpinLock(&(Vcb->OverflowQueueSpinLock), &SavedIrql);
1384 Vcb->PostedRequestCount--;
1385 KeReleaseSpinLock(&(Vcb->OverflowQueueSpinLock), SavedIrql);
1386
1387 KdPrint((" *** Thr: %x ThCnt: %x QCnt: %x Terminated!\n", PsGetCurrentThread(), Vcb->PostedRequestCount, Vcb->OverflowQueueCount));
1388
1389 return;
1390 } // end UDFCommonDispatch()
1391
1392
1393 /*************************************************************************
1394 *
1395 * Function: UDFInitializeVCB()
1396 *
1397 * Description:
1398 * Perform the initialization for a VCB structure.
1399 *
1400 * Expected Interrupt Level (for execution) :
1401 *
1402 * IRQL PASSIVE_LEVEL
1403 *
1404 * Return Value: status
1405 *
1406 *************************************************************************/
1407 NTSTATUS
1408 UDFInitializeVCB(
1409 IN PDEVICE_OBJECT PtrVolumeDeviceObject,
1410 IN PDEVICE_OBJECT PtrTargetDeviceObject,
1411 IN PVPB PtrVPB
1412 )
1413 {
1414 NTSTATUS RC = STATUS_SUCCESS;
1415 PVCB Vcb = NULL;
1416 SHORT i;
1417
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;
1427
1428 Vcb = (PVCB)(PtrVolumeDeviceObject->DeviceExtension);
1429
1430 _SEH2_TRY {
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));
1434
1435 // Initialize the signature fields
1436 Vcb->NodeIdentifier.NodeType = UDF_NODE_TYPE_VCB;
1437 Vcb->NodeIdentifier.NodeSize = sizeof(VCB);
1438
1439 // Initialize the ERESOURCE object.
1440 RC = UDFInitializeResourceLite(&(Vcb->VCBResource));
1441 if(!NT_SUCCESS(RC))
1442 try_return(RC);
1443 VCBResourceInit = TRUE;
1444
1445 RC = UDFInitializeResourceLite(&(Vcb->BitMapResource1));
1446 if(!NT_SUCCESS(RC))
1447 try_return(RC);
1448 BitMapResource1Init = TRUE;
1449
1450 RC = UDFInitializeResourceLite(&(Vcb->FcbListResource));
1451 if(!NT_SUCCESS(RC))
1452 try_return(RC);
1453 FcbListResourceInit = TRUE;
1454
1455 RC = UDFInitializeResourceLite(&(Vcb->FileIdResource));
1456 if(!NT_SUCCESS(RC))
1457 try_return(RC);
1458 FileIdResourceInit = TRUE;
1459
1460 RC = UDFInitializeResourceLite(&(Vcb->DlocResource));
1461 if(!NT_SUCCESS(RC))
1462 try_return(RC);
1463 DlocResourceInit = TRUE;
1464
1465 RC = UDFInitializeResourceLite(&(Vcb->DlocResource2));
1466 if(!NT_SUCCESS(RC))
1467 try_return(RC);
1468 DlocResource2Init = TRUE;
1469
1470 RC = UDFInitializeResourceLite(&(Vcb->FlushResource));
1471 if(!NT_SUCCESS(RC))
1472 try_return(RC);
1473 FlushResourceInit = TRUE;
1474
1475 RC = UDFInitializeResourceLite(&(Vcb->PreallocResource));
1476 if(!NT_SUCCESS(RC))
1477 try_return(RC);
1478 PreallocResourceInit = TRUE;
1479
1480 RC = UDFInitializeResourceLite(&(Vcb->IoResource));
1481 if(!NT_SUCCESS(RC))
1482 try_return(RC);
1483 IoResourceInit = TRUE;
1484
1485 // RC = UDFInitializeResourceLite(&(Vcb->DelayedCloseResource));
1486 // ASSERT(NT_SUCCESS(RC));
1487
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);
1498 }
1499
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;
1510
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;
1515
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.
1519 Vcb->Vpb = PtrVPB;
1520 // Target Vcb field in Vcb onto itself. This required for check in
1521 // open/lock/unlock volume dispatch poits
1522 Vcb->Vcb=Vcb;
1523
1524 // Set the removable media flag based on the real device's
1525 // characteristics
1526 if (PtrVPB->RealDevice->Characteristics & FILE_REMOVABLE_MEDIA) {
1527 Vcb->VCBFlags |= UDF_VCB_FLAGS_REMOVABLE_MEDIA;
1528 }
1529
1530 // Initialize the list anchor (head) for some lists in this VCB.
1531 InitializeListHead(&(Vcb->NextFCB));
1532 InitializeListHead(&(Vcb->NextNotifyIRP));
1533 InitializeListHead(&(Vcb->VolumeOpenListHead));
1534
1535 // Initialize the overflow queue for the volume
1536 Vcb->OverflowQueueCount = 0;
1537 InitializeListHead(&(Vcb->OverflowQueue));
1538
1539 Vcb->PostedRequestCount = 0;
1540 KeInitializeSpinLock(&(Vcb->OverflowQueueSpinLock));
1541
1542 // Initialize the notify IRP list mutex
1543 FsRtlNotifyInitializeSync(&(Vcb->NotifyIRPMutex));
1544
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)));
1550
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 = ??
1556
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
1559 // information
1560 Vcb->NTRequiredFCB->CommonFCBHeader.ValidDataLength.QuadPart = 0x7FFFFFFFFFFFFFFFULL;
1561
1562 Vcb->VolumeLockPID = -1;
1563
1564 Vcb->VCBOpenCount = 1;
1565
1566 Vcb->WCacheMaxBlocks = UDFGlobalData.WCacheMaxBlocks;
1567 Vcb->WCacheMaxFrames = UDFGlobalData.WCacheMaxFrames;
1568 Vcb->WCacheBlocksPerFrameSh = UDFGlobalData.WCacheBlocksPerFrameSh;
1569 Vcb->WCacheFramesToKeepFree = UDFGlobalData.WCacheFramesToKeepFree;
1570
1571 // Create a stream file object for this volume.
1572 //Vcb->PtrStreamFileObject = IoCreateStreamFileObject(NULL,
1573 // Vcb->Vpb->RealDevice);
1574 //ASSERT(Vcb->PtrStreamFileObject);
1575
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);
1580
1581 //Vcb->PtrStreamFileObject->Vpb = PtrVPB;
1582
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));
1587
1588 Vcb->TargetDevName.Buffer = (PWCHAR)MyAllocatePool__(NonPagedPool, sizeof(MOUNTDEV_NAME));
1589 if(!Vcb->TargetDevName.Buffer)
1590 try_return(RC = STATUS_INSUFFICIENT_RESOURCES);
1591
1592 RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME /*IOCTL_MOUNTDEV_QUERY_DEVICE_NAME*/, Vcb->TargetDeviceObject,
1593 NULL,0,
1594 (PVOID)(Vcb->TargetDevName.Buffer),sizeof(MOUNTDEV_NAME),
1595 FALSE, NULL);
1596 if(!NT_SUCCESS(RC)) {
1597
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;
1602 }
1603
1604 RC = UDFPhSendIOCTL(IOCTL_CDRW_GET_DEVICE_NAME /*IOCTL_MOUNTDEV_QUERY_DEVICE_NAME*/, Vcb->TargetDeviceObject,
1605 NULL,0,
1606 (PVOID)(Vcb->TargetDevName.Buffer), Vcb->TargetDevName.Buffer[0]+sizeof(MOUNTDEV_NAME),
1607 FALSE, NULL);
1608 if(!NT_SUCCESS(RC))
1609 goto Kill_DevName_buffer;
1610
1611 } else {
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);
1619 goto read_reg;
1620 }
1621 }
1622
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;
1627
1628 for(;i>=0;i--) {
1629 if(Vcb->TargetDevName.Buffer[i] == L'\\') {
1630
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;
1634 break;
1635 }
1636 }
1637
1638 KdPrint((" TargetDevName: %S\n", Vcb->TargetDevName.Buffer));
1639
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);
1644
1645 read_reg:
1646
1647 UDFReleaseResource(&(UDFGlobalData.GlobalDataResource));
1648
1649 // Mark the fact that this VCB structure is initialized.
1650 Vcb->VCBFlags |= UDF_VCB_FLAGS_VCB_INITIALIZED;
1651
1652 RC = STATUS_SUCCESS;
1653
1654 try_exit: NOTHING;
1655
1656 } _SEH2_FINALLY {
1657
1658 if(!NT_SUCCESS(RC)) {
1659 if(Vcb->TargetDevName.Buffer)
1660 MyFreePool__(Vcb->TargetDevName.Buffer);
1661 if(Vcb->NTRequiredFCB)
1662 MyFreePool__(Vcb->NTRequiredFCB);
1663 if(Vcb->Statistics)
1664 MyFreePool__(Vcb->Statistics);
1665
1666 if(VCBResourceInit)
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));
1682 if(IoResourceInit)
1683 UDFDeleteResource(&(Vcb->IoResource));
1684 }
1685 } _SEH2_END;
1686
1687 return RC;
1688 } // end UDFInitializeVCB()
1689
1690 UDFFSD_MEDIA_TYPE
1691 UDFGetMediaClass(
1692 PVCB Vcb
1693 )
1694 {
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))
1699 return MediaCdrom;
1700 if(Vcb->CDR_Mode)
1701 return MediaCdr;
1702 if((Vcb->MediaType >= MediaType_UnknownSize_CDR) &&
1703 (Vcb->MediaType < MediaType_UnknownSize_CDRW)) {
1704 return MediaCdr;
1705 }
1706 if((Vcb->MediaType >= MediaType_UnknownSize_CDRW) &&
1707 (Vcb->MediaType < MediaType_UnknownSize_Unknown)) {
1708 return MediaCdrw;
1709 }
1710 if(Vcb->MediaClassEx == CdMediaClass_CDR) {
1711 return MediaCdr;
1712 }
1713 if(Vcb->MediaClassEx == CdMediaClass_DVDR ||
1714 Vcb->MediaClassEx == CdMediaClass_DVDpR ||
1715 Vcb->MediaClassEx == CdMediaClass_HD_DVDR ||
1716 Vcb->MediaClassEx == CdMediaClass_BDR) {
1717 return MediaDvdr;
1718 }
1719 if(Vcb->MediaClassEx == CdMediaClass_CDRW) {
1720 return MediaCdrw;
1721 }
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) {
1728 return MediaDvdrw;
1729 }
1730 //
1731 if(Vcb->MediaClassEx == CdMediaClass_CDROM ||
1732 Vcb->MediaClassEx == CdMediaClass_DVDROM ||
1733 Vcb->MediaClassEx == CdMediaClass_HD_DVDROM ||
1734 Vcb->MediaClassEx == CdMediaClass_BDROM) {
1735 return MediaCdrom;
1736 }
1737 return MediaCdrom;
1738 #ifdef UDF_HDD_SUPPORT
1739 case FILE_DEVICE_DISK_FILE_SYSTEM:
1740 if(Vcb->TargetDeviceObject->Characteristics & FILE_FLOPPY_DISKETTE)
1741 return MediaFloppy;
1742 if(Vcb->TargetDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
1743 return MediaZip;
1744 return MediaHdd;
1745 #endif //UDF_HDD_SUPPORT
1746 }
1747 return MediaUnknown;
1748 } // end UDFGetMediaClass()
1749
1750 typedef ULONG
1751 (*ptrUDFGetParameter)(
1752 IN PVCB Vcb,
1753 IN PCWSTR Name,
1754 IN ULONG DefValue
1755 );
1756
1757 VOID
1758 UDFUpdateCompatOption(
1759 PVCB Vcb,
1760 BOOLEAN Update,
1761 BOOLEAN UseCfg,
1762 PCWSTR Name,
1763 ULONG Flag,
1764 BOOLEAN Default
1765 )
1766 {
1767 ptrUDFGetParameter UDFGetParameter = UseCfg ? UDFGetCfgParameter : UDFGetRegParameter;
1768
1769 if(UDFGetParameter(Vcb, Name, Update ? ((Vcb->CompatFlags & Flag) ? TRUE : FALSE) : Default)) {
1770 Vcb->CompatFlags |= Flag;
1771 } else {
1772 Vcb->CompatFlags &= ~Flag;
1773 }
1774 } // end UDFUpdateCompatOption()
1775
1776 VOID
1777 UDFReadRegKeys(
1778 PVCB Vcb,
1779 BOOLEAN Update,
1780 BOOLEAN UseCfg
1781 )
1782 {
1783 ULONG mult = 1;
1784 ptrUDFGetParameter UDFGetParameter = UseCfg ? UDFGetCfgParameter : UDFGetRegParameter;
1785
1786 Vcb->DefaultRegName = UDFMediaClassName[(ULONG)UDFGetMediaClass(Vcb)].ClassName;
1787
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);
1801 if(!Vcb->FECharge)
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
1816 if(!Update) {
1817 Vcb->SystemCacheGran = (1 << UDFGetParameter(Vcb, UDF_READAHEAD_GRAN_NAME, 0)) * PAGE_SIZE;
1818 if(!Vcb->SystemCacheGran)
1819 Vcb->SystemCacheGran = UDF_DEFAULT_READAHEAD_GRAN;
1820 }
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;
1826 } else
1827 if(Vcb->BM_FlushPriod == (ULONG)-1) {
1828 Vcb->BM_FlushPriod = 0;
1829 }
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;
1834 } else
1835 if(Vcb->Tree_FlushPriod == (ULONG)-1) {
1836 Vcb->Tree_FlushPriod = 0;
1837 }
1838 Vcb->SkipCountLimit = UDFGetParameter(Vcb, UDF_NO_UPDATE_PERIOD_NAME,
1839 Update ? Vcb->SkipCountLimit : 0);
1840 if(!Vcb->SkipCountLimit)
1841 Vcb->SkipCountLimit = -1;
1842
1843 Vcb->SkipEjectCountLimit = UDFGetParameter(Vcb, UDF_NO_EJECT_PERIOD_NAME,
1844 Update ? Vcb->SkipEjectCountLimit : 3);
1845
1846 if(!Update) {
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;
1852 }
1853 // The mimimum FileSize increment when we'll decide not to allocate
1854 // on-disk space.
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;
1862
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);
1893
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
1900 );
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;
1914 } else {
1915 Vcb->FlushMedia = FALSE;
1916 }
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;
1921 } else {
1922 Vcb->DoNotCompareBeforeWrite = FALSE;
1923 }
1924 if(!Update) {
1925 if(UDFGetParameter(Vcb, UDF_CHAINED_IO, TRUE)) {
1926 Vcb->CacheChainedIo = TRUE;
1927 }
1928
1929 if(UDFGetParameter(Vcb, UDF_FORCE_MOUNT_ALL, FALSE)) {
1930 Vcb->VCBFlags |= UDF_VCB_FLAGS_RAW_DISK;
1931 }
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;
1939 }
1940 }
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;
1945 }
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;
1951 }
1952
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;
1957 }
1958
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;
1963 }
1964
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;
1968 }
1969
1970 mult = UDFGetParameter(Vcb, UDF_CACHE_SIZE_MULTIPLIER, 1);
1971 if(!mult) mult = 1;
1972 Vcb->WCacheMaxBlocks *= mult;
1973 Vcb->WCacheMaxFrames *= mult;
1974
1975 if(UDFGetParameter(Vcb, UDF_USE_EJECT_BUTTON, TRUE)) {
1976 Vcb->UseEvent = TRUE;
1977 }
1978 }
1979 return;
1980 } // end UDFReadRegKeys()
1981
1982 ULONG
1983 UDFGetRegParameter(
1984 IN PVCB Vcb,
1985 IN PCWSTR Name,
1986 IN ULONG DefValue
1987 )
1988 {
1989 return UDFRegCheckParameterValue(&(UDFGlobalData.SavedRegPath),
1990 Name,
1991 Vcb ? &(Vcb->TargetDevName) : NULL,
1992 Vcb ? Vcb->DefaultRegName : NULL,
1993 DefValue);
1994 } // end UDFGetRegParameter()
1995
1996 ULONG
1997 UDFGetCfgParameter(
1998 IN PVCB Vcb,
1999 IN PCWSTR Name,
2000 IN ULONG DefValue
2001 )
2002 {
2003 ULONG len;
2004 CHAR NameA[128];
2005 ULONG ret_val=0;
2006 CHAR a;
2007 BOOLEAN wait_name=TRUE;
2008 BOOLEAN wait_val=FALSE;
2009 BOOLEAN wait_nl=FALSE;
2010 ULONG radix=10;
2011 ULONG i;
2012
2013 PUCHAR Cfg = Vcb->Cfg;
2014 ULONG Length = Vcb->CfgLength;
2015
2016 if(!Cfg || !Length)
2017 return DefValue;
2018
2019 len = wcslen(Name);
2020 if(len >= sizeof(NameA))
2021 return DefValue;
2022 sprintf(NameA, "%S", Name);
2023
2024 for(i=0; i<Length; i++) {
2025 a=Cfg[i];
2026 switch(a) {
2027 case '\n':
2028 case '\r':
2029 case ',':
2030 if(wait_val)
2031 return DefValue;
2032 continue;
2033 case ';':
2034 case '#':
2035 case '[': // ignore sections for now, treat as comment
2036 if(!wait_name)
2037 return DefValue;
2038 wait_nl = TRUE;
2039 continue;
2040 case '=':
2041 if(!wait_val)
2042 return DefValue;
2043 continue;
2044 case ' ':
2045 case '\t':
2046 continue;
2047 default:
2048 if(wait_nl)
2049 continue;
2050 }
2051 if(wait_name) {
2052 if(i+len+2 > Length)
2053 return DefValue;
2054 if(RtlCompareMemory(Cfg+i, NameA, len) == len) {
2055 a=Cfg[i+len];
2056 switch(a) {
2057 case '\n':
2058 case '\r':
2059 case ',':
2060 case ';':
2061 case '#':
2062 return DefValue;
2063 case '=':
2064 case ' ':
2065 case '\t':
2066 break;
2067 default:
2068 wait_nl = TRUE;
2069 wait_val = FALSE;
2070 i+=len;
2071 continue;
2072 }
2073 wait_name = FALSE;
2074 wait_nl = FALSE;
2075 wait_val = TRUE;
2076 i+=len;
2077
2078 } else {
2079 wait_nl = TRUE;
2080 }
2081 continue;
2082 }
2083 if(wait_val) {
2084 if(i+3 > Length) {
2085 if(a=='0' && Cfg[i+1]=='x') {
2086 i+=2;
2087 radix=16;
2088 }
2089 }
2090 if(i >= Length) {
2091 return DefValue;
2092 }
2093 while(i<Length) {
2094 a=Cfg[i];
2095 switch(a) {
2096 case '\n':
2097 case '\r':
2098 case ' ':
2099 case '\t':
2100 case ',':
2101 case ';':
2102 case '#':
2103 if(wait_val)
2104 return DefValue;
2105 return ret_val;
2106 }
2107 if(a >= '0' && a <= '9') {
2108 a -= '0';
2109 } else {
2110 if(radix != 16)
2111 return DefValue;
2112 if(a >= 'a' && a <= 'f') {
2113 a -= 'a';
2114 } else
2115 if(a >= 'A' && a <= 'F') {
2116 a -= 'A';
2117 } else {
2118 return DefValue;
2119 }
2120 a += 0x0a;
2121 }
2122 ret_val = ret_val*radix + a;
2123 wait_val = FALSE;
2124 i++;
2125 }
2126 return ret_val;
2127 }
2128 }
2129 return DefValue;
2130
2131 } // end UDFGetCfgParameter()
2132
2133 VOID
2134 UDFReleaseVCB(
2135 PVCB Vcb
2136 )
2137 {
2138 LARGE_INTEGER delay;
2139 KdPrint(("UDFReleaseVCB\n"));
2140
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
2147 }
2148
2149 _SEH2_TRY {
2150 KdPrint(("UDF: Flushing buffers\n"));
2151 UDFVRelease(Vcb);
2152 WCacheFlushAll__(&(Vcb->FastCache),Vcb);
2153 WCacheRelease__(&(Vcb->FastCache));
2154
2155 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2156 BrutePoint();
2157 } _SEH2_END;
2158
2159 #ifdef UDF_DBG
2160 _SEH2_TRY {
2161 if (!ExIsResourceAcquiredShared(&UDFGlobalData.GlobalDataResource)) {
2162 KdPrint(("UDF: attempt to access to not protected data\n"));
2163 KdPrint(("UDF: UDFGlobalData\n"));
2164 BrutePoint();
2165 }
2166 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2167 BrutePoint();
2168 } _SEH2_END;
2169 #endif
2170
2171 _SEH2_TRY {
2172 RemoveEntryList(&(Vcb->NextVCB));
2173 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2174 BrutePoint();
2175 } _SEH2_END;
2176
2177 /* _SEH2_TRY {
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) {
2182 BrutePoint();
2183 }*/
2184
2185 _SEH2_TRY {
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) {
2197 BrutePoint();
2198 } _SEH2_END;
2199
2200 _SEH2_TRY {
2201 KdPrint(("UDF: Cleanup VCB\n"));
2202 ASSERT(IsListEmpty(&(Vcb->NextNotifyIRP)));
2203 FsRtlNotifyUninitializeSync(&(Vcb->NotifyIRPMutex));
2204 UDFCleanupVCB(Vcb);
2205 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2206 BrutePoint();
2207 } _SEH2_END;
2208
2209 _SEH2_TRY {
2210 KdPrint(("UDF: Delete DO\n"));
2211 IoDeleteDevice(Vcb->VCBDeviceObject);
2212 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) {
2213 BrutePoint();
2214 } _SEH2_END;
2215
2216 } // end UDFReleaseVCB()
2217
2218 /*
2219 Read DWORD from Registry
2220 */
2221 ULONG
2222 UDFRegCheckParameterValue(
2223 IN PUNICODE_STRING RegistryPath,
2224 IN PCWSTR Name,
2225 IN PUNICODE_STRING PtrVolumePath,
2226 IN PCWSTR DefaultPath,
2227 IN ULONG DefValue
2228 )
2229 {
2230 NTSTATUS status;
2231
2232 ULONG val = DefValue;
2233
2234 UNICODE_STRING paramStr;
2235 UNICODE_STRING defaultParamStr;
2236 UNICODE_STRING paramPathUnknownStr;
2237
2238 UNICODE_STRING paramSuffix;
2239 UNICODE_STRING paramPath;
2240 UNICODE_STRING paramPathUnknown;
2241 UNICODE_STRING paramDevPath;
2242 UNICODE_STRING defaultParamPath;
2243
2244 _SEH2_TRY {
2245
2246 paramPath.Buffer = NULL;
2247 paramDevPath.Buffer = NULL;
2248 paramPathUnknown.Buffer = NULL;
2249 defaultParamPath.Buffer = NULL;
2250
2251 // First append \Parameters to the passed in registry path
2252 // Note, RtlInitUnicodeString doesn't allocate memory
2253 RtlInitUnicodeString(&paramStr, L"\\Parameters");
2254 RtlInitUnicodeString(&paramPath, NULL);
2255
2256 RtlInitUnicodeString(&paramPathUnknownStr, REG_DEFAULT_UNKNOWN);
2257 RtlInitUnicodeString(&paramPathUnknown, NULL);
2258
2259 paramPathUnknown.MaximumLength = RegistryPath->Length + paramPathUnknownStr.Length + paramStr.Length + sizeof(WCHAR);
2260 paramPath.MaximumLength = RegistryPath->Length + paramStr.Length + sizeof(WCHAR);
2261
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);
2266 }
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);
2271 }
2272
2273 RtlZeroMemory(paramPath.Buffer, paramPath.MaximumLength);
2274 status = RtlAppendUnicodeToString(&paramPath, RegistryPath->Buffer);
2275 if(!NT_SUCCESS(status)) {
2276 try_return(val = DefValue);
2277 }
2278 status = RtlAppendUnicodeToString(&paramPath, paramStr.Buffer);
2279 if(!NT_SUCCESS(status)) {
2280 try_return(val = DefValue);
2281 }
2282 KdPrint(("UDFCheckRegValue: (1) |%S|\n", paramPath.Buffer));
2283
2284 RtlZeroMemory(paramPathUnknown.Buffer, paramPathUnknown.MaximumLength);
2285 status = RtlAppendUnicodeToString(&paramPathUnknown, RegistryPath->Buffer);
2286 if(!NT_SUCCESS(status)) {
2287 try_return(val = DefValue);
2288 }
2289 status = RtlAppendUnicodeToString(&paramPathUnknown, paramStr.Buffer);
2290 if(!NT_SUCCESS(status)) {
2291 try_return(val = DefValue);
2292 }
2293 status = RtlAppendUnicodeToString(&paramPathUnknown, paramPathUnknownStr.Buffer);
2294 if(!NT_SUCCESS(status)) {
2295 try_return(val = DefValue);
2296 }
2297 KdPrint(("UDFCheckRegValue: (2) |%S|\n", paramPathUnknown.Buffer));
2298
2299 // First append \Parameters\Default_XXX to the passed in registry path
2300 if(DefaultPath) {
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);
2308 }
2309
2310 RtlZeroMemory(defaultParamPath.Buffer, defaultParamPath.MaximumLength);
2311 status = RtlAppendUnicodeToString(&defaultParamPath, paramPath.Buffer);
2312 if(!NT_SUCCESS(status)) {
2313 try_return(val = DefValue);
2314 }
2315 status = RtlAppendUnicodeToString(&defaultParamPath, defaultParamStr.Buffer);
2316 if(!NT_SUCCESS(status)) {
2317 try_return(val = DefValue);
2318 }
2319 KdPrint(("UDFCheckRegValue: (3) |%S|\n", defaultParamPath.Buffer));
2320 }
2321
2322 if(PtrVolumePath) {
2323 paramSuffix = *PtrVolumePath;
2324 } else {
2325 RtlInitUnicodeString(&paramSuffix, NULL);
2326 }
2327
2328 RtlInitUnicodeString(&paramDevPath, 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);
2334 }
2335
2336 RtlZeroMemory(paramDevPath.Buffer, paramDevPath.MaximumLength);
2337 status = RtlAppendUnicodeToString(&paramDevPath, paramPath.Buffer);
2338 if(!NT_SUCCESS(status)) {
2339 try_return(val = DefValue);
2340 }
2341 if(paramSuffix.Buffer) {
2342 status = RtlAppendUnicodeToString(&paramDevPath, paramSuffix.Buffer);
2343 if(!NT_SUCCESS(status)) {
2344 try_return(val = DefValue);
2345 }
2346 }
2347
2348 KdPrint(( " Parameter = %ws\n", Name));
2349
2350 {
2351 HKEY hk = NULL;
2352 status = RegTGetKeyHandle(NULL, RegistryPath->Buffer, &hk);
2353 if(NT_SUCCESS(status)) {
2354 RegTCloseKeyHandle(hk);
2355 }
2356 }
2357
2358
2359 // *** Read GLOBAL_DEFAULTS from
2360 // "\DwUdf\Parameters_Unknown\"
2361
2362 status = RegTGetDwordValue(NULL, paramPath.Buffer, Name, &val);
2363
2364 // *** Read DEV_CLASS_SPEC_DEFAULTS (if any) from
2365 // "\DwUdf\Parameters_%DevClass%\"
2366
2367 if(DefaultPath) {
2368 status = RegTGetDwordValue(NULL, defaultParamPath.Buffer, Name, &val);
2369 }
2370
2371 // *** Read DEV_SPEC_PARAMS from (if device supports GetDevName)
2372 // "\DwUdf\Parameters\%DevName%\"
2373
2374 status = RegTGetDwordValue(NULL, paramDevPath.Buffer, Name, &val);
2375
2376 try_exit: NOTHING;
2377
2378 } _SEH2_FINALLY {
2379
2380 if(DefaultPath && defaultParamPath.Buffer) {
2381 MyFreePool__(defaultParamPath.Buffer);
2382 }
2383 if(paramPath.Buffer) {
2384 MyFreePool__(paramPath.Buffer);
2385 }
2386 if(paramDevPath.Buffer) {
2387 MyFreePool__(paramDevPath.Buffer);
2388 }
2389 if(paramPathUnknown.Buffer) {
2390 MyFreePool__(paramPathUnknown.Buffer);
2391 }
2392 } _SEH2_END;
2393
2394 KdPrint(( "UDFCheckRegValue: %ws for drive %s is %x\n\n", Name, PtrVolumePath, val));
2395 return val;
2396 } // end UDFRegCheckParameterValue()
2397
2398 /*
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.
2403
2404 Arguments:
2405
2406 IrpContext - IrpContext to initialize.
2407
2408 IrpContextLite - source for initialization
2409
2410 Return Value:
2411
2412 None
2413
2414 */
2415 VOID
2416 UDFInitializeIrpContextFromLite(
2417 OUT PtrUDFIrpContext *IrpContext,
2418 IN PtrUDFIrpContextLite IrpContextLite
2419 )
2420 {
2421 (*IrpContext) = UDFAllocateIrpContext(NULL, IrpContextLite->RealDevice);
2422 // Zero and then initialize the structure.
2423
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);
2429
2430 // Set the wait parameter
2431 UDFSetFlag( (*IrpContext)->IrpContextFlags, UDF_IRP_CONTEXT_CAN_BLOCK );
2432
2433 return;
2434 } // end UDFInitializeIrpContextFromLite()
2435
2436 /*
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.
2441
2442 Arguments:
2443
2444 IrpContext - IrpContext to initialize.
2445
2446 IrpContextLite - source for initialization
2447
2448 Return Value:
2449
2450 None
2451
2452 */
2453 NTSTATUS
2454 UDFInitializeIrpContextLite(
2455 OUT PtrUDFIrpContextLite *IrpContextLite,
2456 IN PtrUDFIrpContext IrpContext,
2457 IN PtrUDFFCB Fcb
2458 )
2459 {
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 ));
2465
2466 LocalIrpContextLite->NodeIdentifier.NodeType = UDF_NODE_TYPE_IRP_CONTEXT_LITE;
2467 LocalIrpContextLite->NodeIdentifier.NodeSize = sizeof(UDFIrpContextLite);
2468
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;
2475
2476 return STATUS_SUCCESS;
2477 } // end UDFInitializeIrpContextLite()
2478
2479 NTSTATUS
2480 NTAPI
2481 UDFQuerySetEA(
2482 PDEVICE_OBJECT DeviceObject, // the logical volume device object
2483 PIRP Irp // I/O Request Packet
2484 )
2485 {
2486 NTSTATUS RC = STATUS_SUCCESS;
2487 // PtrUDFIrpContext PtrIrpContext = NULL;
2488 BOOLEAN AreWeTopLevel = FALSE;
2489
2490 KdPrint(("UDFQuerySetEA: \n"));
2491
2492 FsRtlEnterFileSystem();
2493 ASSERT(DeviceObject);
2494 ASSERT(Irp);
2495
2496 // set the top level context
2497 AreWeTopLevel = UDFIsIrpTopLevel(Irp);
2498
2499 RC = STATUS_EAS_NOT_SUPPORTED;
2500 Irp->IoStatus.Status = RC;
2501 Irp->IoStatus.Information = 0;
2502 // complete the IRP
2503 IoCompleteRequest(Irp, IO_DISK_INCREMENT);
2504
2505 if(AreWeTopLevel) {
2506 IoSetTopLevelIrp(NULL);
2507 }
2508
2509 FsRtlExitFileSystem();
2510
2511 return(RC);
2512 } // end UDFQuerySetEA()
2513
2514 ULONG
2515 UDFIsResourceAcquired(
2516 IN PERESOURCE Resource
2517 )
2518 {
2519 ULONG ReAcqRes =
2520 ExIsResourceAcquiredExclusiveLite(Resource) ? 1 :
2521 (ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0);
2522 return ReAcqRes;
2523 } // end UDFIsResourceAcquired()
2524
2525 BOOLEAN
2526 UDFAcquireResourceExclusiveWithCheck(
2527 IN PERESOURCE Resource
2528 )
2529 {
2530 ULONG ReAcqRes =
2531 ExIsResourceAcquiredExclusiveLite(Resource) ? 1 :
2532 (ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0);
2533 if(ReAcqRes) {
2534 KdPrint(("UDFAcquireResourceExclusiveWithCheck: ReAcqRes, %x\n", ReAcqRes));
2535 } else {
2536 // BrutePoint();
2537 }
2538
2539 if(ReAcqRes == 1) {
2540 // OK
2541 } else
2542 if(ReAcqRes == 2) {
2543 KdPrint(("UDFAcquireResourceExclusiveWithCheck: !!! Shared !!!\n"));
2544 //BrutePoint();
2545 } else {
2546 UDFAcquireResourceExclusive(Resource, TRUE);
2547 return TRUE;
2548 }
2549 return FALSE;
2550 } // end UDFAcquireResourceExclusiveWithCheck()
2551
2552 BOOLEAN
2553 UDFAcquireResourceSharedWithCheck(
2554 IN PERESOURCE Resource
2555 )
2556 {
2557 ULONG ReAcqRes =
2558 ExIsResourceAcquiredExclusiveLite(Resource) ? 1 :
2559 (ExIsResourceAcquiredSharedLite(Resource) ? 2 : 0);
2560 if(ReAcqRes) {
2561 KdPrint(("UDFAcquireResourceSharedWithCheck: ReAcqRes, %x\n", ReAcqRes));
2562 /* } else {
2563 BrutePoint();*/
2564 }
2565
2566 if(ReAcqRes == 2) {
2567 // OK
2568 } else
2569 if(ReAcqRes == 1) {
2570 KdPrint(("UDFAcquireResourceSharedWithCheck: Exclusive\n"));
2571 //BrutePoint();
2572 } else {
2573 UDFAcquireResourceShared(Resource, TRUE);
2574 return TRUE;
2575 }
2576 return FALSE;
2577 } // end UDFAcquireResourceSharedWithCheck()
2578
2579 NTSTATUS
2580 UDFWCacheErrorHandler(
2581 IN PVOID Context,
2582 IN PWCACHE_ERROR_CONTEXT ErrorInfo
2583 )
2584 {
2585 InterlockedIncrement((PLONG)&(((PVCB)Context)->IoErrorCounter));
2586 return ErrorInfo->Status;
2587 }
2588
2589 #include "Include/misc_common.cpp"
2590 #include "Include/regtools.cpp"
2591