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