Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

845 lines
20 KiB

/*++
Copyright (c) 1991 Microsoft Corporation
Module Name:
blio.c
Abstract:
This module contains the code that implements the switch function for
I/O operations between then operating system loader, the target file
system, and the target device.
Author:
David N. Cutler (davec) 10-May-1991
Revision History:
--*/
#include "bootlib.h"
//
// Define generic filesystem context area.
//
// N.B. An FS_STRUCTURE_CONTEXT structure is temporarily used when
// determining the file system for a volume. Once the file system
// is recognized, a file system specific structure is allocated from
// the heap to retain the file system structure information.
//
typedef union {
CDFS_STRUCTURE_CONTEXT CdfsStructure;
FAT_STRUCTURE_CONTEXT FatStructure;
HPFS_STRUCTURE_CONTEXT HpfsStructure;
NTFS_STRUCTURE_CONTEXT NtfsStructure;
#if defined(ELTORITO)
ETFS_STRUCTURE_CONTEXT EtfsStructure;
#endif
#ifdef DBLSPACE_LEGAL
DBLS_STRUCTURE_CONTEXT DblsStructure;
#endif
} FS_STRUCTURE_CONTEXT, *PFS_STRUCTURE_CONTEXT;
#ifdef DBLSPACE_LEGAL
//
// Define value controlling whether we transparently
// find files in \dblspace.000 cvf in fat drives.
// See BlSetAutoDoubleSpace for a full description.
//
BOOLEAN BlAutoDoubleSpace = FALSE;
#endif
//
// Define file table.
//
BL_FILE_TABLE BlFileTable[BL_FILE_TABLE_SIZE];
ARC_STATUS
BlIoInitialize (
VOID
)
/*++
Routine Description:
This routine initializes the file table used by the OS loader and
initializes the boot loader filesystems.
Arguments:
None.
Return Value:
ESUCCESS is returned if the initialization is successful. Otherwise,
return an unsuccessful status.
--*/
{
ULONG Index;
ARC_STATUS Status;
//
// Initialize the file table.
//
for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
BlFileTable[Index].Flags.Open = 0;
}
if((Status = FatInitialize()) != ESUCCESS) {
return Status;
}
#ifdef DBLSPACE_LEGAL
if((Status = DblsInitialize()) != ESUCCESS) {
return Status;
}
#endif
if((Status = HpfsInitialize()) != ESUCCESS) {
return Status;
}
if((Status = NtfsInitialize()) != ESUCCESS) {
return Status;
}
if((Status = CdfsInitialize()) != ESUCCESS) {
return Status;
}
return ESUCCESS;
}
PBOOTFS_INFO
BlGetFsInfo(
IN ULONG DeviceId
)
/*++
Routine Description:
Returns filesystem information for the filesystem on the specified device
Arguments:
FileId - Supplies the file table index of the device
Return Value:
PBOOTFS_INFO - Pointer to the BOOTFS_INFO structure for the filesystem
NULL - unknown filesystem
--*/
{
FS_STRUCTURE_CONTEXT FsStructure;
PBL_DEVICE_ENTRY_TABLE Table;
if ((Table = IsFatFileStructure(DeviceId, &FsStructure)) != NULL) {
return(Table->BootFsInfo);
}
if ((Table = IsHpfsFileStructure(DeviceId, &FsStructure)) != NULL) {
return(Table->BootFsInfo);
}
if ((Table = IsNtfsFileStructure(DeviceId, &FsStructure)) != NULL) {
return(Table->BootFsInfo);
}
if ((Table = IsCdfsFileStructure(DeviceId, &FsStructure)) != NULL) {
return(Table->BootFsInfo);
}
return(NULL);
}
ARC_STATUS
BlClose (
IN ULONG FileId
)
/*++
Routine Description:
This function closes a file or a device that is open.
Arguments:
FileId - Supplies the file table index.
Return Value:
If the specified file is open, then a close is attempted and
the status of the operation is returned. Otherwise, return an
unsuccessful status.
--*/
{
#ifdef DBLSPACE_LEGAL
//
// If the file is opened and is a double space file then we need to
// also close the cvf.
//
if ((BlFileTable[FileId].Flags.Open == 1) &&
(BlFileTable[FileId].Flags.DoubleSpace == 1)) {
BlFileTable[ BlFileTable[FileId].DeviceId ].DeviceEntryTable->Close(BlFileTable[FileId].DeviceId);
}
#endif
//
// If the file is open, then attempt to close it. Otherwise return an
// access error.
//
if (BlFileTable[FileId].Flags.Open == 1) {
return (BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
} else {
return EACCES;
}
}
ARC_STATUS
BlMount (
IN PCHAR MountPath,
IN MOUNT_OPERATION Operation
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
UNREFERENCED_PARAMETER(MountPath);
UNREFERENCED_PARAMETER(Operation);
return ESUCCESS;
}
ARC_STATUS
BlOpen (
IN ULONG DeviceId,
IN PCHAR OpenPath,
IN OPEN_MODE OpenMode,
OUT PULONG FileId
)
/*++
Routine Description:
This function opens a file on the specified device. The type of file
system is automatically recognized.
Arguments:
DeviceId - Supplies the file table index of the device.
OpenPath - Supplies a pointer to the name of the file to be opened.
#ifdef DBLSPACE_LEGAL
If auto DoubleSpace is enabled, this routine will attempt to
locate this file on \dblspace.000 if the host partition is FAT
and that CVF exists. If the file cannot be located in the CVF,
then it is looked for in the partition outside the cvf as in a
standard non-DoubleSpace open. The caller must not specify
the \dblspace.000 prefix in the OpenPath if auto DoubleSpace
is enabled. See BlSetAutoDoubleSpace().
#endif
OpenMode - Supplies the mode of the open.
FileId - Supplies a pointer to a variable that receives the file
table index of the open file.
Return Value:
If a free file table entry is available and the file structure on
the specified device is recognized, then an open is attempted and
the status of the operation is returned. Otherwise, return an
unsuccessful status.
--*/
{
ULONG Index;
FS_STRUCTURE_CONTEXT FsStructureTemp;
PFS_STRUCTURE_CONTEXT FsStructure;
ULONG ContextSize;
#ifdef DBLSPACE_LEGAL
//
// Special case the double space partition. We do that by looking
// for a path name that start with "\dblspace.0"
//
if(BlAutoDoubleSpace || !strncmp(OpenPath, "\\dblspace.0", sizeof("\\dblspace.0")-1)) {
ARC_STATUS Status;
ULONG CvfId;
CHAR SavedChar;
PCHAR CvfOpenPath;
//
// Search for a free file table index for the cvf
//
for (CvfId = 0; CvfId < BL_FILE_TABLE_SIZE; CvfId += 1) {
if (BlFileTable[CvfId].Flags.Open == 0) {
//
// Fat is the only one to recognize a cvf file.
//
// If automounting DoubleSpace and the host partition
// is not FAT, then try a standard non-DoubleSpace open.
//
if ((BlFileTable[CvfId].DeviceEntryTable =
IsFatFileStructure(DeviceId, &FsStructureTemp)) == NULL) {
if(BlAutoDoubleSpace) {
goto NonDoubleSpaceOpen;
}
return EACCES;
}
FsStructure = BlAllocateHeap(sizeof(FAT_STRUCTURE_CONTEXT));
if (FsStructure == NULL) {
return ENOMEM;
}
RtlCopyMemory(FsStructure, &FsStructureTemp, sizeof(FAT_STRUCTURE_CONTEXT));
BlFileTable[CvfId].StructureContext = FsStructure;
BlFileTable[CvfId].DeviceId = DeviceId;
//
// Now we open the cvf file. The name of the cvf file is the
// first component of the path name. It must always be
// "\dblspace.0xx" long so what we'll do is jam a null into
// the open path and use it.
//
// If automounting dblspace.000, then supply the implied \dblspace.000.
//
if(BlAutoDoubleSpace) {
CvfOpenPath = "\\dblspace.000";
} else {
SavedChar = OpenPath[sizeof("\\dblspace.000")-1];
OpenPath[sizeof("\\dblspace.000")-1] = 0;
CvfOpenPath = OpenPath;
}
Status = (BlFileTable[CvfId].DeviceEntryTable->Open)(CvfOpenPath,
ArcOpenReadOnly,
&CvfId);
if(!BlAutoDoubleSpace) {
OpenPath[sizeof("\\dblspace.000")-1] = SavedChar;
}
if (Status != ESUCCESS) {
//
// We were unable to open the DoubleSpace CVF.
// If automounting, try a standard non-DoubleSpace open.
//
if(BlAutoDoubleSpace) {
goto NonDoubleSpaceOpen;
}
return Status;
}
break;
}
}
//
// If we didn't find a free table entry, return error.
//
if(CvfId == BL_FILE_TABLE_SIZE) {
return EACCES;
}
//
// Search for a free file table index for the file
//
for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
if (BlFileTable[Index].Flags.Open == 0) {
//
// Double space is the only one that can recognize this
//
if ((BlFileTable[Index].DeviceEntryTable =
IsDblsFileStructure(CvfId, &FsStructureTemp)) == NULL) {
BlClose(CvfId);
//
// Dblspace.000 is not a DoubleSpace cvf or is damaged, etc.
//
if(BlAutoDoubleSpace) {
goto NonDoubleSpaceOpen;
}
return EACCES;
}
FsStructure = BlAllocateHeap(sizeof(DBLS_STRUCTURE_CONTEXT));
if (FsStructure == NULL) {
return ENOMEM;
}
RtlCopyMemory(FsStructure, &FsStructureTemp, sizeof(DBLS_STRUCTURE_CONTEXT));
BlFileTable[Index].StructureContext = FsStructure;
*FileId = Index;
BlFileTable[Index].DeviceId = CvfId;
BlFileTable[FileId].Flags.DoubleSpace = 1;
//
// If we are automounting, then there is no \dblspace.000
// at the beginning of the open path. If not automounting,
// the caller must have specified \dblspace.000\xxx explicitly.
//
CvfOpenPath = BlAutoDoubleSpace
? OpenPath
: (OpenPath + sizeof("dblspace.000") - 1);
Status = (BlFileTable[Index].DeviceEntryTable->Open)(CvfOpenPath,
OpenMode,
FileId);
if (Status != ESUCCESS) {
//
// The file could not be located in the cvf.
//
BlClose( CvfId );
//**** this is just a hack to make everything work. Don't know why but this works...
//**** ULONG FileId2;
//**** BlOpen(DeviceId, "\\", ArcOpenReadOnly, &FileId2);
//**** BlClose(FileId2);
if(BlAutoDoubleSpace) {
goto NonDoubleSpaceOpen;
}
}
return Status;
}
}
//
// We didn't find a free table entry -- close the CVF and return error.
//
BlClose(CvfId);
return EACCES;
}
NonDoubleSpaceOpen:
#endif // def DBLSPACE_LEGAL
//
// Search for a free file table entry.
//
for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
if (BlFileTable[Index].Flags.Open == 0) {
//
// Attempt to recognize the file system on the specified
// device. If no one recognizes it then return an unsuccessful
// status.
//
if ((BlFileTable[Index].DeviceEntryTable =
IsFatFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
ContextSize = sizeof(FAT_STRUCTURE_CONTEXT);
} else if ((BlFileTable[Index].DeviceEntryTable =
IsHpfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
ContextSize = sizeof(HPFS_STRUCTURE_CONTEXT);
} else if ((BlFileTable[Index].DeviceEntryTable =
IsNtfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
ContextSize = sizeof(NTFS_STRUCTURE_CONTEXT);
#if defined(ELTORITO)
//
// This must go before the check for Cdfs; otherwise Cdfs will be detected.
// Since BIOS calls already set up to use EDDS, reads will succeed, and checks
// against ISO will succeed. We check El Torito-specific fields here as well as ISO
//
} else if ((BlFileTable[Index].DeviceEntryTable =
IsEtfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
ContextSize = sizeof(ETFS_STRUCTURE_CONTEXT);
#endif
} else if ((BlFileTable[Index].DeviceEntryTable =
IsCdfsFileStructure(DeviceId, &FsStructureTemp)) != NULL) {
ContextSize = sizeof(CDFS_STRUCTURE_CONTEXT);
} else {
return EACCES;
}
FsStructure = BlAllocateHeap(ContextSize);
if (FsStructure == NULL) {
return ENOMEM;
}
RtlCopyMemory(FsStructure, &FsStructureTemp, ContextSize);
BlFileTable[Index].StructureContext = FsStructure;
//
// Someone has mounted the volume so now attempt to open the file.
//
*FileId = Index;
BlFileTable[Index].DeviceId = DeviceId;
return (BlFileTable[Index].DeviceEntryTable->Open)(OpenPath,
OpenMode,
FileId);
}
}
//
// No free file table entry could be found.
//
return EACCES;
}
ARC_STATUS
BlRead (
IN ULONG FileId,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG Count
)
/*++
Routine Description:
This function reads from a file or a device that is open.
Arguments:
FileId - Supplies the file table index.
Buffer - Supplies a pointer to the buffer that receives the data
read.
Length - Supplies the number of bytes that are to be read.
Count - Supplies a pointer to a variable that receives the number of
bytes actually transfered.
Return Value:
If the specified file is open for read, then a read is attempted
and the status of the operation is returned. Otherwise, return an
unsuccessful status.
--*/
{
//
// If the file is open for read, then attempt to read from it. Otherwise
// return an access error.
//
if ((BlFileTable[FileId].Flags.Open == 1) &&
(BlFileTable[FileId].Flags.Read == 1)) {
return (BlFileTable[FileId].DeviceEntryTable->Read)(FileId,
Buffer,
Length,
Count);
} else {
return EACCES;
}
}
ARC_STATUS
BlGetReadStatus (
IN ULONG FileId
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
return ESUCCESS;
}
ARC_STATUS
BlSeek (
IN ULONG FileId,
IN PLARGE_INTEGER Offset,
IN SEEK_MODE SeekMode
)
/*++
Routine Description:
Arguments:
Return Value:
If the specified file is open, then a seek is attempted and
the status of the operation is returned. Otherwise, return an
unsuccessful status.
--*/
{
//
// If the file is open, then attempt to seek on it. Otherwise return an
// access error.
//
if (BlFileTable[FileId].Flags.Open == 1) {
return (BlFileTable[FileId].DeviceEntryTable->Seek)(FileId,
Offset,
SeekMode);
} else {
return EACCES;
}
}
ARC_STATUS
BlWrite (
IN ULONG FileId,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG Count
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
//
// If the file is open for write, then attempt to write to it. Otherwise
// return an access error.
//
if ((BlFileTable[FileId].Flags.Open == 1) &&
(BlFileTable[FileId].Flags.Write == 1)) {
return (BlFileTable[FileId].DeviceEntryTable->Write)(FileId,
Buffer,
Length,
Count);
} else {
return EACCES;
}
}
ARC_STATUS
BlGetFileInformation (
IN ULONG FileId,
IN PFILE_INFORMATION FileInformation
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
//
// If the file is open, then attempt to get file information. Otherwise
// return an access error.
//
if (BlFileTable[FileId].Flags.Open == 1) {
return (BlFileTable[FileId].DeviceEntryTable->GetFileInformation)(FileId,
FileInformation);
} else {
return EACCES;
}
}
ARC_STATUS
BlSetFileInformation (
IN ULONG FileId,
IN ULONG AttributeFlags,
IN ULONG AttributeMask
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
//
// If the file is open, then attempt to Set file information. Otherwise
// return an access error.
//
if (BlFileTable[FileId].Flags.Open == 1) {
return (BlFileTable[FileId].DeviceEntryTable->SetFileInformation)(FileId,
AttributeFlags,
AttributeMask);
} else {
return EACCES;
}
}
ARC_STATUS
BlRename(
IN ULONG FileId,
IN PCHAR NewName
)
/*++
Routine Description:
Rename an open file or directory.
Arguments:
FileId - supplies a handle to an open file or directory. The file
need not be open for write access.
NewName - New name to give the file or directory (filename part only).
Return Value:
Status indicating result of the operation.
--*/
{
if(BlFileTable[FileId].Flags.Open == 1) {
return(BlFileTable[FileId].DeviceEntryTable->Rename(FileId,
NewName
)
);
} else {
return(EACCES);
}
}
#ifdef DBLSPACE_LEGAL
VOID
BlSetAutoDoubleSpace(
IN BOOLEAN Enable
)
/*++
Routine Description:
Enable or disable transparent opens of files contained in a
000 CVF on a partition.
This "auto DoubleSpace" provides the equivalent of an automount capability.
If enabled, BlOpen will attempt to open files on a fat partition in a CVF
with sequence 000, without the need for the caller to specify \dblspace.000
as part of the file name. If disabled, files on DoubleSpace drives must be
explicitly named using \dblspace.0xx as the first component of the path.
Arguments:
Enable - if TRUE (non-0), enable transparent doublespace access.
if FALSE (0), disable it.
Return Value:
Status indicating result of the operation.
--*/
{
BlAutoDoubleSpace = Enable;
}
#endif