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)
_Function_class_(DRIVER_DISPATCH)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)
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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)
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
_Requires_lock_held_(_Global_critical_region_)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
FatSetFullNameInFcb(_In_ PIRP_CONTEXT IrpContext,_Inout_ PFCB Fcb,_In_ PUNICODE_STRING FinalName)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
FatCheckSystemSecurityAccess(_In_ PIRP_CONTEXT IrpContext)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
FatCheckShareAccess(_In_ PIRP_CONTEXT IrpContext,_In_ PFILE_OBJECT FileObject,_In_ PFCB FcbOrDcb,_In_ PACCESS_MASK DesiredAccess,_In_ ULONG ShareAccess)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
FatCallSelfCompletionRoutine(__in PDEVICE_OBJECT DeviceObject,__in PIRP Irp,__in PVOID Contxt)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