]> git.proxmox.com Git - mirror_edk2.git/blobdiff - StdLib/LibC/Uefi/SysCalls.c
Add device abstraction code for the UEFI Console and UEFI Shell-based file systems.
[mirror_edk2.git] / StdLib / LibC / Uefi / SysCalls.c
index 624d45878e166e78aa218cf545c01f244125b18b..b3ca5b89b4993ad958e525f76b37da1099d13b45 100644 (file)
@@ -13,6 +13,7 @@
 **/\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
@@ -66,15 +49,18 @@ NormalizePath( const CHAR16 *path)
     @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
@@ -91,7 +77,7 @@ ValidateFD( int fd, int IsOpen)
   @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
@@ -102,8 +88,8 @@ FindFreeFD( int MinFd )
 \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
@@ -111,6 +97,22 @@ FindFreeFD( int MinFd )
   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
@@ -119,15 +121,14 @@ FindFreeFD( int MinFd )
                   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
@@ -138,16 +139,19 @@ isatty  (int fildes)
 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
@@ -160,36 +164,37 @@ IsDupFd( int fd)
 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
@@ -210,41 +215,28 @@ close  (int fd)
   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
@@ -366,23 +358,23 @@ fcntl     (int fildes, int cmd, ...)
         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
@@ -441,9 +433,10 @@ dup2    (int fildes, int fildes2)
     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
@@ -486,53 +479,21 @@ dup2    (int fildes, int fildes2)
               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
@@ -551,37 +512,35 @@ lseek (int fildes, __off_t offset, int how)
     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
@@ -608,112 +567,215 @@ mkdir (const char *path, __mode_t perms)
     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
@@ -745,168 +807,54 @@ open   (const char *name, int oflags, int mode)
               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
@@ -935,7 +883,7 @@ _EFI_FileInfo( EFI_FILE_INFO *FileInfo, struct stat *statbuf)
       - 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
@@ -943,37 +891,19 @@ _EFI_FileInfo( EFI_FILE_INFO *FileInfo, struct stat *statbuf)
                   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
@@ -988,26 +918,17 @@ fstat (int fildes, struct stat *statbuf)
 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
@@ -1017,6 +938,33 @@ lstat (const char *path, struct stat *statbuf)
   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
@@ -1083,59 +1031,22 @@ lstat (const char *path, struct stat *statbuf)
 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
@@ -1159,40 +1070,62 @@ WideTtyCvt( CHAR16 *dest, const char *buf, size_t n)
   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