reactos/drivers/filesystems/vfatfs/create.c

1099 lines
36 KiB
C
Raw Permalink Normal View History

2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-14 20:58:39 +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>
*/
/* INCLUDES *****************************************************************/
#include "vfat.h"
#define NDEBUG
#include <debug.h>
/* 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;
}
2002-08-14 David Welch <welch@computer2.darkstar.org> * subsys/smss/init.c (SmPagingFilesQueryRoutine): If possible take the size of the paging file from the registry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/section.c (MmCreateDataFileSection): Extend the section if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/pagefile.c (NtCreatePagingFile): Set the file size using the FileAllocationInformation class. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/mm/anonmem.c (MmWritePageVirtualMemory): Implemented function to write anonymous memory pages to the swap file. * ntoskrnl/mm/anonmem.c (MmFreeVirtualMemoryPage): Free any swap page associated with the page. * ntoskrnl/mm/mpw.c (MmWriteDirtyPages): New function to find pages to write to disk. * ntoskrnl/mm/mpw.c (MmMpwThreadMain): Implemented MPW functionality. * ntoskrnl/mm/rmap.c (MmWritePagePhysicalAddress): New function to write a single page back to disk. * ntoskrnl/mm/rmap.c (MmSetCleanAllRmaps, MmSetDirtyAllRmaps, MmIsDirtyPageRmap): New rmap function to support the MPW thread. * ntoskrnl/mm/section.c (MmWritePageSectionView): Implemented function to write back section pages. * ntoskrnl/mm/section.c (MmFreeSectionPage): Free any swap entry associated with the page; mark pages shared with the cache as dirty if necessary. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/ldr/loader.c (LdrPEProcessModule): Set name of the module into the module text structure. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/io/rw.c (NtReadFile, NtWriteFile): Use the correct test for whether to wait for the completion of i/o. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cm/ntfunc.c (NtFlushKey): Request synchronous i/o from NtOpenFile. * ntoskrnl/cm/regfile (CmiInitPermanentRegistryHive): Request synchronous i/o from NtCreateFile. * ntoskrnl/dbg/kdb_stabs.c (LdrpLoadModuleSymbols): Request synchronous i/o from NtOpenFile. * ntoskrnl/ldr/sysdll.c (LdrpMapSystemDll): Request synchronous i/o from NtOpenFile. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosSuggestFreeCacheSegment): Maintain the correct reference count. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/view.c (CcRosFlushCacheSegment): New function to write back a modified cache segment. * ntoskrnl/cc/view.c (CcRosFlushDirtyPages): New function to flush some dirty pages from the cache. * ntoskrnl/cc/view.c (CcRosMarkDirtyCacheSegment): New function to mark a cache segment modified while mapped into memory as dirty. 2002-08-14 David Welch <welch@computer2.darkstar.org> * ntoskrnl/cc/pin.c (CcMapData, CcUnpinData, CcSetDirtyPinnedData): Store the dirty status in the BCB; don't write back dirty data immediately. 2002-08-14 David Welch <welch@computer2.darkstar.org> * include/ntos/mm.h: Added SEC_XXXX defines from 'Windows NT/2000 Native API Reference' 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/ea.c (VfatSetExtendedAttributes): Empty placeholder for extended attribute functions. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/finfo.c (VfatSetAllocationSizeInformation): Added function to set allocation size. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/fcb.c (vfatFCBInitializeCache): Renamed to vfatFCBInitializeCacheFromVolume. * drivers/fs/vfat/fcb.c (vfatMakeFCBFromDirEntry): Don't initialise the cache with a file object representing the volume unless the FCB is for a directory. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/create.c (VfatPagingFileCreate): Added a new function for handling paging file only code. * drivers/fs/vfat/create.c (VfatSupersedeFile): Added a new function for doing a file supersede. * drivers/fs/vfat/create.c (VfatCreateFile): Reformatted and adjusted control flow. Set allocation size and extended attributes on create. * drivers/fs/vfat/create.c (VfatCreate): Removed goto. 2002-08-14 David Welch <welch@computer2.darkstar.org> * drivers/fs/vfat/cleanup.c (VfatCleanupFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/close.c (VfatCloseFile): Renamed updEntry to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (updEntry): Renamed to VfatUpdateEntry. * drivers/fs/vfat/dirwr.c (addEntry): Renamed to VfatAddEntry. 2002-08-14 David Welch <welch@computer2.darkstar.org> * apps/tests/sectest/sectest.c (main): Fixed formatting. svn path=/trunk/; revision=3331
2002-08-14 20:58:39 +00:00
/*
* 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);
[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
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. */
[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)
{
vfatAddToStat(DeviceExt, Fat.CreateHits, 1);
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;
LONG idx, FileNameLen;
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;
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
Status = vfatGetFCBForFile(DeviceExt, &ParentFcb, &TargetFcb, &PathNameU);
if (NT_SUCCESS(Status))
{
[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);
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
*/
[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);
[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 */
}
[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);
}
[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;
ASSERT(pFcb == 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
if (pFcb->OpenHandleCount == 0)
{
[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);
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;
}
}
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++;
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);
}
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 */