3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 * PROJECT: ReactOS kernel
21 * FILE: drivers/filesystems/fastfat/create.c
22 * PURPOSE: VFAT Filesystem
23 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
24 * Pierre Schweitzer (pierre@reactos.org)
27 /* INCLUDES *****************************************************************/
34 /* FUNCTIONS *****************************************************************/
38 PFAT_DIR_ENTRY pEntry
,
39 PUNICODE_STRING NameU
)
45 RtlCopyMemory(cString
, pEntry
->ShortName
, 11);
47 if (cString
[0] == 0x05)
52 StringA
.Buffer
= cString
;
53 for (StringA
.Length
= 0;
54 StringA
.Length
< 8 && StringA
.Buffer
[StringA
.Length
] != ' ';
56 StringA
.MaximumLength
= StringA
.Length
;
58 RtlOemStringToUnicodeString(NameU
, &StringA
, FALSE
);
60 if (BooleanFlagOn(pEntry
->lCase
, VFAT_CASE_LOWER_BASE
))
62 RtlDowncaseUnicodeString(NameU
, NameU
, FALSE
);
65 if (cString
[8] != ' ')
67 Length
= NameU
->Length
;
68 NameU
->Buffer
+= Length
/ sizeof(WCHAR
);
69 if (!FAT_ENTRY_VOLUME(pEntry
))
71 Length
+= sizeof(WCHAR
);
72 NameU
->Buffer
[0] = L
'.';
76 NameU
->MaximumLength
-= Length
;
78 StringA
.Buffer
= &cString
[8];
79 for (StringA
.Length
= 0;
80 StringA
.Length
< 3 && StringA
.Buffer
[StringA
.Length
] != ' ';
82 StringA
.MaximumLength
= StringA
.Length
;
83 RtlOemStringToUnicodeString(NameU
, &StringA
, FALSE
);
84 if (BooleanFlagOn(pEntry
->lCase
, VFAT_CASE_LOWER_EXT
))
86 RtlDowncaseUnicodeString(NameU
, NameU
, FALSE
);
88 NameU
->Buffer
-= Length
/ sizeof(WCHAR
);
89 NameU
->Length
+= Length
;
90 NameU
->MaximumLength
+= Length
;
93 NameU
->Buffer
[NameU
->Length
/ sizeof(WCHAR
)] = 0;
94 DPRINT("'%wZ'\n", NameU
);
98 * FUNCTION: Find a file
102 PDEVICE_EXTENSION DeviceExt
,
104 PUNICODE_STRING FileToFindU
,
105 PVFAT_DIRENTRY_CONTEXT DirContext
,
108 PWCHAR PathNameBuffer
;
109 USHORT PathNameBufferLength
;
111 PVOID Context
= NULL
;
115 UNICODE_STRING PathNameU
;
116 UNICODE_STRING FileToFindUpcase
;
118 BOOLEAN IsFatX
= vfatVolumeIsFatX(DeviceExt
);
120 DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n",
121 Parent
, FileToFindU
, DirContext
->DirIndex
);
122 DPRINT("FindFile: Path %wZ\n",&Parent
->PathNameU
);
124 PathNameBufferLength
= LONGNAME_MAX_LENGTH
* sizeof(WCHAR
);
125 PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameBufferLength
+ sizeof(WCHAR
), TAG_NAME
);
128 return STATUS_INSUFFICIENT_RESOURCES
;
131 PathNameU
.Buffer
= PathNameBuffer
;
132 PathNameU
.Length
= 0;
133 PathNameU
.MaximumLength
= PathNameBufferLength
;
135 DirContext
->LongNameU
.Length
= 0;
136 DirContext
->ShortNameU
.Length
= 0;
138 WildCard
= FsRtlDoesNameContainWildCards(FileToFindU
);
140 if (WildCard
== FALSE
)
142 /* if there is no '*?' in the search name, than look first for an existing fcb */
143 RtlCopyUnicodeString(&PathNameU
, &Parent
->PathNameU
);
144 if (!vfatFCBIsRoot(Parent
))
146 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = L
'\\';
147 PathNameU
.Length
+= sizeof(WCHAR
);
149 RtlAppendUnicodeStringToString(&PathNameU
, FileToFindU
);
150 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = 0;
151 rcFcb
= vfatGrabFCBFromTable(DeviceExt
, &PathNameU
);
154 ULONG startIndex
= rcFcb
->startIndex
;
155 if (IsFatX
&& !vfatFCBIsRoot(Parent
))
159 if(startIndex
>= DirContext
->DirIndex
)
161 RtlCopyUnicodeString(&DirContext
->LongNameU
, &rcFcb
->LongNameU
);
162 RtlCopyUnicodeString(&DirContext
->ShortNameU
, &rcFcb
->ShortNameU
);
163 RtlCopyMemory(&DirContext
->DirEntry
, &rcFcb
->entry
, sizeof(DIR_ENTRY
));
164 DirContext
->StartIndex
= rcFcb
->startIndex
;
165 DirContext
->DirIndex
= rcFcb
->dirIndex
;
166 DPRINT("FindFile: new Name %wZ, DirIndex %u (%u)\n",
167 &DirContext
->LongNameU
, DirContext
->DirIndex
, DirContext
->StartIndex
);
168 Status
= STATUS_SUCCESS
;
172 DPRINT("FCB not found for %wZ\n", &PathNameU
);
173 Status
= STATUS_UNSUCCESSFUL
;
175 vfatReleaseFCB(DeviceExt
, rcFcb
);
176 ExFreePoolWithTag(PathNameBuffer
, TAG_NAME
);
181 /* FsRtlIsNameInExpression need the searched string to be upcase,
182 * even if IgnoreCase is specified */
183 Status
= RtlUpcaseUnicodeString(&FileToFindUpcase
, FileToFindU
, TRUE
);
184 if (!NT_SUCCESS(Status
))
186 ExFreePoolWithTag(PathNameBuffer
, TAG_NAME
);
192 Status
= VfatGetNextDirEntry(DeviceExt
, &Context
, &Page
, Parent
, DirContext
, First
);
194 if (Status
== STATUS_NO_MORE_ENTRIES
)
198 if (ENTRY_VOLUME(IsFatX
, &DirContext
->DirEntry
))
200 DirContext
->DirIndex
++;
203 if (DirContext
->LongNameU
.Length
== 0 ||
204 DirContext
->ShortNameU
.Length
== 0)
206 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
207 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
209 ASSERT(DirContext
->LongNameU
.Length
!= 0 &&
210 DirContext
->ShortNameU
.Length
!= 0);
212 DirContext
->DirIndex
++;
217 Found
= FsRtlIsNameInExpression(&FileToFindUpcase
, &DirContext
->LongNameU
, TRUE
, NULL
) ||
218 FsRtlIsNameInExpression(&FileToFindUpcase
, &DirContext
->ShortNameU
, TRUE
, NULL
);
222 Found
= FsRtlAreNamesEqual(&DirContext
->LongNameU
, FileToFindU
, TRUE
, NULL
) ||
223 FsRtlAreNamesEqual(&DirContext
->ShortNameU
, FileToFindU
, TRUE
, NULL
);
230 RtlCopyUnicodeString(&PathNameU
, &Parent
->PathNameU
);
231 if (!vfatFCBIsRoot(Parent
))
233 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = L
'\\';
234 PathNameU
.Length
+= sizeof(WCHAR
);
236 RtlAppendUnicodeStringToString(&PathNameU
, &DirContext
->LongNameU
);
237 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = 0;
238 rcFcb
= vfatGrabFCBFromTable(DeviceExt
, &PathNameU
);
241 RtlCopyMemory(&DirContext
->DirEntry
, &rcFcb
->entry
, sizeof(DIR_ENTRY
));
242 vfatReleaseFCB(DeviceExt
, rcFcb
);
245 DPRINT("%u\n", DirContext
->LongNameU
.Length
);
246 DPRINT("FindFile: new Name %wZ, DirIndex %u\n",
247 &DirContext
->LongNameU
, DirContext
->DirIndex
);
251 CcUnpinData(Context
);
253 RtlFreeUnicodeString(&FileToFindUpcase
);
254 ExFreePoolWithTag(PathNameBuffer
, TAG_NAME
);
255 return STATUS_SUCCESS
;
257 DirContext
->DirIndex
++;
262 CcUnpinData(Context
);
265 RtlFreeUnicodeString(&FileToFindUpcase
);
266 ExFreePoolWithTag(PathNameBuffer
, TAG_NAME
);
271 * FUNCTION: Opens a file
276 PDEVICE_EXTENSION DeviceExt
,
277 PUNICODE_STRING PathNameU
,
278 PFILE_OBJECT FileObject
,
279 ULONG RequestedDisposition
,
280 ULONG RequestedOptions
,
286 DPRINT("VfatOpenFile(%p, '%wZ', %p, %p)\n", DeviceExt
, PathNameU
, FileObject
, ParentFcb
);
288 if (FileObject
->RelatedFileObject
)
290 DPRINT("'%wZ'\n", &FileObject
->RelatedFileObject
->FileName
);
292 *ParentFcb
= FileObject
->RelatedFileObject
->FsContext
;
299 if (!DeviceExt
->FatInfo
.FixedMedia
)
301 Status
= VfatBlockDeviceIoControl(DeviceExt
->StorageDevice
,
302 IOCTL_DISK_CHECK_VERIFY
,
308 if (!NT_SUCCESS(Status
))
310 DPRINT("Status %lx\n", Status
);
318 vfatGrabFCB(DeviceExt
, *ParentFcb
);
321 /* try first to find an existing FCB in memory */
322 DPRINT("Checking for existing FCB in memory\n");
324 Status
= vfatGetFCBForFile(DeviceExt
, ParentFcb
, &Fcb
, PathNameU
);
325 if (!NT_SUCCESS(Status
))
327 DPRINT ("Could not make a new FCB, status: %x\n", Status
);
331 /* Fail, if we try to overwrite an existing directory */
332 if ((!BooleanFlagOn(RequestedOptions
, FILE_DIRECTORY_FILE
) && vfatFCBIsDirectory(Fcb
)) &&
333 (RequestedDisposition
== FILE_OVERWRITE
||
334 RequestedDisposition
== FILE_OVERWRITE_IF
||
335 RequestedDisposition
== FILE_SUPERSEDE
))
337 vfatReleaseFCB(DeviceExt
, Fcb
);
338 return STATUS_OBJECT_NAME_COLLISION
;
341 if (BooleanFlagOn(Fcb
->Flags
, FCB_DELETE_PENDING
))
343 vfatReleaseFCB(DeviceExt
, Fcb
);
344 return STATUS_DELETE_PENDING
;
347 /* Fail, if we try to overwrite a read-only file */
348 if (vfatFCBIsReadOnly(Fcb
) &&
349 (RequestedDisposition
== FILE_OVERWRITE
||
350 RequestedDisposition
== FILE_OVERWRITE_IF
))
352 vfatReleaseFCB(DeviceExt
, Fcb
);
353 return STATUS_ACCESS_DENIED
;
356 if (vfatFCBIsReadOnly(Fcb
) &&
357 (RequestedOptions
& FILE_DELETE_ON_CLOSE
))
359 vfatReleaseFCB(DeviceExt
, Fcb
);
360 return STATUS_CANNOT_DELETE
;
363 if ((vfatFCBIsRoot(Fcb
) ||
364 (Fcb
->LongNameU
.Length
== sizeof(WCHAR
) && Fcb
->LongNameU
.Buffer
[0] == L
'.') ||
365 (Fcb
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && Fcb
->LongNameU
.Buffer
[0] == L
'.' && Fcb
->LongNameU
.Buffer
[1] == L
'.')) &&
366 BooleanFlagOn(RequestedOptions
, FILE_DELETE_ON_CLOSE
))
368 // we cannot delete a '.', '..' or the root directory
369 vfatReleaseFCB(DeviceExt
, Fcb
);
370 return STATUS_CANNOT_DELETE
;
373 /* If that one was marked for closing, remove it */
374 if (BooleanFlagOn(Fcb
->Flags
, FCB_DELAYED_CLOSE
))
376 BOOLEAN ConcurrentDeletion
;
377 PVFAT_CLOSE_CONTEXT CloseContext
;
379 /* Get the context */
380 CloseContext
= Fcb
->CloseContext
;
381 /* Is someone already taking over? */
382 if (CloseContext
!= NULL
)
384 ConcurrentDeletion
= FALSE
;
386 ExAcquireFastMutex(&VfatGlobalData
->CloseMutex
);
387 /* Check whether it was already removed, if not, do it */
388 if (!IsListEmpty(&CloseContext
->CloseListEntry
))
390 RemoveEntryList(&CloseContext
->CloseListEntry
);
391 --VfatGlobalData
->CloseCount
;
392 ConcurrentDeletion
= TRUE
;
394 ExReleaseFastMutex(&VfatGlobalData
->CloseMutex
);
396 /* It's not delayed anymore! */
397 ClearFlag(Fcb
->Flags
, FCB_DELAYED_CLOSE
);
398 /* Release the extra reference (would have been removed by IRP_MJ_CLOSE) */
399 vfatReleaseFCB(DeviceExt
, Fcb
);
400 Fcb
->CloseContext
= NULL
;
401 /* If no concurrent deletion, free work item */
402 if (!ConcurrentDeletion
)
404 ExFreeToPagedLookasideList(&VfatGlobalData
->CloseContextLookasideList
, CloseContext
);
408 DPRINT("Reusing delayed close FCB for %wZ\n", &Fcb
->PathNameU
);
411 DPRINT("Attaching FCB to fileObject\n");
412 Status
= vfatAttachFCBToFileObject(DeviceExt
, Fcb
, FileObject
);
413 if (!NT_SUCCESS(Status
))
415 vfatReleaseFCB(DeviceExt
, Fcb
);
421 * FUNCTION: Create or open a file
425 PDEVICE_OBJECT DeviceObject
,
428 PIO_STACK_LOCATION Stack
;
429 PFILE_OBJECT FileObject
;
430 NTSTATUS Status
= STATUS_SUCCESS
;
431 PDEVICE_EXTENSION DeviceExt
;
432 ULONG RequestedDisposition
, RequestedOptions
;
433 PVFATFCB pFcb
= NULL
;
434 PVFATFCB ParentFcb
= NULL
;
435 PVFATCCB pCcb
= NULL
;
437 BOOLEAN PagingFileCreate
;
439 BOOLEAN OpenTargetDir
;
440 BOOLEAN TrailingBackslash
;
441 UNICODE_STRING FileNameU
;
442 UNICODE_STRING PathNameU
;
445 /* Unpack the various parameters. */
446 Stack
= IoGetCurrentIrpStackLocation(Irp
);
447 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>> 24) & 0xff);
448 RequestedOptions
= Stack
->Parameters
.Create
.Options
& FILE_VALID_OPTION_FLAGS
;
449 PagingFileCreate
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_PAGING_FILE
);
450 OpenTargetDir
= BooleanFlagOn(Stack
->Flags
, SL_OPEN_TARGET_DIRECTORY
);
452 FileObject
= Stack
->FileObject
;
453 DeviceExt
= DeviceObject
->DeviceExtension
;
455 if (BooleanFlagOn(Stack
->Parameters
.Create
.Options
, FILE_OPEN_BY_FILE_ID
))
457 return STATUS_NOT_IMPLEMENTED
;
460 /* Check their validity. */
461 if (BooleanFlagOn(RequestedOptions
, FILE_DIRECTORY_FILE
) &&
462 RequestedDisposition
== FILE_SUPERSEDE
)
464 return STATUS_INVALID_PARAMETER
;
467 if (BooleanFlagOn(RequestedOptions
, FILE_DIRECTORY_FILE
) &&
468 BooleanFlagOn(RequestedOptions
, FILE_NON_DIRECTORY_FILE
))
470 return STATUS_INVALID_PARAMETER
;
473 /* Deny create if the volume is locked */
474 if (BooleanFlagOn(DeviceExt
->Flags
, VCB_VOLUME_LOCKED
))
476 return STATUS_ACCESS_DENIED
;
479 /* This a open operation for the volume itself */
480 if (FileObject
->FileName
.Length
== 0 &&
481 (FileObject
->RelatedFileObject
== NULL
||
482 FileObject
->RelatedFileObject
->FsContext2
!= NULL
||
483 FileObject
->RelatedFileObject
->FsContext
== DeviceExt
->VolumeFcb
))
485 DPRINT("Volume opening\n");
487 if (RequestedDisposition
!= FILE_OPEN
&&
488 RequestedDisposition
!= FILE_OPEN_IF
)
490 return STATUS_ACCESS_DENIED
;
493 if (BooleanFlagOn(RequestedOptions
, FILE_DIRECTORY_FILE
) &&
494 (FileObject
->RelatedFileObject
== NULL
|| FileObject
->RelatedFileObject
->FsContext2
== NULL
|| FileObject
->RelatedFileObject
->FsContext
== DeviceExt
->VolumeFcb
))
496 return STATUS_NOT_A_DIRECTORY
;
501 return STATUS_INVALID_PARAMETER
;
504 if (BooleanFlagOn(RequestedOptions
, FILE_DELETE_ON_CLOSE
))
506 return STATUS_CANNOT_DELETE
;
509 vfatAddToStat(DeviceExt
, Fat
.CreateHits
, 1);
511 pFcb
= DeviceExt
->VolumeFcb
;
513 if (pFcb
->OpenHandleCount
== 0)
515 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
516 Stack
->Parameters
.Create
.ShareAccess
,
518 &pFcb
->FCBShareAccess
);
522 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
523 Stack
->Parameters
.Create
.ShareAccess
,
525 &pFcb
->FCBShareAccess
,
527 if (!NT_SUCCESS(Status
))
529 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
534 vfatAttachFCBToFileObject(DeviceExt
, pFcb
, FileObject
);
535 DeviceExt
->OpenHandleCount
++;
536 pFcb
->OpenHandleCount
++;
537 vfatAddToStat(DeviceExt
, Fat
.SuccessfulCreates
, 1);
539 Irp
->IoStatus
.Information
= FILE_OPENED
;
540 return STATUS_SUCCESS
;
543 if (FileObject
->RelatedFileObject
!= NULL
&&
544 FileObject
->RelatedFileObject
->FsContext
== DeviceExt
->VolumeFcb
)
546 ASSERT(FileObject
->FileName
.Length
!= 0);
547 return STATUS_OBJECT_PATH_NOT_FOUND
;
550 /* Check for illegal characters and illegal dot sequences in the file name */
551 PathNameU
= FileObject
->FileName
;
552 c
= PathNameU
.Buffer
+ PathNameU
.Length
/ sizeof(WCHAR
);
556 while (c
-- > PathNameU
.Buffer
)
558 if (*c
== L
'\\' || c
== PathNameU
.Buffer
)
560 if (Dots
&& last
> c
)
562 return STATUS_OBJECT_NAME_INVALID
;
564 if (*c
== L
'\\' && (c
- 1) > PathNameU
.Buffer
&&
567 return STATUS_OBJECT_NAME_INVALID
;
578 if (*c
!= '\\' && vfatIsLongIllegal(*c
))
580 return STATUS_OBJECT_NAME_INVALID
;
584 /* Check if we try to open target directory of root dir */
585 if (OpenTargetDir
&& FileObject
->RelatedFileObject
== NULL
&& PathNameU
.Length
== sizeof(WCHAR
) &&
586 PathNameU
.Buffer
[0] == L
'\\')
588 return STATUS_INVALID_PARAMETER
;
591 if (FileObject
->RelatedFileObject
&& PathNameU
.Length
>= sizeof(WCHAR
) && PathNameU
.Buffer
[0] == L
'\\')
593 return STATUS_OBJECT_NAME_INVALID
;
596 TrailingBackslash
= FALSE
;
597 if (PathNameU
.Length
> sizeof(WCHAR
) && PathNameU
.Buffer
[PathNameU
.Length
/sizeof(WCHAR
)-1] == L
'\\')
599 PathNameU
.Length
-= sizeof(WCHAR
);
600 TrailingBackslash
= TRUE
;
603 if (PathNameU
.Length
> sizeof(WCHAR
) && PathNameU
.Buffer
[PathNameU
.Length
/sizeof(WCHAR
)-1] == L
'\\')
605 return STATUS_OBJECT_NAME_INVALID
;
608 /* Try opening the file. */
611 vfatAddToStat(DeviceExt
, Fat
.CreateHits
, 1);
613 Status
= VfatOpenFile(DeviceExt
, &PathNameU
, FileObject
, RequestedDisposition
, RequestedOptions
, &ParentFcb
);
618 LONG idx
, FileNameLen
;
620 vfatAddToStat(DeviceExt
, Fat
.CreateHits
, 1);
622 ParentFcb
= (FileObject
->RelatedFileObject
!= NULL
) ? FileObject
->RelatedFileObject
->FsContext
: NULL
;
625 vfatGrabFCB(DeviceExt
, ParentFcb
);
628 Status
= vfatGetFCBForFile(DeviceExt
, &ParentFcb
, &TargetFcb
, &PathNameU
);
629 if (NT_SUCCESS(Status
))
631 vfatReleaseFCB(DeviceExt
, TargetFcb
);
632 Irp
->IoStatus
.Information
= FILE_EXISTS
;
636 Irp
->IoStatus
.Information
= FILE_DOES_NOT_EXIST
;
639 idx
= FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1;
641 /* Skip trailing \ - if any */
642 if (PathNameU
.Buffer
[idx
] == L
'\\')
645 PathNameU
.Length
-= sizeof(WCHAR
);
649 while (idx
>= 0 && PathNameU
.Buffer
[idx
] != L
'\\')
654 if (idx
> 0 || PathNameU
.Buffer
[0] == L
'\\')
656 /* We don't want to include / in the name */
657 FileNameLen
= PathNameU
.Length
- ((idx
+ 1) * sizeof(WCHAR
));
659 /* Update FO just to keep file name */
660 /* Skip first slash */
662 FileObject
->FileName
.Length
= FileNameLen
;
663 RtlMoveMemory(&PathNameU
.Buffer
[0], &PathNameU
.Buffer
[idx
], FileObject
->FileName
.Length
);
665 /* Terminate the string at the last backslash */
666 PathNameU
.Buffer
[idx
+ 1] = UNICODE_NULL
;
667 PathNameU
.Length
= (idx
+ 1) * sizeof(WCHAR
);
668 PathNameU
.MaximumLength
= PathNameU
.Length
+ sizeof(WCHAR
);
670 /* Update the file object as well */
671 FileObject
->FileName
.Length
= PathNameU
.Length
;
672 FileObject
->FileName
.MaximumLength
= PathNameU
.MaximumLength
;
677 /* This is a relative open and we have only the filename, so open the parent directory
678 * It is in RelatedFileObject
680 ASSERT(FileObject
->RelatedFileObject
!= NULL
);
682 /* No need to modify the FO, it already has the name */
685 /* We're done with opening! */
686 if (ParentFcb
!= NULL
)
688 Status
= vfatAttachFCBToFileObject(DeviceExt
, ParentFcb
, FileObject
);
691 if (NT_SUCCESS(Status
))
693 pFcb
= FileObject
->FsContext
;
694 ASSERT(pFcb
== ParentFcb
);
696 if (pFcb
->OpenHandleCount
== 0)
698 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
699 Stack
->Parameters
.Create
.ShareAccess
,
701 &pFcb
->FCBShareAccess
);
705 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
706 Stack
->Parameters
.Create
.ShareAccess
,
708 &pFcb
->FCBShareAccess
,
710 if (!NT_SUCCESS(Status
))
712 VfatCloseFile(DeviceExt
, FileObject
);
713 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
718 pCcb
= FileObject
->FsContext2
;
719 if (BooleanFlagOn(RequestedOptions
, FILE_DELETE_ON_CLOSE
))
721 pCcb
->Flags
|= CCB_DELETE_ON_CLOSE
;
724 pFcb
->OpenHandleCount
++;
725 DeviceExt
->OpenHandleCount
++;
727 else if (ParentFcb
!= NULL
)
729 vfatReleaseFCB(DeviceExt
, ParentFcb
);
732 if (NT_SUCCESS(Status
))
734 vfatAddToStat(DeviceExt
, Fat
.SuccessfulCreates
, 1);
738 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
745 * If the directory containing the file to open doesn't exist then
748 if (Status
== STATUS_OBJECT_PATH_NOT_FOUND
||
749 Status
== STATUS_INVALID_PARAMETER
||
750 Status
== STATUS_DELETE_PENDING
||
751 Status
== STATUS_ACCESS_DENIED
||
752 Status
== STATUS_OBJECT_NAME_COLLISION
)
756 vfatReleaseFCB(DeviceExt
, ParentFcb
);
758 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
762 if (!NT_SUCCESS(Status
) && ParentFcb
== NULL
)
764 DPRINT1("VfatOpenFile failed for '%wZ', status %x\n", &PathNameU
, Status
);
765 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
769 Attributes
= (Stack
->Parameters
.Create
.FileAttributes
& (FILE_ATTRIBUTE_ARCHIVE
|
770 FILE_ATTRIBUTE_SYSTEM
|
771 FILE_ATTRIBUTE_HIDDEN
|
772 FILE_ATTRIBUTE_DIRECTORY
|
773 FILE_ATTRIBUTE_READONLY
));
775 /* If the file open failed then create the required file */
776 if (!NT_SUCCESS (Status
))
778 if (RequestedDisposition
== FILE_CREATE
||
779 RequestedDisposition
== FILE_OPEN_IF
||
780 RequestedDisposition
== FILE_OVERWRITE_IF
||
781 RequestedDisposition
== FILE_SUPERSEDE
)
783 if (!BooleanFlagOn(RequestedOptions
, FILE_DIRECTORY_FILE
))
785 if (TrailingBackslash
)
787 vfatReleaseFCB(DeviceExt
, ParentFcb
);
788 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
789 return STATUS_OBJECT_NAME_INVALID
;
791 Attributes
|= FILE_ATTRIBUTE_ARCHIVE
;
793 vfatSplitPathName(&PathNameU
, NULL
, &FileNameU
);
794 Status
= VfatAddEntry(DeviceExt
, &FileNameU
, &pFcb
, ParentFcb
, RequestedOptions
,
796 vfatReleaseFCB(DeviceExt
, ParentFcb
);
797 if (NT_SUCCESS(Status
))
799 Status
= vfatAttachFCBToFileObject(DeviceExt
, pFcb
, FileObject
);
800 if (!NT_SUCCESS(Status
))
802 vfatReleaseFCB(DeviceExt
, pFcb
);
803 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
807 Irp
->IoStatus
.Information
= FILE_CREATED
;
808 VfatSetAllocationSizeInformation(FileObject
,
811 &Irp
->Overlay
.AllocationSize
);
812 VfatSetExtendedAttributes(FileObject
,
813 Irp
->AssociatedIrp
.SystemBuffer
,
814 Stack
->Parameters
.Create
.EaLength
);
816 if (PagingFileCreate
)
818 pFcb
->Flags
|= FCB_IS_PAGE_FILE
;
819 SetFlag(DeviceExt
->Flags
, VCB_IS_SYS_OR_HAS_PAGE
);
824 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
830 vfatReleaseFCB(DeviceExt
, ParentFcb
);
831 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
839 vfatReleaseFCB(DeviceExt
, ParentFcb
);
842 pFcb
= FileObject
->FsContext
;
844 /* Otherwise fail if the caller wanted to create a new file */
845 if (RequestedDisposition
== FILE_CREATE
)
847 VfatCloseFile(DeviceExt
, FileObject
);
848 if (TrailingBackslash
&& !vfatFCBIsDirectory(pFcb
))
850 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
851 return STATUS_OBJECT_NAME_INVALID
;
853 Irp
->IoStatus
.Information
= FILE_EXISTS
;
854 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
855 return STATUS_OBJECT_NAME_COLLISION
;
858 if (pFcb
->OpenHandleCount
!= 0)
860 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
861 Stack
->Parameters
.Create
.ShareAccess
,
863 &pFcb
->FCBShareAccess
,
865 if (!NT_SUCCESS(Status
))
867 VfatCloseFile(DeviceExt
, FileObject
);
868 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
874 * Check the file has the requested attributes
876 if (BooleanFlagOn(RequestedOptions
, FILE_NON_DIRECTORY_FILE
) &&
877 vfatFCBIsDirectory(pFcb
))
879 VfatCloseFile (DeviceExt
, FileObject
);
880 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
881 return STATUS_FILE_IS_A_DIRECTORY
;
883 if (BooleanFlagOn(RequestedOptions
, FILE_DIRECTORY_FILE
) &&
884 !vfatFCBIsDirectory(pFcb
))
886 VfatCloseFile (DeviceExt
, FileObject
);
887 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
888 return STATUS_NOT_A_DIRECTORY
;
890 if (TrailingBackslash
&& !vfatFCBIsDirectory(pFcb
))
892 VfatCloseFile (DeviceExt
, FileObject
);
893 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
894 return STATUS_OBJECT_NAME_INVALID
;
896 #ifndef USE_ROS_CC_AND_FS
897 if (!vfatFCBIsDirectory(pFcb
))
899 if (BooleanFlagOn(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
, FILE_WRITE_DATA
) ||
900 RequestedDisposition
== FILE_OVERWRITE
||
901 RequestedDisposition
== FILE_OVERWRITE_IF
||
902 (RequestedOptions
& FILE_DELETE_ON_CLOSE
))
904 if (!MmFlushImageSection(&pFcb
->SectionObjectPointers
, MmFlushForWrite
))
906 DPRINT1("%wZ\n", &pFcb
->PathNameU
);
907 DPRINT1("%d %d %d\n", Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_WRITE_DATA
,
908 RequestedDisposition
== FILE_OVERWRITE
, RequestedDisposition
== FILE_OVERWRITE_IF
);
909 VfatCloseFile (DeviceExt
, FileObject
);
910 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
911 return (BooleanFlagOn(RequestedOptions
, FILE_DELETE_ON_CLOSE
)) ? STATUS_CANNOT_DELETE
912 : STATUS_SHARING_VIOLATION
;
917 if (PagingFileCreate
)
920 * Do more checking for page files. It is possible,
921 * that the file was opened and closed previously
922 * as a normal cached file. In this case, the cache
923 * manager has referenced the fileobject and the fcb
924 * is held in memory. Try to remove the fileobject
925 * from cache manager and use the fcb.
927 if (pFcb
->RefCount
> 1)
929 if(!BooleanFlagOn(pFcb
->Flags
, FCB_IS_PAGE_FILE
))
931 VfatCloseFile(DeviceExt
, FileObject
);
932 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
933 return STATUS_INVALID_PARAMETER
;
938 pFcb
->Flags
|= FCB_IS_PAGE_FILE
;
939 SetFlag(DeviceExt
->Flags
, VCB_IS_SYS_OR_HAS_PAGE
);
944 if (BooleanFlagOn(pFcb
->Flags
, FCB_IS_PAGE_FILE
))
946 VfatCloseFile(DeviceExt
, FileObject
);
947 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
948 return STATUS_INVALID_PARAMETER
;
952 if (RequestedDisposition
== FILE_OVERWRITE
||
953 RequestedDisposition
== FILE_OVERWRITE_IF
||
954 RequestedDisposition
== FILE_SUPERSEDE
)
956 if ((BooleanFlagOn(*pFcb
->Attributes
, FILE_ATTRIBUTE_HIDDEN
) && !BooleanFlagOn(Attributes
, FILE_ATTRIBUTE_HIDDEN
)) ||
957 (BooleanFlagOn(*pFcb
->Attributes
, FILE_ATTRIBUTE_SYSTEM
) && !BooleanFlagOn(Attributes
, FILE_ATTRIBUTE_SYSTEM
)))
959 VfatCloseFile(DeviceExt
, FileObject
);
960 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
961 return STATUS_ACCESS_DENIED
;
964 if (!vfatFCBIsDirectory(pFcb
))
966 LARGE_INTEGER SystemTime
;
968 if (RequestedDisposition
== FILE_SUPERSEDE
)
970 *pFcb
->Attributes
= Attributes
;
974 *pFcb
->Attributes
|= Attributes
;
976 *pFcb
->Attributes
|= FILE_ATTRIBUTE_ARCHIVE
;
978 KeQuerySystemTime(&SystemTime
);
979 if (vfatVolumeIsFatX(DeviceExt
))
981 FsdSystemTimeToDosDateTime(DeviceExt
,
982 &SystemTime
, &pFcb
->entry
.FatX
.UpdateDate
,
983 &pFcb
->entry
.FatX
.UpdateTime
);
987 FsdSystemTimeToDosDateTime(DeviceExt
,
988 &SystemTime
, &pFcb
->entry
.Fat
.UpdateDate
,
989 &pFcb
->entry
.Fat
.UpdateTime
);
992 VfatUpdateEntry(DeviceExt
, pFcb
);
995 ExAcquireResourceExclusiveLite(&(pFcb
->MainResource
), TRUE
);
996 Status
= VfatSetAllocationSizeInformation(FileObject
,
999 &Irp
->Overlay
.AllocationSize
);
1000 ExReleaseResourceLite(&(pFcb
->MainResource
));
1001 if (!NT_SUCCESS (Status
))
1003 VfatCloseFile(DeviceExt
, FileObject
);
1004 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
1009 if (RequestedDisposition
== FILE_SUPERSEDE
)
1011 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
1013 else if (RequestedDisposition
== FILE_OVERWRITE
||
1014 RequestedDisposition
== FILE_OVERWRITE_IF
)
1016 Irp
->IoStatus
.Information
= FILE_OVERWRITTEN
;
1020 Irp
->IoStatus
.Information
= FILE_OPENED
;
1024 if (pFcb
->OpenHandleCount
== 0)
1026 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
1027 Stack
->Parameters
.Create
.ShareAccess
,
1029 &pFcb
->FCBShareAccess
);
1033 IoUpdateShareAccess(FileObject
,
1034 &pFcb
->FCBShareAccess
);
1037 pCcb
= FileObject
->FsContext2
;
1038 if (BooleanFlagOn(RequestedOptions
, FILE_DELETE_ON_CLOSE
))
1040 pCcb
->Flags
|= CCB_DELETE_ON_CLOSE
;
1043 if (Irp
->IoStatus
.Information
== FILE_CREATED
)
1045 vfatReportChange(DeviceExt
,
1047 (vfatFCBIsDirectory(pFcb
) ?
1048 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
1051 else if (Irp
->IoStatus
.Information
== FILE_OVERWRITTEN
||
1052 Irp
->IoStatus
.Information
== FILE_SUPERSEDED
)
1054 vfatReportChange(DeviceExt
,
1056 FILE_NOTIFY_CHANGE_LAST_WRITE
| FILE_NOTIFY_CHANGE_ATTRIBUTES
| FILE_NOTIFY_CHANGE_SIZE
,
1057 FILE_ACTION_MODIFIED
);
1060 pFcb
->OpenHandleCount
++;
1061 DeviceExt
->OpenHandleCount
++;
1063 /* FIXME : test write access if requested */
1065 /* FIXME: That is broken, we cannot reach this code path with failure */
1066 ASSERT(NT_SUCCESS(Status
));
1067 if (NT_SUCCESS(Status
))
1069 vfatAddToStat(DeviceExt
, Fat
.SuccessfulCreates
, 1);
1073 vfatAddToStat(DeviceExt
, Fat
.FailedCreates
, 1);
1080 * FUNCTION: Create or open a file
1084 PVFAT_IRP_CONTEXT IrpContext
)
1090 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
1092 /* DeviceObject represents FileSystem instead of logical volume */
1093 DPRINT ("FsdCreate called with file system\n");
1094 IrpContext
->Irp
->IoStatus
.Information
= FILE_OPENED
;
1095 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
1097 return STATUS_SUCCESS
;
1100 IrpContext
->Irp
->IoStatus
.Information
= 0;
1101 ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
, TRUE
);
1102 Status
= VfatCreateFile(IrpContext
->DeviceObject
, IrpContext
->Irp
);
1103 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
1105 if (NT_SUCCESS(Status
))
1106 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;