1 /* 2 * COPYRIGHT: See COPYRIGHT.TXT 3 * PROJECT: Ext2 File System Driver for WinNT/2K/XP 4 * FILE: fsctl.c 5 * PROGRAMMER: Matt Wu <mattwu@163.com> 6 * HOMEPAGE: http://www.ext2fsd.com 7 * UPDATE HISTORY: 8 */ 9 10 /* INCLUDES *****************************************************************/ 11 12 #include "ext2fs.h" 13 14 /* GLOBALS ***************************************************************/ 15 16 extern PEXT2_GLOBAL Ext2Global; 17 18 /* DEFINITIONS *************************************************************/ 19 20 #ifdef ALLOC_PRAGMA 21 #pragma alloc_text(PAGE, Ext2IsHandleCountZero) 22 #pragma alloc_text(PAGE, Ext2LockVcb) 23 #pragma alloc_text(PAGE, Ext2LockVolume) 24 #pragma alloc_text(PAGE, Ext2UnlockVcb) 25 #pragma alloc_text(PAGE, Ext2UnlockVolume) 26 #pragma alloc_text(PAGE, Ext2AllowExtendedDasdIo) 27 #pragma alloc_text(PAGE, Ext2GetRetrievalPointerBase) 28 #pragma alloc_text(PAGE, Ext2QueryExtentMappings) 29 #pragma alloc_text(PAGE, Ext2QueryRetrievalPointers) 30 #pragma alloc_text(PAGE, Ext2GetRetrievalPointers) 31 #pragma alloc_text(PAGE, Ext2UserFsRequest) 32 #pragma alloc_text(PAGE, Ext2IsMediaWriteProtected) 33 #pragma alloc_text(PAGE, Ext2MountVolume) 34 #pragma alloc_text(PAGE, Ext2PurgeVolume) 35 #pragma alloc_text(PAGE, Ext2PurgeFile) 36 #pragma alloc_text(PAGE, Ext2DismountVolume) 37 #pragma alloc_text(PAGE, Ext2IsVolumeMounted) 38 #pragma alloc_text(PAGE, Ext2VerifyVolume) 39 #pragma alloc_text(PAGE, Ext2FileSystemControl) 40 #endif 41 42 43 VOID 44 Ext2SetVpbFlag ( 45 IN PVPB Vpb, 46 IN USHORT Flag ) 47 { 48 KIRQL OldIrql; 49 50 IoAcquireVpbSpinLock(&OldIrql); 51 Vpb->Flags |= Flag; 52 IoReleaseVpbSpinLock(OldIrql); 53 } 54 55 VOID 56 Ext2ClearVpbFlag ( 57 IN PVPB Vpb, 58 IN USHORT Flag ) 59 { 60 KIRQL OldIrql; 61 62 IoAcquireVpbSpinLock(&OldIrql); 63 Vpb->Flags &= ~Flag; 64 IoReleaseVpbSpinLock(OldIrql); 65 } 66 67 BOOLEAN 68 Ext2IsHandleCountZero(IN PEXT2_VCB Vcb) 69 { 70 PEXT2_FCB Fcb; 71 PLIST_ENTRY List; 72 73 for ( List = Vcb->FcbList.Flink; 74 List != &Vcb->FcbList; 75 List = List->Flink ) { 76 77 Fcb = CONTAINING_RECORD(List, EXT2_FCB, Next); 78 79 ASSERT((Fcb->Identifier.Type == EXT2FCB) && 80 (Fcb->Identifier.Size == sizeof(EXT2_FCB))); 81 82 DEBUG(DL_INF, ( "Ext2IsHandleCountZero: Inode:%xh File:%S OpenHandleCount=%xh\n", 83 Fcb->Inode->i_ino, Fcb->Mcb->ShortName.Buffer, Fcb->OpenHandleCount)); 84 85 if (Fcb->OpenHandleCount) { 86 return FALSE; 87 } 88 } 89 90 return TRUE; 91 } 92 93 NTSTATUS 94 Ext2LockVcb (IN PEXT2_VCB Vcb, 95 IN PFILE_OBJECT FileObject) 96 { 97 NTSTATUS Status = STATUS_SUCCESS; 98 99 _SEH2_TRY { 100 101 if (FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { 102 DEBUG(DL_INF, ( "Ext2LockVolume: Volume is already locked.\n")); 103 Status = STATUS_ACCESS_DENIED; 104 _SEH2_LEAVE; 105 } 106 107 if (Vcb->OpenHandleCount > (ULONG)(FileObject ? 1 : 0)) { 108 DEBUG(DL_INF, ( "Ext2LockVcb: There are still opened files.\n")); 109 110 Status = STATUS_ACCESS_DENIED; 111 _SEH2_LEAVE; 112 } 113 114 if (!Ext2IsHandleCountZero(Vcb)) { 115 DEBUG(DL_INF, ( "Ext2LockVcb: Thare are still opened files.\n")); 116 117 Status = STATUS_ACCESS_DENIED; 118 _SEH2_LEAVE; 119 } 120 121 SetLongFlag(Vcb->Flags, VCB_VOLUME_LOCKED); 122 Ext2SetVpbFlag(Vcb->Vpb, VPB_LOCKED); 123 Vcb->LockFile = FileObject; 124 125 DEBUG(DL_INF, ( "Ext2LockVcb: Volume locked.\n")); 126 127 } _SEH2_FINALLY { 128 // Nothing 129 } _SEH2_END; 130 131 return Status; 132 } 133 134 135 NTSTATUS 136 Ext2LockVolume (IN PEXT2_IRP_CONTEXT IrpContext) 137 { 138 PIO_STACK_LOCATION IrpSp; 139 PDEVICE_OBJECT DeviceObject; 140 PEXT2_VCB Vcb = NULL; 141 NTSTATUS Status; 142 BOOLEAN VcbResourceAcquired = FALSE; 143 144 _SEH2_TRY { 145 146 ASSERT(IrpContext != NULL); 147 148 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 149 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 150 151 DeviceObject = IrpContext->DeviceObject; 152 153 Status = STATUS_UNSUCCESSFUL; 154 155 // 156 // This request is not allowed on the main device object 157 // 158 if (IsExt2FsDevice(DeviceObject)) { 159 Status = STATUS_INVALID_PARAMETER; 160 _SEH2_LEAVE; 161 } 162 163 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 164 165 ASSERT(Vcb != NULL); 166 167 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 168 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 169 170 ASSERT(IsMounted(Vcb)); 171 172 IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp); 173 174 #if (_WIN32_WINNT >= 0x0500) 175 CcWaitForCurrentLazyWriterActivity(); 176 #endif 177 ExAcquireResourceExclusiveLite( 178 &Vcb->MainResource, 179 TRUE ); 180 181 VcbResourceAcquired = TRUE; 182 183 /* flush dirty data before locking the volume */ 184 if (!IsVcbReadOnly(Vcb)) { 185 Ext2FlushFiles(IrpContext, Vcb, FALSE); 186 Ext2FlushVolume(IrpContext, Vcb, FALSE); 187 } 188 189 Status = Ext2LockVcb(Vcb, IrpSp->FileObject); 190 191 } _SEH2_FINALLY { 192 193 if (VcbResourceAcquired) { 194 ExReleaseResourceLite(&Vcb->MainResource); 195 } 196 197 if (!IrpContext->ExceptionInProgress) { 198 Ext2CompleteIrpContext(IrpContext, Status); 199 } 200 } _SEH2_END; 201 202 return Status; 203 } 204 205 NTSTATUS 206 Ext2UnlockVcb ( IN PEXT2_VCB Vcb, 207 IN PFILE_OBJECT FileObject ) 208 { 209 NTSTATUS Status; 210 211 _SEH2_TRY { 212 213 if (FileObject && FileObject->FsContext != Vcb) { 214 Status = STATUS_NOT_LOCKED; 215 _SEH2_LEAVE; 216 } 217 218 if (!FlagOn(Vcb->Flags, VCB_VOLUME_LOCKED)) { 219 DEBUG(DL_ERR, ( ": Ext2UnlockVcb: Volume is not locked.\n")); 220 Status = STATUS_NOT_LOCKED; 221 _SEH2_LEAVE; 222 } 223 224 if (Vcb->LockFile == FileObject) { 225 ClearFlag(Vcb->Flags, VCB_VOLUME_LOCKED); 226 Ext2ClearVpbFlag(Vcb->Vpb, VPB_LOCKED); 227 DEBUG(DL_INF, ( "Ext2UnlockVcb: Volume unlocked.\n")); 228 Status = STATUS_SUCCESS; 229 } else { 230 Status = STATUS_NOT_LOCKED; 231 } 232 233 } _SEH2_FINALLY { 234 // Nothing 235 } _SEH2_END; 236 237 return Status; 238 } 239 240 NTSTATUS 241 Ext2UnlockVolume ( 242 IN PEXT2_IRP_CONTEXT IrpContext 243 ) 244 { 245 PIO_STACK_LOCATION IrpSp = NULL; 246 PDEVICE_OBJECT DeviceObject = NULL; 247 PEXT2_VCB Vcb = NULL; 248 NTSTATUS Status; 249 BOOLEAN VcbResourceAcquired = FALSE; 250 251 _SEH2_TRY { 252 253 ASSERT(IrpContext != NULL); 254 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 255 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 256 257 DeviceObject = IrpContext->DeviceObject; 258 IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp); 259 260 // 261 // This request is not allowed on the main device object 262 // 263 if (IsExt2FsDevice(DeviceObject)) { 264 Status = STATUS_INVALID_PARAMETER; 265 _SEH2_LEAVE; 266 } 267 268 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 269 ASSERT(Vcb != NULL); 270 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 271 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 272 273 ExAcquireResourceExclusiveLite( 274 &Vcb->MainResource, 275 TRUE ); 276 VcbResourceAcquired = TRUE; 277 278 Status = Ext2UnlockVcb(Vcb, IrpSp->FileObject); 279 280 } _SEH2_FINALLY { 281 282 if (VcbResourceAcquired) { 283 ExReleaseResourceLite(&Vcb->MainResource); 284 } 285 286 if (!IrpContext->ExceptionInProgress) { 287 Ext2CompleteIrpContext(IrpContext, Status); 288 } 289 } _SEH2_END; 290 291 return Status; 292 } 293 294 295 NTSTATUS 296 Ext2InvalidateVolumes ( IN PEXT2_IRP_CONTEXT IrpContext ) 297 { 298 NTSTATUS Status; 299 PIRP Irp; 300 PIO_STACK_LOCATION IrpSp; 301 302 #ifndef __REACTOS__ 303 PVPB NewVpb = NULL; 304 #endif 305 HANDLE Handle; 306 PLIST_ENTRY ListEntry; 307 308 ULONG InputLength = 0; 309 PFILE_OBJECT FileObject; 310 PDEVICE_OBJECT DeviceObject; 311 BOOLEAN GlobalResourceAcquired = FALSE; 312 313 LUID Privilege = {SE_TCB_PRIVILEGE, 0}; 314 315 _SEH2_TRY { 316 317 Irp = IrpContext->Irp; 318 IrpSp = IoGetCurrentIrpStackLocation(Irp); 319 320 if (!IsExt2FsDevice(IrpSp->DeviceObject)) { 321 Status = STATUS_INVALID_DEVICE_REQUEST; 322 _SEH2_LEAVE; 323 } 324 325 if (!SeSinglePrivilegeCheck(Privilege, Irp->RequestorMode)) { 326 Status = STATUS_PRIVILEGE_NOT_HELD; 327 _SEH2_LEAVE; 328 } 329 330 331 #ifndef _GNU_NTIFS_ 332 InputLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; 333 #else 334 InputLength = ((PEXTENDED_IO_STACK_LOCATION)(IrpSp))-> 335 Parameters.FileSystemControl.InputBufferLength; 336 #endif 337 338 #if defined(_WIN64) 339 if (IoIs32bitProcess(Irp)) { 340 if (InputLength != sizeof(UINT32)) { 341 Status = STATUS_INVALID_PARAMETER; 342 _SEH2_LEAVE; 343 } 344 Handle = (HANDLE) LongToHandle( (*(PUINT32)Irp->AssociatedIrp.SystemBuffer) ); 345 } else 346 #endif 347 { 348 if (InputLength != sizeof(HANDLE)) { 349 Status = STATUS_INVALID_PARAMETER; 350 _SEH2_LEAVE; 351 } 352 Handle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer; 353 } 354 355 Status = ObReferenceObjectByHandle( Handle, 356 0, 357 *IoFileObjectType, 358 KernelMode, 359 (void **)&FileObject, 360 NULL ); 361 362 if (!NT_SUCCESS(Status)) { 363 _SEH2_LEAVE; 364 } else { 365 DeviceObject = FileObject->DeviceObject; 366 ObDereferenceObject(FileObject); 367 } 368 369 ExAcquireResourceExclusiveLite(&Ext2Global->Resource, TRUE); 370 GlobalResourceAcquired = TRUE; 371 372 ListEntry = Ext2Global->VcbList.Flink; 373 while (ListEntry != &Ext2Global->VcbList) { 374 375 PEXT2_VCB Vcb = CONTAINING_RECORD(ListEntry, EXT2_VCB, Next); 376 ListEntry = ListEntry->Flink; 377 378 DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Vcb=%xh Vcb->Vpb=%xh " 379 "Blink = %p &Vcb->Next = %p\n", 380 Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next)); 381 382 if (Vcb->Vpb && (Vcb->Vpb->RealDevice == DeviceObject)) { 383 384 DEBUG(DL_DBG, ( "Ext2InvalidateVolumes: Got Vcb=%xh Vcb->Vpb=%xh " 385 "Blink = %p &Vcb->Next = %p\n", 386 Vcb, Vcb->Vpb, ListEntry->Blink, &Vcb->Next)); 387 /* dismount the volume */ 388 Ext2CheckDismount(IrpContext, Vcb, FALSE); 389 } 390 } 391 392 } _SEH2_FINALLY { 393 394 if (GlobalResourceAcquired) { 395 ExReleaseResourceLite(&Ext2Global->Resource); 396 } 397 398 if (!IrpContext->ExceptionInProgress) { 399 Ext2CompleteIrpContext(IrpContext, Status); 400 } 401 } _SEH2_END; 402 403 return Status; 404 } 405 406 NTSTATUS 407 Ext2AllowExtendedDasdIo(IN PEXT2_IRP_CONTEXT IrpContext) 408 { 409 PIO_STACK_LOCATION IrpSp; 410 PEXT2_VCB Vcb; 411 PEXT2_CCB Ccb; 412 NTSTATUS status; 413 414 IrpSp = IoGetCurrentIrpStackLocation(IrpContext->Irp); 415 416 Vcb = (PEXT2_VCB) IrpSp->FileObject->FsContext; 417 Ccb = (PEXT2_CCB) IrpSp->FileObject->FsContext2; 418 419 ASSERT(Vcb != NULL); 420 421 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 422 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 423 424 ASSERT(IsMounted(Vcb)); 425 426 if (Ccb) { 427 SetLongFlag(Ccb->Flags, CCB_ALLOW_EXTENDED_DASD_IO); 428 status = STATUS_SUCCESS; 429 } else { 430 status = STATUS_INVALID_PARAMETER; 431 } 432 433 Ext2CompleteIrpContext(IrpContext, status); 434 return status; 435 } 436 437 /* 438 * Ext2OplockRequest 439 * 440 * oplock requests handler routine 441 * 442 * Arguments: 443 * IrpContext: the ext2 irp context 444 * 445 * Return Value: 446 * NTSTATUS: The return status for the operation 447 * 448 */ 449 450 NTSTATUS 451 Ext2OplockRequest ( 452 IN PEXT2_IRP_CONTEXT IrpContext 453 ) 454 { 455 NTSTATUS Status; 456 457 ULONG FsCtrlCode; 458 PDEVICE_OBJECT DeviceObject; 459 PFILE_OBJECT FileObject; 460 461 PIRP Irp = NULL; 462 PIO_STACK_LOCATION IrpSp; 463 PEXTENDED_IO_STACK_LOCATION EIrpSp; 464 465 PEXT2_VCB Vcb = NULL; 466 PEXT2_FCB Fcb = NULL; 467 PEXT2_CCB Ccb = NULL; 468 469 ULONG OplockCount = 0; 470 471 BOOLEAN VcbResourceAcquired = FALSE; 472 BOOLEAN FcbResourceAcquired = FALSE; 473 474 ASSERT(IrpContext); 475 476 _SEH2_TRY { 477 478 Irp = IrpContext->Irp; 479 ASSERT(Irp); 480 481 IrpSp = IoGetCurrentIrpStackLocation(Irp); 482 ASSERT(IrpSp); 483 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp; 484 485 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 486 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 487 488 DeviceObject = IrpContext->DeviceObject; 489 490 // 491 // This request is not allowed on the main device object 492 // 493 if (IsExt2FsDevice(DeviceObject)) { 494 Status = STATUS_INVALID_DEVICE_REQUEST; 495 _SEH2_LEAVE; 496 } 497 498 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 499 500 ASSERT(Vcb != NULL); 501 502 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 503 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 504 505 ASSERT(IsMounted(Vcb)); 506 507 FileObject = IrpContext->FileObject; 508 509 Fcb = (PEXT2_FCB) FileObject->FsContext; 510 511 // 512 // This request is not allowed on volumes 513 // 514 515 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) { 516 Status = STATUS_INVALID_PARAMETER; 517 _SEH2_LEAVE; 518 } 519 520 ASSERT((Fcb->Identifier.Type == EXT2FCB) && 521 (Fcb->Identifier.Size == sizeof(EXT2_FCB))); 522 523 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) { 524 Status = STATUS_FILE_DELETED; 525 _SEH2_LEAVE; 526 } 527 528 Ccb = (PEXT2_CCB) FileObject->FsContext2; 529 if (Ccb == NULL) { 530 Status = STATUS_INVALID_PARAMETER; 531 _SEH2_LEAVE; 532 } 533 534 535 ASSERT((Ccb->Identifier.Type == EXT2CCB) && 536 (Ccb->Identifier.Size == sizeof(EXT2_CCB))); 537 538 FsCtrlCode = EIrpSp->Parameters.FileSystemControl.FsControlCode; 539 540 switch (FsCtrlCode) { 541 542 case FSCTL_REQUEST_OPLOCK_LEVEL_1: 543 case FSCTL_REQUEST_OPLOCK_LEVEL_2: 544 case FSCTL_REQUEST_BATCH_OPLOCK: 545 546 VcbResourceAcquired = 547 ExAcquireResourceSharedLite( 548 &Vcb->MainResource, 549 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ); 550 551 ClearFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); 552 553 FcbResourceAcquired = 554 ExAcquireResourceExclusiveLite ( 555 &Fcb->MainResource, 556 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)); 557 558 if (FsCtrlCode == FSCTL_REQUEST_OPLOCK_LEVEL_2) { 559 OplockCount = (ULONG) FsRtlAreThereCurrentFileLocks(&Fcb->FileLockAnchor); 560 } else { 561 OplockCount = Fcb->OpenHandleCount; 562 } 563 564 break; 565 566 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: 567 case FSCTL_OPBATCH_ACK_CLOSE_PENDING : 568 case FSCTL_OPLOCK_BREAK_NOTIFY: 569 case FSCTL_OPLOCK_BREAK_ACK_NO_2: 570 571 FcbResourceAcquired = 572 ExAcquireResourceSharedLite ( 573 &Fcb->MainResource, 574 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT)); 575 576 break; 577 578 default: 579 580 Ext2BugCheck(EXT2_BUGCHK_FSCTL, FsCtrlCode, 0, 0); 581 } 582 583 584 // 585 // Call the FsRtl routine to grant/acknowledge oplock. 586 // 587 588 Status = FsRtlOplockFsctrl( &Fcb->Oplock, 589 Irp, 590 OplockCount ); 591 592 // 593 // Set the flag indicating if Fast I/O is possible 594 // 595 596 Fcb->Header.IsFastIoPossible = Ext2IsFastIoPossible(Fcb); 597 IrpContext->Irp = NULL; 598 599 } _SEH2_FINALLY { 600 601 if (FcbResourceAcquired) { 602 ExReleaseResourceLite(&Fcb->MainResource); 603 } 604 605 if (VcbResourceAcquired) { 606 ExReleaseResourceLite(&Vcb->MainResource); 607 } 608 609 if (!_SEH2_AbnormalTermination()) { 610 Ext2CompleteIrpContext(IrpContext, Status); 611 } 612 } _SEH2_END; 613 614 return Status; 615 } 616 617 NTSTATUS 618 Ext2IsVolumeDirty ( 619 IN PEXT2_IRP_CONTEXT IrpContext 620 ) 621 { 622 NTSTATUS status = STATUS_SUCCESS; 623 PIRP Irp; 624 PEXTENDED_IO_STACK_LOCATION IrpSp; 625 PULONG VolumeState; 626 627 _SEH2_TRY { 628 629 Irp = IrpContext->Irp; 630 IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp); 631 632 // 633 // Get a pointer to the output buffer. Look at the system buffer field in th 634 // irp first. Then the Irp Mdl. 635 // 636 637 if (Irp->AssociatedIrp.SystemBuffer != NULL) { 638 639 VolumeState = Irp->AssociatedIrp.SystemBuffer; 640 641 } else if (Irp->MdlAddress != NULL) { 642 643 VolumeState = MmGetSystemAddressForMdl( Irp->MdlAddress ); 644 645 } else { 646 647 status = STATUS_INVALID_USER_BUFFER; 648 _SEH2_LEAVE; 649 } 650 651 if (IrpSp->Parameters.FileSystemControl.OutputBufferLength < sizeof(ULONG)) { 652 status = STATUS_INVALID_PARAMETER; 653 _SEH2_LEAVE; 654 } 655 656 *VolumeState = 0; 657 658 } _SEH2_FINALLY { 659 660 if (!IrpContext->ExceptionInProgress) { 661 Ext2CompleteIrpContext(IrpContext, status); 662 } 663 } _SEH2_END; 664 665 return status; 666 } 667 668 669 NTSTATUS 670 Ext2QueryExtentMappings( 671 IN PEXT2_IRP_CONTEXT IrpContext, 672 IN PEXT2_VCB Vcb, 673 IN PEXT2_FCB Fcb, 674 IN PLARGE_INTEGER RequestVbn, 675 OUT PLARGE_INTEGER * pMappedRuns 676 ) 677 { 678 PLARGE_INTEGER MappedRuns = NULL; 679 PLARGE_INTEGER PartialRuns = NULL; 680 681 PEXT2_EXTENT Chain = NULL; 682 PEXT2_EXTENT Extent = NULL; 683 684 LONGLONG Vbn = 0; 685 ULONG Length = 0; 686 ULONG i = 0; 687 688 NTSTATUS Status = STATUS_SUCCESS; 689 690 _SEH2_TRY { 691 692 /* now building all the request extents */ 693 while (Vbn < RequestVbn->QuadPart) { 694 695 Length = 0x80000000; /* 2g bytes */ 696 if (RequestVbn->QuadPart < Vbn + Length) { 697 Length = (ULONG)(RequestVbn->QuadPart - Vbn); 698 } 699 700 /* build extents for sub-range */ 701 Extent = NULL; 702 Status = Ext2BuildExtents( 703 IrpContext, 704 Vcb, 705 Fcb->Mcb, 706 Vbn, 707 Length, 708 FALSE, 709 &Extent); 710 711 if (!NT_SUCCESS(Status)) { 712 _SEH2_LEAVE; 713 } 714 715 if (Chain) { 716 Ext2JointExtents(Chain, Extent); 717 } else { 718 Chain = Extent; 719 } 720 721 /* allocate extent array */ 722 PartialRuns = Ext2AllocatePool( 723 NonPagedPool, 724 (Ext2CountExtents(Chain) + 2) * 725 (2 * sizeof(LARGE_INTEGER)), 726 'RE2E'); 727 728 if (PartialRuns == NULL) { 729 Status = STATUS_INSUFFICIENT_RESOURCES; 730 _SEH2_LEAVE; 731 } 732 RtlZeroMemory( PartialRuns, 733 (Ext2CountExtents(Chain) + 2) * 734 (2 * sizeof(LARGE_INTEGER))); 735 736 if (MappedRuns) { 737 RtlMoveMemory(PartialRuns, 738 MappedRuns, 739 i * 2 * sizeof(LARGE_INTEGER)); 740 Ext2FreePool(MappedRuns, 'RE2E'); 741 } 742 MappedRuns = PartialRuns; 743 744 /* walk all the Mcb runs in Extent */ 745 for (; Extent != NULL; Extent = Extent->Next) { 746 MappedRuns[i*2 + 0].QuadPart = Vbn + Extent->Offset; 747 MappedRuns[i*2 + 1].QuadPart = Extent->Lba; 748 i = i+1; 749 } 750 751 Vbn = Vbn + Length; 752 } 753 754 *pMappedRuns = MappedRuns; 755 756 } _SEH2_FINALLY { 757 758 if (!NT_SUCCESS(Status) || Status == STATUS_PENDING) { 759 if (MappedRuns) { 760 Ext2FreePool(MappedRuns, 'RE2E'); 761 } 762 *pMappedRuns = NULL; 763 } 764 765 if (Chain) { 766 Ext2DestroyExtentChain(Chain); 767 } 768 } _SEH2_END; 769 770 return Status; 771 } 772 773 NTSTATUS 774 Ext2QueryRetrievalPointers ( 775 IN PEXT2_IRP_CONTEXT IrpContext 776 ) 777 { 778 PIRP Irp = NULL; 779 PIO_STACK_LOCATION IrpSp; 780 PEXTENDED_IO_STACK_LOCATION EIrpSp; 781 782 PDEVICE_OBJECT DeviceObject; 783 PFILE_OBJECT FileObject; 784 785 PEXT2_VCB Vcb = NULL; 786 PEXT2_FCB Fcb = NULL; 787 PEXT2_CCB Ccb = NULL; 788 789 PLARGE_INTEGER RequestVbn; 790 PLARGE_INTEGER * pMappedRuns; 791 792 ULONG InputSize; 793 ULONG OutputSize; 794 795 NTSTATUS Status = STATUS_SUCCESS; 796 797 BOOLEAN FcbResourceAcquired = FALSE; 798 799 _SEH2_TRY { 800 801 ASSERT(IrpContext); 802 Irp = IrpContext->Irp; 803 ASSERT(Irp); 804 805 IrpSp = IoGetCurrentIrpStackLocation(Irp); 806 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp; 807 ASSERT(IrpSp); 808 809 InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength; 810 OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength; 811 812 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 813 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 814 815 DeviceObject = IrpContext->DeviceObject; 816 817 DbgBreak(); 818 819 /* This request is not allowed on the main device object */ 820 if (IsExt2FsDevice(DeviceObject)) { 821 Status = STATUS_INVALID_DEVICE_REQUEST; 822 _SEH2_LEAVE; 823 } 824 825 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 826 ASSERT(Vcb != NULL); 827 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 828 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 829 ASSERT(IsMounted(Vcb)); 830 831 FileObject = IrpContext->FileObject; 832 Fcb = (PEXT2_FCB) FileObject->FsContext; 833 834 /* check Fcb is valid or not */ 835 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) { 836 Status = STATUS_INVALID_PARAMETER; 837 _SEH2_LEAVE; 838 } 839 840 ASSERT((Fcb->Identifier.Type == EXT2FCB) && 841 (Fcb->Identifier.Size == sizeof(EXT2_FCB))); 842 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) { 843 Status = STATUS_FILE_DELETED; 844 _SEH2_LEAVE; 845 } 846 847 Ccb = (PEXT2_CCB) FileObject->FsContext2; 848 if (Ccb == NULL) { 849 Status = STATUS_INVALID_PARAMETER; 850 _SEH2_LEAVE; 851 } 852 853 ASSERT((Ccb->Identifier.Type == EXT2CCB) && 854 (Ccb->Identifier.Size == sizeof(EXT2_CCB))); 855 856 /* Is requstor in kernel and Fcb a paging file ? */ 857 if (Irp->RequestorMode != KernelMode || 858 !IsFlagOn(Fcb->Flags, FCB_PAGE_FILE) || 859 InputSize != sizeof(LARGE_INTEGER) || 860 OutputSize != sizeof(PVOID)) { 861 Status = STATUS_INVALID_PARAMETER; 862 _SEH2_LEAVE; 863 } 864 865 if (!ExAcquireResourceExclusiveLite ( 866 &Fcb->MainResource, Ext2CanIWait())) { 867 Status = STATUS_PENDING; 868 _SEH2_LEAVE; 869 } 870 FcbResourceAcquired = TRUE; 871 872 RequestVbn = EIrpSp->Parameters.FileSystemControl.Type3InputBuffer; 873 pMappedRuns = Irp->UserBuffer; 874 875 DbgBreak(); 876 877 /* request size beyonds whole file size */ 878 if (RequestVbn->QuadPart >= Fcb->Header.AllocationSize.QuadPart) { 879 Status = STATUS_END_OF_FILE; 880 _SEH2_LEAVE; 881 } 882 883 Status = Ext2QueryExtentMappings( 884 IrpContext, 885 Vcb, 886 Fcb, 887 RequestVbn, 888 pMappedRuns 889 ); 890 891 } _SEH2_FINALLY { 892 893 if (FcbResourceAcquired) { 894 ExReleaseResourceLite(&Fcb->MainResource); 895 } 896 897 if (!_SEH2_AbnormalTermination()) { 898 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { 899 Status = Ext2QueueRequest(IrpContext); 900 } else { 901 Ext2CompleteIrpContext(IrpContext, Status); 902 } 903 } 904 } _SEH2_END; 905 906 return Status; 907 } 908 909 910 NTSTATUS 911 Ext2GetRetrievalPointers ( 912 IN PEXT2_IRP_CONTEXT IrpContext 913 ) 914 { 915 PIRP Irp = NULL; 916 PIO_STACK_LOCATION IrpSp; 917 PEXTENDED_IO_STACK_LOCATION EIrpSp; 918 919 PDEVICE_OBJECT DeviceObject; 920 PFILE_OBJECT FileObject; 921 922 PEXT2_VCB Vcb = NULL; 923 PEXT2_FCB Fcb = NULL; 924 PEXT2_CCB Ccb = NULL; 925 926 PSTARTING_VCN_INPUT_BUFFER SVIB; 927 PRETRIEVAL_POINTERS_BUFFER RPSB; 928 929 PEXT2_EXTENT Chain = NULL; 930 PEXT2_EXTENT Extent = NULL; 931 932 LONGLONG Vbn = 0; 933 ULONG Length = 0; 934 ULONG i = 0; 935 936 ULONG UsedSize = 0; 937 ULONG InputSize; 938 ULONG OutputSize; 939 940 NTSTATUS Status = STATUS_SUCCESS; 941 942 BOOLEAN FcbResourceAcquired = FALSE; 943 944 _SEH2_TRY { 945 946 ASSERT(IrpContext); 947 Irp = IrpContext->Irp; 948 ASSERT(Irp); 949 950 IrpSp = IoGetCurrentIrpStackLocation(Irp); 951 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp; 952 ASSERT(IrpSp); 953 954 InputSize = EIrpSp->Parameters.FileSystemControl.InputBufferLength; 955 OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength; 956 957 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 958 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 959 960 DeviceObject = IrpContext->DeviceObject; 961 962 /* This request is not allowed on the main device object */ 963 if (IsExt2FsDevice(DeviceObject)) { 964 Status = STATUS_INVALID_DEVICE_REQUEST; 965 _SEH2_LEAVE; 966 } 967 968 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 969 ASSERT(Vcb != NULL); 970 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 971 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 972 ASSERT(IsMounted(Vcb)); 973 974 FileObject = IrpContext->FileObject; 975 Fcb = (PEXT2_FCB) FileObject->FsContext; 976 977 /* check Fcb is valid or not */ 978 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) { 979 Status = STATUS_INVALID_PARAMETER; 980 _SEH2_LEAVE; 981 } 982 983 ASSERT((Fcb->Identifier.Type == EXT2FCB) && 984 (Fcb->Identifier.Size == sizeof(EXT2_FCB))); 985 986 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) { 987 Status = STATUS_FILE_DELETED; 988 _SEH2_LEAVE; 989 } 990 991 Ccb = (PEXT2_CCB) FileObject->FsContext2; 992 if (Ccb == NULL) { 993 Status = STATUS_INVALID_PARAMETER; 994 _SEH2_LEAVE; 995 } 996 997 ASSERT((Ccb->Identifier.Type == EXT2CCB) && 998 (Ccb->Identifier.Size == sizeof(EXT2_CCB))); 999 1000 if (InputSize < sizeof(STARTING_VCN_INPUT_BUFFER) || 1001 OutputSize < sizeof(RETRIEVAL_POINTERS_BUFFER) ) { 1002 Status = STATUS_BUFFER_TOO_SMALL; 1003 _SEH2_LEAVE; 1004 } 1005 1006 if (!ExAcquireResourceExclusiveLite ( 1007 &Fcb->MainResource, Ext2CanIWait())) { 1008 Status = STATUS_PENDING; 1009 _SEH2_LEAVE; 1010 } 1011 FcbResourceAcquired = TRUE; 1012 1013 SVIB = (PSTARTING_VCN_INPUT_BUFFER) 1014 EIrpSp->Parameters.FileSystemControl.Type3InputBuffer; 1015 RPSB = (PRETRIEVAL_POINTERS_BUFFER) Ext2GetUserBuffer(Irp); 1016 1017 /* probe user buffer */ 1018 1019 _SEH2_TRY { 1020 if (Irp->RequestorMode != KernelMode) { 1021 ProbeForRead (SVIB, InputSize, sizeof(UCHAR)); 1022 ProbeForWrite(RPSB, OutputSize, sizeof(UCHAR)); 1023 } 1024 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 1025 Status = STATUS_INVALID_USER_BUFFER; 1026 } _SEH2_END; 1027 1028 if (!NT_SUCCESS(Status)) { 1029 _SEH2_LEAVE; 1030 } 1031 1032 UsedSize = FIELD_OFFSET(RETRIEVAL_POINTERS_BUFFER, Extents[0]); 1033 1034 /* request size beyonds whole file size ? */ 1035 DEBUG(DL_DBG, ("Ext2GetRetrievalPointers: Startin from Vbn: %I64xh\n", 1036 SVIB->StartingVcn.QuadPart)); 1037 Vbn = (SVIB->StartingVcn.QuadPart << BLOCK_BITS); 1038 if (Vbn >= Fcb->Header.AllocationSize.QuadPart ) { 1039 Status = STATUS_END_OF_FILE; 1040 _SEH2_LEAVE; 1041 } 1042 1043 /* now building all the request extents */ 1044 while (Vbn < Fcb->Header.AllocationSize.QuadPart) { 1045 1046 ASSERT(Chain == NULL); 1047 Length = 0x80000000; /* 2g bytes */ 1048 if (Fcb->Header.AllocationSize.QuadPart < Vbn + Length) { 1049 Length = (ULONG)(Fcb->Header.AllocationSize.QuadPart - Vbn); 1050 } 1051 1052 /* build extents for sub-range */ 1053 Status = Ext2BuildExtents( 1054 IrpContext, 1055 Vcb, 1056 Fcb->Mcb, 1057 Vbn, 1058 Length, 1059 FALSE, 1060 &Chain); 1061 1062 if (!NT_SUCCESS(Status)) { 1063 DbgBreak(); 1064 _SEH2_LEAVE; 1065 } 1066 1067 /* fill user buffer of RETRIEVAL_POINTERS_BUFFER */ 1068 Extent = Chain; 1069 while (Extent) { 1070 1071 DEBUG(DL_MAP, ("Ext2GetRetrievalPointers: %wZ %d Vbn = %I64xh Lbn = %I64xh\n", 1072 &Fcb->Mcb->FullName, i, 1073 ((Vbn + Extent->Offset) >> BLOCK_BITS), 1074 Extent->Lba)); 1075 1076 RPSB->Extents[i].Lcn.QuadPart = (Extent->Lba >> BLOCK_BITS); 1077 RPSB->Extents[i].NextVcn.QuadPart = ((Vbn + Extent->Offset + Extent->Length) >> BLOCK_BITS); 1078 if (i == 0) { 1079 RPSB->StartingVcn.QuadPart = ((Vbn + Extent->Offset) >> BLOCK_BITS); 1080 } else { 1081 ASSERT(RPSB->Extents[i-1].NextVcn.QuadPart == ((Vbn + Extent->Offset) >> BLOCK_BITS)); 1082 } 1083 if (UsedSize + sizeof(RETRIEVAL_POINTERS_BUFFER) > OutputSize) { 1084 Status = STATUS_BUFFER_OVERFLOW; 1085 _SEH2_LEAVE; 1086 } 1087 UsedSize += sizeof(LARGE_INTEGER) * 2; 1088 Irp->IoStatus.Information = (ULONG_PTR)UsedSize; 1089 RPSB->ExtentCount = ++i; 1090 Extent = Extent->Next; 1091 } 1092 1093 if (Chain) { 1094 Ext2DestroyExtentChain(Chain); 1095 Chain = NULL; 1096 } 1097 1098 Vbn = Vbn + Length; 1099 } 1100 1101 #if 0 1102 { 1103 NTSTATUS _s; 1104 ULONG _i = 0; 1105 LARGE_INTEGER RequestVbn = Fcb->Header.AllocationSize; 1106 PLARGE_INTEGER MappedRuns = NULL; 1107 1108 _s = Ext2QueryExtentMappings( 1109 IrpContext, 1110 Vcb, 1111 Fcb, 1112 &RequestVbn, 1113 &MappedRuns 1114 ); 1115 if (!NT_SUCCESS(_s) || NULL == MappedRuns) { 1116 DbgBreak(); 1117 goto exit_to_get_rps; 1118 } 1119 1120 while (MappedRuns[_i*2 + 0].QuadPart != 0 || 1121 MappedRuns[_i*2 + 1].QuadPart != 0 ) { 1122 DEBUG(DL_MAP, ("Ext2QueryExtentMappings: %wZ %d Vbn = %I64xh Lbn = %I64xh\n", 1123 &Fcb->Mcb->FullName, _i, 1124 MappedRuns[_i*2 + 0].QuadPart, 1125 MappedRuns[_i*2 + 1].QuadPart)); 1126 _i++; 1127 } 1128 1129 exit_to_get_rps: 1130 1131 if (MappedRuns) { 1132 Ext2FreePool(MappedRuns, 'RE2E'); 1133 } 1134 } 1135 #endif 1136 1137 } _SEH2_FINALLY { 1138 1139 if (FcbResourceAcquired) { 1140 ExReleaseResourceLite(&Fcb->MainResource); 1141 } 1142 1143 if (Chain) { 1144 Ext2DestroyExtentChain(Chain); 1145 } 1146 1147 if (!_SEH2_AbnormalTermination()) { 1148 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { 1149 Status = Ext2QueueRequest(IrpContext); 1150 } else { 1151 Ext2CompleteIrpContext(IrpContext, Status); 1152 } 1153 } 1154 } _SEH2_END; 1155 1156 return Status; 1157 } 1158 1159 NTSTATUS 1160 Ext2GetRetrievalPointerBase ( 1161 IN PEXT2_IRP_CONTEXT IrpContext 1162 ) 1163 { 1164 PIRP Irp = NULL; 1165 PIO_STACK_LOCATION IrpSp; 1166 PEXTENDED_IO_STACK_LOCATION EIrpSp; 1167 1168 PDEVICE_OBJECT DeviceObject; 1169 PFILE_OBJECT FileObject; 1170 1171 PEXT2_VCB Vcb = NULL; 1172 PEXT2_FCB Fcb = NULL; 1173 PEXT2_CCB Ccb = NULL; 1174 1175 PLARGE_INTEGER FileAreaOffset; 1176 1177 ULONG OutputSize; 1178 1179 NTSTATUS Status = STATUS_SUCCESS; 1180 1181 BOOLEAN FcbResourceAcquired = FALSE; 1182 1183 _SEH2_TRY { 1184 1185 ASSERT(IrpContext); 1186 Irp = IrpContext->Irp; 1187 ASSERT(Irp); 1188 1189 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1190 EIrpSp = (PEXTENDED_IO_STACK_LOCATION)IrpSp; 1191 ASSERT(IrpSp); 1192 1193 OutputSize = EIrpSp->Parameters.FileSystemControl.OutputBufferLength; 1194 1195 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 1196 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 1197 1198 DeviceObject = IrpContext->DeviceObject; 1199 1200 /* This request is not allowed on the main device object */ 1201 if (IsExt2FsDevice(DeviceObject)) { 1202 Status = STATUS_INVALID_DEVICE_REQUEST; 1203 _SEH2_LEAVE; 1204 } 1205 1206 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 1207 ASSERT(Vcb != NULL); 1208 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 1209 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 1210 ASSERT(IsMounted(Vcb)); 1211 1212 FileObject = IrpContext->FileObject; 1213 Fcb = (PEXT2_FCB) FileObject->FsContext; 1214 1215 /* check Fcb is valid or not */ 1216 if (Fcb == NULL || Fcb->Identifier.Type == EXT2VCB) { 1217 Status = STATUS_INVALID_PARAMETER; 1218 _SEH2_LEAVE; 1219 } 1220 1221 ASSERT((Fcb->Identifier.Type == EXT2FCB) && 1222 (Fcb->Identifier.Size == sizeof(EXT2_FCB))); 1223 1224 if (IsFlagOn(Fcb->Mcb->Flags, MCB_FILE_DELETED)) { 1225 Status = STATUS_FILE_DELETED; 1226 _SEH2_LEAVE; 1227 } 1228 1229 Ccb = (PEXT2_CCB) FileObject->FsContext2; 1230 if (Ccb == NULL) { 1231 Status = STATUS_INVALID_PARAMETER; 1232 _SEH2_LEAVE; 1233 } 1234 1235 ASSERT((Ccb->Identifier.Type == EXT2CCB) && 1236 (Ccb->Identifier.Size == sizeof(EXT2_CCB))); 1237 1238 if (OutputSize < sizeof(LARGE_INTEGER)) { 1239 Status = STATUS_BUFFER_TOO_SMALL; 1240 _SEH2_LEAVE; 1241 } 1242 1243 if (!ExAcquireResourceExclusiveLite ( 1244 &Fcb->MainResource, Ext2CanIWait())) { 1245 Status = STATUS_PENDING; 1246 _SEH2_LEAVE; 1247 } 1248 FcbResourceAcquired = TRUE; 1249 1250 FileAreaOffset = (PLARGE_INTEGER) Ext2GetUserBuffer(Irp); 1251 1252 /* probe user buffer */ 1253 1254 _SEH2_TRY { 1255 if (Irp->RequestorMode != KernelMode) { 1256 ProbeForWrite(FileAreaOffset, OutputSize, sizeof(UCHAR)); 1257 } 1258 1259 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { 1260 1261 Status = STATUS_INVALID_USER_BUFFER; 1262 } _SEH2_END; 1263 1264 if (!NT_SUCCESS(Status)) { 1265 _SEH2_LEAVE; 1266 } 1267 1268 DEBUG(DL_DBG, ("Ext2GetRetrievalPointerBase: FileAreaOffset is 0.\n")); 1269 1270 FileAreaOffset->QuadPart = 0; // sector offset to the first allocatable unit on the filesystem 1271 1272 Irp->IoStatus.Information = sizeof(LARGE_INTEGER); 1273 1274 } _SEH2_FINALLY { 1275 1276 if (FcbResourceAcquired) { 1277 ExReleaseResourceLite(&Fcb->MainResource); 1278 } 1279 1280 if (!_SEH2_AbnormalTermination()) { 1281 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { 1282 Status = Ext2QueueRequest(IrpContext); 1283 } else { 1284 Ext2CompleteIrpContext(IrpContext, Status); 1285 } 1286 } 1287 } _SEH2_END; 1288 1289 return Status; 1290 } 1291 1292 NTSTATUS 1293 Ext2InspectReparseData( 1294 IN PREPARSE_DATA_BUFFER RDB, 1295 IN ULONG InputBufferLength 1296 ) 1297 { 1298 NTSTATUS Status = STATUS_SUCCESS; 1299 1300 if (!RDB) { 1301 Status = STATUS_INVALID_PARAMETER; 1302 goto out; 1303 } 1304 1305 if (InputBufferLength < sizeof(REPARSE_DATA_BUFFER)) { 1306 Status = STATUS_BUFFER_OVERFLOW; 1307 goto out; 1308 } 1309 1310 if (InputBufferLength < RDB->ReparseDataLength) { 1311 Status = STATUS_BUFFER_OVERFLOW; 1312 goto out; 1313 } 1314 1315 if (RDB->ReparseTag != IO_REPARSE_TAG_SYMLINK) { 1316 Status = STATUS_NOT_IMPLEMENTED; 1317 goto out; 1318 } 1319 1320 if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer 1321 + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset 1322 + RDB->SymbolicLinkReparseBuffer.SubstituteNameLength 1323 > (PUCHAR)RDB + InputBufferLength ) { 1324 Status = STATUS_BUFFER_OVERFLOW; 1325 goto out; 1326 } 1327 1328 if ((PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer 1329 + RDB->SymbolicLinkReparseBuffer.PrintNameOffset 1330 + RDB->SymbolicLinkReparseBuffer.PrintNameLength 1331 > (PUCHAR)RDB + InputBufferLength) { 1332 Status = STATUS_BUFFER_OVERFLOW; 1333 goto out; 1334 } 1335 1336 if (RDB->SymbolicLinkReparseBuffer.Flags != SYMLINK_FLAG_RELATIVE) { 1337 Status = STATUS_NOT_IMPLEMENTED; 1338 goto out; 1339 } 1340 1341 out: 1342 return Status; 1343 } 1344 1345 VOID 1346 Ext2InitializeReparseData(IN PREPARSE_DATA_BUFFER RDB, USHORT PathBufferLength) 1347 { 1348 ASSERT(FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.SubstituteNameOffset) == 1349 REPARSE_DATA_BUFFER_HEADER_SIZE); 1350 RDB->ReparseTag = IO_REPARSE_TAG_SYMLINK; 1351 RDB->ReparseDataLength = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) - 1352 FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer.DataBuffer) + 1353 PathBufferLength * sizeof(WCHAR); 1354 RDB->Reserved = 0; 1355 RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset = PathBufferLength; 1356 RDB->SymbolicLinkReparseBuffer.SubstituteNameLength = PathBufferLength; 1357 RDB->SymbolicLinkReparseBuffer.PrintNameOffset = 0; 1358 RDB->SymbolicLinkReparseBuffer.PrintNameLength = PathBufferLength; 1359 RDB->SymbolicLinkReparseBuffer.Flags = SYMLINK_FLAG_RELATIVE; 1360 RtlZeroMemory(&RDB->SymbolicLinkReparseBuffer.PathBuffer, PathBufferLength * 2); 1361 } 1362 1363 NTSTATUS 1364 Ext2ReadSymlink ( 1365 IN PEXT2_IRP_CONTEXT IrpContext, 1366 IN PEXT2_VCB Vcb, 1367 IN PEXT2_MCB Mcb, 1368 IN PVOID Buffer, 1369 IN ULONG Size, 1370 OUT PULONG BytesRead 1371 ) 1372 { 1373 return Ext2ReadInode ( IrpContext, 1374 Vcb, 1375 Mcb, 1376 0, 1377 Buffer, 1378 Size, 1379 FALSE, 1380 BytesRead); 1381 } 1382 1383 1384 1385 NTSTATUS 1386 Ext2GetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext) 1387 { 1388 PIRP Irp = NULL; 1389 PIO_STACK_LOCATION IrpSp; 1390 PEXTENDED_IO_STACK_LOCATION EIrpSp; 1391 1392 PDEVICE_OBJECT DeviceObject; 1393 1394 PEXT2_VCB Vcb = NULL; 1395 PEXT2_CCB Ccb = NULL; 1396 PEXT2_MCB Mcb = NULL; 1397 1398 NTSTATUS Status = STATUS_UNSUCCESSFUL; 1399 BOOLEAN MainResourceAcquired = FALSE; 1400 1401 PVOID OutputBuffer; 1402 ULONG OutputBufferLength; 1403 ULONG BytesRead = 0; 1404 1405 PREPARSE_DATA_BUFFER RDB; 1406 1407 UNICODE_STRING UniName; 1408 OEM_STRING OemName; 1409 1410 PCHAR OemNameBuffer = NULL; 1411 int OemNameLength = 0, i; 1412 1413 Ccb = IrpContext->Ccb; 1414 ASSERT(Ccb != NULL); 1415 ASSERT((Ccb->Identifier.Type == EXT2CCB) && 1416 (Ccb->Identifier.Size == sizeof(EXT2_CCB))); 1417 DeviceObject = IrpContext->DeviceObject; 1418 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 1419 Mcb = IrpContext->Fcb->Mcb; 1420 Irp = IrpContext->Irp; 1421 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1422 1423 _SEH2_TRY { 1424 1425 if (!Mcb || !IsInodeSymLink(&Mcb->Inode) || 1426 !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) { 1427 Status = STATUS_NOT_A_REPARSE_POINT; 1428 _SEH2_LEAVE; 1429 } 1430 1431 OutputBuffer = (PVOID)Irp->AssociatedIrp.SystemBuffer; 1432 OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength; 1433 1434 RDB = (PREPARSE_DATA_BUFFER)OutputBuffer; 1435 if (!RDB) { 1436 Status = STATUS_INVALID_PARAMETER; 1437 _SEH2_LEAVE; 1438 } 1439 if (OutputBufferLength < sizeof(REPARSE_DATA_BUFFER)) { 1440 Status = STATUS_BUFFER_OVERFLOW; 1441 _SEH2_LEAVE; 1442 } 1443 1444 OemNameLength = (ULONG)Mcb->Inode.i_size; 1445 if (OemNameLength > USHRT_MAX) { 1446 Status = STATUS_INVALID_PARAMETER; 1447 _SEH2_LEAVE; 1448 } 1449 OemName.Length = (USHORT)OemNameLength; 1450 OemName.MaximumLength = OemNameLength + 1; 1451 OemNameBuffer = OemName.Buffer = Ext2AllocatePool(NonPagedPool, 1452 OemName.MaximumLength, 1453 'NL2E'); 1454 if (!OemNameBuffer) { 1455 Status = STATUS_INSUFFICIENT_RESOURCES; 1456 _SEH2_LEAVE; 1457 } 1458 1459 Status = Ext2ReadSymlink(IrpContext, 1460 Vcb, 1461 Mcb, 1462 OemNameBuffer, 1463 OemNameLength, 1464 &BytesRead 1465 ); 1466 OemName.Buffer[OemName.Length] = '\0'; 1467 for (i = 0;i < OemName.Length;i++) { 1468 if (OemName.Buffer[i] == '/') { 1469 OemName.Buffer[i] = '\\'; 1470 } 1471 } 1472 1473 if (OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) > USHRT_MAX) { 1474 UniName.Length = USHRT_MAX; 1475 } else { 1476 UniName.Length = (USHORT)OutputBufferLength - FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer); 1477 } 1478 UniName.MaximumLength = UniName.Length; 1479 UniName.Length = (USHORT)Ext2OEMToUnicodeSize(Vcb, &OemName); 1480 Irp->IoStatus.Information = FIELD_OFFSET(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer) + 2 * UniName.Length; 1481 if (UniName.MaximumLength < 2*UniName.Length) { 1482 Status = STATUS_BUFFER_TOO_SMALL; 1483 _SEH2_LEAVE; 1484 } 1485 1486 Ext2InitializeReparseData(RDB, UniName.Length); 1487 UniName.Buffer = RDB->SymbolicLinkReparseBuffer.PathBuffer; 1488 /* 1489 (PWCHAR)((PUCHAR)& 1490 + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset); 1491 */ 1492 Ext2OEMToUnicode(Vcb, &UniName, &OemName); 1493 RtlMoveMemory( (PUCHAR)RDB->SymbolicLinkReparseBuffer.PathBuffer + 1494 RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset, 1495 UniName.Buffer, UniName.Length); 1496 1497 Status = STATUS_SUCCESS; 1498 1499 } _SEH2_FINALLY { 1500 1501 if (OemNameBuffer) { 1502 Ext2FreePool(OemNameBuffer, 'NL2E'); 1503 } 1504 1505 if (!_SEH2_AbnormalTermination()) { 1506 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { 1507 Status = Ext2QueueRequest(IrpContext); 1508 } else { 1509 Ext2CompleteIrpContext(IrpContext, Status); 1510 } 1511 } 1512 } _SEH2_END; 1513 1514 return Status; 1515 } 1516 1517 1518 NTSTATUS 1519 Ext2WriteSymlink ( 1520 IN PEXT2_IRP_CONTEXT IrpContext, 1521 IN PEXT2_VCB Vcb, 1522 IN PEXT2_MCB Mcb, 1523 IN PVOID Buffer, 1524 IN ULONG Size, 1525 OUT PULONG BytesWritten 1526 ) 1527 { 1528 NTSTATUS Status = STATUS_SUCCESS; 1529 PUCHAR Data = (PUCHAR)(&Mcb->Inode.i_block[0]); 1530 1531 if (Size >= EXT2_LINKLEN_IN_INODE) { 1532 1533 /* initialize inode i_block[] */ 1534 if (0 == Mcb->Inode.i_blocks) { 1535 memset(Data, 0, EXT2_LINKLEN_IN_INODE); 1536 ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL); 1537 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 1538 } 1539 1540 Status = Ext2WriteInode(IrpContext, Vcb, Mcb, 1541 0, Buffer, Size, 1542 FALSE, BytesWritten); 1543 if (!NT_SUCCESS(Status)) { 1544 goto out; 1545 } 1546 1547 } else { 1548 1549 /* free inode blocks before writing in line */ 1550 if (Mcb->Inode.i_blocks) { 1551 LARGE_INTEGER Zero = {0, 0}; 1552 Ext2TruncateFile(IrpContext, Vcb, Mcb, &Zero); 1553 } 1554 1555 ClearFlag(Mcb->Inode.i_flags, EXT4_EXTENTS_FL); 1556 memset(Data, 0, EXT2_LINKLEN_IN_INODE); 1557 RtlCopyMemory(Data, Buffer, Size); 1558 } 1559 1560 Mcb->Inode.i_size = Size; 1561 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 1562 1563 if (BytesWritten) { 1564 *BytesWritten = Size; 1565 } 1566 1567 out: 1568 return Status; 1569 } 1570 1571 NTSTATUS 1572 Ext2SetReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext) 1573 { 1574 PIRP Irp = NULL; 1575 PIO_STACK_LOCATION IrpSp; 1576 1577 PDEVICE_OBJECT DeviceObject; 1578 1579 PEXT2_VCB Vcb = NULL; 1580 PEXT2_FCB Fcb = NULL; 1581 PEXT2_CCB Ccb = NULL; 1582 PEXT2_MCB Mcb = NULL; 1583 1584 NTSTATUS Status = STATUS_UNSUCCESSFUL; 1585 1586 PVOID InputBuffer; 1587 ULONG InputBufferLength; 1588 ULONG BytesWritten = 0; 1589 1590 PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */ 1591 PEXT2_MCB ParentMcb = NULL; 1592 1593 PREPARSE_DATA_BUFFER RDB; 1594 1595 UNICODE_STRING UniName; 1596 OEM_STRING OemName; 1597 1598 PCHAR OemNameBuffer = NULL; 1599 int OemNameLength = 0, i; 1600 1601 BOOLEAN MainResourceAcquired = FALSE; 1602 BOOLEAN FcbLockAcquired = FALSE; 1603 1604 _SEH2_TRY { 1605 1606 Ccb = IrpContext->Ccb; 1607 ASSERT(Ccb != NULL); 1608 ASSERT((Ccb->Identifier.Type == EXT2CCB) && 1609 (Ccb->Identifier.Size == sizeof(EXT2_CCB))); 1610 DeviceObject = IrpContext->DeviceObject; 1611 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 1612 Fcb = IrpContext->Fcb; 1613 Mcb = Fcb->Mcb; 1614 Irp = IrpContext->Irp; 1615 IrpSp = IoGetCurrentIrpStackLocation(Irp); 1616 1617 ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); 1618 FcbLockAcquired = TRUE; 1619 1620 ParentMcb = Mcb->Parent; 1621 ParentDcb = ParentMcb->Fcb; 1622 if (ParentDcb == NULL) { 1623 ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb); 1624 } 1625 if (ParentDcb) { 1626 Ext2ReferXcb(&ParentDcb->ReferenceCount); 1627 } 1628 1629 if (!Mcb) 1630 _SEH2_LEAVE; 1631 1632 if (FcbLockAcquired) { 1633 ExReleaseResourceLite(&Vcb->FcbLock); 1634 FcbLockAcquired = FALSE; 1635 } 1636 1637 if (!ExAcquireResourceSharedLite( 1638 &Fcb->MainResource, 1639 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { 1640 Status = STATUS_PENDING; 1641 _SEH2_LEAVE; 1642 } 1643 MainResourceAcquired = TRUE; 1644 1645 InputBuffer = Irp->AssociatedIrp.SystemBuffer; 1646 InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength; 1647 1648 RDB = (PREPARSE_DATA_BUFFER)InputBuffer; 1649 Status = Ext2InspectReparseData(RDB, InputBufferLength); 1650 if (!NT_SUCCESS(Status)) { 1651 _SEH2_LEAVE; 1652 } 1653 1654 UniName.Length = RDB->SymbolicLinkReparseBuffer.SubstituteNameLength; 1655 UniName.MaximumLength = UniName.Length; 1656 UniName.Buffer = 1657 (PWCHAR)((PUCHAR)&RDB->SymbolicLinkReparseBuffer.PathBuffer 1658 + RDB->SymbolicLinkReparseBuffer.SubstituteNameOffset); 1659 1660 OemNameLength = Ext2UnicodeToOEMSize(Vcb, &UniName); 1661 if (OemNameLength > USHRT_MAX) { 1662 Status = STATUS_INVALID_PARAMETER; 1663 _SEH2_LEAVE; 1664 } 1665 OemName.Length = (USHORT)OemNameLength; 1666 OemName.MaximumLength = OemNameLength + 1; 1667 OemNameBuffer = OemName.Buffer = Ext2AllocatePool(PagedPool, 1668 OemName.MaximumLength, 1669 'NL2E'); 1670 if (!OemNameBuffer) { 1671 Status = STATUS_INSUFFICIENT_RESOURCES; 1672 _SEH2_LEAVE; 1673 } 1674 1675 Ext2UnicodeToOEM(Vcb, &OemName, &UniName); 1676 OemName.Buffer[OemName.Length] = '\0'; 1677 for (i = 0;i < OemName.Length;i++) { 1678 if (OemName.Buffer[i] == '\\') { 1679 OemName.Buffer[i] = '/'; 1680 } 1681 } 1682 1683 /* free all data blocks of the inode (to be set as symlink) */ 1684 { 1685 LARGE_INTEGER zero = {0}; 1686 Status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &zero); 1687 } 1688 1689 /* decrease dir count of group desc and vcb stat */ 1690 if (S_ISDIR(Mcb->Inode.i_mode)) { 1691 1692 ULONG group = (Mcb->Inode.i_ino - 1) / INODES_PER_GROUP; 1693 Ext2UpdateGroupDirStat(IrpContext, Vcb, group); 1694 1695 /* drop extra reference for dir inode */ 1696 ext3_dec_count(&Mcb->Inode); 1697 } 1698 1699 /* overwrite inode mode as type SYMLINK */ 1700 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 1701 SetFlag(Mcb->FileAttr, FILE_ATTRIBUTE_REPARSE_POINT); 1702 1703 Status = Ext2WriteSymlink(IrpContext, Vcb, Mcb, OemNameBuffer, 1704 OemNameLength, &BytesWritten); 1705 if (NT_SUCCESS(Status)) { 1706 Ext2SetFileType(IrpContext, Vcb, ParentDcb, Mcb, 1707 S_IFLNK | S_IRWXUGO); 1708 } 1709 1710 } _SEH2_FINALLY { 1711 1712 if (FcbLockAcquired) { 1713 ExReleaseResourceLite(&Vcb->FcbLock); 1714 FcbLockAcquired = FALSE; 1715 } 1716 1717 if (MainResourceAcquired) { 1718 ExReleaseResourceLite(&Fcb->MainResource); 1719 } 1720 1721 if (OemNameBuffer) { 1722 Ext2FreePool(OemNameBuffer, 'NL2E'); 1723 } 1724 1725 if (NT_SUCCESS(Status)) { 1726 Ext2NotifyReportChange( 1727 IrpContext, 1728 Vcb, 1729 Mcb, 1730 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1731 FILE_ACTION_MODIFIED ); 1732 } 1733 1734 if (!_SEH2_AbnormalTermination()) { 1735 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { 1736 Status = Ext2QueueRequest(IrpContext); 1737 } else { 1738 Ext2CompleteIrpContext(IrpContext, Status); 1739 } 1740 } 1741 1742 if (ParentDcb) { 1743 Ext2ReleaseFcb(ParentDcb); 1744 } 1745 } _SEH2_END; 1746 1747 return Status; 1748 } 1749 1750 NTSTATUS 1751 Ext2TruncateSymlink( 1752 PEXT2_IRP_CONTEXT IrpContext, 1753 PEXT2_VCB Vcb, 1754 PEXT2_MCB Mcb, 1755 ULONG Size 1756 ) 1757 { 1758 NTSTATUS status = STATUS_SUCCESS; 1759 PUCHAR data = (PUCHAR)&Mcb->Inode.i_block; 1760 ULONG len = (ULONG)Mcb->Inode.i_size; 1761 LARGE_INTEGER NewSize; 1762 1763 if (len < EXT2_LINKLEN_IN_INODE && !Mcb->Inode.i_blocks) { 1764 1765 RtlZeroMemory(data + Size, EXT2_LINKLEN_IN_INODE - Size); 1766 Mcb->Inode.i_size = Size; 1767 Ext2SaveInode(IrpContext, Vcb, &Mcb->Inode); 1768 1769 } else { 1770 NewSize.QuadPart = Size; 1771 status = Ext2TruncateFile(IrpContext, Vcb, Mcb, &NewSize); 1772 if (!NT_SUCCESS(status)) { 1773 goto out; 1774 } 1775 } 1776 1777 out: 1778 return status; 1779 } 1780 1781 1782 /* FIXME: We can only handle one reparse point right now. */ 1783 NTSTATUS 1784 Ext2DeleteReparsePoint (IN PEXT2_IRP_CONTEXT IrpContext) 1785 { 1786 PIRP Irp = NULL; 1787 1788 PDEVICE_OBJECT DeviceObject; 1789 1790 PEXT2_VCB Vcb = NULL; 1791 PEXT2_FCB Fcb = NULL; 1792 PEXT2_CCB Ccb = NULL; 1793 PEXT2_MCB Mcb = NULL; 1794 1795 PEXT2_FCB ParentDcb = NULL; /* Dcb of it's current parent */ 1796 PEXT2_MCB ParentMcb = NULL; 1797 1798 NTSTATUS Status = STATUS_UNSUCCESSFUL; 1799 1800 BOOLEAN FcbLockAcquired = FALSE; 1801 BOOLEAN MainResourceAcquired = FALSE; 1802 1803 1804 _SEH2_TRY { 1805 1806 Ccb = IrpContext->Ccb; 1807 ASSERT(Ccb != NULL); 1808 ASSERT((Ccb->Identifier.Type == EXT2CCB) && 1809 (Ccb->Identifier.Size == sizeof(EXT2_CCB))); 1810 DeviceObject = IrpContext->DeviceObject; 1811 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 1812 Mcb = IrpContext->Fcb->Mcb; 1813 Irp = IrpContext->Irp; 1814 1815 ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); 1816 FcbLockAcquired = TRUE; 1817 1818 ParentMcb = Mcb->Parent; 1819 ParentDcb = ParentMcb->Fcb; 1820 if (ParentDcb == NULL) { 1821 ParentDcb = Ext2AllocateFcb(Vcb, ParentMcb); 1822 } 1823 if (ParentDcb) { 1824 Ext2ReferXcb(&ParentDcb->ReferenceCount); 1825 } 1826 1827 if (!Mcb || !IsInodeSymLink(&Mcb->Inode) || 1828 !IsFlagOn(Ccb->Flags, CCB_OPEN_REPARSE_POINT)) { 1829 Status = STATUS_NOT_A_REPARSE_POINT; 1830 _SEH2_LEAVE; 1831 } 1832 1833 Fcb = Ext2AllocateFcb (Vcb, Mcb); 1834 if (Fcb) { 1835 Ext2ReferXcb(&Fcb->ReferenceCount); 1836 } else { 1837 Status = STATUS_INSUFFICIENT_RESOURCES; 1838 _SEH2_LEAVE; 1839 } 1840 1841 if (FcbLockAcquired) { 1842 ExReleaseResourceLite(&Vcb->FcbLock); 1843 FcbLockAcquired = FALSE; 1844 } 1845 1846 if (!ExAcquireResourceSharedLite( 1847 &Fcb->MainResource, 1848 IsFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) )) { 1849 Status = STATUS_PENDING; 1850 _SEH2_LEAVE; 1851 } 1852 MainResourceAcquired = TRUE; 1853 1854 Status = Ext2TruncateSymlink(IrpContext, Vcb, Mcb, 0); 1855 if (!NT_SUCCESS(Status)) { 1856 _SEH2_LEAVE; 1857 } 1858 1859 /* inode is to be removed */ 1860 SetFlag(Ccb->Flags, CCB_DELETE_ON_CLOSE); 1861 1862 } _SEH2_FINALLY { 1863 1864 if (FcbLockAcquired) { 1865 ExReleaseResourceLite(&Vcb->FcbLock); 1866 } 1867 1868 if (MainResourceAcquired) { 1869 ExReleaseResourceLite(&Fcb->MainResource); 1870 } 1871 1872 if (NT_SUCCESS(Status)) { 1873 Ext2NotifyReportChange( 1874 IrpContext, 1875 Vcb, 1876 Mcb, 1877 FILE_NOTIFY_CHANGE_ATTRIBUTES, 1878 FILE_ACTION_MODIFIED ); 1879 1880 } 1881 1882 if (!_SEH2_AbnormalTermination()) { 1883 if (Status == STATUS_PENDING || Status == STATUS_CANT_WAIT) { 1884 Status = Ext2QueueRequest(IrpContext); 1885 } else { 1886 Ext2CompleteIrpContext(IrpContext, Status); 1887 } 1888 } 1889 1890 if (ParentDcb) { 1891 Ext2ReleaseFcb(ParentDcb); 1892 } 1893 1894 if (Fcb) { 1895 Ext2ReleaseFcb(Fcb); 1896 } 1897 } _SEH2_END; 1898 1899 return Status; 1900 } 1901 1902 NTSTATUS 1903 Ext2UserFsRequest (IN PEXT2_IRP_CONTEXT IrpContext) 1904 { 1905 PIRP Irp; 1906 PIO_STACK_LOCATION IoStackLocation; 1907 ULONG FsControlCode; 1908 NTSTATUS Status; 1909 1910 ASSERT(IrpContext); 1911 1912 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 1913 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 1914 1915 Irp = IrpContext->Irp; 1916 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 1917 1918 #ifndef _GNU_NTIFS_ 1919 FsControlCode = 1920 IoStackLocation->Parameters.FileSystemControl.FsControlCode; 1921 #else 1922 FsControlCode = ((PEXTENDED_IO_STACK_LOCATION) 1923 IoStackLocation)->Parameters.FileSystemControl.FsControlCode; 1924 #endif 1925 1926 switch (FsControlCode) { 1927 1928 case FSCTL_GET_REPARSE_POINT: 1929 Status = Ext2GetReparsePoint(IrpContext); 1930 break; 1931 1932 case FSCTL_SET_REPARSE_POINT: 1933 Status = Ext2SetReparsePoint(IrpContext); 1934 break; 1935 1936 case FSCTL_DELETE_REPARSE_POINT: 1937 Status = Ext2DeleteReparsePoint(IrpContext); 1938 break; 1939 1940 case FSCTL_LOCK_VOLUME: 1941 Status = Ext2LockVolume(IrpContext); 1942 break; 1943 1944 case FSCTL_UNLOCK_VOLUME: 1945 Status = Ext2UnlockVolume(IrpContext); 1946 break; 1947 1948 case FSCTL_DISMOUNT_VOLUME: 1949 Status = Ext2DismountVolume(IrpContext); 1950 break; 1951 1952 case FSCTL_IS_VOLUME_MOUNTED: 1953 Status = Ext2IsVolumeMounted(IrpContext); 1954 break; 1955 1956 case FSCTL_INVALIDATE_VOLUMES: 1957 Status = Ext2InvalidateVolumes(IrpContext); 1958 break; 1959 1960 #if (_WIN32_WINNT >= 0x0500) 1961 case FSCTL_ALLOW_EXTENDED_DASD_IO: 1962 Status = Ext2AllowExtendedDasdIo(IrpContext); 1963 break; 1964 #endif //(_WIN32_WINNT >= 0x0500) 1965 1966 case FSCTL_REQUEST_OPLOCK_LEVEL_1: 1967 case FSCTL_REQUEST_OPLOCK_LEVEL_2: 1968 case FSCTL_REQUEST_BATCH_OPLOCK: 1969 case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE: 1970 case FSCTL_OPBATCH_ACK_CLOSE_PENDING: 1971 case FSCTL_OPLOCK_BREAK_NOTIFY: 1972 case FSCTL_OPLOCK_BREAK_ACK_NO_2: 1973 1974 Status = Ext2OplockRequest(IrpContext); 1975 break; 1976 1977 case FSCTL_IS_VOLUME_DIRTY: 1978 Status = Ext2IsVolumeDirty(IrpContext); 1979 break; 1980 1981 case FSCTL_QUERY_RETRIEVAL_POINTERS: 1982 Status = Ext2QueryRetrievalPointers(IrpContext); 1983 break; 1984 1985 case FSCTL_GET_RETRIEVAL_POINTERS: 1986 Status = Ext2GetRetrievalPointers(IrpContext); 1987 break; 1988 1989 case FSCTL_GET_RETRIEVAL_POINTER_BASE: 1990 Status = Ext2GetRetrievalPointerBase(IrpContext); 1991 break; 1992 1993 default: 1994 1995 DEBUG(DL_INF, ( "Ext2UserFsRequest: Invalid User Request: %xh.\n", FsControlCode)); 1996 Status = STATUS_INVALID_DEVICE_REQUEST; 1997 1998 Ext2CompleteIrpContext(IrpContext, Status); 1999 } 2000 2001 return Status; 2002 } 2003 2004 BOOLEAN 2005 Ext2IsMediaWriteProtected ( 2006 IN PEXT2_IRP_CONTEXT IrpContext, 2007 IN PDEVICE_OBJECT TargetDevice 2008 ) 2009 { 2010 PIRP Irp; 2011 KEVENT Event; 2012 NTSTATUS Status; 2013 IO_STATUS_BLOCK IoStatus; 2014 2015 KeInitializeEvent(&Event, NotificationEvent, FALSE); 2016 2017 Irp = IoBuildDeviceIoControlRequest( IOCTL_DISK_IS_WRITABLE, 2018 TargetDevice, 2019 NULL, 2020 0, 2021 NULL, 2022 0, 2023 FALSE, 2024 &Event, 2025 &IoStatus ); 2026 2027 if (Irp == NULL) { 2028 return FALSE; 2029 } 2030 2031 SetFlag(IoGetNextIrpStackLocation(Irp)->Flags, SL_OVERRIDE_VERIFY_VOLUME); 2032 2033 Status = IoCallDriver(TargetDevice, Irp); 2034 2035 if (Status == STATUS_PENDING) { 2036 2037 (VOID) KeWaitForSingleObject( &Event, 2038 Executive, 2039 KernelMode, 2040 FALSE, 2041 (PLARGE_INTEGER)NULL ); 2042 2043 Status = IoStatus.Status; 2044 } 2045 2046 return (BOOLEAN)(Status == STATUS_MEDIA_WRITE_PROTECTED); 2047 } 2048 2049 NTSTATUS 2050 Ext2MountVolume (IN PEXT2_IRP_CONTEXT IrpContext) 2051 { 2052 PDEVICE_OBJECT MainDeviceObject; 2053 BOOLEAN GlobalDataResourceAcquired = FALSE; 2054 PIRP Irp; 2055 PIO_STACK_LOCATION IoStackLocation; 2056 PDEVICE_OBJECT TargetDeviceObject; 2057 NTSTATUS Status = STATUS_UNRECOGNIZED_VOLUME; 2058 PDEVICE_OBJECT VolumeDeviceObject = NULL; 2059 PEXT2_VCB Vcb = NULL, OldVcb = NULL; 2060 PVPB OldVpb = NULL, Vpb = NULL; 2061 PEXT2_SUPER_BLOCK Ext2Sb = NULL; 2062 ULONG dwBytes; 2063 DISK_GEOMETRY DiskGeometry; 2064 2065 _SEH2_TRY { 2066 2067 ASSERT(IrpContext != NULL); 2068 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 2069 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 2070 2071 MainDeviceObject = IrpContext->DeviceObject; 2072 2073 // 2074 // Make sure we can wait. 2075 // 2076 2077 SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT); 2078 2079 // 2080 // This request is only allowed on the main device object 2081 // 2082 if (!IsExt2FsDevice(MainDeviceObject)) { 2083 Status = STATUS_INVALID_DEVICE_REQUEST; 2084 _SEH2_LEAVE; 2085 } 2086 2087 if (IsFlagOn(Ext2Global->Flags, EXT2_UNLOAD_PENDING)) { 2088 Status = STATUS_UNRECOGNIZED_VOLUME; 2089 _SEH2_LEAVE; 2090 } 2091 2092 #if 0 2093 if (IrpContext->RealDevice->Size >= sizeof(ULONG) + sizeof(DEVICE_OBJECT) && 2094 *((PULONG)IrpContext->RealDevice->DeviceExtension) == 'DSSA') { 2095 } else { 2096 Status = STATUS_UNRECOGNIZED_VOLUME; 2097 _SEH2_LEAVE; 2098 } 2099 #endif 2100 2101 Irp = IrpContext->Irp; 2102 IoStackLocation = IoGetCurrentIrpStackLocation(Irp); 2103 TargetDeviceObject = 2104 IoStackLocation->Parameters.MountVolume.DeviceObject; 2105 2106 dwBytes = sizeof(DISK_GEOMETRY); 2107 Status = Ext2DiskIoControl( 2108 TargetDeviceObject, 2109 IOCTL_DISK_GET_DRIVE_GEOMETRY, 2110 NULL, 2111 0, 2112 &DiskGeometry, 2113 &dwBytes ); 2114 2115 if (!NT_SUCCESS(Status)) { 2116 _SEH2_LEAVE; 2117 } 2118 2119 Status = IoCreateDevice( 2120 MainDeviceObject->DriverObject, 2121 sizeof(EXT2_VCB), 2122 NULL, 2123 FILE_DEVICE_DISK_FILE_SYSTEM, 2124 0, 2125 FALSE, 2126 &VolumeDeviceObject ); 2127 2128 if (!NT_SUCCESS(Status)) { 2129 _SEH2_LEAVE; 2130 } 2131 INC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB)); 2132 2133 #ifdef _PNP_POWER_ 2134 /* don't care about power management requests */ 2135 VolumeDeviceObject->DeviceObjectExtension->PowerControlNeeded = FALSE; 2136 #endif 2137 2138 VolumeDeviceObject->StackSize = (CCHAR)(TargetDeviceObject->StackSize + 1); 2139 ClearFlag(VolumeDeviceObject->Flags, DO_DEVICE_INITIALIZING); 2140 2141 /* 2142 These are for buffer-address alignment requirements. 2143 Never do this check, unless you want fail user requests :) 2144 2145 if (TargetDeviceObject->AlignmentRequirement > 2146 VolumeDeviceObject->AlignmentRequirement) { 2147 2148 VolumeDeviceObject->AlignmentRequirement = 2149 TargetDeviceObject->AlignmentRequirement; 2150 } 2151 2152 if (DiskGeometry.BytesPerSector - 1 > 2153 VolumeDeviceObject->AlignmentRequirement) { 2154 VolumeDeviceObject->AlignmentRequirement = 2155 DiskGeometry.BytesPerSector - 1; 2156 TargetDeviceObject->AlignmentRequirement = 2157 DiskGeometry.BytesPerSector - 1; 2158 } 2159 */ 2160 (IoStackLocation->Parameters.MountVolume.Vpb)->DeviceObject = 2161 VolumeDeviceObject; 2162 Vpb = IoStackLocation->Parameters.MountVolume.Vpb; 2163 2164 Vcb = (PEXT2_VCB) VolumeDeviceObject->DeviceExtension; 2165 2166 RtlZeroMemory(Vcb, sizeof(EXT2_VCB)); 2167 Vcb->Identifier.Type = EXT2VCB; 2168 Vcb->Identifier.Size = sizeof(EXT2_VCB); 2169 Vcb->TargetDeviceObject = TargetDeviceObject; 2170 Vcb->DiskGeometry = DiskGeometry; 2171 InitializeListHead(&Vcb->Next); 2172 2173 Status = Ext2LoadSuper(Vcb, FALSE, &Ext2Sb); 2174 if (!NT_SUCCESS(Status)) { 2175 Vcb = NULL; 2176 Status = STATUS_UNRECOGNIZED_VOLUME; 2177 _SEH2_LEAVE; 2178 } 2179 ASSERT (NULL != Ext2Sb); 2180 2181 /* check Linux Ext2/Ext3 volume magic */ 2182 if (Ext2Sb->s_magic == EXT2_SUPER_MAGIC) { 2183 DEBUG(DL_INF, ( "Volume of ext2 file system is found.\n")); 2184 } else { 2185 Status = STATUS_UNRECOGNIZED_VOLUME; 2186 Vcb = NULL; 2187 _SEH2_LEAVE; 2188 } 2189 2190 DEBUG(DL_DBG, ("Ext2MountVolume: DevObject=%p Vcb=%p\n", VolumeDeviceObject, Vcb)); 2191 2192 /* initialize Vcb structure */ 2193 Status = Ext2InitializeVcb( IrpContext, Vcb, Ext2Sb, 2194 TargetDeviceObject, 2195 VolumeDeviceObject, Vpb); 2196 2197 if (NT_SUCCESS(Status)) { 2198 2199 PLIST_ENTRY List; 2200 2201 ExAcquireResourceExclusiveLite(&(Ext2Global->Resource), TRUE); 2202 GlobalDataResourceAcquired = TRUE; 2203 2204 for (List = Ext2Global->VcbList.Flink; 2205 List != &Ext2Global->VcbList; 2206 List = List->Flink) { 2207 2208 OldVcb = CONTAINING_RECORD(List, EXT2_VCB, Next); 2209 OldVpb = OldVcb->Vpb; 2210 2211 /* in case we are already in the queue, should not happen */ 2212 if (OldVpb == Vpb) { 2213 continue; 2214 } 2215 2216 if ( (OldVpb->SerialNumber == Vpb->SerialNumber) && 2217 (!IsMounted(OldVcb)) && (IsFlagOn(OldVcb->Flags, VCB_NEW_VPB)) && 2218 (OldVpb->RealDevice == TargetDeviceObject) && 2219 (OldVpb->VolumeLabelLength == Vpb->VolumeLabelLength) && 2220 (RtlEqualMemory(&OldVpb->VolumeLabel[0], 2221 &Vpb->VolumeLabel[0], 2222 Vpb->VolumeLabelLength)) && 2223 (RtlEqualMemory(&OldVcb->SuperBlock->s_uuid[0], 2224 &Vcb->SuperBlock->s_uuid[0], 16)) ) { 2225 ClearFlag(OldVcb->Flags, VCB_MOUNTED); 2226 } 2227 } 2228 2229 SetLongFlag(Vcb->Flags, VCB_MOUNTED); 2230 SetFlag(Vcb->Vpb->Flags, VPB_MOUNTED); 2231 Ext2InsertVcb(Vcb); 2232 Vcb = NULL; 2233 Vpb = NULL; 2234 ObDereferenceObject(TargetDeviceObject); 2235 2236 } else { 2237 2238 Vcb = NULL; 2239 } 2240 2241 } _SEH2_FINALLY { 2242 2243 if (GlobalDataResourceAcquired) { 2244 ExReleaseResourceLite(&Ext2Global->Resource); 2245 } 2246 2247 if (!NT_SUCCESS(Status)) { 2248 2249 if (!NT_SUCCESS(Status)) { 2250 if ( Vpb != NULL ) { 2251 Vpb->DeviceObject = NULL; 2252 } 2253 } 2254 2255 if (Vcb) { 2256 Ext2DestroyVcb(Vcb); 2257 } else { 2258 if (Ext2Sb) { 2259 Ext2FreePool(Ext2Sb, EXT2_SB_MAGIC); 2260 } 2261 if (VolumeDeviceObject) { 2262 IoDeleteDevice(VolumeDeviceObject); 2263 DEC_MEM_COUNT(PS_VCB, VolumeDeviceObject, sizeof(EXT2_VCB)); 2264 } 2265 } 2266 } 2267 2268 if (!IrpContext->ExceptionInProgress) { 2269 Ext2CompleteIrpContext(IrpContext, Status); 2270 } 2271 } _SEH2_END; 2272 2273 return Status; 2274 } 2275 2276 VOID 2277 Ext2VerifyVcb (IN PEXT2_IRP_CONTEXT IrpContext, 2278 IN PEXT2_VCB Vcb ) 2279 { 2280 NTSTATUS Status = STATUS_SUCCESS; 2281 2282 BOOLEAN bVerify = FALSE; 2283 ULONG ChangeCount = 0; 2284 ULONG dwBytes; 2285 2286 PIRP Irp; 2287 PEXTENDED_IO_STACK_LOCATION IrpSp; 2288 2289 _SEH2_TRY { 2290 2291 ASSERT(IrpContext != NULL); 2292 2293 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 2294 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 2295 2296 Irp = IrpContext->Irp; 2297 IrpSp = (PEXTENDED_IO_STACK_LOCATION)IoGetCurrentIrpStackLocation(Irp); 2298 2299 bVerify = IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 2300 2301 if ( (IsFlagOn(Vcb->Flags, VCB_REMOVABLE_MEDIA) || 2302 IsFlagOn(Vcb->Flags, VCB_FLOPPY_DISK)) && !bVerify ) { 2303 2304 dwBytes = sizeof(ULONG); 2305 Status = Ext2DiskIoControl( 2306 Vcb->TargetDeviceObject, 2307 IOCTL_DISK_CHECK_VERIFY, 2308 NULL, 2309 0, 2310 &ChangeCount, 2311 &dwBytes ); 2312 2313 if ( STATUS_VERIFY_REQUIRED == Status || 2314 STATUS_DEVICE_NOT_READY == Status || 2315 STATUS_NO_MEDIA_IN_DEVICE == Status || 2316 (NT_SUCCESS(Status) && 2317 (ChangeCount != Vcb->ChangeCount))) { 2318 2319 KIRQL Irql; 2320 2321 IoAcquireVpbSpinLock(&Irql); 2322 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) { 2323 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 2324 } 2325 IoReleaseVpbSpinLock(Irql); 2326 2327 } else { 2328 2329 if (!NT_SUCCESS(Status)) { 2330 Ext2NormalizeAndRaiseStatus(IrpContext, Status); 2331 } 2332 } 2333 } 2334 2335 if ( IsFlagOn(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME)) { 2336 IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice ); 2337 Ext2NormalizeAndRaiseStatus ( IrpContext, 2338 STATUS_VERIFY_REQUIRED ); 2339 } 2340 2341 if (IsMounted(Vcb)) { 2342 2343 if ( (IrpContext->MajorFunction == IRP_MJ_WRITE) || 2344 (IrpContext->MajorFunction == IRP_MJ_SET_INFORMATION) || 2345 (IrpContext->MajorFunction == IRP_MJ_SET_EA) || 2346 (IrpContext->MajorFunction == IRP_MJ_FLUSH_BUFFERS) || 2347 (IrpContext->MajorFunction == IRP_MJ_SET_VOLUME_INFORMATION) || 2348 (IrpContext->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL && 2349 IrpContext->MinorFunction == IRP_MN_USER_FS_REQUEST && 2350 IrpSp->Parameters.FileSystemControl.FsControlCode == 2351 FSCTL_MARK_VOLUME_DIRTY)) { 2352 2353 if (IsFlagOn(Vcb->Flags, VCB_WRITE_PROTECTED)) { 2354 2355 KIRQL Irql; 2356 2357 IoAcquireVpbSpinLock(&Irql); 2358 if (Vcb->Vpb == Vcb->Vpb->RealDevice->Vpb) { 2359 SetFlag (Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 2360 } 2361 IoReleaseVpbSpinLock(Irql); 2362 2363 IoSetHardErrorOrVerifyDevice( Irp, Vcb->Vpb->RealDevice ); 2364 2365 Ext2RaiseStatus(IrpContext, STATUS_MEDIA_WRITE_PROTECTED); 2366 } 2367 } 2368 } 2369 2370 } _SEH2_FINALLY { 2371 2372 } _SEH2_END; 2373 2374 } 2375 2376 2377 NTSTATUS 2378 Ext2VerifyVolume (IN PEXT2_IRP_CONTEXT IrpContext) 2379 { 2380 PDEVICE_OBJECT DeviceObject; 2381 NTSTATUS Status = STATUS_UNSUCCESSFUL; 2382 PEXT2_SUPER_BLOCK ext2_sb = NULL; 2383 PEXT2_VCB Vcb = NULL; 2384 BOOLEAN VcbResourceAcquired = FALSE; 2385 PIRP Irp; 2386 ULONG ChangeCount = 0; 2387 ULONG dwBytes; 2388 2389 _SEH2_TRY { 2390 2391 ASSERT(IrpContext != NULL); 2392 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 2393 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 2394 2395 DeviceObject = IrpContext->DeviceObject; 2396 // 2397 // This request is not allowed on the main device object 2398 // 2399 if (IsExt2FsDevice(DeviceObject)) { 2400 Status = STATUS_INVALID_DEVICE_REQUEST; 2401 _SEH2_LEAVE; 2402 } 2403 2404 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 2405 ASSERT(Vcb != NULL); 2406 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 2407 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 2408 2409 VcbResourceAcquired = 2410 ExAcquireResourceExclusiveLite( 2411 &Vcb->MainResource, 2412 TRUE ); 2413 2414 if (!FlagOn(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME)) { 2415 Status = STATUS_SUCCESS; 2416 _SEH2_LEAVE; 2417 } 2418 2419 if (!IsMounted(Vcb)) { 2420 Status = STATUS_WRONG_VOLUME; 2421 _SEH2_LEAVE; 2422 } 2423 2424 dwBytes = sizeof(ULONG); 2425 Status = Ext2DiskIoControl( 2426 Vcb->TargetDeviceObject, 2427 IOCTL_DISK_CHECK_VERIFY, 2428 NULL, 2429 0, 2430 &ChangeCount, 2431 &dwBytes ); 2432 2433 2434 if (!NT_SUCCESS(Status)) { 2435 Status = STATUS_WRONG_VOLUME; 2436 _SEH2_LEAVE; 2437 } else { 2438 Vcb->ChangeCount = ChangeCount; 2439 } 2440 2441 Irp = IrpContext->Irp; 2442 2443 Status = Ext2LoadSuper(Vcb, TRUE, &ext2_sb); 2444 2445 if (!NT_SUCCESS(Status)) { 2446 _SEH2_LEAVE; 2447 } 2448 2449 ASSERT(NULL != ext2_sb); 2450 if ((ext2_sb->s_magic == EXT2_SUPER_MAGIC) && 2451 (memcmp(ext2_sb->s_uuid, SUPER_BLOCK->s_uuid, 16) == 0) && 2452 (memcmp(ext2_sb->s_volume_name, SUPER_BLOCK->s_volume_name, 16) ==0)) { 2453 2454 ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME); 2455 2456 if (Ext2IsMediaWriteProtected(IrpContext, Vcb->TargetDeviceObject)) { 2457 SetLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED); 2458 } else { 2459 ClearLongFlag(Vcb->Flags, VCB_WRITE_PROTECTED); 2460 } 2461 2462 DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify succeeded.\n")); 2463 2464 } else { 2465 2466 Status = STATUS_WRONG_VOLUME; 2467 Ext2PurgeVolume(Vcb, FALSE); 2468 2469 SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING); 2470 ClearFlag(Vcb->TargetDeviceObject->Flags, DO_VERIFY_VOLUME); 2471 2472 DEBUG(DL_INF, ( "Ext2VerifyVolume: Volume verify failed.\n")); 2473 } 2474 2475 } _SEH2_FINALLY { 2476 2477 if (ext2_sb) 2478 Ext2FreePool(ext2_sb, EXT2_SB_MAGIC); 2479 2480 if (VcbResourceAcquired) { 2481 ExReleaseResourceLite(&Vcb->MainResource); 2482 } 2483 2484 if (!IrpContext->ExceptionInProgress) { 2485 Ext2CompleteIrpContext(IrpContext, Status); 2486 } 2487 } _SEH2_END; 2488 2489 return Status; 2490 } 2491 2492 2493 NTSTATUS 2494 Ext2IsVolumeMounted (IN PEXT2_IRP_CONTEXT IrpContext) 2495 { 2496 PDEVICE_OBJECT DeviceObject; 2497 PEXT2_VCB Vcb = 0; 2498 NTSTATUS Status = STATUS_SUCCESS; 2499 2500 ASSERT(IrpContext); 2501 2502 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 2503 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 2504 2505 2506 DeviceObject = IrpContext->DeviceObject; 2507 2508 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 2509 2510 ASSERT(IsMounted(Vcb)); 2511 2512 Ext2VerifyVcb (IrpContext, Vcb); 2513 2514 Ext2CompleteIrpContext(IrpContext, Status); 2515 2516 return Status; 2517 } 2518 2519 2520 NTSTATUS 2521 Ext2DismountVolume (IN PEXT2_IRP_CONTEXT IrpContext) 2522 { 2523 PDEVICE_OBJECT DeviceObject; 2524 NTSTATUS Status = STATUS_UNSUCCESSFUL; 2525 PEXT2_VCB Vcb = NULL; 2526 BOOLEAN VcbResourceAcquired = FALSE; 2527 2528 _SEH2_TRY { 2529 2530 ASSERT(IrpContext != NULL); 2531 2532 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 2533 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 2534 2535 DeviceObject = IrpContext->DeviceObject; 2536 2537 // 2538 // This request is not allowed on the main device object 2539 // 2540 if (IsExt2FsDevice(DeviceObject)) { 2541 Status = STATUS_INVALID_DEVICE_REQUEST; 2542 _SEH2_LEAVE; 2543 } 2544 2545 Vcb = (PEXT2_VCB) DeviceObject->DeviceExtension; 2546 2547 ASSERT(Vcb != NULL); 2548 2549 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 2550 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 2551 2552 ASSERT(IsMounted(Vcb)); 2553 2554 ExAcquireResourceExclusiveLite( 2555 &Vcb->MainResource, 2556 TRUE ); 2557 2558 VcbResourceAcquired = TRUE; 2559 2560 if ( IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) { 2561 Status = STATUS_VOLUME_DISMOUNTED; 2562 _SEH2_LEAVE; 2563 } 2564 2565 Ext2FlushFiles(IrpContext, Vcb, FALSE); 2566 Ext2FlushVolume(IrpContext, Vcb, FALSE); 2567 2568 ExReleaseResourceLite(&Vcb->MainResource); 2569 VcbResourceAcquired = FALSE; 2570 2571 Ext2PurgeVolume(Vcb, TRUE); 2572 Ext2CheckDismount(IrpContext, Vcb, TRUE); 2573 2574 DEBUG(DL_INF, ( "Ext2Dismount: Volume dismount pending.\n")); 2575 Status = STATUS_SUCCESS; 2576 2577 } _SEH2_FINALLY { 2578 2579 if (VcbResourceAcquired) { 2580 ExReleaseResourceLite(&Vcb->MainResource); 2581 } 2582 2583 if (!IrpContext->ExceptionInProgress) { 2584 Ext2CompleteIrpContext(IrpContext, Status); 2585 } 2586 } _SEH2_END; 2587 2588 return Status; 2589 } 2590 2591 BOOLEAN 2592 Ext2CheckDismount ( 2593 IN PEXT2_IRP_CONTEXT IrpContext, 2594 IN PEXT2_VCB Vcb, 2595 IN BOOLEAN bForce ) 2596 { 2597 KIRQL Irql; 2598 PVPB Vpb = Vcb->Vpb, NewVpb = NULL; 2599 BOOLEAN bDeleted = FALSE, bTearDown = FALSE; 2600 ULONG UnCleanCount = 0; 2601 2602 NewVpb = ExAllocatePoolWithTag(NonPagedPool, VPB_SIZE, TAG_VPB); 2603 if (NewVpb == NULL) { 2604 DEBUG(DL_ERR, ( "Ex2CheckDismount: failed to allocate NewVpb.\n")); 2605 return FALSE; 2606 } 2607 DEBUG(DL_DBG, ("Ext2CheckDismount: NewVpb allocated: %p\n", NewVpb)); 2608 INC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB)); 2609 memset(NewVpb, '_', VPB_SIZE); 2610 RtlZeroMemory(NewVpb, sizeof(VPB)); 2611 2612 ExAcquireResourceExclusiveLite( 2613 &Ext2Global->Resource, TRUE ); 2614 2615 ExAcquireResourceExclusiveLite( 2616 &Vcb->MainResource, TRUE ); 2617 2618 if (IrpContext && 2619 IrpContext->MajorFunction == IRP_MJ_CREATE && 2620 IrpContext->RealDevice == Vcb->RealDevice) { 2621 UnCleanCount = 2; 2622 } else { 2623 UnCleanCount = 1; 2624 } 2625 2626 IoAcquireVpbSpinLock (&Irql); 2627 2628 DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb %p ioctl=%d Device %p\n", 2629 Vpb, Vpb->ReferenceCount, Vpb->RealDevice)); 2630 2631 if (Vpb->ReferenceCount <= UnCleanCount) { 2632 2633 if (!IsFlagOn(Vcb->Flags, VCB_DISMOUNT_PENDING)) { 2634 2635 ClearFlag(Vpb->Flags, VPB_MOUNTED); 2636 ClearFlag(Vpb->Flags, VPB_LOCKED); 2637 2638 if ((Vcb->RealDevice != Vpb->RealDevice) && 2639 (Vcb->RealDevice->Vpb == Vpb)) { 2640 SetFlag(Vcb->RealDevice->Flags, DO_DEVICE_INITIALIZING); 2641 SetFlag(Vpb->Flags, VPB_PERSISTENT ); 2642 } 2643 2644 Ext2RemoveVcb(Vcb); 2645 SetLongFlag(Vcb->Flags, VCB_DISMOUNT_PENDING); 2646 } 2647 2648 if (Vpb->ReferenceCount) { 2649 bTearDown = TRUE; 2650 } else { 2651 bDeleted = TRUE; 2652 Vpb->DeviceObject = NULL; 2653 } 2654 2655 DEBUG(DL_DBG, ("Ext2CheckDismount: Vpb: %p bDeleted=%d bTearDown=%d\n", 2656 Vpb, bDeleted, bTearDown)); 2657 2658 2659 } else if (bForce) { 2660 2661 DEBUG(DL_DBG, ( "Ext2CheckDismount: New/Old Vpb %p/%p Realdevice = %p\n", 2662 NewVpb, Vcb->Vpb, Vpb->RealDevice)); 2663 2664 /* keep vpb president and later we'll free it */ 2665 SetFlag(Vpb->Flags, VPB_PERSISTENT); 2666 2667 Vcb->Vpb2 = Vcb->Vpb; 2668 NewVpb->Type = IO_TYPE_VPB; 2669 NewVpb->Size = sizeof(VPB); 2670 NewVpb->Flags = Vpb->Flags & VPB_REMOVE_PENDING; 2671 NewVpb->RealDevice = Vpb->RealDevice; 2672 NewVpb->RealDevice->Vpb = NewVpb; 2673 NewVpb = NULL; 2674 ClearFlag(Vpb->Flags, VPB_MOUNTED); 2675 SetLongFlag(Vcb->Flags, VCB_NEW_VPB); 2676 ClearLongFlag(Vcb->Flags, VCB_MOUNTED); 2677 } 2678 2679 IoReleaseVpbSpinLock(Irql); 2680 2681 ExReleaseResourceLite(&Vcb->MainResource); 2682 ExReleaseResourceLite(&Ext2Global->Resource); 2683 2684 if (bTearDown) { 2685 DEBUG(DL_DBG, ( "Ext2CheckDismount: Tearing vcb %p ...\n", Vcb)); 2686 Ext2TearDownStream(Vcb); 2687 } 2688 2689 if (bDeleted) { 2690 DEBUG(DL_DBG, ( "Ext2CheckDismount: Deleting vcb %p ...\n", Vcb)); 2691 Ext2DestroyVcb(Vcb); 2692 } 2693 2694 if (NewVpb != NULL) { 2695 DEBUG(DL_DBG, ( "Ext2CheckDismount: freeing new Vpb %p\n", NewVpb)); 2696 ExFreePoolWithTag(NewVpb, TAG_VPB); 2697 DEC_MEM_COUNT(PS_VPB, NewVpb, sizeof(VPB)); 2698 } 2699 2700 return bDeleted; 2701 } 2702 2703 NTSTATUS 2704 Ext2PurgeVolume (IN PEXT2_VCB Vcb, 2705 IN BOOLEAN FlushBeforePurge ) 2706 { 2707 PEXT2_FCB Fcb; 2708 LIST_ENTRY List, *Next; 2709 2710 BOOLEAN VcbResourceAcquired = FALSE; 2711 BOOLEAN FcbResourceAcquired = FALSE; 2712 BOOLEAN gdResourceAcquired = FALSE; 2713 2714 _SEH2_TRY { 2715 2716 ASSERT(Vcb != NULL); 2717 ASSERT((Vcb->Identifier.Type == EXT2VCB) && 2718 (Vcb->Identifier.Size == sizeof(EXT2_VCB))); 2719 2720 ExAcquireResourceExclusiveLite(&Vcb->MainResource, TRUE); 2721 VcbResourceAcquired = TRUE; 2722 2723 if (IsVcbReadOnly(Vcb)) { 2724 FlushBeforePurge = FALSE; 2725 } 2726 2727 InitializeListHead(&List); 2728 2729 ExAcquireResourceExclusiveLite(&Vcb->FcbLock, TRUE); 2730 FcbResourceAcquired = TRUE; 2731 2732 while (!IsListEmpty(&Vcb->FcbList)) { 2733 2734 Next = RemoveHeadList(&Vcb->FcbList); 2735 Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next); 2736 2737 DEBUG(DL_INF, ( "Ext2PurgeVolume: %wZ refercount=%xh\n", 2738 &Fcb->Mcb->FullName, Fcb->ReferenceCount)); 2739 InsertTailList(&List, &Fcb->Next); 2740 } 2741 2742 while (!IsListEmpty(&List)) { 2743 2744 Next = RemoveHeadList(&List); 2745 Fcb = CONTAINING_RECORD(Next, EXT2_FCB, Next); 2746 2747 if (ExAcquireResourceExclusiveLite( 2748 &Fcb->MainResource, 2749 TRUE )) { 2750 2751 Ext2PurgeFile(Fcb, FlushBeforePurge); 2752 2753 if (Fcb->ReferenceCount <= 1) { 2754 Fcb->TsDrop.QuadPart = 0; 2755 InsertHeadList(&Vcb->FcbList, &Fcb->Next); 2756 } else { 2757 InsertTailList(&Vcb->FcbList, &Fcb->Next); 2758 } 2759 ExReleaseResourceLite(&Fcb->MainResource); 2760 } 2761 } 2762 2763 if (FcbResourceAcquired) { 2764 ExReleaseResourceLite(&Vcb->FcbLock); 2765 FcbResourceAcquired = FALSE; 2766 } 2767 2768 /* acquire bd lock to avoid bh creation */ 2769 ExAcquireResourceExclusiveLite(&Vcb->sbi.s_gd_lock, TRUE); 2770 gdResourceAcquired = TRUE; 2771 2772 /* discard buffer_headers for group_desc */ 2773 Ext2DropBH(Vcb); 2774 2775 if (FlushBeforePurge) { 2776 ExAcquireSharedStarveExclusive(&Vcb->PagingIoResource, TRUE); 2777 ExReleaseResourceLite(&Vcb->PagingIoResource); 2778 2779 CcFlushCache(&Vcb->SectionObject, NULL, 0, NULL); 2780 } 2781 2782 if (Vcb->SectionObject.ImageSectionObject) { 2783 MmFlushImageSection(&Vcb->SectionObject, MmFlushForWrite); 2784 } 2785 2786 if (Vcb->SectionObject.DataSectionObject) { 2787 CcPurgeCacheSection(&Vcb->SectionObject, NULL, 0, FALSE); 2788 } 2789 2790 DEBUG(DL_INF, ( "Ext2PurgeVolume: Volume flushed and purged.\n")); 2791 2792 } _SEH2_FINALLY { 2793 2794 if (gdResourceAcquired) { 2795 ExReleaseResourceLite(&Vcb->sbi.s_gd_lock); 2796 } 2797 2798 if (FcbResourceAcquired) { 2799 ExReleaseResourceLite(&Vcb->FcbLock); 2800 } 2801 2802 if (VcbResourceAcquired) { 2803 ExReleaseResourceLite(&Vcb->MainResource); 2804 } 2805 } _SEH2_END; 2806 2807 return STATUS_SUCCESS; 2808 } 2809 2810 NTSTATUS 2811 Ext2PurgeFile ( IN PEXT2_FCB Fcb, 2812 IN BOOLEAN FlushBeforePurge ) 2813 { 2814 IO_STATUS_BLOCK IoStatus; 2815 2816 ASSERT(Fcb != NULL); 2817 2818 ASSERT((Fcb->Identifier.Type == EXT2FCB) && 2819 (Fcb->Identifier.Size == sizeof(EXT2_FCB))); 2820 2821 2822 if (!IsVcbReadOnly(Fcb->Vcb) && FlushBeforePurge) { 2823 DEBUG(DL_INF, ( "Ext2PurgeFile: CcFlushCache on %wZ.\n", 2824 &Fcb->Mcb->FullName)); 2825 ExAcquireSharedStarveExclusive(&Fcb->PagingIoResource, TRUE); 2826 ExReleaseResourceLite(&Fcb->PagingIoResource); 2827 CcFlushCache(&Fcb->SectionObject, NULL, 0, &IoStatus); 2828 ClearFlag(Fcb->Flags, FCB_FILE_MODIFIED); 2829 } 2830 2831 if (Fcb->SectionObject.ImageSectionObject) { 2832 DEBUG(DL_INF, ( "Ext2PurgeFile: MmFlushImageSection on %wZ.\n", 2833 &Fcb->Mcb->FullName)); 2834 MmFlushImageSection(&Fcb->SectionObject, MmFlushForWrite); 2835 } 2836 2837 if (Fcb->SectionObject.DataSectionObject) { 2838 DEBUG(DL_INF, ( "Ext2PurgeFile: CcPurgeCacheSection on %wZ.\n", 2839 &Fcb->Mcb->FullName)); 2840 CcPurgeCacheSection(&Fcb->SectionObject, NULL, 0, FALSE); 2841 } 2842 2843 return STATUS_SUCCESS; 2844 } 2845 2846 2847 NTSTATUS 2848 Ext2FileSystemControl (IN PEXT2_IRP_CONTEXT IrpContext) 2849 { 2850 NTSTATUS Status; 2851 2852 ASSERT(IrpContext); 2853 2854 ASSERT((IrpContext->Identifier.Type == EXT2ICX) && 2855 (IrpContext->Identifier.Size == sizeof(EXT2_IRP_CONTEXT))); 2856 2857 switch (IrpContext->MinorFunction) { 2858 2859 case IRP_MN_USER_FS_REQUEST: 2860 Status = Ext2UserFsRequest(IrpContext); 2861 break; 2862 2863 case IRP_MN_MOUNT_VOLUME: 2864 Status = Ext2MountVolume(IrpContext); 2865 break; 2866 2867 case IRP_MN_VERIFY_VOLUME: 2868 Status = Ext2VerifyVolume(IrpContext); 2869 break; 2870 2871 default: 2872 2873 DEBUG(DL_ERR, ( "Ext2FilsSystemControl: Invalid Device Request.\n")); 2874 Status = STATUS_INVALID_DEVICE_REQUEST; 2875 Ext2CompleteIrpContext(IrpContext, Status); 2876 } 2877 2878 return Status; 2879 } 2880