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