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/Console/daConsole.c | 558 ++++++++++++++++++++++ StdLib/LibC/Uefi/Devices/UefiShell/daShell.c | 650 ++++++++++++++++++++++++++ StdLib/LibC/Uefi/Devices/Utility/DevGenisis.c | 139 ++++++ StdLib/LibC/Uefi/Devices/Utility/DevSearch.c | 112 +++++ StdLib/LibC/Uefi/Devices/Utility/Path.c | 382 +++++++++++++++ StdLib/LibC/Uefi/Devices/daConsole.inf | 63 +++ StdLib/LibC/Uefi/Devices/daShell.inf | 63 +++ StdLib/LibC/Uefi/Devices/daUtility.inf | 56 +++ 8 files changed, 2023 insertions(+) create mode 100644 StdLib/LibC/Uefi/Devices/Console/daConsole.c create mode 100644 StdLib/LibC/Uefi/Devices/UefiShell/daShell.c create mode 100644 StdLib/LibC/Uefi/Devices/Utility/DevGenisis.c create mode 100644 StdLib/LibC/Uefi/Devices/Utility/DevSearch.c create mode 100644 StdLib/LibC/Uefi/Devices/Utility/Path.c create mode 100644 StdLib/LibC/Uefi/Devices/daConsole.inf create mode 100644 StdLib/LibC/Uefi/Devices/daShell.inf create mode 100644 StdLib/LibC/Uefi/Devices/daUtility.inf (limited to 'StdLib/LibC/Uefi/Devices') diff --git a/StdLib/LibC/Uefi/Devices/Console/daConsole.c b/StdLib/LibC/Uefi/Devices/Console/daConsole.c new file mode 100644 index 0000000000..c579959081 --- /dev/null +++ b/StdLib/LibC/Uefi/Devices/Console/daConsole.c @@ -0,0 +1,558 @@ +/** @file + Abstract device driver for the UEFI Console. + + Manipulates abstractions for stdin, stdout, stderr. + + Copyright (c) 2010 - 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.php. + + 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 + +static const CHAR16* const +stdioNames[NUM_SPECIAL] = { + L"stdin:", L"stdout:", L"stderr:" +}; + +static const int stdioFlags[NUM_SPECIAL] = { + O_RDONLY, // stdin + O_WRONLY, // stdout + O_WRONLY // stderr +}; + +static DeviceNode *ConNode[NUM_SPECIAL]; +static ConInstance *ConInstanceList; + +ssize_t +WideTtyCvt( CHAR16 *dest, const char *buf, size_t n) +{ + UINTN i; + wint_t wc; + + for(i = 0; i < n; ++i) { + wc = btowc(*buf++); + if( wc == 0) { + break; + }; + if(wc < 0) { + wc = BLOCKELEMENT_LIGHT_SHADE; + } + if(wc == L'\n') { + *dest++ = L'\r'; + } + *dest++ = (CHAR16)wc; + } + *dest = 0; + return (ssize_t)i; +} + +static +int +EFIAPI +da_ConClose( + IN struct __filedes *filp +) +{ + ConInstance *Stream; + + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; // Looks like a bad File Descriptor pointer + } + gMD->StdIo[Stream->InstanceNum] = NULL; // Mark the stream as closed + return RETURN_SUCCESS; +} + +static +off_t +EFIAPI +da_ConSeek( + struct __filedes *filp, + off_t Position, + int whence ///< Ignored by Console +) +{ + ConInstance *Stream; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; + XYoffset CursorPos; + + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; // Looks like a bad This pointer + } + if(Stream->InstanceNum == STDIN_FILENO) { + // Seek is not valid for stdin + EFIerrno = RETURN_UNSUPPORTED; + return -1; + } + // Everything is OK to do the final verification and "seek". + Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev; + CursorPos.Offset = Position; + + EFIerrno = Proto->SetCursorPosition(Proto, + (INTN)CursorPos.XYpos.Column, + (INTN)CursorPos.XYpos.Row); + + if(RETURN_ERROR(EFIerrno)) { + return -1; + } + else { + return Position; + } +} + +static +ssize_t +EFIAPI +da_ConRead( + IN OUT struct __filedes *filp, + IN OUT off_t *offset, // Console ignores this + IN size_t BufferSize, + OUT VOID *Buffer +) +{ + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto; + ConInstance *Stream; + CHAR16 *OutPtr; + EFI_INPUT_KEY Key; + UINTN NumChar; + UINTN Edex; + EFI_STATUS Status = RETURN_SUCCESS; + UINTN i; + + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; // Looks like a bad This pointer + } + if(Stream->InstanceNum != STDIN_FILENO) { + // Read only valid for stdin + EFIerrno = RETURN_UNSUPPORTED; + return -1; + } + // It looks like things are OK for trying to read + // We will accumulate *BufferSize characters or until we encounter + // an "activation" character. Currently any control character. + Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev; + OutPtr = Buffer; + NumChar = (BufferSize - 1) / sizeof(CHAR16); + i = 0; + do { + if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) { + Status = gBS->WaitForEvent( 1, &Proto->WaitForKey, &Edex); + if(Status != RETURN_SUCCESS) { + break; + } + Status = Proto->ReadKeyStroke(Proto, &Key); + if(Status != RETURN_SUCCESS) { + break; + } + } + else { + Key.ScanCode = Stream->UnGetKey.ScanCode; + Key.UnicodeChar = Stream->UnGetKey.UnicodeChar; + Stream->UnGetKey.ScanCode = SCAN_NULL; + Stream->UnGetKey.UnicodeChar = CHAR_NULL; + } + if(Key.ScanCode == SCAN_NULL) { + *OutPtr++ = Key.UnicodeChar; + ++i; + } + if(iswcntrl(Key.UnicodeChar)) { // If a control character, or a scan code + break; + } + } while(i < NumChar); + + *OutPtr = L'\0'; // Terminate the input buffer + EFIerrno = Status; + return (ssize_t)(i * sizeof(CHAR16)); // Will be 0 if we didn't get a key +} + +/* Write a NULL terminated WCS to the EFI console. + + @param[in,out] BufferSize Number of bytes in Buffer. Set to zero if + the string couldn't be displayed. + @param[in] Buffer The WCS string to be displayed + + @return The number of characters written. +*/ +static +ssize_t +EFIAPI +da_ConWrite( + IN struct __filedes *filp, + IN off_t *Position, + IN size_t BufferSize, + IN const void *Buffer + ) +{ + EFI_STATUS Status; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; + ConInstance *Stream; + ssize_t NumChar; + //XYoffset CursorPos; + + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; // Looks like a bad This pointer + } + if(Stream->InstanceNum == STDIN_FILENO) { + // Write is not valid for stdin + EFIerrno = RETURN_UNSUPPORTED; + return -1; + } + // Everything is OK to do the write. + Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev; + + // Convert string from MBCS to WCS and translate \n to \r\n. + NumChar = WideTtyCvt(gMD->UString, (const char *)Buffer, BufferSize); + //if(NumChar > 0) { + // BufferSize = (size_t)(NumChar * sizeof(CHAR16)); + //} + BufferSize = NumChar; + + //if( Position != NULL) { + // CursorPos.Offset = (UINT64)*Position; + + // Status = Proto->SetCursorPosition(Proto, + // (INTN)CursorPos.XYpos.Column, + // (INTN)CursorPos.XYpos.Row); + // if(RETURN_ERROR(Status)) { + // return -1; + // } + //} + + // Send the Unicode buffer to the console + Status = Proto->OutputString( Proto, gMD->UString); + // Depending on status, update BufferSize and return + if(RETURN_ERROR(Status)) { + BufferSize = 0; // We don't really know how many characters made it out + } + else { + //BufferSize = NumChar; + Stream->NumWritten += NumChar; + } + EFIerrno = Status; + return BufferSize; +} + +/** Console-specific helper function for the fstat() function. + + st_size Set to number of characters read for stdin and number written for stdout and stderr. + st_physsize 1 for stdin, 0 if QueryMode error, else max X and Y coordinates for the current mode. + st_curpos 0 for stdin, current X & Y coordinates for stdout and stderr + st_blksize Set to 1 since this is a character device + + All other members of the stat structure are left unchanged. +**/ +static +int +EFIAPI +da_ConStat( + struct __filedes *filp, + struct stat *Buffer, + void *Something + ) +{ + ConInstance *Stream; + EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Proto; + XYoffset CursorPos; + INT32 OutMode; + UINTN ModeCol; + UINTN ModeRow; + +// ConGetInfo + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if ((Stream->Cookie != CON_COOKIE) || // Cookie == 'IoAb' + (Buffer == NULL)) + { + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; + } + // All of our parameters are correct, so fill in the information. + Buffer->st_blksize = 1; + +// ConGetPosition + if(Stream->InstanceNum == STDIN_FILENO) { + // This is stdin + Buffer->st_curpos = 0; + Buffer->st_size = (off_t)Stream->NumRead; + Buffer->st_physsize = 1; + } + else { + Proto = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *)Stream->Dev; + CursorPos.XYpos.Column = (UINT32)Proto->Mode->CursorColumn; + CursorPos.XYpos.Row = (UINT32)Proto->Mode->CursorRow; + Buffer->st_curpos = (off_t)CursorPos.Offset; + Buffer->st_size = (off_t)Stream->NumWritten; + + OutMode = Proto->Mode->Mode; + EFIerrno = Proto->QueryMode(Proto, (UINTN)OutMode, &ModeCol, &ModeRow); + if(RETURN_ERROR(EFIerrno)) { + Buffer->st_physsize = 0; + } + else { + CursorPos.XYpos.Column = (UINT32)ModeCol; + CursorPos.XYpos.Row = (UINT32)ModeRow; + Buffer->st_physsize = (off_t)CursorPos.Offset; + } + } + return 0; +} + +static +int +EFIAPI +da_ConIoctl( + struct __filedes *filp, + ULONGN cmd, + void *argp + ) +{ + return -EPERM; +} + +/** Open an abstract Console Device. +**/ +int +EFIAPI +da_ConOpen( + struct __filedes *filp, + void *DevInstance, + wchar_t *Path, // Not used for console devices + wchar_t *Flags // Not used for console devices + ) +{ + ConInstance *Stream; + + if((filp == NULL) || + (DevInstance == NULL)) + { + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; + } + Stream = (ConInstance *)DevInstance; + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return -1; // Looks like a bad This pointer + } + gMD->StdIo[Stream->InstanceNum] = (ConInstance *)DevInstance; + filp->f_iflags |= (S_IFREG | _S_IFCHR | _S_ICONSOLE); + filp->f_offset = 0; + filp->f_ops = &Stream->Abstraction; + + return 0; +} + +#include +/* Returns a bit mask describing which operations could be completed immediately. + + (POLLIN | POLLRDNORM) A Unicode character is available to read + (POLLIN) A ScanCode is ready. + (POLLOUT) The device is ready for output - always set on stdout and stderr. + +*/ +static +short +EFIAPI +da_ConPoll( + struct __filedes *filp, + short events + ) +{ + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Proto; + ConInstance *Stream; + EFI_STATUS Status = RETURN_SUCCESS; + short RdyMask = 0; + + Stream = BASE_CR(filp->f_ops, ConInstance, Abstraction); + // Quick check to see if Stream looks reasonable + if(Stream->Cookie != CON_COOKIE) { // Cookie == 'IoAb' + EFIerrno = RETURN_INVALID_PARAMETER; + return POLLNVAL; // Looks like a bad filp pointer + } + if(Stream->InstanceNum == 0) { + // Only input is supported for this device + Proto = (EFI_SIMPLE_TEXT_INPUT_PROTOCOL *)Stream->Dev; + if((Stream->UnGetKey.UnicodeChar == CHAR_NULL) && (Stream->UnGetKey.ScanCode == SCAN_NULL)) { + Status = Proto->ReadKeyStroke(Proto, &Stream->UnGetKey); + if(Status == RETURN_SUCCESS) { + RdyMask = POLLIN; + if(Stream->UnGetKey.UnicodeChar != CHAR_NULL) { + RdyMask |= POLLRDNORM; + } + } + else { + Stream->UnGetKey.ScanCode = SCAN_NULL; + Stream->UnGetKey.UnicodeChar = CHAR_NULL; + } + } + } + else if(Stream->InstanceNum < NUM_SPECIAL) { // Not 0, is it 1 or 2? + // Only output is supported for this device + RdyMask = POLLOUT; + } + else { + RdyMask = POLLERR; // Not one of the standard streams + } + EFIerrno = Status; + + return (RdyMask & (events | POLL_RETONLY)); +} + +/** Construct the Console stream devices: stdin, stdout, stderr. + + Allocate the instance structure and populate it with the information for + each stream device. +**/ +RETURN_STATUS +EFIAPI +__Cons_construct( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + ConInstance *Stream; + RETURN_STATUS Status = RETURN_SUCCESS; + int i; + + ConInstanceList = (ConInstance *)AllocateZeroPool(NUM_SPECIAL * sizeof(ConInstance)); + if(ConInstanceList == NULL) { + return RETURN_OUT_OF_RESOURCES; + } + + for( i = 0; i < NUM_SPECIAL; ++i) { + // Get pointer to instance. + Stream = &ConInstanceList[i]; + + Stream->Cookie = CON_COOKIE; + Stream->InstanceNum = i; + + switch(i) { + case STDIN_FILENO: + Stream->Dev = SystemTable->ConIn; + break; + case STDOUT_FILENO: + Stream->Dev = SystemTable->ConOut; + break; + case STDERR_FILENO: + if(SystemTable->StdErr == NULL) { + Stream->Dev = SystemTable->ConOut; + } + else { + Stream->Dev = SystemTable->StdErr; + } + break; + default: + return RETURN_VOLUME_CORRUPTED; // This is a "should never happen" case. + } + + Stream->Abstraction.fo_close = &da_ConClose; + Stream->Abstraction.fo_read = &da_ConRead; + Stream->Abstraction.fo_write = &da_ConWrite; + Stream->Abstraction.fo_stat = &da_ConStat; + Stream->Abstraction.fo_lseek = &da_ConSeek; + Stream->Abstraction.fo_fcntl = &fnullop_fcntl; + Stream->Abstraction.fo_ioctl = &da_ConIoctl; + Stream->Abstraction.fo_poll = &da_ConPoll; + Stream->Abstraction.fo_flush = &fnullop_flush; + Stream->Abstraction.fo_delete = &fbadop_delete; + Stream->Abstraction.fo_mkdir = &fbadop_mkdir; + Stream->Abstraction.fo_rmdir = &fbadop_rmdir; + Stream->Abstraction.fo_rename = &fbadop_rename; + + Stream->NumRead = 0; + Stream->NumWritten = 0; + Stream->UnGetKey.ScanCode = SCAN_NULL; + Stream->UnGetKey.UnicodeChar = CHAR_NULL; + + if(Stream->Dev == NULL) { + continue; // No device for this stream. + } + ConNode[i] = __DevRegister(stdioNames[i], NULL, &da_ConOpen, Stream, 1, sizeof(ConInstance), stdioFlags[i]); + if(ConNode[i] == NULL) { + Status = EFIerrno; + break; + } + Stream->Parent = ConNode[i]; + } + return Status; +} + +RETURN_STATUS +EFIAPI +__Cons_deconstruct( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable +) +{ + int i; + + for(i = 0; i < NUM_SPECIAL; ++i) { + if(ConNode[i] != NULL) { + FreePool(ConNode[i]); + } + } + if(ConInstanceList != NULL) { + FreePool(ConInstanceList); + } + + return RETURN_SUCCESS; +} + +/* ######################################################################### */ +#if 0 /* Not implemented for Console */ + +static +int +EFIAPI +da_ConCntl( + struct __filedes *filp, + UINT32, + void *, + void * + ) +{ +} + +static +int +EFIAPI +da_ConFlush( + struct __filedes *filp + ) +{ + return 0; +} +#endif /* Not implemented for Console */ 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; +} diff --git a/StdLib/LibC/Uefi/Devices/Utility/DevGenisis.c b/StdLib/LibC/Uefi/Devices/Utility/DevGenisis.c new file mode 100644 index 0000000000..2bdb33ac53 --- /dev/null +++ b/StdLib/LibC/Uefi/Devices/Utility/DevGenisis.c @@ -0,0 +1,139 @@ +/** @file + Device Abstraction: device creation utility functions. + + 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.php. + + 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 + +LIST_ENTRY daDeviceList = INITIALIZE_LIST_HEAD_VARIABLE(daDeviceList); +DeviceNode *daDefaultDevice = NULL; ///< Device to use if nothing else found +DeviceNode *daRootDevice = NULL; ///< Device containing the root file system +DeviceNode *daCurrentDevice = NULL; ///< Device currently being accessed + +/* Commonly used fileops + fnullop_* Does nothing and returns success. + fbadop_* Does nothing and returns EPERM +*/ +int fnullop_fcntl (struct __filedes *filp, UINT32 Cmd, void *p3, void *p4) +{ return 0; } + +short fnullop_poll (struct __filedes *filp, short Events) +{ + return ((POLLIN | POLLRDNORM | POLLOUT) & Events); +} + +int fnullop_flush (struct __filedes *filp) +{ return 0; } + +int fbadop_stat (struct __filedes *filp, struct stat *StatBuf, void *Buf) +{ return -EPERM; } + +int fbadop_ioctl (struct __filedes *filp, ULONGN Cmd, void *argp) +{ return -EPERM; } + +int fbadop_delete (struct __filedes *filp) +{ return -EPERM; } + +int fbadop_mkdir (const char *path, __mode_t perms) +{ return -EPERM; } + +int fbadop_rename (const char *from, const char *to) +{ return -EPERM; } + +int fbadop_rmdir (struct __filedes *filp) +{ return -EPERM; } + +/** Add a new device to the device list. + If both DevName and DevProto are NULL, register this as the Default device. + + @param DevName Name of the device to add. + @param DevProto Pointer to the GUID identifying the protocol associated with this device. + If DevProto is NULL, startup code will not try to find instances + of this device. + @param OpenFunc Pointer to the device's Open function. + @param InstanceList Optional pointer to the device's initialized instance list. + If InstanceList is NULL, the application startup code will + scan for instances of the protocol identified by DevProto and + populate the InstanceList in the order those protocols are found. + @param NumInstance Number of instances in InstanceList. + @param Modes Bit-mapped flags indicating operations (R, W, RW, ...) permitted to this device. + +**/ +DeviceNode * +EFIAPI +__DevRegister( + IN const CHAR16 *DevName, + IN GUID *DevProto, + IN FO_OPEN OpenFunc, + IN void *InstanceList, + IN int NumInstance, + IN UINT32 InstanceSize, + IN UINT32 Modes + ) +{ + DeviceNode *Node; + GenericInstance *GIp; + char *GenPtr; + int i; + + /* Validate parameters */ + if(((DevName == NULL) && (DevProto != NULL)) || + (OpenFunc == NULL)) { + EFIerrno = RETURN_INVALID_PARAMETER; + return NULL; + } + Node = (DeviceNode *)AllocateZeroPool(sizeof(DeviceNode)); + if(Node == NULL) { + EFIerrno = RETURN_OUT_OF_RESOURCES; + return NULL; + } + + Node->DevName = DevName; + Node->DevProto = DevProto; + Node->InstanceList = InstanceList; + Node->OpenFunc = OpenFunc; + Node->InstanceSize = InstanceSize; + Node->NumInstances = NumInstance; + Node->OpModes = Modes; + + /* Update the Parent member of each element of the InstanceList */ + if(InstanceList != NULL) { + GenPtr = InstanceList; + + for(i = 0; i < NumInstance; ++i) { // Iterate through each element of InstanceList + GIp = (GenericInstance *)GenPtr; + GIp->Parent = Node; // Initializing the Parent member & InstanceNum + //GIp->InstanceNum = i; + GenPtr += InstanceSize; + } + } + if(DevName == NULL) { + if(daDefaultDevice != NULL) { + EFIerrno = RETURN_INVALID_PARAMETER; + return NULL; + } + daDefaultDevice = Node; + } + else { + (void) InsertTailList(&daDeviceList, &Node->DevList); + } + EFIerrno = RETURN_SUCCESS; + return Node; +} diff --git a/StdLib/LibC/Uefi/Devices/Utility/DevSearch.c b/StdLib/LibC/Uefi/Devices/Utility/DevSearch.c new file mode 100644 index 0000000000..b0fc7bacd1 --- /dev/null +++ b/StdLib/LibC/Uefi/Devices/Utility/DevSearch.c @@ -0,0 +1,112 @@ +/** @file + Device Abstraction: Search device list for a matching device. + + 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.php. + + 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 + +/** Find a DeviceNode matching DevName or DevProto, or both. + + If DevName is NULL, then the device name is not used in the search. + If DevProto is NULL, then the protocol GUID is not used in the search. + If both are NULL, then INVALID_PARAMETER is returned. + If both DevName and DevProto are specified, then both must match. + If both are specified but only one matches, then DEVICE_ERROR is returned. + + @param DevName Name of the Device Abstraction to find. + @param DevProto GUID of the Protocol associated with the Device Abstraction. + @param Node Pointer to the pointer to receive the found Device Node's address. + + @retval RETURN_SUCCESS The desired Device Node was found. + @retval RETURN_INVALID_PARAMETER Both DevName and DevProto are NULL or Node is NULL. + @retval RETURN_DEVICE_ERROR DevName matched but DevProto did not. + @retval RETURN_NOT_FOUND The desired device was not found. +**/ +EFI_STATUS +EFIAPI +__DevSearch( + IN CHAR16 *DevName, + IN GUID *DevProto, + OUT DeviceNode **Node + ) +{ + RETURN_STATUS Status = RETURN_NOT_FOUND; + DeviceNode *WorkNode; + INT32 DevMatched; + + if(((DevName == NULL) && (DevProto == NULL)) || (Node == NULL)) { + Status = RETURN_INVALID_PARAMETER; + } + else { + if(IsListEmpty((LIST_ENTRY *)&daDeviceList)) { + Status = RETURN_NOT_FOUND; + } + else { + /* Traverse the list of Device Nodes hunting for a match */ + WorkNode = (DeviceNode *)GetFirstNode((LIST_ENTRY *)&daDeviceList); + do { + /* Use DevMatched to keep track of the three match conditions. */ + DevMatched = 0; + if(DevName != NULL) { + ++DevMatched; + if(wcsncmp(DevName, WorkNode->DevName, wcslen(WorkNode->DevName)) == 0) { + ++DevMatched; + } + } + /* At this point, DevMatched has one of the following values: + 0 DevName == NULL, no name comparison + 1 DevName did not match WorkNode's name + 2 DevName MATCHED + */ + if((DevMatched != 1) && (DevProto != NULL) && (WorkNode->DevProto != NULL)) { + /* Only bother with the GUID comparison if: + * There was NOT a name mismatch + * DevProto is NOT NULL -- there is a GUID to compare + * WorkNode->DevProto is NOT NULL + */ + if(CompareGuid(DevProto, WorkNode->DevProto)) { + // GUIDs matched, we found it + Status = RETURN_SUCCESS; + *Node = WorkNode; + break; + } + else { + // GUIDs did not match + if(DevMatched == 2) { + // Name matched, GUID did not! + Status = RETURN_DEVICE_ERROR; + break; // Don't try any more, we have an internal problem + } + } + } + else { + if(DevMatched == 2) { + // Device Name matched, GUIDs skipped + Status = RETURN_SUCCESS; + *Node = WorkNode; + break; + } + } + // Check the next device in the list + WorkNode = (DeviceNode *)GetNextNode(&daDeviceList, (LIST_ENTRY *)WorkNode); + } while(&daDeviceList != (LIST_ENTRY *)WorkNode); + } + } + return Status; +} diff --git a/StdLib/LibC/Uefi/Devices/Utility/Path.c b/StdLib/LibC/Uefi/Devices/Utility/Path.c new file mode 100644 index 0000000000..92bb1a20b7 --- /dev/null +++ b/StdLib/LibC/Uefi/Devices/Utility/Path.c @@ -0,0 +1,382 @@ +/** @file + Device Abstraction: Path manipulation utilities. + + 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.php. + + 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 + +/** Identify the type of path pointed to by Path. + + Paths are classified based upon their initial character sequences. + ^\\ Absolute Path + ^\. Relative Path + ^[^:\\]: Mapping Path + .* Relative Path + + Mapping paths are broken into two parts at the ':'. The part to the left of the ':' + is the Map Name, pointed to by Path, and the part to the right of the ':' is pointed + to by NewPath. + + If Path was not a Mapping Path, then NewPath is set to Path. + + @param[in] Path Pointer to the path to be classified. + @param[out] NewPath Pointer to the path portion of a mapping path. + @param[out] Length Length of the Map Name portion of the path. + + @retval PathAbsolute Path is an absolute path. NewPath points to the first '\'. + @retval PathRelative Path is a relative path. NewPath = Path. + @retval PathMapping Path is a mapping path. NewPath points to the character following ':'. + @retval PathError Path is NULL. +**/ +PATH_CLASS +EFIAPI +ClassifyPath( + IN wchar_t * Path, + OUT wchar_t ** NewPath, + OUT int * const Length + ) +{ + size_t MapLen; + + if(Path == NULL) { + return PathError; // Bad parameter + } + if(NewPath != NULL) { + *NewPath = Path; // Setup default condition + } + if((*Path == L'\\') || (*Path == L'\0')) { + return PathAbsolute; + } + if(*Path == L'.') { + return PathRelative; + } + /* The easy stuff has been done, now see if this is a mapping path. + See if there is a ':' in Path that isn't the first character and is before + any '\\' characters. + */ + MapLen = wcscspn(Path, L"\\:"); + if(Length != NULL) { + *Length = (int)MapLen; + } + /* MapLen == 0 means that the first character is a ':' + == PathLen means that there are no '\\' or ':' + Otherwise, Path[MapLen] == ':' for a mapping path + or '\\' for a relative path. + */ + if(MapLen == 0) { + return PathError; + } + if(Path[MapLen] == L':') { + if(NewPath != NULL) { + *NewPath = &Path[MapLen + 1]; // Point to character after then ':'. Might be '\0'. + } + return PathMapping; + } + return PathRelative; +} + +/* Normalize a narrow-character path and produce a wide-character path + that has forward slashes replaced with backslashes. + Backslashes are directory separators in UEFI File Paths. + + It is the caller's responsibility to eventually free() the returned buffer. + + @param[in] path A pointer to the narrow-character path to be normalized. + + @return A pointer to a buffer containing the normalized, wide-character, path. +*/ +wchar_t * +NormalizePath( const char *path) +{ + wchar_t *temp; + wchar_t *OldPath; + wchar_t *NewPath; + size_t Length; + + OldPath = AsciiStrToUnicodeStr(path, gMD->UString); + Length = wcslen(OldPath) + 1; + + NewPath = calloc(Length, sizeof(wchar_t)); + if(NewPath != NULL) { + temp = NewPath; + for( ; *OldPath; ++OldPath) { + if(*OldPath == L'/') { + *temp = L'\\'; + } + else { + *temp = *OldPath; + } + ++temp; + } + } + else { + errno = ENOMEM; + EFIerrno = RETURN_OUT_OF_RESOURCES; + } + return NewPath; +} + +/** Process a wide character string representing a Mapping Path and extract the instance number. + + The instance number is the sequence of decimal digits immediately to the left + of the ":" in the Map Name portion of a Mapping Path. + + This function is called with a pointer to beginning of the Map Name. + Thus Path[Length] must be a ':' and Path[Length - 1] must be a decimal digit. + If either of these are not true, an instance value of 0 is returned. + + If Path is NULL, an instance value of 0 is returned. + + @param[in] Path Points to the beginning of a Mapping Path + @param[in] Length Number of valid characters to the left of the ':' + + @return Returns either 0 or the value of the contiguous digits to the left of the ':'. +**/ +int +EFIAPI +PathInstance( + const wchar_t *Path, + int Length + ) +{ + wchar_t *temp; + int instance = 0; + + if((Path != NULL) && (Path[Length] == L':') && (Length > 0)) { + for(temp = __UNCONST(&Path[Length - 1]); Length > 0; --Length) { + if(!iswdigit(*temp)) { + break; + } + --temp; + } + instance = (int)wcstol(temp+1, NULL, 10); + } + return instance; +} + +/** Transform a relative path into an absolute path. + + If Path is NULL, return NULL. + Otherwise, pre-pend the CWD to Path then process the resulting path to: + - Replace "/./" with "/" + - Replace "//../" with "/" + - Do not allow one to back up past the root, "/" + + Also sets the Current Working Device to the Root Device. + + Path must be a previously allocated buffer. PathAdjust will + allocate a new buffer to hold the results of the transformation + and free Path. A pointer to the newly allocated buffer is returned. + + @param[in] Path A pointer to the path to be transformed. This buffer + will always be freed. + + @return A pointer to a buffer containing the transformed path. +**/ +wchar_t * +EFIAPI +PathAdjust( + wchar_t *Path + ) +{ + wchar_t *NewPath; + + NewPath = calloc(PATH_MAX, sizeof(wchar_t)); + if(NewPath != NULL) { + wmemcpy(NewPath, Path, PATH_MAX); + } + else { + errno = ENOMEM; + } + free(Path); + return NewPath; +} + +/** Replace the leading portion of Path with any aliases. + + Aliases are read from /etc/fstab. If there is an associated device, the + Current Working Device is set to that device. + + Path must be a previously allocated buffer. PathAlias will + allocate a new buffer to hold the results of the transformation + then free Path. A pointer to the newly allocated buffer is returned. + + @param[in] Path A pointer to the original, unaliased, path. This + buffer is always freed. + @param[out] Node Filled in with a pointer to the Device Node describing + the device abstraction associated with this path. + + @return A pointer to a buffer containing the aliased path. +**/ +wchar_t * +EFIAPI +PathAlias( + wchar_t *Path, + DeviceNode **Node + ) +{ + wchar_t *NewPath; + + NewPath = calloc(PATH_MAX, sizeof(wchar_t)); + if(NewPath != NULL) { + wmemcpy(NewPath, Path, PATH_MAX); + } + else { + errno = ENOMEM; + } + free(Path); + *Node = NULL; + return NewPath; +} + +/** Parse a path producing the target device, device instance, and file path. + + @param[in] path + @param[out] FullPath + @param[out] DevNode + @param[out] Which + + @retval RETURN_SUCCESS The path was parsed successfully. + @retval RETURN_NOT_FOUND The path does not map to a valid device. + @retval RETURN_OUT_OF_RESOURCES Insufficient memory to calloc a MapName buffer. + The errno variable is set to ENOMEM. + @retval RETURN_INVALID_PARAMETER The path parameter is not valid. + The errno variable is set to EINVAL. +**/ +RETURN_STATUS +EFIAPI +ParsePath( + IN const char *path, + OUT wchar_t **FullPath, + OUT DeviceNode **DevNode, + OUT int *Which + ) +{ + int MapLen; + PATH_CLASS PathClass; + wchar_t *NewPath; + wchar_t *WPath = NULL; + wchar_t *MPath = NULL; + DeviceNode *Node = NULL; + RETURN_STATUS Status = RETURN_NOT_FOUND; + int Instance = 0; + BOOLEAN ReMapped; + + ReMapped = FALSE; + + // Convert name from MBCS to WCS and change '/' to '\\' + WPath = NormalizePath( path); + PathClass = ClassifyPath(WPath, &NewPath, &MapLen); + +reclassify: + switch(PathClass) { + case PathMapping: + if(!ReMapped) { + if((NewPath == NULL) || (*NewPath == L'\0')) { /* Nothing after the ':' */ + PathClass = PathAbsolute; + } + else { + Instance = PathInstance(WPath, MapLen); + PathClass = ClassifyPath(NewPath, NULL, NULL); + } + ReMapped = TRUE; + if(WPath[MapLen] == L':') { + // Get the Map Name, including the trailing ':'. */ + MPath = calloc(MapLen+2, sizeof(wchar_t)); + if(MPath != NULL) { + wmemcpy(MPath, WPath, MapLen+2); + } + else { + errno = ENOMEM; + Status = RETURN_OUT_OF_RESOURCES; + break; // Exit the switch(PathClass) statement. + } + } + if(WPath != NewPath) { + /* Shift the RHS of the path down to the start of the buffer. */ + wmemmove(WPath, NewPath, wcslen(NewPath)+1); + NewPath = WPath; + } + goto reclassify; + } + /* Fall through to PathError if Remapped. + This means that the path looked like "foo:bar:something". + */ + + case PathError: + errno = EINVAL; + Status = RETURN_INVALID_PARAMETER; + break; + + case PathRelative: + /* Transform a relative path into an Absolute path. + Prepends CWD and handles ./ and ../ entries. + It is the caller's responsibility to free the space + allocated to WPath. + */ + WPath = PathAdjust(NewPath); // WPath was malloc()ed by PathAdjust + + case PathAbsolute: + /* Perform any path aliasing. For example: /dev/foo -> { node.foo, "" } + The current volume and directory are updated in the path as needed. + It is the caller's responsibility to free the space + allocated to WPath. + */ + Status = RETURN_SUCCESS; + WPath = PathAlias(WPath, &Node); // PathAlias frees its argument and malloc()s a new one. + break; + } + if(!RETURN_ERROR(Status)) { + *FullPath = WPath; + *Which = Instance; + + /* At this point, WPath is an absolute path, + MPath is either NULL or points to the Map Name, + and Instance is the instance number. + */ + if(MPath == NULL) { + /* This is NOT a mapped path. */ + if(Node == NULL) { + Node = daDefaultDevice; + } + if(Node != NULL) { + Status = RETURN_SUCCESS; + } + } + else { + /* This is a mapped path. */ + Status = __DevSearch( MPath, NULL, &Node); + if(Status == RETURN_NOT_FOUND) { + Node = daDefaultDevice; + + if(Node != NULL) { + Status = RETURN_SUCCESS; + } + } + } + if(DevNode != NULL) { + *DevNode = Node; + } + } + if(MPath != NULL) { + free(MPath); // We don't need this any more. + } + return Status; +} diff --git a/StdLib/LibC/Uefi/Devices/daConsole.inf b/StdLib/LibC/Uefi/Devices/daConsole.inf new file mode 100644 index 0000000000..17865e4fec --- /dev/null +++ b/StdLib/LibC/Uefi/Devices/daConsole.inf @@ -0,0 +1,63 @@ +## @file +# Standard C library: Console Device Abstraction. +# +# 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 which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DevConsole + FILE_GUID = 42c078ef-14a8-4e30-9329-6f12d796e54a + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = DevConsole + CONSTRUCTOR = __Cons_construct + DESTRUCTOR = __Cons_deconstruct + +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + Console/daConsole.c + +[Packages] + StdLib/StdLib.dec + StdLibPrivateInternalFiles/DoNotUse.dec + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + UefiBootServicesTableLib + LibC + LibWchar + LibUefi + DevUtility + +[Protocols] + gEfiSimpleTextInProtocolGuid + gEfiSimpleTextOutProtocolGuid + +################################################################ +# +# The Build Options, below, are only used when building the C library. +# DO NOT use them when building your application! +# Nasty things could happen if you do. +# +# /Oi is required for Microsoft VC++ to allow "intrinsic" functions to be +# defined in this library. +# +#[BuildOptions] +# MSFT:*_*_*_CC_FLAGS = /Oi- diff --git a/StdLib/LibC/Uefi/Devices/daShell.inf b/StdLib/LibC/Uefi/Devices/daShell.inf new file mode 100644 index 0000000000..7b56f37363 --- /dev/null +++ b/StdLib/LibC/Uefi/Devices/daShell.inf @@ -0,0 +1,63 @@ +## @file +# Standard C library: Shell-Hosted Device Abstraction. +# +# When this library is included in an application, it creates the default device. +# This allows every device type not recognized to be passed to the shell for processing. +# +# 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 which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DevShell + FILE_GUID = 42c078ef-14a8-4e30-9329-6f12d796e54a + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = DevShell + CONSTRUCTOR = __ctor_DevShell + DESTRUCTOR = __dtor_DevShell + +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + UefiShell/daShell.c + +[Packages] + StdLib/StdLib.dec + StdLibPrivateInternalFiles/DoNotUse.dec + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + MemoryAllocationLib + UefiBootServicesTableLib + LibC + LibString + LibStdLib + LibWchar + LibUefi + DevUtility + +################################################################ +# +# The Build Options, below, are only used when building the C library. +# DO NOT use them when building your application! +# Nasty things could happen if you do. +# +# /Oi is required for Microsoft VC++ to allow "intrinsic" functions to be +# defined in this library. +# +#[BuildOptions] +# MSFT:*_*_*_CC_FLAGS = /Oi- diff --git a/StdLib/LibC/Uefi/Devices/daUtility.inf b/StdLib/LibC/Uefi/Devices/daUtility.inf new file mode 100644 index 0000000000..53daad28ac --- /dev/null +++ b/StdLib/LibC/Uefi/Devices/daUtility.inf @@ -0,0 +1,56 @@ +## @file +# Standard C library: Console Device Abstraction. +# +# 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 which accompanies this +# distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php. +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = DevUtility + FILE_GUID = 42c078ef-14a8-4e30-9329-6f12d796e54a + MODULE_TYPE = UEFI_APPLICATION + VERSION_STRING = 1.0 + LIBRARY_CLASS = DevUtility + +# +# VALID_ARCHITECTURES = IA32 X64 IPF +# + +[Sources] + Utility/DevGenisis.c + Utility/DevSearch.c + Utility/Path.c + +[Packages] + StdLib/StdLib.dec + StdLibPrivateInternalFiles/DoNotUse.dec + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + +[LibraryClasses] + BaseLib + BaseMemoryLib + MemoryAllocationLib + LibC + LibWchar + LibUefi + +################################################################ +# +# The Build Options, below, are only used when building the C library. +# DO NOT use them when building your application! +# Nasty things could happen if you do. +# +# /Oi- is required for Microsoft VC++ to allow "intrinsic" functions to be +# defined in this library. +# +#[BuildOptions] +# MSFT:*_*_*_CC_FLAGS = /Oi- -- cgit v1.2.3