1 /*++ 2 3 Copyright (c) 1989-2000 Microsoft Corporation 4 5 Module Name: 6 7 Create.c 8 9 Abstract: 10 11 This module implements the File Create routine for Fat called by the 12 dispatch driver. 13 14 15 --*/ 16 17 #include "fatprocs.h" 18 19 // 20 // The Bug check file id for this module 21 // 22 23 #define BugCheckFileId (FAT_BUG_CHECK_CREATE) 24 25 // 26 // The debug trace level 27 // 28 29 #define Dbg (DEBUG_TRACE_CREATE) 30 31 32 // 33 // Macros for incrementing performance counters. 34 // 35 36 #define CollectCreateHitStatistics(VCB) { \ 37 PFILE_SYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors]; \ 38 Stats->Fat.CreateHits += 1; \ 39 } 40 41 #define CollectCreateStatistics(VCB,STATUS) { \ 42 PFILE_SYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors]; \ 43 if ((STATUS) == STATUS_SUCCESS) { \ 44 Stats->Fat.SuccessfulCreates += 1; \ 45 } else { \ 46 Stats->Fat.FailedCreates += 1; \ 47 } \ 48 } 49 50 LUID FatSecurityPrivilege = { SE_SECURITY_PRIVILEGE, 0 }; 51 52 // 53 // local procedure prototypes 54 // 55 56 _Requires_lock_held_(_Global_critical_region_) 57 IO_STATUS_BLOCK 58 FatOpenVolume ( 59 _In_ PIRP_CONTEXT IrpContext, 60 _Inout_ PFILE_OBJECT FileObject, 61 _Inout_ PVCB Vcb, 62 _In_ PACCESS_MASK DesiredAccess, 63 _In_ USHORT ShareAccess, 64 _In_ ULONG CreateDisposition 65 ); 66 67 _Requires_lock_held_(_Global_critical_region_) 68 IO_STATUS_BLOCK 69 FatOpenRootDcb ( 70 _In_ PIRP_CONTEXT IrpContext, 71 _Inout_ PFILE_OBJECT FileObject, 72 _Inout_ PVCB Vcb, 73 _In_ PACCESS_MASK DesiredAccess, 74 _In_ USHORT ShareAccess, 75 _In_ ULONG CreateDisposition 76 ); 77 78 _Requires_lock_held_(_Global_critical_region_) 79 IO_STATUS_BLOCK 80 FatOpenExistingDcb ( 81 _In_ PIRP_CONTEXT IrpContext, 82 _In_ PIO_STACK_LOCATION IrpSp, 83 _Inout_ PFILE_OBJECT FileObject, 84 _Inout_ PVCB Vcb, 85 _Inout_ PDCB Dcb, 86 _In_ PACCESS_MASK DesiredAccess, 87 _In_ USHORT ShareAccess, 88 _In_ ULONG CreateDisposition, 89 _In_ BOOLEAN NoEaKnowledge, 90 _In_ BOOLEAN DeleteOnClose, 91 _In_ BOOLEAN OpenRequiringOplock, 92 _In_ BOOLEAN FileNameOpenedDos, 93 _Out_ PBOOLEAN OplockPostIrp 94 ); 95 96 _Requires_lock_held_(_Global_critical_region_) 97 IO_STATUS_BLOCK 98 FatOpenExistingFcb ( 99 _In_ PIRP_CONTEXT IrpContext, 100 _In_ PIO_STACK_LOCATION IrpSp, 101 _Inout_ PFILE_OBJECT FileObject, 102 _Inout_ PVCB Vcb, 103 _Inout_ PFCB Fcb, 104 _In_ PACCESS_MASK DesiredAccess, 105 _In_ USHORT ShareAccess, 106 _In_ ULONG AllocationSize, 107 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 108 _In_ ULONG EaLength, 109 _In_ USHORT FileAttributes, 110 _In_ ULONG CreateDisposition, 111 _In_ BOOLEAN NoEaKnowledge, 112 _In_ BOOLEAN DeleteOnClose, 113 _In_ BOOLEAN OpenRequiringOplock, 114 _In_ BOOLEAN FileNameOpenedDos, 115 _Out_ PBOOLEAN OplockPostIrp 116 ); 117 118 _Requires_lock_held_(_Global_critical_region_) 119 IO_STATUS_BLOCK 120 FatOpenTargetDirectory ( 121 _In_ PIRP_CONTEXT IrpContext, 122 _Inout_ PFILE_OBJECT FileObject, 123 _Inout_ PDCB Dcb, 124 _In_ PACCESS_MASK DesiredAccess, 125 _In_ USHORT ShareAccess, 126 _In_ BOOLEAN DoesNameExist, 127 _In_ BOOLEAN FileNameOpenedDos 128 ); 129 130 _Success_(return.Status == STATUS_SUCCESS) 131 _Requires_lock_held_(_Global_critical_region_) 132 IO_STATUS_BLOCK 133 FatOpenExistingDirectory ( 134 _In_ PIRP_CONTEXT IrpContext, 135 _In_ PIO_STACK_LOCATION IrpSp, 136 _Inout_ PFILE_OBJECT FileObject, 137 _Inout_ PVCB Vcb, 138 _Outptr_result_maybenull_ PDCB *Dcb, 139 _In_ PDCB ParentDcb, 140 _In_ PDIRENT Dirent, 141 _In_ ULONG LfnByteOffset, 142 _In_ ULONG DirentByteOffset, 143 _In_ PUNICODE_STRING Lfn, 144 _In_ PACCESS_MASK DesiredAccess, 145 _In_ USHORT ShareAccess, 146 _In_ ULONG CreateDisposition, 147 _In_ BOOLEAN NoEaKnowledge, 148 _In_ BOOLEAN DeleteOnClose, 149 _In_ BOOLEAN FileNameOpenedDos, 150 _In_ BOOLEAN OpenRequiringOplock 151 ); 152 153 _Requires_lock_held_(_Global_critical_region_) 154 IO_STATUS_BLOCK 155 FatOpenExistingFile ( 156 _In_ PIRP_CONTEXT IrpContext, 157 _Inout_ PFILE_OBJECT FileObject, 158 _Inout_ PVCB Vcb, 159 _Outptr_result_maybenull_ PFCB *Fcb, 160 _In_ PDCB ParentDcb, 161 _In_ PDIRENT Dirent, 162 _In_ ULONG LfnByteOffset, 163 _In_ ULONG DirentByteOffset, 164 _In_ PUNICODE_STRING Lfn, 165 _In_ PUNICODE_STRING OrigLfn, 166 _In_ PACCESS_MASK DesiredAccess, 167 _In_ USHORT ShareAccess, 168 _In_ ULONG AllocationSize, 169 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 170 _In_ ULONG EaLength, 171 _In_ USHORT FileAttributes, 172 _In_ ULONG CreateDisposition, 173 _In_ BOOLEAN IsPagingFile, 174 _In_ BOOLEAN NoEaKnowledge, 175 _In_ BOOLEAN DeleteOnClose, 176 _In_ BOOLEAN OpenRequiringOplock, 177 _In_ BOOLEAN FileNameOpenedDos 178 ); 179 180 _Requires_lock_held_(_Global_critical_region_) 181 IO_STATUS_BLOCK 182 FatCreateNewDirectory ( 183 _In_ PIRP_CONTEXT IrpContext, 184 _In_ PIO_STACK_LOCATION IrpSp, 185 _Inout_ PFILE_OBJECT FileObject, 186 _Inout_ PVCB Vcb, 187 _Inout_ PDCB ParentDcb, 188 _In_ POEM_STRING OemName, 189 _In_ PUNICODE_STRING UnicodeName, 190 _In_ PACCESS_MASK DesiredAccess, 191 _In_ USHORT ShareAccess, 192 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 193 _In_ ULONG EaLength, 194 _In_ USHORT FileAttributes, 195 _In_ BOOLEAN NoEaKnowledge, 196 _In_ BOOLEAN DeleteOnClose, 197 _In_ BOOLEAN OpenRequiringOplock 198 ); 199 200 _Requires_lock_held_(_Global_critical_region_) 201 IO_STATUS_BLOCK 202 FatCreateNewFile ( 203 _In_ PIRP_CONTEXT IrpContext, 204 _In_ PIO_STACK_LOCATION IrpSp, 205 _Inout_ PFILE_OBJECT FileObject, 206 _Inout_ PVCB Vcb, 207 _Inout_ PDCB ParentDcb, 208 _In_ POEM_STRING OemName, 209 _In_ PUNICODE_STRING UnicodeName, 210 _In_ PACCESS_MASK DesiredAccess, 211 _In_ USHORT ShareAccess, 212 _In_ ULONG AllocationSize, 213 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 214 _In_ ULONG EaLength, 215 _In_ USHORT FileAttributes, 216 _In_ PUNICODE_STRING LfnBuffer, 217 _In_ BOOLEAN IsPagingFile, 218 _In_ BOOLEAN NoEaKnowledge, 219 _In_ BOOLEAN DeleteOnClose, 220 _In_ BOOLEAN OpenRequiringOplock, 221 _In_ BOOLEAN TemporaryFile 222 ); 223 224 225 _Requires_lock_held_(_Global_critical_region_) 226 IO_STATUS_BLOCK 227 FatSupersedeOrOverwriteFile ( 228 _In_ PIRP_CONTEXT IrpContext, 229 _Inout_ PFILE_OBJECT FileObject, 230 _Inout_ PFCB Fcb, 231 _In_ ULONG AllocationSize, 232 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 233 _In_ ULONG EaLength, 234 _In_ USHORT FileAttributes, 235 _In_ ULONG CreateDisposition, 236 _In_ BOOLEAN NoEaKnowledge 237 ); 238 239 NTSTATUS 240 FatCheckSystemSecurityAccess ( 241 _In_ PIRP_CONTEXT IrpContext 242 ); 243 244 NTSTATUS 245 FatCheckShareAccess ( 246 _In_ PIRP_CONTEXT IrpContext, 247 _In_ PFILE_OBJECT FileObject, 248 _In_ PFCB Fcb, 249 _In_ PACCESS_MASK DesiredAccess, 250 _In_ ULONG ShareAccess 251 ); 252 253 #ifdef ALLOC_PRAGMA 254 #pragma alloc_text(PAGE, FatCheckShareAccess) 255 #pragma alloc_text(PAGE, FatCheckSystemSecurityAccess) 256 #pragma alloc_text(PAGE, FatCommonCreate) 257 258 #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) 259 #pragma alloc_text(PAGE, FatCommonCreateOnNewStack) 260 #pragma alloc_text(PAGE, FatCommonCreateCallout) 261 #endif 262 263 #pragma alloc_text(PAGE, FatCreateNewDirectory) 264 #pragma alloc_text(PAGE, FatCreateNewFile) 265 #pragma alloc_text(PAGE, FatFsdCreate) 266 #pragma alloc_text(PAGE, FatOpenExistingDcb) 267 #pragma alloc_text(PAGE, FatOpenExistingDirectory) 268 #pragma alloc_text(PAGE, FatOpenExistingFcb) 269 #pragma alloc_text(PAGE, FatOpenExistingFile) 270 #pragma alloc_text(PAGE, FatOpenRootDcb) 271 #pragma alloc_text(PAGE, FatOpenTargetDirectory) 272 #pragma alloc_text(PAGE, FatOpenVolume) 273 #pragma alloc_text(PAGE, FatSupersedeOrOverwriteFile) 274 #pragma alloc_text(PAGE, FatSetFullNameInFcb) 275 #endif 276 277 278 _Function_class_(IRP_MJ_CREATE) 279 _Function_class_(DRIVER_DISPATCH) 280 NTSTATUS 281 NTAPI 282 FatFsdCreate ( 283 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject, 284 _Inout_ PIRP Irp 285 ) 286 287 /*++ 288 289 Routine Description: 290 291 This routine implements the FSD part of the NtCreateFile and NtOpenFile 292 API calls. 293 294 Arguments: 295 296 VolumeDeviceObject - Supplies the volume device object where the 297 file/directory exists that we are trying to open/create 298 299 Irp - Supplies the Irp being processed 300 301 Return Value: 302 303 NTSTATUS - The Fsd status for the Irp 304 305 --*/ 306 307 { 308 NTSTATUS Status; 309 PIRP_CONTEXT IrpContext = NULL; 310 311 BOOLEAN TopLevel; 312 BOOLEAN ExceptionCompletedIrp = FALSE; 313 314 315 PAGED_CODE(); 316 317 // 318 // If we were called with our file system device object instead of a 319 // volume device object, just complete this request with STATUS_SUCCESS 320 // 321 322 if ( FatDeviceIsFatFsdo( VolumeDeviceObject)) { 323 324 Irp->IoStatus.Status = STATUS_SUCCESS; 325 Irp->IoStatus.Information = FILE_OPENED; 326 327 IoCompleteRequest( Irp, IO_DISK_INCREMENT ); 328 329 return STATUS_SUCCESS; 330 } 331 332 TimerStart(Dbg); 333 334 DebugTrace(+1, Dbg, "FatFsdCreate\n", 0); 335 336 // 337 // Call the common create routine, with block allowed if the operation 338 // is synchronous. 339 // 340 341 FsRtlEnterFileSystem(); 342 343 TopLevel = FatIsIrpTopLevel( Irp ); 344 345 _SEH2_TRY { 346 347 IrpContext = FatCreateIrpContext( Irp, TRUE ); 348 349 #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) 350 Status = FatCommonCreateOnNewStack( IrpContext, Irp ); 351 #else 352 Status = FatCommonCreate( IrpContext, Irp ); 353 #endif 354 355 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 356 357 // 358 // We had some trouble trying to perform the requested 359 // operation, so we'll abort the I/O request with 360 // the error status that we get back from the 361 // execption code 362 // 363 364 Status = FatProcessException( IrpContext, Irp, _SEH2_GetExceptionCode() ); 365 ExceptionCompletedIrp = TRUE; 366 } _SEH2_END; 367 368 if (TopLevel) { IoSetTopLevelIrp( NULL ); } 369 370 FsRtlExitFileSystem(); 371 372 373 // 374 // Complete the request, unless we had an exception, in which case it 375 // was completed in FatProcessException (and the IrpContext freed). 376 // 377 // IrpContext is freed inside FatCompleteRequest. 378 // 379 380 if (!ExceptionCompletedIrp && Status != STATUS_PENDING) { 381 FatCompleteRequest( IrpContext, Irp, Status ); 382 } 383 384 // 385 // And return to our caller 386 // 387 388 DebugTrace(-1, Dbg, "FatFsdCreate -> %08lx\n", Status ); 389 390 TimerStop(Dbg,"FatFsdCreate"); 391 392 UNREFERENCED_PARAMETER( VolumeDeviceObject ); 393 394 return Status; 395 } 396 397 #if (NTDDI_VERSION >= NTDDI_WINTHRESHOLD) 398 _Requires_lock_held_(_Global_critical_region_) 399 VOID 400 FatCommonCreateCallout ( 401 _In_ PFAT_CALLOUT_PARAMETERS CalloutParameters 402 ) 403 404 /*++ 405 406 Routine Description: 407 408 This function is the callout routine that will execute on a new stack when 409 processing a create. It simply calls FatCommonCreate() with the parameters 410 in the context and stores the return value in the context. 411 412 Arguments: 413 414 Context - Supplies an opaque pointer to this function's context. It is actually 415 an FAT_CALLOUT_PARAMETERS structure. 416 417 Return Value: 418 419 None. 420 421 --*/ 422 423 { 424 PAGED_CODE(); 425 426 // 427 // Call FatCommonCreate() with the passed parameters and store the result. 428 // Exceptions cannot be raised across stack boundaries, so we need to catch 429 // exceptions here and deal with them. 430 // 431 432 try { 433 434 CalloutParameters->IrpStatus = FatCommonCreate( CalloutParameters->Create.IrpContext, 435 CalloutParameters->Create.Irp ); 436 437 } except (FatExceptionFilter( CalloutParameters->Create.IrpContext, GetExceptionInformation() )) { 438 439 // 440 // Return the resulting status. 441 // 442 443 CalloutParameters->ExceptionStatus = GetExceptionCode(); 444 } 445 446 } 447 448 449 _Requires_lock_held_(_Global_critical_region_) 450 NTSTATUS 451 FatCommonCreateOnNewStack ( 452 _In_ PIRP_CONTEXT IrpContext, 453 _In_ PIRP Irp 454 ) 455 456 /*++ 457 458 Routine Description: 459 460 This routine sets up a switch to a new stack and call to FatCommonCreate(). 461 462 Arguments: 463 464 IrpContext - Supplies the context structure for the overall request. 465 466 Irp - Supplies the IRP being processed. 467 468 CreateContext - Supplies a pointer on the old stack that is used to 469 store context information for the create itself. 470 471 Return Value: 472 473 NTSTATUS - The status from FatCommonCreate(). 474 475 --*/ 476 { 477 FAT_CALLOUT_PARAMETERS CalloutParameters; 478 NTSTATUS status; 479 480 PAGED_CODE(); 481 482 // 483 // Create requests consume a lot of stack space. As such, we always switch to a 484 // new stack when processing a create. Setup the callout parameters and make the 485 // call. Note that this cannot fail, since we pass a stack context for a reserve stack. 486 // 487 488 CalloutParameters.Create.IrpContext = IrpContext; 489 CalloutParameters.Create.Irp = Irp; 490 CalloutParameters.ExceptionStatus = CalloutParameters.IrpStatus = STATUS_SUCCESS; 491 492 // 493 // Mark that we are swapping the stack 494 // 495 496 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_SWAPPED_STACK ); 497 498 status = KeExpandKernelStackAndCalloutEx( FatCommonCreateCallout, 499 &CalloutParameters, 500 KERNEL_STACK_SIZE, 501 FALSE, 502 NULL ); 503 504 // 505 // Mark that the stack is no longer swapped. Note that there are paths 506 // that may clear this flag before returning. 507 // 508 509 if (status != STATUS_PENDING) { 510 511 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_SWAPPED_STACK ); 512 } 513 514 // 515 // If we had an exception occur, re-raise the exception. 516 // 517 518 if (!NT_SUCCESS( CalloutParameters.ExceptionStatus )) { 519 FatRaiseStatus( IrpContext, CalloutParameters.ExceptionStatus ); 520 } 521 522 // 523 // If the call to KeExpandKernelStackAndCalloutEx returns an error this 524 // means that the callout routine (FatCommonCreateCallout) was never 525 // called. Translate that error, and return it. 526 // 527 528 if (!NT_SUCCESS( status )) { 529 530 // 531 // Translate to an expected error value 532 // 533 534 if (status == STATUS_NO_MEMORY) { 535 536 status = STATUS_INSUFFICIENT_RESOURCES; 537 } 538 539 return status; 540 } 541 542 // 543 // Return the status given to us by the callout. 544 // 545 546 return CalloutParameters.IrpStatus; 547 } 548 #endif 549 550 _Requires_lock_held_(_Global_critical_region_) 551 NTSTATUS 552 FatCommonCreate ( 553 _Inout_ PIRP_CONTEXT IrpContext, 554 _Inout_ PIRP Irp 555 ) 556 557 /*++ 558 559 Routine Description: 560 561 This is the common routine for creating/opening a file called by 562 both the fsd and fsp threads. 563 564 Arguments: 565 566 Irp - Supplies the Irp to process 567 568 Return Value: 569 570 NTSTATUS - the return status for the operation 571 572 --*/ 573 574 { 575 NTSTATUS Status; 576 IO_STATUS_BLOCK Iosb = {0}; 577 PIO_STACK_LOCATION IrpSp; 578 579 PFILE_OBJECT FileObject; 580 PFILE_OBJECT RelatedFileObject; 581 UNICODE_STRING FileName; 582 ULONG AllocationSize; 583 PFILE_FULL_EA_INFORMATION EaBuffer; 584 PACCESS_MASK DesiredAccess; 585 ULONG Options; 586 USHORT FileAttributes; 587 USHORT ShareAccess; 588 ULONG EaLength; 589 590 BOOLEAN CreateDirectory; 591 BOOLEAN NoIntermediateBuffering; 592 BOOLEAN OpenDirectory; 593 BOOLEAN IsPagingFile; 594 BOOLEAN OpenTargetDirectory; 595 BOOLEAN DirectoryFile; 596 BOOLEAN NonDirectoryFile; 597 BOOLEAN NoEaKnowledge; 598 BOOLEAN DeleteOnClose; 599 BOOLEAN OpenRequiringOplock; 600 BOOLEAN TemporaryFile; 601 BOOLEAN FileNameOpenedDos = FALSE; 602 603 ULONG CreateDisposition; 604 605 PVCB Vcb; 606 PFCB Fcb = NULL; 607 PCCB Ccb; 608 PDCB ParentDcb; 609 PDCB FinalDcb = NULL; 610 611 UNICODE_STRING FinalName = {0}; 612 UNICODE_STRING RemainingPart; 613 UNICODE_STRING NextRemainingPart = {0}; 614 UNICODE_STRING UpcasedFinalName; 615 WCHAR UpcasedBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE]; 616 617 OEM_STRING OemFinalName; 618 UCHAR OemBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE*2]; 619 620 PDIRENT Dirent; 621 PBCB DirentBcb = NULL; 622 ULONG LfnByteOffset; 623 ULONG DirentByteOffset; 624 625 BOOLEAN PostIrp = FALSE; 626 BOOLEAN OplockPostIrp = FALSE; 627 BOOLEAN TrailingBackslash; 628 BOOLEAN FirstLoop = TRUE; 629 630 ULONG MatchFlags = 0; 631 632 CCB LocalCcb; 633 UNICODE_STRING Lfn; 634 UNICODE_STRING OrigLfn = {0}; 635 636 WCHAR LfnBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE]; 637 638 PAGED_CODE(); 639 640 // 641 // Get the current IRP stack location 642 // 643 644 IrpSp = IoGetCurrentIrpStackLocation( Irp ); 645 646 DebugTrace(+1, Dbg, "FatCommonCreate\n", 0 ); 647 DebugTrace( 0, Dbg, "Irp = %p\n", Irp ); 648 DebugTrace( 0, Dbg, "->Flags = %08lx\n", Irp->Flags ); 649 DebugTrace( 0, Dbg, "->FileObject = %p\n", IrpSp->FileObject ); 650 DebugTrace( 0, Dbg, " ->RelatedFileObject = %p\n", IrpSp->FileObject->RelatedFileObject ); 651 DebugTrace( 0, Dbg, " ->FileName = %wZ\n", &IrpSp->FileObject->FileName ); 652 DebugTrace( 0, Dbg, " ->FileName.Length = 0n%d\n", IrpSp->FileObject->FileName.Length ); 653 DebugTrace( 0, Dbg, "->AllocationSize.LowPart = %08lx\n", Irp->Overlay.AllocationSize.LowPart ); 654 DebugTrace( 0, Dbg, "->AllocationSize.HighPart = %08lx\n", Irp->Overlay.AllocationSize.HighPart ); 655 DebugTrace( 0, Dbg, "->SystemBuffer = %p\n", Irp->AssociatedIrp.SystemBuffer ); 656 DebugTrace( 0, Dbg, "->DesiredAccess = %08lx\n", IrpSp->Parameters.Create.SecurityContext->DesiredAccess ); 657 DebugTrace( 0, Dbg, "->Options = %08lx\n", IrpSp->Parameters.Create.Options ); 658 DebugTrace( 0, Dbg, "->FileAttributes = %04x\n", IrpSp->Parameters.Create.FileAttributes ); 659 DebugTrace( 0, Dbg, "->ShareAccess = %04x\n", IrpSp->Parameters.Create.ShareAccess ); 660 DebugTrace( 0, Dbg, "->EaLength = %08lx\n", IrpSp->Parameters.Create.EaLength ); 661 662 // 663 // This is here because the Win32 layer can't avoid sending me double 664 // beginning backslashes. 665 // 666 667 if ((IrpSp->FileObject->FileName.Length > sizeof(WCHAR)) && 668 (IrpSp->FileObject->FileName.Buffer[1] == L'\\') && 669 (IrpSp->FileObject->FileName.Buffer[0] == L'\\')) { 670 671 IrpSp->FileObject->FileName.Length -= sizeof(WCHAR); 672 673 RtlMoveMemory( &IrpSp->FileObject->FileName.Buffer[0], 674 &IrpSp->FileObject->FileName.Buffer[1], 675 IrpSp->FileObject->FileName.Length ); 676 677 // 678 // If there are still two beginning backslashes, the name is bogus. 679 // 680 681 if ((IrpSp->FileObject->FileName.Length > sizeof(WCHAR)) && 682 (IrpSp->FileObject->FileName.Buffer[1] == L'\\') && 683 (IrpSp->FileObject->FileName.Buffer[0] == L'\\')) { 684 685 DebugTrace(-1, Dbg, "FatCommonCreate -> STATUS_OBJECT_NAME_INVALID\n", 0); 686 return STATUS_OBJECT_NAME_INVALID; 687 } 688 } 689 690 // 691 // Reference our input parameters to make things easier 692 // 693 694 NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL ); 695 696 FileObject = IrpSp->FileObject; 697 FileName = FileObject->FileName; 698 RelatedFileObject = FileObject->RelatedFileObject; 699 AllocationSize = Irp->Overlay.AllocationSize.LowPart; 700 EaBuffer = Irp->AssociatedIrp.SystemBuffer; 701 DesiredAccess = &IrpSp->Parameters.Create.SecurityContext->DesiredAccess; 702 Options = IrpSp->Parameters.Create.Options; 703 FileAttributes = IrpSp->Parameters.Create.FileAttributes & ~FILE_ATTRIBUTE_NORMAL; 704 ShareAccess = IrpSp->Parameters.Create.ShareAccess; 705 EaLength = IrpSp->Parameters.Create.EaLength; 706 707 // 708 // Set up the file object's Vpb pointer in case anything happens. 709 // This will allow us to get a reasonable pop-up. 710 // 711 712 if ( RelatedFileObject != NULL ) { 713 FileObject->Vpb = RelatedFileObject->Vpb; 714 } 715 716 // 717 // Force setting the archive bit in the attributes byte to follow OS/2, 718 // & DOS semantics. Also mask out any extraneous bits, note that 719 // we can't use the ATTRIBUTE_VALID_FLAGS constant because that has 720 // the control and normal flags set. 721 // 722 // Delay setting ARCHIVE in case this is a directory: 2/16/95 723 // 724 725 FileAttributes &= (FILE_ATTRIBUTE_READONLY | 726 FILE_ATTRIBUTE_HIDDEN | 727 FILE_ATTRIBUTE_SYSTEM | 728 FILE_ATTRIBUTE_ARCHIVE | 729 FILE_ATTRIBUTE_ENCRYPTED); 730 731 // 732 // Locate the volume device object and Vcb that we are trying to access 733 // 734 735 Vcb = &((PVOLUME_DEVICE_OBJECT)IrpSp->DeviceObject)->Vcb; 736 737 // 738 // Decipher Option flags and values 739 // 740 741 // 742 // If this is an open by fileid operation, just fail it explicitly. FAT's 743 // source of fileids is not reversible for open operations. 744 // 745 746 if (BooleanFlagOn( Options, FILE_OPEN_BY_FILE_ID )) { 747 748 return STATUS_NOT_IMPLEMENTED; 749 } 750 751 DirectoryFile = BooleanFlagOn( Options, FILE_DIRECTORY_FILE ); 752 NonDirectoryFile = BooleanFlagOn( Options, FILE_NON_DIRECTORY_FILE ); 753 NoIntermediateBuffering = BooleanFlagOn( Options, FILE_NO_INTERMEDIATE_BUFFERING ); 754 NoEaKnowledge = BooleanFlagOn( Options, FILE_NO_EA_KNOWLEDGE ); 755 DeleteOnClose = BooleanFlagOn( Options, FILE_DELETE_ON_CLOSE ); 756 #if (NTDDI_VERSION >= NTDDI_WIN7) 757 OpenRequiringOplock = BooleanFlagOn( Options, FILE_OPEN_REQUIRING_OPLOCK ); 758 #else 759 OpenRequiringOplock = FALSE; 760 #endif 761 762 TemporaryFile = BooleanFlagOn( IrpSp->Parameters.Create.FileAttributes, 763 FILE_ATTRIBUTE_TEMPORARY ); 764 765 CreateDisposition = (Options >> 24) & 0x000000ff; 766 767 IsPagingFile = BooleanFlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE ); 768 OpenTargetDirectory = BooleanFlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY ); 769 770 CreateDirectory = (BOOLEAN)(DirectoryFile && 771 ((CreateDisposition == FILE_CREATE) || 772 (CreateDisposition == FILE_OPEN_IF))); 773 774 OpenDirectory = (BOOLEAN)(DirectoryFile && 775 ((CreateDisposition == FILE_OPEN) || 776 (CreateDisposition == FILE_OPEN_IF))); 777 778 779 // 780 // Make sure the input large integer is valid and that the dir/nondir 781 // indicates a storage type we understand. 782 // 783 784 if (Irp->Overlay.AllocationSize.HighPart != 0 || 785 (DirectoryFile && NonDirectoryFile)) { 786 787 DebugTrace(-1, Dbg, "FatCommonCreate -> STATUS_INVALID_PARAMETER\n", 0); 788 return STATUS_INVALID_PARAMETER; 789 } 790 791 // 792 // Acquire exclusive access to the vcb, and enqueue the Irp if 793 // we didn't get it. 794 // 795 796 if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) { 797 798 DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0); 799 800 Iosb.Status = FatFsdPostRequest( IrpContext, Irp ); 801 802 DebugTrace(-1, Dbg, "FatCommonCreate -> %08lx\n", Iosb.Status ); 803 return Iosb.Status; 804 } 805 806 // 807 // Make sure we haven't been called recursively by a filter inside an existing 808 // create request. 809 // 810 811 if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS)) { 812 813 #ifdef _MSC_VER 814 #pragma prefast( suppress:28159, "this is a serious programming error if it happens" ) 815 #endif 816 FatBugCheck( 0, 0, 0); 817 } 818 819 // 820 // Initialize the DirentBcb to null 821 // 822 823 DirentBcb = NULL; 824 825 // 826 // Initialize our temp strings with their stack buffers. 827 // 828 829 OemFinalName.Length = 0; 830 OemFinalName.MaximumLength = sizeof( OemBuffer); 831 OemFinalName.Buffer = (PCHAR)OemBuffer; 832 833 UpcasedFinalName.Length = 0; 834 UpcasedFinalName.MaximumLength = sizeof( UpcasedBuffer); 835 UpcasedFinalName.Buffer = UpcasedBuffer; 836 837 Lfn.Length = 0; 838 Lfn.MaximumLength = sizeof( LfnBuffer); 839 Lfn.Buffer = LfnBuffer; 840 841 _SEH2_TRY { 842 843 // 844 // Make sure the vcb is in a usable condition. This will raise 845 // and error condition if the volume is unusable 846 // 847 848 FatVerifyVcb( IrpContext, Vcb ); 849 850 // 851 // If the Vcb is locked then we cannot open another file 852 // 853 854 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) { 855 856 DebugTrace(0, Dbg, "Volume is locked\n", 0); 857 858 Status = STATUS_ACCESS_DENIED; 859 if (Vcb->VcbCondition != VcbGood) { 860 861 Status = STATUS_VOLUME_DISMOUNTED; 862 } 863 try_return( Iosb.Status = Status ); 864 } 865 866 // 867 // Don't allow the DELETE_ON_CLOSE option if the volume is 868 // write-protected. 869 // 870 871 if (DeleteOnClose && FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) { 872 873 // 874 // Set the real device for the pop-up info, and set the verify 875 // bit in the device object, so that we will force a verify 876 // in case the user put the correct media back in. 877 // 878 879 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 880 Vcb->Vpb->RealDevice ); 881 882 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 883 884 FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); 885 } 886 887 // 888 // If this is a fat32 volume, EA's are not supported. 889 // 890 891 if (EaBuffer != NULL) { 892 893 try_return( Iosb.Status = STATUS_EAS_NOT_SUPPORTED ); 894 } 895 896 // 897 // Check if we are opening the volume and not a file/directory. 898 // We are opening the volume if the name is empty and there 899 // isn't a related file object. If there is a related file object 900 // then it is the Vcb itself. 901 // 902 903 if (FileName.Length == 0) { 904 905 PVCB DecodeVcb = NULL; 906 907 if (RelatedFileObject == NULL || 908 FatDecodeFileObject( RelatedFileObject, 909 &DecodeVcb, 910 &Fcb, 911 &Ccb ) == UserVolumeOpen) { 912 913 NT_ASSERT( RelatedFileObject == NULL || Vcb == DecodeVcb ); 914 915 // 916 // Check if we were to open a directory 917 // 918 919 if (DirectoryFile) { 920 921 DebugTrace(0, Dbg, "Cannot open volume as a directory\n", 0); 922 923 try_return( Iosb.Status = STATUS_NOT_A_DIRECTORY ); 924 } 925 926 // 927 // Can't open the TargetDirectory of the DASD volume. 928 // 929 930 if (OpenTargetDirectory) { 931 932 try_return( Iosb.Status = STATUS_INVALID_PARAMETER ); 933 } 934 935 DebugTrace(0, Dbg, "Opening the volume, Vcb = %p\n", Vcb); 936 937 CollectCreateHitStatistics(Vcb); 938 939 Iosb = FatOpenVolume( IrpContext, 940 FileObject, 941 Vcb, 942 DesiredAccess, 943 ShareAccess, 944 CreateDisposition ); 945 946 Irp->IoStatus.Information = Iosb.Information; 947 try_return( Iosb.Status ); 948 } 949 } 950 951 // 952 // If there is a related file object then this is a relative open. 953 // The related file object is the directory to start our search at. 954 // Return an error if it is not a directory. 955 // 956 957 if (RelatedFileObject != NULL) { 958 959 PVCB RelatedVcb; 960 PDCB RelatedDcb; 961 PCCB RelatedCcb; 962 TYPE_OF_OPEN TypeOfOpen; 963 964 TypeOfOpen = FatDecodeFileObject( RelatedFileObject, 965 &RelatedVcb, 966 &RelatedDcb, 967 &RelatedCcb ); 968 969 if (TypeOfOpen != UserFileOpen && 970 TypeOfOpen != UserDirectoryOpen) { 971 972 DebugTrace(0, Dbg, "Invalid related file object\n", 0); 973 974 try_return( Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND ); 975 } 976 977 // 978 // A relative open must be via a relative path. 979 // 980 981 if (FileName.Length != 0 && 982 FileName.Buffer[0] == L'\\') { 983 984 try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); 985 } 986 987 // 988 // Set up the file object's Vpb pointer in case anything happens. 989 // 990 991 NT_ASSERT( Vcb == RelatedVcb ); 992 993 FileObject->Vpb = RelatedFileObject->Vpb; 994 995 // 996 // Now verify the related Fcb so we don't get in trouble later 997 // by assuming its in good shape. 998 // 999 1000 FatVerifyFcb( IrpContext, RelatedDcb ); 1001 1002 ParentDcb = RelatedDcb; 1003 1004 } else { 1005 1006 // 1007 // This is not a relative open, so check if we're 1008 // opening the root dcb 1009 // 1010 1011 if ((FileName.Length == sizeof(WCHAR)) && 1012 (FileName.Buffer[0] == L'\\')) { 1013 1014 // 1015 // Check if we were not supposed to open a directory 1016 // 1017 1018 if (NonDirectoryFile) { 1019 1020 DebugTrace(0, Dbg, "Cannot open root directory as a file\n", 0); 1021 1022 try_return( Iosb.Status = STATUS_FILE_IS_A_DIRECTORY ); 1023 } 1024 1025 // 1026 // Can't open the TargetDirectory of the root directory. 1027 // 1028 1029 if (OpenTargetDirectory) { 1030 1031 try_return( Iosb.Status = STATUS_INVALID_PARAMETER ); 1032 } 1033 1034 // 1035 // Not allowed to delete root directory. 1036 // 1037 1038 if (DeleteOnClose) { 1039 1040 try_return( Iosb.Status = STATUS_CANNOT_DELETE ); 1041 } 1042 1043 DebugTrace(0, Dbg, "Opening root dcb\n", 0); 1044 1045 CollectCreateHitStatistics(Vcb); 1046 1047 Iosb = FatOpenRootDcb( IrpContext, 1048 FileObject, 1049 Vcb, 1050 DesiredAccess, 1051 ShareAccess, 1052 CreateDisposition ); 1053 1054 Irp->IoStatus.Information = Iosb.Information; 1055 try_return( Iosb.Status ); 1056 } 1057 1058 // 1059 // Nope, we will be opening relative to the root directory. 1060 // 1061 1062 ParentDcb = Vcb->RootDcb; 1063 1064 // 1065 // Now verify the root Dcb so we don't get in trouble later 1066 // by assuming its in good shape. 1067 // 1068 1069 FatVerifyFcb( IrpContext, ParentDcb ); 1070 } 1071 1072 // 1073 // FatCommonCreate(): trailing backslash check 1074 // 1075 1076 1077 if ((FileName.Length != 0) && 1078 (FileName.Buffer[FileName.Length/sizeof(WCHAR)-1] == L'\\')) { 1079 1080 FileName.Length -= sizeof(WCHAR); 1081 TrailingBackslash = TRUE; 1082 1083 } else { 1084 1085 TrailingBackslash = FALSE; 1086 } 1087 1088 // 1089 // Check for max path. We might want to tighten this down to DOS MAX_PATH 1090 // for maximal interchange with non-NT platforms, but for now defer to the 1091 // possibility of something depending on it. 1092 // 1093 1094 if (ParentDcb->FullFileName.Buffer == NULL) { 1095 1096 FatSetFullFileNameInFcb( IrpContext, ParentDcb ); 1097 } 1098 1099 if ((USHORT) (ParentDcb->FullFileName.Length + sizeof(WCHAR) + FileName.Length) <= FileName.Length) { 1100 1101 try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); 1102 } 1103 1104 // 1105 // We loop here until we land on an Fcb that is in a good 1106 // condition. This way we can reopen files that have stale handles 1107 // to files of the same name but are now different. 1108 // 1109 1110 while ( TRUE ) { 1111 1112 Fcb = ParentDcb; 1113 RemainingPart = FileName; 1114 1115 // 1116 // Now walk down the Dcb tree looking for the longest prefix. 1117 // This one exit condition in the while() is to handle a 1118 // special case condition (relative NULL name open), the main 1119 // exit conditions are at the bottom of the loop. 1120 // 1121 1122 while (RemainingPart.Length != 0) { 1123 1124 PFCB NextFcb; 1125 1126 FsRtlDissectName( RemainingPart, 1127 &FinalName, 1128 &NextRemainingPart ); 1129 1130 // 1131 // If RemainingPart starts with a backslash the name is 1132 // invalid. 1133 // Check for no more than 255 characters in FinalName 1134 // 1135 1136 if (((NextRemainingPart.Length != 0) && (NextRemainingPart.Buffer[0] == L'\\')) || 1137 (FinalName.Length > 255*sizeof(WCHAR))) { 1138 1139 try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); 1140 } 1141 1142 // 1143 // Now, try to convert this one component into Oem and search 1144 // the splay tree. If it works then that's great, otherwise 1145 // we have to try with the UNICODE name instead. 1146 // 1147 1148 FatEnsureStringBufferEnough( &OemFinalName, 1149 FinalName.Length); 1150 1151 Status = RtlUpcaseUnicodeStringToCountedOemString( &OemFinalName, &FinalName, FALSE ); 1152 1153 1154 if (NT_SUCCESS(Status)) { 1155 1156 NextFcb = FatFindFcb( IrpContext, 1157 &Fcb->Specific.Dcb.RootOemNode, 1158 (PSTRING)&OemFinalName, 1159 &FileNameOpenedDos ); 1160 1161 } else { 1162 1163 NextFcb = NULL; 1164 OemFinalName.Length = 0; 1165 1166 if (Status != STATUS_UNMAPPABLE_CHARACTER) { 1167 1168 try_return( Iosb.Status = Status ); 1169 } 1170 } 1171 1172 // 1173 // If we didn't find anything searching the Oem space, we 1174 // have to try the Unicode space. To save cycles in the 1175 // common case that this tree is empty, we do a quick check 1176 // here. 1177 // 1178 1179 if ((NextFcb == NULL) && Fcb->Specific.Dcb.RootUnicodeNode) { 1180 1181 // 1182 // First downcase, then upcase the string, because this 1183 // is what happens when putting names into the tree (see 1184 // strucsup.c, FatConstructNamesInFcb()). 1185 // 1186 1187 FatEnsureStringBufferEnough( &UpcasedFinalName, 1188 FinalName.Length); 1189 1190 Status = RtlDowncaseUnicodeString(&UpcasedFinalName, &FinalName, FALSE ); 1191 NT_ASSERT( NT_SUCCESS( Status )); 1192 1193 Status = RtlUpcaseUnicodeString( &UpcasedFinalName, &UpcasedFinalName, FALSE ); 1194 NT_ASSERT( NT_SUCCESS( Status )); 1195 1196 1197 NextFcb = FatFindFcb( IrpContext, 1198 &Fcb->Specific.Dcb.RootUnicodeNode, 1199 (PSTRING)&UpcasedFinalName, 1200 &FileNameOpenedDos ); 1201 } 1202 1203 // 1204 // If we got back an Fcb then we consumed the FinalName 1205 // legitimately, so the remaining name is now RemainingPart. 1206 // 1207 1208 if (NextFcb != NULL) { 1209 Fcb = NextFcb; 1210 RemainingPart = NextRemainingPart; 1211 } 1212 1213 if ((NextFcb == NULL) || 1214 (NodeType(NextFcb) == FAT_NTC_FCB) || 1215 (NextRemainingPart.Length == 0)) { 1216 1217 break; 1218 } 1219 } 1220 1221 // 1222 // Remaining name cannot start with a backslash 1223 // 1224 1225 if (RemainingPart.Length && (RemainingPart.Buffer[0] == L'\\')) { 1226 1227 RemainingPart.Length -= sizeof(WCHAR); 1228 RemainingPart.Buffer += 1; 1229 } 1230 1231 // 1232 // Now verify that everybody up to the longest found prefix is valid. 1233 // 1234 1235 _SEH2_TRY { 1236 1237 FatVerifyFcb( IrpContext, Fcb ); 1238 1239 } _SEH2_EXCEPT( (_SEH2_GetExceptionCode() == STATUS_FILE_INVALID) ? 1240 EXCEPTION_EXECUTE_HANDLER : 1241 EXCEPTION_CONTINUE_SEARCH ) { 1242 1243 FatResetExceptionState( IrpContext ); 1244 } _SEH2_END; 1245 1246 if ( Fcb->FcbCondition == FcbGood ) { 1247 1248 // 1249 // If we are trying to open a paging file and have happened 1250 // upon the DelayedCloseFcb, make it go away, and try again. 1251 // 1252 1253 if (IsPagingFile && FirstLoop && 1254 (NodeType(Fcb) == FAT_NTC_FCB) && 1255 (!IsListEmpty( &FatData.AsyncCloseList ) || 1256 !IsListEmpty( &FatData.DelayedCloseList ))) { 1257 1258 FatFspClose(Vcb); 1259 1260 FirstLoop = FALSE; 1261 1262 continue; 1263 1264 } else { 1265 1266 break; 1267 } 1268 1269 } else { 1270 1271 FatRemoveNames( IrpContext, Fcb ); 1272 } 1273 } 1274 1275 NT_ASSERT( Fcb->FcbCondition == FcbGood ); 1276 1277 // 1278 // If there is already an Fcb for a paging file open and 1279 // it was not already opened as a paging file, we cannot 1280 // continue as it is too difficult to move a live Fcb to 1281 // non-paged pool. 1282 // 1283 1284 if (IsPagingFile) { 1285 1286 if (NodeType(Fcb) == FAT_NTC_FCB && 1287 !FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) { 1288 1289 try_return( Iosb.Status = STATUS_SHARING_VIOLATION ); 1290 } 1291 1292 // 1293 // Check for a system file. 1294 // 1295 1296 } else if (FlagOn( Fcb->FcbState, FCB_STATE_SYSTEM_FILE )) { 1297 1298 try_return( Iosb.Status = STATUS_ACCESS_DENIED ); 1299 } 1300 1301 // 1302 // If the longest prefix is pending delete (either the file or 1303 // some higher level directory), we cannot continue. 1304 // 1305 1306 if (FlagOn( Fcb->FcbState, FCB_STATE_DELETE_ON_CLOSE )) { 1307 1308 try_return( Iosb.Status = STATUS_DELETE_PENDING ); 1309 } 1310 1311 // 1312 // Now that we've found the longest matching prefix we'll 1313 // check if there isn't any remaining part because that means 1314 // we've located an existing fcb/dcb to open and we can do the open 1315 // without going to the disk 1316 // 1317 1318 if (RemainingPart.Length == 0) { 1319 1320 // 1321 // First check if the user wanted to open the target directory 1322 // and if so then call the subroutine to finish the open. 1323 // 1324 1325 if (OpenTargetDirectory) { 1326 1327 CollectCreateHitStatistics(Vcb); 1328 1329 Iosb = FatOpenTargetDirectory( IrpContext, 1330 FileObject, 1331 Fcb->ParentDcb, 1332 DesiredAccess, 1333 ShareAccess, 1334 TRUE, 1335 FileNameOpenedDos ); 1336 Irp->IoStatus.Information = Iosb.Information; 1337 try_return( Iosb.Status ); 1338 } 1339 1340 // 1341 // We can open an existing fcb/dcb, now we only need to case 1342 // on which type to open. 1343 // 1344 1345 if (NodeType(Fcb) == FAT_NTC_DCB || NodeType(Fcb) == FAT_NTC_ROOT_DCB) { 1346 1347 // 1348 // This is a directory we're opening up so check if 1349 // we were not to open a directory 1350 // 1351 1352 if (NonDirectoryFile) { 1353 1354 DebugTrace(0, Dbg, "Cannot open directory as a file\n", 0); 1355 1356 try_return( Iosb.Status = STATUS_FILE_IS_A_DIRECTORY ); 1357 } 1358 1359 DebugTrace(0, Dbg, "Open existing dcb, Dcb = %p\n", Fcb); 1360 1361 CollectCreateHitStatistics(Vcb); 1362 1363 Iosb = FatOpenExistingDcb( IrpContext, 1364 IrpSp, 1365 FileObject, 1366 Vcb, 1367 (PDCB)Fcb, 1368 DesiredAccess, 1369 ShareAccess, 1370 CreateDisposition, 1371 NoEaKnowledge, 1372 DeleteOnClose, 1373 OpenRequiringOplock, 1374 FileNameOpenedDos, 1375 &OplockPostIrp ); 1376 1377 if (Iosb.Status != STATUS_PENDING) { 1378 1379 Irp->IoStatus.Information = Iosb.Information; 1380 1381 } else { 1382 1383 DebugTrace(0, Dbg, "Enqueue Irp to FSP\n", 0); 1384 1385 PostIrp = TRUE; 1386 } 1387 1388 try_return( Iosb.Status ); 1389 } 1390 1391 // 1392 // Check if we're trying to open an existing Fcb and that 1393 // the user didn't want to open a directory. Note that this 1394 // call might actually come back with status_pending because 1395 // the user wanted to supersede or overwrite the file and we 1396 // cannot block. If it is pending then we do not complete the 1397 // request, and we fall through the bottom to the code that 1398 // dispatches the request to the fsp. 1399 // 1400 1401 if (NodeType(Fcb) == FAT_NTC_FCB) { 1402 1403 // 1404 // Check if we were only to open a directory 1405 // 1406 1407 if (OpenDirectory) { 1408 1409 DebugTrace(0, Dbg, "Cannot open file as directory\n", 0); 1410 1411 try_return( Iosb.Status = STATUS_NOT_A_DIRECTORY ); 1412 } 1413 1414 DebugTrace(0, Dbg, "Open existing fcb, Fcb = %p\n", Fcb); 1415 1416 if ( TrailingBackslash ) { 1417 try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); 1418 } 1419 1420 CollectCreateHitStatistics(Vcb); 1421 1422 Iosb = FatOpenExistingFcb( IrpContext, 1423 IrpSp, 1424 FileObject, 1425 Vcb, 1426 Fcb, 1427 DesiredAccess, 1428 ShareAccess, 1429 AllocationSize, 1430 EaBuffer, 1431 EaLength, 1432 FileAttributes, 1433 CreateDisposition, 1434 NoEaKnowledge, 1435 DeleteOnClose, 1436 OpenRequiringOplock, 1437 FileNameOpenedDos, 1438 &OplockPostIrp ); 1439 1440 if (Iosb.Status != STATUS_PENDING) { 1441 1442 // 1443 // Check if we need to set the cache support flag in 1444 // the file object 1445 // 1446 1447 if (NT_SUCCESS( Iosb.Status) && !NoIntermediateBuffering) { 1448 1449 FileObject->Flags |= FO_CACHE_SUPPORTED; 1450 } 1451 1452 Irp->IoStatus.Information = Iosb.Information; 1453 1454 } else { 1455 1456 DebugTrace(0, Dbg, "Enqueue Irp to FSP\n", 0); 1457 1458 PostIrp = TRUE; 1459 } 1460 1461 try_return( Iosb.Status ); 1462 } 1463 1464 // 1465 // Not and Fcb or a Dcb so we bug check 1466 // 1467 1468 #ifdef _MSC_VER 1469 #pragma prefast( suppress:28159, "this is a serious corruption if it happens" ) 1470 #endif 1471 FatBugCheck( NodeType(Fcb), (ULONG_PTR) Fcb, 0 ); 1472 } 1473 1474 // 1475 // There is more in the name to parse than we have in existing 1476 // fcbs/dcbs. So now make sure that fcb we got for the largest 1477 // matching prefix is really a dcb otherwise we can't go any 1478 // further 1479 // 1480 1481 if ((NodeType(Fcb) != FAT_NTC_DCB) && (NodeType(Fcb) != FAT_NTC_ROOT_DCB)) { 1482 1483 DebugTrace(0, Dbg, "Cannot open file as subdirectory, Fcb = %p\n", Fcb); 1484 1485 try_return( Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND ); 1486 } 1487 1488 // 1489 // Otherwise we continue on processing the Irp and allowing ourselves 1490 // to block for I/O as necessary. Find/create additional dcb's for 1491 // the one we're trying to open. We loop until either remaining part 1492 // is empty or we get a bad filename. When we exit FinalName is 1493 // the last name in the string we're after, and ParentDcb is the 1494 // parent directory that will contain the opened/created 1495 // file/directory. 1496 // 1497 // Make sure the rest of the name is valid in at least the LFN 1498 // character set (which just happens to be that of HPFS). 1499 // 1500 // If we are not in ChicagoMode, use FAT semantics. 1501 // 1502 1503 ParentDcb = Fcb; 1504 FirstLoop = TRUE; 1505 1506 while (TRUE) { 1507 1508 // 1509 // We do one little optimization here on the first iteration of 1510 // the loop since we know that we have already tried to convert 1511 // FinalOemName from the original UNICODE. 1512 // 1513 1514 if (FirstLoop) { 1515 1516 FirstLoop = FALSE; 1517 RemainingPart = NextRemainingPart; 1518 Status = OemFinalName.Length ? STATUS_SUCCESS : STATUS_UNMAPPABLE_CHARACTER; 1519 1520 } else { 1521 1522 // 1523 // Dissect the remaining part. 1524 // 1525 1526 DebugTrace(0, Dbg, "Dissecting the name %wZ\n", &RemainingPart); 1527 1528 FsRtlDissectName( RemainingPart, 1529 &FinalName, 1530 &RemainingPart ); 1531 1532 // 1533 // If RemainingPart starts with a backslash the name is 1534 // invalid. 1535 // Check for no more than 255 characters in FinalName 1536 // 1537 1538 if (((RemainingPart.Length != 0) && (RemainingPart.Buffer[0] == L'\\')) || 1539 (FinalName.Length > 255*sizeof(WCHAR))) { 1540 1541 try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); 1542 } 1543 1544 // 1545 // Now, try to convert this one component into Oem. If it works 1546 // then that's great, otherwise we have to try with the UNICODE 1547 // name instead. 1548 // 1549 1550 FatEnsureStringBufferEnough( &OemFinalName, 1551 FinalName.Length); 1552 1553 Status = RtlUpcaseUnicodeStringToCountedOemString( &OemFinalName, &FinalName, FALSE ); 1554 } 1555 1556 if (NT_SUCCESS(Status)) { 1557 1558 // 1559 // We'll start by trying to locate the dirent for the name. Note 1560 // that we already know that there isn't an Fcb/Dcb for the file 1561 // otherwise we would have found it when we did our prefix lookup. 1562 // 1563 1564 if (FatIsNameShortOemValid( IrpContext, OemFinalName, FALSE, FALSE, FALSE )) { 1565 1566 FatStringTo8dot3( IrpContext, 1567 OemFinalName, 1568 &LocalCcb.OemQueryTemplate.Constant ); 1569 1570 LocalCcb.Flags = 0; 1571 1572 } else { 1573 1574 LocalCcb.Flags = CCB_FLAG_SKIP_SHORT_NAME_COMPARE; 1575 } 1576 1577 } else { 1578 1579 LocalCcb.Flags = CCB_FLAG_SKIP_SHORT_NAME_COMPARE; 1580 1581 if (Status != STATUS_UNMAPPABLE_CHARACTER) { 1582 1583 try_return( Iosb.Status = Status ); 1584 } 1585 } 1586 1587 // 1588 // Now we know a lot about the final name, so do legal name 1589 // checking here. 1590 // 1591 1592 if (FatData.ChicagoMode) { 1593 1594 if (!FatIsNameLongUnicodeValid( IrpContext, &FinalName, FALSE, FALSE, FALSE )) { 1595 1596 try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); 1597 } 1598 1599 } else { 1600 1601 if (FlagOn(LocalCcb.Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE)) { 1602 1603 try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); 1604 } 1605 } 1606 1607 DebugTrace(0, Dbg, "FinalName is %wZ\n", &FinalName); 1608 DebugTrace(0, Dbg, "RemainingPart is %wZ\n", &RemainingPart); 1609 1610 FatEnsureStringBufferEnough( &UpcasedFinalName, 1611 FinalName.Length); 1612 1613 if (!NT_SUCCESS(Status = RtlUpcaseUnicodeString( &UpcasedFinalName, &FinalName, FALSE))) { 1614 1615 try_return( Iosb.Status = Status ); 1616 } 1617 1618 LocalCcb.UnicodeQueryTemplate = UpcasedFinalName; 1619 LocalCcb.ContainsWildCards = FALSE; 1620 1621 Lfn.Length = 0; 1622 1623 1624 FatLocateDirent( IrpContext, 1625 ParentDcb, 1626 &LocalCcb, 1627 0, 1628 &MatchFlags, 1629 &Dirent, 1630 &DirentBcb, 1631 (PVBO)&DirentByteOffset, 1632 &FileNameOpenedDos, 1633 &Lfn, 1634 &OrigLfn); 1635 1636 // 1637 // Remember we read this Dcb for error recovery. 1638 // 1639 1640 FinalDcb = ParentDcb; 1641 1642 // 1643 // If the remaining part is now empty then this is the last name 1644 // in the string and the one we want to open 1645 // 1646 1647 if (RemainingPart.Length == 0) { 1648 1649 1650 break; 1651 } 1652 1653 // 1654 // We didn't find a dirent, bail. 1655 // 1656 1657 if (Dirent == NULL) { 1658 1659 Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND; 1660 try_return( Iosb.Status ); 1661 } 1662 1663 // 1664 // We now have a dirent, make sure it is a directory 1665 // 1666 1667 if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) { 1668 1669 Iosb.Status = STATUS_OBJECT_PATH_NOT_FOUND; 1670 try_return( Iosb.Status ); 1671 } 1672 1673 // 1674 // Compute the LfnByteOffset. 1675 // 1676 1677 LfnByteOffset = DirentByteOffset - 1678 FAT_LFN_DIRENTS_NEEDED(&OrigLfn) * sizeof(LFN_DIRENT); 1679 1680 // 1681 // Create a dcb for the new directory 1682 // 1683 1684 ParentDcb = FatCreateDcb( IrpContext, 1685 Vcb, 1686 ParentDcb, 1687 LfnByteOffset, 1688 DirentByteOffset, 1689 Dirent, 1690 &Lfn ); 1691 1692 // 1693 // Remember we created this Dcb for error recovery. 1694 // 1695 1696 FinalDcb = ParentDcb; 1697 1698 FatSetFullNameInFcb( IrpContext, ParentDcb, &FinalName ); 1699 } 1700 1701 // 1702 // First check if the user wanted to open the target directory 1703 // and if so then call the subroutine to finish the open. 1704 // 1705 1706 if (OpenTargetDirectory) { 1707 1708 Iosb = FatOpenTargetDirectory( IrpContext, 1709 FileObject, 1710 ParentDcb, 1711 DesiredAccess, 1712 ShareAccess, 1713 Dirent ? TRUE : FALSE, 1714 FileNameOpenedDos); 1715 1716 Irp->IoStatus.Information = Iosb.Information; 1717 try_return( Iosb.Status ); 1718 } 1719 1720 if (Dirent != NULL) { 1721 1722 // 1723 // Compute the LfnByteOffset. 1724 // 1725 1726 LfnByteOffset = DirentByteOffset - 1727 FAT_LFN_DIRENTS_NEEDED(&OrigLfn) * sizeof(LFN_DIRENT); 1728 1729 // 1730 // We were able to locate an existing dirent entry, so now 1731 // see if it is a directory that we're trying to open. 1732 // 1733 1734 if (FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) { 1735 1736 // 1737 // Make sure its okay to open a directory 1738 // 1739 1740 if (NonDirectoryFile) { 1741 1742 DebugTrace(0, Dbg, "Cannot open directory as a file\n", 0); 1743 1744 try_return( Iosb.Status = STATUS_FILE_IS_A_DIRECTORY ); 1745 } 1746 1747 DebugTrace(0, Dbg, "Open existing directory\n", 0); 1748 1749 Iosb = FatOpenExistingDirectory( IrpContext, 1750 IrpSp, 1751 FileObject, 1752 Vcb, 1753 &Fcb, 1754 ParentDcb, 1755 Dirent, 1756 LfnByteOffset, 1757 DirentByteOffset, 1758 &Lfn, 1759 DesiredAccess, 1760 ShareAccess, 1761 CreateDisposition, 1762 NoEaKnowledge, 1763 DeleteOnClose, 1764 FileNameOpenedDos, 1765 OpenRequiringOplock ); 1766 1767 Irp->IoStatus.Information = Iosb.Information; 1768 try_return( Iosb.Status ); 1769 } 1770 1771 // 1772 // Otherwise we're trying to open and existing file, and we 1773 // need to check if the user only wanted to open a directory. 1774 // 1775 1776 if (OpenDirectory) { 1777 1778 DebugTrace(0, Dbg, "Cannot open file as directory\n", 0); 1779 1780 try_return( Iosb.Status = STATUS_NOT_A_DIRECTORY ); 1781 } 1782 1783 DebugTrace(0, Dbg, "Open existing file\n", 0); 1784 1785 if ( TrailingBackslash ) { 1786 try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); 1787 } 1788 1789 1790 Iosb = FatOpenExistingFile( IrpContext, 1791 FileObject, 1792 Vcb, 1793 &Fcb, 1794 ParentDcb, 1795 Dirent, 1796 LfnByteOffset, 1797 DirentByteOffset, 1798 &Lfn, 1799 &OrigLfn, 1800 DesiredAccess, 1801 ShareAccess, 1802 AllocationSize, 1803 EaBuffer, 1804 EaLength, 1805 FileAttributes, 1806 CreateDisposition, 1807 IsPagingFile, 1808 NoEaKnowledge, 1809 DeleteOnClose, 1810 OpenRequiringOplock, 1811 FileNameOpenedDos ); 1812 1813 // 1814 // Check if we need to set the cache support flag in 1815 // the file object 1816 // 1817 1818 if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering) { 1819 1820 FileObject->Flags |= FO_CACHE_SUPPORTED; 1821 } 1822 1823 Irp->IoStatus.Information = Iosb.Information; 1824 try_return( Iosb.Status ); 1825 } 1826 1827 // 1828 // We can't locate a dirent so this is a new file. 1829 // 1830 1831 // 1832 // Now check to see if we wanted to only open an existing file. 1833 // And then case on whether we wanted to create a file or a directory. 1834 // 1835 1836 if ((CreateDisposition == FILE_OPEN) || 1837 (CreateDisposition == FILE_OVERWRITE)) { 1838 1839 DebugTrace( 0, Dbg, "Cannot open nonexisting file\n", 0); 1840 1841 try_return( Iosb.Status = STATUS_OBJECT_NAME_NOT_FOUND ); 1842 } 1843 1844 // 1845 // Skip a few cycles later if we know now that the Oem name is not 1846 // valid 8.3. 1847 // 1848 1849 if (FlagOn(LocalCcb.Flags, CCB_FLAG_SKIP_SHORT_NAME_COMPARE)) { 1850 1851 OemFinalName.Length = 0; 1852 } 1853 1854 // 1855 // Determine the granted access for this operation now. 1856 // 1857 1858 if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) { 1859 1860 try_return( Iosb ); 1861 } 1862 1863 if (CreateDirectory) { 1864 1865 DebugTrace(0, Dbg, "Create new directory\n", 0); 1866 1867 // 1868 // If this media is write protected, don't even try the create. 1869 // 1870 1871 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) { 1872 1873 // 1874 // Set the real device for the pop-up info, and set the verify 1875 // bit in the device object, so that we will force a verify 1876 // in case the user put the correct media back in. 1877 // 1878 1879 1880 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 1881 Vcb->Vpb->RealDevice ); 1882 1883 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 1884 1885 FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); 1886 } 1887 1888 // 1889 // Don't allow people to create directories with the 1890 // temporary bit set. 1891 // 1892 1893 if (TemporaryFile) { 1894 1895 try_return( Iosb.Status = STATUS_INVALID_PARAMETER ); 1896 } 1897 1898 Iosb = FatCreateNewDirectory( IrpContext, 1899 IrpSp, 1900 FileObject, 1901 Vcb, 1902 ParentDcb, 1903 &OemFinalName, 1904 &FinalName, 1905 DesiredAccess, 1906 ShareAccess, 1907 EaBuffer, 1908 EaLength, 1909 FileAttributes, 1910 NoEaKnowledge, 1911 DeleteOnClose, 1912 OpenRequiringOplock ); 1913 1914 Irp->IoStatus.Information = Iosb.Information; 1915 try_return( Iosb.Status ); 1916 } 1917 1918 DebugTrace(0, Dbg, "Create new file\n", 0); 1919 1920 if ( TrailingBackslash ) { 1921 1922 try_return( Iosb.Status = STATUS_OBJECT_NAME_INVALID ); 1923 } 1924 1925 // 1926 // If this media is write protected, don't even try the create. 1927 // 1928 1929 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) { 1930 1931 // 1932 // Set the real device for the pop-up info, and set the verify 1933 // bit in the device object, so that we will force a verify 1934 // in case the user put the correct media back in. 1935 // 1936 1937 1938 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 1939 Vcb->Vpb->RealDevice ); 1940 1941 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 1942 1943 FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); 1944 } 1945 1946 1947 Iosb = FatCreateNewFile( IrpContext, 1948 IrpSp, 1949 FileObject, 1950 Vcb, 1951 ParentDcb, 1952 &OemFinalName, 1953 &FinalName, 1954 DesiredAccess, 1955 ShareAccess, 1956 AllocationSize, 1957 EaBuffer, 1958 EaLength, 1959 FileAttributes, 1960 &Lfn, 1961 IsPagingFile, 1962 NoEaKnowledge, 1963 DeleteOnClose, 1964 OpenRequiringOplock, 1965 TemporaryFile ); 1966 1967 // 1968 // Check if we need to set the cache support flag in 1969 // the file object 1970 // 1971 1972 if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering) { 1973 1974 FileObject->Flags |= FO_CACHE_SUPPORTED; 1975 } 1976 1977 Irp->IoStatus.Information = Iosb.Information; 1978 1979 try_exit: NOTHING; 1980 1981 // 1982 // This is a Beta Fix. Do this at a better place later. 1983 // 1984 1985 if (NT_SUCCESS(Iosb.Status) && !OpenTargetDirectory) { 1986 1987 PFCB LocalFcb; 1988 1989 // 1990 // If there is an Fcb/Dcb, set the long file name. 1991 // 1992 1993 LocalFcb = FileObject->FsContext; 1994 1995 if (LocalFcb && 1996 ((NodeType(LocalFcb) == FAT_NTC_FCB) || 1997 (NodeType(LocalFcb) == FAT_NTC_DCB)) && 1998 (LocalFcb->FullFileName.Buffer == NULL)) { 1999 2000 FatSetFullNameInFcb( IrpContext, LocalFcb, &FinalName ); 2001 } 2002 } 2003 2004 } _SEH2_FINALLY { 2005 2006 DebugUnwind( FatCommonCreate ); 2007 2008 #if (NTDDI_VERSION >= NTDDI_WIN7) 2009 2010 // 2011 // If we're not getting out with success, and if the caller wanted 2012 // atomic create-with-oplock semantics make sure we back out any 2013 // oplock that may have been granted. 2014 // 2015 2016 if ((AbnormalTermination() || 2017 !NT_SUCCESS( Iosb.Status )) && 2018 OpenRequiringOplock && 2019 (Iosb.Status != STATUS_CANNOT_BREAK_OPLOCK) && 2020 (IrpContext->ExceptionStatus != STATUS_CANNOT_BREAK_OPLOCK) && 2021 (Fcb != NULL) && 2022 FatIsFileOplockable( Fcb )) { 2023 2024 FsRtlCheckOplockEx( FatGetFcbOplock(Fcb), 2025 IrpContext->OriginatingIrp, 2026 OPLOCK_FLAG_BACK_OUT_ATOMIC_OPLOCK, 2027 NULL, 2028 NULL, 2029 NULL ); 2030 } 2031 #endif 2032 2033 // 2034 // There used to be a test here - the ASSERT replaces it. We will 2035 // never have begun enumerating directories if we post the IRP for 2036 // oplock reasons. 2037 // 2038 2039 NT_ASSERT( !OplockPostIrp || DirentBcb == NULL ); 2040 2041 FatUnpinBcb( IrpContext, DirentBcb ); 2042 2043 // 2044 // If we are in an error path, check for any created subdir Dcbs that 2045 // have to be unwound. Don't whack the root directory. 2046 // 2047 // Note this will leave a branch of Dcbs dangling if the directory file 2048 // had not been built on the leaf (case: opening path which has an 2049 // element containing an invalid character name). 2050 // 2051 2052 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Iosb.Status)) { 2053 2054 ULONG SavedFlags; 2055 2056 // 2057 // Before doing the uninitialize, we have to unpin anything 2058 // that has been repinned, but disable writethrough first. We 2059 // disable raise from unpin-repin since we're already failing. 2060 // 2061 2062 SavedFlags = IrpContext->Flags; 2063 2064 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE | 2065 IRP_CONTEXT_FLAG_DISABLE_WRITE_THROUGH ); 2066 2067 FatUnpinRepinnedBcbs( IrpContext ); 2068 2069 if ((FinalDcb != NULL) && 2070 (NodeType(FinalDcb) == FAT_NTC_DCB) && 2071 IsListEmpty(&FinalDcb->Specific.Dcb.ParentDcbQueue) && 2072 (FinalDcb->OpenCount == 0) && 2073 (FinalDcb->Specific.Dcb.DirectoryFile != NULL)) { 2074 2075 PFILE_OBJECT DirectoryFileObject; 2076 2077 DirectoryFileObject = FinalDcb->Specific.Dcb.DirectoryFile; 2078 2079 FinalDcb->Specific.Dcb.DirectoryFile = NULL; 2080 2081 CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL ); 2082 2083 ObDereferenceObject( DirectoryFileObject ); 2084 } 2085 2086 IrpContext->Flags = SavedFlags; 2087 } 2088 2089 if (_SEH2_AbnormalTermination()) { 2090 2091 FatReleaseVcb( IrpContext, Vcb ); 2092 } 2093 2094 // 2095 // Free up any string buffers we allocated 2096 // 2097 2098 FatFreeStringBuffer( &OemFinalName); 2099 2100 FatFreeStringBuffer( &UpcasedFinalName); 2101 2102 FatFreeStringBuffer( &Lfn); 2103 } _SEH2_END; 2104 2105 // 2106 // The following code is only executed if we are exiting the 2107 // procedure through a normal termination. We complete the request 2108 // and if for any reason that bombs out then we need to unreference 2109 // and possibly delete the fcb and ccb. 2110 // 2111 2112 _SEH2_TRY { 2113 2114 if (PostIrp) { 2115 2116 // 2117 // If the Irp hasn't already been posted, do it now. 2118 // 2119 2120 if (!OplockPostIrp) { 2121 2122 Iosb.Status = FatFsdPostRequest( IrpContext, Irp ); 2123 } 2124 2125 } else { 2126 2127 FatUnpinRepinnedBcbs( IrpContext ); 2128 } 2129 2130 } _SEH2_FINALLY { 2131 2132 DebugUnwind( FatCommonCreate-in-FatCompleteRequest ); 2133 2134 if (_SEH2_AbnormalTermination() ) { 2135 2136 PVCB LocalVcb; 2137 PFCB LocalFcb; 2138 PCCB LocalCcb2; 2139 PFILE_OBJECT DirectoryFileObject; 2140 2141 // 2142 // Unwind all of our counts. Note that if a write failed, then 2143 // the volume has been marked for verify, and all volume 2144 // structures will be cleaned up automatically. 2145 // 2146 2147 (VOID) FatDecodeFileObject( FileObject, &LocalVcb, &LocalFcb, &LocalCcb2 ); 2148 2149 LocalFcb->UncleanCount -= 1; 2150 LocalFcb->OpenCount -= 1; 2151 LocalVcb->OpenFileCount -= 1; 2152 2153 if (IsFileObjectReadOnly(FileObject)) { LocalVcb->ReadOnlyCount -= 1; } 2154 2155 2156 // 2157 // WinSE #307418 "Occasional data corruption when standby/resume 2158 // while copying files to removable FAT formatted media". 2159 // If new file creation request was interrupted by system suspend 2160 // operation we should revert the changes we made to the parent 2161 // directory and to the allocation table. 2162 // 2163 2164 if (IrpContext->ExceptionStatus == STATUS_VERIFY_REQUIRED && 2165 NodeType( LocalFcb ) == FAT_NTC_FCB) { 2166 2167 FatTruncateFileAllocation( IrpContext, LocalFcb, 0 ); 2168 2169 FatDeleteDirent( IrpContext, LocalFcb, NULL, TRUE ); 2170 } 2171 2172 // 2173 // If we leafed out on a new Fcb we should get rid of it at this point. 2174 // 2175 // Since the object isn't being opened, we have to do all of the teardown 2176 // here. Our close path will not occur for this fileobject. Note this 2177 // will leave a branch of Dcbs dangling since we do it by hand and don't 2178 // chase to the root. 2179 // 2180 2181 if (LocalFcb->OpenCount == 0 && 2182 (NodeType( LocalFcb ) == FAT_NTC_FCB || 2183 IsListEmpty(&LocalFcb->Specific.Dcb.ParentDcbQueue))) { 2184 2185 NT_ASSERT( NodeType( LocalFcb ) != FAT_NTC_ROOT_DCB ); 2186 2187 if ( (NodeType( LocalFcb ) == FAT_NTC_DCB) && 2188 (LocalFcb->Specific.Dcb.DirectoryFile != NULL) ) { 2189 2190 DirectoryFileObject = LocalFcb->Specific.Dcb.DirectoryFile; 2191 LocalFcb->Specific.Dcb.DirectoryFile = NULL; 2192 2193 CcUninitializeCacheMap( DirectoryFileObject, 2194 &FatLargeZero, 2195 NULL ); 2196 2197 ObDereferenceObject( DirectoryFileObject ); 2198 2199 } else { 2200 if (ARGUMENT_PRESENT( FileObject )) { 2201 FileObject->SectionObjectPointer = NULL; 2202 } 2203 FatDeleteFcb( IrpContext, &LocalFcb ); 2204 } 2205 } 2206 2207 FatDeleteCcb( IrpContext, &LocalCcb2 ); 2208 2209 FatReleaseVcb( IrpContext, LocalVcb ); 2210 2211 } else { 2212 2213 FatReleaseVcb( IrpContext, Vcb ); 2214 2215 if ( !PostIrp ) { 2216 2217 // 2218 // If this request is successful and the file was opened 2219 // for FILE_EXECUTE access, then set the FileObject bit. 2220 // 2221 2222 NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL ); 2223 if (FlagOn( *DesiredAccess, FILE_EXECUTE )) { 2224 2225 SetFlag( FileObject->Flags, FO_FILE_FAST_IO_READ ); 2226 } 2227 2228 // 2229 // Lock volume in drive if we opened a paging file, allocating a 2230 // reserve MDL to guarantee paging file operations can always 2231 // go forward. 2232 // 2233 2234 if (IsPagingFile && NT_SUCCESS(Iosb.Status)) { 2235 2236 #ifdef _MSC_VER 2237 #pragma prefast( suppress:28112, "this should be safe" ) 2238 #endif 2239 if (!FatReserveMdl) { 2240 2241 PMDL ReserveMdl = IoAllocateMdl( NULL, 2242 FAT_RESERVE_MDL_SIZE * PAGE_SIZE, 2243 TRUE, 2244 FALSE, 2245 NULL ); 2246 2247 // 2248 // Stash the MDL, and if it turned out there was already one there 2249 // just free what we got. 2250 // 2251 2252 #ifndef __REACTOS__ 2253 InterlockedCompareExchangePointer( &FatReserveMdl, ReserveMdl, NULL ); 2254 #else 2255 InterlockedCompareExchangePointer( (void * volatile*)&FatReserveMdl, ReserveMdl, NULL ); 2256 #endif 2257 2258 #ifdef _MSC_VER 2259 #pragma prefast( suppress:28112, "this should be safe" ) 2260 #endif 2261 if (FatReserveMdl != ReserveMdl) { 2262 2263 IoFreeMdl( ReserveMdl ); 2264 } 2265 } 2266 2267 SetFlag(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE); 2268 2269 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) { 2270 2271 FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE ); 2272 } 2273 } 2274 2275 } 2276 } 2277 2278 DebugTrace(-1, Dbg, "FatCommonCreate -> %08lx\n", Iosb.Status); 2279 } _SEH2_END; 2280 2281 CollectCreateStatistics(Vcb, Iosb.Status); 2282 2283 return Iosb.Status; 2284 } 2285 2286 // 2287 // Internal support routine 2288 // 2289 2290 _Requires_lock_held_(_Global_critical_region_) 2291 IO_STATUS_BLOCK 2292 FatOpenVolume ( 2293 _In_ PIRP_CONTEXT IrpContext, 2294 _Inout_ PFILE_OBJECT FileObject, 2295 _Inout_ PVCB Vcb, 2296 _In_ PACCESS_MASK DesiredAccess, 2297 _In_ USHORT ShareAccess, 2298 _In_ ULONG CreateDisposition 2299 ) 2300 2301 /*++ 2302 2303 Routine Description: 2304 2305 This routine opens the specified volume for DASD access 2306 2307 Arguments: 2308 2309 FileObject - Supplies the File object 2310 2311 Vcb - Supplies the Vcb denoting the volume being opened 2312 2313 DesiredAccess - Supplies the desired access of the caller 2314 2315 ShareAccess - Supplies the share access of the caller 2316 2317 CreateDisposition - Supplies the create disposition for this operation 2318 2319 Return Value: 2320 2321 IO_STATUS_BLOCK - Returns the completion status for the operation 2322 2323 --*/ 2324 2325 { 2326 NTSTATUS Status; 2327 PIO_STACK_LOCATION IrpSp; 2328 2329 #ifndef __REACTOS__ 2330 IO_STATUS_BLOCK Iosb = {0,0}; 2331 #else 2332 IO_STATUS_BLOCK Iosb = {{0}}; 2333 #endif 2334 2335 BOOLEAN CleanedVolume = FALSE; 2336 2337 // 2338 // The following variables are for abnormal termination 2339 // 2340 2341 BOOLEAN UnwindShareAccess = FALSE; 2342 PCCB UnwindCcb = NULL; 2343 BOOLEAN UnwindCounts = FALSE; 2344 BOOLEAN UnwindVolumeLock = FALSE; 2345 2346 PAGED_CODE(); 2347 2348 DebugTrace(+1, Dbg, "FatOpenVolume...\n", 0); 2349 2350 _SEH2_TRY { 2351 2352 // 2353 // Check for proper desired access and rights 2354 // 2355 2356 if ((CreateDisposition != FILE_OPEN) && 2357 (CreateDisposition != FILE_OPEN_IF)) { 2358 2359 try_return( Iosb.Status = STATUS_ACCESS_DENIED ); 2360 } 2361 2362 // 2363 // If the user does not want to share write or delete then we will try 2364 // and take out a lock on the volume. 2365 // 2366 2367 if (!FlagOn(ShareAccess, FILE_SHARE_WRITE) && 2368 !FlagOn(ShareAccess, FILE_SHARE_DELETE)) { 2369 2370 #if (NTDDI_VERSION >= NTDDI_VISTA) 2371 // 2372 // See if the user has requested write access. If so, they cannot share 2373 // read. There is one exception to this. We allow autochk to get an 2374 // implicit lock on the volume while still allowing readers. Once the 2375 // the system is booted, though, we do not allow this type of access. 2376 // 2377 2378 if (FlagOn( *DesiredAccess, (FILE_WRITE_DATA | FILE_APPEND_DATA) ) && 2379 FsRtlAreVolumeStartupApplicationsComplete()) { 2380 2381 ClearFlag( ShareAccess, FILE_SHARE_READ ); 2382 } 2383 #endif 2384 2385 // 2386 // Do a quick check here for handles on exclusive open. 2387 // 2388 2389 if (!FlagOn(ShareAccess, FILE_SHARE_READ) && 2390 !FatIsHandleCountZero( IrpContext, Vcb )) { 2391 2392 try_return( Iosb.Status = STATUS_SHARING_VIOLATION ); 2393 } 2394 2395 // 2396 // Force Mm to get rid of its referenced file objects. 2397 // 2398 2399 FatFlushFat( IrpContext, Vcb ); 2400 2401 FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush ); 2402 2403 // 2404 // If the user also does not want to share read then we check 2405 // if anyone is already using the volume, and if so then we 2406 // deny the access. If the user wants to share read then 2407 // we allow the current opens to stay provided they are only 2408 // readonly opens and deny further opens. 2409 // 2410 2411 if (!FlagOn(ShareAccess, FILE_SHARE_READ)) { 2412 2413 if (Vcb->OpenFileCount != 0) { 2414 2415 try_return( Iosb.Status = STATUS_SHARING_VIOLATION ); 2416 } 2417 2418 } else { 2419 2420 if (Vcb->ReadOnlyCount != Vcb->OpenFileCount) { 2421 2422 try_return( Iosb.Status = STATUS_SHARING_VIOLATION ); 2423 } 2424 } 2425 2426 // 2427 // Lock the volume 2428 // 2429 2430 Vcb->VcbState |= VCB_STATE_FLAG_LOCKED; 2431 Vcb->FileObjectWithVcbLocked = FileObject; 2432 UnwindVolumeLock = TRUE; 2433 2434 // 2435 // Clean the volume 2436 // 2437 2438 CleanedVolume = TRUE; 2439 2440 } else if (FlagOn( *DesiredAccess, FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA )) { 2441 2442 // 2443 // Flush the volume and let ourselves push the clean bit out if everything 2444 // worked. 2445 // 2446 2447 if (NT_SUCCESS( FatFlushVolume( IrpContext, Vcb, Flush ))) { 2448 2449 CleanedVolume = TRUE; 2450 } 2451 } 2452 2453 // 2454 // Clean the volume if we believe it safe and reasonable. 2455 // 2456 2457 if (CleanedVolume && 2458 FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ) && 2459 !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ) && 2460 !CcIsThereDirtyData(Vcb->Vpb)) { 2461 2462 // 2463 // Cancel any pending clean volumes. 2464 // 2465 2466 (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer ); 2467 (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc ); 2468 2469 FatMarkVolume( IrpContext, Vcb, VolumeClean ); 2470 ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ); 2471 2472 // 2473 // Unlock the volume if it is removable. 2474 // 2475 2476 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) && 2477 !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) { 2478 2479 FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE ); 2480 } 2481 } 2482 2483 // 2484 // If the volume is already opened by someone then we need to check 2485 // the share access 2486 // 2487 2488 if (Vcb->DirectAccessOpenCount > 0) { 2489 2490 if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess, 2491 ShareAccess, 2492 FileObject, 2493 &Vcb->ShareAccess, 2494 TRUE ))) { 2495 2496 try_return( Iosb.Status ); 2497 } 2498 2499 } else { 2500 2501 IoSetShareAccess( *DesiredAccess, 2502 ShareAccess, 2503 FileObject, 2504 &Vcb->ShareAccess ); 2505 } 2506 2507 UnwindShareAccess = TRUE; 2508 2509 // 2510 // Set up the context and section object pointers, and update 2511 // our reference counts 2512 // 2513 2514 FatSetFileObject( FileObject, 2515 UserVolumeOpen, 2516 Vcb, 2517 UnwindCcb = FatCreateCcb( IrpContext )); 2518 2519 FileObject->SectionObjectPointer = &Vcb->SectionObjectPointers; 2520 2521 Vcb->DirectAccessOpenCount += 1; 2522 Vcb->OpenFileCount += 1; 2523 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 2524 UnwindCounts = TRUE; 2525 FileObject->Flags |= FO_NO_INTERMEDIATE_BUFFERING; 2526 2527 // 2528 // At this point the open will succeed, so check if the user is getting explicit access 2529 // to the device. If not, we will note this so we can deny modifying FSCTL to it. 2530 // 2531 2532 IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp ); 2533 Status = FatExplicitDeviceAccessGranted( IrpContext, 2534 Vcb->Vpb->RealDevice, 2535 IrpSp->Parameters.Create.SecurityContext->AccessState, 2536 (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? 2537 UserMode : 2538 IrpContext->OriginatingIrp->RequestorMode )); 2539 2540 if (NT_SUCCESS( Status )) { 2541 2542 SetFlag( UnwindCcb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); 2543 } 2544 2545 // 2546 // And set our status to success 2547 // 2548 2549 Iosb.Status = STATUS_SUCCESS; 2550 Iosb.Information = FILE_OPENED; 2551 2552 try_exit: NOTHING; 2553 } _SEH2_FINALLY { 2554 2555 DebugUnwind( FatOpenVolume ); 2556 2557 // 2558 // If this is an abnormal termination then undo our work 2559 // 2560 2561 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Iosb.Status)) { 2562 2563 if (UnwindCounts) { 2564 Vcb->DirectAccessOpenCount -= 1; 2565 Vcb->OpenFileCount -= 1; 2566 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } 2567 } 2568 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 2569 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Vcb->ShareAccess ); } 2570 if (UnwindVolumeLock) { Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED; } 2571 } 2572 2573 DebugTrace(-1, Dbg, "FatOpenVolume -> Iosb.Status = %08lx\n", Iosb.Status); 2574 } _SEH2_END; 2575 2576 return Iosb; 2577 } 2578 2579 2580 // 2581 // Internal support routine 2582 // 2583 2584 _Requires_lock_held_(_Global_critical_region_) 2585 IO_STATUS_BLOCK 2586 FatOpenRootDcb ( 2587 _In_ PIRP_CONTEXT IrpContext, 2588 _Inout_ PFILE_OBJECT FileObject, 2589 _Inout_ PVCB Vcb, 2590 _In_ PACCESS_MASK DesiredAccess, 2591 _In_ USHORT ShareAccess, 2592 _In_ ULONG CreateDisposition 2593 ) 2594 2595 /*++ 2596 2597 Routine Description: 2598 2599 This routine opens the root dcb for the volume 2600 2601 Arguments: 2602 2603 FileObject - Supplies the File object 2604 2605 Vcb - Supplies the Vcb denoting the volume whose dcb is being opened. 2606 2607 DesiredAccess - Supplies the desired access of the caller 2608 2609 ShareAccess - Supplies the share access of the caller 2610 2611 CreateDisposition - Supplies the create disposition for this operation 2612 2613 Return Value: 2614 2615 IO_STATUS_BLOCK - Returns the completion status for the operation 2616 2617 Arguments: 2618 2619 --*/ 2620 2621 { 2622 PDCB RootDcb; 2623 IO_STATUS_BLOCK Iosb = {0}; 2624 2625 // 2626 // The following variables are for abnormal termination 2627 // 2628 2629 BOOLEAN UnwindShareAccess = FALSE; 2630 PCCB UnwindCcb = NULL; 2631 BOOLEAN UnwindCounts = FALSE; 2632 BOOLEAN RootDcbAcquired = FALSE; 2633 2634 PAGED_CODE(); 2635 2636 DebugTrace(+1, Dbg, "FatOpenRootDcb...\n", 0); 2637 2638 // 2639 // Locate the root dcb 2640 // 2641 2642 RootDcb = Vcb->RootDcb; 2643 2644 // 2645 // Get the Dcb exlcusive. This is important as cleanup does not 2646 // acquire the Vcb. 2647 // 2648 2649 (VOID)FatAcquireExclusiveFcb( IrpContext, RootDcb ); 2650 RootDcbAcquired = TRUE; 2651 2652 _SEH2_TRY { 2653 2654 // 2655 // Check the create disposition and desired access 2656 // 2657 2658 if ((CreateDisposition != FILE_OPEN) && 2659 (CreateDisposition != FILE_OPEN_IF)) { 2660 2661 Iosb.Status = STATUS_ACCESS_DENIED; 2662 try_return( Iosb ); 2663 } 2664 2665 if (!FatCheckFileAccess( IrpContext, 2666 RootDcb->DirentFatFlags, 2667 DesiredAccess)) { 2668 2669 Iosb.Status = STATUS_ACCESS_DENIED; 2670 try_return( Iosb ); 2671 } 2672 2673 // 2674 // If the Root dcb is already opened by someone then we need 2675 // to check the share access 2676 // 2677 2678 if (RootDcb->OpenCount > 0) { 2679 2680 if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess, 2681 ShareAccess, 2682 FileObject, 2683 &RootDcb->ShareAccess, 2684 TRUE ))) { 2685 2686 try_return( Iosb ); 2687 } 2688 2689 } else { 2690 2691 IoSetShareAccess( *DesiredAccess, 2692 ShareAccess, 2693 FileObject, 2694 &RootDcb->ShareAccess ); 2695 } 2696 2697 UnwindShareAccess = TRUE; 2698 2699 // 2700 // Setup the context and section object pointers, and update 2701 // our reference counts 2702 // 2703 2704 FatSetFileObject( FileObject, 2705 UserDirectoryOpen, 2706 RootDcb, 2707 UnwindCcb = FatCreateCcb( IrpContext )); 2708 2709 RootDcb->UncleanCount += 1; 2710 RootDcb->OpenCount += 1; 2711 Vcb->OpenFileCount += 1; 2712 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 2713 UnwindCounts = TRUE; 2714 2715 // 2716 // And set our status to success 2717 // 2718 2719 Iosb.Status = STATUS_SUCCESS; 2720 Iosb.Information = FILE_OPENED; 2721 2722 try_exit: NOTHING; 2723 } _SEH2_FINALLY { 2724 2725 DebugUnwind( FatOpenRootDcb ); 2726 2727 // 2728 // If this is an abnormal termination then undo our work 2729 // 2730 2731 if (_SEH2_AbnormalTermination()) { 2732 2733 if (UnwindCounts) { 2734 RootDcb->UncleanCount -= 1; 2735 RootDcb->OpenCount -= 1; 2736 Vcb->OpenFileCount -= 1; 2737 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } 2738 } 2739 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 2740 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &RootDcb->ShareAccess ); } 2741 } 2742 2743 if (RootDcbAcquired) { 2744 2745 FatReleaseFcb( IrpContext, RootDcb ); 2746 } 2747 2748 DebugTrace(-1, Dbg, "FatOpenRootDcb -> Iosb.Status = %08lx\n", Iosb.Status); 2749 } _SEH2_END; 2750 2751 return Iosb; 2752 } 2753 2754 2755 // 2756 // Internal support routine 2757 // 2758 2759 _Requires_lock_held_(_Global_critical_region_) 2760 IO_STATUS_BLOCK 2761 FatOpenExistingDcb ( 2762 _In_ PIRP_CONTEXT IrpContext, 2763 _In_ PIO_STACK_LOCATION IrpSp, 2764 _Inout_ PFILE_OBJECT FileObject, 2765 _Inout_ PVCB Vcb, 2766 _Inout_ PDCB Dcb, 2767 _In_ PACCESS_MASK DesiredAccess, 2768 _In_ USHORT ShareAccess, 2769 _In_ ULONG CreateDisposition, 2770 _In_ BOOLEAN NoEaKnowledge, 2771 _In_ BOOLEAN DeleteOnClose, 2772 _In_ BOOLEAN OpenRequiringOplock, 2773 _In_ BOOLEAN FileNameOpenedDos, 2774 _Out_ PBOOLEAN OplockPostIrp 2775 ) 2776 2777 /*++ 2778 2779 Routine Description: 2780 2781 This routine opens the specified existing dcb 2782 2783 Arguments: 2784 2785 FileObject - Supplies the File object 2786 2787 Vcb - Supplies the Vcb denoting the volume containing the dcb 2788 2789 Dcb - Supplies the already existing dcb 2790 2791 DesiredAccess - Supplies the desired access of the caller 2792 2793 ShareAccess - Supplies the share access of the caller 2794 2795 CreateDisposition - Supplies the create disposition for this operation 2796 2797 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 2798 open if the file has NeedEa's. 2799 2800 DeleteOnClose - The caller wants the file gone when the handle is closed 2801 2802 Return Value: 2803 2804 IO_STATUS_BLOCK - Returns the completion status for the operation 2805 2806 --*/ 2807 2808 { 2809 IO_STATUS_BLOCK Iosb = {0}; 2810 PBCB DirentBcb = NULL; 2811 PDIRENT Dirent; 2812 2813 // 2814 // The following variables are for abnormal termination 2815 // 2816 2817 BOOLEAN UnwindShareAccess = FALSE; 2818 PCCB UnwindCcb = NULL; 2819 BOOLEAN DcbAcquired = FALSE; 2820 2821 #if (NTDDI_VERSION <= NTDDI_WIN7) 2822 UNREFERENCED_PARAMETER( OpenRequiringOplock ); 2823 #endif 2824 2825 UNREFERENCED_PARAMETER( IrpSp ); 2826 2827 PAGED_CODE(); 2828 2829 DebugTrace(+1, Dbg, "FatOpenExistingDcb...\n", 0); 2830 2831 // 2832 // Get the Dcb exlcusive. This is important as cleanup does not 2833 // acquire the Vcb. 2834 // 2835 2836 (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb ); 2837 DcbAcquired = TRUE; 2838 2839 _SEH2_TRY { 2840 2841 2842 *OplockPostIrp = FALSE; 2843 2844 // 2845 // Before spending any noticeable effort, see if we have the odd case 2846 // of someone trying to delete-on-close the root dcb. This will only 2847 // happen if we're hit with a null-filename relative open via the root. 2848 // 2849 2850 if (NodeType(Dcb) == FAT_NTC_ROOT_DCB && DeleteOnClose) { 2851 2852 Iosb.Status = STATUS_CANNOT_DELETE; 2853 try_return( Iosb ); 2854 } 2855 2856 #if (NTDDI_VERSION >= NTDDI_WIN8) 2857 2858 // 2859 // Let's make sure that if the caller provided an oplock key that it 2860 // gets stored in the file object. 2861 // 2862 2863 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Dcb), 2864 IrpContext->OriginatingIrp, 2865 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 2866 NULL, 2867 NULL, 2868 NULL ); 2869 2870 if (Iosb.Status != STATUS_SUCCESS) { 2871 2872 try_return( NOTHING ); 2873 } 2874 2875 #endif 2876 // 2877 // If the caller has no Ea knowledge, we immediately check for 2878 // Need Ea's on the file. We don't need to check for ea's on the 2879 // root directory, because it never has any. Fat32 doesn't have 2880 // any, either. 2881 // 2882 2883 if (NoEaKnowledge && NodeType(Dcb) != FAT_NTC_ROOT_DCB && 2884 !FatIsFat32(Vcb)) { 2885 2886 ULONG NeedEaCount; 2887 2888 // 2889 // Get the dirent for the file and then check that the need 2890 // ea count is 0. 2891 // 2892 2893 FatGetDirentFromFcbOrDcb( IrpContext, 2894 Dcb, 2895 FALSE, 2896 &Dirent, 2897 &DirentBcb ); 2898 2899 FatGetNeedEaCount( IrpContext, 2900 Vcb, 2901 Dirent, 2902 &NeedEaCount ); 2903 2904 FatUnpinBcb( IrpContext, DirentBcb ); 2905 2906 if (NeedEaCount != 0) { 2907 2908 Iosb.Status = STATUS_ACCESS_DENIED; 2909 try_return( Iosb ); 2910 } 2911 } 2912 2913 // 2914 // Check the create disposition and desired access 2915 // 2916 2917 if ((CreateDisposition != FILE_OPEN) && 2918 (CreateDisposition != FILE_OPEN_IF)) { 2919 2920 Iosb.Status = STATUS_OBJECT_NAME_COLLISION; 2921 try_return( Iosb ); 2922 } 2923 2924 if (!FatCheckFileAccess( IrpContext, 2925 Dcb->DirentFatFlags, 2926 DesiredAccess)) { 2927 2928 Iosb.Status = STATUS_ACCESS_DENIED; 2929 try_return( Iosb ); 2930 } 2931 2932 // 2933 // If the dcb is already opened by someone then we need 2934 // to check the share access 2935 // 2936 2937 if (Dcb->OpenCount > 0) { 2938 2939 if (!NT_SUCCESS(Iosb.Status = FatCheckShareAccess( IrpContext, 2940 FileObject, 2941 Dcb, 2942 DesiredAccess, 2943 ShareAccess ))) { 2944 #if (NTDDI_VERSION >= NTDDI_WIN8) 2945 2946 NTSTATUS OplockBreakStatus = STATUS_SUCCESS; 2947 2948 // 2949 // If we got a sharing violation try to break outstanding handle 2950 // oplocks and retry the sharing check. If the caller specified 2951 // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock; 2952 // we just return the sharing violation. 2953 // 2954 2955 if ((Iosb.Status == STATUS_SHARING_VIOLATION) && 2956 !FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) { 2957 2958 OplockBreakStatus = FsRtlOplockBreakH( FatGetFcbOplock(Dcb), 2959 IrpContext->OriginatingIrp, 2960 0, 2961 IrpContext, 2962 FatOplockComplete, 2963 FatPrePostIrp ); 2964 2965 // 2966 // If FsRtlOplockBreakH returned STATUS_PENDING, then the IRP 2967 // has been posted and we need to stop working. 2968 // 2969 2970 if (OplockBreakStatus == STATUS_PENDING) { 2971 2972 Iosb.Status = STATUS_PENDING; 2973 *OplockPostIrp = TRUE; 2974 try_return( NOTHING ); 2975 2976 // 2977 // If FsRtlOplockBreakH returned an error we want to return that now. 2978 // 2979 2980 } else if (!NT_SUCCESS( OplockBreakStatus )) { 2981 2982 Iosb.Status = OplockBreakStatus; 2983 try_return( Iosb ); 2984 2985 // 2986 // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating 2987 // that there is no oplock to be broken. The sharing violation is 2988 // returned in that case. 2989 // 2990 2991 } else { 2992 2993 NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS ); 2994 2995 try_return( Iosb ); 2996 } 2997 2998 // 2999 // The initial sharing check failed with something other than sharing 3000 // violation (which should never happen, but let's be future-proof), 3001 // or we *did* get a sharing violation and the caller specified 3002 // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over. 3003 // 3004 3005 } else { 3006 3007 try_return( Iosb ); 3008 } 3009 #else 3010 3011 try_return( Iosb ); 3012 #endif 3013 } 3014 } 3015 3016 #if (NTDDI_VERSION >= NTDDI_WIN8) 3017 3018 // 3019 // Now check that we can continue based on the oplock state of the 3020 // directory. If there are no open handles yet we don't need to do 3021 // this check; oplocks can only exist when there are handles. 3022 // 3023 3024 if (Dcb->UncleanCount != 0) { 3025 3026 Iosb.Status = FsRtlCheckOplock( FatGetFcbOplock(Dcb), 3027 IrpContext->OriginatingIrp, 3028 IrpContext, 3029 FatOplockComplete, 3030 FatPrePostIrp ); 3031 } 3032 3033 // 3034 // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted 3035 // to service an oplock break and we need to leave now. 3036 // 3037 3038 if (Iosb.Status == STATUS_PENDING) { 3039 3040 *OplockPostIrp = TRUE; 3041 try_return( NOTHING ); 3042 } 3043 3044 // 3045 // If the caller wants atomic create-with-oplock semantics, tell 3046 // the oplock package. We haven't incremented the Fcb's UncleanCount 3047 // for this create yet, so add that in on the call. 3048 // 3049 3050 if (OpenRequiringOplock && 3051 (Iosb.Status == STATUS_SUCCESS)) { 3052 3053 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Dcb), 3054 IrpContext->OriginatingIrp, 3055 (Dcb->UncleanCount + 1) ); 3056 } 3057 3058 // 3059 // If we've encountered a failure we need to leave. FsRtlCheckOplock 3060 // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated 3061 // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED 3062 // on the create call. That's an NT_SUCCESS code, so we need to keep 3063 // going. 3064 // 3065 3066 if ((Iosb.Status != STATUS_SUCCESS) && 3067 (Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) { 3068 3069 try_return( NOTHING ); 3070 } 3071 3072 #endif 3073 3074 // 3075 // Now that we're done with the oplock work update the share counts. 3076 // If the Dcb isn't yet opened we just set the share access rather than 3077 // update it. 3078 // 3079 3080 if (Dcb->OpenCount > 0) { 3081 3082 IoUpdateShareAccess( FileObject, &Dcb->ShareAccess ); 3083 3084 } else { 3085 3086 IoSetShareAccess( *DesiredAccess, 3087 ShareAccess, 3088 FileObject, 3089 &Dcb->ShareAccess ); 3090 } 3091 3092 UnwindShareAccess = TRUE; 3093 3094 // 3095 // Setup the context and section object pointers, and update 3096 // our reference counts 3097 // 3098 3099 FatSetFileObject( FileObject, 3100 UserDirectoryOpen, 3101 Dcb, 3102 UnwindCcb = FatCreateCcb( IrpContext )); 3103 3104 Dcb->UncleanCount += 1; 3105 Dcb->OpenCount += 1; 3106 Vcb->OpenFileCount += 1; 3107 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 3108 3109 // 3110 // Mark the delete on close bit if the caller asked for that. 3111 // 3112 3113 { 3114 PCCB Ccb = (PCCB)FileObject->FsContext2; 3115 3116 3117 if (DeleteOnClose) { 3118 3119 SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); 3120 } 3121 if (FileNameOpenedDos) { 3122 3123 SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 3124 } 3125 3126 } 3127 3128 3129 // 3130 // In case this was set, clear it now. 3131 // 3132 3133 ClearFlag(Dcb->FcbState, FCB_STATE_DELAY_CLOSE); 3134 3135 // 3136 // And set our status to success 3137 // 3138 3139 Iosb.Status = STATUS_SUCCESS; 3140 Iosb.Information = FILE_OPENED; 3141 3142 try_exit: NOTHING; 3143 } _SEH2_FINALLY { 3144 3145 DebugUnwind( FatOpenExistingDcb ); 3146 3147 // 3148 // Unpin the Dirent Bcb if pinned. 3149 // 3150 3151 FatUnpinBcb( IrpContext, DirentBcb ); 3152 3153 // 3154 // If this is an abnormal termination then undo our work 3155 // 3156 3157 if (_SEH2_AbnormalTermination()) { 3158 3159 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 3160 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); } 3161 } 3162 3163 if (DcbAcquired) { 3164 3165 FatReleaseFcb( IrpContext, Dcb ); 3166 } 3167 3168 DebugTrace(-1, Dbg, "FatOpenExistingDcb -> Iosb.Status = %08lx\n", Iosb.Status); 3169 } _SEH2_END; 3170 3171 return Iosb; 3172 } 3173 3174 3175 // 3176 // Internal support routine 3177 // 3178 3179 _Requires_lock_held_(_Global_critical_region_) 3180 IO_STATUS_BLOCK 3181 FatOpenExistingFcb ( 3182 _In_ PIRP_CONTEXT IrpContext, 3183 _In_ PIO_STACK_LOCATION IrpSp, 3184 _Inout_ PFILE_OBJECT FileObject, 3185 _Inout_ PVCB Vcb, 3186 _Inout_ PFCB Fcb, 3187 _In_ PACCESS_MASK DesiredAccess, 3188 _In_ USHORT ShareAccess, 3189 _In_ ULONG AllocationSize, 3190 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 3191 _In_ ULONG EaLength, 3192 _In_ USHORT FileAttributes, 3193 _In_ ULONG CreateDisposition, 3194 _In_ BOOLEAN NoEaKnowledge, 3195 _In_ BOOLEAN DeleteOnClose, 3196 _In_ BOOLEAN OpenRequiringOplock, 3197 _In_ BOOLEAN FileNameOpenedDos, 3198 _Out_ PBOOLEAN OplockPostIrp 3199 ) 3200 3201 /*++ 3202 3203 Routine Description: 3204 3205 This routine opens the specified existing fcb 3206 3207 Arguments: 3208 3209 FileObject - Supplies the File object 3210 3211 Vcb - Supplies the Vcb denoting the volume containing the Fcb 3212 3213 Fcb - Supplies the already existing fcb 3214 3215 DesiredAccess - Supplies the desired access of the caller 3216 3217 ShareAccess - Supplies the share access of the caller 3218 3219 AllocationSize - Supplies the initial allocation if the file is being 3220 superseded or overwritten 3221 3222 EaBuffer - Supplies the Ea set if the file is being superseded or 3223 overwritten 3224 3225 EaLength - Supplies the size, in byte, of the EaBuffer 3226 3227 FileAttributes - Supplies file attributes to use if the file is being 3228 superseded or overwritten 3229 3230 CreateDisposition - Supplies the create disposition for this operation 3231 3232 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 3233 open if the file has NeedEa's. 3234 3235 DeleteOnClose - The caller wants the file gone when the handle is closed 3236 3237 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option. 3238 3239 FileNameOpenedDos - The caller hit the short side of the name pair finding 3240 this file 3241 3242 OplockPostIrp - Address to store boolean indicating if the Irp needs to 3243 be posted to the Fsp. 3244 3245 Return Value: 3246 3247 IO_STATUS_BLOCK - Returns the completion status for the operation 3248 3249 --*/ 3250 3251 { 3252 IO_STATUS_BLOCK Iosb = {0}; 3253 3254 PBCB DirentBcb = NULL; 3255 PDIRENT Dirent; 3256 3257 ACCESS_MASK AddedAccess = 0; 3258 3259 // 3260 // The following variables are for abnormal termination 3261 // 3262 3263 BOOLEAN UnwindShareAccess = FALSE; 3264 PCCB UnwindCcb = NULL; 3265 BOOLEAN DecrementFcbOpenCount = FALSE; 3266 BOOLEAN FcbAcquired = FALSE; 3267 3268 3269 PAGED_CODE(); 3270 3271 DebugTrace(+1, Dbg, "FatOpenExistingFcb...\n", 0); 3272 3273 // 3274 // Get the Fcb exlcusive. This is important as cleanup does not 3275 // acquire the Vcb. 3276 // 3277 3278 (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb ); 3279 FcbAcquired = TRUE; 3280 3281 _SEH2_TRY { 3282 3283 3284 *OplockPostIrp = FALSE; 3285 3286 #if (NTDDI_VERSION >= NTDDI_WIN7) 3287 3288 // 3289 // Let's make sure that if the caller provided an oplock key that it 3290 // gets stored in the file object. 3291 // 3292 3293 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb), 3294 IrpContext->OriginatingIrp, 3295 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 3296 NULL, 3297 NULL, 3298 NULL ); 3299 3300 if (Iosb.Status != STATUS_SUCCESS) { 3301 3302 try_return( NOTHING ); 3303 } 3304 #endif 3305 3306 // 3307 // Take special action if there is a current batch oplock or 3308 // batch oplock break in process on the Fcb. 3309 // 3310 3311 if (FsRtlCurrentBatchOplock( FatGetFcbOplock(Fcb) )) { 3312 3313 // 3314 // We remember if a batch oplock break is underway for the 3315 // case where the sharing check fails. 3316 // 3317 3318 Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY; 3319 3320 Iosb.Status = FsRtlCheckOplock( FatGetFcbOplock(Fcb), 3321 IrpContext->OriginatingIrp, 3322 IrpContext, 3323 FatOplockComplete, 3324 FatPrePostIrp ); 3325 3326 // 3327 // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted 3328 // to service an oplock break and we need to leave now. 3329 // 3330 3331 if (Iosb.Status == STATUS_PENDING) { 3332 3333 *OplockPostIrp = TRUE; 3334 try_return( NOTHING ); 3335 } 3336 } 3337 3338 // 3339 // Check if the user wanted to create the file, also special case 3340 // the supersede and overwrite options. Those add additional, 3341 // possibly only implied, desired accesses to the caller, which 3342 // we must be careful to pull back off if the caller did not actually 3343 // request them. 3344 // 3345 // In other words, check against the implied access, but do not modify 3346 // share access as a result. 3347 // 3348 3349 if (CreateDisposition == FILE_CREATE) { 3350 3351 Iosb.Status = STATUS_OBJECT_NAME_COLLISION; 3352 try_return( Iosb ); 3353 3354 } else if (CreateDisposition == FILE_SUPERSEDE) { 3355 3356 SetFlag( AddedAccess, 3357 DELETE & ~(*DesiredAccess) ); 3358 3359 *DesiredAccess |= DELETE; 3360 3361 } else if ((CreateDisposition == FILE_OVERWRITE) || 3362 (CreateDisposition == FILE_OVERWRITE_IF)) { 3363 3364 SetFlag( AddedAccess, 3365 (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) ); 3366 3367 *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES; 3368 } 3369 3370 // 3371 // Check the desired access 3372 // 3373 3374 if (!FatCheckFileAccess( IrpContext, 3375 Fcb->DirentFatFlags, 3376 DesiredAccess )) { 3377 3378 Iosb.Status = STATUS_ACCESS_DENIED; 3379 try_return( Iosb ); 3380 } 3381 3382 3383 // 3384 // Check for trying to delete a read only file. 3385 // 3386 3387 if (DeleteOnClose && 3388 FlagOn( Fcb->DirentFatFlags, FAT_DIRENT_ATTR_READ_ONLY )) { 3389 3390 Iosb.Status = STATUS_CANNOT_DELETE; 3391 try_return( Iosb ); 3392 } 3393 3394 // 3395 // If we are asked to do an overwrite or supersede operation then 3396 // deny access for files where the file attributes for system and 3397 // hidden do not match 3398 // 3399 3400 if ((CreateDisposition == FILE_SUPERSEDE) || 3401 (CreateDisposition == FILE_OVERWRITE) || 3402 (CreateDisposition == FILE_OVERWRITE_IF)) { 3403 3404 BOOLEAN Hidden; 3405 BOOLEAN System; 3406 3407 Hidden = BooleanFlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_HIDDEN ); 3408 System = BooleanFlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_SYSTEM ); 3409 3410 if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) || 3411 (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) { 3412 3413 DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0); 3414 3415 3416 Iosb.Status = STATUS_ACCESS_DENIED; 3417 try_return( Iosb ); 3418 } 3419 3420 // 3421 // If this media is write protected, don't even try the create. 3422 // 3423 3424 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) { 3425 3426 // 3427 // Set the real device for the pop-up info, and set the verify 3428 // bit in the device object, so that we will force a verify 3429 // in case the user put the correct media back in. 3430 // 3431 3432 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 3433 Vcb->Vpb->RealDevice ); 3434 3435 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 3436 3437 FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); 3438 } 3439 } 3440 3441 // 3442 // Check if the Fcb has the proper share access. This routine will also 3443 // check for writable user secions if the user did not allow write sharing. 3444 // 3445 3446 if (!NT_SUCCESS(Iosb.Status = FatCheckShareAccess( IrpContext, 3447 FileObject, 3448 Fcb, 3449 DesiredAccess, 3450 ShareAccess ))) { 3451 3452 #if (NTDDI_VERSION >= NTDDI_WIN7) 3453 3454 NTSTATUS OplockBreakStatus = STATUS_SUCCESS; 3455 3456 // 3457 // If we got a sharing violation try to break outstanding handle 3458 // oplocks and retry the sharing check. If the caller specified 3459 // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock; 3460 // we just return the sharing violation. 3461 // 3462 3463 if ((Iosb.Status == STATUS_SHARING_VIOLATION) && 3464 !FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) { 3465 3466 OplockBreakStatus = FsRtlOplockBreakH( FatGetFcbOplock(Fcb), 3467 IrpContext->OriginatingIrp, 3468 0, 3469 IrpContext, 3470 FatOplockComplete, 3471 FatPrePostIrp ); 3472 3473 // 3474 // If FsRtlOplockBreakH returned STATUS_PENDING, then the IRP 3475 // has been posted and we need to stop working. 3476 // 3477 3478 if (OplockBreakStatus == STATUS_PENDING) { 3479 3480 Iosb.Status = STATUS_PENDING; 3481 *OplockPostIrp = TRUE; 3482 try_return( NOTHING ); 3483 3484 // 3485 // If FsRtlOplockBreakH returned an error we want to return that now. 3486 // 3487 3488 } else if (!NT_SUCCESS( OplockBreakStatus )) { 3489 3490 Iosb.Status = OplockBreakStatus; 3491 try_return( Iosb ); 3492 3493 // 3494 // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating 3495 // that there is no oplock to be broken. The sharing violation is 3496 // returned in that case. 3497 // 3498 3499 } else { 3500 3501 NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS ); 3502 3503 try_return( Iosb ); 3504 } 3505 3506 // 3507 // The initial sharing check failed with something other than sharing 3508 // violation (which should never happen, but let's be future-proof), 3509 // or we *did* get a sharing violation and the caller specified 3510 // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over. 3511 // 3512 3513 } else { 3514 3515 try_return( Iosb ); 3516 } 3517 3518 #else 3519 3520 try_return( Iosb ); 3521 3522 #endif 3523 } 3524 3525 // 3526 // Now check that we can continue based on the oplock state of the 3527 // file. If there are no open handles yet we don't need to do this 3528 // check; oplocks can only exist when there are handles. 3529 // 3530 // It is important that we modified the DesiredAccess in place so 3531 // that the Oplock check proceeds against any added access we had 3532 // to give the caller. 3533 // 3534 3535 if (Fcb->UncleanCount != 0) { 3536 3537 Iosb.Status = FsRtlCheckOplock( FatGetFcbOplock(Fcb), 3538 IrpContext->OriginatingIrp, 3539 IrpContext, 3540 FatOplockComplete, 3541 FatPrePostIrp ); 3542 } 3543 3544 // 3545 // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted 3546 // to service an oplock break and we need to leave now. 3547 // 3548 3549 if (Iosb.Status == STATUS_PENDING) { 3550 3551 *OplockPostIrp = TRUE; 3552 try_return( NOTHING ); 3553 } 3554 3555 // 3556 // If the caller wants atomic create-with-oplock semantics, tell 3557 // the oplock package. We haven't incremented the Fcb's UncleanCount 3558 // for this create yet, so add that in on the call. 3559 // 3560 3561 if (OpenRequiringOplock && 3562 (Iosb.Status == STATUS_SUCCESS)) { 3563 3564 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Fcb), 3565 IrpContext->OriginatingIrp, 3566 (Fcb->UncleanCount + 1) ); 3567 } 3568 3569 // 3570 // If we've encountered a failure we need to leave. FsRtlCheckOplock 3571 // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated 3572 // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED 3573 // on the create call. That's an NT_SUCCESS code, so we need to keep 3574 // going. 3575 // 3576 3577 if ((Iosb.Status != STATUS_SUCCESS) && 3578 (Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) { 3579 3580 try_return( NOTHING ); 3581 } 3582 3583 // 3584 // Set the flag indicating if Fast I/O is possible 3585 // 3586 3587 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); 3588 3589 // 3590 // If the user wants write access access to the file make sure there 3591 // is not a process mapping this file as an image. Any attempt to 3592 // delete the file will be stopped in fileinfo.c 3593 // 3594 // If the user wants to delete on close, we must check at this 3595 // point though. 3596 // 3597 3598 if (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) { 3599 3600 Fcb->OpenCount += 1; 3601 DecrementFcbOpenCount = TRUE; 3602 3603 if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers, 3604 MmFlushForWrite )) { 3605 3606 Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE : 3607 STATUS_SHARING_VIOLATION; 3608 try_return( Iosb ); 3609 } 3610 } 3611 3612 // 3613 // If this is a non-cached open on a non-paging file, and there 3614 // are no open cached handles, but there is a still a data 3615 // section, attempt a flush and purge operation to avoid cache 3616 // coherency overhead later. We ignore any I/O errors from 3617 // the flush. 3618 // 3619 // We set the CREATE_IN_PROGRESS flag to prevent the Fcb from 3620 // going away out from underneath us. 3621 // 3622 3623 if (FlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) && 3624 (Fcb->UncleanCount == Fcb->NonCachedUncleanCount) && 3625 (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) && 3626 !FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) { 3627 3628 SetFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS); 3629 3630 CcFlushCache( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, NULL ); 3631 3632 // 3633 // Grab and release PagingIo to serialize ourselves with the lazy writer. 3634 // This will work to ensure that all IO has completed on the cached 3635 // data and we will succesfully tear away the cache section. 3636 // 3637 3638 ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE); 3639 ExReleaseResourceLite( Fcb->Header.PagingIoResource ); 3640 3641 CcPurgeCacheSection( &Fcb->NonPaged->SectionObjectPointers, 3642 NULL, 3643 0, 3644 FALSE ); 3645 3646 ClearFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS); 3647 } 3648 3649 // 3650 // Check if the user only wanted to open the file 3651 // 3652 3653 if ((CreateDisposition == FILE_OPEN) || 3654 (CreateDisposition == FILE_OPEN_IF)) { 3655 3656 DebugTrace(0, Dbg, "Doing open operation\n", 0); 3657 3658 // 3659 // If the caller has no Ea knowledge, we immediately check for 3660 // Need Ea's on the file. 3661 // 3662 3663 if (NoEaKnowledge && !FatIsFat32(Vcb)) { 3664 3665 ULONG NeedEaCount; 3666 3667 // 3668 // Get the dirent for the file and then check that the need 3669 // ea count is 0. 3670 // 3671 3672 FatGetDirentFromFcbOrDcb( IrpContext, 3673 Fcb, 3674 FALSE, 3675 &Dirent, 3676 &DirentBcb ); 3677 3678 FatGetNeedEaCount( IrpContext, 3679 Vcb, 3680 Dirent, 3681 &NeedEaCount ); 3682 3683 FatUnpinBcb( IrpContext, DirentBcb ); 3684 3685 if (NeedEaCount != 0) { 3686 3687 Iosb.Status = STATUS_ACCESS_DENIED; 3688 try_return( Iosb ); 3689 } 3690 } 3691 3692 // 3693 // Everything checks out okay, so setup the context and 3694 // section object pointers. 3695 // 3696 3697 FatSetFileObject( FileObject, 3698 UserFileOpen, 3699 Fcb, 3700 UnwindCcb = FatCreateCcb( IrpContext )); 3701 3702 FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers; 3703 3704 // 3705 // Fill in the information field, the status field is already 3706 // set. 3707 // 3708 3709 Iosb.Information = FILE_OPENED; 3710 3711 try_return( Iosb ); 3712 } 3713 3714 // 3715 // Check if we are to supersede/overwrite the file, we can wait for 3716 // any I/O at this point 3717 // 3718 3719 if ((CreateDisposition == FILE_SUPERSEDE) || 3720 (CreateDisposition == FILE_OVERWRITE) || 3721 (CreateDisposition == FILE_OVERWRITE_IF)) { 3722 3723 NTSTATUS OldStatus; 3724 3725 DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0); 3726 3727 // 3728 // We remember the previous status code because it may contain 3729 // information about the oplock status. 3730 // 3731 3732 OldStatus = Iosb.Status; 3733 3734 // 3735 // Determine the granted access for this operation now. 3736 // 3737 3738 if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) { 3739 3740 try_return( Iosb ); 3741 } 3742 3743 // 3744 // And overwrite the file. 3745 // 3746 3747 Iosb = FatSupersedeOrOverwriteFile( IrpContext, 3748 FileObject, 3749 Fcb, 3750 AllocationSize, 3751 EaBuffer, 3752 EaLength, 3753 FileAttributes, 3754 CreateDisposition, 3755 NoEaKnowledge ); 3756 3757 if (Iosb.Status == STATUS_SUCCESS) { 3758 3759 Iosb.Status = OldStatus; 3760 } 3761 3762 try_return( Iosb ); 3763 } 3764 3765 // 3766 // If we ever get here then the I/O system gave us some bad input 3767 // 3768 3769 #ifdef _MSC_VER 3770 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" ) 3771 #endif 3772 FatBugCheck( CreateDisposition, 0, 0 ); 3773 3774 try_exit: NOTHING; 3775 3776 // 3777 // Update the share access and counts if successful 3778 // 3779 3780 if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS(Iosb.Status)) { 3781 3782 // 3783 // Now, we may have added some access bits above to indicate the access 3784 // this caller would conflict with (as opposed to what they get) in order 3785 // to perform the overwrite/supersede. We need to make a call to that will 3786 // recalculate the bits in the fileobject to reflect the real access they 3787 // will get. 3788 // 3789 3790 if (AddedAccess) { 3791 3792 NTSTATUS Status; 3793 3794 ClearFlag( *DesiredAccess, AddedAccess ); 3795 3796 #ifdef _MSC_VER 3797 #pragma prefast( suppress:28931, "it needs to be there for debug assert" ); 3798 #endif 3799 Status = IoCheckShareAccess( *DesiredAccess, 3800 ShareAccess, 3801 FileObject, 3802 &Fcb->ShareAccess, 3803 TRUE ); 3804 3805 // 3806 // It must be the case that we are really asking for less access, so 3807 // any conflict must have been detected before this point. 3808 // 3809 3810 NT_ASSERT( Status == STATUS_SUCCESS ); 3811 3812 } else { 3813 3814 IoUpdateShareAccess( FileObject, &Fcb->ShareAccess ); 3815 } 3816 3817 UnwindShareAccess = TRUE; 3818 3819 // 3820 // In case this was set, clear it now. 3821 // 3822 3823 ClearFlag(Fcb->FcbState, FCB_STATE_DELAY_CLOSE); 3824 3825 Fcb->UncleanCount += 1; 3826 Fcb->OpenCount += 1; 3827 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { 3828 Fcb->NonCachedUncleanCount += 1; 3829 } 3830 Vcb->OpenFileCount += 1; 3831 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 3832 3833 { 3834 PCCB Ccb; 3835 3836 Ccb = (PCCB)FileObject->FsContext2; 3837 3838 // 3839 // Mark the DeleteOnClose bit if the operation was successful. 3840 // 3841 3842 if ( DeleteOnClose ) { 3843 3844 SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); 3845 } 3846 3847 // 3848 // Mark the OpenedByShortName bit if the operation was successful. 3849 // 3850 3851 if ( FileNameOpenedDos ) { 3852 3853 SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 3854 } 3855 3856 // 3857 // Mark the ManageVolumeAccess bit if the privilege is held. 3858 // 3859 3860 if (FatCheckManageVolumeAccess( IrpContext, 3861 IrpSp->Parameters.Create.SecurityContext->AccessState, 3862 (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? 3863 UserMode : 3864 IrpContext->OriginatingIrp->RequestorMode ))) { 3865 3866 SetFlag( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); 3867 } 3868 } 3869 3870 3871 } 3872 3873 } _SEH2_FINALLY { 3874 3875 DebugUnwind( FatOpenExistingFcb ); 3876 3877 // 3878 // Unpin the Dirent Bcb if pinned. 3879 // 3880 3881 FatUnpinBcb( IrpContext, DirentBcb ); 3882 3883 // 3884 // If this is an abnormal termination then undo our work 3885 // 3886 3887 if (_SEH2_AbnormalTermination()) { 3888 3889 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 3890 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Fcb->ShareAccess ); } 3891 } 3892 3893 if (DecrementFcbOpenCount) { 3894 3895 Fcb->OpenCount -= 1; 3896 3897 if (Fcb->OpenCount == 0) { 3898 if (ARGUMENT_PRESENT( FileObject )) { 3899 FileObject->SectionObjectPointer = NULL; 3900 } 3901 FatDeleteFcb( IrpContext, &Fcb ); 3902 FcbAcquired = FALSE; 3903 } 3904 } 3905 3906 if (FcbAcquired) { 3907 3908 FatReleaseFcb( IrpContext, Fcb ); 3909 } 3910 3911 DebugTrace(-1, Dbg, "FatOpenExistingFcb -> Iosb.Status = %08lx\n", Iosb.Status); 3912 } _SEH2_END; 3913 3914 return Iosb; 3915 } 3916 3917 // 3918 // Internal support routine 3919 // 3920 3921 _Requires_lock_held_(_Global_critical_region_) 3922 IO_STATUS_BLOCK 3923 FatOpenTargetDirectory ( 3924 _In_ PIRP_CONTEXT IrpContext, 3925 _Inout_ PFILE_OBJECT FileObject, 3926 _Inout_ PDCB Dcb, 3927 _In_ PACCESS_MASK DesiredAccess, 3928 _In_ USHORT ShareAccess, 3929 _In_ BOOLEAN DoesNameExist, 3930 _In_ BOOLEAN FileNameOpenedDos 3931 ) 3932 3933 /*++ 3934 3935 Routine Description: 3936 3937 This routine opens the target directory and replaces the name in the 3938 file object with the remaining name. 3939 3940 Arguments: 3941 3942 FileObject - Supplies the File object 3943 3944 Dcb - Supplies an already existing dcb that we are going to open 3945 3946 DesiredAccess - Supplies the desired access of the caller 3947 3948 ShareAccess - Supplies the share access of the caller 3949 3950 DoesNameExist - Indicates if the file name already exists in the 3951 target directory. 3952 3953 3954 Return Value: 3955 3956 IO_STATUS_BLOCK - Returns the completion status for the operation 3957 3958 --*/ 3959 3960 { 3961 IO_STATUS_BLOCK Iosb = {0}; 3962 3963 // 3964 // The following variables are for abnormal termination 3965 // 3966 3967 BOOLEAN UnwindShareAccess = FALSE; 3968 PCCB UnwindCcb = NULL; 3969 BOOLEAN DcbAcquired = FALSE; 3970 3971 PAGED_CODE(); 3972 3973 DebugTrace(+1, Dbg, "FatOpenTargetDirectory...\n", 0); 3974 3975 // 3976 // Get the Dcb exlcusive. This is important as cleanup does not 3977 // acquire the Vcb. 3978 // 3979 3980 (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb ); 3981 DcbAcquired = TRUE; 3982 3983 _SEH2_TRY { 3984 3985 ULONG i; 3986 3987 // 3988 // If the Dcb is already opened by someone then we need 3989 // to check the share access 3990 // 3991 3992 if (Dcb->OpenCount > 0) { 3993 3994 if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess, 3995 ShareAccess, 3996 FileObject, 3997 &Dcb->ShareAccess, 3998 TRUE ))) { 3999 4000 try_return( Iosb ); 4001 } 4002 4003 } else { 4004 4005 IoSetShareAccess( *DesiredAccess, 4006 ShareAccess, 4007 FileObject, 4008 &Dcb->ShareAccess ); 4009 } 4010 4011 UnwindShareAccess = TRUE; 4012 4013 // 4014 // Setup the context and section object pointers, and update 4015 // our reference counts 4016 // 4017 4018 FatSetFileObject( FileObject, 4019 UserDirectoryOpen, 4020 Dcb, 4021 UnwindCcb = FatCreateCcb( IrpContext )); 4022 4023 Dcb->UncleanCount += 1; 4024 Dcb->OpenCount += 1; 4025 Dcb->Vcb->OpenFileCount += 1; 4026 if (IsFileObjectReadOnly(FileObject)) { Dcb->Vcb->ReadOnlyCount += 1; } 4027 4028 // 4029 // Update the name in the file object, by definition the remaining 4030 // part must be shorter than the original file name so we'll just 4031 // overwrite the file name. 4032 // 4033 4034 i = FileObject->FileName.Length/sizeof(WCHAR) - 1; 4035 4036 // 4037 // Get rid of a trailing backslash 4038 // 4039 4040 if (FileObject->FileName.Buffer[i] == L'\\') { 4041 4042 NT_ASSERT(i != 0); 4043 4044 FileObject->FileName.Length -= sizeof(WCHAR); 4045 i -= 1; 4046 } 4047 4048 // 4049 // Find the first non-backslash character. i will be its index. 4050 // 4051 4052 while (TRUE) { 4053 4054 if (FileObject->FileName.Buffer[i] == L'\\') { 4055 4056 i += 1; 4057 break; 4058 } 4059 4060 if (i == 0) { 4061 break; 4062 } 4063 4064 i--; 4065 } 4066 4067 if (i) { 4068 4069 FileObject->FileName.Length -= (USHORT)(i * sizeof(WCHAR)); 4070 4071 RtlMoveMemory( &FileObject->FileName.Buffer[0], 4072 &FileObject->FileName.Buffer[i], 4073 FileObject->FileName.Length ); 4074 } 4075 4076 // 4077 // And set our status to success 4078 // 4079 4080 Iosb.Status = STATUS_SUCCESS; 4081 Iosb.Information = (DoesNameExist ? FILE_EXISTS : FILE_DOES_NOT_EXIST); 4082 4083 if ( ( NT_SUCCESS(Iosb.Status) ) && ( DoesNameExist ) ) { 4084 PCCB Ccb; 4085 4086 Ccb = (PCCB)FileObject->FsContext2; 4087 4088 // 4089 // Mark the OpenedByShortName bit if the operation was successful. 4090 // 4091 4092 if ( FileNameOpenedDos ) { 4093 4094 SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 4095 } 4096 } 4097 4098 try_exit: NOTHING; 4099 } _SEH2_FINALLY { 4100 4101 DebugUnwind( FatOpenTargetDirectory ); 4102 4103 // 4104 // If this is an abnormal termination then undo our work 4105 // 4106 4107 if (_SEH2_AbnormalTermination()) { 4108 4109 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 4110 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); } 4111 } 4112 4113 if (DcbAcquired) { 4114 4115 FatReleaseFcb( IrpContext, Dcb ); 4116 } 4117 4118 DebugTrace(-1, Dbg, "FatOpenTargetDirectory -> Iosb.Status = %08lx\n", Iosb.Status); 4119 } _SEH2_END; 4120 4121 return Iosb; 4122 } 4123 4124 4125 4126 // 4127 // Internal support routine 4128 // 4129 _Success_(return.Status == STATUS_SUCCESS) 4130 _Requires_lock_held_(_Global_critical_region_) 4131 IO_STATUS_BLOCK 4132 #ifdef _MSC_VER 4133 #pragma warning(suppress:6101) // bug in PREFast means the _Success_ annotation is not correctly applied 4134 #endif 4135 FatOpenExistingDirectory ( 4136 _In_ PIRP_CONTEXT IrpContext, 4137 _In_ PIO_STACK_LOCATION IrpSp, 4138 _Inout_ PFILE_OBJECT FileObject, 4139 _Inout_ PVCB Vcb, 4140 _Outptr_result_maybenull_ PDCB *Dcb, 4141 _In_ PDCB ParentDcb, 4142 _In_ PDIRENT Dirent, 4143 _In_ ULONG LfnByteOffset, 4144 _In_ ULONG DirentByteOffset, 4145 _In_ PUNICODE_STRING Lfn, 4146 _In_ PACCESS_MASK DesiredAccess, 4147 _In_ USHORT ShareAccess, 4148 _In_ ULONG CreateDisposition, 4149 _In_ BOOLEAN NoEaKnowledge, 4150 _In_ BOOLEAN DeleteOnClose, 4151 _In_ BOOLEAN FileNameOpenedDos, 4152 _In_ BOOLEAN OpenRequiringOplock 4153 ) 4154 4155 /*++ 4156 4157 Routine Description: 4158 4159 This routine opens the specified directory. The directory has not 4160 previously been opened. 4161 4162 Arguments: 4163 4164 FileObject - Supplies the File object 4165 4166 Vcb - Supplies the Vcb denoting the volume containing the dcb 4167 4168 Dcb - Returns the newly-created DCB for the file. 4169 4170 ParentDcb - Supplies the parent directory containing the subdirectory 4171 to be opened 4172 4173 DirectoryName - Supplies the file name of the directory being opened. 4174 4175 Dirent - Supplies the dirent for the directory being opened 4176 4177 LfnByteOffset - Tells where the Lfn begins. If there is no Lfn 4178 this field is the same as DirentByteOffset. 4179 4180 DirentByteOffset - Supplies the Vbo of the dirent within its parent 4181 directory 4182 4183 Lfn - May supply a long name for the file. 4184 4185 DesiredAccess - Supplies the desired access of the caller 4186 4187 ShareAccess - Supplies the share access of the caller 4188 4189 CreateDisposition - Supplies the create disposition for this operation 4190 4191 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 4192 open if the file has NeedEa's. 4193 4194 DeleteOnClose - The caller wants the file gone when the handle is closed 4195 4196 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option. 4197 4198 Return Value: 4199 4200 IO_STATUS_BLOCK - Returns the completion status for the operation 4201 4202 --*/ 4203 4204 { 4205 IO_STATUS_BLOCK Iosb = {0}; 4206 4207 // 4208 // The following variables are for abnormal termination 4209 // 4210 4211 PDCB UnwindDcb = NULL; 4212 PCCB UnwindCcb = NULL; 4213 4214 BOOLEAN CountsIncremented = FALSE; 4215 4216 UNREFERENCED_PARAMETER( DeleteOnClose ); 4217 #if (NTDDI_VERSION <= NTDDI_WIN7) 4218 UNREFERENCED_PARAMETER( OpenRequiringOplock ); 4219 #endif 4220 UNREFERENCED_PARAMETER( IrpSp ); 4221 4222 PAGED_CODE(); 4223 4224 DebugTrace(+1, Dbg, "FatOpenExistingDirectory...\n", 0); 4225 4226 _SEH2_TRY { 4227 4228 // 4229 // If the caller has no Ea knowledge, we immediately check for 4230 // Need Ea's on the file. 4231 // 4232 4233 if (NoEaKnowledge && !FatIsFat32(Vcb)) { 4234 4235 ULONG NeedEaCount; 4236 4237 FatGetNeedEaCount( IrpContext, 4238 Vcb, 4239 Dirent, 4240 &NeedEaCount ); 4241 4242 if (NeedEaCount != 0) { 4243 4244 Iosb.Status = STATUS_ACCESS_DENIED; 4245 try_return( Iosb ); 4246 } 4247 } 4248 4249 // 4250 // Check the create disposition and desired access 4251 // 4252 4253 if ((CreateDisposition != FILE_OPEN) && 4254 (CreateDisposition != FILE_OPEN_IF)) { 4255 4256 Iosb.Status = STATUS_OBJECT_NAME_COLLISION; 4257 try_return( Iosb ); 4258 } 4259 4260 if (!FatCheckFileAccess( IrpContext, 4261 Dirent->Attributes, 4262 DesiredAccess)) { 4263 4264 Iosb.Status = STATUS_ACCESS_DENIED; 4265 try_return( Iosb ); 4266 } 4267 4268 // 4269 // Create a new dcb for the directory 4270 // 4271 4272 *Dcb = UnwindDcb = FatCreateDcb( IrpContext, 4273 Vcb, 4274 ParentDcb, 4275 LfnByteOffset, 4276 DirentByteOffset, 4277 Dirent, 4278 Lfn ); 4279 4280 #if (NTDDI_VERSION >= NTDDI_WIN8) 4281 4282 // 4283 // Let's make sure that if the caller provided an oplock key that it 4284 // gets stored in the file object. 4285 // 4286 4287 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(*Dcb), 4288 IrpContext->OriginatingIrp, 4289 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 4290 NULL, 4291 NULL, 4292 NULL ); 4293 4294 // 4295 // If the caller wants atomic create-with-oplock semantics, tell 4296 // the oplock package. We haven't incremented the Fcb's UncleanCount 4297 // for this create yet, so add that in on the call. 4298 // 4299 4300 if (OpenRequiringOplock && 4301 (Iosb.Status == STATUS_SUCCESS)) { 4302 4303 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(*Dcb), 4304 IrpContext->OriginatingIrp, 4305 ((*Dcb)->UncleanCount + 1) ); 4306 } 4307 4308 // 4309 // Get out if either of the above calls failed. Raise to trigger 4310 // cleanup of the new Dcb. 4311 // 4312 4313 if (Iosb.Status != STATUS_SUCCESS) { 4314 4315 NT_ASSERT( Iosb.Status != STATUS_PENDING ); 4316 4317 FatRaiseStatus( IrpContext, Iosb.Status ); 4318 } 4319 #endif 4320 4321 // 4322 // Setup our share access 4323 // 4324 4325 IoSetShareAccess( *DesiredAccess, 4326 ShareAccess, 4327 FileObject, 4328 &(*Dcb)->ShareAccess ); 4329 4330 // 4331 // Setup the context and section object pointers, and update 4332 // our reference counts 4333 // 4334 4335 FatSetFileObject( FileObject, 4336 UserDirectoryOpen, 4337 (*Dcb), 4338 UnwindCcb = FatCreateCcb( IrpContext )); 4339 4340 (*Dcb)->UncleanCount += 1; 4341 (*Dcb)->OpenCount += 1; 4342 Vcb->OpenFileCount += 1; 4343 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 4344 4345 CountsIncremented = TRUE; 4346 4347 4348 // 4349 // And set our status to success 4350 // 4351 4352 Iosb.Status = STATUS_SUCCESS; 4353 Iosb.Information = FILE_OPENED; 4354 4355 if ( NT_SUCCESS(Iosb.Status) ) { 4356 PCCB Ccb; 4357 4358 Ccb = (PCCB)FileObject->FsContext2; 4359 4360 // 4361 // Mark the OpenedByShortName bit if the operation was successful. 4362 // 4363 4364 if ( FileNameOpenedDos ) { 4365 4366 SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 4367 } 4368 } 4369 4370 try_exit: NOTHING; 4371 } _SEH2_FINALLY { 4372 4373 DebugUnwind( FatOpenExistingDirectory ); 4374 4375 // 4376 // If this is an abnormal termination then undo our work 4377 // 4378 4379 if (_SEH2_AbnormalTermination()) { 4380 4381 if (CountsIncremented) { 4382 4383 (*Dcb)->UncleanCount -= 1; 4384 (*Dcb)->OpenCount -= 1; 4385 Vcb->OpenFileCount -= 1; 4386 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } 4387 } 4388 4389 if (UnwindDcb != NULL) { 4390 if (ARGUMENT_PRESENT( FileObject )) { 4391 FileObject->SectionObjectPointer = NULL; 4392 } 4393 FatDeleteFcb( IrpContext, &UnwindDcb ); 4394 *Dcb = NULL; 4395 } 4396 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 4397 } 4398 4399 DebugTrace(-1, Dbg, "FatOpenExistingDirectory -> Iosb.Status = %08lx\n", Iosb.Status); 4400 } _SEH2_END; 4401 4402 return Iosb; 4403 } 4404 4405 4406 // 4407 // Internal support routine 4408 // 4409 4410 _Requires_lock_held_(_Global_critical_region_) 4411 IO_STATUS_BLOCK 4412 FatOpenExistingFile ( 4413 _In_ PIRP_CONTEXT IrpContext, 4414 _Inout_ PFILE_OBJECT FileObject, 4415 _Inout_ PVCB Vcb, 4416 _Outptr_result_maybenull_ PFCB *Fcb, 4417 _In_ PDCB ParentDcb, 4418 _In_ PDIRENT Dirent, 4419 _In_ ULONG LfnByteOffset, 4420 _In_ ULONG DirentByteOffset, 4421 _In_ PUNICODE_STRING Lfn, 4422 _In_ PUNICODE_STRING OrigLfn, 4423 _In_ PACCESS_MASK DesiredAccess, 4424 _In_ USHORT ShareAccess, 4425 _In_ ULONG AllocationSize, 4426 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 4427 _In_ ULONG EaLength, 4428 _In_ USHORT FileAttributes, 4429 _In_ ULONG CreateDisposition, 4430 _In_ BOOLEAN IsPagingFile, 4431 _In_ BOOLEAN NoEaKnowledge, 4432 _In_ BOOLEAN DeleteOnClose, 4433 _In_ BOOLEAN OpenRequiringOplock, 4434 _In_ BOOLEAN FileNameOpenedDos 4435 ) 4436 4437 /*++ 4438 4439 Routine Description: 4440 4441 This routine opens the specified file. The file has not previously 4442 been opened. 4443 4444 Arguments: 4445 4446 FileObject - Supplies the File object 4447 4448 Vcb - Supplies the Vcb denoting the volume containing the file 4449 4450 Fcb - Returns the newly-created FCB for the file. 4451 4452 ParentDcb - Supplies the parent directory containing the file to be 4453 opened 4454 4455 Dirent - Supplies the dirent for the file being opened 4456 4457 LfnByteOffset - Tells where the Lfn begins. If there is no Lfn 4458 this field is the same as DirentByteOffset. 4459 4460 DirentByteOffset - Supplies the Vbo of the dirent within its parent 4461 directory 4462 4463 Lfn - May supply a long name for the file. 4464 4465 DesiredAccess - Supplies the desired access of the caller 4466 4467 ShareAccess - Supplies the share access of the caller 4468 4469 AllocationSize - Supplies the initial allocation if the file is being 4470 superseded, overwritten, or created. 4471 4472 EaBuffer - Supplies the Ea set if the file is being superseded, 4473 overwritten, or created. 4474 4475 EaLength - Supplies the size, in byte, of the EaBuffer 4476 4477 FileAttributes - Supplies file attributes to use if the file is being 4478 superseded, overwritten, or created 4479 4480 CreateDisposition - Supplies the create disposition for this operation 4481 4482 IsPagingFile - Indicates if this is the paging file being opened. 4483 4484 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 4485 open if the file has NeedEa's. 4486 4487 DeleteOnClose - The caller wants the file gone when the handle is closed 4488 4489 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option. 4490 4491 FileNameOpenedDos - The caller opened this file by hitting the 8.3 side 4492 of the Lfn/8.3 pair 4493 4494 Return Value: 4495 4496 IO_STATUS_BLOCK - Returns the completion status for the operation 4497 4498 --*/ 4499 4500 { 4501 IO_STATUS_BLOCK Iosb = {0}; 4502 4503 ACCESS_MASK AddedAccess = 0; 4504 4505 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp ); 4506 4507 // 4508 // The following variables are for abnormal termination 4509 // 4510 4511 PFCB UnwindFcb = NULL; 4512 PCCB UnwindCcb = NULL; 4513 BOOLEAN CountsIncremented = FALSE; 4514 4515 4516 #if (NTDDI_VERSION < NTDDI_WIN7) 4517 UNREFERENCED_PARAMETER( OpenRequiringOplock ); 4518 #endif 4519 4520 PAGED_CODE(); 4521 4522 DebugTrace(+1, Dbg, "FatOpenExistingFile...\n", 0); 4523 4524 _SEH2_TRY { 4525 4526 // 4527 // Check if the user wanted to create the file or if access is 4528 // denied 4529 // 4530 4531 if (CreateDisposition == FILE_CREATE) { 4532 Iosb.Status = STATUS_OBJECT_NAME_COLLISION; 4533 try_return( Iosb ); 4534 4535 } else if ((CreateDisposition == FILE_SUPERSEDE) && !IsPagingFile) { 4536 4537 SetFlag( AddedAccess, 4538 DELETE & ~(*DesiredAccess) ); 4539 4540 *DesiredAccess |= DELETE; 4541 4542 } else if (((CreateDisposition == FILE_OVERWRITE) || 4543 (CreateDisposition == FILE_OVERWRITE_IF)) && !IsPagingFile) { 4544 4545 SetFlag( AddedAccess, 4546 (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) ); 4547 4548 *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES; 4549 } 4550 4551 if (!FatCheckFileAccess( IrpContext, 4552 Dirent->Attributes, 4553 DesiredAccess)) { 4554 4555 Iosb.Status = STATUS_ACCESS_DENIED; 4556 try_return( Iosb ); 4557 } 4558 4559 4560 // 4561 // Check for trying to delete a read only file. 4562 // 4563 4564 if (DeleteOnClose && 4565 FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY )) { 4566 4567 Iosb.Status = STATUS_CANNOT_DELETE; 4568 try_return( Iosb ); 4569 } 4570 4571 // 4572 // IF we are asked to do an overwrite or supersede operation then 4573 // deny access for files where the file attributes for system and 4574 // hidden do not match 4575 // 4576 4577 if ((CreateDisposition == FILE_SUPERSEDE) || 4578 (CreateDisposition == FILE_OVERWRITE) || 4579 (CreateDisposition == FILE_OVERWRITE_IF)) { 4580 4581 BOOLEAN Hidden; 4582 BOOLEAN System; 4583 4584 Hidden = BooleanFlagOn(Dirent->Attributes, FAT_DIRENT_ATTR_HIDDEN ); 4585 System = BooleanFlagOn(Dirent->Attributes, FAT_DIRENT_ATTR_SYSTEM ); 4586 4587 if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) || 4588 (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) { 4589 4590 DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0); 4591 4592 if ( !IsPagingFile ) { 4593 4594 Iosb.Status = STATUS_ACCESS_DENIED; 4595 try_return( Iosb ); 4596 } 4597 } 4598 4599 // 4600 // If this media is write protected, don't even try the create. 4601 // 4602 4603 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) { 4604 4605 // 4606 // Set the real device for the pop-up info, and set the verify 4607 // bit in the device object, so that we will force a verify 4608 // in case the user put the correct media back in. 4609 // 4610 4611 4612 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 4613 Vcb->Vpb->RealDevice ); 4614 4615 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 4616 4617 FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); 4618 } 4619 } 4620 4621 // 4622 // Create a new Fcb for the file, and set the file size in 4623 // the fcb. 4624 // 4625 4626 *Fcb = UnwindFcb = FatCreateFcb( IrpContext, 4627 Vcb, 4628 ParentDcb, 4629 LfnByteOffset, 4630 DirentByteOffset, 4631 Dirent, 4632 Lfn, 4633 OrigLfn, 4634 IsPagingFile, 4635 FALSE ); 4636 4637 4638 (*Fcb)->Header.ValidDataLength.LowPart = (*Fcb)->Header.FileSize.LowPart; 4639 4640 // 4641 // If this is a paging file, lookup the allocation size so that 4642 // the Mcb is always valid 4643 // 4644 4645 if (IsPagingFile) { 4646 4647 FatLookupFileAllocationSize( IrpContext, *Fcb ); 4648 } 4649 4650 #if (NTDDI_VERSION >= NTDDI_WIN7) 4651 4652 // 4653 // Let's make sure that if the caller provided an oplock key that it 4654 // gets stored in the file object. 4655 // 4656 4657 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(*Fcb), 4658 IrpContext->OriginatingIrp, 4659 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 4660 NULL, 4661 NULL, 4662 NULL ); 4663 4664 // 4665 // If the caller wants atomic create-with-oplock semantics, tell 4666 // the oplock package. We haven't incremented the Fcb's UncleanCount 4667 // for this create yet, so add that in on the call. 4668 // 4669 4670 if (OpenRequiringOplock && 4671 (Iosb.Status == STATUS_SUCCESS)) { 4672 4673 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(*Fcb), 4674 IrpContext->OriginatingIrp, 4675 ((*Fcb)->UncleanCount + 1) ); 4676 } 4677 4678 // 4679 // Get out if either of the above calls failed. Raise to trigger 4680 // cleanup of the new Fcb. 4681 // 4682 4683 if (Iosb.Status != STATUS_SUCCESS) { 4684 4685 NT_ASSERT( Iosb.Status != STATUS_PENDING ); 4686 4687 FatRaiseStatus( IrpContext, Iosb.Status ); 4688 } 4689 #endif 4690 4691 // 4692 // Now case on whether we are to simply open, supersede, or 4693 // overwrite the file. 4694 // 4695 4696 switch (CreateDisposition) { 4697 4698 case FILE_OPEN: 4699 case FILE_OPEN_IF: 4700 4701 DebugTrace(0, Dbg, "Doing only an open operation\n", 0); 4702 4703 // 4704 // If the caller has no Ea knowledge, we immediately check for 4705 // Need Ea's on the file. 4706 // 4707 4708 if (NoEaKnowledge && !FatIsFat32(Vcb)) { 4709 4710 ULONG NeedEaCount; 4711 4712 FatGetNeedEaCount( IrpContext, 4713 Vcb, 4714 Dirent, 4715 &NeedEaCount ); 4716 4717 if (NeedEaCount != 0) { 4718 4719 FatRaiseStatus( IrpContext, STATUS_ACCESS_DENIED ); 4720 } 4721 } 4722 4723 // 4724 // Setup the context and section object pointers. 4725 // 4726 4727 FatSetFileObject( FileObject, 4728 UserFileOpen, 4729 *Fcb, 4730 UnwindCcb = FatCreateCcb( IrpContext )); 4731 4732 FileObject->SectionObjectPointer = &(*Fcb)->NonPaged->SectionObjectPointers; 4733 4734 Iosb.Status = STATUS_SUCCESS; 4735 Iosb.Information = FILE_OPENED; 4736 break; 4737 4738 case FILE_SUPERSEDE: 4739 case FILE_OVERWRITE: 4740 case FILE_OVERWRITE_IF: 4741 4742 DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0); 4743 4744 // 4745 // Determine the granted access for this operation now. 4746 // 4747 4748 if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) { 4749 4750 try_return( Iosb ); 4751 } 4752 4753 Iosb = FatSupersedeOrOverwriteFile( IrpContext, 4754 FileObject, 4755 *Fcb, 4756 AllocationSize, 4757 EaBuffer, 4758 EaLength, 4759 FileAttributes, 4760 CreateDisposition, 4761 NoEaKnowledge ); 4762 break; 4763 4764 default: 4765 4766 DebugTrace(0, Dbg, "Illegal Create Disposition\n", 0); 4767 4768 #ifdef _MSC_VER 4769 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" ) 4770 #endif 4771 FatBugCheck( CreateDisposition, 0, 0 ); 4772 break; 4773 } 4774 4775 try_exit: NOTHING; 4776 4777 // 4778 // Setup our share access and counts if things were successful. 4779 // 4780 4781 if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS( Iosb.Status )) { 4782 4783 // 4784 // Remove any virtual access the caller needed to check against, but will 4785 // not really receive. Overwrite/supersede is a bit of a special case. 4786 // 4787 4788 ClearFlag( *DesiredAccess, AddedAccess ); 4789 4790 IoSetShareAccess( *DesiredAccess, 4791 ShareAccess, 4792 FileObject, 4793 &(*Fcb)->ShareAccess ); 4794 4795 (*Fcb)->UncleanCount += 1; 4796 (*Fcb)->OpenCount += 1; 4797 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { 4798 (*Fcb)->NonCachedUncleanCount += 1; 4799 } 4800 Vcb->OpenFileCount += 1; 4801 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 4802 4803 CountsIncremented = TRUE; 4804 } 4805 4806 { 4807 PCCB Ccb; 4808 4809 Ccb = (PCCB)FileObject->FsContext2; 4810 4811 if ( NT_SUCCESS(Iosb.Status) ) { 4812 4813 // 4814 // Mark the DeleteOnClose bit if the operation was successful. 4815 // 4816 4817 if ( DeleteOnClose ) { 4818 4819 SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); 4820 } 4821 4822 // 4823 // Mark the OpenedByShortName bit if the operation was successful. 4824 // 4825 4826 if ( FileNameOpenedDos ) { 4827 4828 SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 4829 } 4830 4831 // 4832 // Mark the ManageVolumeAccess bit if the privilege is held. 4833 // 4834 4835 if (FatCheckManageVolumeAccess( IrpContext, 4836 IrpSp->Parameters.Create.SecurityContext->AccessState, 4837 (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? 4838 UserMode : 4839 IrpContext->OriginatingIrp->RequestorMode ))) { 4840 4841 SetFlag( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); 4842 } 4843 4844 } 4845 } 4846 4847 4848 } _SEH2_FINALLY { 4849 4850 DebugUnwind( FatOpenExistingFile ); 4851 4852 // 4853 // If this is an abnormal termination then undo our work 4854 // 4855 4856 if (_SEH2_AbnormalTermination()) { 4857 4858 if (CountsIncremented) { 4859 (*Fcb)->UncleanCount -= 1; 4860 (*Fcb)->OpenCount -= 1; 4861 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { 4862 (*Fcb)->NonCachedUncleanCount -= 1; 4863 } 4864 Vcb->OpenFileCount -= 1; 4865 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } 4866 } 4867 4868 if (UnwindFcb != NULL) { 4869 if (ARGUMENT_PRESENT( FileObject )) { 4870 FileObject->SectionObjectPointer = NULL; 4871 } 4872 FatDeleteFcb( IrpContext, &UnwindFcb ); 4873 *Fcb = NULL; 4874 } 4875 4876 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 4877 } 4878 4879 DebugTrace(-1, Dbg, "FatOpenExistingFile -> Iosb.Status = %08lx\n", Iosb.Status); 4880 } _SEH2_END; 4881 4882 return Iosb; 4883 } 4884 4885 4886 // 4887 // Internal support routine 4888 // 4889 4890 _Requires_lock_held_(_Global_critical_region_) 4891 IO_STATUS_BLOCK 4892 FatCreateNewDirectory ( 4893 _In_ PIRP_CONTEXT IrpContext, 4894 _In_ PIO_STACK_LOCATION IrpSp, 4895 _Inout_ PFILE_OBJECT FileObject, 4896 _Inout_ PVCB Vcb, 4897 _Inout_ PDCB ParentDcb, 4898 _In_ POEM_STRING OemName, 4899 _In_ PUNICODE_STRING UnicodeName, 4900 _In_ PACCESS_MASK DesiredAccess, 4901 _In_ USHORT ShareAccess, 4902 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 4903 _In_ ULONG EaLength, 4904 _In_ USHORT FileAttributes, 4905 _In_ BOOLEAN NoEaKnowledge, 4906 _In_ BOOLEAN DeleteOnClose, 4907 _In_ BOOLEAN OpenRequiringOplock 4908 ) 4909 4910 /*++ 4911 4912 Routine Description: 4913 4914 This routine creates a new directory. The directory has already been 4915 verified not to exist yet. 4916 4917 Arguments: 4918 4919 FileObject - Supplies the file object for the newly created directory 4920 4921 Vcb - Supplies the Vcb denote the volume to contain the new directory 4922 4923 ParentDcb - Supplies the parent directory containg the newly created 4924 directory 4925 4926 OemName - Supplies the Oem name for the newly created directory. It may 4927 or maynot be 8.3 complient, but will be upcased. 4928 4929 UnicodeName - Supplies the Unicode name for the newly created directory. 4930 It may or maynot be 8.3 complient. This name contains the original 4931 case information. 4932 4933 DesiredAccess - Supplies the desired access of the caller 4934 4935 ShareAccess - Supplies the shared access of the caller 4936 4937 EaBuffer - Supplies the Ea set for the newly created directory 4938 4939 EaLength - Supplies the length, in bytes, of EaBuffer 4940 4941 FileAttributes - Supplies the file attributes for the newly created 4942 directory. 4943 4944 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 4945 open if the file has NeedEa's. 4946 4947 DeleteOnClose - The caller wants the file gone when the handle is closed 4948 4949 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option. 4950 4951 Return Value: 4952 4953 IO_STATUS_BLOCK - Returns the completion status for the operation 4954 4955 --*/ 4956 4957 { 4958 IO_STATUS_BLOCK Iosb; 4959 4960 PDCB Dcb = NULL; 4961 PCCB Ccb = NULL; 4962 4963 PDIRENT Dirent = NULL; 4964 PBCB DirentBcb = NULL; 4965 ULONG DirentsNeeded; 4966 ULONG DirentByteOffset; 4967 4968 PDIRENT ShortDirent; 4969 ULONG ShortDirentByteOffset; 4970 4971 USHORT EaHandle; 4972 4973 BOOLEAN AllLowerComponent; 4974 BOOLEAN AllLowerExtension; 4975 BOOLEAN CreateLfn; 4976 4977 ULONG BytesInFirstPage = 0; 4978 ULONG DirentsInFirstPage = 0; 4979 PDIRENT FirstPageDirent = 0; 4980 4981 PBCB SecondPageBcb = NULL; 4982 ULONG SecondPageOffset; 4983 PDIRENT SecondPageDirent = NULL; 4984 4985 BOOLEAN DirentFromPool = FALSE; 4986 4987 4988 OEM_STRING ShortName; 4989 UCHAR ShortNameBuffer[12]; 4990 4991 #if (NTDDI_VERSION <= NTDDI_WIN7) 4992 UNREFERENCED_PARAMETER( OpenRequiringOplock ); 4993 #endif 4994 4995 UNREFERENCED_PARAMETER( IrpSp ); 4996 4997 PAGED_CODE(); 4998 4999 DebugTrace(+1, Dbg, "FatCreateNewDirectory...\n", 0); 5000 5001 ShortName.Length = 0; 5002 ShortName.MaximumLength = 12; 5003 ShortName.Buffer = (PCHAR)&ShortNameBuffer[0]; 5004 5005 EaHandle = 0; 5006 5007 // 5008 // We fail this operation if the caller doesn't understand Ea's. 5009 // 5010 5011 if (NoEaKnowledge 5012 && EaLength > 0) { 5013 5014 Iosb.Status = STATUS_ACCESS_DENIED; 5015 5016 DebugTrace(-1, Dbg, "FatCreateNewDirectory -> Iosb.Status = %08lx\n", Iosb.Status); 5017 return Iosb; 5018 } 5019 5020 // 5021 // DeleteOnClose and ReadOnly are not compatible. 5022 // 5023 5024 if (DeleteOnClose && FlagOn(FileAttributes, FAT_DIRENT_ATTR_READ_ONLY)) { 5025 5026 Iosb.Status = STATUS_CANNOT_DELETE; 5027 return Iosb; 5028 } 5029 5030 // Now get the names that we will be using. 5031 // 5032 5033 FatSelectNames( IrpContext, 5034 ParentDcb, 5035 OemName, 5036 UnicodeName, 5037 &ShortName, 5038 NULL, 5039 &AllLowerComponent, 5040 &AllLowerExtension, 5041 &CreateLfn ); 5042 5043 // 5044 // If we are not in Chicago mode, ignore the magic bits. 5045 // 5046 5047 if (!FatData.ChicagoMode) { 5048 5049 AllLowerComponent = FALSE; 5050 AllLowerExtension = FALSE; 5051 CreateLfn = FALSE; 5052 } 5053 5054 // 5055 // Create/allocate a new dirent 5056 // 5057 5058 DirentsNeeded = CreateLfn ? FAT_LFN_DIRENTS_NEEDED(UnicodeName) + 1 : 1; 5059 5060 DirentByteOffset = FatCreateNewDirent( IrpContext, 5061 ParentDcb, 5062 DirentsNeeded, 5063 FALSE ); 5064 _SEH2_TRY { 5065 5066 FatPrepareWriteDirectoryFile( IrpContext, 5067 ParentDcb, 5068 DirentByteOffset, 5069 sizeof(DIRENT), 5070 &DirentBcb, 5071 #ifndef __REACTOS__ 5072 &Dirent, 5073 #else 5074 (PVOID *)&Dirent, 5075 #endif 5076 FALSE, 5077 TRUE, 5078 &Iosb.Status ); 5079 5080 NT_ASSERT( NT_SUCCESS( Iosb.Status ) && DirentBcb && Dirent ); 5081 5082 // 5083 // Deal with the special case of an LFN + Dirent structure crossing 5084 // a page boundry. 5085 // 5086 5087 if ((DirentByteOffset / PAGE_SIZE) != 5088 ((DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT)) / PAGE_SIZE)) { 5089 5090 SecondPageBcb; 5091 SecondPageOffset; 5092 SecondPageDirent; 5093 5094 SecondPageOffset = (DirentByteOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE; 5095 5096 BytesInFirstPage = SecondPageOffset - DirentByteOffset; 5097 5098 DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT); 5099 5100 FatPrepareWriteDirectoryFile( IrpContext, 5101 ParentDcb, 5102 SecondPageOffset, 5103 sizeof(DIRENT), 5104 &SecondPageBcb, 5105 #ifndef __REACTOS__ 5106 &SecondPageDirent, 5107 #else 5108 (PVOID *)&SecondPageDirent, 5109 #endif 5110 FALSE, 5111 TRUE, 5112 &Iosb.Status ); 5113 5114 NT_ASSERT( NT_SUCCESS( Iosb.Status ) && SecondPageBcb && SecondPageDirent ); 5115 5116 FirstPageDirent = Dirent; 5117 5118 Dirent = FsRtlAllocatePoolWithTag( PagedPool, 5119 DirentsNeeded * sizeof(DIRENT), 5120 TAG_DIRENT ); 5121 5122 DirentFromPool = TRUE; 5123 } 5124 5125 // 5126 // Bump up Dirent and DirentByteOffset 5127 // 5128 5129 ShortDirent = Dirent + DirentsNeeded - 1; 5130 ShortDirentByteOffset = DirentByteOffset + 5131 (DirentsNeeded - 1) * sizeof(DIRENT); 5132 5133 NT_ASSERT( NT_SUCCESS( Iosb.Status )); 5134 5135 5136 // 5137 // Fill in the fields of the dirent. 5138 // 5139 5140 FatConstructDirent( IrpContext, 5141 ShortDirent, 5142 &ShortName, 5143 AllLowerComponent, 5144 AllLowerExtension, 5145 CreateLfn ? UnicodeName : NULL, 5146 FileAttributes | FAT_DIRENT_ATTR_DIRECTORY, 5147 TRUE, 5148 NULL ); 5149 5150 // 5151 // If the dirent crossed pages, we have to do some real gross stuff. 5152 // 5153 5154 if (DirentFromPool) { 5155 5156 RtlCopyMemory( FirstPageDirent, Dirent, BytesInFirstPage ); 5157 5158 RtlCopyMemory( SecondPageDirent, 5159 Dirent + DirentsInFirstPage, 5160 DirentsNeeded*sizeof(DIRENT) - BytesInFirstPage ); 5161 5162 ShortDirent = SecondPageDirent + (DirentsNeeded - DirentsInFirstPage) - 1; 5163 } 5164 5165 // 5166 // Create a new dcb for the directory. 5167 // 5168 5169 Dcb = FatCreateDcb( IrpContext, 5170 Vcb, 5171 ParentDcb, 5172 DirentByteOffset, 5173 ShortDirentByteOffset, 5174 ShortDirent, 5175 CreateLfn ? UnicodeName : NULL ); 5176 5177 #if (NTDDI_VERSION >= NTDDI_WIN8) 5178 // 5179 // The next three FsRtl calls are for oplock work. We deliberately 5180 // do these here so that if either call fails we will be able to 5181 // clean up without adding a bunch of code to unwind counts, fix 5182 // the file object, etc. 5183 // 5184 5185 // 5186 // Let's make sure that if the caller provided an oplock key that it 5187 // gets stored in the file object. 5188 // 5189 5190 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Dcb), 5191 IrpContext->OriginatingIrp, 5192 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 5193 NULL, 5194 NULL, 5195 NULL ); 5196 5197 // 5198 // If the caller wants atomic create-with-oplock semantics, tell 5199 // the oplock package. We haven't incremented the Dcb's UncleanCount 5200 // for this create yet, so add that in on the call. 5201 // 5202 5203 if (OpenRequiringOplock && 5204 (Iosb.Status == STATUS_SUCCESS)) { 5205 5206 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Dcb), 5207 IrpContext->OriginatingIrp, 5208 (Dcb->UncleanCount + 1) ); 5209 } 5210 5211 // 5212 // Break parent directory oplock. Directory oplock breaks are always 5213 // advisory, so we will never block/get STATUS_PENDING here. On the 5214 // off chance this fails with INSUFFICIENT_RESOURCES we do it here 5215 // where we can still tolerate a failure. 5216 // 5217 5218 if (Iosb.Status == STATUS_SUCCESS) { 5219 5220 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(ParentDcb), 5221 IrpContext->OriginatingIrp, 5222 OPLOCK_FLAG_PARENT_OBJECT, 5223 NULL, 5224 NULL, 5225 NULL ); 5226 } 5227 5228 // 5229 // Get out if any of the oplock calls failed. 5230 // 5231 5232 if (Iosb.Status != STATUS_SUCCESS) { 5233 5234 FatRaiseStatus( IrpContext, Iosb.Status ); 5235 } 5236 #endif 5237 5238 // 5239 // Tentatively add the new Ea's, 5240 // 5241 5242 if (EaLength > 0) { 5243 5244 // 5245 // This returns false if we are trying to create a file 5246 // with Need Ea's and don't understand EA's. 5247 // 5248 5249 FatCreateEa( IrpContext, 5250 Dcb->Vcb, 5251 (PUCHAR) EaBuffer, 5252 EaLength, 5253 &Dcb->ShortName.Name.Oem, 5254 &EaHandle ); 5255 } 5256 5257 if (!FatIsFat32(Dcb->Vcb)) { 5258 5259 ShortDirent->ExtendedAttributes = EaHandle; 5260 } 5261 5262 // 5263 // After this point we cannot just simply mark the dirent deleted, 5264 // we have to deal with the directory file object. 5265 // 5266 5267 // 5268 // Make the dirent into a directory. Note that even if this call 5269 // raises because of disk space, the diectory file object has been 5270 // created. 5271 // 5272 5273 FatInitializeDirectoryDirent( IrpContext, Dcb, ShortDirent ); 5274 5275 // 5276 // Setup the context and section object pointers, and update 5277 // our reference counts. Note that this call cannot fail. 5278 // 5279 5280 FatSetFileObject( FileObject, 5281 UserDirectoryOpen, 5282 Dcb, 5283 Ccb = FatCreateCcb( IrpContext ) ); 5284 5285 // 5286 // Initialize the LongFileName if it has not already been set, so that 5287 // FatNotify below won't have to. If there are filesystem filters 5288 // attached to FAT, the LongFileName could have gotten set if the 5289 // filter queried for name information on this file object while 5290 // watching the IO needed in FatInitializeDirectoryDirent. 5291 // 5292 5293 if (Dcb->FullFileName.Buffer == NULL) { 5294 5295 FatSetFullNameInFcb( IrpContext, Dcb, UnicodeName ); 5296 } 5297 5298 // 5299 // We call the notify package to report that the 5300 // we added a file. 5301 // 5302 5303 FatNotifyReportChange( IrpContext, 5304 Vcb, 5305 Dcb, 5306 FILE_NOTIFY_CHANGE_DIR_NAME, 5307 FILE_ACTION_ADDED ); 5308 5309 // 5310 // Setup our share access 5311 // 5312 5313 IoSetShareAccess( *DesiredAccess, 5314 ShareAccess, 5315 FileObject, 5316 &Dcb->ShareAccess ); 5317 5318 5319 // 5320 // From this point on, nothing can raise. 5321 // 5322 5323 Dcb->UncleanCount += 1; 5324 Dcb->OpenCount += 1; 5325 Vcb->OpenFileCount += 1; 5326 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 5327 5328 if (DeleteOnClose) { 5329 5330 SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); 5331 } 5332 5333 // 5334 // And set our return status 5335 // 5336 5337 Iosb.Status = STATUS_SUCCESS; 5338 Iosb.Information = FILE_CREATED; 5339 5340 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 5341 5342 // 5343 // We'll catch all exceptions and handle them below. 5344 // 5345 5346 Iosb.Status = IrpContext->ExceptionStatus; 5347 } _SEH2_END; 5348 5349 // 5350 // If we failed then undo our work. 5351 // 5352 5353 if (!NT_SUCCESS( Iosb.Status )) { 5354 5355 // 5356 // We always have to delete the Ccb if we created one. 5357 // 5358 5359 if ( Ccb != NULL ) { 5360 5361 FatDeleteCcb( IrpContext, &Ccb ); 5362 } 5363 5364 #ifdef _MSC_VER 5365 #pragma prefast( suppress: 28924, "prefast thinks this test is redundant, but DCB can be NULL depending on where we raise" ) 5366 #endif 5367 if ( Dcb == NULL) { 5368 5369 NT_ASSERT( (ParentDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) || 5370 RtlAreBitsSet( &ParentDcb->Specific.Dcb.FreeDirentBitmap, 5371 DirentByteOffset / sizeof(DIRENT), 5372 DirentsNeeded ) ); 5373 5374 RtlClearBits( &ParentDcb->Specific.Dcb.FreeDirentBitmap, 5375 DirentByteOffset / sizeof(DIRENT), 5376 DirentsNeeded ); 5377 5378 // 5379 // Mark the dirents deleted. The codes is complex because of 5380 // dealing with an LFN than crosses a page boundry. 5381 // 5382 5383 if (Dirent != NULL) { 5384 5385 ULONG i; 5386 5387 // 5388 // We failed before creating a directory file object. 5389 // We can just mark the dirent deleted and exit. 5390 // 5391 5392 for (i = 0; i < DirentsNeeded; i++) { 5393 5394 if (DirentFromPool == FALSE) { 5395 5396 // 5397 // Simple case. 5398 // 5399 5400 Dirent[i].FileName[0] = FAT_DIRENT_DELETED; 5401 5402 } else { 5403 5404 // 5405 // If the second CcPreparePinWrite failed, we have 5406 // to stop early. 5407 // 5408 5409 if ((SecondPageBcb == NULL) && 5410 (i == DirentsInFirstPage)) { 5411 5412 break; 5413 } 5414 5415 // 5416 // Now conditionally update either page. 5417 // 5418 5419 if (i < DirentsInFirstPage) { 5420 5421 FirstPageDirent[i].FileName[0] = FAT_DIRENT_DELETED; 5422 5423 } else { 5424 5425 SecondPageDirent[i - DirentsInFirstPage].FileName[0] = FAT_DIRENT_DELETED; 5426 } 5427 } 5428 } 5429 } 5430 } 5431 } 5432 5433 // 5434 // Just drop the Bcbs we have in the parent right now so if we 5435 // failed to create the directory and we take the path to rip apart 5436 // the partially created child, when we sync-uninit we won't cause 5437 // a lazy writer processing the parent to block on us. This would 5438 // consume one of the lazy writers, one of which must be running free 5439 // in order for us to come back from the sync-uninit. 5440 // 5441 // Neat, huh? 5442 // 5443 // Granted, the delete dirent below will be marginally less efficient 5444 // since the Bcb may be reclaimed by the time it executes. Life is 5445 // tough. 5446 // 5447 5448 FatUnpinBcb( IrpContext, DirentBcb ); 5449 FatUnpinBcb( IrpContext, SecondPageBcb ); 5450 5451 if (DirentFromPool) { 5452 5453 ExFreePool( Dirent ); 5454 } 5455 5456 if (!NT_SUCCESS( Iosb.Status )) { 5457 5458 #ifdef _MSC_VER 5459 #pragma prefast( suppress: 28924, "prefast thinks this test is redundant, but DCB can be NULL depending on where we raise" ) 5460 #endif 5461 if (Dcb != NULL) { 5462 5463 // 5464 // We have created the Dcb. If an error occurred while 5465 // creating the Ea's, there will be no directory file 5466 // object. 5467 // 5468 5469 PFILE_OBJECT DirectoryFileObject; 5470 5471 DirectoryFileObject = Dcb->Specific.Dcb.DirectoryFile; 5472 5473 // 5474 // Knock down all of the repinned data so we can begin to destroy 5475 // this failed child. We don't care about any raising here - we're 5476 // already got a fire going. 5477 // 5478 // Note that if we failed to do this, the repinned initial pieces 5479 // of the child would cause the sync-uninit to block forever. 5480 // 5481 // A previous spin on this fix had us not make the ./.. creation 5482 // "reversible" (bad term) and thus avoid having the Bcb still 5483 // outstanding. This wound up causing very bad things to happen 5484 // on DMF floppies when we tried to do a similar yank-down in the 5485 // create path - we want the purge it does to make sure we never 5486 // try to write the bytes out ... it is just a lot cleaner to 5487 // unpinrepin. I'll leave the reversible logic in place if it ever 5488 // proves useful. 5489 // 5490 5491 // 5492 // There is a possibility that this may be a generally good idea 5493 // for "live" finally clauses - set in ExceptionFilter, clear in 5494 // ProcessException. Think about this. 5495 // 5496 5497 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE ); 5498 FatUnpinRepinnedBcbs( IrpContext ); 5499 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE ); 5500 5501 if (Dcb->FirstClusterOfFile != 0) { 5502 5503 _SEH2_TRY { 5504 5505 Dcb->Header.FileSize.LowPart = 0; 5506 5507 CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile, 5508 (PCC_FILE_SIZES)&Dcb->Header.AllocationSize ); 5509 5510 // 5511 // Now zap the allocation backing it. 5512 // 5513 5514 FatTruncateFileAllocation( IrpContext, Dcb, 0 ); 5515 5516 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 5517 5518 // 5519 // We catch all exceptions that Fat catches, but don't do 5520 // anything with them. 5521 // 5522 } _SEH2_END; 5523 } 5524 5525 if (DirectoryFileObject != NULL) { 5526 5527 FatSyncUninitializeCacheMap( IrpContext, 5528 DirectoryFileObject ); 5529 } 5530 5531 5532 _SEH2_TRY { 5533 5534 // 5535 // Remove the directory entry we made in the parent Dcb. 5536 // 5537 5538 FatDeleteDirent( IrpContext, Dcb, NULL, TRUE ); 5539 5540 // 5541 // FatDeleteDirent can pin and dirty BCBs, so lets unrepin again. 5542 // 5543 5544 FatUnpinRepinnedBcbs( IrpContext ); 5545 5546 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 5547 5548 // 5549 // We catch all exceptions that Fat catches, but don't do 5550 // anything with them. 5551 // 5552 } _SEH2_END; 5553 5554 // 5555 // Finaly, dereference the directory file object. This will 5556 // cause a close Irp to be processed, blowing away the Fcb. 5557 // 5558 5559 if (DirectoryFileObject != NULL) { 5560 5561 // 5562 // Dereference the file object for this DCB. The DCB will 5563 // go away when this file object is closed. 5564 // 5565 5566 Dcb->Specific.Dcb.DirectoryFile = NULL; 5567 ObDereferenceObject( DirectoryFileObject ); 5568 5569 } else { 5570 5571 // 5572 // This was also a PDK fix. If the stream file exists, this would 5573 // be done during the dereference file object operation. Otherwise 5574 // we have to remove the Dcb and check if we should remove the parent. 5575 // For now we will just leave the parent lying around. 5576 // 5577 5578 #ifdef _MSC_VER 5579 #pragma prefast( suppress: 28924, "prefast thinks this test is redundant, but FileObject can be NULL depending on where we raise" ) 5580 #endif 5581 if (ARGUMENT_PRESENT( FileObject )) { 5582 FileObject->SectionObjectPointer = NULL; 5583 } 5584 FatDeleteFcb( IrpContext, &Dcb ); 5585 } 5586 } 5587 5588 DebugTrace(-1, Dbg, "FatCreateNewDirectory -> Iosb.Status = %08lx\n", Iosb.Status); 5589 5590 FatRaiseStatus( IrpContext, Iosb.Status ); 5591 } 5592 5593 UNREFERENCED_PARAMETER( EaBuffer ); 5594 UNREFERENCED_PARAMETER( EaLength ); 5595 5596 return Iosb; 5597 } 5598 5599 5600 // 5601 // Internal support routine 5602 // 5603 5604 _Requires_lock_held_(_Global_critical_region_) 5605 IO_STATUS_BLOCK 5606 FatCreateNewFile ( 5607 _In_ PIRP_CONTEXT IrpContext, 5608 _In_ PIO_STACK_LOCATION IrpSp, 5609 _Inout_ PFILE_OBJECT FileObject, 5610 _Inout_ PVCB Vcb, 5611 _Inout_ PDCB ParentDcb, 5612 _In_ POEM_STRING OemName, 5613 _In_ PUNICODE_STRING UnicodeName, 5614 _In_ PACCESS_MASK DesiredAccess, 5615 _In_ USHORT ShareAccess, 5616 _In_ ULONG AllocationSize, 5617 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 5618 _In_ ULONG EaLength, 5619 _In_ USHORT FileAttributes, 5620 _In_ PUNICODE_STRING LfnBuffer, 5621 _In_ BOOLEAN IsPagingFile, 5622 _In_ BOOLEAN NoEaKnowledge, 5623 _In_ BOOLEAN DeleteOnClose, 5624 _In_ BOOLEAN OpenRequiringOplock, 5625 _In_ BOOLEAN TemporaryFile 5626 ) 5627 5628 /*++ 5629 5630 Routine Description: 5631 5632 This routine creates a new file. The file has already been verified 5633 not to exist yet. 5634 5635 Arguments: 5636 5637 FileObject - Supplies the file object for the newly created file 5638 5639 Vcb - Supplies the Vcb denote the volume to contain the new file 5640 5641 ParentDcb - Supplies the parent directory containg the newly created 5642 File 5643 5644 OemName - Supplies the Oem name for the newly created file. It may 5645 or maynot be 8.3 complient, but will be upcased. 5646 5647 UnicodeName - Supplies the Unicode name for the newly created file. 5648 It may or maynot be 8.3 complient. This name contains the original 5649 case information. 5650 5651 DesiredAccess - Supplies the desired access of the caller 5652 5653 ShareAccess - Supplies the shared access of the caller 5654 5655 AllocationSize - Supplies the initial allocation size for the file 5656 5657 EaBuffer - Supplies the Ea set for the newly created file 5658 5659 EaLength - Supplies the length, in bytes, of EaBuffer 5660 5661 FileAttributes - Supplies the file attributes for the newly created 5662 file 5663 5664 LfnBuffer - A MAX_LFN sized buffer for directory searching 5665 5666 IsPagingFile - Indicates if this is the paging file being created 5667 5668 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 5669 open if the file has NeedEa's. 5670 5671 DeleteOnClose - The caller wants the file gone when the handle is closed 5672 5673 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option. 5674 5675 TemporaryFile - Signals the lazywriter to not write dirty data unless 5676 absolutely has to. 5677 5678 5679 Return Value: 5680 5681 IO_STATUS_BLOCK - Returns the completion status for the operation 5682 5683 --*/ 5684 5685 { 5686 IO_STATUS_BLOCK Iosb = {0}; 5687 5688 PFCB Fcb = NULL; 5689 5690 PDIRENT Dirent = NULL; 5691 PBCB DirentBcb = NULL; 5692 ULONG DirentsNeeded; 5693 ULONG DirentByteOffset; 5694 5695 PDIRENT ShortDirent; 5696 ULONG ShortDirentByteOffset; 5697 5698 USHORT EaHandle; 5699 5700 BOOLEAN AllLowerComponent; 5701 BOOLEAN AllLowerExtension; 5702 BOOLEAN CreateLfn; 5703 5704 ULONG BytesInFirstPage = 0; 5705 ULONG DirentsInFirstPage = 0; 5706 PDIRENT FirstPageDirent = NULL; 5707 5708 PBCB SecondPageBcb = NULL; 5709 ULONG SecondPageOffset; 5710 PDIRENT SecondPageDirent = NULL; 5711 5712 BOOLEAN DirentFromPool = FALSE; 5713 5714 OEM_STRING ShortName; 5715 UCHAR ShortNameBuffer[12]; 5716 5717 UNICODE_STRING UniTunneledShortName; 5718 WCHAR UniTunneledShortNameBuffer[12]; 5719 UNICODE_STRING UniTunneledLongName; 5720 WCHAR UniTunneledLongNameBuffer[26]; 5721 LARGE_INTEGER TunneledCreationTime; 5722 ULONG TunneledDataSize; 5723 BOOLEAN HaveTunneledInformation; 5724 BOOLEAN UsingTunneledLfn = FALSE; 5725 5726 PUNICODE_STRING RealUnicodeName; 5727 5728 5729 // 5730 // The following variables are for abnormal termination 5731 // 5732 5733 PDIRENT UnwindDirent = NULL; 5734 PFCB UnwindFcb = NULL; 5735 BOOLEAN UnwindAllocation = FALSE; 5736 BOOLEAN CountsIncremented = FALSE; 5737 PCCB UnwindCcb = NULL; 5738 5739 ULONG LocalAbnormalTermination = FALSE; 5740 5741 #if (NTDDI_VERSION < NTDDI_WIN7) 5742 UNREFERENCED_PARAMETER( OpenRequiringOplock ); 5743 #endif 5744 5745 PAGED_CODE(); 5746 5747 DebugTrace(+1, Dbg, "FatCreateNewFile...\n", 0); 5748 5749 ShortName.Length = 0; 5750 ShortName.MaximumLength = sizeof(ShortNameBuffer); 5751 ShortName.Buffer = (PCHAR)&ShortNameBuffer[0]; 5752 5753 UniTunneledShortName.Length = 0; 5754 UniTunneledShortName.MaximumLength = sizeof(UniTunneledShortNameBuffer); 5755 UniTunneledShortName.Buffer = &UniTunneledShortNameBuffer[0]; 5756 5757 UniTunneledLongName.Length = 0; 5758 UniTunneledLongName.MaximumLength = sizeof(UniTunneledLongNameBuffer); 5759 UniTunneledLongName.Buffer = &UniTunneledLongNameBuffer[0]; 5760 5761 EaHandle = 0; 5762 5763 // 5764 // We fail this operation if the caller doesn't understand Ea's. 5765 // 5766 5767 if (NoEaKnowledge 5768 && EaLength > 0) { 5769 5770 Iosb.Status = STATUS_ACCESS_DENIED; 5771 5772 DebugTrace(-1, Dbg, "FatCreateNewFile -> Iosb.Status = %08lx\n", Iosb.Status); 5773 return Iosb; 5774 } 5775 5776 // 5777 // DeleteOnClose and ReadOnly are not compatible. 5778 // 5779 5780 if (DeleteOnClose && FlagOn(FileAttributes, FAT_DIRENT_ATTR_READ_ONLY)) { 5781 5782 Iosb.Status = STATUS_CANNOT_DELETE; 5783 return Iosb; 5784 } 5785 5786 // 5787 // Look in the tunnel cache for names and timestamps to restore 5788 // 5789 5790 TunneledDataSize = sizeof(LARGE_INTEGER); 5791 HaveTunneledInformation = FsRtlFindInTunnelCache( &Vcb->Tunnel, 5792 FatDirectoryKey(ParentDcb), 5793 UnicodeName, 5794 &UniTunneledShortName, 5795 &UniTunneledLongName, 5796 &TunneledDataSize, 5797 &TunneledCreationTime ); 5798 NT_ASSERT(TunneledDataSize == sizeof(LARGE_INTEGER)); 5799 5800 // 5801 // Now get the names that we will be using. 5802 // 5803 5804 FatSelectNames( IrpContext, 5805 ParentDcb, 5806 OemName, 5807 UnicodeName, 5808 &ShortName, 5809 (HaveTunneledInformation? &UniTunneledShortName : NULL), 5810 &AllLowerComponent, 5811 &AllLowerExtension, 5812 &CreateLfn ); 5813 5814 // 5815 // If we are not in Chicago mode, ignore the magic bits. 5816 // 5817 5818 RealUnicodeName = UnicodeName; 5819 5820 if (!FatData.ChicagoMode) { 5821 5822 AllLowerComponent = FALSE; 5823 AllLowerExtension = FALSE; 5824 CreateLfn = FALSE; 5825 5826 } else { 5827 5828 // 5829 // If the Unicode name was legal for a short name and we got 5830 // a tunneling hit which had a long name associated which is 5831 // avaliable for use, use it. 5832 // 5833 5834 if (!CreateLfn && 5835 UniTunneledLongName.Length && 5836 !FatLfnDirentExists(IrpContext, ParentDcb, &UniTunneledLongName, LfnBuffer)) { 5837 5838 UsingTunneledLfn = TRUE; 5839 CreateLfn = TRUE; 5840 5841 RealUnicodeName = &UniTunneledLongName; 5842 5843 // 5844 // Short names are always upcase if an LFN exists 5845 // 5846 5847 AllLowerComponent = FALSE; 5848 AllLowerExtension = FALSE; 5849 } 5850 } 5851 5852 5853 // 5854 // Create/allocate a new dirent 5855 // 5856 5857 DirentsNeeded = CreateLfn ? FAT_LFN_DIRENTS_NEEDED(RealUnicodeName) + 1 : 1; 5858 5859 DirentByteOffset = FatCreateNewDirent( IrpContext, 5860 ParentDcb, 5861 DirentsNeeded, 5862 FALSE ); 5863 5864 _SEH2_TRY { 5865 5866 FatPrepareWriteDirectoryFile( IrpContext, 5867 ParentDcb, 5868 DirentByteOffset, 5869 sizeof(DIRENT), 5870 &DirentBcb, 5871 #ifndef __REACTOS__ 5872 &Dirent, 5873 #else 5874 (PVOID *)&Dirent, 5875 #endif 5876 FALSE, 5877 TRUE, 5878 &Iosb.Status ); 5879 5880 NT_ASSERT( NT_SUCCESS( Iosb.Status ) ); 5881 5882 UnwindDirent = Dirent; 5883 5884 // 5885 // Deal with the special case of an LFN + Dirent structure crossing 5886 // a page boundry. 5887 // 5888 5889 if ((DirentByteOffset / PAGE_SIZE) != 5890 ((DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT)) / PAGE_SIZE)) { 5891 5892 SecondPageBcb; 5893 SecondPageOffset; 5894 SecondPageDirent; 5895 5896 SecondPageOffset = (DirentByteOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE; 5897 5898 BytesInFirstPage = SecondPageOffset - DirentByteOffset; 5899 5900 DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT); 5901 5902 FatPrepareWriteDirectoryFile( IrpContext, 5903 ParentDcb, 5904 SecondPageOffset, 5905 sizeof(DIRENT), 5906 &SecondPageBcb, 5907 #ifndef __REACTOS__ 5908 &SecondPageDirent, 5909 #else 5910 (PVOID *)&SecondPageDirent, 5911 #endif 5912 FALSE, 5913 TRUE, 5914 &Iosb.Status ); 5915 5916 NT_ASSERT( NT_SUCCESS( Iosb.Status ) ); 5917 5918 FirstPageDirent = Dirent; 5919 5920 Dirent = FsRtlAllocatePoolWithTag( PagedPool, 5921 DirentsNeeded * sizeof(DIRENT), 5922 TAG_DIRENT ); 5923 5924 DirentFromPool = TRUE; 5925 } 5926 5927 // 5928 // Bump up Dirent and DirentByteOffset 5929 // 5930 5931 ShortDirent = Dirent + DirentsNeeded - 1; 5932 ShortDirentByteOffset = DirentByteOffset + 5933 (DirentsNeeded - 1) * sizeof(DIRENT); 5934 5935 NT_ASSERT( NT_SUCCESS( Iosb.Status )); 5936 5937 5938 // 5939 // Fill in the fields of the dirent. 5940 // 5941 5942 FatConstructDirent( IrpContext, 5943 ShortDirent, 5944 &ShortName, 5945 AllLowerComponent, 5946 AllLowerExtension, 5947 CreateLfn ? RealUnicodeName : NULL, 5948 (FileAttributes | FILE_ATTRIBUTE_ARCHIVE), 5949 TRUE, 5950 (HaveTunneledInformation ? &TunneledCreationTime : NULL) ); 5951 5952 // 5953 // If the dirent crossed pages, we have to do some real gross stuff. 5954 // 5955 5956 if (DirentFromPool) { 5957 5958 RtlCopyMemory( FirstPageDirent, Dirent, BytesInFirstPage ); 5959 5960 RtlCopyMemory( SecondPageDirent, 5961 Dirent + DirentsInFirstPage, 5962 DirentsNeeded*sizeof(DIRENT) - BytesInFirstPage ); 5963 5964 ShortDirent = SecondPageDirent + (DirentsNeeded - DirentsInFirstPage) - 1; 5965 } 5966 5967 // 5968 // Create a new Fcb for the file. Once the Fcb is created we 5969 // will not need to unwind dirent because delete dirent will 5970 // now do the work. 5971 // 5972 5973 Fcb = UnwindFcb = FatCreateFcb( IrpContext, 5974 Vcb, 5975 ParentDcb, 5976 DirentByteOffset, 5977 ShortDirentByteOffset, 5978 ShortDirent, 5979 CreateLfn ? RealUnicodeName : NULL, 5980 CreateLfn ? RealUnicodeName : NULL, 5981 IsPagingFile, 5982 FALSE ); 5983 UnwindDirent = NULL; 5984 5985 #if (NTDDI_VERSION >= NTDDI_WIN7) 5986 // 5987 // The next three FsRtl calls are for oplock work. We deliberately 5988 // do these here so that if either call fails we will be able to 5989 // clean up without adding a bunch of code to unwind counts, fix 5990 // the file object, etc. 5991 // 5992 5993 // 5994 // Let's make sure that if the caller provided an oplock key that it 5995 // gets stored in the file object. 5996 // 5997 5998 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb), 5999 IrpContext->OriginatingIrp, 6000 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 6001 NULL, 6002 NULL, 6003 NULL ); 6004 6005 // 6006 // If the caller wants atomic create-with-oplock semantics, tell 6007 // the oplock package. We haven't incremented the Fcb's UncleanCount 6008 // for this create yet, so add that in on the call. 6009 // 6010 6011 if (OpenRequiringOplock && 6012 (Iosb.Status == STATUS_SUCCESS)) { 6013 6014 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Fcb), 6015 IrpContext->OriginatingIrp, 6016 (Fcb->UncleanCount + 1) ); 6017 } 6018 #endif 6019 6020 #if (NTDDI_VERSION >= NTDDI_WIN8) 6021 // 6022 // Break parent directory oplock. Directory oplock breaks are always 6023 // advisory, so we will never block/get STATUS_PENDING here. On the 6024 // off chance this fails with INSUFFICIENT_RESOURCES we do it here 6025 // where we can still tolerate a failure. 6026 // 6027 6028 if (Iosb.Status == STATUS_SUCCESS) { 6029 6030 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(ParentDcb), 6031 IrpContext->OriginatingIrp, 6032 OPLOCK_FLAG_PARENT_OBJECT, 6033 NULL, 6034 NULL, 6035 NULL ); 6036 } 6037 6038 // 6039 // Get out if any of the oplock calls failed. We raise to provoke 6040 // abnormal termination and ensure that the newly-created Fcb gets 6041 // deleted. 6042 // 6043 6044 if (Iosb.Status != STATUS_SUCCESS) { 6045 6046 FatRaiseStatus( IrpContext, Iosb.Status ); 6047 } 6048 #endif 6049 6050 // 6051 // If this is a temporary file, note it in the FcbState 6052 // 6053 6054 if (TemporaryFile) { 6055 6056 SetFlag( Fcb->FcbState, FCB_STATE_TEMPORARY ); 6057 } 6058 6059 6060 // 6061 // Add some initial file allocation 6062 // 6063 6064 6065 FatAddFileAllocation( IrpContext, Fcb, FileObject, AllocationSize ); 6066 6067 6068 UnwindAllocation = TRUE; 6069 6070 Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE; 6071 6072 // 6073 // Tentatively add the new Ea's 6074 // 6075 6076 if ( EaLength > 0 ) { 6077 6078 FatCreateEa( IrpContext, 6079 Fcb->Vcb, 6080 (PUCHAR) EaBuffer, 6081 EaLength, 6082 &Fcb->ShortName.Name.Oem, 6083 &EaHandle ); 6084 } 6085 6086 if (!FatIsFat32(Fcb->Vcb)) { 6087 6088 ShortDirent->ExtendedAttributes = EaHandle; 6089 } 6090 6091 6092 6093 // 6094 // Initialize the LongFileName right now so that FatNotify 6095 // below won't have to. 6096 // 6097 6098 if (Fcb->FullFileName.Buffer == NULL) { 6099 FatSetFullNameInFcb( IrpContext, Fcb, RealUnicodeName ); 6100 } 6101 6102 // 6103 // Setup the context and section object pointers, and update 6104 // our reference counts 6105 // 6106 6107 FatSetFileObject( FileObject, 6108 UserFileOpen, 6109 Fcb, 6110 UnwindCcb = FatCreateCcb( IrpContext )); 6111 6112 FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers; 6113 6114 // 6115 // We call the notify package to report that the 6116 // we added a file. 6117 // 6118 6119 FatNotifyReportChange( IrpContext, 6120 Vcb, 6121 Fcb, 6122 FILE_NOTIFY_CHANGE_FILE_NAME, 6123 FILE_ACTION_ADDED ); 6124 6125 // 6126 // Setup our share access 6127 // 6128 6129 IoSetShareAccess( *DesiredAccess, 6130 ShareAccess, 6131 FileObject, 6132 &Fcb->ShareAccess ); 6133 6134 Fcb->UncleanCount += 1; 6135 Fcb->OpenCount += 1; 6136 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { 6137 Fcb->NonCachedUncleanCount += 1; 6138 } 6139 Vcb->OpenFileCount += 1; 6140 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 6141 CountsIncremented = TRUE; 6142 6143 6144 // 6145 // And set our return status 6146 // 6147 6148 Iosb.Status = STATUS_SUCCESS; 6149 Iosb.Information = FILE_CREATED; 6150 6151 if ( NT_SUCCESS(Iosb.Status) ) { 6152 6153 // 6154 // Mark the DeleteOnClose bit if the operation was successful. 6155 // 6156 6157 if ( DeleteOnClose ) { 6158 6159 SetFlag( UnwindCcb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); 6160 } 6161 6162 // 6163 // Mark the OpenedByShortName bit if the operation was successful. 6164 // If we created an Lfn, we have some sort of generated short name 6165 // and thus don't consider ourselves to have opened it - though we 6166 // may have had a case mix Lfn "Foo.bar" and generated "FOO.BAR" 6167 // 6168 // Unless, of course, we wanted to create a short name and hit an 6169 // associated Lfn in the tunnel cache 6170 // 6171 6172 if ( !CreateLfn && !UsingTunneledLfn ) { 6173 6174 SetFlag( UnwindCcb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 6175 } 6176 6177 // 6178 // Mark the ManageVolumeAccess bit if the privilege is held. 6179 // 6180 6181 if (FatCheckManageVolumeAccess( IrpContext, 6182 IrpSp->Parameters.Create.SecurityContext->AccessState, 6183 (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? 6184 UserMode : 6185 IrpContext->OriginatingIrp->RequestorMode ))) { 6186 6187 SetFlag( UnwindCcb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); 6188 } 6189 6190 } 6191 6192 6193 } _SEH2_FINALLY { 6194 6195 DebugUnwind( FatCreateNewFile ); 6196 6197 if (UniTunneledLongName.Buffer != UniTunneledLongNameBuffer) { 6198 6199 // 6200 // Tunneling package grew the buffer from pool 6201 // 6202 6203 ExFreePool( UniTunneledLongName.Buffer ); 6204 } 6205 6206 6207 // 6208 // If this is an abnormal termination then undo our work. 6209 // 6210 // The extra exception handling here is complex. We've got 6211 // two places here where an exception can be thrown again. 6212 // 6213 6214 LocalAbnormalTermination = _SEH2_AbnormalTermination(); 6215 6216 if (LocalAbnormalTermination) { 6217 6218 if (CountsIncremented) { 6219 Fcb->UncleanCount -= 1; 6220 Fcb->OpenCount -= 1; 6221 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { 6222 Fcb->NonCachedUncleanCount -= 1; 6223 } 6224 Vcb->OpenFileCount -= 1; 6225 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } 6226 } 6227 6228 if (UnwindFcb == NULL) { 6229 6230 NT_ASSERT( (ParentDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) || 6231 RtlAreBitsSet( &ParentDcb->Specific.Dcb.FreeDirentBitmap, 6232 DirentByteOffset / sizeof(DIRENT), 6233 DirentsNeeded ) ); 6234 6235 RtlClearBits( &ParentDcb->Specific.Dcb.FreeDirentBitmap, 6236 DirentByteOffset / sizeof(DIRENT), 6237 DirentsNeeded ); 6238 } 6239 6240 // 6241 // Mark the dirents deleted. The code is complex because of 6242 // dealing with an LFN that crosses a page boundary. 6243 // 6244 6245 if (UnwindDirent != NULL) { 6246 6247 ULONG i; 6248 6249 for (i = 0; i < DirentsNeeded; i++) { 6250 6251 if (DirentFromPool == FALSE) { 6252 6253 // 6254 // Simple case. 6255 // 6256 6257 Dirent[i].FileName[0] = FAT_DIRENT_DELETED; 6258 6259 } else { 6260 6261 // 6262 // If the second CcPreparePinWrite failed, we have 6263 // to stop early. 6264 // 6265 6266 if ((SecondPageBcb == NULL) && 6267 (i == DirentsInFirstPage)) { 6268 6269 break; 6270 } 6271 6272 // 6273 // Now conditionally update either page. 6274 // 6275 6276 if (i < DirentsInFirstPage) { 6277 6278 FirstPageDirent[i].FileName[0] = FAT_DIRENT_DELETED; 6279 6280 } else { 6281 6282 SecondPageDirent[i - DirentsInFirstPage].FileName[0] = FAT_DIRENT_DELETED; 6283 } 6284 } 6285 } 6286 } 6287 } 6288 6289 // 6290 // We must handle exceptions in the following fragments and plow on with the 6291 // unwind of this create operation. This is basically inverted from the 6292 // previous state of the code. Since AbnormalTermination() changes when we 6293 // enter a new enclosure, we cached the original state ... 6294 // 6295 6296 _SEH2_TRY { 6297 6298 if (LocalAbnormalTermination) { 6299 if (UnwindAllocation) { 6300 FatTruncateFileAllocation( IrpContext, Fcb, 0 ); 6301 } 6302 } 6303 6304 } _SEH2_FINALLY { 6305 6306 _SEH2_TRY { 6307 6308 if (LocalAbnormalTermination) { 6309 if (UnwindFcb != NULL) { 6310 FatDeleteDirent( IrpContext, UnwindFcb, NULL, TRUE ); 6311 } 6312 } 6313 6314 } _SEH2_FINALLY { 6315 6316 if (LocalAbnormalTermination) { 6317 if (UnwindFcb != NULL) { 6318 if (ARGUMENT_PRESENT( FileObject )) { 6319 FileObject->SectionObjectPointer = NULL; 6320 } 6321 FatDeleteFcb( IrpContext, &UnwindFcb ); 6322 } 6323 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 6324 } 6325 6326 // 6327 // This is the normal cleanup code. 6328 // 6329 6330 FatUnpinBcb( IrpContext, DirentBcb ); 6331 FatUnpinBcb( IrpContext, SecondPageBcb ); 6332 6333 if (DirentFromPool) { 6334 6335 ExFreePool( Dirent ); 6336 } 6337 6338 } _SEH2_END; 6339 } _SEH2_END; 6340 6341 DebugTrace(-1, Dbg, "FatCreateNewFile -> Iosb.Status = %08lx\n", Iosb.Status); 6342 } _SEH2_END; 6343 6344 return Iosb; 6345 } 6346 6347 6348 // 6349 // Internal support routine 6350 // 6351 6352 _Requires_lock_held_(_Global_critical_region_) 6353 IO_STATUS_BLOCK 6354 FatSupersedeOrOverwriteFile ( 6355 _In_ PIRP_CONTEXT IrpContext, 6356 _Inout_ PFILE_OBJECT FileObject, 6357 _Inout_ PFCB Fcb, 6358 _In_ ULONG AllocationSize, 6359 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 6360 _In_ ULONG EaLength, 6361 _In_ USHORT FileAttributes, 6362 _In_ ULONG CreateDisposition, 6363 _In_ BOOLEAN NoEaKnowledge 6364 ) 6365 6366 /*++ 6367 6368 Routine Description: 6369 6370 This routine performs a file supersede or overwrite operation. 6371 6372 Arguments: 6373 6374 FileObject - Supplies a pointer to the file object 6375 6376 Fcb - Supplies a pointer to the Fcb 6377 6378 AllocationSize - Supplies an initial allocation size 6379 6380 EaBuffer - Supplies the Ea set for the superseded/overwritten file 6381 6382 EaLength - Supplies the length, in bytes, of EaBuffer 6383 6384 FileAttributes - Supplies the supersede/overwrite file attributes 6385 6386 CreateDisposition - Supplies the create disposition for the file 6387 It must be either supersede, overwrite, or overwrite if. 6388 6389 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 6390 open if the file has NeedEa's. 6391 6392 Return Value: 6393 6394 IO_STATUS_BLOCK - Returns the completion status for the operation 6395 6396 --*/ 6397 6398 { 6399 IO_STATUS_BLOCK Iosb = {0}; 6400 6401 PDIRENT Dirent; 6402 PBCB DirentBcb; 6403 6404 USHORT EaHandle = 0; 6405 BOOLEAN EaChange = FALSE; 6406 BOOLEAN ReleasePaging = FALSE; 6407 6408 PCCB Ccb; 6409 6410 ULONG NotifyFilter; 6411 ULONG HeaderSize = 0; 6412 LARGE_INTEGER AllocSize = {0}; 6413 6414 // 6415 // The following variables are for abnormal termination 6416 // 6417 6418 PCCB UnwindCcb = NULL; 6419 USHORT UnwindEa = 0; 6420 6421 PAGED_CODE(); 6422 6423 DebugTrace(+1, Dbg, "FatSupersedeOrOverwriteFile...\n", 0); 6424 6425 DirentBcb = NULL; 6426 6427 // 6428 // We fail this operation if the caller doesn't understand Ea's. 6429 // 6430 6431 if (NoEaKnowledge 6432 && EaLength > 0) { 6433 6434 Iosb.Status = STATUS_ACCESS_DENIED; 6435 6436 DebugTrace(-1, Dbg, "FatSupersedeOrOverwriteFile -> Iosb.Status = %08lx\n", Iosb.Status); 6437 return Iosb; 6438 } 6439 6440 _SEH2_TRY { 6441 6442 // 6443 // Before we actually truncate, check to see if the purge 6444 // is going to fail. 6445 // 6446 6447 if (!MmCanFileBeTruncated( &Fcb->NonPaged->SectionObjectPointers, 6448 &FatLargeZero )) { 6449 6450 try_return( Iosb.Status = STATUS_USER_MAPPED_FILE ); 6451 } 6452 6453 // 6454 // Setup the context and section object pointers, and update 6455 // our reference counts 6456 // 6457 6458 FatSetFileObject( FileObject, 6459 UserFileOpen, 6460 Fcb, 6461 Ccb = UnwindCcb = FatCreateCcb( IrpContext )); 6462 6463 FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers; 6464 6465 // 6466 // Since this is an supersede/overwrite, purge the section so 6467 // that mappers will see zeros. We set the CREATE_IN_PROGRESS flag 6468 // to prevent the Fcb from going away out from underneath us. 6469 // 6470 6471 SetFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS); 6472 6473 CcPurgeCacheSection( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, FALSE ); 6474 6475 // 6476 // Tentatively add the new Ea's 6477 // 6478 6479 if (EaLength > 0) { 6480 6481 FatCreateEa( IrpContext, 6482 Fcb->Vcb, 6483 (PUCHAR) EaBuffer, 6484 EaLength, 6485 &Fcb->ShortName.Name.Oem, 6486 &EaHandle ); 6487 6488 UnwindEa = EaHandle; 6489 EaChange = TRUE; 6490 } 6491 6492 #if (NTDDI_VERSION >= NTDDI_WIN8) 6493 // 6494 // Break parent directory oplock. Directory oplock breaks are always 6495 // advisory, so we will never block/get STATUS_PENDING here. On the 6496 // off chance this fails with INSUFFICIENT_RESOURCES we do it here 6497 // where we can still tolerate a failure. 6498 // 6499 6500 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb->ParentDcb), 6501 IrpContext->OriginatingIrp, 6502 OPLOCK_FLAG_PARENT_OBJECT, 6503 NULL, 6504 NULL, 6505 NULL ); 6506 6507 if (Iosb.Status != STATUS_SUCCESS) { 6508 6509 FatRaiseStatus( IrpContext, Iosb.Status ); 6510 } 6511 #endif 6512 6513 // 6514 // Now set the new allocation size, we do that by first 6515 // zeroing out the current file size. Then we truncate and 6516 // allocate up to the new allocation size 6517 // 6518 6519 (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE ); 6520 ReleasePaging = TRUE; 6521 6522 Fcb->Header.FileSize.LowPart = 0; 6523 Fcb->Header.ValidDataLength.LowPart = 0; 6524 Fcb->ValidDataToDisk = 0; 6525 6526 6527 // 6528 // Validate that the allocation size will work. 6529 // 6530 6531 AllocSize.QuadPart = AllocationSize; 6532 if (!FatIsIoRangeValid( Fcb->Vcb, AllocSize, 0 )) { 6533 6534 DebugTrace(-1, Dbg, "Illegal allocation size\n", 0); 6535 6536 FatRaiseStatus( IrpContext, STATUS_DISK_FULL ); 6537 } 6538 6539 6540 // 6541 // Tell the cache manager the size went to zero 6542 // This call is unconditional, because MM always wants to know. 6543 // 6544 6545 CcSetFileSizes( FileObject, 6546 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize ); 6547 6548 FatTruncateFileAllocation( IrpContext, Fcb, AllocationSize+HeaderSize ); 6549 6550 ExReleaseResourceLite( Fcb->Header.PagingIoResource ); 6551 ReleasePaging = FALSE; 6552 6553 FatAddFileAllocation( IrpContext, Fcb, FileObject, AllocationSize+HeaderSize ); 6554 6555 Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE; 6556 6557 // 6558 // Modify the attributes and time of the file, by first reading 6559 // in the dirent for the file and then updating its attributes 6560 // and time fields. Note that for supersede we replace the file 6561 // attributes as opposed to adding to them. 6562 // 6563 6564 FatGetDirentFromFcbOrDcb( IrpContext, 6565 Fcb, 6566 FALSE, 6567 &Dirent, 6568 &DirentBcb ); 6569 // 6570 // We should get the dirent since this Fcb is in good condition, verified as 6571 // we crawled down the prefix tree. 6572 // 6573 // Update the appropriate dirent fields, and the fcb fields 6574 // 6575 6576 Dirent->FileSize = 0; 6577 6578 6579 FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; 6580 6581 if (CreateDisposition == FILE_SUPERSEDE) { 6582 6583 Dirent->Attributes = (UCHAR)FileAttributes; 6584 6585 } else { 6586 6587 Dirent->Attributes |= (UCHAR)FileAttributes; 6588 } 6589 6590 Fcb->DirentFatFlags = Dirent->Attributes; 6591 6592 KeQuerySystemTime( &Fcb->LastWriteTime ); 6593 6594 (VOID)FatNtTimeToFatTime( IrpContext, 6595 &Fcb->LastWriteTime, 6596 TRUE, 6597 &Dirent->LastWriteTime, 6598 NULL ); 6599 6600 if (FatData.ChicagoMode) { 6601 6602 Dirent->LastAccessDate = Dirent->LastWriteTime.Date; 6603 } 6604 6605 NotifyFilter = FILE_NOTIFY_CHANGE_LAST_WRITE 6606 | FILE_NOTIFY_CHANGE_ATTRIBUTES 6607 | FILE_NOTIFY_CHANGE_SIZE; 6608 6609 // 6610 // And now delete the previous Ea set if there was one. 6611 // 6612 6613 if (!FatIsFat32(Fcb->Vcb) && Dirent->ExtendedAttributes != 0) { 6614 6615 // 6616 // **** SDK fix, we won't fail this if there is 6617 // an error in the Ea's, we'll just leave 6618 // the orphaned Ea's in the file. 6619 // 6620 6621 EaChange = TRUE; 6622 6623 _SEH2_TRY { 6624 6625 FatDeleteEa( IrpContext, 6626 Fcb->Vcb, 6627 Dirent->ExtendedAttributes, 6628 &Fcb->ShortName.Name.Oem ); 6629 6630 } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { 6631 6632 FatResetExceptionState( IrpContext ); 6633 } _SEH2_END; 6634 } 6635 6636 // 6637 // Update the extended attributes handle in the dirent. 6638 // 6639 6640 if (EaChange) { 6641 6642 NT_ASSERT(!FatIsFat32(Fcb->Vcb)); 6643 6644 Dirent->ExtendedAttributes = EaHandle; 6645 6646 NotifyFilter |= FILE_NOTIFY_CHANGE_EA; 6647 } 6648 6649 // 6650 // Now update the dirent to the new ea handle and set the bcb dirty 6651 // Once we do this we can no longer back out the Ea 6652 // 6653 6654 FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE ); 6655 UnwindEa = 0; 6656 6657 // 6658 // Indicate that the Eas for this file have changed. 6659 // 6660 6661 Ccb->EaModificationCount += Fcb->EaModificationCount; 6662 6663 // 6664 // Check to see if we need to notify outstanding Irps for full 6665 // changes only (i.e., we haven't added, deleted, or renamed the file). 6666 // 6667 6668 FatNotifyReportChange( IrpContext, 6669 Fcb->Vcb, 6670 Fcb, 6671 NotifyFilter, 6672 FILE_ACTION_MODIFIED ); 6673 6674 // 6675 // And set our status to success 6676 // 6677 6678 Iosb.Status = STATUS_SUCCESS; 6679 6680 if (CreateDisposition == FILE_SUPERSEDE) { 6681 6682 Iosb.Information = FILE_SUPERSEDED; 6683 6684 } else { 6685 6686 Iosb.Information = FILE_OVERWRITTEN; 6687 } 6688 6689 try_exit: NOTHING; 6690 } _SEH2_FINALLY { 6691 6692 DebugUnwind( FatSupersedeOfOverwriteFile ); 6693 6694 if (ReleasePaging) { ExReleaseResourceLite( Fcb->Header.PagingIoResource ); } 6695 6696 // 6697 // If this is an abnormal termination then undo our work. 6698 // 6699 6700 if (_SEH2_AbnormalTermination()) { 6701 6702 if (UnwindEa != 0) { FatDeleteEa( IrpContext, Fcb->Vcb, UnwindEa, &Fcb->ShortName.Name.Oem ); } 6703 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 6704 } 6705 6706 FatUnpinBcb( IrpContext, DirentBcb ); 6707 6708 ClearFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS); 6709 6710 DebugTrace(-1, Dbg, "FatSupersedeOrOverwriteFile -> Iosb.Status = %08lx\n", Iosb.Status); 6711 } _SEH2_END; 6712 6713 return Iosb; 6714 } 6715 6716 6717 VOID 6718 FatSetFullNameInFcb ( 6719 _In_ PIRP_CONTEXT IrpContext, 6720 _Inout_ PFCB Fcb, 6721 _In_ PUNICODE_STRING FinalName 6722 ) 6723 6724 /*++ 6725 6726 Routine Description: 6727 6728 This routine attempts a quick form of the full FatSetFullFileNameInFcb 6729 operation. 6730 6731 NOTE: this routine is probably not worth the code duplication involved, 6732 and is not equipped to handle the cases where the parent doesn't have 6733 the full name set up. 6734 6735 Arguments: 6736 6737 Fcb - Supplies a pointer to the Fcb 6738 6739 FinalName - Supplies the last component of the path to this Fcb's dirent 6740 6741 Return Value: 6742 6743 None. May silently fail. 6744 6745 --*/ 6746 6747 { 6748 PAGED_CODE(); 6749 6750 UNREFERENCED_PARAMETER( IrpContext ); 6751 6752 NT_ASSERT( Fcb->FullFileName.Buffer == NULL ); 6753 6754 // 6755 // Prefer the ExactCaseLongName of the file for this operation, if set. In 6756 // this way we avoid building the fullname with a short filename. Several 6757 // operations assume this - the FinalNameLength in particular is the Lfn 6758 // (if existant) length, and we use this to crack the fullname in paths 6759 // such as the FsRtlNotify caller. 6760 // 6761 // If the caller specified a particular name and it is short, it is the 6762 // case that the long name was set up. 6763 // 6764 6765 if (Fcb->ExactCaseLongName.Buffer) { 6766 6767 NT_ASSERT( Fcb->ExactCaseLongName.Length != 0 ); 6768 FinalName = &Fcb->ExactCaseLongName; 6769 } 6770 6771 // 6772 // Special case the root. 6773 // 6774 6775 if (NodeType(Fcb->ParentDcb) == FAT_NTC_ROOT_DCB) { 6776 6777 Fcb->FullFileName.Length = 6778 Fcb->FullFileName.MaximumLength = sizeof(WCHAR) + FinalName->Length; 6779 6780 Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag( PagedPool, 6781 Fcb->FullFileName.Length, 6782 TAG_FILENAME_BUFFER ); 6783 6784 Fcb->FullFileName.Buffer[0] = L'\\'; 6785 6786 RtlCopyMemory( &Fcb->FullFileName.Buffer[1], 6787 &FinalName->Buffer[0], 6788 FinalName->Length ); 6789 6790 } else { 6791 6792 PUNICODE_STRING Prefix; 6793 6794 Prefix = &Fcb->ParentDcb->FullFileName; 6795 6796 // 6797 // It is possible our parent's full filename is not set. Simply fail 6798 // this attempt. 6799 // 6800 6801 if (Prefix->Buffer == NULL) { 6802 6803 return; 6804 } 6805 6806 Fcb->FullFileName.Length = 6807 Fcb->FullFileName.MaximumLength = Prefix->Length + sizeof(WCHAR) + FinalName->Length; 6808 6809 Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag( PagedPool, 6810 Fcb->FullFileName.Length, 6811 TAG_FILENAME_BUFFER ); 6812 6813 RtlCopyMemory( &Fcb->FullFileName.Buffer[0], 6814 &Prefix->Buffer[0], 6815 Prefix->Length ); 6816 6817 Fcb->FullFileName.Buffer[Prefix->Length / sizeof(WCHAR)] = L'\\'; 6818 6819 RtlCopyMemory( &Fcb->FullFileName.Buffer[(Prefix->Length / sizeof(WCHAR)) + 1], 6820 &FinalName->Buffer[0], 6821 FinalName->Length ); 6822 6823 } 6824 } 6825 6826 6827 NTSTATUS 6828 FatCheckSystemSecurityAccess ( 6829 _In_ PIRP_CONTEXT IrpContext 6830 ) 6831 { 6832 PACCESS_STATE AccessState; 6833 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp ); 6834 6835 PAGED_CODE(); 6836 6837 // 6838 // We check if the caller wants ACCESS_SYSTEM_SECURITY access on this 6839 // object and fail the request if he does. 6840 // 6841 6842 NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL ); 6843 AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; 6844 6845 // 6846 // Check if the remaining privilege includes ACCESS_SYSTEM_SECURITY. 6847 // 6848 6849 if (FlagOn( AccessState->RemainingDesiredAccess, ACCESS_SYSTEM_SECURITY )) { 6850 6851 if (!SeSinglePrivilegeCheck( FatSecurityPrivilege, 6852 UserMode )) { 6853 6854 return STATUS_ACCESS_DENIED; 6855 } 6856 6857 // 6858 // Move this privilege from the Remaining access to Granted access. 6859 // 6860 6861 ClearFlag( AccessState->RemainingDesiredAccess, ACCESS_SYSTEM_SECURITY ); 6862 SetFlag( AccessState->PreviouslyGrantedAccess, ACCESS_SYSTEM_SECURITY ); 6863 } 6864 6865 return STATUS_SUCCESS; 6866 } 6867 6868 6869 NTSTATUS 6870 FatCheckShareAccess ( 6871 _In_ PIRP_CONTEXT IrpContext, 6872 _In_ PFILE_OBJECT FileObject, 6873 _In_ PFCB FcbOrDcb, 6874 _In_ PACCESS_MASK DesiredAccess, 6875 _In_ ULONG ShareAccess 6876 ) 6877 6878 /*++ 6879 6880 Routine Description: 6881 6882 This routine checks conditions that may result in a sharing violation. 6883 6884 Arguments: 6885 6886 FileObject - Pointer to the file object of the current open request. 6887 6888 FcbOrDcb - Supplies a pointer to the Fcb/Dcb. 6889 6890 DesiredAccess - Desired access of current open request. 6891 6892 ShareAccess - Shared access requested by current open request. 6893 6894 Return Value: 6895 6896 If the accessor has access to the file, STATUS_SUCCESS is returned. 6897 Otherwise, STATUS_SHARING_VIOLATION is returned. 6898 6899 --*/ 6900 6901 { 6902 PAGED_CODE(); 6903 6904 #if (NTDDI_VERSION >= NTDDI_VISTA) 6905 // 6906 // Do an extra test for writeable user sections if the user did not allow 6907 // write sharing - this is neccessary since a section may exist with no handles 6908 // open to the file its based against. 6909 // 6910 6911 if ((NodeType( FcbOrDcb ) == FAT_NTC_FCB) && 6912 !FlagOn( ShareAccess, FILE_SHARE_WRITE ) && 6913 FlagOn( *DesiredAccess, FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE | MAXIMUM_ALLOWED ) && 6914 MmDoesFileHaveUserWritableReferences( &FcbOrDcb->NonPaged->SectionObjectPointers )) { 6915 6916 return STATUS_SHARING_VIOLATION; 6917 } 6918 #endif 6919 6920 // 6921 // Check if the Fcb has the proper share access. 6922 // 6923 6924 return IoCheckShareAccess( *DesiredAccess, 6925 ShareAccess, 6926 FileObject, 6927 &FcbOrDcb->ShareAccess, 6928 FALSE ); 6929 6930 UNREFERENCED_PARAMETER( IrpContext ); 6931 } 6932 6933 // 6934 // Lifted from NTFS. 6935 // 6936 6937 NTSTATUS 6938 FatCallSelfCompletionRoutine ( 6939 __in PDEVICE_OBJECT DeviceObject, 6940 __in PIRP Irp, 6941 __in PVOID Contxt 6942 ) 6943 6944 { 6945 // 6946 // Set the event so that our call will wake up. 6947 // 6948 6949 KeSetEvent( (PKEVENT)Contxt, 0, FALSE ); 6950 6951 UNREFERENCED_PARAMETER( DeviceObject ); 6952 UNREFERENCED_PARAMETER( Irp ); 6953 6954 // 6955 // If we change this return value then FatIoCallSelf needs to reference the 6956 // file object. 6957 // 6958 6959 return STATUS_MORE_PROCESSING_REQUIRED; 6960 } 6961