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