2005-08-24 18:29:45 +00:00
|
|
|
/*
|
2022-09-24 13:24:08 +00:00
|
|
|
* PROJECT: VFAT Filesystem
|
|
|
|
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
|
|
|
* PURPOSE: Routines to manipulate FCBs
|
|
|
|
* COPYRIGHT: Copyright 1998 Jason Filby <jasonfilby@yahoo.com>
|
|
|
|
* Copyright 2001 Rex Jolliff <rex@lvcablemodem.com>
|
|
|
|
* Copyright 2005-2022 Hervé Poussineau <hpoussin@reactos.org>
|
|
|
|
* Copyright 2008-2018 Pierre Schweitzer <pierre@reactos.org>
|
|
|
|
*/
|
2001-05-02 03:18:03 +00:00
|
|
|
|
|
|
|
/* ------------------------------------------------------- INCLUDES */
|
|
|
|
|
2013-12-19 16:20:28 +00:00
|
|
|
#include "vfat.h"
|
|
|
|
|
|
|
|
#define NDEBUG
|
|
|
|
#include <debug.h>
|
|
|
|
|
2007-11-21 17:18:25 +00:00
|
|
|
#ifdef __GNUC__
|
2005-01-12 12:33:57 +00:00
|
|
|
#include <wctype.h> /* towlower prototype */
|
2007-11-21 17:18:25 +00:00
|
|
|
#endif
|
2001-05-02 03:18:03 +00:00
|
|
|
|
|
|
|
/* -------------------------------------------------------- DEFINES */
|
2002-09-08 10:23:54 +00:00
|
|
|
|
2018-04-28 07:34:10 +00:00
|
|
|
#ifdef KDBG
|
|
|
|
extern UNICODE_STRING DebugFile;
|
|
|
|
#endif
|
|
|
|
|
2001-05-02 03:18:03 +00:00
|
|
|
/* -------------------------------------------------------- PUBLICS */
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
static
|
|
|
|
ULONG
|
|
|
|
vfatNameHash(
|
|
|
|
ULONG hash,
|
|
|
|
PUNICODE_STRING NameU)
|
* Used look aside lists to allocate memory for VFATFCB, VFATCCB and VFAT_IRP_CONTEXT.
* Removed IsLastEntry, IsVolEntry, IsDeletedEntry, vfat_wstrlen, vfatGrabFCB,
vfat_initstr, vfat_wcsncat, vfat_wcsncpy, vfat_movestr, wstrcmpi and replaced
this functions with existing equivalents or functions from ntoskrnl.
* Merged GetEntryName into vfatGetNextDirEntry for reducing some overhead.
* Implemented a file name cache to speed up the searching for existing fcb.
* Removed some calls to FsdDosDateTimeToFileTime.
* Moved the call to CcZeroData behind the initializing of the cache (in VfatWrite).
* Using existing fcbs in FindFile if there is no '*?' within the search name.
svn path=/trunk/; revision=3740
2002-11-11 21:49:18 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
* Used look aside lists to allocate memory for VFATFCB, VFATCCB and VFAT_IRP_CONTEXT.
* Removed IsLastEntry, IsVolEntry, IsDeletedEntry, vfat_wstrlen, vfatGrabFCB,
vfat_initstr, vfat_wcsncat, vfat_wcsncpy, vfat_movestr, wstrcmpi and replaced
this functions with existing equivalents or functions from ntoskrnl.
* Merged GetEntryName into vfatGetNextDirEntry for reducing some overhead.
* Implemented a file name cache to speed up the searching for existing fcb.
* Removed some calls to FsdDosDateTimeToFileTime.
* Moved the call to CcZeroData behind the initializing of the cache (in VfatWrite).
* Using existing fcbs in FindFile if there is no '*?' within the search name.
svn path=/trunk/; revision=3740
2002-11-11 21:49:18 +00:00
|
|
|
}
|
|
|
|
|
2003-10-11 17:51:56 +00:00
|
|
|
VOID
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatSplitPathName(
|
|
|
|
PUNICODE_STRING PathNameU,
|
|
|
|
PUNICODE_STRING DirNameU,
|
|
|
|
PUNICODE_STRING FileNameU)
|
2003-10-11 17:51:56 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
|
|
|
}
|
2003-10-11 17:51:56 +00:00
|
|
|
}
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
static
|
|
|
|
VOID
|
|
|
|
vfatInitFcb(
|
|
|
|
PVFATFCB Fcb,
|
|
|
|
PUNICODE_STRING NameU)
|
2003-10-11 17:51:56 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-04-27 16:56:31 +00:00
|
|
|
Fcb->RFCB.NodeTypeCode = NODE_TYPE_FCB;
|
|
|
|
Fcb->RFCB.NodeByteSize = sizeof(VFATFCB);
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
2005-05-08 02:16:32 +00:00
|
|
|
}
|
2003-10-11 17:51:56 +00:00
|
|
|
|
2001-07-20 08:00:21 +00:00
|
|
|
PVFATFCB
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatNewFCB(
|
|
|
|
PDEVICE_EXTENSION pVCB,
|
|
|
|
PUNICODE_STRING pFileNameU)
|
2001-05-02 03:18:03 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
PVFATFCB rcFCB;
|
|
|
|
|
|
|
|
DPRINT("'%wZ'\n", pFileNameU);
|
|
|
|
|
|
|
|
rcFCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->FcbLookasideList);
|
|
|
|
if (rcFCB == NULL)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
RtlZeroMemory(rcFCB, sizeof(VFATFCB));
|
|
|
|
vfatInitFcb(rcFCB, pFileNameU);
|
2017-02-17 21:24:12 +00:00
|
|
|
if (vfatVolumeIsFatX(pVCB))
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
2016-08-06 08:30:30 +00:00
|
|
|
InitializeListHead(&rcFCB->ParentListHead);
|
2013-12-09 18:48:13 +00:00
|
|
|
|
|
|
|
return rcFCB;
|
2001-05-02 03:18:03 +00:00
|
|
|
}
|
|
|
|
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
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;
|
|
|
|
}
|
2014-10-20 09:31:50 +00:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2005-05-08 02:16:32 +00:00
|
|
|
VOID
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatDestroyCCB(
|
|
|
|
PVFATCCB pCcb)
|
* Used look aside lists to allocate memory for VFATFCB, VFATCCB and VFAT_IRP_CONTEXT.
* Removed IsLastEntry, IsVolEntry, IsDeletedEntry, vfat_wstrlen, vfatGrabFCB,
vfat_initstr, vfat_wcsncat, vfat_wcsncpy, vfat_movestr, wstrcmpi and replaced
this functions with existing equivalents or functions from ntoskrnl.
* Merged GetEntryName into vfatGetNextDirEntry for reducing some overhead.
* Implemented a file name cache to speed up the searching for existing fcb.
* Removed some calls to FsdDosDateTimeToFileTime.
* Moved the call to CcZeroData behind the initializing of the cache (in VfatWrite).
* Using existing fcbs in FindFile if there is no '*?' within the search name.
svn path=/trunk/; revision=3740
2002-11-11 21:49:18 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
if (pCcb->SearchPattern.Buffer)
|
|
|
|
{
|
2018-08-21 06:36:51 +00:00
|
|
|
ExFreePoolWithTag(pCcb->SearchPattern.Buffer, TAG_SEARCH);
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
|
|
|
ExFreeToNPagedLookasideList(&VfatGlobalData->CcbLookasideList, pCcb);
|
* Used look aside lists to allocate memory for VFATFCB, VFATCCB and VFAT_IRP_CONTEXT.
* Removed IsLastEntry, IsVolEntry, IsDeletedEntry, vfat_wstrlen, vfatGrabFCB,
vfat_initstr, vfat_wcsncat, vfat_wcsncpy, vfat_movestr, wstrcmpi and replaced
this functions with existing equivalents or functions from ntoskrnl.
* Merged GetEntryName into vfatGetNextDirEntry for reducing some overhead.
* Implemented a file name cache to speed up the searching for existing fcb.
* Removed some calls to FsdDosDateTimeToFileTime.
* Moved the call to CcZeroData behind the initializing of the cache (in VfatWrite).
* Using existing fcbs in FindFile if there is no '*?' within the search name.
svn path=/trunk/; revision=3740
2002-11-11 21:49:18 +00:00
|
|
|
}
|
|
|
|
|
2001-07-20 08:00:21 +00:00
|
|
|
VOID
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatDestroyFCB(
|
|
|
|
PVFATFCB pFCB)
|
2001-05-10 04:02:21 +00:00
|
|
|
{
|
2018-04-28 07:34:10 +00:00
|
|
|
#ifdef KDBG
|
|
|
|
if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &pFCB->LongNameU, FALSE, NULL))
|
|
|
|
{
|
|
|
|
DPRINT1("Destroying: %p (%wZ) %d\n", pFCB, &pFCB->PathNameU, pFCB->RefCount);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
FsRtlUninitializeFileLock(&pFCB->FileLock);
|
[FASTFAT] Improvements for volume dismount + minor bugfixing.
- Cache the RootFcb so that its cleanup can be handled separately
during dismounting.
- Force volume dismount at cleanup if the VCB_DISMOUNT_PENDING flag
is set.
- Actually dismount a volume if its VCB has been flagged as not good,
or if we force dismounting.
NOTE: In their *CheckForDismount() function, our 3rd-party FS drivers
as well as MS' fastfat, perform a comparison check of the current VCB's
VPB ReferenceCount with some sort of "dangling"/"residual" open count.
It seems to be related to the fact that the volume root directory as
well as auxiliary data stream(s) are still opened, and only these are
allowed to be opened at that moment. After analysis it appears that for
the ReactOS' fastfat, this number is equal to "3".
- On dismounting, cleanup and destroy the RootFcb, VolumeFcb and the
FATFileObject. Then cleanup the SpareVPB or the IoVPB members, and
finish by removing the dismounted volume from the VolumeListEntry
and cleaning up the notify synchronization object and the resources.
- During dismounting, and on shutdown, flush the volume before
resetting its dirty bit.
- On shutdown, after volume flushing, try to unmount it without forcing.
- Release the VCB resources only when we actually dismount the volume
in VfatCheckForDismount().
- Initialize first the notify list and the synchronization object,
before sending the FSRTL_VOLUME_MOUNT notification.
- If we failed at mounting a volume but its VCB's FATFileObject was
already initialized, first call CcUninitializeCacheMap() on it
before dereferencing it.
- Send FSRTL_VOLUME_LOCK, FSRTL_VOLUME_LOCK_FAILED and
FSRTL_VOLUME_UNLOCK notifications during volume locking (and failure)
and volume unlocking.
- Flush the volume before locking it, and clean its dirty bit if needed.
NOTE: In addition to checking for VCB_CLEAR_DIRTY, we also check for the
presence of the VCB_IS_DIRTY flag before cleaning up the dirty bit: this
allows us to not re-clean the bit if it has been previously cleaned.
This is needed for instance in this scenario:
- The volume is locked (it gets flushed and the dirty bit is possibly cleared);
- The volume then gets formatted with a completely different FS, that
possibly clears up the first sector (e.g. BTRFS ignores 1st sector);
- The volume is then dismounted: if we didn't check whether VCB_IS_DIRTY
was set prior to resetting it, we could attempt clearing it again! But
now that the volume's filesystem has been completely changed, we would
then try to modify the dirty bit on an erroneous position on disk!
That's why it should not be touched in this case during dismounting.
- The volume is unlocked (same comment as above), and later can be
detected as being BTRFS.
2018-11-11 16:17:48 +00:00
|
|
|
|
2016-08-06 08:57:47 +00:00
|
|
|
if (!vfatFCBIsRoot(pFCB) &&
|
|
|
|
!BooleanFlagOn(pFCB->Flags, FCB_IS_FAT) && !BooleanFlagOn(pFCB->Flags, FCB_IS_VOLUME))
|
|
|
|
{
|
|
|
|
RemoveEntryList(&pFCB->ParentListEntry);
|
|
|
|
}
|
2013-12-09 18:48:13 +00:00
|
|
|
ExFreePool(pFCB->PathNameBuffer);
|
|
|
|
ExDeleteResourceLite(&pFCB->PagingIoResource);
|
|
|
|
ExDeleteResourceLite(&pFCB->MainResource);
|
2016-08-06 08:30:30 +00:00
|
|
|
ASSERT(IsListEmpty(&pFCB->ParentListHead));
|
2017-03-04 14:48:05 +00:00
|
|
|
ExFreeToNPagedLookasideList(&VfatGlobalData->FcbLookasideList, pFCB);
|
2001-05-10 04:02:21 +00:00
|
|
|
}
|
|
|
|
|
2005-01-12 10:46:13 +00:00
|
|
|
BOOLEAN
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatFCBIsRoot(
|
|
|
|
PVFATFCB FCB)
|
2001-07-05 01:51:53 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
return FCB->PathNameU.Length == sizeof(WCHAR) && FCB->PathNameU.Buffer[0] == L'\\' ? TRUE : FALSE;
|
2001-05-02 03:18:03 +00:00
|
|
|
}
|
|
|
|
|
2014-10-26 20:20:42 +00:00
|
|
|
VOID
|
2018-04-28 07:34:10 +00:00
|
|
|
#ifndef KDBG
|
2014-10-26 20:20:42 +00:00
|
|
|
vfatGrabFCB(
|
2018-04-28 07:34:10 +00:00
|
|
|
#else
|
|
|
|
_vfatGrabFCB(
|
|
|
|
#endif
|
2014-10-26 20:20:42 +00:00
|
|
|
PDEVICE_EXTENSION pVCB,
|
2018-04-28 07:34:10 +00:00
|
|
|
PVFATFCB pFCB
|
|
|
|
#ifdef KDBG
|
|
|
|
,
|
|
|
|
PCSTR File,
|
|
|
|
ULONG Line,
|
|
|
|
PCSTR Func
|
|
|
|
#endif
|
|
|
|
)
|
2014-10-26 20:20:42 +00:00
|
|
|
{
|
2018-04-28 07:34:10 +00:00
|
|
|
#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);
|
|
|
|
}
|
[FASTFAT] Improvements for volume dismount + minor bugfixing.
- Cache the RootFcb so that its cleanup can be handled separately
during dismounting.
- Force volume dismount at cleanup if the VCB_DISMOUNT_PENDING flag
is set.
- Actually dismount a volume if its VCB has been flagged as not good,
or if we force dismounting.
NOTE: In their *CheckForDismount() function, our 3rd-party FS drivers
as well as MS' fastfat, perform a comparison check of the current VCB's
VPB ReferenceCount with some sort of "dangling"/"residual" open count.
It seems to be related to the fact that the volume root directory as
well as auxiliary data stream(s) are still opened, and only these are
allowed to be opened at that moment. After analysis it appears that for
the ReactOS' fastfat, this number is equal to "3".
- On dismounting, cleanup and destroy the RootFcb, VolumeFcb and the
FATFileObject. Then cleanup the SpareVPB or the IoVPB members, and
finish by removing the dismounted volume from the VolumeListEntry
and cleaning up the notify synchronization object and the resources.
- During dismounting, and on shutdown, flush the volume before
resetting its dirty bit.
- On shutdown, after volume flushing, try to unmount it without forcing.
- Release the VCB resources only when we actually dismount the volume
in VfatCheckForDismount().
- Initialize first the notify list and the synchronization object,
before sending the FSRTL_VOLUME_MOUNT notification.
- If we failed at mounting a volume but its VCB's FATFileObject was
already initialized, first call CcUninitializeCacheMap() on it
before dereferencing it.
- Send FSRTL_VOLUME_LOCK, FSRTL_VOLUME_LOCK_FAILED and
FSRTL_VOLUME_UNLOCK notifications during volume locking (and failure)
and volume unlocking.
- Flush the volume before locking it, and clean its dirty bit if needed.
NOTE: In addition to checking for VCB_CLEAR_DIRTY, we also check for the
presence of the VCB_IS_DIRTY flag before cleaning up the dirty bit: this
allows us to not re-clean the bit if it has been previously cleaned.
This is needed for instance in this scenario:
- The volume is locked (it gets flushed and the dirty bit is possibly cleared);
- The volume then gets formatted with a completely different FS, that
possibly clears up the first sector (e.g. BTRFS ignores 1st sector);
- The volume is then dismounted: if we didn't check whether VCB_IS_DIRTY
was set prior to resetting it, we could attempt clearing it again! But
now that the volume's filesystem has been completely changed, we would
then try to modify the dirty bit on an erroneous position on disk!
That's why it should not be touched in this case during dismounting.
- The volume is unlocked (same comment as above), and later can be
detected as being BTRFS.
2018-11-11 16:17:48 +00:00
|
|
|
#else
|
|
|
|
DPRINT("Grabbing FCB at %p: %wZ, refCount:%d\n",
|
|
|
|
pFCB, &pFCB->PathNameU, pFCB->RefCount);
|
2018-04-28 07:34:10 +00:00
|
|
|
#endif
|
|
|
|
|
2014-10-26 20:29:00 +00:00
|
|
|
ASSERT(ExIsResourceAcquiredExclusive(&pVCB->DirResource));
|
|
|
|
|
[FASTFAT] Improvements for volume dismount + minor bugfixing.
- Cache the RootFcb so that its cleanup can be handled separately
during dismounting.
- Force volume dismount at cleanup if the VCB_DISMOUNT_PENDING flag
is set.
- Actually dismount a volume if its VCB has been flagged as not good,
or if we force dismounting.
NOTE: In their *CheckForDismount() function, our 3rd-party FS drivers
as well as MS' fastfat, perform a comparison check of the current VCB's
VPB ReferenceCount with some sort of "dangling"/"residual" open count.
It seems to be related to the fact that the volume root directory as
well as auxiliary data stream(s) are still opened, and only these are
allowed to be opened at that moment. After analysis it appears that for
the ReactOS' fastfat, this number is equal to "3".
- On dismounting, cleanup and destroy the RootFcb, VolumeFcb and the
FATFileObject. Then cleanup the SpareVPB or the IoVPB members, and
finish by removing the dismounted volume from the VolumeListEntry
and cleaning up the notify synchronization object and the resources.
- During dismounting, and on shutdown, flush the volume before
resetting its dirty bit.
- On shutdown, after volume flushing, try to unmount it without forcing.
- Release the VCB resources only when we actually dismount the volume
in VfatCheckForDismount().
- Initialize first the notify list and the synchronization object,
before sending the FSRTL_VOLUME_MOUNT notification.
- If we failed at mounting a volume but its VCB's FATFileObject was
already initialized, first call CcUninitializeCacheMap() on it
before dereferencing it.
- Send FSRTL_VOLUME_LOCK, FSRTL_VOLUME_LOCK_FAILED and
FSRTL_VOLUME_UNLOCK notifications during volume locking (and failure)
and volume unlocking.
- Flush the volume before locking it, and clean its dirty bit if needed.
NOTE: In addition to checking for VCB_CLEAR_DIRTY, we also check for the
presence of the VCB_IS_DIRTY flag before cleaning up the dirty bit: this
allows us to not re-clean the bit if it has been previously cleaned.
This is needed for instance in this scenario:
- The volume is locked (it gets flushed and the dirty bit is possibly cleared);
- The volume then gets formatted with a completely different FS, that
possibly clears up the first sector (e.g. BTRFS ignores 1st sector);
- The volume is then dismounted: if we didn't check whether VCB_IS_DIRTY
was set prior to resetting it, we could attempt clearing it again! But
now that the volume's filesystem has been completely changed, we would
then try to modify the dirty bit on an erroneous position on disk!
That's why it should not be touched in this case during dismounting.
- The volume is unlocked (same comment as above), and later can be
detected as being BTRFS.
2018-11-11 16:17:48 +00:00
|
|
|
ASSERT(!BooleanFlagOn(pFCB->Flags, FCB_IS_FAT));
|
|
|
|
ASSERT(pFCB != pVCB->VolumeFcb && !BooleanFlagOn(pFCB->Flags, FCB_IS_VOLUME));
|
2014-11-05 19:06:19 +00:00
|
|
|
ASSERT(pFCB->RefCount > 0);
|
2014-10-26 20:20:42 +00:00
|
|
|
++pFCB->RefCount;
|
|
|
|
}
|
|
|
|
|
2001-07-20 08:00:21 +00:00
|
|
|
VOID
|
2018-04-28 07:34:10 +00:00
|
|
|
#ifndef KDBG
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatReleaseFCB(
|
2018-04-28 07:34:10 +00:00
|
|
|
#else
|
|
|
|
_vfatReleaseFCB(
|
|
|
|
#endif
|
2013-12-09 18:48:13 +00:00
|
|
|
PDEVICE_EXTENSION pVCB,
|
2018-04-28 07:34:10 +00:00
|
|
|
PVFATFCB pFCB
|
|
|
|
#ifdef KDBG
|
|
|
|
,
|
|
|
|
PCSTR File,
|
|
|
|
ULONG Line,
|
|
|
|
PCSTR Func
|
|
|
|
#endif
|
|
|
|
)
|
2001-05-02 03:18:03 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
PVFATFCB tmpFcb;
|
|
|
|
|
2018-04-28 07:34:10 +00:00
|
|
|
#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
|
[FASTFAT] Improvements for volume dismount + minor bugfixing.
- Cache the RootFcb so that its cleanup can be handled separately
during dismounting.
- Force volume dismount at cleanup if the VCB_DISMOUNT_PENDING flag
is set.
- Actually dismount a volume if its VCB has been flagged as not good,
or if we force dismounting.
NOTE: In their *CheckForDismount() function, our 3rd-party FS drivers
as well as MS' fastfat, perform a comparison check of the current VCB's
VPB ReferenceCount with some sort of "dangling"/"residual" open count.
It seems to be related to the fact that the volume root directory as
well as auxiliary data stream(s) are still opened, and only these are
allowed to be opened at that moment. After analysis it appears that for
the ReactOS' fastfat, this number is equal to "3".
- On dismounting, cleanup and destroy the RootFcb, VolumeFcb and the
FATFileObject. Then cleanup the SpareVPB or the IoVPB members, and
finish by removing the dismounted volume from the VolumeListEntry
and cleaning up the notify synchronization object and the resources.
- During dismounting, and on shutdown, flush the volume before
resetting its dirty bit.
- On shutdown, after volume flushing, try to unmount it without forcing.
- Release the VCB resources only when we actually dismount the volume
in VfatCheckForDismount().
- Initialize first the notify list and the synchronization object,
before sending the FSRTL_VOLUME_MOUNT notification.
- If we failed at mounting a volume but its VCB's FATFileObject was
already initialized, first call CcUninitializeCacheMap() on it
before dereferencing it.
- Send FSRTL_VOLUME_LOCK, FSRTL_VOLUME_LOCK_FAILED and
FSRTL_VOLUME_UNLOCK notifications during volume locking (and failure)
and volume unlocking.
- Flush the volume before locking it, and clean its dirty bit if needed.
NOTE: In addition to checking for VCB_CLEAR_DIRTY, we also check for the
presence of the VCB_IS_DIRTY flag before cleaning up the dirty bit: this
allows us to not re-clean the bit if it has been previously cleaned.
This is needed for instance in this scenario:
- The volume is locked (it gets flushed and the dirty bit is possibly cleared);
- The volume then gets formatted with a completely different FS, that
possibly clears up the first sector (e.g. BTRFS ignores 1st sector);
- The volume is then dismounted: if we didn't check whether VCB_IS_DIRTY
was set prior to resetting it, we could attempt clearing it again! But
now that the volume's filesystem has been completely changed, we would
then try to modify the dirty bit on an erroneous position on disk!
That's why it should not be touched in this case during dismounting.
- The volume is unlocked (same comment as above), and later can be
detected as being BTRFS.
2018-11-11 16:17:48 +00:00
|
|
|
DPRINT("Releasing FCB at %p: %wZ, refCount:%d\n",
|
2013-12-09 18:48:13 +00:00
|
|
|
pFCB, &pFCB->PathNameU, pFCB->RefCount);
|
2018-04-28 07:34:10 +00:00
|
|
|
#endif
|
2013-12-09 18:48:13 +00:00
|
|
|
|
2014-10-26 20:29:00 +00:00
|
|
|
ASSERT(ExIsResourceAcquiredExclusive(&pVCB->DirResource));
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
while (pFCB)
|
|
|
|
{
|
[FASTFAT] Don't leak directories FILE_OBJECT, FCB and cache entries.
Once a directory is crossed (opened or a child is opened), associated
FCB structure is created in FastFAT, but also a stream FO for caching.
Up to now, due to an extra reference taken by the stream file object,
even when the directory was no longer used, the directory was kept in
memory: the FCB was never deleted, the file object was never dereferenced,
and the cache never released.
The immediate effect of this bug is that our FAT driver was leaking every
directory that was used affecting the whole OS situation. In case of
directories intensive operation (like extraction the ReactOS source code
in ReactOS ;-)), we were just killin the whole OS RAM without any way to
release it and recover.
The other side effects: IOs were faster as half of the FS was always
permanant in RAM.
This commit fixes the issue by forcing the FSD to release the FO,
and the cache when a directory is no longer used, leading to its
destruction in RAM.
Downside: on IO intensive operation, expect slowdowns, obviously,
there's less caching now. But more efficient!
CORE-14557
2018-04-26 16:25:19 +00:00
|
|
|
ULONG RefCount;
|
|
|
|
|
[FASTFAT] Improvements for volume dismount + minor bugfixing.
- Cache the RootFcb so that its cleanup can be handled separately
during dismounting.
- Force volume dismount at cleanup if the VCB_DISMOUNT_PENDING flag
is set.
- Actually dismount a volume if its VCB has been flagged as not good,
or if we force dismounting.
NOTE: In their *CheckForDismount() function, our 3rd-party FS drivers
as well as MS' fastfat, perform a comparison check of the current VCB's
VPB ReferenceCount with some sort of "dangling"/"residual" open count.
It seems to be related to the fact that the volume root directory as
well as auxiliary data stream(s) are still opened, and only these are
allowed to be opened at that moment. After analysis it appears that for
the ReactOS' fastfat, this number is equal to "3".
- On dismounting, cleanup and destroy the RootFcb, VolumeFcb and the
FATFileObject. Then cleanup the SpareVPB or the IoVPB members, and
finish by removing the dismounted volume from the VolumeListEntry
and cleaning up the notify synchronization object and the resources.
- During dismounting, and on shutdown, flush the volume before
resetting its dirty bit.
- On shutdown, after volume flushing, try to unmount it without forcing.
- Release the VCB resources only when we actually dismount the volume
in VfatCheckForDismount().
- Initialize first the notify list and the synchronization object,
before sending the FSRTL_VOLUME_MOUNT notification.
- If we failed at mounting a volume but its VCB's FATFileObject was
already initialized, first call CcUninitializeCacheMap() on it
before dereferencing it.
- Send FSRTL_VOLUME_LOCK, FSRTL_VOLUME_LOCK_FAILED and
FSRTL_VOLUME_UNLOCK notifications during volume locking (and failure)
and volume unlocking.
- Flush the volume before locking it, and clean its dirty bit if needed.
NOTE: In addition to checking for VCB_CLEAR_DIRTY, we also check for the
presence of the VCB_IS_DIRTY flag before cleaning up the dirty bit: this
allows us to not re-clean the bit if it has been previously cleaned.
This is needed for instance in this scenario:
- The volume is locked (it gets flushed and the dirty bit is possibly cleared);
- The volume then gets formatted with a completely different FS, that
possibly clears up the first sector (e.g. BTRFS ignores 1st sector);
- The volume is then dismounted: if we didn't check whether VCB_IS_DIRTY
was set prior to resetting it, we could attempt clearing it again! But
now that the volume's filesystem has been completely changed, we would
then try to modify the dirty bit on an erroneous position on disk!
That's why it should not be touched in this case during dismounting.
- The volume is unlocked (same comment as above), and later can be
detected as being BTRFS.
2018-11-11 16:17:48 +00:00
|
|
|
ASSERT(!BooleanFlagOn(pFCB->Flags, FCB_IS_FAT));
|
|
|
|
ASSERT(pFCB != pVCB->VolumeFcb && !BooleanFlagOn(pFCB->Flags, FCB_IS_VOLUME));
|
2014-11-05 19:06:19 +00:00
|
|
|
ASSERT(pFCB->RefCount > 0);
|
[FASTFAT] Don't leak directories FILE_OBJECT, FCB and cache entries.
Once a directory is crossed (opened or a child is opened), associated
FCB structure is created in FastFAT, but also a stream FO for caching.
Up to now, due to an extra reference taken by the stream file object,
even when the directory was no longer used, the directory was kept in
memory: the FCB was never deleted, the file object was never dereferenced,
and the cache never released.
The immediate effect of this bug is that our FAT driver was leaking every
directory that was used affecting the whole OS situation. In case of
directories intensive operation (like extraction the ReactOS source code
in ReactOS ;-)), we were just killin the whole OS RAM without any way to
release it and recover.
The other side effects: IOs were faster as half of the FS was always
permanant in RAM.
This commit fixes the issue by forcing the FSD to release the FO,
and the cache when a directory is no longer used, leading to its
destruction in RAM.
Downside: on IO intensive operation, expect slowdowns, obviously,
there's less caching now. But more efficient!
CORE-14557
2018-04-26 16:25:19 +00:00
|
|
|
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)
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
ASSERT(pFCB->OpenHandleCount == 0);
|
2013-12-09 18:48:13 +00:00
|
|
|
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);
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatDestroyFCB(pFCB);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
tmpFcb = NULL;
|
|
|
|
}
|
|
|
|
pFCB = tmpFcb;
|
|
|
|
}
|
2001-05-02 03:18:03 +00:00
|
|
|
}
|
|
|
|
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
static
|
2001-07-20 08:00:21 +00:00
|
|
|
VOID
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatAddFCBToTable(
|
|
|
|
PDEVICE_EXTENSION pVCB,
|
|
|
|
PVFATFCB pFCB)
|
2001-05-02 03:18:03 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
ULONG Index;
|
|
|
|
ULONG ShortIndex;
|
|
|
|
|
2016-08-07 14:24:45 +00:00
|
|
|
ASSERT(pFCB->Hash.Hash == vfatNameHash(0, &pFCB->PathNameU));
|
2013-12-09 18:48:13 +00:00
|
|
|
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)
|
|
|
|
{
|
2014-10-26 20:20:42 +00:00
|
|
|
vfatGrabFCB(pVCB, pFCB->parentFcb);
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
2001-05-02 03:18:03 +00:00
|
|
|
}
|
|
|
|
|
2016-08-05 10:48:01 +00:00
|
|
|
static
|
|
|
|
VOID
|
|
|
|
vfatInitFCBFromDirEntry(
|
|
|
|
PDEVICE_EXTENSION Vcb,
|
2022-09-13 21:32:01 +00:00
|
|
|
PVFATFCB ParentFcb,
|
2016-08-05 10:48:01 +00:00
|
|
|
PVFATFCB Fcb,
|
|
|
|
PVFAT_DIRENTRY_CONTEXT DirContext)
|
|
|
|
{
|
|
|
|
ULONG Size;
|
|
|
|
|
|
|
|
RtlCopyMemory(&Fcb->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY));
|
|
|
|
RtlCopyUnicodeString(&Fcb->ShortNameU, &DirContext->ShortNameU);
|
2016-08-07 14:24:45 +00:00
|
|
|
Fcb->Hash.Hash = vfatNameHash(0, &Fcb->PathNameU);
|
2017-02-17 21:24:12 +00:00
|
|
|
if (vfatVolumeIsFatX(Vcb))
|
2016-08-05 10:48:01 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-02-17 21:24:12 +00:00
|
|
|
else if (vfatVolumeIsFatX(Vcb))
|
2016-08-05 10:48:01 +00:00
|
|
|
{
|
|
|
|
Size = Fcb->entry.FatX.FileSize;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Size = Fcb->entry.Fat.FileSize;
|
|
|
|
}
|
|
|
|
Fcb->dirIndex = DirContext->DirIndex;
|
|
|
|
Fcb->startIndex = DirContext->StartIndex;
|
2022-09-13 21:32:01 +00:00
|
|
|
Fcb->parentFcb = ParentFcb;
|
|
|
|
if (vfatVolumeIsFatX(Vcb) && !vfatFCBIsRoot(ParentFcb))
|
2016-08-05 10:48:01 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2016-08-07 12:29:48 +00:00
|
|
|
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);
|
2016-08-07 14:24:45 +00:00
|
|
|
Fcb->Hash.Hash = vfatNameHash(0, &Fcb->PathNameU);
|
2017-02-17 21:24:12 +00:00
|
|
|
if (vfatVolumeIsFatX(pVCB))
|
2016-08-07 12:29:48 +00:00
|
|
|
{
|
|
|
|
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,
|
2016-04-30 08:20:00 +00:00
|
|
|
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;
|
|
|
|
|
2016-04-30 08:20:00 +00:00
|
|
|
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
|
|
|
|
2014-11-06 00:07:01 +00:00
|
|
|
/* Get full path name */
|
2016-04-30 08:20:00 +00:00
|
|
|
Status = vfatMakeFullName(ParentFcb, &DirContext->LongNameU, &DirContext->ShortNameU, &Fcb->PathNameU);
|
2014-11-06 00:07:01 +00:00
|
|
|
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);
|
|
|
|
|
2016-08-05 10:48:01 +00:00
|
|
|
/* Save old parent */
|
|
|
|
OldParent = Fcb->parentFcb;
|
2016-08-06 08:30:30 +00:00
|
|
|
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
|
|
|
|
2016-08-05 10:48:01 +00:00
|
|
|
/* Reinit FCB */
|
2022-09-13 21:32:01 +00:00
|
|
|
vfatInitFCBFromDirEntry(pVCB, ParentFcb, Fcb, DirContext);
|
2016-04-30 08:20:00 +00:00
|
|
|
|
2016-08-05 10:48:01 +00:00
|
|
|
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
|
|
|
{
|
2016-08-05 10:48:01 +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
|
|
|
}
|
2016-08-06 08:30:30 +00:00
|
|
|
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);
|
|
|
|
|
2014-11-06 00:07:01 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
|
2001-07-20 08:00:21 +00:00
|
|
|
PVFATFCB
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatGrabFCBFromTable(
|
|
|
|
PDEVICE_EXTENSION pVCB,
|
|
|
|
PUNICODE_STRING PathNameU)
|
2001-05-02 03:18:03 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
PVFATFCB rcFCB;
|
|
|
|
ULONG Hash;
|
|
|
|
UNICODE_STRING DirNameU;
|
|
|
|
UNICODE_STRING FileNameU;
|
|
|
|
PUNICODE_STRING FcbNameU;
|
|
|
|
|
|
|
|
HASHENTRY* entry;
|
|
|
|
|
|
|
|
DPRINT("'%wZ'\n", PathNameU);
|
|
|
|
|
2015-12-08 12:57:45 +00:00
|
|
|
ASSERT(PathNameU->Length >= sizeof(WCHAR) && PathNameU->Buffer[0] == L'\\');
|
2013-12-09 18:48:13 +00:00
|
|
|
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))
|
|
|
|
{
|
2014-10-26 20:20:42 +00:00
|
|
|
vfatGrabFCB(pVCB, rcFCB);
|
2013-12-09 18:48:13 +00:00
|
|
|
return rcFCB;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
entry = entry->next;
|
|
|
|
}
|
|
|
|
return NULL;
|
2001-05-02 03:18:03 +00:00
|
|
|
}
|
2001-05-10 04:02:21 +00:00
|
|
|
|
2001-07-20 08:00:21 +00:00
|
|
|
PVFATFCB
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatMakeRootFCB(
|
|
|
|
PDEVICE_EXTENSION pVCB)
|
2001-07-05 01:51:53 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
PVFATFCB FCB;
|
|
|
|
ULONG FirstCluster, CurrentCluster, Size = 0;
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\");
|
|
|
|
|
[FASTFAT] Improvements for volume dismount + minor bugfixing.
- Cache the RootFcb so that its cleanup can be handled separately
during dismounting.
- Force volume dismount at cleanup if the VCB_DISMOUNT_PENDING flag
is set.
- Actually dismount a volume if its VCB has been flagged as not good,
or if we force dismounting.
NOTE: In their *CheckForDismount() function, our 3rd-party FS drivers
as well as MS' fastfat, perform a comparison check of the current VCB's
VPB ReferenceCount with some sort of "dangling"/"residual" open count.
It seems to be related to the fact that the volume root directory as
well as auxiliary data stream(s) are still opened, and only these are
allowed to be opened at that moment. After analysis it appears that for
the ReactOS' fastfat, this number is equal to "3".
- On dismounting, cleanup and destroy the RootFcb, VolumeFcb and the
FATFileObject. Then cleanup the SpareVPB or the IoVPB members, and
finish by removing the dismounted volume from the VolumeListEntry
and cleaning up the notify synchronization object and the resources.
- During dismounting, and on shutdown, flush the volume before
resetting its dirty bit.
- On shutdown, after volume flushing, try to unmount it without forcing.
- Release the VCB resources only when we actually dismount the volume
in VfatCheckForDismount().
- Initialize first the notify list and the synchronization object,
before sending the FSRTL_VOLUME_MOUNT notification.
- If we failed at mounting a volume but its VCB's FATFileObject was
already initialized, first call CcUninitializeCacheMap() on it
before dereferencing it.
- Send FSRTL_VOLUME_LOCK, FSRTL_VOLUME_LOCK_FAILED and
FSRTL_VOLUME_UNLOCK notifications during volume locking (and failure)
and volume unlocking.
- Flush the volume before locking it, and clean its dirty bit if needed.
NOTE: In addition to checking for VCB_CLEAR_DIRTY, we also check for the
presence of the VCB_IS_DIRTY flag before cleaning up the dirty bit: this
allows us to not re-clean the bit if it has been previously cleaned.
This is needed for instance in this scenario:
- The volume is locked (it gets flushed and the dirty bit is possibly cleared);
- The volume then gets formatted with a completely different FS, that
possibly clears up the first sector (e.g. BTRFS ignores 1st sector);
- The volume is then dismounted: if we didn't check whether VCB_IS_DIRTY
was set prior to resetting it, we could attempt clearing it again! But
now that the volume's filesystem has been completely changed, we would
then try to modify the dirty bit on an erroneous position on disk!
That's why it should not be touched in this case during dismounting.
- The volume is unlocked (same comment as above), and later can be
detected as being BTRFS.
2018-11-11 16:17:48 +00:00
|
|
|
ASSERT(pVCB->RootFcb == NULL);
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
FCB = vfatNewFCB(pVCB, &NameU);
|
2017-02-17 21:24:12 +00:00
|
|
|
if (vfatVolumeIsFatX(pVCB))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
|
[FASTFAT] Improvements for volume dismount + minor bugfixing.
- Cache the RootFcb so that its cleanup can be handled separately
during dismounting.
- Force volume dismount at cleanup if the VCB_DISMOUNT_PENDING flag
is set.
- Actually dismount a volume if its VCB has been flagged as not good,
or if we force dismounting.
NOTE: In their *CheckForDismount() function, our 3rd-party FS drivers
as well as MS' fastfat, perform a comparison check of the current VCB's
VPB ReferenceCount with some sort of "dangling"/"residual" open count.
It seems to be related to the fact that the volume root directory as
well as auxiliary data stream(s) are still opened, and only these are
allowed to be opened at that moment. After analysis it appears that for
the ReactOS' fastfat, this number is equal to "3".
- On dismounting, cleanup and destroy the RootFcb, VolumeFcb and the
FATFileObject. Then cleanup the SpareVPB or the IoVPB members, and
finish by removing the dismounted volume from the VolumeListEntry
and cleaning up the notify synchronization object and the resources.
- During dismounting, and on shutdown, flush the volume before
resetting its dirty bit.
- On shutdown, after volume flushing, try to unmount it without forcing.
- Release the VCB resources only when we actually dismount the volume
in VfatCheckForDismount().
- Initialize first the notify list and the synchronization object,
before sending the FSRTL_VOLUME_MOUNT notification.
- If we failed at mounting a volume but its VCB's FATFileObject was
already initialized, first call CcUninitializeCacheMap() on it
before dereferencing it.
- Send FSRTL_VOLUME_LOCK, FSRTL_VOLUME_LOCK_FAILED and
FSRTL_VOLUME_UNLOCK notifications during volume locking (and failure)
and volume unlocking.
- Flush the volume before locking it, and clean its dirty bit if needed.
NOTE: In addition to checking for VCB_CLEAR_DIRTY, we also check for the
presence of the VCB_IS_DIRTY flag before cleaning up the dirty bit: this
allows us to not re-clean the bit if it has been previously cleaned.
This is needed for instance in this scenario:
- The volume is locked (it gets flushed and the dirty bit is possibly cleared);
- The volume then gets formatted with a completely different FS, that
possibly clears up the first sector (e.g. BTRFS ignores 1st sector);
- The volume is then dismounted: if we didn't check whether VCB_IS_DIRTY
was set prior to resetting it, we could attempt clearing it again! But
now that the volume's filesystem has been completely changed, we would
then try to modify the dirty bit on an erroneous position on disk!
That's why it should not be touched in this case during dismounting.
- The volume is unlocked (same comment as above), and later can be
detected as being BTRFS.
2018-11-11 16:17:48 +00:00
|
|
|
/* Cache it */
|
|
|
|
pVCB->RootFcb = FCB;
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
return FCB;
|
2001-05-10 04:02:21 +00:00
|
|
|
}
|
|
|
|
|
2001-07-20 08:00:21 +00:00
|
|
|
PVFATFCB
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatOpenRootFCB(
|
|
|
|
PDEVICE_EXTENSION pVCB)
|
2001-05-10 04:02:21 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
PVFATFCB FCB;
|
|
|
|
UNICODE_STRING NameU = RTL_CONSTANT_STRING(L"\\");
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
FCB = vfatGrabFCBFromTable(pVCB, &NameU);
|
|
|
|
if (FCB == NULL)
|
|
|
|
{
|
|
|
|
FCB = vfatMakeRootFCB(pVCB);
|
|
|
|
}
|
[FASTFAT] Improvements for volume dismount + minor bugfixing.
- Cache the RootFcb so that its cleanup can be handled separately
during dismounting.
- Force volume dismount at cleanup if the VCB_DISMOUNT_PENDING flag
is set.
- Actually dismount a volume if its VCB has been flagged as not good,
or if we force dismounting.
NOTE: In their *CheckForDismount() function, our 3rd-party FS drivers
as well as MS' fastfat, perform a comparison check of the current VCB's
VPB ReferenceCount with some sort of "dangling"/"residual" open count.
It seems to be related to the fact that the volume root directory as
well as auxiliary data stream(s) are still opened, and only these are
allowed to be opened at that moment. After analysis it appears that for
the ReactOS' fastfat, this number is equal to "3".
- On dismounting, cleanup and destroy the RootFcb, VolumeFcb and the
FATFileObject. Then cleanup the SpareVPB or the IoVPB members, and
finish by removing the dismounted volume from the VolumeListEntry
and cleaning up the notify synchronization object and the resources.
- During dismounting, and on shutdown, flush the volume before
resetting its dirty bit.
- On shutdown, after volume flushing, try to unmount it without forcing.
- Release the VCB resources only when we actually dismount the volume
in VfatCheckForDismount().
- Initialize first the notify list and the synchronization object,
before sending the FSRTL_VOLUME_MOUNT notification.
- If we failed at mounting a volume but its VCB's FATFileObject was
already initialized, first call CcUninitializeCacheMap() on it
before dereferencing it.
- Send FSRTL_VOLUME_LOCK, FSRTL_VOLUME_LOCK_FAILED and
FSRTL_VOLUME_UNLOCK notifications during volume locking (and failure)
and volume unlocking.
- Flush the volume before locking it, and clean its dirty bit if needed.
NOTE: In addition to checking for VCB_CLEAR_DIRTY, we also check for the
presence of the VCB_IS_DIRTY flag before cleaning up the dirty bit: this
allows us to not re-clean the bit if it has been previously cleaned.
This is needed for instance in this scenario:
- The volume is locked (it gets flushed and the dirty bit is possibly cleared);
- The volume then gets formatted with a completely different FS, that
possibly clears up the first sector (e.g. BTRFS ignores 1st sector);
- The volume is then dismounted: if we didn't check whether VCB_IS_DIRTY
was set prior to resetting it, we could attempt clearing it again! But
now that the volume's filesystem has been completely changed, we would
then try to modify the dirty bit on an erroneous position on disk!
That's why it should not be touched in this case during dismounting.
- The volume is unlocked (same comment as above), and later can be
detected as being BTRFS.
2018-11-11 16:17:48 +00:00
|
|
|
ASSERT(FCB == pVCB->RootFcb);
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
return FCB;
|
2001-05-10 04:02:21 +00:00
|
|
|
}
|
|
|
|
|
2001-07-05 01:51:53 +00:00
|
|
|
NTSTATUS
|
2005-11-04 00:03:34 +00:00
|
|
|
vfatMakeFCBFromDirEntry(
|
2013-12-09 18:48:13 +00:00
|
|
|
PVCB vcb,
|
|
|
|
PVFATFCB directoryFCB,
|
|
|
|
PVFAT_DIRENTRY_CONTEXT DirContext,
|
|
|
|
PVFATFCB *fileFCB)
|
2001-05-10 04:02:21 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
2013-12-09 18:48:13 +00:00
|
|
|
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
Status = vfatMakeFullName(directoryFCB, &DirContext->LongNameU, &DirContext->ShortNameU, &NameU);
|
|
|
|
if (!NT_SUCCESS(Status))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
[FASTFAT]
- Implement vfatPrepareTargetForRename() that prepares for renaming. It tries to open target and deletes it if it exists and if allowed. And then, it opens the parent directory.
- Implement VfatSetRenameInformation() that actually does the renaming (call as SetInformationFile). It handles cases we we have (or we don't have) TargetDirectory provided. It sends notifications as appropriated on demands.
- Implement vfatRenameEntry() that renames an entry in place. So far, it only supports FATX entries renaming. FAT entries are a bit more complex. It falls back to vfatMoveEntry() in later cases.
- Implement VfatMoveEntry() that will move an entry accross directories (or in place for FAT). Its principles are simple: it deletes the entry in old parent, and recreate it in new parent, keeping file metadata & data.
- Modify VfatDelEntry() and VfatAddEntry() so that they can handle deleting an entry without touching its data and adding an entry with an already provided FCB and thus use the given metadata.
- Implement vfatDelFCBFromTable() which is just old code moved to new routine to allow reuse. It deletes a FCB entry from hash table. Doesn't deal with references!
- Implement vfatMakeFullName() which is mostly old code moved to new routine to allow reuse. It allocates buffer and copy data for FCB full name.
- Implement vfatUpdateFCB() that will update a FCB with new names and parent. It will remove anything related to old name and will recreate using new data. It will adjust references count.
- Modify vfatMakeFCBFromDirEntry() so that it calls vfatMakeFullName().
- Modify vfatReleaseFCB() so that it calls vfatDelFCBFromTable().
- Revert VfatOpenFile() to its previous features.
- Modify VfatCreateFile() to reimplement support for SL_OPEN_TARGET_DIRECTORY. It is way less hackish than previously. It also properly opens parent now, by incrementing its handle count and by setting appropriate access rights.
[KERNEL32]
- Rewritten MoveFileWithProgressW() to implement all the missing features that are used in Windows 2k3 including links and reparse points.
- Implemented BasepMoveFileDelayed() to replace deprecated add_boot_rename_entry(). This functions is matching the features implemented in SMSS.
- Implemented BasepMoveFileCopyProgress() which is used in MoveFileWithProgressW().
- Stubbed BasepNotifyTrackingService() which is not use at the moment (FastFAT, even in Windows doesn't provide such feature).
- Reimplemented ReplaceFileA(), MoveFileWithProgressA() to quit Winisms and use our internal helpers.
- Make MoveFileX() use MoveFileWithProgressX() directly.
- Fixed a few prototypes.
TL;DR:
This (huge) commit implements file and directory renaming in FastFAT driver. This allows getting rid of old implementation in kernel32 where files were force copied.
A feature is still missing, but Jérôme should implement it anytime soon (he prototyped it already): moving directories across volumes. This requires some work in BasepCopyFileExW().
Kudos to all the devs who helped me on this: Christoph, Hervé, Jérôme, Thomas.
This finally allows killing CR-52... It was about time!
svn path=/trunk/; revision=64836
2014-10-19 21:38:32 +00:00
|
|
|
return Status;
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
rcFCB = vfatNewFCB(vcb, &NameU);
|
2022-09-13 21:32:01 +00:00
|
|
|
vfatInitFCBFromDirEntry(vcb, directoryFCB, rcFCB, DirContext);
|
2013-12-09 18:48:13 +00:00
|
|
|
|
2014-11-05 19:06:19 +00:00
|
|
|
rcFCB->RefCount = 1;
|
2016-08-06 08:30:30 +00:00
|
|
|
InsertTailList(&directoryFCB->ParentListHead, &rcFCB->ParentListEntry);
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatAddFCBToTable(vcb, rcFCB);
|
|
|
|
*fileFCB = rcFCB;
|
|
|
|
|
2017-02-04 19:37:40 +00:00
|
|
|
ExFreePoolWithTag(NameU.Buffer, TAG_FCB);
|
2013-12-09 18:48:13 +00:00
|
|
|
return STATUS_SUCCESS;
|
2001-05-10 04:02:21 +00:00
|
|
|
}
|
|
|
|
|
2001-07-05 01:51:53 +00:00
|
|
|
NTSTATUS
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatAttachFCBToFileObject(
|
|
|
|
PDEVICE_EXTENSION vcb,
|
|
|
|
PVFATFCB fcb,
|
|
|
|
PFILE_OBJECT fileObject)
|
2001-05-10 04:02:21 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
PVFATCCB newCCB;
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2018-04-28 07:34:10 +00:00
|
|
|
#ifdef KDBG
|
|
|
|
if (DebugFile.Buffer != NULL && FsRtlIsNameInExpression(&DebugFile, &fcb->LongNameU, FALSE, NULL))
|
|
|
|
{
|
|
|
|
DPRINT1("Attaching %p to %p (%d)\n", fcb, fileObject, fcb->RefCount);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList);
|
|
|
|
if (newCCB == NULL)
|
|
|
|
{
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
}
|
|
|
|
RtlZeroMemory(newCCB, sizeof (VFATCCB));
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
fileObject->SectionObjectPointer = &fcb->SectionObjectPointers;
|
|
|
|
fileObject->FsContext = fcb;
|
|
|
|
fileObject->FsContext2 = newCCB;
|
2018-05-18 08:29:45 +00:00
|
|
|
fileObject->Vpb = vcb->IoVPB;
|
2013-12-09 18:48:13 +00:00
|
|
|
DPRINT("file open: fcb:%p PathName:%wZ\n", fcb, &fcb->PathNameU);
|
2007-10-19 23:21:45 +00:00
|
|
|
|
2018-04-28 07:34:10 +00:00
|
|
|
#ifdef KDBG
|
|
|
|
fcb->Flags &= ~FCB_CLEANED_UP;
|
|
|
|
fcb->Flags &= ~FCB_CLOSED;
|
|
|
|
#endif
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
return STATUS_SUCCESS;
|
2001-07-05 01:51:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatDirFindFile(
|
|
|
|
PDEVICE_EXTENSION pDeviceExt,
|
|
|
|
PVFATFCB pDirectoryFCB,
|
|
|
|
PUNICODE_STRING FileToFindU,
|
|
|
|
PVFATFCB *pFoundFCB)
|
2001-07-05 01:51:53 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
2017-02-18 21:37:56 +00:00
|
|
|
BOOLEAN IsFatX = vfatVolumeIsFatX(pDeviceExt);
|
2013-12-09 18:48:13 +00:00
|
|
|
|
|
|
|
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);
|
2018-05-18 12:03:20 +00:00
|
|
|
DirContext.DeviceExt = pDeviceExt;
|
2013-12-09 18:48:13 +00:00
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
2017-02-17 22:25:03 +00:00
|
|
|
status = VfatGetNextDirEntry(pDeviceExt,
|
|
|
|
&Context,
|
2013-12-09 18:48:13 +00:00
|
|
|
&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);
|
|
|
|
|
2017-02-18 21:37:56 +00:00
|
|
|
if (!ENTRY_VOLUME(IsFatX, &DirContext.DirEntry))
|
2013-12-09 18:48:13 +00:00
|
|
|
{
|
2015-11-30 11:25:14 +00:00
|
|
|
if (DirContext.LongNameU.Length == 0 ||
|
|
|
|
DirContext.ShortNameU.Length == 0)
|
|
|
|
{
|
|
|
|
DPRINT1("WARNING: File system corruption detected. You may need to run a disk repair utility.\n");
|
|
|
|
if (VfatGlobalData->Flags & VFAT_BREAK_ON_CORRUPTION)
|
|
|
|
{
|
|
|
|
ASSERT(DirContext.LongNameU.Length != 0 &&
|
|
|
|
DirContext.ShortNameU.Length != 0);
|
|
|
|
}
|
|
|
|
DirContext.DirIndex++;
|
|
|
|
continue;
|
|
|
|
}
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
2001-05-10 04:02:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
2013-12-09 18:48:13 +00:00
|
|
|
vfatGetFCBForFile(
|
|
|
|
PDEVICE_EXTENSION pVCB,
|
|
|
|
PVFATFCB *pParentFCB,
|
|
|
|
PVFATFCB *pFCB,
|
|
|
|
PUNICODE_STRING pFileNameU)
|
2001-05-10 04:02:21 +00:00
|
|
|
{
|
2013-12-09 18:48:13 +00:00
|
|
|
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);
|
|
|
|
|
2015-12-08 12:57:45 +00:00
|
|
|
RtlInitEmptyUnicodeString(&FileNameU, NameBuffer, sizeof(NameBuffer));
|
2013-12-09 18:48:13 +00:00
|
|
|
|
|
|
|
parentFCB = *pParentFCB;
|
|
|
|
|
|
|
|
if (parentFCB == NULL)
|
|
|
|
{
|
2015-12-08 12:57:45 +00:00
|
|
|
/* Passed-in name is the full name */
|
|
|
|
RtlCopyUnicodeString(&FileNameU, pFileNameU);
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
// 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;
|
2014-10-26 20:20:42 +00:00
|
|
|
vfatGrabFCB(pVCB, *pParentFCB);
|
2013-12-09 18:48:13 +00:00
|
|
|
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
|
|
|
|
{
|
2015-12-08 12:57:45 +00:00
|
|
|
/* 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);
|
|
|
|
|
2013-12-09 18:48:13 +00:00
|
|
|
FCB = parentFCB;
|
|
|
|
parentFCB = NULL;
|
2015-12-08 12:57:45 +00:00
|
|
|
prev = curr;
|
2013-12-09 18:48:13 +00:00
|
|
|
last = FileNameU.Buffer + FileNameU.Length / sizeof(WCHAR) - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (curr <= last)
|
|
|
|
{
|
|
|
|
if (parentFCB)
|
|
|
|
{
|
|
|
|
vfatReleaseFCB(pVCB, parentFCB);
|
2014-11-06 00:07:01 +00:00
|
|
|
parentFCB = NULL;
|
2013-12-09 18:48:13 +00:00
|
|
|
}
|
|
|
|
// 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);
|
2014-11-06 00:07:01 +00:00
|
|
|
*pParentFCB = NULL;
|
|
|
|
*pFCB = NULL;
|
2013-12-09 18:48:13 +00:00
|
|
|
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;
|
2001-05-10 04:02:21 +00:00
|
|
|
}
|