1 /** @file
2   Main file for Type shell level 3 function.
3 
4   (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
5   Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved. <BR>
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "UefiShellLevel3CommandsLib.h"
17 
18 #include <Library/ShellLib.h>
19 
20 /**
21   Display a single file to StdOut.
22 
23   If both Ascii and UCS2 are FALSE attempt to discover the file type.
24 
25   @param[in] Handle   The handle to the file to display.
26   @param[in] Ascii    TRUE to force ASCII, FALSE othewise.
27   @param[in] UCS2     TRUE to force UCS2, FALSE othewise.
28 
29   @retval EFI_OUT_OF_RESOURCES  A memory allocation failed.
30   @retval EFI_SUCCESS           The operation was successful.
31 **/
32 EFI_STATUS
33 EFIAPI
TypeFileByHandle(IN SHELL_FILE_HANDLE Handle,IN BOOLEAN Ascii,IN BOOLEAN UCS2)34 TypeFileByHandle (
35   IN SHELL_FILE_HANDLE Handle,
36   IN BOOLEAN Ascii,
37   IN BOOLEAN UCS2
38   )
39 {
40   UINTN       ReadSize;
41   VOID        *Buffer;
42   VOID        *AllocatedBuffer;
43   EFI_STATUS  Status;
44   UINTN       LoopVar;
45   UINTN       LoopSize;
46   CHAR16      AsciiChar;
47   CHAR16      Ucs2Char;
48 
49   ReadSize = PcdGet32(PcdShellFileOperationSize);
50   AllocatedBuffer = AllocateZeroPool(ReadSize);
51   if (AllocatedBuffer == NULL) {
52     return (EFI_OUT_OF_RESOURCES);
53   }
54 
55   Status = ShellSetFilePosition(Handle, 0);
56   ASSERT_EFI_ERROR(Status);
57 
58   while (ReadSize == ((UINTN)PcdGet32(PcdShellFileOperationSize))) {
59     Buffer = AllocatedBuffer;
60     ZeroMem(Buffer, ReadSize);
61     Status = ShellReadFile(Handle, &ReadSize, Buffer);
62     if (EFI_ERROR(Status)){
63       break;
64     }
65 
66     if (!(Ascii|UCS2)) {
67       if (*(UINT16*)Buffer == gUnicodeFileTag) {
68         UCS2 = TRUE;
69       } else {
70         Ascii = TRUE;
71       }
72     }
73 
74     if (Ascii) {
75       LoopSize = ReadSize;
76       for (LoopVar = 0 ; LoopVar < LoopSize ; LoopVar++) {
77         //
78         // The valid range of ASCII characters is 0x20-0x7E.
79         // Display "." when there is an invalid character.
80         //
81         AsciiChar = CHAR_NULL;
82         AsciiChar = ((CHAR8*)Buffer)[LoopVar];
83         if (AsciiChar == '\r' || AsciiChar == '\n') {
84           //
85           // Allow Line Feed (LF) (0xA) & Carriage Return (CR) (0xD)
86           // characters to be displayed as is.
87           //
88           if (AsciiChar == '\n' && ((CHAR8*)Buffer)[LoopVar-1] != '\r') {
89             //
90             // In case Line Feed (0xA) is encountered & Carriage Return (0xD)
91             // was not the previous character, print CR and LF. This is because
92             // Shell 2.0 requires carriage return with line feed for displaying
93             // each new line from left.
94             //
95             ShellPrintEx (-1, -1, L"\r\n");
96             continue;
97           }
98         } else {
99           //
100           // For all other characters which are not printable, display '.'
101           //
102           if (AsciiChar < 0x20 || AsciiChar >= 0x7F) {
103             AsciiChar = '.';
104           }
105         }
106         ShellPrintEx (-1, -1, L"%c", AsciiChar);
107       }
108     } else {
109       if (*(UINT16*)Buffer == gUnicodeFileTag) {
110         //
111         // For unicode files, skip displaying the byte order marker.
112         //
113         Buffer = ((UINT16*)Buffer) + 1;
114         LoopSize = (ReadSize / (sizeof (CHAR16))) - 1;
115       } else {
116         LoopSize = ReadSize / (sizeof (CHAR16));
117       }
118 
119       for (LoopVar = 0 ; LoopVar < LoopSize ; LoopVar++) {
120         //
121         // An invalid range of characters is 0x0-0x1F.
122         // Display "." when there is an invalid character.
123         //
124         Ucs2Char = CHAR_NULL;
125         Ucs2Char = ((CHAR16*)Buffer)[LoopVar];
126         if (Ucs2Char == '\r' || Ucs2Char == '\n') {
127           //
128           // Allow Line Feed (LF) (0xA) & Carriage Return (CR) (0xD)
129           // characters to be displayed as is.
130           //
131           if (Ucs2Char == '\n' && ((CHAR16*)Buffer)[LoopVar-1] != '\r') {
132             //
133             // In case Line Feed (0xA) is encountered & Carriage Return (0xD)
134             // was not the previous character, print CR and LF. This is because
135             // Shell 2.0 requires carriage return with line feed for displaying
136             // each new line from left.
137             //
138             ShellPrintEx (-1, -1, L"\r\n");
139             continue;
140           }
141         }
142         else if (Ucs2Char < 0x20) {
143           //
144           // For all other characters which are not printable, display '.'
145           //
146           Ucs2Char = L'.';
147         }
148         ShellPrintEx (-1, -1, L"%c", Ucs2Char);
149       }
150     }
151 
152     if (ShellGetExecutionBreakFlag()) {
153       break;
154     }
155   }
156   FreePool (AllocatedBuffer);
157   ShellPrintEx (-1, -1, L"\r\n");
158   return (Status);
159 }
160 
161 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
162   {L"-a", TypeFlag},
163   {L"-u", TypeFlag},
164   {NULL, TypeMax}
165   };
166 
167 /**
168   Function for 'type' command.
169 
170   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
171   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
172 **/
173 SHELL_STATUS
174 EFIAPI
ShellCommandRunType(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)175 ShellCommandRunType (
176   IN EFI_HANDLE        ImageHandle,
177   IN EFI_SYSTEM_TABLE  *SystemTable
178   )
179 {
180   EFI_STATUS          Status;
181   LIST_ENTRY          *Package;
182   CHAR16              *ProblemParam;
183   CONST CHAR16        *Param;
184   SHELL_STATUS        ShellStatus;
185   UINTN               ParamCount;
186   EFI_SHELL_FILE_INFO *FileList;
187   EFI_SHELL_FILE_INFO *Node;
188   BOOLEAN             AsciiMode;
189   BOOLEAN             UnicodeMode;
190 
191   ProblemParam        = NULL;
192   ShellStatus         = SHELL_SUCCESS;
193   ParamCount          = 0;
194   FileList            = NULL;
195 
196   //
197   // initialize the shell lib (we must be in non-auto-init...)
198   //
199   Status = ShellInitialize();
200   ASSERT_EFI_ERROR(Status);
201 
202   Status = CommandInit();
203   ASSERT_EFI_ERROR(Status);
204 
205   //
206   // parse the command line
207   //
208   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
209   if (EFI_ERROR(Status)) {
210     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
211       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel3HiiHandle, L"type", ProblemParam);
212       FreePool(ProblemParam);
213       ShellStatus = SHELL_INVALID_PARAMETER;
214     } else {
215       ASSERT(FALSE);
216     }
217   } else {
218     //
219     // check for "-?"
220     //
221     if (ShellCommandLineGetFlag(Package, L"-?")) {
222       ASSERT(FALSE);
223     }
224     AsciiMode   = ShellCommandLineGetFlag(Package, L"-a");
225     UnicodeMode = ShellCommandLineGetFlag(Package, L"-u");
226 
227     if (AsciiMode && UnicodeMode) {
228       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel3HiiHandle, L"type", L"-a & -u");
229       ShellStatus = SHELL_INVALID_PARAMETER;
230    } else if (ShellCommandLineGetRawValue(Package, 1) == NULL) {
231       //
232       // we insufficient parameters
233       //
234       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellLevel3HiiHandle, L"type");
235       ShellStatus = SHELL_INVALID_PARAMETER;
236     } else {
237       //
238       // get a list with each file specified by parameters
239       // if parameter is a directory then add all the files below it to the list
240       //
241       for ( ParamCount = 1, Param = ShellCommandLineGetRawValue(Package, ParamCount)
242           ; Param != NULL
243           ; ParamCount++, Param = ShellCommandLineGetRawValue(Package, ParamCount)
244          ){
245         Status = ShellOpenFileMetaArg((CHAR16*)Param, EFI_FILE_MODE_READ, &FileList);
246         if (EFI_ERROR(Status)) {
247           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel3HiiHandle, L"type", (CHAR16*)Param);
248           ShellStatus = SHELL_NOT_FOUND;
249           break;
250         }
251         //
252         // make sure we completed the param parsing sucessfully...
253         // Also make sure that any previous action was sucessful
254         //
255         if (ShellStatus == SHELL_SUCCESS) {
256           //
257           // check that we have at least 1 file
258           //
259           if (FileList == NULL || IsListEmpty(&FileList->Link)) {
260             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_NF), gShellLevel3HiiHandle, L"type", Param);
261             continue;
262           } else {
263             //
264             // loop through the list and make sure we are not aborting...
265             //
266             for ( Node = (EFI_SHELL_FILE_INFO*)GetFirstNode(&FileList->Link)
267                 ; !IsNull(&FileList->Link, &Node->Link) && !ShellGetExecutionBreakFlag()
268                 ; Node = (EFI_SHELL_FILE_INFO*)GetNextNode(&FileList->Link, &Node->Link)
269                ){
270 
271               if (ShellGetExecutionBreakFlag()) {
272                 break;
273               }
274 
275               //
276               // make sure the file opened ok
277               //
278               if (EFI_ERROR(Node->Status)){
279                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellLevel3HiiHandle, L"type", Node->FileName);
280                 ShellStatus = SHELL_NOT_FOUND;
281                 continue;
282               }
283 
284               //
285               // make sure its not a directory
286               //
287               if (FileHandleIsDirectory(Node->Handle) == EFI_SUCCESS) {
288                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_IS_DIR), gShellLevel3HiiHandle, L"type", Node->FileName);
289                 ShellStatus = SHELL_NOT_FOUND;
290                 continue;
291               }
292 
293               //
294               // do it
295               //
296               Status = TypeFileByHandle (Node->Handle, AsciiMode, UnicodeMode);
297               if (EFI_ERROR(Status)) {
298                 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_TYP_ERROR), gShellLevel3HiiHandle, L"type", Node->FileName);
299                 ShellStatus = SHELL_INVALID_PARAMETER;
300               }
301               ASSERT(ShellStatus == SHELL_SUCCESS);
302             }
303           }
304         }
305         //
306         // Free the fileList
307         //
308         if (FileList != NULL && !IsListEmpty(&FileList->Link)) {
309           Status = ShellCloseFileMetaArg(&FileList);
310         }
311         ASSERT_EFI_ERROR(Status);
312         FileList = NULL;
313       }
314     }
315 
316     //
317     // free the command line package
318     //
319     ShellCommandLineFreeVarList (Package);
320   }
321 
322   if (ShellGetExecutionBreakFlag()) {
323     return (SHELL_ABORTED);
324   }
325 
326   return (ShellStatus);
327 }
328 
329