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/fs/vfat/create.c
22 * PURPOSE: VFAT Filesystem
23 * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
26 /* INCLUDES *****************************************************************/
33 /* FUNCTIONS *****************************************************************/
37 PFAT_DIR_ENTRY pEntry
,
38 PUNICODE_STRING NameU
)
44 RtlCopyMemory(cString
, pEntry
->ShortName
, 11);
46 if (cString
[0] == 0x05)
51 StringA
.Buffer
= cString
;
52 for (StringA
.Length
= 0;
53 StringA
.Length
< 8 && StringA
.Buffer
[StringA
.Length
] != ' ';
55 StringA
.MaximumLength
= StringA
.Length
;
57 RtlOemStringToUnicodeString(NameU
, &StringA
, FALSE
);
59 if (pEntry
->lCase
& VFAT_CASE_LOWER_BASE
)
61 RtlDowncaseUnicodeString(NameU
, NameU
, FALSE
);
64 if (cString
[8] != ' ')
66 Length
= NameU
->Length
;
67 NameU
->Buffer
+= Length
/ sizeof(WCHAR
);
68 if (!FAT_ENTRY_VOLUME(pEntry
))
70 Length
+= sizeof(WCHAR
);
71 NameU
->Buffer
[0] = L
'.';
75 NameU
->MaximumLength
-= Length
;
77 StringA
.Buffer
= &cString
[8];
78 for (StringA
.Length
= 0;
79 StringA
.Length
< 3 && StringA
.Buffer
[StringA
.Length
] != ' ';
81 StringA
.MaximumLength
= StringA
.Length
;
82 RtlOemStringToUnicodeString(NameU
, &StringA
, FALSE
);
83 if (pEntry
->lCase
& VFAT_CASE_LOWER_EXT
)
85 RtlDowncaseUnicodeString(NameU
, NameU
, FALSE
);
87 NameU
->Buffer
-= Length
/ sizeof(WCHAR
);
88 NameU
->Length
+= Length
;
89 NameU
->MaximumLength
+= Length
;
92 NameU
->Buffer
[NameU
->Length
/ sizeof(WCHAR
)] = 0;
93 DPRINT("'%wZ'\n", NameU
);
97 * FUNCTION: Read the volume label
101 PDEVICE_EXTENSION DeviceExt
,
104 PVOID Context
= NULL
;
108 LARGE_INTEGER FileOffset
;
109 UNICODE_STRING NameU
;
111 ULONG EntriesPerPage
;
114 NameU
.Buffer
= Vpb
->VolumeLabel
;
116 NameU
.MaximumLength
= sizeof(Vpb
->VolumeLabel
);
117 *(Vpb
->VolumeLabel
) = 0;
118 Vpb
->VolumeLabelLength
= 0;
120 if (DeviceExt
->Flags
& VCB_IS_FATX
)
122 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
123 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
127 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
128 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
131 ExAcquireResourceExclusiveLite(&DeviceExt
->DirResource
, TRUE
);
132 pFcb
= vfatOpenRootFCB(DeviceExt
);
133 ExReleaseResourceLite(&DeviceExt
->DirResource
);
135 FileOffset
.QuadPart
= 0;
136 if (CcMapData(pFcb
->FileObject
, &FileOffset
, SizeDirEntry
, TRUE
, &Context
, (PVOID
*)&Entry
))
140 if (ENTRY_VOLUME(DeviceExt
, Entry
))
142 /* copy volume label */
143 if (DeviceExt
->Flags
& VCB_IS_FATX
)
145 StringO
.Buffer
= (PCHAR
)Entry
->FatX
.Filename
;
146 StringO
.MaximumLength
= StringO
.Length
= Entry
->FatX
.FilenameLength
;
147 RtlOemStringToUnicodeString(&NameU
, &StringO
, FALSE
);
151 vfat8Dot3ToString(&Entry
->Fat
, &NameU
);
153 Vpb
->VolumeLabelLength
= NameU
.Length
;
156 if (ENTRY_END(DeviceExt
, Entry
))
161 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
162 if ((DirIndex
% EntriesPerPage
) == 0)
164 CcUnpinData(Context
);
165 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
166 if (!CcMapData(pFcb
->FileObject
, &FileOffset
, SizeDirEntry
, TRUE
, &Context
, (PVOID
*)&Entry
))
175 CcUnpinData(Context
);
178 ExAcquireResourceExclusiveLite(&DeviceExt
->DirResource
, TRUE
);
179 vfatReleaseFCB(DeviceExt
, pFcb
);
180 ExReleaseResourceLite(&DeviceExt
->DirResource
);
182 return STATUS_SUCCESS
;
186 * FUNCTION: Find a file
190 PDEVICE_EXTENSION DeviceExt
,
192 PUNICODE_STRING FileToFindU
,
193 PVFAT_DIRENTRY_CONTEXT DirContext
,
196 PWCHAR PathNameBuffer
;
197 USHORT PathNameBufferLength
;
199 PVOID Context
= NULL
;
203 UNICODE_STRING PathNameU
;
204 UNICODE_STRING FileToFindUpcase
;
207 DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n",
208 Parent
, FileToFindU
, DirContext
->DirIndex
);
209 DPRINT("FindFile: Path %wZ\n",&Parent
->PathNameU
);
211 PathNameBufferLength
= LONGNAME_MAX_LENGTH
* sizeof(WCHAR
);
212 PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameBufferLength
+ sizeof(WCHAR
), TAG_VFAT
);
215 return STATUS_INSUFFICIENT_RESOURCES
;
218 PathNameU
.Buffer
= PathNameBuffer
;
219 PathNameU
.Length
= 0;
220 PathNameU
.MaximumLength
= PathNameBufferLength
;
222 DirContext
->LongNameU
.Length
= 0;
223 DirContext
->ShortNameU
.Length
= 0;
225 WildCard
= FsRtlDoesNameContainWildCards(FileToFindU
);
227 if (WildCard
== FALSE
)
229 /* if there is no '*?' in the search name, than look first for an existing fcb */
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
, FileToFindU
);
237 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = 0;
238 rcFcb
= vfatGrabFCBFromTable(DeviceExt
, &PathNameU
);
241 ULONG startIndex
= rcFcb
->startIndex
;
242 if ((rcFcb
->Flags
& FCB_IS_FATX_ENTRY
) && !vfatFCBIsRoot(Parent
))
246 if(startIndex
>= DirContext
->DirIndex
)
248 RtlCopyUnicodeString(&DirContext
->LongNameU
, &rcFcb
->LongNameU
);
249 RtlCopyUnicodeString(&DirContext
->ShortNameU
, &rcFcb
->ShortNameU
);
250 RtlCopyMemory(&DirContext
->DirEntry
, &rcFcb
->entry
, sizeof(DIR_ENTRY
));
251 DirContext
->StartIndex
= rcFcb
->startIndex
;
252 DirContext
->DirIndex
= rcFcb
->dirIndex
;
253 DPRINT("FindFile: new Name %wZ, DirIndex %u (%u)\n",
254 &DirContext
->LongNameU
, DirContext
->DirIndex
, DirContext
->StartIndex
);
255 Status
= STATUS_SUCCESS
;
259 DPRINT("FCB not found for %wZ\n", &PathNameU
);
260 Status
= STATUS_UNSUCCESSFUL
;
262 vfatReleaseFCB(DeviceExt
, rcFcb
);
263 ExFreePool(PathNameBuffer
);
268 /* FsRtlIsNameInExpression need the searched string to be upcase,
269 * even if IgnoreCase is specified */
270 Status
= RtlUpcaseUnicodeString(&FileToFindUpcase
, FileToFindU
, TRUE
);
271 if (!NT_SUCCESS(Status
))
273 ExFreePool(PathNameBuffer
);
279 Status
= DeviceExt
->GetNextDirEntry(&Context
, &Page
, Parent
, DirContext
, First
);
281 if (Status
== STATUS_NO_MORE_ENTRIES
)
285 if (ENTRY_VOLUME(DeviceExt
, &DirContext
->DirEntry
))
287 DirContext
->DirIndex
++;
292 Found
= FsRtlIsNameInExpression(&FileToFindUpcase
, &DirContext
->LongNameU
, TRUE
, NULL
) ||
293 FsRtlIsNameInExpression(&FileToFindUpcase
, &DirContext
->ShortNameU
, TRUE
, NULL
);
297 Found
= FsRtlAreNamesEqual(&DirContext
->LongNameU
, FileToFindU
, TRUE
, NULL
) ||
298 FsRtlAreNamesEqual(&DirContext
->ShortNameU
, FileToFindU
, TRUE
, NULL
);
305 RtlCopyUnicodeString(&PathNameU
, &Parent
->PathNameU
);
306 if (!vfatFCBIsRoot(Parent
))
308 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = L
'\\';
309 PathNameU
.Length
+= sizeof(WCHAR
);
311 RtlAppendUnicodeStringToString(&PathNameU
, &DirContext
->LongNameU
);
312 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = 0;
313 rcFcb
= vfatGrabFCBFromTable(DeviceExt
, &PathNameU
);
316 RtlCopyMemory(&DirContext
->DirEntry
, &rcFcb
->entry
, sizeof(DIR_ENTRY
));
317 vfatReleaseFCB(DeviceExt
, rcFcb
);
320 DPRINT("%u\n", DirContext
->LongNameU
.Length
);
321 DPRINT("FindFile: new Name %wZ, DirIndex %u\n",
322 &DirContext
->LongNameU
, DirContext
->DirIndex
);
326 CcUnpinData(Context
);
328 RtlFreeUnicodeString(&FileToFindUpcase
);
329 ExFreePool(PathNameBuffer
);
330 return STATUS_SUCCESS
;
332 DirContext
->DirIndex
++;
337 CcUnpinData(Context
);
340 RtlFreeUnicodeString(&FileToFindUpcase
);
341 ExFreePool(PathNameBuffer
);
346 * FUNCTION: Opens a file
351 PDEVICE_EXTENSION DeviceExt
,
352 PUNICODE_STRING PathNameU
,
353 PFILE_OBJECT FileObject
,
354 ULONG RequestedDisposition
,
355 BOOLEAN OpenTargetDir
,
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
;
368 (*ParentFcb
)->RefCount
++;
375 if (!DeviceExt
->FatInfo
.FixedMedia
)
377 Status
= VfatBlockDeviceIoControl(DeviceExt
->StorageDevice
,
378 IOCTL_DISK_CHECK_VERIFY
,
384 if (!NT_SUCCESS(Status
))
386 DPRINT("Status %lx\n", Status
);
394 (*ParentFcb
)->RefCount
++;
397 /* try first to find an existing FCB in memory */
398 DPRINT("Checking for existing FCB in memory\n");
400 Status
= vfatGetFCBForFile(DeviceExt
, ParentFcb
, &Fcb
, PathNameU
);
401 if (!NT_SUCCESS(Status
))
403 DPRINT ("Could not make a new FCB, status: %x\n", Status
);
407 /* In case we're to open target, just check whether file exist, but don't open it */
410 vfatReleaseFCB(DeviceExt
, Fcb
);
411 return STATUS_OBJECT_NAME_COLLISION
;
414 if (Fcb
->Flags
& FCB_DELETE_PENDING
)
416 vfatReleaseFCB(DeviceExt
, Fcb
);
417 return STATUS_DELETE_PENDING
;
420 /* Fail, if we try to overwrite a read-only file */
421 if ((*Fcb
->Attributes
& FILE_ATTRIBUTE_READONLY
) &&
422 (RequestedDisposition
== FILE_OVERWRITE
))
424 vfatReleaseFCB(DeviceExt
, Fcb
);
425 return STATUS_ACCESS_DENIED
;
428 DPRINT("Attaching FCB to fileObject\n");
429 Status
= vfatAttachFCBToFileObject(DeviceExt
, Fcb
, FileObject
);
430 if (!NT_SUCCESS(Status
))
432 vfatReleaseFCB(DeviceExt
, Fcb
);
438 * FUNCTION: Create or open a file
442 PDEVICE_OBJECT DeviceObject
,
445 PIO_STACK_LOCATION Stack
;
446 PFILE_OBJECT FileObject
;
447 NTSTATUS Status
= STATUS_SUCCESS
;
448 PDEVICE_EXTENSION DeviceExt
;
449 ULONG RequestedDisposition
, RequestedOptions
;
450 PVFATFCB pFcb
= NULL
;
451 PVFATFCB ParentFcb
= NULL
;
453 BOOLEAN PagingFileCreate
= FALSE
;
455 BOOLEAN OpenTargetDir
= FALSE
;
456 UNICODE_STRING FileNameU
;
457 UNICODE_STRING PathNameU
;
460 /* Unpack the various parameters. */
461 Stack
= IoGetCurrentIrpStackLocation(Irp
);
462 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>> 24) & 0xff);
463 RequestedOptions
= Stack
->Parameters
.Create
.Options
& FILE_VALID_OPTION_FLAGS
;
464 PagingFileCreate
= (Stack
->Flags
& SL_OPEN_PAGING_FILE
) ? TRUE
: FALSE
;
466 OpenTargetDir
= (Stack
->Flags
& SL_OPEN_TARGET_DIRECTORY
) ? TRUE
: FALSE
;
468 OpenTargetDir
= FALSE
;
470 FileObject
= Stack
->FileObject
;
471 DeviceExt
= DeviceObject
->DeviceExtension
;
473 /* Check their validity. */
474 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
475 RequestedDisposition
== FILE_SUPERSEDE
)
477 return STATUS_INVALID_PARAMETER
;
480 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
481 RequestedOptions
& FILE_NON_DIRECTORY_FILE
)
483 return STATUS_INVALID_PARAMETER
;
486 /* This a open operation for the volume itself */
487 if (FileObject
->FileName
.Length
== 0 &&
488 (FileObject
->RelatedFileObject
== NULL
|| FileObject
->RelatedFileObject
->FsContext2
!= NULL
))
490 if (RequestedDisposition
!= FILE_OPEN
&&
491 RequestedDisposition
!= FILE_OPEN_IF
)
493 return STATUS_ACCESS_DENIED
;
496 /* In spite of what is shown in WDK, it seems that Windows FAT driver doesn't perform that test */
497 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
499 return STATUS_NOT_A_DIRECTORY
;
505 return STATUS_INVALID_PARAMETER
;
508 pFcb
= DeviceExt
->VolumeFcb
;
509 vfatAttachFCBToFileObject(DeviceExt
, pFcb
, FileObject
);
512 Irp
->IoStatus
.Information
= FILE_OPENED
;
513 return STATUS_SUCCESS
;
516 /* Check for illegal characters and illegale dot sequences in the file name */
517 PathNameU
= FileObject
->FileName
;
518 c
= PathNameU
.Buffer
+ PathNameU
.Length
/ sizeof(WCHAR
);
521 while (c
-- > PathNameU
.Buffer
)
523 if (*c
== L
'\\' || c
== PathNameU
.Buffer
)
525 if (Dots
&& last
> c
)
527 return STATUS_OBJECT_NAME_INVALID
;
537 if (*c
!= '\\' && vfatIsLongIllegal(*c
))
539 return STATUS_OBJECT_NAME_INVALID
;
543 /* Check if we try to open target directory of root dir */
544 if (OpenTargetDir
&& FileObject
->RelatedFileObject
== NULL
&& PathNameU
.Length
== sizeof(WCHAR
) &&
545 PathNameU
.Buffer
[0] == L
'\\')
547 return STATUS_INVALID_PARAMETER
;
550 if (FileObject
->RelatedFileObject
&& PathNameU
.Length
>= sizeof(WCHAR
) && PathNameU
.Buffer
[0] == L
'\\')
552 return STATUS_OBJECT_NAME_INVALID
;
555 if (PathNameU
.Length
> sizeof(WCHAR
) && PathNameU
.Buffer
[PathNameU
.Length
/sizeof(WCHAR
)-1] == L
'\\')
557 PathNameU
.Length
-= sizeof(WCHAR
);
560 /* Try opening the file. */
561 Status
= VfatOpenFile(DeviceExt
, &PathNameU
, FileObject
, RequestedDisposition
, OpenTargetDir
, &ParentFcb
);
565 LONG idx
, FileNameLen
;
567 if (Status
== STATUS_OBJECT_NAME_COLLISION
)
569 Irp
->IoStatus
.Information
= FILE_EXISTS
;
573 Irp
->IoStatus
.Information
= FILE_DOES_NOT_EXIST
;
576 idx
= FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1;
578 /* Skip tailing \ - if any */
579 if (PathNameU
.Buffer
[idx
] == L
'\\')
582 PathNameU
.Length
-= sizeof(WCHAR
);
586 while (idx
>= 0 && PathNameU
.Buffer
[idx
] != L
'\\')
591 if (idx
> 0 || PathNameU
.Buffer
[0] == L
'\\')
593 /* We don't want to include / in the name */
594 FileNameLen
= PathNameU
.Length
- ((idx
+ 1) * sizeof(WCHAR
));
596 /* Try to open parent */
597 PathNameU
.Length
-= (PathNameU
.Length
- idx
* sizeof(WCHAR
));
598 Status
= VfatOpenFile(DeviceExt
, &PathNameU
, FileObject
, RequestedDisposition
, FALSE
, &ParentFcb
);
600 /* Update FO just to keep file name */
601 /* Skip first slash */
603 FileObject
->FileName
.Length
= FileNameLen
;
604 RtlMoveMemory(&PathNameU
.Buffer
[0], &PathNameU
.Buffer
[idx
], FileObject
->FileName
.Length
);
608 /* This is a relative open and we have only the filename, so open the parent directory
609 * It is in RelatedFileObject
611 BOOLEAN Chomp
= FALSE
;
612 PFILE_OBJECT RelatedFileObject
= FileObject
->RelatedFileObject
;
614 DPRINT("%wZ\n", &PathNameU
);
616 ASSERT(RelatedFileObject
!= NULL
);
618 DPRINT("Relative opening\n");
619 DPRINT("FileObject->RelatedFileObject->FileName: %wZ\n", &RelatedFileObject
->FileName
);
621 /* VfatOpenFile() doesn't like our name ends with \, so chomp it if there's one */
622 if (RelatedFileObject
->FileName
.Buffer
[RelatedFileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1] == L
'\\')
625 RelatedFileObject
->FileName
.Length
-= sizeof(WCHAR
);
628 /* Tricky part - fake our FO. It's NOT relative, we want to open the complete file path */
629 FileObject
->RelatedFileObject
= NULL
;
630 Status
= VfatOpenFile(DeviceExt
, &RelatedFileObject
->FileName
, FileObject
, RequestedDisposition
, FALSE
, &ParentFcb
);
632 /* We're done opening, restore what we broke */
633 FileObject
->RelatedFileObject
= RelatedFileObject
;
634 if (Chomp
) RelatedFileObject
->FileName
.Length
+= sizeof(WCHAR
);
636 /* No need to modify the FO, it already has the name */
643 * If the directory containing the file to open doesn't exist then
646 if (Status
== STATUS_OBJECT_PATH_NOT_FOUND
||
647 Status
== STATUS_INVALID_PARAMETER
||
648 Status
== STATUS_DELETE_PENDING
)
652 vfatReleaseFCB(DeviceExt
, ParentFcb
);
657 if (!NT_SUCCESS(Status
) && ParentFcb
== NULL
)
659 DPRINT1("VfatOpenFile failed for '%wZ', status %x\n", &PathNameU
, Status
);
663 /* If the file open failed then create the required file */
664 if (!NT_SUCCESS (Status
))
666 if (RequestedDisposition
== FILE_CREATE
||
667 RequestedDisposition
== FILE_OPEN_IF
||
668 RequestedDisposition
== FILE_OVERWRITE_IF
||
669 RequestedDisposition
== FILE_SUPERSEDE
)
671 Attributes
= Stack
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
;
672 if (!(RequestedOptions
& FILE_DIRECTORY_FILE
))
673 Attributes
|= FILE_ATTRIBUTE_ARCHIVE
;
674 vfatSplitPathName(&PathNameU
, NULL
, &FileNameU
);
675 Status
= VfatAddEntry(DeviceExt
, &FileNameU
, &pFcb
, ParentFcb
, RequestedOptions
,
676 (UCHAR
)(Attributes
& FILE_ATTRIBUTE_VALID_FLAGS
));
677 vfatReleaseFCB(DeviceExt
, ParentFcb
);
678 if (NT_SUCCESS(Status
))
680 Status
= vfatAttachFCBToFileObject(DeviceExt
, pFcb
, FileObject
);
681 if (!NT_SUCCESS(Status
))
683 vfatReleaseFCB(DeviceExt
, pFcb
);
687 Irp
->IoStatus
.Information
= FILE_CREATED
;
688 VfatSetAllocationSizeInformation(FileObject
,
691 &Irp
->Overlay
.AllocationSize
);
692 VfatSetExtendedAttributes(FileObject
,
693 Irp
->AssociatedIrp
.SystemBuffer
,
694 Stack
->Parameters
.Create
.EaLength
);
696 if (PagingFileCreate
)
698 pFcb
->Flags
|= FCB_IS_PAGE_FILE
;
710 vfatReleaseFCB(DeviceExt
, ParentFcb
);
719 vfatReleaseFCB(DeviceExt
, ParentFcb
);
722 /* Otherwise fail if the caller wanted to create a new file */
723 if (RequestedDisposition
== FILE_CREATE
)
725 Irp
->IoStatus
.Information
= FILE_EXISTS
;
726 VfatCloseFile(DeviceExt
, FileObject
);
727 return STATUS_OBJECT_NAME_COLLISION
;
730 pFcb
= FileObject
->FsContext
;
732 if (pFcb
->OpenHandleCount
!= 0)
734 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
735 Stack
->Parameters
.Create
.ShareAccess
,
737 &pFcb
->FCBShareAccess
,
739 if (!NT_SUCCESS(Status
))
741 VfatCloseFile(DeviceExt
, FileObject
);
747 * Check the file has the requested attributes
749 if (RequestedOptions
& FILE_NON_DIRECTORY_FILE
&&
750 *pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
)
752 VfatCloseFile (DeviceExt
, FileObject
);
753 return STATUS_FILE_IS_A_DIRECTORY
;
755 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
756 !(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
758 VfatCloseFile (DeviceExt
, FileObject
);
759 return STATUS_NOT_A_DIRECTORY
;
761 #ifndef USE_ROS_CC_AND_FS
762 if (!(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
764 if (Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_WRITE_DATA
||
765 RequestedDisposition
== FILE_OVERWRITE
||
766 RequestedDisposition
== FILE_OVERWRITE_IF
)
768 if (!MmFlushImageSection(&pFcb
->SectionObjectPointers
, MmFlushForWrite
))
770 DPRINT1("%wZ\n", &pFcb
->PathNameU
);
771 DPRINT1("%d %d %d\n", Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_WRITE_DATA
,
772 RequestedDisposition
== FILE_OVERWRITE
, RequestedDisposition
== FILE_OVERWRITE_IF
);
773 VfatCloseFile (DeviceExt
, FileObject
);
774 return STATUS_SHARING_VIOLATION
;
779 if (PagingFileCreate
)
782 * Do more checking for page files. It is possible,
783 * that the file was opened and closed previously
784 * as a normal cached file. In this case, the cache
785 * manager has referenced the fileobject and the fcb
786 * is held in memory. Try to remove the fileobject
787 * from cache manager and use the fcb.
789 if (pFcb
->RefCount
> 1)
791 if(!(pFcb
->Flags
& FCB_IS_PAGE_FILE
))
793 VfatCloseFile(DeviceExt
, FileObject
);
794 return STATUS_INVALID_PARAMETER
;
799 pFcb
->Flags
|= FCB_IS_PAGE_FILE
;
804 if (pFcb
->Flags
& FCB_IS_PAGE_FILE
)
806 VfatCloseFile(DeviceExt
, FileObject
);
807 return STATUS_INVALID_PARAMETER
;
811 if (RequestedDisposition
== FILE_OVERWRITE
||
812 RequestedDisposition
== FILE_OVERWRITE_IF
||
813 RequestedDisposition
== FILE_SUPERSEDE
)
815 if (!(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
817 *pFcb
->Attributes
= Stack
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
;
818 *pFcb
->Attributes
|= FILE_ATTRIBUTE_ARCHIVE
;
819 VfatUpdateEntry(pFcb
);
822 ExAcquireResourceExclusiveLite(&(pFcb
->MainResource
), TRUE
);
823 Status
= VfatSetAllocationSizeInformation(FileObject
,
826 &Irp
->Overlay
.AllocationSize
);
827 ExReleaseResourceLite(&(pFcb
->MainResource
));
828 if (!NT_SUCCESS (Status
))
830 VfatCloseFile(DeviceExt
, FileObject
);
835 if (RequestedDisposition
== FILE_SUPERSEDE
)
837 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
839 else if (RequestedDisposition
== FILE_OVERWRITE
||
840 RequestedDisposition
== FILE_OVERWRITE_IF
)
842 Irp
->IoStatus
.Information
= FILE_OVERWRITTEN
;
846 Irp
->IoStatus
.Information
= FILE_OPENED
;
850 if (pFcb
->OpenHandleCount
== 0)
852 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
853 Stack
->Parameters
.Create
.ShareAccess
,
855 &pFcb
->FCBShareAccess
);
859 IoUpdateShareAccess(FileObject
,
860 &pFcb
->FCBShareAccess
);
863 if (Irp
->IoStatus
.Information
== FILE_CREATED
)
865 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
866 &(DeviceExt
->NotifyList
),
867 (PSTRING
)&pFcb
->PathNameU
,
868 pFcb
->PathNameU
.Length
- pFcb
->LongNameU
.Length
,
871 ((*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
872 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
877 pFcb
->OpenHandleCount
++;
879 /* FIXME : test write access if requested */
885 * FUNCTION: Create or open a file
889 PVFAT_IRP_CONTEXT IrpContext
)
895 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
897 /* DeviceObject represents FileSystem instead of logical volume */
898 DPRINT ("FsdCreate called with file system\n");
899 IrpContext
->Irp
->IoStatus
.Information
= FILE_OPENED
;
900 IrpContext
->Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
901 IoCompleteRequest(IrpContext
->Irp
, IO_DISK_INCREMENT
);
902 VfatFreeIrpContext(IrpContext
);
903 return STATUS_SUCCESS
;
906 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
908 return(VfatQueueRequest(IrpContext
));
911 IrpContext
->Irp
->IoStatus
.Information
= 0;
912 ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
, TRUE
);
913 Status
= VfatCreateFile(IrpContext
->DeviceObject
, IrpContext
->Irp
);
914 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
916 IrpContext
->Irp
->IoStatus
.Status
= Status
;
917 IoCompleteRequest(IrpContext
->Irp
,
918 (CCHAR
)(NT_SUCCESS(Status
) ? IO_DISK_INCREMENT
: IO_NO_INCREMENT
));
919 VfatFreeIrpContext(IrpContext
);