Include/ctype.h:             Function declaration and Macro definition of isDirSep
Include/unistd.h:            Declarations added from EfiSysCall.h
Include/utime.h:             New file.  For the Posix utime() function.
Include/sys/_ctype.h:        Update character class bit maps.
Include/sys/EfiSysCall.h:    Move declarations to unistd.h
Include/sys/fcntl.h:         Improve comments.  Add UEFI-specific macros.
Include/sys/filio.h:         Remove declarations for unsupported file ioctls.
Include/sys/stat.h:          Fix flags.  Add macros and declarations.
Include/sys/time.h:          Add declarations for new functions Tm2Efi() and Time2Efi().
Include/sys/types.h:         Use EFI-specific instead of BSD-specific definitions for typedefs.
Include/sys/unistd.h:        Delete inappropriate content.  Guard macro definitions.
LibC/Locale/setlocale.c
LibC/Stdio/{fdopen.c, findfp.c, fopen.c, freopen.c, gettemp.c, makebuf.c, mktemp.c,
            remove.c, stdio.c, tempnam.c, tmpfile.c, tmpnam.c}
LibC/Time/{itimer.c, ZoneProc.c}
LibC/Uefi/SysCalls.c
LibC/Uefi/Devices/Console/daConsole.c
LibC/Uefi/Devices/UefiShell/daShell.c
PosixLib/Gen/readdir.c
                             Include unistd.h instead of EfiSysCall.h
LibC/Ctype/CClass.c:         Character classification function implementation for isDirSep.
LibC/Ctype/iCtype.c:         Update character classification and case conversion tables.
LibC/Time/TimeEfi.c:         Improve comments.  Implement new functions Tm2Efi() and Time2Efi().
LibC/Uefi/StubFunctions.c:   Add missing include.  Cosmetic changes to declarations.
LibC/Uefi/SysCalls.c:        Add support function for utime().
LibC/Uefi/Uefi.inf:          Add LibGen library class dependency.
LibC/Uefi/Xform.c:           Enhance Omode2EFI().
LibC/Uefi/Devices/UefiShell/daShell.c:    Enhance da_ShellMkdir.  Implement da_ShellIoctl to set file times.
PosixLib/Gen/access.c:       New file.  Implement the access() function.
PosixLib/Gen/dirname.c:      Enhance to use isDirSep and differentiate between the device, path, and filename components of UEFI Shell-style paths.
PosixLib/Gen/utime.c:        New file.  Implement the utime() function.
PosixLib/Gen/LibGen.inf:     Change MODULE_TYPE.  Add new files.
Signed-off-by: darylm503
Reviewed-by: geekboy15a
Reviewed-by: jljusten
Reviewed-by: Rahul Khana
Reviewed-by: leegrosenbaum
git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@12800 6f19259b-4bc3-4df7-8a09-765794883524
		
	
		
			
				
	
	
		
			857 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			857 lines
		
	
	
		
			25 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Abstract device driver for the UEFI Shell-hosted environment.
 | 
						|
 | 
						|
  In a Shell-hosted environment, this is the driver that is called
 | 
						|
  when no other driver matches.
 | 
						|
 | 
						|
  Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
 | 
						|
  This program and the accompanying materials are licensed and made available under
 | 
						|
  the terms and conditions of the BSD License that accompanies this distribution.
 | 
						|
  The full text of the license may be found at
 | 
						|
  http://opensource.org/licenses/bsd-license.
 | 
						|
 | 
						|
  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
 | 
						|
  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
 | 
						|
 | 
						|
**/
 | 
						|
#include  <Uefi.h>
 | 
						|
#include  <Library/BaseLib.h>
 | 
						|
#include  <Library/MemoryAllocationLib.h>
 | 
						|
#include  <Library/UefiBootServicesTableLib.h>
 | 
						|
#include  <Library/ShellLib.h>
 | 
						|
 | 
						|
#include  <LibConfig.h>
 | 
						|
 | 
						|
#include  <errno.h>
 | 
						|
#include  <string.h>
 | 
						|
#include  <stdlib.h>
 | 
						|
#include  <stdarg.h>
 | 
						|
#include  <wctype.h>
 | 
						|
#include  <wchar.h>
 | 
						|
#include  <sys/fcntl.h>
 | 
						|
#include  <sys/filio.h>
 | 
						|
#include  <sys/syslimits.h>
 | 
						|
#include  <unistd.h>
 | 
						|
#include  <kfile.h>
 | 
						|
#include  <Device/Device.h>
 | 
						|
#include  <MainData.h>
 | 
						|
#include  <Efi/SysEfi.h>
 | 
						|
 | 
						|
/** EFI Shell specific operations for close().
 | 
						|
 | 
						|
    @param[in]    Fp    Pointer to a file descriptor structure.
 | 
						|
 | 
						|
    @retval      0      Successful completion.
 | 
						|
    @retval     -1      Operation failed.  Further information is specified by errno.
 | 
						|
**/
 | 
						|
static
 | 
						|
int
 | 
						|
EFIAPI
 | 
						|
da_ShellClose(
 | 
						|
  IN      struct __filedes   *Fp
 | 
						|
)
 | 
						|
{
 | 
						|
  EFIerrno = ShellCloseFile( (SHELL_FILE_HANDLE *)&Fp->devdata);
 | 
						|
  if(RETURN_ERROR(EFIerrno)) {
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/** EFI Shell specific operations for deleting a file or directory.
 | 
						|
 | 
						|
    @param[in]    filp    Pointer to a file descriptor structure.
 | 
						|
 | 
						|
    @retval      0      Successful completion.
 | 
						|
    @retval     -1      Operation failed.  Further information is specified by errno.
 | 
						|
**/
 | 
						|
static
 | 
						|
int
 | 
						|
EFIAPI
 | 
						|
da_ShellDelete(
 | 
						|
  struct __filedes   *filp
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS         Status;
 | 
						|
 | 
						|
  Status = ShellDeleteFile( (SHELL_FILE_HANDLE *)&filp->devdata);
 | 
						|
  if(Status != RETURN_SUCCESS) {
 | 
						|
    errno = EFI2errno(Status);
 | 
						|
    EFIerrno = Status;
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/** EFI Shell specific operations for setting the position within a file.
 | 
						|
 | 
						|
    @param[in]    filp    Pointer to a file descriptor structure.
 | 
						|
    @param[in]    offset  Relative position to move to.
 | 
						|
    @param[in]    whence  Specifies the location offset is relative to: Beginning, Current, End.
 | 
						|
 | 
						|
    @return     Returns the new file position or EOF if the seek failed.
 | 
						|
**/
 | 
						|
static
 | 
						|
off_t
 | 
						|
EFIAPI
 | 
						|
da_ShellSeek(
 | 
						|
  struct __filedes   *filp,
 | 
						|
  off_t               offset,
 | 
						|
  int                 whence
 | 
						|
)
 | 
						|
{
 | 
						|
  __off_t             CurPos = -1;
 | 
						|
  RETURN_STATUS       Status = RETURN_SUCCESS;
 | 
						|
  SHELL_FILE_HANDLE   FileHandle;
 | 
						|
 | 
						|
  FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
 | 
						|
 | 
						|
  if(whence != SEEK_SET) {
 | 
						|
    // We are doing a relative seek
 | 
						|
    if(whence == SEEK_END) {
 | 
						|
      // seeking relative to EOF, so position there first.
 | 
						|
      Status = ShellSetFilePosition( FileHandle, 0xFFFFFFFFFFFFFFFFULL);
 | 
						|
    }
 | 
						|
    if(Status == RETURN_SUCCESS) {
 | 
						|
      // Now, determine our current position.
 | 
						|
      Status = ShellGetFilePosition( FileHandle, (UINT64 *)&CurPos);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    CurPos = 0;   // offset is an absolute position for SEEK_SET
 | 
						|
    if(offset < 0) {
 | 
						|
      Status = RETURN_INVALID_PARAMETER;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if(Status == RETURN_SUCCESS) {
 | 
						|
    /* CurPos now indicates the point we are seeking from, so seek... */
 | 
						|
    Status = ShellSetFilePosition( FileHandle, (UINT64)(CurPos + offset));
 | 
						|
    if(Status == RETURN_SUCCESS) {
 | 
						|
      // Now, determine our final position.
 | 
						|
      Status = ShellGetFilePosition( FileHandle, (UINT64 *)&CurPos);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  if(Status != RETURN_SUCCESS) {
 | 
						|
    if(Status == EFI_UNSUPPORTED) {
 | 
						|
      errno = EISDIR;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      errno = EFI2errno(Status);
 | 
						|
    }
 | 
						|
    EFIerrno = Status;
 | 
						|
    CurPos = EOF;
 | 
						|
  }
 | 
						|
  return CurPos;
 | 
						|
}
 | 
						|
 | 
						|
/** The directory path is created with the access permissions specified by
 | 
						|
    perms.
 | 
						|
 | 
						|
    The directory is closed after it is created.
 | 
						|
 | 
						|
    @param[in]    path      The directory to be created.
 | 
						|
    @param[in]    perms     Access permissions for the new directory.
 | 
						|
 | 
						|
    @retval   0   The directory was created successfully.
 | 
						|
    @retval  -1   An error occurred and an error code is stored in errno.
 | 
						|
**/
 | 
						|
static
 | 
						|
int
 | 
						|
EFIAPI
 | 
						|
da_ShellMkdir(
 | 
						|
  const char   *path,
 | 
						|
  __mode_t      perms
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64            TempAttr;
 | 
						|
  SHELL_FILE_HANDLE FileHandle;
 | 
						|
  RETURN_STATUS     Status;
 | 
						|
  EFI_FILE_INFO    *FileInfo;
 | 
						|
  wchar_t          *NewPath;
 | 
						|
  int               retval = -1;
 | 
						|
 | 
						|
  // Convert name from MBCS to WCS and change '/' to '\\'
 | 
						|
  NewPath = NormalizePath( path);
 | 
						|
 | 
						|
  if(NewPath != NULL) {
 | 
						|
    Status = ShellCreateDirectory( NewPath, &FileHandle);
 | 
						|
    if(Status == RETURN_SUCCESS) {
 | 
						|
      FileInfo = ShellGetFileInfo( FileHandle);
 | 
						|
      Status = RETURN_ABORTED;  // In case ShellGetFileInfo() failed
 | 
						|
      if(FileInfo != NULL) {
 | 
						|
        TempAttr  = FileInfo->Attribute & (EFI_FILE_RESERVED | EFI_FILE_DIRECTORY);
 | 
						|
        FileInfo->Attribute = TempAttr | Omode2EFI(perms);
 | 
						|
        Status = ShellSetFileInfo( FileHandle, FileInfo);
 | 
						|
        FreePool(FileInfo);
 | 
						|
        if(Status == RETURN_SUCCESS) {
 | 
						|
          (void)ShellCloseFile(&FileHandle);
 | 
						|
          retval = 0;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
    errno = EFI2errno(Status);
 | 
						|
    EFIerrno = Status;
 | 
						|
    free(NewPath);
 | 
						|
  }
 | 
						|
  return retval;
 | 
						|
}
 | 
						|
 | 
						|
/** EFI Shell specific operations for reading from a file.
 | 
						|
 | 
						|
    @param[in]    filp        Pointer to a file descriptor structure.
 | 
						|
    @param[in]    offset      Offset into the file to begin reading at, or NULL.
 | 
						|
    @param[in]    BufferSize  Number of bytes in Buffer.  Max number of bytes to read.
 | 
						|
    @param[in]    Buffer      Pointer to a buffer to receive the read data.
 | 
						|
 | 
						|
    @return     Returns the number of bytes successfully read,
 | 
						|
                or -1 if the operation failed.  Further information is specified by errno.
 | 
						|
**/
 | 
						|
static
 | 
						|
ssize_t
 | 
						|
EFIAPI
 | 
						|
da_ShellRead(
 | 
						|
  IN OUT  struct __filedes   *filp,
 | 
						|
  IN OUT  off_t              *offset,
 | 
						|
  IN      size_t              BufferSize,
 | 
						|
     OUT  VOID               *Buffer
 | 
						|
)
 | 
						|
{
 | 
						|
  ssize_t           BufSize;
 | 
						|
  SHELL_FILE_HANDLE FileHandle;
 | 
						|
  RETURN_STATUS     Status;
 | 
						|
 | 
						|
  if(offset != NULL) {
 | 
						|
    BufSize = (ssize_t)da_ShellSeek(filp, *offset, SEEK_SET);
 | 
						|
    if(BufSize >= 0) {
 | 
						|
      filp->f_offset = BufSize;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  BufSize = (ssize_t)BufferSize;
 | 
						|
  FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
 | 
						|
 | 
						|
  Status = ShellReadFile( FileHandle, (UINTN *)&BufSize, Buffer);
 | 
						|
  if(Status != RETURN_SUCCESS) {
 | 
						|
    EFIerrno = Status;
 | 
						|
    errno = EFI2errno(Status);
 | 
						|
    if(Status == RETURN_BUFFER_TOO_SMALL) {
 | 
						|
      BufSize = -BufSize;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      BufSize = -1;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    filp->f_offset += BufSize;  // Advance to where we want to read next.
 | 
						|
  }
 | 
						|
  return BufSize;
 | 
						|
}
 | 
						|
 | 
						|
/** EFI Shell specific operations for writing to a file.
 | 
						|
 | 
						|
    @param[in]    filp        Pointer to a file descriptor structure.
 | 
						|
    @param[in]    offset      Offset into the file to begin writing at, or NULL.
 | 
						|
    @param[in]    BufferSize  Number of bytes in Buffer.  Max number of bytes to write.
 | 
						|
    @param[in]    Buffer      Pointer to a buffer containing the data to be written.
 | 
						|
 | 
						|
    @return     Returns the number of bytes successfully written,
 | 
						|
                or -1 if the operation failed.  Further information is specified by errno.
 | 
						|
**/
 | 
						|
static
 | 
						|
ssize_t
 | 
						|
EFIAPI
 | 
						|
da_ShellWrite(
 | 
						|
  IN  struct __filedes     *filp,
 | 
						|
  IN  off_t                *offset,
 | 
						|
  IN  size_t                BufferSize,
 | 
						|
  IN  const void           *Buffer
 | 
						|
  )
 | 
						|
{
 | 
						|
  ssize_t           BufSize;
 | 
						|
  SHELL_FILE_HANDLE FileHandle;
 | 
						|
  RETURN_STATUS     Status;
 | 
						|
  off_t             Position  = 0;
 | 
						|
  int               How       = SEEK_SET;
 | 
						|
 | 
						|
 | 
						|
  if((offset != NULL) || (filp->Oflags & O_APPEND)) {
 | 
						|
    if(filp->Oflags & O_APPEND) {
 | 
						|
      Position  = 0;
 | 
						|
      How       = SEEK_END;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      Position  = *offset;
 | 
						|
      How       = SEEK_SET;
 | 
						|
    }
 | 
						|
    BufSize = (ssize_t)da_ShellSeek(filp, Position, How);
 | 
						|
    if(BufSize >= 0) {
 | 
						|
      filp->f_offset = BufSize;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  BufSize = (ssize_t)BufferSize;
 | 
						|
  FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
 | 
						|
 | 
						|
  Status = ShellWriteFile( FileHandle, (UINTN *)&BufSize, (void *)Buffer);
 | 
						|
 | 
						|
  if(Status != RETURN_SUCCESS) {
 | 
						|
    EFIerrno = Status;
 | 
						|
    errno = EFI2errno(Status);
 | 
						|
    if(Status == EFI_UNSUPPORTED) {
 | 
						|
      errno = EISDIR;
 | 
						|
    }
 | 
						|
    BufSize = -1;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    filp->f_offset += BufSize;  // Advance to where we want to write next.
 | 
						|
  }
 | 
						|
 | 
						|
  return BufSize;
 | 
						|
}
 | 
						|
 | 
						|
/** EFI Shell specific operations for getting information about an open file.
 | 
						|
 | 
						|
    @param[in]    filp        Pointer to a file descriptor structure.
 | 
						|
    @param[out]   statbuf     Buffer in which to store the file status.
 | 
						|
    @param[in]    Something   This parameter is not used by this device.
 | 
						|
 | 
						|
    @retval      0      Successful completion.
 | 
						|
    @retval     -1      Operation failed.  Further information is specified by errno.
 | 
						|
**/
 | 
						|
static
 | 
						|
int
 | 
						|
EFIAPI
 | 
						|
da_ShellStat(
 | 
						|
  struct __filedes   *filp,
 | 
						|
  struct stat        *statbuf,
 | 
						|
  void               *Something
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_FILE_HANDLE FileHandle;
 | 
						|
  EFI_FILE_INFO    *FileInfo      = NULL;
 | 
						|
  UINT64            Attributes;
 | 
						|
  RETURN_STATUS     Status;
 | 
						|
  mode_t            newmode;
 | 
						|
 | 
						|
  FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
 | 
						|
 | 
						|
  FileInfo = ShellGetFileInfo( FileHandle);
 | 
						|
 | 
						|
  if(FileInfo != NULL) {
 | 
						|
    // Got the info, now populate statbuf with it
 | 
						|
    statbuf->st_blksize   = S_BLKSIZE;
 | 
						|
    statbuf->st_size      = FileInfo->FileSize;
 | 
						|
    statbuf->st_physsize  = FileInfo->PhysicalSize;
 | 
						|
    statbuf->st_birthtime = Efi2Time( &FileInfo->CreateTime);
 | 
						|
    statbuf->st_atime     = Efi2Time( &FileInfo->LastAccessTime);
 | 
						|
    statbuf->st_mtime     = Efi2Time( &FileInfo->ModificationTime);
 | 
						|
    Attributes = FileInfo->Attribute;
 | 
						|
    newmode               = (mode_t)(Attributes << S_EFISHIFT) | S_ACC_READ;
 | 
						|
    if((Attributes & EFI_FILE_DIRECTORY) == 0) {
 | 
						|
      newmode |= _S_IFREG;
 | 
						|
      if((Attributes & EFI_FILE_READ_ONLY) == 0) {
 | 
						|
        newmode |= S_ACC_WRITE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      newmode |= _S_IFDIR;
 | 
						|
    }
 | 
						|
    statbuf->st_mode = newmode;
 | 
						|
    Status = RETURN_SUCCESS;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    Status = RETURN_DEVICE_ERROR;
 | 
						|
    errno  = EIO;
 | 
						|
  }
 | 
						|
  EFIerrno  = Status;
 | 
						|
 | 
						|
  if(FileInfo != NULL) {
 | 
						|
    FreePool(FileInfo);     // Release the buffer allocated by the GetInfo function
 | 
						|
  }
 | 
						|
  return (Status == RETURN_SUCCESS)? 0 : -1;
 | 
						|
}
 | 
						|
 | 
						|
/** EFI Shell specific operations for low-level control of a file or device.
 | 
						|
 | 
						|
    @param[in]      filp    Pointer to a file descriptor structure.
 | 
						|
    @param[in]      cmd     The command this ioctl is to perform.
 | 
						|
    @param[in,out]  argp    Zero or more arguments as needed by the command.
 | 
						|
 | 
						|
    @retval      0      Successful completion.
 | 
						|
    @retval     -1      Operation failed.  Further information is specified by errno.
 | 
						|
**/
 | 
						|
static
 | 
						|
int
 | 
						|
EFIAPI
 | 
						|
da_ShellIoctl(
 | 
						|
  struct __filedes   *filp,
 | 
						|
  ULONGN              cmd,
 | 
						|
  va_list             argp
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_FILE_INFO    *FileInfo      = NULL;
 | 
						|
  SHELL_FILE_HANDLE FileHandle;
 | 
						|
  RETURN_STATUS     Status        = RETURN_SUCCESS;
 | 
						|
  int               retval        = 0;
 | 
						|
 | 
						|
  FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
 | 
						|
 | 
						|
  FileInfo = ShellGetFileInfo( FileHandle);
 | 
						|
 | 
						|
  if(FileInfo != NULL) {
 | 
						|
    if( cmd == (ULONGN)FIOSETIME) {
 | 
						|
      struct timeval  *TV;
 | 
						|
      EFI_TIME        *ET;
 | 
						|
      int              mod = 0;
 | 
						|
 | 
						|
      TV = va_arg(argp, struct timeval*);
 | 
						|
      if(TV[0].tv_sec != 0) {
 | 
						|
        ET = Time2Efi(TV[0].tv_sec);
 | 
						|
        if(ET != NULL) {
 | 
						|
          (void) memcpy(&FileInfo->LastAccessTime, ET, sizeof(EFI_TIME));
 | 
						|
          FileInfo->LastAccessTime.Nanosecond = TV[0].tv_usec * 1000;
 | 
						|
          free(ET);
 | 
						|
          ++mod;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      if(TV[1].tv_sec != 0) {
 | 
						|
        ET = Time2Efi(TV[1].tv_sec);
 | 
						|
        if(ET != NULL) {
 | 
						|
          (void) memcpy(&FileInfo->ModificationTime, ET, sizeof(EFI_TIME));
 | 
						|
          FileInfo->ModificationTime.Nanosecond = TV[1].tv_usec * 1000;
 | 
						|
          free(ET);
 | 
						|
          ++mod;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      /* Set access and modification times */
 | 
						|
      Status = ShellSetFileInfo(FileHandle, FileInfo);
 | 
						|
      errno = EFI2errno(Status);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    Status = RETURN_DEVICE_ERROR;
 | 
						|
    errno  = EIO;
 | 
						|
  }
 | 
						|
  if(RETURN_ERROR(Status)) {
 | 
						|
    retval = -1;
 | 
						|
  }
 | 
						|
  EFIerrno  = Status;
 | 
						|
 | 
						|
  if(FileInfo != NULL) {
 | 
						|
    FreePool(FileInfo);     // Release the buffer allocated by the GetInfo function
 | 
						|
  }
 | 
						|
  return retval;
 | 
						|
}
 | 
						|
 | 
						|
/** EFI Shell specific operations for opening a file or directory.
 | 
						|
 | 
						|
    @param[in]    DevNode   Pointer to a device descriptor
 | 
						|
    @param[in]    filp      Pointer to a file descriptor structure.
 | 
						|
    @param[in]    DevInstance   Not used by this device.
 | 
						|
    @param[in]    Path          File-system path to the file or directory.
 | 
						|
    @param[in]    MPath         Device or Map name on which Path resides.
 | 
						|
 | 
						|
    @return     Returns a file descriptor for the newly opened file,
 | 
						|
                or -1 if the Operation failed.  Further information is specified by errno.
 | 
						|
**/
 | 
						|
int
 | 
						|
EFIAPI
 | 
						|
da_ShellOpen(
 | 
						|
  DeviceNode         *DevNode,
 | 
						|
  struct __filedes   *filp,
 | 
						|
  int                 DevInstance,    /* Not used by Shell */
 | 
						|
  wchar_t            *Path,
 | 
						|
  wchar_t            *MPath
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT64                OpenMode;
 | 
						|
  UINT64                Attributes;
 | 
						|
  SHELL_FILE_HANDLE     FileHandle;
 | 
						|
  GenericInstance      *Gip;
 | 
						|
  char                 *NPath;
 | 
						|
  wchar_t              *WPath;
 | 
						|
  RETURN_STATUS         Status;
 | 
						|
  int                   oflags;
 | 
						|
  int                   retval;
 | 
						|
 | 
						|
  EFIerrno = RETURN_SUCCESS;
 | 
						|
 | 
						|
  //Attributes = Omode2EFI(mode);
 | 
						|
  Attributes = 0;
 | 
						|
 | 
						|
  // Convert oflags to Attributes
 | 
						|
  oflags = filp->Oflags;
 | 
						|
  OpenMode = Oflags2EFI(oflags);
 | 
						|
  if(OpenMode == 0) {
 | 
						|
    errno = EINVAL;
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Re-create the full mapped path for the shell. */
 | 
						|
  if(MPath != NULL) {
 | 
						|
    WPath = AllocateZeroPool(PATH_MAX * sizeof(wchar_t) + 1);
 | 
						|
    if(WPath == NULL) {
 | 
						|
      errno = ENOMEM;
 | 
						|
      EFIerrno = RETURN_OUT_OF_RESOURCES;
 | 
						|
      return -1;
 | 
						|
    }
 | 
						|
    wcsncpy(WPath, MPath, NAME_MAX);                /* Get the Map Name */
 | 
						|
    wcsncat(WPath, Path, (PATH_MAX - NAME_MAX));    /* Append the path */
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    WPath = Path;
 | 
						|
  }
 | 
						|
 | 
						|
  retval = -1;    /* Initially assume failure.  */
 | 
						|
 | 
						|
  /* Do we care if the file already exists?
 | 
						|
     If O_TRUNC, then delete the file.  It will be created anew subsequently.
 | 
						|
     If O_EXCL, then error if the file exists and O_CREAT is set.
 | 
						|
 | 
						|
  !!!!!!!!! Change this to use ShellSetFileInfo() to actually truncate the file
 | 
						|
  !!!!!!!!! instead of deleting and re-creating it.
 | 
						|
  */
 | 
						|
  do {  /* Do fake exception handling */
 | 
						|
  if((oflags & O_TRUNC) || ((oflags & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) {
 | 
						|
      Status = ShellIsFile( WPath );
 | 
						|
    if(Status == RETURN_SUCCESS) {
 | 
						|
      // The file exists
 | 
						|
      if(oflags & O_TRUNC) {
 | 
						|
          NPath = AllocateZeroPool(PATH_MAX);
 | 
						|
        if(NPath == NULL) {
 | 
						|
          errno = ENOMEM;
 | 
						|
          EFIerrno = RETURN_OUT_OF_RESOURCES;
 | 
						|
            break;
 | 
						|
        }
 | 
						|
          wcstombs(NPath, WPath, PATH_MAX);
 | 
						|
        // We do a truncate by deleting the existing file and creating a new one.
 | 
						|
        if(unlink(NPath) != 0) {
 | 
						|
          filp->f_iflags = 0;    // Release our reservation on this FD
 | 
						|
          FreePool(NPath);
 | 
						|
            break;
 | 
						|
        }
 | 
						|
        FreePool(NPath);
 | 
						|
      }
 | 
						|
      else if((oflags & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT)) {
 | 
						|
        errno = EEXIST;
 | 
						|
        EFIerrno = RETURN_ACCESS_DENIED;
 | 
						|
        filp->f_iflags = 0;    // Release our reservation on this FD
 | 
						|
          break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  // Call the EFI Shell's Open function
 | 
						|
    Status = ShellOpenFileByName( WPath, &FileHandle, OpenMode, Attributes);
 | 
						|
  if(RETURN_ERROR(Status)) {
 | 
						|
    filp->f_iflags = 0;    // Release our reservation on this FD
 | 
						|
    // Set errno based upon Status
 | 
						|
    errno = EFI2errno(Status);
 | 
						|
    EFIerrno = Status;
 | 
						|
      break;
 | 
						|
  }
 | 
						|
    retval = 0;
 | 
						|
  // Successfully got a regular File
 | 
						|
  filp->f_iflags |= S_IFREG;
 | 
						|
 | 
						|
  // Update the info in the fd
 | 
						|
  filp->devdata = (void *)FileHandle;
 | 
						|
 | 
						|
    Gip = (GenericInstance *)DevNode->InstanceList;
 | 
						|
  filp->f_offset = 0;
 | 
						|
  filp->f_ops = &Gip->Abstraction;
 | 
						|
  //  filp->devdata = FileHandle;
 | 
						|
  } while(FALSE);
 | 
						|
 | 
						|
  /* If we get this far, WPath is not NULL.
 | 
						|
     If MPath is not NULL, then WPath was allocated so we need to free it.
 | 
						|
  */
 | 
						|
  if(MPath != NULL) {
 | 
						|
    FreePool(WPath);
 | 
						|
  }
 | 
						|
  return retval;
 | 
						|
}
 | 
						|
 | 
						|
#include  <sys/poll.h>
 | 
						|
/** Returns a bit mask describing which operations could be completed immediately.
 | 
						|
 | 
						|
    For now, assume the file system, via the shell, is always ready.
 | 
						|
 | 
						|
    (POLLIN | POLLRDNORM)   The file system is ready to be read.
 | 
						|
    (POLLOUT)               The file system is ready for output.
 | 
						|
 | 
						|
    @param[in]    filp    Pointer to a file descriptor structure.
 | 
						|
    @param[in]    events  Bit mask describing which operations to check.
 | 
						|
 | 
						|
    @return     The returned value is a bit mask describing which operations
 | 
						|
                could be completed immediately, without blocking.
 | 
						|
**/
 | 
						|
static
 | 
						|
short
 | 
						|
EFIAPI
 | 
						|
da_ShellPoll(
 | 
						|
  struct __filedes   *filp,
 | 
						|
  short               events
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINT32      RdyMask;
 | 
						|
  short       retval = 0;
 | 
						|
 | 
						|
  RdyMask = (UINT32)filp->Oflags;
 | 
						|
 | 
						|
  switch(RdyMask & O_ACCMODE) {
 | 
						|
    case O_RDONLY:
 | 
						|
      retval = (POLLIN | POLLRDNORM);
 | 
						|
      break;
 | 
						|
 | 
						|
    case O_WRONLY:
 | 
						|
      retval = POLLOUT;
 | 
						|
      break;
 | 
						|
 | 
						|
    case O_RDWR:
 | 
						|
      retval = (POLLIN | POLLRDNORM | POLLOUT);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      retval = POLLERR;
 | 
						|
      break;
 | 
						|
  }
 | 
						|
  return (retval & (events | POLL_RETONLY));
 | 
						|
}
 | 
						|
 | 
						|
/** EFI Shell specific operations for renaming a file.
 | 
						|
 | 
						|
    @param[in]    from    Name of the file to be renamed.
 | 
						|
    @param[in]    to      New name for the file.
 | 
						|
 | 
						|
    @retval      0      Successful completion.
 | 
						|
    @retval     -1      Operation failed.  Further information is specified by errno.
 | 
						|
**/
 | 
						|
static
 | 
						|
int
 | 
						|
EFIAPI
 | 
						|
da_ShellRename(
 | 
						|
  const char   *from,
 | 
						|
  const char   *to
 | 
						|
  )
 | 
						|
{
 | 
						|
  RETURN_STATUS       Status;
 | 
						|
  EFI_FILE_INFO      *NewFileInfo;
 | 
						|
  EFI_FILE_INFO      *OldFileInfo;
 | 
						|
  wchar_t            *NewFn;
 | 
						|
  int                 OldFd;
 | 
						|
  SHELL_FILE_HANDLE   FileHandle;
 | 
						|
  wchar_t            *NormalizedPath;
 | 
						|
 | 
						|
  // Open old file
 | 
						|
  OldFd = open(from, O_RDWR, 0);
 | 
						|
  if(OldFd >= 0) {
 | 
						|
    FileHandle = (SHELL_FILE_HANDLE)gMD->fdarray[OldFd].devdata;
 | 
						|
 | 
						|
    NewFileInfo = malloc(sizeof(EFI_FILE_INFO) + PATH_MAX);
 | 
						|
    if(NewFileInfo != NULL) {
 | 
						|
      OldFileInfo = ShellGetFileInfo( FileHandle);
 | 
						|
      if(OldFileInfo != NULL) {
 | 
						|
        // Copy the Old file info into our new buffer, and free the old.
 | 
						|
        memcpy(NewFileInfo, OldFileInfo, sizeof(EFI_FILE_INFO));
 | 
						|
        FreePool(OldFileInfo);
 | 
						|
        // Normalize path and convert to WCS.
 | 
						|
        NormalizedPath = NormalizePath(to);
 | 
						|
        if (NormalizedPath != NULL) {
 | 
						|
        // Strip off all but the file name portion of new
 | 
						|
          NewFn = GetFileNameFromPath(NormalizedPath);
 | 
						|
        // Copy the new file name into our new file info buffer
 | 
						|
          wcsncpy(NewFileInfo->FileName, NewFn, wcslen(NewFn) + 1);
 | 
						|
          // Update the size of the structure.
 | 
						|
          NewFileInfo->Size = sizeof(EFI_FILE_INFO) + StrSize(NewFn);
 | 
						|
        // Apply the new file name
 | 
						|
        Status = ShellSetFileInfo(FileHandle, NewFileInfo);
 | 
						|
          free(NormalizedPath);
 | 
						|
        free(NewFileInfo);
 | 
						|
        if(Status == EFI_SUCCESS) {
 | 
						|
          // File has been successfully renamed.  We are DONE!
 | 
						|
          return 0;
 | 
						|
        }
 | 
						|
        errno = EFI2errno( Status );
 | 
						|
        EFIerrno = Status;
 | 
						|
      }
 | 
						|
      else {
 | 
						|
          free(NewFileInfo);
 | 
						|
          errno = ENOMEM;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        free(NewFileInfo);
 | 
						|
        errno = EIO;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      errno = ENOMEM;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
/** EFI Shell specific operations for deleting directories.
 | 
						|
 | 
						|
    @param[in]    filp    Pointer to a file descriptor structure.
 | 
						|
 | 
						|
    @retval      0      Successful completion.
 | 
						|
    @retval     -1      Operation failed.  Further information is specified by errno.
 | 
						|
**/
 | 
						|
static
 | 
						|
int
 | 
						|
EFIAPI
 | 
						|
da_ShellRmdir(
 | 
						|
  struct __filedes   *filp
 | 
						|
  )
 | 
						|
{
 | 
						|
  SHELL_FILE_HANDLE FileHandle;
 | 
						|
  RETURN_STATUS     Status = RETURN_SUCCESS;
 | 
						|
  EFI_FILE_INFO     *FileInfo;
 | 
						|
  int               OldErrno;
 | 
						|
  int               Count = 0;
 | 
						|
  BOOLEAN           NoFile = FALSE;
 | 
						|
 | 
						|
  OldErrno  = errno;  // Save the original value
 | 
						|
  errno = 0;    // Make it easier to see if we have an error later
 | 
						|
 | 
						|
  FileHandle = (SHELL_FILE_HANDLE)filp->devdata;
 | 
						|
 | 
						|
  FileInfo = ShellGetFileInfo(FileHandle);
 | 
						|
  if(FileInfo != NULL) {
 | 
						|
    if((FileInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
 | 
						|
      errno = ENOTDIR;
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      FreePool(FileInfo);  // Free up the buffer from ShellGetFileInfo()
 | 
						|
      // See if the directory has any entries other than ".." and ".".
 | 
						|
      Status = ShellFindFirstFile( FileHandle, &FileInfo);
 | 
						|
      if(Status == RETURN_SUCCESS) {
 | 
						|
        ++Count;
 | 
						|
        while(Count < 3) {
 | 
						|
          Status = ShellFindNextFile( FileHandle, FileInfo, &NoFile);
 | 
						|
          if(Status == RETURN_SUCCESS) {
 | 
						|
            if(NoFile) {
 | 
						|
              break;
 | 
						|
            }
 | 
						|
            ++Count;
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            Count = 99;
 | 
						|
          }
 | 
						|
        }
 | 
						|
        /*  Count == 99 and FileInfo is allocated if ShellFindNextFile failed.
 | 
						|
            ShellFindNextFile has freed FileInfo itself if it sets NoFile TRUE.
 | 
						|
        */
 | 
						|
        if((! NoFile) || (Count == 99)) {
 | 
						|
          free(FileInfo);   // Free buffer from ShellFindFirstFile()
 | 
						|
        }
 | 
						|
        if(Count < 3) {
 | 
						|
          // Directory is empty
 | 
						|
          Status = ShellDeleteFile( &FileHandle);
 | 
						|
          if(Status == RETURN_SUCCESS) {
 | 
						|
            EFIerrno = RETURN_SUCCESS;
 | 
						|
            errno    = OldErrno;    // Restore the original value
 | 
						|
            return 0;
 | 
						|
            /* ######## SUCCESSFUL RETURN ######## */
 | 
						|
          }
 | 
						|
          /*  FileInfo is freed and FileHandle closed. */
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          if(Count == 99) {
 | 
						|
            errno = EIO;
 | 
						|
          }
 | 
						|
          else {
 | 
						|
            errno = ENOTEMPTY;
 | 
						|
          }
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    errno = EIO;
 | 
						|
  }
 | 
						|
  ShellCloseFile( &FileHandle);
 | 
						|
  EFIerrno = Status;
 | 
						|
  if(errno == 0) {
 | 
						|
    errno = EFI2errno( Status );
 | 
						|
  }
 | 
						|
  return -1;
 | 
						|
}
 | 
						|
 | 
						|
/** Construct an instance of the abstract Shell device.
 | 
						|
 | 
						|
    Allocate the instance structure and populate it with the information for
 | 
						|
    the device.
 | 
						|
 | 
						|
    @param[in]    ImageHandle   This application's image handle.
 | 
						|
    @param[in]    SystemTable   Pointer to the UEFI System Table.
 | 
						|
 | 
						|
    @retval     RETURN_SUCCESS            Successful completion.
 | 
						|
    @retval     RETURN_OUT_OF_RESOURCES   Failed to allocate memory for new device.
 | 
						|
    @retval     RETURN_INVALID_PARAMETER  A default device has already been created.
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
__ctor_DevShell(
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
)
 | 
						|
{
 | 
						|
  GenericInstance    *Stream;
 | 
						|
  DeviceNode     *Node;
 | 
						|
  RETURN_STATUS   Status;
 | 
						|
 | 
						|
  Stream = (GenericInstance *)AllocateZeroPool(sizeof(GenericInstance));
 | 
						|
  if(Stream == NULL) {
 | 
						|
    return RETURN_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Stream->Cookie      = CON_COOKIE;
 | 
						|
  Stream->InstanceNum = 1;
 | 
						|
  Stream->Dev = NULL;
 | 
						|
  Stream->Abstraction.fo_close    = &da_ShellClose;
 | 
						|
  Stream->Abstraction.fo_read     = &da_ShellRead;
 | 
						|
  Stream->Abstraction.fo_write    = &da_ShellWrite;
 | 
						|
  Stream->Abstraction.fo_fcntl    = &fnullop_fcntl;
 | 
						|
  Stream->Abstraction.fo_poll     = &da_ShellPoll;
 | 
						|
  Stream->Abstraction.fo_flush    = &fnullop_flush;
 | 
						|
  Stream->Abstraction.fo_stat     = &da_ShellStat;
 | 
						|
  Stream->Abstraction.fo_ioctl    = &da_ShellIoctl;
 | 
						|
  Stream->Abstraction.fo_delete   = &da_ShellDelete;
 | 
						|
  Stream->Abstraction.fo_rmdir    = &da_ShellRmdir;
 | 
						|
  Stream->Abstraction.fo_mkdir    = &da_ShellMkdir;
 | 
						|
  Stream->Abstraction.fo_rename   = &da_ShellRename;
 | 
						|
  Stream->Abstraction.fo_lseek    = &da_ShellSeek;
 | 
						|
 | 
						|
  Node = __DevRegister(NULL, NULL, &da_ShellOpen, Stream, 1, sizeof(GenericInstance), O_RDWR);
 | 
						|
  Status = EFIerrno;
 | 
						|
  Stream->Parent = Node;
 | 
						|
 | 
						|
  return  Status;
 | 
						|
}
 | 
						|
 | 
						|
/** Destructor for previously constructed EFI Shell device instances.
 | 
						|
 | 
						|
    @param[in]    ImageHandle   This application's image handle.
 | 
						|
    @param[in]    SystemTable   Pointer to the UEFI System Table.
 | 
						|
 | 
						|
    @retval      0      Successful completion is always returned.
 | 
						|
**/
 | 
						|
RETURN_STATUS
 | 
						|
EFIAPI
 | 
						|
__dtor_DevShell(
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
)
 | 
						|
{
 | 
						|
  if(daDefaultDevice != NULL) {
 | 
						|
    if(daDefaultDevice->InstanceList != NULL) {
 | 
						|
      FreePool(daDefaultDevice->InstanceList);
 | 
						|
    }
 | 
						|
    FreePool(daDefaultDevice);
 | 
						|
  }
 | 
						|
  return RETURN_SUCCESS;
 | 
						|
}
 |