]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
pointer verification (not NULL) and buffer overrun fixes.
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Ls.c
1 /** @file
2 Main file for ls shell level 2 function.
3
4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "UefiShellLevel2CommandsLib.h"
16 #include <Guid/FileSystemInfo.h>
17
18 /**
19 print out the list of files and directories from the LS command
20
21 @param[in] Rec TRUE to automatically recurse into each found directory
22 FALSE to only list the specified directory.
23 @param[in] Attribs List of required Attribute for display.
24 If 0 then all non-system and non-hidden files will be printed.
25 @param[in] Sfo TRUE to use Standard Format Output, FALSE otherwise
26 @param[in] Path String with starting path.
27 @param[in] First TRUE for the original and FALSE for any recursion spawned instances.
28 @param[in] Count The count of bits enabled in Attribs.
29 @param[in] TimeZone The current time zone offset.
30
31 @retval SHELL_SUCCESS the printing was sucessful.
32 **/
33 SHELL_STATUS
34 EFIAPI
35 PrintLsOutput(
36 IN CONST BOOLEAN Rec,
37 IN CONST UINT64 Attribs,
38 IN CONST BOOLEAN Sfo,
39 IN CONST CHAR16 *Path,
40 IN CONST BOOLEAN First,
41 IN CONST UINTN Count,
42 IN CONST INT16 TimeZone
43 )
44 {
45 EFI_STATUS Status;
46 EFI_SHELL_FILE_INFO *ListHead;
47 EFI_SHELL_FILE_INFO *Node;
48 SHELL_STATUS ShellStatus;
49 UINT64 FileCount;
50 UINT64 DirCount;
51 UINT64 FileSize;
52 CHAR16 *DirectoryName;
53 UINTN LongestPath;
54 EFI_FILE_SYSTEM_INFO *SysInfo;
55 UINTN SysInfoSize;
56 SHELL_FILE_HANDLE ShellFileHandle;
57 CHAR16 *CorrectedPath;
58 EFI_FILE_PROTOCOL *EfiFpHandle;
59
60 FileCount = 0;
61 DirCount = 0;
62 FileSize = 0;
63 ListHead = NULL;
64 ShellStatus = SHELL_SUCCESS;
65 LongestPath = 0;
66 CorrectedPath = NULL;
67
68 CorrectedPath = StrnCatGrow(&CorrectedPath, NULL, Path, 0);
69 ASSERT(CorrectedPath != NULL);
70 ShellCommandCleanPath(CorrectedPath);
71
72 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
73 if (EFI_ERROR(Status)) {
74 return (SHELL_DEVICE_ERROR);
75 }
76 if (ListHead == NULL || IsListEmpty(&ListHead->Link)) {
77 //
78 // On the first one only we expect to find something...
79 // do we find the . and .. directories otherwise?
80 //
81 if (First) {
82 return (SHELL_NOT_FOUND);
83 }
84 return (SHELL_SUCCESS);
85 }
86
87 if (Sfo && First) {
88 //
89 // Get the first valid handle (directories)
90 //
91 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
92 ; !IsNull(&ListHead->Link, &Node->Link) && Node->Handle == NULL
93 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
94 );
95
96 if (Node->Handle == NULL) {
97 DirectoryName = GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link))->FullName);
98
99 //
100 // We need to open something up to get system information
101 //
102 Status = gEfiShellProtocol->OpenFileByName(
103 DirectoryName,
104 &ShellFileHandle,
105 EFI_FILE_MODE_READ);
106
107 ASSERT_EFI_ERROR(Status);
108 FreePool(DirectoryName);
109
110 //
111 // Get the Volume Info from ShellFileHandle
112 //
113 SysInfo = NULL;
114 SysInfoSize = 0;
115 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle);
116 Status = EfiFpHandle->GetInfo(
117 EfiFpHandle,
118 &gEfiFileSystemInfoGuid,
119 &SysInfoSize,
120 SysInfo);
121
122 if (Status == EFI_BUFFER_TOO_SMALL) {
123 SysInfo = AllocateZeroPool(SysInfoSize);
124 Status = EfiFpHandle->GetInfo(
125 EfiFpHandle,
126 &gEfiFileSystemInfoGuid,
127 &SysInfoSize,
128 SysInfo);
129 }
130
131 ASSERT_EFI_ERROR(Status);
132
133 gEfiShellProtocol->CloseFile(ShellFileHandle);
134 } else {
135 //
136 // Get the Volume Info from Node->Handle
137 //
138 SysInfo = NULL;
139 SysInfoSize = 0;
140 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(Node->Handle);
141 Status = EfiFpHandle->GetInfo(
142 EfiFpHandle,
143 &gEfiFileSystemInfoGuid,
144 &SysInfoSize,
145 SysInfo);
146
147 if (Status == EFI_BUFFER_TOO_SMALL) {
148 SysInfo = AllocateZeroPool(SysInfoSize);
149 Status = EfiFpHandle->GetInfo(
150 EfiFpHandle,
151 &gEfiFileSystemInfoGuid,
152 &SysInfoSize,
153 SysInfo);
154 }
155
156 ASSERT_EFI_ERROR(Status);
157 }
158
159 ShellPrintHiiEx (
160 -1,
161 -1,
162 NULL,
163 STRING_TOKEN (STR_GEN_SFO_HEADER),
164 gShellLevel2HiiHandle,
165 L"ls");
166 //
167 // print VolumeInfo table
168 //
169 ASSERT(SysInfo != NULL);
170 ShellPrintHiiEx (
171 0,
172 gST->ConOut->Mode->CursorRow,
173 NULL,
174 STRING_TOKEN (STR_LS_SFO_VOLINFO),
175 gShellLevel2HiiHandle,
176 SysInfo->VolumeLabel,
177 SysInfo->VolumeSize,
178 SysInfo->ReadOnly?L"TRUE":L"FALSE",
179 SysInfo->FreeSpace,
180 SysInfo->BlockSize
181 );
182 if (SysInfo != NULL) {
183 FreePool(SysInfo);
184 }
185 }
186
187 if (!Sfo) {
188 //
189 // get directory name from path...
190 //
191 DirectoryName = GetFullyQualifiedPath(CorrectedPath);
192
193 //
194 // print header
195 //
196 ShellPrintHiiEx (
197 0,
198 gST->ConOut->Mode->CursorRow,
199 NULL,
200 STRING_TOKEN (STR_LS_HEADER_LINE1),
201 gShellLevel2HiiHandle,
202 DirectoryName
203 );
204 FreePool(DirectoryName);
205 }
206 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
207 ; !IsNull(&ListHead->Link, &Node->Link)
208 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
209 ){
210 ASSERT(Node != NULL);
211 if (LongestPath < StrSize(Node->FullName)) {
212 LongestPath = StrSize(Node->FullName);
213 }
214 ASSERT(Node->Info != NULL);
215 ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute);
216 if (Attribs == 0) {
217 //
218 // NOT system & NOT hidden
219 //
220 if ( (Node->Info->Attribute & EFI_FILE_SYSTEM)
221 || (Node->Info->Attribute & EFI_FILE_HIDDEN)
222 ){
223 continue;
224 }
225 } else if (Attribs != EFI_FILE_VALID_ATTR) {
226 if (Count == 1) {
227 //
228 // the bit must match
229 //
230 if ( (Node->Info->Attribute & Attribs) != Attribs) {
231 continue;
232 }
233 } else {
234 //
235 // exact match on all bits
236 //
237 if ( (Node->Info->Attribute|EFI_FILE_ARCHIVE) != (Attribs|EFI_FILE_ARCHIVE)) {
238 continue;
239 }
240 }
241 }
242
243 if (Sfo) {
244 //
245 // Print the FileInfo Table
246 //
247 ShellPrintHiiEx (
248 0,
249 gST->ConOut->Mode->CursorRow,
250 NULL,
251 STRING_TOKEN (STR_LS_SFO_FILEINFO),
252 gShellLevel2HiiHandle,
253 Node->FullName,
254 Node->Info->FileSize,
255 Node->Info->PhysicalSize,
256 (Node->Info->Attribute & EFI_FILE_ARCHIVE) != 0?L"a":L"",
257 (Node->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"d":L"",
258 (Node->Info->Attribute & EFI_FILE_HIDDEN) != 0?L"h":L"",
259 (Node->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L"r":L"",
260 (Node->Info->Attribute & EFI_FILE_SYSTEM) != 0?L"s":L"",
261 Node->Info->CreateTime.Hour,
262 Node->Info->CreateTime.Minute,
263 Node->Info->CreateTime.Second,
264 Node->Info->CreateTime.Day,
265 Node->Info->CreateTime.Month,
266 Node->Info->CreateTime.Year,
267 Node->Info->LastAccessTime.Hour,
268 Node->Info->LastAccessTime.Minute,
269 Node->Info->LastAccessTime.Second,
270 Node->Info->LastAccessTime.Day,
271 Node->Info->LastAccessTime.Month,
272 Node->Info->LastAccessTime.Year,
273 Node->Info->ModificationTime.Hour,
274 Node->Info->ModificationTime.Minute,
275 Node->Info->ModificationTime.Second,
276 Node->Info->ModificationTime.Day,
277 Node->Info->ModificationTime.Month,
278 Node->Info->ModificationTime.Year
279 );
280 } else {
281 //
282 // print this one out...
283 // first print the universal start, next print the type specific name format, last print the CRLF
284 //
285 ShellPrintHiiEx (
286 -1,
287 -1,
288 NULL,
289 STRING_TOKEN (STR_LS_LINE_START_ALL),
290 gShellLevel2HiiHandle,
291 &Node->Info->ModificationTime,
292 (Node->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"<DIR>":L"",
293 (Node->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L'r':L' ',
294 Node->Info->FileSize
295 );
296 if (Node->Info->Attribute & EFI_FILE_DIRECTORY) {
297 DirCount++;
298 ShellPrintHiiEx (
299 -1,
300 -1,
301 NULL,
302 STRING_TOKEN (STR_LS_LINE_END_DIR),
303 gShellLevel2HiiHandle,
304 Node->FileName
305 );
306 } else {
307 FileCount++;
308 FileSize += Node->Info->FileSize;
309 if ( (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".nsh", (CHAR16*)&(Node->FileName[StrLen (Node->FileName) - 4])) == 0)
310 || (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".efi", (CHAR16*)&(Node->FileName[StrLen (Node->FileName) - 4])) == 0)
311 ){
312 ShellPrintHiiEx (
313 -1,
314 -1,
315 NULL,
316 STRING_TOKEN (STR_LS_LINE_END_EXE),
317 gShellLevel2HiiHandle,
318 Node->FileName
319 );
320 } else {
321 ShellPrintHiiEx (
322 -1,
323 -1,
324 NULL,
325 STRING_TOKEN (STR_LS_LINE_END_FILE),
326 gShellLevel2HiiHandle,
327 Node->FileName
328 );
329 }
330 }
331 }
332 }
333
334 if (!Sfo) {
335 //
336 // print footer
337 //
338 ShellPrintHiiEx (
339 -1,
340 -1,
341 NULL,
342 STRING_TOKEN (STR_LS_FOOTER_LINE),
343 gShellLevel2HiiHandle,
344 FileCount,
345 FileSize,
346 DirCount
347 );
348 }
349
350 if (Rec){
351 DirectoryName = AllocateZeroPool(LongestPath + 2*sizeof(CHAR16));
352 if (DirectoryName == NULL) {
353 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);
354 ShellStatus = SHELL_OUT_OF_RESOURCES;
355 } else {
356 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
357 ; !IsNull(&ListHead->Link, &Node->Link)
358 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
359 ){
360 //
361 // recurse on any directory except the traversing ones...
362 //
363 if (((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY)
364 && StrCmp(Node->FileName, L".") != 0
365 && StrCmp(Node->FileName, L"..") != 0
366 ){
367 StrCpy(DirectoryName, Node->FullName);
368 StrCat(DirectoryName, L"\\*");
369 PrintLsOutput(
370 Rec,
371 Attribs,
372 Sfo,
373 DirectoryName,
374 FALSE,
375 Count,
376 TimeZone);
377 }
378 }
379 FreePool(DirectoryName);
380 }
381 }
382
383 FreePool(CorrectedPath);
384 ShellCloseFileMetaArg(&ListHead);
385 FreePool(ListHead);
386 return (ShellStatus);
387 }
388
389 STATIC CONST SHELL_PARAM_ITEM LsParamList[] = {
390 {L"-r", TypeFlag},
391 {L"-a", TypeStart},
392 {L"-sfo", TypeFlag},
393 {NULL, TypeMax}
394 };
395
396 /**
397 Function for 'ls' command.
398
399 @param[in] ImageHandle Handle to the Image (NULL if Internal).
400 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
401 **/
402 SHELL_STATUS
403 EFIAPI
404 ShellCommandRunLs (
405 IN EFI_HANDLE ImageHandle,
406 IN EFI_SYSTEM_TABLE *SystemTable
407 )
408 {
409 EFI_STATUS Status;
410 LIST_ENTRY *Package;
411 CHAR16 *ProblemParam;
412 CONST CHAR16 *Attribs;
413 SHELL_STATUS ShellStatus;
414 UINT64 RequiredAttributes;
415 CONST CHAR16 *PathName;
416 CONST CHAR16 *CurDir;
417 UINTN Count;
418 CHAR16 *FullPath;
419 UINTN Size;
420 EFI_TIME TheTime;
421 BOOLEAN SfoMode;
422
423 Size = 0;
424 FullPath = NULL;
425 ProblemParam = NULL;
426 Attribs = NULL;
427 ShellStatus = SHELL_SUCCESS;
428 RequiredAttributes = 0;
429 PathName = NULL;
430 CurDir = NULL;
431 Count = 0;
432
433 //
434 // initialize the shell lib (we must be in non-auto-init...)
435 //
436 Status = ShellInitialize();
437 ASSERT_EFI_ERROR(Status);
438
439 //
440 // Fix local copies of the protocol pointers
441 //
442 Status = CommandInit();
443 ASSERT_EFI_ERROR(Status);
444
445 //
446 // parse the command line
447 //
448 Status = ShellCommandLineParse (LsParamList, &Package, &ProblemParam, TRUE);
449 if (EFI_ERROR(Status)) {
450 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
451 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);
452 FreePool(ProblemParam);
453 ShellStatus = SHELL_INVALID_PARAMETER;
454 } else {
455 ASSERT(FALSE);
456 }
457 } else {
458 //
459 // check for "-?"
460 //
461 if (ShellCommandLineGetFlag(Package, L"-?")) {
462 ASSERT(FALSE);
463 }
464
465 if (ShellCommandLineGetCount(Package) > 2) {
466 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle);
467 ShellStatus = SHELL_INVALID_PARAMETER;
468 } else {
469 //
470 // check for -a
471 //
472 if (ShellCommandLineGetFlag(Package, L"-a")) {
473 for ( Attribs = ShellCommandLineGetValue(Package, L"-a")
474 ; Attribs != NULL && *Attribs != CHAR_NULL && ShellStatus == SHELL_SUCCESS
475 ; Attribs++
476 ){
477 switch (*Attribs) {
478 case L'a':
479 case L'A':
480 RequiredAttributes |= EFI_FILE_ARCHIVE;
481 Count++;
482 continue;
483 case L's':
484 case L'S':
485 RequiredAttributes |= EFI_FILE_SYSTEM;
486 Count++;
487 continue;
488 case L'h':
489 case L'H':
490 RequiredAttributes |= EFI_FILE_HIDDEN;
491 Count++;
492 continue;
493 case L'r':
494 case L'R':
495 RequiredAttributes |= EFI_FILE_READ_ONLY;
496 Count++;
497 continue;
498 case L'd':
499 case L'D':
500 RequiredAttributes |= EFI_FILE_DIRECTORY;
501 Count++;
502 continue;
503 default:
504 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ATTRIBUTE), gShellLevel2HiiHandle, ShellCommandLineGetValue(Package, L"-a"));
505 ShellStatus = SHELL_INVALID_PARAMETER;
506 break;
507 } // switch
508 } // for loop
509 //
510 // if nothing is specified all are specified
511 //
512 if (RequiredAttributes == 0) {
513 RequiredAttributes = EFI_FILE_VALID_ATTR;
514 }
515 } // if -a present
516 if (ShellStatus == SHELL_SUCCESS) {
517 PathName = ShellCommandLineGetRawValue(Package, 1);
518 if (PathName == NULL) {
519 CurDir = gEfiShellProtocol->GetCurDir(NULL);
520 if (CurDir == NULL) {
521 ShellStatus = SHELL_NOT_FOUND;
522 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
523 }
524 }
525 if (PathName != NULL) {
526 if (StrStr(PathName, L":") == NULL && gEfiShellProtocol->GetCurDir(NULL) == NULL) {
527 ShellStatus = SHELL_NOT_FOUND;
528 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
529 } else {
530 ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL));
531 StrnCatGrow(&FullPath, &Size, PathName, 0);
532 if (ShellIsDirectory(PathName) == EFI_SUCCESS) {
533 StrnCatGrow(&FullPath, &Size, L"\\*", 0);
534 }
535 }
536 } else {
537 ASSERT(FullPath == NULL);
538 StrnCatGrow(&FullPath, NULL, L"*", 0);
539 }
540 Status = gRT->GetTime(&TheTime, NULL);
541 ASSERT_EFI_ERROR(Status);
542 SfoMode = ShellCommandLineGetFlag(Package, L"-sfo");
543 if (ShellStatus == SHELL_SUCCESS) {
544 ShellStatus = PrintLsOutput(
545 ShellCommandLineGetFlag(Package, L"-r"),
546 RequiredAttributes,
547 SfoMode,
548 FullPath,
549 TRUE,
550 Count,
551 (INT16)(TheTime.TimeZone==2047?0:TheTime.TimeZone)
552 );
553 if (ShellStatus == SHELL_NOT_FOUND) {
554 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_FILES), gShellLevel2HiiHandle);
555 } else if (ShellStatus == SHELL_INVALID_PARAMETER) {
556 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle);
557 } else if (ShellStatus != SHELL_SUCCESS) {
558 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle);
559 }
560 }
561 }
562 }
563 }
564
565 if (FullPath != NULL) {
566 FreePool(FullPath);
567 }
568 //
569 // free the command line package
570 //
571 ShellCommandLineFreeVarList (Package);
572
573 return (ShellStatus);
574 }