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