2 Main file for ls shell level 2 function.
4 Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
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
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.
16 #include "UefiShellLevel2CommandsLib.h"
17 #include <Guid/FileSystemInfo.h>
20 print out the standard format output volume entry.
22 @param[in] TheList a list of files from the volume.
26 PrintSfoVolumeInfoTableEntry(
27 IN CONST EFI_SHELL_FILE_INFO
*TheList
31 EFI_SHELL_FILE_INFO
*Node
;
32 CHAR16
*DirectoryName
;
33 EFI_FILE_SYSTEM_INFO
*SysInfo
;
35 SHELL_FILE_HANDLE ShellFileHandle
;
36 EFI_FILE_PROTOCOL
*EfiFpHandle
;
39 // Get the first valid handle (directories)
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
)
46 if (Node
->Handle
== NULL
) {
47 DirectoryName
= GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO
*)GetFirstNode(&TheList
->Link
))->FullName
);
50 // We need to open something up to get system information
52 Status
= gEfiShellProtocol
->OpenFileByName(
58 ASSERT_EFI_ERROR(Status
);
59 FreePool(DirectoryName
);
62 // Get the Volume Info from ShellFileHandle
66 EfiFpHandle
= ConvertShellHandleToEfiFileProtocol(ShellFileHandle
);
67 Status
= EfiFpHandle
->GetInfo(
69 &gEfiFileSystemInfoGuid
,
74 if (Status
== EFI_BUFFER_TOO_SMALL
) {
75 SysInfo
= AllocateZeroPool(SysInfoSize
);
76 Status
= EfiFpHandle
->GetInfo(
78 &gEfiFileSystemInfoGuid
,
84 ASSERT_EFI_ERROR(Status
);
86 gEfiShellProtocol
->CloseFile(ShellFileHandle
);
89 // Get the Volume Info from Node->Handle
93 EfiFpHandle
= ConvertShellHandleToEfiFileProtocol(Node
->Handle
);
94 Status
= EfiFpHandle
->GetInfo(
96 &gEfiFileSystemInfoGuid
,
101 if (Status
== EFI_BUFFER_TOO_SMALL
) {
102 SysInfo
= AllocateZeroPool(SysInfoSize
);
103 Status
= EfiFpHandle
->GetInfo(
105 &gEfiFileSystemInfoGuid
,
111 ASSERT_EFI_ERROR(Status
);
118 STRING_TOKEN (STR_GEN_SFO_HEADER
),
119 gShellLevel2HiiHandle
,
123 // print VolumeInfo table
125 ASSERT(SysInfo
!= NULL
);
128 gST
->ConOut
->Mode
->CursorRow
,
130 STRING_TOKEN (STR_LS_SFO_VOLINFO
),
131 gShellLevel2HiiHandle
,
132 SysInfo
->VolumeLabel
,
134 SysInfo
->ReadOnly
?L
"TRUE":L
"FALSE",
139 SHELL_FREE_NON_NULL(SysInfo
);
145 print out the info on a single file.
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.
156 PrintFileInformation(
157 IN CONST BOOLEAN Sfo
,
158 IN CONST EFI_SHELL_FILE_INFO
*TheNode
,
164 ASSERT(Files
!= NULL
);
165 ASSERT(Size
!= NULL
);
166 ASSERT(Dirs
!= NULL
);
167 ASSERT(TheNode
!= NULL
);
171 // Print the FileInfo Table
175 gST
->ConOut
->Mode
->CursorRow
,
177 STRING_TOKEN (STR_LS_SFO_FILEINFO
),
178 gShellLevel2HiiHandle
,
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
208 // print this one out...
209 // first print the universal start, next print the type specific name format, last print the CRLF
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
222 if (TheNode
->Info
->Attribute
& EFI_FILE_DIRECTORY
) {
228 STRING_TOKEN (STR_LS_LINE_END_DIR
),
229 gShellLevel2HiiHandle
,
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)
242 STRING_TOKEN (STR_LS_LINE_END_EXE
),
243 gShellLevel2HiiHandle
,
251 STRING_TOKEN (STR_LS_LINE_END_FILE
),
252 gShellLevel2HiiHandle
,
261 print out the header when not using standard format output.
263 @param[in] Path String with starting path.
268 IN CONST CHAR16
*Path
271 CHAR16
*DirectoryName
;
274 // get directory name from path...
276 DirectoryName
= GetFullyQualifiedPath(Path
);
278 if (DirectoryName
!= NULL
) {
284 gST
->ConOut
->Mode
->CursorRow
,
286 STRING_TOKEN (STR_LS_HEADER_LINE1
),
287 gShellLevel2HiiHandle
,
291 SHELL_FREE_NON_NULL(DirectoryName
);
296 print out the footer when not using standard format output.
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.
317 STRING_TOKEN (STR_LS_FOOTER_LINE
),
318 gShellLevel2HiiHandle
,
326 print out the list of files and directories from the LS command
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] Path String with starting path.
334 @param[in] First TRUE for the original and FALSE for any recursion spawned instances.
335 @param[in] Count The count of bits enabled in Attribs.
336 @param[in] TimeZone The current time zone offset.
338 @retval SHELL_SUCCESS the printing was sucessful.
343 IN CONST BOOLEAN Rec
,
344 IN CONST UINT64 Attribs
,
345 IN CONST BOOLEAN Sfo
,
346 IN CONST CHAR16
*Path
,
347 IN CONST BOOLEAN First
,
348 IN CONST UINTN Count
,
349 IN CONST INT16 TimeZone
353 EFI_SHELL_FILE_INFO
*ListHead
;
354 EFI_SHELL_FILE_INFO
*Node
;
355 SHELL_STATUS ShellStatus
;
359 CHAR16
*DirectoryName
;
361 CHAR16
*CorrectedPath
;
367 ShellStatus
= SHELL_SUCCESS
;
369 CorrectedPath
= NULL
;
371 CorrectedPath
= StrnCatGrow(&CorrectedPath
, NULL
, Path
, 0);
372 if (CorrectedPath
== NULL
) {
373 return (SHELL_OUT_OF_RESOURCES
);
376 PathCleanUpDirectories(CorrectedPath
);
379 PrintNonSfoHeader(CorrectedPath
);
382 Status
= ShellOpenFileMetaArg((CHAR16
*)CorrectedPath
, EFI_FILE_MODE_READ
, &ListHead
);
383 if (EFI_ERROR(Status
)) {
384 SHELL_FREE_NON_NULL(CorrectedPath
);
385 if(Status
== EFI_NOT_FOUND
){
386 return (SHELL_NOT_FOUND
);
388 return (SHELL_DEVICE_ERROR
);
390 if (ListHead
== NULL
|| IsListEmpty(&ListHead
->Link
)) {
391 SHELL_FREE_NON_NULL(CorrectedPath
);
393 // On the first one only we expect to find something...
394 // do we find the . and .. directories otherwise?
397 return (SHELL_NOT_FOUND
);
399 return (SHELL_SUCCESS
);
403 PrintSfoVolumeInfoTableEntry(ListHead
);
406 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
)
407 ; !IsNull(&ListHead
->Link
, &Node
->Link
)
408 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ListHead
->Link
, &Node
->Link
)
410 ASSERT(Node
!= NULL
);
411 if (LongestPath
< StrSize(Node
->FullName
)) {
412 LongestPath
= StrSize(Node
->FullName
);
414 ASSERT(Node
->Info
!= NULL
);
415 ASSERT((Node
->Info
->Attribute
& EFI_FILE_VALID_ATTR
) == Node
->Info
->Attribute
);
418 // NOT system & NOT hidden
420 if ( (Node
->Info
->Attribute
& EFI_FILE_SYSTEM
)
421 || (Node
->Info
->Attribute
& EFI_FILE_HIDDEN
)
425 } else if ((Attribs
!= EFI_FILE_VALID_ATTR
) ||
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).
434 if ( (Node
->Info
->Attribute
& Attribs
) != Attribs
) {
439 PrintFileInformation(Sfo
, Node
, &FileCount
, &FileSize
, &DirCount
);
443 PrintNonSfoFooter(FileCount
, FileSize
, DirCount
);
447 DirectoryName
= AllocateZeroPool(LongestPath
+ 2*sizeof(CHAR16
));
448 if (DirectoryName
== NULL
) {
449 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_MEM
), gShellLevel2HiiHandle
);
450 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
452 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
)
453 ; !IsNull(&ListHead
->Link
, &Node
->Link
) && ShellStatus
== SHELL_SUCCESS
454 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ListHead
->Link
, &Node
->Link
)
456 if (ShellGetExecutionBreakFlag ()) {
457 ShellStatus
= SHELL_ABORTED
;
462 // recurse on any directory except the traversing ones...
464 if (((Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
)
465 && StrCmp(Node
->FileName
, L
".") != 0
466 && StrCmp(Node
->FileName
, L
"..") != 0
468 StrCpy(DirectoryName
, Node
->FullName
);
469 StrCat(DirectoryName
, L
"\\*");
470 ShellStatus
= PrintLsOutput(
480 FreePool(DirectoryName
);
484 FreePool(CorrectedPath
);
485 ShellCloseFileMetaArg(&ListHead
);
486 return (ShellStatus
);
489 STATIC CONST SHELL_PARAM_ITEM LsParamList
[] = {
497 Function for 'ls' command.
499 @param[in] ImageHandle Handle to the Image (NULL if Internal).
500 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
505 IN EFI_HANDLE ImageHandle
,
506 IN EFI_SYSTEM_TABLE
*SystemTable
511 CHAR16
*ProblemParam
;
512 CONST CHAR16
*Attribs
;
513 SHELL_STATUS ShellStatus
;
514 UINT64 RequiredAttributes
;
515 CONST CHAR16
*PathName
;
516 CONST CHAR16
*CurDir
;
527 ShellStatus
= SHELL_SUCCESS
;
528 RequiredAttributes
= 0;
534 // initialize the shell lib (we must be in non-auto-init...)
536 Status
= ShellInitialize();
537 ASSERT_EFI_ERROR(Status
);
540 // Fix local copies of the protocol pointers
542 Status
= CommandInit();
543 ASSERT_EFI_ERROR(Status
);
546 // parse the command line
548 Status
= ShellCommandLineParse (LsParamList
, &Package
, &ProblemParam
, TRUE
);
549 if (EFI_ERROR(Status
)) {
550 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
551 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, ProblemParam
);
552 FreePool(ProblemParam
);
553 ShellStatus
= SHELL_INVALID_PARAMETER
;
561 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
565 if (ShellCommandLineGetCount(Package
) > 2) {
566 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellLevel2HiiHandle
);
567 ShellStatus
= SHELL_INVALID_PARAMETER
;
572 if (ShellCommandLineGetFlag(Package
, L
"-a")) {
573 for ( Attribs
= ShellCommandLineGetValue(Package
, L
"-a")
574 ; Attribs
!= NULL
&& *Attribs
!= CHAR_NULL
&& ShellStatus
== SHELL_SUCCESS
580 RequiredAttributes
|= EFI_FILE_ARCHIVE
;
585 RequiredAttributes
|= EFI_FILE_SYSTEM
;
590 RequiredAttributes
|= EFI_FILE_HIDDEN
;
595 RequiredAttributes
|= EFI_FILE_READ_ONLY
;
600 RequiredAttributes
|= EFI_FILE_DIRECTORY
;
604 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ATTRIBUTE
), gShellLevel2HiiHandle
, ShellCommandLineGetValue(Package
, L
"-a"));
605 ShellStatus
= SHELL_INVALID_PARAMETER
;
610 // if nothing is specified all are specified
612 if (RequiredAttributes
== 0) {
613 RequiredAttributes
= EFI_FILE_VALID_ATTR
;
616 if (ShellStatus
== SHELL_SUCCESS
) {
617 PathName
= ShellCommandLineGetRawValue(Package
, 1);
618 if (PathName
== NULL
) {
619 CurDir
= gEfiShellProtocol
->GetCurDir(NULL
);
620 if (CurDir
== NULL
) {
621 ShellStatus
= SHELL_NOT_FOUND
;
622 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
625 if (PathName
!= NULL
) {
626 if (StrStr(PathName
, L
":") == NULL
&& gEfiShellProtocol
->GetCurDir(NULL
) == NULL
) {
627 ShellStatus
= SHELL_NOT_FOUND
;
628 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
630 ASSERT((FullPath
== NULL
&& Size
== 0) || (FullPath
!= NULL
));
631 StrnCatGrow(&FullPath
, &Size
, PathName
, 0);
632 if (ShellIsDirectory(PathName
) == EFI_SUCCESS
) {
633 if (PathName
[StrLen (PathName
) - 1] == '\\') {
635 // For path ending with '\', just append '*'.
637 StrnCatGrow (&FullPath
, &Size
, L
"*", 0);
638 } else if (PathName
[StrLen (PathName
) - 1] == '*') {
640 // For path ending with '*', do nothing.
644 // Otherwise, append '\*' to directory name.
646 StrnCatGrow (&FullPath
, &Size
, L
"\\*", 0);
651 ASSERT(FullPath
== NULL
);
652 StrnCatGrow(&FullPath
, NULL
, L
"*", 0);
654 Status
= gRT
->GetTime(&TheTime
, NULL
);
655 if (EFI_ERROR(Status
)) {
656 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN
), gShellLevel2HiiHandle
, L
"gRT->GetTime", Status
);
657 TheTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
660 SfoMode
= ShellCommandLineGetFlag(Package
, L
"-sfo");
661 if (ShellStatus
== SHELL_SUCCESS
) {
662 ShellStatus
= PrintLsOutput(
663 ShellCommandLineGetFlag(Package
, L
"-r"),
669 (INT16
)(TheTime
.TimeZone
==EFI_UNSPECIFIED_TIMEZONE
?0:TheTime
.TimeZone
)
671 if (ShellStatus
== SHELL_NOT_FOUND
) {
672 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_LS_FILE_NOT_FOUND
), gShellLevel2HiiHandle
);
673 } else if (ShellStatus
== SHELL_INVALID_PARAMETER
) {
674 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellLevel2HiiHandle
);
675 } else if (ShellStatus
== SHELL_ABORTED
) {
679 } else if (ShellStatus
!= SHELL_SUCCESS
) {
680 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellLevel2HiiHandle
);
687 if (FullPath
!= NULL
) {
691 // free the command line package
693 ShellCommandLineFreeVarList (Package
);
695 return (ShellStatus
);