mirror of https://github.com/acidanthera/audk.git
1276 lines
40 KiB
C
1276 lines
40 KiB
C
/** @file
|
|
EFI versions of NetBSD system calls.
|
|
|
|
Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
|
|
This program and the accompanying materials are licensed and made available under
|
|
the terms and conditions of the BSD License that accompanies this distribution.
|
|
The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
**/
|
|
#include <Uefi.h>
|
|
#include <Library/UefiLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/MemoryAllocationLib.h>
|
|
#include <Library/ShellLib.h>
|
|
|
|
#include <LibConfig.h>
|
|
#include <sys/EfiCdefs.h>
|
|
|
|
#include <sys/ansi.h>
|
|
#include <errno.h>
|
|
#include <stdarg.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <wchar.h>
|
|
#include <sys/poll.h>
|
|
#include <sys/fcntl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/syslimits.h>
|
|
#include <sys/filio.h>
|
|
#include <Efi/SysEfi.h>
|
|
#include <unistd.h>
|
|
#include <kfile.h>
|
|
#include <Device/Device.h>
|
|
#include <MainData.h>
|
|
#include <extern.h>
|
|
|
|
/* EFI versions of BSD system calls used in stdio */
|
|
|
|
/* Validate that fd refers to a valid file descriptor.
|
|
IsOpen is interpreted as follows:
|
|
- Positive fd must be OPEN
|
|
- Zero fd must be CLOSED
|
|
- Negative fd may be OPEN or CLOSED
|
|
|
|
@retval TRUE fd is VALID
|
|
@retval FALSE fd is INVALID
|
|
*/
|
|
BOOLEAN
|
|
ValidateFD( int fd, int IsOpen)
|
|
{
|
|
struct __filedes *filp;
|
|
BOOLEAN retval = FALSE;
|
|
|
|
if((fd >= 0) && (fd < OPEN_MAX)) {
|
|
filp = &gMD->fdarray[fd];
|
|
retval = TRUE;
|
|
if(IsOpen >= 0) {
|
|
retval = (BOOLEAN)((filp->f_iflags != 0) && // TRUE if OPEN
|
|
FILE_IS_USABLE(filp)); // and Usable (not Larval or Closing)
|
|
if(IsOpen == VALID_CLOSED) {
|
|
retval = (BOOLEAN)!retval; // We want TRUE if CLOSED
|
|
}
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/* Find and reserve a free File Descriptor.
|
|
|
|
Returns the first free File Descriptor greater than or equal to the,
|
|
already validated, fd specified by Minfd.
|
|
|
|
@return Returns -1 if there are no free FDs. Otherwise returns the
|
|
found fd.
|
|
*/
|
|
int
|
|
FindFreeFD( int MinFd )
|
|
{
|
|
struct __filedes *Mfd;
|
|
int i;
|
|
int fd = -1;
|
|
|
|
Mfd = gMD->fdarray;
|
|
|
|
// Get an available fd
|
|
for(i=MinFd; i < OPEN_MAX; ++i) {
|
|
if(Mfd[i].f_iflags == 0) {
|
|
Mfd[i].f_iflags = FIF_LARVAL; // Temporarily mark this fd as reserved
|
|
fd = i;
|
|
break;
|
|
}
|
|
}
|
|
return fd;
|
|
}
|
|
|
|
/* Mark that an open file is to be deleted when closed. */
|
|
int
|
|
DeleteOnClose(int fd)
|
|
{
|
|
int retval = 0;
|
|
|
|
if(ValidateFD( fd, VALID_OPEN)) {
|
|
gMD->fdarray[fd].f_iflags |= FIF_DELCLOSE;
|
|
}
|
|
else {
|
|
errno = EBADF;
|
|
retval = -1;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/** The isatty() function tests whether fildes, an open file descriptor,
|
|
is associated with a terminal device.
|
|
|
|
@retval 1 fildes is associated with a terminal.
|
|
@retval 0 fildes is not associated with a terminal. errno is set to
|
|
EBADF if fildes is not a valid open FD.
|
|
**/
|
|
int
|
|
isatty (int fd)
|
|
{
|
|
int retval = 0;
|
|
struct __filedes *Fp;
|
|
|
|
if(ValidateFD( fd, VALID_OPEN)) {
|
|
Fp = &gMD->fdarray[fd];
|
|
retval = Fp->f_iflags & _S_ITTY;
|
|
}
|
|
else {
|
|
errno = EBADF;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/** Determine if file descriptor fd is a duplicate of some other fd.
|
|
|
|
@param[in] fd The file descriptor to check.
|
|
|
|
@retval TRUE fd is a duplicate of another fd.
|
|
@retval FALSE fd is unique.
|
|
**/
|
|
static BOOLEAN
|
|
IsDupFd( int fd)
|
|
{
|
|
void * DevData;
|
|
const struct fileops *FileOps;
|
|
int i;
|
|
BOOLEAN Ret = FALSE;
|
|
|
|
if(ValidateFD( fd, VALID_OPEN )) {
|
|
FileOps = gMD->fdarray[fd].f_ops;
|
|
DevData = gMD->fdarray[fd].devdata;
|
|
for(i=0; i < OPEN_MAX; ++i) {
|
|
if(i == fd) continue;
|
|
if(ValidateFD( i, VALID_OPEN )) { // TRUE if fd is valid and OPEN
|
|
if((gMD->fdarray[i].f_ops == FileOps)
|
|
&&(gMD->fdarray[i].devdata == DevData )) {
|
|
Ret = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return Ret;
|
|
}
|
|
|
|
/** Close a file and set its fd to the specified state.
|
|
|
|
@param[in] fd The file descriptor to close.
|
|
@param[in] NewState State to set the fd to after the file is closed.
|
|
|
|
@retval 0 The operation completed successfully.
|
|
@retval -1 The operation failed. Further information is in errno.
|
|
**/
|
|
static int
|
|
_closeX (int fd, int NewState)
|
|
{
|
|
struct __filedes *Fp;
|
|
int retval = 0;
|
|
|
|
// Verify my pointers and get my FD.
|
|
if(ValidateFD( fd, VALID_OPEN )) {
|
|
Fp = &gMD->fdarray[fd];
|
|
// Check if there are other users of this FileHandle
|
|
if(Fp->RefCount == 1) { // There should be no other users
|
|
if(! IsDupFd(fd)) {
|
|
// Only do the close if no one else is using the FileHandle
|
|
if(Fp->f_iflags & FIF_DELCLOSE) {
|
|
/* Handle files marked "Delete on Close". */
|
|
if(Fp->f_ops->fo_delete != NULL) {
|
|
retval = Fp->f_ops->fo_delete(Fp);
|
|
}
|
|
}
|
|
else {
|
|
retval = Fp->f_ops->fo_close( Fp);
|
|
}
|
|
}
|
|
Fp->f_iflags = NewState; // Close this FD or reserve it
|
|
Fp->RefCount = 0; // No one using this FD
|
|
}
|
|
else {
|
|
--Fp->RefCount; /* One less user of this FD */
|
|
}
|
|
}
|
|
else {
|
|
// Bad FD
|
|
retval = -1;
|
|
errno = EBADF;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/** The close() function deallocates the file descriptor indicated by fd.
|
|
To deallocate means to make the file descriptor available for return by
|
|
subsequent calls to open() or other functions that allocate file
|
|
descriptors. All outstanding record locks owned by the process on the file
|
|
associated with the file descriptor are removed (that is, unlocked).
|
|
|
|
@retval 0 Successful completion.
|
|
@retval -1 An error occurred and errno is set to identify the error.
|
|
**/
|
|
int
|
|
close (int fd)
|
|
{
|
|
return _closeX(fd, 0);
|
|
}
|
|
|
|
/**
|
|
**/
|
|
int
|
|
unlink (const char *path)
|
|
{
|
|
struct __filedes *Fp;
|
|
int fd;
|
|
int retval = -1;
|
|
|
|
EFIerrno = RETURN_SUCCESS;
|
|
|
|
fd = open(path, O_WRONLY, 0);
|
|
if(fd >= 0) {
|
|
Fp = &gMD->fdarray[fd];
|
|
|
|
if(Fp->f_ops->fo_delete != NULL) {
|
|
retval = Fp->f_ops->fo_delete(Fp);
|
|
}
|
|
Fp->f_iflags = 0; // Close this FD
|
|
Fp->RefCount = 0; // No one using this FD
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/** The fcntl() function shall perform the operations described below on open
|
|
files. The fildes argument is a file descriptor.
|
|
|
|
The available values for cmd are defined in <fcntl.h> and are as follows:
|
|
- F_DUPFD - Return a new file descriptor which shall be the lowest
|
|
numbered available (that is, not already open) file
|
|
descriptor greater than or equal to the third argument, arg,
|
|
taken as an integer of type int. The new file descriptor
|
|
shall refer to the same open file description as the original
|
|
file descriptor, and shall share any locks. The FD_CLOEXEC
|
|
flag associated with the new file descriptor shall be cleared
|
|
to keep the file open across calls to one of the exec functions.
|
|
- F_GETFD - Get the file descriptor flags defined in <fcntl.h> that are
|
|
associated with the file descriptor fildes. File descriptor
|
|
flags are associated with a single file descriptor and do not
|
|
affect other file descriptors that refer to the same file.
|
|
- F_SETFD - Set the file descriptor flags defined in <fcntl.h>, that are
|
|
associated with fildes, to the third argument, arg, taken
|
|
as type int. If the FD_CLOEXEC flag in the third argument
|
|
is 0, the file shall remain open across the exec
|
|
functions; otherwise, the file shall be closed upon
|
|
successful execution of one of the exec functions.
|
|
- F_GETFL - Get the file status flags and file access modes, defined in
|
|
<fcntl.h>, for the file description associated with fildes.
|
|
The file access modes can be extracted from the return
|
|
value using the mask O_ACCMODE, which is defined in
|
|
<fcntl.h>. File status flags and file access modes are
|
|
associated with the file description and do not affect
|
|
other file descriptors that refer to the same file with
|
|
different open file descriptions.
|
|
- F_SETFL - Set the file status flags, defined in <fcntl.h>, for the file
|
|
description associated with fildes from the corresponding
|
|
bits in the third argument, arg, taken as type int. Bits
|
|
corresponding to the file access mode and the file creation
|
|
flags, as defined in <fcntl.h>, that are set in arg shall
|
|
be ignored. If any bits in arg other than those mentioned
|
|
here are changed by the application, the result is unspecified.
|
|
- F_GETOWN - If fildes refers to a socket, get the process or process group
|
|
ID specified to receive SIGURG signals when out-of-band
|
|
data is available. Positive values indicate a process ID;
|
|
negative values, other than -1, indicate a process group
|
|
ID. If fildes does not refer to a socket, the results are
|
|
unspecified.
|
|
- F_SETOWN - If fildes refers to a socket, set the process or process
|
|
group ID specified to receive SIGURG signals when
|
|
out-of-band data is available, using the value of the third
|
|
argument, arg, taken as type int. Positive values indicate
|
|
a process ID; negative values, other than -1, indicate a
|
|
process group ID. If fildes does not refer to a socket, the
|
|
results are unspecified.
|
|
|
|
The fcntl() function shall fail if:
|
|
|
|
[EBADF] The fildes argument is not a valid open file descriptor.
|
|
[EINVAL] The cmd argument is invalid, or the cmd argument is F_DUPFD
|
|
and arg is negative or greater than or equal to {OPEN_MAX}.
|
|
[EMFILE] The argument cmd is F_DUPFD and {OPEN_MAX} file descriptors
|
|
are currently open in the calling process, or no file
|
|
descriptors greater than or equal to arg are available.
|
|
[EOVERFLOW] One of the values to be returned cannot be represented correctly.
|
|
|
|
@return Upon successful completion, the value returned shall depend on
|
|
cmd as follows:
|
|
- F_DUPFD - A new file descriptor.
|
|
- F_GETFD - Value of flags defined in <fcntl.h>. The return value
|
|
shall not be negative.
|
|
- F_SETFD - Value other than -1.
|
|
- F_GETFL - Value of file status flags and access modes. The return
|
|
value is not negative.
|
|
- F_SETFL - Value other than -1.
|
|
- F_GETOWN - Value of the socket owner process or process group;
|
|
this will not be -1.
|
|
- F_SETOWN - Value other than -1.
|
|
Otherwise, -1 shall be returned and errno set to indicate the error.
|
|
|
|
**/
|
|
int
|
|
fcntl (int fildes, int cmd, ...)
|
|
{
|
|
va_list p3;
|
|
struct __filedes *MyFd;
|
|
int retval = -1;
|
|
int temp;
|
|
|
|
//Print(L"%a( %d, %d, ...)\n", __func__, fildes, cmd);
|
|
va_start(p3, cmd);
|
|
|
|
if(ValidateFD( fildes, VALID_OPEN )) {
|
|
MyFd = &gMD->fdarray[fildes];
|
|
|
|
switch(cmd) {
|
|
case F_DUPFD:
|
|
temp = va_arg(p3, int);
|
|
if(ValidateFD( temp, VALID_DONT_CARE )) {
|
|
temp = FindFreeFD( temp );
|
|
if(temp < 0) {
|
|
errno = EMFILE;
|
|
break;
|
|
}
|
|
/* temp is now a valid fd reserved for further use
|
|
so copy fd into temp.
|
|
*/
|
|
(void)memcpy(&gMD->fdarray[temp], MyFd, sizeof(struct __filedes));
|
|
retval = temp;
|
|
}
|
|
else {
|
|
errno = EINVAL;
|
|
}
|
|
break;
|
|
|
|
case F_SETFL:
|
|
retval = MyFd->Oflags; // Get original value
|
|
temp = va_arg(p3, int);
|
|
temp &= O_SETMASK; // Only certain bits can be set
|
|
temp |= retval & O_SETMASK;
|
|
MyFd->Oflags = temp; // Set new value
|
|
break;
|
|
|
|
case F_SETFD:
|
|
retval = MyFd->f_iflags;
|
|
break;
|
|
//case F_SETOWN:
|
|
// retval = MyFd->SocProc;
|
|
// MyFd->SocProc = va_arg(p3, int);
|
|
// break;
|
|
case F_GETFD:
|
|
retval = MyFd->f_iflags;
|
|
break;
|
|
case F_GETFL:
|
|
retval = MyFd->Oflags;
|
|
break;
|
|
//case F_GETOWN:
|
|
// retval = MyFd->SocProc;
|
|
// break;
|
|
default:
|
|
errno = EINVAL;
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
// Bad FD
|
|
errno = EBADF;
|
|
}
|
|
va_end(p3);
|
|
return retval;;
|
|
}
|
|
|
|
/** The dup() function provides an alternative interface to the
|
|
service provided by fcntl() using the F_DUPFD command. The call:
|
|
- fid = dup(fildes);
|
|
shall be equivalent to:
|
|
- fid = fcntl(fildes, F_DUPFD, 0);
|
|
|
|
@return Upon successful completion a non-negative integer, namely the
|
|
file descriptor, shall be returned; otherwise, -1 shall be
|
|
returned and errno set to indicate the error.
|
|
**/
|
|
int
|
|
dup (int fildes)
|
|
{
|
|
return fcntl(fildes, F_DUPFD, 0);
|
|
}
|
|
|
|
/** The dup2() function provides an alternative interface to the
|
|
service provided by fcntl() using the F_DUPFD command. The call:
|
|
- fid = dup2(fildes, fildes2);
|
|
shall be equivalent to:
|
|
- close(fildes2);
|
|
- fid = fcntl(fildes, F_DUPFD, fildes2);
|
|
except for the following:
|
|
- If fildes2 is less than 0 or greater than or equal to {OPEN_MAX},
|
|
dup2() shall return -1 with errno set to [EBADF].
|
|
- If fildes is a valid file descriptor and is equal to fildes2, dup2()
|
|
shall return fildes2 without closing it.
|
|
- If fildes is not a valid file descriptor, dup2() shall return -1 and
|
|
shall not close fildes2.
|
|
- The value returned shall be equal to the value of fildes2 upon
|
|
successful completion, or -1 upon failure.
|
|
|
|
@return Upon successful completion a non-negative integer, namely
|
|
fildes2, shall be returned; otherwise, -1 shall be
|
|
returned and errno set to EBADF indicate the error.
|
|
**/
|
|
int
|
|
dup2 (int fildes, int fildes2)
|
|
{
|
|
int retval = -1;
|
|
|
|
if(ValidateFD( fildes, VALID_OPEN)) {
|
|
retval = fildes2;
|
|
if( fildes != fildes2) {
|
|
if(ValidateFD( fildes2, VALID_DONT_CARE)) {
|
|
gMD->fdarray[fildes2].f_iflags = FIF_LARVAL; // Mark the file closed, but reserved
|
|
(void)memcpy(&gMD->fdarray[fildes2], // Duplicate fildes into fildes2
|
|
&gMD->fdarray[fildes], sizeof(struct __filedes));
|
|
gMD->fdarray[fildes2].MyFD = (UINT16)fildes2;
|
|
}
|
|
else {
|
|
errno = EBADF;
|
|
retval = -1;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
errno = EBADF;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/** Reposition a file's read/write offset.
|
|
|
|
The lseek() function repositions the offset of the file descriptor fildes
|
|
to the argument offset according to the directive how. The argument
|
|
fildes must be an open file descriptor. lseek() repositions the file
|
|
pointer fildes as follows:
|
|
|
|
If how is SEEK_SET, the offset is set to offset bytes.
|
|
|
|
If how is SEEK_CUR, the offset is set to its current location
|
|
plus offset bytes.
|
|
|
|
If how is SEEK_END, the offset is set to the size of the file
|
|
plus offset bytes.
|
|
|
|
The lseek() function allows the file offset to be set beyond the end of
|
|
the existing end-of-file of the file. If data is later written at this
|
|
point, subsequent reads of the data in the gap return bytes of zeros
|
|
(until data is actually written into the gap).
|
|
|
|
Some devices are incapable of seeking. The value of the pointer associ-
|
|
ated with such a device is undefined.
|
|
|
|
@return Upon successful completion, lseek() returns the resulting offset
|
|
location as measured in bytes from the beginning of the file.
|
|
Otherwise, a value of -1 is returned and errno is set to
|
|
indicate the error.
|
|
**/
|
|
__off_t
|
|
lseek (int fd, __off_t offset, int how)
|
|
{
|
|
__off_t CurPos = -1;
|
|
// RETURN_STATUS Status = RETURN_SUCCESS;
|
|
struct __filedes *filp;
|
|
|
|
EFIerrno = RETURN_SUCCESS; // In case of error without an EFI call
|
|
|
|
if( how == SEEK_SET || how == SEEK_CUR || how == SEEK_END) {
|
|
if(ValidateFD( fd, VALID_OPEN)) {
|
|
filp = &gMD->fdarray[fd];
|
|
// Both of our parameters have been verified as valid
|
|
CurPos = filp->f_ops->fo_lseek( filp, offset, how);
|
|
if(CurPos >= 0) {
|
|
filp->f_offset = CurPos;
|
|
}
|
|
}
|
|
else {
|
|
errno = EBADF; // Bad File Descriptor
|
|
}
|
|
}
|
|
else {
|
|
errno = EINVAL; // Invalid how argument
|
|
}
|
|
return CurPos;
|
|
}
|
|
|
|
/** The directory path is created with the access permissions specified by
|
|
perms.
|
|
|
|
The directory is closed after it is created.
|
|
|
|
@retval 0 The directory was created successfully.
|
|
@retval -1 An error occurred and error codes are stored in errno and EFIerrno.
|
|
**/
|
|
int
|
|
mkdir (const char *path, __mode_t perms)
|
|
{
|
|
wchar_t *NewPath;
|
|
DeviceNode *Node;
|
|
char *GenI;
|
|
RETURN_STATUS Status;
|
|
int Instance = 0;
|
|
int retval = 0;
|
|
|
|
Status = ParsePath(path, &NewPath, &Node, &Instance, NULL);
|
|
if(Status == RETURN_SUCCESS) {
|
|
GenI = Node->InstanceList;
|
|
if(GenI == NULL) {
|
|
errno = EPERM;
|
|
retval = -1;
|
|
}
|
|
else {
|
|
//GenI += (Instance * Node->InstanceSize);
|
|
retval = ((GenericInstance *)GenI)->Abstraction.fo_mkdir( path, perms);
|
|
}
|
|
free(NewPath);
|
|
}
|
|
else {
|
|
retval = -1;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/** Open a file.
|
|
|
|
The EFI ShellOpenFileByName() function is used to perform the low-level
|
|
file open operation. The primary task of open() is to translate from the
|
|
flags used in the <stdio.h> environment to those used by the EFI function.
|
|
|
|
The only valid flag combinations for ShellOpenFileByName() are:
|
|
- Read
|
|
- Read/Write
|
|
- Create/Read/Write
|
|
|
|
The mode value is saved in the FD to indicate permissions for further operations.
|
|
|
|
O_RDONLY -- flags = EFI_FILE_MODE_READ -- this is always done
|
|
O_WRONLY -- flags |= EFI_FILE_MODE_WRITE
|
|
O_RDWR -- flags |= EFI_FILE_MODE_WRITE -- READ is already set
|
|
|
|
O_NONBLOCK -- ignored
|
|
O_APPEND -- Seek to EOF before every write
|
|
O_CREAT -- flags |= EFI_FILE_MODE_CREATE
|
|
O_TRUNC -- delete first then create new
|
|
O_EXCL -- if O_CREAT is also set, open will fail if the file already exists.
|
|
**/
|
|
int
|
|
open(
|
|
const char *path,
|
|
int oflags,
|
|
int mode
|
|
)
|
|
{
|
|
wchar_t *NewPath;
|
|
wchar_t *MPath;
|
|
DeviceNode *Node;
|
|
struct __filedes *filp;
|
|
int Instance = 0;
|
|
RETURN_STATUS Status;
|
|
UINT64 OpenMode;
|
|
int fd = -1;
|
|
int doresult;
|
|
|
|
Status = ParsePath(path, &NewPath, &Node, &Instance, &MPath);
|
|
if(Status == RETURN_SUCCESS) {
|
|
if((Node == NULL) ||
|
|
(Node->InstanceList == NULL)) {
|
|
errno = EPERM;
|
|
}
|
|
else {
|
|
// Could add a test to see if the file name begins with a period.
|
|
// If it does, then add the HIDDEN flag to Attributes.
|
|
|
|
// Get an available fd
|
|
fd = FindFreeFD( VALID_CLOSED );
|
|
|
|
if( fd < 0 ) {
|
|
// All available FDs are in use
|
|
errno = EMFILE;
|
|
}
|
|
else {
|
|
filp = &gMD->fdarray[fd];
|
|
// Save the flags and mode in the File Descriptor
|
|
filp->Oflags = oflags;
|
|
filp->Omode = mode;
|
|
|
|
doresult = Node->OpenFunc(Node, filp, Instance, NewPath, MPath);
|
|
if(doresult < 0) {
|
|
filp->f_iflags = 0; // Release this FD
|
|
fd = -1; // Indicate an error
|
|
}
|
|
else {
|
|
// Re-use OpenMode in order to build our final f_iflags value
|
|
OpenMode = ( mode & S_ACC_READ ) ? S_ACC_READ : 0;
|
|
OpenMode |= ( mode & S_ACC_WRITE ) ? S_ACC_WRITE : 0;
|
|
|
|
filp->f_iflags |= (UINT32)OpenMode;
|
|
++filp->RefCount;
|
|
FILE_SET_MATURE(filp);
|
|
}
|
|
}
|
|
}
|
|
if(NewPath != NULL) {
|
|
free(NewPath);
|
|
}
|
|
}
|
|
if(MPath != NULL) {
|
|
free(MPath); // We don't need this any more.
|
|
}
|
|
// return the fd of our now open file
|
|
return fd;
|
|
}
|
|
|
|
|
|
/**
|
|
Poll a list of file descriptors.
|
|
|
|
The ::poll routine waits for up to timeout milliseconds for an event
|
|
to occur on one or more of the file descriptors listed. The event
|
|
types of interested are specified for each file descriptor in the events
|
|
field. The actual event detected is returned in the revents field of
|
|
the array. The
|
|
<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">POSIX</a>
|
|
documentation is available online.
|
|
|
|
@param [in] pfd Address of an array of pollfd structures.
|
|
|
|
@param [in] nfds Number of elements in the array of pollfd structures.
|
|
|
|
@param [in] timeout Length of time in milliseconds to wait for the event
|
|
|
|
@return The number of file descriptors with detected events. Zero
|
|
indicates that the call timed out and -1 indicates an error.
|
|
|
|
**/
|
|
int
|
|
poll (
|
|
struct pollfd * pfd,
|
|
nfds_t nfds,
|
|
int timeout
|
|
)
|
|
{
|
|
struct __filedes * pDescriptor;
|
|
struct pollfd * pEnd;
|
|
struct pollfd * pPollFD;
|
|
int SelectedFDs;
|
|
EFI_STATUS Status;
|
|
EFI_EVENT Timer;
|
|
UINT64 TimerTicks;
|
|
|
|
//
|
|
// Create the timer for the timeout
|
|
//
|
|
Timer = NULL;
|
|
Status = EFI_SUCCESS;
|
|
if ( INFTIM != timeout ) {
|
|
Status = gBS->CreateEvent ( EVT_TIMER,
|
|
TPL_NOTIFY,
|
|
NULL,
|
|
NULL,
|
|
&Timer );
|
|
if ( !EFI_ERROR ( Status )) {
|
|
//
|
|
// Start the timeout timer
|
|
//
|
|
TimerTicks = timeout;
|
|
TimerTicks *= 1000 * 10;
|
|
Status = gBS->SetTimer ( Timer,
|
|
TimerRelative,
|
|
TimerTicks );
|
|
}
|
|
else {
|
|
SelectedFDs = -1;
|
|
errno = ENOMEM;
|
|
}
|
|
}
|
|
if ( !EFI_ERROR ( Status )) {
|
|
//
|
|
// Poll until an event is detected or the timer fires
|
|
//
|
|
SelectedFDs = 0;
|
|
errno = 0;
|
|
do {
|
|
//
|
|
// Poll the list of file descriptors
|
|
//
|
|
pPollFD = pfd;
|
|
pEnd = &pPollFD [ nfds ];
|
|
while ( pEnd > pPollFD ) {
|
|
//
|
|
// Validate the file descriptor
|
|
//
|
|
if ( !ValidateFD ( pPollFD->fd, VALID_OPEN )) {
|
|
errno = EINVAL;
|
|
return -1;
|
|
}
|
|
|
|
//
|
|
// Poll the device or file
|
|
//
|
|
pDescriptor = &gMD->fdarray [ pPollFD->fd ];
|
|
pPollFD->revents = pDescriptor->f_ops->fo_poll ( pDescriptor,
|
|
pPollFD->events );
|
|
|
|
//
|
|
// Determine if this file descriptor detected an event
|
|
//
|
|
if ( 0 != pPollFD->revents ) {
|
|
//
|
|
// Select this descriptor
|
|
//
|
|
SelectedFDs += 1;
|
|
}
|
|
|
|
//
|
|
// Set the next file descriptor
|
|
//
|
|
pPollFD += 1;
|
|
}
|
|
|
|
//
|
|
// Check for timeout
|
|
//
|
|
if ( NULL != Timer ) {
|
|
Status = gBS->CheckEvent ( Timer );
|
|
if ( EFI_SUCCESS == Status ) {
|
|
//
|
|
// Timeout
|
|
//
|
|
break;
|
|
}
|
|
else if ( EFI_NOT_READY == Status ) {
|
|
Status = EFI_SUCCESS;
|
|
}
|
|
}
|
|
} while (( 0 == SelectedFDs )
|
|
&& ( EFI_SUCCESS == Status ));
|
|
|
|
//
|
|
// Stop the timer
|
|
//
|
|
if ( NULL != Timer ) {
|
|
gBS->SetTimer ( Timer,
|
|
TimerCancel,
|
|
0 );
|
|
}
|
|
}
|
|
else {
|
|
SelectedFDs = -1;
|
|
errno = EAGAIN;
|
|
}
|
|
|
|
//
|
|
// Release the timer
|
|
//
|
|
if ( NULL != Timer ) {
|
|
gBS->CloseEvent ( Timer );
|
|
}
|
|
|
|
//
|
|
// Return the number of selected file system descriptors
|
|
//
|
|
return SelectedFDs;
|
|
}
|
|
|
|
|
|
/** The rename() function changes the name of a file.
|
|
The old argument points to the pathname of the file to be renamed. The new
|
|
argument points to the new pathname of the file.
|
|
|
|
If the old argument points to the pathname of a file that is not a
|
|
directory, the new argument shall not point to the pathname of a
|
|
directory. If the file named by the new argument exists, it shall be
|
|
removed and old renamed to new. Write access permission is required for
|
|
both the directory containing old and the directory containing new.
|
|
|
|
If the old argument points to the pathname of a directory, the new
|
|
argument shall not point to the pathname of a file that is not a
|
|
directory. If the directory named by the new argument exists, it shall be
|
|
removed and old renamed to new.
|
|
|
|
The new pathname shall not contain a path prefix that names old. Write
|
|
access permission is required for the directory containing old and the
|
|
directory containing new. If the old argument points to the pathname of a
|
|
directory, write access permission may be required for the directory named
|
|
by old, and, if it exists, the directory named by new.
|
|
|
|
If the rename() function fails for any reason other than [EIO], any file
|
|
named by new shall be unaffected.
|
|
|
|
@return Upon successful completion, rename() shall return 0; otherwise,
|
|
-1 shall be returned, errno shall be set to indicate the error,
|
|
and neither the file named by old nor the file named by new
|
|
shall be changed or created.
|
|
**/
|
|
int
|
|
rename(
|
|
const char *from,
|
|
const char *to
|
|
)
|
|
{
|
|
wchar_t *FromPath;
|
|
DeviceNode *FromNode;
|
|
char *GenI;
|
|
int Instance = 0;
|
|
RETURN_STATUS Status;
|
|
int retval = -1;
|
|
|
|
Status = ParsePath(from, &FromPath, &FromNode, &Instance, NULL);
|
|
if(Status == RETURN_SUCCESS) {
|
|
GenI = FromNode->InstanceList;
|
|
if(GenI == NULL) {
|
|
errno = EPERM;
|
|
retval = -1;
|
|
}
|
|
else {
|
|
//GenI += (Instance * FromNode->InstanceSize);
|
|
retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( from, to);
|
|
}
|
|
free(FromPath);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/**
|
|
**/
|
|
int
|
|
rmdir(
|
|
const char *path
|
|
)
|
|
{
|
|
struct __filedes *filp;
|
|
int fd;
|
|
int retval = -1;
|
|
|
|
fd = open(path, O_RDWR, 0);
|
|
if(fd >= 0) {
|
|
filp = &gMD->fdarray[fd];
|
|
|
|
retval = filp->f_ops->fo_rmdir(filp);
|
|
filp->f_iflags = 0; // Close this FD
|
|
filp->RefCount = 0; // No one using this FD
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/** The fstat() function obtains information about an open file associated
|
|
with the file descriptor fildes, and shall write it to the area pointed to
|
|
by buf.
|
|
|
|
The buf argument is a pointer to a stat structure, as defined
|
|
in <sys/stat.h>, into which information is placed concerning the file.
|
|
|
|
The structure members st_mode, st_ino, st_dev, st_uid, st_gid, st_atime,
|
|
st_ctime, and st_mtime shall have meaningful values. The value of the
|
|
member st_nlink shall be set to the number of links to the file.
|
|
|
|
The fstat() function shall update any time-related fields before writing
|
|
into the stat structure.
|
|
|
|
The fstat() function is implemented using the ShellGetFileInfo()
|
|
function.
|
|
|
|
The stat structure members which don't have direct analogs to EFI file
|
|
information are filled in as follows:
|
|
- st_mode Populated with information from fildes
|
|
- st_ino Set to zero. (inode)
|
|
- st_dev Set to zero.
|
|
- st_uid Set to zero.
|
|
- st_gid Set to zero.
|
|
- st_nlink Set to one.
|
|
|
|
@param[in] fd File descriptor as returned from open().
|
|
@param[out] statbuf Buffer in which the file status is put.
|
|
|
|
@retval 0 Successful Completion.
|
|
@retval -1 An error has occurred and errno has been set to
|
|
identify the error.
|
|
**/
|
|
int
|
|
fstat (int fd, struct stat *statbuf)
|
|
{
|
|
int retval = -1;
|
|
struct __filedes *filp;
|
|
|
|
if(ValidateFD( fd, VALID_OPEN)) {
|
|
filp = &gMD->fdarray[fd];
|
|
retval = filp->f_ops->fo_stat(filp, statbuf, NULL);
|
|
}
|
|
else {
|
|
errno = EBADF;
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/** Obtains information about the file pointed to by path.
|
|
|
|
Opens the file pointed to by path, calls _EFI_FileInfo with the file's handle,
|
|
then closes the file.
|
|
|
|
@retval 0 Successful Completion.
|
|
@retval -1 An error has occurred and errno has been set to
|
|
identify the error.
|
|
**/
|
|
int
|
|
stat (const char *path, struct stat *statbuf)
|
|
{
|
|
int fd;
|
|
int retval = -1;
|
|
struct __filedes *filp;
|
|
|
|
fd = open(path, O_RDONLY, 0);
|
|
if(fd >= 0) {
|
|
filp = &gMD->fdarray[fd];
|
|
retval = filp->f_ops->fo_stat( filp, statbuf, NULL);
|
|
close(fd);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
/** Same as stat since EFI doesn't have symbolic links. **/
|
|
int
|
|
lstat (const char *path, struct stat *statbuf)
|
|
{
|
|
return stat(path, statbuf);
|
|
}
|
|
|
|
/** Control a device.
|
|
**/
|
|
int
|
|
ioctl(
|
|
int fd,
|
|
unsigned long request,
|
|
...
|
|
)
|
|
{
|
|
int retval = -1;
|
|
struct __filedes *filp;
|
|
va_list argp;
|
|
|
|
va_start(argp, request);
|
|
|
|
if(ValidateFD( fd, VALID_OPEN)) {
|
|
filp = &gMD->fdarray[fd];
|
|
|
|
if(request == FIODLEX) {
|
|
/* set Delete-on-Close */
|
|
filp->f_iflags |= FIF_DELCLOSE;
|
|
retval = 0;
|
|
}
|
|
else if(request == FIONDLEX) {
|
|
/* clear Delete-on-Close */
|
|
filp->f_iflags &= ~FIF_DELCLOSE;
|
|
retval = 0;
|
|
}
|
|
else {
|
|
/* All other requests. */
|
|
retval = filp->f_ops->fo_ioctl(filp, request, argp);
|
|
}
|
|
}
|
|
else {
|
|
errno = EBADF;
|
|
}
|
|
va_end(argp);
|
|
|
|
return retval;
|
|
}
|
|
|
|
/** Read from a file.
|
|
|
|
The read() function shall attempt to read nbyte bytes from the file
|
|
associated with the open file descriptor, fildes, into the buffer pointed
|
|
to by buf.
|
|
|
|
Before any action described below is taken, and if nbyte is zero, the
|
|
read() function may detect and return errors as described below. In the
|
|
absence of errors, or if error detection is not performed, the read()
|
|
function shall return zero and have no other results.
|
|
|
|
On files that support seeking (for example, a regular file), the read()
|
|
shall start at a position in the file given by the file offset associated
|
|
with fildes. The file offset shall be incremented by the number of bytes
|
|
actually read.
|
|
|
|
Files that do not support seeking - for example, terminals - always read
|
|
from the current position. The value of a file offset associated with
|
|
such a file is undefined.
|
|
|
|
No data transfer shall occur past the current end-of-file. If the
|
|
starting position is at or after the end-of-file, 0 shall be returned.
|
|
|
|
The read() function reads data previously written to a file. If any
|
|
portion of a regular file prior to the end-of-file has not been written,
|
|
read() shall return bytes with value 0. For example, lseek() allows the
|
|
file offset to be set beyond the end of existing data in the file. If data
|
|
is later written at this point, subsequent reads in the gap between the
|
|
previous end of data and the newly written data shall return bytes with
|
|
value 0 until data is written into the gap.
|
|
|
|
Upon successful completion, where nbyte is greater than 0, read() shall
|
|
mark for update the st_atime field of the file, and shall return the
|
|
number of bytes read. This number shall never be greater than nbyte. The
|
|
value returned may be less than nbyte if the number of bytes left in the
|
|
file is less than nbyte, if the read() request was interrupted by a
|
|
signal, or if the file is a pipe or FIFO or special file and has fewer
|
|
than nbyte bytes immediately available for reading. For example, a read()
|
|
from a file associated with a terminal may return one typed line of data.
|
|
|
|
If fildes does not refer to a directory, the function reads the requested
|
|
number of bytes from the file at the file's current position and returns
|
|
them in buf. If the read goes beyond the end of the file, the read
|
|
length is truncated to the end of the file. The file's current position is
|
|
increased by the number of bytes returned.
|
|
|
|
If fildes refers to a directory, the function reads the directory entry at
|
|
the file's current position and returns the entry in buf. If buf
|
|
is not large enough to hold the current directory entry, then
|
|
errno is set to EBUFSIZE, EFIerrno is set to EFI_BUFFER_TOO_SMALL, and the
|
|
current file position is not updated. The size of the buffer needed to read
|
|
the entry will be returned as a negative number. On success, the current
|
|
position is updated to the next directory entry. If there are no more
|
|
directory entries, the read returns a zero-length buffer.
|
|
EFI_FILE_INFO is the structure returned as the directory entry.
|
|
|
|
@return Upon successful completion, read() returns a non-negative integer
|
|
indicating the number of bytes actually read. Otherwise, the
|
|
functions return a negative value and sets errno to indicate the
|
|
error. If errno is EBUFSIZE, the absolute value of the
|
|
return value indicates the size of the buffer needed to read
|
|
the directory entry.
|
|
**/
|
|
ssize_t
|
|
read (int fildes, void *buf, size_t nbyte)
|
|
{
|
|
struct __filedes *filp;
|
|
ssize_t BufSize;
|
|
|
|
BufSize = (ssize_t)nbyte;
|
|
if(ValidateFD( fildes, VALID_OPEN)) {
|
|
filp = &gMD->fdarray[fildes];
|
|
|
|
BufSize = filp->f_ops->fo_read(filp, &filp->f_offset, nbyte, buf);
|
|
}
|
|
else {
|
|
errno = EBADF;
|
|
BufSize = -EBADF;
|
|
}
|
|
return BufSize;
|
|
}
|
|
|
|
/** Write data to a file.
|
|
|
|
This function writes the specified number of bytes to the file at the current
|
|
file position. The current file position is advanced the actual number of bytes
|
|
written, which is returned in BufferSize. Partial writes only occur when there
|
|
has been a data error during the write attempt (such as "volume space full").
|
|
The file is automatically grown to hold the data if required. Direct writes to
|
|
opened directories are not supported.
|
|
|
|
If fildes refers to a terminal device, isatty() returns TRUE, a partial write
|
|
will occur if a NULL or EOF character is encountered before n characters have
|
|
been written. Characters inserted due to line-end translations will not be
|
|
counted. Unconvertable characters are translated into the UEFI character
|
|
BLOCKELEMENT_LIGHT_SHADE.
|
|
|
|
Since the UEFI console device works on wide characters, the buffer is assumed
|
|
to contain a single-byte character stream which is then translated to wide
|
|
characters using the btowc() functions. The resulting wide character stream
|
|
is what is actually sent to the UEFI console.
|
|
|
|
QUESTION: Should writes to stdout or stderr always succeed?
|
|
**/
|
|
ssize_t
|
|
write (int fd, const void *buf, size_t nbyte)
|
|
{
|
|
struct __filedes *filp;
|
|
ssize_t BufSize;
|
|
// EFI_FILE_HANDLE FileHandle;
|
|
// RETURN_STATUS Status = RETURN_SUCCESS;
|
|
|
|
BufSize = (ssize_t)nbyte;
|
|
|
|
if(ValidateFD( fd, VALID_OPEN)) {
|
|
filp = &gMD->fdarray[fd];
|
|
|
|
BufSize = filp->f_ops->fo_write(filp, &filp->f_offset, nbyte, buf);
|
|
}
|
|
else {
|
|
errno = EBADF;
|
|
BufSize = -EBADF;
|
|
}
|
|
return BufSize;
|
|
}
|
|
|
|
/** Gets the current working directory.
|
|
|
|
The getcwd() function shall place an absolute pathname of the current
|
|
working directory in the array pointed to by buf, and return buf.The
|
|
size argument is the size in bytes of the character array pointed to
|
|
by the buf argument.
|
|
|
|
@param[in,out] buf The buffer to fill.
|
|
@param[in] size The number of bytes in buffer.
|
|
|
|
@retval NULL The function failed. The value in errno provides
|
|
further information about the cause of the failure.
|
|
Values for errno are:
|
|
- EINVAL: buf is NULL or size is zero.
|
|
- ENOENT: directory does not exist.
|
|
- ERANGE: buf size is too small to hold CWD
|
|
|
|
@retval buf The function completed successfully.
|
|
**/
|
|
char
|
|
*getcwd (char *buf, size_t size)
|
|
{
|
|
CONST CHAR16 *Cwd;
|
|
|
|
if (size == 0 || buf == NULL) {
|
|
errno = EINVAL;
|
|
return NULL;
|
|
}
|
|
|
|
Cwd = ShellGetCurrentDir(NULL);
|
|
if (Cwd == NULL) {
|
|
errno = ENOENT;
|
|
return NULL;
|
|
}
|
|
if (size < ((StrLen (Cwd) + 1) * sizeof (CHAR8))) {
|
|
errno = ERANGE;
|
|
return (NULL);
|
|
}
|
|
return (UnicodeStrToAsciiStr(Cwd, buf));
|
|
}
|
|
|
|
/** Change the current working directory.
|
|
|
|
The chdir() function shall cause the directory named by the pathname
|
|
pointed to by the path argument to become the current working directory;
|
|
that is, the starting point for path searches for pathnames not beginning
|
|
with '/'.
|
|
|
|
@param[in] path The new path to set.
|
|
|
|
@retval 0 Operation completed successfully.
|
|
@retval -1 Function failed. The value in errno provides more
|
|
information on the cause of failure:
|
|
- EPERM: Operation not supported with this Shell version.
|
|
- ENOMEM: Unable to allocate memory.
|
|
- ENOENT: Target directory does not exist.
|
|
|
|
@todo Add non-NEW-shell CWD changing.
|
|
**/
|
|
int
|
|
chdir (const char *path)
|
|
{
|
|
CONST CHAR16 *Cwd;
|
|
EFI_STATUS Status;
|
|
CHAR16 *UnicodePath;
|
|
|
|
/* Old Shell does not support Set Current Dir. */
|
|
if(gEfiShellProtocol != NULL) {
|
|
Cwd = ShellGetCurrentDir(NULL);
|
|
if (Cwd != NULL) {
|
|
/* We have shell support */
|
|
UnicodePath = AllocatePool(((AsciiStrLen (path) + 1) * sizeof (CHAR16)));
|
|
if (UnicodePath == NULL) {
|
|
errno = ENOMEM;
|
|
return -1;
|
|
}
|
|
AsciiStrToUnicodeStr(path, UnicodePath);
|
|
Status = gEfiShellProtocol->SetCurDir(NULL, UnicodePath);
|
|
FreePool(UnicodePath);
|
|
if (EFI_ERROR(Status)) {
|
|
errno = ENOENT;
|
|
return -1;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
/* Add here for non-shell */
|
|
errno = EPERM;
|
|
return -1;
|
|
}
|
|
|
|
pid_t tcgetpgrp (int x)
|
|
{
|
|
return ((pid_t)(UINTN)(gImageHandle));
|
|
}
|
|
|
|
pid_t getpgrp(void)
|
|
{
|
|
return ((pid_t)(UINTN)(gImageHandle));
|
|
}
|
|
|
|
/* Internal worker function for utimes.
|
|
This works around an error produced by GCC when the va_* macros
|
|
are used within a function with a fixed number of arguments.
|
|
*/
|
|
static
|
|
int
|
|
EFIAPI
|
|
va_Utimes(
|
|
const char *path,
|
|
...
|
|
)
|
|
{
|
|
struct __filedes *filp;
|
|
va_list ap;
|
|
int fd;
|
|
int retval = -1;
|
|
|
|
va_start(ap, path);
|
|
fd = open(path, O_RDWR, 0);
|
|
if(fd >= 0) {
|
|
filp = &gMD->fdarray[fd];
|
|
retval = filp->f_ops->fo_ioctl( filp, FIOSETIME, ap);
|
|
close(fd);
|
|
}
|
|
va_end(ap);
|
|
return retval;
|
|
}
|
|
|
|
/** Set file access and modification times.
|
|
|
|
@param[in] path
|
|
@param[in] times
|
|
|
|
@return
|
|
**/
|
|
int
|
|
utimes(
|
|
const char *path,
|
|
const struct timeval *times
|
|
)
|
|
{
|
|
return va_Utimes(path, times);
|
|
}
|
|
|