2002-08-14 20:58:39 +00:00
|
|
|
/*
|
2022-09-24 13:24:08 +00:00
|
|
|
* PROJECT: VFAT Filesystem
|
|
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
|
|
* PURPOSE: File creation routines
|
|
|
|
* COPYRIGHT: Copyright 1998 Jason Filby <jasonfilby@yahoo.com>
|
|
|
|
* Copyright 2010-2019 Pierre Schweitzer <pierre@reactos.org>
|
1999-12-11 21:14:49 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
|
|
|
#include "vfat.h"
|
|
|
|
|
2013-12-19 16:20:28 +00:00
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
2001-03-13 16:25:55 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
1999-12-11 21:14:49 +00:00
|
|
|
|
2013-12-09 10:35:15 +00:00
|
|
|
VOID
|
|
|
|
vfat8Dot3ToString(
|
|
|
|
PFAT_DIR_ENTRY pEntry,
|
|
|
|
PUNICODE_STRING NameU)
|
2001-05-02 03:18:03 +00:00
|
|
|
{
|
2013-12-09 10:35:15 +00:00
|
|
|
OEM_STRING StringA;
|
|
|
|
USHORT Length;
|
|
|
|
CHAR cString[12];
|
2005-11-04 00:10:39 +00:00
|
|
|
|
2013-12-09 10:35:15 +00:00
|
|
|
RtlCopyMemory(cString, pEntry->ShortName, 11);
|
|
|
|
cString[11] = 0;
|
|
|
|
if (cString[0] == 0x05)
|
|
|
|
{
|
|
|
|
cString[0] = 0xe5;
|
|
|
|
}
|
2005-11-04 00:10:39 +00:00
|
|
|
|
2013-12-09 10:35:15 +00:00
|
|
|
StringA.Buffer = cString;
|
|
|
|
for (StringA.Length = 0;
|
|
|
|
StringA.Length < 8 && StringA.Buffer[StringA.Length] != ' ';
|
|
|
|
StringA.Length++);
|
|
|
|
StringA.MaximumLength = StringA.Length;
|
2005-11-04 00:10:39 +00:00
|
|
|
|
2013-12-09 10:35:15 +00:00
|
|
|
RtlOemStringToUnicodeString(NameU, &StringA, FALSE);
|
2005-11-04 00:10:39 +00:00
|
|
|
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(pEntry->lCase, VFAT_CASE_LOWER_BASE))
|
2013-12-09 10:35:15 +00:00
|
|
|
{
|
|
|
|
RtlDowncaseUnicodeString(NameU, NameU, FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cString[8] != ' ')
|
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
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);
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(pEntry->lCase, VFAT_CASE_LOWER_EXT))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
RtlDowncaseUnicodeString(NameU, NameU, FALSE);
|
|
|
|
}
|
|
|
|
NameU->Buffer -= Length / sizeof(WCHAR);
|
|
|
|
NameU->Length += Length;
|
|
|
|
NameU->MaximumLength += Length;
|
|
|
|
}
|
2013-12-09 10:35:15 +00:00
|
|
|
|
|
|
|
NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0;
|
|
|
|
DPRINT("'%wZ'\n", NameU);
|
2001-05-02 03:18:03 +00:00
|
|
|
}
|
|
|
|
|
1999-12-11 21:14:49 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Find a file
|
|
|
|
*/
|
2013-12-09 18:48:13 +00:00
|
|
|
NTSTATUS
|
|
|
|
FindFile(
|
|
|
|
PDEVICE_EXTENSION DeviceExt,
|
|
|
|
PVFATFCB Parent,
|
|
|
|
PUNICODE_STRING FileToFindU,
|
|
|
|
PVFAT_DIRENTRY_CONTEXT DirContext,
|
|
|
|
BOOLEAN First)
|
1999-12-11 21:14:49 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
PWCHAR PathNameBuffer;
|
|
|
|
USHORT PathNameBufferLength;
|
|
|
|
NTSTATUS Status;
|
|
|
|
PVOID Context = NULL;
|
|
|
|
PVOID Page;
|
|
|
|
PVFATFCB rcFcb;
|
|
|
|
BOOLEAN Found;
|
|
|
|
UNICODE_STRING PathNameU;
|
|
|
|
UNICODE_STRING FileToFindUpcase;
|
|
|
|
BOOLEAN WildCard;
|
2017-02-18 21:37:56 +00:00
|
|
|
BOOLEAN IsFatX = vfatVolumeIsFatX(DeviceExt);
|
2013-12-09 18:48:13 +00:00
|
|
|
|
|
|
|
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);
|
2018-08-21 06:36:51 +00:00
|
|
|
PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameBufferLength + sizeof(WCHAR), TAG_NAME);
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
2017-02-18 21:37:56 +00:00
|
|
|
if (IsFatX && !vfatFCBIsRoot(Parent))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
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);
|
2018-08-21 06:36:51 +00:00
|
|
|
ExFreePoolWithTag(PathNameBuffer, TAG_NAME);
|
2013-12-09 18:48:13 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* FsRtlIsNameInExpression need the searched string to be upcase,
|
|
|
|
* even if IgnoreCase is specified */
|
|
|
|
Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFindU, TRUE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2018-08-21 06:36:51 +00:00
|
|
|
ExFreePoolWithTag(PathNameBuffer, TAG_NAME);
|
2013-12-09 18:48:13 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2013-12-12 13:51:50 +00:00
|
|
|
while (TRUE)
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
2017-02-17 22:25:03 +00:00
|
|
|
Status = VfatGetNextDirEntry(DeviceExt, &Context, &Page, Parent, DirContext, First);
|
2013-12-09 18:48:13 +00:00
|
|
|
First = FALSE;
|
|
|
|
if (Status == STATUS_NO_MORE_ENTRIES)
|
|
|
|
{
|
|
|
|
break;
|
|
|
|
}
|
2017-02-18 21:37:56 +00:00
|
|
|
if (ENTRY_VOLUME(IsFatX, &DirContext->DirEntry))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
DirContext->DirIndex++;
|
|
|
|
continue;
|
|
|
|
}
|
2015-11-30 11:25:14 +00:00
|
|
|
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;
|
|
|
|
}
|
2013-12-09 18:48:13 +00:00
|
|
|
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);
|
2018-08-21 06:36:51 +00:00
|
|
|
ExFreePoolWithTag(PathNameBuffer, TAG_NAME);
|
2013-12-09 18:48:13 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
DirContext->DirIndex++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Context)
|
|
|
|
{
|
|
|
|
CcUnpinData(Context);
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlFreeUnicodeString(&FileToFindUpcase);
|
2018-08-21 06:36:51 +00:00
|
|
|
ExFreePoolWithTag(PathNameBuffer, TAG_NAME);
|
2013-12-09 18:48:13 +00:00
|
|
|
return Status;
|
2001-05-02 03:18:03 +00:00
|
|
|
}
|
1999-12-11 21:14:49 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* FUNCTION: Opens a file
|
|
|
|
*/
|
2013-12-09 18:48:13 +00:00
|
|
|
static
|
|
|
|
NTSTATUS
|
|
|
|
VfatOpenFile(
|
|
|
|
PDEVICE_EXTENSION DeviceExt,
|
|
|
|
PUNICODE_STRING PathNameU,
|
|
|
|
PFILE_OBJECT FileObject,
|
2013-12-11 11:42:44 +00:00
|
|
|
ULONG RequestedDisposition,
|
2015-11-19 16:36:39 +00:00
|
|
|
ULONG RequestedOptions,
|
2013-12-09 18:48:13 +00:00
|
|
|
PVFATFCB *ParentFcb)
|
1999-12-11 21:14:49 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
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))
|
|
|
|
{
|
2013-12-12 13:51:50 +00:00
|
|
|
DPRINT("Status %lx\n", Status);
|
2013-12-09 18:48:13 +00:00
|
|
|
*ParentFcb = NULL;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*ParentFcb)
|
|
|
|
{
|
2014-10-26 20:20:42 +00:00
|
|
|
vfatGrabFCB(DeviceExt, *ParentFcb);
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* try first to find an existing FCB in memory */
|
|
|
|
DPRINT("Checking for existing FCB in memory\n");
|
|
|
|
|
|
|
|
Status = vfatGetFCBForFile(DeviceExt, ParentFcb, &Fcb, PathNameU);
|
2013-12-12 13:51:50 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
DPRINT ("Could not make a new FCB, status: %x\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
2014-04-28 19:40:26 +00:00
|
|
|
|
2015-11-19 16:36:39 +00:00
|
|
|
/* Fail, if we try to overwrite an existing directory */
|
2017-02-17 17:58:18 +00:00
|
|
|
if ((!BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) && vfatFCBIsDirectory(Fcb)) &&
|
2015-11-19 16:36:39 +00:00
|
|
|
(RequestedDisposition == FILE_OVERWRITE ||
|
|
|
|
RequestedDisposition == FILE_OVERWRITE_IF ||
|
|
|
|
RequestedDisposition == FILE_SUPERSEDE))
|
|
|
|
{
|
|
|
|
vfatReleaseFCB(DeviceExt, Fcb);
|
|
|
|
return STATUS_OBJECT_NAME_COLLISION;
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(Fcb->Flags, FCB_DELETE_PENDING))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
2013-12-12 13:51:50 +00:00
|
|
|
vfatReleaseFCB(DeviceExt, Fcb);
|
2013-12-09 18:48:13 +00:00
|
|
|
return STATUS_DELETE_PENDING;
|
|
|
|
}
|
2013-12-11 11:42:44 +00:00
|
|
|
|
|
|
|
/* Fail, if we try to overwrite a read-only file */
|
2017-02-17 17:58:18 +00:00
|
|
|
if (vfatFCBIsReadOnly(Fcb) &&
|
2015-11-13 19:03:34 +00:00
|
|
|
(RequestedDisposition == FILE_OVERWRITE ||
|
|
|
|
RequestedDisposition == FILE_OVERWRITE_IF))
|
2013-12-11 11:42:44 +00:00
|
|
|
{
|
|
|
|
vfatReleaseFCB(DeviceExt, Fcb);
|
|
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:58:18 +00:00
|
|
|
if (vfatFCBIsReadOnly(Fcb) &&
|
2016-08-11 13:25:57 +00:00
|
|
|
(RequestedOptions & FILE_DELETE_ON_CLOSE))
|
|
|
|
{
|
|
|
|
vfatReleaseFCB(DeviceExt, Fcb);
|
|
|
|
return STATUS_CANNOT_DELETE;
|
|
|
|
}
|
|
|
|
|
2020-09-26 22:39:15 +00:00
|
|
|
if ((vfatFCBIsRoot(Fcb) || IsDotOrDotDot(&Fcb->LongNameU)) &&
|
2017-02-17 17:58:18 +00:00
|
|
|
BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE))
|
2016-08-11 13:25:57 +00:00
|
|
|
{
|
|
|
|
// we cannot delete a '.', '..' or the root directory
|
|
|
|
vfatReleaseFCB(DeviceExt, Fcb);
|
|
|
|
return STATUS_CANNOT_DELETE;
|
|
|
|
}
|
|
|
|
|
[FASTFAT] Implement delayed close
When we're about to close a file (ie, forget everything about it
and release any associated structure), actually delay it.
This allows keep data fresh in memory for faster reuse in case
it would be required. The effective closing will only happen after some time.
For specific operations, this will produce a real speed up in ReactOS.
For instance, with that patch, Winamp starts within seconds, instead of dozen
of minutes.
In most cases, it will bring ReactOS to performances it had before fixing
the huge leak in FastFAT (commit 94ead99) without leaking the whole FS.
For now, due to regressions, this is only activated for files and not
for directories. Once it gets fixed, it will be enabled for both.
CORE-14826
CORE-14917
2018-08-18 15:04:02 +00:00
|
|
|
/* 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);
|
|
|
|
}
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
DPRINT("Attaching FCB to fileObject\n");
|
|
|
|
Status = vfatAttachFCBToFileObject(DeviceExt, Fcb, FileObject);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2013-12-12 13:51:50 +00:00
|
|
|
vfatReleaseFCB(DeviceExt, Fcb);
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
|
|
|
return Status;
|
2005-11-04 00:07:47 +00:00
|
|
|
}
|
2002-08-14 20:58:39 +00:00
|
|
|
|
2005-11-04 00:07:47 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Create or open a file
|
|
|
|
*/
|
2013-12-09 18:48:13 +00:00
|
|
|
static NTSTATUS
|
|
|
|
VfatCreateFile(
|
|
|
|
PDEVICE_OBJECT DeviceObject,
|
|
|
|
PIRP Irp)
|
2005-11-04 00:07:47 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
PIO_STACK_LOCATION Stack;
|
|
|
|
PFILE_OBJECT FileObject;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PDEVICE_EXTENSION DeviceExt;
|
|
|
|
ULONG RequestedDisposition, RequestedOptions;
|
|
|
|
PVFATFCB pFcb = NULL;
|
|
|
|
PVFATFCB ParentFcb = NULL;
|
2017-05-02 19:33:14 +00:00
|
|
|
PVFATCCB pCcb = NULL;
|
2013-12-09 18:48:13 +00:00
|
|
|
PWCHAR c, last;
|
2014-10-27 13:39:03 +00:00
|
|
|
BOOLEAN PagingFileCreate;
|
2013-12-09 18:48:13 +00:00
|
|
|
BOOLEAN Dots;
|
2014-10-27 13:39:03 +00:00
|
|
|
BOOLEAN OpenTargetDir;
|
2017-02-26 13:32:55 +00:00
|
|
|
BOOLEAN TrailingBackslash;
|
2013-12-09 18:48:13 +00:00
|
|
|
UNICODE_STRING FileNameU;
|
|
|
|
UNICODE_STRING PathNameU;
|
|
|
|
ULONG Attributes;
|
|
|
|
|
|
|
|
/* Unpack the various parameters. */
|
2013-12-12 13:51:50 +00:00
|
|
|
Stack = IoGetCurrentIrpStackLocation(Irp);
|
2013-12-09 18:48:13 +00:00
|
|
|
RequestedDisposition = ((Stack->Parameters.Create.Options >> 24) & 0xff);
|
|
|
|
RequestedOptions = Stack->Parameters.Create.Options & FILE_VALID_OPTION_FLAGS;
|
2017-02-17 17:58:18 +00:00
|
|
|
PagingFileCreate = BooleanFlagOn(Stack->Flags, SL_OPEN_PAGING_FILE);
|
|
|
|
OpenTargetDir = BooleanFlagOn(Stack->Flags, SL_OPEN_TARGET_DIRECTORY);
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
FileObject = Stack->FileObject;
|
|
|
|
DeviceExt = DeviceObject->DeviceExtension;
|
|
|
|
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(Stack->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID))
|
2016-08-08 07:28:14 +00:00
|
|
|
{
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
/* Check their validity. */
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) &&
|
2013-12-09 18:48:13 +00:00
|
|
|
RequestedDisposition == FILE_SUPERSEDE)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
2005-11-04 00:10:39 +00:00
|
|
|
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) &&
|
|
|
|
BooleanFlagOn(RequestedOptions, FILE_NON_DIRECTORY_FILE))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2014-10-30 20:56:40 +00:00
|
|
|
/* Deny create if the volume is locked */
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(DeviceExt->Flags, VCB_VOLUME_LOCKED))
|
2014-10-30 20:56:40 +00:00
|
|
|
{
|
|
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
/* This a open operation for the volume itself */
|
|
|
|
if (FileObject->FileName.Length == 0 &&
|
2015-11-29 18:43:50 +00:00
|
|
|
(FileObject->RelatedFileObject == NULL ||
|
|
|
|
FileObject->RelatedFileObject->FsContext2 != NULL ||
|
|
|
|
FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
2014-11-02 11:30:14 +00:00
|
|
|
DPRINT("Volume opening\n");
|
2014-10-30 20:56:40 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
if (RequestedDisposition != FILE_OPEN &&
|
|
|
|
RequestedDisposition != FILE_OPEN_IF)
|
2005-11-24 21:08:13 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
return STATUS_ACCESS_DENIED;
|
2005-11-24 21:08:13 +00:00
|
|
|
}
|
2017-02-26 18:46:30 +00:00
|
|
|
|
|
|
|
if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) &&
|
|
|
|
(FileObject->RelatedFileObject == NULL || FileObject->RelatedFileObject->FsContext2 == NULL || FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
return STATUS_NOT_A_DIRECTORY;
|
|
|
|
}
|
2011-03-02 21:51:33 +00:00
|
|
|
|
2014-04-28 19:40:26 +00:00
|
|
|
if (OpenTargetDir)
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE))
|
2016-08-11 13:25:57 +00:00
|
|
|
{
|
|
|
|
return STATUS_CANNOT_DELETE;
|
|
|
|
}
|
|
|
|
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.CreateHits, 1);
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
pFcb = DeviceExt->VolumeFcb;
|
2014-11-27 20:28:50 +00:00
|
|
|
|
|
|
|
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,
|
2019-02-14 09:48:32 +00:00
|
|
|
TRUE);
|
2014-11-27 20:28:50 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2014-11-27 20:28:50 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject);
|
2014-10-30 20:56:40 +00:00
|
|
|
DeviceExt->OpenHandleCount++;
|
2014-11-29 20:09:44 +00:00
|
|
|
pFcb->OpenHandleCount++;
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.SuccessfulCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
|
|
|
|
Irp->IoStatus.Information = FILE_OPENED;
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2015-11-29 18:43:50 +00:00
|
|
|
if (FileObject->RelatedFileObject != NULL &&
|
|
|
|
FileObject->RelatedFileObject->FsContext == DeviceExt->VolumeFcb)
|
|
|
|
{
|
|
|
|
ASSERT(FileObject->FileName.Length != 0);
|
|
|
|
return STATUS_OBJECT_PATH_NOT_FOUND;
|
|
|
|
}
|
|
|
|
|
2016-11-13 15:31:39 +00:00
|
|
|
/* Check for illegal characters and illegal dot sequences in the file name */
|
2013-12-09 18:48:13 +00:00
|
|
|
PathNameU = FileObject->FileName;
|
|
|
|
c = PathNameU.Buffer + PathNameU.Length / sizeof(WCHAR);
|
|
|
|
last = c - 1;
|
2017-02-26 13:32:55 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
Dots = TRUE;
|
|
|
|
while (c-- > PathNameU.Buffer)
|
|
|
|
{
|
|
|
|
if (*c == L'\\' || c == PathNameU.Buffer)
|
|
|
|
{
|
|
|
|
if (Dots && last > c)
|
|
|
|
{
|
|
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
2017-02-26 13:32:55 +00:00
|
|
|
if (*c == L'\\' && (c - 1) > PathNameU.Buffer &&
|
|
|
|
*(c - 1) == L'\\')
|
|
|
|
{
|
|
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
last = c - 1;
|
|
|
|
Dots = TRUE;
|
|
|
|
}
|
|
|
|
else if (*c != L'.')
|
|
|
|
{
|
|
|
|
Dots = FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (*c != '\\' && vfatIsLongIllegal(*c))
|
|
|
|
{
|
|
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-28 19:40:26 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
if (FileObject->RelatedFileObject && PathNameU.Length >= sizeof(WCHAR) && PathNameU.Buffer[0] == L'\\')
|
|
|
|
{
|
|
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
|
|
|
|
2017-02-26 13:57:17 +00:00
|
|
|
TrailingBackslash = FALSE;
|
2013-12-09 18:48:13 +00:00
|
|
|
if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\')
|
|
|
|
{
|
|
|
|
PathNameU.Length -= sizeof(WCHAR);
|
2017-02-26 13:57:17 +00:00
|
|
|
TrailingBackslash = TRUE;
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
|
|
|
|
2015-11-29 20:23:43 +00:00
|
|
|
if (PathNameU.Length > sizeof(WCHAR) && PathNameU.Buffer[PathNameU.Length/sizeof(WCHAR)-1] == L'\\')
|
|
|
|
{
|
|
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
/* Try opening the file. */
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
if (!OpenTargetDir)
|
2014-04-28 19:40:26 +00:00
|
|
|
{
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.CreateHits, 1);
|
|
|
|
|
2015-11-19 16:36:39 +00:00
|
|
|
Status = VfatOpenFile(DeviceExt, &PathNameU, FileObject, RequestedDisposition, RequestedOptions, &ParentFcb);
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PVFATFCB TargetFcb;
|
2017-09-26 13:49:09 +00:00
|
|
|
LONG idx, FileNameLen;
|
2014-04-28 19:40:26 +00:00
|
|
|
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.CreateHits, 1);
|
|
|
|
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
ParentFcb = (FileObject->RelatedFileObject != NULL) ? FileObject->RelatedFileObject->FsContext : NULL;
|
2014-11-05 23:23:52 +00:00
|
|
|
if (ParentFcb)
|
|
|
|
{
|
|
|
|
vfatGrabFCB(DeviceExt, ParentFcb);
|
|
|
|
}
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
|
2017-09-26 12:36:17 +00:00
|
|
|
Status = vfatGetFCBForFile(DeviceExt, &ParentFcb, &TargetFcb, &PathNameU);
|
2014-11-05 23:23:52 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
2014-04-28 19:40:26 +00:00
|
|
|
{
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
vfatReleaseFCB(DeviceExt, TargetFcb);
|
2014-04-28 19:40:26 +00:00
|
|
|
Irp->IoStatus.Information = FILE_EXISTS;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Irp->IoStatus.Information = FILE_DOES_NOT_EXIST;
|
|
|
|
}
|
|
|
|
|
|
|
|
idx = FileObject->FileName.Length / sizeof(WCHAR) - 1;
|
|
|
|
|
2014-11-06 00:07:01 +00:00
|
|
|
/* Skip trailing \ - if any */
|
2014-04-28 19:40:26 +00:00
|
|
|
if (PathNameU.Buffer[idx] == L'\\')
|
|
|
|
{
|
|
|
|
--idx;
|
|
|
|
PathNameU.Length -= sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Get file name */
|
|
|
|
while (idx >= 0 && PathNameU.Buffer[idx] != L'\\')
|
|
|
|
{
|
|
|
|
--idx;
|
|
|
|
}
|
|
|
|
|
2014-04-29 18:25:02 +00:00
|
|
|
if (idx > 0 || PathNameU.Buffer[0] == L'\\')
|
2014-04-28 19:40:26 +00:00
|
|
|
{
|
2017-09-26 13:49:09 +00:00
|
|
|
/* 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
|
2017-09-26 12:36:17 +00:00
|
|
|
/* 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;
|
2017-09-26 13:49:09 +00:00
|
|
|
#endif
|
2014-04-28 19:40:26 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* This is a relative open and we have only the filename, so open the parent directory
|
|
|
|
* It is in RelatedFileObject
|
|
|
|
*/
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
ASSERT(FileObject->RelatedFileObject != NULL);
|
2014-04-28 19:40:26 +00:00
|
|
|
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
/* No need to modify the FO, it already has the name */
|
|
|
|
}
|
2014-04-28 19:40:26 +00:00
|
|
|
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
/* We're done with opening! */
|
|
|
|
if (ParentFcb != NULL)
|
|
|
|
{
|
|
|
|
Status = vfatAttachFCBToFileObject(DeviceExt, ParentFcb, FileObject);
|
|
|
|
}
|
2014-04-28 19:40:26 +00:00
|
|
|
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
pFcb = FileObject->FsContext;
|
2014-11-05 23:23:52 +00:00
|
|
|
ASSERT(pFcb == ParentFcb);
|
2014-04-28 19:40:26 +00:00
|
|
|
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
if (pFcb->OpenHandleCount == 0)
|
2014-04-28 19:40:26 +00:00
|
|
|
{
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
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);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
return Status;
|
|
|
|
}
|
2014-04-28 19:40:26 +00:00
|
|
|
}
|
|
|
|
|
2017-05-02 19:33:14 +00:00
|
|
|
pCcb = FileObject->FsContext2;
|
|
|
|
if (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE))
|
|
|
|
{
|
|
|
|
pCcb->Flags |= CCB_DELETE_ON_CLOSE;
|
|
|
|
}
|
|
|
|
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
pFcb->OpenHandleCount++;
|
2014-10-30 20:56:40 +00:00
|
|
|
DeviceExt->OpenHandleCount++;
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
}
|
|
|
|
else if (ParentFcb != NULL)
|
|
|
|
{
|
|
|
|
vfatReleaseFCB(DeviceExt, ParentFcb);
|
2014-04-28 19:40:26 +00:00
|
|
|
}
|
|
|
|
|
2017-09-24 09:50:36 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
vfatAddToStat(DeviceExt, Fat.SuccessfulCreates, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
|
|
|
}
|
|
|
|
|
2014-04-28 19:40:26 +00:00
|
|
|
return Status;
|
|
|
|
}
|
2013-12-09 18:48:13 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 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 ||
|
2015-11-22 21:46:58 +00:00
|
|
|
Status == STATUS_DELETE_PENDING ||
|
|
|
|
Status == STATUS_ACCESS_DENIED ||
|
|
|
|
Status == STATUS_OBJECT_NAME_COLLISION)
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
if (ParentFcb)
|
|
|
|
{
|
|
|
|
vfatReleaseFCB(DeviceExt, ParentFcb);
|
|
|
|
}
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status) && ParentFcb == NULL)
|
|
|
|
{
|
2014-04-25 17:09:37 +00:00
|
|
|
DPRINT1("VfatOpenFile failed for '%wZ', status %x\n", &PathNameU, Status);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2018-01-06 21:02:10 +00:00
|
|
|
Attributes = (Stack->Parameters.Create.FileAttributes & (FILE_ATTRIBUTE_ARCHIVE |
|
|
|
|
FILE_ATTRIBUTE_SYSTEM |
|
|
|
|
FILE_ATTRIBUTE_HIDDEN |
|
|
|
|
FILE_ATTRIBUTE_DIRECTORY |
|
|
|
|
FILE_ATTRIBUTE_READONLY));
|
2018-01-01 11:12:08 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
/* 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)
|
|
|
|
{
|
2017-02-17 17:58:18 +00:00
|
|
|
if (!BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE))
|
2017-02-26 13:57:17 +00:00
|
|
|
{
|
|
|
|
if (TrailingBackslash)
|
|
|
|
{
|
|
|
|
vfatReleaseFCB(DeviceExt, ParentFcb);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2017-02-26 13:57:17 +00:00
|
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
2013-12-10 09:53:21 +00:00
|
|
|
Attributes |= FILE_ATTRIBUTE_ARCHIVE;
|
2017-02-26 13:57:17 +00:00
|
|
|
}
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatSplitPathName(&PathNameU, NULL, &FileNameU);
|
2020-09-26 22:39:15 +00:00
|
|
|
|
|
|
|
if (IsDotOrDotDot(&FileNameU))
|
|
|
|
{
|
|
|
|
vfatReleaseFCB(DeviceExt, ParentFcb);
|
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
|
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
2013-12-09 18:48:13 +00:00
|
|
|
Status = VfatAddEntry(DeviceExt, &FileNameU, &pFcb, ParentFcb, RequestedOptions,
|
2018-01-06 21:02:10 +00:00
|
|
|
Attributes, NULL);
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatReleaseFCB(DeviceExt, ParentFcb);
|
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
Status = vfatAttachFCBToFileObject(DeviceExt, pFcb, FileObject);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
vfatReleaseFCB(DeviceExt, pFcb);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
2018-05-16 19:44:47 +00:00
|
|
|
SetFlag(DeviceExt->Flags, VCB_IS_SYS_OR_HAS_PAGE);
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-02-26 14:43:01 +00:00
|
|
|
vfatReleaseFCB(DeviceExt, ParentFcb);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (ParentFcb)
|
|
|
|
{
|
|
|
|
vfatReleaseFCB(DeviceExt, ParentFcb);
|
|
|
|
}
|
|
|
|
|
2017-02-26 13:57:17 +00:00
|
|
|
pFcb = FileObject->FsContext;
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
/* Otherwise fail if the caller wanted to create a new file */
|
|
|
|
if (RequestedDisposition == FILE_CREATE)
|
|
|
|
{
|
|
|
|
VfatCloseFile(DeviceExt, FileObject);
|
2017-02-26 13:57:17 +00:00
|
|
|
if (TrailingBackslash && !vfatFCBIsDirectory(pFcb))
|
|
|
|
{
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2017-02-26 13:57:17 +00:00
|
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
|
|
|
Irp->IoStatus.Information = FILE_EXISTS;
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
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);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2005-12-04 15:09:07 +00:00
|
|
|
return Status;
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
2005-12-04 15:09:07 +00:00
|
|
|
}
|
2005-11-04 00:10:39 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
/*
|
|
|
|
* Check the file has the requested attributes
|
|
|
|
*/
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(RequestedOptions, FILE_NON_DIRECTORY_FILE) &&
|
|
|
|
vfatFCBIsDirectory(pFcb))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
VfatCloseFile (DeviceExt, FileObject);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
return STATUS_FILE_IS_A_DIRECTORY;
|
|
|
|
}
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(RequestedOptions, FILE_DIRECTORY_FILE) &&
|
|
|
|
!vfatFCBIsDirectory(pFcb))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
VfatCloseFile (DeviceExt, FileObject);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
return STATUS_NOT_A_DIRECTORY;
|
|
|
|
}
|
2017-02-26 13:57:17 +00:00
|
|
|
if (TrailingBackslash && !vfatFCBIsDirectory(pFcb))
|
2017-02-26 13:32:55 +00:00
|
|
|
{
|
|
|
|
VfatCloseFile (DeviceExt, FileObject);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2017-02-26 13:32:55 +00:00
|
|
|
return STATUS_OBJECT_NAME_INVALID;
|
|
|
|
}
|
2006-12-31 16:43:40 +00:00
|
|
|
#ifndef USE_ROS_CC_AND_FS
|
2017-02-17 17:58:18 +00:00
|
|
|
if (!vfatFCBIsDirectory(pFcb))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(Stack->Parameters.Create.SecurityContext->DesiredAccess, FILE_WRITE_DATA) ||
|
2013-12-09 18:48:13 +00:00
|
|
|
RequestedDisposition == FILE_OVERWRITE ||
|
2016-08-11 13:25:57 +00:00
|
|
|
RequestedDisposition == FILE_OVERWRITE_IF ||
|
|
|
|
(RequestedOptions & FILE_DELETE_ON_CLOSE))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
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);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2017-02-17 17:58:18 +00:00
|
|
|
return (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE)) ? STATUS_CANNOT_DELETE
|
|
|
|
: STATUS_SHARING_VIOLATION;
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2006-12-31 16:43:40 +00:00
|
|
|
#endif
|
2013-12-09 18:48:13 +00:00
|
|
|
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)
|
|
|
|
{
|
2017-02-17 17:58:18 +00:00
|
|
|
if(!BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
VfatCloseFile(DeviceExt, FileObject);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pFcb->Flags |= FCB_IS_PAGE_FILE;
|
2018-05-16 19:44:47 +00:00
|
|
|
SetFlag(DeviceExt->Flags, VCB_IS_SYS_OR_HAS_PAGE);
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-02-17 17:58:18 +00:00
|
|
|
if (BooleanFlagOn(pFcb->Flags, FCB_IS_PAGE_FILE))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
VfatCloseFile(DeviceExt, FileObject);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
}
|
1999-12-11 21:14:49 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
if (RequestedDisposition == FILE_OVERWRITE ||
|
|
|
|
RequestedDisposition == FILE_OVERWRITE_IF ||
|
|
|
|
RequestedDisposition == FILE_SUPERSEDE)
|
|
|
|
{
|
2018-01-01 11:12:08 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2017-02-17 17:58:18 +00:00
|
|
|
if (!vfatFCBIsDirectory(pFcb))
|
2013-12-10 18:48:55 +00:00
|
|
|
{
|
2018-01-07 10:34:41 +00:00
|
|
|
LARGE_INTEGER SystemTime;
|
|
|
|
|
2018-01-01 13:29:15 +00:00
|
|
|
if (RequestedDisposition == FILE_SUPERSEDE)
|
|
|
|
{
|
2018-01-06 21:02:10 +00:00
|
|
|
*pFcb->Attributes = Attributes;
|
2018-01-01 13:29:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-01-06 21:02:10 +00:00
|
|
|
*pFcb->Attributes |= Attributes;
|
2018-01-01 13:29:15 +00:00
|
|
|
}
|
2013-12-10 18:48:55 +00:00
|
|
|
*pFcb->Attributes |= FILE_ATTRIBUTE_ARCHIVE;
|
2018-01-07 10:34:41 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-05-18 12:03:20 +00:00
|
|
|
VfatUpdateEntry(DeviceExt, pFcb);
|
2013-12-10 18:48:55 +00:00
|
|
|
}
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
ExAcquireResourceExclusiveLite(&(pFcb->MainResource), TRUE);
|
|
|
|
Status = VfatSetAllocationSizeInformation(FileObject,
|
|
|
|
pFcb,
|
|
|
|
DeviceExt,
|
|
|
|
&Irp->Overlay.AllocationSize);
|
|
|
|
ExReleaseResourceLite(&(pFcb->MainResource));
|
|
|
|
if (!NT_SUCCESS (Status))
|
|
|
|
{
|
|
|
|
VfatCloseFile(DeviceExt, FileObject);
|
2017-09-24 09:50:36 +00:00
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
2013-12-09 18:48:13 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-05-02 19:33:14 +00:00
|
|
|
pCcb = FileObject->FsContext2;
|
|
|
|
if (BooleanFlagOn(RequestedOptions, FILE_DELETE_ON_CLOSE))
|
|
|
|
{
|
|
|
|
pCcb->Flags |= CCB_DELETE_ON_CLOSE;
|
|
|
|
}
|
|
|
|
|
2014-03-07 19:46:37 +00:00
|
|
|
if (Irp->IoStatus.Information == FILE_CREATED)
|
|
|
|
{
|
2018-01-07 13:16:11 +00:00
|
|
|
vfatReportChange(DeviceExt,
|
|
|
|
pFcb,
|
|
|
|
(vfatFCBIsDirectory(pFcb) ?
|
|
|
|
FILE_NOTIFY_CHANGE_DIR_NAME : FILE_NOTIFY_CHANGE_FILE_NAME),
|
|
|
|
FILE_ACTION_ADDED);
|
2014-03-07 19:46:37 +00:00
|
|
|
}
|
2018-01-07 10:44:25 +00:00
|
|
|
else if (Irp->IoStatus.Information == FILE_OVERWRITTEN ||
|
|
|
|
Irp->IoStatus.Information == FILE_SUPERSEDED)
|
|
|
|
{
|
2018-01-07 13:16:11 +00:00
|
|
|
vfatReportChange(DeviceExt,
|
|
|
|
pFcb,
|
|
|
|
FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE,
|
|
|
|
FILE_ACTION_MODIFIED);
|
2018-01-07 10:44:25 +00:00
|
|
|
}
|
2014-03-07 19:46:37 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
pFcb->OpenHandleCount++;
|
2014-10-30 20:56:40 +00:00
|
|
|
DeviceExt->OpenHandleCount++;
|
2013-12-09 18:48:13 +00:00
|
|
|
|
|
|
|
/* FIXME : test write access if requested */
|
|
|
|
|
2017-12-17 17:25:43 +00:00
|
|
|
/* FIXME: That is broken, we cannot reach this code path with failure */
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
2017-09-24 09:50:36 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
vfatAddToStat(DeviceExt, Fat.SuccessfulCreates, 1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
vfatAddToStat(DeviceExt, Fat.FailedCreates, 1);
|
|
|
|
}
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
return Status;
|
|
|
|
}
|
1999-12-11 21:14:49 +00:00
|
|
|
|
2000-07-07 02:14:14 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Create or open a file
|
|
|
|
*/
|
2013-12-09 18:48:13 +00:00
|
|
|
NTSTATUS
|
|
|
|
VfatCreate(
|
|
|
|
PVFAT_IRP_CONTEXT IrpContext)
|
2000-07-07 02:14:14 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
2015-05-15 16:03:29 +00:00
|
|
|
IrpContext->PriorityBoost = IO_DISK_INCREMENT;
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
IrpContext->Irp->IoStatus.Information = 0;
|
|
|
|
ExAcquireResourceExclusiveLite(&IrpContext->DeviceExt->DirResource, TRUE);
|
|
|
|
Status = VfatCreateFile(IrpContext->DeviceObject, IrpContext->Irp);
|
|
|
|
ExReleaseResourceLite(&IrpContext->DeviceExt->DirResource);
|
|
|
|
|
2015-05-15 16:03:29 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
IrpContext->PriorityBoost = IO_DISK_INCREMENT;
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
return Status;
|
2000-07-07 02:14:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* EOF */
|