ReactOS 0.4.16-dev-340-g0540c21
create.c
Go to the documentation of this file.
1/*++
2
3Copyright (c) 1989-2000 Microsoft Corporation
4
5Module Name:
6
7 Create.c
8
9Abstract:
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
51
52//
53// local procedure prototypes
54//
55
56_Requires_lock_held_(_Global_critical_region_)
59 _In_ PIRP_CONTEXT IrpContext,
65 );
66
67_Requires_lock_held_(_Global_critical_region_)
69FatOpenRootDcb (
70 _In_ PIRP_CONTEXT IrpContext,
76 );
77
78_Requires_lock_held_(_Global_critical_region_)
80FatOpenExistingDcb (
81 _In_ PIRP_CONTEXT IrpContext,
93 _Out_ PBOOLEAN OplockPostIrp
94 );
95
96_Requires_lock_held_(_Global_critical_region_)
98FatOpenExistingFcb (
99 _In_ PIRP_CONTEXT IrpContext,
115 _Out_ PBOOLEAN OplockPostIrp
116 );
117
118_Requires_lock_held_(_Global_critical_region_)
120FatOpenTargetDirectory (
121 _In_ PIRP_CONTEXT IrpContext,
126 _In_ BOOLEAN DoesNameExist,
128 );
129
131_Requires_lock_held_(_Global_critical_region_)
133FatOpenExistingDirectory (
134 _In_ PIRP_CONTEXT IrpContext,
151 );
152
153_Requires_lock_held_(_Global_critical_region_)
155FatOpenExistingFile (
156 _In_ PIRP_CONTEXT IrpContext,
165 _In_ PUNICODE_STRING OrigLfn,
173 _In_ BOOLEAN IsPagingFile,
178 );
179
180_Requires_lock_held_(_Global_critical_region_)
182FatCreateNewDirectory (
183 _In_ PIRP_CONTEXT IrpContext,
198 );
199
200_Requires_lock_held_(_Global_critical_region_)
202FatCreateNewFile (
203 _In_ PIRP_CONTEXT IrpContext,
216 _In_ PUNICODE_STRING LfnBuffer,
217 _In_ BOOLEAN IsPagingFile,
221 _In_ BOOLEAN TemporaryFile
222 );
223
224
225_Requires_lock_held_(_Global_critical_region_)
227FatSupersedeOrOverwriteFile (
228 _In_ PIRP_CONTEXT IrpContext,
237 );
238
241 _In_ PIRP_CONTEXT IrpContext
242 );
243
246 _In_ PIRP_CONTEXT IrpContext,
248 _In_ PFCB Fcb,
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
281NTAPI
282FatFsdCreate (
283 _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
285 )
286
287/*++
288
289Routine Description:
290
291 This routine implements the FSD part of the NtCreateFile and NtOpenFile
292 API calls.
293
294Arguments:
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
301Return Value:
302
303 NTSTATUS - The Fsd status for the Irp
304
305--*/
306
307{
309 PIRP_CONTEXT IrpContext = NULL;
310
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
328
329 return STATUS_SUCCESS;
330 }
331
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
342
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
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
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_)
399VOID
400FatCommonCreateCallout (
401 _In_ PFAT_CALLOUT_PARAMETERS CalloutParameters
402 )
403
404/*++
405
406Routine 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
412Arguments:
413
414 Context - Supplies an opaque pointer to this function's context. It is actually
415 an FAT_CALLOUT_PARAMETERS structure.
416
417Return 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_)
451FatCommonCreateOnNewStack (
452 _In_ PIRP_CONTEXT IrpContext,
454 )
455
456/*++
457
458Routine Description:
459
460 This routine sets up a switch to a new stack and call to FatCommonCreate().
461
462Arguments:
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
471Return Value:
472
473 NTSTATUS - The status from FatCommonCreate().
474
475--*/
476{
477 FAT_CALLOUT_PARAMETERS CalloutParameters;
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,
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
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_)
552FatCommonCreate (
553 _Inout_ PIRP_CONTEXT IrpContext,
555 )
556
557/*++
558
559Routine Description:
560
561 This is the common routine for creating/opening a file called by
562 both the fsd and fsp threads.
563
564Arguments:
565
566 Irp - Supplies the Irp to process
567
568Return Value:
569
570 NTSTATUS - the return status for the operation
571
572--*/
573
574{
576 IO_STATUS_BLOCK Iosb = {0};
578
580 PFILE_OBJECT RelatedFileObject;
589
591 BOOLEAN NoIntermediateBuffering;
593 BOOLEAN IsPagingFile;
594 BOOLEAN OpenTargetDirectory;
596 BOOLEAN NonDirectoryFile;
600 BOOLEAN TemporaryFile;
602
604
605 PVCB Vcb;
606 PFCB Fcb = NULL;
607 PCCB Ccb;
609 PDCB FinalDcb = NULL;
610
611 UNICODE_STRING FinalName = {0};
613 UNICODE_STRING NextRemainingPart = {0};
614 UNICODE_STRING UpcasedFinalName;
616
617 OEM_STRING OemFinalName;
619
621 PBCB DirentBcb = NULL;
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;
634 UNICODE_STRING OrigLfn = {0};
635
637
638 PAGED_CODE();
639
640 //
641 // Get the current IRP stack location
642 //
643
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);
687 }
688 }
689
690 //
691 // Reference our input parameters to make things easier
692 //
693
694 NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL );
695
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
730
731 //
732 // Locate the volume device object and Vcb that we are trying to access
733 //
734
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
747
749 }
750
752 NonDirectoryFile = BooleanFlagOn( Options, FILE_NON_DIRECTORY_FILE );
753 NoIntermediateBuffering = BooleanFlagOn( Options, FILE_NO_INTERMEDIATE_BUFFERING );
756#if (NTDDI_VERSION >= NTDDI_WIN7)
758#else
760#endif
761
762 TemporaryFile = BooleanFlagOn( IrpSp->Parameters.Create.FileAttributes,
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
773
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);
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
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
859 if (Vcb->VcbCondition != VcbGood) {
860
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
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
885 }
886
887 //
888 // If this is a fat32 volume, EA's are not supported.
889 //
890
891 if (EaBuffer != NULL) {
892
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
924 }
925
926 //
927 // Can't open the TargetDirectory of the DASD volume.
928 //
929
930 if (OpenTargetDirectory) {
931
933 }
934
935 DebugTrace(0, Dbg, "Opening the volume, Vcb = %p\n", Vcb);
936
938
939 Iosb = FatOpenVolume( IrpContext,
941 Vcb,
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;
963
964 TypeOfOpen = FatDecodeFileObject( RelatedFileObject,
965 &RelatedVcb,
966 &RelatedDcb,
967 &RelatedCcb );
968
969 if (TypeOfOpen != UserFileOpen &&
971
972 DebugTrace(0, Dbg, "Invalid related file object\n", 0);
973
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
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
1023 }
1024
1025 //
1026 // Can't open the TargetDirectory of the root directory.
1027 //
1028
1029 if (OpenTargetDirectory) {
1030
1032 }
1033
1034 //
1035 // Not allowed to delete root directory.
1036 //
1037
1038 if (DeleteOnClose) {
1039
1041 }
1042
1043 DebugTrace(0, Dbg, "Opening root dcb\n", 0);
1044
1046
1047 Iosb = FatOpenRootDcb( IrpContext,
1048 FileObject,
1049 Vcb,
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
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;
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
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
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,
1160
1161 } else {
1162
1163 NextFcb = NULL;
1164 OemFinalName.Length = 0;
1165
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 );
1192
1193 Status = RtlUpcaseUnicodeString( &UpcasedFinalName, &UpcasedFinalName, FALSE );
1195
1196
1197 NextFcb = FatFindFcb( IrpContext,
1198 &Fcb->Specific.Dcb.RootUnicodeNode,
1199 (PSTRING)&UpcasedFinalName,
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
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) &&
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
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 &&
1288
1290 }
1291
1292 //
1293 // Check for a system file.
1294 //
1295
1296 } else if (FlagOn( Fcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
1297
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
1307
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
1328
1329 Iosb = FatOpenTargetDirectory( IrpContext,
1330 FileObject,
1331 Fcb->ParentDcb,
1334 TRUE,
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
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
1357 }
1358
1359 DebugTrace(0, Dbg, "Open existing dcb, Dcb = %p\n", Fcb);
1360
1362
1363 Iosb = FatOpenExistingDcb( IrpContext,
1364 IrpSp,
1365 FileObject,
1366 Vcb,
1367 (PDCB)Fcb,
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
1412 }
1413
1414 DebugTrace(0, Dbg, "Open existing fcb, Fcb = %p\n", Fcb);
1415
1416 if ( TrailingBackslash ) {
1418 }
1419
1421
1422 Iosb = FatOpenExistingFcb( IrpContext,
1423 IrpSp,
1424 FileObject,
1425 Vcb,
1426 Fcb,
1430 EaBuffer,
1431 EaLength,
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
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
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
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;
1519
1520 } else {
1521
1522 //
1523 // Dissect the remaining part.
1524 //
1525
1526 DebugTrace(0, Dbg, "Dissecting the name %wZ\n", &RemainingPart);
1527
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
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
1575 }
1576
1577 } else {
1578
1580
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
1597 }
1598
1599 } else {
1600
1602
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,
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
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
1670 try_return( Iosb.Status );
1671 }
1672
1673 //
1674 // Compute the LfnByteOffset.
1675 //
1676
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,
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,
1713 Dirent ? TRUE : FALSE,
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
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
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,
1758 &Lfn,
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
1781 }
1782
1783 DebugTrace(0, Dbg, "Open existing file\n", 0);
1784
1785 if ( TrailingBackslash ) {
1787 }
1788
1789
1790 Iosb = FatOpenExistingFile( IrpContext,
1791 FileObject,
1792 Vcb,
1793 &Fcb,
1794 ParentDcb,
1795 Dirent,
1798 &Lfn,
1799 &OrigLfn,
1803 EaBuffer,
1804 EaLength,
1807 IsPagingFile,
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
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) ||
1838
1839 DebugTrace( 0, Dbg, "Cannot open nonexisting file\n", 0);
1840
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
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
1886 }
1887
1888 //
1889 // Don't allow people to create directories with the
1890 // temporary bit set.
1891 //
1892
1893 if (TemporaryFile) {
1894
1896 }
1897
1898 Iosb = FatCreateNewDirectory( IrpContext,
1899 IrpSp,
1900 FileObject,
1901 Vcb,
1902 ParentDcb,
1903 &OemFinalName,
1904 &FinalName,
1907 EaBuffer,
1908 EaLength,
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
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
1944 }
1945
1946
1947 Iosb = FatCreateNewFile( IrpContext,
1948 IrpSp,
1949 FileObject,
1950 Vcb,
1951 ParentDcb,
1952 &OemFinalName,
1953 &FinalName,
1957 EaBuffer,
1958 EaLength,
1960 &Lfn,
1961 IsPagingFile,
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
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 )) &&
2019 (Iosb.Status != STATUS_CANNOT_BREAK_OPLOCK) &&
2020 (IrpContext->ExceptionStatus != STATUS_CANNOT_BREAK_OPLOCK) &&
2021 (Fcb != NULL) &&
2023
2024 FsRtlCheckOplockEx( FatGetFcbOplock(Fcb),
2025 IrpContext->OriginatingIrp,
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 |
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
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
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
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 {
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 );
2224
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,
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__
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
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
2282
2283 return Iosb.Status;
2284}
2285
2286//
2287// Internal support routine
2288//
2289
2290_Requires_lock_held_(_Global_critical_region_)
2293 _In_ PIRP_CONTEXT IrpContext,
2299 )
2300
2301/*++
2302
2303Routine Description:
2304
2305 This routine opens the specified volume for DASD access
2306
2307Arguments:
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
2319Return Value:
2320
2321 IO_STATUS_BLOCK - Returns the completion status for the operation
2322
2323--*/
2324
2325{
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;
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) &&
2358
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
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
2379 FsRtlAreVolumeStartupApplicationsComplete()) {
2380
2382 }
2383#endif
2384
2385 //
2386 // Do a quick check here for handles on exclusive open.
2387 //
2388
2390 !FatIsHandleCountZero( IrpContext, Vcb )) {
2391
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
2412
2413 if (Vcb->OpenFileCount != 0) {
2414
2416 }
2417
2418 } else {
2419
2420 if (Vcb->ReadOnlyCount != Vcb->OpenFileCount) {
2421
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
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 );
2471
2472 //
2473 // Unlock the volume if it is removable.
2474 //
2475
2476 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
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
2492 FileObject,
2493 &Vcb->ShareAccess,
2494 TRUE ))) {
2495
2496 try_return( Iosb.Status );
2497 }
2498
2499 } else {
2500
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
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;
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 );
2534 Vcb->Vpb->RealDevice,
2535 IrpSp->Parameters.Create.SecurityContext->AccessState,
2537 UserMode :
2538 IrpContext->OriginatingIrp->RequestorMode ));
2539
2540 if (NT_SUCCESS( Status )) {
2541
2543 }
2544
2545 //
2546 // And set our status to success
2547 //
2548
2549 Iosb.Status = STATUS_SUCCESS;
2550 Iosb.Information = FILE_OPENED;
2551
2552 try_exit: NOTHING;
2553 } _SEH2_FINALLY {
2554
2556
2557 //
2558 // If this is an abnormal termination then undo our work
2559 //
2560
2561 if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Iosb.Status)) {
2562
2563 if (UnwindCounts) {
2564 Vcb->DirectAccessOpenCount -= 1;
2565 Vcb->OpenFileCount -= 1;
2566 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
2567 }
2568 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
2569 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Vcb->ShareAccess ); }
2570 if (UnwindVolumeLock) { Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED; }
2571 }
2572
2573 DebugTrace(-1, Dbg, "FatOpenVolume -> Iosb.Status = %08lx\n", Iosb.Status);
2574 } _SEH2_END;
2575
2576 return Iosb;
2577}
2578
2579
2580//
2581// Internal support routine
2582//
2583
2584_Requires_lock_held_(_Global_critical_region_)
2586FatOpenRootDcb (
2587 _In_ PIRP_CONTEXT IrpContext,
2593 )
2594
2595/*++
2596
2597Routine Description:
2598
2599 This routine opens the root dcb for the volume
2600
2601Arguments:
2602
2603 FileObject - Supplies the File object
2604
2605 Vcb - Supplies the Vcb denoting the volume whose dcb is being opened.
2606
2607 DesiredAccess - Supplies the desired access of the caller
2608
2609 ShareAccess - Supplies the share access of the caller
2610
2611 CreateDisposition - Supplies the create disposition for this operation
2612
2613Return Value:
2614
2615 IO_STATUS_BLOCK - Returns the completion status for the operation
2616
2617Arguments:
2618
2619--*/
2620
2621{
2622 PDCB RootDcb;
2623 IO_STATUS_BLOCK Iosb = {0};
2624
2625 //
2626 // The following variables are for abnormal termination
2627 //
2628
2629 BOOLEAN UnwindShareAccess = FALSE;
2631 BOOLEAN UnwindCounts = FALSE;
2632 BOOLEAN RootDcbAcquired = FALSE;
2633
2634 PAGED_CODE();
2635
2636 DebugTrace(+1, Dbg, "FatOpenRootDcb...\n", 0);
2637
2638 //
2639 // Locate the root dcb
2640 //
2641
2642 RootDcb = Vcb->RootDcb;
2643
2644 //
2645 // Get the Dcb exlcusive. This is important as cleanup does not
2646 // acquire the Vcb.
2647 //
2648
2649 (VOID)FatAcquireExclusiveFcb( IrpContext, RootDcb );
2650 RootDcbAcquired = TRUE;
2651
2652 _SEH2_TRY {
2653
2654 //
2655 // Check the create disposition and desired access
2656 //
2657
2658 if ((CreateDisposition != FILE_OPEN) &&
2660
2661 Iosb.Status = STATUS_ACCESS_DENIED;
2662 try_return( Iosb );
2663 }
2664
2665 if (!FatCheckFileAccess( IrpContext,
2666 RootDcb->DirentFatFlags,
2667 DesiredAccess)) {
2668
2669 Iosb.Status = STATUS_ACCESS_DENIED;
2670 try_return( Iosb );
2671 }
2672
2673 //
2674 // If the Root dcb is already opened by someone then we need
2675 // to check the share access
2676 //
2677
2678 if (RootDcb->OpenCount > 0) {
2679
2682 FileObject,
2683 &RootDcb->ShareAccess,
2684 TRUE ))) {
2685
2686 try_return( Iosb );
2687 }
2688
2689 } else {
2690
2693 FileObject,
2694 &RootDcb->ShareAccess );
2695 }
2696
2697 UnwindShareAccess = TRUE;
2698
2699 //
2700 // Setup the context and section object pointers, and update
2701 // our reference counts
2702 //
2703
2706 RootDcb,
2707 UnwindCcb = FatCreateCcb( IrpContext ));
2708
2709 RootDcb->UncleanCount += 1;
2710 RootDcb->OpenCount += 1;
2711 Vcb->OpenFileCount += 1;
2712 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
2713 UnwindCounts = TRUE;
2714
2715 //
2716 // And set our status to success
2717 //
2718
2719 Iosb.Status = STATUS_SUCCESS;
2720 Iosb.Information = FILE_OPENED;
2721
2722 try_exit: NOTHING;
2723 } _SEH2_FINALLY {
2724
2725 DebugUnwind( FatOpenRootDcb );
2726
2727 //
2728 // If this is an abnormal termination then undo our work
2729 //
2730
2732
2733 if (UnwindCounts) {
2734 RootDcb->UncleanCount -= 1;
2735 RootDcb->OpenCount -= 1;
2736 Vcb->OpenFileCount -= 1;
2737 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
2738 }
2739 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
2740 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &RootDcb->ShareAccess ); }
2741 }
2742
2743 if (RootDcbAcquired) {
2744
2745 FatReleaseFcb( IrpContext, RootDcb );
2746 }
2747
2748 DebugTrace(-1, Dbg, "FatOpenRootDcb -> Iosb.Status = %08lx\n", Iosb.Status);
2749 } _SEH2_END;
2750
2751 return Iosb;
2752}
2753
2754
2755//
2756// Internal support routine
2757//
2758
2759_Requires_lock_held_(_Global_critical_region_)
2761FatOpenExistingDcb (
2762 _In_ PIRP_CONTEXT IrpContext,
2774 _Out_ PBOOLEAN OplockPostIrp
2775 )
2776
2777/*++
2778
2779Routine Description:
2780
2781 This routine opens the specified existing dcb
2782
2783Arguments:
2784
2785 FileObject - Supplies the File object
2786
2787 Vcb - Supplies the Vcb denoting the volume containing the dcb
2788
2789 Dcb - Supplies the already existing dcb
2790
2791 DesiredAccess - Supplies the desired access of the caller
2792
2793 ShareAccess - Supplies the share access of the caller
2794
2795 CreateDisposition - Supplies the create disposition for this operation
2796
2797 NoEaKnowledge - This opener doesn't understand Ea's and we fail this
2798 open if the file has NeedEa's.
2799
2800 DeleteOnClose - The caller wants the file gone when the handle is closed
2801
2802Return Value:
2803
2804 IO_STATUS_BLOCK - Returns the completion status for the operation
2805
2806--*/
2807
2808{
2809 IO_STATUS_BLOCK Iosb = {0};
2810 PBCB DirentBcb = NULL;
2812
2813 //
2814 // The following variables are for abnormal termination
2815 //
2816
2817 BOOLEAN UnwindShareAccess = FALSE;
2819 BOOLEAN DcbAcquired = FALSE;
2820
2821#if (NTDDI_VERSION <= NTDDI_WIN7)
2823#endif
2824
2826
2827 PAGED_CODE();
2828
2829 DebugTrace(+1, Dbg, "FatOpenExistingDcb...\n", 0);
2830
2831 //
2832 // Get the Dcb exlcusive. This is important as cleanup does not
2833 // acquire the Vcb.
2834 //
2835
2836 (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb );
2837 DcbAcquired = TRUE;
2838
2839 _SEH2_TRY {
2840
2841
2842 *OplockPostIrp = FALSE;
2843
2844 //
2845 // Before spending any noticeable effort, see if we have the odd case
2846 // of someone trying to delete-on-close the root dcb. This will only
2847 // happen if we're hit with a null-filename relative open via the root.
2848 //
2849
2851
2852 Iosb.Status = STATUS_CANNOT_DELETE;
2853 try_return( Iosb );
2854 }
2855
2856#if (NTDDI_VERSION >= NTDDI_WIN8)
2857
2858 //
2859 // Let's make sure that if the caller provided an oplock key that it
2860 // gets stored in the file object.
2861 //
2862
2863 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Dcb),
2864 IrpContext->OriginatingIrp,
2866 NULL,
2867 NULL,
2868 NULL );
2869
2870 if (Iosb.Status != STATUS_SUCCESS) {
2871
2873 }
2874
2875#endif
2876 //
2877 // If the caller has no Ea knowledge, we immediately check for
2878 // Need Ea's on the file. We don't need to check for ea's on the
2879 // root directory, because it never has any. Fat32 doesn't have
2880 // any, either.
2881 //
2882
2884 !FatIsFat32(Vcb)) {
2885
2887
2888 //
2889 // Get the dirent for the file and then check that the need
2890 // ea count is 0.
2891 //
2892
2893 FatGetDirentFromFcbOrDcb( IrpContext,
2894 Dcb,
2895 FALSE,
2896 &Dirent,
2897 &DirentBcb );
2898
2899 FatGetNeedEaCount( IrpContext,
2900 Vcb,
2901 Dirent,
2902 &NeedEaCount );
2903
2904 FatUnpinBcb( IrpContext, DirentBcb );
2905
2906 if (NeedEaCount != 0) {
2907
2908 Iosb.Status = STATUS_ACCESS_DENIED;
2909 try_return( Iosb );
2910 }
2911 }
2912
2913 //
2914 // Check the create disposition and desired access
2915 //
2916
2917 if ((CreateDisposition != FILE_OPEN) &&
2919
2921 try_return( Iosb );
2922 }
2923
2924 if (!FatCheckFileAccess( IrpContext,
2925 Dcb->DirentFatFlags,
2926 DesiredAccess)) {
2927
2928 Iosb.Status = STATUS_ACCESS_DENIED;
2929 try_return( Iosb );
2930 }
2931
2932 //
2933 // If the dcb is already opened by someone then we need
2934 // to check the share access
2935 //
2936
2937 if (Dcb->OpenCount > 0) {
2938
2939 if (!NT_SUCCESS(Iosb.Status = FatCheckShareAccess( IrpContext,
2940 FileObject,
2941 Dcb,
2943 ShareAccess ))) {
2944#if (NTDDI_VERSION >= NTDDI_WIN8)
2945
2946 NTSTATUS OplockBreakStatus = STATUS_SUCCESS;
2947
2948 //
2949 // If we got a sharing violation try to break outstanding handle
2950 // oplocks and retry the sharing check. If the caller specified
2951 // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock;
2952 // we just return the sharing violation.
2953 //
2954
2955 if ((Iosb.Status == STATUS_SHARING_VIOLATION) &&
2957
2958 OplockBreakStatus = FsRtlOplockBreakH( FatGetFcbOplock(Dcb),
2959 IrpContext->OriginatingIrp,
2960 0,
2961 IrpContext,
2963 FatPrePostIrp );
2964
2965 //
2966 // If FsRtlOplockBreakH returned STATUS_PENDING, then the IRP
2967 // has been posted and we need to stop working.
2968 //
2969
2970 if (OplockBreakStatus == STATUS_PENDING) {
2971
2972 Iosb.Status = STATUS_PENDING;
2973 *OplockPostIrp = TRUE;
2975
2976 //
2977 // If FsRtlOplockBreakH returned an error we want to return that now.
2978 //
2979
2980 } else if (!NT_SUCCESS( OplockBreakStatus )) {
2981
2982 Iosb.Status = OplockBreakStatus;
2983 try_return( Iosb );
2984
2985 //
2986 // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating
2987 // that there is no oplock to be broken. The sharing violation is
2988 // returned in that case.
2989 //
2990
2991 } else {
2992
2993 NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS );
2994
2995 try_return( Iosb );
2996 }
2997
2998 //
2999 // The initial sharing check failed with something other than sharing
3000 // violation (which should never happen, but let's be future-proof),
3001 // or we *did* get a sharing violation and the caller specified
3002 // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over.
3003 //
3004
3005 } else {
3006
3007 try_return( Iosb );
3008 }
3009#else
3010
3011 try_return( Iosb );
3012#endif
3013 }
3014 }
3015
3016#if (NTDDI_VERSION >= NTDDI_WIN8)
3017
3018 //
3019 // Now check that we can continue based on the oplock state of the
3020 // directory. If there are no open handles yet we don't need to do
3021 // this check; oplocks can only exist when there are handles.
3022 //
3023
3024 if (Dcb->UncleanCount != 0) {
3025
3027 IrpContext->OriginatingIrp,
3028 IrpContext,
3030 FatPrePostIrp );
3031 }
3032
3033 //
3034 // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
3035 // to service an oplock break and we need to leave now.
3036 //
3037
3038 if (Iosb.Status == STATUS_PENDING) {
3039
3040 *OplockPostIrp = TRUE;
3042 }
3043
3044 //
3045 // If the caller wants atomic create-with-oplock semantics, tell
3046 // the oplock package. We haven't incremented the Fcb's UncleanCount
3047 // for this create yet, so add that in on the call.
3048 //
3049
3050 if (OpenRequiringOplock &&
3051 (Iosb.Status == STATUS_SUCCESS)) {
3052
3054 IrpContext->OriginatingIrp,
3055 (Dcb->UncleanCount + 1) );
3056 }
3057
3058 //
3059 // If we've encountered a failure we need to leave. FsRtlCheckOplock
3060 // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated
3061 // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED
3062 // on the create call. That's an NT_SUCCESS code, so we need to keep
3063 // going.
3064 //
3065
3066 if ((Iosb.Status != STATUS_SUCCESS) &&
3068
3070 }
3071
3072#endif
3073
3074 //
3075 // Now that we're done with the oplock work update the share counts.
3076 // If the Dcb isn't yet opened we just set the share access rather than
3077 // update it.
3078 //
3079
3080 if (Dcb->OpenCount > 0) {
3081
3083
3084 } else {
3085
3088 FileObject,
3089 &Dcb->ShareAccess );
3090 }
3091
3092 UnwindShareAccess = TRUE;
3093
3094 //
3095 // Setup the context and section object pointers, and update
3096 // our reference counts
3097 //
3098
3101 Dcb,
3102 UnwindCcb = FatCreateCcb( IrpContext ));
3103
3104 Dcb->UncleanCount += 1;
3105 Dcb->OpenCount += 1;
3106 Vcb->OpenFileCount += 1;
3107 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
3108
3109 //
3110 // Mark the delete on close bit if the caller asked for that.
3111 //
3112
3113 {
3114 PCCB Ccb = (PCCB)FileObject->FsContext2;
3115
3116
3117 if (DeleteOnClose) {
3118
3120 }
3121 if (FileNameOpenedDos) {
3122
3124 }
3125
3126 }
3127
3128
3129 //
3130 // In case this was set, clear it now.
3131 //
3132
3134
3135 //
3136 // And set our status to success
3137 //
3138
3139 Iosb.Status = STATUS_SUCCESS;
3140 Iosb.Information = FILE_OPENED;
3141
3142 try_exit: NOTHING;
3143 } _SEH2_FINALLY {
3144
3145 DebugUnwind( FatOpenExistingDcb );
3146
3147 //
3148 // Unpin the Dirent Bcb if pinned.
3149 //
3150
3151 FatUnpinBcb( IrpContext, DirentBcb );
3152
3153 //
3154 // If this is an abnormal termination then undo our work
3155 //
3156
3158
3159 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
3160 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); }
3161 }
3162
3163 if (DcbAcquired) {
3164
3165 FatReleaseFcb( IrpContext, Dcb );
3166 }
3167
3168 DebugTrace(-1, Dbg, "FatOpenExistingDcb -> Iosb.Status = %08lx\n", Iosb.Status);
3169 } _SEH2_END;
3170
3171 return Iosb;
3172}
3173
3174
3175//
3176// Internal support routine
3177//
3178
3179_Requires_lock_held_(_Global_critical_region_)
3181FatOpenExistingFcb (
3182 _In_ PIRP_CONTEXT IrpContext,
3198 _Out_ PBOOLEAN OplockPostIrp
3199 )
3200
3201/*++
3202
3203Routine Description:
3204
3205 This routine opens the specified existing fcb
3206
3207Arguments:
3208
3209 FileObject - Supplies the File object
3210
3211 Vcb - Supplies the Vcb denoting the volume containing the Fcb
3212
3213 Fcb - Supplies the already existing fcb
3214
3215 DesiredAccess - Supplies the desired access of the caller
3216
3217 ShareAccess - Supplies the share access of the caller
3218
3219 AllocationSize - Supplies the initial allocation if the file is being
3220 superseded or overwritten
3221
3222 EaBuffer - Supplies the Ea set if the file is being superseded or
3223 overwritten
3224
3225 EaLength - Supplies the size, in byte, of the EaBuffer
3226
3227 FileAttributes - Supplies file attributes to use if the file is being
3228 superseded or overwritten
3229
3230 CreateDisposition - Supplies the create disposition for this operation
3231
3232 NoEaKnowledge - This opener doesn't understand Ea's and we fail this
3233 open if the file has NeedEa's.
3234
3235 DeleteOnClose - The caller wants the file gone when the handle is closed
3236
3237 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
3238
3239 FileNameOpenedDos - The caller hit the short side of the name pair finding
3240 this file
3241
3242 OplockPostIrp - Address to store boolean indicating if the Irp needs to
3243 be posted to the Fsp.
3244
3245Return Value:
3246
3247 IO_STATUS_BLOCK - Returns the completion status for the operation
3248
3249--*/
3250
3251{
3252 IO_STATUS_BLOCK Iosb = {0};
3253
3254 PBCB DirentBcb = NULL;
3256
3257 ACCESS_MASK AddedAccess = 0;
3258
3259 //
3260 // The following variables are for abnormal termination
3261 //
3262
3263 BOOLEAN UnwindShareAccess = FALSE;
3265 BOOLEAN DecrementFcbOpenCount = FALSE;
3266 BOOLEAN FcbAcquired = FALSE;
3267
3268
3269 PAGED_CODE();
3270
3271 DebugTrace(+1, Dbg, "FatOpenExistingFcb...\n", 0);
3272
3273 //
3274 // Get the Fcb exlcusive. This is important as cleanup does not
3275 // acquire the Vcb.
3276 //
3277
3278 (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
3279 FcbAcquired = TRUE;
3280
3281 _SEH2_TRY {
3282
3283
3284 *OplockPostIrp = FALSE;
3285
3286#if (NTDDI_VERSION >= NTDDI_WIN7)
3287
3288 //
3289 // Let's make sure that if the caller provided an oplock key that it
3290 // gets stored in the file object.
3291 //
3292
3293 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb),
3294 IrpContext->OriginatingIrp,
3296 NULL,
3297 NULL,
3298 NULL );
3299
3300 if (Iosb.Status != STATUS_SUCCESS) {
3301
3303 }
3304#endif
3305
3306 //
3307 // Take special action if there is a current batch oplock or
3308 // batch oplock break in process on the Fcb.
3309 //
3310
3312
3313 //
3314 // We remember if a batch oplock break is underway for the
3315 // case where the sharing check fails.
3316 //
3317
3318 Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY;
3319
3321 IrpContext->OriginatingIrp,
3322 IrpContext,
3324 FatPrePostIrp );
3325
3326 //
3327 // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
3328 // to service an oplock break and we need to leave now.
3329 //
3330
3331 if (Iosb.Status == STATUS_PENDING) {
3332
3333 *OplockPostIrp = TRUE;
3335 }
3336 }
3337
3338 //
3339 // Check if the user wanted to create the file, also special case
3340 // the supersede and overwrite options. Those add additional,
3341 // possibly only implied, desired accesses to the caller, which
3342 // we must be careful to pull back off if the caller did not actually
3343 // request them.
3344 //
3345 // In other words, check against the implied access, but do not modify
3346 // share access as a result.
3347 //
3348
3350
3352 try_return( Iosb );
3353
3354 } else if (CreateDisposition == FILE_SUPERSEDE) {
3355
3356 SetFlag( AddedAccess,
3357 DELETE & ~(*DesiredAccess) );
3358
3360
3361 } else if ((CreateDisposition == FILE_OVERWRITE) ||
3363
3364 SetFlag( AddedAccess,
3366
3368 }
3369
3370 //
3371 // Check the desired access
3372 //
3373
3374 if (!FatCheckFileAccess( IrpContext,
3376 DesiredAccess )) {
3377
3378 Iosb.Status = STATUS_ACCESS_DENIED;
3379 try_return( Iosb );
3380 }
3381
3382
3383 //
3384 // Check for trying to delete a read only file.
3385 //
3386
3387 if (DeleteOnClose &&
3389
3390 Iosb.Status = STATUS_CANNOT_DELETE;
3391 try_return( Iosb );
3392 }
3393
3394 //
3395 // If we are asked to do an overwrite or supersede operation then
3396 // deny access for files where the file attributes for system and
3397 // hidden do not match
3398 //
3399
3403
3406
3409
3410 if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) ||
3412
3413 DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0);
3414
3415
3416 Iosb.Status = STATUS_ACCESS_DENIED;
3417 try_return( Iosb );
3418 }
3419
3420 //
3421 // If this media is write protected, don't even try the create.
3422 //
3423
3424 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
3425
3426 //
3427 // Set the real device for the pop-up info, and set the verify
3428 // bit in the device object, so that we will force a verify
3429 // in case the user put the correct media back in.
3430 //
3431
3432 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
3433 Vcb->Vpb->RealDevice );
3434
3435 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
3436
3438 }
3439 }
3440
3441 //
3442 // Check if the Fcb has the proper share access. This routine will also
3443 // check for writable user secions if the user did not allow write sharing.
3444 //
3445
3446 if (!NT_SUCCESS(Iosb.Status = FatCheckShareAccess( IrpContext,
3447 FileObject,
3448 Fcb,
3450 ShareAccess ))) {
3451
3452#if (NTDDI_VERSION >= NTDDI_WIN7)
3453
3454 NTSTATUS OplockBreakStatus = STATUS_SUCCESS;
3455
3456 //
3457 // If we got a sharing violation try to break outstanding handle
3458 // oplocks and retry the sharing check. If the caller specified
3459 // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock;
3460 // we just return the sharing violation.
3461 //
3462
3463 if ((Iosb.Status == STATUS_SHARING_VIOLATION) &&
3465
3466 OplockBreakStatus = FsRtlOplockBreakH( FatGetFcbOplock(Fcb),
3467 IrpContext->OriginatingIrp,
3468 0,
3469 IrpContext,
3471 FatPrePostIrp );
3472
3473 //
3474 // If FsRtlOplockBreakH returned STATUS_PENDING, then the IRP
3475 // has been posted and we need to stop working.
3476 //
3477
3478 if (OplockBreakStatus == STATUS_PENDING) {
3479
3480 Iosb.Status = STATUS_PENDING;
3481 *OplockPostIrp = TRUE;
3483
3484 //
3485 // If FsRtlOplockBreakH returned an error we want to return that now.
3486 //
3487
3488 } else if (!NT_SUCCESS( OplockBreakStatus )) {
3489
3490 Iosb.Status = OplockBreakStatus;
3491 try_return( Iosb );
3492
3493 //
3494 // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating
3495 // that there is no oplock to be broken. The sharing violation is
3496 // returned in that case.
3497 //
3498
3499 } else {
3500
3501 NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS );
3502
3503 try_return( Iosb );
3504 }
3505
3506 //
3507 // The initial sharing check failed with something other than sharing
3508 // violation (which should never happen, but let's be future-proof),
3509 // or we *did* get a sharing violation and the caller specified
3510 // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over.
3511 //
3512
3513 } else {
3514
3515 try_return( Iosb );
3516 }
3517
3518#else
3519
3520 try_return( Iosb );
3521
3522#endif
3523 }
3524
3525 //
3526 // Now check that we can continue based on the oplock state of the
3527 // file. If there are no open handles yet we don't need to do this
3528 // check; oplocks can only exist when there are handles.
3529 //
3530 // It is important that we modified the DesiredAccess in place so
3531 // that the Oplock check proceeds against any added access we had
3532 // to give the caller.
3533 //
3534
3535 if (Fcb->UncleanCount != 0) {
3536
3538 IrpContext->OriginatingIrp,
3539 IrpContext,
3541 FatPrePostIrp );
3542 }
3543
3544 //
3545 // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
3546 // to service an oplock break and we need to leave now.
3547 //
3548
3549 if (Iosb.Status == STATUS_PENDING) {
3550
3551 *OplockPostIrp = TRUE;
3553 }
3554
3555 //
3556 // If the caller wants atomic create-with-oplock semantics, tell
3557 // the oplock package. We haven't incremented the Fcb's UncleanCount
3558 // for this create yet, so add that in on the call.
3559 //
3560
3561 if (OpenRequiringOplock &&
3562 (Iosb.Status == STATUS_SUCCESS)) {
3563
3565 IrpContext->OriginatingIrp,
3566 (Fcb->UncleanCount + 1) );
3567 }
3568
3569 //
3570 // If we've encountered a failure we need to leave. FsRtlCheckOplock
3571 // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated
3572 // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED
3573 // on the create call. That's an NT_SUCCESS code, so we need to keep
3574 // going.
3575 //
3576
3577 if ((Iosb.Status != STATUS_SUCCESS) &&
3579
3581 }
3582
3583 //
3584 // Set the flag indicating if Fast I/O is possible
3585 //
3586
3587 Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
3588
3589 //
3590 // If the user wants write access access to the file make sure there
3591 // is not a process mapping this file as an image. Any attempt to
3592 // delete the file will be stopped in fileinfo.c
3593 //
3594 // If the user wants to delete on close, we must check at this
3595 // point though.
3596 //
3597
3599
3600 Fcb->OpenCount += 1;
3601 DecrementFcbOpenCount = TRUE;
3602
3604 MmFlushForWrite )) {
3605
3608 try_return( Iosb );
3609 }
3610 }
3611
3612 //
3613 // If this is a non-cached open on a non-paging file, and there
3614 // are no open cached handles, but there is a still a data
3615 // section, attempt a flush and purge operation to avoid cache
3616 // coherency overhead later. We ignore any I/O errors from
3617 // the flush.
3618 //
3619 // We set the CREATE_IN_PROGRESS flag to prevent the Fcb from
3620 // going away out from underneath us.
3621 //
3622
3627
3629
3631
3632 //
3633 // Grab and release PagingIo to serialize ourselves with the lazy writer.
3634 // This will work to ensure that all IO has completed on the cached
3635 // data and we will succesfully tear away the cache section.
3636 //
3637
3638 ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE);
3639 ExReleaseResourceLite( Fcb->Header.PagingIoResource );
3640
3642 NULL,
3643 0,
3644 FALSE );
3645
3647 }
3648
3649 //
3650 // Check if the user only wanted to open the file
3651 //
3652
3653 if ((CreateDisposition == FILE_OPEN) ||
3655
3656 DebugTrace(0, Dbg, "Doing open operation\n", 0);
3657
3658 //
3659 // If the caller has no Ea knowledge, we immediately check for
3660 // Need Ea's on the file.
3661 //
3662
3663 if (NoEaKnowledge && !FatIsFat32(Vcb)) {
3664
3666
3667 //
3668 // Get the dirent for the file and then check that the need
3669 // ea count is 0.
3670 //
3671
3672 FatGetDirentFromFcbOrDcb( IrpContext,
3673 Fcb,
3674 FALSE,
3675 &Dirent,
3676 &DirentBcb );
3677
3678 FatGetNeedEaCount( IrpContext,
3679 Vcb,
3680 Dirent,
3681 &NeedEaCount );
3682
3683 FatUnpinBcb( IrpContext, DirentBcb );
3684
3685 if (NeedEaCount != 0) {
3686
3687 Iosb.Status = STATUS_ACCESS_DENIED;
3688 try_return( Iosb );
3689 }
3690 }
3691
3692 //
3693 // Everything checks out okay, so setup the context and
3694 // section object pointers.
3695 //
3696
3699 Fcb,
3700 UnwindCcb = FatCreateCcb( IrpContext ));
3701
3702 FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
3703
3704 //
3705 // Fill in the information field, the status field is already
3706 // set.
3707 //
3708
3709 Iosb.Information = FILE_OPENED;
3710
3711 try_return( Iosb );
3712 }
3713
3714 //
3715 // Check if we are to supersede/overwrite the file, we can wait for
3716 // any I/O at this point
3717 //
3718
3722
3723 NTSTATUS OldStatus;
3724
3725 DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0);
3726
3727 //
3728 // We remember the previous status code because it may contain
3729 // information about the oplock status.
3730 //
3731
3732 OldStatus = Iosb.Status;
3733
3734 //
3735 // Determine the granted access for this operation now.
3736 //
3737
3738 if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
3739
3740 try_return( Iosb );
3741 }
3742
3743 //
3744 // And overwrite the file.
3745 //
3746
3747 Iosb = FatSupersedeOrOverwriteFile( IrpContext,
3748 FileObject,
3749 Fcb,
3751 EaBuffer,
3752 EaLength,
3755 NoEaKnowledge );
3756
3757 if (Iosb.Status == STATUS_SUCCESS) {
3758
3759 Iosb.Status = OldStatus;
3760 }
3761
3762 try_return( Iosb );
3763 }
3764
3765 //
3766 // If we ever get here then the I/O system gave us some bad input
3767 //
3768
3769#ifdef _MSC_VER
3770#pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
3771#endif
3773
3774 try_exit: NOTHING;
3775
3776 //
3777 // Update the share access and counts if successful
3778 //
3779
3780 if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS(Iosb.Status)) {
3781
3782 //
3783 // Now, we may have added some access bits above to indicate the access
3784 // this caller would conflict with (as opposed to what they get) in order
3785 // to perform the overwrite/supersede. We need to make a call to that will
3786 // recalculate the bits in the fileobject to reflect the real access they
3787 // will get.
3788 //
3789
3790 if (AddedAccess) {
3791
3793
3794 ClearFlag( *DesiredAccess, AddedAccess );
3795
3796#ifdef _MSC_VER
3797#pragma prefast( suppress:28931, "it needs to be there for debug assert" );
3798#endif
3801 FileObject,
3802 &Fcb->ShareAccess,
3803 TRUE );
3804
3805 //
3806 // It must be the case that we are really asking for less access, so
3807 // any conflict must have been detected before this point.
3808 //
3809
3811
3812 } else {
3813
3815 }
3816
3817 UnwindShareAccess = TRUE;
3818
3819 //
3820 // In case this was set, clear it now.
3821 //
3822
3824
3825 Fcb->UncleanCount += 1;
3826 Fcb->OpenCount += 1;
3829 }
3830 Vcb->OpenFileCount += 1;
3831 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
3832
3833 {
3834 PCCB Ccb;
3835
3836 Ccb = (PCCB)FileObject->FsContext2;
3837
3838 //
3839 // Mark the DeleteOnClose bit if the operation was successful.
3840 //
3841
3842 if ( DeleteOnClose ) {
3843
3845 }
3846
3847 //
3848 // Mark the OpenedByShortName bit if the operation was successful.
3849 //
3850
3851 if ( FileNameOpenedDos ) {
3852
3854 }
3855
3856 //
3857 // Mark the ManageVolumeAccess bit if the privilege is held.
3858 //
3859
3860 if (FatCheckManageVolumeAccess( IrpContext,
3861 IrpSp->Parameters.Create.SecurityContext->AccessState,
3863 UserMode :
3864 IrpContext->OriginatingIrp->RequestorMode ))) {
3865
3867 }
3868 }
3869
3870
3871 }
3872
3873 } _SEH2_FINALLY {
3874
3875 DebugUnwind( FatOpenExistingFcb );
3876
3877 //
3878 // Unpin the Dirent Bcb if pinned.
3879 //
3880
3881 FatUnpinBcb( IrpContext, DirentBcb );
3882
3883 //
3884 // If this is an abnormal termination then undo our work
3885 //
3886
3888
3889 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
3890 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Fcb->ShareAccess ); }
3891 }
3892
3893 if (DecrementFcbOpenCount) {
3894
3895 Fcb->OpenCount -= 1;
3896
3897 if (Fcb->OpenCount == 0) {
3899 FileObject->SectionObjectPointer = NULL;
3900 }
3901 FatDeleteFcb( IrpContext, &Fcb );
3902 FcbAcquired = FALSE;
3903 }
3904 }
3905
3906 if (FcbAcquired) {
3907
3908 FatReleaseFcb( IrpContext, Fcb );
3909 }
3910
3911 DebugTrace(-1, Dbg, "FatOpenExistingFcb -> Iosb.Status = %08lx\n", Iosb.Status);
3912 } _SEH2_END;
3913
3914 return Iosb;
3915}
3916
3917//
3918// Internal support routine
3919//
3920
3921_Requires_lock_held_(_Global_critical_region_)
3923FatOpenTargetDirectory (
3924 _In_ PIRP_CONTEXT IrpContext,
3929 _In_ BOOLEAN DoesNameExist,
3931 )
3932
3933/*++
3934
3935Routine Description:
3936
3937 This routine opens the target directory and replaces the name in the
3938 file object with the remaining name.
3939
3940Arguments:
3941
3942 FileObject - Supplies the File object
3943
3944 Dcb - Supplies an already existing dcb that we are going to open
3945
3946 DesiredAccess - Supplies the desired access of the caller
3947
3948 ShareAccess - Supplies the share access of the caller
3949
3950 DoesNameExist - Indicates if the file name already exists in the
3951 target directory.
3952
3953
3954Return Value:
3955
3956 IO_STATUS_BLOCK - Returns the completion status for the operation
3957
3958--*/
3959
3960{
3961 IO_STATUS_BLOCK Iosb = {0};
3962
3963 //
3964 // The following variables are for abnormal termination
3965 //
3966
3967 BOOLEAN UnwindShareAccess = FALSE;
3969 BOOLEAN DcbAcquired = FALSE;
3970
3971 PAGED_CODE();
3972
3973 DebugTrace(+1, Dbg, "FatOpenTargetDirectory...\n", 0);
3974
3975 //
3976 // Get the Dcb exlcusive. This is important as cleanup does not
3977 // acquire the Vcb.
3978 //
3979
3980 (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb );
3981 DcbAcquired = TRUE;
3982
3983 _SEH2_TRY {
3984
3985 ULONG i;
3986
3987 //
3988 // If the Dcb is already opened by someone then we need
3989 // to check the share access
3990 //
3991
3992 if (Dcb->OpenCount > 0) {
3993
3996 FileObject,
3997 &Dcb->ShareAccess,
3998 TRUE ))) {
3999
4000 try_return( Iosb );
4001 }
4002
4003 } else {
4004
4007 FileObject,
4008 &Dcb->ShareAccess );
4009 }
4010
4011 UnwindShareAccess = TRUE;
4012
4013 //
4014 // Setup the context and section object pointers, and update
4015 // our reference counts
4016 //
4017
4020 Dcb,
4021 UnwindCcb = FatCreateCcb( IrpContext ));
4022
4023 Dcb->UncleanCount += 1;
4024 Dcb->OpenCount += 1;
4025 Dcb->Vcb->OpenFileCount += 1;
4026 if (IsFileObjectReadOnly(FileObject)) { Dcb->Vcb->ReadOnlyCount += 1; }
4027
4028 //
4029 // Update the name in the file object, by definition the remaining
4030 // part must be shorter than the original file name so we'll just
4031 // overwrite the file name.
4032 //
4033
4034 i = FileObject->FileName.Length/sizeof(WCHAR) - 1;
4035
4036 //
4037 // Get rid of a trailing backslash
4038 //
4039
4040 if (FileObject->FileName.Buffer[i] == L'\\') {
4041
4042 NT_ASSERT(i != 0);
4043
4044 FileObject->FileName.Length -= sizeof(WCHAR);
4045 i -= 1;
4046 }
4047
4048 //
4049 // Find the first non-backslash character. i will be its index.
4050 //
4051
4052 while (TRUE) {
4053
4054 if (FileObject->FileName.Buffer[i] == L'\\') {
4055
4056 i += 1;
4057 break;
4058 }
4059
4060 if (i == 0) {
4061 break;
4062 }
4063
4064 i--;
4065 }
4066
4067 if (i) {
4068
4069 FileObject->FileName.Length -= (USHORT)(i * sizeof(WCHAR));
4070
4071 RtlMoveMemory( &FileObject->FileName.Buffer[0],
4072 &FileObject->FileName.Buffer[i],
4073 FileObject->FileName.Length );
4074 }
4075
4076 //
4077 // And set our status to success
4078 //
4079
4080 Iosb.Status = STATUS_SUCCESS;
4081 Iosb.Information = (DoesNameExist ? FILE_EXISTS : FILE_DOES_NOT_EXIST);
4082
4083 if ( ( NT_SUCCESS(Iosb.Status) ) && ( DoesNameExist ) ) {
4084 PCCB Ccb;
4085
4086 Ccb = (PCCB)FileObject->FsContext2;
4087
4088 //
4089 // Mark the OpenedByShortName bit if the operation was successful.
4090 //
4091
4092 if ( FileNameOpenedDos ) {
4093
4095 }
4096 }
4097
4098 try_exit: NOTHING;
4099 } _SEH2_FINALLY {
4100
4101 DebugUnwind( FatOpenTargetDirectory );
4102
4103 //
4104 // If this is an abnormal termination then undo our work
4105 //
4106
4108
4109 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
4110 if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); }
4111 }
4112
4113 if (DcbAcquired) {
4114
4115 FatReleaseFcb( IrpContext, Dcb );
4116 }
4117
4118 DebugTrace(-1, Dbg, "FatOpenTargetDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
4119 } _SEH2_END;
4120
4121 return Iosb;
4122}
4123
4124
4125
4126//
4127// Internal support routine
4128//
4130_Requires_lock_held_(_Global_critical_region_)
4132#ifdef _MSC_VER
4133#pragma warning(suppress:6101) // bug in PREFast means the _Success_ annotation is not correctly applied
4134#endif
4135FatOpenExistingDirectory (
4136 _In_ PIRP_CONTEXT IrpContext,
4153 )
4154
4155/*++
4156
4157Routine Description:
4158
4159 This routine opens the specified directory. The directory has not
4160 previously been opened.
4161
4162Arguments:
4163
4164 FileObject - Supplies the File object
4165
4166 Vcb - Supplies the Vcb denoting the volume containing the dcb
4167
4168 Dcb - Returns the newly-created DCB for the file.
4169
4170 ParentDcb - Supplies the parent directory containing the subdirectory
4171 to be opened
4172
4173 DirectoryName - Supplies the file name of the directory being opened.
4174
4175 Dirent - Supplies the dirent for the directory being opened
4176
4177 LfnByteOffset - Tells where the Lfn begins. If there is no Lfn
4178 this field is the same as DirentByteOffset.
4179
4180 DirentByteOffset - Supplies the Vbo of the dirent within its parent
4181 directory
4182
4183 Lfn - May supply a long name for the file.
4184
4185 DesiredAccess - Supplies the desired access of the caller
4186
4187 ShareAccess - Supplies the share access of the caller
4188
4189 CreateDisposition - Supplies the create disposition for this operation
4190
4191 NoEaKnowledge - This opener doesn't understand Ea's and we fail this
4192 open if the file has NeedEa's.
4193
4194 DeleteOnClose - The caller wants the file gone when the handle is closed
4195
4196 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
4197
4198Return Value:
4199
4200 IO_STATUS_BLOCK - Returns the completion status for the operation
4201
4202--*/
4203
4204{
4205 IO_STATUS_BLOCK Iosb = {0};
4206
4207 //
4208 // The following variables are for abnormal termination
4209 //
4210
4213
4215
4217#if (NTDDI_VERSION <= NTDDI_WIN7)
4219#endif
4221
4223
4224 DebugTrace(+1, Dbg, "FatOpenExistingDirectory...\n", 0);
4225
4227
4228 //
4229 // If the caller has no Ea knowledge, we immediately check for
4230 // Need Ea's on the file.
4231 //
4232
4233 if (NoEaKnowledge && !FatIsFat32(Vcb)) {
4234
4236
4237 FatGetNeedEaCount( IrpContext,
4238 Vcb,
4239 Dirent,
4240 &NeedEaCount );
4241
4242 if (NeedEaCount != 0) {
4243
4244 Iosb.Status = STATUS_ACCESS_DENIED;
4245 try_return( Iosb );
4246 }
4247 }
4248
4249 //
4250 // Check the create disposition and desired access
4251 //
4252
4253 if ((CreateDisposition != FILE_OPEN) &&
4255
4257 try_return( Iosb );
4258 }
4259
4260 if (!FatCheckFileAccess( IrpContext,
4261 Dirent->Attributes,
4262 DesiredAccess)) {
4263
4264 Iosb.Status = STATUS_ACCESS_DENIED;
4265 try_return( Iosb );
4266 }
4267
4268 //
4269 // Create a new dcb for the directory
4270 //
4271
4272 *Dcb = UnwindDcb = FatCreateDcb( IrpContext,
4273 Vcb,
4274 ParentDcb,
4277 Dirent,
4278 Lfn );
4279
4280#if (NTDDI_VERSION >= NTDDI_WIN8)
4281
4282 //
4283 // Let's make sure that if the caller provided an oplock key that it
4284 // gets stored in the file object.
4285 //
4286
4287 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(*Dcb),
4288 IrpContext->OriginatingIrp,
4290 NULL,
4291 NULL,
4292 NULL );
4293
4294 //
4295 // If the caller wants atomic create-with-oplock semantics, tell
4296 // the oplock package. We haven't incremented the Fcb's UncleanCount
4297 // for this create yet, so add that in on the call.
4298 //
4299
4301 (Iosb.Status == STATUS_SUCCESS)) {
4302
4304 IrpContext->OriginatingIrp,
4305 ((*Dcb)->UncleanCount + 1) );
4306 }
4307
4308 //
4309 // Get out if either of the above calls failed. Raise to trigger
4310 // cleanup of the new Dcb.
4311 //
4312
4313 if (Iosb.Status != STATUS_SUCCESS) {
4314
4315 NT_ASSERT( Iosb.Status != STATUS_PENDING );
4316
4317 FatRaiseStatus( IrpContext, Iosb.Status );
4318 }
4319#endif
4320
4321 //
4322 // Setup our share access
4323 //
4324
4327 FileObject,
4328 &(*Dcb)->ShareAccess );
4329
4330 //
4331 // Setup the context and section object pointers, and update
4332 // our reference counts
4333 //
4334
4337 (*Dcb),
4338 UnwindCcb = FatCreateCcb( IrpContext ));
4339
4340 (*Dcb)->UncleanCount += 1;
4341 (*Dcb)->OpenCount += 1;
4342 Vcb->OpenFileCount += 1;
4343 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
4344
4346
4347
4348 //
4349 // And set our status to success
4350 //
4351
4352 Iosb.Status = STATUS_SUCCESS;
4353 Iosb.Information = FILE_OPENED;
4354
4355 if ( NT_SUCCESS(Iosb.Status) ) {
4356 PCCB Ccb;
4357
4358 Ccb = (PCCB)FileObject->FsContext2;
4359
4360 //
4361 // Mark the OpenedByShortName bit if the operation was successful.
4362 //
4363
4364 if ( FileNameOpenedDos ) {
4365
4367 }
4368 }
4369
4370 try_exit: NOTHING;
4372
4373 DebugUnwind( FatOpenExistingDirectory );
4374
4375 //
4376 // If this is an abnormal termination then undo our work
4377 //
4378
4380
4381 if (CountsIncremented) {
4382
4383 (*Dcb)->UncleanCount -= 1;
4384 (*Dcb)->OpenCount -= 1;
4385 Vcb->OpenFileCount -= 1;
4386 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
4387 }
4388
4389 if (UnwindDcb != NULL) {
4391 FileObject->SectionObjectPointer = NULL;
4392 }
4393 FatDeleteFcb( IrpContext, &UnwindDcb );
4394 *Dcb = NULL;
4395 }
4396 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
4397 }
4398
4399 DebugTrace(-1, Dbg, "FatOpenExistingDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
4401
4402 return Iosb;
4403}
4404
4405
4406//
4407// Internal support routine
4408//
4409
4410_Requires_lock_held_(_Global_critical_region_)
4412FatOpenExistingFile (
4413 _In_ PIRP_CONTEXT IrpContext,
4422 _In_ PUNICODE_STRING OrigLfn,
4430 _In_ BOOLEAN IsPagingFile,
4435 )
4436
4437/*++
4438
4439Routine Description:
4440
4441 This routine opens the specified file. The file has not previously
4442 been opened.
4443
4444Arguments:
4445
4446 FileObject - Supplies the File object
4447
4448 Vcb - Supplies the Vcb denoting the volume containing the file
4449
4450 Fcb - Returns the newly-created FCB for the file.
4451
4452 ParentDcb - Supplies the parent directory containing the file to be
4453 opened
4454
4455 Dirent - Supplies the dirent for the file being opened
4456
4457 LfnByteOffset - Tells where the Lfn begins. If there is no Lfn
4458 this field is the same as DirentByteOffset.
4459
4460 DirentByteOffset - Supplies the Vbo of the dirent within its parent
4461 directory
4462
4463 Lfn - May supply a long name for the file.
4464
4465 DesiredAccess - Supplies the desired access of the caller
4466
4467 ShareAccess - Supplies the share access of the caller
4468
4469 AllocationSize - Supplies the initial allocation if the file is being
4470 superseded, overwritten, or created.
4471
4472 EaBuffer - Supplies the Ea set if the file is being superseded,
4473 overwritten, or created.
4474
4475 EaLength - Supplies the size, in byte, of the EaBuffer
4476
4477 FileAttributes - Supplies file attributes to use if the file is being
4478 superseded, overwritten, or created
4479
4480 CreateDisposition - Supplies the create disposition for this operation
4481
4482 IsPagingFile - Indicates if this is the paging file being opened.
4483
4484 NoEaKnowledge - This opener doesn't understand Ea's and we fail this
4485 open if the file has NeedEa's.
4486
4487 DeleteOnClose - The caller wants the file gone when the handle is closed
4488
4489 OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
4490
4491 FileNameOpenedDos - The caller opened this file by hitting the 8.3 side
4492 of the Lfn/8.3 pair
4493
4494Return Value:
4495
4496 IO_STATUS_BLOCK - Returns the completion status for the operation
4497
4498--*/
4499
4500{
4501 IO_STATUS_BLOCK Iosb = {0};
4502
4503 ACCESS_MASK AddedAccess = 0;
4504
4505 PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
4506
4507 //
4508 // The following variables are for abnormal termination
4509 //
4510
4511 PFCB UnwindFcb = NULL;
4514
4515
4516#if (NTDDI_VERSION < NTDDI_WIN7)
4518#endif
4519
4520 PAGED_CODE();
4521
4522 DebugTrace(+1, Dbg, "FatOpenExistingFile...\n", 0);
4523
4524 _SEH2_TRY {
4525
4526 //
4527 // Check if the user wanted to create the file or if access is
4528 // denied
4529 //
4530
4533 try_return( Iosb );
4534
4535 } else if ((CreateDisposition == FILE_SUPERSEDE) && !IsPagingFile) {
4536
4537 SetFlag( AddedAccess,
4538 DELETE & ~(*DesiredAccess) );
4539
4541
4542 } else if (((CreateDisposition == FILE_OVERWRITE) ||
4543 (CreateDisposition == FILE_OVERWRITE_IF)) && !IsPagingFile) {
4544
4545 SetFlag( AddedAccess,
4547
4549 }
4550
4551 if (!FatCheckFileAccess( IrpContext,
4552 Dirent->Attributes,
4553 DesiredAccess)) {
4554
4555 Iosb.Status = STATUS_ACCESS_DENIED;
4556 try_return( Iosb );
4557 }
4558
4559
4560 //
4561 // Check for trying to delete a read only file.
4562 //
4563
4564 if (DeleteOnClose &&
4565 FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY )) {
4566
4567 Iosb.Status = STATUS_CANNOT_DELETE;
4568 try_return( Iosb );
4569 }
4570
4571 //
4572 // IF we are asked to do an overwrite or supersede operation then
4573 // deny access for files where the file attributes for system and
4574 // hidden do not match
4575 //
4576
4580
4583
4586
4587 if ((Hidden && !FlagOn(FileAttributes, FILE_ATTRIBUTE_HIDDEN)) ||
4589
4590 DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0);
4591
4592 if ( !IsPagingFile ) {
4593
4594 Iosb.Status = STATUS_ACCESS_DENIED;
4595 try_return( Iosb );
4596 }
4597 }
4598
4599 //
4600 // If this media is write protected, don't even try the create.
4601 //
4602
4603 if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
4604
4605 //
4606 // Set the real device for the pop-up info, and set the verify
4607 // bit in the device object, so that we will force a verify
4608 // in case the user put the correct media back in.
4609 //
4610
4611
4612 IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
4613 Vcb->Vpb->RealDevice );
4614
4615 SetFlag(Vcb->Vpb->RealDevice->Flags, DO_VERIFY_VOLUME);
4616
4618 }
4619 }
4620
4621 //
4622 // Create a new Fcb for the file, and set the file size in
4623 // the fcb.
4624 //
4625
4626 *Fcb = UnwindFcb = FatCreateFcb( IrpContext,
4627 Vcb,
4628 ParentDcb,
4631 Dirent,
4632 Lfn,
4633 OrigLfn,
4634 IsPagingFile,
4635 FALSE );
4636
4637
4638 (*Fcb)->Header.ValidDataLength.LowPart = (*Fcb)->Header.FileSize.LowPart;
4639
4640 //
4641 // If this is a paging file, lookup the allocation size so that
4642 // the Mcb is always valid
4643 //
4644
4645 if (IsPagingFile) {
4646
4647 FatLookupFileAllocationSize( IrpContext, *Fcb );
4648 }
4649
4650#if (NTDDI_VERSION >= NTDDI_WIN7)
4651
4652 //
4653 // Let's make sure that if the caller provided an oplock key that it
4654 // gets stored in the file object.
4655 //
4656
4657 Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(*Fcb),
4658 IrpContext->OriginatingIrp,
4660 NULL,
4661 NULL,
4662 NULL );
4663
4664 //
4665 // If the caller wants atomic create-with-oplock semantics, tell
4666 // the oplock package. We haven't incremented the Fcb's UncleanCount
4667 // for this create yet, so add that in on the call.
4668 //
4669
4670 if (OpenRequiringOplock &&
4671 (Iosb.Status == STATUS_SUCCESS)) {
4672
4674 IrpContext->OriginatingIrp,
4675 ((*Fcb)->UncleanCount + 1) );
4676 }
4677
4678 //
4679 // Get out if either of the above calls failed. Raise to trigger
4680 // cleanup of the new Fcb.
4681 //
4682
4683 if (Iosb.Status != STATUS_SUCCESS) {
4684
4685 NT_ASSERT( Iosb.Status != STATUS_PENDING );
4686
4687 FatRaiseStatus( IrpContext, Iosb.Status );
4688 }
4689#endif
4690
4691 //
4692 // Now case on whether we are to simply open, supersede, or
4693 // overwrite the file.
4694 //
4695
4696 switch (CreateDisposition) {
4697
4698 case FILE_OPEN:
4699 case FILE_OPEN_IF:
4700
4701 DebugTrace(0, Dbg, "Doing only an open operation\n", 0);
4702
4703 //
4704 // If the caller has no Ea knowledge, we immediately check for
4705 // Need Ea's on the file.
4706 //
4707
4708 if (NoEaKnowledge && !FatIsFat32(Vcb)) {
4709
4711
4712 FatGetNeedEaCount( IrpContext,
4713 Vcb,
4714 Dirent,
4715 &NeedEaCount );
4716
4717 if (NeedEaCount != 0) {
4718
4719 FatRaiseStatus( IrpContext, STATUS_ACCESS_DENIED );
4720 }
4721 }
4722
4723 //
4724 // Setup the context and section object pointers.
4725 //
4726
4729 *Fcb,
4730 UnwindCcb = FatCreateCcb( IrpContext ));
4731
4732 FileObject->SectionObjectPointer = &(*Fcb)->NonPaged->SectionObjectPointers;
4733
4734 Iosb.Status = STATUS_SUCCESS;
4735 Iosb.Information = FILE_OPENED;
4736 break;
4737
4738 case FILE_SUPERSEDE:
4739 case FILE_OVERWRITE:
4740 case FILE_OVERWRITE_IF:
4741
4742 DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0);
4743
4744 //
4745 // Determine the granted access for this operation now.
4746 //
4747
4748 if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
4749
4750 try_return( Iosb );
4751 }
4752
4753 Iosb = FatSupersedeOrOverwriteFile( IrpContext,
4754 FileObject,
4755 *Fcb,
4757 EaBuffer,
4758 EaLength,
4761 NoEaKnowledge );
4762 break;
4763
4764 default:
4765
4766 DebugTrace(0, Dbg, "Illegal Create Disposition\n", 0);
4767
4768#ifdef _MSC_VER
4769#pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
4770#endif
4772 break;
4773 }
4774
4775 try_exit: NOTHING;
4776
4777 //
4778 // Setup our share access and counts if things were successful.
4779 //
4780
4781 if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS( Iosb.Status )) {
4782
4783 //
4784 // Remove any virtual access the caller needed to check against, but will
4785 // not really receive. Overwrite/supersede is a bit of a special case.
4786 //
4787
4788 ClearFlag( *DesiredAccess, AddedAccess );
4789
4792 FileObject,
4793 &(*Fcb)->ShareAccess );
4794
4795 (*Fcb)->UncleanCount += 1;
4796 (*Fcb)->OpenCount += 1;
4798 (*Fcb)->NonCachedUncleanCount += 1;
4799 }
4800 Vcb->OpenFileCount += 1;
4801 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
4802
4804 }
4805
4806 {
4807 PCCB Ccb;
4808
4809 Ccb = (PCCB)FileObject->FsContext2;
4810
4811 if ( NT_SUCCESS(Iosb.Status) ) {
4812
4813 //
4814 // Mark the DeleteOnClose bit if the operation was successful.
4815 //
4816
4817 if ( DeleteOnClose ) {
4818
4820 }
4821
4822 //
4823 // Mark the OpenedByShortName bit if the operation was successful.
4824 //
4825
4826 if ( FileNameOpenedDos ) {
4827
4829 }
4830
4831 //
4832 // Mark the ManageVolumeAccess bit if the privilege is held.
4833 //
4834
4835 if (FatCheckManageVolumeAccess( IrpContext,
4836 IrpSp->Parameters.Create.SecurityContext->AccessState,
4838 UserMode :
4839 IrpContext->OriginatingIrp->RequestorMode ))) {
4840
4842 }
4843
4844 }
4845 }
4846
4847
4848 } _SEH2_FINALLY {
4849
4850 DebugUnwind( FatOpenExistingFile );
4851
4852 //
4853 // If this is an abnormal termination then undo our work
4854 //
4855
4857
4858 if (CountsIncremented) {
4859 (*Fcb)->UncleanCount -= 1;
4860 (*Fcb)->OpenCount -= 1;
4862 (*Fcb)->NonCachedUncleanCount -= 1;
4863 }
4864 Vcb->OpenFileCount -= 1;
4865 if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
4866 }
4867
4868 if (UnwindFcb != NULL) {
4870 FileObject->SectionObjectPointer = NULL;
4871 }
4872 FatDeleteFcb( IrpContext, &UnwindFcb );
4873 *Fcb = NULL;
4874 }
4875
4876 if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
4877 }
4878
4879 DebugTrace(-1, Dbg, "FatOpenExistingFile -> Iosb.Status = %08lx\n", Iosb.Status);
4880 } _SEH2_END;
4881
4882 return Iosb;
4883}
4884
4885
4886//
4887// Internal support routine
4888//
4889
4890_Requires_lock_held_(_Global_critical_region_)
4892FatCreateNewDirectory (
4893 _In_ PIRP_CONTEXT IrpContext,