reactos/drivers/filesystems/fastfat/fcb.c

1076 lines
30 KiB
C
Raw Normal View History

/*
[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
* FILE: drivers/filesystems/fastfat/fcb.c
* PURPOSE: Routines to manipulate FCBs.
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PROGRAMMER: Jason Filby (jasonfilby@yahoo.com)
* Rex Jolliff (rex@lvcablemodem.com)
* Herve Poussineau (reactos@poussine.freesurf.fr)
[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
* Pierre Schweitzer (pierre@reactos.org)
*/
/* ------------------------------------------------------- INCLUDES */
#include "vfat.h"
#define NDEBUG
#include <debug.h>
#ifdef __GNUC__
#include <wctype.h> /* towlower prototype */
#endif
/* -------------------------------------------------------- DEFINES */
#define TAG_FCB 'BCFV'
#ifdef KDBG
extern UNICODE_STRING DebugFile;
#endif
/* -------------------------------------------------------- PUBLICS */
static
ULONG
vfatNameHash(
ULONG hash,
PUNICODE_STRING NameU)
{
PWCHAR last;
PWCHAR curr;
register WCHAR c;
// LFN could start from "."
//ASSERT(NameU->Buffer[0] != L'.');
curr = NameU->Buffer;
last = NameU->Buffer + NameU->Length / sizeof(WCHAR);
while(curr < last)
{
c = towlower(*curr++);
hash = (hash + (c << 4) + (c >> 4)) * 11;
}
return hash;
}
VOID
vfatSplitPathName(
PUNICODE_STRING PathNameU,
PUNICODE_STRING DirNameU,
PUNICODE_STRING FileNameU)
{
PWCHAR pName;
USHORT Length = 0;
pName = PathNameU->Buffer + PathNameU->Length / sizeof(WCHAR) - 1;
while (*pName != L'\\' && pName >= PathNameU->Buffer)
{
pName--;
Length++;
}
ASSERT(*pName == L'\\' || pName < PathNameU->Buffer);
if (FileNameU)
{
FileNameU->Buffer = pName + 1;
FileNameU->Length = FileNameU->MaximumLength = Length * sizeof(WCHAR);
}
if (DirNameU)
{
DirNameU->Buffer = PathNameU->Buffer;
DirNameU->Length = (pName + 1 - PathNameU->Buffer) * sizeof(WCHAR);
DirNameU->MaximumLength = DirNameU->Length;
}
}
static
VOID
vfatInitFcb(
PVFATFCB Fcb,
PUNICODE_STRING NameU)
{
USHORT PathNameBufferLength;
if (NameU)
PathNameBufferLength = NameU->Length + sizeof(WCHAR);
else
PathNameBufferLength = 0;
Fcb->PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameBufferLength, TAG_FCB);
if (!Fcb->PathNameBuffer)
{
/* FIXME: what to do if no more memory? */
DPRINT1("Unable to initialize FCB for filename '%wZ'\n", NameU);
KeBugCheckEx(FAT_FILE_SYSTEM, (ULONG_PTR)Fcb, (ULONG_PTR)NameU, 0, 0);
}
Fcb->RFCB.NodeTypeCode = NODE_TYPE_FCB;
Fcb->RFCB.NodeByteSize = sizeof(VFATFCB);
Fcb->PathNameU.Length = 0;
Fcb->PathNameU.Buffer = Fcb->PathNameBuffer;
Fcb->PathNameU.MaximumLength = PathNameBufferLength;
Fcb->ShortNameU.Length = 0;
Fcb->ShortNameU.Buffer = Fcb->ShortNameBuffer;
Fcb->ShortNameU.MaximumLength = sizeof(Fcb->ShortNameBuffer);
Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
if (NameU && NameU->Length)
{
RtlCopyUnicodeString(&Fcb->PathNameU, NameU);
vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
}
else
{
Fcb->DirNameU.Buffer = Fcb->LongNameU.Buffer = NULL;
Fcb->DirNameU.MaximumLength = Fcb->DirNameU.Length = 0;
Fcb->LongNameU.MaximumLength = Fcb->LongNameU.Length = 0;
}
RtlZeroMemory(&Fcb->FCBShareAccess, sizeof(SHARE_ACCESS));
Fcb->OpenHandleCount = 0;
}
PVFATFCB
vfatNewFCB(
PDEVICE_EXTENSION pVCB,
PUNICODE_STRING pFileNameU)
{
PVFATFCB rcFCB;
DPRINT("'%wZ'\n", pFileNameU);
rcFCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->FcbLookasideList);
if (rcFCB == NULL)
{
return NULL;
}
RtlZeroMemory(rcFCB, sizeof(VFATFCB));
vfatInitFcb(rcFCB, pFileNameU);
if (vfatVolumeIsFatX(pVCB))
rcFCB->Attributes = &rcFCB->entry.FatX.Attrib;
else
rcFCB->Attributes = &rcFCB->entry.Fat.Attrib;
rcFCB->Hash.Hash = vfatNameHash(0, &rcFCB->PathNameU);
rcFCB->Hash.self = rcFCB;
rcFCB->ShortHash.self = rcFCB;
ExInitializeResourceLite(&rcFCB->PagingIoResource);
ExInitializeResourceLite(&rcFCB->MainResource);
FsRtlInitializeFileLock(&rcFCB->FileLock, NULL, NULL);
ExInitializeFastMutex(&rcFCB->LastMutex);
rcFCB->RFCB.PagingIoResource = &rcFCB->PagingIoResource;
rcFCB->RFCB.Resource = &rcFCB->MainResource;
rcFCB->RFCB.IsFastIoPossible = FastIoIsNotPossible;
InitializeListHead(&rcFCB->ParentListHead);
return rcFCB;
}
[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
static
VOID
vfatDelFCBFromTable(
PDEVICE_EXTENSION pVCB,
PVFATFCB pFCB)
{
ULONG Index;
ULONG ShortIndex;
HASHENTRY* entry;
Index = pFCB->Hash.Hash % pVCB->HashTableSize;
ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize;
if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
{
entry = pVCB->FcbHashTable[ShortIndex];
if (entry->self == pFCB)
{
pVCB->FcbHashTable[ShortIndex] = entry->next;
}
else
{
while (entry->next->self != pFCB)
{
entry = entry->next;
}
entry->next = pFCB->ShortHash.next;
}
}
entry = pVCB->FcbHashTable[Index];
if (entry->self == pFCB)
{
pVCB->FcbHashTable[Index] = entry->next;
}
else
{
while (entry->next->self != pFCB)
{
entry = entry->next;
}
entry->next = pFCB->Hash.next;
}
RemoveEntryList(&pFCB->FcbListEntry);
[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
}
static
NTSTATUS
vfatMakeFullName(
PVFATFCB directoryFCB,
PUNICODE_STRING LongNameU,
PUNICODE_STRING ShortNameU,
PUNICODE_STRING NameU)
{
PWCHAR PathNameBuffer;
USHORT PathNameLength;
PathNameLength = directoryFCB->PathNameU.Length + max(LongNameU->Length, ShortNameU->Length);
if (!vfatFCBIsRoot(directoryFCB))
{
PathNameLength += sizeof(WCHAR);
}
if (PathNameLength > LONGNAME_MAX_LENGTH * sizeof(WCHAR))
{
return STATUS_OBJECT_NAME_INVALID;
}
PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameLength + sizeof(WCHAR), TAG_FCB);
if (!PathNameBuffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
NameU->Buffer = PathNameBuffer;
NameU->Length = 0;
NameU->MaximumLength = PathNameLength;
RtlCopyUnicodeString(NameU, &directoryFCB->PathNameU);
if (!vfatFCBIsRoot(directoryFCB))
{
RtlAppendUnicodeToString(NameU, L"\\");
}
if (LongNameU->Length > 0)
{
RtlAppendUnicodeStringToString(NameU, LongNameU);
}
else
{
RtlAppendUnicodeStringToString(NameU, ShortNameU);
}
NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0;
return STATUS_SUCCESS;
}
VOID
vfatDestroyCCB(
PVFATCCB pCcb)
{
if (pCcb->SearchPattern.Buffer)
{
ExFreePoolWithTag(pCcb->SearchPattern.Buffer, TAG_VFAT);
}
ExFreeToNPagedLookasideList(&VfatGlobalData->CcbLookasideList, pCcb);
}
VOID
vfatDestroyFCB(
PVFATFCB pFCB)
{
#ifdef KDBG
if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &pFCB->LongNameU, FALSE, NULL))
{
DPRINT1("Destroying: %p (%wZ) %d\n", pFCB, &pFCB->PathNameU, pFCB->RefCount);
}
#endif
FsRtlUninitializeFileLock(&pFCB->FileLock);
if (!vfatFCBIsRoot(pFCB) &&
!BooleanFlagOn(pFCB->Flags, FCB_IS_FAT) && !BooleanFlagOn(pFCB->Flags, FCB_IS_VOLUME))
{
RemoveEntryList(&pFCB->ParentListEntry);
}
ExFreePool(pFCB->PathNameBuffer);
ExDeleteResourceLite(&pFCB->PagingIoResource);
ExDeleteResourceLite(&pFCB->MainResource);
ASSERT(IsListEmpty(&pFCB->ParentListHead));
ExFreeToNPagedLookasideList(&VfatGlobalData->FcbLookasideList, pFCB);
}
BOOLEAN
vfatFCBIsRoot(
PVFATFCB FCB)
{
return FCB->PathNameU.Length == sizeof(WCHAR) && FCB->PathNameU.Buffer[0] == L'\\' ? TRUE : FALSE;
}
VOID
#ifndef KDBG
vfatGrabFCB(
#else
_vfatGrabFCB(
#endif
PDEVICE_EXTENSION pVCB,
PVFATFCB pFCB
#ifdef KDBG
,
PCSTR File,
ULONG Line,
PCSTR Func
#endif
)
{
#ifdef KDBG
if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &pFCB->LongNameU, FALSE, NULL))
{
DPRINT1("Inc ref count (%d, oc: %d) for: %p (%wZ) at: %s(%d) %s\n", pFCB->RefCount, pFCB->OpenHandleCount, pFCB, &pFCB->PathNameU, File, Line, Func);
}
#endif
ASSERT(ExIsResourceAcquiredExclusive(&pVCB->DirResource));
ASSERT(pFCB != pVCB->VolumeFcb);
ASSERT(pFCB->RefCount > 0);
++pFCB->RefCount;
}
VOID
#ifndef KDBG
vfatReleaseFCB(
#else
_vfatReleaseFCB(
#endif
PDEVICE_EXTENSION pVCB,
PVFATFCB pFCB
#ifdef KDBG
,
PCSTR File,
ULONG Line,
PCSTR Func
#endif
)
{
PVFATFCB tmpFcb;
#ifdef KDBG
if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &pFCB->LongNameU, FALSE, NULL))
{
DPRINT1("Dec ref count (%d, oc: %d) for: %p (%wZ) at: %s(%d) %s\n", pFCB->RefCount, pFCB->OpenHandleCount, pFCB, &pFCB->PathNameU, File, Line, Func);
}
#else
DPRINT("releasing FCB at %p: %wZ, refCount:%d\n",
pFCB, &pFCB->PathNameU, pFCB->RefCount);
#endif
ASSERT(ExIsResourceAcquiredExclusive(&pVCB->DirResource));
while (pFCB)
{
ULONG RefCount;
ASSERT(pFCB != pVCB->VolumeFcb);
ASSERT(pFCB->RefCount > 0);
RefCount = --pFCB->RefCount;
if (RefCount == 1 && BooleanFlagOn(pFCB->Flags, FCB_CACHE_INITIALIZED))
{
PFILE_OBJECT tmpFileObject;
tmpFileObject = pFCB->FileObject;
pFCB->FileObject = NULL;
CcUninitializeCacheMap(tmpFileObject, NULL, NULL);
ClearFlag(pFCB->Flags, FCB_CACHE_INITIALIZED);
ObDereferenceObject(tmpFileObject);
}
if (RefCount == 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
ASSERT(pFCB->OpenHandleCount == 0);
tmpFcb = 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
vfatDelFCBFromTable(pVCB, pFCB);
vfatDestroyFCB(pFCB);
}
else
{
tmpFcb = NULL;
}
pFCB = tmpFcb;
}
}
[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
static
VOID
vfatAddFCBToTable(
PDEVICE_EXTENSION pVCB,
PVFATFCB pFCB)
{
ULONG Index;
ULONG ShortIndex;
ASSERT(pFCB->Hash.Hash == vfatNameHash(0, &pFCB->PathNameU));
Index = pFCB->Hash.Hash % pVCB->HashTableSize;
ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize;
InsertTailList(&pVCB->FcbListHead, &pFCB->FcbListEntry);
pFCB->Hash.next = pVCB->FcbHashTable[Index];
pVCB->FcbHashTable[Index] = &pFCB->Hash;
if (pFCB->Hash.Hash != pFCB->ShortHash.Hash)
{
pFCB->ShortHash.next = pVCB->FcbHashTable[ShortIndex];
pVCB->FcbHashTable[ShortIndex] = &pFCB->ShortHash;
}
if (pFCB->parentFcb)
{
vfatGrabFCB(pVCB, pFCB->parentFcb);
}
}
static
VOID
vfatInitFCBFromDirEntry(
PDEVICE_EXTENSION Vcb,
PVFATFCB Fcb,
PVFAT_DIRENTRY_CONTEXT DirContext)
{
ULONG Size;
RtlCopyMemory(&Fcb->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY));
RtlCopyUnicodeString(&Fcb->ShortNameU, &DirContext->ShortNameU);
Fcb->Hash.Hash = vfatNameHash(0, &Fcb->PathNameU);
if (vfatVolumeIsFatX(Vcb))
{
Fcb->ShortHash.Hash = Fcb->Hash.Hash;
}
else
{
Fcb->ShortHash.Hash = vfatNameHash(0, &Fcb->DirNameU);
Fcb->ShortHash.Hash = vfatNameHash(Fcb->ShortHash.Hash, &Fcb->ShortNameU);
}
if (vfatFCBIsDirectory(Fcb))
{
ULONG FirstCluster, CurrentCluster;
NTSTATUS Status = STATUS_SUCCESS;
Size = 0;
FirstCluster = vfatDirEntryGetFirstCluster(Vcb, &Fcb->entry);
if (FirstCluster == 1)
{
Size = Vcb->FatInfo.rootDirectorySectors * Vcb->FatInfo.BytesPerSector;
}
else if (FirstCluster != 0)
{
CurrentCluster = FirstCluster;
while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
{
Size += Vcb->FatInfo.BytesPerCluster;
Status = NextCluster(Vcb, FirstCluster, &CurrentCluster, FALSE);
}
}
}
else if (vfatVolumeIsFatX(Vcb))
{
Size = Fcb->entry.FatX.FileSize;
}
else
{
Size = Fcb->entry.Fat.FileSize;
}
Fcb->dirIndex = DirContext->DirIndex;
Fcb->startIndex = DirContext->StartIndex;
if (vfatVolumeIsFatX(Vcb) && !vfatFCBIsRoot(Fcb))
{
ASSERT(DirContext->DirIndex >= 2 && DirContext->StartIndex >= 2);
Fcb->dirIndex = DirContext->DirIndex-2;
Fcb->startIndex = DirContext->StartIndex-2;
}
Fcb->RFCB.FileSize.QuadPart = Size;
Fcb->RFCB.ValidDataLength.QuadPart = Size;
Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP_64(Size, Vcb->FatInfo.BytesPerCluster);
}
NTSTATUS
vfatSetFCBNewDirName(
PDEVICE_EXTENSION pVCB,
PVFATFCB Fcb,
PVFATFCB ParentFcb)
{
NTSTATUS Status;
UNICODE_STRING NewNameU;
/* Get full path name */
Status = vfatMakeFullName(ParentFcb, &Fcb->LongNameU, &Fcb->ShortNameU, &NewNameU);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Delete old name */
if (Fcb->PathNameBuffer)
{
ExFreePoolWithTag(Fcb->PathNameBuffer, TAG_FCB);
}
Fcb->PathNameU = NewNameU;
/* Delete from table */
vfatDelFCBFromTable(pVCB, Fcb);
/* Split it properly */
Fcb->PathNameBuffer = Fcb->PathNameU.Buffer;
Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
Fcb->Hash.Hash = vfatNameHash(0, &Fcb->PathNameU);
if (vfatVolumeIsFatX(pVCB))
{
Fcb->ShortHash.Hash = Fcb->Hash.Hash;
}
else
{
Fcb->ShortHash.Hash = vfatNameHash(0, &Fcb->DirNameU);
Fcb->ShortHash.Hash = vfatNameHash(Fcb->ShortHash.Hash, &Fcb->ShortNameU);
}
vfatAddFCBToTable(pVCB, Fcb);
vfatReleaseFCB(pVCB, ParentFcb);
return STATUS_SUCCESS;
}
[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
NTSTATUS
vfatUpdateFCB(
PDEVICE_EXTENSION pVCB,
PVFATFCB Fcb,
PVFAT_DIRENTRY_CONTEXT DirContext,
[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
PVFATFCB ParentFcb)
{
NTSTATUS Status;
PVFATFCB OldParent;
DPRINT("vfatUpdateFCB(%p, %p, %p, %p)\n", pVCB, Fcb, DirContext, 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
/* Get full path name */
Status = vfatMakeFullName(ParentFcb, &DirContext->LongNameU, &DirContext->ShortNameU, &Fcb->PathNameU);
if (!NT_SUCCESS(Status))
{
return 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
/* Delete old name */
if (Fcb->PathNameBuffer)
{
ExFreePoolWithTag(Fcb->PathNameBuffer, TAG_FCB);
}
/* Delete from table */
vfatDelFCBFromTable(pVCB, Fcb);
/* Split it properly */
Fcb->PathNameBuffer = Fcb->PathNameU.Buffer;
Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
/* Save old parent */
OldParent = Fcb->parentFcb;
RemoveEntryList(&Fcb->ParentListEntry);
[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
/* Reinit FCB */
vfatInitFCBFromDirEntry(pVCB, Fcb, DirContext);
if (vfatFCBIsDirectory(Fcb))
[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
{
CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, 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
}
Fcb->parentFcb = ParentFcb;
InsertTailList(&ParentFcb->ParentListHead, &Fcb->ParentListEntry);
[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
vfatAddFCBToTable(pVCB, Fcb);
/* If we moved across directories, dereference our old parent
* We also dereference in case we're just renaming since AddFCBToTable references it
[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(pVCB, OldParent);
return STATUS_SUCCESS;
}
PVFATFCB
vfatGrabFCBFromTable(
PDEVICE_EXTENSION pVCB,
PUNICODE_STRING PathNameU)
{
PVFATFCB rcFCB;
ULONG Hash;
UNICODE_STRING DirNameU;
UNICODE_STRING FileNameU;
PUNICODE_STRING FcbNameU;
HASHENTRY* entry;
DPRINT("'%wZ'\n", PathNameU);
ASSERT(PathNameU->Length >= sizeof(WCHAR) && PathNameU->Buffer[0] == L'\\');
Hash = vfatNameHash(0, PathNameU);
entry = pVCB->FcbHashTable[Hash % pVCB->HashTableSize];
if (entry)
{
vfatSplitPathName(PathNameU, &DirNameU, &FileNameU);
}
while (entry)
{
if (entry->Hash == Hash)
{
rcFCB = entry->self;
DPRINT("'%wZ' '%wZ'\n", &DirNameU, &rcFCB->DirNameU);
if (RtlEqualUnicodeString(&DirNameU, &rcFCB->DirNameU, TRUE))
{
if (rcFCB->Hash.Hash == Hash)
{
FcbNameU = &rcFCB->LongNameU;
}
else
{
FcbNameU = &rcFCB->ShortNameU;
}
/* compare the file name */
DPRINT("'%wZ' '%wZ'\n", &FileNameU, FcbNameU);
if (RtlEqualUnicodeString(&FileNameU, FcbNameU, TRUE))
{
vfatGrabFCB(pVCB, rcFCB);
return rcFCB;
}
}
}
entry = entry->next;
}
return NULL;
}
PVFATFCB
vfatMakeRootFCB(
PDEVICE_EXTENSION pVCB)
{
PVFATFCB FCB;
ULONG FirstCluster, CurrentCluster, Size = 0;
NTSTATUS Status = STATUS_SUCCESS;
UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\");
FCB = vfatNewFCB(pVCB, &NameU);
if (vfatVolumeIsFatX(pVCB))
{
memset(FCB->entry.FatX.Filename, ' ', 42);
FCB->entry.FatX.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
FCB->entry.FatX.Attrib = FILE_ATTRIBUTE_DIRECTORY;
FCB->entry.FatX.FirstCluster = 1;
Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
}
else
{
memset(FCB->entry.Fat.ShortName, ' ', 11);
FCB->entry.Fat.FileSize = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
FCB->entry.Fat.Attrib = FILE_ATTRIBUTE_DIRECTORY;
if (pVCB->FatInfo.FatType == FAT32)
{
CurrentCluster = FirstCluster = pVCB->FatInfo.RootCluster;
FCB->entry.Fat.FirstCluster = (unsigned short)(FirstCluster & 0xffff);
FCB->entry.Fat.FirstClusterHigh = (unsigned short)(FirstCluster >> 16);
while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
{
Size += pVCB->FatInfo.BytesPerCluster;
Status = NextCluster (pVCB, FirstCluster, &CurrentCluster, FALSE);
}
}
else
{
FCB->entry.Fat.FirstCluster = 1;
Size = pVCB->FatInfo.rootDirectorySectors * pVCB->FatInfo.BytesPerSector;
}
}
FCB->ShortHash.Hash = FCB->Hash.Hash;
FCB->RefCount = 2;
FCB->dirIndex = 0;
FCB->RFCB.FileSize.QuadPart = Size;
FCB->RFCB.ValidDataLength.QuadPart = Size;
FCB->RFCB.AllocationSize.QuadPart = Size;
FCB->RFCB.IsFastIoPossible = FastIoIsNotPossible;
vfatFCBInitializeCacheFromVolume(pVCB, FCB);
vfatAddFCBToTable(pVCB, FCB);
return FCB;
}
PVFATFCB
vfatOpenRootFCB(
PDEVICE_EXTENSION pVCB)
{
PVFATFCB FCB;
UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\");
FCB = vfatGrabFCBFromTable(pVCB, &NameU);
if (FCB == NULL)
{
FCB = vfatMakeRootFCB(pVCB);
}
return FCB;
}
NTSTATUS
vfatMakeFCBFromDirEntry(
PVCB vcb,
PVFATFCB directoryFCB,
PVFAT_DIRENTRY_CONTEXT DirContext,
PVFATFCB *fileFCB)
{
PVFATFCB rcFCB;
UNICODE_STRING NameU;
[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
NTSTATUS 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
Status = vfatMakeFullName(directoryFCB, &DirContext->LongNameU, &DirContext->ShortNameU, &NameU);
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
return Status;
}
rcFCB = vfatNewFCB(vcb, &NameU);
vfatInitFCBFromDirEntry(vcb, rcFCB, DirContext);
rcFCB->RefCount = 1;
rcFCB->parentFcb = directoryFCB;
InsertTailList(&directoryFCB->ParentListHead, &rcFCB->ParentListEntry);
vfatAddFCBToTable(vcb, rcFCB);
*fileFCB = rcFCB;
ExFreePoolWithTag(NameU.Buffer, TAG_FCB);
return STATUS_SUCCESS;
}
NTSTATUS
vfatAttachFCBToFileObject(
PDEVICE_EXTENSION vcb,
PVFATFCB fcb,
PFILE_OBJECT fileObject)
{
PVFATCCB newCCB;
UNREFERENCED_PARAMETER(vcb);
#ifdef KDBG
if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &fcb->LongNameU, FALSE, NULL))
{
DPRINT1("Attaching %p to %p (%d)\n", fcb, fileObject, fcb->RefCount);
}
#endif
newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
if (newCCB == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
RtlZeroMemory(newCCB, sizeof (VFATCCB));
fileObject->SectionObjectPointer = &fcb->SectionObjectPointers;
fileObject->FsContext = fcb;
fileObject->FsContext2 = newCCB;
fileObject->Vpb = vcb->IoVPB;
DPRINT("file open: fcb:%p PathName:%wZ\n", fcb, &fcb->PathNameU);
#ifdef KDBG
fcb->Flags &= ~FCB_CLEANED_UP;
fcb->Flags &= ~FCB_CLOSED;
#endif
return STATUS_SUCCESS;
}
NTSTATUS
vfatDirFindFile(
PDEVICE_EXTENSION pDeviceExt,
PVFATFCB pDirectoryFCB,
PUNICODE_STRING FileToFindU,
PVFATFCB *pFoundFCB)
{
NTSTATUS status;
PVOID Context = NULL;
PVOID Page = NULL;
BOOLEAN First = TRUE;
VFAT_DIRENTRY_CONTEXT DirContext;
/* This buffer must have a size of 260 characters, because
vfatMakeFCBFromDirEntry can copy 20 name entries with 13 characters. */
WCHAR LongNameBuffer[260];
WCHAR ShortNameBuffer[13];
BOOLEAN FoundLong = FALSE;
BOOLEAN FoundShort = FALSE;
BOOLEAN IsFatX = vfatVolumeIsFatX(pDeviceExt);
ASSERT(pDeviceExt);
ASSERT(pDirectoryFCB);
ASSERT(FileToFindU);
DPRINT("vfatDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
pDeviceExt, pDirectoryFCB, FileToFindU);
DPRINT("Dir Path:%wZ\n", &pDirectoryFCB->PathNameU);
DirContext.DirIndex = 0;
DirContext.LongNameU.Buffer = LongNameBuffer;
DirContext.LongNameU.Length = 0;
DirContext.LongNameU.MaximumLength = sizeof(LongNameBuffer);
DirContext.ShortNameU.Buffer = ShortNameBuffer;
DirContext.ShortNameU.Length = 0;
DirContext.ShortNameU.MaximumLength = sizeof(ShortNameBuffer);
DirContext.DeviceExt = pDeviceExt;
while (TRUE)
{
status = VfatGetNextDirEntry(pDeviceExt,
&Context,
&Page,
pDirectoryFCB,
&DirContext,
First);
First = FALSE;
if (status == STATUS_NO_MORE_ENTRIES)
{
return STATUS_OBJECT_NAME_NOT_FOUND;
}
if (!NT_SUCCESS(status))
{
return status;
}
DPRINT(" Index:%u longName:%wZ\n",
DirContext.DirIndex, &DirContext.LongNameU);
if (!ENTRY_VOLUME(IsFatX, &DirContext.DirEntry))
{
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;
}
FoundLong = RtlEqualUnicodeString(FileToFindU, &DirContext.LongNameU, TRUE);
if (FoundLong == FALSE)
{
FoundShort = RtlEqualUnicodeString(FileToFindU, &DirContext.ShortNameU, TRUE);
}
if (FoundLong || FoundShort)
{
status = vfatMakeFCBFromDirEntry(pDeviceExt,
pDirectoryFCB,
&DirContext,
pFoundFCB);
CcUnpinData(Context);
return status;
}
}
DirContext.DirIndex++;
}
return STATUS_OBJECT_NAME_NOT_FOUND;
}
NTSTATUS
vfatGetFCBForFile(
PDEVICE_EXTENSION pVCB,
PVFATFCB *pParentFCB,
PVFATFCB *pFCB,
PUNICODE_STRING pFileNameU)
{
NTSTATUS status;
PVFATFCB FCB = NULL;
PVFATFCB parentFCB;
UNICODE_STRING NameU;
UNICODE_STRING RootNameU = RTL_CONSTANT_STRING(L"\\");
UNICODE_STRING FileNameU;
WCHAR NameBuffer[260];
PWCHAR curr, prev, last;
ULONG Length;
DPRINT("vfatGetFCBForFile (%p,%p,%p,%wZ)\n",
pVCB, pParentFCB, pFCB, pFileNameU);
RtlInitEmptyUnicodeString(&FileNameU, NameBuffer, sizeof(NameBuffer));
parentFCB = *pParentFCB;
if (parentFCB == NULL)
{
/* Passed-in name is the full name */
RtlCopyUnicodeString(&FileNameU, pFileNameU);
// Trivial case, open of the root directory on volume
if (RtlEqualUnicodeString(&FileNameU, &RootNameU, FALSE))
{
DPRINT("returning root FCB\n");
FCB = vfatOpenRootFCB(pVCB);
*pFCB = FCB;
*pParentFCB = NULL;
return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
}
/* Check for an existing FCB */
FCB = vfatGrabFCBFromTable(pVCB, &FileNameU);
if (FCB)
{
*pFCB = FCB;
*pParentFCB = FCB->parentFcb;
vfatGrabFCB(pVCB, *pParentFCB);
return STATUS_SUCCESS;
}
last = curr = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
while (*curr != L'\\' && curr > FileNameU.Buffer)
{
curr--;
}
if (curr > FileNameU.Buffer)
{
NameU.Buffer = FileNameU.Buffer;
NameU.MaximumLength = NameU.Length = (curr - FileNameU.Buffer) * sizeof(WCHAR);
FCB = vfatGrabFCBFromTable(pVCB, &NameU);
if (FCB)
{
Length = (curr - FileNameU.Buffer) * sizeof(WCHAR);
if (Length != FCB->PathNameU.Length)
{
if (FileNameU.Length + FCB->PathNameU.Length - Length > FileNameU.MaximumLength)
{
vfatReleaseFCB(pVCB, FCB);
return STATUS_OBJECT_NAME_INVALID;
}
RtlMoveMemory(FileNameU.Buffer + FCB->PathNameU.Length / sizeof(WCHAR),
curr, FileNameU.Length - Length);
FileNameU.Length += (USHORT)(FCB->PathNameU.Length - Length);
curr = FileNameU.Buffer + FCB->PathNameU.Length / sizeof(WCHAR);
last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
}
RtlCopyMemory(FileNameU.Buffer, FCB->PathNameU.Buffer, FCB->PathNameU.Length);
}
}
else
{
FCB = NULL;
}
if (FCB == NULL)
{
FCB = vfatOpenRootFCB(pVCB);
curr = FileNameU.Buffer;
}
parentFCB = NULL;
prev = curr;
}
else
{
/* Make absolute path */
RtlCopyUnicodeString(&FileNameU, &parentFCB->PathNameU);
curr = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
if (*curr != L'\\')
{
RtlAppendUnicodeToString(&FileNameU, L"\\");
curr++;
}
ASSERT(*curr == L'\\');
RtlAppendUnicodeStringToString(&FileNameU, pFileNameU);
FCB = parentFCB;
parentFCB = NULL;
prev = curr;
last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
}
while (curr <= last)
{
if (parentFCB)
{
vfatReleaseFCB(pVCB, parentFCB);
parentFCB = NULL;
}
// fail if element in FCB is not a directory
if (!vfatFCBIsDirectory(FCB))
{
DPRINT ("Element in requested path is not a directory\n");
vfatReleaseFCB(pVCB, FCB);
FCB = NULL;
*pParentFCB = NULL;
*pFCB = NULL;
return STATUS_OBJECT_PATH_NOT_FOUND;
}
parentFCB = FCB;
if (prev < curr)
{
Length = (curr - prev) * sizeof(WCHAR);
if (Length != parentFCB->LongNameU.Length)
{
if (FileNameU.Length + parentFCB->LongNameU.Length - Length > FileNameU.MaximumLength)
{
vfatReleaseFCB(pVCB, parentFCB);
*pParentFCB = NULL;
*pFCB = NULL;
return STATUS_OBJECT_NAME_INVALID;
}
RtlMoveMemory(prev + parentFCB->LongNameU.Length / sizeof(WCHAR), curr,
FileNameU.Length - (curr - FileNameU.Buffer) * sizeof(WCHAR));
FileNameU.Length += (USHORT)(parentFCB->LongNameU.Length - Length);
curr = prev + parentFCB->LongNameU.Length / sizeof(WCHAR);
last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
}
RtlCopyMemory(prev, parentFCB->LongNameU.Buffer, parentFCB->LongNameU.Length);
}
curr++;
prev = curr;
while (*curr != L'\\' && curr <= last)
{
curr++;
}
NameU.Buffer = FileNameU.Buffer;
NameU.Length = (curr - NameU.Buffer) * sizeof(WCHAR);
NameU.MaximumLength = FileNameU.MaximumLength;
DPRINT("%wZ\n", &NameU);
FCB = vfatGrabFCBFromTable(pVCB, &NameU);
if (FCB == NULL)
{
NameU.Buffer = prev;
NameU.MaximumLength = NameU.Length = (curr - prev) * sizeof(WCHAR);
status = vfatDirFindFile(pVCB, parentFCB, &NameU, &FCB);
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
{
*pFCB = NULL;
if (curr > last)
{
*pParentFCB = parentFCB;
return STATUS_OBJECT_NAME_NOT_FOUND;
}
else
{
vfatReleaseFCB(pVCB, parentFCB);
*pParentFCB = NULL;
return STATUS_OBJECT_PATH_NOT_FOUND;
}
}
else if (!NT_SUCCESS(status))
{
vfatReleaseFCB(pVCB, parentFCB);
*pParentFCB = NULL;
*pFCB = NULL;
return status;
}
}
}
*pParentFCB = parentFCB;
*pFCB = FCB;
return STATUS_SUCCESS;
}