1 /************************************************************************* 2 * 3 * File: misc.c 4 * 5 * Module: Ext2 File System Driver (Kernel mode execution only) 6 * 7 * Description: 8 * This file contains some miscellaneous support routines. 9 * 10 * Author: Manoj Paul Joseph 11 * 12 * 13 *************************************************************************/ 14 15 #include "ext2fsd.h" 16 17 // define the file specific bug-check id 18 #define EXT2_BUG_CHECK_ID EXT2_FILE_MISC 19 20 #define DEBUG_LEVEL ( DEBUG_TRACE_MISC ) 21 22 /************************************************************************* 23 * 24 * Function: Ext2InitializeZones() 25 * 26 * Description: 27 * Allocates some memory for global zones used to allocate FSD structures. 28 * Either all memory will be allocated or we will back out gracefully. 29 * 30 * Expected Interrupt Level (for execution) : 31 * 32 * IRQL_PASSIVE_LEVEL 33 * 34 * Return Value: STATUS_SUCCESS/Error 35 * 36 *************************************************************************/ 37 NTSTATUS NTAPI Ext2InitializeZones( 38 void) 39 { 40 NTSTATUS RC = STATUS_SUCCESS; 41 uint32 SizeOfZone = Ext2GlobalData.DefaultZoneSizeInNumStructs; 42 uint32 SizeOfObjectNameZone = 0; 43 uint32 SizeOfCCBZone = 0; 44 uint32 SizeOfFCBZone = 0; 45 uint32 SizeOfByteLockZone = 0; 46 uint32 SizeOfIrpContextZone = 0; 47 48 try { 49 50 // initialize the spinlock protecting the zones 51 KeInitializeSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock)); 52 53 // determine memory requirements 54 switch (MmQuerySystemSize()) { 55 case MmSmallSystem: 56 // this is just for illustration purposes. I will multiply 57 // number of structures with some arbitrary amount depending 58 // upon available memory in the system ... You should choose a 59 // more intelligent method suitable to your memory consumption 60 // and the amount of memory available. 61 SizeOfObjectNameZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER); 62 SizeOfCCBZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER); 63 SizeOfFCBZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER); 64 SizeOfByteLockZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER); 65 SizeOfIrpContextZone = (2 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER); 66 break; 67 case MmMediumSystem: 68 SizeOfObjectNameZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER); 69 SizeOfCCBZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER); 70 SizeOfFCBZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER); 71 SizeOfByteLockZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER); 72 SizeOfIrpContextZone = (4 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER); 73 break; 74 case MmLargeSystem: 75 SizeOfObjectNameZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2ObjectName))) + sizeof(ZONE_SEGMENT_HEADER); 76 SizeOfCCBZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2CCB))) + sizeof(ZONE_SEGMENT_HEADER); 77 SizeOfFCBZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FCB))) + sizeof(ZONE_SEGMENT_HEADER); 78 SizeOfByteLockZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2FileLockInfo))) + sizeof(ZONE_SEGMENT_HEADER); 79 SizeOfIrpContextZone = (8 * SizeOfZone * Ext2QuadAlign(sizeof(Ext2IrpContext))) + sizeof(ZONE_SEGMENT_HEADER); 80 break; 81 } 82 83 // typical NT methodology (at least until *someone* exposed the "difference" between a server and workstation ;-) 84 if (MmIsThisAnNtAsSystem()) { 85 SizeOfObjectNameZone *= EXT2_NTAS_MULTIPLE; 86 SizeOfCCBZone *= EXT2_NTAS_MULTIPLE; 87 SizeOfFCBZone *= EXT2_NTAS_MULTIPLE; 88 SizeOfByteLockZone *= EXT2_NTAS_MULTIPLE; 89 SizeOfIrpContextZone *= EXT2_NTAS_MULTIPLE; 90 } 91 92 // allocate memory for each of the zones and initialize the zones ... 93 if (!(Ext2GlobalData.ObjectNameZone = Ext2AllocatePool(NonPagedPool, SizeOfObjectNameZone ))) { 94 RC = STATUS_INSUFFICIENT_RESOURCES; 95 try_return(); 96 } 97 98 if (!(Ext2GlobalData.CCBZone = Ext2AllocatePool(NonPagedPool, SizeOfCCBZone ))) { 99 RC = STATUS_INSUFFICIENT_RESOURCES; 100 try_return(); 101 } 102 103 if (!(Ext2GlobalData.FCBZone = Ext2AllocatePool(NonPagedPool, SizeOfFCBZone ))) { 104 RC = STATUS_INSUFFICIENT_RESOURCES; 105 try_return(); 106 } 107 108 if (!(Ext2GlobalData.ByteLockZone = Ext2AllocatePool(NonPagedPool, SizeOfByteLockZone ))) { 109 RC = STATUS_INSUFFICIENT_RESOURCES; 110 try_return(); 111 } 112 113 if (!(Ext2GlobalData.IrpContextZone = Ext2AllocatePool(NonPagedPool, SizeOfIrpContextZone ))) { 114 RC = STATUS_INSUFFICIENT_RESOURCES; 115 try_return(); 116 } 117 118 // initialize each of the zone headers ... 119 if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.ObjectNameZoneHeader), 120 Ext2QuadAlign(sizeof(Ext2ObjectName)), 121 Ext2GlobalData.ObjectNameZone, SizeOfObjectNameZone))) { 122 // failed the initialization, leave ... 123 try_return(); 124 } 125 126 if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.CCBZoneHeader), 127 Ext2QuadAlign(sizeof(Ext2CCB)), 128 Ext2GlobalData.CCBZone, 129 SizeOfCCBZone))) { 130 // failed the initialization, leave ... 131 try_return(); 132 } 133 134 if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.FCBZoneHeader), 135 Ext2QuadAlign(sizeof(Ext2FCB)), 136 Ext2GlobalData.FCBZone, 137 SizeOfFCBZone))) { 138 // failed the initialization, leave ... 139 try_return(); 140 } 141 142 if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.ByteLockZoneHeader), 143 Ext2QuadAlign(sizeof(Ext2FileLockInfo)), 144 Ext2GlobalData.ByteLockZone, 145 SizeOfByteLockZone))) { 146 // failed the initialization, leave ... 147 try_return(); 148 } 149 150 if (!NT_SUCCESS(RC = ExInitializeZone(&(Ext2GlobalData.IrpContextZoneHeader), 151 Ext2QuadAlign(sizeof(Ext2IrpContext)), 152 Ext2GlobalData.IrpContextZone, 153 SizeOfIrpContextZone))) { 154 // failed the initialization, leave ... 155 try_return(); 156 } 157 158 try_exit: NOTHING; 159 160 } finally { 161 if (!NT_SUCCESS(RC)) { 162 // invoke the destroy routine now ... 163 Ext2DestroyZones(); 164 } else { 165 // mark the fact that we have allocated zones ... 166 Ext2SetFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_ZONES_INITIALIZED); 167 } 168 } 169 170 return(RC); 171 } 172 173 174 /************************************************************************* 175 * 176 * Function: Ext2DestroyZones() 177 * 178 * Description: 179 * Free up the previously allocated memory. NEVER do this once the 180 * driver has been successfully loaded. 181 * 182 * Expected Interrupt Level (for execution) : 183 * 184 * IRQL_PASSIVE_LEVEL 185 * 186 * Return Value: None 187 * 188 *************************************************************************/ 189 void NTAPI Ext2DestroyZones( 190 void) 191 { 192 try { 193 // free up each of the pools 194 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.ObjectNameZone); 195 ExFreePool(Ext2GlobalData.ObjectNameZone); 196 197 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.CCBZone); 198 ExFreePool(Ext2GlobalData.CCBZone); 199 200 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.FCBZone); 201 ExFreePool(Ext2GlobalData.FCBZone); 202 203 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.ByteLockZone); 204 ExFreePool(Ext2GlobalData.ByteLockZone); 205 206 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", Ext2GlobalData.IrpContextZone); 207 ExFreePool(Ext2GlobalData.IrpContextZone); 208 } 209 finally 210 { 211 Ext2ClearFlag(Ext2GlobalData.Ext2Flags, EXT2_DATA_FLAGS_ZONES_INITIALIZED); 212 } 213 214 return; 215 } 216 217 218 /************************************************************************* 219 * 220 * Function: Ext2IsIrpTopLevel() 221 * 222 * Description: 223 * Helps the FSD determine who the "top level" caller is for this 224 * request. A request can originate directly from a user process 225 * (in which case, the "top level" will be NULL when this routine 226 * is invoked), OR the user may have originated either from the NT 227 * Cache Manager/VMM ("top level" may be set), or this could be a 228 * recursion into our code in which we would have set the "top level" 229 * field the last time around. 230 * 231 * Expected Interrupt Level (for execution) : 232 * 233 * whatever level a particular dispatch routine is invoked at. 234 * 235 * Return Value: TRUE/FALSE (TRUE if top level was NULL when routine invoked) 236 * 237 *************************************************************************/ 238 BOOLEAN NTAPI Ext2IsIrpTopLevel( 239 PIRP Irp) // the IRP sent to our dispatch routine 240 { 241 BOOLEAN ReturnCode = FALSE; 242 243 if (IoGetTopLevelIrp() == NULL) 244 { 245 // OK, so we can set ourselves to become the "top level" component 246 IoSetTopLevelIrp( Irp ); 247 ReturnCode = TRUE; 248 } 249 250 return(ReturnCode); 251 } 252 253 254 /************************************************************************* 255 * 256 * Function: Ext2ExceptionFilter() 257 * 258 * Description: 259 * This routines allows the driver to determine whether the exception 260 * is an "allowed" exception i.e. one we should not-so-quietly consume 261 * ourselves, or one which should be propagated onwards in which case 262 * we will most likely bring down the machine. 263 * 264 * This routine employs the services of FsRtlIsNtstatusExpected(). This 265 * routine returns a BOOLEAN result. A RC of FALSE will cause us to return 266 * EXCEPTION_CONTINUE_SEARCH which will probably cause a panic. 267 * The FsRtl.. routine returns FALSE iff exception values are (currently) : 268 * STATUS_DATATYPE_MISALIGNMENT || STATUS_ACCESS_VIOLATION || 269 * STATUS_ILLEGAL_INSTRUCTION || STATUS_INSTRUCTION_MISALIGNMENT 270 * 271 * Expected Interrupt Level (for execution) : 272 * 273 * ? 274 * 275 * Return Value: EXCEPTION_EXECUTE_HANDLER/EXECEPTION_CONTINUE_SEARCH 276 * 277 *************************************************************************/ 278 long NTAPI Ext2ExceptionFilter( 279 PtrExt2IrpContext PtrIrpContext, 280 PEXCEPTION_POINTERS PtrExceptionPointers ) 281 { 282 long ReturnCode = EXCEPTION_EXECUTE_HANDLER; 283 NTSTATUS ExceptionCode = STATUS_SUCCESS; 284 285 // figure out the exception code 286 ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionCode; 287 288 if ((ExceptionCode == STATUS_IN_PAGE_ERROR) && (PtrExceptionPointers->ExceptionRecord->NumberParameters >= 3)) 289 { 290 ExceptionCode = PtrExceptionPointers->ExceptionRecord->ExceptionInformation[2]; 291 } 292 293 if (PtrIrpContext) 294 { 295 PtrIrpContext->SavedExceptionCode = ExceptionCode; 296 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_EXCEPTION); 297 } 298 299 // check if we should propagate this exception or not 300 if (!(FsRtlIsNtstatusExpected(ExceptionCode))) 301 { 302 // we are not ok, propagate this exception. 303 // NOTE: we will bring down the machine ... 304 ReturnCode = EXCEPTION_CONTINUE_SEARCH; 305 306 // better free up the IrpContext now ... 307 if (PtrIrpContext) 308 { 309 Ext2ReleaseIrpContext(PtrIrpContext); 310 } 311 } 312 313 // if you wish to perform some special processing when 314 // not propagating the exception, set up the state for 315 // special processing now ... 316 317 // return the appropriate code 318 return(ReturnCode); 319 } 320 321 /************************************************************************* 322 * 323 * Function: Ext2ExceptionHandler() 324 * 325 * Description: 326 * One of the routines in the FSD or in the modules we invoked encountered 327 * an exception. We have decided that we will "handle" the exception. 328 * Therefore we will prevent the machine from a panic ... 329 * You can do pretty much anything you choose to in your commercial 330 * driver at this point to ensure a graceful exit. In the sample 331 * driver, I will simply free up the IrpContext (if any), set the 332 * error code in the IRP and complete the IRP at this time ... 333 * 334 * Expected Interrupt Level (for execution) : 335 * 336 * ? 337 * 338 * Return Value: Error code 339 * 340 *************************************************************************/ 341 NTSTATUS NTAPI Ext2ExceptionHandler( 342 PtrExt2IrpContext PtrIrpContext, 343 PIRP Irp) 344 { 345 NTSTATUS RC; 346 347 ASSERT(Irp); 348 349 if (PtrIrpContext) 350 { 351 RC = PtrIrpContext->SavedExceptionCode; 352 // Free irp context here 353 Ext2ReleaseIrpContext(PtrIrpContext); 354 } 355 else 356 { 357 // must be insufficient resources ...? 358 RC = STATUS_INSUFFICIENT_RESOURCES; 359 } 360 361 // set the error code in the IRP 362 Irp->IoStatus.Status = RC; 363 Irp->IoStatus.Information = 0; 364 365 // complete the IRP 366 IoCompleteRequest(Irp, IO_NO_INCREMENT); 367 368 return(RC); 369 } 370 371 /************************************************************************* 372 * 373 * Function: Ext2LogEvent() 374 * 375 * Description: 376 * Log a message in the NT Event Log. This is a rather simplistic log 377 * methodology since you can potentially utilize the event log to 378 * provide a lot of information to the user (and you should too!) 379 * 380 * Expected Interrupt Level (for execution) : 381 * 382 * IRQL_PASSIVE_LEVEL 383 * 384 * Return Value: None 385 * 386 *************************************************************************/ 387 void NTAPI Ext2LogEvent( 388 NTSTATUS Ext2EventLogId, // the Ext2 private message id 389 NTSTATUS RC) // any NT error code we wish to log ... 390 { 391 try 392 { 393 394 // Implement a call to IoAllocateErrorLogEntry() followed by a call 395 // to IoWriteErrorLogEntry(). You should note that the call to IoWriteErrorLogEntry() 396 // will free memory for the entry once the write completes (which in actuality 397 // is an asynchronous operation). 398 399 } 400 except (EXCEPTION_EXECUTE_HANDLER) 401 { 402 // nothing really we can do here, just do not wish to crash ... 403 NOTHING; 404 } 405 406 return; 407 } 408 409 /************************************************************************* 410 * 411 * Function: Ext2AllocateObjectName() 412 * 413 * Description: 414 * Allocate a new ObjectName structure to represent an open on-disk object. 415 * Also initialize the ObjectName structure to NULL. 416 * 417 * Expected Interrupt Level (for execution) : 418 * 419 * IRQL_PASSIVE_LEVEL 420 * 421 * Return Value: A pointer to the ObjectName structure OR NULL. 422 * 423 *************************************************************************/ 424 PtrExt2ObjectName NTAPI Ext2AllocateObjectName( 425 void) 426 { 427 PtrExt2ObjectName PtrObjectName = NULL; 428 BOOLEAN AllocatedFromZone = TRUE; 429 //KIRQL CurrentIrql; 430 /* 431 // first, try to allocate out of the zone 432 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); 433 if (!ExIsFullZone(&(Ext2GlobalData.ObjectNameZoneHeader))) { 434 // we have enough memory 435 PtrObjectName = (PtrExt2ObjectName)ExAllocateFromZone(&(Ext2GlobalData.ObjectNameZoneHeader)); 436 437 // release the spinlock 438 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 439 } else { 440 // release the spinlock 441 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 442 443 // if we failed to obtain from the zone, get it directly from the VMM 444 */ 445 PtrObjectName = (PtrExt2ObjectName)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2ObjectName)) ); 446 AllocatedFromZone = FALSE; 447 /* 448 } 449 */ 450 // if we could not obtain the required memory, bug-check. 451 // Do NOT do this in your commercial driver, instead handle the error gracefully ... 452 if (!PtrObjectName) 453 { 454 Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2ObjectName)), 0); 455 } 456 457 // zero out the allocated memory block 458 RtlZeroMemory( PtrObjectName, Ext2QuadAlign(sizeof(Ext2ObjectName)) ); 459 460 // set up some fields ... 461 PtrObjectName->NodeIdentifier.NodeType = EXT2_NODE_TYPE_OBJECT_NAME; 462 PtrObjectName->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2ObjectName)); 463 464 465 if (!AllocatedFromZone) 466 { 467 Ext2SetFlag(PtrObjectName->ObjectNameFlags, EXT2_OB_NAME_NOT_FROM_ZONE); 468 } 469 470 return(PtrObjectName); 471 } 472 473 474 /************************************************************************* 475 * 476 * Function: Ext2ReleaseObjectName() 477 * 478 * Description: 479 * Deallocate a previously allocated structure. 480 * 481 * Expected Interrupt Level (for execution) : 482 * 483 * IRQL_PASSIVE_LEVEL 484 * 485 * Return Value: None 486 * 487 *************************************************************************/ 488 void NTAPI Ext2ReleaseObjectName( 489 PtrExt2ObjectName PtrObjectName) 490 { 491 #ifdef USE_ZONES 492 KIRQL CurrentIrql; 493 #endif 494 495 ASSERT(PtrObjectName); 496 PtrObjectName->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; 497 #ifdef USE_ZONES 498 499 // give back memory either to the zone or to the VMM 500 if (!(PtrObjectName->ObjectNameFlags & EXT2_OB_NAME_NOT_FROM_ZONE)) 501 { 502 // back to the zone 503 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); 504 ExFreeToZone(&(Ext2GlobalData.ObjectNameZoneHeader), PtrObjectName); 505 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 506 } 507 else 508 { 509 #endif 510 511 Ext2DeallocateUnicodeString( & PtrObjectName->ObjectName ); 512 513 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrObjectName); 514 ExFreePool(PtrObjectName); 515 516 #ifdef USE_ZONES 517 } 518 #endif 519 return; 520 } 521 522 /************************************************************************* 523 * 524 * Function: Ext2AllocateCCB() 525 * 526 * Description: 527 * Allocate a new CCB structure to represent an open on-disk object. 528 * Also initialize the CCB structure to NULL. 529 * 530 * Expected Interrupt Level (for execution) : 531 * 532 * IRQL_PASSIVE_LEVEL 533 * 534 * Return Value: A pointer to the CCB structure OR NULL. 535 * 536 *************************************************************************/ 537 PtrExt2CCB NTAPI Ext2AllocateCCB( 538 void) 539 { 540 PtrExt2CCB PtrCCB = NULL; 541 BOOLEAN AllocatedFromZone = TRUE; 542 #ifdef USE_ZONES 543 KIRQL CurrentIrql; 544 #endif 545 546 547 #ifdef USE_ZONES 548 // first, try to allocate out of the zone 549 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); 550 if (!ExIsFullZone(&(Ext2GlobalData.CCBZoneHeader))) 551 { 552 // we have enough memory 553 PtrCCB = (PtrExt2CCB)ExAllocateFromZone(&(Ext2GlobalData.CCBZoneHeader)); 554 555 // release the spinlock 556 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 557 } 558 else 559 { 560 // release the spinlock 561 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 562 // if we failed to obtain from the zone, get it directly from the VMM 563 #endif 564 565 PtrCCB = (PtrExt2CCB)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2CCB)) ); 566 AllocatedFromZone = FALSE; 567 568 #ifdef USE_ZONES 569 } 570 #endif 571 572 // if we could not obtain the required memory, bug-check. 573 // Do NOT do this in your commercial driver, instead handle the error gracefully ... 574 if (!PtrCCB) 575 { 576 Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2CCB)), 0); 577 } 578 579 // zero out the allocated memory block 580 RtlZeroMemory(PtrCCB, Ext2QuadAlign(sizeof(Ext2CCB))); 581 582 // set up some fields ... 583 PtrCCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_CCB; 584 PtrCCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2CCB)); 585 586 587 if (!AllocatedFromZone) 588 { 589 Ext2SetFlag(PtrCCB->CCBFlags, EXT2_CCB_NOT_FROM_ZONE); 590 } 591 592 return(PtrCCB); 593 } 594 595 /************************************************************************* 596 * 597 * Function: Ext2ReleaseCCB() 598 * 599 * Description: 600 * Deallocate a previously allocated structure. 601 * 602 * Expected Interrupt Level (for execution) : 603 * 604 * IRQL_PASSIVE_LEVEL 605 * 606 * Return Value: None 607 * 608 *************************************************************************/ 609 void NTAPI Ext2ReleaseCCB( 610 PtrExt2CCB PtrCCB) 611 { 612 #ifdef USE_ZONES 613 KIRQL CurrentIrql; 614 #endif 615 616 ASSERT( PtrCCB ); 617 if(PtrCCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_CCB) 618 { 619 Ext2Panic( PtrCCB, PtrCCB->NodeIdentifier.NodeType, EXT2_NODE_TYPE_CCB ) ; 620 } 621 622 Ext2DeallocateUnicodeString( &PtrCCB->DirectorySearchPattern ); 623 Ext2DeallocateUnicodeString( &PtrCCB->AbsolutePathName ); 624 Ext2DeallocateUnicodeString( &PtrCCB->RenameLinkTargetFileName ); 625 626 627 #ifdef USE_ZONES 628 629 // give back memory either to the zone or to the VMM 630 if (!(PtrCCB->CCBFlags & EXT2_CCB_NOT_FROM_ZONE)) 631 { 632 // back to the zone 633 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); 634 ExFreeToZone(&(Ext2GlobalData.CCBZoneHeader), PtrCCB); 635 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 636 } 637 else 638 { 639 #endif 640 PtrCCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; 641 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrCCB); 642 ExFreePool(PtrCCB); 643 644 #ifdef USE_ZONES 645 } 646 #endif 647 648 return; 649 } 650 651 /************************************************************************* 652 * 653 * Function: Ext2AllocateFCB() 654 * 655 * Description: 656 * Allocate a new FCB structure to represent an open on-disk object. 657 * Also initialize the FCB structure to NULL. 658 * 659 * Expected Interrupt Level (for execution) : 660 * 661 * IRQL_PASSIVE_LEVEL 662 * 663 * Return Value: A pointer to the FCB structure OR NULL. 664 * 665 *************************************************************************/ 666 PtrExt2FCB NTAPI Ext2AllocateFCB( 667 void) 668 { 669 PtrExt2FCB PtrFCB = NULL; 670 BOOLEAN AllocatedFromZone = TRUE; 671 #ifdef USE_ZONES 672 KIRQL CurrentIrql; 673 #endif 674 675 // first, try to allocate out of the zone 676 #ifdef USE_ZONES 677 678 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); 679 if (!ExIsFullZone(&(Ext2GlobalData.FCBZoneHeader))) { 680 // we have enough memory 681 PtrFCB = (PtrExt2FCB)ExAllocateFromZone(&(Ext2GlobalData.FCBZoneHeader)); 682 683 // release the spinlock 684 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 685 } else { 686 // release the spinlock 687 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 688 #endif 689 // if we failed to obtain from the zone, get it directly from the VMM 690 PtrFCB = (PtrExt2FCB)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2FCB)) ); 691 AllocatedFromZone = FALSE; 692 693 #ifdef USE_ZONES 694 } 695 #endif 696 697 // if we could not obtain the required memory, bug-check. 698 // Do NOT do this in your commercial driver, instead handle the error gracefully ... 699 if (!PtrFCB) 700 { 701 Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2FCB)), 0); 702 } 703 704 // zero out the allocated memory block 705 RtlZeroMemory(PtrFCB, Ext2QuadAlign(sizeof(Ext2FCB))); 706 707 // set up some fields ... 708 PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FCB; 709 PtrFCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2FCB)); 710 711 712 if (!AllocatedFromZone) 713 { 714 Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE); 715 } 716 717 return(PtrFCB); 718 } 719 720 721 /************************************************************************* 722 * 723 * Function: Ext2CreateNewFCB() 724 * 725 * Description: 726 * We want to create a new FCB. We will also create a new CCB (presumably) 727 * later. Simply allocate a new FCB structure and initialize fields 728 * appropriately. 729 * This function also takes the file size values that the caller must 730 * have obtained and will set the file size fields appropriately in the 731 * CommonFCBHeader. 732 * Finally, this routine will initialize the FileObject structure passed 733 * in to this function. If you decide to fail the call later, remember 734 * to uninitialize the fields. 735 * 736 * Expected Interrupt Level (for execution) : 737 * 738 * IRQL_PASSIVE_LEVEL 739 * 740 * Return Value: A pointer to the FCB structure OR NULL. 741 * 742 *************************************************************************/ 743 NTSTATUS NTAPI Ext2CreateNewFCB( 744 PtrExt2FCB *ReturnedFCB, 745 LARGE_INTEGER AllocationSize, 746 LARGE_INTEGER EndOfFile, 747 PFILE_OBJECT PtrFileObject, 748 PtrExt2VCB PtrVCB, 749 PtrExt2ObjectName PtrObjectName) 750 { 751 NTSTATUS RC = STATUS_SUCCESS; 752 753 PtrExt2FCB PtrFCB = NULL; 754 PtrExt2NTRequiredFCB PtrReqdFCB = NULL; 755 PFSRTL_COMMON_FCB_HEADER PtrCommonFCBHeader = NULL; 756 757 ASSERT( PtrVCB ); 758 759 try 760 { 761 if( !PtrFileObject ) 762 { 763 PtrFCB = Ext2GetUsedFCB( PtrVCB ); 764 765 } 766 else 767 { 768 // Obtain a new FCB structure. 769 // The function Ext2AllocateFCB() will obtain a new structure either 770 // from a zone or from memory requested directly from the VMM. 771 PtrFCB = Ext2AllocateFCB(); 772 } 773 if (!PtrFCB) 774 { 775 // Assume lack of memory. 776 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 777 } 778 779 // Initialize fields required to interface with the NT Cache Manager. 780 // Note that the returned structure has already been zeroed. This means 781 // that the SectionObject structure has been zeroed which is a 782 // requirement for newly created FCB structures. 783 PtrReqdFCB = &(PtrFCB->NTRequiredFCB); 784 785 // Initialize the MainResource and PagingIoResource structures now. 786 ExInitializeResourceLite(&(PtrReqdFCB->MainResource)); 787 Ext2SetFlag(PtrFCB->FCBFlags, EXT2_INITIALIZED_MAIN_RESOURCE); 788 789 ExInitializeResourceLite(&(PtrReqdFCB->PagingIoResource)); 790 Ext2SetFlag(PtrFCB->FCBFlags, EXT2_INITIALIZED_PAGING_IO_RESOURCE); 791 792 // Start initializing the fields contained in the CommonFCBHeader. 793 PtrCommonFCBHeader = &(PtrReqdFCB->CommonFCBHeader); 794 795 // Disallow fast-IO for now. 796 PtrCommonFCBHeader->IsFastIoPossible = FastIoIsNotPossible; 797 798 // Initialize the MainResource and PagingIoResource pointers in 799 // the CommonFCBHeader structure to point to the ERESOURCE structures we 800 // have allocated and already initialized above. 801 PtrCommonFCBHeader->Resource = &(PtrReqdFCB->MainResource); 802 PtrCommonFCBHeader->PagingIoResource = &(PtrReqdFCB->PagingIoResource); 803 804 // Ignore the Flags field in the CommonFCBHeader for now. Part 3 805 // of the book describes it in greater detail. 806 807 // Initialize the file size values here. 808 PtrCommonFCBHeader->AllocationSize = AllocationSize; 809 PtrCommonFCBHeader->FileSize = EndOfFile; 810 811 // The following will disable ValidDataLength support. However, your 812 // FSD may choose to support this concept. 813 PtrCommonFCBHeader->ValidDataLength.LowPart = 0xFFFFFFFF; 814 PtrCommonFCBHeader->ValidDataLength.HighPart = 0x7FFFFFFF; 815 816 // Initialize other fields for the FCB here ... 817 PtrFCB->PtrVCB = PtrVCB; 818 819 // caller MUST ensure that VCB has been acquired exclusively 820 InsertTailList(&(PtrVCB->FCBListHead), &(PtrFCB->NextFCB)); 821 822 823 InitializeListHead(&(PtrFCB->CCBListHead)); 824 825 // Initialize fields contained in the file object now. 826 if( PtrFileObject ) 827 { 828 PtrFileObject->PrivateCacheMap = NULL; 829 // Note that we could have just as well taken the value of PtrReqdFCB 830 // directly below. The bottom line however is that the FsContext 831 // field must point to a FSRTL_COMMON_FCB_HEADER structure. 832 PtrFileObject->FsContext = (void *)(PtrCommonFCBHeader); 833 PtrFileObject->SectionObjectPointer = &(PtrFCB->NTRequiredFCB.SectionObject) ; 834 } 835 836 // Initialising the object name... 837 PtrFCB->FCBName = PtrObjectName; 838 839 // Returning the FCB... 840 *ReturnedFCB = PtrFCB; 841 try_exit: NOTHING; 842 } 843 844 finally 845 { 846 847 } 848 849 return(RC); 850 } 851 852 853 /************************************************************************* 854 * 855 * Function: Ext2ReleaseFCB() 856 * 857 * Description: 858 * Deallocate a previously allocated structure. 859 * 860 * Expected Interrupt Level (for execution) : 861 * 862 * IRQL_PASSIVE_LEVEL 863 * 864 * Return Value: None 865 * 866 *************************************************************************/ 867 void NTAPI Ext2ReleaseFCB( 868 PtrExt2FCB PtrFCB) 869 { 870 //KIRQL CurrentIrql; 871 872 AssertFCB( PtrFCB ); 873 874 if( PtrFCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_FCB ) 875 { 876 Ext2Panic( PtrFCB, PtrFCB->NodeIdentifier.NodeType, EXT2_NODE_TYPE_FCB ) ; 877 } 878 879 880 PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; 881 882 /* 883 // give back memory either to the zone or to the VMM 884 if (!(PtrFCB->FCBFlags & EXT2_FCB_NOT_FROM_ZONE)) 885 { 886 // back to the zone 887 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); 888 ExFreeToZone(&(Ext2GlobalData.FCBZoneHeader), PtrFCB); 889 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 890 } 891 else 892 { 893 */ 894 895 ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.MainResource ); 896 ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.PagingIoResource ); 897 898 RemoveEntryList(&(PtrFCB->NextFCB)); 899 900 if( PtrFCB->FCBName ) 901 { 902 Ext2ReleaseObjectName( PtrFCB->FCBName ); 903 } 904 905 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrFCB); 906 ExFreePool(PtrFCB); 907 908 /* 909 } 910 */ 911 912 return; 913 } 914 915 /************************************************************************* 916 * 917 * Function: Ext2AllocateByteLocks() 918 * 919 * Description: 920 * Allocate a new byte range lock structure and initialize it to NULL. 921 * 922 * Expected Interrupt Level (for execution) : 923 * 924 * IRQL_PASSIVE_LEVEL 925 * 926 * Return Value: A pointer to the Ext2ByteLocks structure OR NULL. 927 * 928 *************************************************************************/ 929 PtrExt2FileLockInfo NTAPI Ext2AllocateByteLocks( 930 void) 931 { 932 PtrExt2FileLockInfo PtrByteLocks = NULL; 933 BOOLEAN AllocatedFromZone = TRUE; 934 KIRQL CurrentIrql; 935 936 // first, try to allocate out of the zone 937 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); 938 if (!ExIsFullZone(&(Ext2GlobalData.ByteLockZoneHeader))) 939 { 940 // we have enough memory 941 PtrByteLocks = (PtrExt2FileLockInfo)ExAllocateFromZone(&(Ext2GlobalData.ByteLockZoneHeader)); 942 943 // release the spinlock 944 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 945 } 946 else 947 { 948 // release the spinlock 949 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 950 951 // if we failed to obtain from the zone, get it directly from the VMM 952 PtrByteLocks = (PtrExt2FileLockInfo)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2FileLockInfo)) ); 953 AllocatedFromZone = FALSE; 954 } 955 956 // if we could not obtain the required memory, bug-check. 957 // Do NOT do this in your commercial driver, instead handle the error gracefully ... 958 if (!PtrByteLocks) 959 { 960 Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2FileLockInfo)), 0); 961 } 962 963 // zero out the allocated memory block 964 RtlZeroMemory(PtrByteLocks, Ext2QuadAlign(sizeof(PtrExt2FileLockInfo))); 965 966 if (!AllocatedFromZone) 967 { 968 Ext2SetFlag(PtrByteLocks->FileLockFlags, EXT2_BYTE_LOCK_NOT_FROM_ZONE); 969 } 970 971 return(PtrByteLocks); 972 } 973 974 /************************************************************************* 975 * 976 * Function: Ext2ReleaseByteLocks() 977 * 978 * Description: 979 * Deallocate a previously allocated structure. 980 * 981 * Expected Interrupt Level (for execution) : 982 * 983 * IRQL_PASSIVE_LEVEL 984 * 985 * Return Value: None 986 * 987 *************************************************************************/ 988 void NTAPI Ext2ReleaseByteLocks( 989 PtrExt2FileLockInfo PtrByteLocks) 990 { 991 KIRQL CurrentIrql; 992 993 ASSERT(PtrByteLocks); 994 995 // give back memory either to the zone or to the VMM 996 if (!(PtrByteLocks->FileLockFlags & EXT2_BYTE_LOCK_NOT_FROM_ZONE)) { 997 // back to the zone 998 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); 999 ExFreeToZone(&(Ext2GlobalData.ByteLockZoneHeader), PtrByteLocks); 1000 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 1001 } 1002 else 1003 { 1004 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrByteLocks); 1005 ExFreePool(PtrByteLocks); 1006 } 1007 1008 return; 1009 } 1010 1011 1012 /************************************************************************* 1013 * 1014 * Function: Ext2AllocateIrpContext() 1015 * 1016 * Description: 1017 * The sample FSD creates an IRP context for each request received. This 1018 * routine simply allocates (and initializes to NULL) a Ext2IrpContext 1019 * structure. 1020 * Most of the fields in the context structure are then initialized here. 1021 * 1022 * Expected Interrupt Level (for execution) : 1023 * 1024 * IRQL_PASSIVE_LEVEL 1025 * 1026 * Return Value: A pointer to the IrpContext structure OR NULL. 1027 * 1028 *************************************************************************/ 1029 PtrExt2IrpContext NTAPI Ext2AllocateIrpContext( 1030 PIRP Irp, 1031 PDEVICE_OBJECT PtrTargetDeviceObject) 1032 { 1033 PtrExt2IrpContext PtrIrpContext = NULL; 1034 BOOLEAN AllocatedFromZone = TRUE; 1035 //KIRQL CurrentIrql; 1036 PIO_STACK_LOCATION PtrIoStackLocation = NULL; 1037 1038 /* 1039 // Allocation from zone not done at present... 1040 1041 // first, try to allocate out of the zone 1042 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); 1043 if (!ExIsFullZone(&(Ext2GlobalData.IrpContextZoneHeader))) { 1044 // we have enough memory 1045 PtrIrpContext = (PtrExt2IrpContext)ExAllocateFromZone(&(Ext2GlobalData.IrpContextZoneHeader)); 1046 1047 // release the spinlock 1048 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 1049 } else { 1050 // release the spinlock 1051 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 1052 1053 1054 1055 1056 // if we failed to obtain from the zone, get it directly from the VMM 1057 PtrIrpContext = (PtrExt2IrpContext)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2IrpContext)) ); 1058 AllocatedFromZone = FALSE; 1059 } 1060 1061 //No Zone handling for now 1062 */ 1063 1064 PtrIrpContext = (PtrExt2IrpContext)Ext2AllocatePool(NonPagedPool, Ext2QuadAlign(sizeof(Ext2IrpContext)) ); 1065 AllocatedFromZone = FALSE; 1066 1067 // if we could not obtain the required memory, bug-check. 1068 // Do NOT do this in your commercial driver, instead handle the error gracefully ... 1069 if (!PtrIrpContext) 1070 { 1071 Ext2Panic(STATUS_INSUFFICIENT_RESOURCES, Ext2QuadAlign(sizeof(Ext2IrpContext)), 0); 1072 } 1073 1074 // zero out the allocated memory block 1075 RtlZeroMemory(PtrIrpContext, Ext2QuadAlign(sizeof(Ext2IrpContext))); 1076 1077 // set up some fields ... 1078 PtrIrpContext->NodeIdentifier.NodeType = EXT2_NODE_TYPE_IRP_CONTEXT; 1079 PtrIrpContext->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2IrpContext)); 1080 1081 1082 PtrIrpContext->Irp = Irp; 1083 PtrIrpContext->TargetDeviceObject = PtrTargetDeviceObject; 1084 1085 // copy over some fields from the IRP and set appropriate flag values 1086 if (Irp) 1087 { 1088 PtrIoStackLocation = IoGetCurrentIrpStackLocation(Irp); 1089 ASSERT(PtrIoStackLocation); 1090 1091 PtrIrpContext->MajorFunction = PtrIoStackLocation->MajorFunction; 1092 PtrIrpContext->MinorFunction = PtrIoStackLocation->MinorFunction; 1093 1094 // Often, a FSD cannot honor a request for asynchronous processing 1095 // of certain critical requests. For example, a "close" request on 1096 // a file object can typically never be deferred. Therefore, do not 1097 // be surprised if sometimes your FSD (just like all other FSD 1098 // implementations on the Windows NT system) has to override the flag 1099 // below. 1100 if( PtrIoStackLocation->FileObject ) 1101 { 1102 if (IoIsOperationSynchronous(Irp) ) 1103 { 1104 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK); 1105 } 1106 } 1107 else 1108 { 1109 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK); 1110 } 1111 } 1112 1113 if (!AllocatedFromZone) 1114 { 1115 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_NOT_FROM_ZONE); 1116 } 1117 1118 // Are we top-level ? This information is used by the dispatching code 1119 // later (and also by the FSD dispatch routine) 1120 if (IoGetTopLevelIrp() != Irp) 1121 { 1122 // We are not top-level. Note this fact in the context structure 1123 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_NOT_TOP_LEVEL); 1124 } 1125 1126 InitializeListHead( &PtrIrpContext->SavedBCBsListHead ); 1127 1128 return(PtrIrpContext); 1129 } 1130 1131 1132 /************************************************************************* 1133 * 1134 * Function: Ext2ReleaseIrpContext() 1135 * 1136 * Description: 1137 * Deallocate a previously allocated structure. 1138 * 1139 * Expected Interrupt Level (for execution) : 1140 * 1141 * IRQL_PASSIVE_LEVEL 1142 * 1143 * Return Value: None 1144 * 1145 *************************************************************************/ 1146 void NTAPI Ext2ReleaseIrpContext( 1147 PtrExt2IrpContext PtrIrpContext) 1148 { 1149 KIRQL CurrentIrql; 1150 1151 ASSERT(PtrIrpContext); 1152 1153 // Flush the saved BCBs... 1154 Ext2FlushSavedBCBs( PtrIrpContext ); 1155 1156 // give back memory either to the zone or to the VMM 1157 if (!(PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_NOT_FROM_ZONE)) 1158 { 1159 // back to the zone 1160 KeAcquireSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), &CurrentIrql); 1161 ExFreeToZone(&(Ext2GlobalData.IrpContextZoneHeader), PtrIrpContext); 1162 KeReleaseSpinLock(&(Ext2GlobalData.ZoneAllocationSpinLock), CurrentIrql); 1163 } 1164 else 1165 { 1166 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrIrpContext); 1167 ExFreePool(PtrIrpContext); 1168 } 1169 1170 return; 1171 } 1172 1173 /************************************************************************* 1174 * 1175 * Function: Ext2PostRequest() 1176 * 1177 * Description: 1178 * Queue up a request for deferred processing (in the context of a system 1179 * worker thread). The caller must have locked the user buffer (if required) 1180 * 1181 * Expected Interrupt Level (for execution) : 1182 * 1183 * IRQL_PASSIVE_LEVEL 1184 * 1185 * Return Value: STATUS_PENDING 1186 * 1187 *************************************************************************/ 1188 NTSTATUS NTAPI Ext2PostRequest( 1189 PtrExt2IrpContext PtrIrpContext, 1190 PIRP PtrIrp) 1191 { 1192 NTSTATUS RC = STATUS_PENDING; 1193 1194 DebugTrace(DEBUG_TRACE_ASYNC, " === Asynchronous request. Deferring processing", 0); 1195 1196 // mark the IRP pending 1197 IoMarkIrpPending(PtrIrp); 1198 1199 // queue up the request 1200 ExInterlockedInsertTailList( 1201 &Ext2GlobalData.ThreadQueue.ThreadQueueListHead, 1202 &PtrIrpContext->ThreadQueueListEntry, 1203 &Ext2GlobalData.ThreadQueue.SpinLock ); 1204 1205 KeSetEvent( &Ext2GlobalData.ThreadQueue.QueueEvent, 0, FALSE ); 1206 1207 1208 /***************** not using system worker threads ***************** 1209 ExInitializeWorkItem(&(PtrIrpContext->WorkQueueItem), Ext2CommonDispatch, PtrIrpContext); 1210 ExQueueWorkItem( &( PtrIrpContext->WorkQueueItem ), DelayedWorkQueue ); 1211 // CriticalWorkQueue 1212 *****************************************************************************/ 1213 1214 // return status pending 1215 return(RC); 1216 } 1217 1218 1219 /************************************************************************* 1220 * 1221 * Function: Ext2CommonDispatch() 1222 * 1223 * Description: 1224 * The common dispatch routine invoked in the context of a system worker 1225 * thread. All we do here is pretty much case off the major function 1226 * code and invoke the appropriate FSD dispatch routine for further 1227 * processing. 1228 * 1229 * Expected Interrupt Level (for execution) : 1230 * 1231 * IRQL PASSIVE_LEVEL 1232 * 1233 * Return Value: None 1234 * 1235 *************************************************************************/ 1236 void NTAPI Ext2CommonDispatch( 1237 void *Context ) // actually an IRPContext structure 1238 { 1239 NTSTATUS RC = STATUS_SUCCESS; 1240 PtrExt2IrpContext PtrIrpContext = NULL; 1241 PIRP PtrIrp = NULL; 1242 1243 // The context must be a pointer to an IrpContext structure 1244 PtrIrpContext = (PtrExt2IrpContext)Context; 1245 ASSERT(PtrIrpContext); 1246 1247 // Assert that the Context is legitimate 1248 if ((PtrIrpContext->NodeIdentifier.NodeType != EXT2_NODE_TYPE_IRP_CONTEXT) || (PtrIrpContext->NodeIdentifier.NodeSize != Ext2QuadAlign(sizeof(Ext2IrpContext)))) 1249 { 1250 // This does not look good 1251 Ext2Panic(EXT2_ERROR_INTERNAL_ERROR, PtrIrpContext->NodeIdentifier.NodeType, PtrIrpContext->NodeIdentifier.NodeSize); 1252 } 1253 1254 // Get a pointer to the IRP structure 1255 PtrIrp = PtrIrpContext->Irp; 1256 ASSERT(PtrIrp); 1257 1258 // Now, check if the FSD was top level when the IRP was originally invoked 1259 // and set the thread context (for the worker thread) appropriately 1260 if (PtrIrpContext->IrpContextFlags & EXT2_IRP_CONTEXT_NOT_TOP_LEVEL) 1261 { 1262 // The FSD is not top level for the original request 1263 // Set a constant value in TLS to reflect this fact 1264 IoSetTopLevelIrp((PIRP)FSRTL_FSP_TOP_LEVEL_IRP); 1265 } 1266 1267 // Since the FSD routine will now be invoked in the context of this worker 1268 // thread, we should inform the FSD that it is perfectly OK to block in 1269 // the context of this thread 1270 Ext2SetFlag(PtrIrpContext->IrpContextFlags, EXT2_IRP_CONTEXT_CAN_BLOCK); 1271 1272 FsRtlEnterFileSystem(); 1273 1274 try 1275 { 1276 1277 // Pre-processing has been completed; check the Major Function code value 1278 // either in the IrpContext (copied from the IRP), or directly from the 1279 // IRP itself (we will need a pointer to the stack location to do that), 1280 // Then, switch based on the value on the Major Function code 1281 switch (PtrIrpContext->MajorFunction) 1282 { 1283 case IRP_MJ_CREATE: 1284 // Invoke the common create routine 1285 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CREATE request asynchronously .", 0); 1286 (void)Ext2CommonCreate(PtrIrpContext, PtrIrp, FALSE); 1287 break; 1288 case IRP_MJ_READ: 1289 // Invoke the common read routine 1290 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_READ request asynchronously .", 0); 1291 (void)Ext2CommonRead(PtrIrpContext, PtrIrp, FALSE); 1292 break; 1293 case IRP_MJ_WRITE: 1294 // Invoke the common write routine 1295 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_WRITE request asynchronously .", 0); 1296 (void)Ext2CommonWrite(PtrIrpContext, PtrIrp ); 1297 break; 1298 1299 case IRP_MJ_CLEANUP: 1300 // Invoke the common read routine 1301 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CLEANUP request asynchronously .", 0); 1302 (void)Ext2CommonCleanup(PtrIrpContext, PtrIrp, FALSE); 1303 break; 1304 case IRP_MJ_CLOSE: 1305 // Invoke the common read routine 1306 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing IRP_MJ_CLOSE request asynchronously .", 0); 1307 (void)Ext2CommonClose ( PtrIrpContext, PtrIrp, FALSE ); 1308 break; 1309 1310 // Continue with the remaining possible dispatch routines below ... 1311 default: 1312 // This is the case where we have an invalid major function 1313 DebugTrace(DEBUG_TRACE_ASYNC, " === Serviceing asynchronous request. \nUnable to recoganise the IRP!!! How can this be!!!", 0); 1314 PtrIrp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST; 1315 PtrIrp->IoStatus.Information = 0; 1316 1317 Ext2BreakPoint(); 1318 1319 IoCompleteRequest(PtrIrp, IO_NO_INCREMENT); 1320 break; 1321 } 1322 } 1323 except (Ext2ExceptionFilter(PtrIrpContext, GetExceptionInformation())) 1324 { 1325 RC = Ext2ExceptionHandler(PtrIrpContext, PtrIrp); 1326 Ext2LogEvent(EXT2_ERROR_INTERNAL_ERROR, RC); 1327 } 1328 1329 // Enable preemption 1330 FsRtlExitFileSystem(); 1331 1332 // Ensure that the "top-level" field is cleared 1333 IoSetTopLevelIrp(NULL); 1334 1335 PsTerminateSystemThread( RC ); 1336 1337 1338 return; 1339 } 1340 1341 /************************************************************************* 1342 * 1343 * Function: Ext2InitializeVCB() 1344 * 1345 * Description: 1346 * Perform the initialization for a VCB structure. 1347 * 1348 * Expected Interrupt Level (for execution) : 1349 * 1350 * IRQL PASSIVE_LEVEL 1351 * 1352 * Return Value: None 1353 * 1354 *************************************************************************/ 1355 void NTAPI Ext2InitializeVCB( 1356 PDEVICE_OBJECT PtrVolumeDeviceObject, 1357 PDEVICE_OBJECT PtrTargetDeviceObject, 1358 PVPB PtrVPB, 1359 PLARGE_INTEGER AllocationSize ) 1360 { 1361 NTSTATUS RC = STATUS_SUCCESS; 1362 PtrExt2VCB PtrVCB = NULL; 1363 BOOLEAN VCBResourceInitialized = FALSE; 1364 1365 PtrVCB = (PtrExt2VCB)(PtrVolumeDeviceObject->DeviceExtension); 1366 1367 // Zero it out (typically this has already been done by the I/O 1368 // Manager but it does not hurt to do it again)! 1369 RtlZeroMemory(PtrVCB, sizeof(Ext2VCB)); 1370 1371 // Initialize the signature fields 1372 PtrVCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_VCB; 1373 PtrVCB->NodeIdentifier.NodeSize = sizeof(Ext2VCB); 1374 1375 // Initialize the ERESOURCE objects. 1376 RC = ExInitializeResourceLite(&(PtrVCB->VCBResource)); 1377 RC = ExInitializeResourceLite(&(PtrVCB->PagingIoResource)); 1378 1379 ASSERT(NT_SUCCESS(RC)); 1380 VCBResourceInitialized = TRUE; 1381 1382 PtrVCB->TargetDeviceObject = PtrTargetDeviceObject; 1383 1384 PtrVCB->VCBDeviceObject = PtrVolumeDeviceObject; 1385 1386 PtrVCB->PtrVPB = PtrVPB; 1387 1388 // Initialize the list anchor (head) for some lists in this VCB. 1389 InitializeListHead(&(PtrVCB->FCBListHead)); 1390 InitializeListHead(&(PtrVCB->NextNotifyIRP)); 1391 InitializeListHead(&(PtrVCB->VolumeOpenListHead)); 1392 InitializeListHead(&(PtrVCB->ClosableFCBs.ClosableFCBListHead)); 1393 PtrVCB->ClosableFCBs.Count = 0; 1394 1395 // Initialize the notify IRP list mutex 1396 KeInitializeMutex(&(PtrVCB->NotifyIRPMutex), 0); 1397 1398 // Set the initial file size values appropriately. Note that your FSD may 1399 // wish to guess at the initial amount of information you would like to 1400 // read from the disk until you have really determined that this a valid 1401 // logical volume (on disk) that you wish to mount. 1402 PtrVCB->CommonVCBHeader.AllocationSize.QuadPart = AllocationSize->QuadPart; 1403 1404 PtrVCB->CommonVCBHeader.FileSize.QuadPart = AllocationSize->QuadPart; 1405 // You typically do not want to bother with valid data length callbacks 1406 // from the Cache Manager for the file stream opened for volume metadata 1407 // information 1408 PtrVCB->CommonVCBHeader.ValidDataLength.LowPart = 0xFFFFFFFF; 1409 PtrVCB->CommonVCBHeader.ValidDataLength.HighPart = 0x7FFFFFFF; 1410 1411 PtrVCB->CommonVCBHeader.IsFastIoPossible = FastIoIsNotPossible; 1412 1413 PtrVCB->CommonVCBHeader.Resource = &(PtrVCB->VCBResource); 1414 PtrVCB->CommonVCBHeader.PagingIoResource = &(PtrVCB->PagingIoResource); 1415 1416 // Create a stream file object for this volume. 1417 PtrVCB->PtrStreamFileObject = IoCreateStreamFileObject(NULL, 1418 PtrVCB->PtrVPB->RealDevice); 1419 ASSERT(PtrVCB->PtrStreamFileObject); 1420 1421 // Initialize some important fields in the newly created file object. 1422 PtrVCB->PtrStreamFileObject->FsContext = (void *)(&PtrVCB->CommonVCBHeader); 1423 PtrVCB->PtrStreamFileObject->FsContext2 = NULL; 1424 PtrVCB->PtrStreamFileObject->SectionObjectPointer = &(PtrVCB->SectionObject); 1425 1426 PtrVCB->PtrStreamFileObject->Vpb = PtrVPB; 1427 PtrVCB->PtrStreamFileObject->ReadAccess = TRUE; 1428 PtrVCB->PtrStreamFileObject->WriteAccess = TRUE; 1429 1430 // Link this chap onto the global linked list of all VCB structures. 1431 DebugTrace(DEBUG_TRACE_MISC, "*** Attempting to acquire Global Resource Exclusively [FileInfo]", 0); 1432 ExAcquireResourceExclusiveLite(&(Ext2GlobalData.GlobalDataResource), TRUE); 1433 InsertTailList(&(Ext2GlobalData.NextVCB), &(PtrVCB->NextVCB)); 1434 DebugTrace(DEBUG_TRACE_MISC, "*** Global Resource Acquired [FileInfo]", 0); 1435 1436 1437 1438 // Initialize caching for the stream file object. 1439 CcInitializeCacheMap(PtrVCB->PtrStreamFileObject, (PCC_FILE_SIZES)(&(PtrVCB->CommonVCBHeader.AllocationSize)), 1440 TRUE, // We will use pinned access. 1441 &(Ext2GlobalData.CacheMgrCallBacks), PtrVCB ); 1442 1443 1444 Ext2ReleaseResource(&(Ext2GlobalData.GlobalDataResource)); 1445 DebugTrace(DEBUG_TRACE_MISC, "*** Global Resource Released[FileInfo]", 0); 1446 1447 // Mark the fact that this VCB structure is initialized. 1448 Ext2SetFlag(PtrVCB->VCBFlags, EXT2_VCB_FLAGS_VCB_INITIALIZED); 1449 PtrVCB->PtrGroupDescriptors = NULL; 1450 PtrVCB->NoOfGroups = 0; 1451 return; 1452 } 1453 1454 1455 1456 /************************************************************************* 1457 * 1458 * Function: Ext2CompleteRequest() 1459 * 1460 * Description: 1461 * This routine completes a Irp. 1462 * 1463 * Expected Interrupt Level (for execution) : 1464 * 1465 * ??? 1466 * 1467 * Arguments: 1468 * 1469 * Irp - Supplies the Irp being processed 1470 * 1471 * Status - Supplies the status to complete the Irp with 1472 * 1473 * Return Value: none 1474 * 1475 *************************************************************************/ 1476 void NTAPI Ext2CompleteRequest( 1477 IN PIRP Irp OPTIONAL, 1478 IN NTSTATUS Status 1479 ) 1480 { 1481 // 1482 // If we have an Irp then complete the irp. 1483 // 1484 1485 if (Irp != NULL) 1486 { 1487 1488 // 1489 // We got an error, so zero out the information field before 1490 // completing the request if this was an input operation. 1491 // Otherwise IopCompleteRequest will try to copy to the user's buffer. 1492 // 1493 1494 if ( NT_ERROR(Status) && 1495 FlagOn(Irp->Flags, IRP_INPUT_OPERATION) ) { 1496 1497 Irp->IoStatus.Information = 0; 1498 } 1499 1500 Irp->IoStatus.Status = Status; 1501 1502 IoCompleteRequest( Irp, IO_DISK_INCREMENT ); 1503 } 1504 return; 1505 } 1506 1507 1508 /************************************************************************* 1509 * 1510 * Function: Ext2CreateNewCCB() 1511 * 1512 * Description: 1513 * We want to create a new CCB. 1514 * 1515 * Expected Interrupt Level (for execution) : 1516 * 1517 * IRQL_PASSIVE_LEVEL 1518 * 1519 * Return Value: A pointer to the CCB structure OR NULL. 1520 * 1521 *************************************************************************/ 1522 NTSTATUS NTAPI Ext2CreateNewCCB( 1523 PtrExt2CCB *ReturnedCCB, 1524 PtrExt2FCB PtrFCB, 1525 PFILE_OBJECT PtrFileObject ) 1526 { 1527 PtrExt2CCB PtrCCB; 1528 NTSTATUS RC = STATUS_SUCCESS; 1529 1530 try 1531 { 1532 1533 PtrCCB = Ext2AllocateCCB(); 1534 if (!PtrFCB) 1535 { 1536 // Assume lack of memory. 1537 try_return(RC = STATUS_INSUFFICIENT_RESOURCES); 1538 } 1539 PtrCCB->PtrFCB = PtrFCB; 1540 1541 PtrCCB->PtrFileObject = PtrFileObject; 1542 PtrCCB->CurrentByteOffset.QuadPart = 0; 1543 1544 if( PtrFCB->ClosableFCBs.OnClosableFCBList ) 1545 { 1546 // This FCB was on the Closable List... 1547 // Taking it off the list... 1548 // 1549 RemoveEntryList( &PtrFCB->ClosableFCBs.ClosableFCBList ); 1550 PtrFCB->ClosableFCBs.OnClosableFCBList = FALSE; 1551 PtrFCB->PtrVCB->ClosableFCBs.Count --; 1552 } 1553 1554 InterlockedIncrement( &PtrFCB->ReferenceCount ); 1555 InterlockedIncrement( &PtrFCB->OpenHandleCount ); 1556 1557 InsertTailList( &( PtrFCB->CCBListHead ), &(PtrCCB->NextCCB)); 1558 1559 *ReturnedCCB = PtrCCB; 1560 try_exit: NOTHING; 1561 } 1562 finally 1563 { 1564 1565 } 1566 1567 return(RC); 1568 } 1569 1570 1571 /************************************************************************* 1572 * 1573 * Function: Ext2DenyAccess() 1574 * 1575 * Description: 1576 * We want to deny access to an IRP 1577 * 1578 * Expected Interrupt Level (for execution) : 1579 * 1580 * IRQL_PASSIVE_LEVEL 1581 * 1582 * Return Value: NTSTATUS - STATUS_ACCESS_DENIED (always) 1583 * 1584 *************************************************************************/ 1585 NTSTATUS NTAPI Ext2DenyAccess( IN PIRP Irp ) 1586 { 1587 ASSERT( Irp ); 1588 1589 // Just return Access Denied 1590 Irp->IoStatus.Information = 0; 1591 Irp->IoStatus.Status = STATUS_ACCESS_DENIED; 1592 IoCompleteRequest( Irp, IO_DISK_INCREMENT ); 1593 1594 DebugTrace(DEBUG_TRACE_MISC, "DENYING ACCESS (this will do for now!)...", 0); 1595 1596 return STATUS_ACCESS_DENIED; 1597 } 1598 1599 1600 1601 /************************************************************************* 1602 * 1603 * Function: Ext2GetFCB_CCB_VCB_FromFileObject() 1604 * 1605 * Description: 1606 * This routine retrieves the FCB, CCB and VCB from the File Object... 1607 * 1608 * Expected Interrupt Level (for execution) : 1609 * 1610 * ? 1611 * 1612 * Return Value: NTSTATUS - STATUS_SUCCESS(always) 1613 * 1614 *************************************************************************/ 1615 NTSTATUS NTAPI Ext2GetFCB_CCB_VCB_FromFileObject ( 1616 IN PFILE_OBJECT PtrFileObject, 1617 OUT PtrExt2FCB *PPtrFCB, 1618 OUT PtrExt2CCB *PPtrCCB, 1619 OUT PtrExt2VCB *PPtrVCB ) 1620 { 1621 (*PPtrCCB) = (PtrExt2CCB)(PtrFileObject->FsContext2); 1622 if( *PPtrCCB ) 1623 { 1624 ASSERT((*PPtrCCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_CCB); 1625 (*PPtrFCB) = (*PPtrCCB)->PtrFCB; 1626 1627 ASSERT((*PPtrFCB)); 1628 1629 if ((*PPtrFCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_VCB) 1630 { 1631 (*PPtrVCB) = (PtrExt2VCB)(*PPtrFCB); 1632 AssertVCB( (*PPtrVCB) ); 1633 1634 // No FCB 1635 (*PPtrFCB) = NULL; 1636 //found a VCB 1637 } 1638 else 1639 { 1640 AssertFCB( (*PPtrFCB) ); 1641 (*PPtrVCB) = (*PPtrFCB)->PtrVCB; 1642 AssertVCB( (*PPtrVCB) ); 1643 1644 } 1645 } 1646 else 1647 { 1648 // PtrFileObject->FsContext points to NTRequiredFCB 1649 (*PPtrFCB) = CONTAINING_RECORD( PtrFileObject->FsContext, Ext2FCB, NTRequiredFCB ); 1650 ASSERT((*PPtrFCB)); 1651 //(*PPtrFCB) = PtrFileObject->FsContext; 1652 1653 if ((*PPtrFCB)->NodeIdentifier.NodeType == EXT2_NODE_TYPE_FCB) 1654 { 1655 // Making sure I got it right... 1656 AssertFCB( *PPtrFCB ); 1657 (*PPtrVCB) = (*PPtrFCB)->PtrVCB; 1658 AssertVCB( *PPtrVCB ); 1659 } 1660 else 1661 { 1662 // This should be a VCB 1663 1664 (*PPtrVCB) = CONTAINING_RECORD( PtrFileObject->FsContext, Ext2VCB, CommonVCBHeader ); 1665 AssertVCB( *PPtrVCB ); 1666 1667 // No FCB 1668 (*PPtrFCB) = NULL; 1669 //found a VCB 1670 } 1671 1672 } 1673 return STATUS_SUCCESS; 1674 } 1675 1676 1677 void NTAPI Ext2CopyUnicodeString( PUNICODE_STRING PtrDestinationString, PUNICODE_STRING PtrSourceString ) 1678 { 1679 int Count; 1680 // Allcating space for Destination... 1681 PtrDestinationString->Length = PtrSourceString->Length; 1682 PtrDestinationString->MaximumLength = Ext2QuadAlign( PtrSourceString->Length + 2 ); 1683 PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); 1684 1685 // RtlCopyUnicodeString( PtrDestinationString, PtrSourceString ); 1686 1687 for( Count = 0 ; Count < (PtrSourceString->Length/2) ; Count++ ) 1688 { 1689 PtrDestinationString->Buffer[Count] = PtrSourceString->Buffer[Count]; 1690 } 1691 PtrDestinationString->Buffer[Count] = 0; 1692 1693 } 1694 1695 void NTAPI Ext2CopyWideCharToUnicodeString( 1696 PUNICODE_STRING PtrDestinationString, 1697 PCWSTR PtrSourceString ) 1698 { 1699 1700 int Count; 1701 1702 // Determining length... 1703 for( Count = 0 ; PtrSourceString[Count] != 0 ; Count++ ); 1704 1705 // Allcating space for Destination... 1706 PtrDestinationString->Length = Count * 2; 1707 PtrDestinationString->MaximumLength = Ext2QuadAlign( Count * 2 + 2 ); 1708 PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); 1709 1710 // Copying the string over... 1711 for( Count = 0 ; ; Count++ ) 1712 { 1713 PtrDestinationString->Buffer[Count] = PtrSourceString[Count]; 1714 if( PtrSourceString[Count] == 0 ) 1715 break; 1716 } 1717 } 1718 1719 1720 void NTAPI Ext2CopyCharToUnicodeString( 1721 PUNICODE_STRING PtrDestinationString, 1722 PCSTR PtrSourceString, 1723 USHORT SourceStringLength ) 1724 { 1725 int Count; 1726 // Allcating space for Destination... 1727 PtrDestinationString->Length = SourceStringLength * 2; 1728 PtrDestinationString->MaximumLength = Ext2QuadAlign( SourceStringLength * 2 + 2 ); 1729 PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); 1730 1731 // Copying the string over... 1732 for( Count = 0 ; Count < SourceStringLength ; Count++ ) 1733 { 1734 PtrDestinationString->Buffer[Count] = PtrSourceString[Count]; 1735 } 1736 PtrDestinationString->Buffer[Count] = 0; 1737 1738 } 1739 1740 void NTAPI Ext2CopyZCharToUnicodeString( PUNICODE_STRING PtrDestinationString, PCSTR PtrSourceString ) 1741 { 1742 1743 int Count; 1744 1745 // Determining length... 1746 for( Count = 0 ; PtrSourceString[Count] != 0 ; Count++ ); 1747 1748 // Allcating space for Destination... 1749 PtrDestinationString->Length = Count * 2; 1750 PtrDestinationString->MaximumLength = Ext2QuadAlign( Count * 2 + 2 ); 1751 PtrDestinationString->Buffer = Ext2AllocatePool( NonPagedPool, PtrDestinationString->MaximumLength ); 1752 1753 // Copying the string over... 1754 for( Count = 0 ; ; Count++ ) 1755 { 1756 PtrDestinationString->Buffer[Count] = PtrSourceString[Count]; 1757 if( PtrSourceString[Count] == 0 ) 1758 break; 1759 } 1760 } 1761 1762 void NTAPI Ext2ZerooutUnicodeString( PUNICODE_STRING PtrUnicodeString ) 1763 { 1764 PtrUnicodeString->Length = 0; 1765 PtrUnicodeString->MaximumLength =0; 1766 PtrUnicodeString->Buffer = 0; 1767 } 1768 1769 void NTAPI Ext2DeallocateUnicodeString( PUNICODE_STRING PtrUnicodeString ) 1770 { 1771 if( PtrUnicodeString && PtrUnicodeString->Buffer ) 1772 { 1773 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrUnicodeString->Buffer ); 1774 ExFreePool( PtrUnicodeString->Buffer ); 1775 } 1776 PtrUnicodeString->Length = 0; 1777 PtrUnicodeString->MaximumLength =0; 1778 PtrUnicodeString->Buffer = 0; 1779 } 1780 1781 PtrExt2FCB NTAPI Ext2GetUsedFCB( 1782 PtrExt2VCB PtrVCB ) 1783 { 1784 1785 BOOLEAN AllocatedFromZone = FALSE; 1786 PLIST_ENTRY PtrEntry = NULL; 1787 PtrExt2FCB PtrFCB = NULL; 1788 1789 ASSERT( PtrVCB ); 1790 if( PtrVCB->ClosableFCBs.Count < EXT2_MAXCLOSABLE_FCBS_LL ) 1791 { 1792 // 1793 // Too few Closable FCBs 1794 // Will not reuse any FCBs 1795 // Allocating a new one 1796 // 1797 return Ext2AllocateFCB(); 1798 } 1799 // 1800 // Obtaining a used FCB... 1801 // 1802 1803 // Retrieving the first entry in the closable FCB list... 1804 1805 PtrEntry = RemoveHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead ); 1806 1807 PtrFCB = CONTAINING_RECORD( PtrEntry, Ext2FCB, ClosableFCBs.ClosableFCBList ); 1808 1809 // Remembering if the FCB was allocated from the Zone... 1810 AllocatedFromZone = Ext2IsFlagOn( PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE ); 1811 1812 // 1813 // Close this FCB 1814 // 1815 if( !Ext2CloseClosableFCB( PtrFCB ) ) 1816 { 1817 // Couldn't close the FCB!! 1818 // 1819 InsertHeadList( &PtrVCB->ClosableFCBs.ClosableFCBListHead, 1820 &PtrFCB->ClosableFCBs.ClosableFCBList ); 1821 return Ext2AllocateFCB(); 1822 } 1823 1824 PtrVCB->ClosableFCBs.Count--; 1825 DebugTrace( DEBUG_TRACE_SPECIAL, "Count = %ld [Ext2GetUsedFCB]", PtrVCB->ClosableFCBs.Count ); 1826 1827 // 1828 // Getting the FCB ready for reuse by 1829 // zeroing it out... 1830 // 1831 RtlZeroMemory(PtrFCB, Ext2QuadAlign(sizeof(Ext2FCB))); 1832 1833 // set up some fields ... 1834 PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FCB; 1835 PtrFCB->NodeIdentifier.NodeSize = Ext2QuadAlign(sizeof(Ext2FCB)); 1836 1837 1838 if (!AllocatedFromZone) 1839 { 1840 Ext2SetFlag(PtrFCB->FCBFlags, EXT2_FCB_NOT_FROM_ZONE); 1841 } 1842 1843 return PtrFCB; 1844 } 1845 1846 BOOLEAN NTAPI Ext2CloseClosableFCB( 1847 PtrExt2FCB PtrFCB) 1848 { 1849 KIRQL Irql = 0; 1850 PFILE_OBJECT PtrFileObject = NULL; 1851 1852 AssertFCB( PtrFCB ); 1853 1854 // Attempting to acquire the FCB Exclusively... 1855 if(! ExAcquireResourceExclusiveLite( &(PtrFCB->NTRequiredFCB.MainResource ), FALSE ) ) 1856 { 1857 Ext2BreakPoint(); 1858 return FALSE; 1859 } 1860 1861 Irql = KeGetCurrentIrql( ); 1862 1863 if( PtrFCB->ReferenceCount ) 1864 { 1865 // How the hell can this happen!!! 1866 Ext2BreakPoint(); 1867 } 1868 if( PtrFCB->OpenHandleCount ) 1869 { 1870 // How the hell can this happen!!! 1871 Ext2BreakPoint(); 1872 } 1873 1874 // Deleting entry from VCB's FCB list... 1875 RemoveEntryList( &PtrFCB->NextFCB ); 1876 1877 PtrFCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_FREED; 1878 1879 PtrFileObject = PtrFCB->DcbFcb.Dcb.PtrDirFileObject; 1880 1881 if ( PtrFileObject ) 1882 { 1883 // 1884 // Clear the Cache Map... 1885 // 1886 if( PtrFileObject->PrivateCacheMap != NULL) 1887 { 1888 IO_STATUS_BLOCK Status; 1889 DebugTrace( DEBUG_TRACE_SPECIAL, ">>.........Flushing cache.........<<", 0 ); 1890 CcFlushCache( PtrFileObject->SectionObjectPointer, NULL, 0, &Status ); 1891 CcUninitializeCacheMap( PtrFileObject, NULL, NULL ); 1892 } 1893 // 1894 // The File Object is no longer required... 1895 // Close it by dereferenceing it!!! 1896 // 1897 PtrFileObject->FsContext = NULL; 1898 PtrFileObject->FsContext2 = NULL; 1899 ObDereferenceObject( PtrFileObject ); 1900 1901 PtrFCB->DcbFcb.Dcb.PtrDirFileObject = NULL; 1902 PtrFileObject = NULL; 1903 } 1904 1905 // Uninitialize the Resources... 1906 ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.MainResource ); 1907 ExDeleteResourceLite( &PtrFCB->NTRequiredFCB.PagingIoResource ); 1908 1909 // 1910 // Releasing the FCB Name Object... 1911 // 1912 if( PtrFCB->FCBName ) 1913 { 1914 DebugTrace( DEBUG_TRACE_SPECIAL, "Reusing FCB - File Name %S", PtrFCB->FCBName->ObjectName.Buffer ); 1915 Ext2ReleaseObjectName( PtrFCB->FCBName ); 1916 } 1917 else 1918 { 1919 DebugTrace( DEBUG_TRACE_SPECIAL, "Reusing FCB - File Name *Unknown*", 0 ); 1920 } 1921 return TRUE; 1922 } 1923 1924 1925 BOOLEAN NTAPI Ext2SaveBCB( 1926 PtrExt2IrpContext PtrIrpContext, 1927 PBCB PtrBCB, 1928 PFILE_OBJECT PtrFileObject) 1929 { 1930 PEXT2_SAVED_BCBS PtrSavedBCB; 1931 PLIST_ENTRY PtrEntry = NULL; 1932 1933 if( !PtrIrpContext ) 1934 { 1935 // 1936 // NULL passed instead of the IRP Context 1937 // This call should be ignored... 1938 // 1939 return TRUE; 1940 } 1941 1942 if( !AssertBCB( PtrBCB ) ) 1943 { 1944 DebugTrace( DEBUG_TRACE_MISC, "Not saving BCB!!! [Ext2SaveBCB]", 0 ); 1945 return FALSE; 1946 } 1947 1948 1949 DebugTrace( DEBUG_TRACE_SPECIAL, "Saving BCB [Ext2SaveBCB]", 0 ); 1950 1951 // Has the BCB been saved already? 1952 for( PtrEntry = PtrIrpContext->SavedBCBsListHead.Flink; 1953 PtrEntry != &PtrIrpContext->SavedBCBsListHead; 1954 PtrEntry = PtrEntry->Flink ) 1955 { 1956 PtrSavedBCB = CONTAINING_RECORD( PtrEntry, EXT2_SAVED_BCBS, SavedBCBsListEntry ); 1957 ASSERT( PtrSavedBCB ); 1958 if( PtrSavedBCB->PtrBCB == PtrBCB ) 1959 { 1960 1961 // A BCB for this file has already been saved for flushing... 1962 // Won't resave this one... 1963 return TRUE; 1964 } 1965 } 1966 1967 1968 // Reference the BCB 1969 CcRepinBcb( PtrBCB ); 1970 1971 // Now allocate a EXT2_SAVED_BCBS 1972 PtrSavedBCB = Ext2AllocatePool( NonPagedPool, 1973 Ext2QuadAlign( sizeof( EXT2_SAVED_BCBS ) ) ); 1974 if( !PtrSavedBCB ) 1975 return FALSE; 1976 PtrSavedBCB->NodeIdentifier.NodeSize = sizeof( EXT2_SAVED_BCBS ); 1977 PtrSavedBCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_SAVED_BCB; 1978 1979 PtrSavedBCB->PtrBCB = PtrBCB; 1980 // PtrSavedBCB->PtrFileObject = PtrFileObject; 1981 1982 // Now save it in the IRP Context 1983 InsertHeadList( &PtrIrpContext->SavedBCBsListHead, &PtrSavedBCB->SavedBCBsListEntry ); 1984 1985 PtrIrpContext->SavedCount++; 1986 // Return success... 1987 return TRUE; 1988 1989 } 1990 1991 1992 BOOLEAN NTAPI Ext2FlushSavedBCBs( 1993 PtrExt2IrpContext PtrIrpContext ) 1994 { 1995 1996 PLIST_ENTRY PtrEntry = NULL; 1997 PEXT2_SAVED_BCBS PtrSavedBCB = NULL; 1998 IO_STATUS_BLOCK Status; 1999 BOOLEAN RC = TRUE; 2000 2001 if( !IsListEmpty( &PtrIrpContext->SavedBCBsListHead ) ) 2002 { 2003 DebugTrace( DEBUG_TRACE_SPECIAL, "Flushing cache... - Ext2FlushSavedBCBs", 0 ); 2004 } 2005 while( !IsListEmpty( &PtrIrpContext->SavedBCBsListHead ) ) 2006 { 2007 2008 PtrEntry = RemoveTailList( &PtrIrpContext->SavedBCBsListHead ); 2009 if( !PtrEntry ) 2010 { 2011 // No more entries left... 2012 break; 2013 } 2014 2015 // Get the Saved BCB 2016 PtrSavedBCB = CONTAINING_RECORD( PtrEntry, EXT2_SAVED_BCBS, SavedBCBsListEntry ); 2017 if( PtrSavedBCB->NodeIdentifier.NodeType != EXT2_NODE_TYPE_SAVED_BCB ) 2018 { 2019 // Something is wrong... 2020 Ext2BreakPoint(); 2021 return FALSE; 2022 } 2023 2024 if( !AssertBCB( PtrSavedBCB->PtrBCB ) ) 2025 { 2026 // This BCB shouldn't have been saved in the first place... 2027 DebugTrace( DEBUG_TRACE_ERROR, "Unable to flush BCB - Skipping!!! [Ext2SaveBCB]", 0 ); 2028 continue; 2029 } 2030 2031 // Unpin and Flush the cache... 2032 CcUnpinRepinnedBcb( PtrSavedBCB->PtrBCB, TRUE, &Status ); 2033 2034 if( !NT_SUCCESS( Status.Status ) ) 2035 { 2036 // Failure in flushing... 2037 DebugTrace( DEBUG_TRACE_SPECIAL, "Failure flushing cache - Ext2FlushSavedBCBs", 0 ); 2038 RC = FALSE; 2039 } 2040 2041 // Release the Saved BCB 2042 PtrSavedBCB->NodeIdentifier.NodeType = EXT2_NODE_TYPE_INVALID; 2043 2044 DebugTrace( DEBUG_TRACE_FREE, "Freeing = %lX [misc]", PtrSavedBCB ); 2045 ExFreePool( PtrSavedBCB ); 2046 PtrSavedBCB = NULL; 2047 PtrIrpContext->SavedCount--; 2048 } 2049 2050 return RC; 2051 } 2052 2053 BOOLEAN NTAPI AssertBCB( PBCB PtrBCB ) 2054 { 2055 PFILE_OBJECT PtrFileObject = NULL; 2056 2057 /* 2058 * This routine is simplified version of the original 2059 * AssertBCB and doesn't make any assumptions about 2060 * the layout of undocumented BCB structure. 2061 * -- Filip Navara, 18/08/2004 2062 */ 2063 2064 PtrFileObject = CcGetFileObjectFromBcb ( PtrBCB ); 2065 if( !PtrFileObject ) 2066 { 2067 Ext2BreakPoint(); 2068 return FALSE; 2069 } 2070 else 2071 { 2072 return TRUE; 2073 } 2074 } 2075 2076 2077 ULONG NTAPI Ext2Align( ULONG NumberToBeAligned, ULONG Alignment ) 2078 { 2079 if( Alignment & ( Alignment - 1 ) ) 2080 { 2081 // 2082 // Alignment not a power of 2 2083 // Just returning 2084 // 2085 return NumberToBeAligned; 2086 } 2087 if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 ) 2088 { 2089 NumberToBeAligned = NumberToBeAligned + Alignment; 2090 NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) ); 2091 } 2092 return NumberToBeAligned; 2093 } 2094 2095 LONGLONG NTAPI Ext2Align64( LONGLONG NumberToBeAligned, LONGLONG Alignment ) 2096 { 2097 if( Alignment & ( Alignment - 1 ) ) 2098 { 2099 // 2100 // Alignment not a power of 2 2101 // Just returning 2102 // 2103 return NumberToBeAligned; 2104 } 2105 if( ( NumberToBeAligned & ( Alignment - 1 ) ) != 0 ) 2106 { 2107 NumberToBeAligned = NumberToBeAligned + Alignment; 2108 NumberToBeAligned = NumberToBeAligned & ( ~ (Alignment-1) ); 2109 } 2110 return NumberToBeAligned; 2111 } 2112 2113 2114 ULONG NTAPI Ext2GetCurrentTime() 2115 { 2116 LARGE_INTEGER CurrentTime; 2117 ULONG Time; 2118 KeQuerySystemTime( &CurrentTime ); 2119 Time = (ULONG) ( (CurrentTime.QuadPart - Ext2GlobalData.TimeDiff.QuadPart) / 10000000 ); 2120 return Time; 2121 } 2122