mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
722 lines
19 KiB
C
722 lines
19 KiB
C
/*
|
|
* ReactOS kernel
|
|
* Copyright (C) 2002, 2004 ReactOS Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*/
|
|
/*
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: drivers/filesystems/cdfs/fcb.c
|
|
* PURPOSE: CDROM (ISO 9660) filesystem driver
|
|
* PROGRAMMER: Art Yerkes
|
|
* UPDATE HISTORY:
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "cdfs.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
#define ROUND_UP(N, S) ((((N) + (S) - 1) / (S)) * (S))
|
|
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
static BOOLEAN
|
|
CdfsGetNextPathElement(PCUNICODE_STRING CurrentElement, PUNICODE_STRING NextElement)
|
|
{
|
|
*NextElement = *CurrentElement;
|
|
|
|
if (NextElement->Length == 0)
|
|
return FALSE;
|
|
|
|
while ((NextElement->Length) && (NextElement->Buffer[0] != L'\\'))
|
|
{
|
|
NextElement->Buffer++;
|
|
NextElement->Length -= sizeof(WCHAR);
|
|
NextElement->MaximumLength -= sizeof(WCHAR);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
PFCB
|
|
CdfsCreateFCB(PCWSTR FileName)
|
|
{
|
|
PFCB Fcb;
|
|
|
|
Fcb = ExAllocatePoolWithTag(NonPagedPool,
|
|
sizeof(FCB),
|
|
CDFS_NONPAGED_FCB_TAG);
|
|
if(!Fcb) return NULL;
|
|
|
|
RtlZeroMemory(Fcb, sizeof(FCB));
|
|
RtlInitEmptyUnicodeString(&Fcb->PathName, Fcb->PathNameBuffer, sizeof(Fcb->PathNameBuffer));
|
|
|
|
if (FileName)
|
|
{
|
|
RtlAppendUnicodeToString(&Fcb->PathName, FileName);
|
|
if (wcsrchr(Fcb->PathName.Buffer, '\\') != 0)
|
|
{
|
|
Fcb->ObjectName = wcsrchr(Fcb->PathName.Buffer, '\\');
|
|
}
|
|
else
|
|
{
|
|
Fcb->ObjectName = Fcb->PathName.Buffer;
|
|
}
|
|
}
|
|
|
|
ExInitializeResourceLite(&Fcb->PagingIoResource);
|
|
ExInitializeResourceLite(&Fcb->MainResource);
|
|
ExInitializeResourceLite(&Fcb->NameListResource);
|
|
Fcb->RFCB.PagingIoResource = &Fcb->PagingIoResource;
|
|
Fcb->RFCB.Resource = &Fcb->MainResource;
|
|
Fcb->RFCB.IsFastIoPossible = FastIoIsNotPossible;
|
|
InitializeListHead(&Fcb->ShortNameList);
|
|
FsRtlInitializeFileLock(&Fcb->FileLock, NULL, NULL);
|
|
|
|
return(Fcb);
|
|
}
|
|
|
|
|
|
VOID
|
|
CdfsDestroyFCB(PFCB Fcb)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
|
|
FsRtlUninitializeFileLock(&Fcb->FileLock);
|
|
ExDeleteResourceLite(&Fcb->PagingIoResource);
|
|
ExDeleteResourceLite(&Fcb->MainResource);
|
|
|
|
while (!IsListEmpty(&Fcb->ShortNameList))
|
|
{
|
|
Entry = Fcb->ShortNameList.Flink;
|
|
RemoveEntryList(Entry);
|
|
ExFreePoolWithTag(Entry, CDFS_SHORT_NAME_TAG);
|
|
}
|
|
|
|
ExDeleteResourceLite(&Fcb->NameListResource);
|
|
ExFreePoolWithTag(Fcb, CDFS_NONPAGED_FCB_TAG);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CdfsFCBIsDirectory(PFCB Fcb)
|
|
{
|
|
return(Fcb->Entry.FileFlags & FILE_FLAG_DIRECTORY);
|
|
}
|
|
|
|
|
|
BOOLEAN
|
|
CdfsFCBIsRoot(PFCB Fcb)
|
|
{
|
|
return (Fcb->PathName.Length == sizeof(WCHAR) && Fcb->PathName.Buffer[0] == L'\\');
|
|
}
|
|
|
|
|
|
VOID
|
|
CdfsGrabFCB(PDEVICE_EXTENSION Vcb,
|
|
PFCB Fcb)
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
DPRINT("grabbing FCB at %p: %wZ, refCount:%d\n",
|
|
Fcb,
|
|
&Fcb->PathName,
|
|
Fcb->RefCount);
|
|
|
|
KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
|
|
Fcb->RefCount++;
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
|
}
|
|
|
|
|
|
VOID
|
|
CdfsReleaseFCB(PDEVICE_EXTENSION Vcb,
|
|
PFCB Fcb)
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
DPRINT("releasing FCB at %p: %wZ, refCount:%d\n",
|
|
Fcb,
|
|
&Fcb->PathName,
|
|
Fcb->RefCount);
|
|
|
|
KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
|
|
Fcb->RefCount--;
|
|
if (Fcb->RefCount <= 0 && !CdfsFCBIsDirectory(Fcb))
|
|
{
|
|
RemoveEntryList(&Fcb->FcbListEntry);
|
|
CdfsDestroyFCB(Fcb);
|
|
}
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
|
}
|
|
|
|
|
|
VOID
|
|
CdfsAddFCBToTable(PDEVICE_EXTENSION Vcb,
|
|
PFCB Fcb)
|
|
{
|
|
KIRQL oldIrql;
|
|
|
|
KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
|
|
Fcb->DevExt = Vcb;
|
|
InsertTailList(&Vcb->FcbListHead, &Fcb->FcbListEntry);
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
|
}
|
|
|
|
|
|
PFCB
|
|
CdfsGrabFCBFromTable(PDEVICE_EXTENSION Vcb,
|
|
PUNICODE_STRING FileName)
|
|
{
|
|
KIRQL oldIrql;
|
|
PFCB Fcb;
|
|
PLIST_ENTRY current_entry;
|
|
|
|
KeAcquireSpinLock(&Vcb->FcbListLock, &oldIrql);
|
|
|
|
if (FileName == NULL || FileName->Length == 0 || FileName->Buffer[0] == 0)
|
|
{
|
|
DPRINT("Return FCB for stream file object\n");
|
|
Fcb = Vcb->StreamFileObject->FsContext;
|
|
Fcb->RefCount++;
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
|
return(Fcb);
|
|
}
|
|
|
|
current_entry = Vcb->FcbListHead.Flink;
|
|
while (current_entry != &Vcb->FcbListHead)
|
|
{
|
|
Fcb = CONTAINING_RECORD(current_entry, FCB, FcbListEntry);
|
|
|
|
// Disabled the DPRINT! Can't be called at DISPATCH_LEVEL!
|
|
//DPRINT("Comparing '%wZ' and '%wZ'\n", FileName, &Fcb->PathName);
|
|
if (RtlCompareUnicodeString(FileName, &Fcb->PathName, TRUE) == 0)
|
|
{
|
|
Fcb->RefCount++;
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
|
return(Fcb);
|
|
}
|
|
|
|
//FIXME: need to compare against short name in FCB here
|
|
|
|
current_entry = current_entry->Flink;
|
|
}
|
|
KeReleaseSpinLock(&Vcb->FcbListLock, oldIrql);
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CdfsFCBInitializeCache(PVCB Vcb,
|
|
PFCB Fcb)
|
|
{
|
|
PFILE_OBJECT FileObject;
|
|
PCCB newCCB;
|
|
|
|
FileObject = IoCreateStreamFileObject(NULL, Vcb->StorageDevice);
|
|
|
|
newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), CDFS_CCB_TAG);
|
|
if (newCCB == NULL)
|
|
{
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlZeroMemory(newCCB,
|
|
sizeof(CCB));
|
|
|
|
FileObject->ReadAccess = TRUE;
|
|
FileObject->WriteAccess = FALSE;
|
|
FileObject->DeleteAccess = FALSE;
|
|
FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
|
|
FileObject->FsContext = Fcb;
|
|
FileObject->FsContext2 = newCCB;
|
|
newCCB->PtrFileObject = FileObject;
|
|
Fcb->FileObject = FileObject;
|
|
Fcb->DevExt = Vcb;
|
|
|
|
_SEH2_TRY
|
|
{
|
|
CcInitializeCacheMap(FileObject,
|
|
(PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
|
|
FALSE,
|
|
&(CdfsGlobalData->CacheMgrCallbacks),
|
|
Fcb);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
FileObject->FsContext2 = NULL;
|
|
ExFreePoolWithTag(newCCB, CDFS_CCB_TAG);
|
|
ObDereferenceObject(FileObject);
|
|
Fcb->FileObject = NULL;
|
|
return _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
|
|
ObDereferenceObject(FileObject);
|
|
Fcb->Flags |= FCB_CACHE_INITIALIZED;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
PFCB
|
|
CdfsMakeRootFCB(PDEVICE_EXTENSION Vcb)
|
|
{
|
|
PFCB Fcb;
|
|
|
|
Fcb = CdfsCreateFCB(L"\\");
|
|
|
|
Fcb->Entry.DataLengthL = Vcb->CdInfo.RootSize;
|
|
Fcb->Entry.ExtentLocationL = Vcb->CdInfo.RootStart;
|
|
Fcb->Entry.FileFlags = FILE_FLAG_DIRECTORY;
|
|
Fcb->IndexNumber.QuadPart = 0LL;
|
|
Fcb->RefCount = 1;
|
|
Fcb->DirIndex = 0;
|
|
Fcb->RFCB.FileSize.QuadPart = Vcb->CdInfo.RootSize;
|
|
Fcb->RFCB.ValidDataLength.QuadPart = Vcb->CdInfo.RootSize;
|
|
Fcb->RFCB.AllocationSize.QuadPart = Vcb->CdInfo.RootSize;
|
|
|
|
CdfsFCBInitializeCache(Vcb, Fcb);
|
|
CdfsAddFCBToTable(Vcb, Fcb);
|
|
CdfsGrabFCB(Vcb, Fcb);
|
|
|
|
return(Fcb);
|
|
}
|
|
|
|
|
|
PFCB
|
|
CdfsOpenRootFCB(PDEVICE_EXTENSION Vcb)
|
|
{
|
|
UNICODE_STRING FileName;
|
|
PFCB Fcb;
|
|
|
|
RtlInitUnicodeString(&FileName, L"\\");
|
|
|
|
Fcb = CdfsGrabFCBFromTable(Vcb,
|
|
&FileName);
|
|
if (Fcb == NULL)
|
|
{
|
|
Fcb = CdfsMakeRootFCB(Vcb);
|
|
}
|
|
|
|
return(Fcb);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CdfsMakeFCBFromDirEntry(PVCB Vcb,
|
|
PFCB DirectoryFCB,
|
|
PWSTR LongName,
|
|
PWSTR ShortName,
|
|
PDIR_RECORD Record,
|
|
ULONG DirectorySector,
|
|
ULONG DirectoryOffset,
|
|
PFCB * fileFCB)
|
|
{
|
|
WCHAR pathName[MAX_PATH];
|
|
PFCB rcFCB;
|
|
ULONG Size;
|
|
|
|
/* Check if the full string would overflow the pathName buffer (the additional characters are for '\\' and '\0') */
|
|
if ((LongName[0] != 0) &&
|
|
((DirectoryFCB->PathName.Length / sizeof(WCHAR)) + 1 + wcslen(LongName) + 1 > MAX_PATH))
|
|
{
|
|
return(STATUS_OBJECT_NAME_INVALID);
|
|
}
|
|
|
|
wcscpy(pathName, DirectoryFCB->PathName.Buffer);
|
|
if (!CdfsFCBIsRoot(DirectoryFCB))
|
|
{
|
|
wcscat(pathName, L"\\");
|
|
}
|
|
|
|
if (LongName[0] != 0)
|
|
{
|
|
wcscat(pathName, LongName);
|
|
}
|
|
else
|
|
{
|
|
WCHAR entryName[MAX_PATH];
|
|
|
|
CdfsGetDirEntryName(Vcb, Record, entryName);
|
|
wcscat(pathName, entryName);
|
|
}
|
|
|
|
rcFCB = CdfsCreateFCB(pathName);
|
|
memcpy(&rcFCB->Entry, Record, sizeof(DIR_RECORD));
|
|
|
|
/* Copy short name into FCB */
|
|
rcFCB->ShortNameU.Length = wcslen(ShortName) * sizeof(WCHAR);
|
|
rcFCB->ShortNameU.MaximumLength = rcFCB->ShortNameU.Length;
|
|
rcFCB->ShortNameU.Buffer = rcFCB->ShortNameBuffer;
|
|
wcscpy(rcFCB->ShortNameBuffer, ShortName);
|
|
|
|
Size = rcFCB->Entry.DataLengthL;
|
|
|
|
rcFCB->RFCB.FileSize.QuadPart = Size;
|
|
rcFCB->RFCB.ValidDataLength.QuadPart = Size;
|
|
rcFCB->RFCB.AllocationSize.QuadPart = ROUND_UP(Size, BLOCKSIZE);
|
|
if (CdfsFCBIsDirectory(rcFCB))
|
|
{
|
|
CdfsFCBInitializeCache(Vcb, rcFCB);
|
|
}
|
|
rcFCB->IndexNumber.u.HighPart = DirectorySector;
|
|
rcFCB->IndexNumber.u.LowPart = DirectoryOffset;
|
|
rcFCB->RefCount++;
|
|
CdfsAddFCBToTable(Vcb, rcFCB);
|
|
*fileFCB = rcFCB;
|
|
|
|
DPRINT("%S %u %I64d\n", LongName, Size, rcFCB->RFCB.AllocationSize.QuadPart);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CdfsAttachFCBToFileObject(PDEVICE_EXTENSION Vcb,
|
|
PFCB Fcb,
|
|
PFILE_OBJECT FileObject)
|
|
{
|
|
PCCB newCCB;
|
|
|
|
newCCB = ExAllocatePoolWithTag(NonPagedPool, sizeof(CCB), CDFS_CCB_TAG);
|
|
if (newCCB == NULL)
|
|
{
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
memset(newCCB, 0, sizeof(CCB));
|
|
|
|
FileObject->ReadAccess = TRUE;
|
|
FileObject->WriteAccess = FALSE;
|
|
FileObject->DeleteAccess = FALSE;
|
|
FileObject->SectionObjectPointer = &Fcb->SectionObjectPointers;
|
|
FileObject->FsContext = Fcb;
|
|
FileObject->FsContext2 = newCCB;
|
|
newCCB->PtrFileObject = FileObject;
|
|
Fcb->DevExt = Vcb;
|
|
|
|
if (CdfsFCBIsDirectory(Fcb))
|
|
{
|
|
_SEH2_TRY
|
|
{
|
|
CcInitializeCacheMap(FileObject,
|
|
(PCC_FILE_SIZES)(&Fcb->RFCB.AllocationSize),
|
|
FALSE,
|
|
&(CdfsGlobalData->CacheMgrCallbacks),
|
|
Fcb);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
FileObject->FsContext2 = NULL;
|
|
ExFreePoolWithTag(newCCB, CDFS_CCB_TAG);
|
|
return _SEH2_GetExceptionCode();
|
|
}
|
|
_SEH2_END;
|
|
Fcb->Flags |= FCB_CACHE_INITIALIZED;
|
|
}
|
|
|
|
DPRINT("file open: fcb:%p file size: %u\n", Fcb, Fcb->Entry.DataLengthL);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CdfsDirFindFile(PDEVICE_EXTENSION DeviceExt,
|
|
PFCB DirectoryFcb,
|
|
PUNICODE_STRING FileToFind,
|
|
PFCB *FoundFCB)
|
|
{
|
|
UNICODE_STRING TempName;
|
|
WCHAR Name[256];
|
|
PVOID Block;
|
|
ULONG DirSize;
|
|
PDIR_RECORD Record;
|
|
ULONG Offset;
|
|
ULONG BlockOffset;
|
|
NTSTATUS Status;
|
|
|
|
LARGE_INTEGER StreamOffset, OffsetOfEntry;
|
|
PVOID Context;
|
|
|
|
WCHAR ShortNameBuffer[13];
|
|
UNICODE_STRING ShortName;
|
|
UNICODE_STRING LongName;
|
|
UNICODE_STRING FileToFindUpcase;
|
|
|
|
ASSERT(DeviceExt);
|
|
ASSERT(DirectoryFcb);
|
|
ASSERT(FileToFind);
|
|
|
|
DPRINT("CdfsDirFindFile(VCB:%p, dirFCB:%p, File:%wZ)\n",
|
|
DeviceExt,
|
|
DirectoryFcb,
|
|
FileToFind);
|
|
DPRINT("Dir Path:%wZ\n", &DirectoryFcb->PathName);
|
|
|
|
/* default to '.' if no filename specified */
|
|
if (FileToFind->Length == 0)
|
|
{
|
|
RtlInitUnicodeString(&TempName, L".");
|
|
FileToFind = &TempName;
|
|
}
|
|
|
|
DirSize = DirectoryFcb->Entry.DataLengthL;
|
|
StreamOffset.QuadPart = (LONGLONG)DirectoryFcb->Entry.ExtentLocationL * (LONGLONG)BLOCKSIZE;
|
|
|
|
_SEH2_TRY
|
|
{
|
|
CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, MAP_WAIT, &Context, &Block);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPRINT("CcMapData() failed\n");
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
|
|
Offset = 0;
|
|
BlockOffset = 0;
|
|
Record = (PDIR_RECORD)Block;
|
|
|
|
/* Upper case the expression for FsRtlIsNameInExpression */
|
|
Status = RtlUpcaseUnicodeString(&FileToFindUpcase, FileToFind, TRUE);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return Status;
|
|
}
|
|
|
|
while(TRUE)
|
|
{
|
|
if (Record->RecordLength == 0)
|
|
{
|
|
DPRINT("RecordLength == 0 Stopped!\n");
|
|
break;
|
|
}
|
|
|
|
DPRINT("RecordLength %u ExtAttrRecordLength %u NameLength %u\n",
|
|
Record->RecordLength, Record->ExtAttrRecordLength, Record->FileIdLength);
|
|
|
|
if (!CdfsIsRecordValid(DeviceExt, Record))
|
|
{
|
|
RtlFreeUnicodeString(&FileToFindUpcase);
|
|
CcUnpinData(Context);
|
|
return STATUS_DISK_CORRUPT_ERROR;
|
|
}
|
|
|
|
CdfsGetDirEntryName(DeviceExt, Record, Name);
|
|
DPRINT ("Name '%S'\n", Name);
|
|
DPRINT ("Sector %lu\n", DirectoryFcb->Entry.ExtentLocationL);
|
|
DPRINT ("Offset %lu\n", Offset);
|
|
|
|
RtlInitUnicodeString(&LongName, Name);
|
|
RtlInitEmptyUnicodeString(&ShortName, ShortNameBuffer, sizeof(ShortNameBuffer));
|
|
RtlZeroMemory(ShortNameBuffer, sizeof(ShortNameBuffer));
|
|
|
|
OffsetOfEntry.QuadPart = StreamOffset.QuadPart + Offset;
|
|
CdfsShortNameCacheGet(DirectoryFcb, &OffsetOfEntry, &LongName, &ShortName);
|
|
|
|
DPRINT("ShortName '%wZ'\n", &ShortName);
|
|
|
|
ASSERT(LongName.Length >= sizeof(WCHAR));
|
|
ASSERT(ShortName.Length >= sizeof(WCHAR));
|
|
if (FsRtlIsNameInExpression(&FileToFindUpcase, &LongName, TRUE, NULL) ||
|
|
FsRtlIsNameInExpression(&FileToFindUpcase, &ShortName, TRUE, NULL))
|
|
{
|
|
DPRINT("Match found, %S\n", Name);
|
|
Status = CdfsMakeFCBFromDirEntry(DeviceExt,
|
|
DirectoryFcb,
|
|
Name,
|
|
ShortNameBuffer,
|
|
Record,
|
|
DirectoryFcb->Entry.ExtentLocationL,
|
|
Offset,
|
|
FoundFCB);
|
|
|
|
RtlFreeUnicodeString(&FileToFindUpcase);
|
|
CcUnpinData(Context);
|
|
|
|
return(Status);
|
|
}
|
|
|
|
Offset += Record->RecordLength;
|
|
BlockOffset += Record->RecordLength;
|
|
Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset);
|
|
if (BlockOffset >= BLOCKSIZE || Record->RecordLength == 0)
|
|
{
|
|
DPRINT("Map next sector\n");
|
|
CcUnpinData(Context);
|
|
StreamOffset.QuadPart += BLOCKSIZE;
|
|
Offset = ROUND_UP(Offset, BLOCKSIZE);
|
|
BlockOffset = 0;
|
|
|
|
_SEH2_TRY
|
|
{
|
|
CcMapData(DeviceExt->StreamFileObject, &StreamOffset, BLOCKSIZE, MAP_WAIT, &Context, &Block);
|
|
}
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
DPRINT("CcMapData() failed\n");
|
|
RtlFreeUnicodeString(&FileToFindUpcase);
|
|
_SEH2_YIELD(return _SEH2_GetExceptionCode());
|
|
}
|
|
_SEH2_END;
|
|
Record = (PDIR_RECORD)((ULONG_PTR)Block + BlockOffset);
|
|
}
|
|
|
|
if (Offset >= DirSize)
|
|
break;
|
|
}
|
|
|
|
RtlFreeUnicodeString(&FileToFindUpcase);
|
|
CcUnpinData(Context);
|
|
|
|
return(STATUS_OBJECT_NAME_NOT_FOUND);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
CdfsGetFCBForFile(PDEVICE_EXTENSION Vcb,
|
|
PFCB *pParentFCB,
|
|
PFCB *pFCB,
|
|
PUNICODE_STRING FileName)
|
|
{
|
|
UNICODE_STRING PathName;
|
|
UNICODE_STRING NextElement;
|
|
UNICODE_STRING CurrentElement;
|
|
NTSTATUS Status;
|
|
PFCB FCB;
|
|
PFCB parentFCB;
|
|
|
|
DPRINT("CdfsGetFCBForFile(%p, %p, %p, '%wZ')\n",
|
|
Vcb,
|
|
pParentFCB,
|
|
pFCB,
|
|
FileName);
|
|
|
|
/* Trivial case, open of the root directory on volume */
|
|
if (FileName->Length == 0 ||
|
|
((FileName->Buffer[0] == '\\') && (FileName->Length == sizeof(WCHAR))))
|
|
{
|
|
DPRINT("returning root FCB\n");
|
|
|
|
FCB = CdfsOpenRootFCB(Vcb);
|
|
*pFCB = FCB;
|
|
*pParentFCB = NULL;
|
|
|
|
return((FCB != NULL) ? STATUS_SUCCESS : STATUS_OBJECT_PATH_NOT_FOUND);
|
|
}
|
|
else
|
|
{
|
|
/* Start with empty path */
|
|
PathName = *FileName;
|
|
PathName.Length = 0;
|
|
CurrentElement = *FileName;
|
|
|
|
FCB = CdfsOpenRootFCB (Vcb);
|
|
}
|
|
parentFCB = NULL;
|
|
|
|
/* Parse filename and check each path element for existence and access */
|
|
while (CdfsGetNextPathElement(&CurrentElement, &NextElement))
|
|
{
|
|
/* Skip blank directory levels */
|
|
if (CurrentElement.Buffer[0] == L'\\')
|
|
{
|
|
CurrentElement.Buffer++;
|
|
CurrentElement.Length -= sizeof(WCHAR);
|
|
CurrentElement.MaximumLength -= sizeof(WCHAR);
|
|
continue;
|
|
}
|
|
|
|
DPRINT("Parsing, currentElement:%wZ\n", &CurrentElement);
|
|
DPRINT(" parentFCB:%p FCB:%p\n", parentFCB, FCB);
|
|
|
|
/* Descend to next directory level */
|
|
if (parentFCB)
|
|
{
|
|
CdfsReleaseFCB(Vcb, parentFCB);
|
|
parentFCB = NULL;
|
|
}
|
|
|
|
/* fail if element in FCB is not a directory */
|
|
if (!CdfsFCBIsDirectory(FCB))
|
|
{
|
|
DPRINT("Element in requested path is not a directory\n");
|
|
|
|
CdfsReleaseFCB(Vcb, FCB);
|
|
FCB = 0;
|
|
*pParentFCB = NULL;
|
|
*pFCB = NULL;
|
|
|
|
return(STATUS_OBJECT_PATH_NOT_FOUND);
|
|
}
|
|
parentFCB = FCB;
|
|
|
|
/* Extract next directory level */
|
|
PathName.Length = (NextElement.Buffer - FileName->Buffer) * sizeof(WCHAR);
|
|
DPRINT(" PathName:%wZ\n", &PathName);
|
|
|
|
FCB = CdfsGrabFCBFromTable(Vcb, &PathName);
|
|
if (FCB == NULL)
|
|
{
|
|
UNICODE_STRING ChildElement = CurrentElement;
|
|
ChildElement.Length = (NextElement.Buffer - CurrentElement.Buffer) * sizeof(WCHAR);
|
|
|
|
Status = CdfsDirFindFile(Vcb,
|
|
parentFCB,
|
|
&ChildElement,
|
|
&FCB);
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
|
{
|
|
*pParentFCB = parentFCB;
|
|
*pFCB = NULL;
|
|
|
|
if (NextElement.Length == 0)
|
|
{
|
|
return(STATUS_OBJECT_NAME_NOT_FOUND);
|
|
}
|
|
else
|
|
{
|
|
return(STATUS_OBJECT_PATH_NOT_FOUND);
|
|
}
|
|
}
|
|
else if (!NT_SUCCESS(Status))
|
|
{
|
|
CdfsReleaseFCB(Vcb, parentFCB);
|
|
*pParentFCB = NULL;
|
|
*pFCB = NULL;
|
|
|
|
return(Status);
|
|
}
|
|
}
|
|
CurrentElement = NextElement;
|
|
}
|
|
|
|
*pParentFCB = parentFCB;
|
|
*pFCB = FCB;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* EOF */
|