Home | History | Annotate | Download | only in UefiShellLevel2CommandsLib
      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 - 2015, 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
     25 EFIAPI
     26 PrintSfoVolumeInfoTableEntry(
     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 **/
    154 VOID
    155 EFIAPI
    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 EFIAPI
    267 PrintNonSfoHeader(
    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 **/
    302 VOID
    303 EFIAPI
    304 PrintNonSfoFooter(
    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 **/
    341 SHELL_STATUS
    342 EFIAPI
    343 PrintLsOutput(
    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 
    526 STATIC 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 **/
    539 SHELL_STATUS
    540 EFIAPI
    541 ShellCommandRunLs (
    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, L"ls", 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, L"ls");
    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, L"ls", 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, L"ls");
    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           Size = FullPath != NULL? StrSize(FullPath) : 0;
    673           StrnCatGrow(&FullPath, &Size, L"\\", 0);
    674         } else {
    675           if (StrStr(PathName, L":") == NULL && gEfiShellProtocol->GetCurDir(NULL) == NULL) {
    676             //
    677             // If we got something and it doesnt have a fully qualified path, then we needed to have a CWD.
    678             //
    679             ShellStatus = SHELL_NOT_FOUND;
    680             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls");
    681           } else {
    682             //
    683             // We got a valid fully qualified path or we have a CWD
    684             //
    685             ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL));
    686             if (StrStr(PathName, L":") == NULL) {
    687               StrnCatGrow(&FullPath, &Size, gEfiShellProtocol->GetCurDir(NULL), 0);
    688               if (FullPath == NULL) {
    689                 ShellCommandLineFreeVarList (Package);
    690                 return SHELL_OUT_OF_RESOURCES;
    691               }
    692               Size = FullPath != NULL? StrSize(FullPath) : 0;
    693               StrnCatGrow(&FullPath, &Size, L"\\", 0);
    694             }
    695             StrnCatGrow(&FullPath, &Size, PathName, 0);
    696             if (FullPath == NULL) {
    697                 ShellCommandLineFreeVarList (Package);
    698                 return SHELL_OUT_OF_RESOURCES;
    699             }
    700 
    701             if  (ShellIsDirectory(PathName) == EFI_SUCCESS) {
    702               //
    703               // is listing ends with a directory, then we list all files in that directory
    704               //
    705               StrnCatGrow(&SearchString, NULL, L"*", 0);
    706             } else {
    707               //
    708               // must split off the search part that applies to files from the end of the directory part
    709               //
    710               for (StrnCatGrow(&SearchString, NULL, PathName, 0)
    711                 ; SearchString != NULL && StrStr(SearchString, L"\\") != NULL
    712                 ; CopyMem(SearchString, StrStr(SearchString, L"\\") + 1, 1 + StrSize(StrStr(SearchString, L"\\") + 1))) ;
    713               FullPath[StrLen(FullPath) - StrLen(SearchString)] = CHAR_NULL;
    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