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