**/\r
#include <Uefi.h>\r
#include <Library/UefiLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
#include <Library/BaseLib.h>\r
#include <Library/MemoryAllocationLib.h>\r
#include <Library/ShellLib.h>\r
#include <sys/ansi.h>\r
#include <errno.h>\r
#include <stdarg.h>\r
+#include <stdlib.h>\r
#include <string.h>\r
#include <wchar.h>\r
+#include <sys/poll.h>\r
#include <sys/fcntl.h>\r
#include <sys/stat.h>\r
#include <sys/syslimits.h>\r
-#include "SysEfi.h"\r
+#include <Efi/SysEfi.h>\r
+#include <kfile.h>\r
+#include <Device/Device.h>\r
#include <MainData.h>\r
#include <extern.h> // Library/include/extern.h: Private to implementation\r
-#include <Efi/Console.h>\r
-\r
-/* Macros only used in this file. */\r
-// Parameters for the ValidateFD function.\r
-#define VALID_OPEN 1\r
-#define VALID_CLOSED 0\r
-#define VALID_DONT_CARE -1\r
-\r
+#include <sys/EfiSysCall.h>\r
\r
/* EFI versions of BSD system calls used in stdio */\r
\r
-/* Normalize path so that forward slashes are replaced with backslashes.\r
- Backslashes are required for UEFI.\r
-*/\r
-static void\r
-NormalizePath( const CHAR16 *path)\r
-{\r
- CHAR16 *temp;\r
-\r
- for( temp = (CHAR16 *)path; *temp; ++temp) {\r
- if(*temp == L'/') {\r
- *temp = L'\\';\r
- }\r
- }\r
-}\r
-\r
/* Validate that fd refers to a valid file descriptor.\r
IsOpen is interpreted as follows:\r
- Positive fd must be OPEN\r
@retval TRUE fd is VALID\r
@retval FALSE fd is INVALID\r
*/\r
-static BOOLEAN\r
+BOOLEAN\r
ValidateFD( int fd, int IsOpen)\r
{\r
+ struct __filedes *filp;\r
BOOLEAN retval = FALSE;\r
\r
if((fd >= 0) && (fd < OPEN_MAX)) {\r
+ filp = &gMD->fdarray[fd];\r
retval = TRUE;\r
if(IsOpen >= 0) {\r
- retval = (BOOLEAN)(gMD->fdarray[fd].State != 0); // TRUE if OPEN\r
+ retval = (BOOLEAN)((filp->f_iflags != 0) && // TRUE if OPEN\r
+ FILE_IS_USABLE(filp)); // and Usable (not Larval or Closing)\r
if(IsOpen == VALID_CLOSED) {\r
retval = (BOOLEAN)!retval; // We want TRUE if CLOSED\r
}\r
@return Returns -1 if there are no free FDs. Otherwise returns the\r
found fd.\r
*/\r
-static int\r
+int\r
FindFreeFD( int MinFd )\r
{\r
struct __filedes *Mfd;\r
\r
// Get an available fd\r
for(i=MinFd; i < OPEN_MAX; ++i) {\r
- if(Mfd[i].State == 0) {\r
- Mfd[i].State = S_ISYSTEM; // Temporarily mark this fd as reserved\r
+ if(Mfd[i].f_iflags == 0) {\r
+ Mfd[i].f_iflags = FIF_LARVAL; // Temporarily mark this fd as reserved\r
fd = i;\r
break;\r
}\r
return fd;\r
}\r
\r
+/* Mark that an open file is to be deleted when closed. */\r
+int\r
+DeleteOnClose(int fd)\r
+{\r
+ int retval = 0;\r
+\r
+ if(ValidateFD( fd, VALID_OPEN)) {\r
+ gMD->fdarray[fd].f_iflags |= FIF_DELCLOSE;\r
+ }\r
+ else {\r
+ errno = EBADF;\r
+ retval = -1;\r
+ }\r
+ return retval;\r
+}\r
+\r
/** The isatty() function tests whether fildes, an open file descriptor,\r
is associated with a terminal device.\r
\r
EBADF if fildes is not a valid open FD.\r
**/\r
int\r
-isatty (int fildes)\r
+isatty (int fd)\r
{\r
int retval = 0;\r
- EFI_FILE_HANDLE FileHandle;\r
+ struct __filedes *Fp;\r
\r
- if(ValidateFD( fildes, VALID_OPEN)) {\r
- FileHandle = gMD->fdarray[fildes].FileHandle;\r
- retval = (FileHandle >= &gMD->StdIo[0].Abstraction) &&\r
- (FileHandle <= &gMD->StdIo[2].Abstraction);\r
+ if(ValidateFD( fd, VALID_OPEN)) {\r
+ Fp = &gMD->fdarray[fd];\r
+ retval = Fp->f_iflags & _S_ITTY;\r
}\r
else {\r
errno = EBADF;\r
static BOOLEAN\r
IsDupFd( int fd)\r
{\r
- EFI_FILE_HANDLE FileHandle;\r
+ void * DevData;\r
+ const struct fileops *FileOps;\r
int i;\r
BOOLEAN Ret = FALSE;\r
\r
if(ValidateFD( fd, VALID_OPEN )) {\r
- FileHandle = gMD->fdarray[fd].FileHandle;\r
+ FileOps = gMD->fdarray[fd].f_ops;\r
+ DevData = gMD->fdarray[fd].devdata;\r
for(i=0; i < OPEN_MAX; ++i) {\r
if(i == fd) continue;\r
- if(gMD->fdarray[i].State != 0) { // TRUE if fd is OPEN\r
- if(gMD->fdarray[i].FileHandle == FileHandle) {\r
+ if(ValidateFD( i, VALID_OPEN )) { // TRUE if fd is valid and OPEN\r
+ if((gMD->fdarray[i].f_ops == FileOps)\r
+ &&(gMD->fdarray[i].devdata == DevData )) {\r
Ret = TRUE;\r
break;\r
}\r
static int\r
_closeX (int fd, int NewState)\r
{\r
- struct __filedes *Mfd;\r
- RETURN_STATUS Status;\r
+ struct __filedes *Fp;\r
int retval = 0;\r
\r
- Status = EFIerrno = RETURN_SUCCESS; // In case of error before the EFI call.\r
-\r
// Verify my pointers and get my FD.\r
if(ValidateFD( fd, VALID_OPEN )) {\r
- Mfd = &gMD->fdarray[fd];\r
- // Check if there are duplicates using this FileHandle\r
+ Fp = &gMD->fdarray[fd];\r
+ // Check if there are other users of this FileHandle\r
+ if(Fp->RefCount == 1) { // There should be no other users\r
if(! IsDupFd(fd)) {\r
// Only do the close if no one else is using the FileHandle\r
- if(isatty(fd)) {\r
- Status = Mfd->FileHandle->Close( Mfd->FileHandle);\r
+ if(Fp->f_iflags & FIF_DELCLOSE) {\r
+ /* Handle files marked "Delete on Close". */\r
+ if(Fp->f_ops->fo_delete != NULL) {\r
+ retval = Fp->f_ops->fo_delete(Fp);\r
+ }\r
}\r
else {\r
- Status = ShellCloseFile( (SHELL_FILE_HANDLE *)&Mfd->FileHandle);\r
+ retval = Fp->f_ops->fo_close( Fp);\r
}\r
}\r
- Mfd->State = NewState; // Close this FD or reserve it\r
- if(Status != RETURN_SUCCESS) {\r
- errno = EFI2errno(Status);\r
- EFIerrno = Status;\r
- retval = -1;\r
+ Fp->f_iflags = NewState; // Close this FD or reserve it\r
+ Fp->RefCount = 0; // No one using this FD\r
+ }\r
+ else {\r
+ --Fp->RefCount; /* One less user of this FD */\r
}\r
}\r
else {\r
// Bad FD\r
- errno = EBADF;\r
retval = -1;\r
+ errno = EBADF;\r
}\r
return retval;\r
}\r
return _closeX(fd, 0);\r
}\r
\r
-/* Wide character version of unlink */\r
+/**\r
+**/\r
int\r
-Uunlink (const wchar_t *Path)\r
+unlink (const char *path)\r
{\r
- EFI_FILE_HANDLE FileHandle;\r
- RETURN_STATUS Status;\r
+ struct __filedes *Fp;\r
+ int fd;\r
+ int retval = -1;\r
\r
EFIerrno = RETURN_SUCCESS;\r
\r
- NormalizePath( Path);\r
- // We can only delete open files.\r
- Status = ShellOpenFileByName( Path, (SHELL_FILE_HANDLE *)&FileHandle, 3, 0);\r
- if(Status != RETURN_SUCCESS) {\r
- errno = EFI2errno(Status);\r
- EFIerrno = Status;\r
- return -1;\r
+ fd = open(path, O_WRONLY, 0);\r
+ if(fd >= 0) {\r
+ Fp = &gMD->fdarray[fd];\r
+\r
+ if(Fp->f_ops->fo_delete != NULL) {\r
+ retval = Fp->f_ops->fo_delete(Fp);\r
}\r
- Status = ShellDeleteFile( (SHELL_FILE_HANDLE *)&FileHandle);\r
- if(Status != RETURN_SUCCESS) {\r
- errno = EFI2errno(Status);\r
- EFIerrno = Status;\r
- return -1;\r
+ Fp->f_iflags = 0; // Close this FD\r
+ Fp->RefCount = 0; // No one using this FD\r
}\r
- return 0;\r
-}\r
-\r
-/**\r
-**/\r
-int\r
-unlink (const char *path)\r
-{\r
- // Convert path from MBCS to WCS\r
- (void)AsciiStrToUnicodeStr( path, gMD->UString);\r
-\r
- return Uunlink(gMD->UString);\r
+ return retval;\r
}\r
\r
/** The fcntl() function shall perform the operations described below on open\r
break;\r
//case F_SETFL:\r
case F_SETFD:\r
- retval = MyFd->State;\r
- break;\r
- case F_SETOWN:\r
- retval = MyFd->SocProc;\r
- MyFd->SocProc = va_arg(p3, int);\r
+ retval = MyFd->f_iflags;\r
break;\r
+ //case F_SETOWN:\r
+ // retval = MyFd->SocProc;\r
+ // MyFd->SocProc = va_arg(p3, int);\r
+ // break;\r
case F_GETFD:\r
//retval = MyFd->Oflags;\r
- retval = MyFd->State;\r
+ retval = MyFd->f_iflags;\r
break;\r
case F_GETFL:\r
- //retval = MyFd->State;\r
+ //retval = MyFd->f_iflags;\r
retval = MyFd->Oflags;\r
break;\r
- case F_GETOWN:\r
- retval = MyFd->SocProc;\r
- break;\r
+ //case F_GETOWN:\r
+ // retval = MyFd->SocProc;\r
+ // break;\r
default:\r
errno = EINVAL;\r
break;\r
retval = fildes2;\r
if( fildes != fildes2) {\r
if(ValidateFD( fildes2, VALID_DONT_CARE)) {\r
- gMD->fdarray[fildes2].State = S_ISYSTEM; // Mark the file closed, but reserved\r
+ gMD->fdarray[fildes2].f_iflags = FIF_LARVAL; // Mark the file closed, but reserved\r
(void)memcpy(&gMD->fdarray[fildes2], // Duplicate fildes into fildes2\r
&gMD->fdarray[fildes], sizeof(struct __filedes));\r
+ gMD->fdarray[fildes2].MyFD = (UINT16)fildes2;\r
}\r
else {\r
errno = EBADF;\r
indicate the error.\r
**/\r
__off_t\r
-lseek (int fildes, __off_t offset, int how)\r
+lseek (int fd, __off_t offset, int how)\r
{\r
__off_t CurPos = -1;\r
- RETURN_STATUS Status = RETURN_SUCCESS;\r
- EFI_FILE_HANDLE FileHandle;\r
+// RETURN_STATUS Status = RETURN_SUCCESS;\r
+ struct __filedes *filp;\r
\r
EFIerrno = RETURN_SUCCESS; // In case of error without an EFI call\r
\r
if( how == SEEK_SET || how == SEEK_CUR || how == SEEK_END) {\r
- if(ValidateFD( fildes, VALID_OPEN)) {\r
+ if(ValidateFD( fd, VALID_OPEN)) {\r
+ filp = &gMD->fdarray[fd];\r
// Both of our parameters have been verified as valid\r
- FileHandle = gMD->fdarray[fildes].FileHandle;\r
- CurPos = 0;\r
- if(isatty(fildes)) {\r
- Status = FileHandle->SetPosition( FileHandle, offset);\r
- CurPos = offset;\r
- }\r
- else {\r
- if(how != SEEK_SET) {\r
- // We are doing a relative seek\r
- if(how == SEEK_END) {\r
- // seeking relative to EOF, so position there first.\r
- Status = ShellSetFilePosition( (SHELL_FILE_HANDLE)FileHandle, 0xFFFFFFFFFFFFFFFFULL);\r
- }\r
- if(Status == RETURN_SUCCESS) {\r
- // Now, determine our current position.\r
- Status = ShellGetFilePosition( (SHELL_FILE_HANDLE)FileHandle, (UINT64 *)&CurPos);\r
- }\r
- }\r
- if(Status == RETURN_SUCCESS) {\r
- /* CurPos now indicates the point we are seeking from, so seek... */\r
- Status = ShellSetFilePosition( (SHELL_FILE_HANDLE)FileHandle, (UINT64)(CurPos + offset));\r
- if(Status == RETURN_SUCCESS) {\r
- // Now, determine our final position.\r
- Status = ShellGetFilePosition( (SHELL_FILE_HANDLE)FileHandle, (UINT64 *)&CurPos);\r
- }\r
- }\r
- if(Status != RETURN_SUCCESS) {\r
- EFIerrno = Status;\r
- CurPos = -1;\r
- if(Status == EFI_UNSUPPORTED) {\r
- errno = EISDIR;\r
- }\r
- else {\r
- errno = EFI2errno(Status);\r
- }\r
- }\r
+ CurPos = filp->f_ops->fo_lseek( filp, offset, how);\r
+ if(CurPos >= 0) {\r
+ filp->f_offset = CurPos;\r
}\r
}\r
else {\r
The directory is closed after it is created.\r
\r
@retval 0 The directory was created successfully.\r
- @retval -1 An error occurred and an error code is stored in errno.\r
+ @retval -1 An error occurred and error codes are stored in errno and EFIerrno.\r
**/\r
int\r
mkdir (const char *path, __mode_t perms)\r
{\r
- EFI_FILE_HANDLE FileHandle;\r
+ wchar_t *NewPath;\r
+ DeviceNode *Node;\r
+ char *GenI;\r
RETURN_STATUS Status;\r
- EFI_FILE_INFO *FileInfo;\r
-\r
- // Convert name from MBCS to WCS\r
- (void)AsciiStrToUnicodeStr( path, gMD->UString);\r
- NormalizePath( gMD->UString);\r
+ int Instance = 0;\r
+ int retval = 0;\r
\r
-//Print(L"%a( \"%s\", 0x%8X)\n", __func__, gMD->UString, perms);\r
- Status = ShellCreateDirectory( gMD->UString, (SHELL_FILE_HANDLE *)&FileHandle);\r
+ Status = ParsePath(path, &NewPath, &Node, &Instance);\r
if(Status == RETURN_SUCCESS) {\r
- FileInfo = ShellGetFileInfo( FileHandle);\r
- if(FileInfo != NULL) {\r
- FileInfo->Attribute = Omode2EFI(perms);\r
- Status = ShellSetFileInfo( FileHandle, FileInfo);\r
- FreePool(FileInfo);\r
- if(Status == RETURN_SUCCESS) {\r
- (void)ShellCloseFile((SHELL_FILE_HANDLE *)&FileHandle);\r
- return 0;\r
+ GenI = Node->InstanceList;\r
+ if(GenI == NULL) {\r
+ errno = EPERM;\r
+ retval = -1;\r
}\r
+ else {\r
+ GenI += (Instance * Node->InstanceSize);\r
+ retval = ((GenericInstance *)GenI)->Abstraction.fo_mkdir( path, perms);\r
+ }\r
+ free(NewPath);\r
}\r
+ else {\r
+ retval = -1;\r
}\r
- errno = EFI2errno(Status);\r
- EFIerrno = Status;\r
-\r
- return -1;\r
+ return retval;\r
}\r
\r
/** Open a file.\r
O_EXCL -- if O_CREAT is also set, open will fail if the file already exists.\r
**/\r
int\r
-open (const char *name, int oflags, int mode)\r
+open (const char *path, int oflags, int mode)\r
{\r
- EFI_FILE_HANDLE FileHandle;\r
- struct __filedes *Mfd;\r
+ wchar_t *NewPath;\r
+ DeviceNode *Node;\r
+ char *GenI = NULL;\r
+ struct __filedes *filp;\r
+ int Instance = 0;\r
RETURN_STATUS Status;\r
UINT64 OpenMode;\r
- UINT64 Attributes;\r
int fd = -1;\r
- UINT32 NewState;\r
+ int doresult;\r
\r
- EFIerrno = RETURN_SUCCESS;\r
- Mfd = gMD->fdarray;\r
-\r
- // Convert name from MBCS to WCS\r
- (void)AsciiStrToUnicodeStr( name, gMD->UString);\r
- NormalizePath( gMD->UString);\r
-\r
- // Convert oflags to Attributes\r
- OpenMode = Oflags2EFI(oflags);\r
- if(OpenMode == 0) {\r
- errno = EINVAL;\r
- return -1;\r
+ Status = ParsePath(path, &NewPath, &Node, &Instance);\r
+ if(Status == RETURN_SUCCESS) {\r
+ if((Node != NULL) &&\r
+ ((GenI = Node->InstanceList) == NULL)) {\r
+ errno = EPERM;\r
}\r
-\r
- //Attributes = Omode2EFI(mode);\r
- Attributes = 0;\r
-\r
+ else {\r
// Could add a test to see if the file name begins with a period.\r
// If it does, then add the HIDDEN flag to Attributes.\r
\r
// Get an available fd\r
- fd = FindFreeFD( 0 );\r
+ fd = FindFreeFD( VALID_CLOSED );\r
\r
if( fd < 0 ) {\r
// All available FDs are in use\r
errno = EMFILE;\r
return -1;\r
}\r
+ filp = &gMD->fdarray[fd];\r
+ // Save the flags and mode in the File Descriptor\r
+ filp->Oflags = oflags;\r
+ filp->Omode = mode;\r
+\r
+ GenI += (Instance * Node->InstanceSize);\r
+ doresult = Node->OpenFunc(filp, GenI, NewPath, NULL);\r
+ if(doresult < 0) {\r
+ filp->f_iflags = 0; // Release this FD\r
+ fd = -1; // Indicate an error\r
+ }\r
+ else {\r
+ // Re-use OpenMode in order to build our final f_iflags value\r
+ OpenMode = ( mode & S_ACC_READ ) ? S_ACC_READ : 0;\r
+ OpenMode |= ( mode & S_ACC_WRITE ) ? S_ACC_WRITE : 0;\r
\r
- Status = ConOpen( NULL, &FileHandle, gMD->UString, OpenMode, Attributes);\r
- if(Status == RETURN_NO_MAPPING) {\r
- // Not a console device, how about a regular file device?\r
-\r
- /* Do we care if the file already exists?\r
- If O_TRUNC, then delete the file. It will be created anew subsequently.\r
- If O_EXCL, then error if the file exists and O_CREAT is set.\r
-\r
- !!!!!!!!! Change this to use ShellSetFileInfo() to actually truncate the file\r
- !!!!!!!!! instead of deleting and re-creating it.\r
- */\r
- if((oflags & O_TRUNC) || ((oflags & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) {\r
- Status = ShellIsFile( gMD->UString );\r
- if(Status == RETURN_SUCCESS) {\r
- // The file exists\r
- if(oflags & O_TRUNC) {\r
- // We do a truncate by deleting the existing file and creating a new one.\r
- if(Uunlink(gMD->UString) != 0) {\r
- Mfd[fd].State = 0; // Release our reservation on this FD\r
- return -1; // errno and EFIerrno are already set.\r
+ filp->f_iflags |= (UINT32)OpenMode;\r
+ ++filp->RefCount;\r
+ FILE_SET_MATURE(filp);\r
+ }\r
}\r
+ free(NewPath);\r
}\r
- else if(oflags & (O_EXCL | O_CREAT)) {\r
- errno = EEXIST;\r
- EFIerrno = Status;\r
- Mfd[fd].State = 0; // Release our reservation on this FD\r
+ // return the fd of our now open file\r
+ return fd;\r
+}\r
+\r
+\r
+/**\r
+ Poll a list of file descriptors.\r
+\r
+ The ::poll routine waits for up to timeout milliseconds for an event\r
+ to occur on one or more of the file descriptors listed. The event\r
+ types of interested are specified for each file descriptor in the events\r
+ field. The actual event detected is returned in the revents field of\r
+ the array. The\r
+ <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">POSIX</a>\r
+ documentation is available online.\r
+\r
+ @param [in] pfd Address of an array of pollfd structures.\r
+\r
+ @param [in] nfds Number of elements in the array of pollfd structures.\r
+\r
+ @param [in] timeout Length of time in milliseconds to wait for the event\r
+\r
+ @returns The number of file descriptors with detected events. Zero\r
+ indicates that the call timed out and -1 indicates an error.\r
+\r
+ **/\r
+int\r
+poll (\r
+ struct pollfd * pfd,\r
+ nfds_t nfds,\r
+ int timeout\r
+ )\r
+{\r
+ struct __filedes * pDescriptor;\r
+ struct pollfd * pEnd;\r
+ struct pollfd * pPollFD;\r
+ int SelectedFDs;\r
+ EFI_STATUS Status;\r
+ EFI_EVENT Timer;\r
+ UINT64 TimerTicks;\r
+\r
+ //\r
+ // Create the timer for the timeout\r
+ //\r
+ Timer = NULL;\r
+ Status = EFI_SUCCESS;\r
+ if ( INFTIM != timeout ) {\r
+ Status = gBS->CreateEvent ( EVT_TIMER,\r
+ TPL_NOTIFY,\r
+ NULL,\r
+ NULL,\r
+ &Timer );\r
+ if ( !EFI_ERROR ( Status )) {\r
+ //\r
+ // Start the timeout timer\r
+ //\r
+ TimerTicks = timeout;\r
+ TimerTicks *= 1000 * 10;\r
+ Status = gBS->SetTimer ( Timer,\r
+ TimerRelative,\r
+ TimerTicks );\r
+ }\r
+ else {\r
+ SelectedFDs = -1;\r
+ errno = ENOMEM;\r
+ }\r
+ }\r
+ if ( !EFI_ERROR ( Status )) {\r
+ //\r
+ // Poll until an event is detected or the timer fires\r
+ //\r
+ SelectedFDs = 0;\r
+ errno = 0;\r
+ do {\r
+ //\r
+ // Poll the list of file descriptors\r
+ //\r
+ pPollFD = pfd;\r
+ pEnd = &pPollFD [ nfds ];\r
+ while ( pEnd > pPollFD ) {\r
+ //\r
+ // Validate the file descriptor\r
+ //\r
+ if ( !ValidateFD ( pPollFD->fd, VALID_OPEN )) {\r
+ errno = EINVAL;\r
return -1;\r
}\r
+\r
+ //\r
+ // Poll the device or file\r
+ //\r
+ pDescriptor = &gMD->fdarray [ pPollFD->fd ];\r
+ pPollFD->revents = pDescriptor->f_ops->fo_poll ( pDescriptor,\r
+ pPollFD->events );\r
+\r
+ //\r
+ // Determine if this file descriptor detected an event\r
+ //\r
+ if ( 0 != pPollFD->revents ) {\r
+ //\r
+ // Select this descriptor\r
+ //\r
+ SelectedFDs += 1;\r
+ }\r
+\r
+ //\r
+ // Set the next file descriptor\r
+ //\r
+ pPollFD += 1;\r
}\r
+\r
+ //\r
+ // Check for timeout\r
+ //\r
+ if ( NULL != Timer ) {\r
+ Status = gBS->CheckEvent ( Timer );\r
+ if ( EFI_SUCCESS == Status ) {\r
+ //\r
+ // Timeout\r
+ //\r
+ break;\r
+ }\r
+ else if ( EFI_NOT_READY == Status ) {\r
+ Status = EFI_SUCCESS;\r
}\r
- // Call the EFI Shell's Open function\r
- Status = ShellOpenFileByName( gMD->UString, (SHELL_FILE_HANDLE *)&FileHandle, OpenMode, Attributes);\r
- if(RETURN_ERROR(Status)) {\r
- Mfd[fd].State = 0; // Release our reservation on this FD\r
- // Set errno based upon Status\r
- errno = EFI2errno(Status);\r
- EFIerrno = Status;\r
- return -1;\r
}\r
- // Successfully got a regular File\r
- NewState = S_IFREG;\r
+ } while (( 0 == SelectedFDs )\r
+ && ( EFI_SUCCESS == Status ));\r
+ //\r
+ // Stop the timer\r
+ //\r
+ if ( NULL != Timer ) {\r
+ gBS->SetTimer ( Timer,\r
+ TimerCancel,\r
+ 0 );\r
}\r
- else if(Status != RETURN_SUCCESS) {\r
- // Set errno based upon Status\r
- errno = EFI2errno(Status);\r
- EFIerrno = Status;\r
- return -1;\r
}\r
else {\r
- // Succesfully got a Console stream\r
- NewState = S_IFREG | _S_ITTY | _S_IFCHR;\r
+ SelectedFDs = -1;\r
+ errno = EAGAIN;\r
}\r
\r
- // Update the info in the fd\r
- Mfd[fd].FileHandle = FileHandle;\r
- Mfd[fd].Oflags = oflags;\r
- Mfd[fd].Omode = mode;\r
+ //\r
+ // Release the timer\r
+ //\r
+ if ( NULL != Timer ) {\r
+ gBS->CloseEvent ( Timer );\r
+ }\r
\r
- // Re-use OpenMode in order to build our final State value\r
- OpenMode = ( mode & S_ACC_READ ) ? S_ACC_READ : 0;\r
- OpenMode |= ( mode & S_ACC_WRITE ) ? S_ACC_WRITE : 0;\r
+ //\r
+ // Return the number of selected file system descriptors\r
+ //\r
+ return SelectedFDs;\r
+}\r
\r
- Mfd[fd].State = NewState | (UINT32)OpenMode;\r
\r
- // return the fd of our now open file\r
- return fd;\r
-}\r
\r
/** The rename() function changes the name of a file.\r
The old argument points to the pathname of the file to be renamed. The new\r
shall be changed or created.\r
**/\r
int\r
-rename (const char *old, const char *new)\r
-{\r
- // UINT64 InfoSize;\r
- // RETURN_STATUS Status;\r
- // EFI_FILE_INFO *NewFileInfo = NULL;\r
- // EFI_FILE_INFO *OldFileInfo;\r
- // char *Newfn;\r
- // int OldFd;\r
-\r
- //// Open old file\r
- // OldFd = open(old, O_RDONLY, 0);\r
- // if(OldFd >= 0) {\r
- // NewFileInfo = malloc(sizeof(EFI_FILE_INFO) + PATH_MAX);\r
- // if(NewFileInfo != NULL) {\r
- // OldFileInfo = ShellGetFileInfo( FileHandle);\r
- // if(OldFileInfo != NULL) {\r
- // // Copy the Old file info into our new buffer, and free the old.\r
- // memcpy(OldFileInfo, NewFileInfo, sizeof(EFI_FILE_INFO));\r
- // FreePool(OldFileInfo);\r
- // // Strip off all but the file name portion of new\r
- // NewFn = strrchr(new, '/');\r
- // if(NewFn == NULL) {\r
- // NewFn = strrchr(new '\\');\r
- // if(NewFn == NULL) {\r
- // NewFn = new;\r
- // }\r
- // }\r
- // // Convert new name from MBCS to WCS\r
- // (void)AsciiStrToUnicodeStr( NewFn, gMD->UString);\r
- // // Copy the new file name into our new file info buffer\r
- // wcsncpy(NewFileInfo->FileName, gMD->UString, wcslen(gMD->UString)+1);\r
- // // Apply the new file name\r
- // Status = ShellSetFileInfo(FileHandle);\r
- // if(Status == EFI_SUCCESS) {\r
- // // File has been successfully renamed. We are DONE!\r
- // return 0;\r
- // }\r
- // errno = EFI2errno( Status );\r
- // EFIerrno = Status;\r
- // }\r
- // else {\r
- // errno = EIO;\r
- // }\r
- // }\r
- // else {\r
- // errno = ENOMEM;\r
- // }\r
- // }\r
- return -1;\r
-}\r
-\r
-/**\r
-**/\r
-int\r
-rmdir (const char *path)\r
+EFIAPI\r
+rename(\r
+ const char *from,\r
+ const char *to\r
+ )\r
{\r
- EFI_FILE_HANDLE FileHandle;\r
- RETURN_STATUS Status;\r
- EFI_FILE_INFO *FileInfo = NULL;\r
- int Count = 0;\r
- BOOLEAN NoFile = FALSE;\r
-\r
- errno = 0; // Make it easier to see if we have an error later\r
-\r
- // Convert name from MBCS to WCS\r
- (void)AsciiStrToUnicodeStr( path, gMD->UString);\r
- NormalizePath( gMD->UString);\r
-\r
-//Print(L"%a( \"%s\")\n", __func__, gMD->UString);\r
- Status = ShellOpenFileByName( gMD->UString, (SHELL_FILE_HANDLE *)&FileHandle,\r
- (EFI_FILE_MODE_READ || EFI_FILE_MODE_WRITE), 0);\r
+ wchar_t *FromPath;\r
+ DeviceNode *FromNode;\r
+ char *GenI;\r
+ int Instance = 0;\r
+ RETURN_STATUS Status;\r
+ int retval = -1;\r
+\r
+ Status = ParsePath(from, &FromPath, &FromNode, &Instance);\r
if(Status == RETURN_SUCCESS) {\r
- FileInfo = ShellGetFileInfo( (SHELL_FILE_HANDLE)FileHandle);\r
- if(FileInfo != NULL) {\r
- if((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {\r
- errno = ENOTDIR;\r
+ GenI = FromNode->InstanceList;\r
+ if(GenI == NULL) {\r
+ errno = EPERM;\r
+ retval = -1;\r
}\r
else {\r
- // See if the directory has any entries other than ".." and ".".\r
- FreePool(FileInfo); // Free up the buffer from ShellGetFileInfo()\r
- Status = ShellFindFirstFile( (SHELL_FILE_HANDLE)FileHandle, &FileInfo);\r
- if(Status == RETURN_SUCCESS) {\r
- ++Count;\r
- while(Count < 3) {\r
- Status = ShellFindNextFile( (SHELL_FILE_HANDLE)FileHandle, FileInfo, &NoFile);\r
- if(Status == RETURN_SUCCESS) {\r
- if(NoFile) {\r
- break;\r
+ GenI += (Instance * FromNode->InstanceSize);\r
+ retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( from, to);\r
}\r
- ++Count;\r
- }\r
- else {\r
- Count = 99;\r
+ free(FromPath);\r
}\r
- }\r
- FreePool(FileInfo); // Free buffer from ShellFindFirstFile()\r
- if(Count < 3) {\r
- // Directory is empty\r
- Status = ShellDeleteFile( (SHELL_FILE_HANDLE *)&FileHandle);\r
- if(Status == RETURN_SUCCESS) {\r
- EFIerrno = RETURN_SUCCESS;\r
- return 0;\r
- /* ######## SUCCESSFUL RETURN ######## */\r
- }\r
- }\r
- else {\r
- if(Count == 99) {\r
- errno = EIO;\r
- }\r
- else {\r
- errno = ENOTEMPTY;\r
- }\r
- }\r
- }\r
- }\r
- }\r
- else {\r
- errno = EIO;\r
- }\r
- }\r
- EFIerrno = Status;\r
- if(errno == 0) {\r
- errno = EFI2errno( Status );\r
- }\r
- return -1;\r
+ return retval;\r
}\r
\r
-/* Internal File Info. worker function for stat and fstat. */\r
-static\r
-EFI_STATUS\r
-_EFI_FileInfo( EFI_FILE_INFO *FileInfo, struct stat *statbuf)\r
+/**\r
+**/\r
+int\r
+EFIAPI\r
+rmdir(\r
+ const char *path\r
+ )\r
{\r
- UINT64 Attributes;\r
- RETURN_STATUS Status;\r
- mode_t newmode;\r
-\r
- if(FileInfo != NULL) {\r
- // Got the info, now populate statbuf with it\r
- statbuf->st_blksize = S_BLKSIZE;\r
- statbuf->st_size = FileInfo->Size;\r
- statbuf->st_physsize = FileInfo->PhysicalSize;\r
- statbuf->st_birthtime = Efi2Time( &FileInfo->CreateTime);\r
- statbuf->st_atime = Efi2Time( &FileInfo->LastAccessTime);\r
- statbuf->st_mtime = Efi2Time( &FileInfo->ModificationTime);\r
- Attributes = FileInfo->Attribute;\r
- newmode = (mode_t)(Attributes << S_EFISHIFT) | S_ACC_READ;\r
- if((Attributes & EFI_FILE_DIRECTORY) == 0) {\r
- newmode |= _S_IFREG;\r
- if((Attributes & EFI_FILE_READ_ONLY) == 0) {\r
- statbuf->st_mode |= S_ACC_WRITE;\r
+ struct __filedes *filp;\r
+ int fd;\r
+ int retval = -1;\r
+\r
+ fd = open(path, O_RDWR, 0);\r
+ if(fd >= 0) {\r
+ filp = &gMD->fdarray[fd];\r
+\r
+ retval = filp->f_ops->fo_rmdir(filp);\r
}\r
- }\r
- else {\r
- newmode |= _S_IFDIR;\r
- }\r
- statbuf->st_mode = newmode;\r
- Status = RETURN_SUCCESS;\r
- }\r
- else {\r
- Status = RETURN_DEVICE_ERROR;\r
- }\r
- return Status;\r
+ return retval;\r
}\r
\r
/** The fstat() function obtains information about an open file associated\r
- st_gid Set to zero.\r
- st_nlink Set to one.\r
\r
- @param[in] fildes File descriptor as returned from open().\r
+ @param[in] fd File descriptor as returned from open().\r
@param[out] statbuf Buffer in which the file status is put.\r
\r
@retval 0 Successful Completion.\r
identify the error.\r
**/\r
int\r
-fstat (int fildes, struct stat *statbuf)\r
+fstat (int fd, struct stat *statbuf)\r
{\r
- EFI_FILE_HANDLE FileHandle;\r
- RETURN_STATUS Status = RETURN_SUCCESS;\r
- EFI_FILE_INFO *FileInfo = NULL;\r
- UINTN FinfoSize = sizeof(EFI_FILE_INFO);\r
+ int retval = -1;\r
+ struct __filedes *filp;\r
\r
- if(ValidateFD( fildes, VALID_OPEN)) {\r
- FileHandle = gMD->fdarray[fildes].FileHandle;\r
- if(isatty(fildes)) {\r
- FileInfo = AllocateZeroPool(FinfoSize);\r
- if(FileInfo != NULL) {\r
- Status = FileHandle->GetInfo( FileHandle, 0, &FinfoSize, FileInfo);\r
+ if(ValidateFD( fd, VALID_OPEN)) {\r
+ filp = &gMD->fdarray[fd];\r
+ retval = filp->f_ops->fo_stat(filp, statbuf, NULL);\r
}\r
else {\r
- Status = RETURN_OUT_OF_RESOURCES;\r
+ errno = EBADF;\r
}\r
- }\r
- else {\r
- FileInfo = ShellGetFileInfo( FileHandle);\r
- }\r
- Status = _EFI_FileInfo( FileInfo, statbuf);\r
- }\r
- errno = EFI2errno(Status);\r
- EFIerrno = Status;\r
-\r
- if(FileInfo != NULL) {\r
- FreePool(FileInfo); // Release the buffer allocated by the GetInfo function\r
- }\r
-\r
- return errno? -1 : 0;\r
+ return retval;\r
}\r
\r
/** Obtains information about the file pointed to by path.\r
int\r
stat (const char *path, void *statbuf)\r
{\r
- EFI_FILE_HANDLE FileHandle;\r
- RETURN_STATUS Status;\r
- EFI_FILE_INFO *FileInfo;\r
-\r
- errno = 0; // Make it easier to see if we have an error later\r
-\r
- // Convert name from MBCS to WCS\r
- (void)AsciiStrToUnicodeStr( path, gMD->UString);\r
- NormalizePath( gMD->UString);\r
-\r
- Status = ShellOpenFileByName( gMD->UString, (SHELL_FILE_HANDLE *)&FileHandle, EFI_FILE_MODE_READ, 0ULL);\r
- if(Status == RETURN_SUCCESS) {\r
- FileInfo = ShellGetFileInfo( FileHandle);\r
- Status = _EFI_FileInfo( FileInfo, (struct stat *)statbuf);\r
- (void)ShellCloseFile( (SHELL_FILE_HANDLE *)&FileHandle);\r
+ int fd;\r
+ int retval = -1;\r
+ struct __filedes *filp;\r
+\r
+ fd = open(path, O_RDONLY, 0);\r
+ if(fd >= 0) {\r
+ filp = &gMD->fdarray[fd];\r
+ retval = filp->f_ops->fo_stat( filp, statbuf, NULL);\r
+ close(fd);\r
}\r
- errno = EFI2errno(Status);\r
- EFIerrno = Status;\r
-\r
- return errno? -1 : 0;\r
+ return retval;\r
}\r
\r
/** Same as stat since EFI doesn't have symbolic links. **/\r
return stat(path, statbuf);\r
}\r
\r
+/** Control a device.\r
+**/\r
+int\r
+ioctl(\r
+ int fd,\r
+ unsigned long request,\r
+ ...\r
+ )\r
+{\r
+ int retval = -1;\r
+ struct __filedes *filp;\r
+ va_list argp;\r
+\r
+ va_start(argp, request);\r
+\r
+ if(ValidateFD( fd, VALID_OPEN)) {\r
+ filp = &gMD->fdarray[fd];\r
+ retval = filp->f_ops->fo_ioctl(filp, request, argp);\r
+ }\r
+ else {\r
+ errno = EBADF;\r
+ }\r
+ va_end(argp);\r
+\r
+ return retval;\r
+}\r
+\r
/** Read from a file.\r
\r
The read() function shall attempt to read nbyte bytes from the file\r
ssize_t\r
read (int fildes, void *buf, size_t nbyte)\r
{\r
+ struct __filedes *filp;\r
ssize_t BufSize;\r
- EFI_FILE_HANDLE FileHandle;\r
- RETURN_STATUS Status;\r
\r
BufSize = (ssize_t)nbyte;\r
if(ValidateFD( fildes, VALID_OPEN)) {\r
- FileHandle = gMD->fdarray[fildes].FileHandle;\r
- if(isatty(fildes)) {\r
- Status = FileHandle->Read( FileHandle, (UINTN *)&BufSize, buf);\r
- }\r
- else {\r
- Status = ShellReadFile( FileHandle, (UINTN *)&BufSize, buf);\r
- }\r
- if(Status != RETURN_SUCCESS) {\r
- EFIerrno = Status;\r
- errno = EFI2errno(Status);\r
- if(Status == RETURN_BUFFER_TOO_SMALL) {\r
- BufSize = -BufSize;\r
- }\r
- else {\r
- BufSize = -1;\r
- }\r
- }\r
+ filp = &gMD->fdarray[fildes];\r
+\r
+ BufSize = filp->f_ops->fo_read(filp, &filp->f_offset, nbyte, buf);\r
}\r
else {\r
errno = EBADF;\r
+ BufSize = -EBADF;\r
}\r
return BufSize;\r
}\r
\r
-ssize_t\r
-WideTtyCvt( CHAR16 *dest, const char *buf, size_t n)\r
-{\r
- UINTN i;\r
- wint_t wc;\r
-\r
- for(i = 0; i < n; ++i) {\r
- wc = btowc(*buf++);\r
- if( wc == 0) {\r
- break;\r
- };\r
- if(wc < 0) {\r
- wc = BLOCKELEMENT_LIGHT_SHADE;\r
- }\r
- if(wc == L'\n') {\r
- *dest++ = L'\r';\r
- }\r
- *dest++ = (CHAR16)wc;\r
- }\r
- *dest = 0;\r
- return (ssize_t)i;\r
-}\r
-\r
/** Write data to a file.\r
\r
This function writes the specified number of bytes to the file at the current\r
QUESTION: Should writes to stdout or stderr always succeed?\r
**/\r
ssize_t\r
-write (int fildes, const void *buf, size_t n)\r
+write (int fd, const void *buf, size_t nbyte)\r
{\r
+ struct __filedes *filp;\r
ssize_t BufSize;\r
- EFI_FILE_HANDLE FileHandle;\r
- RETURN_STATUS Status = RETURN_SUCCESS;\r
- ssize_t UniBufSz;\r
+// EFI_FILE_HANDLE FileHandle;\r
+// RETURN_STATUS Status = RETURN_SUCCESS;\r
+\r
+ BufSize = (ssize_t)nbyte;\r
\r
- BufSize = (ssize_t)n;\r
+ if(ValidateFD( fd, VALID_OPEN)) {\r
+ filp = &gMD->fdarray[fd];\r
\r
- if(ValidateFD( fildes, VALID_OPEN)) {\r
- FileHandle = gMD->fdarray[fildes].FileHandle;\r
- if(isatty(fildes)) {\r
- // Convert string from MBCS to WCS and translate \n to \r\n.\r
- UniBufSz = WideTtyCvt(gMD->UString, (const char *)buf, n);\r
- if(UniBufSz > 0) {\r
- BufSize = (ssize_t)(UniBufSz * sizeof(CHAR16));\r
- Status = FileHandle->Write( FileHandle, (UINTN *)&BufSize, (void *)gMD->UString);\r
- BufSize = (ssize_t)n; // Always pretend all was output\r
- }\r
+ BufSize = filp->f_ops->fo_write(filp, &filp->f_offset, nbyte, buf);\r
}\r
else {\r
- Status = ShellWriteFile( FileHandle, (UINTN *)&BufSize, (void *)buf);\r
- }\r
- if(Status != RETURN_SUCCESS) {\r
- EFIerrno = Status;\r
- errno = EFI2errno(Status);\r
- if(Status == EFI_UNSUPPORTED) {\r
- errno = EISDIR;\r
+ errno = EBADF;\r
+ BufSize = -EBADF;\r
}\r
- BufSize = -1;\r
+ return BufSize;\r
+}\r
+\r
+/** Gets the current working directory.\r
+\r
+ The getcwd() function shall place an absolute pathname of the current \r
+ working directory in the array pointed to by buf, and return buf. The \r
+ pathname copied to the array shall contain no components that are \r
+ symbolic links. The size argument is the size in bytes of the character \r
+ array pointed to by the buf argument. \r
+ \r
+ @param[in,out] buf The buffer to fill.\r
+ @param[in] size The number of bytes in buffer.\r
+\r
+ @retval NULL The function failed.\r
+ @retval NULL Buf was NULL.\r
+ @retval NULL Size was 0.\r
+ @return buf The function completed successfully. See errno for info.\r
+**/\r
+char \r
+*getcwd (char *buf, size_t size) \r
+{\r
+ CONST CHAR16 *Cwd;\r
+\r
+ if (size == 0 || buf == NULL) {\r
+ errno = EINVAL;\r
+ return NULL;\r
}\r
+\r
+ Cwd = ShellGetCurrentDir(NULL);\r
+ if (Cwd == NULL) {\r
+ errno = EACCES;\r
+ return NULL;\r
}\r
- else {\r
- errno = EBADF;\r
+ if (size < ((StrLen (Cwd) + 1) * sizeof (CHAR8))) {\r
+ errno = ERANGE;\r
+ return (NULL);\r
}\r
- return BufSize;\r
+ \r
+ return (UnicodeStrToAsciiStr(Cwd, buf));\r
}\r