reactos/boot/environ/lib/io/etfs.c

995 lines
24 KiB
C

/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/io/etfs.c
* PURPOSE: Boot Library El Torito File System Management Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <bl.h>
#include <cdfs_new/cd.h>
typedef struct _RAW_ET_VD
{
UCHAR BootIndicator;
UCHAR StandardId[5];
UCHAR Version;
UCHAR SystemId[32];
UCHAR Reserved[32];
ULONG BootCatalogOffset;
UCHAR Padding[1973];
} RAW_ET_VD, *PRAW_ET_VD;
/* DATA VARIABLES ************************************************************/
typedef struct _BL_ETFS_DEVICE
{
ULONG RootDirOffset;
ULONG RootDirSize;
ULONG BlockSize;
ULONG VolumeSize;
BOOLEAN IsIso;
PUCHAR MemoryBlock;
ULONG Offset;
} BL_ETFS_DEVICE, *PBL_ETFS_DEVICE;
typedef struct _BL_ETFS_FILE
{
ULONG DiskOffset;
ULONG DirOffset;
ULONG DirEntOffset;
BL_FILE_INFORMATION;
ULONG DeviceId;
} BL_ETFS_FILE, *PBL_ETFS_FILE;
ULONG EtfsDeviceTableEntries;
PVOID* EtfsDeviceTable;
NTSTATUS
EtfsOpen (
_In_ PBL_FILE_ENTRY Directory,
_In_ PWCHAR FileName,
_In_ ULONG Flags,
_Out_ PBL_FILE_ENTRY *FileEntry
);
NTSTATUS
EtfsGetInformation (
_In_ PBL_FILE_ENTRY FileEntry,
_Out_ PBL_FILE_INFORMATION FileInfo
);
NTSTATUS
EtfsSetInformation (
_In_ PBL_FILE_ENTRY FileEntry,
_In_ PBL_FILE_INFORMATION FileInfo
);
NTSTATUS
EtfsRead (
_In_ PBL_FILE_ENTRY FileEntry,
_In_ PVOID Buffer,
_In_ ULONG Size,
_Out_opt_ PULONG BytesReturned
);
BL_FILE_CALLBACKS EtfsFunctionTable =
{
EtfsOpen,
NULL,
EtfsRead,
NULL,
NULL,
EtfsGetInformation,
EtfsSetInformation
};
/* FUNCTIONS *****************************************************************/
VOID
EtfspGetDirectoryInfo (
_In_ PBL_ETFS_DEVICE EtfsDevice,
_In_ PRAW_DIR_REC DirEntry,
_Out_ PULONG FileOffset,
_Out_ PULONG FileSize,
_Out_opt_ PBOOLEAN IsDirectory
)
{
ULONG SectorOffset;
BOOLEAN IsDir;
*FileOffset = *(PULONG)DirEntry->FileLoc * EtfsDevice->BlockSize;
*FileOffset += (DirEntry->XarLen * EtfsDevice->BlockSize);
SectorOffset = ALIGN_DOWN_BY(*FileOffset, CD_SECTOR_SIZE);
*FileSize = *(PULONG)DirEntry->DataLen;
IsDir = DE_FILE_FLAGS(EtfsDevice->IsIso, DirEntry) & ISO_ATTR_DIRECTORY;
if (IsDir)
{
*FileSize += ALIGN_UP_BY(SectorOffset, CD_SECTOR_SIZE) - SectorOffset;
}
if (IsDirectory)
{
*IsDirectory = IsDir;
}
}
USHORT
EtfspGetDirentNameLength (
_In_ PRAW_DIR_REC DirEntry
)
{
USHORT Length, RealLength;
PUCHAR Pos;
RealLength = Length = DirEntry->FileIdLen;
for (Pos = DirEntry->FileId + Length - 1; Length; --Pos)
{
--Length;
if (*Pos == ';')
{
RealLength = Length;
break;
}
}
Length = RealLength;
for (Pos = DirEntry->FileId + Length - 1; Length; --Pos)
{
--Length;
if (*Pos != '.')
{
break;
}
RealLength = Length;
}
return RealLength;
}
LONG
EtfspCompareNames (
__in PSTRING Name1,
__in PUNICODE_STRING Name2
)
{
ULONG i, l1, l2, l;
l1 = Name1->Length;
l2 = Name2->Length / sizeof(WCHAR);
l = min(l1, l2);
for (i = 0; i < l; i++)
{
if (toupper(Name1->Buffer[i]) != toupper(Name2->Buffer[i]))
{
return toupper(Name1->Buffer[i]) - toupper(Name2->Buffer[i]);
}
}
if (l2 <= l1)
{
return l2 < l1;
}
else
{
return -1;
}
}
BOOLEAN
EtfspFileMatch (
_In_ PRAW_DIR_REC DirEntry,
_In_ PUNICODE_STRING FileName
)
{
BOOLEAN Match;
USHORT Length;
ANSI_STRING DirName;
if ((DirEntry->FileIdLen != 1) ||
((DirEntry->FileId[0] != 0) && (DirEntry->FileId[0] != 1)))
{
Length = EtfspGetDirentNameLength(DirEntry);
DirName.Length = Length;
DirName.MaximumLength = Length;
DirName.Buffer = (PCHAR)DirEntry->FileId;
Match = EtfspCompareNames(&DirName, FileName);
}
else
{
Match = -1;
}
return Match;
}
NTSTATUS
EtfspGetDirent (
_In_ PBL_FILE_ENTRY DirectoryEntry,
_Out_ PRAW_DIR_REC *DirEntry,
_Inout_ PULONG DirentOffset
)
{
PBL_ETFS_FILE EtfsFile;
ULONG FileOffset, DirectoryOffset, AlignedOffset, RemainderOffset;
ULONG DeviceId, ReadSize, DirLen;
PBL_ETFS_DEVICE EtfsDevice;
BOOLEAN NeedRead, IsMulti;
NTSTATUS result;
PRAW_DIR_REC DirEnt;
PUCHAR MemoryBlock;
EtfsFile = DirectoryEntry->FsSpecificData;
DeviceId = EtfsFile->DeviceId;
FileOffset = EtfsFile->DiskOffset;
EtfsDevice = EtfsDeviceTable[DeviceId];
DirectoryOffset = *DirentOffset;
MemoryBlock = EtfsDevice->MemoryBlock;
IsMulti = 0;
AlignedOffset = (FileOffset + *DirentOffset) & ~CD_SECTOR_SIZE;
RemainderOffset = *DirentOffset + FileOffset - AlignedOffset;
ReadSize = 2048 - RemainderOffset;
NeedRead = AlignedOffset == EtfsDevice->Offset ? 0 : 1;
ReadAgain:
if (DirectoryOffset >= EtfsFile->Size)
{
return STATUS_NO_SUCH_FILE;
}
while (ReadSize < MIN_DIR_REC_SIZE)
{
DirectoryOffset += ReadSize;
AlignedOffset += 2048;
ReadSize = 2048;
RemainderOffset = 0;
NeedRead = 1;
if (DirectoryOffset >= EtfsFile->Size)
{
return STATUS_NO_SUCH_FILE;
}
}
if (NeedRead)
{
result = BlDeviceReadAtOffset(DirectoryEntry->DeviceId,
CD_SECTOR_SIZE,
AlignedOffset,
MemoryBlock,
NULL);
if (!NT_SUCCESS(result))
{
EfiPrintf(L"Device read failed %lx\r\n", result);
return result;
}
NeedRead = FALSE;
EtfsDevice->Offset = AlignedOffset;
}
if (!*(MemoryBlock + RemainderOffset))
{
AlignedOffset += 2048;
NeedRead = TRUE;
RemainderOffset = 0;
DirectoryOffset += ReadSize;
ReadSize = 2048;
goto ReadAgain;
}
DirEnt = (PRAW_DIR_REC)(MemoryBlock + RemainderOffset);
DirLen = DirEnt->DirLen;
if (DirLen > ReadSize)
{
EfiPrintf(L"Dir won't fit %lx %lx\r\n", DirLen, ReadSize);
return STATUS_NO_SUCH_FILE;
}
if (IsMulti)
{
if (!(DE_FILE_FLAGS(EtfsDevice->IsIso, DirEnt) & ISO_ATTR_MULTI))
{
IsMulti = TRUE;
}
}
else if (DE_FILE_FLAGS(EtfsDevice->IsIso, DirEnt) & ISO_ATTR_MULTI)
{
IsMulti = TRUE;
}
else
{
if ((DirEnt->FileIdLen != 1) ||
((DirEnt->FileId[0] != 0) && (DirEnt->FileId[0] != 1)))
{
goto Quickie;
}
}
RemainderOffset += DirLen;
DirectoryOffset += DirLen;
ReadSize -= DirLen;
goto ReadAgain;
Quickie:
*DirEntry = DirEnt;
*DirentOffset = DirectoryOffset;
return STATUS_SUCCESS;
}
NTSTATUS
EtfspSearchForDirent (
_In_ PBL_FILE_ENTRY DirectoryEntry,
_In_ PWCHAR FileName,
_Out_ PRAW_DIR_REC *DirEntry,
_Out_ PULONG DirentOffset
)
{
UNICODE_STRING Name;
ULONG NextOffset;
PRAW_DIR_REC DirEnt;
NTSTATUS Status;
RtlInitUnicodeString(&Name, FileName);
for (NextOffset = *DirentOffset;
;
NextOffset = NextOffset + DirEnt->DirLen)
{
Status = EtfspGetDirent(DirectoryEntry, &DirEnt, &NextOffset);
if (!NT_SUCCESS(Status))
{
return STATUS_NO_SUCH_FILE;
}
if (!EtfspFileMatch(DirEnt, &Name))
{
break;
}
}
*DirEntry = DirEnt;
*DirentOffset = NextOffset;
return 0;
}
NTSTATUS
EtfspCachedSearchForDirent (
_In_ PBL_FILE_ENTRY DirectoryEntry,
_In_ PWCHAR FileName,
_Out_ PRAW_DIR_REC *DirEntry,
_Out_ PULONG DirOffset,
_In_ BOOLEAN KeepOffset
)
{
PBL_ETFS_FILE EtfsFile;
PBL_ETFS_DEVICE EtfsDevice;
NTSTATUS Status;
ULONG DirentOffset;
PRAW_DIR_REC Dirent;
UNICODE_STRING Name;
EtfsFile = DirectoryEntry->FsSpecificData;
EtfsDevice = EtfsDeviceTable[EtfsFile->DeviceId];
RtlInitUnicodeString(&Name, FileName);
DirentOffset = EtfsFile->DirEntOffset;
if ((KeepOffset) ||
(ALIGN_DOWN_BY((DirentOffset + EtfsFile->DiskOffset), CD_SECTOR_SIZE) ==
EtfsDevice->Offset))
{
Status = EtfspGetDirent(DirectoryEntry, &Dirent, &DirentOffset);
if (NT_SUCCESS(Status))
{
if (!EtfspFileMatch(Dirent, &Name))
{
*DirEntry = Dirent;
*DirOffset = DirentOffset;
return STATUS_SUCCESS;
}
}
else
{
DirentOffset = 0;
}
}
else
{
DirentOffset = 0;
}
Status = EtfspSearchForDirent(DirectoryEntry,
FileName,
DirEntry,
&DirentOffset);
if (!(NT_SUCCESS(Status)) && (DirentOffset))
{
DirentOffset = 0;
Status = EtfspSearchForDirent(DirectoryEntry,
FileName,
DirEntry,
&DirentOffset);
}
if (NT_SUCCESS(Status))
{
*DirOffset = DirentOffset;
}
return Status;
}
NTSTATUS
EtfsRead (
_In_ PBL_FILE_ENTRY FileEntry,
_In_ PVOID Buffer,
_In_ ULONG Size,
_Out_opt_ PULONG BytesReturned
)
{
ULONG BytesRead;
PBL_ETFS_FILE EtfsFile;
NTSTATUS Status;
/* Assume failure for now */
BytesRead = 0;
/* Make sure that the read is within the file's boundaries */
EtfsFile = FileEntry->FsSpecificData;
if ((Size + EtfsFile->Offset) > EtfsFile->Size)
{
/* Bail out otherwise */
Status = STATUS_INVALID_PARAMETER;
}
else
{
/* Read the offset that matches this file's offset, on the disk */
Status = BlDeviceReadAtOffset(FileEntry->DeviceId,
Size,
EtfsFile->Offset + EtfsFile->DiskOffset,
Buffer,
&BytesRead);
if (NT_SUCCESS(Status))
{
/* Update the file offset and return the size as having been read */
EtfsFile->Offset += Size;
BytesRead = Size;
}
}
/* Check if caller wanted to know how many bytes were read */
if (BytesReturned)
{
/* Return the value */
*BytesReturned = BytesRead;
}
/* All done */
return Status;
}
NTSTATUS
EtfsSetInformation (
_In_ PBL_FILE_ENTRY FileEntry,
_In_ PBL_FILE_INFORMATION FileInfo
)
{
PBL_ETFS_FILE EtfsFile;
BL_FILE_INFORMATION LocalFileInfo;
/* Get the underlying ETFS file data structure */
EtfsFile = (PBL_ETFS_FILE)FileEntry->FsSpecificData;
/* Make a copy of the incoming attributes, but ignore the new offset */
LocalFileInfo = *FileInfo;
LocalFileInfo.Offset = EtfsFile->Offset;
/* Check if these match exactly the current file */
if (!RtlEqualMemory(&LocalFileInfo, &EtfsFile->Size, sizeof(*FileInfo)))
{
/* Nope -- which means caller is trying to change an immutable */
EfiPrintf(L"Incorrect information change\r\n");
return STATUS_INVALID_PARAMETER;
}
/* Is the offset past the end of the file? */
if (FileInfo->Offset >= EtfsFile->Size)
{
/* Don't allow EOF */
EfiPrintf(L"Offset too large: %lx vs %lx\r\n", FileInfo->Offset, EtfsFile->Size);
return STATUS_INVALID_PARAMETER;
}
/* Update the offset */
EtfsFile->Offset = FileInfo->Offset;
return STATUS_SUCCESS;
}
NTSTATUS
EtfsGetInformation (
_In_ PBL_FILE_ENTRY FileEntry,
_Out_ PBL_FILE_INFORMATION FileInfo
)
{
PBL_ETFS_FILE EtfsFile;
/* Get the underlying ETFS file data structure */
EtfsFile = (PBL_ETFS_FILE)FileEntry->FsSpecificData;
/* Copy the cached information structure within it */
RtlCopyMemory(FileInfo, &EtfsFile->Size, sizeof(*FileInfo));
return STATUS_SUCCESS;
}
NTSTATUS
EtfsOpen (
_In_ PBL_FILE_ENTRY Directory,
_In_ PWCHAR FileName,
_In_ ULONG Flags,
_Out_ PBL_FILE_ENTRY *FileEntry
)
{
PBL_ETFS_DEVICE EtfsDevice;
NTSTATUS Status;
PBL_FILE_ENTRY NewFile;
PWCHAR FilePath, FormatString;
PBL_ETFS_FILE EtfsFile;
ULONG DeviceId, FileSize, DirOffset, FileOffset, Size;
PRAW_DIR_REC DirEntry;
BOOLEAN IsDirectory;
EtfsFile = Directory->FsSpecificData;
DeviceId = EtfsFile->DeviceId;
EtfsDevice = EtfsDeviceTable[DeviceId];
/* Find the given file (or directory) in the given directory */
Status = EtfspCachedSearchForDirent(Directory,
FileName,
&DirEntry,
&DirOffset,
FALSE);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Find out information about the file (or directory) we found */
EtfspGetDirectoryInfo(EtfsDevice,
DirEntry,
&FileOffset,
&FileSize,
&IsDirectory);
/* Allocate a file entry */
NewFile = BlMmAllocateHeap(sizeof(*NewFile));
if (!NewFile)
{
return STATUS_NO_MEMORY;
}
/* Zero it out */
RtlZeroMemory(NewFile, sizeof(*NewFile));
/* Figure out the size of the path and filename plus a slash and NUL */
Size = wcslen(Directory->FilePath) + wcslen(FileName) + 2;
FilePath = BlMmAllocateHeap(Size * sizeof(WCHAR));
if (!FilePath)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Allocate an ETFS file entry */
EtfsFile = (PBL_ETFS_FILE)BlMmAllocateHeap(sizeof(*EtfsFile));
if (!EtfsFile)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
/* Zero it out */
RtlZeroMemory(EtfsFile, sizeof(*EtfsFile));
/* Capture the device ID of the directory */
NewFile->DeviceId = Directory->DeviceId;
/* Check if this is the root or a filename\directory under */
FormatString = L"%ls%ls";
if (Directory->FilePath[1])
{
FormatString = L"%ls\\%ls";
}
/* Combine the paths, and save the final path in the file entry */
_snwprintf(FilePath, Size, FormatString, Directory->FilePath, FileName);
NewFile->FilePath = FilePath;
/* Copy the ETFS function callbacks into the file netry */
RtlCopyMemory(&NewFile->Callbacks,
&EtfsFunctionTable,
sizeof(NewFile->Callbacks));
/* Fill out the rest of the details */
EtfsFile->DiskOffset = FileOffset;
EtfsFile->DirOffset = DirOffset;
EtfsFile->Size = FileSize;
EtfsFile->DeviceId = DeviceId;
/* Check if this is a directory */
if (IsDirectory)
{
EtfsFile->Flags |= BL_ETFS_FILE_ENTRY_DIRECTORY;
NewFile->Flags |= BL_FILE_ENTRY_DIRECTORY;
}
/* Write down the name of the filesystem */
EtfsFile->FsName = L"cdfs";
/* All done, return the file entry, and save the ETFS side */
NewFile->FsSpecificData = EtfsFile;
*FileEntry = NewFile;
return Status;
Quickie:
/* Failure path -- free the file path if we had one */
if (NewFile->FilePath)
{
BlMmFreeHeap(NewFile->FilePath);
}
/* Free the ETFS file entry if we had one */
if (NewFile->FsSpecificData)
{
BlMmFreeHeap(NewFile->FsSpecificData);
}
/* Free the file entry itself, and return the error code */
BlMmFreeHeap(NewFile);
return Status;
}
NTSTATUS
EtfspCheckCdfs (
_In_ PBL_ETFS_DEVICE EtfsDevice,
_In_ ULONG DeviceId,
_Out_ PRAW_ISO_VD *VolumeDescriptor,
_Out_ PBOOLEAN VolumeIsIso
)
{
EfiPrintf(L"Raw Cdfs not implemented\r\n");
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
EtfspCheckEtfs (
_In_ PBL_ETFS_DEVICE EtfsDevice,
_In_ ULONG DeviceId,
_Out_ PRAW_ISO_VD *VolumeDescriptor,
_Out_ PBOOLEAN VolumeIsIso
)
{
PRAW_ISO_VD IsoVd;
PRAW_ET_VD EtVd;
NTSTATUS Status;
BOOLEAN IsIso;
BL_DEVICE_INFORMATION DeviceInformation;
ULONG Unknown, BytesRead;
ANSI_STRING CompareString, String;
/* Save our static buffer pointer */
IsoVd = (PRAW_ISO_VD)EtfsDevice->MemoryBlock;
EtVd = (PRAW_ET_VD)IsoVd;
/* First, read the El Torito Volume Descriptor */
BlDeviceGetInformation(DeviceId, &DeviceInformation);
Unknown = DeviceInformation.BlockDeviceInfo.Unknown;
DeviceInformation.BlockDeviceInfo.Unknown |= 1;
BlDeviceSetInformation(DeviceId, &DeviceInformation);
Status = BlDeviceReadAtOffset(DeviceId,
CD_SECTOR_SIZE,
(FIRST_VD_SECTOR + 1) * CD_SECTOR_SIZE,
EtfsDevice->MemoryBlock,
&BytesRead);
DeviceInformation.BlockDeviceInfo.Unknown = Unknown;
BlDeviceSetInformation(DeviceId, &DeviceInformation);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L" read failed\r\n");
return Status;
}
/* Remember that's where we last read */
EtfsDevice->Offset = (FIRST_VD_SECTOR + 1) * CD_SECTOR_SIZE;
/* Check if it's EL TORITO! */
RtlInitString(&String, "EL TORITO SPECIFICATION");
CompareString.Buffer = (PCHAR)EtVd->SystemId;
CompareString.Length = 23;
CompareString.MaximumLength = 23;
if (!RtlEqualString(&CompareString, &String, TRUE))
{
return STATUS_UNSUCCESSFUL;
}
/* Check the version and boot indicator */
if ((EtVd->Version != 1) || (EtVd->BootIndicator))
{
return STATUS_UNSUCCESSFUL;
}
/* Check if it has the CD0001 identifier */
RtlInitString(&String, ISO_VOL_ID);
CompareString.Buffer = (PCHAR)EtVd->StandardId;
CompareString.Length = 5;
CompareString.MaximumLength = 5;
if (!RtlEqualString(&CompareString, &String, TRUE))
{
return STATUS_UNSUCCESSFUL;
}
/* Step two, we now want to read the ISO Volume Descriptor */
DeviceInformation.BlockDeviceInfo.Unknown |= 1u;
BlDeviceSetInformation(DeviceId, &DeviceInformation);
Status = BlDeviceReadAtOffset(DeviceId,
CD_SECTOR_SIZE,
FIRST_VD_SECTOR * CD_SECTOR_SIZE,
EtfsDevice->MemoryBlock,
&BytesRead);
DeviceInformation.BlockDeviceInfo.Unknown = Unknown;
BlDeviceSetInformation(DeviceId, &DeviceInformation);
if (!NT_SUCCESS(Status))
{
return Status;
}
/* Remember where we left off */
EtfsDevice->Offset = FIRST_VD_SECTOR * CD_SECTOR_SIZE;
/* This should also say CD0001 */
CompareString.Buffer = (PCHAR)IsoVd->StandardId;
CompareString.Length = 5;
CompareString.MaximumLength = 5;
IsIso = RtlEqualString(&CompareString, &String, TRUE);
if (!IsIso)
{
return STATUS_UNSUCCESSFUL;
}
/* And should be a version we support */
if ((IsoVd->Version != VERSION_1) || (IsoVd->DescType != VD_PRIMARY))
{
return STATUS_UNSUCCESSFUL;
}
/* Return back to the caller */
*VolumeDescriptor = IsoVd;
*VolumeIsIso = IsIso;
return STATUS_SUCCESS;
}
NTSTATUS
EtfspDeviceContextDestroy (
_In_ PBL_ETFS_DEVICE EtfsDevice
)
{
if (EtfsDevice->MemoryBlock)
{
BlMmFreeHeap(EtfsDevice->MemoryBlock);
}
BlMmFreeHeap(EtfsDevice);
return STATUS_SUCCESS;
}
NTSTATUS
EtfspCreateContext (
_In_ ULONG DeviceId,
_Out_ PBL_ETFS_DEVICE *EtfsDevice
)
{
PBL_ETFS_DEVICE NewContext;
PVOID MemoryBlock;
NTSTATUS Status;
BOOLEAN IsIso;
PRAW_ISO_VD RawVd;
NewContext = (PBL_ETFS_DEVICE)BlMmAllocateHeap(sizeof(*NewContext));
if (!NewContext)
{
return STATUS_NO_MEMORY;
}
RtlZeroMemory(NewContext, sizeof(*NewContext));
MemoryBlock = BlMmAllocateHeap(CD_SECTOR_SIZE);
NewContext->MemoryBlock = MemoryBlock;
if (!MemoryBlock)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
Status = EtfspCheckEtfs(NewContext, DeviceId, &RawVd, &IsIso);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Drive not EDFS. Checking for CDFS: %lx\r\n");
Status = EtfspCheckCdfs(NewContext, DeviceId, &RawVd, &IsIso);
}
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"Drive not CDFS. Failing: %lx\r\n");
goto Quickie;
}
NewContext->IsIso = IsIso;
NewContext->BlockSize = RVD_LB_SIZE(RawVd, IsIso);
NewContext->VolumeSize = RVD_VOL_SIZE(RawVd, IsIso);
EtfspGetDirectoryInfo(NewContext,
(PRAW_DIR_REC)RVD_ROOT_DE(RawVd, IsIso),
&NewContext->RootDirOffset,
&NewContext->RootDirSize,
0);
Status = STATUS_SUCCESS;
Quickie:
if (!NT_SUCCESS(Status))
{
EtfspDeviceContextDestroy(NewContext);
NewContext = NULL;
}
*EtfsDevice = NewContext;
return Status;
}
NTSTATUS
EtfspDeviceTableDestroyEntry (
_In_ PBL_ETFS_DEVICE EtfsDevice,
_In_ ULONG Index
)
{
EtfspDeviceContextDestroy(EtfsDevice);
EtfsDeviceTable[Index] = NULL;
return STATUS_SUCCESS;
}
NTSTATUS
EtfsMount (
_In_ ULONG DeviceId,
_In_ ULONG Unknown,
_Out_ PBL_FILE_ENTRY* FileEntry
)
{
PBL_ETFS_DEVICE EtfsDevice = NULL;
PBL_FILE_ENTRY RootEntry;
NTSTATUS Status;
PBL_ETFS_FILE EtfsFile;
EfiPrintf(L"Trying to mount as ETFS...\r\n");
Status = EtfspCreateContext(DeviceId, &EtfsDevice);
if (!NT_SUCCESS(Status))
{
EfiPrintf(L"ETFS context failed: %lx\r\n");
return Status;
}
Status = BlTblSetEntry(&EtfsDeviceTable,
&EtfsDeviceTableEntries,
EtfsDevice,
&DeviceId,
TblDoNotPurgeEntry);
if (!NT_SUCCESS(Status))
{
EtfspDeviceContextDestroy(EtfsDevice);
return Status;
}
RootEntry = BlMmAllocateHeap(sizeof(*RootEntry));
if (!RootEntry)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
RtlZeroMemory(RootEntry, sizeof(*RootEntry));
RootEntry->FilePath = BlMmAllocateHeap(4);
if (!RootEntry->FilePath)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
wcsncpy(RootEntry->FilePath, L"\\", 1);
RootEntry->DeviceId = DeviceId;
RtlCopyMemory(&RootEntry->Callbacks,
&EtfsFunctionTable,
sizeof(RootEntry->Callbacks));
EtfsFile = (PBL_ETFS_FILE)BlMmAllocateHeap(sizeof(*EtfsFile));
if (!EtfsFile)
{
Status = STATUS_NO_MEMORY;
goto Quickie;
}
RootEntry->Flags |= 0x10000;
RtlZeroMemory(EtfsFile, sizeof(*EtfsFile));
RootEntry->FsSpecificData = EtfsFile;
EtfsFile->DeviceId = DeviceId;
EtfsFile->Flags |= 1;
EtfsFile->DiskOffset = EtfsDevice->RootDirOffset;
EtfsFile->DirOffset = 0;
EtfsFile->Size = EtfsDevice->RootDirSize;
EtfsFile->FsName = L"cdfs";
*FileEntry = RootEntry;
return STATUS_SUCCESS;
Quickie:
if (RootEntry->FilePath)
{
BlMmFreeHeap(RootEntry->FilePath);
}
if (RootEntry->FsSpecificData)
{
BlMmFreeHeap(RootEntry->FsSpecificData);
}
if (RootEntry)
{
BlMmFreeHeap(RootEntry);
}
EtfspDeviceTableDestroyEntry(EtfsDevice, DeviceId);
return Status;
}
NTSTATUS
EtfsInitialize (
VOID
)
{
NTSTATUS Status;
/* Allocate the device table with 2 entries*/
EtfsDeviceTableEntries = 2;
EtfsDeviceTable = BlMmAllocateHeap(sizeof(PBL_FILE_ENTRY) *
EtfsDeviceTableEntries);
if (EtfsDeviceTable)
{
/* Zero it out */
RtlZeroMemory(EtfsDeviceTable,
sizeof(PBL_FILE_ENTRY) * EtfsDeviceTableEntries);
Status = STATUS_SUCCESS;
}
else
{
/* No memory, fail */
Status = STATUS_NO_MEMORY;
}
/* Return back to caller */
return Status;
}