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