/* * ReactOS kernel * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * PROJECT: ReactOS kernel * FILE: drivers/filesystems/fastfat/create.c * PURPOSE: VFAT Filesystem * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) * Pierre Schweitzer (pierre@reactos.org) */ /* INCLUDES *****************************************************************/ #include "vfat.h" #define NDEBUG #include /* FUNCTIONS *****************************************************************/ VOID vfat8Dot3ToString( PFAT_DIR_ENTRY pEntry, PUNICODE_STRING NameU) { OEM_STRING StringA; USHORT Length; CHAR cString[12]; RtlCopyMemory(cString, pEntry->ShortName, 11); cString[11] = 0; if (cString[0] == 0x05) { cString[0] = 0xe5; } StringA.Buffer = cString; for (StringA.Length = 0; StringA.Length < 8 && StringA.Buffer[StringA.Length] != ' '; StringA.Length++); StringA.MaximumLength = StringA.Length; RtlOemStringToUnicodeString(NameU, &StringA, FALSE); if (BooleanFlagOn(pEntry->lCase, VFAT_CASE_LOWER_BASE)) { RtlDowncaseUnicodeString(NameU, NameU, FALSE); } if (cString[8] != ' ') { Length = NameU->Length; NameU->Buffer += Length / sizeof(WCHAR); if (!FAT_ENTRY_VOLUME(pEntry)) { Length += sizeof(WCHAR); NameU->Buffer[0] = L'.'; NameU->Buffer++; } NameU->Length = 0; NameU->MaximumLength -= Length; StringA.Buffer = &cString[8]; for (StringA.Length = 0; StringA.Length < 3 && StringA.Buffer[StringA.Length] != ' '; StringA.Length++); StringA.MaximumLength = StringA.Length; RtlOemStringToUnicodeString(NameU, &StringA, FALSE); if (BooleanFlagOn(pEntry->lCase, VFAT_CASE_LOWER_EXT)) { RtlDowncaseUnicodeString(NameU, NameU, FALSE); } NameU->Buffer -= Length / sizeof(WCHAR); NameU->Length += Length; NameU->MaximumLength += Length; } NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0; DPRINT("'%wZ'\n", NameU); } /* * FUNCTION: Find a file */ NTSTATUS FindFile( PDEVICE_EXTENSION DeviceExt, PVFATFCB Parent, PUNICODE_STRING FileToFindU, PVFAT_DIRENTRY_CONTEXT DirContext, BOOLEAN First) { PWCHAR PathNameBuffer; USHORT PathNameBufferLength; NTSTATUS Status; PVOID Context = NULL; PVOID Page; PVFATFCB rcFcb; BOOLEAN Found; UNICODE_STRING PathNameU; UNICODE_STRING FileToFindUpcase; BOOLEAN WildCard; BOOLEAN IsFatX = vfatVolumeIsFatX(DeviceExt); DPRINT("FindFile(Parent %p, FileToFind '%wZ', DirIndex: %u)\n", Parent, FileToFindU, DirContext->DirIndex); DPRINT("FindFile: Path %wZ\n",&Parent->PathNameU); PathNameBufferLength = LONGNAME_MAX_LENGTH * sizeof(WCHAR); PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameBufferLength + sizeof(WCHAR), TAG_NAME); if (!PathNameBuffer) { return STATUS_INSUFFICIENT_RESOURCES; } PathNameU.Buffer = PathNameBuffer; PathNameU.Length = 0; PathNameU.MaximumLength = PathNameBufferLength; DirContext->LongNameU.Length = 0; DirContext->ShortNameU.Length = 0; WildCard = FsRtlDoesNameContainWildCards(FileToFindU); if (WildCard == FALSE) { /* if there is no '*?' in the search name, than look first for an existing fcb */ RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU); if (!vfatFCBIsRoot(Parent)) { PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\'; PathNameU.Length += sizeof(WCHAR); } RtlAppendUnicodeStringToString(&PathNameU, FileToFindU); PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0; rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU); if (rcFcb) { ULONG startIndex = rcFcb->startIndex; if (IsFatX && !vfatFCBIsRoot(Parent)) { startIndex += 2; } if(startIndex >= DirContext->DirIndex) { RtlCopyUnicodeString(&DirContext->LongNameU, &rcFcb->LongNameU); RtlCopyUnicodeString(&DirContext->ShortNameU, &rcFcb->ShortNameU); RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY)); DirContext->StartIndex = rcFcb->startIndex; DirContext->DirIndex = rcFcb->dirIndex; DPRINT("FindFile: new Name %wZ, DirIndex %u (%u)\n", &DirContext->LongNameU, DirContext->DirIndex, DirContext->StartIndex); Status = STATUS_SUCCESS; } else { DPRINT("FCB not found for %wZ\n", &PathNameU); Status = STATUS_UNSUCCESSFUL; } vfatReleaseFCB(DeviceExt, rcFcb); ExFreePoolWithTag(PathNameBuffer, TAG_NAME); return Status; } } /* FsRtlIsNameInExpression need the searched string to be upcase, * even if IgnoreCase is specified */ Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFindU, TRUE); if (!NT_SUCCESS(Status)) { ExFreePoolWithTag(PathNameBuffer, TAG_NAME); return Status; } while (TRUE) { Status = VfatGetNextDirEntry(DeviceExt, &Context, &Page, Parent, DirContext, First); First = FALSE; if (Status == STATUS_NO_MORE_ENTRIES) { break; } if (ENTRY_VOLUME(IsFatX, &DirContext->DirEntry)) { DirContext->DirIndex++; continue; } if (DirContext->LongNameU.Length == 0 || DirContext->ShortNameU.Length == 0) { DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n"); if (VfatGlobalData->Flags & VFAT_BREAK_ON_CORRUPTION) { ASSERT(DirContext->LongNameU.Length != 0 && DirContext->ShortNameU.Length != 0); } DirContext->DirIndex++; continue; } if (WildCard) { Found = FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->LongNameU, TRUE, NULL) || FsRtlIsNameInExpression(&FileToFindUpcase, &DirContext->ShortNameU, TRUE, NULL); } else { Found = FsRtlAreNamesEqual(&DirContext->LongNameU, FileToFindU, TRUE, NULL) || FsRtlAreNamesEqual(&DirContext->ShortNameU, FileToFindU, TRUE, NULL); } if (Found) { if (WildCard) { RtlCopyUnicodeString(&PathNameU, &Parent->PathNameU); if (!vfatFCBIsRoot(Parent)) { PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = L'\\'; PathNameU.Length += sizeof(WCHAR); } RtlAppendUnicodeStringToString(&PathNameU, &DirContext->LongNameU); PathNameU.Buffer[PathNameU.Length / sizeof(WCHAR)] = 0; rcFcb = vfatGrabFCBFromTable(DeviceExt, &PathNameU); if (rcFcb != NULL) { RtlCopyMemory(&DirContext->DirEntry, &rcFcb->entry, sizeof(DIR_ENTRY)); vfatReleaseFCB(DeviceExt, rcFcb); } } DPRINT("%u\n", DirContext->LongNameU.Length); DPRINT("FindFile: new Name %wZ, DirIndex %u\n", &DirContext->LongNameU, DirContext->DirIndex); if (Context) { CcUnpinData(Context); } RtlFreeUnicodeString(&FileToFindUpcase); ExFreePoolWithTag(PathNameBuffer, TAG_NAME); return STATUS_SUCCESS; } DirContext->DirIndex++; } if (Context) { CcUnpinData(Context); } RtlFreeUnicodeString(&FileToFindUpcase); ExFreePoolWithTag(PathNameBuffer, TAG_NAME); return Status; } /* * FUNCTION: Opens a file */ static NTSTATUS VfatOpenFile( PDEVICE_EXTENSION DeviceExt, PUNICODE_STRING PathNameU, PFILE_OBJECT FileObject, ULONG RequestedDisposition, ULONG RequestedOptions, PVFATFCB *ParentFcb) { PVFATFCB Fcb; NTSTATUS Status; DPRINT("VfatOpenFile(%p, '%wZ', %p, %p)\n", DeviceExt, PathNameU, FileObject, ParentFcb); if (FileObject->RelatedFileObject) { DPRINT("'%wZ'\n", &FileObject->RelatedFileObject->FileName); *ParentFcb = FileObject->RelatedFileObject->FsContext; } else { *ParentFcb = NULL; } if (!DeviceExt->FatInfo.FixedMedia) { Status = VfatBlockDeviceIoControl(DeviceExt->StorageDevice, IOCTL_DISK_CHECK_VERIFY, NULL, 0, NULL, 0, FALSE); if (!NT_SUCCESS(Status)) { DPRINT("Status %lx\n", Status); *ParentFcb = NULL; return Status; } } if (*ParentFcb) { vfatGrabFCB(DeviceExt, *ParentFcb); } /* try first to find an existing FCB in memory */ DPRINT("Checking for existing FCB in memory\n"); Status = vfatGetFCBForFile(DeviceExt, ParentFcb, &Fcb, PathNameU); if (!NT_SUCCESS(Status)) { DPRINT ("Could not make a new FCB, status: %x\n", Status); return Status; } /* Fail, if we try to overwrite an existing directory */ if ((!BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && vfatFCBIsDirectory(Fcb)) && (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE)) { vfatReleaseFCB(DeviceExt, Fcb); return STATUS_OBJECT_NAME_COLLISION; } if (BooleanFlagOn(Fcb->Flags, FCB_DELETE_PENDING)) { vfatReleaseFCB(DeviceExt, Fcb); return STATUS_DELETE_PENDING; } /* Fail, if we try to overwrite a read-only file */ if (vfatFCBIsReadOnly(Fcb) && (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF)) { vfatReleaseFCB(DeviceExt, Fcb); return STATUS_ACCESS_DENIED; } if (vfatFCBIsReadOnly(Fcb) && (RequestedOptions & FILE_DELETE_ON_CLOSE)) { vfatReleaseFCB(DeviceExt, Fcb); return STATUS_CANNOT_DELETE; } if ((vfatFCBIsRoot(Fcb) || IsDotOrDotDot(&Fcb->LongNameU)) && BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) { // we cannot delete a '.', '..' or the root directory vfatReleaseFCB(DeviceExt, Fcb); return STATUS_CANNOT_DELETE; } /* If that one was marked for closing, remove it */ if (BooleanFlagOn(Fcb->Flags, FCB_DELAYED_CLOSE)) { BOOLEAN ConcurrentDeletion; PVFAT_CLOSE_CONTEXT CloseContext; /* Get the context */ CloseContext = Fcb->CloseContext; /* Is someone already taking over? */ if (CloseContext != NULL) { ConcurrentDeletion = FALSE; /* Lock list */ ExAcquireFastMutex(&VfatGlobalData->CloseMutex); /* Check whether it was already removed, if not, do it */ if (!IsListEmpty(&CloseContext->CloseListEntry)) { RemoveEntryList(&CloseContext->CloseListEntry); --VfatGlobalData->CloseCount; ConcurrentDeletion = TRUE; } ExReleaseFastMutex(&VfatGlobalData->CloseMutex); /* It's not delayed anymore! */ ClearFlag(Fcb->Flags, FCB_DELAYED_CLOSE); /* Release the extra reference (would have been removed by IRP_MJ_CLOSE) */ vfatReleaseFCB(DeviceExt, Fcb); Fcb->CloseContext = NULL; /* If no concurrent deletion, free work item */ if (!ConcurrentDeletion) { ExFreeToPagedLookasideList(&VfatGlobalData->CloseContextLookasideList, CloseContext); } } DPRINT("Reusing delayed close FCB for %wZ\n", &Fcb->PathNameU); } DPRINT("Attaching FCB to fileObject\n"); Status = vfatAttachFCBToFileObject(DeviceExt, Fcb, FileObject); if (!NT_SUCCESS(Status)) { vfatReleaseFCB(DeviceExt, Fcb); } return Status; } /* * FUNCTION: Create or open a file */ static NTSTATUS VfatCreateFile( PDEVICE_OBJECT DeviceObject, PIRP Irp) { PIO_STACK_LOCATION Stack; PFILE_OBJECT FileObject; NTSTATUS Status = STATUS_SUCCESS; PDEVICE_EXTENSION DeviceExt; ULONG RequestedDisposition, RequestedOptions; PVFATFCB pFcb = NULL; PVFATFCB ParentFcb = NULL; PVFATCCB pCcb = NULL; PWCHAR c, last; BOOLEAN PagingFileCreate; BOOLEAN Dots; BOOLEAN OpenTargetDir; BOOLEAN TrailingBackslash; UNICODE_STRING FileNameU; UNICODE_STRING PathNameU; ULONG Attributes; /* Unpack the various parameters. */ Stack = IoGetCurrentIrpStackLocation(Irp); RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff); RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS; PagingFileCreate = BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE); OpenTargetDir = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY); FileObject = Stack->FileObject; DeviceExt = DeviceObject->DeviceExtension; if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID)) { return STATUS_NOT_IMPLEMENTED; } /* Check their validity. */ if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && RequestedDisposition == FILE_SUPERSEDE) { return STATUS_INVALID_PARAMETER; } if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && BooleanFlagOn(RequestedOptions, FILE_NON_DIRECTORY_FILE)) { return STATUS_INVALID_PARAMETER; } /* Deny create if the volume is locked */ if (BooleanFlagOn(DeviceExt->Flags, VCB_VOLUME_LOCKED)) { return STATUS_ACCESS_DENIED; } /* This a open operation for the volume itself */ if (FileObject->FileName.Length == 0 && (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 != NULL || FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb)) { DPRINT("Volume opening\n"); if (RequestedDisposition != FILE_OPEN && RequestedDisposition != FILE_OPEN_IF) { return STATUS_ACCESS_DENIED; } if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && (FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 == NULL || FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb)) { return STATUS_NOT_A_DIRECTORY; } if (OpenTargetDir) { return STATUS_INVALID_PARAMETER; } if (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) { return STATUS_CANNOT_DELETE; } vfatAddToStat(DeviceExt, Fat.CreateHits, 1); pFcb = DeviceExt->VolumeFcb; if (pFcb->OpenHandleCount == 0) { IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, Stack->Parameters.Create.ShareAccess, FileObject, &pFcb->FCBShareAccess); } else { Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, Stack->Parameters.Create.ShareAccess, FileObject, &pFcb->FCBShareAccess, TRUE); if (!NT_SUCCESS(Status)) { vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return Status; } } vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject); DeviceExt->OpenHandleCount++; pFcb->OpenHandleCount++; vfatAddToStat(DeviceExt, Fat.SuccessfulCreates, 1); Irp->IoStatus.Information = FILE_OPENED; return STATUS_SUCCESS; } if (FileObject->RelatedFileObject != NULL && FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb) { ASSERT(FileObject->FileName.Length != 0); return STATUS_OBJECT_PATH_NOT_FOUND; } /* Check for illegal characters and illegal dot sequences in the file name */ PathNameU = FileObject->FileName; c = PathNameU.Buffer + PathNameU.Length / sizeof(WCHAR); last = c - 1; Dots = TRUE; while (c-- > PathNameU.Buffer) { if (*c == L'\\' || c == PathNameU.Buffer) { if (Dots && last > c) { return STATUS_OBJECT_NAME_INVALID; } if (*c == L'\\' && (c - 1) > PathNameU.Buffer && *(c - 1) == L'\\') { return STATUS_OBJECT_NAME_INVALID; } last = c - 1; Dots = TRUE; } else if (*c != L'.') { Dots = FALSE; } if (*c != '\\' && vfatIsLongIllegal(*c)) { return STATUS_OBJECT_NAME_INVALID; } } /* Check if we try to open target directory of root dir */ if (OpenTargetDir && FileObject->RelatedFileObject == NULL && PathNameU.Length == sizeof(WCHAR) && PathNameU.Buffer[0] == L'\\') { return STATUS_INVALID_PARAMETER; } if (FileObject->RelatedFileObject && PathNameU.Length >= sizeof(WCHAR) && PathNameU.Buffer[0] == L'\\') { return STATUS_OBJECT_NAME_INVALID; } TrailingBackslash = FALSE; if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\') { PathNameU.Length -= sizeof(WCHAR); TrailingBackslash = TRUE; } if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\') { return STATUS_OBJECT_NAME_INVALID; } /* Try opening the file. */ if (!OpenTargetDir) { vfatAddToStat(DeviceExt, Fat.CreateHits, 1); Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, RequestedOptions, &ParentFcb); } else { PVFATFCB TargetFcb; LONG idx, FileNameLen; vfatAddToStat(DeviceExt, Fat.CreateHits, 1); ParentFcb = (FileObject->RelatedFileObject != NULL) ? FileObject->RelatedFileObject->FsContext : NULL; if (ParentFcb) { vfatGrabFCB(DeviceExt, ParentFcb); } Status = vfatGetFCBForFile(DeviceExt, &ParentFcb, &TargetFcb, &PathNameU); if (NT_SUCCESS(Status)) { vfatReleaseFCB(DeviceExt, TargetFcb); Irp->IoStatus.Information = FILE_EXISTS; } else { Irp->IoStatus.Information = FILE_DOES_NOT_EXIST; } idx = FileObject->FileName.Length / sizeof(WCHAR) - 1; /* Skip trailing \ - if any */ if (PathNameU.Buffer[idx] == L'\\') { --idx; PathNameU.Length -= sizeof(WCHAR); } /* Get file name */ while (idx >= 0 && PathNameU.Buffer[idx] != L'\\') { --idx; } if (idx > 0 || PathNameU.Buffer[0] == L'\\') { /* We don't want to include / in the name */ FileNameLen = PathNameU.Length - ((idx + 1) * sizeof(WCHAR)); /* Update FO just to keep file name */ /* Skip first slash */ ++idx; FileObject->FileName.Length = FileNameLen; RtlMoveMemory(&PathNameU.Buffer[0], &PathNameU.Buffer[idx], FileObject->FileName.Length); #if 0 /* Terminate the string at the last backslash */ PathNameU.Buffer[idx + 1] = UNICODE_NULL; PathNameU.Length = (idx + 1) * sizeof(WCHAR); PathNameU.MaximumLength = PathNameU.Length + sizeof(WCHAR); /* Update the file object as well */ FileObject->FileName.Length = PathNameU.Length; FileObject->FileName.MaximumLength = PathNameU.MaximumLength; #endif } else { /* This is a relative open and we have only the filename, so open the parent directory * It is in RelatedFileObject */ ASSERT(FileObject->RelatedFileObject != NULL); /* No need to modify the FO, it already has the name */ } /* We're done with opening! */ if (ParentFcb != NULL) { Status = vfatAttachFCBToFileObject(DeviceExt, ParentFcb, FileObject); } if (NT_SUCCESS(Status)) { pFcb = FileObject->FsContext; ASSERT(pFcb == ParentFcb); if (pFcb->OpenHandleCount == 0) { IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, Stack->Parameters.Create.ShareAccess, FileObject, &pFcb->FCBShareAccess); } else { Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, Stack->Parameters.Create.ShareAccess, FileObject, &pFcb->FCBShareAccess, FALSE); if (!NT_SUCCESS(Status)) { VfatCloseFile(DeviceExt, FileObject); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return Status; } } pCcb = FileObject->FsContext2; if (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) { pCcb->Flags |= CCB_DELETE_ON_CLOSE; } pFcb->OpenHandleCount++; DeviceExt->OpenHandleCount++; } else if (ParentFcb != NULL) { vfatReleaseFCB(DeviceExt, ParentFcb); } if (NT_SUCCESS(Status)) { vfatAddToStat(DeviceExt, Fat.SuccessfulCreates, 1); } else { vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); } return Status; } /* * If the directory containing the file to open doesn't exist then * fail immediately */ if (Status == STATUS_OBJECT_PATH_NOT_FOUND || Status == STATUS_INVALID_PARAMETER || Status == STATUS_DELETE_PENDING || Status == STATUS_ACCESS_DENIED || Status == STATUS_OBJECT_NAME_COLLISION) { if (ParentFcb) { vfatReleaseFCB(DeviceExt, ParentFcb); } vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return Status; } if (!NT_SUCCESS(Status) && ParentFcb == NULL) { DPRINT1("VfatOpenFile failed for '%wZ', status %x\n", &PathNameU, Status); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return Status; } Attributes = (Stack->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY)); /* If the file open failed then create the required file */ if (!NT_SUCCESS (Status)) { if (RequestedDisposition == FILE_CREATE || RequestedDisposition == FILE_OPEN_IF || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) { if (!BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE)) { if (TrailingBackslash) { vfatReleaseFCB(DeviceExt, ParentFcb); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return STATUS_OBJECT_NAME_INVALID; } Attributes |= FILE_ATTRIBUTE_ARCHIVE; } vfatSplitPathName(&PathNameU, NULL, &FileNameU); if (IsDotOrDotDot(&FileNameU)) { vfatReleaseFCB(DeviceExt, ParentFcb); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return STATUS_OBJECT_NAME_INVALID; } Status = VfatAddEntry(DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions, Attributes, NULL); vfatReleaseFCB(DeviceExt, ParentFcb); if (NT_SUCCESS(Status)) { Status = vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject); if (!NT_SUCCESS(Status)) { vfatReleaseFCB(DeviceExt, pFcb); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return Status; } Irp->IoStatus.Information = FILE_CREATED; VfatSetAllocationSizeInformation(FileObject, pFcb, DeviceExt, &Irp->Overlay.AllocationSize); VfatSetExtendedAttributes(FileObject, Irp->AssociatedIrp.SystemBuffer, Stack->Parameters.Create.EaLength); if (PagingFileCreate) { pFcb->Flags |= FCB_IS_PAGE_FILE; SetFlag(DeviceExt->Flags, VCB_IS_SYS_OR_HAS_PAGE); } } else { vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return Status; } } else { vfatReleaseFCB(DeviceExt, ParentFcb); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return Status; } } else { if (ParentFcb) { vfatReleaseFCB(DeviceExt, ParentFcb); } pFcb = FileObject->FsContext; /* Otherwise fail if the caller wanted to create a new file */ if (RequestedDisposition == FILE_CREATE) { VfatCloseFile(DeviceExt, FileObject); if (TrailingBackslash && !vfatFCBIsDirectory(pFcb)) { vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return STATUS_OBJECT_NAME_INVALID; } Irp->IoStatus.Information = FILE_EXISTS; vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return STATUS_OBJECT_NAME_COLLISION; } if (pFcb->OpenHandleCount != 0) { Status = IoCheckShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, Stack->Parameters.Create.ShareAccess, FileObject, &pFcb->FCBShareAccess, FALSE); if (!NT_SUCCESS(Status)) { VfatCloseFile(DeviceExt, FileObject); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return Status; } } /* * Check the file has the requested attributes */ if (BooleanFlagOn(RequestedOptions, FILE_NON_DIRECTORY_FILE) && vfatFCBIsDirectory(pFcb)) { VfatCloseFile (DeviceExt, FileObject); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return STATUS_FILE_IS_A_DIRECTORY; } if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && !vfatFCBIsDirectory(pFcb)) { VfatCloseFile (DeviceExt, FileObject); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return STATUS_NOT_A_DIRECTORY; } if (TrailingBackslash && !vfatFCBIsDirectory(pFcb)) { VfatCloseFile (DeviceExt, FileObject); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return STATUS_OBJECT_NAME_INVALID; } #ifndef USE_ROS_CC_AND_FS if (!vfatFCBIsDirectory(pFcb)) { if (BooleanFlagOn(Stack->Parameters.Create.SecurityContext->DesiredAccess, FILE_WRITE_DATA) || RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || (RequestedOptions & FILE_DELETE_ON_CLOSE)) { if (!MmFlushImageSection(&pFcb->SectionObjectPointers, MmFlushForWrite)) { DPRINT1("%wZ\n", &pFcb->PathNameU); DPRINT1("%d %d %d\n", Stack->Parameters.Create.SecurityContext->DesiredAccess & FILE_WRITE_DATA, RequestedDisposition == FILE_OVERWRITE, RequestedDisposition == FILE_OVERWRITE_IF); VfatCloseFile (DeviceExt, FileObject); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) ? STATUS_CANNOT_DELETE : STATUS_SHARING_VIOLATION; } } } #endif if (PagingFileCreate) { /* FIXME: * Do more checking for page files. It is possible, * that the file was opened and closed previously * as a normal cached file. In this case, the cache * manager has referenced the fileobject and the fcb * is held in memory. Try to remove the fileobject * from cache manager and use the fcb. */ if (pFcb->RefCount > 1) { if(!BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE)) { VfatCloseFile(DeviceExt, FileObject); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return STATUS_INVALID_PARAMETER; } } else { pFcb->Flags |= FCB_IS_PAGE_FILE; SetFlag(DeviceExt->Flags, VCB_IS_SYS_OR_HAS_PAGE); } } else { if (BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE)) { VfatCloseFile(DeviceExt, FileObject); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return STATUS_INVALID_PARAMETER; } } if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF || RequestedDisposition == FILE_SUPERSEDE) { if ((BooleanFlagOn(*pFcb->Attributes, FILE_ATTRIBUTE_HIDDEN) && !BooleanFlagOn(Attributes, FILE_ATTRIBUTE_HIDDEN)) || (BooleanFlagOn(*pFcb->Attributes, FILE_ATTRIBUTE_SYSTEM) && !BooleanFlagOn(Attributes, FILE_ATTRIBUTE_SYSTEM))) { VfatCloseFile(DeviceExt, FileObject); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return STATUS_ACCESS_DENIED; } if (!vfatFCBIsDirectory(pFcb)) { LARGE_INTEGER SystemTime; if (RequestedDisposition == FILE_SUPERSEDE) { *pFcb->Attributes = Attributes; } else { *pFcb->Attributes |= Attributes; } *pFcb->Attributes |= FILE_ATTRIBUTE_ARCHIVE; KeQuerySystemTime(&SystemTime); if (vfatVolumeIsFatX(DeviceExt)) { FsdSystemTimeToDosDateTime(DeviceExt, &SystemTime, &pFcb->entry.FatX.UpdateDate, &pFcb->entry.FatX.UpdateTime); } else { FsdSystemTimeToDosDateTime(DeviceExt, &SystemTime, &pFcb->entry.Fat.UpdateDate, &pFcb->entry.Fat.UpdateTime); } VfatUpdateEntry(DeviceExt, pFcb); } ExAcquireResourceExclusiveLite(&(pFcb->MainResource), TRUE); Status = VfatSetAllocationSizeInformation(FileObject, pFcb, DeviceExt, &Irp->Overlay.AllocationSize); ExReleaseResourceLite(&(pFcb->MainResource)); if (!NT_SUCCESS (Status)) { VfatCloseFile(DeviceExt, FileObject); vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); return Status; } } if (RequestedDisposition == FILE_SUPERSEDE) { Irp->IoStatus.Information = FILE_SUPERSEDED; } else if (RequestedDisposition == FILE_OVERWRITE || RequestedDisposition == FILE_OVERWRITE_IF) { Irp->IoStatus.Information = FILE_OVERWRITTEN; } else { Irp->IoStatus.Information = FILE_OPENED; } } if (pFcb->OpenHandleCount == 0) { IoSetShareAccess(Stack->Parameters.Create.SecurityContext->DesiredAccess, Stack->Parameters.Create.ShareAccess, FileObject, &pFcb->FCBShareAccess); } else { IoUpdateShareAccess(FileObject, &pFcb->FCBShareAccess); } pCcb = FileObject->FsContext2; if (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) { pCcb->Flags |= CCB_DELETE_ON_CLOSE; } if (Irp->IoStatus.Information == FILE_CREATED) { vfatReportChange(DeviceExt, pFcb, (vfatFCBIsDirectory(pFcb) ? FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME), FILE_ACTION_ADDED); } else if (Irp->IoStatus.Information == FILE_OVERWRITTEN || Irp->IoStatus.Information == FILE_SUPERSEDED) { vfatReportChange(DeviceExt, pFcb, FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE, FILE_ACTION_MODIFIED); } pFcb->OpenHandleCount++; DeviceExt->OpenHandleCount++; /* FIXME : test write access if requested */ /* FIXME: That is broken, we cannot reach this code path with failure */ ASSERT(NT_SUCCESS(Status)); if (NT_SUCCESS(Status)) { vfatAddToStat(DeviceExt, Fat.SuccessfulCreates, 1); } else { vfatAddToStat(DeviceExt, Fat.FailedCreates, 1); } return Status; } /* * FUNCTION: Create or open a file */ NTSTATUS VfatCreate( PVFAT_IRP_CONTEXT IrpContext) { NTSTATUS Status; ASSERT(IrpContext); if (IrpContext->DeviceObject == VfatGlobalData->DeviceObject) { /* DeviceObject represents FileSystem instead of logical volume */ DPRINT ("FsdCreate called with file system\n"); IrpContext->Irp->IoStatus.Information = FILE_OPENED; IrpContext->PriorityBoost = IO_DISK_INCREMENT; return STATUS_SUCCESS; } IrpContext->Irp->IoStatus.Information = 0; ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE); Status = VfatCreateFile(IrpContext->DeviceObject, IrpContext->Irp); ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource); if (NT_SUCCESS(Status)) IrpContext->PriorityBoost = IO_DISK_INCREMENT; return Status; } /* EOF */