Home | History | Annotate | Download | only in Uefi
      1 /** @file
      2   EFI versions of NetBSD system calls.
      3 
      4   Copyright (c) 2016, Daryl McDaniel. All rights reserved.<BR>
      5   Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
      6   This program and the accompanying materials are licensed and made available under
      7   the terms and conditions of the BSD License that accompanies this distribution.
      8   The full text of the license may be found at
      9   http://opensource.org/licenses/bsd-license.
     10 
     11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 #include  <Uefi.h>
     16 #include  <Library/UefiLib.h>
     17 #include  <Library/UefiBootServicesTableLib.h>
     18 #include  <Library/BaseLib.h>
     19 #include  <Library/MemoryAllocationLib.h>
     20 #include  <Library/ShellLib.h>
     21 
     22 #include  <LibConfig.h>
     23 #include  <sys/EfiCdefs.h>
     24 
     25 #include  <sys/ansi.h>
     26 #include  <errno.h>
     27 #include  <stdarg.h>
     28 #include  <stdlib.h>
     29 #include  <string.h>
     30 #include  <wchar.h>
     31 #include  <sys/poll.h>
     32 #include  <sys/fcntl.h>
     33 #include  <sys/stat.h>
     34 #include  <sys/syslimits.h>
     35 #include  <sys/filio.h>
     36 #include  <Efi/SysEfi.h>
     37 #include  <unistd.h>
     38 #include  <kfile.h>
     39 #include  <Device/Device.h>
     40 #include  <Device/IIO.h>
     41 #include  <MainData.h>
     42 #include  <extern.h>
     43 
     44 /* EFI versions of BSD system calls used in stdio */
     45 
     46 /*  Validate that fd refers to a valid file descriptor.
     47     IsOpen is interpreted as follows:
     48       - Positive  fd must be OPEN
     49       - Zero      fd must be CLOSED
     50       - Negative  fd may be OPEN or CLOSED
     51 
     52     @retval TRUE  fd is VALID
     53     @retval FALSE fd is INVALID
     54 */
     55 BOOLEAN
     56 ValidateFD( int fd, int IsOpen)
     57 {
     58   struct __filedes    *filp;
     59   BOOLEAN   retval = FALSE;
     60 
     61   if((fd >= 0) && (fd < OPEN_MAX)) {
     62     filp = &gMD->fdarray[fd];
     63     retval = TRUE;
     64     if(IsOpen >= 0) {
     65       retval = (BOOLEAN)((filp->f_iflags != 0)  &&    // TRUE if OPEN
     66                          FILE_IS_USABLE(filp));         // and Usable (not Larval or Closing)
     67       if(IsOpen == VALID_CLOSED) {
     68         retval = (BOOLEAN)!retval;                      // We want TRUE if CLOSED
     69       }
     70     }
     71   }
     72   return retval;
     73 }
     74 
     75 /* Find and reserve a free File Descriptor.
     76 
     77   Returns the first free File Descriptor greater than or equal to the,
     78   already validated, fd specified by Minfd.
     79 
     80   @return   Returns -1 if there are no free FDs.  Otherwise returns the
     81             found fd.
     82 */
     83 int
     84 FindFreeFD( int MinFd )
     85 {
     86   struct __filedes    *Mfd;
     87   int i;
     88   int fd = -1;
     89 
     90   Mfd = gMD->fdarray;
     91 
     92   // Get an available fd
     93   for(i=MinFd; i < OPEN_MAX; ++i) {
     94     if(Mfd[i].f_iflags == 0) {
     95       Mfd[i].f_iflags = FIF_LARVAL; // Temporarily mark this fd as reserved
     96       fd = i;
     97       break;
     98     }
     99   }
    100   return fd;
    101 }
    102 
    103 /* Mark that an open file is to be deleted when closed. */
    104 int
    105 DeleteOnClose(int fd)
    106 {
    107   int   retval = 0;
    108 
    109   if(ValidateFD( fd, VALID_OPEN)) {
    110     gMD->fdarray[fd].f_iflags |= FIF_DELCLOSE;
    111   }
    112   else {
    113     errno = EBADF;
    114     retval = -1;
    115   }
    116   return retval;
    117 }
    118 
    119 /** The isatty() function tests whether fd, an open file descriptor,
    120     is associated with a terminal device.
    121 
    122     @param[in]  fd  File Descriptor for the file to be examined.
    123 
    124     @retval   1   fd is associated with a terminal.
    125     @retval   0   fd is not associated with a terminal.  errno is set to
    126                   EBADF if fd is not a valid open FD.
    127 **/
    128 int
    129 isatty  (int fd)
    130 {
    131   int   retval = 0;
    132   struct __filedes *Fp;
    133 
    134   if(ValidateFD( fd, VALID_OPEN)) {
    135     Fp = &gMD->fdarray[fd];
    136     retval =  (Fp->f_iflags & _S_ITTY) ? 1 : 0;
    137   }
    138   else {
    139     errno = EBADF;
    140   }
    141   return retval;
    142 }
    143 
    144 /** Determine if file descriptor fd is a duplicate of some other fd.
    145 
    146     @param[in]    fd    The file descriptor to check.
    147 
    148     @retval   TRUE    fd is a duplicate of another fd.
    149     @retval   FALSE   fd is unique.
    150 **/
    151 static BOOLEAN
    152 IsDupFd( int fd)
    153 {
    154   void * DevData;
    155   const struct fileops   *FileOps;
    156   int                   i;
    157   BOOLEAN               Ret = FALSE;
    158 
    159   if(ValidateFD( fd, VALID_OPEN )) {
    160     FileOps = gMD->fdarray[fd].f_ops;
    161     DevData = gMD->fdarray[fd].devdata;
    162     for(i=0; i < OPEN_MAX; ++i) {
    163       if(i == fd)   continue;
    164       if(ValidateFD( i, VALID_OPEN )) {   // TRUE if fd is valid and OPEN
    165         if((gMD->fdarray[i].f_ops == FileOps)
    166           &&(gMD->fdarray[i].devdata == DevData )) {
    167           Ret = TRUE;
    168           break;
    169         }
    170       }
    171     }
    172   }
    173   return Ret;
    174 }
    175 
    176 /** Worker function to Close a file and set its fd to the specified state.
    177 
    178     @param[in]    fd          The file descriptor to close.
    179     @param[in]    NewState    State to set the fd to after the file is closed.
    180 
    181     @retval    0    The operation completed successfully.
    182     @retval   -1    The operation failed.  Further information is in errno.
    183                       * EBADF   fd is not a valid or open file descriptor.
    184 **/
    185 static int
    186 _closeX  (int fd, int NewState)
    187 {
    188   struct __filedes     *Fp;
    189   int                   retval = 0;
    190 
    191   // Verify my pointers and get my FD.
    192   if(ValidateFD( fd, VALID_OPEN )) {
    193     Fp = &gMD->fdarray[fd];
    194     // Check if there are other users of this FileHandle
    195     if(Fp->RefCount == 1) { // There should be no other users
    196       if(! IsDupFd(fd)) {
    197         // Only do the close if no one else is using the FileHandle
    198         if(Fp->f_iflags & FIF_DELCLOSE) {
    199           /* Handle files marked "Delete on Close". */
    200           if(Fp->f_ops->fo_delete != NULL) {
    201             retval = Fp->f_ops->fo_delete(Fp);
    202           }
    203         }
    204         else {
    205           retval = Fp->f_ops->fo_close( Fp);
    206         }
    207       }
    208       Fp->f_iflags = NewState;    // Close this FD or reserve it
    209       Fp->RefCount = 0;           // No one using this FD
    210     }
    211     else {
    212       --Fp->RefCount;   /* One less user of this FD */
    213     }
    214   }
    215   else {
    216     // Bad FD
    217     retval = -1;
    218     errno = EBADF;
    219   }
    220   return retval;
    221 }
    222 
    223 /** The close() function deallocates the file descriptor indicated by fd.
    224     To deallocate means to make the file descriptor available for return by
    225     subsequent calls to open() or other functions that allocate file
    226     descriptors. All outstanding record locks owned by the process on the file
    227     associated with the file descriptor are removed (that is, unlocked).
    228 
    229     @param[in]    fd          Descriptor for the File to close.
    230 
    231     @retval   0     Successful completion.
    232     @retval   -1    An error occurred and errno is set to identify the error.
    233 **/
    234 int
    235 close  (int fd)
    236 {
    237   return _closeX(fd, 0);
    238 }
    239 
    240 /** Delete the file specified by path.
    241 
    242     @param[in]    path  The MBCS path of the file to delete.
    243 
    244     @retval   -1  Unable to open the file specified by path.
    245     @retval   -1  If (errno == EPERM), unlink is not permited for this file.
    246     @retval   -1  Low-level delete filed.  Reason is in errno.
    247     @retval   0   The file was successfully deleted.
    248 **/
    249 int
    250 unlink (const char *path)
    251 {
    252   struct __filedes     *Fp;
    253   int                   fd;
    254   int                   retval = -1;
    255 
    256   EFIerrno = RETURN_SUCCESS;
    257 
    258   fd = open(path, O_WRONLY, 0);
    259   if(fd >= 0) {
    260     Fp = &gMD->fdarray[fd];
    261 
    262     if(Fp->f_ops->fo_delete != NULL) {
    263       retval = Fp->f_ops->fo_delete(Fp);
    264   }
    265     Fp->f_iflags = 0;    // Close this FD
    266     Fp->RefCount = 0;    // No one using this FD
    267   }
    268   return retval;
    269 }
    270 
    271 /** The fcntl() function shall perform the operations described below on open
    272     files. The fildes argument is a file descriptor.
    273 
    274     The available values for cmd are defined in <fcntl.h> and are as follows:
    275       - F_DUPFD - Return a new file descriptor which shall be the lowest
    276                   numbered available (that is, not already open) file
    277                   descriptor greater than or equal to the third argument, arg,
    278                   taken as an integer of type int. The new file descriptor
    279                   shall refer to the same open file description as the original
    280                   file descriptor, and shall share any locks. The FD_CLOEXEC
    281                   flag associated with the new file descriptor shall be cleared
    282                   to keep the file open across calls to one of the exec functions.
    283       - F_GETFD - Get the file descriptor flags defined in <fcntl.h> that are
    284                   associated with the file descriptor fildes. File descriptor
    285                   flags are associated with a single file descriptor and do not
    286                   affect other file descriptors that refer to the same file.
    287       - F_SETFD - Set the file descriptor flags defined in <fcntl.h>, that are
    288                   associated with fildes, to the third argument, arg, taken
    289                   as type int. If the FD_CLOEXEC flag in the third argument
    290                   is 0, the file shall remain open across the exec
    291                   functions; otherwise, the file shall be closed upon
    292                   successful execution of one of the exec functions.
    293       - F_GETFL - Get the file status flags and file access modes, defined in
    294                   <fcntl.h>, for the file description associated with fildes.
    295                   The file access modes can be extracted from the return
    296                   value using the mask O_ACCMODE, which is defined in
    297                   <fcntl.h>. File status flags and file access modes are
    298                   associated with the file description and do not affect
    299                   other file descriptors that refer to the same file with
    300                   different open file descriptions.
    301       - F_SETFL - Set the file status flags, defined in <fcntl.h>, for the file
    302                   description associated with fildes from the corresponding
    303                   bits in the third argument, arg, taken as type int. Bits
    304                   corresponding to the file access mode and the file creation
    305                   flags, as defined in <fcntl.h>, that are set in arg shall
    306                   be ignored. If any bits in arg other than those mentioned
    307                   here are changed by the application, the result is unspecified.
    308       - F_GETOWN -  If fildes refers to a socket, get the process or process group
    309                   ID specified to receive SIGURG signals when out-of-band
    310                   data is available. Positive values indicate a process ID;
    311                   negative values, other than -1, indicate a process group
    312                   ID. If fildes does not refer to a socket, the results are
    313                   unspecified.
    314       - F_SETOWN -  If fildes refers to a socket, set the process or process
    315                   group ID specified to receive SIGURG signals when
    316                   out-of-band data is available, using the value of the third
    317                   argument, arg, taken as type int. Positive values indicate
    318                   a process ID; negative values, other than -1, indicate a
    319                   process group ID. If fildes does not refer to a socket, the
    320                   results are unspecified.
    321 
    322     The fcntl() function shall fail if:
    323 
    324     [EBADF]       The fildes argument is not a valid open file descriptor.
    325     [EINVAL]      The cmd argument is invalid, or the cmd argument is F_DUPFD
    326                   and arg is negative or greater than or equal to {OPEN_MAX}.
    327     [EMFILE]      The argument cmd is F_DUPFD and {OPEN_MAX} file descriptors
    328                   are currently open in the calling process, or no file
    329                   descriptors greater than or equal to arg are available.
    330     [EOVERFLOW]   One of the values to be returned cannot be represented correctly.
    331 
    332     @param[in]      fildes    Descriptor for the file to be controlled.
    333     @param[in]      cmd       Command to be acted upon.
    334     @param[in,out]  ...       Optional additional parameters as required by cmd.
    335 
    336     @return   Upon successful completion, the value returned shall depend on
    337               cmd as follows:
    338                 - F_DUPFD - A new file descriptor.
    339                 - F_GETFD - Value of flags defined in <fcntl.h>. The return value
    340                             shall not be negative.
    341                 - F_SETFD - Value other than -1.
    342                 - F_GETFL - Value of file status flags and access modes. The return
    343                             value is not negative.
    344                 - F_SETFL - Value other than -1.
    345                 - F_GETOWN  - Value of the socket owner process or process group;
    346                             this will not be -1.
    347                 - F_SETOWN - Value other than -1.
    348               Otherwise, -1 shall be returned and errno set to indicate the error.
    349 
    350 **/
    351 int
    352 fcntl     (int fildes, int cmd, ...)
    353 {
    354   va_list             p3;
    355   struct __filedes   *MyFd;
    356   int                 retval = -1;
    357   int                 temp;
    358 
    359 //Print(L"%a( %d, %d, ...)\n", __func__, fildes, cmd);
    360   va_start(p3, cmd);
    361 
    362   if(ValidateFD( fildes, VALID_OPEN )) {
    363     MyFd = &gMD->fdarray[fildes];
    364 
    365     switch(cmd) {
    366       case F_DUPFD:
    367         temp = va_arg(p3, int);
    368         if(ValidateFD( temp, VALID_DONT_CARE )) {
    369           temp = FindFreeFD( temp );
    370           if(temp < 0) {
    371             errno = EMFILE;
    372             break;
    373           }
    374           /* temp is now a valid fd reserved for further use
    375              so copy fd into temp.
    376           */
    377           (void)memcpy(&gMD->fdarray[temp], MyFd, sizeof(struct __filedes));
    378           retval = temp;
    379         }
    380         else {
    381           errno = EINVAL;
    382         }
    383         break;
    384 
    385       case F_SETFL:
    386         retval = MyFd->Oflags;        // Get original value
    387         temp = va_arg(p3, int);
    388         temp &= O_SETMASK;            // Only certain bits can be set
    389         temp |= retval & O_SETMASK;
    390         MyFd->Oflags = temp;          // Set new value
    391         break;
    392 
    393       case F_SETFD:
    394         retval = MyFd->f_iflags;
    395         break;
    396       //case F_SETOWN:
    397       //  retval = MyFd->SocProc;
    398       //  MyFd->SocProc = va_arg(p3, int);
    399       //  break;
    400       case F_GETFD:
    401         retval = MyFd->f_iflags;
    402         break;
    403       case F_GETFL:
    404         retval = MyFd->Oflags;
    405         break;
    406       //case F_GETOWN:
    407       //  retval = MyFd->SocProc;
    408       //  break;
    409       default:
    410         errno  = EINVAL;
    411         break;
    412     }
    413   }
    414   else {
    415     // Bad FD
    416     errno = EBADF;
    417   }
    418   va_end(p3);
    419   return retval;;
    420 }
    421 
    422 /** The dup() function provides an alternative interface to the
    423     service provided by fcntl() using the F_DUPFD command. The call:
    424       - fid = dup(fildes);
    425     shall be equivalent to:
    426       - fid = fcntl(fildes, F_DUPFD, 0);
    427 
    428     @param[in]    fildes    Descriptor for the file to be examined.
    429 
    430     @return   Upon successful completion a non-negative integer, namely the
    431               file descriptor, shall be returned; otherwise, -1 shall be
    432               returned and errno set to indicate the error.
    433 **/
    434 int
    435 dup   (int fildes)
    436 {
    437   return fcntl(fildes, F_DUPFD, 0);
    438 }
    439 
    440 /** Make fildes2 refer to a duplicate of fildes.
    441 
    442     The dup2() function provides an alternative interface to the
    443     service provided by fcntl() using the F_DUPFD command. The call:
    444       - fid = dup2(fildes, fildes2);
    445     shall be equivalent to:
    446       - close(fildes2);
    447       - fid = fcntl(fildes, F_DUPFD, fildes2);
    448     except for the following:
    449       - If fildes2 is less than 0 or greater than or equal to {OPEN_MAX},
    450         dup2() shall return -1 with errno set to [EBADF].
    451       - If fildes is a valid file descriptor and is equal to fildes2, dup2()
    452         shall return fildes2 without closing it.
    453       - If fildes is not a valid file descriptor, dup2() shall return -1 and
    454         shall not close fildes2.
    455       - The value returned shall be equal to the value of fildes2 upon
    456         successful completion, or -1 upon failure.
    457 
    458     @param[in]  fildes    File Descriptor to be duplicated.
    459     @param[in]  fildes2   File Descriptor to be made a duplicate of fildes.
    460 
    461     @return   Upon successful completion a non-negative integer, namely
    462               fildes2, shall be returned; otherwise, -1 shall be
    463               returned and errno set to EBADF indicate the error.
    464 **/
    465 int
    466 dup2    (int fildes, int fildes2)
    467 {
    468   int retval = -1;
    469 
    470   if(ValidateFD( fildes, VALID_OPEN)) {
    471     retval = fildes2;
    472     if( fildes != fildes2) {
    473       if(ValidateFD( fildes2, VALID_DONT_CARE)) {
    474         gMD->fdarray[fildes2].f_iflags = FIF_LARVAL;  // Mark the file closed, but reserved
    475         (void)memcpy(&gMD->fdarray[fildes2],      // Duplicate fildes into fildes2
    476                      &gMD->fdarray[fildes], sizeof(struct __filedes));
    477         gMD->fdarray[fildes2].MyFD = (UINT16)fildes2;
    478       }
    479       else {
    480         errno = EBADF;
    481         retval = -1;
    482       }
    483     }
    484   }
    485   else {
    486     errno = EBADF;
    487   }
    488   return retval;
    489 }
    490 
    491 /** Reposition a file's read/write offset.
    492 
    493     The lseek() function repositions the offset of the file descriptor fildes
    494     to the argument offset according to the directive how.  The argument
    495     fildes must be an open file descriptor.  lseek() repositions the file
    496     pointer fildes as follows:
    497 
    498       - If how is SEEK_SET, the offset is set to offset bytes.
    499 
    500       - If how is SEEK_CUR, the offset is set to its current location
    501         plus offset bytes.
    502 
    503       - If how is SEEK_END, the offset is set to the size of the file
    504         plus offset bytes.
    505 
    506     The lseek() function allows the file offset to be set beyond the end of
    507     the existing end-of-file of the file.  If data is later written at this
    508     point, subsequent reads of the data in the gap return bytes of zeros
    509     (until data is actually written into the gap).
    510 
    511     Some devices are incapable of seeking.  The value of the pointer associ-
    512     ated with such a device is undefined.
    513 
    514     @param[in]  fd        Descriptor for the File to be affected.
    515     @param[in]  offset    Value to adjust the file position by.
    516     @param[in]  how       How the file position is to be adjusted.
    517 
    518     @return   Upon successful completion, lseek() returns the resulting offset
    519               location as measured in bytes from the beginning of the file.
    520               Otherwise, a value of -1 is returned and errno is set to
    521               indicate the error.
    522 **/
    523 __off_t
    524 lseek (int fd, __off_t offset, int how)
    525 {
    526   __off_t             CurPos = -1;
    527 //  RETURN_STATUS       Status = RETURN_SUCCESS;
    528   struct __filedes   *filp;
    529 
    530   EFIerrno = RETURN_SUCCESS;    // In case of error without an EFI call
    531 
    532   if( how == SEEK_SET || how == SEEK_CUR  || how == SEEK_END) {
    533     if(ValidateFD( fd, VALID_OPEN)) {
    534       filp = &gMD->fdarray[fd];
    535       // Both of our parameters have been verified as valid
    536       CurPos = filp->f_ops->fo_lseek( filp, offset, how);
    537       if(CurPos >= 0) {
    538         filp->f_offset = CurPos;
    539       }
    540     }
    541     else {
    542       errno = EBADF;  // Bad File Descriptor
    543     }
    544   }
    545   else {
    546     errno = EINVAL;   // Invalid how argument
    547   }
    548   return CurPos;
    549 }
    550 
    551 /** The directory path is created with the access permissions specified by
    552     perms.
    553 
    554     The directory is closed after it is created.
    555 
    556     @param[in]  path    The path to a directory to create.
    557     @param[in]  perms   Permissions as defined in <sys/stat.h>
    558 
    559     @retval   0   The directory was created successfully.
    560     @retval  -1   An error occurred and error codes are stored in errno and EFIerrno.
    561 **/
    562 int
    563 mkdir (const char *path, __mode_t perms)
    564 {
    565   wchar_t            *NewPath;
    566   DeviceNode         *Node;
    567   char               *GenI;
    568   RETURN_STATUS       Status;
    569   int                 Instance  = 0;
    570   int                 retval = 0;
    571 
    572   Status = ParsePath(path, &NewPath, &Node, &Instance, NULL);
    573   if(Status == RETURN_SUCCESS) {
    574     GenI = Node->InstanceList;
    575     if(GenI == NULL) {
    576       errno   = EPERM;
    577       retval  = -1;
    578       }
    579     else {
    580       //GenI += (Instance * Node->InstanceSize);
    581       retval = ((GenericInstance *)GenI)->Abstraction.fo_mkdir( path, perms);
    582       }
    583     free(NewPath);
    584     }
    585   else {
    586     retval = -1;
    587   }
    588   return retval;
    589 }
    590 
    591 /** Open a file.
    592     The open() function establishes the connection between a file and a file
    593     descriptor.  It creates an open file description that refers to a file
    594     and a file descriptor that refers to that open file description. The file
    595     descriptor is used by other I/O functions to refer to that file.
    596 
    597     The open() function returns a file descriptor for the named file that is
    598     the lowest file descriptor not currently open for that process. The open
    599     file description is new, and therefore the file descriptor shall not
    600     share it with any other process in the system.
    601 
    602     The file offset used to mark the current position within the file is set
    603     to the beginning of the file.
    604 
    605     The EFI ShellOpenFileByName() function is used to perform the low-level
    606     file open operation.  The primary task of open() is to translate from the
    607     flags used in the <stdio.h> environment to those used by the EFI function.
    608 
    609     The file status flags and file access modes of the open file description
    610     are set according to the value of oflags.
    611 
    612     Values for oflags are constructed by a bitwise-inclusive OR of flags from
    613     the following list, defined in <fcntl.h>. Applications shall specify
    614     exactly one of { O_RDONLY, O_RDWR, O_WRONLY } in the value of oflags.
    615     Any combination of { O_NONBLOCK, O_APPEND, O_CREAT, O_TRUNC, O_EXCL } may
    616     also be specified in oflags.
    617 
    618     The only valid flag combinations for ShellOpenFileByName() are:
    619       - Read
    620       - Read/Write
    621       - Create/Read/Write
    622 
    623     Values for mode specify the access permissions for newly created files.
    624     The mode value is saved in the FD to indicate permissions for further operations.
    625 
    626     O_RDONLY      -- flags = EFI_FILE_MODE_READ -- this is always done
    627     O_WRONLY      -- flags |= EFI_FILE_MODE_WRITE
    628     O_RDWR        -- flags |= EFI_FILE_MODE_WRITE -- READ is already set
    629 
    630     O_NONBLOCK    -- ignored
    631     O_APPEND      -- Seek to EOF before every write
    632     O_CREAT       -- flags |= EFI_FILE_MODE_CREATE
    633     O_TRUNC       -- delete first then create new
    634     O_EXCL        -- if O_CREAT is also set, open will fail if the file already exists.
    635 
    636     @param[in]    Path      The path argument points to a pathname naming the
    637                             object to be opened.
    638     @param[in]    oflags    File status flags and file access modes of the
    639                             open file description.
    640     @param[in]    mode      File access permission bits as defined in
    641                             <sys/stat.h>.  Only used if a file is created
    642                             as a result of the open.
    643 
    644     @return     Upon successful completion, open() opens the file and returns
    645                 a non-negative integer representing the lowest numbered
    646                 unused file descriptor. Otherwise, open returns -1 and sets
    647                 errno to indicate the error. If a negative value is
    648                 returned, no files are created or modified.
    649                   - EMFILE - No file descriptors available -- Max number already open.
    650                   - EINVAL - Bad value specified for oflags or mode.
    651                   - ENOMEM - Failure allocating memory for internal buffers.
    652                   - EEXIST - File exists and open attempted with (O_EXCL | O_CREAT) set.
    653                   - EIO - UEFI failure.  Check value in EFIerrno.
    654 **/
    655 int
    656 open(
    657   const char *path,
    658   int oflags,
    659   int mode
    660   )
    661 {
    662   wchar_t              *NewPath;
    663   wchar_t              *MPath;
    664   DeviceNode           *Node;
    665   struct __filedes     *filp;
    666   struct termios       *Termio;
    667   int                   Instance  = 0;
    668   RETURN_STATUS         Status;
    669   UINT32                OpenMode;
    670   int                   fd = -1;
    671   int                   doresult;
    672 
    673   Status = ParsePath(path, &NewPath, &Node, &Instance, &MPath);
    674   if(Status == RETURN_SUCCESS) {
    675     if ((Node == NULL)               ||
    676         (Node->InstanceList == NULL))
    677     {
    678       errno   = EPERM;
    679     }
    680     else {
    681       // Could add a test to see if the file name begins with a period.
    682       // If it does, then add the HIDDEN flag to Attributes.
    683 
    684       // Get an available fd
    685       fd = FindFreeFD( VALID_CLOSED );
    686 
    687       if( fd < 0 ) {
    688         // All available FDs are in use
    689         errno = EMFILE;
    690       }
    691       else {
    692         filp = &gMD->fdarray[fd];
    693         // Save the flags and mode in the File Descriptor
    694         filp->Oflags = oflags;
    695         filp->Omode = mode;
    696 
    697         doresult = Node->OpenFunc(Node, filp, Instance, NewPath, MPath);
    698         if(doresult < 0) {
    699           filp->f_iflags = 0;   // Release this FD
    700           fd = -1;              // Indicate an error
    701         }
    702         else {
    703           // Build our final f_iflags value
    704           OpenMode  = ( mode & S_ACC_READ )  ? S_ACC_READ : 0;
    705           OpenMode |= ( mode & S_ACC_WRITE ) ? S_ACC_WRITE : 0;
    706 
    707           filp->f_iflags |= OpenMode;
    708 
    709           if((oflags & O_TTY_INIT) && (filp->f_iflags & _S_ITTY) && (filp->devdata != NULL)) {
    710             // Initialize the device's termios flags to a "sane" value
    711             Termio = &((cIIO *)filp->devdata)->Termio;
    712             Termio->c_iflag = ICRNL | IGNSPEC;
    713             Termio->c_oflag = OPOST | ONLCR | OXTABS | ONOEOT | ONOCR | ONLRET | OCTRL;
    714             Termio->c_lflag = ECHO | ECHOE | ECHONL | ICANON;
    715             Termio->c_cc[VERASE]  = 0x08;   // ^H Backspace
    716             Termio->c_cc[VKILL]   = 0x15;   // ^U
    717             Termio->c_cc[VINTR]   = 0x03;   // ^C Interrupt character
    718           }
    719           ++filp->RefCount;
    720           FILE_SET_MATURE(filp);
    721         }
    722       }
    723     }
    724     free(NewPath);
    725   }
    726   free(MPath);    // We don't need this any more.
    727 
    728   // return the fd of our now open file
    729   return fd;
    730 }
    731 
    732 
    733 /**
    734   Poll a list of file descriptors.
    735 
    736   The ::poll routine waits for up to timeout milliseconds for an event
    737   to occur on one or more of the file descriptors listed.  The event
    738   types of interested are specified for each file descriptor in the events
    739   field.  The actual event detected is returned in the revents field of
    740   the array.  The
    741   <a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">POSIX</a>
    742   documentation is available online.
    743 
    744   @param[in]  pfd       Address of an array of pollfd structures.
    745 
    746   @param[in]  nfds      Number of elements in the array of pollfd structures.
    747 
    748   @param[in]  timeout   Length of time in milliseconds to wait for the event
    749 
    750   @return     The number of file descriptors with detected events.  Zero
    751               indicates that the call timed out and -1 indicates an error.
    752 
    753  **/
    754 int
    755 poll (
    756   struct pollfd * pfd,
    757   nfds_t nfds,
    758   int timeout
    759   )
    760 {
    761   struct __filedes * pDescriptor;
    762   struct pollfd * pEnd;
    763   struct pollfd * pPollFD;
    764   int SelectedFDs;
    765   EFI_STATUS Status;
    766   EFI_EVENT Timer;
    767   UINT64 TimerTicks;
    768 
    769   //
    770   //  Create the timer for the timeout
    771   //
    772   Timer = NULL;
    773   Status = EFI_SUCCESS;
    774   if ( INFTIM != timeout ) {
    775     Status = gBS->CreateEvent ( EVT_TIMER,
    776                                 TPL_NOTIFY,
    777                                 NULL,
    778                                 NULL,
    779                                 &Timer );
    780     if ( !EFI_ERROR ( Status )) {
    781       //
    782       //  Start the timeout timer
    783       //
    784       TimerTicks = timeout;
    785       TimerTicks *= 1000 * 10;
    786       Status = gBS->SetTimer ( Timer,
    787                                TimerRelative,
    788                                TimerTicks );
    789     }
    790     else {
    791       SelectedFDs = -1;
    792       errno = ENOMEM;
    793     }
    794   }
    795   if ( !EFI_ERROR ( Status )) {
    796     //
    797     //  Poll until an event is detected or the timer fires
    798     //
    799     SelectedFDs = 0;
    800     errno = 0;
    801     do {
    802       //
    803       //  Poll the list of file descriptors
    804       //
    805       pPollFD = pfd;
    806       pEnd = &pPollFD [ nfds ];
    807       while ( pEnd > pPollFD ) {
    808         //
    809         //  Validate the file descriptor
    810         //
    811         if ( !ValidateFD ( pPollFD->fd, VALID_OPEN )) {
    812           errno = EINVAL;
    813           return -1;
    814         }
    815 
    816         //
    817         //  Poll the device or file
    818         //
    819         pDescriptor = &gMD->fdarray [ pPollFD->fd ];
    820         pPollFD->revents = pDescriptor->f_ops->fo_poll ( pDescriptor,
    821                                                          pPollFD->events );
    822 
    823         //
    824         //  Determine if this file descriptor detected an event
    825         //
    826         if ( 0 != pPollFD->revents ) {
    827           //
    828           //  Select this descriptor
    829           //
    830           SelectedFDs += 1;
    831         }
    832 
    833         //
    834         //  Set the next file descriptor
    835         //
    836         pPollFD += 1;
    837       }
    838 
    839       //
    840       //  Check for timeout
    841       //
    842       if ( NULL != Timer ) {
    843         Status = gBS->CheckEvent ( Timer );
    844         if ( EFI_SUCCESS == Status ) {
    845           //
    846           //  Timeout
    847           //
    848           break;
    849         }
    850         else if ( EFI_NOT_READY == Status ) {
    851           Status = EFI_SUCCESS;
    852     }
    853     }
    854     } while (( 0 == SelectedFDs )
    855         && ( EFI_SUCCESS == Status ));
    856 
    857     //
    858     //  Stop the timer
    859     //
    860     if ( NULL != Timer ) {
    861       gBS->SetTimer ( Timer,
    862                       TimerCancel,
    863                       0 );
    864   }
    865   }
    866   else {
    867     SelectedFDs = -1;
    868     errno = EAGAIN;
    869   }
    870 
    871   //
    872   //  Release the timer
    873   //
    874   if ( NULL != Timer ) {
    875     gBS->CloseEvent ( Timer );
    876   }
    877 
    878   //
    879   //  Return the number of selected file system descriptors
    880   //
    881   return SelectedFDs;
    882 }
    883 
    884 
    885 /** The rename() function changes the name of a file.
    886     The From argument points to the pathname of the file to be renamed. The To
    887     argument points to the new pathname of the file.
    888 
    889     If the From argument points to the pathname of a file that is not a
    890     directory, the To argument shall not point to the pathname of a
    891     directory. If the file named by the To argument exists, it shall be
    892     removed and From renamed to To. Write access permission is required for
    893     both the directory containing old and the directory containing To.
    894 
    895     If the From argument points to the pathname of a directory, the To
    896     argument shall not point to the pathname of a file that is not a
    897     directory. If the directory named by the To argument exists, it shall be
    898     removed and From renamed to To.
    899 
    900     The To pathname shall not contain a path prefix that names From. Write
    901     access permission is required for the directory containing From and the
    902     directory containing To. If the From argument points to the pathname of a
    903     directory, write access permission may be required for the directory named
    904     by From, and, if it exists, the directory named by To.
    905 
    906     If the rename() function fails for any reason other than [EIO], any file
    907     named by To shall be unaffected.
    908 
    909     @param[in]  From    Path to the file to be renamed.
    910     @param[in]  To      The new name of From.
    911 
    912     @retval   0     Successful completion.
    913     @retval   -1    An error has occured and errno has been set to further specify the error.
    914                     Neither the file named by From nor the file named by To are
    915                     changed or created.
    916                       - ENXIO: Path specified is not supported by any loaded driver.
    917                       - ENOMEM: Insufficient memory to calloc a MapName buffer.
    918                       - EINVAL: The path parameter is not valid.
    919 **/
    920 int
    921 rename(
    922   const char *From,
    923   const char *To
    924   )
    925 {
    926   wchar_t            *FromPath;
    927   DeviceNode         *FromNode;
    928   char               *GenI;
    929   int                 Instance    = 0;
    930   RETURN_STATUS       Status;
    931   int                 retval      = -1;
    932 
    933   Status = ParsePath(From, &FromPath, &FromNode, &Instance, NULL);
    934   if(Status == RETURN_SUCCESS) {
    935     GenI = FromNode->InstanceList;
    936     if(GenI == NULL) {
    937       errno   = EPERM;
    938       retval  = -1;
    939       }
    940       else {
    941       //GenI += (Instance * FromNode->InstanceSize);
    942       retval = ((GenericInstance *)GenI)->Abstraction.fo_rename( From, To);
    943               }
    944     free(FromPath);
    945             }
    946   return retval;
    947 }
    948 
    949 /** Delete a specified directory.
    950 
    951     @param[in]  path    Path to the directory to delete.
    952 
    953     @retval   -1    The directory couldn't be opened (doesn't exist).
    954     @retval   -1    The directory wasn't empty or an IO error occured.
    955 **/
    956 int
    957 rmdir(
    958   const char *path
    959   )
    960 {
    961   struct __filedes   *filp;
    962   int                 fd;
    963   int                 retval = -1;
    964 
    965   fd = open(path, O_RDWR, 0);
    966   if(fd >= 0) {
    967     filp = &gMD->fdarray[fd];
    968 
    969     retval = filp->f_ops->fo_rmdir(filp);
    970     filp->f_iflags = 0;           // Close this FD
    971     filp->RefCount = 0;           // No one using this FD
    972   }
    973   return retval;
    974 }
    975 
    976 /** The fstat() function obtains information about an open file associated
    977     with the file descriptor fd, and writes it to the area pointed to
    978     by statbuf.
    979 
    980     The statbuf argument is a pointer to a stat structure, as defined
    981     in <sys/stat.h>, into which information is placed concerning the file.
    982 
    983     The structure members st_mode, st_ino, st_dev, st_uid, st_gid, st_atime,
    984     st_ctime, and st_mtime shall have meaningful values. The value of the
    985     member st_nlink shall be set to the number of links to the file.
    986 
    987     The fstat() function shall update any time-related fields before writing
    988     into the stat structure.
    989 
    990     The fstat() function is implemented using the ShellGetFileInfo()
    991     function.
    992 
    993     The stat structure members which don't have direct analogs to EFI file
    994     information are filled in as follows:
    995       - st_mode     Populated with information from fd
    996       - st_ino      Set to zero.  (inode)
    997       - st_dev      Set to zero.
    998       - st_uid      Set to zero.
    999       - st_gid      Set to zero.
   1000       - st_nlink    Set to one.
   1001 
   1002     @param[in]    fd        File descriptor as returned from open().
   1003     @param[out]   statbuf   Buffer in which the file status is put.
   1004 
   1005     @retval    0  Successful Completion.
   1006     @retval   -1  An error has occurred and errno has been set to
   1007                   identify the error.
   1008 **/
   1009 int
   1010 fstat (int fd, struct stat *statbuf)
   1011 {
   1012   int                 retval = -1;
   1013   struct __filedes   *filp;
   1014 
   1015   if(ValidateFD( fd, VALID_OPEN)) {
   1016     filp = &gMD->fdarray[fd];
   1017     retval = filp->f_ops->fo_stat(filp, statbuf, NULL);
   1018       }
   1019       else {
   1020     errno   =  EBADF;
   1021       }
   1022   return retval;
   1023 }
   1024 
   1025 /** Obtains information about the file pointed to by path.
   1026 
   1027     Opens the file pointed to by path, calls _EFI_FileInfo with the file's handle,
   1028     then closes the file.
   1029 
   1030     @param[in]    path      Path to the file to obtain information about.
   1031     @param[out]   statbuf   Buffer in which the file status is put.
   1032 
   1033     @retval    0  Successful Completion.
   1034     @retval   -1  An error has occurred and errno has been set to
   1035                   identify the error.
   1036 **/
   1037 int
   1038 stat   (const char *path, struct stat *statbuf)
   1039 {
   1040   int                 fd;
   1041   int                 retval  = -1;
   1042   struct __filedes   *filp;
   1043 
   1044   fd = open(path, O_RDONLY, 0);
   1045   if(fd >= 0) {
   1046     filp = &gMD->fdarray[fd];
   1047     retval = filp->f_ops->fo_stat( filp, statbuf, NULL);
   1048     close(fd);
   1049   }
   1050   return retval;
   1051 }
   1052 
   1053 /**  Same as stat since EFI doesn't have symbolic links.
   1054 
   1055     @param[in]    path      Path to the file to obtain information about.
   1056     @param[out]   statbuf   Buffer in which the file status is put.
   1057 
   1058     @retval    0  Successful Completion.
   1059     @retval   -1  An error has occurred and errno has been set to
   1060                   identify the error.
   1061 **/
   1062 int
   1063 lstat (const char *path, struct stat *statbuf)
   1064 {
   1065   return stat(path, statbuf);
   1066 }
   1067 
   1068 /** Control a device.
   1069 
   1070     @param[in]        fd        Descriptor for the file to be acted upon.
   1071     @param[in]        request   Specifies the operation to perform.
   1072     @param[in,out]    ...       Zero or more parameters as required for request.
   1073 
   1074     @retval   >=0   The operation completed successfully.
   1075     @retval   -1    An error occured.  More information is in errno.
   1076 **/
   1077 int
   1078 ioctl(
   1079   int             fd,
   1080   unsigned long   request,
   1081   ...
   1082   )
   1083 {
   1084   int                 retval = -1;
   1085   struct __filedes   *filp;
   1086   va_list             argp;
   1087 
   1088   va_start(argp, request);
   1089 
   1090   if(ValidateFD( fd, VALID_OPEN)) {
   1091     filp = &gMD->fdarray[fd];
   1092 
   1093     if(request == FIODLEX) {
   1094       /* set Delete-on-Close */
   1095       filp->f_iflags |= FIF_DELCLOSE;
   1096       retval = 0;
   1097     }
   1098     else if(request == FIONDLEX) {
   1099       /* clear Delete-on-Close */
   1100       filp->f_iflags &= ~FIF_DELCLOSE;
   1101       retval = 0;
   1102     }
   1103     else {
   1104       /* All other requests. */
   1105       retval = filp->f_ops->fo_ioctl(filp, request, argp);
   1106     }
   1107   }
   1108   else {
   1109     errno   =  EBADF;
   1110   }
   1111   va_end(argp);
   1112 
   1113   return retval;
   1114 }
   1115 
   1116 /** Read from a file.
   1117 
   1118     The read() function shall attempt to read nbyte bytes from the file
   1119     associated with the open file descriptor, fildes, into the buffer pointed
   1120     to by buf.
   1121 
   1122     Before any action described below is taken, and if nbyte is zero, the
   1123     read() function may detect and return errors as described below. In the
   1124     absence of errors, or if error detection is not performed, the read()
   1125     function shall return zero and have no other results.
   1126 
   1127     On files that support seeking (for example, a regular file), the read()
   1128     shall start at a position in the file given by the file offset associated
   1129     with fildes. The file offset shall be incremented by the number of bytes
   1130     actually read.
   1131 
   1132     Files that do not support seeking - for example, terminals - always read
   1133     from the current position. The value of a file offset associated with
   1134     such a file is undefined.
   1135 
   1136     No data transfer shall occur past the current end-of-file. If the
   1137     starting position is at or after the end-of-file, 0 shall be returned.
   1138 
   1139     The read() function reads data previously written to a file. If any
   1140     portion of a regular file prior to the end-of-file has not been written,
   1141     read() shall return bytes with value 0. For example, lseek() allows the
   1142     file offset to be set beyond the end of existing data in the file. If data
   1143     is later written at this point, subsequent reads in the gap between the
   1144     previous end of data and the newly written data shall return bytes with
   1145     value 0 until data is written into the gap.
   1146 
   1147     Upon successful completion, where nbyte is greater than 0, read() shall
   1148     mark for update the st_atime field of the file, and shall return the
   1149     number of bytes read. This number shall never be greater than nbyte. The
   1150     value returned may be less than nbyte if the number of bytes left in the
   1151     file is less than nbyte, if the read() request was interrupted by a
   1152     signal, or if the file is a pipe or FIFO or special file and has fewer
   1153     than nbyte bytes immediately available for reading. For example, a read()
   1154     from a file associated with a terminal may return one typed line of data.
   1155 
   1156     If fildes does not refer to a directory, the function reads the requested
   1157     number of bytes from the file at the file's current position and returns
   1158     them in buf. If the read goes beyond the end of the file, the read
   1159     length is truncated to the end of the file. The file's current position is
   1160     increased by the number of bytes returned.
   1161 
   1162     If fildes refers to a directory, the function reads the directory entry at
   1163     the file's current position and returns the entry in buf. If buf
   1164     is not large enough to hold the current directory entry, then
   1165     errno is set to EBUFSIZE, EFIerrno is set to EFI_BUFFER_TOO_SMALL, and the
   1166     current file position is not updated. The size of the buffer needed to read
   1167     the entry will be returned as a negative number. On success, the current
   1168     position is updated to the next directory entry. If there are no more
   1169     directory entries, the read returns a zero-length buffer.
   1170     EFI_FILE_INFO is the structure returned as the directory entry.
   1171 
   1172     @param[in]    fildes  Descriptor of the file to be read.
   1173     @param[out]   buf     Pointer to location in which to store the read data.
   1174     @param[in]    nbyte   Maximum number of bytes to be read.
   1175 
   1176     @return   Upon successful completion, read() returns a non-negative integer
   1177               indicating the number of bytes actually read. Otherwise, the
   1178               functions return a negative value and sets errno to indicate the
   1179               error.  If errno is EBUFSIZE, the absolute value of the
   1180               return value indicates the size of the buffer needed to read
   1181               the directory entry.
   1182 **/
   1183 ssize_t
   1184 read   (int fildes, void *buf, size_t nbyte)
   1185 {
   1186   struct __filedes *filp;
   1187   cIIO             *IIO;
   1188   ssize_t           BufSize;
   1189 
   1190   BufSize = (ssize_t)nbyte;
   1191   if(BufSize > 0) {
   1192     if(ValidateFD( fildes, VALID_OPEN)) {
   1193       filp = &gMD->fdarray[fildes];
   1194 
   1195       IIO = filp->devdata;
   1196       if(isatty(fildes) && (IIO != NULL)) {
   1197         BufSize = IIO->Read(filp, nbyte, buf);
   1198       }
   1199       else {
   1200         BufSize = filp->f_ops->fo_read(filp, &filp->f_offset, nbyte, buf);
   1201       }
   1202     }
   1203     else {
   1204       errno = EBADF;
   1205       BufSize = -1;
   1206     }
   1207   }
   1208   return BufSize;
   1209 }
   1210 
   1211 /** Write data to a file.
   1212 
   1213     This function writes the specified number of bytes to the file at the current
   1214     file position. The current file position is advanced the actual number of bytes
   1215     written. Partial writes only occur when there has been a data error during
   1216     the write attempt (such as "volume space full").  The file is automatically
   1217     grown to hold the data if required.
   1218 
   1219     Direct writes to opened directories are not supported.
   1220 
   1221     If fildes refers to a terminal device, isatty() returns TRUE, a partial write
   1222     will occur if a NULL or EOF character is encountered before n characters have
   1223     been written.  Characters inserted due to line-end translations or TAB
   1224     expansion will not be counted.  Unconvertable characters are translated into
   1225     the UEFI character BLOCKELEMENT_LIGHT_SHADE.
   1226 
   1227     Since the UEFI console device works on wide characters, the buffer is assumed
   1228     to contain a byte-oriented multi-byte character stream which is then
   1229     translated to wide characters using the mbtowc() functions.  The resulting
   1230     wide character stream is what is actually sent to the UEFI console.
   1231 
   1232     Although both text and binary wide-oriented streams are conceptually
   1233     sequences of wide characters, the external file associated with a
   1234     wide-oriented stream is a sequence of multibyte characters,
   1235     generalized as follows:
   1236       - Multibyte encodings within files may contain embedded null bytes
   1237         (unlike multibyte encodings valid for use internal to the program).
   1238       - A file need not begin nor end in the initial shift state.
   1239 
   1240     @param[in]  fd      Descriptor of file to be written to.
   1241     @param[in]  buf     Pointer to data to write to the file.
   1242     @param[in]  nbyte   Number of bytes to be written to the file.
   1243 
   1244     @retval   >=0   Number of bytes actually written to the file.
   1245     @retval   <0    An error occurred.  More data is provided by errno.
   1246 **/
   1247 ssize_t
   1248 write  (int fd, const void *buf, size_t nbyte)
   1249 {
   1250   struct __filedes *filp;
   1251   cIIO             *IIO;
   1252   ssize_t           BufSize;
   1253 
   1254   BufSize = (ssize_t)nbyte;
   1255 
   1256   if(ValidateFD( fd, VALID_OPEN)) {
   1257     filp = &gMD->fdarray[fd];
   1258     if ((filp->Oflags & O_ACCMODE) != 0) {
   1259       // File is open for writing
   1260       IIO = filp->devdata;
   1261       if(isatty(fd) && (IIO != NULL)) {
   1262         // Output to an Interactive I/O device
   1263         // (Terminal device or the slave side of a pseudo-tty)
   1264         BufSize = IIO->Write(filp, buf, nbyte);
   1265       }
   1266       else {
   1267         // Output to a regular file, socket, pipe, etc.
   1268         BufSize = filp->f_ops->fo_write(filp, &filp->f_offset, nbyte, buf);
   1269       }
   1270     }
   1271     else {
   1272       // File is NOT open for writing
   1273       errno = EINVAL;
   1274       BufSize = -1;
   1275     }
   1276   }
   1277   else {
   1278     // fd is not for a valid open file
   1279     errno = EBADF;
   1280     BufSize = -1;
   1281   }
   1282   return BufSize;
   1283 }
   1284 
   1285 /** Gets the current working directory.
   1286 
   1287   The getcwd() function shall place an absolute pathname of the current
   1288   working directory in the array pointed to by buf, and return buf.The
   1289   size argument is the size in bytes of the character array pointed to
   1290   by the buf argument.
   1291 
   1292   @param[in,out] buf    The buffer to fill.
   1293   @param[in]     size   The number of bytes in buffer.
   1294 
   1295   @retval NULL          The function failed.  The value in errno provides
   1296                         further information about the cause of the failure.
   1297                         Values for errno are:
   1298                           - EINVAL: buf is NULL or size is zero.
   1299                           - ENOENT: directory does not exist.
   1300                           - ERANGE: buf size is too small to hold CWD
   1301 
   1302   @retval buf           The function completed successfully.
   1303 **/
   1304 char
   1305 *getcwd (char *buf, size_t size)
   1306 {
   1307   CONST CHAR16 *Cwd;
   1308 
   1309   if (size == 0 || buf == NULL) {
   1310     errno = EINVAL;
   1311     return NULL;
   1312     }
   1313 
   1314   Cwd = ShellGetCurrentDir(NULL);
   1315   if (Cwd == NULL) {
   1316     errno = ENOENT;
   1317     return NULL;
   1318   }
   1319   if (size < ((StrLen (Cwd) + 1) * sizeof (CHAR8))) {
   1320     errno = ERANGE;
   1321     return (NULL);
   1322   }
   1323   return (UnicodeStrToAsciiStr(Cwd, buf));
   1324 }
   1325 
   1326 /** Change the current working directory.
   1327 
   1328   The chdir() function shall cause the directory named by the pathname
   1329   pointed to by the path argument to become the current working directory;
   1330   that is, the starting point for path searches for pathnames not beginning
   1331   with '/'.
   1332 
   1333   @param[in] path   The new path to set.
   1334 
   1335   @retval   0   Operation completed successfully.
   1336   @retval  -1   Function failed.  The value in errno provides more
   1337                 information on the cause of failure:
   1338                   - EPERM: Operation not supported with this Shell version.
   1339                   - ENOMEM: Unable to allocate memory.
   1340                   - ENOENT: Target directory does not exist.
   1341 
   1342   @todo Add non-NEW-shell CWD changing.
   1343 **/
   1344 int
   1345 chdir (const char *path)
   1346 {
   1347   CONST CHAR16 *Cwd;
   1348   EFI_STATUS   Status;
   1349   CHAR16       *UnicodePath;
   1350 
   1351   /* Old Shell does not support Set Current Dir. */
   1352   if(gEfiShellProtocol != NULL) {
   1353     Cwd = ShellGetCurrentDir(NULL);
   1354     if (Cwd != NULL) {
   1355       /* We have shell support */
   1356       UnicodePath = AllocatePool(((AsciiStrLen (path) + 1) * sizeof (CHAR16)));
   1357       if (UnicodePath == NULL) {
   1358         errno = ENOMEM;
   1359         return -1;
   1360       }
   1361       AsciiStrToUnicodeStr(path, UnicodePath);
   1362       Status = gEfiShellProtocol->SetCurDir(NULL, UnicodePath);
   1363       FreePool(UnicodePath);
   1364       if (EFI_ERROR(Status)) {
   1365         errno = ENOENT;
   1366         return -1;
   1367       } else {
   1368         return 0;
   1369       }
   1370     }
   1371   }
   1372   /* Add here for non-shell */
   1373   errno = EPERM;
   1374   return -1;
   1375 }
   1376 
   1377 /** Get the foreground process group ID associated with a terminal.
   1378 
   1379     Just returns the Image Handle for the requestor since UEFI does not have
   1380     a concept of processes or groups.
   1381 
   1382     @param[in]    x   Ignored.
   1383 
   1384     @return   Returns the Image Handle of the application or driver which
   1385               called this function.
   1386 **/
   1387 pid_t tcgetpgrp (int x)
   1388 {
   1389   return ((pid_t)(UINTN)(gImageHandle));
   1390 }
   1391 
   1392 /** Get the process group ID of the calling process.
   1393 
   1394     Just returns the Image Handle for the requestor since UEFI does not have
   1395     a concept of processes or groups.
   1396 
   1397     @return   Returns the Image Handle of the application or driver which
   1398               called this function.
   1399 **/
   1400 pid_t getpgrp(void)
   1401 {
   1402   return ((pid_t)(UINTN)(gImageHandle));
   1403 }
   1404 
   1405 /* Internal worker function for utimes.
   1406     This works around an error produced by GCC when the va_* macros
   1407     are used within a function with a fixed number of arguments.
   1408 */
   1409 static
   1410 int
   1411 EFIAPI
   1412 va_Utimes(
   1413   const char   *path,
   1414   ...
   1415   )
   1416 {
   1417   struct __filedes   *filp;
   1418   va_list             ap;
   1419   int                 fd;
   1420   int                 retval  = -1;
   1421 
   1422   va_start(ap, path);
   1423   fd = open(path, O_RDWR, 0);
   1424   if(fd >= 0) {
   1425     filp = &gMD->fdarray[fd];
   1426     retval = filp->f_ops->fo_ioctl( filp, FIOSETIME, ap);
   1427     close(fd);
   1428   }
   1429   va_end(ap);
   1430   return retval;
   1431 }
   1432 
   1433 /** Set file access and modification times.
   1434 
   1435     @param[in]  path    Path to the file to be modified.
   1436     @param[in]  times   Pointer to an array of two timeval structures
   1437 
   1438     @retval   0     File times successfully set.
   1439     @retval   -1    An error occured.  Error type in errno.
   1440 **/
   1441 int
   1442 utimes(
   1443   const char *path,
   1444   const struct timeval *times
   1445   )
   1446 {
   1447   return va_Utimes(path, times);
   1448 }
   1449