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