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
;
114 NTSTATUS Status
= STATUS_SUCCESS
;
116 NameU
.Buffer
= Vpb
->VolumeLabel
;
118 NameU
.MaximumLength
= sizeof(Vpb
->VolumeLabel
);
119 *(Vpb
->VolumeLabel
) = 0;
120 Vpb
->VolumeLabelLength
= 0;
122 if (DeviceExt
->Flags
& VCB_IS_FATX
)
124 SizeDirEntry
= sizeof(FATX_DIR_ENTRY
);
125 EntriesPerPage
= FATX_ENTRIES_PER_PAGE
;
129 SizeDirEntry
= sizeof(FAT_DIR_ENTRY
);
130 EntriesPerPage
= FAT_ENTRIES_PER_PAGE
;
133 ExAcquireResourceExclusiveLite(&DeviceExt
->DirResource
, TRUE
);
134 pFcb
= vfatOpenRootFCB(DeviceExt
);
135 ExReleaseResourceLite(&DeviceExt
->DirResource
);
137 FileOffset
.QuadPart
= 0;
140 CcMapData(pFcb
->FileObject
, &FileOffset
, SizeDirEntry
, MAP_WAIT
, &Context
, (PVOID
*)&Entry
);
142 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
144 Status
= _SEH2_GetExceptionCode();
147 if (NT_SUCCESS(Status
))
151 if (ENTRY_VOLUME(DeviceExt
, Entry
))
153 /* copy volume label */
154 if (DeviceExt
->Flags
& VCB_IS_FATX
)
156 StringO
.Buffer
= (PCHAR
)Entry
->FatX
.Filename
;
157 StringO
.MaximumLength
= StringO
.Length
= Entry
->FatX
.FilenameLength
;
158 RtlOemStringToUnicodeString(&NameU
, &StringO
, FALSE
);
162 vfat8Dot3ToString(&Entry
->Fat
, &NameU
);
164 Vpb
->VolumeLabelLength
= NameU
.Length
;
167 if (ENTRY_END(DeviceExt
, Entry
))
172 Entry
= (PDIR_ENTRY
)((ULONG_PTR
)Entry
+ SizeDirEntry
);
173 if ((DirIndex
% EntriesPerPage
) == 0)
175 CcUnpinData(Context
);
176 FileOffset
.u
.LowPart
+= PAGE_SIZE
;
179 CcMapData(pFcb
->FileObject
, &FileOffset
, SizeDirEntry
, MAP_WAIT
, &Context
, (PVOID
*)&Entry
);
181 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
183 Status
= _SEH2_GetExceptionCode();
186 if (!NT_SUCCESS(Status
))
195 CcUnpinData(Context
);
198 ExAcquireResourceExclusiveLite(&DeviceExt
->DirResource
, TRUE
);
199 vfatReleaseFCB(DeviceExt
, pFcb
);
200 ExReleaseResourceLite(&DeviceExt
->DirResource
);
202 return STATUS_SUCCESS
;
206 * FUNCTION: Find a file
210 PDEVICE_EXTENSION DeviceExt
,
212 PUNICODE_STRING FileToFindU
,
213 PVFAT_DIRENTRY_CONTEXT DirContext
,
216 PWCHAR PathNameBuffer
;
217 USHORT PathNameBufferLength
;
219 PVOID Context
= NULL
;
223 UNICODE_STRING PathNameU
;
224 UNICODE_STRING FileToFindUpcase
;
227 DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n",
228 Parent
, FileToFindU
, DirContext
->DirIndex
);
229 DPRINT("FindFile: Path %wZ\n",&Parent
->PathNameU
);
231 PathNameBufferLength
= LONGNAME_MAX_LENGTH
* sizeof(WCHAR
);
232 PathNameBuffer
= ExAllocatePoolWithTag(NonPagedPool
, PathNameBufferLength
+ sizeof(WCHAR
), TAG_VFAT
);
235 return STATUS_INSUFFICIENT_RESOURCES
;
238 PathNameU
.Buffer
= PathNameBuffer
;
239 PathNameU
.Length
= 0;
240 PathNameU
.MaximumLength
= PathNameBufferLength
;
242 DirContext
->LongNameU
.Length
= 0;
243 DirContext
->ShortNameU
.Length
= 0;
245 WildCard
= FsRtlDoesNameContainWildCards(FileToFindU
);
247 if (WildCard
== FALSE
)
249 /* if there is no '*?' in the search name, than look first for an existing fcb */
250 RtlCopyUnicodeString(&PathNameU
, &Parent
->PathNameU
);
251 if (!vfatFCBIsRoot(Parent
))
253 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = L
'\\';
254 PathNameU
.Length
+= sizeof(WCHAR
);
256 RtlAppendUnicodeStringToString(&PathNameU
, FileToFindU
);
257 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = 0;
258 rcFcb
= vfatGrabFCBFromTable(DeviceExt
, &PathNameU
);
261 ULONG startIndex
= rcFcb
->startIndex
;
262 if ((rcFcb
->Flags
& FCB_IS_FATX_ENTRY
) && !vfatFCBIsRoot(Parent
))
266 if(startIndex
>= DirContext
->DirIndex
)
268 RtlCopyUnicodeString(&DirContext
->LongNameU
, &rcFcb
->LongNameU
);
269 RtlCopyUnicodeString(&DirContext
->ShortNameU
, &rcFcb
->ShortNameU
);
270 RtlCopyMemory(&DirContext
->DirEntry
, &rcFcb
->entry
, sizeof(DIR_ENTRY
));
271 DirContext
->StartIndex
= rcFcb
->startIndex
;
272 DirContext
->DirIndex
= rcFcb
->dirIndex
;
273 DPRINT("FindFile: new Name %wZ, DirIndex %u (%u)\n",
274 &DirContext
->LongNameU
, DirContext
->DirIndex
, DirContext
->StartIndex
);
275 Status
= STATUS_SUCCESS
;
279 DPRINT("FCB not found for %wZ\n", &PathNameU
);
280 Status
= STATUS_UNSUCCESSFUL
;
282 vfatReleaseFCB(DeviceExt
, rcFcb
);
283 ExFreePool(PathNameBuffer
);
288 /* FsRtlIsNameInExpression need the searched string to be upcase,
289 * even if IgnoreCase is specified */
290 Status
= RtlUpcaseUnicodeString(&FileToFindUpcase
, FileToFindU
, TRUE
);
291 if (!NT_SUCCESS(Status
))
293 ExFreePool(PathNameBuffer
);
299 Status
= DeviceExt
->GetNextDirEntry(&Context
, &Page
, Parent
, DirContext
, First
);
301 if (Status
== STATUS_NO_MORE_ENTRIES
)
305 if (ENTRY_VOLUME(DeviceExt
, &DirContext
->DirEntry
))
307 DirContext
->DirIndex
++;
310 if (DirContext
->LongNameU
.Length
== 0 ||
311 DirContext
->ShortNameU
.Length
== 0)
313 DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
314 if (VfatGlobalData
->Flags
& VFAT_BREAK_ON_CORRUPTION
)
316 ASSERT(DirContext
->LongNameU
.Length
!= 0 &&
317 DirContext
->ShortNameU
.Length
!= 0);
319 DirContext
->DirIndex
++;
324 Found
= FsRtlIsNameInExpression(&FileToFindUpcase
, &DirContext
->LongNameU
, TRUE
, NULL
) ||
325 FsRtlIsNameInExpression(&FileToFindUpcase
, &DirContext
->ShortNameU
, TRUE
, NULL
);
329 Found
= FsRtlAreNamesEqual(&DirContext
->LongNameU
, FileToFindU
, TRUE
, NULL
) ||
330 FsRtlAreNamesEqual(&DirContext
->ShortNameU
, FileToFindU
, TRUE
, NULL
);
337 RtlCopyUnicodeString(&PathNameU
, &Parent
->PathNameU
);
338 if (!vfatFCBIsRoot(Parent
))
340 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = L
'\\';
341 PathNameU
.Length
+= sizeof(WCHAR
);
343 RtlAppendUnicodeStringToString(&PathNameU
, &DirContext
->LongNameU
);
344 PathNameU
.Buffer
[PathNameU
.Length
/ sizeof(WCHAR
)] = 0;
345 rcFcb
= vfatGrabFCBFromTable(DeviceExt
, &PathNameU
);
348 RtlCopyMemory(&DirContext
->DirEntry
, &rcFcb
->entry
, sizeof(DIR_ENTRY
));
349 vfatReleaseFCB(DeviceExt
, rcFcb
);
352 DPRINT("%u\n", DirContext
->LongNameU
.Length
);
353 DPRINT("FindFile: new Name %wZ, DirIndex %u\n",
354 &DirContext
->LongNameU
, DirContext
->DirIndex
);
358 CcUnpinData(Context
);
360 RtlFreeUnicodeString(&FileToFindUpcase
);
361 ExFreePool(PathNameBuffer
);
362 return STATUS_SUCCESS
;
364 DirContext
->DirIndex
++;
369 CcUnpinData(Context
);
372 RtlFreeUnicodeString(&FileToFindUpcase
);
373 ExFreePool(PathNameBuffer
);
378 * FUNCTION: Opens a file
383 PDEVICE_EXTENSION DeviceExt
,
384 PUNICODE_STRING PathNameU
,
385 PFILE_OBJECT FileObject
,
386 ULONG RequestedDisposition
,
387 ULONG RequestedOptions
,
393 DPRINT("VfatOpenFile(%p, '%wZ', %p, %p)\n", DeviceExt
, PathNameU
, FileObject
, ParentFcb
);
395 if (FileObject
->RelatedFileObject
)
397 DPRINT("'%wZ'\n", &FileObject
->RelatedFileObject
->FileName
);
399 *ParentFcb
= FileObject
->RelatedFileObject
->FsContext
;
406 if (!DeviceExt
->FatInfo
.FixedMedia
)
408 Status
= VfatBlockDeviceIoControl(DeviceExt
->StorageDevice
,
409 IOCTL_DISK_CHECK_VERIFY
,
415 if (!NT_SUCCESS(Status
))
417 DPRINT("Status %lx\n", Status
);
425 vfatGrabFCB(DeviceExt
, *ParentFcb
);
428 /* try first to find an existing FCB in memory */
429 DPRINT("Checking for existing FCB in memory\n");
431 Status
= vfatGetFCBForFile(DeviceExt
, ParentFcb
, &Fcb
, PathNameU
);
432 if (!NT_SUCCESS(Status
))
434 DPRINT ("Could not make a new FCB, status: %x\n", Status
);
438 /* Fail, if we try to overwrite an existing directory */
439 if ((!(RequestedOptions
& FILE_DIRECTORY_FILE
) && (*Fcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
)) &&
440 (RequestedDisposition
== FILE_OVERWRITE
||
441 RequestedDisposition
== FILE_OVERWRITE_IF
||
442 RequestedDisposition
== FILE_SUPERSEDE
))
444 vfatReleaseFCB(DeviceExt
, Fcb
);
445 return STATUS_OBJECT_NAME_COLLISION
;
448 if (Fcb
->Flags
& FCB_DELETE_PENDING
)
450 vfatReleaseFCB(DeviceExt
, Fcb
);
451 return STATUS_DELETE_PENDING
;
454 /* Fail, if we try to overwrite a read-only file */
455 if ((*Fcb
->Attributes
& FILE_ATTRIBUTE_READONLY
) &&
456 (RequestedDisposition
== FILE_OVERWRITE
||
457 RequestedDisposition
== FILE_OVERWRITE_IF
))
459 vfatReleaseFCB(DeviceExt
, Fcb
);
460 return STATUS_ACCESS_DENIED
;
463 if ((*Fcb
->Attributes
& FILE_ATTRIBUTE_READONLY
) &&
464 (RequestedOptions
& FILE_DELETE_ON_CLOSE
))
466 vfatReleaseFCB(DeviceExt
, Fcb
);
467 return STATUS_CANNOT_DELETE
;
470 if ((vfatFCBIsRoot(Fcb
) ||
471 (Fcb
->LongNameU
.Length
== sizeof(WCHAR
) && Fcb
->LongNameU
.Buffer
[0] == L
'.') ||
472 (Fcb
->LongNameU
.Length
== 2 * sizeof(WCHAR
) && Fcb
->LongNameU
.Buffer
[0] == L
'.' && Fcb
->LongNameU
.Buffer
[1] == L
'.')) &&
473 (RequestedOptions
& FILE_DELETE_ON_CLOSE
))
475 // we cannot delete a '.', '..' or the root directory
476 vfatReleaseFCB(DeviceExt
, Fcb
);
477 return STATUS_CANNOT_DELETE
;
480 DPRINT("Attaching FCB to fileObject\n");
481 Status
= vfatAttachFCBToFileObject(DeviceExt
, Fcb
, FileObject
);
482 if (!NT_SUCCESS(Status
))
484 vfatReleaseFCB(DeviceExt
, Fcb
);
490 * FUNCTION: Create or open a file
494 PDEVICE_OBJECT DeviceObject
,
497 PIO_STACK_LOCATION Stack
;
498 PFILE_OBJECT FileObject
;
499 NTSTATUS Status
= STATUS_SUCCESS
;
500 PDEVICE_EXTENSION DeviceExt
;
501 ULONG RequestedDisposition
, RequestedOptions
;
502 PVFATFCB pFcb
= NULL
;
503 PVFATFCB ParentFcb
= NULL
;
505 BOOLEAN PagingFileCreate
;
507 BOOLEAN OpenTargetDir
;
508 UNICODE_STRING FileNameU
;
509 UNICODE_STRING PathNameU
;
512 /* Unpack the various parameters. */
513 Stack
= IoGetCurrentIrpStackLocation(Irp
);
514 RequestedDisposition
= ((Stack
->Parameters
.Create
.Options
>> 24) & 0xff);
515 RequestedOptions
= Stack
->Parameters
.Create
.Options
& FILE_VALID_OPTION_FLAGS
;
516 PagingFileCreate
= (Stack
->Flags
& SL_OPEN_PAGING_FILE
) ? TRUE
: FALSE
;
517 OpenTargetDir
= (Stack
->Flags
& SL_OPEN_TARGET_DIRECTORY
) ? TRUE
: FALSE
;
519 FileObject
= Stack
->FileObject
;
520 DeviceExt
= DeviceObject
->DeviceExtension
;
522 if (Stack
->Parameters
.Create
.Options
& FILE_OPEN_BY_FILE_ID
)
524 return STATUS_NOT_IMPLEMENTED
;
527 /* Check their validity. */
528 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
529 RequestedDisposition
== FILE_SUPERSEDE
)
531 return STATUS_INVALID_PARAMETER
;
534 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
535 RequestedOptions
& FILE_NON_DIRECTORY_FILE
)
537 return STATUS_INVALID_PARAMETER
;
540 /* Deny create if the volume is locked */
541 if (DeviceExt
->Flags
& VCB_VOLUME_LOCKED
)
543 return STATUS_ACCESS_DENIED
;
546 /* This a open operation for the volume itself */
547 if (FileObject
->FileName
.Length
== 0 &&
548 (FileObject
->RelatedFileObject
== NULL
||
549 FileObject
->RelatedFileObject
->FsContext2
!= NULL
||
550 FileObject
->RelatedFileObject
->FsContext
== DeviceExt
->VolumeFcb
))
552 DPRINT("Volume opening\n");
554 if (RequestedDisposition
!= FILE_OPEN
&&
555 RequestedDisposition
!= FILE_OPEN_IF
)
557 return STATUS_ACCESS_DENIED
;
560 /* In spite of what is shown in WDK, it seems that Windows FAT driver doesn't perform that test */
561 if (RequestedOptions
& FILE_DIRECTORY_FILE
)
563 return STATUS_NOT_A_DIRECTORY
;
569 return STATUS_INVALID_PARAMETER
;
572 if (RequestedOptions
& FILE_DELETE_ON_CLOSE
)
574 return STATUS_CANNOT_DELETE
;
577 pFcb
= DeviceExt
->VolumeFcb
;
579 if (pFcb
->OpenHandleCount
== 0)
581 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
582 Stack
->Parameters
.Create
.ShareAccess
,
584 &pFcb
->FCBShareAccess
);
588 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
589 Stack
->Parameters
.Create
.ShareAccess
,
591 &pFcb
->FCBShareAccess
,
593 if (!NT_SUCCESS(Status
))
599 vfatAttachFCBToFileObject(DeviceExt
, pFcb
, FileObject
);
600 DeviceExt
->OpenHandleCount
++;
601 pFcb
->OpenHandleCount
++;
603 Irp
->IoStatus
.Information
= FILE_OPENED
;
604 return STATUS_SUCCESS
;
607 if (FileObject
->RelatedFileObject
!= NULL
&&
608 FileObject
->RelatedFileObject
->FsContext
== DeviceExt
->VolumeFcb
)
610 ASSERT(FileObject
->FileName
.Length
!= 0);
611 return STATUS_OBJECT_PATH_NOT_FOUND
;
614 /* Check for illegal characters and illegal dot sequences in the file name */
615 PathNameU
= FileObject
->FileName
;
616 c
= PathNameU
.Buffer
+ PathNameU
.Length
/ sizeof(WCHAR
);
619 while (c
-- > PathNameU
.Buffer
)
621 if (*c
== L
'\\' || c
== PathNameU
.Buffer
)
623 if (Dots
&& last
> c
)
625 return STATUS_OBJECT_NAME_INVALID
;
635 if (*c
!= '\\' && vfatIsLongIllegal(*c
))
637 return STATUS_OBJECT_NAME_INVALID
;
641 /* Check if we try to open target directory of root dir */
642 if (OpenTargetDir
&& FileObject
->RelatedFileObject
== NULL
&& PathNameU
.Length
== sizeof(WCHAR
) &&
643 PathNameU
.Buffer
[0] == L
'\\')
645 return STATUS_INVALID_PARAMETER
;
648 if (FileObject
->RelatedFileObject
&& PathNameU
.Length
>= sizeof(WCHAR
) && PathNameU
.Buffer
[0] == L
'\\')
650 return STATUS_OBJECT_NAME_INVALID
;
653 if (PathNameU
.Length
> sizeof(WCHAR
) && PathNameU
.Buffer
[PathNameU
.Length
/sizeof(WCHAR
)-1] == L
'\\')
655 PathNameU
.Length
-= sizeof(WCHAR
);
658 if (PathNameU
.Length
> sizeof(WCHAR
) && PathNameU
.Buffer
[PathNameU
.Length
/sizeof(WCHAR
)-1] == L
'\\')
660 return STATUS_OBJECT_NAME_INVALID
;
663 /* Try opening the file. */
666 Status
= VfatOpenFile(DeviceExt
, &PathNameU
, FileObject
, RequestedDisposition
, RequestedOptions
, &ParentFcb
);
671 LONG idx
, FileNameLen
;
673 ParentFcb
= (FileObject
->RelatedFileObject
!= NULL
) ? FileObject
->RelatedFileObject
->FsContext
: NULL
;
676 vfatGrabFCB(DeviceExt
, ParentFcb
);
678 Status
= vfatGetFCBForFile(DeviceExt
, &ParentFcb
, &TargetFcb
, &PathNameU
);
680 if (NT_SUCCESS(Status
))
682 vfatReleaseFCB(DeviceExt
, TargetFcb
);
683 Irp
->IoStatus
.Information
= FILE_EXISTS
;
687 Irp
->IoStatus
.Information
= FILE_DOES_NOT_EXIST
;
690 idx
= FileObject
->FileName
.Length
/ sizeof(WCHAR
) - 1;
692 /* Skip trailing \ - if any */
693 if (PathNameU
.Buffer
[idx
] == L
'\\')
696 PathNameU
.Length
-= sizeof(WCHAR
);
700 while (idx
>= 0 && PathNameU
.Buffer
[idx
] != L
'\\')
705 if (idx
> 0 || PathNameU
.Buffer
[0] == L
'\\')
707 /* We don't want to include / in the name */
708 FileNameLen
= PathNameU
.Length
- ((idx
+ 1) * sizeof(WCHAR
));
710 /* Update FO just to keep file name */
711 /* Skip first slash */
713 FileObject
->FileName
.Length
= FileNameLen
;
714 RtlMoveMemory(&PathNameU
.Buffer
[0], &PathNameU
.Buffer
[idx
], FileObject
->FileName
.Length
);
718 /* This is a relative open and we have only the filename, so open the parent directory
719 * It is in RelatedFileObject
721 ASSERT(FileObject
->RelatedFileObject
!= NULL
);
723 /* No need to modify the FO, it already has the name */
726 /* We're done with opening! */
727 if (ParentFcb
!= NULL
)
729 Status
= vfatAttachFCBToFileObject(DeviceExt
, ParentFcb
, FileObject
);
732 if (NT_SUCCESS(Status
))
734 pFcb
= FileObject
->FsContext
;
735 ASSERT(pFcb
== ParentFcb
);
737 if (pFcb
->OpenHandleCount
== 0)
739 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
740 Stack
->Parameters
.Create
.ShareAccess
,
742 &pFcb
->FCBShareAccess
);
746 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
747 Stack
->Parameters
.Create
.ShareAccess
,
749 &pFcb
->FCBShareAccess
,
751 if (!NT_SUCCESS(Status
))
753 VfatCloseFile(DeviceExt
, FileObject
);
758 pFcb
->OpenHandleCount
++;
759 DeviceExt
->OpenHandleCount
++;
761 else if (ParentFcb
!= NULL
)
763 vfatReleaseFCB(DeviceExt
, ParentFcb
);
770 * If the directory containing the file to open doesn't exist then
773 if (Status
== STATUS_OBJECT_PATH_NOT_FOUND
||
774 Status
== STATUS_INVALID_PARAMETER
||
775 Status
== STATUS_DELETE_PENDING
||
776 Status
== STATUS_ACCESS_DENIED
||
777 Status
== STATUS_OBJECT_NAME_COLLISION
)
781 vfatReleaseFCB(DeviceExt
, ParentFcb
);
786 if (!NT_SUCCESS(Status
) && ParentFcb
== NULL
)
788 DPRINT1("VfatOpenFile failed for '%wZ', status %x\n", &PathNameU
, Status
);
792 /* If the file open failed then create the required file */
793 if (!NT_SUCCESS (Status
))
795 if (RequestedDisposition
== FILE_CREATE
||
796 RequestedDisposition
== FILE_OPEN_IF
||
797 RequestedDisposition
== FILE_OVERWRITE_IF
||
798 RequestedDisposition
== FILE_SUPERSEDE
)
800 Attributes
= Stack
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
;
801 if (!(RequestedOptions
& FILE_DIRECTORY_FILE
))
802 Attributes
|= FILE_ATTRIBUTE_ARCHIVE
;
803 vfatSplitPathName(&PathNameU
, NULL
, &FileNameU
);
804 Status
= VfatAddEntry(DeviceExt
, &FileNameU
, &pFcb
, ParentFcb
, RequestedOptions
,
805 (UCHAR
)(Attributes
& FILE_ATTRIBUTE_VALID_FLAGS
), NULL
);
806 vfatReleaseFCB(DeviceExt
, ParentFcb
);
807 if (NT_SUCCESS(Status
))
809 Status
= vfatAttachFCBToFileObject(DeviceExt
, pFcb
, FileObject
);
810 if (!NT_SUCCESS(Status
))
812 vfatReleaseFCB(DeviceExt
, pFcb
);
816 Irp
->IoStatus
.Information
= FILE_CREATED
;
817 VfatSetAllocationSizeInformation(FileObject
,
820 &Irp
->Overlay
.AllocationSize
);
821 VfatSetExtendedAttributes(FileObject
,
822 Irp
->AssociatedIrp
.SystemBuffer
,
823 Stack
->Parameters
.Create
.EaLength
);
825 if (PagingFileCreate
)
827 pFcb
->Flags
|= FCB_IS_PAGE_FILE
;
839 vfatReleaseFCB(DeviceExt
, ParentFcb
);
848 vfatReleaseFCB(DeviceExt
, ParentFcb
);
851 /* Otherwise fail if the caller wanted to create a new file */
852 if (RequestedDisposition
== FILE_CREATE
)
854 Irp
->IoStatus
.Information
= FILE_EXISTS
;
855 VfatCloseFile(DeviceExt
, FileObject
);
856 return STATUS_OBJECT_NAME_COLLISION
;
859 pFcb
= FileObject
->FsContext
;
861 if (pFcb
->OpenHandleCount
!= 0)
863 Status
= IoCheckShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
864 Stack
->Parameters
.Create
.ShareAccess
,
866 &pFcb
->FCBShareAccess
,
868 if (!NT_SUCCESS(Status
))
870 VfatCloseFile(DeviceExt
, FileObject
);
876 * Check the file has the requested attributes
878 if (RequestedOptions
& FILE_NON_DIRECTORY_FILE
&&
879 *pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
)
881 VfatCloseFile (DeviceExt
, FileObject
);
882 return STATUS_FILE_IS_A_DIRECTORY
;
884 if (RequestedOptions
& FILE_DIRECTORY_FILE
&&
885 !(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
887 VfatCloseFile (DeviceExt
, FileObject
);
888 return STATUS_NOT_A_DIRECTORY
;
890 #ifndef USE_ROS_CC_AND_FS
891 if (!(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
893 if (Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_WRITE_DATA
||
894 RequestedDisposition
== FILE_OVERWRITE
||
895 RequestedDisposition
== FILE_OVERWRITE_IF
||
896 (RequestedOptions
& FILE_DELETE_ON_CLOSE
))
898 if (!MmFlushImageSection(&pFcb
->SectionObjectPointers
, MmFlushForWrite
))
900 DPRINT1("%wZ\n", &pFcb
->PathNameU
);
901 DPRINT1("%d %d %d\n", Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
& FILE_WRITE_DATA
,
902 RequestedDisposition
== FILE_OVERWRITE
, RequestedDisposition
== FILE_OVERWRITE_IF
);
903 VfatCloseFile (DeviceExt
, FileObject
);
904 return (RequestedOptions
& FILE_DELETE_ON_CLOSE
) ? STATUS_CANNOT_DELETE
905 : STATUS_SHARING_VIOLATION
;
910 if (PagingFileCreate
)
913 * Do more checking for page files. It is possible,
914 * that the file was opened and closed previously
915 * as a normal cached file. In this case, the cache
916 * manager has referenced the fileobject and the fcb
917 * is held in memory. Try to remove the fileobject
918 * from cache manager and use the fcb.
920 if (pFcb
->RefCount
> 1)
922 if(!(pFcb
->Flags
& FCB_IS_PAGE_FILE
))
924 VfatCloseFile(DeviceExt
, FileObject
);
925 return STATUS_INVALID_PARAMETER
;
930 pFcb
->Flags
|= FCB_IS_PAGE_FILE
;
935 if (pFcb
->Flags
& FCB_IS_PAGE_FILE
)
937 VfatCloseFile(DeviceExt
, FileObject
);
938 return STATUS_INVALID_PARAMETER
;
942 if (RequestedDisposition
== FILE_OVERWRITE
||
943 RequestedDisposition
== FILE_OVERWRITE_IF
||
944 RequestedDisposition
== FILE_SUPERSEDE
)
946 if (!(*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
))
948 *pFcb
->Attributes
= Stack
->Parameters
.Create
.FileAttributes
& ~FILE_ATTRIBUTE_NORMAL
;
949 *pFcb
->Attributes
|= FILE_ATTRIBUTE_ARCHIVE
;
950 VfatUpdateEntry(pFcb
);
953 ExAcquireResourceExclusiveLite(&(pFcb
->MainResource
), TRUE
);
954 Status
= VfatSetAllocationSizeInformation(FileObject
,
957 &Irp
->Overlay
.AllocationSize
);
958 ExReleaseResourceLite(&(pFcb
->MainResource
));
959 if (!NT_SUCCESS (Status
))
961 VfatCloseFile(DeviceExt
, FileObject
);
966 if (RequestedDisposition
== FILE_SUPERSEDE
)
968 Irp
->IoStatus
.Information
= FILE_SUPERSEDED
;
970 else if (RequestedDisposition
== FILE_OVERWRITE
||
971 RequestedDisposition
== FILE_OVERWRITE_IF
)
973 Irp
->IoStatus
.Information
= FILE_OVERWRITTEN
;
977 Irp
->IoStatus
.Information
= FILE_OPENED
;
981 if (pFcb
->OpenHandleCount
== 0)
983 IoSetShareAccess(Stack
->Parameters
.Create
.SecurityContext
->DesiredAccess
,
984 Stack
->Parameters
.Create
.ShareAccess
,
986 &pFcb
->FCBShareAccess
);
990 IoUpdateShareAccess(FileObject
,
991 &pFcb
->FCBShareAccess
);
994 if (Irp
->IoStatus
.Information
== FILE_CREATED
)
996 FsRtlNotifyFullReportChange(DeviceExt
->NotifySync
,
997 &(DeviceExt
->NotifyList
),
998 (PSTRING
)&pFcb
->PathNameU
,
999 pFcb
->PathNameU
.Length
- pFcb
->LongNameU
.Length
,
1002 ((*pFcb
->Attributes
& FILE_ATTRIBUTE_DIRECTORY
) ?
1003 FILE_NOTIFY_CHANGE_DIR_NAME
: FILE_NOTIFY_CHANGE_FILE_NAME
),
1008 pFcb
->OpenHandleCount
++;
1009 DeviceExt
->OpenHandleCount
++;
1011 /* FIXME : test write access if requested */
1017 * FUNCTION: Create or open a file
1021 PVFAT_IRP_CONTEXT IrpContext
)
1027 if (IrpContext
->DeviceObject
== VfatGlobalData
->DeviceObject
)
1029 /* DeviceObject represents FileSystem instead of logical volume */
1030 DPRINT ("FsdCreate called with file system\n");
1031 IrpContext
->Irp
->IoStatus
.Information
= FILE_OPENED
;
1032 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;
1034 return STATUS_SUCCESS
;
1037 if (!(IrpContext
->Flags
& IRPCONTEXT_CANWAIT
))
1039 return VfatMarkIrpContextForQueue(IrpContext
);
1042 IrpContext
->Irp
->IoStatus
.Information
= 0;
1043 ExAcquireResourceExclusiveLite(&IrpContext
->DeviceExt
->DirResource
, TRUE
);
1044 Status
= VfatCreateFile(IrpContext
->DeviceObject
, IrpContext
->Irp
);
1045 ExReleaseResourceLite(&IrpContext
->DeviceExt
->DirResource
);
1047 if (NT_SUCCESS(Status
))
1048 IrpContext
->PriorityBoost
= IO_DISK_INCREMENT
;