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