ReactOS  0.4.13-dev-479-gec9c8fd
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 #ifndef __REACTOS__
577  IO_STATUS_BLOCK Iosb = {0};
578 #else
579  IO_STATUS_BLOCK Iosb = {{0}};
580 #endif
582 
584  PFILE_OBJECT RelatedFileObject;
589  ULONG Options;
592  ULONG EaLength;
593 
595  BOOLEAN NoIntermediateBuffering;
597  BOOLEAN IsPagingFile;
598  BOOLEAN OpenTargetDirectory;
600  BOOLEAN NonDirectoryFile;
604  BOOLEAN TemporaryFile;
606 
608 
609  PVCB Vcb;
610  PFCB Fcb = NULL;
611  PCCB Ccb;
612  PDCB ParentDcb;
613  PDCB FinalDcb = NULL;
614 
615  UNICODE_STRING FinalName = {0};
617  UNICODE_STRING NextRemainingPart = {0};
618  UNICODE_STRING UpcasedFinalName;
619  WCHAR UpcasedBuffer[ FAT_CREATE_INITIAL_NAME_BUF_SIZE];
620 
621  OEM_STRING OemFinalName;
623 
624  PDIRENT Dirent;
625  PBCB DirentBcb = NULL;
628 
629  BOOLEAN PostIrp = FALSE;
630  BOOLEAN OplockPostIrp = FALSE;
631  BOOLEAN TrailingBackslash;
632  BOOLEAN FirstLoop = TRUE;
633 
634  ULONG MatchFlags = 0;
635 
636  CCB LocalCcb;
638  UNICODE_STRING OrigLfn = {0};
639 
641 
642  PAGED_CODE();
643 
644  //
645  // Get the current IRP stack location
646  //
647 
649 
650  DebugTrace(+1, Dbg, "FatCommonCreate\n", 0 );
651  DebugTrace( 0, Dbg, "Irp = %p\n", Irp );
652  DebugTrace( 0, Dbg, "->Flags = %08lx\n", Irp->Flags );
653  DebugTrace( 0, Dbg, "->FileObject = %p\n", IrpSp->FileObject );
654  DebugTrace( 0, Dbg, " ->RelatedFileObject = %p\n", IrpSp->FileObject->RelatedFileObject );
655  DebugTrace( 0, Dbg, " ->FileName = %wZ\n", &IrpSp->FileObject->FileName );
656  DebugTrace( 0, Dbg, " ->FileName.Length = 0n%d\n", IrpSp->FileObject->FileName.Length );
657  DebugTrace( 0, Dbg, "->AllocationSize.LowPart = %08lx\n", Irp->Overlay.AllocationSize.LowPart );
658  DebugTrace( 0, Dbg, "->AllocationSize.HighPart = %08lx\n", Irp->Overlay.AllocationSize.HighPart );
659  DebugTrace( 0, Dbg, "->SystemBuffer = %p\n", Irp->AssociatedIrp.SystemBuffer );
660  DebugTrace( 0, Dbg, "->DesiredAccess = %08lx\n", IrpSp->Parameters.Create.SecurityContext->DesiredAccess );
661  DebugTrace( 0, Dbg, "->Options = %08lx\n", IrpSp->Parameters.Create.Options );
662  DebugTrace( 0, Dbg, "->FileAttributes = %04x\n", IrpSp->Parameters.Create.FileAttributes );
663  DebugTrace( 0, Dbg, "->ShareAccess = %04x\n", IrpSp->Parameters.Create.ShareAccess );
664  DebugTrace( 0, Dbg, "->EaLength = %08lx\n", IrpSp->Parameters.Create.EaLength );
665 
666  //
667  // This is here because the Win32 layer can't avoid sending me double
668  // beginning backslashes.
669  //
670 
671  if ((IrpSp->FileObject->FileName.Length > sizeof(WCHAR)) &&
672  (IrpSp->FileObject->FileName.Buffer[1] == L'\\') &&
673  (IrpSp->FileObject->FileName.Buffer[0] == L'\\')) {
674 
675  IrpSp->FileObject->FileName.Length -= sizeof(WCHAR);
676 
677  RtlMoveMemory( &IrpSp->FileObject->FileName.Buffer[0],
678  &IrpSp->FileObject->FileName.Buffer[1],
679  IrpSp->FileObject->FileName.Length );
680 
681  //
682  // If there are still two beginning backslashes, the name is bogus.
683  //
684 
685  if ((IrpSp->FileObject->FileName.Length > sizeof(WCHAR)) &&
686  (IrpSp->FileObject->FileName.Buffer[1] == L'\\') &&
687  (IrpSp->FileObject->FileName.Buffer[0] == L'\\')) {
688 
689  DebugTrace(-1, Dbg, "FatCommonCreate -> STATUS_OBJECT_NAME_INVALID\n", 0);
691  }
692  }
693 
694  //
695  // Reference our input parameters to make things easier
696  //
697 
698  NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL );
699 
702  RelatedFileObject = FileObject->RelatedFileObject;
703  AllocationSize = Irp->Overlay.AllocationSize.LowPart;
704  EaBuffer = Irp->AssociatedIrp.SystemBuffer;
705  DesiredAccess = &IrpSp->Parameters.Create.SecurityContext->DesiredAccess;
706  Options = IrpSp->Parameters.Create.Options;
708  ShareAccess = IrpSp->Parameters.Create.ShareAccess;
709  EaLength = IrpSp->Parameters.Create.EaLength;
710 
711  //
712  // Set up the file object's Vpb pointer in case anything happens.
713  // This will allow us to get a reasonable pop-up.
714  //
715 
716  if ( RelatedFileObject != NULL ) {
717  FileObject->Vpb = RelatedFileObject->Vpb;
718  }
719 
720  //
721  // Force setting the archive bit in the attributes byte to follow OS/2,
722  // & DOS semantics. Also mask out any extraneous bits, note that
723  // we can't use the ATTRIBUTE_VALID_FLAGS constant because that has
724  // the control and normal flags set.
725  //
726  // Delay setting ARCHIVE in case this is a directory: 2/16/95
727  //
728 
734 
735  //
736  // Locate the volume device object and Vcb that we are trying to access
737  //
738 
740 
741  //
742  // Decipher Option flags and values
743  //
744 
745  //
746  // If this is an open by fileid operation, just fail it explicitly. FAT's
747  // source of fileids is not reversible for open operations.
748  //
749 
751 
752  return STATUS_NOT_IMPLEMENTED;
753  }
754 
756  NonDirectoryFile = BooleanFlagOn( Options, FILE_NON_DIRECTORY_FILE );
757  NoIntermediateBuffering = BooleanFlagOn( Options, FILE_NO_INTERMEDIATE_BUFFERING );
760 #if (NTDDI_VERSION >= NTDDI_WIN7)
762 #else
764 #endif
765 
766  TemporaryFile = BooleanFlagOn( IrpSp->Parameters.Create.FileAttributes,
768 
769  CreateDisposition = (Options >> 24) & 0x000000ff;
770 
771  IsPagingFile = BooleanFlagOn( IrpSp->Flags, SL_OPEN_PAGING_FILE );
772  OpenTargetDirectory = BooleanFlagOn( IrpSp->Flags, SL_OPEN_TARGET_DIRECTORY );
773 
777 
781 
782 
783  //
784  // Make sure the input large integer is valid and that the dir/nondir
785  // indicates a storage type we understand.
786  //
787 
788  if (Irp->Overlay.AllocationSize.HighPart != 0 ||
789  (DirectoryFile && NonDirectoryFile)) {
790 
791  DebugTrace(-1, Dbg, "FatCommonCreate -> STATUS_INVALID_PARAMETER\n", 0);
793  }
794 
795  //
796  // Acquire exclusive access to the vcb, and enqueue the Irp if
797  // we didn't get it.
798  //
799 
800  if (!FatAcquireExclusiveVcb( IrpContext, Vcb )) {
801 
802  DebugTrace(0, Dbg, "Cannot acquire Vcb\n", 0);
803 
804  Iosb.Status = FatFsdPostRequest( IrpContext, Irp );
805 
806  DebugTrace(-1, Dbg, "FatCommonCreate -> %08lx\n", Iosb.Status );
807  return Iosb.Status;
808  }
809 
810  //
811  // Make sure we haven't been called recursively by a filter inside an existing
812  // create request.
813  //
814 
815  if (FlagOn( Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS)) {
816 
817 #ifdef _MSC_VER
818 #pragma prefast( suppress:28159, "this is a serious programming error if it happens" )
819 #endif
820  FatBugCheck( 0, 0, 0);
821  }
822 
823  //
824  // Initialize the DirentBcb to null
825  //
826 
827  DirentBcb = NULL;
828 
829  //
830  // Initialize our temp strings with their stack buffers.
831  //
832 
833  OemFinalName.Length = 0;
834  OemFinalName.MaximumLength = sizeof( OemBuffer);
835  OemFinalName.Buffer = (PCHAR)OemBuffer;
836 
837  UpcasedFinalName.Length = 0;
838  UpcasedFinalName.MaximumLength = sizeof( UpcasedBuffer);
839  UpcasedFinalName.Buffer = UpcasedBuffer;
840 
841  Lfn.Length = 0;
842  Lfn.MaximumLength = sizeof( LfnBuffer);
843  Lfn.Buffer = LfnBuffer;
844 
845  _SEH2_TRY {
846 
847  //
848  // Make sure the vcb is in a usable condition. This will raise
849  // and error condition if the volume is unusable
850  //
851 
852  FatVerifyVcb( IrpContext, Vcb );
853 
854  //
855  // If the Vcb is locked then we cannot open another file
856  //
857 
858  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_LOCKED)) {
859 
860  DebugTrace(0, Dbg, "Volume is locked\n", 0);
861 
863  if (Vcb->VcbCondition != VcbGood) {
864 
866  }
867  try_return( Iosb.Status = Status );
868  }
869 
870  //
871  // Don't allow the DELETE_ON_CLOSE option if the volume is
872  // write-protected.
873  //
874 
876 
877  //
878  // Set the real device for the pop-up info, and set the verify
879  // bit in the device object, so that we will force a verify
880  // in case the user put the correct media back in.
881  //
882 
883  IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
884  Vcb->Vpb->RealDevice );
885 
887 
889  }
890 
891  //
892  // If this is a fat32 volume, EA's are not supported.
893  //
894 
895  if (EaBuffer != NULL) {
896 
898  }
899 
900  //
901  // Check if we are opening the volume and not a file/directory.
902  // We are opening the volume if the name is empty and there
903  // isn't a related file object. If there is a related file object
904  // then it is the Vcb itself.
905  //
906 
907  if (FileName.Length == 0) {
908 
909  PVCB DecodeVcb = NULL;
910 
911  if (RelatedFileObject == NULL ||
912  FatDecodeFileObject( RelatedFileObject,
913  &DecodeVcb,
914  &Fcb,
915  &Ccb ) == UserVolumeOpen) {
916 
917  NT_ASSERT( RelatedFileObject == NULL || Vcb == DecodeVcb );
918 
919  //
920  // Check if we were to open a directory
921  //
922 
923  if (DirectoryFile) {
924 
925  DebugTrace(0, Dbg, "Cannot open volume as a directory\n", 0);
926 
928  }
929 
930  //
931  // Can't open the TargetDirectory of the DASD volume.
932  //
933 
934  if (OpenTargetDirectory) {
935 
937  }
938 
939  DebugTrace(0, Dbg, "Opening the volume, Vcb = %p\n", Vcb);
940 
942 
943  Iosb = FatOpenVolume( IrpContext,
944  FileObject,
945  Vcb,
947  ShareAccess,
949 
950  Irp->IoStatus.Information = Iosb.Information;
951  try_return( Iosb.Status );
952  }
953  }
954 
955  //
956  // If there is a related file object then this is a relative open.
957  // The related file object is the directory to start our search at.
958  // Return an error if it is not a directory.
959  //
960 
961  if (RelatedFileObject != NULL) {
962 
963  PVCB RelatedVcb;
964  PDCB RelatedDcb;
965  PCCB RelatedCcb;
967 
968  TypeOfOpen = FatDecodeFileObject( RelatedFileObject,
969  &RelatedVcb,
970  &RelatedDcb,
971  &RelatedCcb );
972 
973  if (TypeOfOpen != UserFileOpen &&
975 
976  DebugTrace(0, Dbg, "Invalid related file object\n", 0);
977 
979  }
980 
981  //
982  // A relative open must be via a relative path.
983  //
984 
985  if (FileName.Length != 0 &&
986  FileName.Buffer[0] == L'\\') {
987 
989  }
990 
991  //
992  // Set up the file object's Vpb pointer in case anything happens.
993  //
994 
995  NT_ASSERT( Vcb == RelatedVcb );
996 
997  FileObject->Vpb = RelatedFileObject->Vpb;
998 
999  //
1000  // Now verify the related Fcb so we don't get in trouble later
1001  // by assuming its in good shape.
1002  //
1003 
1004  FatVerifyFcb( IrpContext, RelatedDcb );
1005 
1006  ParentDcb = RelatedDcb;
1007 
1008  } else {
1009 
1010  //
1011  // This is not a relative open, so check if we're
1012  // opening the root dcb
1013  //
1014 
1015  if ((FileName.Length == sizeof(WCHAR)) &&
1016  (FileName.Buffer[0] == L'\\')) {
1017 
1018  //
1019  // Check if we were not supposed to open a directory
1020  //
1021 
1022  if (NonDirectoryFile) {
1023 
1024  DebugTrace(0, Dbg, "Cannot open root directory as a file\n", 0);
1025 
1027  }
1028 
1029  //
1030  // Can't open the TargetDirectory of the root directory.
1031  //
1032 
1033  if (OpenTargetDirectory) {
1034 
1036  }
1037 
1038  //
1039  // Not allowed to delete root directory.
1040  //
1041 
1042  if (DeleteOnClose) {
1043 
1044  try_return( Iosb.Status = STATUS_CANNOT_DELETE );
1045  }
1046 
1047  DebugTrace(0, Dbg, "Opening root dcb\n", 0);
1048 
1050 
1051  Iosb = FatOpenRootDcb( IrpContext,
1052  FileObject,
1053  Vcb,
1054  DesiredAccess,
1055  ShareAccess,
1057 
1058  Irp->IoStatus.Information = Iosb.Information;
1059  try_return( Iosb.Status );
1060  }
1061 
1062  //
1063  // Nope, we will be opening relative to the root directory.
1064  //
1065 
1066  ParentDcb = Vcb->RootDcb;
1067 
1068  //
1069  // Now verify the root Dcb so we don't get in trouble later
1070  // by assuming its in good shape.
1071  //
1072 
1073  FatVerifyFcb( IrpContext, ParentDcb );
1074  }
1075 
1076  //
1077  // FatCommonCreate(): trailing backslash check
1078  //
1079 
1080 
1081  if ((FileName.Length != 0) &&
1082  (FileName.Buffer[FileName.Length/sizeof(WCHAR)-1] == L'\\')) {
1083 
1084  FileName.Length -= sizeof(WCHAR);
1085  TrailingBackslash = TRUE;
1086 
1087  } else {
1088 
1089  TrailingBackslash = FALSE;
1090  }
1091 
1092  //
1093  // Check for max path. We might want to tighten this down to DOS MAX_PATH
1094  // for maximal interchange with non-NT platforms, but for now defer to the
1095  // possibility of something depending on it.
1096  //
1097 
1098  if (ParentDcb->FullFileName.Buffer == NULL) {
1099 
1100  FatSetFullFileNameInFcb( IrpContext, ParentDcb );
1101  }
1102 
1103  if ((USHORT) (ParentDcb->FullFileName.Length + sizeof(WCHAR) + FileName.Length) <= FileName.Length) {
1104 
1106  }
1107 
1108  //
1109  // We loop here until we land on an Fcb that is in a good
1110  // condition. This way we can reopen files that have stale handles
1111  // to files of the same name but are now different.
1112  //
1113 
1114  while ( TRUE ) {
1115 
1116  Fcb = ParentDcb;
1118 
1119  //
1120  // Now walk down the Dcb tree looking for the longest prefix.
1121  // This one exit condition in the while() is to handle a
1122  // special case condition (relative NULL name open), the main
1123  // exit conditions are at the bottom of the loop.
1124  //
1125 
1126  while (RemainingPart.Length != 0) {
1127 
1128  PFCB NextFcb;
1129 
1131  &FinalName,
1132  &NextRemainingPart );
1133 
1134  //
1135  // If RemainingPart starts with a backslash the name is
1136  // invalid.
1137  // Check for no more than 255 characters in FinalName
1138  //
1139 
1140  if (((NextRemainingPart.Length != 0) && (NextRemainingPart.Buffer[0] == L'\\')) ||
1141  (FinalName.Length > 255*sizeof(WCHAR))) {
1142 
1144  }
1145 
1146  //
1147  // Now, try to convert this one component into Oem and search
1148  // the splay tree. If it works then that's great, otherwise
1149  // we have to try with the UNICODE name instead.
1150  //
1151 
1152  FatEnsureStringBufferEnough( &OemFinalName,
1153  FinalName.Length);
1154 
1155  Status = RtlUpcaseUnicodeStringToCountedOemString( &OemFinalName, &FinalName, FALSE );
1156 
1157 
1158  if (NT_SUCCESS(Status)) {
1159 
1160  NextFcb = FatFindFcb( IrpContext,
1161  &Fcb->Specific.Dcb.RootOemNode,
1162  (PSTRING)&OemFinalName,
1163  &FileNameOpenedDos );
1164 
1165  } else {
1166 
1167  NextFcb = NULL;
1168  OemFinalName.Length = 0;
1169 
1171 
1172  try_return( Iosb.Status = Status );
1173  }
1174  }
1175 
1176  //
1177  // If we didn't find anything searching the Oem space, we
1178  // have to try the Unicode space. To save cycles in the
1179  // common case that this tree is empty, we do a quick check
1180  // here.
1181  //
1182 
1183  if ((NextFcb == NULL) && Fcb->Specific.Dcb.RootUnicodeNode) {
1184 
1185  //
1186  // First downcase, then upcase the string, because this
1187  // is what happens when putting names into the tree (see
1188  // strucsup.c, FatConstructNamesInFcb()).
1189  //
1190 
1191  FatEnsureStringBufferEnough( &UpcasedFinalName,
1192  FinalName.Length);
1193 
1194  Status = RtlDowncaseUnicodeString(&UpcasedFinalName, &FinalName, FALSE );
1196 
1197  Status = RtlUpcaseUnicodeString( &UpcasedFinalName, &UpcasedFinalName, FALSE );
1199 
1200 
1201  NextFcb = FatFindFcb( IrpContext,
1202  &Fcb->Specific.Dcb.RootUnicodeNode,
1203  (PSTRING)&UpcasedFinalName,
1204  &FileNameOpenedDos );
1205  }
1206 
1207  //
1208  // If we got back an Fcb then we consumed the FinalName
1209  // legitimately, so the remaining name is now RemainingPart.
1210  //
1211 
1212  if (NextFcb != NULL) {
1213  Fcb = NextFcb;
1214  RemainingPart = NextRemainingPart;
1215  }
1216 
1217  if ((NextFcb == NULL) ||
1218  (NodeType(NextFcb) == FAT_NTC_FCB) ||
1219  (NextRemainingPart.Length == 0)) {
1220 
1221  break;
1222  }
1223  }
1224 
1225  //
1226  // Remaining name cannot start with a backslash
1227  //
1228 
1229  if (RemainingPart.Length && (RemainingPart.Buffer[0] == L'\\')) {
1230 
1231  RemainingPart.Length -= sizeof(WCHAR);
1232  RemainingPart.Buffer += 1;
1233  }
1234 
1235  //
1236  // Now verify that everybody up to the longest found prefix is valid.
1237  //
1238 
1239  _SEH2_TRY {
1240 
1241  FatVerifyFcb( IrpContext, Fcb );
1242 
1246 
1247  FatResetExceptionState( IrpContext );
1248  } _SEH2_END;
1249 
1250  if ( Fcb->FcbCondition == FcbGood ) {
1251 
1252  //
1253  // If we are trying to open a paging file and have happened
1254  // upon the DelayedCloseFcb, make it go away, and try again.
1255  //
1256 
1257  if (IsPagingFile && FirstLoop &&
1258  (NodeType(Fcb) == FAT_NTC_FCB) &&
1261 
1262  FatFspClose(Vcb);
1263 
1264  FirstLoop = FALSE;
1265 
1266  continue;
1267 
1268  } else {
1269 
1270  break;
1271  }
1272 
1273  } else {
1274 
1275  FatRemoveNames( IrpContext, Fcb );
1276  }
1277  }
1278 
1280 
1281  //
1282  // If there is already an Fcb for a paging file open and
1283  // it was not already opened as a paging file, we cannot
1284  // continue as it is too difficult to move a live Fcb to
1285  // non-paged pool.
1286  //
1287 
1288  if (IsPagingFile) {
1289 
1290  if (NodeType(Fcb) == FAT_NTC_FCB &&
1292 
1294  }
1295 
1296  //
1297  // Check for a system file.
1298  //
1299 
1300  } else if (FlagOn( Fcb->FcbState, FCB_STATE_SYSTEM_FILE )) {
1301 
1302  try_return( Iosb.Status = STATUS_ACCESS_DENIED );
1303  }
1304 
1305  //
1306  // If the longest prefix is pending delete (either the file or
1307  // some higher level directory), we cannot continue.
1308  //
1309 
1311 
1313  }
1314 
1315  //
1316  // Now that we've found the longest matching prefix we'll
1317  // check if there isn't any remaining part because that means
1318  // we've located an existing fcb/dcb to open and we can do the open
1319  // without going to the disk
1320  //
1321 
1322  if (RemainingPart.Length == 0) {
1323 
1324  //
1325  // First check if the user wanted to open the target directory
1326  // and if so then call the subroutine to finish the open.
1327  //
1328 
1329  if (OpenTargetDirectory) {
1330 
1332 
1333  Iosb = FatOpenTargetDirectory( IrpContext,
1334  FileObject,
1335  Fcb->ParentDcb,
1336  DesiredAccess,
1337  ShareAccess,
1338  TRUE,
1340  Irp->IoStatus.Information = Iosb.Information;
1341  try_return( Iosb.Status );
1342  }
1343 
1344  //
1345  // We can open an existing fcb/dcb, now we only need to case
1346  // on which type to open.
1347  //
1348 
1350 
1351  //
1352  // This is a directory we're opening up so check if
1353  // we were not to open a directory
1354  //
1355 
1356  if (NonDirectoryFile) {
1357 
1358  DebugTrace(0, Dbg, "Cannot open directory as a file\n", 0);
1359 
1361  }
1362 
1363  DebugTrace(0, Dbg, "Open existing dcb, Dcb = %p\n", Fcb);
1364 
1366 
1367  Iosb = FatOpenExistingDcb( IrpContext,
1368  IrpSp,
1369  FileObject,
1370  Vcb,
1371  (PDCB)Fcb,
1372  DesiredAccess,
1373  ShareAccess,
1375  NoEaKnowledge,
1376  DeleteOnClose,
1379  &OplockPostIrp );
1380 
1381  if (Iosb.Status != STATUS_PENDING) {
1382 
1383  Irp->IoStatus.Information = Iosb.Information;
1384 
1385  } else {
1386 
1387  DebugTrace(0, Dbg, "Enqueue Irp to FSP\n", 0);
1388 
1389  PostIrp = TRUE;
1390  }
1391 
1392  try_return( Iosb.Status );
1393  }
1394 
1395  //
1396  // Check if we're trying to open an existing Fcb and that
1397  // the user didn't want to open a directory. Note that this
1398  // call might actually come back with status_pending because
1399  // the user wanted to supersede or overwrite the file and we
1400  // cannot block. If it is pending then we do not complete the
1401  // request, and we fall through the bottom to the code that
1402  // dispatches the request to the fsp.
1403  //
1404 
1405  if (NodeType(Fcb) == FAT_NTC_FCB) {
1406 
1407  //
1408  // Check if we were only to open a directory
1409  //
1410 
1411  if (OpenDirectory) {
1412 
1413  DebugTrace(0, Dbg, "Cannot open file as directory\n", 0);
1414 
1416  }
1417 
1418  DebugTrace(0, Dbg, "Open existing fcb, Fcb = %p\n", Fcb);
1419 
1420  if ( TrailingBackslash ) {
1422  }
1423 
1425 
1426  Iosb = FatOpenExistingFcb( IrpContext,
1427  IrpSp,
1428  FileObject,
1429  Vcb,
1430  Fcb,
1431  DesiredAccess,
1432  ShareAccess,
1434  EaBuffer,
1435  EaLength,
1438  NoEaKnowledge,
1439  DeleteOnClose,
1442  &OplockPostIrp );
1443 
1444  if (Iosb.Status != STATUS_PENDING) {
1445 
1446  //
1447  // Check if we need to set the cache support flag in
1448  // the file object
1449  //
1450 
1451  if (NT_SUCCESS( Iosb.Status) && !NoIntermediateBuffering) {
1452 
1454  }
1455 
1456  Irp->IoStatus.Information = Iosb.Information;
1457 
1458  } else {
1459 
1460  DebugTrace(0, Dbg, "Enqueue Irp to FSP\n", 0);
1461 
1462  PostIrp = TRUE;
1463  }
1464 
1465  try_return( Iosb.Status );
1466  }
1467 
1468  //
1469  // Not and Fcb or a Dcb so we bug check
1470  //
1471 
1472 #ifdef _MSC_VER
1473 #pragma prefast( suppress:28159, "this is a serious corruption if it happens" )
1474 #endif
1475  FatBugCheck( NodeType(Fcb), (ULONG_PTR) Fcb, 0 );
1476  }
1477 
1478  //
1479  // There is more in the name to parse than we have in existing
1480  // fcbs/dcbs. So now make sure that fcb we got for the largest
1481  // matching prefix is really a dcb otherwise we can't go any
1482  // further
1483  //
1484 
1485  if ((NodeType(Fcb) != FAT_NTC_DCB) && (NodeType(Fcb) != FAT_NTC_ROOT_DCB)) {
1486 
1487  DebugTrace(0, Dbg, "Cannot open file as subdirectory, Fcb = %p\n", Fcb);
1488 
1490  }
1491 
1492  //
1493  // Otherwise we continue on processing the Irp and allowing ourselves
1494  // to block for I/O as necessary. Find/create additional dcb's for
1495  // the one we're trying to open. We loop until either remaining part
1496  // is empty or we get a bad filename. When we exit FinalName is
1497  // the last name in the string we're after, and ParentDcb is the
1498  // parent directory that will contain the opened/created
1499  // file/directory.
1500  //
1501  // Make sure the rest of the name is valid in at least the LFN
1502  // character set (which just happens to be that of HPFS).
1503  //
1504  // If we are not in ChicagoMode, use FAT semantics.
1505  //
1506 
1507  ParentDcb = Fcb;
1508  FirstLoop = TRUE;
1509 
1510  while (TRUE) {
1511 
1512  //
1513  // We do one little optimization here on the first iteration of
1514  // the loop since we know that we have already tried to convert
1515  // FinalOemName from the original UNICODE.
1516  //
1517 
1518  if (FirstLoop) {
1519 
1520  FirstLoop = FALSE;
1521  RemainingPart = NextRemainingPart;
1523 
1524  } else {
1525 
1526  //
1527  // Dissect the remaining part.
1528  //
1529 
1530  DebugTrace(0, Dbg, "Dissecting the name %wZ\n", &RemainingPart);
1531 
1533  &FinalName,
1534  &RemainingPart );
1535 
1536  //
1537  // If RemainingPart starts with a backslash the name is
1538  // invalid.
1539  // Check for no more than 255 characters in FinalName
1540  //
1541 
1542  if (((RemainingPart.Length != 0) && (RemainingPart.Buffer[0] == L'\\')) ||
1543  (FinalName.Length > 255*sizeof(WCHAR))) {
1544 
1546  }
1547 
1548  //
1549  // Now, try to convert this one component into Oem. If it works
1550  // then that's great, otherwise we have to try with the UNICODE
1551  // name instead.
1552  //
1553 
1554  FatEnsureStringBufferEnough( &OemFinalName,
1555  FinalName.Length);
1556 
1557  Status = RtlUpcaseUnicodeStringToCountedOemString( &OemFinalName, &FinalName, FALSE );
1558  }
1559 
1560  if (NT_SUCCESS(Status)) {
1561 
1562  //
1563  // We'll start by trying to locate the dirent for the name. Note
1564  // that we already know that there isn't an Fcb/Dcb for the file
1565  // otherwise we would have found it when we did our prefix lookup.
1566  //
1567 
1568  if (FatIsNameShortOemValid( IrpContext, OemFinalName, FALSE, FALSE, FALSE )) {
1569 
1570  FatStringTo8dot3( IrpContext,
1571  OemFinalName,
1572  &LocalCcb.OemQueryTemplate.Constant );
1573 
1574  LocalCcb.Flags = 0;
1575 
1576  } else {
1577 
1579  }
1580 
1581  } else {
1582 
1584 
1586 
1587  try_return( Iosb.Status = Status );
1588  }
1589  }
1590 
1591  //
1592  // Now we know a lot about the final name, so do legal name
1593  // checking here.
1594  //
1595 
1596  if (FatData.ChicagoMode) {
1597 
1598  if (!FatIsNameLongUnicodeValid( IrpContext, &FinalName, FALSE, FALSE, FALSE )) {
1599 
1601  }
1602 
1603  } else {
1604 
1606 
1608  }
1609  }
1610 
1611  DebugTrace(0, Dbg, "FinalName is %wZ\n", &FinalName);
1612  DebugTrace(0, Dbg, "RemainingPart is %wZ\n", &RemainingPart);
1613 
1614  FatEnsureStringBufferEnough( &UpcasedFinalName,
1615  FinalName.Length);
1616 
1617  if (!NT_SUCCESS(Status = RtlUpcaseUnicodeString( &UpcasedFinalName, &FinalName, FALSE))) {
1618 
1619  try_return( Iosb.Status = Status );
1620  }
1621 
1622  LocalCcb.UnicodeQueryTemplate = UpcasedFinalName;
1623  LocalCcb.ContainsWildCards = FALSE;
1624 
1625  Lfn.Length = 0;
1626 
1627 
1628  FatLocateDirent( IrpContext,
1629  ParentDcb,
1630  &LocalCcb,
1631  0,
1632  &MatchFlags,
1633  &Dirent,
1634  &DirentBcb,
1637  &Lfn,
1638  &OrigLfn);
1639 
1640  //
1641  // Remember we read this Dcb for error recovery.
1642  //
1643 
1644  FinalDcb = ParentDcb;
1645 
1646  //
1647  // If the remaining part is now empty then this is the last name
1648  // in the string and the one we want to open
1649  //
1650 
1651  if (RemainingPart.Length == 0) {
1652 
1653 
1654  break;
1655  }
1656 
1657  //
1658  // We didn't find a dirent, bail.
1659  //
1660 
1661  if (Dirent == NULL) {
1662 
1664  try_return( Iosb.Status );
1665  }
1666 
1667  //
1668  // We now have a dirent, make sure it is a directory
1669  //
1670 
1671  if (!FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
1672 
1674  try_return( Iosb.Status );
1675  }
1676 
1677  //
1678  // Compute the LfnByteOffset.
1679  //
1680 
1682  FAT_LFN_DIRENTS_NEEDED(&OrigLfn) * sizeof(LFN_DIRENT);
1683 
1684  //
1685  // Create a dcb for the new directory
1686  //
1687 
1688  ParentDcb = FatCreateDcb( IrpContext,
1689  Vcb,
1690  ParentDcb,
1691  LfnByteOffset,
1693  Dirent,
1694  &Lfn );
1695 
1696  //
1697  // Remember we created this Dcb for error recovery.
1698  //
1699 
1700  FinalDcb = ParentDcb;
1701 
1702  FatSetFullNameInFcb( IrpContext, ParentDcb, &FinalName );
1703  }
1704 
1705  //
1706  // First check if the user wanted to open the target directory
1707  // and if so then call the subroutine to finish the open.
1708  //
1709 
1710  if (OpenTargetDirectory) {
1711 
1712  Iosb = FatOpenTargetDirectory( IrpContext,
1713  FileObject,
1714  ParentDcb,
1715  DesiredAccess,
1716  ShareAccess,
1717  Dirent ? TRUE : FALSE,
1719 
1720  Irp->IoStatus.Information = Iosb.Information;
1721  try_return( Iosb.Status );
1722  }
1723 
1724  if (Dirent != NULL) {
1725 
1726  //
1727  // Compute the LfnByteOffset.
1728  //
1729 
1731  FAT_LFN_DIRENTS_NEEDED(&OrigLfn) * sizeof(LFN_DIRENT);
1732 
1733  //
1734  // We were able to locate an existing dirent entry, so now
1735  // see if it is a directory that we're trying to open.
1736  //
1737 
1738  if (FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_DIRECTORY )) {
1739 
1740  //
1741  // Make sure its okay to open a directory
1742  //
1743 
1744  if (NonDirectoryFile) {
1745 
1746  DebugTrace(0, Dbg, "Cannot open directory as a file\n", 0);
1747 
1749  }
1750 
1751  DebugTrace(0, Dbg, "Open existing directory\n", 0);
1752 
1753  Iosb = FatOpenExistingDirectory( IrpContext,
1754  IrpSp,
1755  FileObject,
1756  Vcb,
1757  &Fcb,
1758  ParentDcb,
1759  Dirent,
1760  LfnByteOffset,
1762  &Lfn,
1763  DesiredAccess,
1764  ShareAccess,
1766  NoEaKnowledge,
1767  DeleteOnClose,
1770 
1771  Irp->IoStatus.Information = Iosb.Information;
1772  try_return( Iosb.Status );
1773  }
1774 
1775  //
1776  // Otherwise we're trying to open and existing file, and we
1777  // need to check if the user only wanted to open a directory.
1778  //
1779 
1780  if (OpenDirectory) {
1781 
1782  DebugTrace(0, Dbg, "Cannot open file as directory\n", 0);
1783 
1785  }
1786 
1787  DebugTrace(0, Dbg, "Open existing file\n", 0);
1788 
1789  if ( TrailingBackslash ) {
1791  }
1792 
1793 
1794  Iosb = FatOpenExistingFile( IrpContext,
1795  FileObject,
1796  Vcb,
1797  &Fcb,
1798  ParentDcb,
1799  Dirent,
1800  LfnByteOffset,
1802  &Lfn,
1803  &OrigLfn,
1804  DesiredAccess,
1805  ShareAccess,
1807  EaBuffer,
1808  EaLength,
1811  IsPagingFile,
1812  NoEaKnowledge,
1813  DeleteOnClose,
1816 
1817  //
1818  // Check if we need to set the cache support flag in
1819  // the file object
1820  //
1821 
1822  if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering) {
1823 
1825  }
1826 
1827  Irp->IoStatus.Information = Iosb.Information;
1828  try_return( Iosb.Status );
1829  }
1830 
1831  //
1832  // We can't locate a dirent so this is a new file.
1833  //
1834 
1835  //
1836  // Now check to see if we wanted to only open an existing file.
1837  // And then case on whether we wanted to create a file or a directory.
1838  //
1839 
1840  if ((CreateDisposition == FILE_OPEN) ||
1842 
1843  DebugTrace( 0, Dbg, "Cannot open nonexisting file\n", 0);
1844 
1846  }
1847 
1848  //
1849  // Skip a few cycles later if we know now that the Oem name is not
1850  // valid 8.3.
1851  //
1852 
1854 
1855  OemFinalName.Length = 0;
1856  }
1857 
1858  //
1859  // Determine the granted access for this operation now.
1860  //
1861 
1862  if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
1863 
1864  try_return( Iosb );
1865  }
1866 
1867  if (CreateDirectory) {
1868 
1869  DebugTrace(0, Dbg, "Create new directory\n", 0);
1870 
1871  //
1872  // If this media is write protected, don't even try the create.
1873  //
1874 
1875  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
1876 
1877  //
1878  // Set the real device for the pop-up info, and set the verify
1879  // bit in the device object, so that we will force a verify
1880  // in case the user put the correct media back in.
1881  //
1882 
1883 
1884  IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
1885  Vcb->Vpb->RealDevice );
1886 
1888 
1890  }
1891 
1892  //
1893  // Don't allow people to create directories with the
1894  // temporary bit set.
1895  //
1896 
1897  if (TemporaryFile) {
1898 
1900  }
1901 
1902  Iosb = FatCreateNewDirectory( IrpContext,
1903  IrpSp,
1904  FileObject,
1905  Vcb,
1906  ParentDcb,
1907  &OemFinalName,
1908  &FinalName,
1909  DesiredAccess,
1910  ShareAccess,
1911  EaBuffer,
1912  EaLength,
1914  NoEaKnowledge,
1915  DeleteOnClose,
1917 
1918  Irp->IoStatus.Information = Iosb.Information;
1919  try_return( Iosb.Status );
1920  }
1921 
1922  DebugTrace(0, Dbg, "Create new file\n", 0);
1923 
1924  if ( TrailingBackslash ) {
1925 
1927  }
1928 
1929  //
1930  // If this media is write protected, don't even try the create.
1931  //
1932 
1933  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
1934 
1935  //
1936  // Set the real device for the pop-up info, and set the verify
1937  // bit in the device object, so that we will force a verify
1938  // in case the user put the correct media back in.
1939  //
1940 
1941 
1942  IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
1943  Vcb->Vpb->RealDevice );
1944 
1946 
1948  }
1949 
1950 
1951  Iosb = FatCreateNewFile( IrpContext,
1952  IrpSp,
1953  FileObject,
1954  Vcb,
1955  ParentDcb,
1956  &OemFinalName,
1957  &FinalName,
1958  DesiredAccess,
1959  ShareAccess,
1961  EaBuffer,
1962  EaLength,
1964  &Lfn,
1965  IsPagingFile,
1966  NoEaKnowledge,
1967  DeleteOnClose,
1969  TemporaryFile );
1970 
1971  //
1972  // Check if we need to set the cache support flag in
1973  // the file object
1974  //
1975 
1976  if (NT_SUCCESS(Iosb.Status) && !NoIntermediateBuffering) {
1977 
1979  }
1980 
1981  Irp->IoStatus.Information = Iosb.Information;
1982 
1983  try_exit: NOTHING;
1984 
1985  //
1986  // This is a Beta Fix. Do this at a better place later.
1987  //
1988 
1989  if (NT_SUCCESS(Iosb.Status) && !OpenTargetDirectory) {
1990 
1991  PFCB LocalFcb;
1992 
1993  //
1994  // If there is an Fcb/Dcb, set the long file name.
1995  //
1996 
1997  LocalFcb = FileObject->FsContext;
1998 
1999  if (LocalFcb &&
2000  ((NodeType(LocalFcb) == FAT_NTC_FCB) ||
2001  (NodeType(LocalFcb) == FAT_NTC_DCB)) &&
2002  (LocalFcb->FullFileName.Buffer == NULL)) {
2003 
2004  FatSetFullNameInFcb( IrpContext, LocalFcb, &FinalName );
2005  }
2006  }
2007 
2008  } _SEH2_FINALLY {
2009 
2010  DebugUnwind( FatCommonCreate );
2011 
2012 #if (NTDDI_VERSION >= NTDDI_WIN7)
2013 
2014  //
2015  // If we're not getting out with success, and if the caller wanted
2016  // atomic create-with-oplock semantics make sure we back out any
2017  // oplock that may have been granted.
2018  //
2019 
2020  if ((AbnormalTermination() ||
2021  !NT_SUCCESS( Iosb.Status )) &&
2023  (Iosb.Status != STATUS_CANNOT_BREAK_OPLOCK) &&
2024  (IrpContext->ExceptionStatus != STATUS_CANNOT_BREAK_OPLOCK) &&
2025  (Fcb != NULL) &&
2026  FatIsFileOplockable( Fcb )) {
2027 
2028  FsRtlCheckOplockEx( FatGetFcbOplock(Fcb),
2029  IrpContext->OriginatingIrp,
2031  NULL,
2032  NULL,
2033  NULL );
2034  }
2035 #endif
2036 
2037  //
2038  // There used to be a test here - the ASSERT replaces it. We will
2039  // never have begun enumerating directories if we post the IRP for
2040  // oplock reasons.
2041  //
2042 
2043  NT_ASSERT( !OplockPostIrp || DirentBcb == NULL );
2044 
2045  FatUnpinBcb( IrpContext, DirentBcb );
2046 
2047  //
2048  // If we are in an error path, check for any created subdir Dcbs that
2049  // have to be unwound. Don't whack the root directory.
2050  //
2051  // Note this will leave a branch of Dcbs dangling if the directory file
2052  // had not been built on the leaf (case: opening path which has an
2053  // element containing an invalid character name).
2054  //
2055 
2056  if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Iosb.Status)) {
2057 
2058  ULONG SavedFlags;
2059 
2060  //
2061  // Before doing the uninitialize, we have to unpin anything
2062  // that has been repinned, but disable writethrough first. We
2063  // disable raise from unpin-repin since we're already failing.
2064  //
2065 
2066  SavedFlags = IrpContext->Flags;
2067 
2068  SetFlag( IrpContext->Flags, IRP_CONTEXT_FLAG_DISABLE_RAISE |
2070 
2071  FatUnpinRepinnedBcbs( IrpContext );
2072 
2073  if ((FinalDcb != NULL) &&
2074  (NodeType(FinalDcb) == FAT_NTC_DCB) &&
2075  IsListEmpty(&FinalDcb->Specific.Dcb.ParentDcbQueue) &&
2076  (FinalDcb->OpenCount == 0) &&
2077  (FinalDcb->Specific.Dcb.DirectoryFile != NULL)) {
2078 
2079  PFILE_OBJECT DirectoryFileObject;
2080 
2081  DirectoryFileObject = FinalDcb->Specific.Dcb.DirectoryFile;
2082 
2083  FinalDcb->Specific.Dcb.DirectoryFile = NULL;
2084 
2085  CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL );
2086 
2087  ObDereferenceObject( DirectoryFileObject );
2088  }
2089 
2090  IrpContext->Flags = SavedFlags;
2091  }
2092 
2093  if (_SEH2_AbnormalTermination()) {
2094 
2095  FatReleaseVcb( IrpContext, Vcb );
2096  }
2097 
2098  //
2099  // Free up any string buffers we allocated
2100  //
2101 
2102  FatFreeStringBuffer( &OemFinalName);
2103 
2104  FatFreeStringBuffer( &UpcasedFinalName);
2105 
2107  } _SEH2_END;
2108 
2109  //
2110  // The following code is only executed if we are exiting the
2111  // procedure through a normal termination. We complete the request
2112  // and if for any reason that bombs out then we need to unreference
2113  // and possibly delete the fcb and ccb.
2114  //
2115 
2116  _SEH2_TRY {
2117 
2118  if (PostIrp) {
2119 
2120  //
2121  // If the Irp hasn't already been posted, do it now.
2122  //
2123 
2124  if (!OplockPostIrp) {
2125 
2126  Iosb.Status = FatFsdPostRequest( IrpContext, Irp );
2127  }
2128 
2129  } else {
2130 
2131  FatUnpinRepinnedBcbs( IrpContext );
2132  }
2133 
2134  } _SEH2_FINALLY {
2135 
2136  DebugUnwind( FatCommonCreate-in-FatCompleteRequest );
2137 
2138  if (_SEH2_AbnormalTermination() ) {
2139 
2140  PVCB LocalVcb;
2141  PFCB LocalFcb;
2142  PCCB LocalCcb2;
2143  PFILE_OBJECT DirectoryFileObject;
2144 
2145  //
2146  // Unwind all of our counts. Note that if a write failed, then
2147  // the volume has been marked for verify, and all volume
2148  // structures will be cleaned up automatically.
2149  //
2150 
2151  (VOID) FatDecodeFileObject( FileObject, &LocalVcb, &LocalFcb, &LocalCcb2 );
2152 
2153  LocalFcb->UncleanCount -= 1;
2154  LocalFcb->OpenCount -= 1;
2155  LocalVcb->OpenFileCount -= 1;
2156 
2157  if (IsFileObjectReadOnly(FileObject)) { LocalVcb->ReadOnlyCount -= 1; }
2158 
2159 
2160  //
2161  // WinSE #307418 "Occasional data corruption when standby/resume
2162  // while copying files to removable FAT formatted media".
2163  // If new file creation request was interrupted by system suspend
2164  // operation we should revert the changes we made to the parent
2165  // directory and to the allocation table.
2166  //
2167 
2168  if (IrpContext->ExceptionStatus == STATUS_VERIFY_REQUIRED &&
2169  NodeType( LocalFcb ) == FAT_NTC_FCB) {
2170 
2171  FatTruncateFileAllocation( IrpContext, LocalFcb, 0 );
2172 
2173  FatDeleteDirent( IrpContext, LocalFcb, NULL, TRUE );
2174  }
2175 
2176  //
2177  // If we leafed out on a new Fcb we should get rid of it at this point.
2178  //
2179  // Since the object isn't being opened, we have to do all of the teardown
2180  // here. Our close path will not occur for this fileobject. Note this
2181  // will leave a branch of Dcbs dangling since we do it by hand and don't
2182  // chase to the root.
2183  //
2184 
2185  if (LocalFcb->OpenCount == 0 &&
2186  (NodeType( LocalFcb ) == FAT_NTC_FCB ||
2187  IsListEmpty(&LocalFcb->Specific.Dcb.ParentDcbQueue))) {
2188 
2189  NT_ASSERT( NodeType( LocalFcb ) != FAT_NTC_ROOT_DCB );
2190 
2191  if ( (NodeType( LocalFcb ) == FAT_NTC_DCB) &&
2192  (LocalFcb->Specific.Dcb.DirectoryFile != NULL) ) {
2193 
2194  DirectoryFileObject = LocalFcb->Specific.Dcb.DirectoryFile;
2195  LocalFcb->Specific.Dcb.DirectoryFile = NULL;
2196 
2197  CcUninitializeCacheMap( DirectoryFileObject,
2198  &FatLargeZero,
2199  NULL );
2200 
2201  ObDereferenceObject( DirectoryFileObject );
2202 
2203  } else {
2204  if (ARGUMENT_PRESENT( FileObject )) {
2205  FileObject->SectionObjectPointer = NULL;
2206  }
2207  FatDeleteFcb( IrpContext, &LocalFcb );
2208  }
2209  }
2210 
2211  FatDeleteCcb( IrpContext, &LocalCcb2 );
2212 
2213  FatReleaseVcb( IrpContext, LocalVcb );
2214 
2215  } else {
2216 
2217  FatReleaseVcb( IrpContext, Vcb );
2218 
2219  if ( !PostIrp ) {
2220 
2221  //
2222  // If this request is successful and the file was opened
2223  // for FILE_EXECUTE access, then set the FileObject bit.
2224  //
2225 
2226  NT_ASSERT( IrpSp->Parameters.Create.SecurityContext != NULL );
2227  if (FlagOn( *DesiredAccess, FILE_EXECUTE )) {
2228 
2230  }
2231 
2232  //
2233  // Lock volume in drive if we opened a paging file, allocating a
2234  // reserve MDL to guarantee paging file operations can always
2235  // go forward.
2236  //
2237 
2238  if (IsPagingFile && NT_SUCCESS(Iosb.Status)) {
2239 
2240 #ifdef _MSC_VER
2241 #pragma prefast( suppress:28112, "this should be safe" )
2242 #endif
2243  if (!FatReserveMdl) {
2244 
2245  PMDL ReserveMdl = IoAllocateMdl( NULL,
2247  TRUE,
2248  FALSE,
2249  NULL );
2250 
2251  //
2252  // Stash the MDL, and if it turned out there was already one there
2253  // just free what we got.
2254  //
2255 
2256 #ifndef __REACTOS__
2258 #else
2259  InterlockedCompareExchangePointer( (void * volatile*)&FatReserveMdl, ReserveMdl, NULL );
2260 #endif
2261 
2262 #ifdef _MSC_VER
2263 #pragma prefast( suppress:28112, "this should be safe" )
2264 #endif
2265  if (FatReserveMdl != ReserveMdl) {
2266 
2267  IoFreeMdl( ReserveMdl );
2268  }
2269  }
2270 
2272 
2273  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA)) {
2274 
2275  FatToggleMediaEjectDisable( IrpContext, Vcb, TRUE );
2276  }
2277  }
2278 
2279  }
2280  }
2281 
2282  DebugTrace(-1, Dbg, "FatCommonCreate -> %08lx\n", Iosb.Status);
2283  } _SEH2_END;
2284 
2285  CollectCreateStatistics(Vcb, Iosb.Status);
2286 
2287  return Iosb.Status;
2288 }
2289 
2290 //
2291 // Internal support routine
2292 //
2293 
2294 _Requires_lock_held_(_Global_critical_region_)
2296 FatOpenVolume (
2297  _In_ PIRP_CONTEXT IrpContext,
2299  _Inout_ PVCB Vcb,
2303  )
2304 
2305 /*++
2306 
2307 Routine Description:
2308 
2309  This routine opens the specified volume for DASD access
2310 
2311 Arguments:
2312 
2313  FileObject - Supplies the File object
2314 
2315  Vcb - Supplies the Vcb denoting the volume being opened
2316 
2317  DesiredAccess - Supplies the desired access of the caller
2318 
2319  ShareAccess - Supplies the share access of the caller
2320 
2321  CreateDisposition - Supplies the create disposition for this operation
2322 
2323 Return Value:
2324 
2325  IO_STATUS_BLOCK - Returns the completion status for the operation
2326 
2327 --*/
2328 
2329 {
2330  NTSTATUS Status;
2332 
2333 #ifndef __REACTOS__
2334  IO_STATUS_BLOCK Iosb = {0,0};
2335 #else
2336  IO_STATUS_BLOCK Iosb = {{0}};
2337 #endif
2338 
2339  BOOLEAN CleanedVolume = FALSE;
2340 
2341  //
2342  // The following variables are for abnormal termination
2343  //
2344 
2345  BOOLEAN UnwindShareAccess = FALSE;
2346  PCCB UnwindCcb = NULL;
2347  BOOLEAN UnwindCounts = FALSE;
2348  BOOLEAN UnwindVolumeLock = FALSE;
2349 
2350  PAGED_CODE();
2351 
2352  DebugTrace(+1, Dbg, "FatOpenVolume...\n", 0);
2353 
2354  _SEH2_TRY {
2355 
2356  //
2357  // Check for proper desired access and rights
2358  //
2359 
2360  if ((CreateDisposition != FILE_OPEN) &&
2362 
2363  try_return( Iosb.Status = STATUS_ACCESS_DENIED );
2364  }
2365 
2366  //
2367  // If the user does not want to share write or delete then we will try
2368  // and take out a lock on the volume.
2369  //
2370 
2373 
2374 #if (NTDDI_VERSION >= NTDDI_VISTA)
2375  //
2376  // See if the user has requested write access. If so, they cannot share
2377  // read. There is one exception to this. We allow autochk to get an
2378  // implicit lock on the volume while still allowing readers. Once the
2379  // the system is booted, though, we do not allow this type of access.
2380  //
2381 
2383  FsRtlAreVolumeStartupApplicationsComplete()) {
2384 
2386  }
2387 #endif
2388 
2389  //
2390  // Do a quick check here for handles on exclusive open.
2391  //
2392 
2394  !FatIsHandleCountZero( IrpContext, Vcb )) {
2395 
2397  }
2398 
2399  //
2400  // Force Mm to get rid of its referenced file objects.
2401  //
2402 
2403  FatFlushFat( IrpContext, Vcb );
2404 
2405  FatPurgeReferencedFileObjects( IrpContext, Vcb->RootDcb, Flush );
2406 
2407  //
2408  // If the user also does not want to share read then we check
2409  // if anyone is already using the volume, and if so then we
2410  // deny the access. If the user wants to share read then
2411  // we allow the current opens to stay provided they are only
2412  // readonly opens and deny further opens.
2413  //
2414 
2416 
2417  if (Vcb->OpenFileCount != 0) {
2418 
2420  }
2421 
2422  } else {
2423 
2424  if (Vcb->ReadOnlyCount != Vcb->OpenFileCount) {
2425 
2427  }
2428  }
2429 
2430  //
2431  // Lock the volume
2432  //
2433 
2434  Vcb->VcbState |= VCB_STATE_FLAG_LOCKED;
2435  Vcb->FileObjectWithVcbLocked = FileObject;
2436  UnwindVolumeLock = TRUE;
2437 
2438  //
2439  // Clean the volume
2440  //
2441 
2442  CleanedVolume = TRUE;
2443 
2445 
2446  //
2447  // Flush the volume and let ourselves push the clean bit out if everything
2448  // worked.
2449  //
2450 
2451  if (NT_SUCCESS( FatFlushVolume( IrpContext, Vcb, Flush ))) {
2452 
2453  CleanedVolume = TRUE;
2454  }
2455  }
2456 
2457  //
2458  // Clean the volume if we believe it safe and reasonable.
2459  //
2460 
2461  if (CleanedVolume &&
2462  FlagOn( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY ) &&
2463  !FlagOn( Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY ) &&
2464  !CcIsThereDirtyData(Vcb->Vpb)) {
2465 
2466  //
2467  // Cancel any pending clean volumes.
2468  //
2469 
2470  (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
2471  (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );
2472 
2473  FatMarkVolume( IrpContext, Vcb, VolumeClean );
2475 
2476  //
2477  // Unlock the volume if it is removable.
2478  //
2479 
2480  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
2482 
2483  FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
2484  }
2485  }
2486 
2487  //
2488  // If the volume is already opened by someone then we need to check
2489  // the share access
2490  //
2491 
2492  if (Vcb->DirectAccessOpenCount > 0) {
2493 
2495  ShareAccess,
2496  FileObject,
2497  &Vcb->ShareAccess,
2498  TRUE ))) {
2499 
2500  try_return( Iosb.Status );
2501  }
2502 
2503  } else {
2504 
2506  ShareAccess,
2507  FileObject,
2508  &Vcb->ShareAccess );
2509  }
2510 
2511  UnwindShareAccess = TRUE;
2512 
2513  //
2514  // Set up the context and section object pointers, and update
2515  // our reference counts
2516  //
2517 
2520  Vcb,
2521  UnwindCcb = FatCreateCcb( IrpContext ));
2522 
2523  FileObject->SectionObjectPointer = &Vcb->SectionObjectPointers;
2524 
2525  Vcb->DirectAccessOpenCount += 1;
2526  Vcb->OpenFileCount += 1;
2527  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
2528  UnwindCounts = TRUE;
2530 
2531  //
2532  // At this point the open will succeed, so check if the user is getting explicit access
2533  // to the device. If not, we will note this so we can deny modifying FSCTL to it.
2534  //
2535 
2536  IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
2537  Status = FatExplicitDeviceAccessGranted( IrpContext,
2538  Vcb->Vpb->RealDevice,
2539  IrpSp->Parameters.Create.SecurityContext->AccessState,
2541  UserMode :
2542  IrpContext->OriginatingIrp->RequestorMode ));
2543 
2544  if (NT_SUCCESS( Status )) {
2545 
2547  }
2548 
2549  //
2550  // And set our status to success
2551  //
2552 
2553  Iosb.Status = STATUS_SUCCESS;
2554  Iosb.Information = FILE_OPENED;
2555 
2556  try_exit: NOTHING;
2557  } _SEH2_FINALLY {
2558 
2560 
2561  //
2562  // If this is an abnormal termination then undo our work
2563  //
2564 
2565  if (_SEH2_AbnormalTermination() || !NT_SUCCESS(Iosb.Status)) {
2566 
2567  if (UnwindCounts) {
2568  Vcb->DirectAccessOpenCount -= 1;
2569  Vcb->OpenFileCount -= 1;
2570  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
2571  }
2572  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
2573  if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Vcb->ShareAccess ); }
2574  if (UnwindVolumeLock) { Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED; }
2575  }
2576 
2577  DebugTrace(-1, Dbg, "FatOpenVolume -> Iosb.Status = %08lx\n", Iosb.Status);
2578  } _SEH2_END;
2579 
2580  return Iosb;
2581 }
2582 
2583 
2584 //
2585 // Internal support routine
2586 //
2587 
2588 _Requires_lock_held_(_Global_critical_region_)
2590 FatOpenRootDcb (
2591  _In_ PIRP_CONTEXT IrpContext,
2593  _Inout_ PVCB Vcb,
2597  )
2598 
2599 /*++
2600 
2601 Routine Description:
2602 
2603  This routine opens the root dcb for the volume
2604 
2605 Arguments:
2606 
2607  FileObject - Supplies the File object
2608 
2609  Vcb - Supplies the Vcb denoting the volume whose dcb is being opened.
2610 
2611  DesiredAccess - Supplies the desired access of the caller
2612 
2613  ShareAccess - Supplies the share access of the caller
2614 
2615  CreateDisposition - Supplies the create disposition for this operation
2616 
2617 Return Value:
2618 
2619  IO_STATUS_BLOCK - Returns the completion status for the operation
2620 
2621 Arguments:
2622 
2623 --*/
2624 
2625 {
2626  PDCB RootDcb;
2627 #ifndef __REACTOS__
2628  IO_STATUS_BLOCK Iosb = {0};
2629 #else
2630  IO_STATUS_BLOCK Iosb = {{0}};
2631 #endif
2632 
2633  //
2634  // The following variables are for abnormal termination
2635  //
2636 
2637  BOOLEAN UnwindShareAccess = FALSE;
2638  PCCB UnwindCcb = NULL;
2639  BOOLEAN UnwindCounts = FALSE;
2640  BOOLEAN RootDcbAcquired = FALSE;
2641 
2642  PAGED_CODE();
2643 
2644  DebugTrace(+1, Dbg, "FatOpenRootDcb...\n", 0);
2645 
2646  //
2647  // Locate the root dcb
2648  //
2649 
2650  RootDcb = Vcb->RootDcb;
2651 
2652  //
2653  // Get the Dcb exlcusive. This is important as cleanup does not
2654  // acquire the Vcb.
2655  //
2656 
2657  (VOID)FatAcquireExclusiveFcb( IrpContext, RootDcb );
2658  RootDcbAcquired = TRUE;
2659 
2660  _SEH2_TRY {
2661 
2662  //
2663  // Check the create disposition and desired access
2664  //
2665 
2666  if ((CreateDisposition != FILE_OPEN) &&
2668 
2669  Iosb.Status = STATUS_ACCESS_DENIED;
2670  try_return( Iosb );
2671  }
2672 
2673  if (!FatCheckFileAccess( IrpContext,
2674  RootDcb->DirentFatFlags,
2675  DesiredAccess)) {
2676 
2677  Iosb.Status = STATUS_ACCESS_DENIED;
2678  try_return( Iosb );
2679  }
2680 
2681  //
2682  // If the Root dcb is already opened by someone then we need
2683  // to check the share access
2684  //
2685 
2686  if (RootDcb->OpenCount > 0) {
2687 
2689  ShareAccess,
2690  FileObject,
2691  &RootDcb->ShareAccess,
2692  TRUE ))) {
2693 
2694  try_return( Iosb );
2695  }
2696 
2697  } else {
2698 
2700  ShareAccess,
2701  FileObject,
2702  &RootDcb->ShareAccess );
2703  }
2704 
2705  UnwindShareAccess = TRUE;
2706 
2707  //
2708  // Setup the context and section object pointers, and update
2709  // our reference counts
2710  //
2711 
2714  RootDcb,
2715  UnwindCcb = FatCreateCcb( IrpContext ));
2716 
2717  RootDcb->UncleanCount += 1;
2718  RootDcb->OpenCount += 1;
2719  Vcb->OpenFileCount += 1;
2720  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
2721  UnwindCounts = TRUE;
2722 
2723  //
2724  // And set our status to success
2725  //
2726 
2727  Iosb.Status = STATUS_SUCCESS;
2728  Iosb.Information = FILE_OPENED;
2729 
2730  try_exit: NOTHING;
2731  } _SEH2_FINALLY {
2732 
2733  DebugUnwind( FatOpenRootDcb );
2734 
2735  //
2736  // If this is an abnormal termination then undo our work
2737  //
2738 
2739  if (_SEH2_AbnormalTermination()) {
2740 
2741  if (UnwindCounts) {
2742  RootDcb->UncleanCount -= 1;
2743  RootDcb->OpenCount -= 1;
2744  Vcb->OpenFileCount -= 1;
2745  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
2746  }
2747  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
2748  if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &RootDcb->ShareAccess ); }
2749  }
2750 
2751  if (RootDcbAcquired) {
2752 
2753  FatReleaseFcb( IrpContext, RootDcb );
2754  }
2755 
2756  DebugTrace(-1, Dbg, "FatOpenRootDcb -> Iosb.Status = %08lx\n", Iosb.Status);
2757  } _SEH2_END;
2758 
2759  return Iosb;
2760 }
2761 
2762 
2763 //
2764 // Internal support routine
2765 //
2766 
2767 _Requires_lock_held_(_Global_critical_region_)
2769 FatOpenExistingDcb (
2770  _In_ PIRP_CONTEXT IrpContext,
2773  _Inout_ PVCB Vcb,
2774  _Inout_ PDCB Dcb,
2782  _Out_ PBOOLEAN OplockPostIrp
2783  )
2784 
2785 /*++
2786 
2787 Routine Description:
2788 
2789  This routine opens the specified existing dcb
2790 
2791 Arguments:
2792 
2793  FileObject - Supplies the File object
2794 
2795  Vcb - Supplies the Vcb denoting the volume containing the dcb
2796 
2797  Dcb - Supplies the already existing dcb
2798 
2799  DesiredAccess - Supplies the desired access of the caller
2800 
2801  ShareAccess - Supplies the share access of the caller
2802 
2803  CreateDisposition - Supplies the create disposition for this operation
2804 
2805  NoEaKnowledge - This opener doesn't understand Ea's and we fail this
2806  open if the file has NeedEa's.
2807 
2808  DeleteOnClose - The caller wants the file gone when the handle is closed
2809 
2810 Return Value:
2811 
2812  IO_STATUS_BLOCK - Returns the completion status for the operation
2813 
2814 --*/
2815 
2816 {
2817 #ifndef __REACTOS__
2818  IO_STATUS_BLOCK Iosb = {0};
2819 #else
2820  IO_STATUS_BLOCK Iosb = {{0}};
2821 #endif
2822  PBCB DirentBcb = NULL;
2823  PDIRENT Dirent;
2824 
2825  //
2826  // The following variables are for abnormal termination
2827  //
2828 
2829  BOOLEAN UnwindShareAccess = FALSE;
2830  PCCB UnwindCcb = NULL;
2831  BOOLEAN DcbAcquired = FALSE;
2832 
2833 #if (NTDDI_VERSION <= NTDDI_WIN7)
2835 #endif
2836 
2838 
2839  PAGED_CODE();
2840 
2841  DebugTrace(+1, Dbg, "FatOpenExistingDcb...\n", 0);
2842 
2843  //
2844  // Get the Dcb exlcusive. This is important as cleanup does not
2845  // acquire the Vcb.
2846  //
2847 
2848  (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb );
2849  DcbAcquired = TRUE;
2850 
2851  _SEH2_TRY {
2852 
2853 
2854  *OplockPostIrp = FALSE;
2855 
2856  //
2857  // Before spending any noticeable effort, see if we have the odd case
2858  // of someone trying to delete-on-close the root dcb. This will only
2859  // happen if we're hit with a null-filename relative open via the root.
2860  //
2861 
2863 
2864  Iosb.Status = STATUS_CANNOT_DELETE;
2865  try_return( Iosb );
2866  }
2867 
2868 #if (NTDDI_VERSION >= NTDDI_WIN8)
2869 
2870  //
2871  // Let's make sure that if the caller provided an oplock key that it
2872  // gets stored in the file object.
2873  //
2874 
2875  Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Dcb),
2876  IrpContext->OriginatingIrp,
2878  NULL,
2879  NULL,
2880  NULL );
2881 
2882  if (Iosb.Status != STATUS_SUCCESS) {
2883 
2884  try_return( NOTHING );
2885  }
2886 
2887 #endif
2888  //
2889  // If the caller has no Ea knowledge, we immediately check for
2890  // Need Ea's on the file. We don't need to check for ea's on the
2891  // root directory, because it never has any. Fat32 doesn't have
2892  // any, either.
2893  //
2894 
2896  !FatIsFat32(Vcb)) {
2897 
2899 
2900  //
2901  // Get the dirent for the file and then check that the need
2902  // ea count is 0.
2903  //
2904 
2905  FatGetDirentFromFcbOrDcb( IrpContext,
2906  Dcb,
2907  FALSE,
2908  &Dirent,
2909  &DirentBcb );
2910 
2911  FatGetNeedEaCount( IrpContext,
2912  Vcb,
2913  Dirent,
2914  &NeedEaCount );
2915 
2916  FatUnpinBcb( IrpContext, DirentBcb );
2917 
2918  if (NeedEaCount != 0) {
2919 
2920  Iosb.Status = STATUS_ACCESS_DENIED;
2921  try_return( Iosb );
2922  }
2923  }
2924 
2925  //
2926  // Check the create disposition and desired access
2927  //
2928 
2929  if ((CreateDisposition != FILE_OPEN) &&
2931 
2933  try_return( Iosb );
2934  }
2935 
2936  if (!FatCheckFileAccess( IrpContext,
2937  Dcb->DirentFatFlags,
2938  DesiredAccess)) {
2939 
2940  Iosb.Status = STATUS_ACCESS_DENIED;
2941  try_return( Iosb );
2942  }
2943 
2944  //
2945  // If the dcb is already opened by someone then we need
2946  // to check the share access
2947  //
2948 
2949  if (Dcb->OpenCount > 0) {
2950 
2951  if (!NT_SUCCESS(Iosb.Status = FatCheckShareAccess( IrpContext,
2952  FileObject,
2953  Dcb,
2954  DesiredAccess,
2955  ShareAccess ))) {
2956 #if (NTDDI_VERSION >= NTDDI_WIN8)
2957 
2958  NTSTATUS OplockBreakStatus = STATUS_SUCCESS;
2959 
2960  //
2961  // If we got a sharing violation try to break outstanding handle
2962  // oplocks and retry the sharing check. If the caller specified
2963  // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock;
2964  // we just return the sharing violation.
2965  //
2966 
2967  if ((Iosb.Status == STATUS_SHARING_VIOLATION) &&
2969 
2970  OplockBreakStatus = FsRtlOplockBreakH( FatGetFcbOplock(Dcb),
2971  IrpContext->OriginatingIrp,
2972  0,
2973  IrpContext,
2975  FatPrePostIrp );
2976 
2977  //
2978  // If FsRtlOplockBreakH returned STATUS_PENDING, then the IRP
2979  // has been posted and we need to stop working.
2980  //
2981 
2982  if (OplockBreakStatus == STATUS_PENDING) {
2983 
2984  Iosb.Status = STATUS_PENDING;
2985  *OplockPostIrp = TRUE;
2986  try_return( NOTHING );
2987 
2988  //
2989  // If FsRtlOplockBreakH returned an error we want to return that now.
2990  //
2991 
2992  } else if (!NT_SUCCESS( OplockBreakStatus )) {
2993 
2994  Iosb.Status = OplockBreakStatus;
2995  try_return( Iosb );
2996 
2997  //
2998  // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating
2999  // that there is no oplock to be broken. The sharing violation is
3000  // returned in that case.
3001  //
3002 
3003  } else {
3004 
3005  NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS );
3006 
3007  try_return( Iosb );
3008  }
3009 
3010  //
3011  // The initial sharing check failed with something other than sharing
3012  // violation (which should never happen, but let's be future-proof),
3013  // or we *did* get a sharing violation and the caller specified
3014  // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over.
3015  //
3016 
3017  } else {
3018 
3019  try_return( Iosb );
3020  }
3021 #else
3022 
3023  try_return( Iosb );
3024 #endif
3025  }
3026  }
3027 
3028 #if (NTDDI_VERSION >= NTDDI_WIN8)
3029 
3030  //
3031  // Now check that we can continue based on the oplock state of the
3032  // directory. If there are no open handles yet we don't need to do
3033  // this check; oplocks can only exist when there are handles.
3034  //
3035 
3036  if (Dcb->UncleanCount != 0) {
3037 
3039  IrpContext->OriginatingIrp,
3040  IrpContext,
3042  FatPrePostIrp );
3043  }
3044 
3045  //
3046  // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
3047  // to service an oplock break and we need to leave now.
3048  //
3049 
3050  if (Iosb.Status == STATUS_PENDING) {
3051 
3052  *OplockPostIrp = TRUE;
3053  try_return( NOTHING );
3054  }
3055 
3056  //
3057  // If the caller wants atomic create-with-oplock semantics, tell
3058  // the oplock package. We haven't incremented the Fcb's UncleanCount
3059  // for this create yet, so add that in on the call.
3060  //
3061 
3062  if (OpenRequiringOplock &&
3063  (Iosb.Status == STATUS_SUCCESS)) {
3064 
3066  IrpContext->OriginatingIrp,
3067  (Dcb->UncleanCount + 1) );
3068  }
3069 
3070  //
3071  // If we've encountered a failure we need to leave. FsRtlCheckOplock
3072  // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated
3073  // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED
3074  // on the create call. That's an NT_SUCCESS code, so we need to keep
3075  // going.
3076  //
3077 
3078  if ((Iosb.Status != STATUS_SUCCESS) &&
3079  (Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) {
3080 
3081  try_return( NOTHING );
3082  }
3083 
3084 #endif
3085 
3086  //
3087  // Now that we're done with the oplock work update the share counts.
3088  // If the Dcb isn't yet opened we just set the share access rather than
3089  // update it.
3090  //
3091 
3092  if (Dcb->OpenCount > 0) {
3093 
3095 
3096  } else {
3097 
3099  ShareAccess,
3100  FileObject,
3101  &Dcb->ShareAccess );
3102  }
3103 
3104  UnwindShareAccess = TRUE;
3105 
3106  //
3107  // Setup the context and section object pointers, and update
3108  // our reference counts
3109  //
3110 
3113  Dcb,
3114  UnwindCcb = FatCreateCcb( IrpContext ));
3115 
3116  Dcb->UncleanCount += 1;
3117  Dcb->OpenCount += 1;
3118  Vcb->OpenFileCount += 1;
3119  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
3120 
3121  //
3122  // Mark the delete on close bit if the caller asked for that.
3123  //
3124 
3125  {
3126  PCCB Ccb = (PCCB)FileObject->FsContext2;
3127 
3128 
3129  if (DeleteOnClose) {
3130 
3132  }
3133  if (FileNameOpenedDos) {
3134 
3136  }
3137 
3138  }
3139 
3140 
3141  //
3142  // In case this was set, clear it now.
3143  //
3144 
3145  ClearFlag(Dcb->FcbState, FCB_STATE_DELAY_CLOSE);
3146 
3147  //
3148  // And set our status to success
3149  //
3150 
3151  Iosb.Status = STATUS_SUCCESS;
3152  Iosb.Information = FILE_OPENED;
3153 
3154  try_exit: NOTHING;
3155  } _SEH2_FINALLY {
3156 
3157  DebugUnwind( FatOpenExistingDcb );
3158 
3159  //
3160  // Unpin the Dirent Bcb if pinned.
3161  //
3162 
3163  FatUnpinBcb( IrpContext, DirentBcb );
3164 
3165  //
3166  // If this is an abnormal termination then undo our work
3167  //
3168 
3169  if (_SEH2_AbnormalTermination()) {
3170 
3171  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
3172  if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); }
3173  }
3174 
3175  if (DcbAcquired) {
3176 
3177  FatReleaseFcb( IrpContext, Dcb );
3178  }
3179 
3180  DebugTrace(-1, Dbg, "FatOpenExistingDcb -> Iosb.Status = %08lx\n", Iosb.Status);
3181  } _SEH2_END;
3182 
3183  return Iosb;
3184 }
3185 
3186 
3187 //
3188 // Internal support routine
3189 //
3190 
3191 _Requires_lock_held_(_Global_critical_region_)
3193 FatOpenExistingFcb (
3194  _In_ PIRP_CONTEXT IrpContext,
3197  _Inout_ PVCB Vcb,
3198  _Inout_ PFCB Fcb,
3210  _Out_ PBOOLEAN OplockPostIrp
3211  )
3212 
3213 /*++
3214 
3215 Routine Description:
3216 
3217  This routine opens the specified existing fcb
3218 
3219 Arguments:
3220 
3221  FileObject - Supplies the File object
3222 
3223  Vcb - Supplies the Vcb denoting the volume containing the Fcb
3224 
3225  Fcb - Supplies the already existing fcb
3226 
3227  DesiredAccess - Supplies the desired access of the caller
3228 
3229  ShareAccess - Supplies the share access of the caller
3230 
3231  AllocationSize - Supplies the initial allocation if the file is being
3232  superseded or overwritten
3233 
3234  EaBuffer - Supplies the Ea set if the file is being superseded or
3235  overwritten
3236 
3237  EaLength - Supplies the size, in byte, of the EaBuffer
3238 
3239  FileAttributes - Supplies file attributes to use if the file is being
3240  superseded or overwritten
3241 
3242  CreateDisposition - Supplies the create disposition for this operation
3243 
3244  NoEaKnowledge - This opener doesn't understand Ea's and we fail this
3245  open if the file has NeedEa's.
3246 
3247  DeleteOnClose - The caller wants the file gone when the handle is closed
3248 
3249  OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
3250 
3251  FileNameOpenedDos - The caller hit the short side of the name pair finding
3252  this file
3253 
3254  OplockPostIrp - Address to store boolean indicating if the Irp needs to
3255  be posted to the Fsp.
3256 
3257 Return Value:
3258 
3259  IO_STATUS_BLOCK - Returns the completion status for the operation
3260 
3261 --*/
3262 
3263 {
3264 #ifndef __REACTOS__
3265  IO_STATUS_BLOCK Iosb = {0};
3266 #else
3267  IO_STATUS_BLOCK Iosb = {{0}};
3268 #endif
3269 
3270  PBCB DirentBcb = NULL;
3271  PDIRENT Dirent;
3272 
3273  ACCESS_MASK AddedAccess = 0;
3274 
3275  //
3276  // The following variables are for abnormal termination
3277  //
3278 
3279  BOOLEAN UnwindShareAccess = FALSE;
3280  PCCB UnwindCcb = NULL;
3281  BOOLEAN DecrementFcbOpenCount = FALSE;
3282  BOOLEAN FcbAcquired = FALSE;
3283 
3284 
3285  PAGED_CODE();
3286 
3287  DebugTrace(+1, Dbg, "FatOpenExistingFcb...\n", 0);
3288 
3289  //
3290  // Get the Fcb exlcusive. This is important as cleanup does not
3291  // acquire the Vcb.
3292  //
3293 
3294  (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );
3295  FcbAcquired = TRUE;
3296 
3297  _SEH2_TRY {
3298 
3299 
3300  *OplockPostIrp = FALSE;
3301 
3302 #if (NTDDI_VERSION >= NTDDI_WIN7)
3303 
3304  //
3305  // Let's make sure that if the caller provided an oplock key that it
3306  // gets stored in the file object.
3307  //
3308 
3309  Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(Fcb),
3310  IrpContext->OriginatingIrp,
3312  NULL,
3313  NULL,
3314  NULL );
3315 
3316  if (Iosb.Status != STATUS_SUCCESS) {
3317 
3318  try_return( NOTHING );
3319  }
3320 #endif
3321 
3322  //
3323  // Take special action if there is a current batch oplock or
3324  // batch oplock break in process on the Fcb.
3325  //
3326 
3328 
3329  //
3330  // We remember if a batch oplock break is underway for the
3331  // case where the sharing check fails.
3332  //
3333 
3334  Iosb.Information = FILE_OPBATCH_BREAK_UNDERWAY;
3335 
3337  IrpContext->OriginatingIrp,
3338  IrpContext,
3340  FatPrePostIrp );
3341 
3342  //
3343  // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
3344  // to service an oplock break and we need to leave now.
3345  //
3346 
3347  if (Iosb.Status == STATUS_PENDING) {
3348 
3349  *OplockPostIrp = TRUE;
3350  try_return( NOTHING );
3351  }
3352  }
3353 
3354  //
3355  // Check if the user wanted to create the file, also special case
3356  // the supersede and overwrite options. Those add additional,
3357  // possibly only implied, desired accesses to the caller, which
3358  // we must be careful to pull back off if the caller did not actually
3359  // request them.
3360  //
3361  // In other words, check against the implied access, but do not modify
3362  // share access as a result.
3363  //
3364 
3365  if (CreateDisposition == FILE_CREATE) {
3366 
3368  try_return( Iosb );
3369 
3370  } else if (CreateDisposition == FILE_SUPERSEDE) {
3371 
3372  SetFlag( AddedAccess,
3373  DELETE & ~(*DesiredAccess) );
3374 
3375  *DesiredAccess |= DELETE;
3376 
3377  } else if ((CreateDisposition == FILE_OVERWRITE) ||
3379 
3380  SetFlag( AddedAccess,
3382 
3384  }
3385 
3386  //
3387  // Check the desired access
3388  //
3389 
3390  if (!FatCheckFileAccess( IrpContext,
3392  DesiredAccess )) {
3393 
3394  Iosb.Status = STATUS_ACCESS_DENIED;
3395  try_return( Iosb );
3396  }
3397 
3398 
3399  //
3400  // Check for trying to delete a read only file.
3401  //
3402 
3403  if (DeleteOnClose &&
3405 
3406  Iosb.Status = STATUS_CANNOT_DELETE;
3407  try_return( Iosb );
3408  }
3409 
3410  //
3411  // If we are asked to do an overwrite or supersede operation then
3412  // deny access for files where the file attributes for system and
3413  // hidden do not match
3414  //
3415 
3416  if ((CreateDisposition == FILE_SUPERSEDE) ||
3419 
3420  BOOLEAN Hidden;
3421  BOOLEAN System;
3422 
3425 
3428 
3429  DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0);
3430 
3431 
3432  Iosb.Status = STATUS_ACCESS_DENIED;
3433  try_return( Iosb );
3434  }
3435 
3436  //
3437  // If this media is write protected, don't even try the create.
3438  //
3439 
3440  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
3441 
3442  //
3443  // Set the real device for the pop-up info, and set the verify
3444  // bit in the device object, so that we will force a verify
3445  // in case the user put the correct media back in.
3446  //
3447 
3448  IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
3449  Vcb->Vpb->RealDevice );
3450 
3452 
3454  }
3455  }
3456 
3457  //
3458  // Check if the Fcb has the proper share access. This routine will also
3459  // check for writable user secions if the user did not allow write sharing.
3460  //
3461 
3462  if (!NT_SUCCESS(Iosb.Status = FatCheckShareAccess( IrpContext,
3463  FileObject,
3464  Fcb,
3465  DesiredAccess,
3466  ShareAccess ))) {
3467 
3468 #if (NTDDI_VERSION >= NTDDI_WIN7)
3469 
3470  NTSTATUS OplockBreakStatus = STATUS_SUCCESS;
3471 
3472  //
3473  // If we got a sharing violation try to break outstanding handle
3474  // oplocks and retry the sharing check. If the caller specified
3475  // FILE_COMPLETE_IF_OPLOCKED we don't bother breaking the oplock;
3476  // we just return the sharing violation.
3477  //
3478 
3479  if ((Iosb.Status == STATUS_SHARING_VIOLATION) &&
3481 
3482  OplockBreakStatus = FsRtlOplockBreakH( FatGetFcbOplock(Fcb),
3483  IrpContext->OriginatingIrp,
3484  0,
3485  IrpContext,
3487  FatPrePostIrp );
3488 
3489  //
3490  // If FsRtlOplockBreakH returned STATUS_PENDING, then the IRP
3491  // has been posted and we need to stop working.
3492  //
3493 
3494  if (OplockBreakStatus == STATUS_PENDING) {
3495 
3496  Iosb.Status = STATUS_PENDING;
3497  *OplockPostIrp = TRUE;
3498  try_return( NOTHING );
3499 
3500  //
3501  // If FsRtlOplockBreakH returned an error we want to return that now.
3502  //
3503 
3504  } else if (!NT_SUCCESS( OplockBreakStatus )) {
3505 
3506  Iosb.Status = OplockBreakStatus;
3507  try_return( Iosb );
3508 
3509  //
3510  // Otherwise FsRtlOplockBreakH returned STATUS_SUCCESS, indicating
3511  // that there is no oplock to be broken. The sharing violation is
3512  // returned in that case.
3513  //
3514 
3515  } else {
3516 
3517  NT_ASSERT( OplockBreakStatus == STATUS_SUCCESS );
3518 
3519  try_return( Iosb );
3520  }
3521 
3522  //
3523  // The initial sharing check failed with something other than sharing
3524  // violation (which should never happen, but let's be future-proof),
3525  // or we *did* get a sharing violation and the caller specified
3526  // FILE_COMPLETE_IF_OPLOCKED. Either way this create is over.
3527  //
3528 
3529  } else {
3530 
3531  try_return( Iosb );
3532  }
3533 
3534 #else
3535 
3536  try_return( Iosb );
3537 
3538 #endif
3539  }
3540 
3541  //
3542  // Now check that we can continue based on the oplock state of the
3543  // file. If there are no open handles yet we don't need to do this
3544  // check; oplocks can only exist when there are handles.
3545  //
3546  // It is important that we modified the DesiredAccess in place so
3547  // that the Oplock check proceeds against any added access we had
3548  // to give the caller.
3549  //
3550 
3551  if (Fcb->UncleanCount != 0) {
3552 
3554  IrpContext->OriginatingIrp,
3555  IrpContext,
3557  FatPrePostIrp );
3558  }
3559 
3560  //
3561  // if FsRtlCheckOplock returns STATUS_PENDING the IRP has been posted
3562  // to service an oplock break and we need to leave now.
3563  //
3564 
3565  if (Iosb.Status == STATUS_PENDING) {
3566 
3567  *OplockPostIrp = TRUE;
3568  try_return( NOTHING );
3569  }
3570 
3571  //
3572  // If the caller wants atomic create-with-oplock semantics, tell
3573  // the oplock package. We haven't incremented the Fcb's UncleanCount
3574  // for this create yet, so add that in on the call.
3575  //
3576 
3577  if (OpenRequiringOplock &&
3578  (Iosb.Status == STATUS_SUCCESS)) {
3579 
3581  IrpContext->OriginatingIrp,
3582  (Fcb->UncleanCount + 1) );
3583  }
3584 
3585  //
3586  // If we've encountered a failure we need to leave. FsRtlCheckOplock
3587  // will have returned STATUS_OPLOCK_BREAK_IN_PROGRESS if it initiated
3588  // and oplock break and the caller specified FILE_COMPLETE_IF_OPLOCKED
3589  // on the create call. That's an NT_SUCCESS code, so we need to keep
3590  // going.
3591  //
3592 
3593  if ((Iosb.Status != STATUS_SUCCESS) &&
3594  (Iosb.Status != STATUS_OPLOCK_BREAK_IN_PROGRESS)) {
3595 
3596  try_return( NOTHING );
3597  }
3598 
3599  //
3600  // Set the flag indicating if Fast I/O is possible
3601  //
3602 
3603  Fcb->Header.IsFastIoPossible = FatIsFastIoPossible( Fcb );
3604 
3605  //
3606  // If the user wants write access access to the file make sure there
3607  // is not a process mapping this file as an image. Any attempt to
3608  // delete the file will be stopped in fileinfo.c
3609  //
3610  // If the user wants to delete on close, we must check at this
3611  // point though.
3612  //
3613 
3615 
3616  Fcb->OpenCount += 1;
3617  DecrementFcbOpenCount = TRUE;
3618 
3620  MmFlushForWrite )) {
3621 
3624  try_return( Iosb );
3625  }
3626  }
3627 
3628  //
3629  // If this is a non-cached open on a non-paging file, and there
3630  // are no open cached handles, but there is a still a data
3631  // section, attempt a flush and purge operation to avoid cache
3632  // coherency overhead later. We ignore any I/O errors from
3633  // the flush.
3634  //
3635  // We set the CREATE_IN_PROGRESS flag to prevent the Fcb from
3636  // going away out from underneath us.
3637  //
3638 
3643 
3645 
3647 
3648  //
3649  // Grab and release PagingIo to serialize ourselves with the lazy writer.
3650  // This will work to ensure that all IO has completed on the cached
3651  // data and we will succesfully tear away the cache section.
3652  //
3653 
3654  ExAcquireResourceExclusiveLite( Fcb->Header.PagingIoResource, TRUE);
3655  ExReleaseResourceLite( Fcb->Header.PagingIoResource );
3656 
3658  NULL,
3659  0,
3660  FALSE );
3661 
3663  }
3664 
3665  //
3666  // Check if the user only wanted to open the file
3667  //
3668 
3669  if ((CreateDisposition == FILE_OPEN) ||
3671 
3672  DebugTrace(0, Dbg, "Doing open operation\n", 0);
3673 
3674  //
3675  // If the caller has no Ea knowledge, we immediately check for
3676  // Need Ea's on the file.
3677  //
3678 
3679  if (NoEaKnowledge && !FatIsFat32(Vcb)) {
3680 
3682 
3683  //
3684  // Get the dirent for the file and then check that the need
3685  // ea count is 0.
3686  //
3687 
3688  FatGetDirentFromFcbOrDcb( IrpContext,
3689  Fcb,
3690  FALSE,
3691  &Dirent,
3692  &DirentBcb );
3693 
3694  FatGetNeedEaCount( IrpContext,
3695  Vcb,
3696  Dirent,
3697  &NeedEaCount );
3698 
3699  FatUnpinBcb( IrpContext, DirentBcb );
3700 
3701  if (NeedEaCount != 0) {
3702 
3703  Iosb.Status = STATUS_ACCESS_DENIED;
3704  try_return( Iosb );
3705  }
3706  }
3707 
3708  //
3709  // Everything checks out okay, so setup the context and
3710  // section object pointers.
3711  //
3712 
3714  UserFileOpen,
3715  Fcb,
3716  UnwindCcb = FatCreateCcb( IrpContext ));
3717 
3718  FileObject->SectionObjectPointer = &Fcb->NonPaged->SectionObjectPointers;
3719 
3720  //
3721  // Fill in the information field, the status field is already
3722  // set.
3723  //
3724 
3725  Iosb.Information = FILE_OPENED;
3726 
3727  try_return( Iosb );
3728  }
3729 
3730  //
3731  // Check if we are to supersede/overwrite the file, we can wait for
3732  // any I/O at this point
3733  //
3734 
3735  if ((CreateDisposition == FILE_SUPERSEDE) ||
3738 
3739  NTSTATUS OldStatus;
3740 
3741  DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0);
3742 
3743  //
3744  // We remember the previous status code because it may contain
3745  // information about the oplock status.
3746  //
3747 
3748  OldStatus = Iosb.Status;
3749 
3750  //
3751  // Determine the granted access for this operation now.
3752  //
3753 
3754  if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
3755 
3756  try_return( Iosb );
3757  }
3758 
3759  //
3760  // And overwrite the file.
3761  //
3762 
3763  Iosb = FatSupersedeOrOverwriteFile( IrpContext,
3764  FileObject,
3765  Fcb,
3767  EaBuffer,
3768  EaLength,
3771  NoEaKnowledge );
3772 
3773  if (Iosb.Status == STATUS_SUCCESS) {
3774 
3775  Iosb.Status = OldStatus;
3776  }
3777 
3778  try_return( Iosb );
3779  }
3780 
3781  //
3782  // If we ever get here then the I/O system gave us some bad input
3783  //
3784 
3785 #ifdef _MSC_VER
3786 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
3787 #endif
3788  FatBugCheck( CreateDisposition, 0, 0 );
3789 
3790  try_exit: NOTHING;
3791 
3792  //
3793  // Update the share access and counts if successful
3794  //
3795 
3796  if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS(Iosb.Status)) {
3797 
3798  //
3799  // Now, we may have added some access bits above to indicate the access
3800  // this caller would conflict with (as opposed to what they get) in order
3801  // to perform the overwrite/supersede. We need to make a call to that will
3802  // recalculate the bits in the fileobject to reflect the real access they
3803  // will get.
3804  //
3805 
3806  if (AddedAccess) {
3807 
3808  NTSTATUS Status;
3809 
3810  ClearFlag( *DesiredAccess, AddedAccess );
3811 
3812 #ifdef _MSC_VER
3813 #pragma prefast( suppress:28931, "it needs to be there for debug assert" );
3814 #endif
3816  ShareAccess,
3817  FileObject,
3818  &Fcb->ShareAccess,
3819  TRUE );
3820 
3821  //
3822  // It must be the case that we are really asking for less access, so
3823  // any conflict must have been detected before this point.
3824  //
3825 
3827 
3828  } else {
3829 
3831  }
3832 
3833  UnwindShareAccess = TRUE;
3834 
3835  //
3836  // In case this was set, clear it now.
3837  //
3838 
3840 
3841  Fcb->UncleanCount += 1;
3842  Fcb->OpenCount += 1;
3844  Fcb->NonCachedUncleanCount += 1;
3845  }
3846  Vcb->OpenFileCount += 1;
3847  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
3848 
3849  {
3850  PCCB Ccb;
3851 
3852  Ccb = (PCCB)FileObject->FsContext2;
3853 
3854  //
3855  // Mark the DeleteOnClose bit if the operation was successful.
3856  //
3857 
3858  if ( DeleteOnClose ) {
3859 
3861  }
3862 
3863  //
3864  // Mark the OpenedByShortName bit if the operation was successful.
3865  //
3866 
3867  if ( FileNameOpenedDos ) {
3868 
3870  }
3871 
3872  //
3873  // Mark the ManageVolumeAccess bit if the privilege is held.
3874  //
3875 
3876  if (FatCheckManageVolumeAccess( IrpContext,
3877  IrpSp->Parameters.Create.SecurityContext->AccessState,
3879  UserMode :
3880  IrpContext->OriginatingIrp->RequestorMode ))) {
3881 
3883  }
3884  }
3885 
3886 
3887  }
3888 
3889  } _SEH2_FINALLY {
3890 
3891  DebugUnwind( FatOpenExistingFcb );
3892 
3893  //
3894  // Unpin the Dirent Bcb if pinned.
3895  //
3896 
3897  FatUnpinBcb( IrpContext, DirentBcb );
3898 
3899  //
3900  // If this is an abnormal termination then undo our work
3901  //
3902 
3903  if (_SEH2_AbnormalTermination()) {
3904 
3905  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
3906  if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Fcb->ShareAccess ); }
3907  }
3908 
3909  if (DecrementFcbOpenCount) {
3910 
3911  Fcb->OpenCount -= 1;
3912 
3913  if (Fcb->OpenCount == 0) {
3914  if (ARGUMENT_PRESENT( FileObject )) {
3915  FileObject->SectionObjectPointer = NULL;
3916  }
3917  FatDeleteFcb( IrpContext, &Fcb );
3918  FcbAcquired = FALSE;
3919  }
3920  }
3921 
3922  if (FcbAcquired) {
3923 
3924  FatReleaseFcb( IrpContext, Fcb );
3925  }
3926 
3927  DebugTrace(-1, Dbg, "FatOpenExistingFcb -> Iosb.Status = %08lx\n", Iosb.Status);
3928  } _SEH2_END;
3929 
3930  return Iosb;
3931 }
3932 
3933 //
3934 // Internal support routine
3935 //
3936 
3937 _Requires_lock_held_(_Global_critical_region_)
3939 FatOpenTargetDirectory (
3940  _In_ PIRP_CONTEXT IrpContext,
3942  _Inout_ PDCB Dcb,
3945  _In_ BOOLEAN DoesNameExist,
3947  )
3948 
3949 /*++
3950 
3951 Routine Description:
3952 
3953  This routine opens the target directory and replaces the name in the
3954  file object with the remaining name.
3955 
3956 Arguments:
3957 
3958  FileObject - Supplies the File object
3959 
3960  Dcb - Supplies an already existing dcb that we are going to open
3961 
3962  DesiredAccess - Supplies the desired access of the caller
3963 
3964  ShareAccess - Supplies the share access of the caller
3965 
3966  DoesNameExist - Indicates if the file name already exists in the
3967  target directory.
3968 
3969 
3970 Return Value:
3971 
3972  IO_STATUS_BLOCK - Returns the completion status for the operation
3973 
3974 --*/
3975 
3976 {
3977 #ifndef __REACTOS__
3978  IO_STATUS_BLOCK Iosb = {0};
3979 #else
3980  IO_STATUS_BLOCK Iosb = {{0}};
3981 #endif
3982 
3983  //
3984  // The following variables are for abnormal termination
3985  //
3986 
3987  BOOLEAN UnwindShareAccess = FALSE;
3988  PCCB UnwindCcb = NULL;
3989  BOOLEAN DcbAcquired = FALSE;
3990 
3991  PAGED_CODE();
3992 
3993  DebugTrace(+1, Dbg, "FatOpenTargetDirectory...\n", 0);
3994 
3995  //
3996  // Get the Dcb exlcusive. This is important as cleanup does not
3997  // acquire the Vcb.
3998  //
3999 
4000  (VOID)FatAcquireExclusiveFcb( IrpContext, Dcb );
4001  DcbAcquired = TRUE;
4002 
4003  _SEH2_TRY {
4004 
4005  ULONG i;
4006 
4007  //
4008  // If the Dcb is already opened by someone then we need
4009  // to check the share access
4010  //
4011 
4012  if (Dcb->OpenCount > 0) {
4013 
4015  ShareAccess,
4016  FileObject,
4017  &Dcb->ShareAccess,
4018  TRUE ))) {
4019 
4020  try_return( Iosb );
4021  }
4022 
4023  } else {
4024 
4026  ShareAccess,
4027  FileObject,
4028  &Dcb->ShareAccess );
4029  }
4030 
4031  UnwindShareAccess = TRUE;
4032 
4033  //
4034  // Setup the context and section object pointers, and update
4035  // our reference counts
4036  //
4037 
4040  Dcb,
4041  UnwindCcb = FatCreateCcb( IrpContext ));
4042 
4043  Dcb->UncleanCount += 1;
4044  Dcb->OpenCount += 1;
4045  Dcb->Vcb->OpenFileCount += 1;
4046  if (IsFileObjectReadOnly(FileObject)) { Dcb->Vcb->ReadOnlyCount += 1; }
4047 
4048  //
4049  // Update the name in the file object, by definition the remaining
4050  // part must be shorter than the original file name so we'll just
4051  // overwrite the file name.
4052  //
4053 
4054  i = FileObject->FileName.Length/sizeof(WCHAR) - 1;
4055 
4056  //
4057  // Get rid of a trailing backslash
4058  //
4059 
4060  if (FileObject->FileName.Buffer[i] == L'\\') {
4061 
4062  NT_ASSERT(i != 0);
4063 
4064  FileObject->FileName.Length -= sizeof(WCHAR);
4065  i -= 1;
4066  }
4067 
4068  //
4069  // Find the first non-backslash character. i will be its index.
4070  //
4071 
4072  while (TRUE) {
4073 
4074  if (FileObject->FileName.Buffer[i] == L'\\') {
4075 
4076  i += 1;
4077  break;
4078  }
4079 
4080  if (i == 0) {
4081  break;
4082  }
4083 
4084  i--;
4085  }
4086 
4087  if (i) {
4088 
4089  FileObject->FileName.Length -= (USHORT)(i * sizeof(WCHAR));
4090 
4094  }
4095 
4096  //
4097  // And set our status to success
4098  //
4099 
4100  Iosb.Status = STATUS_SUCCESS;
4101  Iosb.Information = (DoesNameExist ? FILE_EXISTS : FILE_DOES_NOT_EXIST);
4102 
4103  if ( ( NT_SUCCESS(Iosb.Status) ) && ( DoesNameExist ) ) {
4104  PCCB Ccb;
4105 
4106  Ccb = (PCCB)FileObject->FsContext2;
4107 
4108  //
4109  // Mark the OpenedByShortName bit if the operation was successful.
4110  //
4111 
4112  if ( FileNameOpenedDos ) {
4113 
4115  }
4116  }
4117 
4118  try_exit: NOTHING;
4119  } _SEH2_FINALLY {
4120 
4121  DebugUnwind( FatOpenTargetDirectory );
4122 
4123  //
4124  // If this is an abnormal termination then undo our work
4125  //
4126 
4127  if (_SEH2_AbnormalTermination()) {
4128 
4129  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
4130  if (UnwindShareAccess) { IoRemoveShareAccess( FileObject, &Dcb->ShareAccess ); }
4131  }
4132 
4133  if (DcbAcquired) {
4134 
4135  FatReleaseFcb( IrpContext, Dcb );
4136  }
4137 
4138  DebugTrace(-1, Dbg, "FatOpenTargetDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
4139  } _SEH2_END;
4140 
4141  return Iosb;
4142 }
4143 
4144 
4145 
4146 //
4147 // Internal support routine
4148 //
4149 _Success_(return.Status == STATUS_SUCCESS)
4150 _Requires_lock_held_(_Global_critical_region_)
4152 #ifdef _MSC_VER
4153 #pragma warning(suppress:6101) // bug in PREFast means the _Success_ annotation is not correctly applied
4154 #endif
4155 FatOpenExistingDirectory (
4156  _In_ PIRP_CONTEXT IrpContext,
4159  _Inout_ PVCB Vcb,
4173  )
4174 
4175 /*++
4176 
4177 Routine Description:
4178 
4179  This routine opens the specified directory. The directory has not
4180  previously been opened.
4181 
4182 Arguments:
4183 
4184  FileObject - Supplies the File object
4185 
4186  Vcb - Supplies the Vcb denoting the volume containing the dcb
4187 
4188  Dcb - Returns the newly-created DCB for the file.
4189 
4190  ParentDcb - Supplies the parent directory containing the subdirectory
4191  to be opened
4192 
4193  DirectoryName - Supplies the file name of the directory being opened.
4194 
4195  Dirent - Supplies the dirent for the directory being opened
4196 
4197  LfnByteOffset - Tells where the Lfn begins. If there is no Lfn
4198  this field is the same as DirentByteOffset.
4199 
4200  DirentByteOffset - Supplies the Vbo of the dirent within its parent
4201  directory
4202 
4203  Lfn - May supply a long name for the file.
4204 
4205  DesiredAccess - Supplies the desired access of the caller
4206 
4207  ShareAccess - Supplies the share access of the caller
4208 
4209  CreateDisposition - Supplies the create disposition for this operation
4210 
4211  NoEaKnowledge - This opener doesn't understand Ea's and we fail this
4212  open if the file has NeedEa's.
4213 
4214  DeleteOnClose - The caller wants the file gone when the handle is closed
4215 
4216  OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
4217 
4218 Return Value:
4219 
4220  IO_STATUS_BLOCK - Returns the completion status for the operation
4221 
4222 --*/
4223 
4225 #ifndef __REACTOS__
4226  IO_STATUS_BLOCK Iosb = {0};
4227 #else
4228  IO_STATUS_BLOCK Iosb = {{0}};
4229 #endif
4230 
4231  //
4232  // The following variables are for abnormal termination
4233  //
4234 
4237 
4239 
4241 #if (NTDDI_VERSION <= NTDDI_WIN7)
4243 #endif
4245 
4246  PAGED_CODE();
4247 
4248  DebugTrace(+1, Dbg, "FatOpenExistingDirectory...\n", 0);
4249 
4251 
4252  //
4253  // If the caller has no Ea knowledge, we immediately check for
4254  // Need Ea's on the file.
4255  //
4256 
4257  if (NoEaKnowledge && !FatIsFat32(Vcb)) {
4258 
4260 
4261  FatGetNeedEaCount( IrpContext,
4262  Vcb,
4263  Dirent,
4264  &NeedEaCount );
4265 
4266  if (NeedEaCount != 0) {
4267 
4268  Iosb.Status = STATUS_ACCESS_DENIED;
4269  try_return( Iosb );
4270  }
4271  }
4272 
4273  //
4274  // Check the create disposition and desired access
4275  //
4276 
4277  if ((CreateDisposition != FILE_OPEN) &&
4279 
4281  try_return( Iosb );
4282  }
4283 
4284  if (!FatCheckFileAccess( IrpContext,
4285  Dirent->Attributes,
4286  DesiredAccess)) {
4287 
4288  Iosb.Status = STATUS_ACCESS_DENIED;
4289  try_return( Iosb );
4290  }
4291 
4292  //
4293  // Create a new dcb for the directory
4294  //
4295 
4296  *Dcb = UnwindDcb = FatCreateDcb( IrpContext,
4297  Vcb,
4298  ParentDcb,
4299  LfnByteOffset,
4301  Dirent,
4302  Lfn );
4303 
4304 #if (NTDDI_VERSION >= NTDDI_WIN8)
4305 
4306  //
4307  // Let's make sure that if the caller provided an oplock key that it
4308  // gets stored in the file object.
4309  //
4310 
4311  Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(*Dcb),
4312  IrpContext->OriginatingIrp,
4314  NULL,
4315  NULL,
4316  NULL );
4317 
4318  //
4319  // If the caller wants atomic create-with-oplock semantics, tell
4320  // the oplock package. We haven't incremented the Fcb's UncleanCount
4321  // for this create yet, so add that in on the call.
4322  //
4323 
4325  (Iosb.Status == STATUS_SUCCESS)) {
4326 
4328  IrpContext->OriginatingIrp,
4329  ((*Dcb)->UncleanCount + 1) );
4330  }
4331 
4332  //
4333  // Get out if either of the above calls failed. Raise to trigger
4334  // cleanup of the new Dcb.
4335  //
4336 
4337  if (Iosb.Status != STATUS_SUCCESS) {
4338 
4339  NT_ASSERT( Iosb.Status != STATUS_PENDING );
4340 
4341  FatRaiseStatus( IrpContext, Iosb.Status );
4342  }
4343 #endif
4344 
4345  //
4346  // Setup our share access
4347  //
4348 
4350  ShareAccess,
4351  FileObject,
4352  &(*Dcb)->ShareAccess );
4353 
4354  //
4355  // Setup the context and section object pointers, and update
4356  // our reference counts
4357  //
4358 
4361  (*Dcb),
4362  UnwindCcb = FatCreateCcb( IrpContext ));
4363 
4364  (*Dcb)->UncleanCount += 1;
4365  (*Dcb)->OpenCount += 1;
4366  Vcb->OpenFileCount += 1;
4367  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
4368 
4370 
4371 
4372  //
4373  // And set our status to success
4374  //
4375 
4376  Iosb.Status = STATUS_SUCCESS;
4377  Iosb.Information = FILE_OPENED;
4378 
4379  if ( NT_SUCCESS(Iosb.Status) ) {
4380  PCCB Ccb;
4381 
4382  Ccb = (PCCB)FileObject->FsContext2;
4383 
4384  //
4385  // Mark the OpenedByShortName bit if the operation was successful.
4386  //
4387 
4388  if ( FileNameOpenedDos ) {
4389 
4391  }
4392  }
4393 
4394  try_exit: NOTHING;
4396 
4397  DebugUnwind( FatOpenExistingDirectory );
4398 
4399  //
4400  // If this is an abnormal termination then undo our work
4401  //
4402 
4404 
4405  if (CountsIncremented) {
4406 
4407  (*Dcb)->UncleanCount -= 1;
4408  (*Dcb)->OpenCount -= 1;
4409  Vcb->OpenFileCount -= 1;
4410  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
4411  }
4412 
4413  if (UnwindDcb != NULL) {
4414  if (ARGUMENT_PRESENT( FileObject )) {
4415  FileObject->SectionObjectPointer = NULL;
4416  }
4417  FatDeleteFcb( IrpContext, &UnwindDcb );
4418  *Dcb = NULL;
4419  }
4420  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
4421  }
4422 
4423  DebugTrace(-1, Dbg, "FatOpenExistingDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
4425 
4426  return Iosb;
4427 }
4428 
4429 
4430 //
4431 // Internal support routine
4432 //
4433 
4434 _Requires_lock_held_(_Global_critical_region_)
4436 FatOpenExistingFile (
4437  _In_ PIRP_CONTEXT IrpContext,
4439  _Inout_ PVCB Vcb,
4446  _In_ PUNICODE_STRING OrigLfn,
4454  _In_ BOOLEAN IsPagingFile,
4459  )
4460 
4461 /*++
4462 
4463 Routine Description:
4464 
4465  This routine opens the specified file. The file has not previously
4466  been opened.
4467 
4468 Arguments:
4469 
4470  FileObject - Supplies the File object
4471 
4472  Vcb - Supplies the Vcb denoting the volume containing the file
4473 
4474  Fcb - Returns the newly-created FCB for the file.
4475 
4476  ParentDcb - Supplies the parent directory containing the file to be
4477  opened
4478 
4479  Dirent - Supplies the dirent for the file being opened
4480 
4481  LfnByteOffset - Tells where the Lfn begins. If there is no Lfn
4482  this field is the same as DirentByteOffset.
4483 
4484  DirentByteOffset - Supplies the Vbo of the dirent within its parent
4485  directory
4486 
4487  Lfn - May supply a long name for the file.
4488 
4489  DesiredAccess - Supplies the desired access of the caller
4490 
4491  ShareAccess - Supplies the share access of the caller
4492 
4493  AllocationSize - Supplies the initial allocation if the file is being
4494  superseded, overwritten, or created.
4495 
4496  EaBuffer - Supplies the Ea set if the file is being superseded,
4497  overwritten, or created.
4498 
4499  EaLength - Supplies the size, in byte, of the EaBuffer
4500 
4501  FileAttributes - Supplies file attributes to use if the file is being
4502  superseded, overwritten, or created
4503 
4504  CreateDisposition - Supplies the create disposition for this operation
4505 
4506  IsPagingFile - Indicates if this is the paging file being opened.
4507 
4508  NoEaKnowledge - This opener doesn't understand Ea's and we fail this
4509  open if the file has NeedEa's.
4510 
4511  DeleteOnClose - The caller wants the file gone when the handle is closed
4512 
4513  OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
4514 
4515  FileNameOpenedDos - The caller opened this file by hitting the 8.3 side
4516  of the Lfn/8.3 pair
4517 
4518 Return Value:
4519 
4520  IO_STATUS_BLOCK - Returns the completion status for the operation
4521 
4522 --*/
4523 
4524 {
4525 #ifndef __REACTOS__
4526  IO_STATUS_BLOCK Iosb = {0};
4527 #else
4528  IO_STATUS_BLOCK Iosb = {{0}};
4529 #endif
4530 
4531  ACCESS_MASK AddedAccess = 0;
4532 
4533  PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( IrpContext->OriginatingIrp );
4534 
4535  //
4536  // The following variables are for abnormal termination
4537  //
4538 
4539  PFCB UnwindFcb = NULL;
4540  PCCB UnwindCcb = NULL;
4542 
4543 
4544 #if (NTDDI_VERSION < NTDDI_WIN7)
4546 #endif
4547 
4548  PAGED_CODE();
4549 
4550  DebugTrace(+1, Dbg, "FatOpenExistingFile...\n", 0);
4551 
4552  _SEH2_TRY {
4553 
4554  //
4555  // Check if the user wanted to create the file or if access is
4556  // denied
4557  //
4558 
4559  if (CreateDisposition == FILE_CREATE) {
4561  try_return( Iosb );
4562 
4563  } else if ((CreateDisposition == FILE_SUPERSEDE) && !IsPagingFile) {
4564 
4565  SetFlag( AddedAccess,
4566  DELETE & ~(*DesiredAccess) );
4567 
4568  *DesiredAccess |= DELETE;
4569 
4570  } else if (((CreateDisposition == FILE_OVERWRITE) ||
4571  (CreateDisposition == FILE_OVERWRITE_IF)) && !IsPagingFile) {
4572 
4573  SetFlag( AddedAccess,
4575 
4577  }
4578 
4579  if (!FatCheckFileAccess( IrpContext,
4580  Dirent->Attributes,
4581  DesiredAccess)) {
4582 
4583  Iosb.Status = STATUS_ACCESS_DENIED;
4584  try_return( Iosb );
4585  }
4586 
4587 
4588  //
4589  // Check for trying to delete a read only file.
4590  //
4591 
4592  if (DeleteOnClose &&
4593  FlagOn( Dirent->Attributes, FAT_DIRENT_ATTR_READ_ONLY )) {
4594 
4595  Iosb.Status = STATUS_CANNOT_DELETE;
4596  try_return( Iosb );
4597  }
4598 
4599  //
4600  // IF we are asked to do an overwrite or supersede operation then
4601  // deny access for files where the file attributes for system and
4602  // hidden do not match
4603  //
4604 
4605  if ((CreateDisposition == FILE_SUPERSEDE) ||
4608 
4609  BOOLEAN Hidden;
4610  BOOLEAN System;
4611 
4614 
4617 
4618  DebugTrace(0, Dbg, "The hidden and/or system bits do not match\n", 0);
4619 
4620  if ( !IsPagingFile ) {
4621 
4622  Iosb.Status = STATUS_ACCESS_DENIED;
4623  try_return( Iosb );
4624  }
4625  }
4626 
4627  //
4628  // If this media is write protected, don't even try the create.
4629  //
4630 
4631  if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_WRITE_PROTECTED)) {
4632 
4633  //
4634  // Set the real device for the pop-up info, and set the verify
4635  // bit in the device object, so that we will force a verify
4636  // in case the user put the correct media back in.
4637  //
4638 
4639 
4640  IoSetHardErrorOrVerifyDevice( IrpContext->OriginatingIrp,
4641  Vcb->Vpb->RealDevice );
4642 
4644 
4646  }
4647  }
4648 
4649  //
4650  // Create a new Fcb for the file, and set the file size in
4651  // the fcb.
4652  //
4653 
4654  *Fcb = UnwindFcb = FatCreateFcb( IrpContext,
4655  Vcb,
4656  ParentDcb,
4657  LfnByteOffset,
4659  Dirent,
4660  Lfn,
4661  OrigLfn,
4662  IsPagingFile,
4663  FALSE );
4664 
4665 
4666  (*Fcb)->Header.ValidDataLength.LowPart = (*Fcb)->Header.FileSize.LowPart;
4667 
4668  //
4669  // If this is a paging file, lookup the allocation size so that
4670  // the Mcb is always valid
4671  //
4672 
4673  if (IsPagingFile) {
4674 
4675  FatLookupFileAllocationSize( IrpContext, *Fcb );
4676  }
4677 
4678 #if (NTDDI_VERSION >= NTDDI_WIN7)
4679 
4680  //
4681  // Let's make sure that if the caller provided an oplock key that it
4682  // gets stored in the file object.
4683  //
4684 
4685  Iosb.Status = FsRtlCheckOplockEx( FatGetFcbOplock(*Fcb),
4686  IrpContext->OriginatingIrp,
4688  NULL,
4689  NULL,
4690  NULL );
4691 
4692  //
4693  // If the caller wants atomic create-with-oplock semantics, tell
4694  // the oplock package. We haven't incremented the Fcb's UncleanCount
4695  // for this create yet, so add that in on the call.
4696  //
4697 
4698  if (OpenRequiringOplock &&
4699  (Iosb.Status == STATUS_SUCCESS)) {
4700 
4702  IrpContext->OriginatingIrp,
4703  ((*Fcb)->UncleanCount + 1) );
4704  }
4705 
4706  //
4707  // Get out if either of the above calls failed. Raise to trigger
4708  // cleanup of the new Fcb.
4709  //
4710 
4711  if (Iosb.Status != STATUS_SUCCESS) {
4712 
4713  NT_ASSERT( Iosb.Status != STATUS_PENDING );
4714 
4715  FatRaiseStatus( IrpContext, Iosb.Status );
4716  }
4717 #endif
4718 
4719  //
4720  // Now case on whether we are to simply open, supersede, or
4721  // overwrite the file.
4722  //
4723 
4724  switch (CreateDisposition) {
4725 
4726  case FILE_OPEN:
4727  case FILE_OPEN_IF:
4728 
4729  DebugTrace(0, Dbg, "Doing only an open operation\n", 0);
4730 
4731  //
4732  // If the caller has no Ea knowledge, we immediately check for
4733  // Need Ea's on the file.
4734  //
4735 
4736  if (NoEaKnowledge && !FatIsFat32(Vcb)) {
4737 
4739 
4740  FatGetNeedEaCount( IrpContext,
4741  Vcb,
4742  Dirent,
4743  &NeedEaCount );
4744 
4745  if (NeedEaCount != 0) {
4746 
4747  FatRaiseStatus( IrpContext, STATUS_ACCESS_DENIED );
4748  }
4749  }
4750 
4751  //
4752  // Setup the context and section object pointers.
4753  //
4754 
4756  UserFileOpen,
4757  *Fcb,
4758  UnwindCcb = FatCreateCcb( IrpContext ));
4759 
4760  FileObject->SectionObjectPointer = &(*Fcb)->NonPaged->SectionObjectPointers;
4761 
4762  Iosb.Status = STATUS_SUCCESS;
4763  Iosb.Information = FILE_OPENED;
4764  break;
4765 
4766  case FILE_SUPERSEDE:
4767  case FILE_OVERWRITE:
4768  case FILE_OVERWRITE_IF:
4769 
4770  DebugTrace(0, Dbg, "Doing supersede/overwrite operation\n", 0);
4771 
4772  //
4773  // Determine the granted access for this operation now.
4774  //
4775 
4776  if (!NT_SUCCESS( Iosb.Status = FatCheckSystemSecurityAccess( IrpContext ))) {
4777 
4778  try_return( Iosb );
4779  }
4780 
4781  Iosb = FatSupersedeOrOverwriteFile( IrpContext,
4782  FileObject,
4783  *Fcb,
4785  EaBuffer,
4786  EaLength,
4789  NoEaKnowledge );
4790  break;
4791 
4792  default:
4793 
4794  DebugTrace(0, Dbg, "Illegal Create Disposition\n", 0);
4795 
4796 #ifdef _MSC_VER
4797 #pragma prefast( suppress:28159, "things are seriously wrong if we get here" )
4798 #endif
4799  FatBugCheck( CreateDisposition, 0, 0 );
4800  break;
4801  }
4802 
4803  try_exit: NOTHING;
4804 
4805  //
4806  // Setup our share access and counts if things were successful.
4807  //
4808 
4809  if ((Iosb.Status != STATUS_PENDING) && NT_SUCCESS( Iosb.Status )) {
4810 
4811  //
4812  // Remove any virtual access the caller needed to check against, but will
4813  // not really receive. Overwrite/supersede is a bit of a special case.
4814  //
4815 
4816  ClearFlag( *DesiredAccess, AddedAccess );
4817 
4819  ShareAccess,
4820  FileObject,
4821  &(*Fcb)->ShareAccess );
4822 
4823  (*Fcb)->UncleanCount += 1;
4824  (*Fcb)->OpenCount += 1;
4826  (*Fcb)->NonCachedUncleanCount += 1;
4827  }
4828  Vcb->OpenFileCount += 1;
4829  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount += 1; }
4830 
4832  }
4833 
4834  {
4835  PCCB Ccb;
4836 
4837  Ccb = (PCCB)FileObject->FsContext2;
4838 
4839  if ( NT_SUCCESS(Iosb.Status) ) {
4840 
4841  //
4842  // Mark the DeleteOnClose bit if the operation was successful.
4843  //
4844 
4845  if ( DeleteOnClose ) {
4846 
4848  }
4849 
4850  //
4851  // Mark the OpenedByShortName bit if the operation was successful.
4852  //
4853 
4854  if ( FileNameOpenedDos ) {
4855 
4857  }
4858 
4859  //
4860  // Mark the ManageVolumeAccess bit if the privilege is held.
4861  //
4862 
4863  if (FatCheckManageVolumeAccess( IrpContext,
4864  IrpSp->Parameters.Create.SecurityContext->AccessState,
4866  UserMode :
4867  IrpContext->OriginatingIrp->RequestorMode ))) {
4868 
4870  }
4871 
4872  }
4873  }
4874 
4875 
4876  } _SEH2_FINALLY {
4877 
4878  DebugUnwind( FatOpenExistingFile );
4879 
4880  //
4881  // If this is an abnormal termination then undo our work
4882  //
4883 
4884  if (_SEH2_AbnormalTermination()) {
4885 
4886  if (CountsIncremented) {
4887  (*Fcb)->UncleanCount -= 1;
4888  (*Fcb)->OpenCount -= 1;
4890  (*Fcb)->NonCachedUncleanCount -= 1;
4891  }
4892  Vcb->OpenFileCount -= 1;
4893  if (IsFileObjectReadOnly(FileObject)) { Vcb->ReadOnlyCount -= 1; }
4894  }
4895 
4896  if (UnwindFcb != NULL) {
4897  if (ARGUMENT_PRESENT( FileObject )) {
4898  FileObject->SectionObjectPointer = NULL;
4899  }
4900  FatDeleteFcb( IrpContext, &UnwindFcb );
4901  *Fcb = NULL;
4902  }
4903 
4904  if (UnwindCcb != NULL) { FatDeleteCcb( IrpContext, &UnwindCcb ); }
4905  }
4906 
4907  DebugTrace(-1, Dbg, "FatOpenExistingFile -> Iosb.Status = %08lx\n", Iosb.Status);
4908  } _SEH2_END;
4909 
4910  return Iosb;
4911 }
4912 
4913 
4914 //
4915 // Internal support routine
4916 //
4917 
4918 _Requires_lock_held_(_Global_critical_region_)
4920 FatCreateNewDirectory (
4921  _In_ PIRP_CONTEXT IrpContext,
4924  _Inout_ PVCB Vcb,
4936  )
4937 
4938 /*++
4939 
4940 Routine Description:
4941 
4942  This routine creates a new directory. The directory has already been
4943  verified not to exist yet.
4944 
4945 Arguments:
4946 
4947  FileObject - Supplies the file object for the newly created directory
4948 
4949  Vcb - Supplies the Vcb denote the volume to contain the new directory
4950 
4951  ParentDcb - Supplies the parent directory containg the newly created
4952  directory
4953 
4954  OemName - Supplies the Oem name for the newly created directory. It may
4955  or maynot be 8.3 complient, but will be upcased.
4956 
4957  UnicodeName - Supplies the Unicode name for the newly created directory.
4958  It may or maynot be 8.3 complient. This name contains the original
4959  case information.
4960 
4961  DesiredAccess - Supplies the desired access of the caller
4962 
4963  ShareAccess - Supplies the shared access of the caller
4964 
4965  EaBuffer - Supplies the Ea set for the newly created directory
4966 
4967  EaLength - Supplies the length, in bytes, of EaBuffer
4968 
4969  FileAttributes - Supplies the file attributes for the newly created
4970  directory.
4971 
4972  NoEaKnowledge - This opener doesn't understand Ea's and we fail this
4973  open if the file has NeedEa's.
4974 
4975  DeleteOnClose - The caller wants the file gone when the handle is closed
4976 
4977  OpenRequiringOplock - The caller provided the FILE_OPEN_REQUIRING_OPLOCK option.
4978 
4979 Return Value:
4980 
4981  IO_STATUS_BLOCK - Returns the completion status for the operation
4982 
4983 --*/
4984 
4985 {
4987 
4988  PDCB Dcb = NULL;
4989  PCCB Ccb = NULL;
4990 
4991  PDIRENT Dirent = NULL;
4992  PBCB DirentBcb = NULL;
4995 
4996  PDIRENT ShortDirent;
4997  ULONG ShortDirentByteOffset;
4998 
4999  USHORT EaHandle;
5000 
5004 
5005  ULONG BytesInFirstPage = 0;
5006  ULONG DirentsInFirstPage = 0;
5007  PDIRENT FirstPageDirent = 0;
5008 
5009  PBCB SecondPageBcb = NULL;
5010  ULONG SecondPageOffset;
5011  PDIRENT SecondPageDirent = NULL;
5012 
5013  BOOLEAN DirentFromPool = FALSE;
5014 
5015 
5017  UCHAR ShortNameBuffer[12];
5018 
5019 #if (NTDDI_VERSION <= NTDDI_WIN7)
5021 #endif
5022 
5024 
5025  PAGED_CODE();
5026 
5027  DebugTrace(+1, Dbg, "FatCreateNewDirectory...\n", 0);
5028 
5029  ShortName.Length = 0;
5030  ShortName.MaximumLength = 12;
5031  ShortName.Buffer = (PCHAR)&ShortNameBuffer[0];
5032 
5033  EaHandle = 0;
5034 
5035  //
5036  // We fail this operation if the caller doesn't understand Ea's.
5037  //
5038 
5039  if (NoEaKnowledge
5040  && EaLength > 0) {
5041 
5042  Iosb.Status = STATUS_ACCESS_DENIED;
5043 
5044  DebugTrace(-1, Dbg, "FatCreateNewDirectory -> Iosb.Status = %08lx\n", Iosb.Status);
5045  return Iosb;
5046  }
5047 
5048  //
5049  // DeleteOnClose and ReadOnly are not compatible.
5050  //
5051 
5053 
5054  Iosb.Status = STATUS_CANNOT_DELETE;
5055  return Iosb;
5056  }
5057 
5058  // Now get the names that we will be using.
5059  //
5060 
5061  FatSelectNames( IrpContext,
5062  ParentDcb,
5063  OemName,
5064  UnicodeName,
5065  &ShortName,
5066  NULL,
5069  &CreateLfn );
5070 
5071  //
5072  // If we are not in Chicago mode, ignore the magic bits.
5073  //
5074 
5075  if (!FatData.ChicagoMode) {
5076 
5079  CreateLfn = FALSE;
5080  }
5081 
5082  //
5083  // Create/allocate a new dirent
5084  //
5085 
5087 
5088  DirentByteOffset = FatCreateNewDirent( IrpContext,
5089  ParentDcb,
5090  DirentsNeeded,
5091  FALSE );
5092  _SEH2_TRY {
5093 
5094  FatPrepareWriteDirectoryFile( IrpContext,
5095  ParentDcb,
5097  sizeof(DIRENT),
5098  &DirentBcb,
5099 #ifndef __REACTOS__
5100  &Dirent,
5101 #else
5102  (PVOID *)&Dirent,
5103 #endif
5104  FALSE,
5105  TRUE,
5106  &Iosb.Status );
5107 
5108  NT_ASSERT( NT_SUCCESS( Iosb.Status ) && DirentBcb && Dirent );
5109 
5110  //
5111  // Deal with the special case of an LFN + Dirent structure crossing
5112  // a page boundry.
5113  //
5114 
5115  if ((DirentByteOffset / PAGE_SIZE) !=
5116  ((DirentByteOffset + (DirentsNeeded - 1) * sizeof(DIRENT)) / PAGE_SIZE)) {
5117 
5118  SecondPageBcb;
5119  SecondPageOffset;
5120  SecondPageDirent;
5121 
5122  SecondPageOffset = (DirentByteOffset & ~(PAGE_SIZE - 1)) + PAGE_SIZE;
5123 
5124  BytesInFirstPage = SecondPageOffset - DirentByteOffset;
5125 
5126  DirentsInFirstPage = BytesInFirstPage / sizeof(DIRENT);
5127 
5128  FatPrepareWriteDirectoryFile( IrpContext,
5129  ParentDcb,
5130  SecondPageOffset,
5131  sizeof(DIRENT),
5132  &SecondPageBcb,
5133 #ifndef __REACTOS__
5134  &SecondPageDirent,
5135 #else
5136  (PVOID *)&SecondPageDirent,
5137 #endif
5138  FALSE,
5139  TRUE,
5140  &Iosb.Status );
5141 
5142  NT_ASSERT( NT_SUCCESS( Iosb.Status ) && SecondPageBcb && SecondPageDirent );
5143 
5144  FirstPageDirent = Dirent;
5145 
5147  DirentsNeeded * sizeof(DIRENT),
5148  TAG_DIRENT );
5149 
5150  DirentFromPool = TRUE;
5151  }
5152 
5153  //
5154  // Bump up Dirent and DirentByteOffset
5155  //
5156 
5157  ShortDirent = Dirent + DirentsNeeded - 1;
5158  ShortDirentByteOffset = DirentByteOffset +
5159  (DirentsNeeded - 1) * sizeof(DIRENT);
5160 
5161  NT_ASSERT( NT_SUCCESS( Iosb.Status ));
5162 
5163 
5164  //
5165  // Fill in the fields of the dirent.
5166  //
5167 
5168  FatConstructDirent( IrpContext,
5169  ShortDirent,
5170  &ShortName,
5175  TRUE,
5176  NULL );