-/* $Id: fcb.c,v 1.3 2001/05/10 06:30:23 rex Exp $
+/* $Id: fcb.c,v 1.8 2001/07/28 07:05:56 hbirr Exp $
*
*
* FILE: fcb.c
/* -------------------------------------------------------- PUBLICS */
-PVFATFCB vfatNewFCB (PWCHAR pFileName)
+PVFATFCB
+vfatNewFCB(PWCHAR pFileName)
{
PVFATFCB rcFCB;
return rcFCB;
}
-void vfatDestroyFCB (PVFATFCB pFCB)
+VOID
+vfatDestroyFCB(PVFATFCB pFCB)
{
ExFreePool (pFCB);
}
-void vfatGrabFCB (PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
+BOOL
+vfatFCBIsDirectory(PDEVICE_EXTENSION pVCB, PVFATFCB FCB)
+{
+ return FCB->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY;
+}
+
+BOOL
+vfatFCBIsRoot(PVFATFCB FCB)
+{
+ return wcscmp (FCB->PathName, L"\\") == 0;
+}
+
+VOID
+vfatGrabFCB(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
{
KIRQL oldIrql;
+ DPRINT ("grabbing FCB at %x: %S, refCount:%d\n",
+ pFCB,
+ pFCB->PathName,
+ pFCB->RefCount);
+
KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
pFCB->RefCount++;
KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
}
-void vfatReleaseFCB (PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
+VOID
+vfatReleaseFCB(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
{
KIRQL oldIrql;
+ DPRINT ("releasing FCB at %x: %S, refCount:%d\n",
+ pFCB,
+ pFCB->PathName,
+ pFCB->RefCount);
+
KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
pFCB->RefCount--;
if (pFCB->RefCount <= 0 && !vfatFCBIsDirectory (pVCB, pFCB))
KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
}
-void vfatAddFCBToTable (PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
+VOID
+vfatAddFCBToTable(PDEVICE_EXTENSION pVCB, PVFATFCB pFCB)
{
KIRQL oldIrql;
KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
}
-PVFATFCB
-vfatGrabFCBFromTable (PDEVICE_EXTENSION pVCB, PWSTR pFileName)
+PVFATFCB
+vfatGrabFCBFromTable(PDEVICE_EXTENSION pVCB, PWSTR pFileName)
{
KIRQL oldIrql;
PVFATFCB rcFCB;
PLIST_ENTRY current_entry;
- CHECKPOINT;
KeAcquireSpinLock (&pVCB->FcbListLock, &oldIrql);
- CHECKPOINT;
current_entry = pVCB->FcbListHead.Flink;
while (current_entry != &pVCB->FcbListHead)
{
rcFCB = CONTAINING_RECORD (current_entry, VFATFCB, FcbListEntry);
- DPRINT ("Next FCB in list at %x\n", rcFCB);
- DPRINT (" PathName:%S\n", rcFCB->PathName);
-
if (wstrcmpi (pFileName, rcFCB->PathName))
{
rcFCB->RefCount++;
KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
return rcFCB;
}
+
+ //FIXME: need to compare against short name in FCB here
+
current_entry = current_entry->Flink;
}
- CHECKPOINT;
KeReleaseSpinLock (&pVCB->FcbListLock, oldIrql);
return NULL;
}
-PVFATFCB
-vfatMakeRootFCB (PDEVICE_EXTENSION pVCB)
+NTSTATUS
+vfatFCBInitializeCache (PVCB vcb, PVFATFCB fcb)
{
NTSTATUS status;
- PVFATFCB FCB;
PFILE_OBJECT fileObject;
ULONG bytesPerCluster;
ULONG fileCacheQuantum;
+ PVFATCCB newCCB;
- FCB = vfatNewFCB (L"\\");
- memset (FCB->entry.Filename, ' ', 11);
- FCB->entry.FileSize = pVCB->rootDirectorySectors * BLOCKSIZE;
- FCB->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
- if (pVCB->FatType == FAT32)
- {
- FCB->entry.FirstCluster = 2;
- }
- else
+ fileObject = IoCreateStreamFileObject (NULL, vcb->StorageDevice);
+
+ newCCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
+ if (newCCB == NULL)
{
- FCB->entry.FirstCluster = 1;
+ return STATUS_INSUFFICIENT_RESOURCES;
}
- FCB->RefCount = 1;
- fileObject = IoCreateStreamFileObject (NULL, pVCB->StorageDevice);
-
- bytesPerCluster = pVCB->Boot->SectorsPerCluster * BLOCKSIZE;
+ memset (newCCB, 0, sizeof (VFATCCB));
+
+ fileObject->Flags = fileObject->Flags | FO_FCB_IS_VALID |
+ FO_DIRECT_CACHE_PAGING_READ;
+ fileObject->SectionObjectPointers = &fcb->SectionObjectPointers;
+ fileObject->FsContext = (PVOID) &fcb->RFCB;
+ fileObject->FsContext2 = newCCB;
+ newCCB->pFcb = fcb;
+ newCCB->PtrFileObject = fileObject;
+ fcb->pDevExt = vcb;
+
+ bytesPerCluster = vcb->Boot->SectorsPerCluster * BLOCKSIZE;
fileCacheQuantum = (bytesPerCluster >= PAGESIZE) ?
bytesPerCluster : PAGESIZE;
status = CcRosInitializeFileCache (fileObject,
- &FCB->RFCB.Bcb,
+ &fcb->RFCB.Bcb,
fileCacheQuantum);
if (!NT_SUCCESS (status))
{
KeBugCheck (0);
}
ObDereferenceObject (fileObject);
- vfatAddFCBToTable (pVCB, FCB);
+ fcb->isCacheInitialized = TRUE;
- return FCB;
+ return status;
+}
+
+NTSTATUS
+vfatRequestAndValidateRegion(PDEVICE_EXTENSION pDeviceExt,
+ PVFATFCB pFCB,
+ ULONG pOffset,
+ PVOID * pBuffer,
+ PCACHE_SEGMENT * pCacheSegment,
+ BOOL pExtend)
+{
+ NTSTATUS status;
+ BOOLEAN valid;
+ BOOLEAN isRoot;
+ ULONG currentCluster;
+ ULONG i;
+
+ status = CcRosRequestCacheSegment(pFCB->RFCB.Bcb,
+ pOffset,
+ pBuffer,
+ &valid,
+ pCacheSegment);
+ if (!NT_SUCCESS (status))
+ {
+ return status;
+ }
+
+ isRoot = vfatFCBIsRoot (pFCB);
+ if (!valid)
+ {
+ currentCluster = vfatDirEntryGetFirstCluster (pDeviceExt, &pFCB->entry);
+ status = OffsetToCluster (pDeviceExt,
+ vfatDirEntryGetFirstCluster (pDeviceExt, &pFCB->entry),
+ pOffset,
+ ¤tCluster,
+ pExtend);
+ if (!NT_SUCCESS (status))
+ {
+ return status;
+ }
+
+ if (PAGESIZE > pDeviceExt->BytesPerCluster)
+ {
+ for (i = 0; i < (PAGESIZE / pDeviceExt->BytesPerCluster); i++)
+ {
+ status = VfatRawReadCluster (pDeviceExt,
+ vfatDirEntryGetFirstCluster (pDeviceExt, &pFCB->entry),
+ ((PCHAR)*pBuffer) +
+ (i * pDeviceExt->BytesPerCluster),
+ currentCluster);
+ if (!NT_SUCCESS (status))
+ {
+ CcRosReleaseCacheSegment(pFCB->RFCB.Bcb, *pCacheSegment, FALSE);
+ return status;
+ }
+ status = NextCluster (pDeviceExt,
+ vfatDirEntryGetFirstCluster (pDeviceExt, &pFCB->entry),
+ ¤tCluster,
+ pExtend);
+ if (!NT_SUCCESS (status))
+ {
+ CcRosReleaseCacheSegment(pFCB->RFCB.Bcb, *pCacheSegment, FALSE);
+ return status;
+ }
+ if ((currentCluster) == 0xFFFFFFFF)
+ {
+ break;
+ }
+ }
+ }
+ else
+ {
+ status = VfatRawReadCluster (pDeviceExt,
+ vfatDirEntryGetFirstCluster (pDeviceExt, &pFCB->entry),
+ *pBuffer,
+ currentCluster);
+ if (!NT_SUCCESS (status))
+ {
+ CcRosReleaseCacheSegment(pFCB->RFCB.Bcb, *pCacheSegment, FALSE);
+ return status;
+ }
+ }
+ }
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+vfatReleaseRegion (PDEVICE_EXTENSION pDeviceExt,
+ PVFATFCB pFCB,
+ PCACHE_SEGMENT pCacheSegment)
+{
+ return CcRosReleaseCacheSegment (pFCB->RFCB.Bcb, pCacheSegment, TRUE);
+}
+
+PVFATFCB
+vfatMakeRootFCB(PDEVICE_EXTENSION pVCB)
+{
+ PVFATFCB FCB;
+
+ FCB = vfatNewFCB(L"\\");
+ memset(FCB->entry.Filename, ' ', 11);
+ FCB->entry.FileSize = pVCB->rootDirectorySectors * BLOCKSIZE;
+ FCB->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+ if (pVCB->FatType == FAT32)
+ {
+ FCB->entry.FirstCluster = ((struct _BootSector32*)(pVCB->Boot))->RootCluster & 0xffff;
+ FCB->entry.FirstClusterHigh = ((struct _BootSector32*)(pVCB->Boot))->RootCluster >> 16;
+ }
+ else
+ {
+ FCB->entry.FirstCluster = 1;
+ }
+ FCB->RefCount = 1;
+
+ vfatFCBInitializeCache(pVCB, FCB);
+ vfatAddFCBToTable(pVCB, FCB);
+ vfatGrabFCB(pVCB, FCB);
+
+ return(FCB);
}
-PVFATFCB
-vfatOpenRootFCB (PDEVICE_EXTENSION pVCB)
+PVFATFCB
+vfatOpenRootFCB(PDEVICE_EXTENSION pVCB)
{
PVFATFCB FCB;
FCB = vfatGrabFCBFromTable (pVCB, L"\\");
- if (FCB != NULL)
+ if (FCB == NULL)
{
- return FCB;
+ FCB = vfatMakeRootFCB (pVCB);
}
- FCB = vfatMakeRootFCB (pVCB);
return FCB;
}
-BOOL
-vfatFCBIsDirectory (PDEVICE_EXTENSION pVCB, PVFATFCB FCB)
+NTSTATUS
+vfatMakeFCBFromDirEntry(PVCB vcb,
+ PVFATFCB directoryFCB,
+ PWSTR longName,
+ PFAT_DIR_ENTRY dirEntry,
+ PVFATFCB * fileFCB)
{
- return FCB->entry.Attrib & FILE_ATTRIBUTE_DIRECTORY;
+ PVFATFCB rcFCB;
+ WCHAR pathName [MAX_PATH];
+
+ if (longName [0] != 0 && wcslen (directoryFCB->PathName) +
+ sizeof(WCHAR) + wcslen (longName) > MAX_PATH)
+ {
+ return STATUS_OBJECT_NAME_INVALID;
+ }
+ wcscpy (pathName, directoryFCB->PathName);
+ if (!vfatFCBIsRoot (directoryFCB))
+ {
+ wcscat (pathName, L"\\");
+ }
+ if (longName [0] != 0)
+ {
+ wcscat (pathName, longName);
+ }
+ else
+ {
+ WCHAR entryName [MAX_PATH];
+
+ vfatGetDirEntryName (dirEntry, entryName);
+ wcscat (pathName, entryName);
+ }
+ rcFCB = vfatNewFCB (pathName);
+ memcpy (&rcFCB->entry, dirEntry, sizeof (FAT_DIR_ENTRY));
+
+ vfatFCBInitializeCache (vcb, rcFCB);
+ vfatAddFCBToTable (vcb, rcFCB);
+ vfatGrabFCB (vcb, rcFCB);
+ *fileFCB = rcFCB;
+
+ return STATUS_SUCCESS;
}
-PVFATFCB
-vfatDirFindFile (PDEVICE_EXTENSION pVCB,
- PVFATFCB parentFCB,
- const PWSTR elementName)
+NTSTATUS
+vfatAttachFCBToFileObject (PDEVICE_EXTENSION vcb,
+ PVFATFCB fcb,
+ PFILE_OBJECT fileObject)
{
- UNIMPLEMENTED;
+ NTSTATUS status;
+ PVFATCCB newCCB;
+
+ newCCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB);
+ if (newCCB == NULL)
+ {
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
+ memset (newCCB, 0, sizeof (VFATCCB));
+
+ fileObject->Flags = fileObject->Flags | FO_FCB_IS_VALID |
+ FO_DIRECT_CACHE_PAGING_READ;
+ fileObject->SectionObjectPointers = &fcb->SectionObjectPointers;
+ fileObject->FsContext = (PVOID) &fcb->RFCB;
+ fileObject->FsContext2 = newCCB;
+ newCCB->pFcb = fcb;
+ newCCB->PtrFileObject = fileObject;
+ fcb->pDevExt = vcb;
+
+ if (!fcb->isCacheInitialized)
+ {
+ ULONG bytesPerCluster;
+ ULONG fileCacheQuantum;
+
+ bytesPerCluster = vcb->Boot->SectorsPerCluster * BLOCKSIZE;
+ fileCacheQuantum = (bytesPerCluster >= PAGESIZE) ? bytesPerCluster :
+ PAGESIZE;
+ status = CcRosInitializeFileCache (fileObject,
+ &fcb->RFCB.Bcb,
+ fileCacheQuantum);
+ if (!NT_SUCCESS (status))
+ {
+ DbgPrint ("CcRosInitializeFileCache failed\n");
+ KeBugCheck (0);
+ }
+ fcb->isCacheInitialized = TRUE;
+ }
+
+ DPRINT ("file open: fcb:%x file size: %d\n", fcb, fcb->entry.FileSize);
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+vfatDirFindFile (PDEVICE_EXTENSION pDeviceExt,
+ PVFATFCB pDirectoryFCB,
+ PWSTR pFileToFind,
+ PVFATFCB * pFoundFCB)
+{
+ BOOL finishedScanningDirectory;
+ ULONG directoryIndex;
+ NTSTATUS status;
+ WCHAR defaultFileName [2];
+ WCHAR currentLongName [256];
+ FAT_DIR_ENTRY currentDirEntry;
+ WCHAR currentEntryName [256];
+
+ assert (pDeviceExt);
+ assert (pDirectoryFCB);
+ assert (pFileToFind);
+
+ DPRINT ("vfatDirFindFile(VCB:%08x, dirFCB:%08x, File:%S)\n",
+ pDeviceExt,
+ pDirectoryFCB,
+ pFileToFind);
+ DPRINT ("Dir Path:%S\n", pDirectoryFCB->PathName);
+
+ // default to '.' if no filename specified
+ if (wcslen (pFileToFind) == 0)
+ {
+ defaultFileName [0] = L'.';
+ defaultFileName [1] = 0;
+ pFileToFind = defaultFileName;
+ }
+
+ directoryIndex = 0;
+ finishedScanningDirectory = FALSE;
+ while (!finishedScanningDirectory)
+ {
+ status = vfatGetNextDirEntry (pDeviceExt,
+ pDirectoryFCB,
+ &directoryIndex,
+ currentLongName,
+ ¤tDirEntry);
+ if (status == STATUS_NO_MORE_ENTRIES)
+ {
+ finishedScanningDirectory = TRUE;
+ continue;
+ }
+ else if (!NT_SUCCESS(status))
+ {
+ return status;
+ }
+
+ DPRINT (" Index:%d longName:%S\n",
+ directoryIndex,
+ currentLongName);
+
+ if (!vfatIsDirEntryDeleted (¤tDirEntry)
+ && !vfatIsDirEntryVolume(¤tDirEntry))
+ {
+ if (currentLongName [0] != L'\0' && wstrcmpjoki (currentLongName, pFileToFind))
+ {
+ DPRINT ("Match found, %S\n", currentLongName);
+ status = vfatMakeFCBFromDirEntry (pDeviceExt,
+ pDirectoryFCB,
+ currentLongName,
+ ¤tDirEntry,
+ pFoundFCB);
+ return status;
+ }
+ else
+ {
+ vfatGetDirEntryName (¤tDirEntry, currentEntryName);
+ DPRINT (" entryName:%S\n", currentEntryName);
+
+ if (wstrcmpjoki (currentEntryName, pFileToFind))
+ {
+ DPRINT ("Match found, %S\n", currentEntryName);
+ status = vfatMakeFCBFromDirEntry (pDeviceExt,
+ pDirectoryFCB,
+ currentLongName,
+ ¤tDirEntry,
+ pFoundFCB);
+ return status;
+ }
+ }
+ }
+ }
+
+ return STATUS_OBJECT_NAME_NOT_FOUND;
}
NTSTATUS
PVFATFCB *pFCB,
const PWSTR pFileName)
{
+ NTSTATUS status;
WCHAR pathName [MAX_PATH];
WCHAR elementName [MAX_PATH];
PWCHAR currentElement;
PVFATFCB FCB;
PVFATFCB parentFCB;
+ DPRINT ("vfatGetFCBForFile (%x,%x,%x,%S)\n",
+ pVCB,
+ pParentFCB,
+ pFCB,
+ pFileName);
+
// Trivial case, open of the root directory on volume
if (pFileName [0] == L'\0' || wcscmp (pFileName, L"\\") == 0)
{
- currentElement = pFileName;
- //FIXME: grab/create root RCB and return it
- FCB = vfatGrabFCBFromTable (pVCB, L"\\");
- if (FCB == NULL)
- {
- FCB = vfatMakeRootFCB (pVCB);
- *pFCB = FCB;
- *pParentFCB = NULL;
+ DPRINT ("returning root FCB\n");
- return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
- }
+ FCB = vfatOpenRootFCB (pVCB);
+ *pFCB = FCB;
+ *pParentFCB = NULL;
+
+ return (FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND;
}
else
{
continue;
}
- currentElement = vfatGetNextPathElement (currentElement);
+ DPRINT ("Parsing, currentElement:%S\n", currentElement);
+ DPRINT (" parentFCB:%x FCB:%x\n", parentFCB, FCB);
// descend to next directory level
if (parentFCB)
// fail if element in FCB is not a directory
if (!vfatFCBIsDirectory (pVCB, FCB))
{
+ DPRINT ("Element in requested path is not a directory\n");
+
vfatReleaseFCB (pVCB, FCB);
FCB = 0;
+ *pParentFCB = NULL;
+ *pFCB = NULL;
+
return STATUS_OBJECT_PATH_NOT_FOUND;
}
parentFCB = FCB;
vfatWSubString (pathName,
pFileName,
vfatGetNextPathElement (currentElement) - pFileName);
+ DPRINT (" pathName:%S\n", pathName);
FCB = vfatGrabFCBFromTable (pVCB, pathName);
if (FCB == NULL)
vfatWSubString (elementName,
currentElement,
vfatGetNextPathElement (currentElement) - currentElement);
- FCB = vfatDirFindFile (pVCB, parentFCB, elementName);
- if (FCB == NULL)
+ DPRINT (" elementName:%S\n", elementName);
+
+ status = vfatDirFindFile (pVCB, parentFCB, elementName, &FCB);
+ if (status == STATUS_OBJECT_NAME_NOT_FOUND)
{
*pParentFCB = parentFCB;
*pFCB = NULL;
- if (vfatGetNextPathElement (currentElement) == 0)
+ currentElement = vfatGetNextPathElement(currentElement);
+ if (*currentElement == L'\0' || vfatGetNextPathElement(currentElement + 1) == 0)
{
return STATUS_OBJECT_NAME_NOT_FOUND;
}
return STATUS_OBJECT_PATH_NOT_FOUND;
}
}
+ else if (!NT_SUCCESS (status))
+ {
+ vfatReleaseFCB (pVCB, parentFCB);
+ *pParentFCB = NULL;
+ *pFCB = NULL;
- // FIXME: check security on directory element and fail if access denied
+ return status;
+ }
}
+ currentElement = vfatGetNextPathElement (currentElement);
}
*pParentFCB = parentFCB;