[FASTFAT]

After renaming a directory, rename any children FCB that would still exist in the FSD. This will allow next directory opening to properly work and open correct data.
This defeats corruption on directory renaming.
Unfortunately, this solution is not ideal and our driver should be reworked so that it quits using a hash table and it quits storing the whole path in the FCBs.

Deep thanks to Wim Hueskes and Thomas Faber for their help debugging the issue!

CORE-11377

svn path=/trunk/; revision=72145
This commit is contained in:
Pierre Schweitzer 2016-08-07 12:29:48 +00:00
parent bf98b09370
commit 2f3c2c58d2
3 changed files with 88 additions and 0 deletions

View file

@ -427,6 +427,53 @@ vfatInitFCBFromDirEntry(
Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP_64(Size, Vcb->FatInfo.BytesPerCluster);
}
NTSTATUS
vfatSetFCBNewDirName(
PDEVICE_EXTENSION pVCB,
PVFATFCB Fcb,
PVFATFCB ParentFcb)
{
NTSTATUS Status;
UNICODE_STRING NewNameU;
/* Get full path name */
Status = vfatMakeFullName(ParentFcb, &Fcb->LongNameU, &Fcb->ShortNameU, &NewNameU);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Delete old name */
if (Fcb->PathNameBuffer)
{
ExFreePoolWithTag(Fcb->PathNameBuffer, TAG_FCB);
}
Fcb->PathNameU = NewNameU;
/* Delete from table */
vfatDelFCBFromTable(pVCB, Fcb);
/* Split it properly */
Fcb->PathNameBuffer = Fcb->PathNameU.Buffer;
Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
if (pVCB->Flags & VCB_IS_FATX)
{
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;
}
NTSTATUS
vfatUpdateFCB(
PDEVICE_EXTENSION pVCB,

View file

@ -487,6 +487,36 @@ IsThereAChildOpened(PVFATFCB FCB)
return FALSE;
}
static
VOID
VfatRenameChildFCB(
PDEVICE_EXTENSION DeviceExt,
PVFATFCB FCB)
{
PLIST_ENTRY Entry;
PVFATFCB Child;
if (IsListEmpty(&FCB->ParentListHead))
return;
for (Entry = FCB->ParentListHead.Flink; Entry != &FCB->ParentListHead; Entry = Entry->Flink)
{
NTSTATUS Status;
Child = CONTAINING_RECORD(Entry, VFATFCB, ParentListEntry);
DPRINT("Found %wZ with still %lu references (parent: %lu)!\n", &Child->PathNameU, Child->RefCount, FCB->RefCount);
Status = vfatSetFCBNewDirName(DeviceExt, Child, FCB);
if (!NT_SUCCESS(Status))
continue;
if (vfatFCBIsDirectory(Child))
{
VfatRenameChildFCB(DeviceExt, Child);
}
}
}
/*
* FUNCTION: Set the file name information
*/
@ -911,6 +941,11 @@ VfatSetRenameInformation(
}
}
if (NT_SUCCESS(Status) && vfatFCBIsDirectory(FCB))
{
VfatRenameChildFCB(DeviceExt, FCB);
}
ASSERT(OldReferences == OldParent->RefCount + 1); // removed file
ASSERT(NewReferences == ParentFCB->RefCount - 1); // new file
Cleanup:

View file

@ -817,6 +817,12 @@ vfatNewFCB(
PDEVICE_EXTENSION pVCB,
PUNICODE_STRING pFileNameU);
NTSTATUS
vfatSetFCBNewDirName(
PDEVICE_EXTENSION pVCB,
PVFATFCB Fcb,
PVFATFCB ParentFcb);
NTSTATUS
vfatUpdateFCB(
PDEVICE_EXTENSION pVCB,