X-Git-Url: https://git.reactos.org/?p=reactos.git;a=blobdiff_plain;f=drivers%2Ffilesystems%2Ffastfat%2Ffcb.c;h=df4dd54e0834fd5f09f63088429254846f69db6b;hp=a4eef71a64acd9fcf784728d835e98657b5ce3a2;hb=e8103dd4d34bc35c53eb4b4da0845fe08548f9e6;hpb=73d72624b097cb6c2f8481e75e99ed28ccbe907c diff --git a/drivers/filesystems/fastfat/fcb.c b/drivers/filesystems/fastfat/fcb.c index a4eef71a64a..df4dd54e083 100644 --- a/drivers/filesystems/fastfat/fcb.c +++ b/drivers/filesystems/fastfat/fcb.c @@ -1,11 +1,12 @@ /* -* FILE: drivers/fs/vfat/fcb.c +* FILE: drivers/filesystems/fastfat/fcb.c * PURPOSE: Routines to manipulate FCBs. * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) * Rex Jolliff (rex@lvcablemodem.com) * Herve Poussineau (reactos@poussine.freesurf.fr) +* Pierre Schweitzer (pierre@reactos.org) */ /* ------------------------------------------------------- INCLUDES */ @@ -156,6 +157,100 @@ vfatNewFCB( return rcFCB; } +static +VOID +vfatDelFCBFromTable( + PDEVICE_EXTENSION pVCB, + PVFATFCB pFCB) +{ + ULONG Index; + ULONG ShortIndex; + HASHENTRY* entry; + + Index = pFCB->Hash.Hash % pVCB->HashTableSize; + ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize; + + if (pFCB->Hash.Hash != pFCB->ShortHash.Hash) + { + entry = pVCB->FcbHashTable[ShortIndex]; + if (entry->self == pFCB) + { + pVCB->FcbHashTable[ShortIndex] = entry->next; + } + else + { + while (entry->next->self != pFCB) + { + entry = entry->next; + } + entry->next = pFCB->ShortHash.next; + } + } + entry = pVCB->FcbHashTable[Index]; + if (entry->self == pFCB) + { + pVCB->FcbHashTable[Index] = entry->next; + } + else + { + while (entry->next->self != pFCB) + { + entry = entry->next; + } + entry->next = pFCB->Hash.next; + } + + RemoveEntryList(&pFCB->FcbListEntry); +} + +static +NTSTATUS +vfatMakeFullName( + PVFATFCB directoryFCB, + PUNICODE_STRING LongNameU, + PUNICODE_STRING ShortNameU, + PUNICODE_STRING NameU) +{ + PWCHAR PathNameBuffer; + USHORT PathNameLength; + + PathNameLength = directoryFCB->PathNameU.Length + max(LongNameU->Length, ShortNameU->Length); + if (!vfatFCBIsRoot(directoryFCB)) + { + PathNameLength += sizeof(WCHAR); + } + + if (PathNameLength > LONGNAME_MAX_LENGTH * sizeof(WCHAR)) + { + return STATUS_OBJECT_NAME_INVALID; + } + PathNameBuffer = ExAllocatePoolWithTag(NonPagedPool, PathNameLength + sizeof(WCHAR), TAG_FCB); + if (!PathNameBuffer) + { + return STATUS_INSUFFICIENT_RESOURCES; + } + NameU->Buffer = PathNameBuffer; + NameU->Length = 0; + NameU->MaximumLength = PathNameLength; + + RtlCopyUnicodeString(NameU, &directoryFCB->PathNameU); + if (!vfatFCBIsRoot(directoryFCB)) + { + RtlAppendUnicodeToString(NameU, L"\\"); + } + if (LongNameU->Length > 0) + { + RtlAppendUnicodeStringToString(NameU, LongNameU); + } + else + { + RtlAppendUnicodeStringToString(NameU, ShortNameU); + } + NameU->Buffer[NameU->Length / sizeof(WCHAR)] = 0; + + return STATUS_SUCCESS; +} + VOID vfatDestroyCCB( PVFATCCB pCcb) @@ -182,7 +277,7 @@ BOOLEAN vfatFCBIsDirectory( PVFATFCB FCB) { - return *FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY; + return ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY); } BOOLEAN @@ -192,57 +287,40 @@ vfatFCBIsRoot( return FCB->PathNameU.Length == sizeof(WCHAR) && FCB->PathNameU.Buffer[0] == L'\\' ? TRUE : FALSE; } +VOID +vfatGrabFCB( + PDEVICE_EXTENSION pVCB, + PVFATFCB pFCB) +{ + ASSERT(ExIsResourceAcquiredExclusive(&pVCB->DirResource)); + + ASSERT(pFCB != pVCB->VolumeFcb); + ASSERT(pFCB->RefCount > 0); + ++pFCB->RefCount; +} + VOID vfatReleaseFCB( PDEVICE_EXTENSION pVCB, PVFATFCB pFCB) { - HASHENTRY* entry; - ULONG Index; - ULONG ShortIndex; PVFATFCB tmpFcb; DPRINT("releasing FCB at %p: %wZ, refCount:%d\n", pFCB, &pFCB->PathNameU, pFCB->RefCount); + ASSERT(ExIsResourceAcquiredExclusive(&pVCB->DirResource)); + while (pFCB) { - Index = pFCB->Hash.Hash % pVCB->HashTableSize; - ShortIndex = pFCB->ShortHash.Hash % pVCB->HashTableSize; + ASSERT(pFCB != pVCB->VolumeFcb); + ASSERT(pFCB->RefCount > 0); pFCB->RefCount--; if (pFCB->RefCount == 0) { + ASSERT(pFCB->OpenHandleCount == 0); tmpFcb = pFCB->parentFcb; - RemoveEntryList (&pFCB->FcbListEntry); - 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; - } + vfatDelFCBFromTable(pVCB, pFCB); vfatDestroyFCB(pFCB); } else @@ -253,6 +331,7 @@ vfatReleaseFCB( } } +static VOID vfatAddFCBToTable( PDEVICE_EXTENSION pVCB, @@ -275,8 +354,72 @@ vfatAddFCBToTable( } if (pFCB->parentFcb) { - pFCB->parentFcb->RefCount++; + vfatGrabFCB(pVCB, pFCB->parentFcb); + } +} + +NTSTATUS +vfatUpdateFCB( + PDEVICE_EXTENSION pVCB, + PVFATFCB Fcb, + PUNICODE_STRING LongName, + PUNICODE_STRING ShortName, + PVFATFCB ParentFcb) +{ + NTSTATUS Status; + PVFATFCB OldParent; + + DPRINT("vfatUpdateFCB(%p, %p, %wZ, %wZ, %p)\n", pVCB, Fcb, LongName, ShortName, ParentFcb); + + /* Get full path name */ + Status = vfatMakeFullName(ParentFcb, LongName, ShortName, &Fcb->PathNameU); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + /* 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); + + /* Copy short name */ + RtlCopyUnicodeString(&Fcb->ShortNameU, ShortName); + + /* Recompute hashes */ + Fcb->Hash.Hash = vfatNameHash(0, &Fcb->PathNameU); + 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); + } + + /* Set parent */ + OldParent = Fcb->parentFcb; + Fcb->parentFcb = ParentFcb; + + /* Add to the table */ + vfatAddFCBToTable(pVCB, Fcb); + + /* If we moved across directories, dereference our old parent + * We also dereference in case we're just renaming since AddFCBToTable references it + */ + vfatReleaseFCB(pVCB, OldParent); + + return STATUS_SUCCESS; } PVFATFCB @@ -322,7 +465,7 @@ vfatGrabFCBFromTable( DPRINT("'%wZ' '%wZ'\n", &FileNameU, FcbNameU); if (RtlEqualUnicodeString(&FileNameU, FcbNameU, TRUE)) { - rcFCB->RefCount++; + vfatGrabFCB(pVCB, rcFCB); return rcFCB; } } @@ -340,12 +483,14 @@ vfatFCBInitializeCacheFromVolume( { PFILE_OBJECT fileObject; PVFATCCB newCCB; + NTSTATUS status; fileObject = IoCreateStreamFileObject (NULL, vcb->StorageDevice); newCCB = ExAllocateFromNPagedLookasideList(&VfatGlobalData->CcbLookasideList); if (newCCB == NULL) { + ObDereferenceObject(fileObject); return STATUS_INSUFFICIENT_RESOURCES; } RtlZeroMemory(newCCB, sizeof (VFATCCB)); @@ -354,14 +499,26 @@ vfatFCBInitializeCacheFromVolume( fileObject->FsContext = fcb; fileObject->FsContext2 = newCCB; fcb->FileObject = fileObject; - fcb->RefCount++; - CcInitializeCacheMap(fileObject, - (PCC_FILE_SIZES)(&fcb->RFCB.AllocationSize), - TRUE, - &VfatGlobalData->CacheMgrCallbacks, - fcb); + _SEH2_TRY + { + CcInitializeCacheMap(fileObject, + (PCC_FILE_SIZES)(&fcb->RFCB.AllocationSize), + TRUE, + &VfatGlobalData->CacheMgrCallbacks, + fcb); + } + _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) + { + status = _SEH2_GetExceptionCode(); + fcb->FileObject = NULL; + ExFreeToNPagedLookasideList(&VfatGlobalData->CcbLookasideList, newCCB); + ObDereferenceObject(fileObject); + return status; + } + _SEH2_END; + vfatGrabFCB(vcb, fcb); fcb->Flags |= FCB_CACHE_INITIALIZED; return STATUS_SUCCESS; } @@ -445,47 +602,15 @@ vfatMakeFCBFromDirEntry( PVFATFCB *fileFCB) { PVFATFCB rcFCB; - PWCHAR PathNameBuffer; - USHORT PathNameLength; ULONG Size; - ULONG hash; - UNICODE_STRING NameU; + NTSTATUS Status; - PathNameLength = directoryFCB->PathNameU.Length + max(DirContext->LongNameU.Length, DirContext->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) + Status = vfatMakeFullName(directoryFCB, &DirContext->LongNameU, &DirContext->ShortNameU, &NameU); + if (!NT_SUCCESS(Status)) { - return STATUS_INSUFFICIENT_RESOURCES; + return Status; } - NameU.Buffer = PathNameBuffer; - NameU.Length = 0; - NameU.MaximumLength = PathNameLength; - - RtlCopyUnicodeString(&NameU, &directoryFCB->PathNameU); - if (!vfatFCBIsRoot(directoryFCB)) - { - RtlAppendUnicodeToString(&NameU, L"\\"); - } - hash = vfatNameHash(0, &NameU); - if (DirContext->LongNameU.Length > 0) - { - RtlAppendUnicodeStringToString(&NameU, &DirContext->LongNameU); - } - else - { - RtlAppendUnicodeStringToString(&NameU, &DirContext->ShortNameU); - } - NameU.Buffer[NameU.Length / sizeof(WCHAR)] = 0; rcFCB = vfatNewFCB(vcb, &NameU); RtlCopyMemory(&rcFCB->entry, &DirContext->DirEntry, sizeof (DIR_ENTRY)); @@ -496,7 +621,8 @@ vfatMakeFCBFromDirEntry( } else { - rcFCB->ShortHash.Hash = vfatNameHash(hash, &rcFCB->ShortNameU); + rcFCB->ShortHash.Hash = vfatNameHash(0, &rcFCB->DirNameU); + rcFCB->ShortHash.Hash = vfatNameHash(rcFCB->ShortHash.Hash, &rcFCB->ShortNameU); } if (vfatFCBIsDirectory(rcFCB)) @@ -538,7 +664,7 @@ vfatMakeFCBFromDirEntry( rcFCB->RFCB.FileSize.QuadPart = Size; rcFCB->RFCB.ValidDataLength.QuadPart = Size; rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, vcb->FatInfo.BytesPerCluster); - rcFCB->RefCount++; + rcFCB->RefCount = 1; if (vfatFCBIsDirectory(rcFCB)) { vfatFCBInitializeCacheFromVolume(vcb, rcFCB); @@ -547,7 +673,7 @@ vfatMakeFCBFromDirEntry( vfatAddFCBToTable(vcb, rcFCB); *fileFCB = rcFCB; - ExFreePool(PathNameBuffer); + ExFreePool(NameU.Buffer); return STATUS_SUCCESS; } @@ -700,7 +826,7 @@ vfatGetFCBForFile( { *pFCB = FCB; *pParentFCB = FCB->parentFcb; - (*pParentFCB)->RefCount++; + vfatGrabFCB(pVCB, *pParentFCB); return STATUS_SUCCESS; } @@ -761,7 +887,7 @@ vfatGetFCBForFile( if (parentFCB) { vfatReleaseFCB(pVCB, parentFCB); - parentFCB = 0; + parentFCB = NULL; } // fail if element in FCB is not a directory if (!vfatFCBIsDirectory(FCB)) @@ -784,6 +910,8 @@ vfatGetFCBForFile( if (FileNameU.Length + parentFCB->LongNameU.Length - Length > FileNameU.MaximumLength) { vfatReleaseFCB(pVCB, parentFCB); + *pParentFCB = NULL; + *pFCB = NULL; return STATUS_OBJECT_NAME_INVALID; } RtlMoveMemory(prev + parentFCB->LongNameU.Length / sizeof(WCHAR), curr,