/*
-* 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 */
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)
vfatFCBIsDirectory(
PVFATFCB FCB)
{
- return *FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY;
+ return ((*FCB->Attributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY);
}
BOOLEAN
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
}
}
+static
VOID
vfatAddFCBToTable(
PDEVICE_EXTENSION pVCB,
}
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
DPRINT("'%wZ' '%wZ'\n", &FileNameU, FcbNameU);
if (RtlEqualUnicodeString(&FileNameU, FcbNameU, TRUE))
{
- rcFCB->RefCount++;
+ vfatGrabFCB(pVCB, rcFCB);
return rcFCB;
}
}
{
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));
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;
}
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));
}
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))
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);
vfatAddFCBToTable(vcb, rcFCB);
*fileFCB = rcFCB;
- ExFreePool(PathNameBuffer);
+ ExFreePool(NameU.Buffer);
return STATUS_SUCCESS;
}
{
*pFCB = FCB;
*pParentFCB = FCB->parentFcb;
- (*pParentFCB)->RefCount++;
+ vfatGrabFCB(pVCB, *pParentFCB);
return STATUS_SUCCESS;
}
if (parentFCB)
{
vfatReleaseFCB(pVCB, parentFCB);
- parentFCB = 0;
+ parentFCB = NULL;
}
// fail if element in FCB is not a directory
if (!vfatFCBIsDirectory(FCB))
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,