2 Main file for ls shell level 2 function.
4 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "UefiShellLevel2CommandsLib.h"
16 #include <Guid/FileSystemInfo.h>
19 print out the list of files and directories from the LS command
21 @param[in] Rec TRUE to automatically recurse into each found directory
22 FALSE to only list the specified directory.
23 @param[in] Attribs List of required Attribute for display.
24 If 0 then all non-system and non-hidden files will be printed.
25 @param[in] Sfo TRUE to use Standard Format Output, FALSE otherwise
26 @param[in] Path String with starting path.
27 @param[in] First TRUE for the original and FALSE for any recursion spawned instances.
28 @param[in] Count The count of bits enabled in Attribs.
29 @param[in] TimeZone The current time zone offset.
31 @retval SHELL_SUCCESS the printing was sucessful.
37 IN CONST UINT64 Attribs
,
39 IN CONST CHAR16
*Path
,
40 IN CONST BOOLEAN First
,
42 IN CONST INT16 TimeZone
46 EFI_SHELL_FILE_INFO
*ListHead
;
47 EFI_SHELL_FILE_INFO
*Node
;
48 SHELL_STATUS ShellStatus
;
52 CHAR16
*DirectoryName
;
54 EFI_FILE_SYSTEM_INFO
*SysInfo
;
56 SHELL_FILE_HANDLE ShellFileHandle
;
57 CHAR16
*CorrectedPath
;
58 EFI_FILE_PROTOCOL
*EfiFpHandle
;
64 ShellStatus
= SHELL_SUCCESS
;
68 CorrectedPath
= StrnCatGrow(&CorrectedPath
, NULL
, Path
, 0);
69 ASSERT(CorrectedPath
!= NULL
);
70 PathCleanUpDirectories(CorrectedPath
);
72 Status
= ShellOpenFileMetaArg((CHAR16
*)CorrectedPath
, EFI_FILE_MODE_READ
, &ListHead
);
73 if (EFI_ERROR(Status
)) {
74 return (SHELL_DEVICE_ERROR
);
76 if (ListHead
== NULL
|| IsListEmpty(&ListHead
->Link
)) {
78 // On the first one only we expect to find something...
79 // do we find the . and .. directories otherwise?
82 return (SHELL_NOT_FOUND
);
84 return (SHELL_SUCCESS
);
89 // Get the first valid handle (directories)
91 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
)
92 ; !IsNull(&ListHead
->Link
, &Node
->Link
) && Node
->Handle
== NULL
93 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ListHead
->Link
, &Node
->Link
)
96 if (Node
->Handle
== NULL
) {
97 DirectoryName
= GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
))->FullName
);
100 // We need to open something up to get system information
102 Status
= gEfiShellProtocol
->OpenFileByName(
107 ASSERT_EFI_ERROR(Status
);
108 FreePool(DirectoryName
);
111 // Get the Volume Info from ShellFileHandle
115 EfiFpHandle
= ConvertShellHandleToEfiFileProtocol(ShellFileHandle
);
116 Status
= EfiFpHandle
->GetInfo(
118 &gEfiFileSystemInfoGuid
,
122 if (Status
== EFI_BUFFER_TOO_SMALL
) {
123 SysInfo
= AllocateZeroPool(SysInfoSize
);
124 Status
= EfiFpHandle
->GetInfo(
126 &gEfiFileSystemInfoGuid
,
131 ASSERT_EFI_ERROR(Status
);
133 gEfiShellProtocol
->CloseFile(ShellFileHandle
);
136 // Get the Volume Info from Node->Handle
140 EfiFpHandle
= ConvertShellHandleToEfiFileProtocol(Node
->Handle
);
141 Status
= EfiFpHandle
->GetInfo(
143 &gEfiFileSystemInfoGuid
,
147 if (Status
== EFI_BUFFER_TOO_SMALL
) {
148 SysInfo
= AllocateZeroPool(SysInfoSize
);
149 Status
= EfiFpHandle
->GetInfo(
151 &gEfiFileSystemInfoGuid
,
156 ASSERT_EFI_ERROR(Status
);
163 STRING_TOKEN (STR_GEN_SFO_HEADER
),
164 gShellLevel2HiiHandle
,
167 // print VolumeInfo table
169 ASSERT(SysInfo
!= NULL
);
172 gST
->ConOut
->Mode
->CursorRow
,
174 STRING_TOKEN (STR_LS_SFO_VOLINFO
),
175 gShellLevel2HiiHandle
,
176 SysInfo
->VolumeLabel
,
178 SysInfo
->ReadOnly
?L
"TRUE":L
"FALSE",
182 if (SysInfo
!= NULL
) {
189 // get directory name from path...
191 DirectoryName
= GetFullyQualifiedPath(CorrectedPath
);
198 gST
->ConOut
->Mode
->CursorRow
,
200 STRING_TOKEN (STR_LS_HEADER_LINE1
),
201 gShellLevel2HiiHandle
,
204 FreePool(DirectoryName
);
206 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
)
207 ; !IsNull(&ListHead
->Link
, &Node
->Link
)
208 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ListHead
->Link
, &Node
->Link
)
210 ASSERT(Node
!= NULL
);
211 if (LongestPath
< StrSize(Node
->FullName
)) {
212 LongestPath
= StrSize(Node
->FullName
);
214 ASSERT(Node
->Info
!= NULL
);
215 ASSERT((Node
->Info
->Attribute
& EFI_FILE_VALID_ATTR
) == Node
->Info
->Attribute
);
218 // NOT system & NOT hidden
220 if ( (Node
->Info
->Attribute
& EFI_FILE_SYSTEM
)
221 || (Node
->Info
->Attribute
& EFI_FILE_HIDDEN
)
225 } else if (Attribs
!= EFI_FILE_VALID_ATTR
) {
228 // the bit must match
230 if ( (Node
->Info
->Attribute
& Attribs
) != Attribs
) {
235 // exact match on all bits
237 if ( (Node
->Info
->Attribute
|EFI_FILE_ARCHIVE
) != (Attribs
|EFI_FILE_ARCHIVE
)) {
245 // Print the FileInfo Table
249 gST
->ConOut
->Mode
->CursorRow
,
251 STRING_TOKEN (STR_LS_SFO_FILEINFO
),
252 gShellLevel2HiiHandle
,
254 Node
->Info
->FileSize
,
255 Node
->Info
->PhysicalSize
,
256 (Node
->Info
->Attribute
& EFI_FILE_ARCHIVE
) != 0?L
"a":L
"",
257 (Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0?L
"d":L
"",
258 (Node
->Info
->Attribute
& EFI_FILE_HIDDEN
) != 0?L
"h":L
"",
259 (Node
->Info
->Attribute
& EFI_FILE_READ_ONLY
) != 0?L
"r":L
"",
260 (Node
->Info
->Attribute
& EFI_FILE_SYSTEM
) != 0?L
"s":L
"",
261 Node
->Info
->CreateTime
.Hour
,
262 Node
->Info
->CreateTime
.Minute
,
263 Node
->Info
->CreateTime
.Second
,
264 Node
->Info
->CreateTime
.Day
,
265 Node
->Info
->CreateTime
.Month
,
266 Node
->Info
->CreateTime
.Year
,
267 Node
->Info
->LastAccessTime
.Hour
,
268 Node
->Info
->LastAccessTime
.Minute
,
269 Node
->Info
->LastAccessTime
.Second
,
270 Node
->Info
->LastAccessTime
.Day
,
271 Node
->Info
->LastAccessTime
.Month
,
272 Node
->Info
->LastAccessTime
.Year
,
273 Node
->Info
->ModificationTime
.Hour
,
274 Node
->Info
->ModificationTime
.Minute
,
275 Node
->Info
->ModificationTime
.Second
,
276 Node
->Info
->ModificationTime
.Day
,
277 Node
->Info
->ModificationTime
.Month
,
278 Node
->Info
->ModificationTime
.Year
282 // print this one out...
283 // first print the universal start, next print the type specific name format, last print the CRLF
289 STRING_TOKEN (STR_LS_LINE_START_ALL
),
290 gShellLevel2HiiHandle
,
291 &Node
->Info
->ModificationTime
,
292 (Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) != 0?L
"<DIR>":L
"",
293 (Node
->Info
->Attribute
& EFI_FILE_READ_ONLY
) != 0?L
'r':L
' ',
296 if (Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) {
302 STRING_TOKEN (STR_LS_LINE_END_DIR
),
303 gShellLevel2HiiHandle
,
308 FileSize
+= Node
->Info
->FileSize
;
309 if ( (gUnicodeCollation
->StriColl(gUnicodeCollation
, (CHAR16
*)L
".nsh", (CHAR16
*)&(Node
->FileName
[StrLen (Node
->FileName
) - 4])) == 0)
310 || (gUnicodeCollation
->StriColl(gUnicodeCollation
, (CHAR16
*)L
".efi", (CHAR16
*)&(Node
->FileName
[StrLen (Node
->FileName
) - 4])) == 0)
316 STRING_TOKEN (STR_LS_LINE_END_EXE
),
317 gShellLevel2HiiHandle
,
325 STRING_TOKEN (STR_LS_LINE_END_FILE
),
326 gShellLevel2HiiHandle
,
342 STRING_TOKEN (STR_LS_FOOTER_LINE
),
343 gShellLevel2HiiHandle
,
351 DirectoryName
= AllocateZeroPool(LongestPath
+ 2*sizeof(CHAR16
));
352 if (DirectoryName
== NULL
) {
353 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_MEM
), gShellLevel2HiiHandle
);
354 ShellStatus
= SHELL_OUT_OF_RESOURCES
;
356 for ( Node
= (EFI_SHELL_FILE_INFO
*)GetFirstNode(&ListHead
->Link
)
357 ; !IsNull(&ListHead
->Link
, &Node
->Link
) && ShellStatus
== SHELL_SUCCESS
358 ; Node
= (EFI_SHELL_FILE_INFO
*)GetNextNode(&ListHead
->Link
, &Node
->Link
)
360 if (ShellGetExecutionBreakFlag ()) {
361 ShellStatus
= SHELL_ABORTED
;
366 // recurse on any directory except the traversing ones...
368 if (((Node
->Info
->Attribute
& EFI_FILE_DIRECTORY
) == EFI_FILE_DIRECTORY
)
369 && StrCmp(Node
->FileName
, L
".") != 0
370 && StrCmp(Node
->FileName
, L
"..") != 0
372 StrCpy(DirectoryName
, Node
->FullName
);
373 StrCat(DirectoryName
, L
"\\*");
374 ShellStatus
= PrintLsOutput(
384 FreePool(DirectoryName
);
388 FreePool(CorrectedPath
);
389 ShellCloseFileMetaArg(&ListHead
);
391 return (ShellStatus
);
394 STATIC CONST SHELL_PARAM_ITEM LsParamList
[] = {
402 Function for 'ls' command.
404 @param[in] ImageHandle Handle to the Image (NULL if Internal).
405 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
410 IN EFI_HANDLE ImageHandle
,
411 IN EFI_SYSTEM_TABLE
*SystemTable
416 CHAR16
*ProblemParam
;
417 CONST CHAR16
*Attribs
;
418 SHELL_STATUS ShellStatus
;
419 UINT64 RequiredAttributes
;
420 CONST CHAR16
*PathName
;
421 CONST CHAR16
*CurDir
;
432 ShellStatus
= SHELL_SUCCESS
;
433 RequiredAttributes
= 0;
439 // initialize the shell lib (we must be in non-auto-init...)
441 Status
= ShellInitialize();
442 ASSERT_EFI_ERROR(Status
);
445 // Fix local copies of the protocol pointers
447 Status
= CommandInit();
448 ASSERT_EFI_ERROR(Status
);
451 // parse the command line
453 Status
= ShellCommandLineParse (LsParamList
, &Package
, &ProblemParam
, TRUE
);
454 if (EFI_ERROR(Status
)) {
455 if (Status
== EFI_VOLUME_CORRUPTED
&& ProblemParam
!= NULL
) {
456 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PROBLEM
), gShellLevel2HiiHandle
, ProblemParam
);
457 FreePool(ProblemParam
);
458 ShellStatus
= SHELL_INVALID_PARAMETER
;
466 if (ShellCommandLineGetFlag(Package
, L
"-?")) {
470 if (ShellCommandLineGetCount(Package
) > 2) {
471 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_TOO_MANY
), gShellLevel2HiiHandle
);
472 ShellStatus
= SHELL_INVALID_PARAMETER
;
477 if (ShellCommandLineGetFlag(Package
, L
"-a")) {
478 for ( Attribs
= ShellCommandLineGetValue(Package
, L
"-a")
479 ; Attribs
!= NULL
&& *Attribs
!= CHAR_NULL
&& ShellStatus
== SHELL_SUCCESS
485 RequiredAttributes
|= EFI_FILE_ARCHIVE
;
490 RequiredAttributes
|= EFI_FILE_SYSTEM
;
495 RequiredAttributes
|= EFI_FILE_HIDDEN
;
500 RequiredAttributes
|= EFI_FILE_READ_ONLY
;
505 RequiredAttributes
|= EFI_FILE_DIRECTORY
;
509 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_ATTRIBUTE
), gShellLevel2HiiHandle
, ShellCommandLineGetValue(Package
, L
"-a"));
510 ShellStatus
= SHELL_INVALID_PARAMETER
;
515 // if nothing is specified all are specified
517 if (RequiredAttributes
== 0) {
518 RequiredAttributes
= EFI_FILE_VALID_ATTR
;
521 if (ShellStatus
== SHELL_SUCCESS
) {
522 PathName
= ShellCommandLineGetRawValue(Package
, 1);
523 if (PathName
== NULL
) {
524 CurDir
= gEfiShellProtocol
->GetCurDir(NULL
);
525 if (CurDir
== NULL
) {
526 ShellStatus
= SHELL_NOT_FOUND
;
527 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
530 if (PathName
!= NULL
) {
531 if (StrStr(PathName
, L
":") == NULL
&& gEfiShellProtocol
->GetCurDir(NULL
) == NULL
) {
532 ShellStatus
= SHELL_NOT_FOUND
;
533 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_CWD
), gShellLevel2HiiHandle
);
535 ASSERT((FullPath
== NULL
&& Size
== 0) || (FullPath
!= NULL
));
536 StrnCatGrow(&FullPath
, &Size
, PathName
, 0);
537 if (ShellIsDirectory(PathName
) == EFI_SUCCESS
) {
538 StrnCatGrow(&FullPath
, &Size
, L
"\\*", 0);
542 ASSERT(FullPath
== NULL
);
543 StrnCatGrow(&FullPath
, NULL
, L
"*", 0);
545 Status
= gRT
->GetTime(&TheTime
, NULL
);
546 if (EFI_ERROR(Status
)) {
547 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN
), gShellLevel2HiiHandle
, L
"gRT->GetTime", Status
);
548 TheTime
.TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
551 SfoMode
= ShellCommandLineGetFlag(Package
, L
"-sfo");
552 if (ShellStatus
== SHELL_SUCCESS
) {
553 ShellStatus
= PrintLsOutput(
554 ShellCommandLineGetFlag(Package
, L
"-r"),
560 (INT16
)(TheTime
.TimeZone
==EFI_UNSPECIFIED_TIMEZONE
?0:TheTime
.TimeZone
)
562 if (ShellStatus
== SHELL_NOT_FOUND
) {
563 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_NO_FILES
), gShellLevel2HiiHandle
);
564 } else if (ShellStatus
== SHELL_INVALID_PARAMETER
) {
565 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellLevel2HiiHandle
);
566 } else if (ShellStatus
== SHELL_ABORTED
) {
570 } else if (ShellStatus
!= SHELL_SUCCESS
) {
571 ShellPrintHiiEx(-1, -1, NULL
, STRING_TOKEN (STR_GEN_PARAM_INV
), gShellLevel2HiiHandle
);
578 if (FullPath
!= NULL
) {
582 // free the command line package
584 ShellCommandLineFreeVarList (Package
);
586 return (ShellStatus
);