[FASTFAT]
authorPierre Schweitzer <pierre@reactos.org>
Sun, 7 Aug 2016 12:29:48 +0000 (12:29 +0000)
committerPierre Schweitzer <pierre@reactos.org>
Sun, 7 Aug 2016 12:29:48 +0000 (12:29 +0000)
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

reactos/drivers/filesystems/fastfat/fcb.c
reactos/drivers/filesystems/fastfat/finfo.c
reactos/drivers/filesystems/fastfat/vfat.h

index 3a63a34..3002e21 100644 (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,
index 6c9549a..f6f342d 100644 (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:
index 5ab03aa..f149065 100644 (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,