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( 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( 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( Status = STATUS_SHARING_VIOLATION ); 2416 } 2417 2418 } else { 2419 2420 if (Vcb->ReadOnlyCount != Vcb->OpenFileCount) { 2421 2422 try_return( 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(Status = IoCheckShareAccess( *DesiredAccess, 2491 ShareAccess, 2492 FileObject, 2493 &Vcb->ShareAccess, 2494 TRUE ))) { 2495 2496 try_return( NOTHING ); 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 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(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", Status); 2574 } _SEH2_END; 2575 2576 Iosb.Status = Status; 2577 return Iosb; 2578 } 2579 2580 2581 // 2582 // Internal support routine 2583 // 2584 2585 _Requires_lock_held_(_Global_critical_region_) 2586 IO_STATUS_BLOCK 2587 FatOpenRootDcb ( 2588 _In_ PIRP_CONTEXT IrpContext, 2589 _Inout_ PFILE_OBJECT FileObject, 2590 _Inout_ PVCB Vcb, 2591 _In_ PACCESS_MASK DesiredAccess, 2592 _In_ USHORT ShareAccess, 2593 _In_ ULONG CreateDisposition 2594 ) 2595 2596 /*++ 2597 2598 Routine Description: 2599 2600 This routine opens the root dcb for the volume 2601 2602 Arguments: 2603 2604 FileObject - Supplies the File object 2605 2606 Vcb - Supplies the Vcb denoting the volume whose dcb is being opened. 2607 2608 DesiredAccess - Supplies the desired access of the caller 2609 2610 ShareAccess - Supplies the share access of the caller 2611 2612 CreateDisposition - Supplies the create disposition for this operation 2613 2614 Return Value: 2615 2616 IO_STATUS_BLOCK - Returns the completion status for the operation 2617 2618 Arguments: 2619 2620 --*/ 2621 2622 { 2623 PDCB RootDcb; 2624 IO_STATUS_BLOCK Iosb = {0}; 2625 2626 // 2627 // The following variables are for abnormal termination 2628 // 2629 2630 BOOLEAN UnwindShareAccess = FALSE; 2631 PCCB UnwindCcb = NULL; 2632 BOOLEAN UnwindCounts = FALSE; 2633 BOOLEAN RootDcbAcquired = FALSE; 2634 2635 PAGED_CODE(); 2636 2637 DebugTrace(+1, Dbg, "FatOpenRootDcb...\n", 0); 2638 2639 // 2640 // Locate the root dcb 2641 // 2642 2643 RootDcb = Vcb->RootDcb; 2644 2645 // 2646 // Get the Dcb exlcusive. This is important as cleanup does not 2647 // acquire the Vcb. 2648 // 2649 2650 (VOID)FatAcquireExclusiveFcb( IrpContext, RootDcb ); 2651 RootDcbAcquired = TRUE; 2652 2653 _SEH2_TRY { 2654 2655 // 2656 // Check the create disposition and desired access 2657 // 2658 2659 if ((CreateDisposition != FILE_OPEN) && 2660 (CreateDisposition != FILE_OPEN_IF)) { 2661 2662 Iosb.Status = STATUS_ACCESS_DENIED; 2663 try_return( Iosb ); 2664 } 2665 2666 if (!FatCheckFileAccess( IrpContext, 2667 RootDcb->DirentFatFlags, 2668 DesiredAccess)) { 2669 2670 Iosb.Status = STATUS_ACCESS_DENIED; 2671 try_return( Iosb ); 2672 } 2673 2674 // 2675 // If the Root dcb is already opened by someone then we need 2676 // to check the share access 2677 // 2678 2679 if (RootDcb->OpenCount > 0) { 2680 2681 if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess, 2682 ShareAccess, 2683 FileObject, 2684 &RootDcb->ShareAccess, 2685 TRUE ))) { 2686 2687 try_return( Iosb ); 2688 } 2689 2690 } else { 2691 2692 IoSetShareAccess( *DesiredAccess, 2693 ShareAccess, 2694 FileObject, 2695 &RootDcb->ShareAccess ); 2696 } 2697 2698 UnwindShareAccess = TRUE; 2699 2700 // 2701 // Setup the context and section object pointers, and update 2702 // our reference counts 2703 // 2704 2705 FatSetFileObject( FileObject, 2706 UserDirectoryOpen, 2707 RootDcb, 2708 UnwindCcb = FatCreateCcb( IrpContext )); 2709 2710 RootDcb->UncleanCount += 1; 2711 RootDcb->OpenCount += 1; 2712 Vcb->OpenFileCount += 1; 2713 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 2714 UnwindCounts = TRUE; 2715 2716 // 2717 // And set our status to success 2718 // 2719 2720 Iosb.Status = STATUS_SUCCESS; 2721 Iosb.Information = FILE_OPENED; 2722 2723 try_exit: NOTHING; 2724 } _SEH2_FINALLY { 2725 2726 DebugUnwind( FatOpenRootDcb ); 2727 2728 // 2729 // If this is an abnormal termination then undo our work 2730 // 2731 2732 if (_SEH2_AbnormalTermination()) { 2733 2734 if (UnwindCounts) { 2735 RootDcb->UncleanCount -= 1; 2736 RootDcb->OpenCount -= 1; 2737 Vcb->OpenFileCount -= 1; 2738 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } 2739 } 2740 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 2741 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &RootDcb->ShareAccess ); } 2742 } 2743 2744 if (RootDcbAcquired) { 2745 2746 FatReleaseFcb( IrpContext, RootDcb ); 2747 } 2748 2749 DebugTrace(-1, Dbg, "FatOpenRootDcb -> Iosb.Status = %08lx\n", Iosb.Status); 2750 } _SEH2_END; 2751 2752 return Iosb; 2753 } 2754 2755 2756 // 2757 // Internal support routine 2758 // 2759 2760 _Requires_lock_held_(_Global_critical_region_) 2761 IO_STATUS_BLOCK 2762 FatOpenExistingDcb ( 2763 _In_ PIRP_CONTEXT IrpContext, 2764 _In_ PIO_STACK_LOCATION IrpSp, 2765 _Inout_ PFILE_OBJECT FileObject, 2766 _Inout_ PVCB Vcb, 2767 _Inout_ PDCB Dcb, 2768 _In_ PACCESS_MASK DesiredAccess, 2769 _In_ USHORT ShareAccess, 2770 _In_ ULONG CreateDisposition, 2771 _In_ BOOLEAN NoEaKnowledge, 2772 _In_ BOOLEAN DeleteOnClose, 2773 _In_ BOOLEAN OpenRequiringOplock, 2774 _In_ BOOLEAN FileNameOpenedDos, 2775 _Out_ PBOOLEAN OplockPostIrp 2776 ) 2777 2778 /*++ 2779 2780 Routine Description: 2781 2782 This routine opens the specified existing dcb 2783 2784 Arguments: 2785 2786 FileObject - Supplies the File object 2787 2788 Vcb - Supplies the Vcb denoting the volume containing the dcb 2789 2790 Dcb - Supplies the already existing dcb 2791 2792 DesiredAccess - Supplies the desired access of the caller 2793 2794 ShareAccess - Supplies the share access of the caller 2795 2796 CreateDisposition - Supplies the create disposition for this operation 2797 2798 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 2799 open if the file has NeedEa's. 2800 2801 DeleteOnClose - The caller wants the file gone when the handle is closed 2802 2803 Return Value: 2804 2805 IO_STATUS_BLOCK - Returns the completion status for the operation 2806 2807 --*/ 2808 2809 { 2810 IO_STATUS_BLOCK Iosb = {0}; 2811 PBCB DirentBcb = NULL; 2812 PDIRENT Dirent; 2813 2814 // 2815 // The following variables are for abnormal termination 2816 // 2817 2818 BOOLEAN UnwindShareAccess = FALSE; 2819 PCCB UnwindCcb = NULL; 2820 BOOLEAN DcbAcquired = FALSE; 2821 2822 #if (NTDDI_VERSION <= NTDDI_WIN7) 2823 UNREFERENCED_PARAMETER( OpenRequiringOplock ); 2824 #endif 2825 2826 UNREFERENCED_PARAMETER( IrpSp ); 2827 2828 PAGED_CODE(); 2829 2830 DebugTrace(+1, Dbg, "FatOpenExistingDcb...\n", 0); 2831 2832 // 2833 // Get the Dcb exlcusive. This is important as cleanup does not 2834 // acquire the Vcb. 2835 // 2836 2837 (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb ); 2838 DcbAcquired = TRUE; 2839 2840 _SEH2_TRY { 2841 2842 2843 *OplockPostIrp = FALSE; 2844 2845 // 2846 // Before spending any noticeable effort, see if we have the odd case 2847 // of someone trying to delete-on-close the root dcb. This will only 2848 // happen if we're hit with a null-filename relative open via the root. 2849 // 2850 2851 if (NodeType(Dcb) == FAT_NTC_ROOT_DCB && DeleteOnClose) { 2852 2853 Iosb.Status = STATUS_CANNOT_DELETE; 2854 try_return( Iosb ); 2855 } 2856 2857 #if (NTDDI_VERSION >= NTDDI_WIN8) 2858 2859 // 2860 // Let's make sure that if the caller provided an oplock key that it 2861 // gets stored in the file object. 2862 // 2863 2864 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Dcb), 2865 IrpContext->OriginatingIrp, 2866 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 2867 NULL, 2868 NULL, 2869 NULL ); 2870 2871 if (Iosb.Status != STATUS_SUCCESS) { 2872 2873 try_return( NOTHING ); 2874 } 2875 2876 #endif 2877 // 2878 // If the caller has no Ea knowledge, we immediately check for 2879 // Need Ea's on the file. We don't need to check for ea's on the 2880 // root directory, because it never has any. Fat32 doesn't have 2881 // any, either. 2882 // 2883 2884 if (NoEaKnowledge && NodeType(Dcb) != FAT_NTC_ROOT_DCB && 2885 !FatIsFat32(Vcb)) { 2886 2887 ULONG NeedEaCount; 2888 2889 // 2890 // Get the dirent for the file and then check that the need 2891 // ea count is 0. 2892 // 2893 2894 FatGetDirentFromFcbOrDcb( IrpContext, 2895 Dcb, 2896 FALSE, 2897 &Dirent, 2898 &DirentBcb ); 2899 2900 FatGetNeedEaCount( IrpContext, 2901 Vcb, 2902 Dirent, 2903 &NeedEaCount ); 2904 2905 FatUnpinBcb( IrpContext, DirentBcb ); 2906 2907 if (NeedEaCount != 0) { 2908 2909 Iosb.Status = STATUS_ACCESS_DENIED; 2910 try_return( Iosb ); 2911 } 2912 } 2913 2914 // 2915 // Check the create disposition and desired access 2916 // 2917 2918 if ((CreateDisposition != FILE_OPEN) && 2919 (CreateDisposition != FILE_OPEN_IF)) { 2920 2921 Iosb.Status = STATUS_OBJECT_NAME_COLLISION; 2922 try_return( Iosb ); 2923 } 2924 2925 if (!FatCheckFileAccess( IrpContext, 2926 Dcb->DirentFatFlags, 2927 DesiredAccess)) { 2928 2929 Iosb.Status = STATUS_ACCESS_DENIED; 2930 try_return( Iosb ); 2931 } 2932 2933 // 2934 // If the dcb is already opened by someone then we need 2935 // to check the share access 2936 // 2937 2938 if (Dcb->OpenCount > 0) { 2939 2940 if (!NT_SUCCESS(Iosb.Status = FatCheckShareAccess( IrpContext, 2941 FileObject, 2942 Dcb, 2943 DesiredAccess, 2944 ShareAccess ))) { 2945 #if (NTDDI_VERSION >= NTDDI_WIN8) 2946 2947 NTSTATUS OplockBreakStatus = STATUS_SUCCESS; 2948 2949 // 2950 // If we got a sharing violation try to break outstanding handle 2951 // oplocks and retry the sharing check. If the caller specified 2952 // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock; 2953 // we just return the sharing violation. 2954 // 2955 2956 if ((Iosb.Status == STATUS_SHARING_VIOLATION) && 2957 !FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) { 2958 2959 OplockBreakStatus = FsRtlOplockBreakH( FatGetFcbOplock(Dcb), 2960 IrpContext->OriginatingIrp, 2961 0, 2962 IrpContext, 2963 FatOplockComplete, 2964 FatPrePostIrp ); 2965 2966 // 2967 // If FsRtlOplockBreakH returned STATUS_PENDING, then the IRP 2968 // has been posted and we need to stop working. 2969 // 2970 2971 if (OplockBreakStatus == STATUS_PENDING) { 2972 2973 Iosb.Status = STATUS_PENDING; 2974 *OplockPostIrp = TRUE; 2975 try_return( NOTHING ); 2976 2977 // 2978 // If FsRtlOplockBreakH returned an error we want to return that now. 2979 // 2980 2981 } else if (!NT_SUCCESS( OplockBreakStatus )) { 2982 2983 Iosb.Status = OplockBreakStatus; 2984 try_return( Iosb ); 2985 2986 // 2987 // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating 2988 // that there is no oplock to be broken. The sharing violation is 2989 // returned in that case. 2990 // 2991 2992 } else { 2993 2994 NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS ); 2995 2996 try_return( Iosb ); 2997 } 2998 2999 // 3000 // The initial sharing check failed with something other than sharing 3001 // violation (which should never happen, but let's be future-proof), 3002 // or we *did* get a sharing violation and the caller specified 3003 // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over. 3004 // 3005 3006 } else { 3007 3008 try_return( Iosb ); 3009 } 3010 #else 3011 3012 try_return( Iosb ); 3013 #endif 3014 } 3015 } 3016 3017 #if (NTDDI_VERSION >= NTDDI_WIN8) 3018 3019 // 3020 // Now check that we can continue based on the oplock state of the 3021 // directory. If there are no open handles yet we don't need to do 3022 // this check; oplocks can only exist when there are handles. 3023 // 3024 3025 if (Dcb->UncleanCount != 0) { 3026 3027 Iosb.Status = FsRtlCheckOplock( FatGetFcbOplock(Dcb), 3028 IrpContext->OriginatingIrp, 3029 IrpContext, 3030 FatOplockComplete, 3031 FatPrePostIrp ); 3032 } 3033 3034 // 3035 // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted 3036 // to service an oplock break and we need to leave now. 3037 // 3038 3039 if (Iosb.Status == STATUS_PENDING) { 3040 3041 *OplockPostIrp = TRUE; 3042 try_return( NOTHING ); 3043 } 3044 3045 // 3046 // If the caller wants atomic create-with-oplock semantics, tell 3047 // the oplock package. We haven't incremented the Fcb's UncleanCount 3048 // for this create yet, so add that in on the call. 3049 // 3050 3051 if (OpenRequiringOplock && 3052 (Iosb.Status == STATUS_SUCCESS)) { 3053 3054 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Dcb), 3055 IrpContext->OriginatingIrp, 3056 (Dcb->UncleanCount + 1) ); 3057 } 3058 3059 // 3060 // If we've encountered a failure we need to leave. FsRtlCheckOplock 3061 // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated 3062 // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED 3063 // on the create call. That's an NT_SUCCESS code, so we need to keep 3064 // going. 3065 // 3066 3067 if ((Iosb.Status != STATUS_SUCCESS) && 3068 (Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) { 3069 3070 try_return( NOTHING ); 3071 } 3072 3073 #endif 3074 3075 // 3076 // Now that we're done with the oplock work update the share counts. 3077 // If the Dcb isn't yet opened we just set the share access rather than 3078 // update it. 3079 // 3080 3081 if (Dcb->OpenCount > 0) { 3082 3083 IoUpdateShareAccess( FileObject, &Dcb->ShareAccess ); 3084 3085 } else { 3086 3087 IoSetShareAccess( *DesiredAccess, 3088 ShareAccess, 3089 FileObject, 3090 &Dcb->ShareAccess ); 3091 } 3092 3093 UnwindShareAccess = TRUE; 3094 3095 // 3096 // Setup the context and section object pointers, and update 3097 // our reference counts 3098 // 3099 3100 FatSetFileObject( FileObject, 3101 UserDirectoryOpen, 3102 Dcb, 3103 UnwindCcb = FatCreateCcb( IrpContext )); 3104 3105 Dcb->UncleanCount += 1; 3106 Dcb->OpenCount += 1; 3107 Vcb->OpenFileCount += 1; 3108 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 3109 3110 // 3111 // Mark the delete on close bit if the caller asked for that. 3112 // 3113 3114 { 3115 PCCB Ccb = (PCCB)FileObject->FsContext2; 3116 3117 3118 if (DeleteOnClose) { 3119 3120 SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); 3121 } 3122 if (FileNameOpenedDos) { 3123 3124 SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 3125 } 3126 3127 } 3128 3129 3130 // 3131 // In case this was set, clear it now. 3132 // 3133 3134 ClearFlag(Dcb->FcbState, FCB_STATE_DELAY_CLOSE); 3135 3136 // 3137 // And set our status to success 3138 // 3139 3140 Iosb.Status = STATUS_SUCCESS; 3141 Iosb.Information = FILE_OPENED; 3142 3143 try_exit: NOTHING; 3144 } _SEH2_FINALLY { 3145 3146 DebugUnwind( FatOpenExistingDcb ); 3147 3148 // 3149 // Unpin the Dirent Bcb if pinned. 3150 // 3151 3152 FatUnpinBcb( IrpContext, DirentBcb ); 3153 3154 // 3155 // If this is an abnormal termination then undo our work 3156 // 3157 3158 if (_SEH2_AbnormalTermination()) { 3159 3160 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 3161 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); } 3162 } 3163 3164 if (DcbAcquired) { 3165 3166 FatReleaseFcb( IrpContext, Dcb ); 3167 } 3168 3169 DebugTrace(-1, Dbg, "FatOpenExistingDcb -> Iosb.Status = %08lx\n", Iosb.Status); 3170 } _SEH2_END; 3171 3172 return Iosb; 3173 } 3174 3175 3176 // 3177 // Internal support routine 3178 // 3179 3180 _Requires_lock_held_(_Global_critical_region_) 3181 IO_STATUS_BLOCK 3182 FatOpenExistingFcb ( 3183 _In_ PIRP_CONTEXT IrpContext, 3184 _In_ PIO_STACK_LOCATION IrpSp, 3185 _Inout_ PFILE_OBJECT FileObject, 3186 _Inout_ PVCB Vcb, 3187 _Inout_ PFCB Fcb, 3188 _In_ PACCESS_MASK DesiredAccess, 3189 _In_ USHORT ShareAccess, 3190 _In_ ULONG AllocationSize, 3191 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 3192 _In_ ULONG EaLength, 3193 _In_ USHORT FileAttributes, 3194 _In_ ULONG CreateDisposition, 3195 _In_ BOOLEAN NoEaKnowledge, 3196 _In_ BOOLEAN DeleteOnClose, 3197 _In_ BOOLEAN OpenRequiringOplock, 3198 _In_ BOOLEAN FileNameOpenedDos, 3199 _Out_ PBOOLEAN OplockPostIrp 3200 ) 3201 3202 /*++ 3203 3204 Routine Description: 3205 3206 This routine opens the specified existing fcb 3207 3208 Arguments: 3209 3210 FileObject - Supplies the File object 3211 3212 Vcb - Supplies the Vcb denoting the volume containing the Fcb 3213 3214 Fcb - Supplies the already existing fcb 3215 3216 DesiredAccess - Supplies the desired access of the caller 3217 3218 ShareAccess - Supplies the share access of the caller 3219 3220 AllocationSize - Supplies the initial allocation if the file is being 3221 superseded or overwritten 3222 3223 EaBuffer - Supplies the Ea set if the file is being superseded or 3224 overwritten 3225 3226 EaLength - Supplies the size, in byte, of the EaBuffer 3227 3228 FileAttributes - Supplies file attributes to use if the file is being 3229 superseded or overwritten 3230 3231 CreateDisposition - Supplies the create disposition for this operation 3232 3233 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 3234 open if the file has NeedEa's. 3235 3236 DeleteOnClose - The caller wants the file gone when the handle is closed 3237 3238 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option. 3239 3240 FileNameOpenedDos - The caller hit the short side of the name pair finding 3241 this file 3242 3243 OplockPostIrp - Address to store boolean indicating if the Irp needs to 3244 be posted to the Fsp. 3245 3246 Return Value: 3247 3248 IO_STATUS_BLOCK - Returns the completion status for the operation 3249 3250 --*/ 3251 3252 { 3253 IO_STATUS_BLOCK Iosb = {0}; 3254 3255 PBCB DirentBcb = NULL; 3256 PDIRENT Dirent; 3257 3258 ACCESS_MASK AddedAccess = 0; 3259 3260 // 3261 // The following variables are for abnormal termination 3262 // 3263 3264 BOOLEAN UnwindShareAccess = FALSE; 3265 PCCB UnwindCcb = NULL; 3266 BOOLEAN DecrementFcbOpenCount = FALSE; 3267 BOOLEAN FcbAcquired = FALSE; 3268 3269 3270 PAGED_CODE(); 3271 3272 DebugTrace(+1, Dbg, "FatOpenExistingFcb...\n", 0); 3273 3274 // 3275 // Get the Fcb exlcusive. This is important as cleanup does not 3276 // acquire the Vcb. 3277 // 3278 3279 (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb ); 3280 FcbAcquired = TRUE; 3281 3282 _SEH2_TRY { 3283 3284 3285 *OplockPostIrp = FALSE; 3286 3287 #if (NTDDI_VERSION >= NTDDI_WIN7) 3288 3289 // 3290 // Let's make sure that if the caller provided an oplock key that it 3291 // gets stored in the file object. 3292 // 3293 3294 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb), 3295 IrpContext->OriginatingIrp, 3296 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 3297 NULL, 3298 NULL, 3299 NULL ); 3300 3301 if (Iosb.Status != STATUS_SUCCESS) { 3302 3303 try_return( NOTHING ); 3304 } 3305 #endif 3306 3307 // 3308 // Take special action if there is a current batch oplock or 3309 // batch oplock break in process on the Fcb. 3310 // 3311 3312 if (FsRtlCurrentBatchOplock( FatGetFcbOplock(Fcb) )) { 3313 3314 // 3315 // We remember if a batch oplock break is underway for the 3316 // case where the sharing check fails. 3317 // 3318 3319 Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY; 3320 3321 Iosb.Status = FsRtlCheckOplock( FatGetFcbOplock(Fcb), 3322 IrpContext->OriginatingIrp, 3323 IrpContext, 3324 FatOplockComplete, 3325 FatPrePostIrp ); 3326 3327 // 3328 // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted 3329 // to service an oplock break and we need to leave now. 3330 // 3331 3332 if (Iosb.Status == STATUS_PENDING) { 3333 3334 *OplockPostIrp = TRUE; 3335 try_return( NOTHING ); 3336 } 3337 } 3338 3339 // 3340 // Check if the user wanted to create the file, also special case 3341 // the supersede and overwrite options. Those add additional, 3342 // possibly only implied, desired accesses to the caller, which 3343 // we must be careful to pull back off if the caller did not actually 3344 // request them. 3345 // 3346 // In other words, check against the implied access, but do not modify 3347 // share access as a result. 3348 // 3349 3350 if (CreateDisposition == FILE_CREATE) { 3351 3352 Iosb.Status = STATUS_OBJECT_NAME_COLLISION; 3353 try_return( Iosb ); 3354 3355 } else if (CreateDisposition == FILE_SUPERSEDE) { 3356 3357 SetFlag( AddedAccess, 3358 DELETE & ~(*DesiredAccess) ); 3359 3360 *DesiredAccess |= DELETE; 3361 3362 } else if ((CreateDisposition == FILE_OVERWRITE) || 3363 (CreateDisposition == FILE_OVERWRITE_IF)) { 3364 3365 SetFlag( AddedAccess, 3366 (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) ); 3367 3368 *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES; 3369 } 3370 3371 // 3372 // Check the desired access 3373 // 3374 3375 if (!FatCheckFileAccess( IrpContext, 3376 Fcb->DirentFatFlags, 3377 DesiredAccess )) { 3378 3379 Iosb.Status = STATUS_ACCESS_DENIED; 3380 try_return( Iosb ); 3381 } 3382 3383 3384 // 3385 // Check for trying to delete a read only file. 3386 // 3387 3388 if (DeleteOnClose && 3389 FlagOn( Fcb->DirentFatFlags, FAT_DIRENT_ATTR_READ_ONLY )) { 3390 3391 Iosb.Status = STATUS_CANNOT_DELETE; 3392 try_return( Iosb ); 3393 } 3394 3395 // 3396 // If we are asked to do an overwrite or supersede operation then 3397 // deny access for files where the file attributes for system and 3398 // hidden do not match 3399 // 3400 3401 if ((CreateDisposition == FILE_SUPERSEDE) || 3402 (CreateDisposition == FILE_OVERWRITE) || 3403 (CreateDisposition == FILE_OVERWRITE_IF)) { 3404 3405 BOOLEAN Hidden; 3406 BOOLEAN System; 3407 3408 Hidden = BooleanFlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_HIDDEN ); 3409 System = BooleanFlagOn(Fcb->DirentFatFlags, FAT_DIRENT_ATTR_SYSTEM ); 3410 3411 if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) || 3412 (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) { 3413 3414 DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0); 3415 3416 3417 Iosb.Status = STATUS_ACCESS_DENIED; 3418 try_return( Iosb ); 3419 } 3420 3421 // 3422 // If this media is write protected, don't even try the create. 3423 // 3424 3425 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) { 3426 3427 // 3428 // Set the real device for the pop-up info, and set the verify 3429 // bit in the device object, so that we will force a verify 3430 // in case the user put the correct media back in. 3431 // 3432 3433 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 3434 Vcb->Vpb->RealDevice ); 3435 3436 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 3437 3438 FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); 3439 } 3440 } 3441 3442 // 3443 // Check if the Fcb has the proper share access. This routine will also 3444 // check for writable user secions if the user did not allow write sharing. 3445 // 3446 3447 if (!NT_SUCCESS(Iosb.Status = FatCheckShareAccess( IrpContext, 3448 FileObject, 3449 Fcb, 3450 DesiredAccess, 3451 ShareAccess ))) { 3452 3453 #if (NTDDI_VERSION >= NTDDI_WIN7) 3454 3455 NTSTATUS OplockBreakStatus = STATUS_SUCCESS; 3456 3457 // 3458 // If we got a sharing violation try to break outstanding handle 3459 // oplocks and retry the sharing check. If the caller specified 3460 // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock; 3461 // we just return the sharing violation. 3462 // 3463 3464 if ((Iosb.Status == STATUS_SHARING_VIOLATION) && 3465 !FlagOn( IrpSp->Parameters.Create.Options, FILE_COMPLETE_IF_OPLOCKED )) { 3466 3467 OplockBreakStatus = FsRtlOplockBreakH( FatGetFcbOplock(Fcb), 3468 IrpContext->OriginatingIrp, 3469 0, 3470 IrpContext, 3471 FatOplockComplete, 3472 FatPrePostIrp ); 3473 3474 // 3475 // If FsRtlOplockBreakH returned STATUS_PENDING, then the IRP 3476 // has been posted and we need to stop working. 3477 // 3478 3479 if (OplockBreakStatus == STATUS_PENDING) { 3480 3481 Iosb.Status = STATUS_PENDING; 3482 *OplockPostIrp = TRUE; 3483 try_return( NOTHING ); 3484 3485 // 3486 // If FsRtlOplockBreakH returned an error we want to return that now. 3487 // 3488 3489 } else if (!NT_SUCCESS( OplockBreakStatus )) { 3490 3491 Iosb.Status = OplockBreakStatus; 3492 try_return( Iosb ); 3493 3494 // 3495 // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating 3496 // that there is no oplock to be broken. The sharing violation is 3497 // returned in that case. 3498 // 3499 3500 } else { 3501 3502 NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS ); 3503 3504 try_return( Iosb ); 3505 } 3506 3507 // 3508 // The initial sharing check failed with something other than sharing 3509 // violation (which should never happen, but let's be future-proof), 3510 // or we *did* get a sharing violation and the caller specified 3511 // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over. 3512 // 3513 3514 } else { 3515 3516 try_return( Iosb ); 3517 } 3518 3519 #else 3520 3521 try_return( Iosb ); 3522 3523 #endif 3524 } 3525 3526 // 3527 // Now check that we can continue based on the oplock state of the 3528 // file. If there are no open handles yet we don't need to do this 3529 // check; oplocks can only exist when there are handles. 3530 // 3531 // It is important that we modified the DesiredAccess in place so 3532 // that the Oplock check proceeds against any added access we had 3533 // to give the caller. 3534 // 3535 3536 if (Fcb->UncleanCount != 0) { 3537 3538 Iosb.Status = FsRtlCheckOplock( FatGetFcbOplock(Fcb), 3539 IrpContext->OriginatingIrp, 3540 IrpContext, 3541 FatOplockComplete, 3542 FatPrePostIrp ); 3543 } 3544 3545 // 3546 // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted 3547 // to service an oplock break and we need to leave now. 3548 // 3549 3550 if (Iosb.Status == STATUS_PENDING) { 3551 3552 *OplockPostIrp = TRUE; 3553 try_return( NOTHING ); 3554 } 3555 3556 // 3557 // If the caller wants atomic create-with-oplock semantics, tell 3558 // the oplock package. We haven't incremented the Fcb's UncleanCount 3559 // for this create yet, so add that in on the call. 3560 // 3561 3562 if (OpenRequiringOplock && 3563 (Iosb.Status == STATUS_SUCCESS)) { 3564 3565 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Fcb), 3566 IrpContext->OriginatingIrp, 3567 (Fcb->UncleanCount + 1) ); 3568 } 3569 3570 // 3571 // If we've encountered a failure we need to leave. FsRtlCheckOplock 3572 // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated 3573 // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED 3574 // on the create call. That's an NT_SUCCESS code, so we need to keep 3575 // going. 3576 // 3577 3578 if ((Iosb.Status != STATUS_SUCCESS) && 3579 (Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) { 3580 3581 try_return( NOTHING ); 3582 } 3583 3584 // 3585 // Set the flag indicating if Fast I/O is possible 3586 // 3587 3588 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb ); 3589 3590 // 3591 // If the user wants write access access to the file make sure there 3592 // is not a process mapping this file as an image. Any attempt to 3593 // delete the file will be stopped in fileinfo.c 3594 // 3595 // If the user wants to delete on close, we must check at this 3596 // point though. 3597 // 3598 3599 if (FlagOn(*DesiredAccess, FILE_WRITE_DATA) || DeleteOnClose) { 3600 3601 Fcb->OpenCount += 1; 3602 DecrementFcbOpenCount = TRUE; 3603 3604 if (!MmFlushImageSection( &Fcb->NonPaged->SectionObjectPointers, 3605 MmFlushForWrite )) { 3606 3607 Iosb.Status = DeleteOnClose ? STATUS_CANNOT_DELETE : 3608 STATUS_SHARING_VIOLATION; 3609 try_return( Iosb ); 3610 } 3611 } 3612 3613 // 3614 // If this is a non-cached open on a non-paging file, and there 3615 // are no open cached handles, but there is a still a data 3616 // section, attempt a flush and purge operation to avoid cache 3617 // coherency overhead later. We ignore any I/O errors from 3618 // the flush. 3619 // 3620 // We set the CREATE_IN_PROGRESS flag to prevent the Fcb from 3621 // going away out from underneath us. 3622 // 3623 3624 if (FlagOn( FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING ) && 3625 (Fcb->UncleanCount == Fcb->NonCachedUncleanCount) && 3626 (Fcb->NonPaged->SectionObjectPointers.DataSectionObject != NULL) && 3627 !FlagOn( Fcb->FcbState, FCB_STATE_PAGING_FILE )) { 3628 3629 SetFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS); 3630 3631 CcFlushCache( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, NULL ); 3632 3633 // 3634 // Grab and release PagingIo to serialize ourselves with the lazy writer. 3635 // This will work to ensure that all IO has completed on the cached 3636 // data and we will succesfully tear away the cache section. 3637 // 3638 3639 ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE); 3640 ExReleaseResourceLite( Fcb->Header.PagingIoResource ); 3641 3642 CcPurgeCacheSection( &Fcb->NonPaged->SectionObjectPointers, 3643 NULL, 3644 0, 3645 FALSE ); 3646 3647 ClearFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS); 3648 } 3649 3650 // 3651 // Check if the user only wanted to open the file 3652 // 3653 3654 if ((CreateDisposition == FILE_OPEN) || 3655 (CreateDisposition == FILE_OPEN_IF)) { 3656 3657 DebugTrace(0, Dbg, "Doing open operation\n", 0); 3658 3659 // 3660 // If the caller has no Ea knowledge, we immediately check for 3661 // Need Ea's on the file. 3662 // 3663 3664 if (NoEaKnowledge && !FatIsFat32(Vcb)) { 3665 3666 ULONG NeedEaCount; 3667 3668 // 3669 // Get the dirent for the file and then check that the need 3670 // ea count is 0. 3671 // 3672 3673 FatGetDirentFromFcbOrDcb( IrpContext, 3674 Fcb, 3675 FALSE, 3676 &Dirent, 3677 &DirentBcb ); 3678 3679 FatGetNeedEaCount( IrpContext, 3680 Vcb, 3681 Dirent, 3682 &NeedEaCount ); 3683 3684 FatUnpinBcb( IrpContext, DirentBcb ); 3685 3686 if (NeedEaCount != 0) { 3687 3688 Iosb.Status = STATUS_ACCESS_DENIED; 3689 try_return( Iosb ); 3690 } 3691 } 3692 3693 // 3694 // Everything checks out okay, so setup the context and 3695 // section object pointers. 3696 // 3697 3698 FatSetFileObject( FileObject, 3699 UserFileOpen, 3700 Fcb, 3701 UnwindCcb = FatCreateCcb( IrpContext )); 3702 3703 FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers; 3704 3705 // 3706 // Fill in the information field, the status field is already 3707 // set. 3708 // 3709 3710 Iosb.Information = FILE_OPENED; 3711 3712 try_return( Iosb ); 3713 } 3714 3715 // 3716 // Check if we are to supersede/overwrite the file, we can wait for 3717 // any I/O at this point 3718 // 3719 3720 if ((CreateDisposition == FILE_SUPERSEDE) || 3721 (CreateDisposition == FILE_OVERWRITE) || 3722 (CreateDisposition == FILE_OVERWRITE_IF)) { 3723 3724 NTSTATUS OldStatus; 3725 3726 DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0); 3727 3728 // 3729 // We remember the previous status code because it may contain 3730 // information about the oplock status. 3731 // 3732 3733 OldStatus = Iosb.Status; 3734 3735 // 3736 // Determine the granted access for this operation now. 3737 // 3738 3739 if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) { 3740 3741 try_return( Iosb ); 3742 } 3743 3744 // 3745 // And overwrite the file. 3746 // 3747 3748 Iosb = FatSupersedeOrOverwriteFile( IrpContext, 3749 FileObject, 3750 Fcb, 3751 AllocationSize, 3752 EaBuffer, 3753 EaLength, 3754 FileAttributes, 3755 CreateDisposition, 3756 NoEaKnowledge ); 3757 3758 if (Iosb.Status == STATUS_SUCCESS) { 3759 3760 Iosb.Status = OldStatus; 3761 } 3762 3763 try_return( Iosb ); 3764 } 3765 3766 // 3767 // If we ever get here then the I/O system gave us some bad input 3768 // 3769 3770 #ifdef _MSC_VER 3771 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" ) 3772 #endif 3773 FatBugCheck( CreateDisposition, 0, 0 ); 3774 3775 try_exit: NOTHING; 3776 3777 // 3778 // Update the share access and counts if successful 3779 // 3780 3781 if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS(Iosb.Status)) { 3782 3783 // 3784 // Now, we may have added some access bits above to indicate the access 3785 // this caller would conflict with (as opposed to what they get) in order 3786 // to perform the overwrite/supersede. We need to make a call to that will 3787 // recalculate the bits in the fileobject to reflect the real access they 3788 // will get. 3789 // 3790 3791 if (AddedAccess) { 3792 3793 NTSTATUS Status; 3794 3795 ClearFlag( *DesiredAccess, AddedAccess ); 3796 3797 #ifdef _MSC_VER 3798 #pragma prefast( suppress:28931, "it needs to be there for debug assert" ); 3799 #endif 3800 Status = IoCheckShareAccess( *DesiredAccess, 3801 ShareAccess, 3802 FileObject, 3803 &Fcb->ShareAccess, 3804 TRUE ); 3805 3806 // 3807 // It must be the case that we are really asking for less access, so 3808 // any conflict must have been detected before this point. 3809 // 3810 3811 NT_ASSERT( Status == STATUS_SUCCESS ); 3812 3813 } else { 3814 3815 IoUpdateShareAccess( FileObject, &Fcb->ShareAccess ); 3816 } 3817 3818 UnwindShareAccess = TRUE; 3819 3820 // 3821 // In case this was set, clear it now. 3822 // 3823 3824 ClearFlag(Fcb->FcbState, FCB_STATE_DELAY_CLOSE); 3825 3826 Fcb->UncleanCount += 1; 3827 Fcb->OpenCount += 1; 3828 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { 3829 Fcb->NonCachedUncleanCount += 1; 3830 } 3831 Vcb->OpenFileCount += 1; 3832 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 3833 3834 { 3835 PCCB Ccb; 3836 3837 Ccb = (PCCB)FileObject->FsContext2; 3838 3839 // 3840 // Mark the DeleteOnClose bit if the operation was successful. 3841 // 3842 3843 if ( DeleteOnClose ) { 3844 3845 SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); 3846 } 3847 3848 // 3849 // Mark the OpenedByShortName bit if the operation was successful. 3850 // 3851 3852 if ( FileNameOpenedDos ) { 3853 3854 SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 3855 } 3856 3857 // 3858 // Mark the ManageVolumeAccess bit if the privilege is held. 3859 // 3860 3861 if (FatCheckManageVolumeAccess( IrpContext, 3862 IrpSp->Parameters.Create.SecurityContext->AccessState, 3863 (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? 3864 UserMode : 3865 IrpContext->OriginatingIrp->RequestorMode ))) { 3866 3867 SetFlag( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); 3868 } 3869 } 3870 3871 3872 } 3873 3874 } _SEH2_FINALLY { 3875 3876 DebugUnwind( FatOpenExistingFcb ); 3877 3878 // 3879 // Unpin the Dirent Bcb if pinned. 3880 // 3881 3882 FatUnpinBcb( IrpContext, DirentBcb ); 3883 3884 // 3885 // If this is an abnormal termination then undo our work 3886 // 3887 3888 if (_SEH2_AbnormalTermination()) { 3889 3890 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 3891 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Fcb->ShareAccess ); } 3892 } 3893 3894 if (DecrementFcbOpenCount) { 3895 3896 Fcb->OpenCount -= 1; 3897 3898 if (Fcb->OpenCount == 0) { 3899 if (ARGUMENT_PRESENT( FileObject )) { 3900 FileObject->SectionObjectPointer = NULL; 3901 } 3902 FatDeleteFcb( IrpContext, &Fcb ); 3903 FcbAcquired = FALSE; 3904 } 3905 } 3906 3907 if (FcbAcquired) { 3908 3909 FatReleaseFcb( IrpContext, Fcb ); 3910 } 3911 3912 DebugTrace(-1, Dbg, "FatOpenExistingFcb -> Iosb.Status = %08lx\n", Iosb.Status); 3913 } _SEH2_END; 3914 3915 return Iosb; 3916 } 3917 3918 // 3919 // Internal support routine 3920 // 3921 3922 _Requires_lock_held_(_Global_critical_region_) 3923 IO_STATUS_BLOCK 3924 FatOpenTargetDirectory ( 3925 _In_ PIRP_CONTEXT IrpContext, 3926 _Inout_ PFILE_OBJECT FileObject, 3927 _Inout_ PDCB Dcb, 3928 _In_ PACCESS_MASK DesiredAccess, 3929 _In_ USHORT ShareAccess, 3930 _In_ BOOLEAN DoesNameExist, 3931 _In_ BOOLEAN FileNameOpenedDos 3932 ) 3933 3934 /*++ 3935 3936 Routine Description: 3937 3938 This routine opens the target directory and replaces the name in the 3939 file object with the remaining name. 3940 3941 Arguments: 3942 3943 FileObject - Supplies the File object 3944 3945 Dcb - Supplies an already existing dcb that we are going to open 3946 3947 DesiredAccess - Supplies the desired access of the caller 3948 3949 ShareAccess - Supplies the share access of the caller 3950 3951 DoesNameExist - Indicates if the file name already exists in the 3952 target directory. 3953 3954 3955 Return Value: 3956 3957 IO_STATUS_BLOCK - Returns the completion status for the operation 3958 3959 --*/ 3960 3961 { 3962 IO_STATUS_BLOCK Iosb = {0}; 3963 3964 // 3965 // The following variables are for abnormal termination 3966 // 3967 3968 BOOLEAN UnwindShareAccess = FALSE; 3969 PCCB UnwindCcb = NULL; 3970 BOOLEAN DcbAcquired = FALSE; 3971 3972 PAGED_CODE(); 3973 3974 DebugTrace(+1, Dbg, "FatOpenTargetDirectory...\n", 0); 3975 3976 // 3977 // Get the Dcb exlcusive. This is important as cleanup does not 3978 // acquire the Vcb. 3979 // 3980 3981 (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb ); 3982 DcbAcquired = TRUE; 3983 3984 _SEH2_TRY { 3985 3986 ULONG i; 3987 3988 // 3989 // If the Dcb is already opened by someone then we need 3990 // to check the share access 3991 // 3992 3993 if (Dcb->OpenCount > 0) { 3994 3995 if (!NT_SUCCESS(Iosb.Status = IoCheckShareAccess( *DesiredAccess, 3996 ShareAccess, 3997 FileObject, 3998 &Dcb->ShareAccess, 3999 TRUE ))) { 4000 4001 try_return( Iosb ); 4002 } 4003 4004 } else { 4005 4006 IoSetShareAccess( *DesiredAccess, 4007 ShareAccess, 4008 FileObject, 4009 &Dcb->ShareAccess ); 4010 } 4011 4012 UnwindShareAccess = TRUE; 4013 4014 // 4015 // Setup the context and section object pointers, and update 4016 // our reference counts 4017 // 4018 4019 FatSetFileObject( FileObject, 4020 UserDirectoryOpen, 4021 Dcb, 4022 UnwindCcb = FatCreateCcb( IrpContext )); 4023 4024 Dcb->UncleanCount += 1; 4025 Dcb->OpenCount += 1; 4026 Dcb->Vcb->OpenFileCount += 1; 4027 if (IsFileObjectReadOnly(FileObject)) { Dcb->Vcb->ReadOnlyCount += 1; } 4028 4029 // 4030 // Update the name in the file object, by definition the remaining 4031 // part must be shorter than the original file name so we'll just 4032 // overwrite the file name. 4033 // 4034 4035 i = FileObject->FileName.Length/sizeof(WCHAR) - 1; 4036 4037 // 4038 // Get rid of a trailing backslash 4039 // 4040 4041 if (FileObject->FileName.Buffer[i] == L'\\') { 4042 4043 NT_ASSERT(i != 0); 4044 4045 FileObject->FileName.Length -= sizeof(WCHAR); 4046 i -= 1; 4047 } 4048 4049 // 4050 // Find the first non-backslash character. i will be its index. 4051 // 4052 4053 while (TRUE) { 4054 4055 if (FileObject->FileName.Buffer[i] == L'\\') { 4056 4057 i += 1; 4058 break; 4059 } 4060 4061 if (i == 0) { 4062 break; 4063 } 4064 4065 i--; 4066 } 4067 4068 if (i) { 4069 4070 FileObject->FileName.Length -= (USHORT)(i * sizeof(WCHAR)); 4071 4072 RtlMoveMemory( &FileObject->FileName.Buffer[0], 4073 &FileObject->FileName.Buffer[i], 4074 FileObject->FileName.Length ); 4075 } 4076 4077 // 4078 // And set our status to success 4079 // 4080 4081 Iosb.Status = STATUS_SUCCESS; 4082 Iosb.Information = (DoesNameExist ? FILE_EXISTS : FILE_DOES_NOT_EXIST); 4083 4084 if ( ( NT_SUCCESS(Iosb.Status) ) && ( DoesNameExist ) ) { 4085 PCCB Ccb; 4086 4087 Ccb = (PCCB)FileObject->FsContext2; 4088 4089 // 4090 // Mark the OpenedByShortName bit if the operation was successful. 4091 // 4092 4093 if ( FileNameOpenedDos ) { 4094 4095 SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 4096 } 4097 } 4098 4099 try_exit: NOTHING; 4100 } _SEH2_FINALLY { 4101 4102 DebugUnwind( FatOpenTargetDirectory ); 4103 4104 // 4105 // If this is an abnormal termination then undo our work 4106 // 4107 4108 if (_SEH2_AbnormalTermination()) { 4109 4110 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 4111 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); } 4112 } 4113 4114 if (DcbAcquired) { 4115 4116 FatReleaseFcb( IrpContext, Dcb ); 4117 } 4118 4119 DebugTrace(-1, Dbg, "FatOpenTargetDirectory -> Iosb.Status = %08lx\n", Iosb.Status); 4120 } _SEH2_END; 4121 4122 return Iosb; 4123 } 4124 4125 4126 4127 // 4128 // Internal support routine 4129 // 4130 _Success_(return.Status == STATUS_SUCCESS) 4131 _Requires_lock_held_(_Global_critical_region_) 4132 IO_STATUS_BLOCK 4133 #ifdef _MSC_VER 4134 #pragma warning(suppress:6101) // bug in PREFast means the _Success_ annotation is not correctly applied 4135 #endif 4136 FatOpenExistingDirectory ( 4137 _In_ PIRP_CONTEXT IrpContext, 4138 _In_ PIO_STACK_LOCATION IrpSp, 4139 _Inout_ PFILE_OBJECT FileObject, 4140 _Inout_ PVCB Vcb, 4141 _Outptr_result_maybenull_ PDCB *Dcb, 4142 _In_ PDCB ParentDcb, 4143 _In_ PDIRENT Dirent, 4144 _In_ ULONG LfnByteOffset, 4145 _In_ ULONG DirentByteOffset, 4146 _In_ PUNICODE_STRING Lfn, 4147 _In_ PACCESS_MASK DesiredAccess, 4148 _In_ USHORT ShareAccess, 4149 _In_ ULONG CreateDisposition, 4150 _In_ BOOLEAN NoEaKnowledge, 4151 _In_ BOOLEAN DeleteOnClose, 4152 _In_ BOOLEAN FileNameOpenedDos, 4153 _In_ BOOLEAN OpenRequiringOplock 4154 ) 4155 4156 /*++ 4157 4158 Routine Description: 4159 4160 This routine opens the specified directory. The directory has not 4161 previously been opened. 4162 4163 Arguments: 4164 4165 FileObject - Supplies the File object 4166 4167 Vcb - Supplies the Vcb denoting the volume containing the dcb 4168 4169 Dcb - Returns the newly-created DCB for the file. 4170 4171 ParentDcb - Supplies the parent directory containing the subdirectory 4172 to be opened 4173 4174 DirectoryName - Supplies the file name of the directory being opened. 4175 4176 Dirent - Supplies the dirent for the directory being opened 4177 4178 LfnByteOffset - Tells where the Lfn begins. If there is no Lfn 4179 this field is the same as DirentByteOffset. 4180 4181 DirentByteOffset - Supplies the Vbo of the dirent within its parent 4182 directory 4183 4184 Lfn - May supply a long name for the file. 4185 4186 DesiredAccess - Supplies the desired access of the caller 4187 4188 ShareAccess - Supplies the share access of the caller 4189 4190 CreateDisposition - Supplies the create disposition for this operation 4191 4192 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 4193 open if the file has NeedEa's. 4194 4195 DeleteOnClose - The caller wants the file gone when the handle is closed 4196 4197 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option. 4198 4199 Return Value: 4200 4201 IO_STATUS_BLOCK - Returns the completion status for the operation 4202 4203 --*/ 4204 4205 { 4206 IO_STATUS_BLOCK Iosb = {0}; 4207 4208 // 4209 // The following variables are for abnormal termination 4210 // 4211 4212 PDCB UnwindDcb = NULL; 4213 PCCB UnwindCcb = NULL; 4214 4215 BOOLEAN CountsIncremented = FALSE; 4216 4217 UNREFERENCED_PARAMETER( DeleteOnClose ); 4218 #if (NTDDI_VERSION <= NTDDI_WIN7) 4219 UNREFERENCED_PARAMETER( OpenRequiringOplock ); 4220 #endif 4221 UNREFERENCED_PARAMETER( IrpSp ); 4222 4223 PAGED_CODE(); 4224 4225 DebugTrace(+1, Dbg, "FatOpenExistingDirectory...\n", 0); 4226 4227 _SEH2_TRY { 4228 4229 // 4230 // If the caller has no Ea knowledge, we immediately check for 4231 // Need Ea's on the file. 4232 // 4233 4234 if (NoEaKnowledge && !FatIsFat32(Vcb)) { 4235 4236 ULONG NeedEaCount; 4237 4238 FatGetNeedEaCount( IrpContext, 4239 Vcb, 4240 Dirent, 4241 &NeedEaCount ); 4242 4243 if (NeedEaCount != 0) { 4244 4245 Iosb.Status = STATUS_ACCESS_DENIED; 4246 try_return( Iosb ); 4247 } 4248 } 4249 4250 // 4251 // Check the create disposition and desired access 4252 // 4253 4254 if ((CreateDisposition != FILE_OPEN) && 4255 (CreateDisposition != FILE_OPEN_IF)) { 4256 4257 Iosb.Status = STATUS_OBJECT_NAME_COLLISION; 4258 try_return( Iosb ); 4259 } 4260 4261 if (!FatCheckFileAccess( IrpContext, 4262 Dirent->Attributes, 4263 DesiredAccess)) { 4264 4265 Iosb.Status = STATUS_ACCESS_DENIED; 4266 try_return( Iosb ); 4267 } 4268 4269 // 4270 // Create a new dcb for the directory 4271 // 4272 4273 *Dcb = UnwindDcb = FatCreateDcb( IrpContext, 4274 Vcb, 4275 ParentDcb, 4276 LfnByteOffset, 4277 DirentByteOffset, 4278 Dirent, 4279 Lfn ); 4280 4281 #if (NTDDI_VERSION >= NTDDI_WIN8) 4282 4283 // 4284 // Let's make sure that if the caller provided an oplock key that it 4285 // gets stored in the file object. 4286 // 4287 4288 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(*Dcb), 4289 IrpContext->OriginatingIrp, 4290 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 4291 NULL, 4292 NULL, 4293 NULL ); 4294 4295 // 4296 // If the caller wants atomic create-with-oplock semantics, tell 4297 // the oplock package. We haven't incremented the Fcb's UncleanCount 4298 // for this create yet, so add that in on the call. 4299 // 4300 4301 if (OpenRequiringOplock && 4302 (Iosb.Status == STATUS_SUCCESS)) { 4303 4304 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(*Dcb), 4305 IrpContext->OriginatingIrp, 4306 ((*Dcb)->UncleanCount + 1) ); 4307 } 4308 4309 // 4310 // Get out if either of the above calls failed. Raise to trigger 4311 // cleanup of the new Dcb. 4312 // 4313 4314 if (Iosb.Status != STATUS_SUCCESS) { 4315 4316 NT_ASSERT( Iosb.Status != STATUS_PENDING ); 4317 4318 FatRaiseStatus( IrpContext, Iosb.Status ); 4319 } 4320 #endif 4321 4322 // 4323 // Setup our share access 4324 // 4325 4326 IoSetShareAccess( *DesiredAccess, 4327 ShareAccess, 4328 FileObject, 4329 &(*Dcb)->ShareAccess ); 4330 4331 // 4332 // Setup the context and section object pointers, and update 4333 // our reference counts 4334 // 4335 4336 FatSetFileObject( FileObject, 4337 UserDirectoryOpen, 4338 (*Dcb), 4339 UnwindCcb = FatCreateCcb( IrpContext )); 4340 4341 (*Dcb)->UncleanCount += 1; 4342 (*Dcb)->OpenCount += 1; 4343 Vcb->OpenFileCount += 1; 4344 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 4345 4346 CountsIncremented = TRUE; 4347 4348 4349 // 4350 // And set our status to success 4351 // 4352 4353 Iosb.Status = STATUS_SUCCESS; 4354 Iosb.Information = FILE_OPENED; 4355 4356 if ( NT_SUCCESS(Iosb.Status) ) { 4357 PCCB Ccb; 4358 4359 Ccb = (PCCB)FileObject->FsContext2; 4360 4361 // 4362 // Mark the OpenedByShortName bit if the operation was successful. 4363 // 4364 4365 if ( FileNameOpenedDos ) { 4366 4367 SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 4368 } 4369 } 4370 4371 try_exit: NOTHING; 4372 } _SEH2_FINALLY { 4373 4374 DebugUnwind( FatOpenExistingDirectory ); 4375 4376 // 4377 // If this is an abnormal termination then undo our work 4378 // 4379 4380 if (_SEH2_AbnormalTermination()) { 4381 4382 if (CountsIncremented) { 4383 4384 (*Dcb)->UncleanCount -= 1; 4385 (*Dcb)->OpenCount -= 1; 4386 Vcb->OpenFileCount -= 1; 4387 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } 4388 } 4389 4390 if (UnwindDcb != NULL) { 4391 if (ARGUMENT_PRESENT( FileObject )) { 4392 FileObject->SectionObjectPointer = NULL; 4393 } 4394 FatDeleteFcb( IrpContext, &UnwindDcb ); 4395 *Dcb = NULL; 4396 } 4397 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 4398 } 4399 4400 DebugTrace(-1, Dbg, "FatOpenExistingDirectory -> Iosb.Status = %08lx\n", Iosb.Status); 4401 } _SEH2_END; 4402 4403 return Iosb; 4404 } 4405 4406 4407 // 4408 // Internal support routine 4409 // 4410 4411 _Requires_lock_held_(_Global_critical_region_) 4412 IO_STATUS_BLOCK 4413 FatOpenExistingFile ( 4414 _In_ PIRP_CONTEXT IrpContext, 4415 _Inout_ PFILE_OBJECT FileObject, 4416 _Inout_ PVCB Vcb, 4417 _Outptr_result_maybenull_ PFCB *Fcb, 4418 _In_ PDCB ParentDcb, 4419 _In_ PDIRENT Dirent, 4420 _In_ ULONG LfnByteOffset, 4421 _In_ ULONG DirentByteOffset, 4422 _In_ PUNICODE_STRING Lfn, 4423 _In_ PUNICODE_STRING OrigLfn, 4424 _In_ PACCESS_MASK DesiredAccess, 4425 _In_ USHORT ShareAccess, 4426 _In_ ULONG AllocationSize, 4427 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 4428 _In_ ULONG EaLength, 4429 _In_ USHORT FileAttributes, 4430 _In_ ULONG CreateDisposition, 4431 _In_ BOOLEAN IsPagingFile, 4432 _In_ BOOLEAN NoEaKnowledge, 4433 _In_ BOOLEAN DeleteOnClose, 4434 _In_ BOOLEAN OpenRequiringOplock, 4435 _In_ BOOLEAN FileNameOpenedDos 4436 ) 4437 4438 /*++ 4439 4440 Routine Description: 4441 4442 This routine opens the specified file. The file has not previously 4443 been opened. 4444 4445 Arguments: 4446 4447 FileObject - Supplies the File object 4448 4449 Vcb - Supplies the Vcb denoting the volume containing the file 4450 4451 Fcb - Returns the newly-created FCB for the file. 4452 4453 ParentDcb - Supplies the parent directory containing the file to be 4454 opened 4455 4456 Dirent - Supplies the dirent for the file being opened 4457 4458 LfnByteOffset - Tells where the Lfn begins. If there is no Lfn 4459 this field is the same as DirentByteOffset. 4460 4461 DirentByteOffset - Supplies the Vbo of the dirent within its parent 4462 directory 4463 4464 Lfn - May supply a long name for the file. 4465 4466 DesiredAccess - Supplies the desired access of the caller 4467 4468 ShareAccess - Supplies the share access of the caller 4469 4470 AllocationSize - Supplies the initial allocation if the file is being 4471 superseded, overwritten, or created. 4472 4473 EaBuffer - Supplies the Ea set if the file is being superseded, 4474 overwritten, or created. 4475 4476 EaLength - Supplies the size, in byte, of the EaBuffer 4477 4478 FileAttributes - Supplies file attributes to use if the file is being 4479 superseded, overwritten, or created 4480 4481 CreateDisposition - Supplies the create disposition for this operation 4482 4483 IsPagingFile - Indicates if this is the paging file being opened. 4484 4485 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 4486 open if the file has NeedEa's. 4487 4488 DeleteOnClose - The caller wants the file gone when the handle is closed 4489 4490 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option. 4491 4492 FileNameOpenedDos - The caller opened this file by hitting the 8.3 side 4493 of the Lfn/8.3 pair 4494 4495 Return Value: 4496 4497 IO_STATUS_BLOCK - Returns the completion status for the operation 4498 4499 --*/ 4500 4501 { 4502 IO_STATUS_BLOCK Iosb = {0}; 4503 4504 ACCESS_MASK AddedAccess = 0; 4505 4506 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp ); 4507 4508 // 4509 // The following variables are for abnormal termination 4510 // 4511 4512 PFCB UnwindFcb = NULL; 4513 PCCB UnwindCcb = NULL; 4514 BOOLEAN CountsIncremented = FALSE; 4515 4516 4517 #if (NTDDI_VERSION < NTDDI_WIN7) 4518 UNREFERENCED_PARAMETER( OpenRequiringOplock ); 4519 #endif 4520 4521 PAGED_CODE(); 4522 4523 DebugTrace(+1, Dbg, "FatOpenExistingFile...\n", 0); 4524 4525 _SEH2_TRY { 4526 4527 // 4528 // Check if the user wanted to create the file or if access is 4529 // denied 4530 // 4531 4532 if (CreateDisposition == FILE_CREATE) { 4533 Iosb.Status = STATUS_OBJECT_NAME_COLLISION; 4534 try_return( Iosb ); 4535 4536 } else if ((CreateDisposition == FILE_SUPERSEDE) && !IsPagingFile) { 4537 4538 SetFlag( AddedAccess, 4539 DELETE & ~(*DesiredAccess) ); 4540 4541 *DesiredAccess |= DELETE; 4542 4543 } else if (((CreateDisposition == FILE_OVERWRITE) || 4544 (CreateDisposition == FILE_OVERWRITE_IF)) && !IsPagingFile) { 4545 4546 SetFlag( AddedAccess, 4547 (FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES) & ~(*DesiredAccess) ); 4548 4549 *DesiredAccess |= FILE_WRITE_DATA | FILE_WRITE_EA | FILE_WRITE_ATTRIBUTES; 4550 } 4551 4552 if (!FatCheckFileAccess( IrpContext, 4553 Dirent->Attributes, 4554 DesiredAccess)) { 4555 4556 Iosb.Status = STATUS_ACCESS_DENIED; 4557 try_return( Iosb ); 4558 } 4559 4560 4561 // 4562 // Check for trying to delete a read only file. 4563 // 4564 4565 if (DeleteOnClose && 4566 FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY )) { 4567 4568 Iosb.Status = STATUS_CANNOT_DELETE; 4569 try_return( Iosb ); 4570 } 4571 4572 // 4573 // IF we are asked to do an overwrite or supersede operation then 4574 // deny access for files where the file attributes for system and 4575 // hidden do not match 4576 // 4577 4578 if ((CreateDisposition == FILE_SUPERSEDE) || 4579 (CreateDisposition == FILE_OVERWRITE) || 4580 (CreateDisposition == FILE_OVERWRITE_IF)) { 4581 4582 BOOLEAN Hidden; 4583 BOOLEAN System; 4584 4585 Hidden = BooleanFlagOn(Dirent->Attributes, FAT_DIRENT_ATTR_HIDDEN ); 4586 System = BooleanFlagOn(Dirent->Attributes, FAT_DIRENT_ATTR_SYSTEM ); 4587 4588 if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) || 4589 (System && !FlagOn(FileAttributes, FILE_ATTRIBUTE_SYSTEM))) { 4590 4591 DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0); 4592 4593 if ( !IsPagingFile ) { 4594 4595 Iosb.Status = STATUS_ACCESS_DENIED; 4596 try_return( Iosb ); 4597 } 4598 } 4599 4600 // 4601 // If this media is write protected, don't even try the create. 4602 // 4603 4604 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) { 4605 4606 // 4607 // Set the real device for the pop-up info, and set the verify 4608 // bit in the device object, so that we will force a verify 4609 // in case the user put the correct media back in. 4610 // 4611 4612 4613 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp, 4614 Vcb->Vpb->RealDevice ); 4615 4616 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME); 4617 4618 FatRaiseStatus( IrpContext, STATUS_MEDIA_WRITE_PROTECTED ); 4619 } 4620 } 4621 4622 // 4623 // Create a new Fcb for the file, and set the file size in 4624 // the fcb. 4625 // 4626 4627 *Fcb = UnwindFcb = FatCreateFcb( IrpContext, 4628 Vcb, 4629 ParentDcb, 4630 LfnByteOffset, 4631 DirentByteOffset, 4632 Dirent, 4633 Lfn, 4634 OrigLfn, 4635 IsPagingFile, 4636 FALSE ); 4637 4638 4639 (*Fcb)->Header.ValidDataLength.LowPart = (*Fcb)->Header.FileSize.LowPart; 4640 4641 // 4642 // If this is a paging file, lookup the allocation size so that 4643 // the Mcb is always valid 4644 // 4645 4646 if (IsPagingFile) { 4647 4648 FatLookupFileAllocationSize( IrpContext, *Fcb ); 4649 } 4650 4651 #if (NTDDI_VERSION >= NTDDI_WIN7) 4652 4653 // 4654 // Let's make sure that if the caller provided an oplock key that it 4655 // gets stored in the file object. 4656 // 4657 4658 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(*Fcb), 4659 IrpContext->OriginatingIrp, 4660 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 4661 NULL, 4662 NULL, 4663 NULL ); 4664 4665 // 4666 // If the caller wants atomic create-with-oplock semantics, tell 4667 // the oplock package. We haven't incremented the Fcb's UncleanCount 4668 // for this create yet, so add that in on the call. 4669 // 4670 4671 if (OpenRequiringOplock && 4672 (Iosb.Status == STATUS_SUCCESS)) { 4673 4674 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(*Fcb), 4675 IrpContext->OriginatingIrp, 4676 ((*Fcb)->UncleanCount + 1) ); 4677 } 4678 4679 // 4680 // Get out if either of the above calls failed. Raise to trigger 4681 // cleanup of the new Fcb. 4682 // 4683 4684 if (Iosb.Status != STATUS_SUCCESS) { 4685 4686 NT_ASSERT( Iosb.Status != STATUS_PENDING ); 4687 4688 FatRaiseStatus( IrpContext, Iosb.Status ); 4689 } 4690 #endif 4691 4692 // 4693 // Now case on whether we are to simply open, supersede, or 4694 // overwrite the file. 4695 // 4696 4697 switch (CreateDisposition) { 4698 4699 case FILE_OPEN: 4700 case FILE_OPEN_IF: 4701 4702 DebugTrace(0, Dbg, "Doing only an open operation\n", 0); 4703 4704 // 4705 // If the caller has no Ea knowledge, we immediately check for 4706 // Need Ea's on the file. 4707 // 4708 4709 if (NoEaKnowledge && !FatIsFat32(Vcb)) { 4710 4711 ULONG NeedEaCount; 4712 4713 FatGetNeedEaCount( IrpContext, 4714 Vcb, 4715 Dirent, 4716 &NeedEaCount ); 4717 4718 if (NeedEaCount != 0) { 4719 4720 FatRaiseStatus( IrpContext, STATUS_ACCESS_DENIED ); 4721 } 4722 } 4723 4724 // 4725 // Setup the context and section object pointers. 4726 // 4727 4728 FatSetFileObject( FileObject, 4729 UserFileOpen, 4730 *Fcb, 4731 UnwindCcb = FatCreateCcb( IrpContext )); 4732 4733 FileObject->SectionObjectPointer = &(*Fcb)->NonPaged->SectionObjectPointers; 4734 4735 Iosb.Status = STATUS_SUCCESS; 4736 Iosb.Information = FILE_OPENED; 4737 break; 4738 4739 case FILE_SUPERSEDE: 4740 case FILE_OVERWRITE: 4741 case FILE_OVERWRITE_IF: 4742 4743 DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0); 4744 4745 // 4746 // Determine the granted access for this operation now. 4747 // 4748 4749 if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) { 4750 4751 try_return( Iosb ); 4752 } 4753 4754 Iosb = FatSupersedeOrOverwriteFile( IrpContext, 4755 FileObject, 4756 *Fcb, 4757 AllocationSize, 4758 EaBuffer, 4759 EaLength, 4760 FileAttributes, 4761 CreateDisposition, 4762 NoEaKnowledge ); 4763 break; 4764 4765 default: 4766 4767 DebugTrace(0, Dbg, "Illegal Create Disposition\n", 0); 4768 4769 #ifdef _MSC_VER 4770 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" ) 4771 #endif 4772 FatBugCheck( CreateDisposition, 0, 0 ); 4773 break; 4774 } 4775 4776 try_exit: NOTHING; 4777 4778 // 4779 // Setup our share access and counts if things were successful. 4780 // 4781 4782 if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS( Iosb.Status )) { 4783 4784 // 4785 // Remove any virtual access the caller needed to check against, but will 4786 // not really receive. Overwrite/supersede is a bit of a special case. 4787 // 4788 4789 ClearFlag( *DesiredAccess, AddedAccess ); 4790 4791 IoSetShareAccess( *DesiredAccess, 4792 ShareAccess, 4793 FileObject, 4794 &(*Fcb)->ShareAccess ); 4795 4796 (*Fcb)->UncleanCount += 1; 4797 (*Fcb)->OpenCount += 1; 4798 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { 4799 (*Fcb)->NonCachedUncleanCount += 1; 4800 } 4801 Vcb->OpenFileCount += 1; 4802 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 4803 4804 CountsIncremented = TRUE; 4805 } 4806 4807 { 4808 PCCB Ccb; 4809 4810 Ccb = (PCCB)FileObject->FsContext2; 4811 4812 if ( NT_SUCCESS(Iosb.Status) ) { 4813 4814 // 4815 // Mark the DeleteOnClose bit if the operation was successful. 4816 // 4817 4818 if ( DeleteOnClose ) { 4819 4820 SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); 4821 } 4822 4823 // 4824 // Mark the OpenedByShortName bit if the operation was successful. 4825 // 4826 4827 if ( FileNameOpenedDos ) { 4828 4829 SetFlag( Ccb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 4830 } 4831 4832 // 4833 // Mark the ManageVolumeAccess bit if the privilege is held. 4834 // 4835 4836 if (FatCheckManageVolumeAccess( IrpContext, 4837 IrpSp->Parameters.Create.SecurityContext->AccessState, 4838 (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? 4839 UserMode : 4840 IrpContext->OriginatingIrp->RequestorMode ))) { 4841 4842 SetFlag( Ccb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); 4843 } 4844 4845 } 4846 } 4847 4848 4849 } _SEH2_FINALLY { 4850 4851 DebugUnwind( FatOpenExistingFile ); 4852 4853 // 4854 // If this is an abnormal termination then undo our work 4855 // 4856 4857 if (_SEH2_AbnormalTermination()) { 4858 4859 if (CountsIncremented) { 4860 (*Fcb)->UncleanCount -= 1; 4861 (*Fcb)->OpenCount -= 1; 4862 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { 4863 (*Fcb)->NonCachedUncleanCount -= 1; 4864 } 4865 Vcb->OpenFileCount -= 1; 4866 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } 4867 } 4868 4869 if (UnwindFcb != NULL) { 4870 if (ARGUMENT_PRESENT( FileObject )) { 4871 FileObject->SectionObjectPointer = NULL; 4872 } 4873 FatDeleteFcb( IrpContext, &UnwindFcb ); 4874 *Fcb = NULL; 4875 } 4876 4877 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 4878 } 4879 4880 DebugTrace(-1, Dbg, "FatOpenExistingFile -> Iosb.Status = %08lx\n", Iosb.Status); 4881 } _SEH2_END; 4882 4883 return Iosb; 4884 } 4885 4886 4887 // 4888 // Internal support routine 4889 // 4890 4891 _Requires_lock_held_(_Global_critical_region_) 4892 IO_STATUS_BLOCK 4893 FatCreateNewDirectory ( 4894 _In_ PIRP_CONTEXT IrpContext, 4895 _In_ PIO_STACK_LOCATION IrpSp, 4896 _Inout_ PFILE_OBJECT FileObject, 4897 _Inout_ PVCB Vcb, 4898 _Inout_ PDCB ParentDcb, 4899 _In_ POEM_STRING OemName, 4900 _In_ PUNICODE_STRING UnicodeName, 4901 _In_ PACCESS_MASK DesiredAccess, 4902 _In_ USHORT ShareAccess, 4903 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 4904 _In_ ULONG EaLength, 4905 _In_ USHORT FileAttributes, 4906 _In_ BOOLEAN NoEaKnowledge, 4907 _In_ BOOLEAN DeleteOnClose, 4908 _In_ BOOLEAN OpenRequiringOplock 4909 ) 4910 4911 /*++ 4912 4913 Routine Description: 4914 4915 This routine creates a new directory. The directory has already been 4916 verified not to exist yet. 4917 4918 Arguments: 4919 4920 FileObject - Supplies the file object for the newly created directory 4921 4922 Vcb - Supplies the Vcb denote the volume to contain the new directory 4923 4924 ParentDcb - Supplies the parent directory containg the newly created 4925 directory 4926 4927 OemName - Supplies the Oem name for the newly created directory. It may 4928 or maynot be 8.3 complient, but will be upcased. 4929 4930 UnicodeName - Supplies the Unicode name for the newly created directory. 4931 It may or maynot be 8.3 complient. This name contains the original 4932 case information. 4933 4934 DesiredAccess - Supplies the desired access of the caller 4935 4936 ShareAccess - Supplies the shared access of the caller 4937 4938 EaBuffer - Supplies the Ea set for the newly created directory 4939 4940 EaLength - Supplies the length, in bytes, of EaBuffer 4941 4942 FileAttributes - Supplies the file attributes for the newly created 4943 directory. 4944 4945 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 4946 open if the file has NeedEa's. 4947 4948 DeleteOnClose - The caller wants the file gone when the handle is closed 4949 4950 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option. 4951 4952 Return Value: 4953 4954 IO_STATUS_BLOCK - Returns the completion status for the operation 4955 4956 --*/ 4957 4958 { 4959 IO_STATUS_BLOCK Iosb; 4960 4961 PDCB Dcb = NULL; 4962 PCCB Ccb = NULL; 4963 4964 PDIRENT Dirent = NULL; 4965 PBCB DirentBcb = NULL; 4966 ULONG DirentsNeeded; 4967 ULONG DirentByteOffset; 4968 4969 PDIRENT ShortDirent; 4970 ULONG ShortDirentByteOffset; 4971 4972 USHORT EaHandle; 4973 4974 BOOLEAN AllLowerComponent; 4975 BOOLEAN AllLowerExtension; 4976 BOOLEAN CreateLfn; 4977 4978 ULONG BytesInFirstPage = 0; 4979 ULONG DirentsInFirstPage = 0; 4980 PDIRENT FirstPageDirent = 0; 4981 4982 PBCB SecondPageBcb = NULL; 4983 ULONG SecondPageOffset; 4984 PDIRENT SecondPageDirent = NULL; 4985 4986 BOOLEAN DirentFromPool = FALSE; 4987 4988 4989 OEM_STRING ShortName; 4990 UCHAR ShortNameBuffer[12]; 4991 4992 #if (NTDDI_VERSION <= NTDDI_WIN7) 4993 UNREFERENCED_PARAMETER( OpenRequiringOplock ); 4994 #endif 4995 4996 UNREFERENCED_PARAMETER( IrpSp ); 4997 4998 PAGED_CODE(); 4999 5000 DebugTrace(+1, Dbg, "FatCreateNewDirectory...\n", 0); 5001 5002 ShortName.Length = 0; 5003 ShortName.MaximumLength = 12; 5004 ShortName.Buffer = (PCHAR)&ShortNameBuffer[0]; 5005 5006 EaHandle = 0; 5007 5008 // 5009 // We fail this operation if the caller doesn't understand Ea's. 5010 // 5011 5012 if (NoEaKnowledge 5013 && EaLength > 0) { 5014 5015 Iosb.Status = STATUS_ACCESS_DENIED; 5016 5017 DebugTrace(-1, Dbg, "FatCreateNewDirectory -> Iosb.Status = %08lx\n", Iosb.Status); 5018 return Iosb; 5019 } 5020 5021 // 5022 // DeleteOnClose and ReadOnly are not compatible. 5023 // 5024 5025 if (DeleteOnClose && FlagOn(FileAttributes, FAT_DIRENT_ATTR_READ_ONLY)) { 5026 5027 Iosb.Status = STATUS_CANNOT_DELETE; 5028 return Iosb; 5029 } 5030 5031 // Now get the names that we will be using. 5032 // 5033 5034 FatSelectNames( IrpContext, 5035 ParentDcb, 5036 OemName, 5037 UnicodeName, 5038 &ShortName, 5039 NULL, 5040 &AllLowerComponent, 5041 &AllLowerExtension, 5042 &CreateLfn ); 5043 5044 // 5045 // If we are not in Chicago mode, ignore the magic bits. 5046 // 5047 5048 if (!FatData.ChicagoMode) { 5049 5050 AllLowerComponent = FALSE; 5051 AllLowerExtension = FALSE; 5052 CreateLfn = FALSE; 5053 } 5054 5055 // 5056 // Create/allocate a new dirent 5057 // 5058 5059 DirentsNeeded = CreateLfn ? FAT_LFN_DIRENTS_NEEDED(UnicodeName) + 1 : 1; 5060 5061 DirentByteOffset = FatCreateNewDirent( IrpContext, 5062 ParentDcb, 5063 DirentsNeeded, 5064 FALSE ); 5065 _SEH2_TRY { 5066 5067 FatPrepareWriteDirectoryFile( IrpContext, 5068 ParentDcb, 5069 DirentByteOffset, 5070 sizeof(DIRENT), 5071 &DirentBcb, 5072 #ifndef __REACTOS__ 5073 &Dirent, 5074 #else 5075 (PVOID *)&Dirent, 5076 #endif 5077 FALSE, 5078 TRUE, 5079 &Iosb.Status ); 5080 5081 NT_ASSERT( NT_SUCCESS( Iosb.Status ) && DirentBcb && Dirent ); 5082 5083 // 5084 // Deal with the special case of an LFN + Dirent structure crossing 5085 // a page boundry. 5086 // 5087 5088 if ((DirentByteOffset / PAGE_SIZE) != 5089 ((DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT)) / PAGE_SIZE)) { 5090 5091 SecondPageBcb; 5092 SecondPageOffset; 5093 SecondPageDirent; 5094 5095 SecondPageOffset = (DirentByteOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE; 5096 5097 BytesInFirstPage = SecondPageOffset - DirentByteOffset; 5098 5099 DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT); 5100 5101 FatPrepareWriteDirectoryFile( IrpContext, 5102 ParentDcb, 5103 SecondPageOffset, 5104 sizeof(DIRENT), 5105 &SecondPageBcb, 5106 #ifndef __REACTOS__ 5107 &SecondPageDirent, 5108 #else 5109 (PVOID *)&SecondPageDirent, 5110 #endif 5111 FALSE, 5112 TRUE, 5113 &Iosb.Status ); 5114 5115 NT_ASSERT( NT_SUCCESS( Iosb.Status ) && SecondPageBcb && SecondPageDirent ); 5116 5117 FirstPageDirent = Dirent; 5118 5119 Dirent = FsRtlAllocatePoolWithTag( PagedPool, 5120 DirentsNeeded * sizeof(DIRENT), 5121 TAG_DIRENT ); 5122 5123 DirentFromPool = TRUE; 5124 } 5125 5126 // 5127 // Bump up Dirent and DirentByteOffset 5128 // 5129 5130 ShortDirent = Dirent + DirentsNeeded - 1; 5131 ShortDirentByteOffset = DirentByteOffset + 5132 (DirentsNeeded - 1) * sizeof(DIRENT); 5133 5134 NT_ASSERT( NT_SUCCESS( Iosb.Status )); 5135 5136 5137 // 5138 // Fill in the fields of the dirent. 5139 // 5140 5141 FatConstructDirent( IrpContext, 5142 ShortDirent, 5143 &ShortName, 5144 AllLowerComponent, 5145 AllLowerExtension, 5146 CreateLfn ? UnicodeName : NULL, 5147 FileAttributes | FAT_DIRENT_ATTR_DIRECTORY, 5148 TRUE, 5149 NULL ); 5150 5151 // 5152 // If the dirent crossed pages, we have to do some real gross stuff. 5153 // 5154 5155 if (DirentFromPool) { 5156 5157 RtlCopyMemory( FirstPageDirent, Dirent, BytesInFirstPage ); 5158 5159 RtlCopyMemory( SecondPageDirent, 5160 Dirent + DirentsInFirstPage, 5161 DirentsNeeded*sizeof(DIRENT) - BytesInFirstPage ); 5162 5163 ShortDirent = SecondPageDirent + (DirentsNeeded - DirentsInFirstPage) - 1; 5164 } 5165 5166 // 5167 // Create a new dcb for the directory. 5168 // 5169 5170 Dcb = FatCreateDcb( IrpContext, 5171 Vcb, 5172 ParentDcb, 5173 DirentByteOffset, 5174 ShortDirentByteOffset, 5175 ShortDirent, 5176 CreateLfn ? UnicodeName : NULL ); 5177 5178 #if (NTDDI_VERSION >= NTDDI_WIN8) 5179 // 5180 // The next three FsRtl calls are for oplock work. We deliberately 5181 // do these here so that if either call fails we will be able to 5182 // clean up without adding a bunch of code to unwind counts, fix 5183 // the file object, etc. 5184 // 5185 5186 // 5187 // Let's make sure that if the caller provided an oplock key that it 5188 // gets stored in the file object. 5189 // 5190 5191 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Dcb), 5192 IrpContext->OriginatingIrp, 5193 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 5194 NULL, 5195 NULL, 5196 NULL ); 5197 5198 // 5199 // If the caller wants atomic create-with-oplock semantics, tell 5200 // the oplock package. We haven't incremented the Dcb's UncleanCount 5201 // for this create yet, so add that in on the call. 5202 // 5203 5204 if (OpenRequiringOplock && 5205 (Iosb.Status == STATUS_SUCCESS)) { 5206 5207 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Dcb), 5208 IrpContext->OriginatingIrp, 5209 (Dcb->UncleanCount + 1) ); 5210 } 5211 5212 // 5213 // Break parent directory oplock. Directory oplock breaks are always 5214 // advisory, so we will never block/get STATUS_PENDING here. On the 5215 // off chance this fails with INSUFFICIENT_RESOURCES we do it here 5216 // where we can still tolerate a failure. 5217 // 5218 5219 if (Iosb.Status == STATUS_SUCCESS) { 5220 5221 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(ParentDcb), 5222 IrpContext->OriginatingIrp, 5223 OPLOCK_FLAG_PARENT_OBJECT, 5224 NULL, 5225 NULL, 5226 NULL ); 5227 } 5228 5229 // 5230 // Get out if any of the oplock calls failed. 5231 // 5232 5233 if (Iosb.Status != STATUS_SUCCESS) { 5234 5235 FatRaiseStatus( IrpContext, Iosb.Status ); 5236 } 5237 #endif 5238 5239 // 5240 // Tentatively add the new Ea's, 5241 // 5242 5243 if (EaLength > 0) { 5244 5245 // 5246 // This returns false if we are trying to create a file 5247 // with Need Ea's and don't understand EA's. 5248 // 5249 5250 FatCreateEa( IrpContext, 5251 Dcb->Vcb, 5252 (PUCHAR) EaBuffer, 5253 EaLength, 5254 &Dcb->ShortName.Name.Oem, 5255 &EaHandle ); 5256 } 5257 5258 if (!FatIsFat32(Dcb->Vcb)) { 5259 5260 ShortDirent->ExtendedAttributes = EaHandle; 5261 } 5262 5263 // 5264 // After this point we cannot just simply mark the dirent deleted, 5265 // we have to deal with the directory file object. 5266 // 5267 5268 // 5269 // Make the dirent into a directory. Note that even if this call 5270 // raises because of disk space, the diectory file object has been 5271 // created. 5272 // 5273 5274 FatInitializeDirectoryDirent( IrpContext, Dcb, ShortDirent ); 5275 5276 // 5277 // Setup the context and section object pointers, and update 5278 // our reference counts. Note that this call cannot fail. 5279 // 5280 5281 FatSetFileObject( FileObject, 5282 UserDirectoryOpen, 5283 Dcb, 5284 Ccb = FatCreateCcb( IrpContext ) ); 5285 5286 // 5287 // Initialize the LongFileName if it has not already been set, so that 5288 // FatNotify below won't have to. If there are filesystem filters 5289 // attached to FAT, the LongFileName could have gotten set if the 5290 // filter queried for name information on this file object while 5291 // watching the IO needed in FatInitializeDirectoryDirent. 5292 // 5293 5294 if (Dcb->FullFileName.Buffer == NULL) { 5295 5296 FatSetFullNameInFcb( IrpContext, Dcb, UnicodeName ); 5297 } 5298 5299 // 5300 // We call the notify package to report that the 5301 // we added a file. 5302 // 5303 5304 FatNotifyReportChange( IrpContext, 5305 Vcb, 5306 Dcb, 5307 FILE_NOTIFY_CHANGE_DIR_NAME, 5308 FILE_ACTION_ADDED ); 5309 5310 // 5311 // Setup our share access 5312 // 5313 5314 IoSetShareAccess( *DesiredAccess, 5315 ShareAccess, 5316 FileObject, 5317 &Dcb->ShareAccess ); 5318 5319 5320 // 5321 // From this point on, nothing can raise. 5322 // 5323 5324 Dcb->UncleanCount += 1; 5325 Dcb->OpenCount += 1; 5326 Vcb->OpenFileCount += 1; 5327 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 5328 5329 if (DeleteOnClose) { 5330 5331 SetFlag( Ccb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); 5332 } 5333 5334 // 5335 // And set our return status 5336 // 5337 5338 Iosb.Status = STATUS_SUCCESS; 5339 Iosb.Information = FILE_CREATED; 5340 5341 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 5342 5343 // 5344 // We'll catch all exceptions and handle them below. 5345 // 5346 5347 Iosb.Status = IrpContext->ExceptionStatus; 5348 } _SEH2_END; 5349 5350 // 5351 // If we failed then undo our work. 5352 // 5353 5354 if (!NT_SUCCESS( Iosb.Status )) { 5355 5356 // 5357 // We always have to delete the Ccb if we created one. 5358 // 5359 5360 if ( Ccb != NULL ) { 5361 5362 FatDeleteCcb( IrpContext, &Ccb ); 5363 } 5364 5365 #ifdef _MSC_VER 5366 #pragma prefast( suppress: 28924, "prefast thinks this test is redundant, but DCB can be NULL depending on where we raise" ) 5367 #endif 5368 if ( Dcb == NULL) { 5369 5370 NT_ASSERT( (ParentDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) || 5371 RtlAreBitsSet( &ParentDcb->Specific.Dcb.FreeDirentBitmap, 5372 DirentByteOffset / sizeof(DIRENT), 5373 DirentsNeeded ) ); 5374 5375 RtlClearBits( &ParentDcb->Specific.Dcb.FreeDirentBitmap, 5376 DirentByteOffset / sizeof(DIRENT), 5377 DirentsNeeded ); 5378 5379 // 5380 // Mark the dirents deleted. The codes is complex because of 5381 // dealing with an LFN than crosses a page boundry. 5382 // 5383 5384 if (Dirent != NULL) { 5385 5386 ULONG i; 5387 5388 // 5389 // We failed before creating a directory file object. 5390 // We can just mark the dirent deleted and exit. 5391 // 5392 5393 for (i = 0; i < DirentsNeeded; i++) { 5394 5395 if (DirentFromPool == FALSE) { 5396 5397 // 5398 // Simple case. 5399 // 5400 5401 Dirent[i].FileName[0] = FAT_DIRENT_DELETED; 5402 5403 } else { 5404 5405 // 5406 // If the second CcPreparePinWrite failed, we have 5407 // to stop early. 5408 // 5409 5410 if ((SecondPageBcb == NULL) && 5411 (i == DirentsInFirstPage)) { 5412 5413 break; 5414 } 5415 5416 // 5417 // Now conditionally update either page. 5418 // 5419 5420 if (i < DirentsInFirstPage) { 5421 5422 FirstPageDirent[i].FileName[0] = FAT_DIRENT_DELETED; 5423 5424 } else { 5425 5426 SecondPageDirent[i - DirentsInFirstPage].FileName[0] = FAT_DIRENT_DELETED; 5427 } 5428 } 5429 } 5430 } 5431 } 5432 } 5433 5434 // 5435 // Just drop the Bcbs we have in the parent right now so if we 5436 // failed to create the directory and we take the path to rip apart 5437 // the partially created child, when we sync-uninit we won't cause 5438 // a lazy writer processing the parent to block on us. This would 5439 // consume one of the lazy writers, one of which must be running free 5440 // in order for us to come back from the sync-uninit. 5441 // 5442 // Neat, huh? 5443 // 5444 // Granted, the delete dirent below will be marginally less efficient 5445 // since the Bcb may be reclaimed by the time it executes. Life is 5446 // tough. 5447 // 5448 5449 FatUnpinBcb( IrpContext, DirentBcb ); 5450 FatUnpinBcb( IrpContext, SecondPageBcb ); 5451 5452 if (DirentFromPool) { 5453 5454 ExFreePool( Dirent ); 5455 } 5456 5457 if (!NT_SUCCESS( Iosb.Status )) { 5458 5459 #ifdef _MSC_VER 5460 #pragma prefast( suppress: 28924, "prefast thinks this test is redundant, but DCB can be NULL depending on where we raise" ) 5461 #endif 5462 if (Dcb != NULL) { 5463 5464 // 5465 // We have created the Dcb. If an error occurred while 5466 // creating the Ea's, there will be no directory file 5467 // object. 5468 // 5469 5470 PFILE_OBJECT DirectoryFileObject; 5471 5472 DirectoryFileObject = Dcb->Specific.Dcb.DirectoryFile; 5473 5474 // 5475 // Knock down all of the repinned data so we can begin to destroy 5476 // this failed child. We don't care about any raising here - we're 5477 // already got a fire going. 5478 // 5479 // Note that if we failed to do this, the repinned initial pieces 5480 // of the child would cause the sync-uninit to block forever. 5481 // 5482 // A previous spin on this fix had us not make the ./.. creation 5483 // "reversible" (bad term) and thus avoid having the Bcb still 5484 // outstanding. This wound up causing very bad things to happen 5485 // on DMF floppies when we tried to do a similar yank-down in the 5486 // create path - we want the purge it does to make sure we never 5487 // try to write the bytes out ... it is just a lot cleaner to 5488 // unpinrepin. I'll leave the reversible logic in place if it ever 5489 // proves useful. 5490 // 5491 5492 // 5493 // There is a possibility that this may be a generally good idea 5494 // for "live" finally clauses - set in ExceptionFilter, clear in 5495 // ProcessException. Think about this. 5496 // 5497 5498 SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE ); 5499 FatUnpinRepinnedBcbs( IrpContext ); 5500 ClearFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE ); 5501 5502 if (Dcb->FirstClusterOfFile != 0) { 5503 5504 _SEH2_TRY { 5505 5506 Dcb->Header.FileSize.LowPart = 0; 5507 5508 CcSetFileSizes( Dcb->Specific.Dcb.DirectoryFile, 5509 (PCC_FILE_SIZES)&Dcb->Header.AllocationSize ); 5510 5511 // 5512 // Now zap the allocation backing it. 5513 // 5514 5515 FatTruncateFileAllocation( IrpContext, Dcb, 0 ); 5516 5517 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 5518 5519 // 5520 // We catch all exceptions that Fat catches, but don't do 5521 // anything with them. 5522 // 5523 } _SEH2_END; 5524 } 5525 5526 if (DirectoryFileObject != NULL) { 5527 5528 FatSyncUninitializeCacheMap( IrpContext, 5529 DirectoryFileObject ); 5530 } 5531 5532 5533 _SEH2_TRY { 5534 5535 // 5536 // Remove the directory entry we made in the parent Dcb. 5537 // 5538 5539 FatDeleteDirent( IrpContext, Dcb, NULL, TRUE ); 5540 5541 // 5542 // FatDeleteDirent can pin and dirty BCBs, so lets unrepin again. 5543 // 5544 5545 FatUnpinRepinnedBcbs( IrpContext ); 5546 5547 } _SEH2_EXCEPT(FatExceptionFilter( IrpContext, _SEH2_GetExceptionInformation() )) { 5548 5549 // 5550 // We catch all exceptions that Fat catches, but don't do 5551 // anything with them. 5552 // 5553 } _SEH2_END; 5554 5555 // 5556 // Finaly, dereference the directory file object. This will 5557 // cause a close Irp to be processed, blowing away the Fcb. 5558 // 5559 5560 if (DirectoryFileObject != NULL) { 5561 5562 // 5563 // Dereference the file object for this DCB. The DCB will 5564 // go away when this file object is closed. 5565 // 5566 5567 Dcb->Specific.Dcb.DirectoryFile = NULL; 5568 ObDereferenceObject( DirectoryFileObject ); 5569 5570 } else { 5571 5572 // 5573 // This was also a PDK fix. If the stream file exists, this would 5574 // be done during the dereference file object operation. Otherwise 5575 // we have to remove the Dcb and check if we should remove the parent. 5576 // For now we will just leave the parent lying around. 5577 // 5578 5579 #ifdef _MSC_VER 5580 #pragma prefast( suppress: 28924, "prefast thinks this test is redundant, but FileObject can be NULL depending on where we raise" ) 5581 #endif 5582 if (ARGUMENT_PRESENT( FileObject )) { 5583 FileObject->SectionObjectPointer = NULL; 5584 } 5585 FatDeleteFcb( IrpContext, &Dcb ); 5586 } 5587 } 5588 5589 DebugTrace(-1, Dbg, "FatCreateNewDirectory -> Iosb.Status = %08lx\n", Iosb.Status); 5590 5591 FatRaiseStatus( IrpContext, Iosb.Status ); 5592 } 5593 5594 UNREFERENCED_PARAMETER( EaBuffer ); 5595 UNREFERENCED_PARAMETER( EaLength ); 5596 5597 return Iosb; 5598 } 5599 5600 5601 // 5602 // Internal support routine 5603 // 5604 5605 _Requires_lock_held_(_Global_critical_region_) 5606 IO_STATUS_BLOCK 5607 FatCreateNewFile ( 5608 _In_ PIRP_CONTEXT IrpContext, 5609 _In_ PIO_STACK_LOCATION IrpSp, 5610 _Inout_ PFILE_OBJECT FileObject, 5611 _Inout_ PVCB Vcb, 5612 _Inout_ PDCB ParentDcb, 5613 _In_ POEM_STRING OemName, 5614 _In_ PUNICODE_STRING UnicodeName, 5615 _In_ PACCESS_MASK DesiredAccess, 5616 _In_ USHORT ShareAccess, 5617 _In_ ULONG AllocationSize, 5618 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 5619 _In_ ULONG EaLength, 5620 _In_ USHORT FileAttributes, 5621 _In_ PUNICODE_STRING LfnBuffer, 5622 _In_ BOOLEAN IsPagingFile, 5623 _In_ BOOLEAN NoEaKnowledge, 5624 _In_ BOOLEAN DeleteOnClose, 5625 _In_ BOOLEAN OpenRequiringOplock, 5626 _In_ BOOLEAN TemporaryFile 5627 ) 5628 5629 /*++ 5630 5631 Routine Description: 5632 5633 This routine creates a new file. The file has already been verified 5634 not to exist yet. 5635 5636 Arguments: 5637 5638 FileObject - Supplies the file object for the newly created file 5639 5640 Vcb - Supplies the Vcb denote the volume to contain the new file 5641 5642 ParentDcb - Supplies the parent directory containg the newly created 5643 File 5644 5645 OemName - Supplies the Oem name for the newly created file. It may 5646 or maynot be 8.3 complient, but will be upcased. 5647 5648 UnicodeName - Supplies the Unicode name for the newly created file. 5649 It may or maynot be 8.3 complient. This name contains the original 5650 case information. 5651 5652 DesiredAccess - Supplies the desired access of the caller 5653 5654 ShareAccess - Supplies the shared access of the caller 5655 5656 AllocationSize - Supplies the initial allocation size for the file 5657 5658 EaBuffer - Supplies the Ea set for the newly created file 5659 5660 EaLength - Supplies the length, in bytes, of EaBuffer 5661 5662 FileAttributes - Supplies the file attributes for the newly created 5663 file 5664 5665 LfnBuffer - A MAX_LFN sized buffer for directory searching 5666 5667 IsPagingFile - Indicates if this is the paging file being created 5668 5669 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 5670 open if the file has NeedEa's. 5671 5672 DeleteOnClose - The caller wants the file gone when the handle is closed 5673 5674 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option. 5675 5676 TemporaryFile - Signals the lazywriter to not write dirty data unless 5677 absolutely has to. 5678 5679 5680 Return Value: 5681 5682 IO_STATUS_BLOCK - Returns the completion status for the operation 5683 5684 --*/ 5685 5686 { 5687 IO_STATUS_BLOCK Iosb = {0}; 5688 5689 PFCB Fcb = NULL; 5690 5691 PDIRENT Dirent = NULL; 5692 PBCB DirentBcb = NULL; 5693 ULONG DirentsNeeded; 5694 ULONG DirentByteOffset; 5695 5696 PDIRENT ShortDirent; 5697 ULONG ShortDirentByteOffset; 5698 5699 USHORT EaHandle; 5700 5701 BOOLEAN AllLowerComponent; 5702 BOOLEAN AllLowerExtension; 5703 BOOLEAN CreateLfn; 5704 5705 ULONG BytesInFirstPage = 0; 5706 ULONG DirentsInFirstPage = 0; 5707 PDIRENT FirstPageDirent = NULL; 5708 5709 PBCB SecondPageBcb = NULL; 5710 ULONG SecondPageOffset; 5711 PDIRENT SecondPageDirent = NULL; 5712 5713 BOOLEAN DirentFromPool = FALSE; 5714 5715 OEM_STRING ShortName; 5716 UCHAR ShortNameBuffer[12]; 5717 5718 UNICODE_STRING UniTunneledShortName; 5719 WCHAR UniTunneledShortNameBuffer[12]; 5720 UNICODE_STRING UniTunneledLongName; 5721 WCHAR UniTunneledLongNameBuffer[26]; 5722 LARGE_INTEGER TunneledCreationTime; 5723 ULONG TunneledDataSize; 5724 BOOLEAN HaveTunneledInformation; 5725 BOOLEAN UsingTunneledLfn = FALSE; 5726 5727 PUNICODE_STRING RealUnicodeName; 5728 5729 5730 // 5731 // The following variables are for abnormal termination 5732 // 5733 5734 PDIRENT UnwindDirent = NULL; 5735 PFCB UnwindFcb = NULL; 5736 BOOLEAN UnwindAllocation = FALSE; 5737 BOOLEAN CountsIncremented = FALSE; 5738 PCCB UnwindCcb = NULL; 5739 5740 ULONG LocalAbnormalTermination = FALSE; 5741 5742 #if (NTDDI_VERSION < NTDDI_WIN7) 5743 UNREFERENCED_PARAMETER( OpenRequiringOplock ); 5744 #endif 5745 5746 PAGED_CODE(); 5747 5748 DebugTrace(+1, Dbg, "FatCreateNewFile...\n", 0); 5749 5750 ShortName.Length = 0; 5751 ShortName.MaximumLength = sizeof(ShortNameBuffer); 5752 ShortName.Buffer = (PCHAR)&ShortNameBuffer[0]; 5753 5754 UniTunneledShortName.Length = 0; 5755 UniTunneledShortName.MaximumLength = sizeof(UniTunneledShortNameBuffer); 5756 UniTunneledShortName.Buffer = &UniTunneledShortNameBuffer[0]; 5757 5758 UniTunneledLongName.Length = 0; 5759 UniTunneledLongName.MaximumLength = sizeof(UniTunneledLongNameBuffer); 5760 UniTunneledLongName.Buffer = &UniTunneledLongNameBuffer[0]; 5761 5762 EaHandle = 0; 5763 5764 // 5765 // We fail this operation if the caller doesn't understand Ea's. 5766 // 5767 5768 if (NoEaKnowledge 5769 && EaLength > 0) { 5770 5771 Iosb.Status = STATUS_ACCESS_DENIED; 5772 5773 DebugTrace(-1, Dbg, "FatCreateNewFile -> Iosb.Status = %08lx\n", Iosb.Status); 5774 return Iosb; 5775 } 5776 5777 // 5778 // DeleteOnClose and ReadOnly are not compatible. 5779 // 5780 5781 if (DeleteOnClose && FlagOn(FileAttributes, FAT_DIRENT_ATTR_READ_ONLY)) { 5782 5783 Iosb.Status = STATUS_CANNOT_DELETE; 5784 return Iosb; 5785 } 5786 5787 // 5788 // Look in the tunnel cache for names and timestamps to restore 5789 // 5790 5791 TunneledDataSize = sizeof(LARGE_INTEGER); 5792 HaveTunneledInformation = FsRtlFindInTunnelCache( &Vcb->Tunnel, 5793 FatDirectoryKey(ParentDcb), 5794 UnicodeName, 5795 &UniTunneledShortName, 5796 &UniTunneledLongName, 5797 &TunneledDataSize, 5798 &TunneledCreationTime ); 5799 NT_ASSERT(TunneledDataSize == sizeof(LARGE_INTEGER)); 5800 5801 // 5802 // Now get the names that we will be using. 5803 // 5804 5805 FatSelectNames( IrpContext, 5806 ParentDcb, 5807 OemName, 5808 UnicodeName, 5809 &ShortName, 5810 (HaveTunneledInformation? &UniTunneledShortName : NULL), 5811 &AllLowerComponent, 5812 &AllLowerExtension, 5813 &CreateLfn ); 5814 5815 // 5816 // If we are not in Chicago mode, ignore the magic bits. 5817 // 5818 5819 RealUnicodeName = UnicodeName; 5820 5821 if (!FatData.ChicagoMode) { 5822 5823 AllLowerComponent = FALSE; 5824 AllLowerExtension = FALSE; 5825 CreateLfn = FALSE; 5826 5827 } else { 5828 5829 // 5830 // If the Unicode name was legal for a short name and we got 5831 // a tunneling hit which had a long name associated which is 5832 // avaliable for use, use it. 5833 // 5834 5835 if (!CreateLfn && 5836 UniTunneledLongName.Length && 5837 !FatLfnDirentExists(IrpContext, ParentDcb, &UniTunneledLongName, LfnBuffer)) { 5838 5839 UsingTunneledLfn = TRUE; 5840 CreateLfn = TRUE; 5841 5842 RealUnicodeName = &UniTunneledLongName; 5843 5844 // 5845 // Short names are always upcase if an LFN exists 5846 // 5847 5848 AllLowerComponent = FALSE; 5849 AllLowerExtension = FALSE; 5850 } 5851 } 5852 5853 5854 // 5855 // Create/allocate a new dirent 5856 // 5857 5858 DirentsNeeded = CreateLfn ? FAT_LFN_DIRENTS_NEEDED(RealUnicodeName) + 1 : 1; 5859 5860 DirentByteOffset = FatCreateNewDirent( IrpContext, 5861 ParentDcb, 5862 DirentsNeeded, 5863 FALSE ); 5864 5865 _SEH2_TRY { 5866 5867 FatPrepareWriteDirectoryFile( IrpContext, 5868 ParentDcb, 5869 DirentByteOffset, 5870 sizeof(DIRENT), 5871 &DirentBcb, 5872 #ifndef __REACTOS__ 5873 &Dirent, 5874 #else 5875 (PVOID *)&Dirent, 5876 #endif 5877 FALSE, 5878 TRUE, 5879 &Iosb.Status ); 5880 5881 NT_ASSERT( NT_SUCCESS( Iosb.Status ) ); 5882 5883 UnwindDirent = Dirent; 5884 5885 // 5886 // Deal with the special case of an LFN + Dirent structure crossing 5887 // a page boundry. 5888 // 5889 5890 if ((DirentByteOffset / PAGE_SIZE) != 5891 ((DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT)) / PAGE_SIZE)) { 5892 5893 SecondPageBcb; 5894 SecondPageOffset; 5895 SecondPageDirent; 5896 5897 SecondPageOffset = (DirentByteOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE; 5898 5899 BytesInFirstPage = SecondPageOffset - DirentByteOffset; 5900 5901 DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT); 5902 5903 FatPrepareWriteDirectoryFile( IrpContext, 5904 ParentDcb, 5905 SecondPageOffset, 5906 sizeof(DIRENT), 5907 &SecondPageBcb, 5908 #ifndef __REACTOS__ 5909 &SecondPageDirent, 5910 #else 5911 (PVOID *)&SecondPageDirent, 5912 #endif 5913 FALSE, 5914 TRUE, 5915 &Iosb.Status ); 5916 5917 NT_ASSERT( NT_SUCCESS( Iosb.Status ) ); 5918 5919 FirstPageDirent = Dirent; 5920 5921 Dirent = FsRtlAllocatePoolWithTag( PagedPool, 5922 DirentsNeeded * sizeof(DIRENT), 5923 TAG_DIRENT ); 5924 5925 DirentFromPool = TRUE; 5926 } 5927 5928 // 5929 // Bump up Dirent and DirentByteOffset 5930 // 5931 5932 ShortDirent = Dirent + DirentsNeeded - 1; 5933 ShortDirentByteOffset = DirentByteOffset + 5934 (DirentsNeeded - 1) * sizeof(DIRENT); 5935 5936 NT_ASSERT( NT_SUCCESS( Iosb.Status )); 5937 5938 5939 // 5940 // Fill in the fields of the dirent. 5941 // 5942 5943 FatConstructDirent( IrpContext, 5944 ShortDirent, 5945 &ShortName, 5946 AllLowerComponent, 5947 AllLowerExtension, 5948 CreateLfn ? RealUnicodeName : NULL, 5949 (FileAttributes | FILE_ATTRIBUTE_ARCHIVE), 5950 TRUE, 5951 (HaveTunneledInformation ? &TunneledCreationTime : NULL) ); 5952 5953 // 5954 // If the dirent crossed pages, we have to do some real gross stuff. 5955 // 5956 5957 if (DirentFromPool) { 5958 5959 RtlCopyMemory( FirstPageDirent, Dirent, BytesInFirstPage ); 5960 5961 RtlCopyMemory( SecondPageDirent, 5962 Dirent + DirentsInFirstPage, 5963 DirentsNeeded*sizeof(DIRENT) - BytesInFirstPage ); 5964 5965 ShortDirent = SecondPageDirent + (DirentsNeeded - DirentsInFirstPage) - 1; 5966 } 5967 5968 // 5969 // Create a new Fcb for the file. Once the Fcb is created we 5970 // will not need to unwind dirent because delete dirent will 5971 // now do the work. 5972 // 5973 5974 Fcb = UnwindFcb = FatCreateFcb( IrpContext, 5975 Vcb, 5976 ParentDcb, 5977 DirentByteOffset, 5978 ShortDirentByteOffset, 5979 ShortDirent, 5980 CreateLfn ? RealUnicodeName : NULL, 5981 CreateLfn ? RealUnicodeName : NULL, 5982 IsPagingFile, 5983 FALSE ); 5984 UnwindDirent = NULL; 5985 5986 #if (NTDDI_VERSION >= NTDDI_WIN7) 5987 // 5988 // The next three FsRtl calls are for oplock work. We deliberately 5989 // do these here so that if either call fails we will be able to 5990 // clean up without adding a bunch of code to unwind counts, fix 5991 // the file object, etc. 5992 // 5993 5994 // 5995 // Let's make sure that if the caller provided an oplock key that it 5996 // gets stored in the file object. 5997 // 5998 5999 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb), 6000 IrpContext->OriginatingIrp, 6001 OPLOCK_FLAG_OPLOCK_KEY_CHECK_ONLY, 6002 NULL, 6003 NULL, 6004 NULL ); 6005 6006 // 6007 // If the caller wants atomic create-with-oplock semantics, tell 6008 // the oplock package. We haven't incremented the Fcb's UncleanCount 6009 // for this create yet, so add that in on the call. 6010 // 6011 6012 if (OpenRequiringOplock && 6013 (Iosb.Status == STATUS_SUCCESS)) { 6014 6015 Iosb.Status = FsRtlOplockFsctrl( FatGetFcbOplock(Fcb), 6016 IrpContext->OriginatingIrp, 6017 (Fcb->UncleanCount + 1) ); 6018 } 6019 #endif 6020 6021 #if (NTDDI_VERSION >= NTDDI_WIN8) 6022 // 6023 // Break parent directory oplock. Directory oplock breaks are always 6024 // advisory, so we will never block/get STATUS_PENDING here. On the 6025 // off chance this fails with INSUFFICIENT_RESOURCES we do it here 6026 // where we can still tolerate a failure. 6027 // 6028 6029 if (Iosb.Status == STATUS_SUCCESS) { 6030 6031 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(ParentDcb), 6032 IrpContext->OriginatingIrp, 6033 OPLOCK_FLAG_PARENT_OBJECT, 6034 NULL, 6035 NULL, 6036 NULL ); 6037 } 6038 6039 // 6040 // Get out if any of the oplock calls failed. We raise to provoke 6041 // abnormal termination and ensure that the newly-created Fcb gets 6042 // deleted. 6043 // 6044 6045 if (Iosb.Status != STATUS_SUCCESS) { 6046 6047 FatRaiseStatus( IrpContext, Iosb.Status ); 6048 } 6049 #endif 6050 6051 // 6052 // If this is a temporary file, note it in the FcbState 6053 // 6054 6055 if (TemporaryFile) { 6056 6057 SetFlag( Fcb->FcbState, FCB_STATE_TEMPORARY ); 6058 } 6059 6060 6061 // 6062 // Add some initial file allocation 6063 // 6064 6065 6066 FatAddFileAllocation( IrpContext, Fcb, FileObject, AllocationSize ); 6067 6068 6069 UnwindAllocation = TRUE; 6070 6071 Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE; 6072 6073 // 6074 // Tentatively add the new Ea's 6075 // 6076 6077 if ( EaLength > 0 ) { 6078 6079 FatCreateEa( IrpContext, 6080 Fcb->Vcb, 6081 (PUCHAR) EaBuffer, 6082 EaLength, 6083 &Fcb->ShortName.Name.Oem, 6084 &EaHandle ); 6085 } 6086 6087 if (!FatIsFat32(Fcb->Vcb)) { 6088 6089 ShortDirent->ExtendedAttributes = EaHandle; 6090 } 6091 6092 6093 6094 // 6095 // Initialize the LongFileName right now so that FatNotify 6096 // below won't have to. 6097 // 6098 6099 if (Fcb->FullFileName.Buffer == NULL) { 6100 FatSetFullNameInFcb( IrpContext, Fcb, RealUnicodeName ); 6101 } 6102 6103 // 6104 // Setup the context and section object pointers, and update 6105 // our reference counts 6106 // 6107 6108 FatSetFileObject( FileObject, 6109 UserFileOpen, 6110 Fcb, 6111 UnwindCcb = FatCreateCcb( IrpContext )); 6112 6113 FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers; 6114 6115 // 6116 // We call the notify package to report that the 6117 // we added a file. 6118 // 6119 6120 FatNotifyReportChange( IrpContext, 6121 Vcb, 6122 Fcb, 6123 FILE_NOTIFY_CHANGE_FILE_NAME, 6124 FILE_ACTION_ADDED ); 6125 6126 // 6127 // Setup our share access 6128 // 6129 6130 IoSetShareAccess( *DesiredAccess, 6131 ShareAccess, 6132 FileObject, 6133 &Fcb->ShareAccess ); 6134 6135 Fcb->UncleanCount += 1; 6136 Fcb->OpenCount += 1; 6137 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { 6138 Fcb->NonCachedUncleanCount += 1; 6139 } 6140 Vcb->OpenFileCount += 1; 6141 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; } 6142 CountsIncremented = TRUE; 6143 6144 6145 // 6146 // And set our return status 6147 // 6148 6149 Iosb.Status = STATUS_SUCCESS; 6150 Iosb.Information = FILE_CREATED; 6151 6152 if ( NT_SUCCESS(Iosb.Status) ) { 6153 6154 // 6155 // Mark the DeleteOnClose bit if the operation was successful. 6156 // 6157 6158 if ( DeleteOnClose ) { 6159 6160 SetFlag( UnwindCcb->Flags, CCB_FLAG_DELETE_ON_CLOSE ); 6161 } 6162 6163 // 6164 // Mark the OpenedByShortName bit if the operation was successful. 6165 // If we created an Lfn, we have some sort of generated short name 6166 // and thus don't consider ourselves to have opened it - though we 6167 // may have had a case mix Lfn "Foo.bar" and generated "FOO.BAR" 6168 // 6169 // Unless, of course, we wanted to create a short name and hit an 6170 // associated Lfn in the tunnel cache 6171 // 6172 6173 if ( !CreateLfn && !UsingTunneledLfn ) { 6174 6175 SetFlag( UnwindCcb->Flags, CCB_FLAG_OPENED_BY_SHORTNAME ); 6176 } 6177 6178 // 6179 // Mark the ManageVolumeAccess bit if the privilege is held. 6180 // 6181 6182 if (FatCheckManageVolumeAccess( IrpContext, 6183 IrpSp->Parameters.Create.SecurityContext->AccessState, 6184 (KPROCESSOR_MODE)( FlagOn( IrpSp->Flags, SL_FORCE_ACCESS_CHECK ) ? 6185 UserMode : 6186 IrpContext->OriginatingIrp->RequestorMode ))) { 6187 6188 SetFlag( UnwindCcb->Flags, CCB_FLAG_MANAGE_VOLUME_ACCESS ); 6189 } 6190 6191 } 6192 6193 6194 } _SEH2_FINALLY { 6195 6196 DebugUnwind( FatCreateNewFile ); 6197 6198 if (UniTunneledLongName.Buffer != UniTunneledLongNameBuffer) { 6199 6200 // 6201 // Tunneling package grew the buffer from pool 6202 // 6203 6204 ExFreePool( UniTunneledLongName.Buffer ); 6205 } 6206 6207 6208 // 6209 // If this is an abnormal termination then undo our work. 6210 // 6211 // The extra exception handling here is complex. We've got 6212 // two places here where an exception can be thrown again. 6213 // 6214 6215 LocalAbnormalTermination = _SEH2_AbnormalTermination(); 6216 6217 if (LocalAbnormalTermination) { 6218 6219 if (CountsIncremented) { 6220 Fcb->UncleanCount -= 1; 6221 Fcb->OpenCount -= 1; 6222 if (FlagOn(FileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING)) { 6223 Fcb->NonCachedUncleanCount -= 1; 6224 } 6225 Vcb->OpenFileCount -= 1; 6226 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; } 6227 } 6228 6229 if (UnwindFcb == NULL) { 6230 6231 NT_ASSERT( (ParentDcb->Specific.Dcb.UnusedDirentVbo == 0xffffffff) || 6232 RtlAreBitsSet( &ParentDcb->Specific.Dcb.FreeDirentBitmap, 6233 DirentByteOffset / sizeof(DIRENT), 6234 DirentsNeeded ) ); 6235 6236 RtlClearBits( &ParentDcb->Specific.Dcb.FreeDirentBitmap, 6237 DirentByteOffset / sizeof(DIRENT), 6238 DirentsNeeded ); 6239 } 6240 6241 // 6242 // Mark the dirents deleted. The code is complex because of 6243 // dealing with an LFN that crosses a page boundary. 6244 // 6245 6246 if (UnwindDirent != NULL) { 6247 6248 ULONG i; 6249 6250 for (i = 0; i < DirentsNeeded; i++) { 6251 6252 if (DirentFromPool == FALSE) { 6253 6254 // 6255 // Simple case. 6256 // 6257 6258 Dirent[i].FileName[0] = FAT_DIRENT_DELETED; 6259 6260 } else { 6261 6262 // 6263 // If the second CcPreparePinWrite failed, we have 6264 // to stop early. 6265 // 6266 6267 if ((SecondPageBcb == NULL) && 6268 (i == DirentsInFirstPage)) { 6269 6270 break; 6271 } 6272 6273 // 6274 // Now conditionally update either page. 6275 // 6276 6277 if (i < DirentsInFirstPage) { 6278 6279 FirstPageDirent[i].FileName[0] = FAT_DIRENT_DELETED; 6280 6281 } else { 6282 6283 SecondPageDirent[i - DirentsInFirstPage].FileName[0] = FAT_DIRENT_DELETED; 6284 } 6285 } 6286 } 6287 } 6288 } 6289 6290 // 6291 // We must handle exceptions in the following fragments and plow on with the 6292 // unwind of this create operation. This is basically inverted from the 6293 // previous state of the code. Since AbnormalTermination() changes when we 6294 // enter a new enclosure, we cached the original state ... 6295 // 6296 6297 _SEH2_TRY { 6298 6299 if (LocalAbnormalTermination) { 6300 if (UnwindAllocation) { 6301 FatTruncateFileAllocation( IrpContext, Fcb, 0 ); 6302 } 6303 } 6304 6305 } _SEH2_FINALLY { 6306 6307 _SEH2_TRY { 6308 6309 if (LocalAbnormalTermination) { 6310 if (UnwindFcb != NULL) { 6311 FatDeleteDirent( IrpContext, UnwindFcb, NULL, TRUE ); 6312 } 6313 } 6314 6315 } _SEH2_FINALLY { 6316 6317 if (LocalAbnormalTermination) { 6318 if (UnwindFcb != NULL) { 6319 if (ARGUMENT_PRESENT( FileObject )) { 6320 FileObject->SectionObjectPointer = NULL; 6321 } 6322 FatDeleteFcb( IrpContext, &UnwindFcb ); 6323 } 6324 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 6325 } 6326 6327 // 6328 // This is the normal cleanup code. 6329 // 6330 6331 FatUnpinBcb( IrpContext, DirentBcb ); 6332 FatUnpinBcb( IrpContext, SecondPageBcb ); 6333 6334 if (DirentFromPool) { 6335 6336 ExFreePool( Dirent ); 6337 } 6338 6339 } _SEH2_END; 6340 } _SEH2_END; 6341 6342 DebugTrace(-1, Dbg, "FatCreateNewFile -> Iosb.Status = %08lx\n", Iosb.Status); 6343 } _SEH2_END; 6344 6345 return Iosb; 6346 } 6347 6348 6349 // 6350 // Internal support routine 6351 // 6352 6353 _Requires_lock_held_(_Global_critical_region_) 6354 IO_STATUS_BLOCK 6355 FatSupersedeOrOverwriteFile ( 6356 _In_ PIRP_CONTEXT IrpContext, 6357 _Inout_ PFILE_OBJECT FileObject, 6358 _Inout_ PFCB Fcb, 6359 _In_ ULONG AllocationSize, 6360 _In_ PFILE_FULL_EA_INFORMATION EaBuffer, 6361 _In_ ULONG EaLength, 6362 _In_ USHORT FileAttributes, 6363 _In_ ULONG CreateDisposition, 6364 _In_ BOOLEAN NoEaKnowledge 6365 ) 6366 6367 /*++ 6368 6369 Routine Description: 6370 6371 This routine performs a file supersede or overwrite operation. 6372 6373 Arguments: 6374 6375 FileObject - Supplies a pointer to the file object 6376 6377 Fcb - Supplies a pointer to the Fcb 6378 6379 AllocationSize - Supplies an initial allocation size 6380 6381 EaBuffer - Supplies the Ea set for the superseded/overwritten file 6382 6383 EaLength - Supplies the length, in bytes, of EaBuffer 6384 6385 FileAttributes - Supplies the supersede/overwrite file attributes 6386 6387 CreateDisposition - Supplies the create disposition for the file 6388 It must be either supersede, overwrite, or overwrite if. 6389 6390 NoEaKnowledge - This opener doesn't understand Ea's and we fail this 6391 open if the file has NeedEa's. 6392 6393 Return Value: 6394 6395 IO_STATUS_BLOCK - Returns the completion status for the operation 6396 6397 --*/ 6398 6399 { 6400 IO_STATUS_BLOCK Iosb = {0}; 6401 6402 PDIRENT Dirent; 6403 PBCB DirentBcb; 6404 6405 USHORT EaHandle = 0; 6406 BOOLEAN EaChange = FALSE; 6407 BOOLEAN ReleasePaging = FALSE; 6408 6409 PCCB Ccb; 6410 6411 ULONG NotifyFilter; 6412 ULONG HeaderSize = 0; 6413 LARGE_INTEGER AllocSize = {0}; 6414 6415 // 6416 // The following variables are for abnormal termination 6417 // 6418 6419 PCCB UnwindCcb = NULL; 6420 USHORT UnwindEa = 0; 6421 6422 PAGED_CODE(); 6423 6424 DebugTrace(+1, Dbg, "FatSupersedeOrOverwriteFile...\n", 0); 6425 6426 DirentBcb = NULL; 6427 6428 // 6429 // We fail this operation if the caller doesn't understand Ea's. 6430 // 6431 6432 if (NoEaKnowledge 6433 && EaLength > 0) { 6434 6435 Iosb.Status = STATUS_ACCESS_DENIED; 6436 6437 DebugTrace(-1, Dbg, "FatSupersedeOrOverwriteFile -> Iosb.Status = %08lx\n", Iosb.Status); 6438 return Iosb; 6439 } 6440 6441 _SEH2_TRY { 6442 6443 // 6444 // Before we actually truncate, check to see if the purge 6445 // is going to fail. 6446 // 6447 6448 if (!MmCanFileBeTruncated( &Fcb->NonPaged->SectionObjectPointers, 6449 &FatLargeZero )) { 6450 6451 try_return( Iosb.Status = STATUS_USER_MAPPED_FILE ); 6452 } 6453 6454 // 6455 // Setup the context and section object pointers, and update 6456 // our reference counts 6457 // 6458 6459 FatSetFileObject( FileObject, 6460 UserFileOpen, 6461 Fcb, 6462 Ccb = UnwindCcb = FatCreateCcb( IrpContext )); 6463 6464 FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers; 6465 6466 // 6467 // Since this is an supersede/overwrite, purge the section so 6468 // that mappers will see zeros. We set the CREATE_IN_PROGRESS flag 6469 // to prevent the Fcb from going away out from underneath us. 6470 // 6471 6472 SetFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS); 6473 6474 CcPurgeCacheSection( &Fcb->NonPaged->SectionObjectPointers, NULL, 0, FALSE ); 6475 6476 // 6477 // Tentatively add the new Ea's 6478 // 6479 6480 if (EaLength > 0) { 6481 6482 FatCreateEa( IrpContext, 6483 Fcb->Vcb, 6484 (PUCHAR) EaBuffer, 6485 EaLength, 6486 &Fcb->ShortName.Name.Oem, 6487 &EaHandle ); 6488 6489 UnwindEa = EaHandle; 6490 EaChange = TRUE; 6491 } 6492 6493 #if (NTDDI_VERSION >= NTDDI_WIN8) 6494 // 6495 // Break parent directory oplock. Directory oplock breaks are always 6496 // advisory, so we will never block/get STATUS_PENDING here. On the 6497 // off chance this fails with INSUFFICIENT_RESOURCES we do it here 6498 // where we can still tolerate a failure. 6499 // 6500 6501 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb->ParentDcb), 6502 IrpContext->OriginatingIrp, 6503 OPLOCK_FLAG_PARENT_OBJECT, 6504 NULL, 6505 NULL, 6506 NULL ); 6507 6508 if (Iosb.Status != STATUS_SUCCESS) { 6509 6510 FatRaiseStatus( IrpContext, Iosb.Status ); 6511 } 6512 #endif 6513 6514 // 6515 // Now set the new allocation size, we do that by first 6516 // zeroing out the current file size. Then we truncate and 6517 // allocate up to the new allocation size 6518 // 6519 6520 (VOID)ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE ); 6521 ReleasePaging = TRUE; 6522 6523 Fcb->Header.FileSize.LowPart = 0; 6524 Fcb->Header.ValidDataLength.LowPart = 0; 6525 Fcb->ValidDataToDisk = 0; 6526 6527 6528 // 6529 // Validate that the allocation size will work. 6530 // 6531 6532 AllocSize.QuadPart = AllocationSize; 6533 if (!FatIsIoRangeValid( Fcb->Vcb, AllocSize, 0 )) { 6534 6535 DebugTrace(-1, Dbg, "Illegal allocation size\n", 0); 6536 6537 FatRaiseStatus( IrpContext, STATUS_DISK_FULL ); 6538 } 6539 6540 6541 // 6542 // Tell the cache manager the size went to zero 6543 // This call is unconditional, because MM always wants to know. 6544 // 6545 6546 CcSetFileSizes( FileObject, 6547 (PCC_FILE_SIZES)&Fcb->Header.AllocationSize ); 6548 6549 FatTruncateFileAllocation( IrpContext, Fcb, AllocationSize+HeaderSize ); 6550 6551 ExReleaseResourceLite( Fcb->Header.PagingIoResource ); 6552 ReleasePaging = FALSE; 6553 6554 FatAddFileAllocation( IrpContext, Fcb, FileObject, AllocationSize+HeaderSize ); 6555 6556 Fcb->FcbState |= FCB_STATE_TRUNCATE_ON_CLOSE; 6557 6558 // 6559 // Modify the attributes and time of the file, by first reading 6560 // in the dirent for the file and then updating its attributes 6561 // and time fields. Note that for supersede we replace the file 6562 // attributes as opposed to adding to them. 6563 // 6564 6565 FatGetDirentFromFcbOrDcb( IrpContext, 6566 Fcb, 6567 FALSE, 6568 &Dirent, 6569 &DirentBcb ); 6570 // 6571 // We should get the dirent since this Fcb is in good condition, verified as 6572 // we crawled down the prefix tree. 6573 // 6574 // Update the appropriate dirent fields, and the fcb fields 6575 // 6576 6577 Dirent->FileSize = 0; 6578 6579 6580 FileAttributes |= FILE_ATTRIBUTE_ARCHIVE; 6581 6582 if (CreateDisposition == FILE_SUPERSEDE) { 6583 6584 Dirent->Attributes = (UCHAR)FileAttributes; 6585 6586 } else { 6587 6588 Dirent->Attributes |= (UCHAR)FileAttributes; 6589 } 6590 6591 Fcb->DirentFatFlags = Dirent->Attributes; 6592 6593 KeQuerySystemTime( &Fcb->LastWriteTime ); 6594 6595 (VOID)FatNtTimeToFatTime( IrpContext, 6596 &Fcb->LastWriteTime, 6597 TRUE, 6598 &Dirent->LastWriteTime, 6599 NULL ); 6600 6601 if (FatData.ChicagoMode) { 6602 6603 Dirent->LastAccessDate = Dirent->LastWriteTime.Date; 6604 } 6605 6606 NotifyFilter = FILE_NOTIFY_CHANGE_LAST_WRITE 6607 | FILE_NOTIFY_CHANGE_ATTRIBUTES 6608 | FILE_NOTIFY_CHANGE_SIZE; 6609 6610 // 6611 // And now delete the previous Ea set if there was one. 6612 // 6613 6614 if (!FatIsFat32(Fcb->Vcb) && Dirent->ExtendedAttributes != 0) { 6615 6616 // 6617 // **** SDK fix, we won't fail this if there is 6618 // an error in the Ea's, we'll just leave 6619 // the orphaned Ea's in the file. 6620 // 6621 6622 EaChange = TRUE; 6623 6624 _SEH2_TRY { 6625 6626 FatDeleteEa( IrpContext, 6627 Fcb->Vcb, 6628 Dirent->ExtendedAttributes, 6629 &Fcb->ShortName.Name.Oem ); 6630 6631 } _SEH2_EXCEPT( EXCEPTION_EXECUTE_HANDLER ) { 6632 6633 FatResetExceptionState( IrpContext ); 6634 } _SEH2_END; 6635 } 6636 6637 // 6638 // Update the extended attributes handle in the dirent. 6639 // 6640 6641 if (EaChange) { 6642 6643 NT_ASSERT(!FatIsFat32(Fcb->Vcb)); 6644 6645 Dirent->ExtendedAttributes = EaHandle; 6646 6647 NotifyFilter |= FILE_NOTIFY_CHANGE_EA; 6648 } 6649 6650 // 6651 // Now update the dirent to the new ea handle and set the bcb dirty 6652 // Once we do this we can no longer back out the Ea 6653 // 6654 6655 FatSetDirtyBcb( IrpContext, DirentBcb, Fcb->Vcb, TRUE ); 6656 UnwindEa = 0; 6657 6658 // 6659 // Indicate that the Eas for this file have changed. 6660 // 6661 6662 Ccb->EaModificationCount += Fcb->EaModificationCount; 6663 6664 // 6665 // Check to see if we need to notify outstanding Irps for full 6666 // changes only (i.e., we haven't added, deleted, or renamed the file). 6667 // 6668 6669 FatNotifyReportChange( IrpContext, 6670 Fcb->Vcb, 6671 Fcb, 6672 NotifyFilter, 6673 FILE_ACTION_MODIFIED ); 6674 6675 // 6676 // And set our status to success 6677 // 6678 6679 Iosb.Status = STATUS_SUCCESS; 6680 6681 if (CreateDisposition == FILE_SUPERSEDE) { 6682 6683 Iosb.Information = FILE_SUPERSEDED; 6684 6685 } else { 6686 6687 Iosb.Information = FILE_OVERWRITTEN; 6688 } 6689 6690 try_exit: NOTHING; 6691 } _SEH2_FINALLY { 6692 6693 DebugUnwind( FatSupersedeOfOverwriteFile ); 6694 6695 if (ReleasePaging) { ExReleaseResourceLite( Fcb->Header.PagingIoResource ); } 6696 6697 // 6698 // If this is an abnormal termination then undo our work. 6699 // 6700 6701 if (_SEH2_AbnormalTermination()) { 6702 6703 if (UnwindEa != 0) { FatDeleteEa( IrpContext, Fcb->Vcb, UnwindEa, &Fcb->ShortName.Name.Oem ); } 6704 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); } 6705 } 6706 6707 FatUnpinBcb( IrpContext, DirentBcb ); 6708 6709 ClearFlag(Fcb->Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS); 6710 6711 DebugTrace(-1, Dbg, "FatSupersedeOrOverwriteFile -> Iosb.Status = %08lx\n", Iosb.Status); 6712 } _SEH2_END; 6713 6714 return Iosb; 6715 } 6716 6717 6718 VOID 6719 FatSetFullNameInFcb ( 6720 _In_ PIRP_CONTEXT IrpContext, 6721 _Inout_ PFCB Fcb, 6722 _In_ PUNICODE_STRING FinalName 6723 ) 6724 6725 /*++ 6726 6727 Routine Description: 6728 6729 This routine attempts a quick form of the full FatSetFullFileNameInFcb 6730 operation. 6731 6732 NOTE: this routine is probably not worth the code duplication involved, 6733 and is not equipped to handle the cases where the parent doesn't have 6734 the full name set up. 6735 6736 Arguments: 6737 6738 Fcb - Supplies a pointer to the Fcb 6739 6740 FinalName - Supplies the last component of the path to this Fcb's dirent 6741 6742 Return Value: 6743 6744 None. May silently fail. 6745 6746 --*/ 6747 6748 { 6749 PAGED_CODE(); 6750 6751 UNREFERENCED_PARAMETER( IrpContext ); 6752 6753 NT_ASSERT( Fcb->FullFileName.Buffer == NULL ); 6754 6755 // 6756 // Prefer the ExactCaseLongName of the file for this operation, if set. In 6757 // this way we avoid building the fullname with a short filename. Several 6758 // operations assume this - the FinalNameLength in particular is the Lfn 6759 // (if existant) length, and we use this to crack the fullname in paths 6760 // such as the FsRtlNotify caller. 6761 // 6762 // If the caller specified a particular name and it is short, it is the 6763 // case that the long name was set up. 6764 // 6765 6766 if (Fcb->ExactCaseLongName.Buffer) { 6767 6768 NT_ASSERT( Fcb->ExactCaseLongName.Length != 0 ); 6769 FinalName = &Fcb->ExactCaseLongName; 6770 } 6771 6772 // 6773 // Special case the root. 6774 // 6775 6776 if (NodeType(Fcb->ParentDcb) == FAT_NTC_ROOT_DCB) { 6777 6778 Fcb->FullFileName.Length = 6779 Fcb->FullFileName.MaximumLength = sizeof(WCHAR) + FinalName->Length; 6780 6781 Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag( PagedPool, 6782 Fcb->FullFileName.Length, 6783 TAG_FILENAME_BUFFER ); 6784 6785 Fcb->FullFileName.Buffer[0] = L'\\'; 6786 6787 RtlCopyMemory( &Fcb->FullFileName.Buffer[1], 6788 &FinalName->Buffer[0], 6789 FinalName->Length ); 6790 6791 } else { 6792 6793 PUNICODE_STRING Prefix; 6794 6795 Prefix = &Fcb->ParentDcb->FullFileName; 6796 6797 // 6798 // It is possible our parent's full filename is not set. Simply fail 6799 // this attempt. 6800 // 6801 6802 if (Prefix->Buffer == NULL) { 6803 6804 return; 6805 } 6806 6807 Fcb->FullFileName.Length = 6808 Fcb->FullFileName.MaximumLength = Prefix->Length + sizeof(WCHAR) + FinalName->Length; 6809 6810 Fcb->FullFileName.Buffer = FsRtlAllocatePoolWithTag( PagedPool, 6811 Fcb->FullFileName.Length, 6812 TAG_FILENAME_BUFFER ); 6813 6814 RtlCopyMemory( &Fcb->FullFileName.Buffer[0], 6815 &Prefix->Buffer[0], 6816 Prefix->Length ); 6817 6818 Fcb->FullFileName.Buffer[Prefix->Length / sizeof(WCHAR)] = L'\\'; 6819 6820 RtlCopyMemory( &Fcb->FullFileName.Buffer[(Prefix->Length / sizeof(WCHAR)) + 1], 6821 &FinalName->Buffer[0], 6822 FinalName->Length ); 6823 6824 } 6825 } 6826 6827 6828 NTSTATUS 6829 FatCheckSystemSecurityAccess ( 6830 _In_ PIRP_CONTEXT IrpContext 6831 ) 6832 { 6833 PACCESS_STATE AccessState; 6834 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp ); 6835 6836 PAGED_CODE(); 6837 6838 // 6839 // We check if the caller wants ACCESS_SYSTEM_SECURITY access on this 6840 // object and fail the request if he does. 6841 // 6842 6843 NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL ); 6844 AccessState = IrpSp->Parameters.Create.SecurityContext->AccessState; 6845 6846 // 6847 // Check if the remaining privilege includes ACCESS_SYSTEM_SECURITY. 6848 // 6849 6850 if (FlagOn( AccessState->RemainingDesiredAccess, ACCESS_SYSTEM_SECURITY )) { 6851 6852 if (!SeSinglePrivilegeCheck( FatSecurityPrivilege, 6853 UserMode )) { 6854 6855 return STATUS_ACCESS_DENIED; 6856 } 6857 6858 // 6859 // Move this privilege from the Remaining access to Granted access. 6860 // 6861 6862 ClearFlag( AccessState->RemainingDesiredAccess, ACCESS_SYSTEM_SECURITY ); 6863 SetFlag( AccessState->PreviouslyGrantedAccess, ACCESS_SYSTEM_SECURITY ); 6864 } 6865 6866 return STATUS_SUCCESS; 6867 } 6868 6869 6870 NTSTATUS 6871 FatCheckShareAccess ( 6872 _In_ PIRP_CONTEXT IrpContext, 6873 _In_ PFILE_OBJECT FileObject, 6874 _In_ PFCB FcbOrDcb, 6875 _In_ PACCESS_MASK DesiredAccess, 6876 _In_ ULONG ShareAccess 6877 ) 6878 6879 /*++ 6880 6881 Routine Description: 6882 6883 This routine checks conditions that may result in a sharing violation. 6884 6885 Arguments: 6886 6887 FileObject - Pointer to the file object of the current open request. 6888 6889 FcbOrDcb - Supplies a pointer to the Fcb/Dcb. 6890 6891 DesiredAccess - Desired access of current open request. 6892 6893 ShareAccess - Shared access requested by current open request. 6894 6895 Return Value: 6896 6897 If the accessor has access to the file, STATUS_SUCCESS is returned. 6898 Otherwise, STATUS_SHARING_VIOLATION is returned. 6899 6900 --*/ 6901 6902 { 6903 PAGED_CODE(); 6904 6905 #if (NTDDI_VERSION >= NTDDI_VISTA) 6906 // 6907 // Do an extra test for writeable user sections if the user did not allow 6908 // write sharing - this is neccessary since a section may exist with no handles 6909 // open to the file its based against. 6910 // 6911 6912 if ((NodeType( FcbOrDcb ) == FAT_NTC_FCB) && 6913 !FlagOn( ShareAccess, FILE_SHARE_WRITE ) && 6914 FlagOn( *DesiredAccess, FILE_EXECUTE | FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | DELETE | MAXIMUM_ALLOWED ) && 6915 MmDoesFileHaveUserWritableReferences( &FcbOrDcb->NonPaged->SectionObjectPointers )) { 6916 6917 return STATUS_SHARING_VIOLATION; 6918 } 6919 #endif 6920 6921 // 6922 // Check if the Fcb has the proper share access. 6923 // 6924 6925 return IoCheckShareAccess( *DesiredAccess, 6926 ShareAccess, 6927 FileObject, 6928 &FcbOrDcb->ShareAccess, 6929 FALSE ); 6930 6931 UNREFERENCED_PARAMETER( IrpContext ); 6932 } 6933 6934 // 6935 // Lifted from NTFS. 6936 // 6937 6938 NTSTATUS 6939 FatCallSelfCompletionRoutine ( 6940 __in PDEVICE_OBJECT DeviceObject, 6941 __in PIRP Irp, 6942 __in PVOID Contxt 6943 ) 6944 6945 { 6946 // 6947 // Set the event so that our call will wake up. 6948 // 6949 6950 KeSetEvent( (PKEVENT)Contxt, 0, FALSE ); 6951 6952 UNREFERENCED_PARAMETER( DeviceObject ); 6953 UNREFERENCED_PARAMETER( Irp ); 6954 6955 // 6956 // If we change this return value then FatIoCallSelf needs to reference the 6957 // file object. 6958 // 6959 6960 return STATUS_MORE_PROCESSING_REQUIRED; 6961 } 6962