StdIn, StdOut, StdErr, etc...).\r
\r
Copyright 2016 Dell Inc.\r
- Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>\r
+ Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r
(C) Copyright 2013 Hewlett-Packard Development Company, L.P.<BR>\r
This program and the accompanying materials\r
are licensed and made available under the terms and conditions of the BSD License\r
#include "Shell.h"\r
#include "FileHandleInternal.h"\r
\r
+#define MEM_WRITE_REALLOC_OVERHEAD 1024\r
+\r
/**\r
- File style interface for console (Open). \r
- \r
+ File style interface for console (Open).\r
+\r
@param[in] This Ignored.\r
@param[out] NewHandle Ignored.\r
@param[in] FileName Ignored.\r
@param[in] OpenMode Ignored.\r
@param[in] Attributes Ignored.\r
- \r
+\r
@retval EFI_NOT_FOUND\r
**/\r
EFI_STATUS\r
\r
/**\r
File style interface for console (Close, Delete, & Flush)\r
- \r
+\r
@param[in] This Ignored.\r
- \r
+\r
@retval EFI_SUCCESS\r
**/\r
EFI_STATUS\r
\r
@param[in] This Ignored.\r
@param[out] Position Ignored.\r
- \r
+\r
@retval EFI_UNSUPPORTED\r
**/\r
EFI_STATUS\r
\r
/**\r
File style interface for console (SetPosition).\r
- \r
+\r
@param[in] This Ignored.\r
@param[in] Position Ignored.\r
- \r
+\r
@retval EFI_UNSUPPORTED\r
**/\r
EFI_STATUS\r
\r
/**\r
File style interface for console (GetInfo).\r
- \r
+\r
@param[in] This Ignored.\r
@param[in] InformationType Ignored.\r
@param[in, out] BufferSize Ignored.\r
@param[out] Buffer Ignored.\r
- \r
+\r
@retval EFI_UNSUPPORTED\r
**/\r
EFI_STATUS\r
\r
/**\r
File style interface for console (SetInfo).\r
- \r
+\r
@param[in] This Ignored.\r
@param[in] InformationType Ignored.\r
@param[in] BufferSize Ignored.\r
@param[in] Buffer Ignored.\r
- \r
+\r
@retval EFI_UNSUPPORTED\r
**/\r
EFI_STATUS\r
File style interface for StdOut (Write).\r
\r
Writes data to the screen.\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
@param[in, out] BufferSize Size in bytes of Buffer.\r
@param[in] Buffer The pointer to the buffer to write.\r
- \r
+\r
@retval EFI_UNSUPPORTED No output console is supported.\r
@return A return value from gST->ConOut->OutputString.\r
**/\r
{\r
if (ShellInfoObject.ShellInitSettings.BitUnion.Bits.NoConsoleOut) {\r
return (EFI_UNSUPPORTED);\r
- } else {\r
- return (gST->ConOut->OutputString(gST->ConOut, Buffer));\r
}\r
+ if (*((CHAR16 *)Buffer) == gUnicodeFileTag) {\r
+ return (gST->ConOut->OutputString(gST->ConOut, (CHAR16 *)Buffer + 1));\r
+ }\r
+ return (gST->ConOut->OutputString(gST->ConOut, Buffer));\r
}\r
\r
/**\r
File style interface for StdIn (Write).\r
- \r
+\r
@param[in] This Ignored.\r
@param[in, out] BufferSize Ignored.\r
@param[in] Buffer Ignored.\r
- \r
+\r
@retval EFI_UNSUPPORTED\r
**/\r
EFI_STATUS\r
File style interface for console StdErr (Write).\r
\r
Writes error to the error output.\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
@param[in, out] BufferSize Size in bytes of Buffer.\r
@param[in] Buffer The pointer to the buffer to write.\r
- \r
+\r
@return A return value from gST->StdErr->OutputString.\r
**/\r
EFI_STATUS\r
\r
/**\r
File style interface for console StdOut (Read).\r
- \r
+\r
@param[in] This Ignored.\r
@param[in, out] BufferSize Ignored.\r
@param[out] Buffer Ignored.\r
- \r
+\r
@retval EFI_UNSUPPORTED\r
**/\r
EFI_STATUS\r
\r
/**\r
File style interface for console StdErr (Read).\r
- \r
+\r
@param[in] This Ignored.\r
@param[in, out] BufferSize Ignored.\r
@param[out] Buffer Ignored.\r
- \r
+\r
@retval EFI_UNSUPPORTED Always.\r
**/\r
EFI_STATUS\r
\r
/**\r
File style interface for NUL file (Read).\r
- \r
+\r
@param[in] This Ignored.\r
@param[in, out] BufferSize Poiner to 0 upon return.\r
@param[out] Buffer Ignored.\r
- \r
+\r
@retval EFI_SUCCESS Always.\r
**/\r
EFI_STATUS\r
\r
/**\r
File style interface for NUL file (Write).\r
- \r
+\r
@param[in] This Ignored.\r
@param[in, out] BufferSize Ignored.\r
@param[in] Buffer Ignored.\r
- \r
+\r
@retval EFI_SUCCESS\r
**/\r
EFI_STATUS\r
return (EFI_SUCCESS);\r
}\r
\r
+/**\r
+ Create the TAB completion list.\r
+\r
+ @param[in] InputString The command line to expand.\r
+ @param[in] StringLen Length of the command line.\r
+ @param[in] BufferSize Buffer size.\r
+ @param[in, out] TabCompletionList Return the TAB completion list.\r
+ @param[in, out] TabUpdatePos Return the TAB update position.\r
+**/\r
+EFI_STATUS\r
+CreateTabCompletionList (\r
+ IN CONST CHAR16 *InputString,\r
+ IN CONST UINTN StringLen,\r
+ IN CONST UINTN BufferSize,\r
+ IN OUT EFI_SHELL_FILE_INFO **TabCompletionList,\r
+ IN OUT UINTN *TabUpdatePos\r
+)\r
+{\r
+ BOOLEAN InQuotation;\r
+ UINTN TabPos;\r
+ UINTN Index;\r
+ CONST CHAR16 *Cwd;\r
+ EFI_STATUS Status;\r
+ CHAR16 *TabStr;\r
+ EFI_SHELL_FILE_INFO *FileList;\r
+ EFI_SHELL_FILE_INFO *FileInfo;\r
+ EFI_SHELL_FILE_INFO *TempFileInfo;\r
+\r
+ //\r
+ // Allocate buffers\r
+ //\r
+ TabStr = AllocateZeroPool (BufferSize);\r
+ if (TabStr == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // handle auto complete of file and directory names...\r
+ // E.g.: cd fs0:\EFI\Bo<TAB>\r
+ // ^ ^\r
+ // TabPos TabUpdatePos\r
+ //\r
+ TabPos = 0;\r
+ *TabUpdatePos = 0;\r
+ FileList = NULL;\r
+ InQuotation = FALSE;\r
+ for (Index = 0; Index < StringLen; Index++) {\r
+ switch (InputString[Index]) {\r
+ case L'\"':\r
+ InQuotation = (BOOLEAN) (!InQuotation);\r
+ break;\r
+\r
+ case L' ':\r
+ if (!InQuotation) {\r
+ TabPos = Index + 1;\r
+ *TabUpdatePos = TabPos;\r
+ }\r
+ break;\r
+\r
+ case L':':\r
+ //\r
+ // handle the case "fs0:<TAB>"\r
+ // Update the TabUpdatePos as well.\r
+ //\r
+ case L'\\':\r
+ *TabUpdatePos = Index + 1;\r
+ break;\r
+\r
+ default:\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (StrStr (InputString + TabPos, L":") == NULL) {\r
+ //\r
+ // If file path doesn't contain ":", ...\r
+ //\r
+ Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir (NULL);\r
+ if (Cwd != NULL) {\r
+ if (InputString[TabPos] != L'\\') {\r
+ //\r
+ // and it doesn't begin with "\\", it's a path relative to current directory.\r
+ // TabStr = "<cwd>\\"\r
+ //\r
+ StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, (BufferSize) / sizeof (CHAR16) - 1);\r
+ StrCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"\\");\r
+ } else {\r
+ //\r
+ // and it begins with "\\", it's a path pointing to root directory of current map.\r
+ // TabStr = "fsx:"\r
+ //\r
+ Index = StrStr (Cwd, L":") - Cwd + 1;\r
+ StrnCpyS (TabStr, BufferSize / sizeof (CHAR16), Cwd, Index);\r
+ }\r
+ }\r
+ }\r
+ StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), InputString + TabPos, StringLen - TabPos);\r
+ StrnCatS (TabStr, (BufferSize) / sizeof (CHAR16), L"*", (BufferSize) / sizeof (CHAR16) - 1 - StrLen (TabStr));\r
+ Status = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FileList);\r
+\r
+ //\r
+ // Filter out the non-directory for "CD" command\r
+ // Filter "." and ".." for all\r
+ //\r
+ if (!EFI_ERROR (Status) && FileList != NULL) {\r
+ //\r
+ // Skip the spaces in the beginning\r
+ //\r
+ while (*InputString == L' ') {\r
+ InputString++;\r
+ }\r
+\r
+ for (FileInfo = (EFI_SHELL_FILE_INFO *) GetFirstNode (&FileList->Link); !IsNull (&FileList->Link, &FileInfo->Link); ) {\r
+ if (((StrCmp (FileInfo->FileName, L".") == 0) || (StrCmp (FileInfo->FileName, L"..") == 0)) ||\r
+ (((InputString[0] == L'c' || InputString[0] == L'C') && (InputString[1] == L'd' || InputString[1] == L'D')) &&\r
+ (ShellIsDirectory (FileInfo->FullName) != EFI_SUCCESS))) {\r
+ TempFileInfo = FileInfo;\r
+ FileInfo = (EFI_SHELL_FILE_INFO *) RemoveEntryList (&FileInfo->Link);\r
+ InternalFreeShellFileInfoNode (TempFileInfo);\r
+ } else {\r
+ FileInfo = (EFI_SHELL_FILE_INFO *) GetNextNode (&FileList->Link, &FileInfo->Link);\r
+ }\r
+ }\r
+ }\r
+\r
+ if (FileList != NULL && !IsListEmpty (&FileList->Link)) {\r
+ Status = EFI_SUCCESS;\r
+ } else {\r
+ ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FileList);\r
+ Status = EFI_NOT_FOUND;\r
+ }\r
+\r
+ FreePool (TabStr);\r
+\r
+ *TabCompletionList = FileList;\r
+ return Status;\r
+}\r
+\r
/**\r
File style interface for console (Read).\r
\r
{\r
CHAR16 *CurrentString;\r
BOOLEAN Done;\r
+ UINTN TabUpdatePos; // Start index of the string updated by TAB stroke\r
UINTN Column; // Column of current cursor\r
UINTN Row; // Row of current cursor\r
UINTN StartColumn; // Column at the beginning of the line\r
UINTN StringLen; // Total length of the line\r
UINTN StringCurPos; // Line index corresponding to the cursor\r
UINTN MaxStr; // Maximum possible line length\r
- UINTN Index;\r
UINTN TotalColumn; // Num of columns in the console\r
UINTN TotalRow; // Num of rows in the console\r
UINTN SkipLength;\r
BOOLEAN InScrolling;\r
EFI_STATUS Status;\r
BOOLEAN InTabScrolling; // Whether in TAB-completion state\r
- EFI_SHELL_FILE_INFO *FoundFileList;\r
- EFI_SHELL_FILE_INFO *TabLinePos;\r
- EFI_SHELL_FILE_INFO *TempPos;\r
- CHAR16 *TabStr;\r
- CHAR16 *TabOutputStr;\r
- BOOLEAN InQuotationMode;\r
- CHAR16 *TempStr;\r
- UINTN TabPos; // Start index of the string to search for TAB completion.\r
- UINTN TabUpdatePos; // Start index of the string updated by TAB stroke\r
-// UINTN Count;\r
+ EFI_SHELL_FILE_INFO *TabCompleteList;\r
+ EFI_SHELL_FILE_INFO *TabCurrent;\r
UINTN EventIndex;\r
- CONST CHAR16 *Cwd;\r
+ CHAR16 *TabOutputStr;\r
\r
//\r
// If buffer is not large enough to hold a CHAR16, return minimum buffer size\r
InScrolling = FALSE;\r
InTabScrolling = FALSE;\r
Status = EFI_SUCCESS;\r
- TabLinePos = NULL;\r
- FoundFileList = NULL;\r
- TempPos = NULL;\r
- TabPos = 0;\r
+ TabOutputStr = NULL;\r
TabUpdatePos = 0;\r
-\r
- //\r
- // Allocate buffers\r
- //\r
- TabStr = AllocateZeroPool (*BufferSize);\r
- if (TabStr == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- TabOutputStr = AllocateZeroPool (*BufferSize);\r
- if (TabOutputStr == NULL) {\r
- FreePool(TabStr);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
+ TabCompleteList = NULL;\r
+ TabCurrent = NULL;\r
\r
//\r
// Get the screen setting and the current cursor location\r
gBS->WaitForEvent (1, &gST->ConIn->WaitForKey, &EventIndex);\r
Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);\r
if (EFI_ERROR (Status)) {\r
+\r
+ if (Status == EFI_NOT_READY)\r
+ continue;\r
+\r
+ ZeroMem (CurrentString, MaxStr * sizeof(CHAR16));\r
+ StringLen = 0;\r
break;\r
}\r
\r
// If we are quitting TAB scrolling...\r
//\r
if (InTabScrolling && Key.UnicodeChar != CHAR_TAB) {\r
- if (FoundFileList != NULL) {\r
- ShellInfoObject.NewEfiShellProtocol->FreeFileList (&FoundFileList);\r
- DEBUG_CODE(FoundFileList = NULL;);\r
- }\r
- InTabScrolling = FALSE;\r
+ if (TabCompleteList != NULL) {\r
+ ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);\r
+ DEBUG_CODE(TabCompleteList = NULL;);\r
+ }\r
+ InTabScrolling = FALSE;\r
}\r
\r
switch (Key.UnicodeChar) {\r
break;\r
\r
case CHAR_TAB:\r
- //\r
- // handle auto complete of file and directory names...\r
- //\r
- if (InTabScrolling) {\r
- ASSERT(FoundFileList != NULL);\r
- ASSERT(TabLinePos != NULL);\r
- TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link);\r
- if (IsNull(&(FoundFileList->Link), &TabLinePos->Link)) {\r
- TabLinePos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &TabLinePos->Link);\r
- }\r
- } else {\r
- TabPos = 0;\r
- TabUpdatePos = 0;\r
- InQuotationMode = FALSE;\r
- for (Index = 0; Index < StringLen; Index++) {\r
- if (CurrentString[Index] == L'\"') {\r
- InQuotationMode = (BOOLEAN)(!InQuotationMode);\r
- }\r
- if (CurrentString[Index] == L' ' && !InQuotationMode) {\r
- TabPos = Index + 1;\r
- TabUpdatePos = Index + 1;\r
- }\r
- if (CurrentString[Index] == L'\\') {\r
- TabUpdatePos = Index + 1;\r
- }\r
+ if (!InTabScrolling) {\r
+ TabCurrent = NULL;\r
+ //\r
+ // Initialize a tab complete operation.\r
+ //\r
+ Status = CreateTabCompletionList (CurrentString, StringLen, *BufferSize, &TabCompleteList, &TabUpdatePos);\r
+ if (!EFI_ERROR(Status)) {\r
+ InTabScrolling = TRUE;\r
}\r
- if (StrStr(CurrentString + TabPos, L":") == NULL) {\r
- Cwd = ShellInfoObject.NewEfiShellProtocol->GetCurDir(NULL);\r
- if (Cwd != NULL) {\r
- StrnCpyS(TabStr, (*BufferSize)/sizeof(CHAR16), Cwd, (*BufferSize)/sizeof(CHAR16) - 1);\r
- StrCatS(TabStr, (*BufferSize)/sizeof(CHAR16), L"\\");\r
- if (TabStr[StrLen(TabStr)-1] == L'\\' && *(CurrentString + TabPos) == L'\\' ) {\r
- TabStr[StrLen(TabStr)-1] = CHAR_NULL;\r
- }\r
- StrnCatS( TabStr, \r
- (*BufferSize)/sizeof(CHAR16), \r
- CurrentString + TabPos, \r
- StringLen - TabPos\r
- );\r
- } else {\r
- *TabStr = CHAR_NULL;\r
- StrnCatS(TabStr, (*BufferSize)/sizeof(CHAR16), CurrentString + TabPos, StringLen - TabPos);\r
- }\r
+\r
+ //\r
+ // We do not set up the replacement.\r
+ // The next section will do that.\r
+ //\r
+ }\r
+\r
+ if (InTabScrolling) {\r
+ //\r
+ // We are in a tab complete operation.\r
+ // set up the next replacement.\r
+ //\r
+ ASSERT(TabCompleteList != NULL);\r
+ if (TabCurrent == NULL) {\r
+ TabCurrent = (EFI_SHELL_FILE_INFO*) GetFirstNode (&TabCompleteList->Link);\r
} else {\r
- StrnCpyS(TabStr, (*BufferSize)/sizeof(CHAR16), CurrentString + TabPos, (*BufferSize)/sizeof(CHAR16) - 1);\r
+ TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);\r
}\r
- StrnCatS(TabStr, (*BufferSize)/sizeof(CHAR16), L"*", (*BufferSize)/sizeof(CHAR16) - 1 - StrLen(TabStr));\r
- FoundFileList = NULL;\r
- Status = ShellInfoObject.NewEfiShellProtocol->FindFiles(TabStr, &FoundFileList);\r
- for ( TempStr = CurrentString\r
- ; *TempStr == L' '\r
- ; TempStr++); // note the ';'... empty for loop\r
+\r
//\r
- // make sure we have a list before we do anything more...\r
+ // Skip over the empty list beginning node\r
//\r
- if (EFI_ERROR (Status) || FoundFileList == NULL) {\r
- InTabScrolling = FALSE;\r
- TabLinePos = NULL;\r
- continue;\r
- } else {\r
- //\r
- // enumerate through the list of files\r
- //\r
- for ( TempPos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&(FoundFileList->Link))\r
- ; !IsNull(&FoundFileList->Link, &TempPos->Link)\r
- ; TempPos = (EFI_SHELL_FILE_INFO*)GetNextNode(&(FoundFileList->Link), &(TempPos->Link))\r
- ){\r
- //\r
- // If "cd" is typed, only directory name will be auto-complete filled\r
- // in either case . and .. will be removed.\r
- //\r
- if ((((TempStr[0] == L'c' || TempStr[0] == L'C') &&\r
- (TempStr[1] == L'd' || TempStr[1] == L'D')\r
- ) && ((ShellIsDirectory(TempPos->FullName) != EFI_SUCCESS)\r
- ||(StrCmp(TempPos->FileName, L".") == 0)\r
- ||(StrCmp(TempPos->FileName, L"..") == 0)\r
- )) || ((StrCmp(TempPos->FileName, L".") == 0)\r
- ||(StrCmp(TempPos->FileName, L"..") == 0))){\r
- TabLinePos = TempPos;\r
- TempPos = (EFI_SHELL_FILE_INFO*)(RemoveEntryList(&(TempPos->Link))->BackLink);\r
- InternalFreeShellFileInfoNode(TabLinePos);\r
- }\r
- }\r
- if (FoundFileList != NULL && !IsListEmpty(&FoundFileList->Link)) {\r
- TabLinePos = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FoundFileList->Link);\r
- InTabScrolling = TRUE;\r
- } else {\r
- FreePool(FoundFileList);\r
- FoundFileList = NULL;\r
- }\r
+ if (IsNull(&TabCompleteList->Link, &TabCurrent->Link)) {\r
+ TabCurrent = (EFI_SHELL_FILE_INFO*) GetNextNode (&TabCompleteList->Link, &TabCurrent->Link);\r
}\r
}\r
break;\r
// the next file or directory name\r
//\r
if (InTabScrolling) {\r
+ TabOutputStr = AllocateZeroPool (*BufferSize);\r
+ if (TabOutputStr == NULL) {\r
+ Status = EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+ if (InTabScrolling && TabOutputStr != NULL) {\r
+\r
//\r
// Adjust the column and row to the start of TAB-completion string.\r
//\r
Column = (StartColumn + TabUpdatePos) % TotalColumn;\r
Row -= (StartColumn + StringCurPos) / TotalColumn - (StartColumn + TabUpdatePos) / TotalColumn;\r
- OutputLength = StrLen (TabLinePos->FileName);\r
+ OutputLength = StrLen (TabCurrent->FileName);\r
//\r
// if the output string contains blank space, quotation marks L'\"'\r
// should be added to the output.\r
//\r
- if (StrStr(TabLinePos->FileName, L" ") != NULL){\r
+ if (StrStr(TabCurrent->FileName, L" ") != NULL){\r
TabOutputStr[0] = L'\"';\r
- CopyMem (TabOutputStr + 1, TabLinePos->FileName, OutputLength * sizeof (CHAR16));\r
+ CopyMem (TabOutputStr + 1, TabCurrent->FileName, OutputLength * sizeof (CHAR16));\r
TabOutputStr[OutputLength + 1] = L'\"';\r
TabOutputStr[OutputLength + 2] = CHAR_NULL;\r
} else {\r
- CopyMem (TabOutputStr, TabLinePos->FileName, OutputLength * sizeof (CHAR16));\r
+ CopyMem (TabOutputStr, TabCurrent->FileName, OutputLength * sizeof (CHAR16));\r
TabOutputStr[OutputLength] = CHAR_NULL;\r
}\r
OutputLength = StrLen (TabOutputStr) < MaxStr - 1 ? StrLen (TabOutputStr) : MaxStr - 1;\r
if (StringLen > TabUpdatePos + OutputLength) {\r
Delete = StringLen - TabUpdatePos - OutputLength;\r
}\r
+\r
+ FreePool(TabOutputStr);\r
}\r
\r
//\r
AddLineToCommandHistory(CurrentString);\r
}\r
\r
- FreePool (TabStr);\r
- FreePool (TabOutputStr);\r
//\r
// Return the data to the caller\r
//\r
// if this was used it should be deallocated by now...\r
// prevent memory leaks...\r
//\r
- ASSERT(FoundFileList == NULL);\r
+ if (TabCompleteList != NULL) {\r
+ ShellInfoObject.NewEfiShellProtocol->FreeFileList (&TabCompleteList);\r
+ }\r
+ ASSERT(TabCompleteList == NULL);\r
\r
return Status;\r
}\r
File style interface for Environment Variable (Close).\r
\r
Frees the memory for this object.\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
- \r
+\r
@retval EFI_SUCCESS\r
**/\r
EFI_STATUS\r
VOID* NewBuffer;\r
UINTN NewSize;\r
EFI_STATUS Status;\r
+ BOOLEAN Volatile;\r
+ UINTN TotalSize;\r
\r
//\r
- // Most if not all UEFI commands will have an '\r\n' at the end of any output. \r
- // Since the output was redirected to a variable, it does not make sense to \r
+ // Most if not all UEFI commands will have an '\r\n' at the end of any output.\r
+ // Since the output was redirected to a variable, it does not make sense to\r
// keep this. So, before closing, strip the trailing '\r\n' from the variable\r
// if it exists.\r
//\r
NewBuffer = NULL;\r
NewSize = 0;\r
+ TotalSize = 0;\r
+\r
+ Status = IsVolatileEnv (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &Volatile);\r
+ if (EFI_ERROR (Status)) {\r
+ return Status;\r
+ }\r
\r
Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
if (Status == EFI_BUFFER_TOO_SMALL) {\r
- NewBuffer = AllocateZeroPool(NewSize + sizeof(CHAR16));\r
+ TotalSize = NewSize + sizeof (CHAR16);\r
+ NewBuffer = AllocateZeroPool (TotalSize);\r
if (NewBuffer == NULL) {\r
return EFI_OUT_OF_RESOURCES;\r
- } \r
+ }\r
Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
}\r
- \r
+\r
if (!EFI_ERROR(Status) && NewBuffer != NULL) {\r
- \r
- if (StrSize(NewBuffer) > 6)\r
- {\r
- if ((((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 2] == CHAR_LINEFEED) \r
- && (((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] == CHAR_CARRIAGE_RETURN)) {\r
- ((CHAR16*)NewBuffer)[(StrSize(NewBuffer)/2) - 3] = CHAR_NULL; \r
+\r
+ if (TotalSize / sizeof (CHAR16) >= 3) {\r
+ if ( (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 2] == CHAR_LINEFEED) &&\r
+ (((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] == CHAR_CARRIAGE_RETURN)\r
+ ) {\r
+ ((CHAR16*)NewBuffer)[TotalSize / sizeof (CHAR16) - 3] = CHAR_NULL;\r
+ //\r
+ // If the NewBuffer end with \r\n\0, We will repace '\r' by '\0' and then update TotalSize.\r
+ //\r
+ TotalSize -= sizeof(CHAR16) * 2;\r
}\r
- \r
- if (IsVolatileEnv(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name)) {\r
- Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
+\r
+ if (Volatile) {\r
+ Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (\r
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+ TotalSize - sizeof (CHAR16),\r
+ NewBuffer\r
+ );\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = ShellAddEnvVarToList (\r
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+ NewBuffer,\r
+ TotalSize,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+ }\r
} else {\r
- Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
+ Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (\r
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+ TotalSize - sizeof (CHAR16),\r
+ NewBuffer\r
+ );\r
+\r
+ if (!EFI_ERROR(Status)) {\r
+ Status = ShellAddEnvVarToList (\r
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+ NewBuffer,\r
+ TotalSize,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+ }\r
}\r
}\r
- } \r
- \r
+ }\r
+\r
SHELL_FREE_NON_NULL(NewBuffer);\r
FreePool((EFI_FILE_PROTOCOL_ENVIRONMENT*)This);\r
return (Status);\r
\r
/**\r
File style interface for Environment Variable (Delete).\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
- \r
+\r
@retval The return value from FileInterfaceEnvClose().\r
**/\r
EFI_STATUS\r
\r
/**\r
File style interface for Environment Variable (Read).\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
@param[in, out] BufferSize Size in bytes of Buffer.\r
@param[out] Buffer The pointer to the buffer to fill.\r
- \r
+\r
@retval EFI_SUCCESS The data was read.\r
**/\r
EFI_STATUS\r
\r
/**\r
File style interface for Volatile Environment Variable (Write).\r
- \r
+ This function also caches the environment variable into gShellEnvVarList.\r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
@param[in, out] BufferSize Size in bytes of Buffer.\r
@param[in] Buffer The pointer to the buffer to write.\r
- \r
- @retval EFI_SUCCESS The data was read.\r
+\r
+ @retval EFI_SUCCESS The data was successfully write to variable.\r
+ @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.\r
**/\r
EFI_STATUS\r
EFIAPI\r
VOID* NewBuffer;\r
UINTN NewSize;\r
EFI_STATUS Status;\r
+ UINTN TotalSize;\r
\r
NewBuffer = NULL;\r
NewSize = 0;\r
+ TotalSize = 0;\r
\r
Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
- if (Status == EFI_BUFFER_TOO_SMALL){\r
- NewBuffer = AllocateZeroPool(NewSize + *BufferSize + sizeof(CHAR16));\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ TotalSize = NewSize + *BufferSize + sizeof (CHAR16);\r
+ } else if (Status == EFI_NOT_FOUND) {\r
+ TotalSize = *BufferSize + sizeof(CHAR16);\r
+ } else {\r
+ return Status;\r
+ }\r
+\r
+ NewBuffer = AllocateZeroPool (TotalSize);\r
+ if (NewBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
}\r
- if (!EFI_ERROR(Status) && NewBuffer != NULL) {\r
- while (((CHAR16*)NewBuffer)[NewSize/2] == CHAR_NULL) {\r
- //\r
- // We want to overwrite the CHAR_NULL\r
- //\r
- NewSize -= 2;\r
- }\r
- CopyMem((UINT8*)NewBuffer + NewSize + 2, Buffer, *BufferSize);\r
- Status = SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, StrSize(NewBuffer), NewBuffer);\r
- FreePool(NewBuffer);\r
- return (Status);\r
- } else {\r
- SHELL_FREE_NON_NULL(NewBuffer);\r
- return (SHELL_SET_ENVIRONMENT_VARIABLE_V(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, *BufferSize, Buffer));\r
+\r
+ if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {\r
+ FreePool (NewBuffer);\r
+ return Status;\r
+ }\r
+\r
+ CopyMem ((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);\r
+ Status = ShellAddEnvVarToList (\r
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+ NewBuffer,\r
+ TotalSize,\r
+ EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ FreePool (NewBuffer);\r
+ return Status;\r
+ }\r
+\r
+ Status = SHELL_SET_ENVIRONMENT_VARIABLE_V (\r
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+ TotalSize - sizeof (CHAR16),\r
+ NewBuffer\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);\r
}\r
+\r
+ FreePool (NewBuffer);\r
+ return Status;\r
}\r
\r
\r
/**\r
File style interface for Non Volatile Environment Variable (Write).\r
- \r
+ This function also caches the environment variable into gShellEnvVarList.\r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
@param[in, out] BufferSize Size in bytes of Buffer.\r
@param[in] Buffer The pointer to the buffer to write.\r
- \r
- @retval EFI_SUCCESS The data was read.\r
+\r
+ @retval EFI_SUCCESS The data was successfully write to variable.\r
+ @retval SHELL_OUT_OF_RESOURCES A memory allocation failed.\r
**/\r
EFI_STATUS\r
EFIAPI\r
VOID* NewBuffer;\r
UINTN NewSize;\r
EFI_STATUS Status;\r
+ UINTN TotalSize;\r
\r
NewBuffer = NULL;\r
NewSize = 0;\r
+ TotalSize = 0;\r
\r
Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
- if (Status == EFI_BUFFER_TOO_SMALL){\r
- NewBuffer = AllocateZeroPool(NewSize + *BufferSize);\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
+ TotalSize = NewSize + *BufferSize + sizeof (CHAR16);\r
+ } else if (Status == EFI_NOT_FOUND) {\r
+ TotalSize = *BufferSize + sizeof (CHAR16);\r
+ } else {\r
+ return Status;\r
+ }\r
+\r
+ NewBuffer = AllocateZeroPool (TotalSize);\r
+ if (NewBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ if (Status == EFI_BUFFER_TOO_SMALL) {\r
Status = SHELL_GET_ENVIRONMENT_VARIABLE(((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name, &NewSize, NewBuffer);\r
}\r
- if (!EFI_ERROR(Status)) {\r
- CopyMem((UINT8*)NewBuffer + NewSize, Buffer, *BufferSize);\r
- return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(\r
- ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
- NewSize + *BufferSize,\r
- NewBuffer));\r
- } else {\r
- return (SHELL_SET_ENVIRONMENT_VARIABLE_NV(\r
- ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
- *BufferSize,\r
- Buffer));\r
+\r
+ if (EFI_ERROR(Status) && Status != EFI_NOT_FOUND) {\r
+ FreePool (NewBuffer);\r
+ return Status;\r
}\r
+\r
+ CopyMem ((UINT8*) NewBuffer + NewSize, Buffer, *BufferSize);\r
+ Status = ShellAddEnvVarToList (\r
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+ NewBuffer,\r
+ TotalSize,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ FreePool (NewBuffer);\r
+ return Status;\r
+ }\r
+\r
+ Status = SHELL_SET_ENVIRONMENT_VARIABLE_NV (\r
+ ((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name,\r
+ TotalSize - sizeof (CHAR16),\r
+ NewBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ ShellRemvoeEnvVarFromList (((EFI_FILE_PROTOCOL_ENVIRONMENT*)This)->Name);\r
+ }\r
+\r
+ FreePool (NewBuffer);\r
+ return Status;\r
}\r
\r
/**\r
@return other a pointer to an EFI_FILE_PROTOCOL structure\r
**/\r
EFI_FILE_PROTOCOL*\r
-EFIAPI\r
CreateFileInterfaceEnv(\r
IN CONST CHAR16 *EnvName\r
)\r
{\r
+ EFI_STATUS Status;\r
EFI_FILE_PROTOCOL_ENVIRONMENT *EnvFileInterface;\r
UINTN EnvNameSize;\r
+ BOOLEAN Volatile;\r
\r
if (EnvName == NULL) {\r
return (NULL);\r
}\r
\r
+ Status = IsVolatileEnv (EnvName, &Volatile);\r
+ if (EFI_ERROR (Status)) {\r
+ return NULL;\r
+ }\r
+\r
//\r
// Get some memory\r
//\r
EnvFileInterface->Flush = FileInterfaceNopGeneric;\r
EnvFileInterface->Delete = FileInterfaceEnvDelete;\r
EnvFileInterface->Read = FileInterfaceEnvRead;\r
- \r
+\r
CopyMem(EnvFileInterface->Name, EnvName, EnvNameSize);\r
\r
//\r
// Assign the different members for Volatile and Non-Volatile variables\r
//\r
- if (IsVolatileEnv(EnvName)) {\r
+ if (Volatile) {\r
EnvFileInterface->Write = FileInterfaceEnvVolWrite;\r
} else {\r
EnvFileInterface->Write = FileInterfaceEnvNonVolWrite;\r
@param[in, out] Row Current row of the cursor position\r
**/\r
VOID\r
-EFIAPI\r
MoveCursorBackward (\r
IN UINTN LineLength,\r
IN OUT UINTN *Column,\r
@param[in, out] Row Current row of the cursor position\r
**/\r
VOID\r
-EFIAPI\r
MoveCursorForward (\r
IN UINTN LineLength,\r
IN UINTN TotalRow,\r
@param[in] StartColumn which column to start at\r
**/\r
VOID\r
-EFIAPI\r
PrintCommandHistory (\r
IN CONST UINTN TotalCols,\r
IN CONST UINTN TotalRows,\r
\r
/**\r
File style interface for Mem (SetPosition).\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
@param[out] Position The position to set.\r
- \r
+\r
@retval EFI_SUCCESS The position was successfully changed.\r
@retval EFI_INVALID_PARAMETER The Position was invalid.\r
**/\r
\r
/**\r
File style interface for Mem (GetPosition).\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
@param[out] Position The pointer to the position.\r
- \r
+\r
@retval EFI_SUCCESS The position was retrieved.\r
-**/ \r
+**/\r
EFI_STATUS\r
EFIAPI\r
FileInterfaceMemGetPosition(\r
return (EFI_SUCCESS);\r
}\r
\r
+/**\r
+ File style interface for Mem (GetInfo).\r
+\r
+ @param This Protocol instance pointer.\r
+ @param InformationType Type of information to return in Buffer.\r
+ @param BufferSize On input size of buffer, on output amount of data in buffer.\r
+ @param Buffer The buffer to return data.\r
+\r
+ @retval EFI_SUCCESS Data was returned.\r
+ @retval EFI_UNSUPPORT InformationType is not supported.\r
+ @retval EFI_NO_MEDIA The device has no media.\r
+ @retval EFI_DEVICE_ERROR The device reported an error.\r
+ @retval EFI_VOLUME_CORRUPTED The file system structures are corrupted.\r
+ @retval EFI_WRITE_PROTECTED The device is write protected.\r
+ @retval EFI_ACCESS_DENIED The file was open for read only.\r
+ @retval EFI_BUFFER_TOO_SMALL Buffer was too small; required size returned in BufferSize.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FileInterfaceMemGetInfo(\r
+ IN EFI_FILE_PROTOCOL *This,\r
+ IN EFI_GUID *InformationType,\r
+ IN OUT UINTN *BufferSize,\r
+ OUT VOID *Buffer\r
+ )\r
+{\r
+ EFI_FILE_INFO *FileInfo;\r
+\r
+ if (CompareGuid (InformationType, &gEfiFileInfoGuid)) {\r
+ if (*BufferSize < sizeof (EFI_FILE_INFO)) {\r
+ *BufferSize = sizeof (EFI_FILE_INFO);\r
+ return EFI_BUFFER_TOO_SMALL;\r
+ }\r
+ if (Buffer == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+ FileInfo = (EFI_FILE_INFO *)Buffer;\r
+ FileInfo->Size = sizeof (*FileInfo);\r
+ ZeroMem (FileInfo, sizeof (*FileInfo));\r
+ FileInfo->FileSize = ((EFI_FILE_PROTOCOL_MEM*)This)->FileSize;\r
+ FileInfo->PhysicalSize = FileInfo->FileSize;\r
+ return EFI_SUCCESS;\r
+ }\r
+\r
+ return EFI_UNSUPPORTED;\r
+}\r
+\r
/**\r
File style interface for Mem (Write).\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
@param[in, out] BufferSize Size in bytes of Buffer.\r
@param[in] Buffer The pointer to the buffer to write.\r
- \r
+\r
@retval EFI_OUT_OF_RESOURCES The operation failed due to lack of resources.\r
@retval EFI_SUCCESS The data was written.\r
**/\r
// Unicode\r
//\r
if ((UINTN)(MemFile->Position + (*BufferSize)) > (UINTN)(MemFile->BufferSize)) {\r
- MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + (*BufferSize) + 10, MemFile->Buffer);\r
- MemFile->BufferSize += (*BufferSize) + 10;\r
+ MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);\r
+ MemFile->BufferSize += (*BufferSize) + MEM_WRITE_REALLOC_OVERHEAD;\r
}\r
CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, Buffer, *BufferSize);\r
MemFile->Position += (*BufferSize);\r
}\r
AsciiSPrint(AsciiBuffer, *BufferSize, "%S", Buffer);\r
if ((UINTN)(MemFile->Position + AsciiStrSize(AsciiBuffer)) > (UINTN)(MemFile->BufferSize)) {\r
- MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + AsciiStrSize(AsciiBuffer) + 10, MemFile->Buffer);\r
- MemFile->BufferSize += AsciiStrSize(AsciiBuffer) + 10;\r
+ MemFile->Buffer = ReallocatePool((UINTN)(MemFile->BufferSize), (UINTN)(MemFile->BufferSize) + AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD, MemFile->Buffer);\r
+ MemFile->BufferSize += AsciiStrSize(AsciiBuffer) + MEM_WRITE_REALLOC_OVERHEAD;\r
}\r
CopyMem(((UINT8*)MemFile->Buffer) + MemFile->Position, AsciiBuffer, AsciiStrSize(AsciiBuffer));\r
MemFile->Position += (*BufferSize / sizeof(CHAR16));\r
\r
/**\r
File style interface for Mem (Read).\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
@param[in, out] BufferSize Size in bytes of Buffer.\r
@param[in] Buffer The pointer to the buffer to fill.\r
- \r
+\r
@retval EFI_SUCCESS The data was read.\r
**/\r
EFI_STATUS\r
File style interface for Mem (Close).\r
\r
Frees all memory associated with this object.\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
- \r
+\r
@retval EFI_SUCCESS The 'file' was closed.\r
-**/ \r
+**/\r
EFI_STATUS\r
EFIAPI\r
FileInterfaceMemClose(\r
@return other A pointer to an EFI_FILE_PROTOCOL structure.\r
**/\r
EFI_FILE_PROTOCOL*\r
-EFIAPI\r
CreateFileInterfaceMem(\r
IN CONST BOOLEAN Unicode\r
)\r
FileInterface->Close = FileInterfaceMemClose;\r
FileInterface->GetPosition = FileInterfaceMemGetPosition;\r
FileInterface->SetPosition = FileInterfaceMemSetPosition;\r
- FileInterface->GetInfo = FileInterfaceNopGetInfo;\r
+ FileInterface->GetInfo = FileInterfaceMemGetInfo;\r
FileInterface->SetInfo = FileInterfaceNopSetInfo;\r
FileInterface->Flush = FileInterfaceNopGeneric;\r
FileInterface->Delete = FileInterfaceNopGeneric;\r
\r
@param This Protocol instance pointer.\r
@param Position Byte position from the start of the file.\r
- \r
+\r
@retval EFI_SUCCESS Data was written.\r
@retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open.\r
\r
\r
@param This Protocol instance pointer.\r
@param Position Byte position from the start of the file.\r
- \r
+\r
@retval EFI_SUCCESS Data was written.\r
@retval EFI_UNSUPPORTED Seek request for non-zero is not valid on open..\r
\r
Close and delete the file handle.\r
\r
@param This Protocol instance pointer.\r
- \r
+\r
@retval EFI_SUCCESS The device was opened.\r
@retval EFI_WARN_DELETE_FAILURE The handle was closed but the file was not deleted.\r
\r
\r
/**\r
File style interface for File (Close).\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
- \r
+\r
@retval EFI_SUCCESS The file was closed.\r
**/\r
EFI_STATUS\r
/**\r
File style interface for File (Write).\r
\r
- If the file was opened with ASCII mode the data will be processed through \r
+ If the file was opened with ASCII mode the data will be processed through\r
AsciiSPrint before writing.\r
- \r
+\r
@param[in] This The pointer to the EFI_FILE_PROTOCOL object.\r
@param[in, out] BufferSize Size in bytes of Buffer.\r
@param[in] Buffer The pointer to the buffer to write.\r
- \r
+\r
@retval EFI_SUCCESS The data was written.\r
**/\r
EFI_STATUS\r
\r
This will create a new EFI_FILE_PROTOCOL identical to the Templace\r
except that the new one has Unicode and Ascii knowledge.\r
- \r
+\r
@param[in] Template A pointer to the EFI_FILE_PROTOCOL object.\r
@param[in] Unicode TRUE for UCS-2, FALSE for ASCII.\r
- \r
+\r
@return a new EFI_FILE_PROTOCOL object to be used instead of the template.\r
**/\r
EFI_FILE_PROTOCOL*\r