We’re facing issues with the input redirection in shell (specifically with the input redirection from ASCII file). I’m wondering if anybody faced similar issues, or perhaps, Shell developers can provide some insights.
According to Shell specification (section 3.4.4.2) shell supports input redirection using the following syntax: ‘Command < filename’ to redirect standard input from a Unicode file. ‘Command <a filename’ to redirect standard input from an ASCII file. Here is the e-mail from one of our developers describing the issues we faced and workarounds we came up with: ===== I faced an issue with input redirection in shell. It is working with Unicode file, but not working with ASCII file. I tried to experiment with the “ls –b” command. The command prints one screen and requests user confirmation to continue (“Press ENTER to continue or “Q” break:”). I created a Unicode file 1.txt which contains only “q”. When I use command “ls –b < 1.txt” the command behaves as expected: prints a single screen and exists as if I pressed “q”. When I converted the same file to ASCII and tried to run “ls –b <a 1.txt” command, the command didn’t work as expected. After displaying the first screen the command printed the message “Press ENTER to continue or “Q” break:” numerous times (about 20) and finally exited without reading the “q” key. I made a fix in FileInterfaceFileRead function in FileHandleWrappers.c file (see the patch below). The function reads ASCII input string and converts it to a Unicode string using UnicodeSPrint function: UnicodeSPrint(Buffer, *BufferSize, L"%a", AsciiBuffer); The problem is that the *BufferSize that is coming to a function as an input parameter is not large enough to add a NULL terminator. In case of “ls –b” command, the *BufferSize is 2, and UnicodeSPrint produces a blank string. I tried to use UnicodeSPrint with a temporary buffer that is large enough for a NULL terminator. Once string is converted I use CopyMem to copy data(excluding NULL terminator) to the original Buffer. These changes resolved the original problem (the redirection from ASCII file worked fine); however, I noticed another problem. If 1.txt ASCII file contains multiple characters, for example “abcdefg” each even character is skipped (using the same command “ls –b <a 1.txt”) and the result is as if user pressed a, c, e, g characters on each “Press ENTER to continue or “Q” break:” request. I found out that this is because size passed to (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer)); function is equal to a total Unicode buffer size, which means the function will read more ASCII characters that can actually fit into a Unicode buffer(twice as much). After setting Size to a half of the Unicode buffer size (*BufferSize/2) the problem was fixed; however, another problem arose: it looks like content of the redirection file affects the redirection behavior. For example having “eeeeq” will results in reading all characters including q. While having “acdeq” will result in successfully reading only a and c and throwing a lot of “Press ENTER to continue or “Q” break:” messages after that like it was described in the beginning. Here is the modifications I’ve made: diff --git a/ShellPkg/Application/Shell/FileHandleWrappers.c b/ShellPkg/Application/Shell/FileHandleWrappers.c index 18b6c3e..8903c50 100644 --- a/ShellPkg/Application/Shell/FileHandleWrappers.c +++ b/ShellPkg/Application/Shell/FileHandleWrappers.c @@ -1671,7 +1671,9 @@ FileInterfaceFileRead( ) { CHAR8 *AsciiBuffer; + VOID *TmpBuf; UINTN Size; + UINTN Number = 0; EFI_STATUS Status; if (((EFI_FILE_PROTOCOL_FILE*)This)->Unicode) { // @@ -1683,9 +1685,22 @@ FileInterfaceFileRead( // Ascii // AsciiBuffer = AllocateZeroPool((Size = *BufferSize)); + Size = *BufferSize/2; Status = (((EFI_FILE_PROTOCOL_FILE*)This)->Orig->Read(((EFI_FILE_PROTOCOL_FILE*)This)->Orig, &Size, AsciiBuffer)); - UnicodeSPrint(Buffer, *BufferSize, L"%a", AsciiBuffer); + if (!EFI_ERROR(Status)) + { + TmpBuf = AllocateZeroPool((*BufferSize + 2)); //UnicodeSPrint adds null terminator to any output so we need a bigger buffer + Number = UnicodeSPrint(TmpBuf, *BufferSize + 2, L"%a", AsciiBuffer); + if (Number) + CopyMem (Buffer, TmpBuf, *BufferSize); //Copy output to final destination without null terminator. + FreePool(TmpBuf); + } FreePool(AsciiBuffer); + if (Number) + *BufferSize = Number*2; + else + *BufferSize = Size*2; + return (Status); } } == Thanks Felix The information contained in this message may be confidential and proprietary to American Megatrends, Inc. This communication is intended to be read only by the individual or entity to whom it is addressed or by their designee. If the reader of this message is not the intended recipient, you are on notice that any distribution of this message, in any form, is strictly prohibited. Please promptly notify the sender by reply e-mail or by telephone at 770-246-8600, and then delete or destroy all copies of the transmission. _______________________________________________ edk2-devel mailing list edk2-devel@lists.01.org https://lists.01.org/mailman/listinfo/edk2-devel