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