From 208eecc0f40885f48f3bdba7941f32225090437e Mon Sep 17 00:00:00 2001 From: Rex Jolliff Date: Thu, 5 Jul 2001 01:51:53 +0000 Subject: [PATCH] Partial directory caching (create calls cached, but dir info calls still use non cached routines). svn path=/trunk/; revision=2038 --- reactos/drivers/fs/vfat/create.c | 197 ++------------ reactos/drivers/fs/vfat/dir.c | 2 + reactos/drivers/fs/vfat/direntry.c | 227 ++++++++++++++++ reactos/drivers/fs/vfat/fcb.c | 421 +++++++++++++++++++++++++---- reactos/drivers/fs/vfat/iface.c | 3 +- reactos/drivers/fs/vfat/makefile | 7 +- reactos/drivers/fs/vfat/string.c | 4 +- reactos/drivers/fs/vfat/vfat.h | 54 +++- 8 files changed, 681 insertions(+), 234 deletions(-) create mode 100644 reactos/drivers/fs/vfat/direntry.c diff --git a/reactos/drivers/fs/vfat/create.c b/reactos/drivers/fs/vfat/create.c index 268bbef4c64..722364a235d 100644 --- a/reactos/drivers/fs/vfat/create.c +++ b/reactos/drivers/fs/vfat/create.c @@ -1,4 +1,4 @@ -/* $Id: create.c,v 1.26 2001/06/14 21:05:08 jfilby Exp $ +/* $Id: create.c,v 1.27 2001/07/05 01:51:52 rex Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -21,10 +21,6 @@ /* GLOBALS *******************************************************************/ -#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24)) - -#define TAG_CCB TAG('V', 'C', 'C', 'B') - /* FUNCTIONS *****************************************************************/ BOOLEAN @@ -60,7 +56,7 @@ IsDeletedEntry (PVOID Block, ULONG Offset) (((FATDirEntry *) Block)[Offset].Filename[0] == 0)); } -static void vfat8Dot3ToString (PCHAR pBasename, PCHAR pExtension, PWSTR pName) +void vfat8Dot3ToString (PCHAR pBasename, PCHAR pExtension, PWSTR pName) { int fromIndex, toIndex; @@ -475,196 +471,57 @@ VfatOpenFile (PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, * FUNCTION: Opens a file */ { - PWSTR current = NULL; - PWSTR next; - PWSTR string; -// PWSTR buffer; // used to store a pointer while checking MAX_PATH conformance PVFATFCB ParentFcb; PVFATFCB Fcb; - PVFATFCB Temp; - PVFATCCB newCCB; NTSTATUS Status; PWSTR AbsFileName = NULL; - ULONG BytesPerCluster, FileCacheQuantum; DPRINT ("VfatOpenFile(%08lx, %08lx, %S)\n", DeviceExt, FileObject, FileName); - /* FIXME : treat relative name */ if (FileObject->RelatedFileObject) { + DPRINT ("Converting relative filename to absolute filename\n"); Status = vfatMakeAbsoluteFilename (FileObject->RelatedFileObject, FileName, &AbsFileName); FileName = AbsFileName; } - /* - * try first to find an existing FCB in memory - */ - CHECKPOINT; + //FIXME: Get cannonical path name (remove .'s, ..'s and extra separators) + DPRINT ("PathName to open: %S\n", FileName); + + /* try first to find an existing FCB in memory */ + DPRINT ("Checking for existing FCB in memory\n"); Fcb = vfatGrabFCBFromTable (DeviceExt, FileName); - if (Fcb != NULL) + if (Fcb == NULL) { - FileObject->FsContext = (PVOID)&Fcb->RFCB; - newCCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB); - memset (newCCB, 0, sizeof (VFATCCB)); - FileObject->Flags = FileObject->Flags | - FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ; - FileObject->SectionObjectPointers = &Fcb->SectionObjectPointers; - FileObject->FsContext2 = newCCB; - newCCB->pFcb = Fcb; - newCCB->PtrFileObject = FileObject; - if (AbsFileName) - ExFreePool (AbsFileName); - return STATUS_SUCCESS; + DPRINT ("No existing FCB found, making a new one if file exists.\n"); + Status = vfatGetFCBForFile (DeviceExt, &ParentFcb, &Fcb, FileName); + if (ParentFcb != NULL) + { + vfatReleaseFCB (DeviceExt, ParentFcb); + } + if (!NT_SUCCESS (Status)) + { + DPRINT ("Could not make a new FCB, status: %x\n", Status); + + if (AbsFileName) + ExFreePool (AbsFileName); + + return Status; + } } - DPRINT ("FileName %S\n", FileName); + DPRINT ("Attaching FCB to fileObject\n"); + Status = vfatAttachFCBToFileObject (DeviceExt, Fcb, FileObject); - string = FileName; - ParentFcb = NULL; - Fcb = vfatNewFCB (L"\\"); - next = &string[0]; - - CHECKPOINT; - if (*next == 0 || *(next+1) == 0) // root - { - memset (Fcb->entry.Filename, ' ', 11); - Fcb->entry.FileSize = DeviceExt->rootDirectorySectors * BLOCKSIZE; - Fcb->entry.Attrib = FILE_ATTRIBUTE_DIRECTORY; - if (DeviceExt->FatType == FAT32) - Fcb->entry.FirstCluster = 2; - else - Fcb->entry.FirstCluster = 1; - /* FIXME : is 1 the good value for mark root? */ - ParentFcb = Fcb; - DPRINT("%S filename, PathName: %S\n",FileName, ParentFcb->PathName); - Fcb = NULL; - } - else - { - while (TRUE) - { - CHECKPOINT; - *next = '\\'; - current = next + 1; - next = wcschr (next + 1, '\\'); - if (next != NULL) - { - *next = 0; - } - else - { - /* reached the last path component */ - DPRINT ("exiting: current '%S'\n", current); - break; - } - - DPRINT ("search for (%S) in (%S)\n", current, ParentFcb ? ParentFcb->PathName : L""); - Status = FindFile (DeviceExt, Fcb, ParentFcb, current, NULL, NULL); - if (Status != STATUS_SUCCESS) - { - CHECKPOINT; - if (Fcb != NULL) - ExFreePool (Fcb); - if (ParentFcb != NULL) - ExFreePool (ParentFcb); - if (AbsFileName) - ExFreePool (AbsFileName); - - DPRINT ("error STATUS_OBJECT_PATH_NOT_FOUND\n"); - return STATUS_OBJECT_PATH_NOT_FOUND; - } - Temp = Fcb; - CHECKPOINT; - if (ParentFcb == NULL) - { - CHECKPOINT; - Fcb = vfatNewFCB (L"\\"); - } - else - Fcb = ParentFcb; - - if (*(Temp->ObjectName)) - { - vfat_wcsncpy(Fcb->PathName+(Fcb->ObjectName-Fcb->PathName),Temp->PathName+(Fcb->ObjectName-Fcb->PathName), MAX_PATH); - - Fcb->ObjectName = &Fcb->PathName[wcslen(Fcb->PathName)]; - Fcb->ObjectName[0]='\\'; - Fcb->ObjectName=&Fcb->ObjectName[1]; - Fcb->ObjectName[0]=0; - } - CHECKPOINT; - ParentFcb = Temp; - } - - if( *current != L'\0' ){ //the file name is directory. there will be no last part. - /* searching for last path component */ - DPRINT ("search for (%S) in (%S)\n", current, Fcb ? Fcb->PathName : L""); - Status = FindFile (DeviceExt, Fcb, ParentFcb, current, NULL, NULL); - if (Status != STATUS_SUCCESS) - { - /* file does not exist */ - CHECKPOINT; - if (Fcb != NULL) - ExFreePool (Fcb); - if (ParentFcb != NULL) - ExFreePool (ParentFcb); - if (AbsFileName) - ExFreePool (AbsFileName); - - return STATUS_OBJECT_NAME_NOT_FOUND; - } - - Temp = Fcb; - - Fcb = ParentFcb; - ParentFcb = Temp; - ParentFcb->ObjectName = &(wcschr (ParentFcb->ObjectName, '\\'))[1]; - } - } - - FileObject->Flags = FileObject->Flags | - FO_FCB_IS_VALID | FO_DIRECT_CACHE_PAGING_READ; - FileObject->SectionObjectPointers = &ParentFcb->SectionObjectPointers; - memset(FileObject->SectionObjectPointers, 0, - sizeof(SECTION_OBJECT_POINTERS)); - FileObject->FsContext = (PVOID)&ParentFcb->RFCB; - newCCB = ExAllocatePoolWithTag (NonPagedPool, sizeof (VFATCCB), TAG_CCB); - memset (newCCB, 0, sizeof (VFATCCB)); - FileObject->FsContext2 = newCCB; - newCCB->pFcb = ParentFcb; - newCCB->PtrFileObject = FileObject; - ParentFcb->RefCount++; - ParentFcb->pDevExt = DeviceExt; - /* FIXME : initialize all fields in FCB and CCB */ - - BytesPerCluster = DeviceExt->Boot->SectorsPerCluster * BLOCKSIZE; - FileCacheQuantum = (BytesPerCluster >= PAGESIZE) ? BytesPerCluster : PAGESIZE; - Status = CcRosInitializeFileCache(FileObject, - &ParentFcb->RFCB.Bcb, - FileCacheQuantum); - if (!NT_SUCCESS(Status)) - { - DbgPrint("CcRosInitializeFileCache failed\n"); - KeBugCheck(0); - } - DPRINT ("file open, fcb=%x\n", ParentFcb); - DPRINT ("FileSize %d\n", ParentFcb->entry.FileSize); - - vfatAddFCBToTable (DeviceExt, ParentFcb); - - if (Fcb) - ExFreePool (Fcb); if (AbsFileName) ExFreePool (AbsFileName); - CHECKPOINT; - return (STATUS_SUCCESS); + return Status; } - NTSTATUS VfatCreateFile (PDEVICE_OBJECT DeviceObject, PIRP Irp) /* diff --git a/reactos/drivers/fs/vfat/dir.c b/reactos/drivers/fs/vfat/dir.c index 2e336c1a6cd..74edb30fe0c 100644 --- a/reactos/drivers/fs/vfat/dir.c +++ b/reactos/drivers/fs/vfat/dir.c @@ -375,3 +375,5 @@ VfatDirectoryControl (PDEVICE_OBJECT DeviceObject, PIRP Irp) IoCompleteRequest (Irp, IO_NO_INCREMENT); return RC; } + + diff --git a/reactos/drivers/fs/vfat/direntry.c b/reactos/drivers/fs/vfat/direntry.c new file mode 100644 index 00000000000..d676218301a --- /dev/null +++ b/reactos/drivers/fs/vfat/direntry.c @@ -0,0 +1,227 @@ +/* $Id: direntry.c,v 1.1 2001/07/05 01:51:52 rex Exp $ + * + * + * FILE: DirEntry.c + * PURPOSE: Routines to manipulate directory entries. + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * PROGRAMMER: Jason Filby (jasonfilby@yahoo.com) + * Rex Jolliff (rex@lvcablemodem.com) + */ + +/* ------------------------------------------------------- INCLUDES */ + +#include +#include +#include + +#define NDEBUG +#include + +#include "vfat.h" + +#define ENTRIES_PER_PAGE(pDeviceExt) (ENTRIES_PER_SECTOR * \ + (PAGESIZE / ((pDeviceExt)->BytesPerSector))) + +ULONG +vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION pDeviceExt, + PFAT_DIR_ENTRY pFatDirEntry) +{ + ULONG cluster; + + if (pDeviceExt->FatType == FAT32) + { + cluster = pFatDirEntry->FirstCluster + + pFatDirEntry->FirstClusterHigh * 65536; + } + else + { + cluster = pFatDirEntry->FirstCluster; + } + + return cluster; +} + +BOOL +vfatIsDirEntryDeleted (FATDirEntry * pFatDirEntry) +{ + return pFatDirEntry->Filename [0] == 0xe5; +} + +BOOL +vfatIsDirEntryEndMarker (FATDirEntry * pFatDirEntry) +{ + return pFatDirEntry->Filename [0] == 0; +} + +BOOL +vfatIsDirEntryLongName (FATDirEntry * pFatDirEntry) +{ + return pFatDirEntry->Attrib == 0x0f; +} + +void +vfatGetDirEntryName (PFAT_DIR_ENTRY dirEntry, PWSTR entryName) +{ + vfat8Dot3ToString (dirEntry->Filename, dirEntry->Ext, entryName); +} + +NTSTATUS +vfatGetNextDirEntry (PDEVICE_EXTENSION pDeviceExt, + PVFATFCB pDirectoryFCB, + ULONG * pDirectoryIndex, + PWSTR pLongFileName, + PFAT_DIR_ENTRY pDirEntry) +{ + NTSTATUS status; + ULONG indexInPage = *pDirectoryIndex % ENTRIES_PER_PAGE(pDeviceExt); + ULONG pageNumber = *pDirectoryIndex / ENTRIES_PER_PAGE(pDeviceExt); + PVOID currentPage = NULL; + PCACHE_SEGMENT cacheSegment = NULL; + FATDirEntry * fatDirEntry; + slot * longNameEntry; + ULONG cpos; + + DPRINT ("vfatGetNextDirEntry (%x,%x,%d,%x,%x)\n", + pDeviceExt, + pDirectoryFCB, + *pDirectoryIndex, + pLongFileName, + pDirEntry); + + *pLongFileName = 0; + + DPRINT ("Validating current directory page\n"); + status = vfatRequestAndValidateRegion (pDeviceExt, + pDirectoryFCB, + pageNumber * PAGESIZE, + (PVOID *) ¤tPage, + &cacheSegment, + FALSE); + if (!NT_SUCCESS (status)) + { + return status; + } + + while (TRUE) + { + fatDirEntry = (FATDirEntry *) currentPage; + + if (vfatIsDirEntryEndMarker (&fatDirEntry [indexInPage])) + { + DPRINT ("end of directory, returning no more entries\n"); + status = vfatReleaseRegion (pDeviceExt, + pDirectoryFCB, + cacheSegment); + return STATUS_NO_MORE_ENTRIES; + } + else if (vfatIsDirEntryLongName (&fatDirEntry [indexInPage])) + { + DPRINT (" long name entry found at %d\n", *pDirectoryIndex); + longNameEntry = (slot *) currentPage; + + DPRINT (" name chunk1:[%.*S] chunk2:[%.*S] chunk3:[%.*S]\n", + 5, longNameEntry [indexInPage].name0_4, + 6, longNameEntry [indexInPage].name5_10, + 2, longNameEntry [indexInPage].name11_12); + + vfat_initstr (pLongFileName, 256); + vfat_wcsncpy (pLongFileName, longNameEntry [indexInPage].name0_4, 5); + vfat_wcsncat (pLongFileName, longNameEntry [indexInPage].name5_10, 5, 6); + vfat_wcsncat (pLongFileName, longNameEntry [indexInPage].name11_12, 11, 2); + + DPRINT (" longName: [%S]\n", pLongFileName); + + cpos = 0; + while ((longNameEntry [indexInPage].id != 0x41) && + (longNameEntry [indexInPage].id != 0x01) && + (longNameEntry [indexInPage].attr > 0)) + { + (*pDirectoryIndex)++; + indexInPage++; + if (indexInPage == ENTRIES_PER_PAGE(pDeviceExt)) + { + indexInPage = 0; + pageNumber++; + + status = vfatReleaseRegion (pDeviceExt, + pDirectoryFCB, + cacheSegment); + if (!NT_SUCCESS (status)) + { + return status; + } + status = vfatRequestAndValidateRegion (pDeviceExt, + pDirectoryFCB, + pageNumber * PAGESIZE, + (PVOID *) ¤tPage, + &cacheSegment, + FALSE); + if (!NT_SUCCESS (status)) + { + return status; + } + longNameEntry = (slot *) currentPage; + } + DPRINT (" index %d\n", *pDirectoryIndex); + + DPRINT (" name chunk1:[%.*S] chunk2:[%.*S] chunk3:[%.*S]\n", + 5, longNameEntry [indexInPage].name0_4, + 6, longNameEntry [indexInPage].name5_10, + 2, longNameEntry [indexInPage].name11_12); + + cpos++; + vfat_movstr (pLongFileName, 13, 0, cpos * 13); + vfat_wcsncpy (pLongFileName, longNameEntry [indexInPage].name0_4, 5); + vfat_wcsncat (pLongFileName, longNameEntry [indexInPage].name5_10, 5, 6); + vfat_wcsncat (pLongFileName, longNameEntry [indexInPage].name11_12, 11, 2); + + DPRINT (" longName: [%S]\n", pLongFileName); + + } + (*pDirectoryIndex)++; + indexInPage++; + if (indexInPage == ENTRIES_PER_PAGE(pDeviceExt)) + { + indexInPage = 0; + pageNumber++; + + status = vfatReleaseRegion (pDeviceExt, + pDirectoryFCB, + cacheSegment); + if (!NT_SUCCESS (status)) + { + return status; + } + status = vfatRequestAndValidateRegion (pDeviceExt, + pDirectoryFCB, + pageNumber * PAGESIZE, + (PVOID *) ¤tPage, + &cacheSegment, + FALSE); + if (!NT_SUCCESS (status)) + { + return status; + } + } + } + else + { + memcpy (pDirEntry, &fatDirEntry [indexInPage], sizeof (FAT_DIR_ENTRY)); + (*pDirectoryIndex)++; + break; + } + } + + DPRINT ("Releasing current directory page\n"); + status = vfatReleaseRegion (pDeviceExt, + pDirectoryFCB, + cacheSegment); + + return status; +} + + + + + diff --git a/reactos/drivers/fs/vfat/fcb.c b/reactos/drivers/fs/vfat/fcb.c index 5ce8360165e..1a47eed93b3 100644 --- a/reactos/drivers/fs/vfat/fcb.c +++ b/reactos/drivers/fs/vfat/fcb.c @@ -1,4 +1,4 @@ -/* $Id: fcb.c,v 1.3 2001/05/10 06:30:23 rex Exp $ +/* $Id: fcb.c,v 1.4 2001/07/05 01:51:52 rex Exp $ * * * FILE: fcb.c @@ -54,10 +54,27 @@ void vfatDestroyFCB (PVFATFCB pFCB) ExFreePool (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); @@ -67,6 +84,11 @@ 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)) @@ -95,39 +117,168 @@ vfatGrabFCBFromTable (PDEVICE_EXTENSION pVCB, PWSTR pFileName) 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; + + fileObject = IoCreateStreamFileObject (NULL, vcb->StorageDevice); + + 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; + + 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); + } + ObDereferenceObject (fileObject); + fcb->isCacheInitialized = TRUE; + + 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); @@ -142,21 +293,10 @@ vfatMakeRootFCB (PDEVICE_EXTENSION pVCB) FCB->entry.FirstCluster = 1; } FCB->RefCount = 1; - fileObject = IoCreateStreamFileObject (NULL, pVCB->StorageDevice); - bytesPerCluster = pVCB->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); - } - ObDereferenceObject (fileObject); + vfatFCBInitializeCache (pVCB, FCB); vfatAddFCBToTable (pVCB, FCB); + vfatGrabFCB(pVCB, FCB); return FCB; } @@ -167,27 +307,191 @@ 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)) + { + 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 @@ -196,26 +500,29 @@ vfatGetFCBForFile (PDEVICE_EXTENSION pVCB, 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 { @@ -235,7 +542,8 @@ vfatGetFCBForFile (PDEVICE_EXTENSION pVCB, 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) @@ -246,8 +554,13 @@ vfatGetFCBForFile (PDEVICE_EXTENSION pVCB, // 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; @@ -256,6 +569,7 @@ vfatGetFCBForFile (PDEVICE_EXTENSION pVCB, vfatWSubString (pathName, pFileName, vfatGetNextPathElement (currentElement) - pFileName); + DPRINT (" pathName:%S\n", pathName); FCB = vfatGrabFCBFromTable (pVCB, pathName); if (FCB == NULL) @@ -263,12 +577,14 @@ vfatGetFCBForFile (PDEVICE_EXTENSION pVCB, 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) + if (vfatGetNextPathElement (vfatGetNextPathElement (currentElement) + 1) == 0) { return STATUS_OBJECT_NAME_NOT_FOUND; } @@ -277,9 +593,16 @@ vfatGetFCBForFile (PDEVICE_EXTENSION pVCB, 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; diff --git a/reactos/drivers/fs/vfat/iface.c b/reactos/drivers/fs/vfat/iface.c index 0be46bc5b03..fe282e324c0 100644 --- a/reactos/drivers/fs/vfat/iface.c +++ b/reactos/drivers/fs/vfat/iface.c @@ -1,4 +1,4 @@ -/* $Id: iface.c,v 1.53 2001/06/11 19:52:22 ekohl Exp $ +/* $Id: iface.c,v 1.54 2001/07/05 01:51:52 rex Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -103,6 +103,7 @@ VfatMountDevice (PDEVICE_EXTENSION DeviceExt, PDEVICE_OBJECT DeviceToMount) DeviceExt->Boot->FATCount * DeviceExt->Boot->FATSectors; DeviceExt->dataStart = DeviceExt->rootStart + DeviceExt->rootDirectorySectors; + DeviceExt->BytesPerSector = DeviceExt->Boot->BytesPerSector; DeviceExt->FATEntriesPerSector = DeviceExt->Boot->BytesPerSector / 32; DeviceExt->BytesPerCluster = DeviceExt->Boot->SectorsPerCluster * DeviceExt->Boot->BytesPerSector; diff --git a/reactos/drivers/fs/vfat/makefile b/reactos/drivers/fs/vfat/makefile index 062b0486629..870527378b7 100644 --- a/reactos/drivers/fs/vfat/makefile +++ b/reactos/drivers/fs/vfat/makefile @@ -1,12 +1,13 @@ -# $Id: makefile,v 1.31 2001/06/22 12:27:48 ekohl Exp $ +# $Id: makefile,v 1.32 2001/07/05 01:51:52 rex Exp $ # # PATH_TO_TOP = ../../.. TARGET=vfatfs -OBJECTS = blockdev.o close.o create.o dir.o dirwr.o iface.o string.o fat.o \ - rw.o finfo.o volume.o shutdown.o cleanup.o fcb.o $(TARGET).coff +OBJECTS = blockdev.o cleanup.o close.o create.o dir.o direntry.o dirwr.o \ + fat.o fcb.o finfo.o iface.o rw.o shutdown.o string.o volume.o \ + $(TARGET).coff LIBS = $(PATH_TO_TOP)/ntoskrnl/ntoskrnl.a diff --git a/reactos/drivers/fs/vfat/string.c b/reactos/drivers/fs/vfat/string.c index 89ee847ec06..b3a8c8a58e4 100644 --- a/reactos/drivers/fs/vfat/string.c +++ b/reactos/drivers/fs/vfat/string.c @@ -1,4 +1,4 @@ -/* $Id: string.c,v 1.7 2001/05/10 04:02:21 rex Exp $ +/* $Id: string.c,v 1.8 2001/07/05 01:51:53 rex Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel @@ -151,7 +151,7 @@ BOOLEAN wstrcmpjoki(PWSTR s1, PWSTR s2) PWCHAR vfatGetNextPathElement (PWCHAR pFileName) { - if (*pFileName != L'\0') + if (*pFileName == L'\0') { return 0; } diff --git a/reactos/drivers/fs/vfat/vfat.h b/reactos/drivers/fs/vfat/vfat.h index 2576b440d30..05f9b18ebfc 100644 --- a/reactos/drivers/fs/vfat/vfat.h +++ b/reactos/drivers/fs/vfat/vfat.h @@ -1,4 +1,4 @@ -/* $Id: vfat.h,v 1.31 2001/06/14 10:02:59 ekohl Exp $ */ +/* $Id: vfat.h,v 1.32 2001/07/05 01:51:53 rex Exp $ */ #include @@ -49,7 +49,7 @@ struct _FATDirEntry { unsigned long FileSize; } __attribute__((packed)); -typedef struct _FATDirEntry FATDirEntry; +typedef struct _FATDirEntry FATDirEntry, FAT_DIR_ENTRY, *PFAT_DIR_ENTRY; struct _slot { @@ -87,10 +87,11 @@ typedef struct PBCB Fat12StorageBcb; BootSector *Boot; int rootDirectorySectors, FATStart, rootStart, dataStart; + int BytesPerSector; int FATEntriesPerSector, FATUnit; ULONG BytesPerCluster; ULONG FatType; -} DEVICE_EXTENSION, *PDEVICE_EXTENSION; +} DEVICE_EXTENSION, *PDEVICE_EXTENSION, VCB, *PVCB; typedef struct _VFATFCB { @@ -105,6 +106,7 @@ typedef struct _VFATFCB PDEVICE_EXTENSION pDevExt; LIST_ENTRY FcbListEntry; struct _VFATFCB* parentFcb; + BOOL isCacheInitialized; } VFATFCB, *PVFATFCB; typedef struct _VFATCCB @@ -120,6 +122,9 @@ typedef struct _VFATCCB // PSTRING DirectorySearchPattern;// for DirectoryControl ? } VFATCCB, *PVFATCCB; +#define TAG(A, B, C, D) (ULONG)(((A)<<0) + ((B)<<8) + ((C)<<16) + ((D)<<24)) + +#define TAG_CCB TAG('V', 'C', 'C', 'B') #define ENTRIES_PER_SECTOR (BLOCKSIZE / sizeof(FATDirEntry)) @@ -249,6 +254,12 @@ BOOL vfatIsFileNameValid (PWCHAR pFileName); /* * functions from fat.c */ +NTSTATUS +OffsetToCluster(PDEVICE_EXTENSION DeviceExt, + ULONG FirstCluster, + ULONG FileOffset, + PULONG Cluster, + BOOLEAN Extend); ULONG ClusterToSector(PDEVICE_EXTENSION DeviceExt, ULONG Cluster); @@ -286,9 +297,9 @@ WriteCluster(PDEVICE_EXTENSION DeviceExt, ULONG ClusterToWrite, ULONG NewValue); -/* - * From create.c - */ +/* --------------------------------------------------------- create.c */ + +void vfat8Dot3ToString (PCHAR pBasename, PCHAR pExtension, PWSTR pName); NTSTATUS ReadVolumeLabel(PDEVICE_EXTENSION DeviceExt, PVPB Vpb); NTSTATUS @@ -296,6 +307,18 @@ VfatOpenFile(PDEVICE_EXTENSION DeviceExt, PFILE_OBJECT FileObject, PWSTR FileName); +/* ----------------------------------------------- DirEntry Functions */ + +ULONG vfatDirEntryGetFirstCluster (PDEVICE_EXTENSION pDeviceExt, + PFAT_DIR_ENTRY pDirEntry); +BOOL vfatIsDirEntryDeleted (FATDirEntry * pFatDirEntry); +void vfatGetDirEntryName (PFAT_DIR_ENTRY pDirEntry, PWSTR pEntryName); +NTSTATUS vfatGetNextDirEntry (PDEVICE_EXTENSION pDeviceExt, + PVFATFCB pDirectoryFCB, + ULONG * pDirectoryIndex, + PWSTR pLongFileName, + PFAT_DIR_ENTRY pDirEntry); + /* ----------------------------------------------------- FCB Functions */ PVFATFCB vfatNewFCB (PWCHAR pFileName); @@ -306,12 +329,25 @@ void vfatAddFCBToTable (PDEVICE_EXTENSION pVCB, PVFATFCB pFCB); PVFATFCB vfatGrabFCBFromTable (PDEVICE_EXTENSION pDeviceExt, PWSTR pFileName); +NTSTATUS vfatRequestAndValidateRegion (PDEVICE_EXTENSION pDeviceExt, + PVFATFCB pFCB, + ULONG pOffset, + PVOID * pBuffer, + PCACHE_SEGMENT * pCacheSegment, + BOOL pExtend); +NTSTATUS vfatReleaseRegion (PDEVICE_EXTENSION pDeviceExt, + PVFATFCB pFCB, + PCACHE_SEGMENT pCacheSegment); PVFATFCB vfatMakeRootFCB (PDEVICE_EXTENSION pVCB); PVFATFCB vfatOpenRootFCB (PDEVICE_EXTENSION pVCB); BOOL vfatFCBIsDirectory (PDEVICE_EXTENSION pVCB, PVFATFCB FCB); -PVFATFCB vfatDirFindFile (PDEVICE_EXTENSION pVCB, - PVFATFCB parentFCB, - const PWSTR elementName); +NTSTATUS vfatAttachFCBToFileObject (PDEVICE_EXTENSION vcb, + PVFATFCB fcb, + PFILE_OBJECT fileObject); +NTSTATUS vfatDirFindFile (PDEVICE_EXTENSION pVCB, + PVFATFCB parentFCB, + PWSTR elementName, + PVFATFCB * fileFCB); NTSTATUS vfatGetFCBForFile (PDEVICE_EXTENSION pVCB, PVFATFCB *pParentFCB, PVFATFCB *pFCB,