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
++;
529 pFcb
->OpenHandleCount
++;
531 Irp
->IoStatus
.Information
= FILE_OPENED
;
532 return STATUS_SUCCESS
;
535 /* Check for illegal characters and illegale dot sequences in the file name */
536 PathNameU
= FileObject
->FileName
;
537 c
= PathNameU
.Buffer
+ PathNameU
.Length
/ sizeof(WCHAR
);
540 while (c
-- > PathNameU
.Buffer
)
542 if (*c
== L
'\\' || c
== PathNameU
.Buffer
)
544 if (Dots
&& last
> c
)
546 return STATUS_OBJECT_NAME_INVALID
;
556 if (*c
!= '\\' && vfatIsLongIllegal(*c
))
558 return STATUS_OBJECT_NAME_INVALID
;
562 /* Check if we try to open target directory of root dir */
563 if (OpenTargetDir
&& FileObject
->RelatedFileObject
== NULL
&& PathNameU
.Length
== sizeof(WCHAR
) &&
564 PathNameU
.Buffer
[0] == L
'\\')
566 return STATUS_INVALID_PARAMETER
;
569 if (FileObject
->RelatedFileObject
&& PathNameU
.Length
>= sizeof(WCHAR
) && PathNameU
.Buffer
[0] == L
'\\')
571 return STATUS_OBJECT_NAME_INVALID
;
574 if (PathNameU
.Length
> sizeof(WCHAR
) && PathNameU
.Buffer
[PathNameU
.Length
/sizeof(WCHAR
)-1] == L
'\\')
576 PathNameU
.Length
-= sizeof(WCHAR
);
579 /* Try opening the file. */
582 Status
= VfatOpenFile(DeviceExt
, &PathNameU
, FileObject
, RequestedDisposition
, &ParentFcb
);
587 LONG idx
, FileNameLen
;
589 ParentFcb
= (FileObject
->RelatedFileObject
!= NULL
) ? FileObject
->RelatedFileObject
->FsContext
: NULL
;
592 vfatGrabFCB(DeviceExt
, ParentFcb
);
594 Status
= vfatGetFCBForFile(DeviceExt
, &ParentFcb
, &TargetFcb
, &PathNameU
);
596 if (NT_SUCCESS(Status
))
598 vfatReleaseFCB(DeviceExt
, TargetFcb
);
599 Irp
->IoStatus
.Information
= FILE_EXISTS
;
603 Irp
->IoStatus
.Information
= FILE_DOES_NOT_EXIST
;
606 idx
= FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1;
608 /* Skip trailing \ - if any */
609 if (PathNameU
.Buffer
[idx
] == L
'\\')
612 PathNameU
.Length
-= sizeof(WCHAR
);
616 while (idx
>= 0 && PathNameU
.Buffer
[idx
] != L
'\\')
621 if (idx
> 0 || PathNameU
.Buffer
[0] == L
'\\')
623 /* We don't want to include / in the name */
624 FileNameLen
= PathNameU
.Length
- ((idx
+ 1) * sizeof(WCHAR
));
626 /* Update FO just to keep file name */
627 /* Skip first slash */
629 FileObject
->FileName
.Length
= FileNameLen
;
630 RtlMoveMemory(&PathNameU
.Buffer
[0], &PathNameU
.Buffer
[idx
], FileObject
->FileName
.Length
);
634 /* This is a relative open and we have only the filename, so open the parent directory
635 * It is in RelatedFileObject
637 ASSERT(FileObject
->RelatedFileObject
!= NULL
);
639 /* No need to modify the FO, it already has the name */
642 /* We're done with opening! */
643 if (ParentFcb
!= NULL
)
645 Status
= vfatAttachFCBToFileObject(DeviceExt
, ParentFcb
, FileObject
);
648 if (NT_SUCCESS(Status
))
650 pFcb
= FileObject
->FsContext
;
651 ASSERT(pFcb
== ParentFcb
);
653 if (pFcb
->OpenHandleCount
== 0)
655 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
656 Stack
->Parameters
.Create
.ShareAccess
,
658 &pFcb
->FCBShareAccess
);
662 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
663 Stack
->Parameters
.Create
.ShareAccess
,
665 &pFcb
->FCBShareAccess
,
667 if (!NT_SUCCESS(Status
))
669 VfatCloseFile(DeviceExt
, FileObject
);
674 pFcb
->OpenHandleCount
++;
675 DeviceExt
->OpenHandleCount
++;
677 else if (ParentFcb
!= NULL
)
679 vfatReleaseFCB(DeviceExt
, ParentFcb
);
686 * If the directory containing the file to open doesn't exist then
689 if (Status
== STATUS_OBJECT_PATH_NOT_FOUND
||
690 Status
== STATUS_INVALID_PARAMETER
||
691 Status
== STATUS_DELETE_PENDING
)
695 vfatReleaseFCB(DeviceExt
, ParentFcb
);
700 if (!NT_SUCCESS(Status
) && ParentFcb
== NULL
)
702 DPRINT1("VfatOpenFile failed for '%wZ', status %x\n", &PathNameU
, Status
);
706 /* If the file open failed then create the required file */
707 if (!NT_SUCCESS (Status
))
709 if (RequestedDisposition
== FILE_CREATE
||
710 RequestedDisposition
== FILE_OPEN_IF
||
711 RequestedDisposition
== FILE_OVERWRITE_IF
||
712 RequestedDisposition
== FILE_SUPERSEDE
)
714 Attributes
= Stack
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
;
715 if (!(RequestedOptions
& FILE_DIRECTORY_FILE
))
716 Attributes
|= FILE_ATTRIBUTE_ARCHIVE
;
717 vfatSplitPathName(&PathNameU
, NULL
, &FileNameU
);
718 Status
= VfatAddEntry(DeviceExt
, &FileNameU
, &pFcb
, ParentFcb
, RequestedOptions
,
719 (UCHAR
)(Attributes
& FILE_ATTRIBUTE_VALID_FLAGS
), NULL
);
720 vfatReleaseFCB(DeviceExt
, ParentFcb
);
721 if (NT_SUCCESS(Status
))
723 Status
= vfatAttachFCBToFileObject(DeviceExt
, pFcb
, FileObject
);
724 if (!NT_SUCCESS(Status
))
726 vfatReleaseFCB(DeviceExt
, pFcb
);
730 Irp
->IoStatus
.Information
= FILE_CREATED
;
731 VfatSetAllocationSizeInformation(FileObject
,
734 &Irp
->Overlay
.AllocationSize
);
735 VfatSetExtendedAttributes(FileObject
,
736 Irp
->AssociatedIrp
.SystemBuffer
,
737 Stack
->Parameters
.Create
.EaLength
);
739 if (PagingFileCreate
)
741 pFcb
->Flags
|= FCB_IS_PAGE_FILE
;
753 vfatReleaseFCB(DeviceExt
, ParentFcb
);
762 vfatReleaseFCB(DeviceExt
, ParentFcb
);
765 /* Otherwise fail if the caller wanted to create a new file */
766 if (RequestedDisposition
== FILE_CREATE
)
768 Irp
->IoStatus
.Information
= FILE_EXISTS
;
769 VfatCloseFile(DeviceExt
, FileObject
);
770 return STATUS_OBJECT_NAME_COLLISION
;
773 pFcb
= FileObject
->FsContext
;
775 if (pFcb
->OpenHandleCount
!= 0)
777 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
778 Stack
->Parameters
.Create
.ShareAccess
,
780 &pFcb
->FCBShareAccess
,
782 if (!NT_SUCCESS(Status
))
784 VfatCloseFile(DeviceExt
, FileObject
);
790 * Check the file has the requested attributes
792 if (RequestedOptions
& FILE_NON_DIRECTORY_FILE
&&
793 *pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
)
795 VfatCloseFile (DeviceExt
, FileObject
);
796 return STATUS_FILE_IS_A_DIRECTORY
;
798 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
799 !(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
801 VfatCloseFile (DeviceExt
, FileObject
);
802 return STATUS_NOT_A_DIRECTORY
;
804 #ifndef USE_ROS_CC_AND_FS
805 if (!(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
807 if (Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_WRITE_DATA
||
808 RequestedDisposition
== FILE_OVERWRITE
||
809 RequestedDisposition
== FILE_OVERWRITE_IF
)
811 if (!MmFlushImageSection(&pFcb
->SectionObjectPointers
, MmFlushForWrite
))
813 DPRINT1("%wZ\n", &pFcb
->PathNameU
);
814 DPRINT1("%d %d %d\n", Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_WRITE_DATA
,
815 RequestedDisposition
== FILE_OVERWRITE
, RequestedDisposition
== FILE_OVERWRITE_IF
);
816 VfatCloseFile (DeviceExt
, FileObject
);
817 return STATUS_SHARING_VIOLATION
;
822 if (PagingFileCreate
)
825 * Do more checking for page files. It is possible,
826 * that the file was opened and closed previously
827 * as a normal cached file. In this case, the cache
828 * manager has referenced the fileobject and the fcb
829 * is held in memory. Try to remove the fileobject
830 * from cache manager and use the fcb.
832 if (pFcb
->RefCount
> 1)
834 if(!(pFcb
->Flags
& FCB_IS_PAGE_FILE
))
836 VfatCloseFile(DeviceExt
, FileObject
);
837 return STATUS_INVALID_PARAMETER
;
842 pFcb
->Flags
|= FCB_IS_PAGE_FILE
;
847 if (pFcb
->Flags
& FCB_IS_PAGE_FILE
)
849 VfatCloseFile(DeviceExt
, FileObject
);
850 return STATUS_INVALID_PARAMETER
;
854 if (RequestedDisposition
== FILE_OVERWRITE
||
855 RequestedDisposition
== FILE_OVERWRITE_IF
||
856 RequestedDisposition
== FILE_SUPERSEDE
)
858 if (!(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
860 *pFcb
->Attributes
= Stack
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
;
861 *pFcb
->Attributes
|= FILE_ATTRIBUTE_ARCHIVE
;
862 VfatUpdateEntry(pFcb
);
865 ExAcquireResourceExclusiveLite(&(pFcb
->MainResource
), TRUE
);
866 Status
= VfatSetAllocationSizeInformation(FileObject
,
869 &Irp
->Overlay
.AllocationSize
);
870 ExReleaseResourceLite(&(pFcb
->MainResource
));
871 if (!NT_SUCCESS (Status
))
873 VfatCloseFile(DeviceExt
, FileObject
);
878 if (RequestedDisposition
== FILE_SUPERSEDE
)
880 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
882 else if (RequestedDisposition
== FILE_OVERWRITE
||
883 RequestedDisposition
== FILE_OVERWRITE_IF
)
885 Irp
->IoStatus
.Information
= FILE_OVERWRITTEN
;
889 Irp
->IoStatus
.Information
= FILE_OPENED
;
893 if (pFcb
->OpenHandleCount
== 0)
895 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
896 Stack
->Parameters
.Create
.ShareAccess
,
898 &pFcb
->FCBShareAccess
);
902 IoUpdateShareAccess(FileObject
,
903 &pFcb
->FCBShareAccess
);
906 if (Irp
->IoStatus
.Information
== FILE_CREATED
)
908 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
909 &(DeviceExt
->NotifyList
),
910 (PSTRING
)&pFcb
->PathNameU
,
911 pFcb
->PathNameU
.Length
- pFcb
->LongNameU
.Length
,
914 ((*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
915 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
920 pFcb
->OpenHandleCount
++;
921 DeviceExt
->OpenHandleCount
++;
923 /* FIXME : test write access if requested */
929 * FUNCTION: Create or open a file
933 PVFAT_IRP_CONTEXT IrpContext
)
939 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
941 /* DeviceObject represents FileSystem instead of logical volume */
942 DPRINT ("FsdCreate called with file system\n");
943 IrpContext
->Irp
->IoStatus
.Information
= FILE_OPENED
;
944 IrpContext
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
945 IoCompleteRequest(IrpContext
->Irp
, IO_DISK_INCREMENT
);
946 VfatFreeIrpContext(IrpContext
);
947 return STATUS_SUCCESS
;
950 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
952 return(VfatQueueRequest(IrpContext
));
955 IrpContext
->Irp
->IoStatus
.Information
= 0;
956 ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
, TRUE
);
957 Status
= VfatCreateFile(IrpContext
->DeviceObject
, IrpContext
->Irp
);
958 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
960 IrpContext
->Irp
->IoStatus
.Status
= Status
;
961 IoCompleteRequest(IrpContext
->Irp
,
962 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
963 VfatFreeIrpContext(IrpContext
);