ReactOS  0.4.15-dev-994-ga9f6032
create.c
Go to the documentation of this file.
1 /*++
2 
3 Copyright (c) 1989-2000 Microsoft Corporation
4 
5 Module Name:
6 
7  Create.c
8 
9 Abstract:
10 
11  This module implements the File Create routine for Fat called by the
12  dispatch driver.
13 
14 
15 --*/
16 
17 #include "fatprocs.h"
18 
19 //
20 // The Bug check file id for this module
21 //
22 
23 #define BugCheckFileId (FAT_BUG_CHECK_CREATE)
24 
25 //
26 // The debug trace level
27 //
28 
29 #define Dbg (DEBUG_TRACE_CREATE)
30 
31 
32 //
33 // Macros for incrementing performance counters.
34 //
35 
36 #define CollectCreateHitStatistics(VCB) { \
37  PFILE_SYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors]; \
38  Stats->Fat.CreateHits += 1; \
39 }
40 
41 #define CollectCreateStatistics(VCB,STATUS) { \
42  PFILE_SYSTEM_STATISTICS Stats = &(VCB)->Statistics[KeGetCurrentProcessorNumber() % FatData.NumberProcessors]; \
43  if ((STATUS) == STATUS_SUCCESS) { \
44  Stats->Fat.SuccessfulCreates += 1; \
45  } else { \
46  Stats->Fat.FailedCreates += 1; \
47  } \
48 }
49 
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_)
69 FatOpenRootDcb (
70  _In_ PIRP_CONTEXT IrpContext,
76  );
77 
78 _Requires_lock_held_(_Global_critical_region_)
80 FatOpenExistingDcb (
81  _In_ PIRP_CONTEXT IrpContext,
93  _Out_ PBOOLEAN OplockPostIrp
94  );
95 
96 _Requires_lock_held_(_Global_critical_region_)
98 FatOpenExistingFcb (
99  _In_ PIRP_CONTEXT IrpContext,
102  _Inout_ PVCB Vcb,
103  _Inout_ PFCB Fcb,
115  _Out_ PBOOLEAN OplockPostIrp
116  );
117 
118 _Requires_lock_held_(_Global_critical_region_)
120 FatOpenTargetDirectory (
121  _In_ PIRP_CONTEXT IrpContext,
123  _Inout_ PDCB Dcb,
126  _In_ BOOLEAN DoesNameExist,
128  );
129 
131 _Requires_lock_held_(_Global_critical_region_)
133 FatOpenExistingDirectory (
134  _In_ PIRP_CONTEXT IrpContext,
137  _Inout_ PVCB Vcb,
151  );
152 
153 _Requires_lock_held_(_Global_critical_region_)
155 FatOpenExistingFile (
156  _In_ PIRP_CONTEXT IrpContext,
158  _Inout_ PVCB Vcb,
165  _In_ PUNICODE_STRING OrigLfn,
173  _In_ BOOLEAN IsPagingFile,
178  );
179 
180 _Requires_lock_held_(_Global_critical_region_)
182 FatCreateNewDirectory (
183  _In_ PIRP_CONTEXT IrpContext,
186  _Inout_ PVCB Vcb,
198  );
199 
200 _Requires_lock_held_(_Global_critical_region_)
202 FatCreateNewFile (
203  _In_ PIRP_CONTEXT IrpContext,
206  _Inout_ PVCB Vcb,
216  _In_ PUNICODE_STRING LfnBuffer,
217  _In_ BOOLEAN IsPagingFile,
221  _In_ BOOLEAN TemporaryFile
222  );
223 
224 
225 _Requires_lock_held_(_Global_critical_region_)
227 FatSupersedeOrOverwriteFile (
228  _In_ PIRP_CONTEXT IrpContext,
230  _Inout_ PFCB Fcb,
237  );
238 
239 NTSTATUS
241  _In_ PIRP_CONTEXT IrpContext
242  );
243 
244 NTSTATUS
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 
280 NTSTATUS
281 NTAPI
282 FatFsdCreate (
283  _In_ PVOLUME_DEVICE_OBJECT VolumeDeviceObject,
285  )
286 
287 /*++
288 
289 Routine Description:
290 
291  This routine implements the FSD part of the NtCreateFile and NtOpenFile
292  API calls.
293 
294 Arguments:
295 
296  VolumeDeviceObject - Supplies the volume device object where the
297  file/directory exists that we are trying to open/create
298 
299  Irp - Supplies the Irp being processed
300 
301 Return Value:
302 
303  NTSTATUS - The Fsd status for the Irp
304 
305 --*/
306 
307 {
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 
332  TimerStart(Dbg);
333 
334  DebugTrace(+1, Dbg, "FatFsdCreate\n", 0);
335 
336  //
337  // Call the common create routine, with block allowed if the operation
338  // is synchronous.
339  //
340 
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_)
399 VOID
400 FatCommonCreateCallout (
401  _In_ PFAT_CALLOUT_PARAMETERS CalloutParameters
402  )
403 
404 /*++
405 
406 Routine Description:
407 
408  This function is the callout routine that will execute on a new stack when
409  processing a create. It simply calls FatCommonCreate() with the parameters
410  in the context and stores the return value in the context.
411 
412 Arguments:
413 
414  Context - Supplies an opaque pointer to this function's context. It is actually
415  an FAT_CALLOUT_PARAMETERS structure.
416 
417 Return Value:
418 
419  None.
420 
421 --*/
422 
423 {
424  PAGED_CODE();
425 
426  //
427  // Call FatCommonCreate() with the passed parameters and store the result.
428  // Exceptions cannot be raised across stack boundaries, so we need to catch
429  // exceptions here and deal with them.
430  //
431 
432  try {
433 
434  CalloutParameters->IrpStatus = FatCommonCreate( CalloutParameters->Create.IrpContext,
435  CalloutParameters->Create.Irp );
436 
437  } except (FatExceptionFilter( CalloutParameters->Create.IrpContext, GetExceptionInformation() )) {
438 
439  //
440  // Return the resulting status.
441  //
442 
443  CalloutParameters->ExceptionStatus = GetExceptionCode();
444  }
445 
446 }
447 
448 
449 _Requires_lock_held_(_Global_critical_region_)
450 NTSTATUS
451 FatCommonCreateOnNewStack (
452  _In_ PIRP_CONTEXT IrpContext,
453  _In_ PIRP Irp
454  )
455 
456 /*++
457 
458 Routine Description:
459 
460  This routine sets up a switch to a new stack and call to FatCommonCreate().
461 
462 Arguments:
463 
464  IrpContext - Supplies the context structure for the overall request.
465 
466  Irp - Supplies the IRP being processed.
467 
468  CreateContext - Supplies a pointer on the old stack that is used to
469  store context information for the create itself.
470 
471 Return Value:
472 
473  NTSTATUS - The status from FatCommonCreate().
474 
475 --*/
476 {
477  FAT_CALLOUT_PARAMETERS CalloutParameters;
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_)
551 NTSTATUS
552 FatCommonCreate (
553  _Inout_ PIRP_CONTEXT IrpContext,
555  )
556 
557 /*++
558 
559 Routine Description:
560 
561  This is the common routine for creating/opening a file called by
562  both the fsd and fsp threads.
563 
564 Arguments:
565 
566  Irp - Supplies the Irp to process
567 
568 Return Value:
569 
570  NTSTATUS - the return status for the operation
571 
572 --*/
573 
574 {
576  IO_STATUS_BLOCK Iosb = {0};
578 
580  PFILE_OBJECT RelatedFileObject;
585  ULONG Options;
588  ULONG EaLength;
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;
608  PDCB ParentDcb;
609  PDCB FinalDcb = NULL;
610 
611  UNICODE_STRING FinalName = {0};
613  UNICODE_STRING NextRemainingPart = {0};
614  UNICODE_STRING UpcasedFinalName;
615  WCHAR UpcasedBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE];
616 
617  OEM_STRING OemFinalName;
619 
620  PDIRENT Dirent;
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 
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;
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 
748  return STATUS_NOT_IMPLEMENTED;
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 
811  if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS)) {
812 
813 #ifdef _MSC_VER
814 #pragma prefast( suppress:28159, "this is a serious programming error if it happens" )
815 #endif
816  FatBugCheck( 0, 0, 0);
817  }
818 
819  //
820  // Initialize the DirentBcb to null
821  //
822 
823  DirentBcb = NULL;
824 
825  //
826  // Initialize our temp strings with their stack buffers.
827  //
828 
829  OemFinalName.Length = 0;
830  OemFinalName.MaximumLength = sizeof( OemBuffer);
831  OemFinalName.Buffer = (PCHAR)OemBuffer;
832 
833  UpcasedFinalName.Length = 0;
834  UpcasedFinalName.MaximumLength = sizeof( UpcasedBuffer);
835  UpcasedFinalName.Buffer = UpcasedBuffer;
836 
837  Lfn.Length = 0;
838  Lfn.MaximumLength = sizeof( LfnBuffer);
839  Lfn.Buffer = LfnBuffer;
840 
841  _SEH2_TRY {
842 
843  //
844  // Make sure the vcb is in a usable condition. This will raise
845  // and error condition if the volume is unusable
846  //
847 
848  FatVerifyVcb( IrpContext, Vcb );
849 
850  //
851  // If the Vcb is locked then we cannot open another file
852  //
853 
854  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
855 
856  DebugTrace(0, Dbg, "Volume is locked\n", 0);
857 
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 
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,
940  FileObject,
941  Vcb,
943  ShareAccess,
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 
1040  try_return( Iosb.Status = STATUS_CANNOT_DELETE );
1041  }
1042 
1043  DebugTrace(0, Dbg, "Opening root dcb\n", 0);
1044 
1046 
1047  Iosb = FatOpenRootDcb( IrpContext,
1048  FileObject,
1049  Vcb,
1050  DesiredAccess,
1051  ShareAccess,
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,
1159  &FileNameOpenedDos );
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,
1200  &FileNameOpenedDos );
1201  }
1202 
1203  //
1204  // If we got back an Fcb then we consumed the FinalName
1205  // legitimately, so the remaining name is now RemainingPart.
1206  //
1207 
1208  if (NextFcb != NULL) {
1209  Fcb = NextFcb;
1210  RemainingPart = NextRemainingPart;
1211  }
1212 
1213  if ((NextFcb == NULL) ||
1214  (NodeType(NextFcb) == FAT_NTC_FCB) ||
1215  (NextRemainingPart.Length == 0)) {
1216 
1217  break;
1218  }
1219  }
1220 
1221  //
1222  // Remaining name cannot start with a backslash
1223  //
1224 
1225  if (RemainingPart.Length && (RemainingPart.Buffer[0] == L'\\')) {
1226 
1227  RemainingPart.Length -= sizeof(WCHAR);
1228  RemainingPart.Buffer += 1;
1229  }
1230 
1231  //
1232  // Now verify that everybody up to the longest found prefix is valid.
1233  //
1234 
1235  _SEH2_TRY {
1236 
1237  FatVerifyFcb( IrpContext, Fcb );
1238 
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 
1298  try_return( Iosb.Status = STATUS_ACCESS_DENIED );
1299  }
1300 
1301  //
1302  // If the longest prefix is pending delete (either the file or
1303  // some higher level directory), we cannot continue.
1304  //
1305 
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,
1332  DesiredAccess,
1333  ShareAccess,
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,
1368  DesiredAccess,
1369  ShareAccess,
1371  NoEaKnowledge,
1372  DeleteOnClose,
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,
1427  DesiredAccess,
1428  ShareAccess,
1430  EaBuffer,
1431  EaLength,
1434  NoEaKnowledge,
1435  DeleteOnClose,
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
1471  FatBugCheck( NodeType(Fcb), (ULONG_PTR) Fcb, 0 );
1472  }
1473 
1474  //
1475  // There is more in the name to parse than we have in existing
1476  // fcbs/dcbs. So now make sure that fcb we got for the largest
1477  // matching prefix is really a dcb otherwise we can't go any
1478  // further
1479  //
1480 
1481  if ((NodeType(Fcb) != FAT_NTC_DCB) && (NodeType(Fcb) != FAT_NTC_ROOT_DCB)) {
1482 
1483  DebugTrace(0, Dbg, "Cannot open file as subdirectory, Fcb = %p\n", Fcb);
1484 
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,
1687  LfnByteOffset,
1689  Dirent,
1690  &Lfn );
1691 
1692  //
1693  // Remember we created this Dcb for error recovery.
1694  //
1695 
1696  FinalDcb = ParentDcb;
1697 
1698  FatSetFullNameInFcb( IrpContext, ParentDcb, &FinalName );
1699  }
1700 
1701  //
1702  // First check if the user wanted to open the target directory
1703  // and if so then call the subroutine to finish the open.
1704  //
1705 
1706  if (OpenTargetDirectory) {
1707 
1708  Iosb = FatOpenTargetDirectory( IrpContext,
1709  FileObject,
1710  ParentDcb,
1711  DesiredAccess,
1712  ShareAccess,
1713  Dirent ? TRUE : FALSE,
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,
1756  LfnByteOffset,
1758  &Lfn,
1759  DesiredAccess,
1760  ShareAccess,
1762  NoEaKnowledge,
1763  DeleteOnClose,
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,
1796  LfnByteOffset,
1798  &Lfn,
1799  &OrigLfn,
1800  DesiredAccess,
1801  ShareAccess,
1803  EaBuffer,
1804  EaLength,
1807  IsPagingFile,
1808  NoEaKnowledge,
1809  DeleteOnClose,
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 
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,
1905  DesiredAccess,
1906  ShareAccess,
1907  EaBuffer,
1908  EaLength,
1910  NoEaKnowledge,
1911  DeleteOnClose,
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 
1942 
1944  }
1945 
1946 
1947  Iosb = FatCreateNewFile( IrpContext,
1948  IrpSp,
1949  FileObject,
1950  Vcb,
1951  ParentDcb,
1952  &OemFinalName,
1953  &FinalName,
1954  DesiredAccess,
1955  ShareAccess,
1957  EaBuffer,
1958  EaLength,
1960  &Lfn,
1961  IsPagingFile,
1962  NoEaKnowledge,
1963  DeleteOnClose,
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) &&
2022  FatIsFileOplockable( Fcb )) {
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 
2089  if (_SEH2_AbnormalTermination()) {
2090 
2091  FatReleaseVcb( IrpContext, Vcb );
2092  }
2093 
2094  //
2095  // Free up any string buffers we allocated
2096  //
2097 
2098  FatFreeStringBuffer( &OemFinalName);
2099 
2100  FatFreeStringBuffer( &UpcasedFinalName);
2101 
2103  } _SEH2_END;
2104 
2105  //
2106  // The following code is only executed if we are exiting the
2107  // procedure through a normal termination. We complete the request
2108  // and if for any reason that bombs out then we need to unreference
2109  // and possibly delete the fcb and ccb.
2110  //
2111 
2112  _SEH2_TRY {
2113 
2114  if (PostIrp) {
2115 
2116  //
2117  // If the Irp hasn't already been posted, do it now.
2118  //
2119 
2120  if (!OplockPostIrp) {
2121 
2122  Iosb.Status = FatFsdPostRequest( IrpContext, Irp );
2123  }
2124 
2125  } else {
2126 
2127  FatUnpinRepinnedBcbs( IrpContext );
2128  }
2129 
2130  } _SEH2_FINALLY {
2131 
2132  DebugUnwind( FatCommonCreate-in-FatCompleteRequest );
2133 
2134  if (_SEH2_AbnormalTermination() ) {
2135 
2136  PVCB LocalVcb;
2137  PFCB LocalFcb;
2138  PCCB LocalCcb2;
2139  PFILE_OBJECT DirectoryFileObject;
2140 
2141  //
2142  // Unwind all of our counts. Note that if a write failed, then
2143  // the volume has been marked for verify, and all volume
2144  // structures will be cleaned up automatically.
2145  //
2146 
2147  (VOID) FatDecodeFileObject( FileObject, &LocalVcb, &LocalFcb, &LocalCcb2 );
2148 
2149  LocalFcb->UncleanCount -= 1;
2150  LocalFcb->OpenCount -= 1;
2151  LocalVcb->OpenFileCount -= 1;
2152 
2153  if (IsFileObjectReadOnly(FileObject)) { LocalVcb->ReadOnlyCount -= 1; }
2154 
2155 
2156  //
2157  // WinSE #307418 "Occasional data corruption when standby/resume
2158  // while copying files to removable FAT formatted media".
2159  // If new file creation request was interrupted by system suspend
2160  // operation we should revert the changes we made to the parent
2161  // directory and to the allocation table.
2162  //
2163 
2164  if (IrpContext->ExceptionStatus == STATUS_VERIFY_REQUIRED &&
2165  NodeType( LocalFcb ) == FAT_NTC_FCB) {
2166 
2167  FatTruncateFileAllocation( IrpContext, LocalFcb, 0 );
2168 
2169  FatDeleteDirent( IrpContext, LocalFcb, NULL, TRUE );
2170  }
2171 
2172  //
2173  // If we leafed out on a new Fcb we should get rid of it at this point.
2174  //
2175  // Since the object isn't being opened, we have to do all of the teardown
2176  // here. Our close path will not occur for this fileobject. Note this
2177  // will leave a branch of Dcbs dangling since we do it by hand and don't
2178  // chase to the root.
2179  //
2180 
2181  if (LocalFcb->OpenCount == 0 &&
2182  (NodeType( LocalFcb ) == FAT_NTC_FCB ||
2183  IsListEmpty(&LocalFcb->Specific.Dcb.ParentDcbQueue))) {
2184 
2185  NT_ASSERT( NodeType( LocalFcb ) != FAT_NTC_ROOT_DCB );
2186 
2187  if ( (NodeType( LocalFcb ) == FAT_NTC_DCB) &&
2188  (LocalFcb->Specific.Dcb.DirectoryFile != NULL) ) {
2189 
2190  DirectoryFileObject = LocalFcb->Specific.Dcb.DirectoryFile;
2191  LocalFcb->Specific.Dcb.DirectoryFile = NULL;
2192 
2193  CcUninitializeCacheMap( DirectoryFileObject,
2194  &FatLargeZero,
2195  NULL );
2196 
2197  ObDereferenceObject( DirectoryFileObject );
2198 
2199  } else {
2200  if (ARGUMENT_PRESENT( FileObject )) {
2201  FileObject->SectionObjectPointer = NULL;
2202  }
2203  FatDeleteFcb( IrpContext, &LocalFcb );
2204  }
2205  }
2206 
2207  FatDeleteCcb( IrpContext, &LocalCcb2 );
2208 
2209  FatReleaseVcb( IrpContext, LocalVcb );
2210 
2211  } else {
2212 
2213  FatReleaseVcb( IrpContext, Vcb );
2214 
2215  if ( !PostIrp ) {
2216 
2217  //
2218  // If this request is successful and the file was opened
2219  // for FILE_EXECUTE access, then set the FileObject bit.
2220  //
2221 
2222  NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL );
2223  if (FlagOn( *DesiredAccess, FILE_EXECUTE )) {
2224 
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 
2281  CollectCreateStatistics(Vcb, Iosb.Status);
2282 
2283  return Iosb.Status;
2284 }
2285 
2286 //
2287 // Internal support routine
2288 //
2289 
2290 _Requires_lock_held_(_Global_critical_region_)
2292 FatOpenVolume (
2293  _In_ PIRP_CONTEXT IrpContext,
2295  _Inout_ PVCB Vcb,
2299  )
2300 
2301 /*++
2302 
2303 Routine Description:
2304 
2305  This routine opens the specified volume for DASD access
2306 
2307 Arguments:
2308 
2309  FileObject - Supplies the File object
2310 
2311  Vcb - Supplies the Vcb denoting the volume being opened
2312 
2313  DesiredAccess - Supplies the desired access of the caller
2314 
2315  ShareAccess - Supplies the share access of the caller
2316 
2317  CreateDisposition - Supplies the create disposition for this operation
2318 
2319 Return Value:
2320 
2321  IO_STATUS_BLOCK - Returns the completion status for the operation
2322 
2323 --*/
2324 
2325 {
2326  NTSTATUS Status;
2328 
2329 #ifndef __REACTOS__
2330  IO_STATUS_BLOCK Iosb = {0,0};
2331 #else
2332  IO_STATUS_BLOCK Iosb = {{0}};
2333 #endif
2334 
2335  BOOLEAN CleanedVolume = FALSE;
2336 
2337  //
2338  // The following variables are for abnormal termination
2339  //
2340 
2341  BOOLEAN UnwindShareAccess = FALSE;
2342  PCCB UnwindCcb = NULL;
2343  BOOLEAN UnwindCounts = FALSE;
2344  BOOLEAN UnwindVolumeLock = FALSE;
2345 
2346  PAGED_CODE();
2347 
2348  DebugTrace(+1, Dbg, "FatOpenVolume...\n", 0);
2349 
2350  _SEH2_TRY {
2351 
2352  //
2353  // Check for proper desired access and rights
2354  //
2355 
2356  if ((CreateDisposition != FILE_OPEN) &&
2358 
2359  try_return( Iosb.Status = STATUS_ACCESS_DENIED );
2360  }
2361 
2362  //
2363  // If the user does not want to share write or delete then we will try
2364  // and take out a lock on the volume.
2365  //
2366 
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 
2491  ShareAccess,
2492  FileObject,
2493  &Vcb->ShareAccess,
2494  TRUE ))) {
2495 
2496  try_return( Iosb.Status );
2497  }
2498 
2499  } else {
2500 
2502  ShareAccess,
2503  FileObject,
2504  &Vcb->ShareAccess );
2505  }
2506 
2507  UnwindShareAccess = TRUE;
2508 
2509  //
2510  // Set up the context and section object pointers, and update
2511  // our reference counts
2512  //
2513 
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 );
2533  Status = FatExplicitDeviceAccessGranted( IrpContext,
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_)
2586 FatOpenRootDcb (
2587  _In_ PIRP_CONTEXT IrpContext,
2589  _Inout_ PVCB Vcb,
2593  )
2594 
2595 /*++
2596 
2597 Routine Description:
2598 
2599  This routine opens the root dcb for the volume
2600 
2601 Arguments:
2602 
2603  FileObject - Supplies the File object
2604 
2605  Vcb - Supplies the Vcb denoting the volume whose dcb is being opened.
2606 
2607  DesiredAccess - Supplies the desired access of the caller
2608 
2609  ShareAccess - Supplies the share access of the caller
2610 
2611  CreateDisposition - Supplies the create disposition for this operation
2612 
2613 Return Value:
2614 
2615  IO_STATUS_BLOCK - Returns the completion status for the operation
2616 
2617 Arguments:
2618 
2619 --*/
2620 
2621 {
2622  PDCB RootDcb;
2623  IO_STATUS_BLOCK Iosb = {0};
2624 
2625  //
2626  // The following variables are for abnormal termination
2627  //
2628 
2629  BOOLEAN UnwindShareAccess = FALSE;
2630  PCCB UnwindCcb = NULL;
2631  BOOLEAN UnwindCounts = FALSE;
2632  BOOLEAN RootDcbAcquired = FALSE;
2633 
2634  PAGED_CODE();
2635 
2636  DebugTrace(+1, Dbg, "FatOpenRootDcb...\n", 0);
2637 
2638  //
2639  // Locate the root dcb
2640  //
2641 
2642  RootDcb = Vcb->RootDcb;
2643 
2644  //
2645  // Get the Dcb exlcusive. This is important as cleanup does not
2646  // acquire the Vcb.
2647  //
2648 
2649  (VOID)FatAcquireExclusiveFcb( IrpContext, RootDcb );
2650  RootDcbAcquired = TRUE;
2651 
2652  _SEH2_TRY {
2653 
2654  //
2655  // Check the create disposition and desired access
2656  //
2657 
2658  if ((CreateDisposition != FILE_OPEN) &&
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 
2681  ShareAccess,
2682  FileObject,
2683  &RootDcb->ShareAccess,
2684  TRUE ))) {
2685 
2686  try_return( Iosb );
2687  }
2688 
2689  } else {
2690 
2692  ShareAccess,
2693  FileObject,
2694  &RootDcb->ShareAccess );
2695  }
2696 
2697  UnwindShareAccess = TRUE;
2698 
2699  //
2700  // Setup the context and section object pointers, and update
2701  // our reference counts
2702  //
2703 
2706  RootDcb,
2707  UnwindCcb = FatCreateCcb( IrpContext ));
2708 
2709  RootDcb->UncleanCount += 1;
2710  RootDcb->OpenCount += 1;
2711  Vcb->OpenFileCount += 1;
2712  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
2713  UnwindCounts = TRUE;
2714 
2715  //
2716  // And set our status to success
2717  //
2718 
2719  Iosb.Status = STATUS_SUCCESS;
2720  Iosb.Information = FILE_OPENED;
2721 
2722  try_exit: NOTHING;
2723  } _SEH2_FINALLY {
2724 
2725  DebugUnwind( FatOpenRootDcb );
2726 
2727  //
2728  // If this is an abnormal termination then undo our work
2729  //
2730 
2731  if (_SEH2_AbnormalTermination()) {
2732 
2733  if (UnwindCounts) {
2734  RootDcb->UncleanCount -= 1;
2735  RootDcb->OpenCount -= 1;
2736  Vcb->OpenFileCount -= 1;
2737  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
2738  }
2739  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
2740  if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &RootDcb->ShareAccess ); }
2741  }
2742 
2743  if (RootDcbAcquired) {
2744 
2745  FatReleaseFcb( IrpContext, RootDcb );
2746  }
2747 
2748  DebugTrace(-1, Dbg, "FatOpenRootDcb -> Iosb.Status = %08lx\n", Iosb.Status);
2749  } _SEH2_END;
2750 
2751  return Iosb;
2752 }
2753 
2754 
2755 //
2756 // Internal support routine
2757 //
2758 
2759 _Requires_lock_held_(_Global_critical_region_)
2761 FatOpenExistingDcb (
2762  _In_ PIRP_CONTEXT IrpContext,
2765  _Inout_ PVCB Vcb,
2766  _Inout_ PDCB Dcb,
2774  _Out_ PBOOLEAN OplockPostIrp
2775  )
2776 
2777 /*++
2778 
2779 Routine Description:
2780 
2781  This routine opens the specified existing dcb
2782 
2783 Arguments:
2784 
2785  FileObject - Supplies the File object
2786 
2787  Vcb - Supplies the Vcb denoting the volume containing the dcb
2788 
2789  Dcb - Supplies the already existing dcb
2790 
2791  DesiredAccess - Supplies the desired access of the caller
2792 
2793  ShareAccess - Supplies the share access of the caller
2794 
2795  CreateDisposition - Supplies the create disposition for this operation
2796 
2797  NoEaKnowledge - This opener doesn't understand Ea's and we fail this
2798  open if the file has NeedEa's.
2799 
2800  DeleteOnClose - The caller wants the file gone when the handle is closed
2801 
2802 Return Value:
2803 
2804  IO_STATUS_BLOCK - Returns the completion status for the operation
2805 
2806 --*/
2807 
2808 {
2809  IO_STATUS_BLOCK Iosb = {0};
2810  PBCB DirentBcb = NULL;
2811  PDIRENT Dirent;
2812 
2813  //
2814  // The following variables are for abnormal termination
2815  //
2816 
2817  BOOLEAN UnwindShareAccess = FALSE;
2818  PCCB UnwindCcb = NULL;
2819  BOOLEAN DcbAcquired = FALSE;
2820 
2821 #if (NTDDI_VERSION <= NTDDI_WIN7)
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 
2872  try_return( NOTHING );
2873  }
2874 
2875 #endif
2876  //
2877  // If the caller has no Ea knowledge, we immediately check for
2878  // Need Ea's on the file. We don't need to check for ea's on the
2879  // root directory, because it never has any. Fat32 doesn't have
2880  // any, either.
2881  //
2882 
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,
2942  DesiredAccess,
2943  ShareAccess ))) {
2944 #if (NTDDI_VERSION >= NTDDI_WIN8)
2945 
2946  NTSTATUS OplockBreakStatus = STATUS_SUCCESS;
2947 
2948  //
2949  // If we got a sharing violation try to break outstanding handle
2950  // oplocks and retry the sharing check. If the caller specified
2951  // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock;
2952  // we just return the sharing violation.
2953  //
2954 
2955  if ((Iosb.Status == STATUS_SHARING_VIOLATION) &&
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;
2974  try_return( NOTHING );
2975 
2976  //
2977  // If FsRtlOplockBreakH returned an error we want to return that now.
2978  //
2979 
2980  } else if (!NT_SUCCESS( OplockBreakStatus )) {
2981 
2982  Iosb.Status = OplockBreakStatus;
2983  try_return( Iosb );
2984 
2985  //
2986  // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating
2987  // that there is no oplock to be broken. The sharing violation is
2988  // returned in that case.
2989  //
2990 
2991  } else {
2992 
2993  NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS );
2994 
2995  try_return( Iosb );
2996  }
2997 
2998  //
2999  // The initial sharing check failed with something other than sharing
3000  // violation (which should never happen, but let's be future-proof),
3001  // or we *did* get a sharing violation and the caller specified
3002  // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over.
3003  //
3004 
3005  } else {
3006 
3007  try_return( Iosb );
3008  }
3009 #else
3010 
3011  try_return( Iosb );
3012 #endif
3013  }
3014  }
3015 
3016 #if (NTDDI_VERSION >= NTDDI_WIN8)
3017 
3018  //
3019  // Now check that we can continue based on the oplock state of the
3020  // directory. If there are no open handles yet we don't need to do
3021  // this check; oplocks can only exist when there are handles.
3022  //
3023 
3024  if (Dcb->UncleanCount != 0) {
3025 
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;
3041  try_return( NOTHING );
3042  }
3043 
3044  //
3045  // If the caller wants atomic create-with-oplock semantics, tell
3046  // the oplock package. We haven't incremented the Fcb's UncleanCount
3047  // for this create yet, so add that in on the call.
3048  //
3049 
3050  if (OpenRequiringOplock &&
3051  (Iosb.Status == STATUS_SUCCESS)) {
3052 
3054  IrpContext->OriginatingIrp,
3055  (Dcb->UncleanCount + 1) );
3056  }
3057 
3058  //
3059  // If we've encountered a failure we need to leave. FsRtlCheckOplock
3060  // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated
3061  // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED
3062  // on the create call. That's an NT_SUCCESS code, so we need to keep
3063  // going.
3064  //
3065 
3066  if ((Iosb.Status != STATUS_SUCCESS) &&
3067  (Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) {
3068 
3069  try_return( NOTHING );
3070  }
3071 
3072 #endif
3073 
3074  //
3075  // Now that we're done with the oplock work update the share counts.
3076  // If the Dcb isn't yet opened we just set the share access rather than
3077  // update it.
3078  //
3079 
3080  if (Dcb->OpenCount > 0) {
3081 
3083 
3084  } else {
3085 
3087  ShareAccess,
3088  FileObject,
3089  &Dcb->ShareAccess );
3090  }
3091 
3092  UnwindShareAccess = TRUE;
3093 
3094  //
3095  // Setup the context and section object pointers, and update
3096  // our reference counts
3097  //
3098 
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 
3133  ClearFlag(Dcb->FcbState, FCB_STATE_DELAY_CLOSE);
3134 
3135  //
3136  // And set our status to success
3137  //
3138 
3139  Iosb.Status = STATUS_SUCCESS;
3140  Iosb.Information = FILE_OPENED;
3141 
3142  try_exit: NOTHING;
3143  } _SEH2_FINALLY {
3144 
3145  DebugUnwind( FatOpenExistingDcb );
3146 
3147  //
3148  // Unpin the Dirent Bcb if pinned.
3149  //
3150 
3151  FatUnpinBcb( IrpContext, DirentBcb );
3152 
3153  //
3154  // If this is an abnormal termination then undo our work
3155  //
3156 
3157  if (_SEH2_AbnormalTermination()) {
3158 
3159  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
3160  if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); }
3161  }
3162 
3163  if (DcbAcquired) {
3164 
3165  FatReleaseFcb( IrpContext, Dcb );
3166  }
3167 
3168  DebugTrace(-1, Dbg, "FatOpenExistingDcb -> Iosb.Status = %08lx\n", Iosb.Status);
3169  } _SEH2_END;
3170 
3171  return Iosb;
3172 }
3173 
3174 
3175 //
3176 // Internal support routine
3177 //
3178 
3179 _Requires_lock_held_(_Global_critical_region_)
3181 FatOpenExistingFcb (
3182  _In_ PIRP_CONTEXT IrpContext,
3185  _Inout_ PVCB Vcb,
3186  _Inout_ PFCB Fcb,
3198  _Out_ PBOOLEAN OplockPostIrp
3199  )
3200 
3201 /*++
3202 
3203 Routine Description:
3204 
3205  This routine opens the specified existing fcb
3206 
3207 Arguments:
3208 
3209  FileObject - Supplies the File object
3210 
3211  Vcb - Supplies the Vcb denoting the volume containing the Fcb
3212 
3213  Fcb - Supplies the already existing fcb
3214 
3215  DesiredAccess - Supplies the desired access of the caller
3216 
3217  ShareAccess - Supplies the share access of the caller
3218 
3219  AllocationSize - Supplies the initial allocation if the file is being
3220  superseded or overwritten
3221 
3222  EaBuffer - Supplies the Ea set if the file is being superseded or
3223  overwritten
3224 
3225  EaLength - Supplies the size, in byte, of the EaBuffer
3226 
3227  FileAttributes - Supplies file attributes to use if the file is being
3228  superseded or overwritten
3229 
3230  CreateDisposition - Supplies the create disposition for this operation
3231 
3232  NoEaKnowledge - This opener doesn't understand Ea's and we fail this
3233  open if the file has NeedEa's.
3234 
3235  DeleteOnClose - The caller wants the file gone when the handle is closed
3236 
3237  OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
3238 
3239  FileNameOpenedDos - The caller hit the short side of the name pair finding
3240  this file
3241 
3242  OplockPostIrp - Address to store boolean indicating if the Irp needs to
3243  be posted to the Fsp.
3244 
3245 Return Value:
3246 
3247  IO_STATUS_BLOCK - Returns the completion status for the operation
3248 
3249 --*/
3250 
3251 {
3252  IO_STATUS_BLOCK Iosb = {0};
3253 
3254  PBCB DirentBcb = NULL;
3255  PDIRENT Dirent;
3256 
3257  ACCESS_MASK AddedAccess = 0;
3258 
3259  //
3260  // The following variables are for abnormal termination
3261  //
3262 
3263  BOOLEAN UnwindShareAccess = FALSE;
3264  PCCB UnwindCcb = NULL;
3265  BOOLEAN DecrementFcbOpenCount = FALSE;
3266  BOOLEAN FcbAcquired = FALSE;
3267 
3268 
3269  PAGED_CODE();
3270 
3271  DebugTrace(+1, Dbg, "FatOpenExistingFcb...\n", 0);
3272 
3273  //
3274  // Get the Fcb exlcusive. This is important as cleanup does not
3275  // acquire the Vcb.
3276  //
3277 
3278  (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
3279  FcbAcquired = TRUE;
3280 
3281  _SEH2_TRY {
3282 
3283 
3284  *OplockPostIrp = FALSE;
3285 
3286 #if (NTDDI_VERSION >= NTDDI_WIN7)
3287 
3288  //
3289  // Let's make sure that if the caller provided an oplock key that it
3290  // gets stored in the file object.
3291  //
3292 
3293  Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb),
3294  IrpContext->OriginatingIrp,
3296  NULL,
3297  NULL,
3298  NULL );
3299 
3300  if (Iosb.Status != STATUS_SUCCESS) {
3301 
3302  try_return( NOTHING );
3303  }
3304 #endif
3305 
3306  //
3307  // Take special action if there is a current batch oplock or
3308  // batch oplock break in process on the Fcb.
3309  //
3310 
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;
3334  try_return( NOTHING );
3335  }
3336  }
3337 
3338  //
3339  // Check if the user wanted to create the file, also special case
3340  // the supersede and overwrite options. Those add additional,
3341  // possibly only implied, desired accesses to the caller, which
3342  // we must be careful to pull back off if the caller did not actually
3343  // request them.
3344  //
3345  // In other words, check against the implied access, but do not modify
3346  // share access as a result.
3347  //
3348 
3349  if (CreateDisposition == FILE_CREATE) {
3350 
3352  try_return( Iosb );
3353 
3354  } else if (CreateDisposition == FILE_SUPERSEDE) {
3355 
3356  SetFlag( AddedAccess,
3357  DELETE & ~(*DesiredAccess) );
3358 
3359  *DesiredAccess |= DELETE;
3360 
3361  } else if ((CreateDisposition == FILE_OVERWRITE) ||
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 
3400  if ((CreateDisposition == FILE_SUPERSEDE) ||
3403 
3404  BOOLEAN Hidden;
3405  BOOLEAN System;
3406 
3409 
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 
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,
3449  DesiredAccess,
3450  ShareAccess ))) {
3451 
3452 #if (NTDDI_VERSION >= NTDDI_WIN7)
3453 
3454  NTSTATUS OplockBreakStatus = STATUS_SUCCESS;
3455 
3456  //
3457  // If we got a sharing violation try to break outstanding handle
3458  // oplocks and retry the sharing check. If the caller specified
3459  // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock;
3460  // we just return the sharing violation.
3461  //
3462 
3463  if ((Iosb.Status == STATUS_SHARING_VIOLATION) &&
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;
3482  try_return( NOTHING );
3483 
3484  //
3485  // If FsRtlOplockBreakH returned an error we want to return that now.
3486  //
3487 
3488  } else if (!NT_SUCCESS( OplockBreakStatus )) {
3489 
3490  Iosb.Status = OplockBreakStatus;
3491  try_return( Iosb );
3492 
3493  //
3494  // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating
3495  // that there is no oplock to be broken. The sharing violation is
3496  // returned in that case.
3497  //
3498 
3499  } else {
3500 
3501  NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS );
3502 
3503  try_return( Iosb );
3504  }
3505 
3506  //
3507  // The initial sharing check failed with something other than sharing
3508  // violation (which should never happen, but let's be future-proof),
3509  // or we *did* get a sharing violation and the caller specified
3510  // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over.
3511  //
3512 
3513  } else {
3514 
3515  try_return( Iosb );
3516  }
3517 
3518 #else
3519 
3520  try_return( Iosb );
3521 
3522 #endif
3523  }
3524 
3525  //
3526  // Now check that we can continue based on the oplock state of the
3527  // file. If there are no open handles yet we don't need to do this
3528  // check; oplocks can only exist when there are handles.
3529  //
3530  // It is important that we modified the DesiredAccess in place so
3531  // that the Oplock check proceeds against any added access we had
3532  // to give the caller.
3533  //
3534 
3535  if (Fcb->UncleanCount != 0) {
3536 
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;
3552  try_return( NOTHING );
3553  }
3554 
3555  //
3556  // If the caller wants atomic create-with-oplock semantics, tell
3557  // the oplock package. We haven't incremented the Fcb's UncleanCount
3558  // for this create yet, so add that in on the call.
3559  //
3560 
3561  if (OpenRequiringOplock &&
3562  (Iosb.Status == STATUS_SUCCESS)) {
3563 
3565  IrpContext->OriginatingIrp,
3566  (Fcb->UncleanCount + 1) );
3567  }
3568 
3569  //
3570  // If we've encountered a failure we need to leave. FsRtlCheckOplock
3571  // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated
3572  // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED
3573  // on the create call. That's an NT_SUCCESS code, so we need to keep
3574  // going.
3575  //
3576 
3577  if ((Iosb.Status != STATUS_SUCCESS) &&
3578  (Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) {
3579 
3580  try_return( NOTHING );
3581  }
3582 
3583  //
3584  // Set the flag indicating if Fast I/O is possible
3585  //
3586 
3587  Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
3588 
3589  //
3590  // If the user wants write access access to the file make sure there
3591  // is not a process mapping this file as an image. Any attempt to
3592  // delete the file will be stopped in fileinfo.c
3593  //
3594  // If the user wants to delete on close, we must check at this
3595  // point though.
3596  //
3597 
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 
3698  UserFileOpen,
3699  Fcb,
3700  UnwindCcb = FatCreateCcb( IrpContext ));
3701 
3702  FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
3703 
3704  //
3705  // Fill in the information field, the status field is already
3706  // set.
3707  //
3708 
3709  Iosb.Information = FILE_OPENED;
3710 
3711  try_return( Iosb );
3712  }
3713 
3714  //
3715  // Check if we are to supersede/overwrite the file, we can wait for
3716  // any I/O at this point
3717  //
3718 
3719  if ((CreateDisposition == FILE_SUPERSEDE) ||
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
3772  FatBugCheck( CreateDisposition, 0, 0 );
3773 
3774  try_exit: NOTHING;
3775 
3776  //
3777  // Update the share access and counts if successful
3778  //
3779 
3780  if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS(Iosb.Status)) {
3781 
3782  //
3783  // Now, we may have added some access bits above to indicate the access
3784  // this caller would conflict with (as opposed to what they get) in order
3785  // to perform the overwrite/supersede. We need to make a call to that will
3786  // recalculate the bits in the fileobject to reflect the real access they
3787  // will get.
3788  //
3789 
3790  if (AddedAccess) {
3791 
3792  NTSTATUS Status;
3793 
3794  ClearFlag( *DesiredAccess, AddedAccess );
3795 
3796 #ifdef _MSC_VER
3797 #pragma prefast( suppress:28931, "it needs to be there for debug assert" );
3798 #endif
3800  ShareAccess,
3801  FileObject,
3802  &Fcb->ShareAccess,
3803  TRUE );
3804 
3805  //
3806  // It must be the case that we are really asking for less access, so
3807  // any conflict must have been detected before this point.
3808  //
3809 
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;
3828  Fcb->NonCachedUncleanCount += 1;
3829  }
3830  Vcb->OpenFileCount += 1;
3831  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
3832 
3833  {
3834  PCCB Ccb;
3835 
3836  Ccb = (PCCB)FileObject->FsContext2;
3837 
3838  //
3839  // Mark the DeleteOnClose bit if the operation was successful.
3840  //
3841 
3842  if ( DeleteOnClose ) {
3843 
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 
3887  if (_SEH2_AbnormalTermination()) {
3888 
3889  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
3890  if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Fcb->ShareAccess ); }
3891  }
3892 
3893  if (DecrementFcbOpenCount) {
3894 
3895  Fcb->OpenCount -= 1;
3896 
3897  if (Fcb->OpenCount == 0) {
3898  if (ARGUMENT_PRESENT( FileObject )) {
3899  FileObject->SectionObjectPointer = NULL;
3900  }
3901  FatDeleteFcb( IrpContext, &Fcb );
3902  FcbAcquired = FALSE;
3903  }
3904  }
3905 
3906  if (FcbAcquired) {
3907 
3908  FatReleaseFcb( IrpContext, Fcb );
3909  }
3910 
3911  DebugTrace(-1, Dbg, "FatOpenExistingFcb -> Iosb.Status = %08lx\n", Iosb.Status);
3912  } _SEH2_END;
3913 
3914  return Iosb;
3915 }
3916 
3917 //
3918 // Internal support routine
3919 //
3920 
3921 _Requires_lock_held_(_Global_critical_region_)
3923 FatOpenTargetDirectory (
3924  _In_ PIRP_CONTEXT IrpContext,
3926  _Inout_ PDCB Dcb,
3929  _In_ BOOLEAN DoesNameExist,
3931  )
3932 
3933 /*++
3934 
3935 Routine Description:
3936 
3937  This routine opens the target directory and replaces the name in the
3938  file object with the remaining name.
3939 
3940 Arguments:
3941 
3942  FileObject - Supplies the File object
3943 
3944  Dcb - Supplies an already existing dcb that we are going to open
3945 
3946  DesiredAccess - Supplies the desired access of the caller
3947 
3948  ShareAccess - Supplies the share access of the caller
3949 
3950  DoesNameExist - Indicates if the file name already exists in the
3951  target directory.
3952 
3953 
3954 Return Value:
3955 
3956  IO_STATUS_BLOCK - Returns the completion status for the operation
3957 
3958 --*/
3959 
3960 {
3961  IO_STATUS_BLOCK Iosb = {0};
3962 
3963  //
3964  // The following variables are for abnormal termination
3965  //
3966 
3967  BOOLEAN UnwindShareAccess = FALSE;
3968  PCCB UnwindCcb = NULL;
3969  BOOLEAN DcbAcquired = FALSE;
3970 
3971  PAGED_CODE();
3972 
3973  DebugTrace(+1, Dbg, "FatOpenTargetDirectory...\n", 0);
3974 
3975  //
3976  // Get the Dcb exlcusive. This is important as cleanup does not
3977  // acquire the Vcb.
3978  //
3979 
3980  (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb );
3981  DcbAcquired = TRUE;
3982 
3983  _SEH2_TRY {
3984 
3985  ULONG i;
3986 
3987  //
3988  // If the Dcb is already opened by someone then we need
3989  // to check the share access
3990  //
3991 
3992  if (Dcb->OpenCount > 0) {
3993 
3995  ShareAccess,
3996  FileObject,
3997  &Dcb->ShareAccess,
3998  TRUE ))) {
3999 
4000  try_return( Iosb );
4001  }
4002 
4003  } else {
4004 
4006  ShareAccess,
4007  FileObject,
4008  &Dcb->ShareAccess );
4009  }
4010 
4011  UnwindShareAccess = TRUE;
4012 
4013  //
4014  // Setup the context and section object pointers, and update
4015  // our reference counts
4016  //
4017 
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 
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 
4107  if (_SEH2_AbnormalTermination()) {
4108 
4109  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
4110  if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); }
4111  }
4112 
4113  if (DcbAcquired) {
4114 
4115  FatReleaseFcb( IrpContext, Dcb );
4116  }
4117 
4118  DebugTrace(-1, Dbg, "FatOpenTargetDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
4119  } _SEH2_END;
4120 
4121  return Iosb;
4122 }
4123 
4124 
4125 
4126 //
4127 // Internal support routine
4128 //
4129 _Success_(return.Status == STATUS_SUCCESS)
4130 _Requires_lock_held_(_Global_critical_region_)
4132 #ifdef _MSC_VER
4133 #pragma warning(suppress:6101) // bug in PREFast means the _Success_ annotation is not correctly applied
4134 #endif
4135 FatOpenExistingDirectory (
4136  _In_ PIRP_CONTEXT IrpContext,
4139  _Inout_ PVCB Vcb,
4153  )
4154 
4155 /*++
4156 
4157 Routine Description:
4158 
4159  This routine opens the specified directory. The directory has not
4160  previously been opened.
4161 
4162 Arguments:
4163 
4164  FileObject - Supplies the File object
4165 
4166  Vcb - Supplies the Vcb denoting the volume containing the dcb
4167 
4168  Dcb - Returns the newly-created DCB for the file.
4169 
4170  ParentDcb - Supplies the parent directory containing the subdirectory
4171  to be opened
4172 
4173  DirectoryName - Supplies the file name of the directory being opened.
4174 
4175  Dirent - Supplies the dirent for the directory being opened
4176 
4177  LfnByteOffset - Tells where the Lfn begins. If there is no Lfn
4178  this field is the same as DirentByteOffset.
4179 
4180  DirentByteOffset - Supplies the Vbo of the dirent within its parent
4181  directory
4182 
4183  Lfn - May supply a long name for the file.
4184 
4185  DesiredAccess - Supplies the desired access of the caller
4186 
4187  ShareAccess - Supplies the share access of the caller
4188 
4189  CreateDisposition - Supplies the create disposition for this operation
4190 
4191  NoEaKnowledge - This opener doesn't understand Ea's and we fail this
4192  open if the file has NeedEa's.
4193 
4194  DeleteOnClose - The caller wants the file gone when the handle is closed
4195 
4196  OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
4197 
4198 Return Value:
4199 
4200  IO_STATUS_BLOCK - Returns the completion status for the operation
4201 
4202 --*/
4203 
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 
4222  PAGED_CODE();
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,
4275  LfnByteOffset,
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 
4326  ShareAccess,
4327  FileObject,
4328  &(*Dcb)->ShareAccess );
4329 
4330  //
4331  // Setup the context and section object pointers, and update
4332  // our reference counts
4333  //
4334 
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) {
4390  if (ARGUMENT_PRESENT( FileObject )) {
4391  FileObject->SectionObjectPointer = NULL;
4392  }
4393  FatDeleteFcb( IrpContext, &UnwindDcb );
4394  *Dcb = NULL;
4395  }
4396  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
4397  }
4398 
4399  DebugTrace(-1, Dbg, "FatOpenExistingDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
4401 
4402  return Iosb;
4403 }
4404 
4405 
4406 //
4407 // Internal support routine
4408 //
4409 
4410 _Requires_lock_held_(_Global_critical_region_)
4412 FatOpenExistingFile (
4413  _In_ PIRP_CONTEXT IrpContext,
4415  _Inout_ PVCB Vcb,
4422  _In_ PUNICODE_STRING OrigLfn,
4430  _In_ BOOLEAN IsPagingFile,
4435  )
4436 
4437 /*++
4438 
4439 Routine Description:
4440 
4441  This routine opens the specified file. The file has not previously
4442  been opened.
4443 
4444 Arguments:
4445 
4446  FileObject - Supplies the File object
4447 
4448  Vcb - Supplies the Vcb denoting the volume containing the file
4449 
4450  Fcb - Returns the newly-created FCB for the file.
4451 
4452  ParentDcb - Supplies the parent directory containing the file to be
4453  opened
4454 
4455  Dirent - Supplies the dirent for the file being opened
4456 
4457  LfnByteOffset - Tells where the Lfn begins. If there is no Lfn
4458  this field is the same as DirentByteOffset.
4459 
4460  DirentByteOffset - Supplies the Vbo of the dirent within its parent
4461  directory
4462 
4463  Lfn - May supply a long name for the file.
4464 
4465  DesiredAccess - Supplies the desired access of the caller
4466 
4467  ShareAccess - Supplies the share access of the caller
4468 
4469  AllocationSize - Supplies the initial allocation if the file is being
4470  superseded, overwritten, or created.
4471 
4472  EaBuffer - Supplies the Ea set if the file is being superseded,
4473  overwritten, or created.
4474 
4475  EaLength - Supplies the size, in byte, of the EaBuffer
4476 
4477  FileAttributes - Supplies file attributes to use if the file is being
4478  superseded, overwritten, or created
4479 
4480  CreateDisposition - Supplies the create disposition for this operation
4481 
4482  IsPagingFile - Indicates if this is the paging file being opened.
4483 
4484  NoEaKnowledge - This opener doesn't understand Ea's and we fail this
4485  open if the file has NeedEa's.
4486 
4487  DeleteOnClose - The caller wants the file gone when the handle is closed
4488 
4489  OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
4490 
4491  FileNameOpenedDos - The caller opened this file by hitting the 8.3 side
4492  of the Lfn/8.3 pair
4493 
4494 Return Value:
4495 
4496  IO_STATUS_BLOCK - Returns the completion status for the operation
4497 
4498 --*/
4499 
4500 {
4501  IO_STATUS_BLOCK Iosb = {0};
4502 
4503  ACCESS_MASK AddedAccess = 0;
4504 
4505  PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
4506 
4507  //
4508  // The following variables are for abnormal termination
4509  //
4510 
4511  PFCB UnwindFcb = NULL;
4512  PCCB UnwindCcb = NULL;
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 
4531  if (CreateDisposition == FILE_CREATE) {
4533  try_return( Iosb );
4534 
4535  } else if ((CreateDisposition == FILE_SUPERSEDE) && !IsPagingFile) {
4536 
4537  SetFlag( AddedAccess,
4538  DELETE & ~(*DesiredAccess) );
4539 
4540  *DesiredAccess |= DELETE;
4541 
4542  } else if (((CreateDisposition == FILE_OVERWRITE) ||
4543  (CreateDisposition == FILE_OVERWRITE_IF)) && !IsPagingFile) {
4544 
4545  SetFlag( AddedAccess,
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 
4577  if ((CreateDisposition == FILE_SUPERSEDE) ||
4580 
4581  BOOLEAN Hidden;
4582  BOOLEAN System;
4583 
4586 
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 
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,
4629  LfnByteOffset,
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 
4728  UserFileOpen,
4729  *Fcb,
4730  UnwindCcb = FatCreateCcb( IrpContext ));
4731 
4732  FileObject->SectionObjectPointer = &(*Fcb)->NonPaged->SectionObjectPointers;
4733 
4734  Iosb.Status = STATUS_SUCCESS;
4735  Iosb.Information = FILE_OPENED;
4736  break;
4737 
4738  case FILE_SUPERSEDE:
4739  case FILE_OVERWRITE:
4740  case FILE_OVERWRITE_IF:
4741 
4742  DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0);
4743 
4744  //
4745  // Determine the granted access for this operation now.
4746  //
4747 
4748  if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
4749 
4750  try_return( Iosb );
4751  }
4752 
4753  Iosb = FatSupersedeOrOverwriteFile( IrpContext,
4754  FileObject,
4755  *Fcb,
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
4771  FatBugCheck( CreateDisposition, 0, 0 );
4772  break;
4773  }
4774 
4775  try_exit: NOTHING;
4776 
4777  //
4778  // Setup our share access and counts if things were successful.
4779  //
4780 
4781  if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS( Iosb.Status )) {
4782 
4783  //
4784  // Remove any virtual access the caller needed to check against, but will
4785  // not really receive. Overwrite/supersede is a bit of a special case.
4786  //
4787 
4788  ClearFlag( *DesiredAccess, AddedAccess );
4789 
4791  ShareAccess,
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 
4856  if (_SEH2_AbnormalTermination()) {
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) {
4869  if (ARGUMENT_PRESENT( FileObject )) {
4870  FileObject->SectionObjectPointer = NULL;
4871  }
4872  FatDeleteFcb( IrpContext, &UnwindFcb );
4873  *Fcb = NULL;
4874  }
4875 
4876  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
4877  }
4878 
4879  DebugTrace(-1, Dbg, "FatOpenExistingFile -> Iosb.Status = %08lx\n", Iosb.Status);
4880  } _SEH2_END;
4881 
4882  return Iosb;
4883 }
4884 
4885 
4886 //
4887 // Internal support routine
4888 //
4889 
4890 _Requires_lock_held_(_Global_critical_region_)
4892 FatCreateNewDirectory (
4893  _In_ PIRP_CONTEXT IrpContext,
4896  _Inout_ PVCB Vcb,
4908  )
4909 
4910 /*++
4911 
4912 Routine Description:
4913 
4914  This routine creates a new directory. The directory has already been
4915  verified not to exist yet.
4916 
4917 Arguments:
4918 
4919  FileObject - Supplies the file object for the newly created directory
4920 
4921  Vcb - Supplies the Vcb denote the volume to contain the new directory
4922 
4923  ParentDcb - Supplies the parent directory containg the newly created
4924  directory
4925 
4926  OemName - Supplies the Oem name for the newly created directory. It may
4927  or maynot be 8.3 complient, but will be upcased.
4928 
4929  UnicodeName - Supplies the Unicode name for the newly created directory.
4930  It may or maynot be 8.3 complient. This name contains the original
4931  case information.
4932 
4933  DesiredAccess - Supplies the desired access of the caller
4934 
4935  ShareAccess - Supplies the shared access of the caller
4936 
4937  EaBuffer - Supplies the Ea set for the newly created directory
4938 
4939  EaLength - Supplies the length, in bytes, of EaBuffer
4940 
4941  FileAttributes - Supplies the file attributes for the newly created
4942  directory.
4943 
4944  NoEaKnowledge - This opener doesn't understand Ea's and we fail this
4945  open if the file has NeedEa's.
4946 
4947  DeleteOnClose - The caller wants the file gone when the handle is closed
4948 
4949  OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
4950 
4951 Return Value:
4952 
4953  IO_STATUS_BLOCK - Returns the completion status for the operation
4954 
4955 --*/
4956 
4957 {
4959 
4960  PDCB Dcb = NULL;
4961  PCCB Ccb = NULL;
4962 
4963  PDIRENT Dirent = NULL;
4964  PBCB DirentBcb = NULL;
4967 
4968  PDIRENT ShortDirent;
4969  ULONG ShortDirentByteOffset;
4970 
4971  USHORT EaHandle;
4972 
4976 
4977  ULONG BytesInFirstPage = 0;
4978  ULONG DirentsInFirstPage = 0;
4979  PDIRENT FirstPageDirent = 0;
4980 
4981  PBCB SecondPageBcb = NULL;
4982  ULONG SecondPageOffset;
4983  PDIRENT SecondPageDirent = NULL;
4984 
4985  BOOLEAN DirentFromPool = FALSE;
4986 
4987 
4989  UCHAR ShortNameBuffer[12];
4990 
4991 #if (NTDDI_VERSION <= NTDDI_WIN7)
4993 #endif
4994 
4996 
4997  PAGED_CODE();
4998 
4999  DebugTrace(+1, Dbg, "FatCreateNewDirectory...\n", 0);
5000 
5001  ShortName.Length = 0;
5002  ShortName.MaximumLength = 12;
5003  ShortName.Buffer = (PCHAR)&ShortNameBuffer[0];
5004 
5005  EaHandle = 0;
5006 
5007  //
5008  // We fail this operation if the caller doesn't understand Ea's.
5009  //
5010 
5011  if (NoEaKnowledge
5012  && EaLength > 0) {
5013 
5014  Iosb.Status = STATUS_ACCESS_DENIED;
5015 
5016  DebugTrace(-1, Dbg, "FatCreateNewDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
5017  return Iosb;
5018  }
5019 
5020  //
5021  // DeleteOnClose and ReadOnly are not compatible.
5022  //
5023 
5025 
5026  Iosb.Status = STATUS_CANNOT_DELETE;
5027  return Iosb;
5028  }
5029 
5030  // Now get the names that we will be using.
5031  //
5032 
5033  FatSelectNames( IrpContext,
5034  ParentDcb,
5035  OemName,
5036  UnicodeName,
5037  &ShortName,
5038  NULL,
5041  &CreateLfn );
5042 
5043  //
5044  // If we are not in Chicago mode, ignore the magic bits.
5045  //
5046 
5047  if (!FatData.ChicagoMode) {
5048 
5051  CreateLfn = FALSE;
5052  }
5053 
5054  //
5055  // Create/allocate a new dirent
5056  //
5057 
5059 
5060  DirentByteOffset = FatCreateNewDirent( IrpContext,
5061  ParentDcb,
5062  DirentsNeeded,
5063  FALSE );
5064  _SEH2_TRY {
5065 
5066  FatPrepareWriteDirectoryFile( IrpContext,
5067  ParentDcb,
5069  sizeof(DIRENT),
5070  &DirentBcb,
5071 #ifndef __REACTOS__
5072  &Dirent,
5073 #else
5074  (PVOID *)&Dirent,
5075 #endif
5076  FALSE,
5077  TRUE,
5078  &Iosb.Status );
5079 
5080  NT_ASSERT( NT_SUCCESS( Iosb.Status ) && DirentBcb && Dirent );
5081 
5082  //
5083  // Deal with the special case of an LFN + Dirent structure crossing
5084  // a page boundry.
5085  //
5086 
5087  if ((DirentByteOffset / PAGE_SIZE) !=
5088  ((DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT)) / PAGE_SIZE)) {
5089 
5090  SecondPageBcb;
5091  SecondPageOffset;
5092  SecondPageDirent;
5093 
5094  SecondPageOffset = (DirentByteOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
5095 
5096  BytesInFirstPage = SecondPageOffset - DirentByteOffset;
5097 
5098  DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT);
5099 
5100  FatPrepareWriteDirectoryFile( IrpContext,
5101  ParentDcb,
5102  SecondPageOffset,
5103  sizeof(DIRENT),
5104  &SecondPageBcb,
5105 #ifndef __REACTOS__
5106  &SecondPageDirent,
5107 #else
5108  (PVOID *)&SecondPageDirent,
5109 #endif
5110  FALSE,
5111  TRUE,
5112  &Iosb.Status );
5113 
5114  NT_ASSERT( NT_SUCCESS( Iosb.Status ) && SecondPageBcb && SecondPageDirent );
5115 
5116  FirstPageDirent = Dirent;
5117 
5119  DirentsNeeded * sizeof(DIRENT),
5120  TAG_DIRENT );
5121 
5122  DirentFromPool = TRUE;
5123  }
5124 
5125  //
5126  // Bump up Dirent and DirentByteOffset
5127  //
5128 
5129  ShortDirent = Dirent + DirentsNeeded - 1;
5130  ShortDirentByteOffset = DirentByteOffset +
5131  (DirentsNeeded - 1) * sizeof(DIRENT);
5132 
5133  NT_ASSERT( NT_SUCCESS( Iosb.Status ));
5134 
5135 
5136  //
5137  // Fill in the fields of the dirent.
5138  //
5139 
5140  FatConstructDirent( IrpContext,
5141  ShortDirent,
5142  &ShortName,
5147  TRUE,
5148  NULL );
5149 
5150  //
5151  // If the dirent crossed pages, we have to do some real gross stuff.
5152  //
5153 
5154  if (DirentFromPool) {
5155 
5156  RtlCopyMemory( FirstPageDirent, Dirent, BytesInFirstPage );
5157 
5158  RtlCopyMemory( SecondPageDirent,
5159  Dirent + DirentsInFirstPage,
5160  DirentsNeeded*sizeof(DIRENT) - BytesInFirstPage );
5161 
5162  ShortDirent = SecondPageDirent + (DirentsNeeded - DirentsInFirstPage) - 1;
5163  }
5164 
5165  //
5166  // Create a new dcb for the directory.
5167  //
5168 
5169  Dcb = FatCreateDcb( IrpContext,
5170  Vcb,
5171  ParentDcb,
5173  ShortDirentByteOffset,
5174  ShortDirent,
5175