]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
adeb987e6ecba93fd65d414bb301c73814b76467
[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 - 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
13 UINTN 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 **/
20 EFI_STATUS
21 PrintSfoVolumeInfoTableEntry(
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 **/
149 VOID
150 PrintFileInformation(
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 **/
259 VOID
260 PrintNonSfoHeader(
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 **/
295 VOID
296 PrintNonSfoFooter(
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 **/
323 VOID
324 FileTimeToLocalTime (
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
421 @retval SHELL_SUCCESS the printing was sucessful.
422 **/
423 SHELL_STATUS
424 PrintLsOutput(
425 IN CONST BOOLEAN Rec,
426 IN CONST UINT64 Attribs,
427 IN CONST BOOLEAN Sfo,
428 IN CONST CHAR16 *RootPath,
429 IN CONST CHAR16 *SearchString,
430 IN BOOLEAN *Found,
431 IN CONST UINTN Count,
432 IN CONST INT16 TimeZone
433 )
434 {
435 EFI_STATUS Status;
436 EFI_SHELL_FILE_INFO *ListHead;
437 EFI_SHELL_FILE_INFO *Node;
438 SHELL_STATUS ShellStatus;
439 UINT64 FileCount;
440 UINT64 DirCount;
441 UINT64 FileSize;
442 UINTN LongestPath;
443 CHAR16 *CorrectedPath;
444 BOOLEAN FoundOne;
445 BOOLEAN HeaderPrinted;
446 EFI_TIME LocalTime;
447
448 HeaderPrinted = FALSE;
449 FileCount = 0;
450 DirCount = 0;
451 FileSize = 0;
452 ListHead = NULL;
453 ShellStatus = SHELL_SUCCESS;
454 LongestPath = 0;
455 CorrectedPath = NULL;
456
457 if (Found != NULL) {
458 FoundOne = *Found;
459 } else {
460 FoundOne = FALSE;
461 }
462
463 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0);
464 if (CorrectedPath == NULL) {
465 return SHELL_OUT_OF_RESOURCES;
466 }
467 if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\'
468 &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') {
469 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\", 0);
470 }
471 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, SearchString, 0);
472 if (CorrectedPath == NULL) {
473 return (SHELL_OUT_OF_RESOURCES);
474 }
475
476 PathCleanUpDirectories(CorrectedPath);
477
478 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
479 if (!EFI_ERROR(Status)) {
480 if (ListHead == NULL || IsListEmpty(&ListHead->Link)) {
481 SHELL_FREE_NON_NULL(CorrectedPath);
482 return (SHELL_SUCCESS);
483 }
484
485 if (Sfo && Found == NULL) {
486 PrintSfoVolumeInfoTableEntry(ListHead);
487 }
488
489 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link), LongestPath = 0
490 ; !IsNull(&ListHead->Link, &Node->Link)
491 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
492 ){
493 if (ShellGetExecutionBreakFlag ()) {
494 ShellStatus = SHELL_ABORTED;
495 break;
496 }
497 ASSERT(Node != NULL);
498
499 //
500 // Change the file time to local time.
501 //
502 Status = gRT->GetTime(&LocalTime, NULL);
503 if (!EFI_ERROR (Status)) {
504 if ((Node->Info->CreateTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) &&
505 (Node->Info->CreateTime.Month >= 1 && Node->Info->CreateTime.Month <= 12)) {
506 //
507 // FileTimeToLocalTime () requires Month is in a valid range, other buffer out-of-band access happens.
508 //
509 FileTimeToLocalTime (&Node->Info->CreateTime, LocalTime.TimeZone);
510 }
511 if ((Node->Info->LastAccessTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) &&
512 (Node->Info->LastAccessTime.Month >= 1 && Node->Info->LastAccessTime.Month <= 12)) {
513 FileTimeToLocalTime (&Node->Info->LastAccessTime, LocalTime.TimeZone);
514 }
515 if ((Node->Info->ModificationTime.TimeZone != EFI_UNSPECIFIED_TIMEZONE) &&
516 (Node->Info->ModificationTime.Month >= 1 && Node->Info->ModificationTime.Month <= 12)) {
517 FileTimeToLocalTime (&Node->Info->ModificationTime, LocalTime.TimeZone);
518 }
519 }
520
521 if (LongestPath < StrSize(Node->FullName)) {
522 LongestPath = StrSize(Node->FullName);
523 }
524 ASSERT(Node->Info != NULL);
525 ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute);
526 if (Attribs == 0) {
527 //
528 // NOT system & NOT hidden
529 //
530 if ( (Node->Info->Attribute & EFI_FILE_SYSTEM)
531 || (Node->Info->Attribute & EFI_FILE_HIDDEN)
532 ){
533 continue;
534 }
535 } else if ((Attribs != EFI_FILE_VALID_ATTR) ||
536 (Count == 5)) {
537 //
538 // Only matches the bits which "Attribs" contains, not
539 // all files/directories with any of the bits.
540 // Count == 5 is used to tell the difference between a user
541 // specifying all bits (EX: -arhsda) and just specifying
542 // -a (means display all files with any attribute).
543 //
544 if ( (Node->Info->Attribute & Attribs) != Attribs) {
545 continue;
546 }
547 }
548
549 if (!Sfo && !HeaderPrinted) {
550 PathRemoveLastItem (CorrectedPath);
551 PrintNonSfoHeader(CorrectedPath);
552 }
553 PrintFileInformation(Sfo, Node, &FileCount, &FileSize, &DirCount);
554 FoundOne = TRUE;
555 HeaderPrinted = TRUE;
556 }
557
558 if (!Sfo && ShellStatus != SHELL_ABORTED) {
559 PrintNonSfoFooter(FileCount, FileSize, DirCount);
560 }
561 }
562
563 if (Rec && ShellStatus != SHELL_ABORTED) {
564 //
565 // Re-Open all the files under the starting path for directories that didnt necessarily match our file filter
566 //
567 ShellCloseFileMetaArg(&ListHead);
568 CorrectedPath[0] = CHAR_NULL;
569 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, RootPath, 0);
570 if (CorrectedPath == NULL) {
571 return SHELL_OUT_OF_RESOURCES;
572 }
573 if (CorrectedPath[StrLen(CorrectedPath)-1] != L'\\'
574 &&CorrectedPath[StrLen(CorrectedPath)-1] != L'/') {
575 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"\\", 0);
576 }
577 CorrectedPath = StrnCatGrow(&CorrectedPath, &LongestPath, L"*", 0);
578 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
579
580 if (!EFI_ERROR(Status)) {
581 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
582 ; !IsNull(&ListHead->Link, &Node->Link) && ShellStatus == SHELL_SUCCESS
583 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
584 ){
585 if (ShellGetExecutionBreakFlag ()) {
586 ShellStatus = SHELL_ABORTED;
587 break;
588 }
589
590 //
591 // recurse on any directory except the traversing ones...
592 //
593 if (((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY)
594 && StrCmp(Node->FileName, L".") != 0
595 && StrCmp(Node->FileName, L"..") != 0
596 ){
597 ShellStatus = PrintLsOutput(
598 Rec,
599 Attribs,
600 Sfo,
601 Node->FullName,
602 SearchString,
603 &FoundOne,
604 Count,
605 TimeZone);
606
607 //
608 // Since it's running recursively, we have to break immediately when returned SHELL_ABORTED
609 //
610 if (ShellStatus == SHELL_ABORTED) {
611 break;
612 }
613 }
614 }
615 }
616 }
617
618 SHELL_FREE_NON_NULL(CorrectedPath);
619 ShellCloseFileMetaArg(&ListHead);
620
621 if (Found == NULL && !FoundOne) {
622 return (SHELL_NOT_FOUND);
623 }
624
625 if (Found != NULL) {
626 *Found = FoundOne;
627 }
628
629 return (ShellStatus);
630 }
631
632 STATIC CONST SHELL_PARAM_ITEM LsParamList[] = {
633 {L"-r", TypeFlag},
634 {L"-a", TypeStart},
635 {L"-sfo", TypeFlag},
636 {NULL, TypeMax}
637 };
638
639 /**
640 Function for 'ls' command.
641
642 @param[in] ImageHandle Handle to the Image (NULL if Internal).
643 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
644 **/
645 SHELL_STATUS
646 EFIAPI
647 ShellCommandRunLs (
648 IN EFI_HANDLE ImageHandle,
649 IN EFI_SYSTEM_TABLE *SystemTable
650 )
651 {
652 EFI_STATUS Status;
653 LIST_ENTRY *Package;
654 CHAR16 *ProblemParam;
655 CONST CHAR16 *Attribs;
656 SHELL_STATUS ShellStatus;
657 UINT64 RequiredAttributes;
658 CONST CHAR16 *PathName;
659 CONST CHAR16 *CurDir;
660 UINTN Count;
661 CHAR16 *FullPath;
662 UINTN Size;
663 EFI_TIME TheTime;
664 CHAR16 *SearchString;
665
666 Size = 0;
667 FullPath = NULL;
668 ProblemParam = NULL;
669 Attribs = NULL;
670 ShellStatus = SHELL_SUCCESS;
671 RequiredAttributes = 0;
672 PathName = NULL;
673 SearchString = NULL;
674 CurDir = NULL;
675 Count = 0;
676
677 //
678 // initialize the shell lib (we must be in non-auto-init...)
679 //
680 Status = ShellInitialize();
681 ASSERT_EFI_ERROR(Status);
682
683 //
684 // Fix local copies of the protocol pointers
685 //
686 Status = CommandInit();
687 ASSERT_EFI_ERROR(Status);
688
689 //
690 // parse the command line
691 //
692 Status = ShellCommandLineParse (LsParamList, &Package, &ProblemParam, TRUE);
693 if (EFI_ERROR(Status)) {
694 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
695 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, L"ls", ProblemParam);
696 FreePool(ProblemParam);
697 ShellStatus = SHELL_INVALID_PARAMETER;
698 } else {
699 ASSERT(FALSE);
700 }
701 } else {
702 //
703 // check for "-?"
704 //
705 if (ShellCommandLineGetFlag(Package, L"-?")) {
706 ASSERT(FALSE);
707 }
708
709 if (ShellCommandLineGetCount(Package) > 2) {
710 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle, L"ls");
711 ShellStatus = SHELL_INVALID_PARAMETER;
712 } else {
713 //
714 // check for -a
715 //
716 if (ShellCommandLineGetFlag(Package, L"-a")) {
717 for ( Attribs = ShellCommandLineGetValue(Package, L"-a")
718 ; Attribs != NULL && *Attribs != CHAR_NULL && ShellStatus == SHELL_SUCCESS
719 ; Attribs++
720 ){
721 switch (*Attribs) {
722 case L'a':
723 case L'A':
724 RequiredAttributes |= EFI_FILE_ARCHIVE;
725 Count++;
726 continue;
727 case L's':
728 case L'S':
729 RequiredAttributes |= EFI_FILE_SYSTEM;
730 Count++;
731 continue;
732 case L'h':
733 case L'H':
734 RequiredAttributes |= EFI_FILE_HIDDEN;
735 Count++;
736 continue;
737 case L'r':
738 case L'R':
739 RequiredAttributes |= EFI_FILE_READ_ONLY;
740 Count++;
741 continue;
742 case L'd':
743 case L'D':
744 RequiredAttributes |= EFI_FILE_DIRECTORY;
745 Count++;
746 continue;
747 default:
748 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ATTRIBUTE), gShellLevel2HiiHandle, L"ls", ShellCommandLineGetValue(Package, L"-a"));
749 ShellStatus = SHELL_INVALID_PARAMETER;
750 break;
751 } // switch
752 } // for loop
753 //
754 // if nothing is specified all are specified
755 //
756 if (RequiredAttributes == 0) {
757 RequiredAttributes = EFI_FILE_VALID_ATTR;
758 }
759 } // if -a present
760 if (ShellStatus == SHELL_SUCCESS) {
761 PathName = ShellCommandLineGetRawValue(Package, 1);
762 if (PathName == NULL) {
763 //
764 // Nothing specified... must start from current directory
765 //
766 CurDir = gEfiShellProtocol->GetCurDir(NULL);
767 if (CurDir == NULL) {
768 ShellStatus = SHELL_NOT_FOUND;
769 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls");
770 }
771 //
772 // Copy to the 2 strings for starting path and file search string
773 //
774 ASSERT(SearchString == NULL);
775 ASSERT(FullPath == NULL);
776 StrnCatGrow(&SearchString, NULL, L"*", 0);
777 StrnCatGrow(&FullPath, NULL, CurDir, 0);
778 Size = FullPath != NULL? StrSize(FullPath) : 0;
779 StrnCatGrow(&FullPath, &Size, L"\\", 0);
780 } else {
781 if (StrStr(PathName, L":") == NULL && gEfiShellProtocol->GetCurDir(NULL) == NULL) {
782 //
783 // If we got something and it doesnt have a fully qualified path, then we needed to have a CWD.
784 //
785 ShellStatus = SHELL_NOT_FOUND;
786 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle, L"ls");
787 } else {
788 //
789 // We got a valid fully qualified path or we have a CWD
790 //
791 ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL));
792 if (StrStr(PathName, L":") == NULL) {
793 StrnCatGrow(&FullPath, &Size, gEfiShellProtocol->GetCurDir(NULL), 0);
794 if (FullPath == NULL) {
795 ShellCommandLineFreeVarList (Package);
796 return SHELL_OUT_OF_RESOURCES;
797 }
798 Size = FullPath != NULL? StrSize(FullPath) : 0;
799 StrnCatGrow(&FullPath, &Size, L"\\", 0);
800 }
801 StrnCatGrow(&FullPath, &Size, PathName, 0);
802 if (FullPath == NULL) {
803 ShellCommandLineFreeVarList (Package);
804 return SHELL_OUT_OF_RESOURCES;
805 }
806
807 if (ShellIsDirectory(PathName) == EFI_SUCCESS) {
808 //
809 // is listing ends with a directory, then we list all files in that directory
810 //
811 StrnCatGrow(&SearchString, NULL, L"*", 0);
812 } else {
813 //
814 // must split off the search part that applies to files from the end of the directory part
815 //
816 StrnCatGrow(&SearchString, NULL, FullPath, 0);
817 if (SearchString == NULL) {
818 FreePool (FullPath);
819 ShellCommandLineFreeVarList (Package);
820 return SHELL_OUT_OF_RESOURCES;
821 }
822 PathRemoveLastItem (FullPath);
823 CopyMem (SearchString, SearchString + StrLen (FullPath), StrSize (SearchString + StrLen (FullPath)));
824 }
825 }
826 }
827 Status = gRT->GetTime(&TheTime, NULL);
828 if (EFI_ERROR(Status)) {
829 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"ls", L"gRT->GetTime", Status);
830 TheTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
831 }
832
833 if (ShellStatus == SHELL_SUCCESS) {
834 ShellStatus = PrintLsOutput(
835 ShellCommandLineGetFlag(Package, L"-r"),
836 RequiredAttributes,
837 ShellCommandLineGetFlag(Package, L"-sfo"),
838 FullPath,
839 SearchString,
840 NULL,
841 Count,
842 TheTime.TimeZone
843 );
844 if (ShellStatus == SHELL_NOT_FOUND) {
845 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_LS_FILE_NOT_FOUND), gShellLevel2HiiHandle, L"ls", FullPath);
846 } else if (ShellStatus == SHELL_INVALID_PARAMETER) {
847 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"ls", FullPath);
848 } else if (ShellStatus == SHELL_ABORTED) {
849 //
850 // Ignore aborting.
851 //
852 } else if (ShellStatus != SHELL_SUCCESS) {
853 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle, L"ls", FullPath);
854 }
855 }
856 }
857 }
858 }
859
860 //
861 // Free memory allocated
862 //
863 SHELL_FREE_NON_NULL(SearchString);
864 SHELL_FREE_NON_NULL(FullPath);
865 ShellCommandLineFreeVarList (Package);
866
867 return (ShellStatus);
868 }