2 Main file for ls shell level 2 function.
4 (C) Copyright 2013-2015 Hewlett-Packard Development Company, L.P.<BR>
5 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
10 #include "UefiShellLevel2CommandsLib.h"
11 #include <Guid/FileSystemInfo.h>
13 UINTN mDayOfMonth
[] = {31, 28, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30};
16 print out the standard format output volume entry.
18 @param[in] TheList a list of files from the volume.
21 PrintSfoVolumeInfoTableEntry(
22 IN CONST EFI_SHELL_FILE_INFO
*TheList
26 EFI_SHELL_FILE_INFO
*Node
;
27 CHAR16
*DirectoryName
;
28 EFI_FILE_SYSTEM_INFO
*SysInfo
;
30 SHELL_FILE_HANDLE ShellFileHandle
;
31 EFI_FILE_PROTOCOL
*EfiFpHandle
;
34 // Get the first valid handle (directories)
36 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&TheList
->Link
)
37 ; !IsNull(&TheList
->Link
, &Node
->Link
) && Node
->Handle
== NULL
38 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&TheList
->Link
, &Node
->Link
)
41 if (Node
->Handle
== NULL
) {
42 DirectoryName
= GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO
*)GetFirstNode(&TheList
->Link
))->FullName
);
45 // We need to open something up to get system information
47 Status
= gEfiShellProtocol
->OpenFileByName(
53 ASSERT_EFI_ERROR(Status
);
54 FreePool(DirectoryName
);
57 // Get the Volume Info from ShellFileHandle
61 EfiFpHandle
= ConvertShellHandleToEfiFileProtocol(ShellFileHandle
);
62 Status
= EfiFpHandle
->GetInfo(
64 &gEfiFileSystemInfoGuid
,
69 if (Status
== EFI_BUFFER_TOO_SMALL
) {
70 SysInfo
= AllocateZeroPool(SysInfoSize
);
71 Status
= EfiFpHandle
->GetInfo(
73 &gEfiFileSystemInfoGuid
,
79 ASSERT_EFI_ERROR(Status
);
81 gEfiShellProtocol
->CloseFile(ShellFileHandle
);
84 // Get the Volume Info from Node->Handle
88 EfiFpHandle
= ConvertShellHandleToEfiFileProtocol(Node
->Handle
);
89 Status
= EfiFpHandle
->GetInfo(
91 &gEfiFileSystemInfoGuid
,
96 if (Status
== EFI_BUFFER_TOO_SMALL
) {
97 SysInfo
= AllocateZeroPool(SysInfoSize
);
98 Status
= EfiFpHandle
->GetInfo(
100 &gEfiFileSystemInfoGuid
,
106 ASSERT_EFI_ERROR(Status
);
113 STRING_TOKEN (STR_GEN_SFO_HEADER
),
114 gShellLevel2HiiHandle
,
118 // print VolumeInfo table
120 ASSERT(SysInfo
!= NULL
);
123 gST
->ConOut
->Mode
->CursorRow
,
125 STRING_TOKEN (STR_LS_SFO_VOLINFO
),
126 gShellLevel2HiiHandle
,
127 SysInfo
->VolumeLabel
,
129 SysInfo
->ReadOnly
?L
"TRUE":L
"FALSE",
134 SHELL_FREE_NON_NULL(SysInfo
);
140 print out the info on a single file.
142 @param[in] Sfo TRUE if in SFO, false otherwise.
143 @param[in] TheNode the EFI_SHELL_FILE_INFO node to print out information on.
144 @param[in] Files incremented if a file is printed.
145 @param[in] Size incremented by file size.
146 @param[in] Dirs incremented if a directory is printed.
150 PrintFileInformation(
151 IN CONST BOOLEAN Sfo
,
152 IN CONST EFI_SHELL_FILE_INFO
*TheNode
,
158 ASSERT(Files
!= NULL
);
159 ASSERT(Size
!= NULL
);
160 ASSERT(Dirs
!= NULL
);
161 ASSERT(TheNode
!= NULL
);
165 // Print the FileInfo Table
169 gST
->ConOut
->Mode
->CursorRow
,
171 STRING_TOKEN (STR_LS_SFO_FILEINFO
),
172 gShellLevel2HiiHandle
,
174 TheNode
->Info
->FileSize
,
175 TheNode
->Info
->PhysicalSize
,
176 (TheNode
->Info
->Attribute
& EFI_FILE_ARCHIVE
) != 0?L
"a":L
"",
177 (TheNode
->Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0?L
"d":L
"",
178 (TheNode
->Info
->Attribute
& EFI_FILE_HIDDEN
) != 0?L
"h":L
"",
179 (TheNode
->Info
->Attribute
& EFI_FILE_READ_ONLY
) != 0?L
"r":L
"",
180 (TheNode
->Info
->Attribute
& EFI_FILE_SYSTEM
) != 0?L
"s":L
"",
181 TheNode
->Info
->CreateTime
.Hour
,
182 TheNode
->Info
->CreateTime
.Minute
,
183 TheNode
->Info
->CreateTime
.Second
,
184 TheNode
->Info
->CreateTime
.Day
,
185 TheNode
->Info
->CreateTime
.Month
,
186 TheNode
->Info
->CreateTime
.Year
,
187 TheNode
->Info
->LastAccessTime
.Hour
,
188 TheNode
->Info
->LastAccessTime
.Minute
,
189 TheNode
->Info
->LastAccessTime
.Second
,
190 TheNode
->Info
->LastAccessTime
.Day
,
191 TheNode
->Info
->LastAccessTime
.Month
,
192 TheNode
->Info
->LastAccessTime
.Year
,
193 TheNode
->Info
->ModificationTime
.Hour
,
194 TheNode
->Info
->ModificationTime
.Minute
,
195 TheNode
->Info
->ModificationTime
.Second
,
196 TheNode
->Info
->ModificationTime
.Day
,
197 TheNode
->Info
->ModificationTime
.Month
,
198 TheNode
->Info
->ModificationTime
.Year
202 // print this one out...
203 // first print the universal start, next print the type specific name format, last print the CRLF
209 STRING_TOKEN (STR_LS_LINE_START_ALL
),
210 gShellLevel2HiiHandle
,
211 &TheNode
->Info
->ModificationTime
,
212 (TheNode
->Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0?L
"<DIR>":L
"",
213 (TheNode
->Info
->Attribute
& EFI_FILE_READ_ONLY
) != 0?L
'r':L
' ',
214 TheNode
->Info
->FileSize
216 if (TheNode
->Info
->Attribute
& EFI_FILE_DIRECTORY
) {
222 STRING_TOKEN (STR_LS_LINE_END_DIR
),
223 gShellLevel2HiiHandle
,
228 (*Size
) += TheNode
->Info
->FileSize
;
229 if ( (gUnicodeCollation
->StriColl(gUnicodeCollation
, (CHAR16
*)L
".nsh", (CHAR16
*)&(TheNode
->FileName
[StrLen (TheNode
->FileName
) - 4])) == 0)
230 || (gUnicodeCollation
->StriColl(gUnicodeCollation
, (CHAR16
*)L
".efi", (CHAR16
*)&(TheNode
->FileName
[StrLen (TheNode
->FileName
) - 4])) == 0)
236 STRING_TOKEN (STR_LS_LINE_END_EXE
),
237 gShellLevel2HiiHandle
,
245 STRING_TOKEN (STR_LS_LINE_END_FILE
),
246 gShellLevel2HiiHandle
,
255 print out the header when not using standard format output.
257 @param[in] Path String with starting path.
261 IN CONST CHAR16
*Path
264 CHAR16
*DirectoryName
;
267 // get directory name from path...
269 DirectoryName
= GetFullyQualifiedPath(Path
);
271 if (DirectoryName
!= NULL
) {
277 gST
->ConOut
->Mode
->CursorRow
,
279 STRING_TOKEN (STR_LS_HEADER_LINE1
),
280 gShellLevel2HiiHandle
,
284 SHELL_FREE_NON_NULL(DirectoryName
);
289 print out the footer when not using standard format output.
291 @param[in] Files The number of files.
292 @param[in] Size The size of files in bytes.
293 @param[in] Dirs The number of directories.
309 STRING_TOKEN (STR_LS_FOOTER_LINE
),
310 gShellLevel2HiiHandle
,
318 Change the file time to local time based on the timezone.
320 @param[in] Time The file time.
321 @param[in] LocalTimeZone Local time zone.
324 FileTimeToLocalTime (
326 IN INT16 LocalTimeZone
331 INTN HourNumberOfTempMinute
;
333 INTN DayNumberOfTempHour
;
335 INTN MonthNumberOfTempDay
;
337 INTN YearNumberOfTempMonth
;
340 ASSERT ((Time
->TimeZone
>= -1440) && (Time
->TimeZone
<=1440));
341 ASSERT ((LocalTimeZone
>= -1440) && (LocalTimeZone
<=1440));
342 ASSERT ((Time
->Month
>= 1) && (Time
->Month
<= 12));
344 if(Time
->TimeZone
== LocalTimeZone
) {
346 //if the file timezone is equal to the local timezone, there is no need to adjust the file time.
351 if((Time
->Year
% 4 == 0 && Time
->Year
/ 100 != 0)||(Time
->Year
% 400 == 0)) {
353 // Day in February of leap year is 29.
358 MinuteDiff
= Time
->TimeZone
- LocalTimeZone
;
359 TempMinute
= Time
->Minute
+ MinuteDiff
;
362 // Calculate Time->Minute
363 // TempHour will be used to calculate Time->Hour
365 HourNumberOfTempMinute
= TempMinute
/ 60;
367 HourNumberOfTempMinute
--;
369 TempHour
= Time
->Hour
+ HourNumberOfTempMinute
;
370 Time
->Minute
= (UINT8
)(TempMinute
- 60 * HourNumberOfTempMinute
);
373 // Calculate Time->Hour
374 // TempDay will be used to calculate Time->Day
376 DayNumberOfTempHour
= TempHour
/ 24 ;
378 DayNumberOfTempHour
--;
380 TempDay
= Time
->Day
+ DayNumberOfTempHour
;
381 Time
->Hour
= (UINT8
)(TempHour
- 24 * DayNumberOfTempHour
);
384 // Calculate Time->Day
385 // TempMonth will be used to calculate Time->Month
387 MonthNumberOfTempDay
= (TempDay
- 1) / (INTN
)mDayOfMonth
[Time
->Month
- 1];
388 MonthRecord
= (INTN
)(Time
->Month
) ;
390 MonthNumberOfTempDay
-- ;
393 TempMonth
= Time
->Month
+ MonthNumberOfTempDay
;
394 Time
->Day
= (UINT8
)(TempDay
- (INTN
)mDayOfMonth
[(MonthRecord
- 1 + 12) % 12] * MonthNumberOfTempDay
);
397 // Calculate Time->Month, Time->Year
399 YearNumberOfTempMonth
= (TempMonth
- 1) / 12;
400 if(TempMonth
- 1 < 0){
401 YearNumberOfTempMonth
--;
403 Time
->Month
= (UINT8
)(TempMonth
- 12 * (YearNumberOfTempMonth
));
404 Time
->Year
= (UINT16
)(Time
->Year
+ YearNumberOfTempMonth
);
408 print out the list of files and directories from the LS command
410 @param[in] Rec TRUE to automatically recurse into each found directory
411 FALSE to only list the specified directory.
412 @param[in] Attribs List of required Attribute for display.
413 If 0 then all non-system and non-hidden files will be printed.
414 @param[in] Sfo TRUE to use Standard Format Output, FALSE otherwise
415 @param[in] RootPath String with starting path to search in.
416 @param[in] SearchString String with search string.
417 @param[in] Found Set to TRUE, if anyone were found.
418 @param[in] Count The count of bits enabled in Attribs.
419 @param[in] TimeZone The current time zone offset.
420 @param[in] ListUnfiltered TRUE to request listing the directory contents
423 @retval SHELL_SUCCESS the printing was sucessful.
427 IN CONST BOOLEAN Rec
,
428 IN CONST UINT64 Attribs
,
429 IN CONST BOOLEAN Sfo
,
430 IN CONST CHAR16
*RootPath
,
431 IN CONST CHAR16
*SearchString
,
433 IN CONST UINTN Count
,
434 IN CONST INT16 TimeZone
,
435 IN CONST BOOLEAN ListUnfiltered
439 EFI_SHELL_FILE_INFO
*ListHead
;
440 EFI_SHELL_FILE_INFO
*Node
;
441 SHELL_STATUS ShellStatus
;
446 CHAR16
*CorrectedPath
;
448 BOOLEAN HeaderPrinted
;
451 HeaderPrinted
= FALSE
;
456 ShellStatus
= SHELL_SUCCESS
;
458 CorrectedPath
= NULL
;
466 CorrectedPath
= StrnCatGrow(&CorrectedPath
, &LongestPath
, RootPath
, 0);
467 if (CorrectedPath
== NULL
) {
468 return SHELL_OUT_OF_RESOURCES
;
470 if (CorrectedPath
[StrLen(CorrectedPath
)-1] != L
'\\'
471 &&CorrectedPath
[StrLen(CorrectedPath
)-1] != L
'/') {
472 CorrectedPath
= StrnCatGrow(&CorrectedPath
, &LongestPath
, L
"\\", 0);
474 CorrectedPath
= StrnCatGrow(&CorrectedPath
, &LongestPath
, SearchString
, 0);
475 if (CorrectedPath
== NULL
) {
476 return (SHELL_OUT_OF_RESOURCES
);
479 PathCleanUpDirectories(CorrectedPath
);
481 Status
= ShellOpenFileMetaArg((CHAR16
*)CorrectedPath
, EFI_FILE_MODE_READ
, &ListHead
);
482 if (!EFI_ERROR(Status
)) {
483 if (ListHead
== NULL
|| IsListEmpty(&ListHead
->Link
)) {
484 SHELL_FREE_NON_NULL(CorrectedPath
);
485 return (SHELL_SUCCESS
);
488 if (Sfo
&& Found
== NULL
) {
489 PrintSfoVolumeInfoTableEntry(ListHead
);
492 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
), LongestPath
= 0
493 ; !IsNull(&ListHead
->Link
, &Node
->Link
)
494 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ListHead
->Link
, &Node
->Link
)
496 if (ShellGetExecutionBreakFlag ()) {
497 ShellStatus
= SHELL_ABORTED
;
500 ASSERT(Node
!= NULL
);
503 // Change the file time to local time.
505 Status
= gRT
->GetTime(&LocalTime
, NULL
);
506 if (!EFI_ERROR (Status
) && (LocalTime
.TimeZone
!= EFI_UNSPECIFIED_TIMEZONE
)) {
507 if ((Node
->Info
->CreateTime
.TimeZone
!= EFI_UNSPECIFIED_TIMEZONE
) &&
508 (Node
->Info
->CreateTime
.Month
>= 1 && Node
->Info
->CreateTime
.Month
<= 12)) {
510 // FileTimeToLocalTime () requires Month is in a valid range, other buffer out-of-band access happens.
512 FileTimeToLocalTime (&Node
->Info
->CreateTime
, LocalTime
.TimeZone
);
514 if ((Node
->Info
->LastAccessTime
.TimeZone
!= EFI_UNSPECIFIED_TIMEZONE
) &&
515 (Node
->Info
->LastAccessTime
.Month
>= 1 && Node
->Info
->LastAccessTime
.Month
<= 12)) {
516 FileTimeToLocalTime (&Node
->Info
->LastAccessTime
, LocalTime
.TimeZone
);
518 if ((Node
->Info
->ModificationTime
.TimeZone
!= EFI_UNSPECIFIED_TIMEZONE
) &&
519 (Node
->Info
->ModificationTime
.Month
>= 1 && Node
->Info
->ModificationTime
.Month
<= 12)) {
520 FileTimeToLocalTime (&Node
->Info
->ModificationTime
, LocalTime
.TimeZone
);
524 if (LongestPath
< StrSize(Node
->FullName
)) {
525 LongestPath
= StrSize(Node
->FullName
);
527 ASSERT(Node
->Info
!= NULL
);
528 ASSERT((Node
->Info
->Attribute
& EFI_FILE_VALID_ATTR
) == Node
->Info
->Attribute
);
531 // NOT system & NOT hidden
533 if ( (Node
->Info
->Attribute
& EFI_FILE_SYSTEM
)
534 || (Node
->Info
->Attribute
& EFI_FILE_HIDDEN
)
538 } else if ((Attribs
!= EFI_FILE_VALID_ATTR
) ||
541 // Only matches the bits which "Attribs" contains, not
542 // all files/directories with any of the bits.
543 // Count == 5 is used to tell the difference between a user
544 // specifying all bits (EX: -arhsda) and just specifying
545 // -a (means display all files with any attribute).
547 if ( (Node
->Info
->Attribute
& Attribs
) != Attribs
) {
552 if (!Sfo
&& !HeaderPrinted
) {
553 PathRemoveLastItem (CorrectedPath
);
554 PrintNonSfoHeader(CorrectedPath
);
556 PrintFileInformation(Sfo
, Node
, &FileCount
, &FileSize
, &DirCount
);
558 HeaderPrinted
= TRUE
;
561 if (!Sfo
&& ShellStatus
!= SHELL_ABORTED
&& HeaderPrinted
) {
562 PrintNonSfoFooter(FileCount
, FileSize
, DirCount
);
566 if (Rec
&& ShellStatus
!= SHELL_ABORTED
) {
568 // Re-Open all the files under the starting path for directories that didnt necessarily match our file filter
570 ShellCloseFileMetaArg(&ListHead
);
571 CorrectedPath
[0] = CHAR_NULL
;
572 CorrectedPath
= StrnCatGrow(&CorrectedPath
, &LongestPath
, RootPath
, 0);
573 if (CorrectedPath
== NULL
) {
574 return SHELL_OUT_OF_RESOURCES
;
576 if (CorrectedPath
[StrLen(CorrectedPath
)-1] != L
'\\'
577 &&CorrectedPath
[StrLen(CorrectedPath
)-1] != L
'/') {
578 CorrectedPath
= StrnCatGrow(&CorrectedPath
, &LongestPath
, L
"\\", 0);
580 CorrectedPath
= StrnCatGrow(&CorrectedPath
, &LongestPath
, L
"*", 0);
581 Status
= ShellOpenFileMetaArg((CHAR16
*)CorrectedPath
, EFI_FILE_MODE_READ
, &ListHead
);
583 if (!EFI_ERROR(Status
)) {
584 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
)
585 ; !IsNull(&ListHead
->Link
, &Node
->Link
) && ShellStatus
== SHELL_SUCCESS
586 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ListHead
->Link
, &Node
->Link
)
588 if (ShellGetExecutionBreakFlag ()) {
589 ShellStatus
= SHELL_ABORTED
;
594 // recurse on any directory except the traversing ones...
596 if (((Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
)
597 && StrCmp(Node
->FileName
, L
".") != 0
598 && StrCmp(Node
->FileName
, L
"..") != 0
600 ShellStatus
= PrintLsOutput(
612 // Since it's running recursively, we have to break immediately when returned SHELL_ABORTED
614 if (ShellStatus
== SHELL_ABORTED
) {
622 SHELL_FREE_NON_NULL(CorrectedPath
);
623 ShellCloseFileMetaArg(&ListHead
);
625 if (Found
== NULL
&& !FoundOne
) {
626 if (ListUnfiltered
) {
628 // When running "ls" without any filtering request, avoid outputing
629 // "File not found" when the directory is entirely empty, but print
630 // header and footer stating "0 File(s), 0 Dir(s)".
633 PrintNonSfoHeader (RootPath
);
634 if (ShellStatus
!= SHELL_ABORTED
) {
635 PrintNonSfoFooter (FileCount
, FileSize
, DirCount
);
639 return (SHELL_NOT_FOUND
);
647 return (ShellStatus
);
650 STATIC CONST SHELL_PARAM_ITEM LsParamList
[] = {
658 Function for 'ls' command.
660 @param[in] ImageHandle Handle to the Image (NULL if Internal).
661 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
666 IN EFI_HANDLE ImageHandle
,
667 IN EFI_SYSTEM_TABLE
*SystemTable
672 CHAR16
*ProblemParam
;
673 CONST CHAR16
*Attribs
;
674 SHELL_STATUS ShellStatus
;
675 UINT64 RequiredAttributes
;
676 CONST CHAR16
*PathName
;
677 CONST CHAR16
*CurDir
;
682 CHAR16
*SearchString
;
683 BOOLEAN ListUnfiltered
;
689 ShellStatus
= SHELL_SUCCESS
;
690 RequiredAttributes
= 0;
695 ListUnfiltered
= FALSE
;
698 // initialize the shell lib (we must be in non-auto-init...)
700 Status
= ShellInitialize();
701 ASSERT_EFI_ERROR(Status
);
704 // Fix local copies of the protocol pointers
706 Status
= CommandInit();
707 ASSERT_EFI_ERROR(Status
);
710 // parse the command line
712 Status
= ShellCommandLineParse (LsParamList
, &Package
, &ProblemParam
, TRUE
);
713 if (EFI_ERROR(Status
)) {
714 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
715 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, L
"ls", ProblemParam
);
716 FreePool(ProblemParam
);
717 ShellStatus
= SHELL_INVALID_PARAMETER
;
725 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
729 if (ShellCommandLineGetCount(Package
) > 2) {
730 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellLevel2HiiHandle
, L
"ls");
731 ShellStatus
= SHELL_INVALID_PARAMETER
;
736 if (ShellCommandLineGetFlag(Package
, L
"-a")) {
737 for ( Attribs
= ShellCommandLineGetValue(Package
, L
"-a")
738 ; Attribs
!= NULL
&& *Attribs
!= CHAR_NULL
&& ShellStatus
== SHELL_SUCCESS
744 RequiredAttributes
|= EFI_FILE_ARCHIVE
;
749 RequiredAttributes
|= EFI_FILE_SYSTEM
;
754 RequiredAttributes
|= EFI_FILE_HIDDEN
;
759 RequiredAttributes
|= EFI_FILE_READ_ONLY
;
764 RequiredAttributes
|= EFI_FILE_DIRECTORY
;
768 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ATTRIBUTE
), gShellLevel2HiiHandle
, L
"ls", ShellCommandLineGetValue(Package
, L
"-a"));
769 ShellStatus
= SHELL_INVALID_PARAMETER
;
774 // if nothing is specified all are specified
776 if (RequiredAttributes
== 0) {
777 RequiredAttributes
= EFI_FILE_VALID_ATTR
;
780 if (ShellStatus
== SHELL_SUCCESS
) {
781 PathName
= ShellCommandLineGetRawValue(Package
, 1);
782 if (PathName
== NULL
) {
784 // Nothing specified... must start from current directory
786 CurDir
= gEfiShellProtocol
->GetCurDir(NULL
);
787 if (CurDir
== NULL
) {
788 ShellStatus
= SHELL_NOT_FOUND
;
789 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
, L
"ls");
791 ListUnfiltered
= TRUE
;
793 // Copy to the 2 strings for starting path and file search string
795 ASSERT(SearchString
== NULL
);
796 ASSERT(FullPath
== NULL
);
797 StrnCatGrow(&SearchString
, NULL
, L
"*", 0);
798 StrnCatGrow(&FullPath
, NULL
, CurDir
, 0);
799 Size
= FullPath
!= NULL
? StrSize(FullPath
) : 0;
800 StrnCatGrow(&FullPath
, &Size
, L
"\\", 0);
802 if (StrStr(PathName
, L
":") == NULL
&& gEfiShellProtocol
->GetCurDir(NULL
) == NULL
) {
804 // If we got something and it doesnt have a fully qualified path, then we needed to have a CWD.
806 ShellStatus
= SHELL_NOT_FOUND
;
807 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
, L
"ls");
810 // We got a valid fully qualified path or we have a CWD
812 ASSERT((FullPath
== NULL
&& Size
== 0) || (FullPath
!= NULL
));
813 if (StrStr(PathName
, L
":") == NULL
) {
814 StrnCatGrow(&FullPath
, &Size
, gEfiShellProtocol
->GetCurDir(NULL
), 0);
815 if (FullPath
== NULL
) {
816 ShellCommandLineFreeVarList (Package
);
817 return SHELL_OUT_OF_RESOURCES
;
819 Size
= FullPath
!= NULL
? StrSize(FullPath
) : 0;
820 StrnCatGrow(&FullPath
, &Size
, L
"\\", 0);
822 StrnCatGrow(&FullPath
, &Size
, PathName
, 0);
823 if (FullPath
== NULL
) {
824 ShellCommandLineFreeVarList (Package
);
825 return SHELL_OUT_OF_RESOURCES
;
828 if (ShellIsDirectory(PathName
) == EFI_SUCCESS
) {
830 // is listing ends with a directory, then we list all files in that directory
832 ListUnfiltered
= TRUE
;
833 StrnCatGrow(&SearchString
, NULL
, L
"*", 0);
836 // must split off the search part that applies to files from the end of the directory part
838 StrnCatGrow(&SearchString
, NULL
, FullPath
, 0);
839 if (SearchString
== NULL
) {
841 ShellCommandLineFreeVarList (Package
);
842 return SHELL_OUT_OF_RESOURCES
;
844 PathRemoveLastItem (FullPath
);
845 CopyMem (SearchString
, SearchString
+ StrLen (FullPath
), StrSize (SearchString
+ StrLen (FullPath
)));
849 Status
= gRT
->GetTime(&TheTime
, NULL
);
850 if (EFI_ERROR(Status
)) {
851 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN
), gShellLevel2HiiHandle
, L
"ls", L
"gRT->GetTime", Status
);
852 TheTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
855 if (ShellStatus
== SHELL_SUCCESS
) {
856 ShellStatus
= PrintLsOutput(
857 ShellCommandLineGetFlag(Package
, L
"-r"),
859 ShellCommandLineGetFlag(Package
, L
"-sfo"),
867 if (ShellStatus
== SHELL_NOT_FOUND
) {
868 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_LS_FILE_NOT_FOUND
), gShellLevel2HiiHandle
, L
"ls", FullPath
);
869 } else if (ShellStatus
== SHELL_INVALID_PARAMETER
) {
870 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellLevel2HiiHandle
, L
"ls", FullPath
);
871 } else if (ShellStatus
== SHELL_ABORTED
) {
875 } else if (ShellStatus
!= SHELL_SUCCESS
) {
876 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellLevel2HiiHandle
, L
"ls", FullPath
);
884 // Free memory allocated
886 SHELL_FREE_NON_NULL(SearchString
);
887 SHELL_FREE_NON_NULL(FullPath
);
888 ShellCommandLineFreeVarList (Package
);
890 return (ShellStatus
);