2 Main file for ls shell level 2 function.
4 Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
5 Copyright (c) 2009 - 2012, 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 list of files and directories from the LS command
22 @param[in] Rec TRUE to automatically recurse into each found directory
23 FALSE to only list the specified directory.
24 @param[in] Attribs List of required Attribute for display.
25 If 0 then all non-system and non-hidden files will be printed.
26 @param[in] Sfo TRUE to use Standard Format Output, FALSE otherwise
27 @param[in] Path String with starting path.
28 @param[in] First TRUE for the original and FALSE for any recursion spawned instances.
29 @param[in] Count The count of bits enabled in Attribs.
30 @param[in] TimeZone The current time zone offset.
32 @retval SHELL_SUCCESS the printing was sucessful.
38 IN CONST UINT64 Attribs
,
40 IN CONST CHAR16
*Path
,
41 IN CONST BOOLEAN First
,
43 IN CONST INT16 TimeZone
47 EFI_SHELL_FILE_INFO
*ListHead
;
48 EFI_SHELL_FILE_INFO
*Node
;
49 SHELL_STATUS ShellStatus
;
53 CHAR16
*DirectoryName
;
55 EFI_FILE_SYSTEM_INFO
*SysInfo
;
57 SHELL_FILE_HANDLE ShellFileHandle
;
58 CHAR16
*CorrectedPath
;
59 EFI_FILE_PROTOCOL
*EfiFpHandle
;
65 ShellStatus
= SHELL_SUCCESS
;
69 CorrectedPath
= StrnCatGrow(&CorrectedPath
, NULL
, Path
, 0);
70 if (CorrectedPath
== NULL
) {
71 return (SHELL_OUT_OF_RESOURCES
);
74 PathCleanUpDirectories(CorrectedPath
);
78 // get directory name from path...
80 DirectoryName
= GetFullyQualifiedPath(CorrectedPath
);
87 gST
->ConOut
->Mode
->CursorRow
,
89 STRING_TOKEN (STR_LS_HEADER_LINE1
),
90 gShellLevel2HiiHandle
,
93 FreePool(DirectoryName
);
96 Status
= ShellOpenFileMetaArg((CHAR16
*)CorrectedPath
, EFI_FILE_MODE_READ
, &ListHead
);
97 if (EFI_ERROR(Status
)) {
98 SHELL_FREE_NON_NULL(CorrectedPath
);
99 if(Status
== EFI_NOT_FOUND
){
100 return (SHELL_NOT_FOUND
);
102 return (SHELL_DEVICE_ERROR
);
104 if (ListHead
== NULL
|| IsListEmpty(&ListHead
->Link
)) {
105 SHELL_FREE_NON_NULL(CorrectedPath
);
107 // On the first one only we expect to find something...
108 // do we find the . and .. directories otherwise?
111 return (SHELL_NOT_FOUND
);
113 return (SHELL_SUCCESS
);
118 // Get the first valid handle (directories)
120 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
)
121 ; !IsNull(&ListHead
->Link
, &Node
->Link
) && Node
->Handle
== NULL
122 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ListHead
->Link
, &Node
->Link
)
125 if (Node
->Handle
== NULL
) {
126 DirectoryName
= GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
))->FullName
);
129 // We need to open something up to get system information
131 Status
= gEfiShellProtocol
->OpenFileByName(
136 ASSERT_EFI_ERROR(Status
);
137 FreePool(DirectoryName
);
140 // Get the Volume Info from ShellFileHandle
144 EfiFpHandle
= ConvertShellHandleToEfiFileProtocol(ShellFileHandle
);
145 Status
= EfiFpHandle
->GetInfo(
147 &gEfiFileSystemInfoGuid
,
151 if (Status
== EFI_BUFFER_TOO_SMALL
) {
152 SysInfo
= AllocateZeroPool(SysInfoSize
);
153 Status
= EfiFpHandle
->GetInfo(
155 &gEfiFileSystemInfoGuid
,
160 ASSERT_EFI_ERROR(Status
);
162 gEfiShellProtocol
->CloseFile(ShellFileHandle
);
165 // Get the Volume Info from Node->Handle
169 EfiFpHandle
= ConvertShellHandleToEfiFileProtocol(Node
->Handle
);
170 Status
= EfiFpHandle
->GetInfo(
172 &gEfiFileSystemInfoGuid
,
176 if (Status
== EFI_BUFFER_TOO_SMALL
) {
177 SysInfo
= AllocateZeroPool(SysInfoSize
);
178 Status
= EfiFpHandle
->GetInfo(
180 &gEfiFileSystemInfoGuid
,
185 ASSERT_EFI_ERROR(Status
);
192 STRING_TOKEN (STR_GEN_SFO_HEADER
),
193 gShellLevel2HiiHandle
,
196 // print VolumeInfo table
198 ASSERT(SysInfo
!= NULL
);
201 gST
->ConOut
->Mode
->CursorRow
,
203 STRING_TOKEN (STR_LS_SFO_VOLINFO
),
204 gShellLevel2HiiHandle
,
205 SysInfo
->VolumeLabel
,
207 SysInfo
->ReadOnly
?L
"TRUE":L
"FALSE",
211 if (SysInfo
!= NULL
) {
216 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
)
217 ; !IsNull(&ListHead
->Link
, &Node
->Link
)
218 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ListHead
->Link
, &Node
->Link
)
220 ASSERT(Node
!= NULL
);
221 if (LongestPath
< StrSize(Node
->FullName
)) {
222 LongestPath
= StrSize(Node
->FullName
);
224 ASSERT(Node
->Info
!= NULL
);
225 ASSERT((Node
->Info
->Attribute
& EFI_FILE_VALID_ATTR
) == Node
->Info
->Attribute
);
228 // NOT system & NOT hidden
230 if ( (Node
->Info
->Attribute
& EFI_FILE_SYSTEM
)
231 || (Node
->Info
->Attribute
& EFI_FILE_HIDDEN
)
235 } else if ((Attribs
!= EFI_FILE_VALID_ATTR
) ||
238 // Only matches the bits which "Attribs" contains, not
239 // all files/directories with any of the bits.
240 // Count == 5 is used to tell the difference between a user
241 // specifying all bits (EX: -arhsda) and just specifying
242 // -a (means display all files with any attribute).
244 if ( (Node
->Info
->Attribute
& Attribs
) != Attribs
) {
251 // Print the FileInfo Table
255 gST
->ConOut
->Mode
->CursorRow
,
257 STRING_TOKEN (STR_LS_SFO_FILEINFO
),
258 gShellLevel2HiiHandle
,
260 Node
->Info
->FileSize
,
261 Node
->Info
->PhysicalSize
,
262 (Node
->Info
->Attribute
& EFI_FILE_ARCHIVE
) != 0?L
"a":L
"",
263 (Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0?L
"d":L
"",
264 (Node
->Info
->Attribute
& EFI_FILE_HIDDEN
) != 0?L
"h":L
"",
265 (Node
->Info
->Attribute
& EFI_FILE_READ_ONLY
) != 0?L
"r":L
"",
266 (Node
->Info
->Attribute
& EFI_FILE_SYSTEM
) != 0?L
"s":L
"",
267 Node
->Info
->CreateTime
.Hour
,
268 Node
->Info
->CreateTime
.Minute
,
269 Node
->Info
->CreateTime
.Second
,
270 Node
->Info
->CreateTime
.Day
,
271 Node
->Info
->CreateTime
.Month
,
272 Node
->Info
->CreateTime
.Year
,
273 Node
->Info
->LastAccessTime
.Hour
,
274 Node
->Info
->LastAccessTime
.Minute
,
275 Node
->Info
->LastAccessTime
.Second
,
276 Node
->Info
->LastAccessTime
.Day
,
277 Node
->Info
->LastAccessTime
.Month
,
278 Node
->Info
->LastAccessTime
.Year
,
279 Node
->Info
->ModificationTime
.Hour
,
280 Node
->Info
->ModificationTime
.Minute
,
281 Node
->Info
->ModificationTime
.Second
,
282 Node
->Info
->ModificationTime
.Day
,
283 Node
->Info
->ModificationTime
.Month
,
284 Node
->Info
->ModificationTime
.Year
288 // print this one out...
289 // first print the universal start, next print the type specific name format, last print the CRLF
295 STRING_TOKEN (STR_LS_LINE_START_ALL
),
296 gShellLevel2HiiHandle
,
297 &Node
->Info
->ModificationTime
,
298 (Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0?L
"<DIR>":L
"",
299 (Node
->Info
->Attribute
& EFI_FILE_READ_ONLY
) != 0?L
'r':L
' ',
302 if (Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) {
308 STRING_TOKEN (STR_LS_LINE_END_DIR
),
309 gShellLevel2HiiHandle
,
314 FileSize
+= Node
->Info
->FileSize
;
315 if ( (gUnicodeCollation
->StriColl(gUnicodeCollation
, (CHAR16
*)L
".nsh", (CHAR16
*)&(Node
->FileName
[StrLen (Node
->FileName
) - 4])) == 0)
316 || (gUnicodeCollation
->StriColl(gUnicodeCollation
, (CHAR16
*)L
".efi", (CHAR16
*)&(Node
->FileName
[StrLen (Node
->FileName
) - 4])) == 0)
322 STRING_TOKEN (STR_LS_LINE_END_EXE
),
323 gShellLevel2HiiHandle
,
331 STRING_TOKEN (STR_LS_LINE_END_FILE
),
332 gShellLevel2HiiHandle
,
348 STRING_TOKEN (STR_LS_FOOTER_LINE
),
349 gShellLevel2HiiHandle
,
357 DirectoryName
= AllocateZeroPool(LongestPath
+ 2*sizeof(CHAR16
));
358 if (DirectoryName
== NULL
) {
359 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_MEM
), gShellLevel2HiiHandle
);
360 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
362 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
)
363 ; !IsNull(&ListHead
->Link
, &Node
->Link
) && ShellStatus
== SHELL_SUCCESS
364 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ListHead
->Link
, &Node
->Link
)
366 if (ShellGetExecutionBreakFlag ()) {
367 ShellStatus
= SHELL_ABORTED
;
372 // recurse on any directory except the traversing ones...
374 if (((Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
)
375 && StrCmp(Node
->FileName
, L
".") != 0
376 && StrCmp(Node
->FileName
, L
"..") != 0
378 StrCpy(DirectoryName
, Node
->FullName
);
379 StrCat(DirectoryName
, L
"\\*");
380 ShellStatus
= PrintLsOutput(
390 FreePool(DirectoryName
);
394 FreePool(CorrectedPath
);
395 ShellCloseFileMetaArg(&ListHead
);
396 return (ShellStatus
);
399 STATIC CONST SHELL_PARAM_ITEM LsParamList
[] = {
407 Function for 'ls' command.
409 @param[in] ImageHandle Handle to the Image (NULL if Internal).
410 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
415 IN EFI_HANDLE ImageHandle
,
416 IN EFI_SYSTEM_TABLE
*SystemTable
421 CHAR16
*ProblemParam
;
422 CONST CHAR16
*Attribs
;
423 SHELL_STATUS ShellStatus
;
424 UINT64 RequiredAttributes
;
425 CONST CHAR16
*PathName
;
426 CONST CHAR16
*CurDir
;
437 ShellStatus
= SHELL_SUCCESS
;
438 RequiredAttributes
= 0;
444 // initialize the shell lib (we must be in non-auto-init...)
446 Status
= ShellInitialize();
447 ASSERT_EFI_ERROR(Status
);
450 // Fix local copies of the protocol pointers
452 Status
= CommandInit();
453 ASSERT_EFI_ERROR(Status
);
456 // parse the command line
458 Status
= ShellCommandLineParse (LsParamList
, &Package
, &ProblemParam
, TRUE
);
459 if (EFI_ERROR(Status
)) {
460 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
461 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, ProblemParam
);
462 FreePool(ProblemParam
);
463 ShellStatus
= SHELL_INVALID_PARAMETER
;
471 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
475 if (ShellCommandLineGetCount(Package
) > 2) {
476 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellLevel2HiiHandle
);
477 ShellStatus
= SHELL_INVALID_PARAMETER
;
482 if (ShellCommandLineGetFlag(Package
, L
"-a")) {
483 for ( Attribs
= ShellCommandLineGetValue(Package
, L
"-a")
484 ; Attribs
!= NULL
&& *Attribs
!= CHAR_NULL
&& ShellStatus
== SHELL_SUCCESS
490 RequiredAttributes
|= EFI_FILE_ARCHIVE
;
495 RequiredAttributes
|= EFI_FILE_SYSTEM
;
500 RequiredAttributes
|= EFI_FILE_HIDDEN
;
505 RequiredAttributes
|= EFI_FILE_READ_ONLY
;
510 RequiredAttributes
|= EFI_FILE_DIRECTORY
;
514 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ATTRIBUTE
), gShellLevel2HiiHandle
, ShellCommandLineGetValue(Package
, L
"-a"));
515 ShellStatus
= SHELL_INVALID_PARAMETER
;
520 // if nothing is specified all are specified
522 if (RequiredAttributes
== 0) {
523 RequiredAttributes
= EFI_FILE_VALID_ATTR
;
526 if (ShellStatus
== SHELL_SUCCESS
) {
527 PathName
= ShellCommandLineGetRawValue(Package
, 1);
528 if (PathName
== NULL
) {
529 CurDir
= gEfiShellProtocol
->GetCurDir(NULL
);
530 if (CurDir
== NULL
) {
531 ShellStatus
= SHELL_NOT_FOUND
;
532 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
535 if (PathName
!= NULL
) {
536 if (StrStr(PathName
, L
":") == NULL
&& gEfiShellProtocol
->GetCurDir(NULL
) == NULL
) {
537 ShellStatus
= SHELL_NOT_FOUND
;
538 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
540 ASSERT((FullPath
== NULL
&& Size
== 0) || (FullPath
!= NULL
));
541 StrnCatGrow(&FullPath
, &Size
, PathName
, 0);
542 if (ShellIsDirectory(PathName
) == EFI_SUCCESS
) {
543 if (PathName
[StrLen (PathName
) - 1] == '\\') {
545 // For path ending with '\', just append '*'.
547 StrnCatGrow (&FullPath
, &Size
, L
"*", 0);
548 } else if (PathName
[StrLen (PathName
) - 1] == '*') {
550 // For path ending with '*', do nothing.
554 // Otherwise, append '\*' to directory name.
556 StrnCatGrow (&FullPath
, &Size
, L
"\\*", 0);
561 ASSERT(FullPath
== NULL
);
562 StrnCatGrow(&FullPath
, NULL
, L
"*", 0);
564 Status
= gRT
->GetTime(&TheTime
, NULL
);
565 if (EFI_ERROR(Status
)) {
566 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN
), gShellLevel2HiiHandle
, L
"gRT->GetTime", Status
);
567 TheTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
570 SfoMode
= ShellCommandLineGetFlag(Package
, L
"-sfo");
571 if (ShellStatus
== SHELL_SUCCESS
) {
572 ShellStatus
= PrintLsOutput(
573 ShellCommandLineGetFlag(Package
, L
"-r"),
579 (INT16
)(TheTime
.TimeZone
==EFI_UNSPECIFIED_TIMEZONE
?0:TheTime
.TimeZone
)
581 if (ShellStatus
== SHELL_NOT_FOUND
) {
582 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_LS_FILE_NOT_FOUND
), gShellLevel2HiiHandle
);
583 } else if (ShellStatus
== SHELL_INVALID_PARAMETER
) {
584 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellLevel2HiiHandle
);
585 } else if (ShellStatus
== SHELL_ABORTED
) {
589 } else if (ShellStatus
!= SHELL_SUCCESS
) {
590 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellLevel2HiiHandle
);
597 if (FullPath
!= NULL
) {
601 // free the command line package
603 ShellCommandLineFreeVarList (Package
);
605 return (ShellStatus
);