From 53e1e5c647b73e45569ed6e8b8a0a5b276aa685e Mon Sep 17 00:00:00 2001 From: darylm503 Date: Tue, 28 Jun 2011 02:34:10 +0000 Subject: =?UTF-8?q?Add=20device=20abstraction=20code=20for=20the=20UEFI=20?= =?UTF-8?q?Console=20and=20UEFI=20Shell-based=20file=20systems.=20Make=20a?= =?UTF-8?q?rgv=20use=20narrow=20characters=20instead=20of=20wide=20charact?= =?UTF-8?q?ers.=20Add=20setenv=20functionality.=20Add=20poll()=20system=20?= =?UTF-8?q?call.=20Change=20signal=20names=20into=20macros=20=E2=80=93=20r?= =?UTF-8?q?equired=20for=20standards=20compliance.=20=20The=20enums=20were?= =?UTF-8?q?=20renamed=20and=20moved=20to=20sys/signal.h=20and=20the=20new?= =?UTF-8?q?=20macros=20reference=20the=20enums.=20Added=20SIGBREAK,=20whic?= =?UTF-8?q?h=20is=20required=20for=20Python.=20Modify=20stdio=20functions?= =?UTF-8?q?=20to=20fail=20cleanly=20when=20called=20with=20a=20NULL=20File?= =?UTF-8?q?=20Pointer=20argument.=20Added=20=20that=20just=20?= =?UTF-8?q?includes=20.=20=20By=20adding=20this=20wrapper,?= =?UTF-8?q?=20we=20improve=20compatibility=20with=20*nix=20files=20which?= =?UTF-8?q?=20assume=20=20exists.=20Add=20=20Added=20m?= =?UTF-8?q?acros=20for=20bcopy(),=20bcmp()=20and=20strsep().=20Modify=20th?= =?UTF-8?q?e=20clock()=20function=20so=20that=20it=20does=20not=20hang=20w?= =?UTF-8?q?hen=20running=20under=20an=20emulation=20environment=20such=20a?= =?UTF-8?q?s=20NT32.=20Move=20TM=20structure=20specific=20macros=20from=20?= =?UTF-8?q?the=20private=20tzfile.h=20into=20=20Add=20strncasecmp?= =?UTF-8?q?=20function.=20Add=20strptime=20function.=20Add=20gettimeofday?= =?UTF-8?q?=20function.=20Add=20getcwd=20function.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@11908 6f19259b-4bc3-4df7-8a09-765794883524 --- StdLib/LibC/Uefi/Devices/UefiShell/daShell.c | 650 +++++++++++++++++++++++++++ 1 file changed, 650 insertions(+) create mode 100644 StdLib/LibC/Uefi/Devices/UefiShell/daShell.c (limited to 'StdLib/LibC/Uefi/Devices/UefiShell/daShell.c') diff --git a/StdLib/LibC/Uefi/Devices/UefiShell/daShell.c b/StdLib/LibC/Uefi/Devices/UefiShell/daShell.c new file mode 100644 index 0000000000..37870e8384 --- /dev/null +++ b/StdLib/LibC/Uefi/Devices/UefiShell/daShell.c @@ -0,0 +1,650 @@ +/** @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.
+ 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 +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static +int +EFIAPI +da_ShellClose( + IN struct __filedes *Fp +) +{ + EFIerrno = ShellCloseFile( (SHELL_FILE_HANDLE *)&Fp->devdata); + if(RETURN_ERROR(EFIerrno)) { + return -1; + } + return 0; +} + +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; +} + +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. + + @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 + ) +{ + 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) { + FileInfo->Attribute = 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; +} + +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; +} + +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; +} + +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 = EFI2errno(Status); + EFIerrno = Status; + + if(FileInfo != NULL) { + FreePool(FileInfo); // Release the buffer allocated by the GetInfo function + } + return errno? -1 : 0; +} + +static +int +EFIAPI +da_ShellIoctl( + struct __filedes *filp, + ULONGN cmd, + void *argp ///< May be a pointer or a value + ) +{ + return 0; +} + +/** Open an abstract Shell File. +**/ +int +EFIAPI +da_ShellOpen( + struct __filedes *filp, + void *DevInstance, + wchar_t *Path, + wchar_t *Flags + ) +{ + UINT64 OpenMode; + UINT64 Attributes; + SHELL_FILE_HANDLE FileHandle; + GenericInstance *Gip; + char *NPath; + RETURN_STATUS Status; + int oflags; + + 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; + } + + /* 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. + */ + if((oflags & O_TRUNC) || ((oflags & (O_EXCL | O_CREAT)) == (O_EXCL | O_CREAT))) { + Status = ShellIsFile( Path ); + if(Status == RETURN_SUCCESS) { + // The file exists + if(oflags & O_TRUNC) { + NPath = AllocateZeroPool(1024); + if(NPath == NULL) { + errno = ENOMEM; + EFIerrno = RETURN_OUT_OF_RESOURCES; + return -1; + } + wcstombs(NPath, Path, 1024); + // 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); + return -1; // errno and EFIerrno are already set. + } + 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 + return -1; + } + } + } + + // Call the EFI Shell's Open function + Status = ShellOpenFileByName( Path, &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; + return -1; + } + // Successfully got a regular File + filp->f_iflags |= S_IFREG; + + // Update the info in the fd + filp->devdata = (void *)FileHandle; + + Gip = (GenericInstance *)DevInstance; + filp->f_offset = 0; + filp->f_ops = &Gip->Abstraction; +// filp->devdata = FileHandle; + + return 0; +} + +#include +/* 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. + +*/ +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)); +} + +static +int +EFIAPI +da_ShellRename( + const char *from, + const char *to + ) +{ + RETURN_STATUS Status; + EFI_FILE_INFO *NewFileInfo; + EFI_FILE_INFO *OldFileInfo; + char *NewFn; + int OldFd; + SHELL_FILE_HANDLE FileHandle; + + // 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(OldFileInfo, NewFileInfo, sizeof(EFI_FILE_INFO)); + FreePool(OldFileInfo); + // Strip off all but the file name portion of new + NewFn = strrchr(to, '/'); + if(NewFn == NULL) { + NewFn = strrchr(to, '\\'); + if(NewFn == NULL) { + NewFn = (char *)to; + } + } + // Convert new name from MBCS to WCS + (void)AsciiStrToUnicodeStr( NewFn, gMD->UString); + // Copy the new file name into our new file info buffer + wcsncpy(NewFileInfo->FileName, gMD->UString, wcslen(gMD->UString)+1); + // Apply the new file name + Status = ShellSetFileInfo(FileHandle, NewFileInfo); + free(NewFileInfo); + if(Status == EFI_SUCCESS) { + // File has been successfully renamed. We are DONE! + return 0; + } + errno = EFI2errno( Status ); + EFIerrno = Status; + } + else { + errno = EIO; + } + } + else { + errno = ENOMEM; + } + } + return -1; +} + +static +int +EFIAPI +da_ShellRmdir( + struct __filedes *filp + ) +{ + SHELL_FILE_HANDLE FileHandle; + RETURN_STATUS Status = RETURN_SUCCESS; + EFI_FILE_INFO *FileInfo = NULL; + int Count = 0; + BOOLEAN NoFile = FALSE; + + 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 { + // See if the directory has any entries other than ".." and ".". + FreePool(FileInfo); // Free up the buffer from ShellGetFileInfo() + 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; + } + } + FreePool(FileInfo); // Free buffer from ShellFindFirstFile() + if(Count < 3) { + // Directory is empty + Status = ShellDeleteFile( &FileHandle); + if(Status == RETURN_SUCCESS) { + EFIerrno = RETURN_SUCCESS; + return 0; + /* ######## SUCCESSFUL RETURN ######## */ + } + } + else { + if(Count == 99) { + errno = EIO; + } + else { + errno = ENOTEMPTY; + } + } + } + } + } + else { + errno = EIO; + } + 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. +**/ +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 = &fbadop_ioctl; + 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; +} + +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; +} -- cgit v1.2.3