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 (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 (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: Read the volume label
102 PDEVICE_EXTENSION DeviceExt
,
105 PVOID Context
= NULL
;
109 LARGE_INTEGER FileOffset
;
110 UNICODE_STRING NameU
;
112 ULONG EntriesPerPage
;
115 NameU
.Buffer
= Vpb
->VolumeLabel
;
117 NameU
.MaximumLength
= sizeof(Vpb
->VolumeLabel
);
118 *(Vpb
->VolumeLabel
) = 0;
119 Vpb
->VolumeLabelLength
= 0;
121 if (DeviceExt
->Flags
& VCB_IS_FATX
)
123 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
124 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
128 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
129 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
132 ExAcquireResourceExclusiveLite(&DeviceExt
->DirResource
, TRUE
);
133 pFcb
= vfatOpenRootFCB(DeviceExt
);
134 ExReleaseResourceLite(&DeviceExt
->DirResource
);
136 FileOffset
.QuadPart
= 0;
137 if (CcMapData(pFcb
->FileObject
, &FileOffset
, SizeDirEntry
, TRUE
, &Context
, (PVOID
*)&Entry
))
141 if (ENTRY_VOLUME(DeviceExt
, Entry
))
143 /* copy volume label */
144 if (DeviceExt
->Flags
& VCB_IS_FATX
)
146 StringO
.Buffer
= (PCHAR
)Entry
->FatX
.Filename
;
147 StringO
.MaximumLength
= StringO
.Length
= Entry
->FatX
.FilenameLength
;
148 RtlOemStringToUnicodeString(&NameU
, &StringO
, FALSE
);
152 vfat8Dot3ToString(&Entry
->Fat
, &NameU
);
154 Vpb
->VolumeLabelLength
= NameU
.Length
;
157 if (ENTRY_END(DeviceExt
, Entry
))
162 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
163 if ((DirIndex
% EntriesPerPage
) == 0)
165 CcUnpinData(Context
);
166 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
167 if (!CcMapData(pFcb
->FileObject
, &FileOffset
, SizeDirEntry
, TRUE
, &Context
, (PVOID
*)&Entry
))
176 CcUnpinData(Context
);
179 ExAcquireResourceExclusiveLite(&DeviceExt
->DirResource
, TRUE
);
180 vfatReleaseFCB(DeviceExt
, pFcb
);
181 ExReleaseResourceLite(&DeviceExt
->DirResource
);
183 return STATUS_SUCCESS
;
187 * FUNCTION: Find a file
191 PDEVICE_EXTENSION DeviceExt
,
193 PUNICODE_STRING FileToFindU
,
194 PVFAT_DIRENTRY_CONTEXT DirContext
,
197 PWCHAR PathNameBuffer
;
198 USHORT PathNameBufferLength
;
200 PVOID Context
= NULL
;
204 UNICODE_STRING PathNameU
;
205 UNICODE_STRING FileToFindUpcase
;
208 DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n",
209 Parent
, FileToFindU
, DirContext
->DirIndex
);
210 DPRINT("FindFile: Path %wZ\n",&Parent
->PathNameU
);
212 PathNameBufferLength
= LONGNAME_MAX_LENGTH
* sizeof(WCHAR
);
213 PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameBufferLength
+ sizeof(WCHAR
), TAG_VFAT
);
216 return STATUS_INSUFFICIENT_RESOURCES
;
219 PathNameU
.Buffer
= PathNameBuffer
;
220 PathNameU
.Length
= 0;
221 PathNameU
.MaximumLength
= PathNameBufferLength
;
223 DirContext
->LongNameU
.Length
= 0;
224 DirContext
->ShortNameU
.Length
= 0;
226 WildCard
= FsRtlDoesNameContainWildCards(FileToFindU
);
228 if (WildCard
== FALSE
)
230 /* if there is no '*?' in the search name, than look first for an existing fcb */
231 RtlCopyUnicodeString(&PathNameU
, &Parent
->PathNameU
);
232 if (!vfatFCBIsRoot(Parent
))
234 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = L
'\\';
235 PathNameU
.Length
+= sizeof(WCHAR
);
237 RtlAppendUnicodeStringToString(&PathNameU
, FileToFindU
);
238 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = 0;
239 rcFcb
= vfatGrabFCBFromTable(DeviceExt
, &PathNameU
);
242 ULONG startIndex
= rcFcb
->startIndex
;
243 if ((rcFcb
->Flags
& FCB_IS_FATX_ENTRY
) && !vfatFCBIsRoot(Parent
))
247 if(startIndex
>= DirContext
->DirIndex
)
249 RtlCopyUnicodeString(&DirContext
->LongNameU
, &rcFcb
->LongNameU
);
250 RtlCopyUnicodeString(&DirContext
->ShortNameU
, &rcFcb
->ShortNameU
);
251 RtlCopyMemory(&DirContext
->DirEntry
, &rcFcb
->entry
, sizeof(DIR_ENTRY
));
252 DirContext
->StartIndex
= rcFcb
->startIndex
;
253 DirContext
->DirIndex
= rcFcb
->dirIndex
;
254 DPRINT("FindFile: new Name %wZ, DirIndex %u (%u)\n",
255 &DirContext
->LongNameU
, DirContext
->DirIndex
, DirContext
->StartIndex
);
256 Status
= STATUS_SUCCESS
;
260 DPRINT("FCB not found for %wZ\n", &PathNameU
);
261 Status
= STATUS_UNSUCCESSFUL
;
263 vfatReleaseFCB(DeviceExt
, rcFcb
);
264 ExFreePool(PathNameBuffer
);
269 /* FsRtlIsNameInExpression need the searched string to be upcase,
270 * even if IgnoreCase is specified */
271 Status
= RtlUpcaseUnicodeString(&FileToFindUpcase
, FileToFindU
, TRUE
);
272 if (!NT_SUCCESS(Status
))
274 ExFreePool(PathNameBuffer
);
280 Status
= DeviceExt
->GetNextDirEntry(&Context
, &Page
, Parent
, DirContext
, First
);
282 if (Status
== STATUS_NO_MORE_ENTRIES
)
286 if (ENTRY_VOLUME(DeviceExt
, &DirContext
->DirEntry
))
288 DirContext
->DirIndex
++;
293 Found
= FsRtlIsNameInExpression(&FileToFindUpcase
, &DirContext
->LongNameU
, TRUE
, NULL
) ||
294 FsRtlIsNameInExpression(&FileToFindUpcase
, &DirContext
->ShortNameU
, TRUE
, NULL
);
298 Found
= FsRtlAreNamesEqual(&DirContext
->LongNameU
, FileToFindU
, TRUE
, NULL
) ||
299 FsRtlAreNamesEqual(&DirContext
->ShortNameU
, FileToFindU
, TRUE
, NULL
);
306 RtlCopyUnicodeString(&PathNameU
, &Parent
->PathNameU
);
307 if (!vfatFCBIsRoot(Parent
))
309 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = L
'\\';
310 PathNameU
.Length
+= sizeof(WCHAR
);
312 RtlAppendUnicodeStringToString(&PathNameU
, &DirContext
->LongNameU
);
313 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = 0;
314 rcFcb
= vfatGrabFCBFromTable(DeviceExt
, &PathNameU
);
317 RtlCopyMemory(&DirContext
->DirEntry
, &rcFcb
->entry
, sizeof(DIR_ENTRY
));
318 vfatReleaseFCB(DeviceExt
, rcFcb
);
321 DPRINT("%u\n", DirContext
->LongNameU
.Length
);
322 DPRINT("FindFile: new Name %wZ, DirIndex %u\n",
323 &DirContext
->LongNameU
, DirContext
->DirIndex
);
327 CcUnpinData(Context
);
329 RtlFreeUnicodeString(&FileToFindUpcase
);
330 ExFreePool(PathNameBuffer
);
331 return STATUS_SUCCESS
;
333 DirContext
->DirIndex
++;
338 CcUnpinData(Context
);
341 RtlFreeUnicodeString(&FileToFindUpcase
);
342 ExFreePool(PathNameBuffer
);
347 * FUNCTION: Opens a file
352 PDEVICE_EXTENSION DeviceExt
,
353 PUNICODE_STRING PathNameU
,
354 PFILE_OBJECT FileObject
,
355 ULONG RequestedDisposition
,
361 DPRINT("VfatOpenFile(%p, '%wZ', %p, %p)\n", DeviceExt
, PathNameU
, FileObject
, ParentFcb
);
363 if (FileObject
->RelatedFileObject
)
365 DPRINT("'%wZ'\n", &FileObject
->RelatedFileObject
->FileName
);
367 *ParentFcb
= FileObject
->RelatedFileObject
->FsContext
;
374 if (!DeviceExt
->FatInfo
.FixedMedia
)
376 Status
= VfatBlockDeviceIoControl(DeviceExt
->StorageDevice
,
377 IOCTL_DISK_CHECK_VERIFY
,
383 if (!NT_SUCCESS(Status
))
385 DPRINT("Status %lx\n", Status
);
393 vfatGrabFCB(DeviceExt
, *ParentFcb
);
396 /* try first to find an existing FCB in memory */
397 DPRINT("Checking for existing FCB in memory\n");
399 Status
= vfatGetFCBForFile(DeviceExt
, ParentFcb
, &Fcb
, PathNameU
);
400 if (!NT_SUCCESS(Status
))
402 DPRINT ("Could not make a new FCB, status: %x\n", Status
);
406 if (Fcb
->Flags
& FCB_DELETE_PENDING
)
408 vfatReleaseFCB(DeviceExt
, Fcb
);
409 return STATUS_DELETE_PENDING
;
412 /* Fail, if we try to overwrite a read-only file */
413 if ((*Fcb
->Attributes
& FILE_ATTRIBUTE_READONLY
) &&
414 (RequestedDisposition
== FILE_OVERWRITE
))
416 vfatReleaseFCB(DeviceExt
, Fcb
);
417 return STATUS_ACCESS_DENIED
;
420 DPRINT("Attaching FCB to fileObject\n");
421 Status
= vfatAttachFCBToFileObject(DeviceExt
, Fcb
, FileObject
);
422 if (!NT_SUCCESS(Status
))
424 vfatReleaseFCB(DeviceExt
, Fcb
);
430 * FUNCTION: Create or open a file
434 PDEVICE_OBJECT DeviceObject
,
437 PIO_STACK_LOCATION Stack
;
438 PFILE_OBJECT FileObject
;
439 NTSTATUS Status
= STATUS_SUCCESS
;
440 PDEVICE_EXTENSION DeviceExt
;
441 ULONG RequestedDisposition
, RequestedOptions
;
442 PVFATFCB pFcb
= NULL
;
443 PVFATFCB ParentFcb
= NULL
;
445 BOOLEAN PagingFileCreate
;
447 BOOLEAN OpenTargetDir
;
448 UNICODE_STRING FileNameU
;
449 UNICODE_STRING PathNameU
;
452 /* Unpack the various parameters. */
453 Stack
= IoGetCurrentIrpStackLocation(Irp
);
454 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>> 24) & 0xff);
455 RequestedOptions
= Stack
->Parameters
.Create
.Options
& FILE_VALID_OPTION_FLAGS
;
456 PagingFileCreate
= (Stack
->Flags
& SL_OPEN_PAGING_FILE
) ? TRUE
: FALSE
;
457 OpenTargetDir
= (Stack
->Flags
& SL_OPEN_TARGET_DIRECTORY
) ? TRUE
: FALSE
;
459 FileObject
= Stack
->FileObject
;
460 DeviceExt
= DeviceObject
->DeviceExtension
;
462 /* Check their validity. */
463 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
464 RequestedDisposition
== FILE_SUPERSEDE
)
466 return STATUS_INVALID_PARAMETER
;
469 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
470 RequestedOptions
& FILE_NON_DIRECTORY_FILE
)
472 return STATUS_INVALID_PARAMETER
;
475 /* Deny create if the volume is locked */
476 if (DeviceExt
->Flags
& VCB_VOLUME_LOCKED
)
478 return STATUS_ACCESS_DENIED
;
481 /* This a open operation for the volume itself */
482 if (FileObject
->FileName
.Length
== 0 &&
483 (FileObject
->RelatedFileObject
== NULL
|| FileObject
->RelatedFileObject
->FsContext2
!= NULL
))
485 DPRINT("Volume opening\n");
487 if (RequestedDisposition
!= FILE_OPEN
&&
488 RequestedDisposition
!= FILE_OPEN_IF
)
490 return STATUS_ACCESS_DENIED
;
493 /* In spite of what is shown in WDK, it seems that Windows FAT driver doesn't perform that test */
494 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
496 return STATUS_NOT_A_DIRECTORY
;
502 return STATUS_INVALID_PARAMETER
;
505 pFcb
= DeviceExt
->VolumeFcb
;
507 if (pFcb
->OpenHandleCount
== 0)
509 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
510 Stack
->Parameters
.Create
.ShareAccess
,
512 &pFcb
->FCBShareAccess
);
516 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
517 Stack
->Parameters
.Create
.ShareAccess
,
519 &pFcb
->FCBShareAccess
,
521 if (!NT_SUCCESS(Status
))
527 vfatAttachFCBToFileObject(DeviceExt
, pFcb
, FileObject
);
528 DeviceExt
->OpenHandleCount
++;
530 Irp
->IoStatus
.Information
= FILE_OPENED
;
531 return STATUS_SUCCESS
;
534 /* Check for illegal characters and illegale dot sequences in the file name */
535 PathNameU
= FileObject
->FileName
;
536 c
= PathNameU
.Buffer
+ PathNameU
.Length
/ sizeof(WCHAR
);
539 while (c
-- > PathNameU
.Buffer
)
541 if (*c
== L
'\\' || c
== PathNameU
.Buffer
)
543 if (Dots
&& last
> c
)
545 return STATUS_OBJECT_NAME_INVALID
;
555 if (*c
!= '\\' && vfatIsLongIllegal(*c
))
557 return STATUS_OBJECT_NAME_INVALID
;
561 /* Check if we try to open target directory of root dir */
562 if (OpenTargetDir
&& FileObject
->RelatedFileObject
== NULL
&& PathNameU
.Length
== sizeof(WCHAR
) &&
563 PathNameU
.Buffer
[0] == L
'\\')
565 return STATUS_INVALID_PARAMETER
;
568 if (FileObject
->RelatedFileObject
&& PathNameU
.Length
>= sizeof(WCHAR
) && PathNameU
.Buffer
[0] == L
'\\')
570 return STATUS_OBJECT_NAME_INVALID
;
573 if (PathNameU
.Length
> sizeof(WCHAR
) && PathNameU
.Buffer
[PathNameU
.Length
/sizeof(WCHAR
)-1] == L
'\\')
575 PathNameU
.Length
-= sizeof(WCHAR
);
578 /* Try opening the file. */
581 Status
= VfatOpenFile(DeviceExt
, &PathNameU
, FileObject
, RequestedDisposition
, &ParentFcb
);
586 LONG idx
, FileNameLen
;
588 ParentFcb
= (FileObject
->RelatedFileObject
!= NULL
) ? FileObject
->RelatedFileObject
->FsContext
: NULL
;
591 vfatGrabFCB(DeviceExt
, ParentFcb
);
593 Status
= vfatGetFCBForFile(DeviceExt
, &ParentFcb
, &TargetFcb
, &PathNameU
);
595 if (NT_SUCCESS(Status
))
597 vfatReleaseFCB(DeviceExt
, TargetFcb
);
598 Irp
->IoStatus
.Information
= FILE_EXISTS
;
602 Irp
->IoStatus
.Information
= FILE_DOES_NOT_EXIST
;
605 idx
= FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1;
607 /* Skip trailing \ - if any */
608 if (PathNameU
.Buffer
[idx
] == L
'\\')
611 PathNameU
.Length
-= sizeof(WCHAR
);
615 while (idx
>= 0 && PathNameU
.Buffer
[idx
] != L
'\\')
620 if (idx
> 0 || PathNameU
.Buffer
[0] == L
'\\')
622 /* We don't want to include / in the name */
623 FileNameLen
= PathNameU
.Length
- ((idx
+ 1) * sizeof(WCHAR
));
625 /* Update FO just to keep file name */
626 /* Skip first slash */
628 FileObject
->FileName
.Length
= FileNameLen
;
629 RtlMoveMemory(&PathNameU
.Buffer
[0], &PathNameU
.Buffer
[idx
], FileObject
->FileName
.Length
);
633 /* This is a relative open and we have only the filename, so open the parent directory
634 * It is in RelatedFileObject
636 ASSERT(FileObject
->RelatedFileObject
!= NULL
);
638 /* No need to modify the FO, it already has the name */
641 /* We're done with opening! */
642 if (ParentFcb
!= NULL
)
644 Status
= vfatAttachFCBToFileObject(DeviceExt
, ParentFcb
, FileObject
);
647 if (NT_SUCCESS(Status
))
649 pFcb
= FileObject
->FsContext
;
650 ASSERT(pFcb
== ParentFcb
);
652 if (pFcb
->OpenHandleCount
== 0)
654 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
655 Stack
->Parameters
.Create
.ShareAccess
,
657 &pFcb
->FCBShareAccess
);
661 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
662 Stack
->Parameters
.Create
.ShareAccess
,
664 &pFcb
->FCBShareAccess
,
666 if (!NT_SUCCESS(Status
))
668 VfatCloseFile(DeviceExt
, FileObject
);
673 pFcb
->OpenHandleCount
++;
674 DeviceExt
->OpenHandleCount
++;
676 else if (ParentFcb
!= NULL
)
678 vfatReleaseFCB(DeviceExt
, ParentFcb
);
685 * If the directory containing the file to open doesn't exist then
688 if (Status
== STATUS_OBJECT_PATH_NOT_FOUND
||
689 Status
== STATUS_INVALID_PARAMETER
||
690 Status
== STATUS_DELETE_PENDING
)
694 vfatReleaseFCB(DeviceExt
, ParentFcb
);
699 if (!NT_SUCCESS(Status
) && ParentFcb
== NULL
)
701 DPRINT1("VfatOpenFile failed for '%wZ', status %x\n", &PathNameU
, Status
);
705 /* If the file open failed then create the required file */
706 if (!NT_SUCCESS (Status
))
708 if (RequestedDisposition
== FILE_CREATE
||
709 RequestedDisposition
== FILE_OPEN_IF
||
710 RequestedDisposition
== FILE_OVERWRITE_IF
||
711 RequestedDisposition
== FILE_SUPERSEDE
)
713 Attributes
= Stack
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
;
714 if (!(RequestedOptions
& FILE_DIRECTORY_FILE
))
715 Attributes
|= FILE_ATTRIBUTE_ARCHIVE
;
716 vfatSplitPathName(&PathNameU
, NULL
, &FileNameU
);
717 Status
= VfatAddEntry(DeviceExt
, &FileNameU
, &pFcb
, ParentFcb
, RequestedOptions
,
718 (UCHAR
)(Attributes
& FILE_ATTRIBUTE_VALID_FLAGS
), NULL
);
719 vfatReleaseFCB(DeviceExt
, ParentFcb
);
720 if (NT_SUCCESS(Status
))
722 Status
= vfatAttachFCBToFileObject(DeviceExt
, pFcb
, FileObject
);
723 if (!NT_SUCCESS(Status
))
725 vfatReleaseFCB(DeviceExt
, pFcb
);
729 Irp
->IoStatus
.Information
= FILE_CREATED
;
730 VfatSetAllocationSizeInformation(FileObject
,
733 &Irp
->Overlay
.AllocationSize
);
734 VfatSetExtendedAttributes(FileObject
,
735 Irp
->AssociatedIrp
.SystemBuffer
,
736 Stack
->Parameters
.Create
.EaLength
);
738 if (PagingFileCreate
)
740 pFcb
->Flags
|= FCB_IS_PAGE_FILE
;
752 vfatReleaseFCB(DeviceExt
, ParentFcb
);
761 vfatReleaseFCB(DeviceExt
, ParentFcb
);
764 /* Otherwise fail if the caller wanted to create a new file */
765 if (RequestedDisposition
== FILE_CREATE
)
767 Irp
->IoStatus
.Information
= FILE_EXISTS
;
768 VfatCloseFile(DeviceExt
, FileObject
);
769 return STATUS_OBJECT_NAME_COLLISION
;
772 pFcb
= FileObject
->FsContext
;
774 if (pFcb
->OpenHandleCount
!= 0)
776 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
777 Stack
->Parameters
.Create
.ShareAccess
,
779 &pFcb
->FCBShareAccess
,
781 if (!NT_SUCCESS(Status
))
783 VfatCloseFile(DeviceExt
, FileObject
);
789 * Check the file has the requested attributes
791 if (RequestedOptions
& FILE_NON_DIRECTORY_FILE
&&
792 *pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
)
794 VfatCloseFile (DeviceExt
, FileObject
);
795 return STATUS_FILE_IS_A_DIRECTORY
;
797 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
798 !(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
800 VfatCloseFile (DeviceExt
, FileObject
);
801 return STATUS_NOT_A_DIRECTORY
;
803 #ifndef USE_ROS_CC_AND_FS
804 if (!(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
806 if (Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_WRITE_DATA
||
807 RequestedDisposition
== FILE_OVERWRITE
||
808 RequestedDisposition
== FILE_OVERWRITE_IF
)
810 if (!MmFlushImageSection(&pFcb
->SectionObjectPointers
, MmFlushForWrite
))
812 DPRINT1("%wZ\n", &pFcb
->PathNameU
);
813 DPRINT1("%d %d %d\n", Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_WRITE_DATA
,
814 RequestedDisposition
== FILE_OVERWRITE
, RequestedDisposition
== FILE_OVERWRITE_IF
);
815 VfatCloseFile (DeviceExt
, FileObject
);
816 return STATUS_SHARING_VIOLATION
;
821 if (PagingFileCreate
)
824 * Do more checking for page files. It is possible,
825 * that the file was opened and closed previously
826 * as a normal cached file. In this case, the cache
827 * manager has referenced the fileobject and the fcb
828 * is held in memory. Try to remove the fileobject
829 * from cache manager and use the fcb.
831 if (pFcb
->RefCount
> 1)
833 if(!(pFcb
->Flags
& FCB_IS_PAGE_FILE
))
835 VfatCloseFile(DeviceExt
, FileObject
);
836 return STATUS_INVALID_PARAMETER
;
841 pFcb
->Flags
|= FCB_IS_PAGE_FILE
;
846 if (pFcb
->Flags
& FCB_IS_PAGE_FILE
)
848 VfatCloseFile(DeviceExt
, FileObject
);
849 return STATUS_INVALID_PARAMETER
;
853 if (RequestedDisposition
== FILE_OVERWRITE
||
854 RequestedDisposition
== FILE_OVERWRITE_IF
||
855 RequestedDisposition
== FILE_SUPERSEDE
)
857 if (!(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
859 *pFcb
->Attributes
= Stack
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
;
860 *pFcb
->Attributes
|= FILE_ATTRIBUTE_ARCHIVE
;
861 VfatUpdateEntry(pFcb
);
864 ExAcquireResourceExclusiveLite(&(pFcb
->MainResource
), TRUE
);
865 Status
= VfatSetAllocationSizeInformation(FileObject
,
868 &Irp
->Overlay
.AllocationSize
);
869 ExReleaseResourceLite(&(pFcb
->MainResource
));
870 if (!NT_SUCCESS (Status
))
872 VfatCloseFile(DeviceExt
, FileObject
);
877 if (RequestedDisposition
== FILE_SUPERSEDE
)
879 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
881 else if (RequestedDisposition
== FILE_OVERWRITE
||
882 RequestedDisposition
== FILE_OVERWRITE_IF
)
884 Irp
->IoStatus
.Information
= FILE_OVERWRITTEN
;
888 Irp
->IoStatus
.Information
= FILE_OPENED
;
892 if (pFcb
->OpenHandleCount
== 0)
894 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
895 Stack
->Parameters
.Create
.ShareAccess
,
897 &pFcb
->FCBShareAccess
);
901 IoUpdateShareAccess(FileObject
,
902 &pFcb
->FCBShareAccess
);
905 if (Irp
->IoStatus
.Information
== FILE_CREATED
)
907 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
908 &(DeviceExt
->NotifyList
),
909 (PSTRING
)&pFcb
->PathNameU
,
910 pFcb
->PathNameU
.Length
- pFcb
->LongNameU
.Length
,
913 ((*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
914 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
919 pFcb
->OpenHandleCount
++;
920 DeviceExt
->OpenHandleCount
++;
922 /* FIXME : test write access if requested */
928 * FUNCTION: Create or open a file
932 PVFAT_IRP_CONTEXT IrpContext
)
938 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
940 /* DeviceObject represents FileSystem instead of logical volume */
941 DPRINT ("FsdCreate called with file system\n");
942 IrpContext
->Irp
->IoStatus
.Information
= FILE_OPENED
;
943 IrpContext
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
944 IoCompleteRequest(IrpContext
->Irp
, IO_DISK_INCREMENT
);
945 VfatFreeIrpContext(IrpContext
);
946 return STATUS_SUCCESS
;
949 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
951 return(VfatQueueRequest(IrpContext
));
954 IrpContext
->Irp
->IoStatus
.Information
= 0;
955 ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
, TRUE
);
956 Status
= VfatCreateFile(IrpContext
->DeviceObject
, IrpContext
->Irp
);
957 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
959 IrpContext
->Irp
->IoStatus
.Status
= Status
;
960 IoCompleteRequest(IrpContext
->Irp
,
961 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
962 VfatFreeIrpContext(IrpContext
);