[FASTFAT]
[reactos.git] / reactos / drivers / filesystems / fastfat / fcb.c
index 62c4653..4808d62 100644 (file)
@@ -153,6 +153,7 @@ vfatNewFCB(
     rcFCB->RFCB.PagingIoResource = &rcFCB->PagingIoResource;
     rcFCB->RFCB.Resource = &rcFCB->MainResource;
     rcFCB->RFCB.IsFastIoPossible = FastIoIsNotPossible;
+    InitializeListHead(&rcFCB->ParentListHead);
 
     return  rcFCB;
 }
@@ -267,10 +268,16 @@ vfatDestroyFCB(
     PVFATFCB pFCB)
 {
     FsRtlUninitializeFileLock(&pFCB->FileLock);
+    if (!vfatFCBIsRoot(pFCB) &&
+        !BooleanFlagOn(pFCB->Flags, FCB_IS_FAT) && !BooleanFlagOn(pFCB->Flags, FCB_IS_VOLUME))
+    {
+        RemoveEntryList(&pFCB->ParentListEntry);
+    }
     ExFreePool(pFCB->PathNameBuffer);
     ExDeleteResourceLite(&pFCB->PagingIoResource);
     ExDeleteResourceLite(&pFCB->MainResource);
     ExFreeToNPagedLookasideList(&VfatGlobalData->FcbLookasideList, pFCB);
+    ASSERT(IsListEmpty(&pFCB->ParentListHead));
 }
 
 BOOLEAN
@@ -340,6 +347,7 @@ vfatAddFCBToTable(
     ULONG Index;
     ULONG ShortIndex;
 
+    ASSERT(pFCB->Hash.Hash == vfatNameHash(0, &pFCB->PathNameU));
     Index = pFCB->Hash.Hash % pVCB->HashTableSize;
     ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize;
 
@@ -358,20 +366,80 @@ vfatAddFCBToTable(
     }
 }
 
+static
+VOID
+vfatInitFCBFromDirEntry(
+    PDEVICE_EXTENSION Vcb,
+    PVFATFCB Fcb,
+    PVFAT_DIRENTRY_CONTEXT DirContext)
+{
+    ULONG Size;
+
+    RtlCopyMemory(&Fcb->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY));
+    RtlCopyUnicodeString(&Fcb->ShortNameU, &DirContext->ShortNameU);
+    Fcb->Hash.Hash = vfatNameHash(0, &Fcb->PathNameU);
+    if (Vcb->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);
+    }
+
+    if (vfatFCBIsDirectory(Fcb))
+    {
+        ULONG FirstCluster, CurrentCluster;
+        NTSTATUS Status = STATUS_SUCCESS;
+        Size = 0;
+        FirstCluster = vfatDirEntryGetFirstCluster(Vcb, &Fcb->entry);
+        if (FirstCluster == 1)
+        {
+            Size = Vcb->FatInfo.rootDirectorySectors * Vcb->FatInfo.BytesPerSector;
+        }
+        else if (FirstCluster != 0)
+        {
+            CurrentCluster = FirstCluster;
+            while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
+            {
+                Size += Vcb->FatInfo.BytesPerCluster;
+                Status = NextCluster(Vcb, FirstCluster, &CurrentCluster, FALSE);
+            }
+        }
+    }
+    else if (Fcb->Flags & FCB_IS_FATX_ENTRY)
+    {
+        Size = Fcb->entry.FatX.FileSize;
+    }
+    else
+    {
+        Size = Fcb->entry.Fat.FileSize;
+    }
+    Fcb->dirIndex = DirContext->DirIndex;
+    Fcb->startIndex = DirContext->StartIndex;
+    if ((Fcb->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot(Fcb))
+    {
+        ASSERT(DirContext->DirIndex >= 2 && DirContext->StartIndex >= 2);
+        Fcb->dirIndex = DirContext->DirIndex-2;
+        Fcb->startIndex = DirContext->StartIndex-2;
+    }
+    Fcb->RFCB.FileSize.QuadPart = Size;
+    Fcb->RFCB.ValidDataLength.QuadPart = Size;
+    Fcb->RFCB.AllocationSize.QuadPart = ROUND_UP_64(Size, Vcb->FatInfo.BytesPerCluster);
+}
+
 NTSTATUS
-vfatUpdateFCB(
+vfatSetFCBNewDirName(
     PDEVICE_EXTENSION pVCB,
     PVFATFCB Fcb,
-    PVFAT_DIRENTRY_CONTEXT DirContext,
     PVFATFCB ParentFcb)
 {
     NTSTATUS Status;
-    PVFATFCB OldParent;
-
-    DPRINT("vfatUpdateFCB(%p, %p, %p, %p)\n", pVCB, Fcb, DirContext, ParentFcb);
+    UNICODE_STRING NewNameU;
 
     /* Get full path name */
-    Status = vfatMakeFullName(ParentFcb, &DirContext->LongNameU, &DirContext->ShortNameU, &Fcb->PathNameU);
+    Status = vfatMakeFullName(ParentFcb, &Fcb->LongNameU, &Fcb->ShortNameU, &NewNameU);
     if (!NT_SUCCESS(Status))
     {
         return Status;
@@ -382,6 +450,7 @@ vfatUpdateFCB(
     {
         ExFreePoolWithTag(Fcb->PathNameBuffer, TAG_FCB);
     }
+    Fcb->PathNameU = NewNameU;
 
     /* Delete from table */
     vfatDelFCBFromTable(pVCB, Fcb);
@@ -390,32 +459,69 @@ vfatUpdateFCB(
     Fcb->PathNameBuffer = Fcb->PathNameU.Buffer;
     Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
     vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
-
-    /* Copy short name */
-    RtlCopyUnicodeString(&Fcb->ShortNameU, &DirContext->ShortNameU);
-
-    /* Recompute hashes */
     Fcb->Hash.Hash = vfatNameHash(0, &Fcb->PathNameU);
     if (pVCB->Flags & VCB_IS_FATX)
     {
         Fcb->ShortHash.Hash = Fcb->Hash.Hash;
-
-        RtlCopyMemory(Fcb->entry.FatX.Filename, DirContext->DirEntry.FatX.Filename, 42);
-        Fcb->entry.FatX.FilenameLength = DirContext->DirEntry.FatX.FilenameLength;
     }
     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,
+    PVFATFCB Fcb,
+    PVFAT_DIRENTRY_CONTEXT DirContext,
+    PVFATFCB ParentFcb)
+{
+    NTSTATUS Status;
+    PVFATFCB OldParent;
+
+    DPRINT("vfatUpdateFCB(%p, %p, %p, %p)\n", pVCB, Fcb, DirContext, ParentFcb);
+
+    /* Get full path name */
+    Status = vfatMakeFullName(ParentFcb, &DirContext->LongNameU, &DirContext->ShortNameU, &Fcb->PathNameU);
+    if (!NT_SUCCESS(Status))
+    {
+        return Status;
+    }
 
-        RtlCopyMemory(Fcb->entry.Fat.ShortName, DirContext->DirEntry.Fat.ShortName, 11);
+    /* Delete old name */
+    if (Fcb->PathNameBuffer)
+    {
+        ExFreePoolWithTag(Fcb->PathNameBuffer, TAG_FCB);
     }
 
-    /* Set parent */
+    /* Delete from table */
+    vfatDelFCBFromTable(pVCB, Fcb);
+
+    /* Split it properly */
+    Fcb->PathNameBuffer = Fcb->PathNameU.Buffer;
+    Fcb->DirNameU.Buffer = Fcb->PathNameU.Buffer;
+    vfatSplitPathName(&Fcb->PathNameU, &Fcb->DirNameU, &Fcb->LongNameU);
+
+    /* Save old parent */
     OldParent = Fcb->parentFcb;
-    Fcb->parentFcb = ParentFcb;
+    RemoveEntryList(&Fcb->ParentListEntry);
+
+    /* Reinit FCB */
+    vfatInitFCBFromDirEntry(pVCB, Fcb, DirContext);
 
-    /* Add to the table */
+    if (vfatFCBIsDirectory(Fcb))
+    {
+        CcFlushCache(&Fcb->SectionObjectPointers, NULL, 0, NULL);
+    }
+    Fcb->parentFcb = ParentFcb;
+    InsertTailList(&ParentFcb->ParentListHead, &Fcb->ParentListEntry);
     vfatAddFCBToTable(pVCB, Fcb);
 
     /* If we moved across directories, dereference our old parent
@@ -607,7 +713,6 @@ vfatMakeFCBFromDirEntry(
     PVFATFCB *fileFCB)
 {
     PVFATFCB rcFCB;
-    ULONG Size;
     UNICODE_STRING NameU;
     NTSTATUS Status;
 
@@ -618,67 +723,25 @@ vfatMakeFCBFromDirEntry(
     }
 
     rcFCB = vfatNewFCB(vcb, &NameU);
-    RtlCopyMemory(&rcFCB->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY));
-    RtlCopyUnicodeString(&rcFCB->ShortNameU, &DirContext->ShortNameU);
-    if (vcb->Flags & VCB_IS_FATX)
-    {
-        rcFCB->ShortHash.Hash = rcFCB->Hash.Hash;
-    }
-    else
-    {
-        rcFCB->ShortHash.Hash = vfatNameHash(0, &rcFCB->DirNameU);
-        rcFCB->ShortHash.Hash = vfatNameHash(rcFCB->ShortHash.Hash, &rcFCB->ShortNameU);
-    }
+    vfatInitFCBFromDirEntry(vcb, rcFCB, DirContext);
 
+    rcFCB->RefCount = 1;
     if (vfatFCBIsDirectory(rcFCB))
     {
-        ULONG FirstCluster, CurrentCluster;
-        NTSTATUS Status = STATUS_SUCCESS;
-        Size = 0;
-        FirstCluster = vfatDirEntryGetFirstCluster(vcb, &rcFCB->entry);
-        if (FirstCluster == 1)
+        Status = vfatFCBInitializeCacheFromVolume(vcb, rcFCB);
+        if (!NT_SUCCESS(Status))
         {
-            Size = vcb->FatInfo.rootDirectorySectors * vcb->FatInfo.BytesPerSector;
+            vfatReleaseFCB(vcb, rcFCB);
+            ExFreePoolWithTag(NameU.Buffer, TAG_FCB);
+            return Status;
         }
-        else if (FirstCluster != 0)
-        {
-            CurrentCluster = FirstCluster;
-            while (CurrentCluster != 0xffffffff && NT_SUCCESS(Status))
-            {
-                Size += vcb->FatInfo.BytesPerCluster;
-                Status = NextCluster(vcb, FirstCluster, &CurrentCluster, FALSE);
-            }
-        }
-    }
-    else if (rcFCB->Flags & FCB_IS_FATX_ENTRY)
-    {
-        Size = rcFCB->entry.FatX.FileSize;
-    }
-    else
-    {
-        Size = rcFCB->entry.Fat.FileSize;
-    }
-    rcFCB->dirIndex = DirContext->DirIndex;
-    rcFCB->startIndex = DirContext->StartIndex;
-    if ((rcFCB->Flags & FCB_IS_FATX_ENTRY) && !vfatFCBIsRoot(directoryFCB))
-    {
-        ASSERT(DirContext->DirIndex >= 2 && DirContext->StartIndex >= 2);
-        rcFCB->dirIndex = DirContext->DirIndex-2;
-        rcFCB->startIndex = DirContext->StartIndex-2;
-    }
-    rcFCB->RFCB.FileSize.QuadPart = Size;
-    rcFCB->RFCB.ValidDataLength.QuadPart = Size;
-    rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP_64(Size, vcb->FatInfo.BytesPerCluster);
-    rcFCB->RefCount = 1;
-    if (vfatFCBIsDirectory(rcFCB))
-    {
-        vfatFCBInitializeCacheFromVolume(vcb, rcFCB);
     }
     rcFCB->parentFcb = directoryFCB;
+    InsertTailList(&directoryFCB->ParentListHead, &rcFCB->ParentListEntry);
     vfatAddFCBToTable(vcb, rcFCB);
     *fileFCB = rcFCB;
 
-    ExFreePool(NameU.Buffer);
+    ExFreePoolWithTag(NameU.Buffer, TAG_FCB);
     return STATUS_SUCCESS;
 }