]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
ShellPkg/Dp: Add null pointer check
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Ls.c
1 /** @file
2 Main file for ls shell level 2 function.
3
4 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2017, 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 "UefiShellLevel2CommandsLib.h"
17 #include <Guid/FileSystemInfo.h>
18
19 UINTN mDayOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30};
20
21 /**
22 print out the standard format output volume entry.
23
24 @param[in] TheList a list of files from the volume.
25 **/
26 EFI_STATUS
27 PrintSfoVolumeInfoTableEntry(
28 IN CONST EFI_SHELL_FILE_INFO *TheList
29 )
30 {
31 EFI_STATUS Status;
32 EFI_SHELL_FILE_INFO *Node;
33 CHAR16 *DirectoryName;
34 EFI_FILE_SYSTEM_INFO *SysInfo;
35 UINTN SysInfoSize;
36 SHELL_FILE_HANDLE ShellFileHandle;
37 EFI_FILE_PROTOCOL *EfiFpHandle;
38
39 //
40 // Get the first valid handle (directories)
41 //
42 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&TheList->Link)
43 ; !IsNull(&TheList->Link, &Node->Link) && Node->Handle == NULL
44 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&TheList->Link, &Node->Link)
45 );
46
47 if (Node->Handle == NULL) {
48 DirectoryName = GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO *)GetFirstNode(&TheList->Link))->FullName);
49
50 //
51 // We need to open something up to get system information
52 //
53 Status = gEfiShellProtocol->OpenFileByName(
54 DirectoryName,
55 &ShellFileHandle,
56 EFI_FILE_MODE_READ
57 );
58
59 ASSERT_EFI_ERROR(Status);
60 FreePool(DirectoryName);
61
62 //
63 // Get the Volume Info from ShellFileHandle
64 //
65 SysInfo = NULL;
66 SysInfoSize = 0;
67 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle);
68 Status = EfiFpHandle->GetInfo(
69 EfiFpHandle,
70 &gEfiFileSystemInfoGuid,
71 &SysInfoSize,
72 SysInfo
73 );
74
75 if (Status == EFI_BUFFER_TOO_SMALL) {
76 SysInfo = AllocateZeroPool(SysInfoSize);
77 Status = EfiFpHandle->GetInfo(
78 EfiFpHandle,
79 &gEfiFileSystemInfoGuid,
80 &SysInfoSize,
81 SysInfo
82 );
83 }
84
85 ASSERT_EFI_ERROR(Status);
86
87 gEfiShellProtocol->CloseFile(ShellFileHandle);
88 } else {
89 //
90 // Get the Volume Info from Node->Handle
91 //
92 SysInfo = NULL;
93 SysInfoSize = 0;
94 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(Node->Handle);
95 Status = EfiFpHandle->GetInfo(
96 EfiFpHandle,
97 &gEfiFileSystemInfoGuid,
98 &SysInfoSize,
99 SysInfo
100 );
101
102 if (Status == EFI_BUFFER_TOO_SMALL) {
103 SysInfo = AllocateZeroPool(SysInfoSize);
104 Status = EfiFpHandle->GetInfo(
105 EfiFpHandle,
106 &gEfiFileSystemInfoGuid,
107 &SysInfoSize,
108 SysInfo
109 );
110 }
111
112 ASSERT_EFI_ERROR(Status);
113 }
114
115 ShellPrintHiiEx (
116 -1,
117 -1,
118 NULL,
119 STRING_TOKEN (STR_GEN_SFO_HEADER),
120 gShellLevel2HiiHandle,
121 L"ls"
122 );
123 //
124 // print VolumeInfo table
125 //
126 ASSERT(SysInfo != NULL);
127 ShellPrintHiiEx (
128 0,
129 gST->ConOut->Mode->CursorRow,
130 NULL,
131 STRING_TOKEN (STR_LS_SFO_VOLINFO),
132 gShellLevel2HiiHandle,
133 SysInfo->VolumeLabel,
134 SysInfo->VolumeSize,
135 SysInfo->ReadOnly?L"TRUE":L"FALSE",
136 SysInfo->FreeSpace,
137 SysInfo->BlockSize
138 );
139
140 SHELL_FREE_NON_NULL(SysInfo);
141
142 return (Status);
143 }
144
145 /**
146 print out the info on a single file.
147
148 @param[in] Sfo TRUE if in SFO, false otherwise.
149 @param[in] TheNode the EFI_SHELL_FILE_INFO node to print out information on.
150 @param[in] Files incremented if a file is printed.
151 @param[in] Size incremented by file size.
152 @param[in] Dirs incremented if a directory is printed.
153
154 **/
155 VOID
156 PrintFileInformation(
157 IN CONST BOOLEAN Sfo,
158 IN CONST EFI_SHELL_FILE_INFO *TheNode,
159 IN UINT64 *Files,
160 IN UINT64 *Size,
161 IN UINT64 *Dirs
162 )
163 {
164 ASSERT(Files != NULL);
165 ASSERT(Size != NULL);
166 ASSERT(Dirs != NULL);
167 ASSERT(TheNode != NULL);
168
169 if (Sfo) {
170 //
171 // Print the FileInfo Table
172 //
173 ShellPrintHiiEx (
174 0,
175 gST->ConOut->Mode->CursorRow,
176 NULL,
177 STRING_TOKEN (STR_LS_SFO_FILEINFO),
178 gShellLevel2HiiHandle,
179 TheNode->FullName,
180 TheNode->Info->FileSize,
181 TheNode->Info->PhysicalSize,
182 (TheNode->Info->Attribute & EFI_FILE_ARCHIVE) != 0?L"a":L"",
183 (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"d":L"",
184 (TheNode->Info->Attribute & EFI_FILE_HIDDEN) != 0?L"h":L"",
185 (TheNode->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L"r":L"",
186 (TheNode->Info->Attribute & EFI_FILE_SYSTEM) != 0?L"s":L"",
187 TheNode->Info->CreateTime.Hour,
188 TheNode->Info->CreateTime.Minute,
189 TheNode->Info->CreateTime.Second,
190 TheNode->Info->CreateTime.Day,
191 TheNode->Info->CreateTime.Month,
192 TheNode->Info->CreateTime.Year,
193 TheNode->Info->LastAccessTime.Hour,
194 TheNode->Info->LastAccessTime.Minute,
195 TheNode->Info->LastAccessTime.Second,
196 TheNode->Info->LastAccessTime.Day,
197 TheNode->Info->LastAccessTime.Month,
198 TheNode->Info->LastAccessTime.Year,
199 TheNode->Info->ModificationTime.Hour,
200 TheNode->Info->ModificationTime.Minute,
201 TheNode->Info->ModificationTime.Second,
202 TheNode->Info->ModificationTime.Day,
203 TheNode->Info->ModificationTime.Month,
204 TheNode->Info->ModificationTime.Year
205 );
206 } else {
207 //
208 // print this one out...
209 // first print the universal start, next print the type specific name format, last print the CRLF
210 //
211 ShellPrintHiiEx (
212 -1,
213 -1,
214 NULL,
215 STRING_TOKEN (STR_LS_LINE_START_ALL),
216 gShellLevel2HiiHandle,
217 &TheNode->Info->ModificationTime,
218 (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"<DIR>":L"",
219 (TheNode->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L'r':L' ',
220 TheNode->Info->FileSize
221 );
222 if (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) {
223 (*Dirs)++;
224 ShellPrintHiiEx (
225 -1,
226 -1,
227 NULL,
228 STRING_TOKEN (STR_LS_LINE_END_DIR),
229 gShellLevel2HiiHandle,
230 TheNode->FileName
231 );
232 } else {
233 (*Files)++;
234 (*Size) += TheNode->Info->FileSize;
235 if ( (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".nsh", (CHAR16*)&(TheNode->FileName[StrLen (TheNode->FileName) - 4])) == 0)
236 || (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".efi", (CHAR16*)&(TheNode->FileName[StrLen (TheNode->FileName) - 4])) == 0)
237 ){
238 ShellPrintHiiEx (
239 -1,
240 -1,
241 NULL,
242 STRING_TOKEN (STR_LS_LINE_END_EXE),
243 gShellLevel2HiiHandle,
244 TheNode->FileName
245 );
246 } else {
247 ShellPrintHiiEx (
248 -1,
249 -1,
250 NULL,
251 STRING_TOKEN (STR_LS_LINE_END_FILE),
252 gShellLevel2HiiHandle,
253 TheNode->FileName
254 );
255 }
256 }
257 }
258 }
259
260 /**
261 print out the header when not using standard format output.
262
263 @param[in] Path String with starting path.
264 **/
265 VOID
266 PrintNonSfoHeader(
267 IN CONST CHAR16 *Path
268 )
269 {
270 CHAR16 *DirectoryName;
271
272 //
273 // get directory name from path...
274 //
275 DirectoryName = GetFullyQualifiedPath(Path);
276
277 if (DirectoryName != NULL) {
278 //
279 // print header
280 //
281 ShellPrintHiiEx (
282 0,
283 gST->ConOut->Mode->CursorRow,
284 NULL,
285 STRING_TOKEN (STR_LS_HEADER_LINE1),
286 gShellLevel2HiiHandle,
287 DirectoryName
288 );
289
290 SHELL_FREE_NON_NULL(DirectoryName);
291 }
292 }
293
294 /**
295 print out the footer when not using standard format output.
296
297 @param[in] Files The number of files.
298 @param[in] Size The size of files in bytes.
299 @param[in] Dirs The number of directories.
300 **/
301 VOID
302 PrintNonSfoFooter(
303 IN UINT64 Files,
304 IN UINT64 Size,
305 IN UINT64 Dirs
306 )
307 {
308 //
309 // print footer
310 //
311 ShellPrintHiiEx (
312 -1,
313 -1,
314 NULL,
315 STRING_TOKEN (STR_LS_FOOTER_LINE),
316 gShellLevel2HiiHandle,
317 Files,
318 Size,
319 Dirs
320 );
321 }
322
323 /**
324 Change the file time to local time based on the timezone.
325
326 @param[in] Time The file time.
327 @param[in] LocalTimeZone Local time zone.
328 **/
329 VOID
330 FileTimeToLocalTime (
331 IN EFI_TIME *Time,
332 IN INT16 LocalTimeZone
333 )
334 {
335 INTN MinuteDiff;
336 INTN TempMinute;
337 INTN HourNumberOfTempMinute;
338 INTN TempHour;
339 INTN DayNumberOfTempHour;
340 INTN TempDay;
341 INTN MonthNumberOfTempDay;
342 INTN TempMonth;
343 INTN YearNumberOfTempMonth;
344 INTN MonthRecord;
345
346 ASSERT ((Time->TimeZone >= -1440) && (Time->TimeZone <=1440));
347 ASSERT ((LocalTimeZone >= -1440) && (LocalTimeZone <=1440));
348 ASSERT ((Time->Month >= 1) && (Time->Month <= 12));
349
350 if(Time->TimeZone == LocalTimeZone) {
351 //
352 //if the file timezone is equal to the local timezone, there is no need to adjust the file time.
353 //
354 return;
355 }
356
357 if((Time->Year % 4 == 0 && Time->Year / 100 != 0)||(Time->Year % 400 == 0)) {
358 //
359 // Day in February of leap year is 29.
360 //
361 mDayOfMonth[1] = 29;
362 }
363
364 MinuteDiff = Time->TimeZone - LocalTimeZone;
365 TempMinute = Time->Minute + MinuteDiff;
366
367 //
368 // Calculate Time->Minute
369 // TempHour will be used to calculate Time->Hour
370 //
371 HourNumberOfTempMinute = TempMinute / 60;
372 if(TempMinute < 0) {
373 HourNumberOfTempMinute --;
374 }
375 TempHour = Time->Hour + HourNumberOfTempMinute;
376 Time->Minute = (UINT8)(TempMinute - 60 * HourNumberOfTempMinute);
377
378 //
379 // Calculate Time->Hour
380 // TempDay will be used to calculate Time->Day
381 //
382 DayNumberOfTempHour = TempHour / 24 ;
383 if(TempHour < 0){
384 DayNumberOfTempHour--;
385 }
386 TempDay = Time->Day + DayNumberOfTempHour;
387 Time->Hour = (UINT8)(TempHour - 24 * DayNumberOfTempHour);
388
389 //
390 // Calculate Time->Day
391 // TempMonth will be used to calculate Time->Month
392 //
393 MonthNumberOfTempDay = (TempDay - 1) / (INTN)mDayOfMonth[Time->Month - 1];
394 MonthRecord = (INTN)(Time->Month) ;
395 if(TempDay - 1 < 0){
396 MonthNumberOfTempDay -- ;
397 MonthRecord -- ;
398 }
399 TempMonth = Time->Month + MonthNumberOfTempDay;
400 Time->Day = (UINT8)(TempDay - (INTN)mDayOfMonth[(MonthRecord - 1 + 12) % 12] * MonthNumberOfTempDay);
401
402 //
403 // Calculate Time->Month, Time->Year
404 //
405 YearNumberOfTempMonth = (TempMonth - 1) / 12;
406 if(TempMonth - 1 < 0){
407 YearNumberOfTempMonth --;
408 }
409 Time->Month = (UINT8)(TempMonth - 12 * (YearNumberOfTempMonth));
410 Time->Year = (UINT16)(Time->Year + YearNumberOfTempMonth);
411 }
412
413 /**
414 print out the list of files and directories from the LS command
415
416 @param[in] Rec TRUE to automatically recurse into each found directory
417 FALSE to only list the specified directory.
418 @param[in] Attribs List of required Attribute for display.
419 If 0 then all non-system and non-hidden files will be printed.
420 @param[in] Sfo TRUE to use Standard Format Output, FALSE otherwise
421 @param[in] RootPath String with starting path to search in.
422 @param[in] SearchString String with search string.
423 @param[in] Found Set to TRUE, if anyone were found.
424 @param[in] Count The count of bits enabled in Attribs.
425 @param[in] TimeZone The current time zone offset.
426
427 @retval SHELL_SUCCESS the printing was sucessful.
428 **/
429 SHELL_STATUS
430 PrintLsOutput(
431 IN CONST BOOLEAN Rec,
432 IN CONST UINT64 Attribs,
433 IN CONST BOOLEAN Sfo,
434 IN CONST CHAR16 *RootPath,
435 IN CONST CHAR16 *SearchString,
436 IN BOOLEAN *Found,
437 IN CONST UINTN Count,
438 IN CONST INT16 TimeZone
439 )
440 {
441 EFI_STATUS Status;
442 EFI_SHELL_FILE_INFO *ListHead;
443 EFI_SHELL_FILE_INFO *Node;
444 SHELL_STATUS ShellStatus;
445 UINT64 FileCount;
446 UINT64 DirCount;
447 UINT64 FileSize;
448 UINTN LongestPath;
449 CHAR16 *CorrectedPath;
450 BOOLEAN FoundOne;
451 BOOLEAN HeaderPrinted;
452 EFI_TIME LocalTime;
453
454 HeaderPrinted = FALSE;
455 FileCount = 0;
456 DirCount = 0;
457 FileSize = 0;
458 ListHead = NULL;
459 ShellStatus = SHELL_SUCCESS;
460 LongestPath = 0;
461 CorrectedPath = NULL;
462
463 if (Found != NULL) {
464 FoundOne = *Found;
465 } else {
466 FoundOne = FALSE;
467 }
468
469 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0);
470 if (CorrectedPath == NULL) {
471 return SHELL_OUT_OF_RESOURCES;
472 }
473 if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\'
474 &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') {
475 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\", 0);
476 }
477 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, SearchString, 0);
478 if (CorrectedPath == NULL) {
479 return (SHELL_OUT_OF_RESOURCES);
480 }
481
482 PathCleanUpDirectories(CorrectedPath);
483
484 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
485 if (!EFI_ERROR(Status)) {
486 if (ListHead == NULL || IsListEmpty(&ListHead->Link)) {
487 SHELL_FREE_NON_NULL(CorrectedPath);
488 return (SHELL_SUCCESS);
489 }
490
491 if (Sfo && Found == NULL) {
492 PrintSfoVolumeInfoTableEntry(ListHead);
493 }
494
495 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link), LongestPath = 0
496 ; !IsNull(&ListHead->Link, &Node->Link)
497 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
498 ){
499 if (ShellGetExecutionBreakFlag ()) {
500 ShellStatus = SHELL_ABORTED;
501 break;
502 }
503 ASSERT(Node != NULL);
504
505 //
506 // Change the file time to local time.
507 //
508 Status = gRT->GetTime(&LocalTime, NULL);
509 if (!EFI_ERROR (Status)) {
510 if ((Node->Info->CreateTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) &&
511 (Node->Info->CreateTime.Month >= 1 && Node->Info->CreateTime.Month <= 12)) {
512 //
513 // FileTimeToLocalTime () requires Month is in a valid range, other buffer out-of-band access happens.
514 //
515 FileTimeToLocalTime (&Node->Info->CreateTime, LocalTime.TimeZone);
516 }
517 if ((Node->Info->LastAccessTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) &&
518 (Node->Info->LastAccessTime.Month >= 1 && Node->Info->LastAccessTime.Month <= 12)) {
519 FileTimeToLocalTime (&Node->Info->LastAccessTime, LocalTime.TimeZone);
520 }
521 if ((Node->Info->ModificationTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) &&
522 (Node->Info->ModificationTime.Month >= 1 && Node->Info->ModificationTime.Month <= 12)) {
523 FileTimeToLocalTime (&Node->Info->ModificationTime, LocalTime.TimeZone);
524 }
525 }
526
527 if (LongestPath < StrSize(Node->FullName)) {
528 LongestPath = StrSize(Node->FullName);
529 }
530 ASSERT(Node->Info != NULL);
531 ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute);
532 if (Attribs == 0) {
533 //
534 // NOT system & NOT hidden
535 //
536 if ( (Node->Info->Attribute & EFI_FILE_SYSTEM)
537 || (Node->Info->Attribute & EFI_FILE_HIDDEN)
538 ){
539 continue;
540 }
541 } else if ((Attribs != EFI_FILE_VALID_ATTR) ||
542 (Count == 5)) {
543 //
544 // Only matches the bits which "Attribs" contains, not
545 // all files/directories with any of the bits.
546 // Count == 5 is used to tell the difference between a user
547 // specifying all bits (EX: -arhsda) and just specifying
548 // -a (means display all files with any attribute).
549 //
550 if ( (Node->Info->Attribute & Attribs) != Attribs) {
551 continue;
552 }
553 }
554
555 if (!Sfo && !HeaderPrinted) {
556 PathRemoveLastItem (CorrectedPath);
557 PrintNonSfoHeader(CorrectedPath);
558 }
559 PrintFileInformation(Sfo, Node, &FileCount, &FileSize, &DirCount);
560 FoundOne = TRUE;
561 HeaderPrinted = TRUE;
562 }
563
564 if (!Sfo && ShellStatus != SHELL_ABORTED) {
565 PrintNonSfoFooter(FileCount, FileSize, DirCount);
566 }
567 }
568
569 if (Rec && ShellStatus != SHELL_ABORTED) {
570 //
571 // Re-Open all the files under the starting path for directories that didnt necessarily match our file filter
572 //
573 ShellCloseFileMetaArg(&ListHead);
574 CorrectedPath[0] = CHAR_NULL;
575 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0);
576 if (CorrectedPath == NULL) {
577 return SHELL_OUT_OF_RESOURCES;
578 }
579 if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\'
580 &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') {
581 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\", 0);
582 }
583 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"*", 0);
584 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
585
586 if (!EFI_ERROR(Status)) {
587 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
588 ; !IsNull(&ListHead->Link, &Node->Link) && ShellStatus == SHELL_SUCCESS
589 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
590 ){
591 if (ShellGetExecutionBreakFlag ()) {
592 ShellStatus = SHELL_ABORTED;
593 break;
594 }
595
596 //
597 // recurse on any directory except the traversing ones...
598 //
599 if (((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY)
600 && StrCmp(Node->FileName, L".") != 0
601 && StrCmp(Node->FileName, L"..") != 0
602 ){
603 ShellStatus = PrintLsOutput(
604 Rec,
605 Attribs,
606 Sfo,
607 Node->FullName,
608 SearchString,
609 &FoundOne,
610 Count,
611 TimeZone);
612
613 //
614 // Since it's running recursively, we have to break immediately when returned SHELL_ABORTED
615 //
616 if (ShellStatus == SHELL_ABORTED) {
617 break;
618 }
619 }
620 }
621 }
622 }
623
624 SHELL_FREE_NON_NULL(CorrectedPath);
625 ShellCloseFileMetaArg(&ListHead);
626
627 if (Found == NULL && !FoundOne) {
628 return (SHELL_NOT_FOUND);
629 }
630
631 if (Found != NULL) {
632 *Found = FoundOne;
633 }
634
635 return (ShellStatus);
636 }
637
638 STATIC CONST SHELL_PARAM_ITEM LsParamList[] = {
639 {L"-r", TypeFlag},
640 {L"-a", TypeStart},
641 {L"-sfo", TypeFlag},
642 {NULL, TypeMax}
643 };
644
645 /**
646 Function for 'ls' command.
647
648 @param[in] ImageHandle Handle to the Image (NULL if Internal).
649 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
650 **/
651 SHELL_STATUS
652 EFIAPI
653 ShellCommandRunLs (
654 IN EFI_HANDLE ImageHandle,
655 IN EFI_SYSTEM_TABLE *SystemTable
656 )
657 {
658 EFI_STATUS Status;
659 LIST_ENTRY *Package;
660 CHAR16 *ProblemParam;
661 CONST CHAR16 *Attribs;
662 SHELL_STATUS ShellStatus;
663 UINT64 RequiredAttributes;
664 CONST CHAR16 *PathName;
665 CONST CHAR16 *CurDir;
666 UINTN Count;
667 CHAR16 *FullPath;
668 UINTN Size;
669 EFI_TIME TheTime;
670 CHAR16 *SearchString;
671
672 Size = 0;
673 FullPath = NULL;
674 ProblemParam = NULL;
675 Attribs = NULL;
676 ShellStatus = SHELL_SUCCESS;
677 RequiredAttributes = 0;
678 PathName = NULL;
679 SearchString = NULL;
680 CurDir = NULL;
681 Count = 0;
682
683 //
684 // initialize the shell lib (we must be in non-auto-init...)
685 //
686 Status = ShellInitialize();
687 ASSERT_EFI_ERROR(Status);
688
689 //
690 // Fix local copies of the protocol pointers
691 //
692 Status = CommandInit();
693 ASSERT_EFI_ERROR(Status);
694
695 //
696 // parse the command line
697 //
698 Status = ShellCommandLineParse (LsParamList, &Package, &ProblemParam, TRUE);
699 if (EFI_ERROR(Status)) {
700 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
701 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"ls", ProblemParam);
702 FreePool(ProblemParam);
703 ShellStatus = SHELL_INVALID_PARAMETER;
704 } else {
705 ASSERT(FALSE);
706 }
707 } else {
708 //
709 // check for "-?"
710 //
711 if (ShellCommandLineGetFlag(Package, L"-?")) {
712 ASSERT(FALSE);
713 }
714
715 if (ShellCommandLineGetCount(Package) > 2) {
716 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"ls");
717 ShellStatus = SHELL_INVALID_PARAMETER;
718 } else {
719 //
720 // check for -a
721 //
722 if (ShellCommandLineGetFlag(Package, L"-a")) {
723 for ( Attribs = ShellCommandLineGetValue(Package, L"-a")
724 ; Attribs != NULL && *Attribs != CHAR_NULL && ShellStatus == SHELL_SUCCESS
725 ; Attribs++
726 ){
727 switch (*Attribs) {
728 case L'a':
729 case L'A':
730 RequiredAttributes |= EFI_FILE_ARCHIVE;
731 Count++;
732 continue;
733 case L's':
734 case L'S':
735 RequiredAttributes |= EFI_FILE_SYSTEM;
736 Count++;
737 continue;
738 case L'h':
739 case L'H':
740 RequiredAttributes |= EFI_FILE_HIDDEN;
741 Count++;
742 continue;
743 case L'r':
744 case L'R':
745 RequiredAttributes |= EFI_FILE_READ_ONLY;
746 Count++;
747 continue;
748 case L'd':
749 case L'D':
750 RequiredAttributes |= EFI_FILE_DIRECTORY;
751 Count++;
752 continue;
753 default:
754 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ATTRIBUTE), gShellLevel2HiiHandle, L"ls", ShellCommandLineGetValue(Package, L"-a"));
755 ShellStatus = SHELL_INVALID_PARAMETER;
756 break;
757 } // switch
758 } // for loop
759 //
760 // if nothing is specified all are specified
761 //
762 if (RequiredAttributes == 0) {
763 RequiredAttributes = EFI_FILE_VALID_ATTR;
764 }
765 } // if -a present
766 if (ShellStatus == SHELL_SUCCESS) {
767 PathName = ShellCommandLineGetRawValue(Package, 1);
768 if (PathName == NULL) {
769 //
770 // Nothing specified... must start from current directory
771 //
772 CurDir = gEfiShellProtocol->GetCurDir(NULL);
773 if (CurDir == NULL) {
774 ShellStatus = SHELL_NOT_FOUND;
775 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls");
776 }
777 //
778 // Copy to the 2 strings for starting path and file search string
779 //
780 ASSERT(SearchString == NULL);
781 ASSERT(FullPath == NULL);
782 StrnCatGrow(&SearchString, NULL, L"*", 0);
783 StrnCatGrow(&FullPath, NULL, CurDir, 0);
784 Size = FullPath != NULL? StrSize(FullPath) : 0;
785 StrnCatGrow(&FullPath, &Size, L"\\", 0);
786 } else {
787 if (StrStr(PathName, L":") == NULL && gEfiShellProtocol->GetCurDir(NULL) == NULL) {
788 //
789 // If we got something and it doesnt have a fully qualified path, then we needed to have a CWD.
790 //
791 ShellStatus = SHELL_NOT_FOUND;
792 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls");
793 } else {
794 //
795 // We got a valid fully qualified path or we have a CWD
796 //
797 ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL));
798 if (StrStr(PathName, L":") == NULL) {
799 StrnCatGrow(&FullPath, &Size, gEfiShellProtocol->GetCurDir(NULL), 0);
800 if (FullPath == NULL) {
801 ShellCommandLineFreeVarList (Package);
802 return SHELL_OUT_OF_RESOURCES;
803 }
804 Size = FullPath != NULL? StrSize(FullPath) : 0;
805 StrnCatGrow(&FullPath, &Size, L"\\", 0);
806 }
807 StrnCatGrow(&FullPath, &Size, PathName, 0);
808 if (FullPath == NULL) {
809 ShellCommandLineFreeVarList (Package);
810 return SHELL_OUT_OF_RESOURCES;
811 }
812
813 if (ShellIsDirectory(PathName) == EFI_SUCCESS) {
814 //
815 // is listing ends with a directory, then we list all files in that directory
816 //
817 StrnCatGrow(&SearchString, NULL, L"*", 0);
818 } else {
819 //
820 // must split off the search part that applies to files from the end of the directory part
821 //
822 StrnCatGrow(&SearchString, NULL, FullPath, 0);
823 if (SearchString == NULL) {
824 FreePool (FullPath);
825 ShellCommandLineFreeVarList (Package);
826 return SHELL_OUT_OF_RESOURCES;
827 }
828 PathRemoveLastItem (FullPath);
829 CopyMem (SearchString, SearchString + StrLen (FullPath), StrSize (SearchString + StrLen (FullPath)));
830 }
831 }
832 }
833 Status = gRT->GetTime(&TheTime, NULL);
834 if (EFI_ERROR(Status)) {
835 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"ls", L"gRT->GetTime", Status);
836 TheTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
837 }
838
839 if (ShellStatus == SHELL_SUCCESS) {
840 ShellStatus = PrintLsOutput(
841 ShellCommandLineGetFlag(Package, L"-r"),
842 RequiredAttributes,
843 ShellCommandLineGetFlag(Package, L"-sfo"),
844 FullPath,
845 SearchString,
846 NULL,
847 Count,
848 TheTime.TimeZone
849 );
850 if (ShellStatus == SHELL_NOT_FOUND) {
851 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LS_FILE_NOT_FOUND), gShellLevel2HiiHandle, L"ls", FullPath);
852 } else if (ShellStatus == SHELL_INVALID_PARAMETER) {
853 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"ls", FullPath);
854 } else if (ShellStatus == SHELL_ABORTED) {
855 //
856 // Ignore aborting.
857 //
858 } else if (ShellStatus != SHELL_SUCCESS) {
859 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"ls", FullPath);
860 }
861 }
862 }
863 }
864 }
865
866 //
867 // Free memory allocated
868 //
869 SHELL_FREE_NON_NULL(SearchString);
870 SHELL_FREE_NON_NULL(FullPath);
871 ShellCommandLineFreeVarList (Package);
872
873 return (ShellStatus);
874 }