VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c@ 99396

Last change on this file since 99396 was 89983, checked in by vboxsync, 4 years ago

Devices/EFI: Merge edk-stable202105 and openssl 1.1.1j and make it build, bugref:4643

  • Property svn:eol-style set to native
File size: 26.9 KB
Line 
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 - 2018, Intel Corporation. All rights reserved.<BR>
6 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8**/
9
10#include "UefiShellLevel2CommandsLib.h"
11#include <Guid/FileSystemInfo.h>
12
13UINTN mDayOfMonth[] = {31, 28, 31, 30, 31, 30, 31, 30, 31, 30, 31, 30};
14
15/**
16 print out the standard format output volume entry.
17
18 @param[in] TheList a list of files from the volume.
19**/
20EFI_STATUS
21PrintSfoVolumeInfoTableEntry(
22 IN CONST EFI_SHELL_FILE_INFO *TheList
23 )
24{
25 EFI_STATUS Status;
26 EFI_SHELL_FILE_INFO *Node;
27 CHAR16 *DirectoryName;
28 EFI_FILE_SYSTEM_INFO *SysInfo;
29 UINTN SysInfoSize;
30 SHELL_FILE_HANDLE ShellFileHandle;
31 EFI_FILE_PROTOCOL *EfiFpHandle;
32
33 //
34 // Get the first valid handle (directories)
35 //
36 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&TheList->Link)
37 ; !IsNull(&TheList->Link, &Node->Link) && Node->Handle == NULL
38 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&TheList->Link, &Node->Link)
39 );
40
41 if (Node->Handle == NULL) {
42 DirectoryName = GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO *)GetFirstNode(&TheList->Link))->FullName);
43
44 //
45 // We need to open something up to get system information
46 //
47 Status = gEfiShellProtocol->OpenFileByName(
48 DirectoryName,
49 &ShellFileHandle,
50 EFI_FILE_MODE_READ
51 );
52
53 ASSERT_EFI_ERROR(Status);
54 FreePool(DirectoryName);
55
56 //
57 // Get the Volume Info from ShellFileHandle
58 //
59 SysInfo = NULL;
60 SysInfoSize = 0;
61 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle);
62 Status = EfiFpHandle->GetInfo(
63 EfiFpHandle,
64 &gEfiFileSystemInfoGuid,
65 &SysInfoSize,
66 SysInfo
67 );
68
69 if (Status == EFI_BUFFER_TOO_SMALL) {
70 SysInfo = AllocateZeroPool(SysInfoSize);
71 Status = EfiFpHandle->GetInfo(
72 EfiFpHandle,
73 &gEfiFileSystemInfoGuid,
74 &SysInfoSize,
75 SysInfo
76 );
77 }
78
79 ASSERT_EFI_ERROR(Status);
80
81 gEfiShellProtocol->CloseFile(ShellFileHandle);
82 } else {
83 //
84 // Get the Volume Info from Node->Handle
85 //
86 SysInfo = NULL;
87 SysInfoSize = 0;
88 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(Node->Handle);
89 Status = EfiFpHandle->GetInfo(
90 EfiFpHandle,
91 &gEfiFileSystemInfoGuid,
92 &SysInfoSize,
93 SysInfo
94 );
95
96 if (Status == EFI_BUFFER_TOO_SMALL) {
97 SysInfo = AllocateZeroPool(SysInfoSize);
98 Status = EfiFpHandle->GetInfo(
99 EfiFpHandle,
100 &gEfiFileSystemInfoGuid,
101 &SysInfoSize,
102 SysInfo
103 );
104 }
105
106 ASSERT_EFI_ERROR(Status);
107 }
108
109 ShellPrintHiiEx (
110 -1,
111 -1,
112 NULL,
113 STRING_TOKEN (STR_GEN_SFO_HEADER),
114 gShellLevel2HiiHandle,
115 L"ls"
116 );
117 //
118 // print VolumeInfo table
119 //
120 ASSERT(SysInfo != NULL);
121 ShellPrintHiiEx (
122 0,
123 gST->ConOut->Mode->CursorRow,
124 NULL,
125 STRING_TOKEN (STR_LS_SFO_VOLINFO),
126 gShellLevel2HiiHandle,
127 SysInfo->VolumeLabel,
128 SysInfo->VolumeSize,
129 SysInfo->ReadOnly?L"TRUE":L"FALSE",
130 SysInfo->FreeSpace,
131 SysInfo->BlockSize
132 );
133
134 SHELL_FREE_NON_NULL(SysInfo);
135
136 return (Status);
137}
138
139/**
140 print out the info on a single file.
141
142 @param[in] Sfo TRUE if in SFO, false otherwise.
143 @param[in] TheNode the EFI_SHELL_FILE_INFO node to print out information on.
144 @param[in] Files incremented if a file is printed.
145 @param[in] Size incremented by file size.
146 @param[in] Dirs incremented if a directory is printed.
147
148**/
149VOID
150PrintFileInformation(
151 IN CONST BOOLEAN Sfo,
152 IN CONST EFI_SHELL_FILE_INFO *TheNode,
153 IN UINT64 *Files,
154 IN UINT64 *Size,
155 IN UINT64 *Dirs
156 )
157{
158 ASSERT(Files != NULL);
159 ASSERT(Size != NULL);
160 ASSERT(Dirs != NULL);
161 ASSERT(TheNode != NULL);
162
163 if (Sfo) {
164 //
165 // Print the FileInfo Table
166 //
167 ShellPrintHiiEx (
168 0,
169 gST->ConOut->Mode->CursorRow,
170 NULL,
171 STRING_TOKEN (STR_LS_SFO_FILEINFO),
172 gShellLevel2HiiHandle,
173 TheNode->FullName,
174 TheNode->Info->FileSize,
175 TheNode->Info->PhysicalSize,
176 (TheNode->Info->Attribute & EFI_FILE_ARCHIVE) != 0?L"a":L"",
177 (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"d":L"",
178 (TheNode->Info->Attribute & EFI_FILE_HIDDEN) != 0?L"h":L"",
179 (TheNode->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L"r":L"",
180 (TheNode->Info->Attribute & EFI_FILE_SYSTEM) != 0?L"s":L"",
181 TheNode->Info->CreateTime.Hour,
182 TheNode->Info->CreateTime.Minute,
183 TheNode->Info->CreateTime.Second,
184 TheNode->Info->CreateTime.Day,
185 TheNode->Info->CreateTime.Month,
186 TheNode->Info->CreateTime.Year,
187 TheNode->Info->LastAccessTime.Hour,
188 TheNode->Info->LastAccessTime.Minute,
189 TheNode->Info->LastAccessTime.Second,
190 TheNode->Info->LastAccessTime.Day,
191 TheNode->Info->LastAccessTime.Month,
192 TheNode->Info->LastAccessTime.Year,
193 TheNode->Info->ModificationTime.Hour,
194 TheNode->Info->ModificationTime.Minute,
195 TheNode->Info->ModificationTime.Second,
196 TheNode->Info->ModificationTime.Day,
197 TheNode->Info->ModificationTime.Month,
198 TheNode->Info->ModificationTime.Year
199 );
200 } else {
201 //
202 // print this one out...
203 // first print the universal start, next print the type specific name format, last print the CRLF
204 //
205 ShellPrintHiiEx (
206 -1,
207 -1,
208 NULL,
209 STRING_TOKEN (STR_LS_LINE_START_ALL),
210 gShellLevel2HiiHandle,
211 &TheNode->Info->ModificationTime,
212 (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"<DIR>":L"",
213 (TheNode->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L'r':L' ',
214 TheNode->Info->FileSize
215 );
216 if (TheNode->Info->Attribute & EFI_FILE_DIRECTORY) {
217 (*Dirs)++;
218 ShellPrintHiiEx (
219 -1,
220 -1,
221 NULL,
222 STRING_TOKEN (STR_LS_LINE_END_DIR),
223 gShellLevel2HiiHandle,
224 TheNode->FileName
225 );
226 } else {
227 (*Files)++;
228 (*Size) += TheNode->Info->FileSize;
229 if ( (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".nsh", (CHAR16*)&(TheNode->FileName[StrLen (TheNode->FileName) - 4])) == 0)
230 || (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".efi", (CHAR16*)&(TheNode->FileName[StrLen (TheNode->FileName) - 4])) == 0)
231 ){
232 ShellPrintHiiEx (
233 -1,
234 -1,
235 NULL,
236 STRING_TOKEN (STR_LS_LINE_END_EXE),
237 gShellLevel2HiiHandle,
238 TheNode->FileName
239 );
240 } else {
241 ShellPrintHiiEx (
242 -1,
243 -1,
244 NULL,
245 STRING_TOKEN (STR_LS_LINE_END_FILE),
246 gShellLevel2HiiHandle,
247 TheNode->FileName
248 );
249 }
250 }
251 }
252}
253
254/**
255 print out the header when not using standard format output.
256
257 @param[in] Path String with starting path.
258**/
259VOID
260PrintNonSfoHeader(
261 IN CONST CHAR16 *Path
262 )
263{
264 CHAR16 *DirectoryName;
265
266 //
267 // get directory name from path...
268 //
269 DirectoryName = GetFullyQualifiedPath(Path);
270
271 if (DirectoryName != NULL) {
272 //
273 // print header
274 //
275 ShellPrintHiiEx (
276 0,
277 gST->ConOut->Mode->CursorRow,
278 NULL,
279 STRING_TOKEN (STR_LS_HEADER_LINE1),
280 gShellLevel2HiiHandle,
281 DirectoryName
282 );
283
284 SHELL_FREE_NON_NULL(DirectoryName);
285 }
286}
287
288/**
289 print out the footer when not using standard format output.
290
291 @param[in] Files The number of files.
292 @param[in] Size The size of files in bytes.
293 @param[in] Dirs The number of directories.
294**/
295VOID
296PrintNonSfoFooter(
297 IN UINT64 Files,
298 IN UINT64 Size,
299 IN UINT64 Dirs
300 )
301{
302 //
303 // print footer
304 //
305 ShellPrintHiiEx (
306 -1,
307 -1,
308 NULL,
309 STRING_TOKEN (STR_LS_FOOTER_LINE),
310 gShellLevel2HiiHandle,
311 Files,
312 Size,
313 Dirs
314 );
315}
316
317/**
318 Change the file time to local time based on the timezone.
319
320 @param[in] Time The file time.
321 @param[in] LocalTimeZone Local time zone.
322**/
323VOID
324FileTimeToLocalTime (
325 IN EFI_TIME *Time,
326 IN INT16 LocalTimeZone
327 )
328{
329 INTN MinuteDiff;
330 INTN TempMinute;
331 INTN HourNumberOfTempMinute;
332 INTN TempHour;
333 INTN DayNumberOfTempHour;
334 INTN TempDay;
335 INTN MonthNumberOfTempDay;
336 INTN TempMonth;
337 INTN YearNumberOfTempMonth;
338 INTN MonthRecord;
339
340 ASSERT ((Time->TimeZone >= -1440) && (Time->TimeZone <=1440));
341 ASSERT ((LocalTimeZone >= -1440) && (LocalTimeZone <=1440));
342 ASSERT ((Time->Month >= 1) && (Time->Month <= 12));
343
344 if(Time->TimeZone == LocalTimeZone) {
345 //
346 //if the file timezone is equal to the local timezone, there is no need to adjust the file time.
347 //
348 return;
349 }
350
351 if((Time->Year % 4 == 0 && Time->Year / 100 != 0)||(Time->Year % 400 == 0)) {
352 //
353 // Day in February of leap year is 29.
354 //
355 mDayOfMonth[1] = 29;
356 }
357
358 MinuteDiff = Time->TimeZone - LocalTimeZone;
359 TempMinute = Time->Minute + MinuteDiff;
360
361 //
362 // Calculate Time->Minute
363 // TempHour will be used to calculate Time->Hour
364 //
365 HourNumberOfTempMinute = TempMinute / 60;
366 if(TempMinute < 0) {
367 HourNumberOfTempMinute --;
368 }
369 TempHour = Time->Hour + HourNumberOfTempMinute;
370 Time->Minute = (UINT8)(TempMinute - 60 * HourNumberOfTempMinute);
371
372 //
373 // Calculate Time->Hour
374 // TempDay will be used to calculate Time->Day
375 //
376 DayNumberOfTempHour = TempHour / 24 ;
377 if(TempHour < 0){
378 DayNumberOfTempHour--;
379 }
380 TempDay = Time->Day + DayNumberOfTempHour;
381 Time->Hour = (UINT8)(TempHour - 24 * DayNumberOfTempHour);
382
383 //
384 // Calculate Time->Day
385 // TempMonth will be used to calculate Time->Month
386 //
387 MonthNumberOfTempDay = (TempDay - 1) / (INTN)mDayOfMonth[Time->Month - 1];
388 MonthRecord = (INTN)(Time->Month) ;
389 if(TempDay - 1 < 0){
390 MonthNumberOfTempDay -- ;
391 MonthRecord -- ;
392 }
393 TempMonth = Time->Month + MonthNumberOfTempDay;
394 Time->Day = (UINT8)(TempDay - (INTN)mDayOfMonth[(MonthRecord - 1 + 12) % 12] * MonthNumberOfTempDay);
395
396 //
397 // Calculate Time->Month, Time->Year
398 //
399 YearNumberOfTempMonth = (TempMonth - 1) / 12;
400 if(TempMonth - 1 < 0){
401 YearNumberOfTempMonth --;
402 }
403 Time->Month = (UINT8)(TempMonth - 12 * (YearNumberOfTempMonth));
404 Time->Year = (UINT16)(Time->Year + YearNumberOfTempMonth);
405}
406
407/**
408 print out the list of files and directories from the LS command
409
410 @param[in] Rec TRUE to automatically recurse into each found directory
411 FALSE to only list the specified directory.
412 @param[in] Attribs List of required Attribute for display.
413 If 0 then all non-system and non-hidden files will be printed.
414 @param[in] Sfo TRUE to use Standard Format Output, FALSE otherwise
415 @param[in] RootPath String with starting path to search in.
416 @param[in] SearchString String with search string.
417 @param[in] Found Set to TRUE, if anyone were found.
418 @param[in] Count The count of bits enabled in Attribs.
419 @param[in] TimeZone The current time zone offset.
420 @param[in] ListUnfiltered TRUE to request listing the directory contents
421 unfiltered.
422
423 @retval SHELL_SUCCESS the printing was sucessful.
424**/
425SHELL_STATUS
426PrintLsOutput(
427 IN CONST BOOLEAN Rec,
428 IN CONST UINT64 Attribs,
429 IN CONST BOOLEAN Sfo,
430 IN CONST CHAR16 *RootPath,
431 IN CONST CHAR16 *SearchString,
432 IN BOOLEAN *Found,
433 IN CONST UINTN Count,
434 IN CONST INT16 TimeZone,
435 IN CONST BOOLEAN ListUnfiltered
436 )
437{
438 EFI_STATUS Status;
439 EFI_SHELL_FILE_INFO *ListHead;
440 EFI_SHELL_FILE_INFO *Node;
441 SHELL_STATUS ShellStatus;
442 UINT64 FileCount;
443 UINT64 DirCount;
444 UINT64 FileSize;
445 UINTN LongestPath;
446 CHAR16 *CorrectedPath;
447 BOOLEAN FoundOne;
448 BOOLEAN HeaderPrinted;
449 EFI_TIME LocalTime;
450
451 HeaderPrinted = FALSE;
452 FileCount = 0;
453 DirCount = 0;
454 FileSize = 0;
455 ListHead = NULL;
456 ShellStatus = SHELL_SUCCESS;
457 LongestPath = 0;
458 CorrectedPath = NULL;
459
460 if (Found != NULL) {
461 FoundOne = *Found;
462 } else {
463 FoundOne = FALSE;
464 }
465
466 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0);
467 if (CorrectedPath == NULL) {
468 return SHELL_OUT_OF_RESOURCES;
469 }
470 if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\'
471 &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') {
472 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\", 0);
473 }
474 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, SearchString, 0);
475 if (CorrectedPath == NULL) {
476 return (SHELL_OUT_OF_RESOURCES);
477 }
478
479 PathCleanUpDirectories(CorrectedPath);
480
481 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
482 if (!EFI_ERROR(Status)) {
483 if (ListHead == NULL || IsListEmpty(&ListHead->Link)) {
484 SHELL_FREE_NON_NULL(CorrectedPath);
485 return (SHELL_SUCCESS);
486 }
487
488 if (Sfo && Found == NULL) {
489 PrintSfoVolumeInfoTableEntry(ListHead);
490 }
491
492 if (!Sfo) {
493 //
494 // Sort the file list by FileName, stably.
495 //
496 // If the call below fails, then the EFI_SHELL_FILE_INFO list anchored to
497 // ListHead will not be changed in any way.
498 //
499 ShellSortFileList (
500 &ListHead,
501 NULL, // Duplicates
502 ShellSortFileListByFileName
503 );
504 }
505
506 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link), LongestPath = 0
507 ; !IsNull(&ListHead->Link, &Node->Link)
508 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
509 ){
510 if (ShellGetExecutionBreakFlag ()) {
511 ShellStatus = SHELL_ABORTED;
512 break;
513 }
514 ASSERT(Node != NULL);
515
516 //
517 // Change the file time to local time.
518 //
519 Status = gRT->GetTime(&LocalTime, NULL);
520 if (!EFI_ERROR (Status) && (LocalTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE)) {
521 if ((Node->Info->CreateTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) &&
522 (Node->Info->CreateTime.Month >= 1 && Node->Info->CreateTime.Month <= 12)) {
523 //
524 // FileTimeToLocalTime () requires Month is in a valid range, other buffer out-of-band access happens.
525 //
526 FileTimeToLocalTime (&Node->Info->CreateTime, LocalTime.TimeZone);
527 }
528 if ((Node->Info->LastAccessTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) &&
529 (Node->Info->LastAccessTime.Month >= 1 && Node->Info->LastAccessTime.Month <= 12)) {
530 FileTimeToLocalTime (&Node->Info->LastAccessTime, LocalTime.TimeZone);
531 }
532 if ((Node->Info->ModificationTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) &&
533 (Node->Info->ModificationTime.Month >= 1 && Node->Info->ModificationTime.Month <= 12)) {
534 FileTimeToLocalTime (&Node->Info->ModificationTime, LocalTime.TimeZone);
535 }
536 }
537
538 if (LongestPath < StrSize(Node->FullName)) {
539 LongestPath = StrSize(Node->FullName);
540 }
541 ASSERT(Node->Info != NULL);
542 ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute);
543 if (Attribs == 0) {
544 //
545 // NOT system & NOT hidden
546 //
547 if ( (Node->Info->Attribute & EFI_FILE_SYSTEM)
548 || (Node->Info->Attribute & EFI_FILE_HIDDEN)
549 ){
550 continue;
551 }
552 } else if ((Attribs != EFI_FILE_VALID_ATTR) ||
553 (Count == 5)) {
554 //
555 // Only matches the bits which "Attribs" contains, not
556 // all files/directories with any of the bits.
557 // Count == 5 is used to tell the difference between a user
558 // specifying all bits (EX: -arhsda) and just specifying
559 // -a (means display all files with any attribute).
560 //
561 if ( (Node->Info->Attribute & Attribs) != Attribs) {
562 continue;
563 }
564 }
565
566 if (!Sfo && !HeaderPrinted) {
567 PathRemoveLastItem (CorrectedPath);
568 PrintNonSfoHeader(CorrectedPath);
569 }
570 PrintFileInformation(Sfo, Node, &FileCount, &FileSize, &DirCount);
571 FoundOne = TRUE;
572 HeaderPrinted = TRUE;
573 }
574
575 if (!Sfo && ShellStatus != SHELL_ABORTED && HeaderPrinted) {
576 PrintNonSfoFooter(FileCount, FileSize, DirCount);
577 }
578 }
579
580 if (Rec && ShellStatus != SHELL_ABORTED) {
581 //
582 // Re-Open all the files under the starting path for directories that didnt necessarily match our file filter
583 //
584 ShellCloseFileMetaArg(&ListHead);
585 CorrectedPath[0] = CHAR_NULL;
586 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0);
587 if (CorrectedPath == NULL) {
588 return SHELL_OUT_OF_RESOURCES;
589 }
590 if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\'
591 &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') {
592 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\", 0);
593 }
594 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"*", 0);
595 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
596
597 if (!EFI_ERROR(Status)) {
598 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
599 ; !IsNull(&ListHead->Link, &Node->Link) && ShellStatus == SHELL_SUCCESS
600 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
601 ){
602 if (ShellGetExecutionBreakFlag ()) {
603 ShellStatus = SHELL_ABORTED;
604 break;
605 }
606
607 //
608 // recurse on any directory except the traversing ones...
609 //
610 if (((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY)
611 && StrCmp(Node->FileName, L".") != 0
612 && StrCmp(Node->FileName, L"..") != 0
613 ){
614 ShellStatus = PrintLsOutput(
615 Rec,
616 Attribs,
617 Sfo,
618 Node->FullName,
619 SearchString,
620 &FoundOne,
621 Count,
622 TimeZone,
623 FALSE);
624
625 //
626 // Since it's running recursively, we have to break immediately when returned SHELL_ABORTED
627 //
628 if (ShellStatus == SHELL_ABORTED) {
629 break;
630 }
631 }
632 }
633 }
634 }
635
636 SHELL_FREE_NON_NULL(CorrectedPath);
637 ShellCloseFileMetaArg(&ListHead);
638
639 if (Found == NULL && !FoundOne) {
640 if (ListUnfiltered) {
641 //
642 // When running "ls" without any filtering request, avoid outputing
643 // "File not found" when the directory is entirely empty, but print
644 // header and footer stating "0 File(s), 0 Dir(s)".
645 //
646 if (!Sfo) {
647 PrintNonSfoHeader (RootPath);
648 if (ShellStatus != SHELL_ABORTED) {
649 PrintNonSfoFooter (FileCount, FileSize, DirCount);
650 }
651 }
652 } else {
653 return (SHELL_NOT_FOUND);
654 }
655 }
656
657 if (Found != NULL) {
658 *Found = FoundOne;
659 }
660
661 return (ShellStatus);
662}
663
664STATIC CONST SHELL_PARAM_ITEM LsParamList[] = {
665 {L"-r", TypeFlag},
666 {L"-a", TypeStart},
667 {L"-sfo", TypeFlag},
668 {NULL, TypeMax}
669 };
670
671/**
672 Function for 'ls' command.
673
674 @param[in] ImageHandle Handle to the Image (NULL if Internal).
675 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
676**/
677SHELL_STATUS
678EFIAPI
679ShellCommandRunLs (
680 IN EFI_HANDLE ImageHandle,
681 IN EFI_SYSTEM_TABLE *SystemTable
682 )
683{
684 EFI_STATUS Status;
685 LIST_ENTRY *Package;
686 CHAR16 *ProblemParam;
687 CONST CHAR16 *Attribs;
688 SHELL_STATUS ShellStatus;
689 UINT64 RequiredAttributes;
690 CONST CHAR16 *PathName;
691 CONST CHAR16 *CurDir;
692 UINTN Count;
693 CHAR16 *FullPath;
694 UINTN Size;
695 EFI_TIME TheTime;
696 CHAR16 *SearchString;
697 BOOLEAN ListUnfiltered;
698
699 Size = 0;
700 FullPath = NULL;
701 ProblemParam = NULL;
702 Attribs = NULL;
703 ShellStatus = SHELL_SUCCESS;
704 RequiredAttributes = 0;
705 PathName = NULL;
706 SearchString = NULL;
707 CurDir = NULL;
708 Count = 0;
709 ListUnfiltered = FALSE;
710
711 //
712 // initialize the shell lib (we must be in non-auto-init...)
713 //
714 Status = ShellInitialize();
715 ASSERT_EFI_ERROR(Status);
716
717 //
718 // Fix local copies of the protocol pointers
719 //
720 Status = CommandInit();
721 ASSERT_EFI_ERROR(Status);
722
723 //
724 // parse the command line
725 //
726 Status = ShellCommandLineParse (LsParamList, &Package, &ProblemParam, TRUE);
727 if (EFI_ERROR(Status)) {
728 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
729 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"ls", ProblemParam);
730 FreePool(ProblemParam);
731 ShellStatus = SHELL_INVALID_PARAMETER;
732 } else {
733 ASSERT(FALSE);
734 }
735 } else {
736 //
737 // check for "-?"
738 //
739 if (ShellCommandLineGetFlag(Package, L"-?")) {
740 ASSERT(FALSE);
741 }
742
743 if (ShellCommandLineGetCount(Package) > 2) {
744 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"ls");
745 ShellStatus = SHELL_INVALID_PARAMETER;
746 } else {
747 //
748 // check for -a
749 //
750 if (ShellCommandLineGetFlag(Package, L"-a")) {
751 for ( Attribs = ShellCommandLineGetValue(Package, L"-a")
752 ; Attribs != NULL && *Attribs != CHAR_NULL && ShellStatus == SHELL_SUCCESS
753 ; Attribs++
754 ){
755 switch (*Attribs) {
756 case L'a':
757 case L'A':
758 RequiredAttributes |= EFI_FILE_ARCHIVE;
759 Count++;
760 continue;
761 case L's':
762 case L'S':
763 RequiredAttributes |= EFI_FILE_SYSTEM;
764 Count++;
765 continue;
766 case L'h':
767 case L'H':
768 RequiredAttributes |= EFI_FILE_HIDDEN;
769 Count++;
770 continue;
771 case L'r':
772 case L'R':
773 RequiredAttributes |= EFI_FILE_READ_ONLY;
774 Count++;
775 continue;
776 case L'd':
777 case L'D':
778 RequiredAttributes |= EFI_FILE_DIRECTORY;
779 Count++;
780 continue;
781 default:
782 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ATTRIBUTE), gShellLevel2HiiHandle, L"ls", ShellCommandLineGetValue(Package, L"-a"));
783 ShellStatus = SHELL_INVALID_PARAMETER;
784 break;
785 } // switch
786 } // for loop
787 //
788 // if nothing is specified all are specified
789 //
790 if (RequiredAttributes == 0) {
791 RequiredAttributes = EFI_FILE_VALID_ATTR;
792 }
793 } // if -a present
794 if (ShellStatus == SHELL_SUCCESS) {
795 PathName = ShellCommandLineGetRawValue(Package, 1);
796 if (PathName == NULL) {
797 //
798 // Nothing specified... must start from current directory
799 //
800 CurDir = gEfiShellProtocol->GetCurDir(NULL);
801 if (CurDir == NULL) {
802 ShellStatus = SHELL_NOT_FOUND;
803 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls");
804 }
805 ListUnfiltered = TRUE;
806 //
807 // Copy to the 2 strings for starting path and file search string
808 //
809 ASSERT(SearchString == NULL);
810 ASSERT(FullPath == NULL);
811 StrnCatGrow(&SearchString, NULL, L"*", 0);
812 StrnCatGrow(&FullPath, NULL, CurDir, 0);
813 Size = FullPath != NULL? StrSize(FullPath) : 0;
814 StrnCatGrow(&FullPath, &Size, L"\\", 0);
815 } else {
816 if (StrStr(PathName, L":") == NULL && gEfiShellProtocol->GetCurDir(NULL) == NULL) {
817 //
818 // If we got something and it doesnt have a fully qualified path, then we needed to have a CWD.
819 //
820 ShellStatus = SHELL_NOT_FOUND;
821 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls");
822 } else {
823 //
824 // We got a valid fully qualified path or we have a CWD
825 //
826 ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL));
827 if (StrStr(PathName, L":") == NULL) {
828 StrnCatGrow(&FullPath, &Size, gEfiShellProtocol->GetCurDir(NULL), 0);
829 if (FullPath == NULL) {
830 ShellCommandLineFreeVarList (Package);
831 return SHELL_OUT_OF_RESOURCES;
832 }
833 Size = FullPath != NULL? StrSize(FullPath) : 0;
834 StrnCatGrow(&FullPath, &Size, L"\\", 0);
835 }
836 StrnCatGrow(&FullPath, &Size, PathName, 0);
837 if (FullPath == NULL) {
838 ShellCommandLineFreeVarList (Package);
839 return SHELL_OUT_OF_RESOURCES;
840 }
841
842 if (ShellIsDirectory(PathName) == EFI_SUCCESS) {
843 //
844 // is listing ends with a directory, then we list all files in that directory
845 //
846 ListUnfiltered = TRUE;
847 StrnCatGrow(&SearchString, NULL, L"*", 0);
848 } else {
849 //
850 // must split off the search part that applies to files from the end of the directory part
851 //
852 StrnCatGrow(&SearchString, NULL, FullPath, 0);
853 if (SearchString == NULL) {
854 FreePool (FullPath);
855 ShellCommandLineFreeVarList (Package);
856 return SHELL_OUT_OF_RESOURCES;
857 }
858 PathRemoveLastItem (FullPath);
859 CopyMem (SearchString, SearchString + StrLen (FullPath), StrSize (SearchString + StrLen (FullPath)));
860 }
861 }
862 }
863 Status = gRT->GetTime(&TheTime, NULL);
864 if (EFI_ERROR(Status)) {
865 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"ls", L"gRT->GetTime", Status);
866 TheTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
867 }
868
869 if (ShellStatus == SHELL_SUCCESS) {
870 ShellStatus = PrintLsOutput(
871 ShellCommandLineGetFlag(Package, L"-r"),
872 RequiredAttributes,
873 ShellCommandLineGetFlag(Package, L"-sfo"),
874 FullPath,
875 SearchString,
876 NULL,
877 Count,
878 TheTime.TimeZone,
879 ListUnfiltered
880 );
881 if (ShellStatus == SHELL_NOT_FOUND) {
882 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LS_FILE_NOT_FOUND), gShellLevel2HiiHandle, L"ls", FullPath);
883 } else if (ShellStatus == SHELL_INVALID_PARAMETER) {
884 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"ls", FullPath);
885 } else if (ShellStatus == SHELL_ABORTED) {
886 //
887 // Ignore aborting.
888 //
889 } else if (ShellStatus != SHELL_SUCCESS) {
890 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"ls", FullPath);
891 }
892 }
893 }
894 }
895 }
896
897 //
898 // Free memory allocated
899 //
900 SHELL_FREE_NON_NULL(SearchString);
901 SHELL_FREE_NON_NULL(FullPath);
902 ShellCommandLineFreeVarList (Package);
903
904 return (ShellStatus);
905}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette