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 - 2016, 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
PrintSfoVolumeInfoTableEntry(IN CONST EFI_SHELL_FILE_INFO * TheList)25 PrintSfoVolumeInfoTableEntry(
26 IN CONST EFI_SHELL_FILE_INFO *TheList
27 )
28 {
29 EFI_STATUS Status;
30 EFI_SHELL_FILE_INFO *Node;
31 CHAR16 *DirectoryName;
32 EFI_FILE_SYSTEM_INFO *SysInfo;
33 UINTN SysInfoSize;
34 SHELL_FILE_HANDLE ShellFileHandle;
35 EFI_FILE_PROTOCOL *EfiFpHandle;
36
37 //
38 // Get the first valid handle (directories)
39 //
40 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&TheList->Link)
41 ; !IsNull(&TheList->Link, &Node->Link) && Node->Handle == NULL
42 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&TheList->Link, &Node->Link)
43 );
44
45 if (Node->Handle == NULL) {
46 DirectoryName = GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO *)GetFirstNode(&TheList->Link))->FullName);
47
48 //
49 // We need to open something up to get system information
50 //
51 Status = gEfiShellProtocol->OpenFileByName(
52 DirectoryName,
53 &ShellFileHandle,
54 EFI_FILE_MODE_READ
55 );
56
57 ASSERT_EFI_ERROR(Status);
58 FreePool(DirectoryName);
59
60 //
61 // Get the Volume Info from ShellFileHandle
62 //
63 SysInfo = NULL;
64 SysInfoSize = 0;
65 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle);
66 Status = EfiFpHandle->GetInfo(
67 EfiFpHandle,
68 &gEfiFileSystemInfoGuid,
69 &SysInfoSize,
70 SysInfo
71 );
72
73 if (Status == EFI_BUFFER_TOO_SMALL) {
74 SysInfo = AllocateZeroPool(SysInfoSize);
75 Status = EfiFpHandle->GetInfo(
76 EfiFpHandle,
77 &gEfiFileSystemInfoGuid,
78 &SysInfoSize,
79 SysInfo
80 );
81 }
82
83 ASSERT_EFI_ERROR(Status);
84
85 gEfiShellProtocol->CloseFile(ShellFileHandle);
86 } else {
87 //
88 // Get the Volume Info from Node->Handle
89 //
90 SysInfo = NULL;
91 SysInfoSize = 0;
92 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(Node->Handle);
93 Status = EfiFpHandle->GetInfo(
94 EfiFpHandle,
95 &gEfiFileSystemInfoGuid,
96 &SysInfoSize,
97 SysInfo
98 );
99
100 if (Status == EFI_BUFFER_TOO_SMALL) {
101 SysInfo = AllocateZeroPool(SysInfoSize);
102 Status = EfiFpHandle->GetInfo(
103 EfiFpHandle,
104 &gEfiFileSystemInfoGuid,
105 &SysInfoSize,
106 SysInfo
107 );
108 }
109
110 ASSERT_EFI_ERROR(Status);
111 }
112
113 ShellPrintHiiEx (
114 -1,
115 -1,
116 NULL,
117 STRING_TOKEN (STR_GEN_SFO_HEADER),
118 gShellLevel2HiiHandle,
119 L"ls"
120 );
121 //
122 // print VolumeInfo table
123 //
124 ASSERT(SysInfo != NULL);
125 ShellPrintHiiEx (
126 0,
127 gST->ConOut->Mode->CursorRow,
128 NULL,
129 STRING_TOKEN (STR_LS_SFO_VOLINFO),
130 gShellLevel2HiiHandle,
131 SysInfo->VolumeLabel,
132 SysInfo->VolumeSize,
133 SysInfo->ReadOnly?L"TRUE":L"FALSE",
134 SysInfo->FreeSpace,
135 SysInfo->BlockSize
136 );
137
138 SHELL_FREE_NON_NULL(SysInfo);
139
140 return (Status);
141 }
142
143 /**
144 print out the info on a single file.
145
146 @param[in] Sfo TRUE if in SFO, false otherwise.
147 @param[in] TheNode the EFI_SHELL_FILE_INFO node to print out information on.
148 @param[in] Files incremented if a file is printed.
149 @param[in] Size incremented by file size.
150 @param[in] Dirs incremented if a directory is printed.
151
152 **/
153 VOID
PrintFileInformation(IN CONST BOOLEAN Sfo,IN CONST EFI_SHELL_FILE_INFO * TheNode,IN UINT64 * Files,IN UINT64 * Size,IN UINT64 * Dirs)154 PrintFileInformation(
155 IN CONST BOOLEAN Sfo,
156 IN CONST EFI_SHELL_FILE_INFO *TheNode,
157 IN UINT64 *Files,
158 IN UINT64 *Size,
159 IN UINT64 *Dirs
160 )
161 {
162 ASSERT(Files != NULL);
163 ASSERT(Size != NULL);
164 ASSERT(Dirs != NULL);
165 ASSERT(TheNode != NULL);
166
167 if (Sfo) {
168 //
169 // Print the FileInfo Table
170 //
171 ShellPrintHiiEx (
172 0,
173 gST->ConOut->Mode->CursorRow,
174 NULL,
175 STRING_TOKEN (STR_LS_SFO_FILEINFO),
176 gShellLevel2HiiHandle,
177 TheNode->FullName,
178 TheNode->Info->FileSize,
179 TheNode->Info->PhysicalSize,
180 (TheNode->Info->Attribute & EFI_FILE_ARCHIVE) != 0?L"a":L"",
181 (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"d":L"",
182 (TheNode->Info->Attribute & EFI_FILE_HIDDEN) != 0?L"h":L"",
183 (TheNode->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L"r":L"",
184 (TheNode->Info->Attribute & EFI_FILE_SYSTEM) != 0?L"s":L"",
185 TheNode->Info->CreateTime.Hour,
186 TheNode->Info->CreateTime.Minute,
187 TheNode->Info->CreateTime.Second,
188 TheNode->Info->CreateTime.Day,
189 TheNode->Info->CreateTime.Month,
190 TheNode->Info->CreateTime.Year,
191 TheNode->Info->LastAccessTime.Hour,
192 TheNode->Info->LastAccessTime.Minute,
193 TheNode->Info->LastAccessTime.Second,
194 TheNode->Info->LastAccessTime.Day,
195 TheNode->Info->LastAccessTime.Month,
196 TheNode->Info->LastAccessTime.Year,
197 TheNode->Info->ModificationTime.Hour,
198 TheNode->Info->ModificationTime.Minute,
199 TheNode->Info->ModificationTime.Second,
200 TheNode->Info->ModificationTime.Day,
201 TheNode->Info->ModificationTime.Month,
202 TheNode->Info->ModificationTime.Year
203 );
204 } else {
205 //
206 // print this one out...
207 // first print the universal start, next print the type specific name format, last print the CRLF
208 //
209 ShellPrintHiiEx (
210 -1,
211 -1,
212 NULL,
213 STRING_TOKEN (STR_LS_LINE_START_ALL),
214 gShellLevel2HiiHandle,
215 &TheNode->Info->ModificationTime,
216 (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"<DIR>":L"",
217 (TheNode->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L'r':L' ',
218 TheNode->Info->FileSize
219 );
220 if (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) {
221 (*Dirs)++;
222 ShellPrintHiiEx (
223 -1,
224 -1,
225 NULL,
226 STRING_TOKEN (STR_LS_LINE_END_DIR),
227 gShellLevel2HiiHandle,
228 TheNode->FileName
229 );
230 } else {
231 (*Files)++;
232 (*Size) += TheNode->Info->FileSize;
233 if ( (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".nsh", (CHAR16*)&(TheNode->FileName[StrLen (TheNode->FileName) - 4])) == 0)
234 || (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".efi", (CHAR16*)&(TheNode->FileName[StrLen (TheNode->FileName) - 4])) == 0)
235 ){
236 ShellPrintHiiEx (
237 -1,
238 -1,
239 NULL,
240 STRING_TOKEN (STR_LS_LINE_END_EXE),
241 gShellLevel2HiiHandle,
242 TheNode->FileName
243 );
244 } else {
245 ShellPrintHiiEx (
246 -1,
247 -1,
248 NULL,
249 STRING_TOKEN (STR_LS_LINE_END_FILE),
250 gShellLevel2HiiHandle,
251 TheNode->FileName
252 );
253 }
254 }
255 }
256 }
257
258 /**
259 print out the header when not using standard format output.
260
261 @param[in] Path String with starting path.
262 **/
263 VOID
PrintNonSfoHeader(IN CONST CHAR16 * Path)264 PrintNonSfoHeader(
265 IN CONST CHAR16 *Path
266 )
267 {
268 CHAR16 *DirectoryName;
269
270 //
271 // get directory name from path...
272 //
273 DirectoryName = GetFullyQualifiedPath(Path);
274
275 if (DirectoryName != NULL) {
276 //
277 // print header
278 //
279 ShellPrintHiiEx (
280 0,
281 gST->ConOut->Mode->CursorRow,
282 NULL,
283 STRING_TOKEN (STR_LS_HEADER_LINE1),
284 gShellLevel2HiiHandle,
285 DirectoryName
286 );
287
288 SHELL_FREE_NON_NULL(DirectoryName);
289 }
290 }
291
292 /**
293 print out the footer when not using standard format output.
294
295 @param[in] Files The number of files.
296 @param[in] Size The size of files in bytes.
297 @param[in] Dirs The number of directories.
298 **/
299 VOID
PrintNonSfoFooter(IN UINT64 Files,IN UINT64 Size,IN UINT64 Dirs)300 PrintNonSfoFooter(
301 IN UINT64 Files,
302 IN UINT64 Size,
303 IN UINT64 Dirs
304 )
305 {
306 //
307 // print footer
308 //
309 ShellPrintHiiEx (
310 -1,
311 -1,
312 NULL,
313 STRING_TOKEN (STR_LS_FOOTER_LINE),
314 gShellLevel2HiiHandle,
315 Files,
316 Size,
317 Dirs
318 );
319 }
320
321 /**
322 print out the list of files and directories from the LS command
323
324 @param[in] Rec TRUE to automatically recurse into each found directory
325 FALSE to only list the specified directory.
326 @param[in] Attribs List of required Attribute for display.
327 If 0 then all non-system and non-hidden files will be printed.
328 @param[in] Sfo TRUE to use Standard Format Output, FALSE otherwise
329 @param[in] RootPath String with starting path to search in.
330 @param[in] SearchString String with search string.
331 @param[in] Found Set to TRUE, if anyone were found.
332 @param[in] Count The count of bits enabled in Attribs.
333 @param[in] TimeZone The current time zone offset.
334
335 @retval SHELL_SUCCESS the printing was sucessful.
336 **/
337 SHELL_STATUS
PrintLsOutput(IN CONST BOOLEAN Rec,IN CONST UINT64 Attribs,IN CONST BOOLEAN Sfo,IN CONST CHAR16 * RootPath,IN CONST CHAR16 * SearchString,IN BOOLEAN * Found,IN CONST UINTN Count,IN CONST INT16 TimeZone)338 PrintLsOutput(
339 IN CONST BOOLEAN Rec,
340 IN CONST UINT64 Attribs,
341 IN CONST BOOLEAN Sfo,
342 IN CONST CHAR16 *RootPath,
343 IN CONST CHAR16 *SearchString,
344 IN BOOLEAN *Found,
345 IN CONST UINTN Count,
346 IN CONST INT16 TimeZone
347 )
348 {
349 EFI_STATUS Status;
350 EFI_SHELL_FILE_INFO *ListHead;
351 EFI_SHELL_FILE_INFO *Node;
352 SHELL_STATUS ShellStatus;
353 UINT64 FileCount;
354 UINT64 DirCount;
355 UINT64 FileSize;
356 UINTN LongestPath;
357 CHAR16 *CorrectedPath;
358 BOOLEAN FoundOne;
359 BOOLEAN HeaderPrinted;
360
361 HeaderPrinted = FALSE;
362 FileCount = 0;
363 DirCount = 0;
364 FileSize = 0;
365 ListHead = NULL;
366 ShellStatus = SHELL_SUCCESS;
367 LongestPath = 0;
368 CorrectedPath = NULL;
369
370 if (Found != NULL) {
371 FoundOne = *Found;
372 } else {
373 FoundOne = FALSE;
374 }
375
376 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0);
377 if (CorrectedPath == NULL) {
378 return SHELL_OUT_OF_RESOURCES;
379 }
380 if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\'
381 &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') {
382 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\", 0);
383 }
384 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, SearchString, 0);
385 if (CorrectedPath == NULL) {
386 return (SHELL_OUT_OF_RESOURCES);
387 }
388
389 PathCleanUpDirectories(CorrectedPath);
390
391 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
392 if (!EFI_ERROR(Status)) {
393 if (ListHead == NULL || IsListEmpty(&ListHead->Link)) {
394 SHELL_FREE_NON_NULL(CorrectedPath);
395 return (SHELL_SUCCESS);
396 }
397
398 if (Sfo && Found == NULL) {
399 PrintSfoVolumeInfoTableEntry(ListHead);
400 }
401
402 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link), LongestPath = 0
403 ; !IsNull(&ListHead->Link, &Node->Link)
404 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
405 ){
406 if (ShellGetExecutionBreakFlag ()) {
407 ShellStatus = SHELL_ABORTED;
408 break;
409 }
410 ASSERT(Node != NULL);
411 if (LongestPath < StrSize(Node->FullName)) {
412 LongestPath = StrSize(Node->FullName);
413 }
414 ASSERT(Node->Info != NULL);
415 ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute);
416 if (Attribs == 0) {
417 //
418 // NOT system & NOT hidden
419 //
420 if ( (Node->Info->Attribute & EFI_FILE_SYSTEM)
421 || (Node->Info->Attribute & EFI_FILE_HIDDEN)
422 ){
423 continue;
424 }
425 } else if ((Attribs != EFI_FILE_VALID_ATTR) ||
426 (Count == 5)) {
427 //
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).
433 //
434 if ( (Node->Info->Attribute & Attribs) != Attribs) {
435 continue;
436 }
437 }
438
439 if (!Sfo && !HeaderPrinted) {
440 PathRemoveLastItem (CorrectedPath);
441 PrintNonSfoHeader(CorrectedPath);
442 }
443 PrintFileInformation(Sfo, Node, &FileCount, &FileSize, &DirCount);
444 FoundOne = TRUE;
445 HeaderPrinted = TRUE;
446 }
447
448 if (!Sfo && ShellStatus != SHELL_ABORTED) {
449 PrintNonSfoFooter(FileCount, FileSize, DirCount);
450 }
451 }
452
453 if (Rec && ShellStatus != SHELL_ABORTED) {
454 //
455 // Re-Open all the files under the starting path for directories that didnt necessarily match our file filter
456 //
457 ShellCloseFileMetaArg(&ListHead);
458 CorrectedPath[0] = CHAR_NULL;
459 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0);
460 if (CorrectedPath == NULL) {
461 return SHELL_OUT_OF_RESOURCES;
462 }
463 if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\'
464 &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') {
465 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\", 0);
466 }
467 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"*", 0);
468 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
469
470 if (!EFI_ERROR(Status)) {
471 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
472 ; !IsNull(&ListHead->Link, &Node->Link) && ShellStatus == SHELL_SUCCESS
473 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
474 ){
475 if (ShellGetExecutionBreakFlag ()) {
476 ShellStatus = SHELL_ABORTED;
477 break;
478 }
479
480 //
481 // recurse on any directory except the traversing ones...
482 //
483 if (((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY)
484 && StrCmp(Node->FileName, L".") != 0
485 && StrCmp(Node->FileName, L"..") != 0
486 ){
487 ShellStatus = PrintLsOutput(
488 Rec,
489 Attribs,
490 Sfo,
491 Node->FullName,
492 SearchString,
493 &FoundOne,
494 Count,
495 TimeZone);
496
497 //
498 // Since it's running recursively, we have to break immediately when returned SHELL_ABORTED
499 //
500 if (ShellStatus == SHELL_ABORTED) {
501 break;
502 }
503 }
504 }
505 }
506 }
507
508 SHELL_FREE_NON_NULL(CorrectedPath);
509 ShellCloseFileMetaArg(&ListHead);
510
511 if (Found == NULL && !FoundOne) {
512 return (SHELL_NOT_FOUND);
513 }
514
515 if (Found != NULL) {
516 *Found = FoundOne;
517 }
518
519 return (ShellStatus);
520 }
521
522 STATIC CONST SHELL_PARAM_ITEM LsParamList[] = {
523 {L"-r", TypeFlag},
524 {L"-a", TypeStart},
525 {L"-sfo", TypeFlag},
526 {NULL, TypeMax}
527 };
528
529 /**
530 Function for 'ls' command.
531
532 @param[in] ImageHandle Handle to the Image (NULL if Internal).
533 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
534 **/
535 SHELL_STATUS
536 EFIAPI
ShellCommandRunLs(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)537 ShellCommandRunLs (
538 IN EFI_HANDLE ImageHandle,
539 IN EFI_SYSTEM_TABLE *SystemTable
540 )
541 {
542 EFI_STATUS Status;
543 LIST_ENTRY *Package;
544 CHAR16 *ProblemParam;
545 CONST CHAR16 *Attribs;
546 SHELL_STATUS ShellStatus;
547 UINT64 RequiredAttributes;
548 CONST CHAR16 *PathName;
549 CONST CHAR16 *CurDir;
550 UINTN Count;
551 CHAR16 *FullPath;
552 UINTN Size;
553 EFI_TIME TheTime;
554 CHAR16 *SearchString;
555
556 Size = 0;
557 FullPath = NULL;
558 ProblemParam = NULL;
559 Attribs = NULL;
560 ShellStatus = SHELL_SUCCESS;
561 RequiredAttributes = 0;
562 PathName = NULL;
563 SearchString = NULL;
564 CurDir = NULL;
565 Count = 0;
566
567 //
568 // initialize the shell lib (we must be in non-auto-init...)
569 //
570 Status = ShellInitialize();
571 ASSERT_EFI_ERROR(Status);
572
573 //
574 // Fix local copies of the protocol pointers
575 //
576 Status = CommandInit();
577 ASSERT_EFI_ERROR(Status);
578
579 //
580 // parse the command line
581 //
582 Status = ShellCommandLineParse (LsParamList, &Package, &ProblemParam, TRUE);
583 if (EFI_ERROR(Status)) {
584 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
585 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"ls", ProblemParam);
586 FreePool(ProblemParam);
587 ShellStatus = SHELL_INVALID_PARAMETER;
588 } else {
589 ASSERT(FALSE);
590 }
591 } else {
592 //
593 // check for "-?"
594 //
595 if (ShellCommandLineGetFlag(Package, L"-?")) {
596 ASSERT(FALSE);
597 }
598
599 if (ShellCommandLineGetCount(Package) > 2) {
600 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"ls");
601 ShellStatus = SHELL_INVALID_PARAMETER;
602 } else {
603 //
604 // check for -a
605 //
606 if (ShellCommandLineGetFlag(Package, L"-a")) {
607 for ( Attribs = ShellCommandLineGetValue(Package, L"-a")
608 ; Attribs != NULL && *Attribs != CHAR_NULL && ShellStatus == SHELL_SUCCESS
609 ; Attribs++
610 ){
611 switch (*Attribs) {
612 case L'a':
613 case L'A':
614 RequiredAttributes |= EFI_FILE_ARCHIVE;
615 Count++;
616 continue;
617 case L's':
618 case L'S':
619 RequiredAttributes |= EFI_FILE_SYSTEM;
620 Count++;
621 continue;
622 case L'h':
623 case L'H':
624 RequiredAttributes |= EFI_FILE_HIDDEN;
625 Count++;
626 continue;
627 case L'r':
628 case L'R':
629 RequiredAttributes |= EFI_FILE_READ_ONLY;
630 Count++;
631 continue;
632 case L'd':
633 case L'D':
634 RequiredAttributes |= EFI_FILE_DIRECTORY;
635 Count++;
636 continue;
637 default:
638 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ATTRIBUTE), gShellLevel2HiiHandle, L"ls", ShellCommandLineGetValue(Package, L"-a"));
639 ShellStatus = SHELL_INVALID_PARAMETER;
640 break;
641 } // switch
642 } // for loop
643 //
644 // if nothing is specified all are specified
645 //
646 if (RequiredAttributes == 0) {
647 RequiredAttributes = EFI_FILE_VALID_ATTR;
648 }
649 } // if -a present
650 if (ShellStatus == SHELL_SUCCESS) {
651 PathName = ShellCommandLineGetRawValue(Package, 1);
652 if (PathName == NULL) {
653 //
654 // Nothing specified... must start from current directory
655 //
656 CurDir = gEfiShellProtocol->GetCurDir(NULL);
657 if (CurDir == NULL) {
658 ShellStatus = SHELL_NOT_FOUND;
659 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls");
660 }
661 //
662 // Copy to the 2 strings for starting path and file search string
663 //
664 ASSERT(SearchString == NULL);
665 ASSERT(FullPath == NULL);
666 StrnCatGrow(&SearchString, NULL, L"*", 0);
667 StrnCatGrow(&FullPath, NULL, CurDir, 0);
668 Size = FullPath != NULL? StrSize(FullPath) : 0;
669 StrnCatGrow(&FullPath, &Size, L"\\", 0);
670 } else {
671 if (StrStr(PathName, L":") == NULL && gEfiShellProtocol->GetCurDir(NULL) == NULL) {
672 //
673 // If we got something and it doesnt have a fully qualified path, then we needed to have a CWD.
674 //
675 ShellStatus = SHELL_NOT_FOUND;
676 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls");
677 } else {
678 //
679 // We got a valid fully qualified path or we have a CWD
680 //
681 ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL));
682 if (StrStr(PathName, L":") == NULL) {
683 StrnCatGrow(&FullPath, &Size, gEfiShellProtocol->GetCurDir(NULL), 0);
684 if (FullPath == NULL) {
685 ShellCommandLineFreeVarList (Package);
686 return SHELL_OUT_OF_RESOURCES;
687 }
688 Size = FullPath != NULL? StrSize(FullPath) : 0;
689 StrnCatGrow(&FullPath, &Size, L"\\", 0);
690 }
691 StrnCatGrow(&FullPath, &Size, PathName, 0);
692 if (FullPath == NULL) {
693 ShellCommandLineFreeVarList (Package);
694 return SHELL_OUT_OF_RESOURCES;
695 }
696
697 if (ShellIsDirectory(PathName) == EFI_SUCCESS) {
698 //
699 // is listing ends with a directory, then we list all files in that directory
700 //
701 StrnCatGrow(&SearchString, NULL, L"*", 0);
702 } else {
703 //
704 // must split off the search part that applies to files from the end of the directory part
705 //
706 StrnCatGrow(&SearchString, NULL, FullPath, 0);
707 if (SearchString == NULL) {
708 FreePool (FullPath);
709 ShellCommandLineFreeVarList (Package);
710 return SHELL_OUT_OF_RESOURCES;
711 }
712 PathRemoveLastItem (FullPath);
713 CopyMem (SearchString, SearchString + StrLen (FullPath), StrSize (SearchString + StrLen (FullPath)));
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