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