NT4/private/ntos/boot/veneer/vrio.c
2020-09-30 17:12:29 +02:00

1426 lines
32 KiB
C

/*
*
* Copyright (c) 1995 FirePower Systems, Inc.
* Copyright (c) 1994 FirePower Systems Inc.
* Copyright (c) 1994 FirmWorks, Mountain View CA USA. All rights reserved.
*
* $RCSfile: vrio.c $
* $Revision: 1.9 $
* $Date: 1996/04/15 02:55:53 $
* $Locker: $
*
*
* Module Name:
* vrio.c
*
* Author:
* Shin Iwamoto at FirePower Systems Inc.
*
* History:
* 26-Sep-94 Shin Iwamoto at FirePower Systems Inc.
* Added checking SeekMode in VrSeek().
* 15-Sep-94 Shin Iwamoto at FirePower Systems Inc.
* Added saving the area pointed to by OpenPath in VrOpen().
* 15-Jul-94 Shin Iwamoto at FirePower Systems Inc.
* Added for XXX_SEEK_IS_BUSTED in VrSeek().
* 14-Jul-94 Shin Iwamoto at FirePower Systems Inc.
* Added ONE_IO_SIZE in VrRead() and VrWrite().
* 13-Jul-94 Shin Iwamoto at FirePower Systems Inc.
* Added ENOSPC checking in VrWrite().
* Added for reading ahead in VrGetReadStatus() and VrRead().
* 11-Jul-94 Shin Iwamoto at FirePower Systems Inc.
* Added some debugging facilities in VrOpen. These were
* from checked-in veneer source code.
* 16-Jun-94 Shin Iwamoto at FirePower Systems Inc.
* Added when a serial device doesn't read in VrRead().
* 15-Jun-94 Shin Iwamoto at FirePower Systems Inc.
* When OpenPath inclues console, the path is for a device.
* So, FilePath was set to null.
* 13-Jun-94 Shin Iwamoto at FirePower Systems Inc.
* Added debugging statements.
* Modified some porting from Mike Tooch at FirmWorks.
* 18-May-94 Shin Iwamoto at FirePower Systems Inc.
* Added for unsinged long size in VrWrite.
* Added a part of VrMount.
* Added that DirectoryFile flag is ignored in
* VrSetFileInformation().
* Added for Delete flag in FileTable in
* VrRead(), VrWrite(), VrSeek(), VrGetReadStatus()
* Added some comments.
* and VrSetFileInformation().
* 17-May-94 Shin Iwamoto at FirePower Systems Inc.
* Added for NetworkDevice in GetDeviceAttribute().
* Added for unsinged long size in VrRead.
* 12-May-94 Shin Iwamoto at FirePower Systems Inc.
* Changed the name, strlen and strncmp to
* VfStrlen and VfStrncmp.
* 11-May-94 Shin Iwamoto at FirePower Systems Inc.
* Added FIleTable. Changed rootnode to RootNode.
* Put cast PCAHR to the first parameter of bzero.
* Changed OFPhandle to OfPhandle.
* Changed the name of VrFindCOnfigurationNode.
* 10-May-94 Shin Iwamoto at FirePower Systems Inc.
* Changed Vr{Open|Close|Read|Write|Seek} because of
* changing the file table structure.
* 05-May-94 Shin Iwamoto at FirePower Systems Inc.
* Created.
*
*/
#include "veneer.h"
//
// Some switches
//
#define MAX_OPEN_PATH_SIZE MAX_PATH_NAME_SIZE
#define ONE_IO_SIZE 1024*1024
#define ZERO_LARGE 0
#define NOT_ZERO_LARGE 1
#define Minimum(X,Y) ((X) < (Y) ? (X) : (Y))
//
// File Table definition
//
FILE_TABLE_ENTRY FileTable[FILE_TABLE_SIZE];
//
// Function declarations
//
STATIC ARC_STATUS
GetFileTableEntry(
OUT PULONG
);
STATIC ARC_STATUS
GetDeviceAttribute(
IN ULONG,
IN PCONFIGURATION_NODE
);
STATIC VOID
AddLargeInt(
PLARGE_INTEGER,
PLARGE_INTEGER
);
STATIC VOID
MoveLargeInt(
PLARGE_INTEGER,
PLARGE_INTEGER
);
STATIC LONG
IsLarge(
PLARGE_INTEGER
);
STATIC VOID
DecrementLarge(
PLARGE_INTEGER
);
/*
* Name: VrOpen
*
* Description:
* This function opens the file specified by OpenPath.
* The pathname is translated into the devicename for Open Firmware,
* then OFOpen is called with the devicename.
*
* Arguments:
* OpenPath - ARC compliant pathname of the device/file to be opened.
* OpenMode - Supplies the mode in which the file is opened.
* FileId - Pointer to a variable that receives the fileid for
* this pathname.
*
* Return Value:
* If the file is successfully opened returns ESUCCESS otherwise
* returns an unsuccessful status.
*
*/
ARC_STATUS
VrOpen(
IN PCHAR OpenPath,
IN OPEN_MODE OpenMode,
OUT PULONG FileId
)
{
PCHAR FilePath, DevicePath, Partition, Console;
ihandle IHandle;
ARC_STATUS Status;
PCONFIGURATION_NODE ConfNode;
PCHAR pstr1;
LONG DevSpecLen;
debug(VRDBG_OPEN, "VrOpen: Entry - Path: %s Mode: %x\n",
OpenPath, OpenMode);
if (strlen(OpenPath) >= MAX_OPEN_PATH_SIZE) {
debug(VRDBG_OPEN, "VrOpen: ENAMETOOLONG: '%s'\n", OpenPath);
return ENAMETOOLONG;
}
//
// Find Partition, Console and FilePath in OpenPath.
//
FilePath = NULL;
Partition = NULL;
Console = NULL;
for (pstr1 = OpenPath; *pstr1; pstr1++) {
if (strncmp(pstr1, "partition", 9) == 0) {
Partition = pstr1;
while (*pstr1++ != ')') {
;
}
FilePath = pstr1;
break;
} else if (strncmp(pstr1, "console", 7) == 0) {
Console = pstr1;
while (*pstr1++ != ')') {
;
}
if (*pstr1 != '\0') {
return EINVAL;
}
FilePath = NULL; // Console is a device.
break;
}
else if (*pstr1 == ')') {
FilePath = pstr1+1;
}
}
//
// Did we eventually wind up with a FilePath after all?
//
if ((FilePath != NULL) && (strlen(FilePath) == 0)) {
FilePath = NULL;
}
debug(VRDBG_OPEN, "VrOpen: Partition '%s' FilePath '%s'\n",
Partition == NULL ? "NULL" : Partition,
FilePath == NULL ? "NULL" : FilePath);
//
// Check open mode for a device.
//
if ((FilePath == NULL) && (OpenMode > ArcOpenReadWrite)) {
debug(VRDBG_OPEN, "VrOpen: EINVAL: '%s'\n", OpenPath);
return EINVAL;
}
//
// Extract the device name from OpenPath.
//
ConfNode = ArcPathToNode(OpenPath);
if (ConfNode == NULL) {
debug(VRDBG_OPEN, "VrOpen: ENODEV: '%s'\n", OpenPath);
return ENODEV;
}
//
// Translate the device name into the device path for Open Firmware.
// Add space for the partition and file components.
//
pstr1 = NodeToPath(ConfNode);
DevSpecLen = strlen(pstr1) + 16; // Enough for a partition specifier.
if (FilePath != NULL) {
DevSpecLen += strlen(FilePath);
}
DevicePath = zalloc(DevSpecLen);
strcpy(DevicePath, pstr1);
free(pstr1);
//
// Get a free entry in the file table.
//
if (Status = GetFileTableEntry(FileId)) {
debug(VRDBG_OPEN, "VrOpen: GetFileTableEntry returned %x\n", Status);
return Status;
}
//
// Set flags in the FileTable.
//
if (Status = GetDeviceAttribute(*FileId, ConfNode)) {
debug(VRDBG_OPEN, "VrOpen: GetDeviceAttribute returned %x\n", Status);
return Status;
}
if ((Partition == NULL) && (FilePath == NULL)) { // A device (not file)
FileTable[*FileId].Flags.Device = 1;
strcat(DevicePath, ":0");
} else { // A file (not a device)
//
// Convert the partition and the filename (if they exist) as follows:
//
// [partition(key1)][<filepath>]
// --> :[key1][,<filepath>]
//
strcat(DevicePath, ":");
if (Partition != NULL) {
FileTable[*FileId].Flags.Partition = (FilePath == NULL);
pstr1 = Partition;
while (*pstr1++ != '(') {
;
}
if (*pstr1 == ')') {
strcat(DevicePath, "0");
} else {
PCHAR pstr2;
pstr2 = DevicePath + strlen(DevicePath);
do {
*pstr2++ = *pstr1++;
} while (*pstr1 != ')');
*pstr2 = '\0';
}
}
if (FilePath != NULL) {
strcat(DevicePath, ",");
strcat(DevicePath, FilePath);
}
}
//
// Now we can open the device path (including the file path).
//
IHandle = OFOpen(DevicePath);
debug(VRDBG_OPEN, "OFOpen: IHandle: %x\n", IHandle);
FileTable[*FileId].PathName = DevicePath;
//
// Checking related to OpenMode.
//
switch (OpenMode) {
case ArcCreateWriteOnly:
case ArcCreateReadWrite:
if (IHandle != 0) {
(VOID)OFClose(IHandle);
return EACCES;
}
break;
default:
if (IHandle == 0) {
return EIO;
}
}
FileTable[*FileId].Flags.Open = 1;
FileTable[*FileId].IHandle = IHandle;
debug(VRDBG_OPEN, "VrOpen: Exit - FileId: %d IHandle: %x\n",
*FileId, IHandle);
return ESUCCESS;
}
/*
* Name: VrClose
*
* Description:
* This function closes a file or a device if it is opened.
*
* Arguments:
* FileId - Supplies the file table index.
*
* Return Value:
* If the specified file is open, then a close is attempted via
* OFClose and ESUCCESS is returned. Otherwise, return an unsuccessful
* status.
*
*/
ARC_STATUS
VrClose(
IN ULONG FileId
)
{
debug(VRDBG_OPEN, "VrClose: Entry - FileId: %d\n", FileId);
if (FileId >= FILE_TABLE_SIZE) {
return EBADF;
}
if (FileTable[FileId].Flags.Open != 1) {
return EACCES;
}
//
// Close the file.
//
(VOID)OFClose(FileTable[FileId].IHandle);
//
// Release the file table entry.
//
// FileTable[FileId].Flags.Open = 0;
bzero((PCHAR)&FileTable[FileId], sizeof(FILE_TABLE_ENTRY));
free(FileTable[FileId].PathName);
debug(VRDBG_OPEN, "VrClose: Exit\n");
return ESUCCESS;
}
/*
* Name: VrRead
*
* Description:
* This function reads data from the device of file specified by FileId
* into the buffer pointed to by Buffer.
*
* Arguments:
* FileId - Supplies the file table index.
* Buffer - Supplies a pointer to the buffer that receives the read
* data.
* Length - Supplies the maximum number of bytes to be read.
* If this field contains the value zero, then no bytes
* are 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 retuned. Otherwise, return
* an unsuccessful status.
*
*/
STATIC CHAR consin_readahead = 0;
ARC_STATUS
VrRead(
IN ULONG FileId,
OUT PVOID Buffer,
IN ULONG Length,
OUT PULONG Count
)
{
LARGE_INTEGER LInteger;
PCHAR buf = (PCHAR) Buffer;
if (FileId == 0) { // stdin
if (consin_readahead) {
*buf = consin_readahead;
consin_readahead = 0;
*Count = 1;
} else {
if (ConsoleIn == 0) {
(void) VrFindConsolePath("stdin");
}
while (((LONG)*Count = OFRead(ConsoleIn, Buffer, Length)) <= 0){
;
}
}
return ESUCCESS;
}
debug(VRDBG_RDWR, "VrRead: Entry - FileId: %d Buf: %x len: %d\n",
FileId, Buffer, Length);
//
// If Length is zero, return as if the function were successful.
//
if (Length == 0) {
*Count = 0;
return ESUCCESS;
}
if (FileId == 1) {
return EBADF;
}
if (FileId >= FILE_TABLE_SIZE) {
return EBADF;
}
if (!(FileTable[FileId].Flags.Open == 1
&& FileTable[FileId].Flags.Read == 1)) {
return EACCES;
}
if (FileTable[FileId].Flags.Delete == 1) {
return EACCES;
}
#ifdef NO_UNSIGNED_LONG_IO
//
// Calls the read routine.
//
(LONG)*Count = OFRead(FileTable[FileId].IHandle, Buffer, Length);
if ((LONG)*Count == -1) {
return EIO; // XXXX
}
#else // NO_UNSIGNED_LONG_IO
//
// Initialize Counter.
//
*Count = 0;
//
// Checking read ahead buffer. If already read, the copy the buffer
// into Buffer.
//
if (FileTable[FileId].ReadAheadCount != 0) {
*Count = FileTable[FileId].ReadAheadCount;
bcopy(FileTable[FileId].ReadAheadBuffer, Buffer, *Count);
Buffer = (PCHAR)Buffer + *Count;
Length -= *Count;
FileTable[FileId].ReadAheadCount = 0;
}
//
// Calls the read routine.
//
while (Length > 0) {
LONG SingleReadSize;
LONG ReadCount;
SingleReadSize = Minimum(Length, ONE_IO_SIZE);
ReadCount = OFRead(FileTable[FileId].IHandle, Buffer, SingleReadSize);
if (ReadCount == -1) {
LONG Status;
//
// If an error in the second or later read happes,
// the offset must be put back using OFSeek.
// In reading ahead, this is useful.
//
if (*Count != 0) {
Status = OFSeek(FileTable[FileId].IHandle,
FileTable[FileId].Position.HighPart,
FileTable[FileId].Position.LowPart);
//
// Ignore Status.
//
}
return EIO; // XXXX
}
//
// Retry to read, when the device is serial and there is no data.
//
if ((ReadCount == -2) && (*Count == 0)) {
continue;
}
//
// Update the number of bytes read successfully.
//
*Count += ReadCount;
//
// If the device represented by FileId is a network device,
// read one time. If not yet read, continue.
//
if (FileTable[FileId].Flags.NetworkDevice == 1) {
if ((ReadCount == 0) && (*Count == 0)) {
continue;
}
return ESUCCESS;
}
//
// Find EOF, then break this loop.
//
if (ReadCount < SingleReadSize) {
break;
}
//
// Update the remaining length and the buffer to point to
// the next position.
//
Length -= SingleReadSize;
Buffer = (PCHAR)Buffer + SingleReadSize;
}
#endif // NO_UNSIGNED_LONG_IO
//
// Calculates the position of the file.
//
LInteger.HighPart = 0;
LInteger.LowPart = *Count;
AddLargeInt(&FileTable[FileId].Position, &LInteger);
debug(VRDBG_RDWR, "VrRead: Exit ReadCount: %d\n", *Count);
return ESUCCESS;
}
/*
* Name: VrWrite
*
* Description:
* This function writes data from memory starting from the buffer
* pointed to by Buffer to the device specified by FileId.
* Upon completion of a successful write, the byte offset for FileId
* is updated; otherwise the byte offset is left unchanged.
*
* Arguments:
* FileId - Supplies the file table index.
* Buffer - Supplies a pointer to the buffer that contains
* the write data.
* Length - Supplies the number of bytes to be written.
* Count - Supplies a pointer to a variable that contains
* the number of bytes actually transfered.
*
* Return Value:
* If the specified file is open for write, then a write is attempted
* using OFWrite and a status is returned. Otherwise, return
* an unsuccessful status.
*
*/
ARC_STATUS
VrWrite(
IN ULONG FileId,
IN PVOID Buffer,
IN ULONG Length,
OUT PULONG Count
)
{
LARGE_INTEGER LInteger;
ARC_STATUS Status;
if (FileId == 1) { // stdout
*Count = OFWrite(ConsoleOut, Buffer, Length);
return ESUCCESS;
}
debug(VRDBG_RDWR, "VrWrite: Entry - FileId: %d Buf: %x len: %d\n",
FileId, Buffer, Length);
//
// If Length is zero, return as if the function were successful.
//
if (Length == 0) {
*Count = 0;
return ESUCCESS;
}
if (FileId == 0) {
return EBADF;
}
if (FileId >= FILE_TABLE_SIZE) {
return EBADF;
}
if (!(FileTable[FileId].Flags.Open == 1
&& FileTable[FileId].Flags.Write == 1)) {
return EACCES;
}
if (FileTable[FileId].Flags.Delete == 1) {
return EACCES;
}
//
// If Length bytes cannot be placed into a network packet,
// return ENOSPC without sending the packet, placing the number of bytes
// that could be written in Count.
//
if (FileTable[FileId].Flags.NetworkDevice == 1) {
ULONG MaxFrameSize;
MaxFrameSize = get_int_prop(OFFinddevice(FileTable[FileId].PathName),
"max-frame-size");
if (Length > MaxFrameSize) {
*Count = MaxFrameSize;
return ENOSPC;
}
}
#ifdef NO_UNSIGNED_LONG_IO
//
// Calls the write routine.
//
Status = ESUCCESS;
(LONG)*Count = OFWrite(FileTable[FileId].IHandle, Buffer, Length);
if ((LONG)*Count == -1) {
return EIO; // XXXX
}
#else // NO_UNSIGNED_LONG_IO
Status = ESUCCESS;
*Count = 0;
while (Length > 0) {
LONG SingleWriteSize;
LONG WriteCount;
SingleWriteSize = Minimum(Length, ONE_IO_SIZE);
WriteCount = OFWrite(FileTable[FileId].IHandle, Buffer,
SingleWriteSize);
if (WriteCount == -1) {
LONG SeekStatus;
//
// If an error in the second or later read happens,
// the offset must be put back using OFSeek.
//
if (*Count != 0) {
SeekStatus = OFSeek(FileTable[FileId].IHandle,
FileTable[FileId].Position.HighPart,
FileTable[FileId].Position.LowPart);
//
// Ignore Status.
//
}
return EIO; // XXXX
}
//
// Update the number of bytes written successfully.
//
*Count += WriteCount;
//
// If the device represented by FileId is a network device,
// write one time. If not yet written, continue.
//
if (FileTable[FileId].Flags.NetworkDevice == 1) {
if (WriteCount == 0) {
continue;
}
return ESUCCESS;
}
//
// Find that the device is full.
//
if (WriteCount < SingleWriteSize) {
Status = ENOSPC;
break;
}
//
// Update the remaining length and the buffer to point to
// the next position.
//
Length -= SingleWriteSize;
Buffer = (PCHAR)Buffer + SingleWriteSize;
}
#endif // NO_UNSIGNED_LONG_IO
//
// Calculates the position of the file.
//
LInteger.HighPart = 0;
LInteger.LowPart = *Count;
AddLargeInt(&FileTable[FileId].Position, &LInteger);
if (FileId >= 2) {
debug(VRDBG_RDWR, "VrWrite: Exit WrtCount: %d, Status: %d\n",
*Count, Status);
}
return Status;
}
/*
* Name: VrMount
*
* Description:
* This function is used to load and unload media for devices that
* support removale media.
*
* Arguments:
* MountPath - Supplies a pointer to the variable that contains
* the path of the device.
* Operation - Supplies a indication whether the media is to be
* loaded or unloaded.
*
* Return Value:
* If the specified path is for device, then a mount is attempted
* a status is returned. Otherwise, return an unsuccessful status.
*
*/
ARC_STATUS
VrMount(
IN PCHAR MountPath,
IN MOUNT_OPERATION Operation
)
{
PCONFIGURATION_NODE ConfNode;
PCHAR FilePath, pstr1;
debug(VRDBG_OPEN, "VrMount: Entry - MountPath: %s Operation: %d\n",
MountPath, Operation);
//
// Check that the MountPath is a device.
//
FilePath = MountPath;
for (pstr1 = MountPath; *pstr1; pstr1++) {
if (strncmp(pstr1, "partition", 9) == 0) {
return EINVAL;
} else if (strncmp(pstr1, "console", 7) == 0) {
return EINVAL;
} else if (*pstr1 == ')') {
FilePath = pstr1+1;
}
}
if (FilePath == MountPath || FilePath[0] != '\0') {
return EINVAL;
}
//
// Find the configuration node using the MountPath.
//
ConfNode = ArcPathToNode(MountPath);
if (ConfNode == NULL) {
return ENOENT;
}
//
// Check that the device is removable.
//
if (!(ConfNode->Component.Flags.Removable)) {
return ENOENT; // XXXX
}
//
// Translate the device name into the device path for Open Firmware.
//
// XXXX
// How do I mount/unmount ?
// If Operation is MountUnloadMedia for not mounted device,
// return ENXIO;
debug(VRDBG_OPEN, "VrMount: Exit\n");
return ESUCCESS;
}
/*
* Name: VrSeek
*
* Description:
* This function changes the byte offset associated with the device,
* partition, or file specified by FileId.
*
* Arguments:
* FileId - Supplies the file table index.
* Offset - Supplies a poiner to a structure that contains
* the offset value.
* SeekMode - Supplies the type of positioning to be performed.
*
* 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.
*
*/
ARC_STATUS
VrSeek(
IN ULONG FileId,
IN PLARGE_INTEGER Offset,
IN SEEK_MODE SeekMode
)
{
LONG Status;
debug(VRDBG_RDWR, "VrSeek: Entry - FileId: %d Offset: %x.%x Mode: %x\n",
FileId, Offset->HighPart, Offset->LowPart, SeekMode);
if (FileId >= FILE_TABLE_SIZE) {
return EBADF;
}
if (FileTable[FileId].Flags.Open != 1) {
return EACCES;
}
if (FileTable[FileId].Flags.Delete == 1) {
return EACCES;
}
if (!(SeekMode == SeekRelative || SeekMode == SeekAbsolute)) {
return EINVAL;
}
//
// If the specified device is Network, only set Offset into FileTable
// because the Offset is interpreted to be a count of input to ignore.
// The offset is cleared after reading the input packet.
//
if (FileTable[FileId].Flags.NetworkDevice == 1) {
(VOID)MoveLargeInt(&FileTable[FileId].Position, Offset);
return ESUCCESS;
}
//
// Set the file position according to SeekMode.
//
if (SeekMode == SeekRelative) {
(VOID)AddLargeInt(&FileTable[FileId].Position, Offset);
} else {
(VOID)MoveLargeInt(&FileTable[FileId].Position, Offset);
}
//
// If FileId is for Network device, the input packets are ignored
// according to Offset and then return with ESUCCESS.
//
if (FileTable[FileId].Flags.NetworkDevice == 1) {
while (IsLarge(&FileTable[FileId].Position) == NOT_ZERO_LARGE) {
LONG ReadSize;
CHAR Buffer[4];
if ((ReadSize = OFRead(FileTable[FileId].IHandle, Buffer, 1))
== -1) {
return EIO;
}
if (ReadSize == 0) {
continue;
}
DecrementLarge(&FileTable[FileId].Position);
}
return ESUCCESS;
}
Status = OFSeek(FileTable[FileId].IHandle,
FileTable[FileId].Position.HighPart,
FileTable[FileId].Position.LowPart);
if (Status == -1) {
return EINVAL; // XXXX
}
debug(VRDBG_RDWR, "VrSeek: Exit\n");
return ESUCCESS;
}
/*
* Name: VrGetDirectoryEntry
*
* Description:
* This function reads directory entries from the system partition
* directory file specified by FileId.
*
* Arguments:
* FileId - Supplies the file table index.
* Buffer - Supplies a pointer to a buffer for the entry data.
* Length - Supplies the number of entries to retrieve.
* Count - Supplies a pointeer to the number of entries read
* into the buffer.
*
* Return Value:
* If the specified file is open for read, then the read is attempted
* and the status is returned. Otherwise, retrun an unsuccessful status.
*
*/
ARC_STATUS
VrGetDirectoryEntry(
IN ULONG FileId,
OUT PDIRECTORY_ENTRY Buffer,
IN ULONG Length,
OUT PULONG Count
)
{
debug(VRDBG_OPEN, "VrGetDirectoryEntry: Entry - FileId: %d Length: %d\n",
FileId, Length);
if (FileId >= FILE_TABLE_SIZE) {
return EBADF;
}
if (FileTable[FileId].Flags.Device) {
return ENOTDIR;
}
if (!(FileTable[FileId].Flags.Open == 1
&& FileTable[FileId].Flags.Read == 1)) {
return EBADF;
}
// XXXX
// Get Director Entry if (FileID != directory) return ENOTDIR;
debug(VRDBG_OPEN, "VrGetDirectoryEntry: Exit\n");
return ESUCCESS;
}
/*
* Name: VrGetFileInformation
*
* Description:
* This function retunrs an information structure about the specified
* file or partition.
*
* Arguments:
* FileId - Supplies the file table index.
* FileInformation - Supplies a pointer to the location of the file
* information data.
*
* Return Value:
* If the specified file is open, then getting the file information is
* attempted and the status is returned. Otherwise, retrun an unsuccessful
* status.
*
*/
ARC_STATUS
VrGetFileInformation(
IN ULONG FileId,
OUT PFILE_INFORMATION pFI
)
{
PFILE_TABLE_ENTRY fte;
ihandle ih;
PCONFIGURATION_NODE node;
ULONG size_thang[2];
debug(VRDBG_OPEN, "VrGetFileInformation: Entry - FileId: %d\n", FileId);
if (FileId >= FILE_TABLE_SIZE) {
debug(VRDBG_OPEN, "VrGetFileInformation: Exit EBADF\n");
return EBADF;
}
fte = &FileTable[FileId];
if (fte->Flags.Open != 1) {
debug(VRDBG_OPEN, "VrGetFileInformation: Exit EACCES\n");
return EACCES;
}
if (fte->Flags.Device == 1) {
debug(VRDBG_OPEN, "VrGetFileInformation: Exit EINVAL\n");
return EINVAL;
}
ih = fte->IHandle;
node = InstanceToNode(ih);
pFI->CurrentPosition = fte->Position;
pFI->Type = node->Component.Type;
(void) OFCallMethod(2, 2, size_thang, "size", ih);
pFI->EndingAddress.HighPart = size_thang[0];
pFI->EndingAddress.LowPart = size_thang[1];
if (fte->Flags.Partition == 1) {
(void) OFCallMethod( 1, 2, &(pFI->StartingAddress.HighPart),
"offset-high", ih);
(void) OFCallMethod( 1, 2, &(pFI->StartingAddress.LowPart),
"offset-low", ih);
AddLargeInt(&pFI->EndingAddress, &pFI->StartingAddress);
pFI->FileName[0] = '\0';
pFI->FileNameLength = 0;
} else {
/*
* It's a file.
*/
pFI->StartingAddress.HighPart = 0;
pFI->StartingAddress.LowPart = 0;
strcpy(pFI->FileName, fte->PathName); // XXX s.b. strncpy(&,&,32)
pFI->FileNameLength = strlen(fte->PathName) + 1;
}
#ifdef XXX
pFI->Attributes = // Get this from the firmware, somehow.
#endif
debug(VRDBG_OPEN, "VrGetFileInformation:\n");
debug(VRDBG_OPEN, "\tStarting %x.%x\n", pFI->StartingAddress.HighPart,
pFI->StartingAddress.LowPart);
debug(VRDBG_OPEN, "\tEnding %x.%x\n", pFI->EndingAddress.HighPart,
pFI->EndingAddress.LowPart);
debug(VRDBG_OPEN, "\tCurrent %x.%x\n", pFI->CurrentPosition.HighPart,
pFI->CurrentPosition.LowPart);
debug(VRDBG_OPEN, "\tType %d FileNameLength %d\n", pFI->Type,
pFI->FileNameLength);
debug(VRDBG_OPEN, "\tFileName '%s'\n",
pFI->FileNameLength ? pFI->FileName : "NULL");
return ESUCCESS;
}
/*
* Name: VrGetReadStatus
*
* Description:
* This function determines if any bytes would be returned if a read
* operation were performed on FileId.
*
* Arguments:
* FileId - Supplies the file table index.
*
* Return Value:
* If the specified file is open, then the getting read status is
* attempted and the status is returned. Otherwise, retrun an unsuccessful
* status.
*
*/
ARC_STATUS
VrGetReadStatus(
IN ULONG FileId
)
{
LONG Count;
if (FileId == 0) { // stdin
if (consin_readahead != 0) {
return (ESUCCESS);
}
if (ConsoleIn == 0) {
(void) VrFindConsolePath("stdin");
}
if (OFRead(ConsoleIn, &consin_readahead, 1) != 1) {
return (EAGAIN);
}
return (ESUCCESS);
}
debug(VRDBG_RDWR, "VrGetReadStatus: Entry - FileId: %d\n", FileId);
if (FileId >= FILE_TABLE_SIZE) {
return EBADF;
}
if (!(FileTable[FileId].Flags.Open == 1
&& FileTable[FileId].Flags.Read == 1)) {
return EACCES;
}
if (FileTable[FileId].Flags.Delete == 1) {
return EACCES;
}
//
// Try to read one byte.
//
Count = OFRead(FileTable[FileId].IHandle,
FileTable[FileId].ReadAheadBuffer,
1);
if (Count != 1) {
FileTable[FileId].ReadAheadCount = 0; // For safety.
debug(VRDBG_RDWR, "VrGetReadStatus: Exit - with EAGAIN\n");
return EAGAIN;
}
//
// Now read ahead one byte.
//
FileTable[FileId].ReadAheadCount = 1;
if (FileId >= 2) {
debug(VRDBG_RDWR, "VrGetReadStatus: Exit\n");
}
return ESUCCESS;
}
/*
* Name: VrSetFileInformation
*
* Description:
* This function sets the file attributes for the specified FileId.
*
* Arguments:
* FileId - Supplies the file table index.
* AttributeFlags - Supplies the attributes to be set for the file.
* AttributeMask - Supplies the attribute Mask.
*
* Return Value:
* If the specified file is open, then the setting file information is
* attempted and the status is returned. Otherwise, retrun an unsuccessful
* status.
*
*/
ARC_STATUS
VrSetFileInformation(
IN ULONG FileId,
IN ULONG AttributeFlags,
IN ULONG AttributeMask
)
{
debug(VRDBG_OPEN, "VrSetFileInformation: Entry - FileId: %d AttributeFlags: %x AttributeMask: %x\n",
FileId, AttributeFlags, AttributeMask);
if (FileId >= FILE_TABLE_SIZE) {
return EBADF;
}
if (!(FileTable[FileId].Flags.Open == 1)) {
return EACCES;
}
if (FileTable[FileId].Flags.Device == 1) {
return EINVAL;
}
//
// The attribute DirectoryFile is ignored for this function.
//
AttributeMask &= ~ArcDirectoryFile;
//
// A file is marked for deletion by setting the DeleteFile flag
// in voth the AttributeFlags and AttributeMask parameters.
// In this case, the file can be access only by Close().
//
if ((AttributeMask & ArcDeleteFile) && (AttributeFlags & ArcDeleteFile)) {
//
// When the file is a derectroy which is not empty or a read-only file,
// EACCESS is retuned.
//
// XXXX not empy check is needed
//
if (!(FileTable[FileId].Flags.Read == 1
&& FileTable[FileId].Flags.Write == 0)) {
return EACCES;
}
FileTable[FileId].Flags.Delete = 1;
}
// XXX return OFSetFileInformation(FileId, Buffer, Length, Count);
debug(VRDBG_OPEN, "VrSetFileInformation: Exit\n");
return(ESUCCESS);
}
/*
* Name: VrIoInitialize
*
* Description:
* This function initializes the I/O entry points in the firmware
* transfer vector and the file table.
*
* Arguments:
* None.
*
* Return Value:
* None.
*
*/
VOID
VrIoInitialize(
VOID
)
{
ULONG Index;
//
// Initialize the I/O entry points in the firmware transfer vector.
//
debug(VRDBG_ENTRY, "VrIoInitialize BEGIN......\n");
(PARC_CLOSE_ROUTINE) SYSTEM_BLOCK->FirmwareVector[CloseRoutine] = VrClose;
(PARC_MOUNT_ROUTINE) SYSTEM_BLOCK->FirmwareVector[MountRoutine] = VrMount;
(PARC_OPEN_ROUTINE) SYSTEM_BLOCK->FirmwareVector[OpenRoutine] = VrOpen;
(PARC_READ_ROUTINE) SYSTEM_BLOCK->FirmwareVector[ReadRoutine] = VrRead;
(PARC_SEEK_ROUTINE) SYSTEM_BLOCK->FirmwareVector[SeekRoutine] = VrSeek;
(PARC_WRITE_ROUTINE) SYSTEM_BLOCK->FirmwareVector[WriteRoutine] = VrWrite;
(PARC_READ_STATUS_ROUTINE)
SYSTEM_BLOCK->FirmwareVector[ReadStatusRoutine] = VrGetReadStatus;
(PARC_GET_FILE_INFO_ROUTINE)
SYSTEM_BLOCK->FirmwareVector[GetFileInformationRoutine] =
VrGetFileInformation;
(PARC_SET_FILE_INFO_ROUTINE)
SYSTEM_BLOCK->FirmwareVector[SetFileInformationRoutine] =
VrSetFileInformation;
(PARC_GET_DIRECTORY_ENTRY_ROUTINE)
SYSTEM_BLOCK->FirmwareVector[GetDirectoryEntryRoutine] =
VrGetDirectoryEntry;
//
// Initialize the file table.
//
for (Index = 0; Index < FILE_TABLE_SIZE; Index++) {
FileTable[Index].Flags.Open = 0;
}
debug(VRDBG_ENTRY, "VrIoInitialize ......END\n");
return;
}
/*
* Name: GetFileTableEntry (internal)
*
* Description:
* This function looks for an unused entry in the FileTable.
*
* Arguments:
* Entry - Pointer to the variable that gets an index
* for the file table.
*
* Return Value:
*
* Returns ESUCCESS if a free entry is found
* or EMFILE if no entry is available.
*
*/
STATIC ARC_STATUS
GetFileTableEntry(
OUT PULONG Entry
)
{
ULONG Index;
for (Index = 2; Index < FILE_TABLE_SIZE; Index++) {
if (FileTable[Index].Flags.Open == 0) {
#ifdef notdef
FileTable[Index].Position.LowPart = 0;
FileTable[Index].Position.HighPart = 0;
#endif // notdef
bzero((PCHAR)&FileTable[Index], sizeof(FILE_TABLE_ENTRY));
*Entry = Index;
return ESUCCESS;
}
}
return EMFILE;
}
/*
* Name: GetDeviceAttribute (internal)
*
* Description:
* This function sets the specified File Table entry to the attribute.
*
* Arguments:
* FileId - Supplies the file table index.
* ConfNode - Supplies a pointer to the Configuration Node.
*
* Return Value:
* If the Configuration node is not peripheral, then return ENODEV.
* Otherwise, returns ESUCCESS.
*
*/
STATIC ARC_STATUS
GetDeviceAttribute(
IN ULONG FileId,
IN PCONFIGURATION_NODE ConfNode
)
{
if (ConfNode->Component.Class != PeripheralClass) {
warn("GetDeviceAttribute: node %s(%d) not PeripheralClass.\n",
ConfNode->ComponentName, ConfNode->Component.Key);
return ENODEV;
}
if (ConfNode->Component.Type == MonitorPeripheral) {
FileTable[FileId].Flags.DisplayDevice = 1;
}
if (ConfNode->Component.Flags.Removable) {
FileTable[FileId].Flags.RemovableDevice = 1;
}
if (ConfNode->Component.Type == NetworkPeripheral) {
FileTable[FileId].Flags.NetworkDevice = 1;
}
if (ConfNode->Component.Flags.Input) {
FileTable[FileId].Flags.Read = 1;
}
if (ConfNode->Component.Flags.Output &&
!(ConfNode->Component.Flags.ReadOnly)) {
FileTable[FileId].Flags.Write = 1;
}
return ESUCCESS;
}
/*
* Name: AddLargeInt (internal)
*
* Description:
* This function adds a large integer into another large ingeger.
*
* Arguments:
* Position - Supplies a pointer to a variable to be added.
* Value - Supplies a pointer to a variable to add.
*
* Return Value:
* None.
*
*/
STATIC VOID
AddLargeInt(
PLARGE_INTEGER Position,
PLARGE_INTEGER Value
)
{
if ((Position->LowPart += Value->LowPart) < Value->LowPart) {
Position->HighPart++;
}
Position->HighPart += Value->HighPart;
}
/*
* Name: DecrementLarge (internal)
*
* Description:
* This function decrements a large integer.
*
* Arguments:
* Position - Supplies a pointer to a variable to be decremented.
*
* Return Value:
* None.
*
*/
STATIC VOID
DecrementLarge(
PLARGE_INTEGER Position
)
{
ULONG ULong = Position->LowPart;
Position->LowPart--;
if (Position->LowPart > ULong) {
Position->HighPart--;
}
}
/*
* Name: MoveLargeInt (internal)
*
* Description:
* This function copies a large integer into another large ingeger.
*
* Arguments:
* Position - Supplies a pointer to a variable to be copied.
* Value - Supplies a pointer to a variable to copy.
*
* Return Value:
* None.
*
*/
STATIC VOID
MoveLargeInt(
PLARGE_INTEGER Position,
PLARGE_INTEGER Value
)
{
Position->LowPart = Value->LowPart;
Position->HighPart = Value->HighPart;
}
/*
* Name: IsLarge (internal)
*
* Description:
* This function determines whether a large integer contains zero.
*
* Arguments:
* Position - Supplies a pointer to a variable to be checked.
*
* Return Value:
* If the large integer is zero, then returns ZERO_LARGE. Otherwise,
* returns NOT_ZERO_LARGE.
*
*/
STATIC LONG
IsLarge(
PLARGE_INTEGER Position
)
{
if (Position->LowPart != 0) {
return NOT_ZERO_LARGE;
}
if (Position->HighPart != 0) {
return NOT_ZERO_LARGE;
}
return ZERO_LARGE;
}