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