]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
55267a467a02ee42cca9398c228d83d26e7d9c1d
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Ls.c
1 /** @file
2 Main file for ls shell level 2 function.
3
4 Copyright (c) 2009 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "UefiShellLevel2CommandsLib.h"
16 #include <Guid/FileSystemInfo.h>
17
18 /**
19 print out the list of files and directories from the LS command
20
21 @param[in] Rec TRUE to automatically recurse into each found directory
22 FALSE to only list the specified directory.
23 @param[in] Attribs List of required Attribute for display.
24 If 0 then all non-system and non-hidden files will be printed.
25 @param[in] Sfo TRUE to use Standard Format Output, FALSE otherwise
26 @param[in] Path String with starting path.
27 @param[in] First TRUE for the original and FALSE for any recursion spawned instances.
28 @param[in] Count The count of bits enabled in Attribs.
29 @param[in] TimeZone The current time zone offset.
30
31 @retval SHELL_SUCCESS the printing was sucessful.
32 **/
33 SHELL_STATUS
34 EFIAPI
35 PrintLsOutput(
36 IN CONST BOOLEAN Rec,
37 IN CONST UINT64 Attribs,
38 IN CONST BOOLEAN Sfo,
39 IN CONST CHAR16 *Path,
40 IN CONST BOOLEAN First,
41 IN CONST UINTN Count,
42 IN CONST INT16 TimeZone
43 )
44 {
45 EFI_STATUS Status;
46 EFI_SHELL_FILE_INFO *ListHead;
47 EFI_SHELL_FILE_INFO *Node;
48 SHELL_STATUS ShellStatus;
49 UINT64 FileCount;
50 UINT64 DirCount;
51 UINT64 FileSize;
52 CHAR16 *DirectoryName;
53 UINTN LongestPath;
54 EFI_FILE_SYSTEM_INFO *SysInfo;
55 UINTN SysInfoSize;
56 SHELL_FILE_HANDLE ShellFileHandle;
57 CHAR16 *CorrectedPath;
58 EFI_FILE_PROTOCOL *EfiFpHandle;
59
60 FileCount = 0;
61 DirCount = 0;
62 FileSize = 0;
63 ListHead = NULL;
64 ShellStatus = SHELL_SUCCESS;
65 LongestPath = 0;
66 CorrectedPath = NULL;
67
68 CorrectedPath = StrnCatGrow(&CorrectedPath, NULL, Path, 0);
69 if (CorrectedPath == NULL) {
70 return (SHELL_OUT_OF_RESOURCES);
71 }
72
73 PathCleanUpDirectories(CorrectedPath);
74
75 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
76 if (EFI_ERROR(Status)) {
77 SHELL_FREE_NON_NULL(CorrectedPath);
78 if(Status == EFI_NOT_FOUND){
79 return (SHELL_NOT_FOUND);
80 }
81 return (SHELL_DEVICE_ERROR);
82 }
83 if (ListHead == NULL || IsListEmpty(&ListHead->Link)) {
84 SHELL_FREE_NON_NULL(CorrectedPath);
85 //
86 // On the first one only we expect to find something...
87 // do we find the . and .. directories otherwise?
88 //
89 if (First) {
90 return (SHELL_NOT_FOUND);
91 }
92 return (SHELL_SUCCESS);
93 }
94
95 if (Sfo && First) {
96 //
97 // Get the first valid handle (directories)
98 //
99 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
100 ; !IsNull(&ListHead->Link, &Node->Link) && Node->Handle == NULL
101 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
102 );
103
104 if (Node->Handle == NULL) {
105 DirectoryName = GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link))->FullName);
106
107 //
108 // We need to open something up to get system information
109 //
110 Status = gEfiShellProtocol->OpenFileByName(
111 DirectoryName,
112 &ShellFileHandle,
113 EFI_FILE_MODE_READ);
114
115 ASSERT_EFI_ERROR(Status);
116 FreePool(DirectoryName);
117
118 //
119 // Get the Volume Info from ShellFileHandle
120 //
121 SysInfo = NULL;
122 SysInfoSize = 0;
123 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle);
124 Status = EfiFpHandle->GetInfo(
125 EfiFpHandle,
126 &gEfiFileSystemInfoGuid,
127 &SysInfoSize,
128 SysInfo);
129
130 if (Status == EFI_BUFFER_TOO_SMALL) {
131 SysInfo = AllocateZeroPool(SysInfoSize);
132 Status = EfiFpHandle->GetInfo(
133 EfiFpHandle,
134 &gEfiFileSystemInfoGuid,
135 &SysInfoSize,
136 SysInfo);
137 }
138
139 ASSERT_EFI_ERROR(Status);
140
141 gEfiShellProtocol->CloseFile(ShellFileHandle);
142 } else {
143 //
144 // Get the Volume Info from Node->Handle
145 //
146 SysInfo = NULL;
147 SysInfoSize = 0;
148 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(Node->Handle);
149 Status = EfiFpHandle->GetInfo(
150 EfiFpHandle,
151 &gEfiFileSystemInfoGuid,
152 &SysInfoSize,
153 SysInfo);
154
155 if (Status == EFI_BUFFER_TOO_SMALL) {
156 SysInfo = AllocateZeroPool(SysInfoSize);
157 Status = EfiFpHandle->GetInfo(
158 EfiFpHandle,
159 &gEfiFileSystemInfoGuid,
160 &SysInfoSize,
161 SysInfo);
162 }
163
164 ASSERT_EFI_ERROR(Status);
165 }
166
167 ShellPrintHiiEx (
168 -1,
169 -1,
170 NULL,
171 STRING_TOKEN (STR_GEN_SFO_HEADER),
172 gShellLevel2HiiHandle,
173 L"ls");
174 //
175 // print VolumeInfo table
176 //
177 ASSERT(SysInfo != NULL);
178 ShellPrintHiiEx (
179 0,
180 gST->ConOut->Mode->CursorRow,
181 NULL,
182 STRING_TOKEN (STR_LS_SFO_VOLINFO),
183 gShellLevel2HiiHandle,
184 SysInfo->VolumeLabel,
185 SysInfo->VolumeSize,
186 SysInfo->ReadOnly?L"TRUE":L"FALSE",
187 SysInfo->FreeSpace,
188 SysInfo->BlockSize
189 );
190 if (SysInfo != NULL) {
191 FreePool(SysInfo);
192 }
193 }
194
195 if (!Sfo) {
196 //
197 // get directory name from path...
198 //
199 DirectoryName = GetFullyQualifiedPath(CorrectedPath);
200
201 //
202 // print header
203 //
204 ShellPrintHiiEx (
205 0,
206 gST->ConOut->Mode->CursorRow,
207 NULL,
208 STRING_TOKEN (STR_LS_HEADER_LINE1),
209 gShellLevel2HiiHandle,
210 DirectoryName
211 );
212 FreePool(DirectoryName);
213 }
214 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
215 ; !IsNull(&ListHead->Link, &Node->Link)
216 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
217 ){
218 ASSERT(Node != NULL);
219 if (LongestPath < StrSize(Node->FullName)) {
220 LongestPath = StrSize(Node->FullName);
221 }
222 ASSERT(Node->Info != NULL);
223 ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute);
224 if (Attribs == 0) {
225 //
226 // NOT system & NOT hidden
227 //
228 if ( (Node->Info->Attribute & EFI_FILE_SYSTEM)
229 || (Node->Info->Attribute & EFI_FILE_HIDDEN)
230 ){
231 continue;
232 }
233 } else if (Attribs != EFI_FILE_VALID_ATTR) {
234 if (Count == 1) {
235 //
236 // the bit must match
237 //
238 if ( (Node->Info->Attribute & Attribs) != Attribs) {
239 continue;
240 }
241 } else {
242 //
243 // exact match on all bits
244 //
245 if ( (Node->Info->Attribute|EFI_FILE_ARCHIVE) != (Attribs|EFI_FILE_ARCHIVE)) {
246 continue;
247 }
248 }
249 }
250
251 if (Sfo) {
252 //
253 // Print the FileInfo Table
254 //
255 ShellPrintHiiEx (
256 0,
257 gST->ConOut->Mode->CursorRow,
258 NULL,
259 STRING_TOKEN (STR_LS_SFO_FILEINFO),
260 gShellLevel2HiiHandle,
261 Node->FullName,
262 Node->Info->FileSize,
263 Node->Info->PhysicalSize,
264 (Node->Info->Attribute & EFI_FILE_ARCHIVE) != 0?L"a":L"",
265 (Node->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"d":L"",
266 (Node->Info->Attribute & EFI_FILE_HIDDEN) != 0?L"h":L"",
267 (Node->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L"r":L"",
268 (Node->Info->Attribute & EFI_FILE_SYSTEM) != 0?L"s":L"",
269 Node->Info->CreateTime.Hour,
270 Node->Info->CreateTime.Minute,
271 Node->Info->CreateTime.Second,
272 Node->Info->CreateTime.Day,
273 Node->Info->CreateTime.Month,
274 Node->Info->CreateTime.Year,
275 Node->Info->LastAccessTime.Hour,
276 Node->Info->LastAccessTime.Minute,
277 Node->Info->LastAccessTime.Second,
278 Node->Info->LastAccessTime.Day,
279 Node->Info->LastAccessTime.Month,
280 Node->Info->LastAccessTime.Year,
281 Node->Info->ModificationTime.Hour,
282 Node->Info->ModificationTime.Minute,
283 Node->Info->ModificationTime.Second,
284 Node->Info->ModificationTime.Day,
285 Node->Info->ModificationTime.Month,
286 Node->Info->ModificationTime.Year
287 );
288 } else {
289 //
290 // print this one out...
291 // first print the universal start, next print the type specific name format, last print the CRLF
292 //
293 ShellPrintHiiEx (
294 -1,
295 -1,
296 NULL,
297 STRING_TOKEN (STR_LS_LINE_START_ALL),
298 gShellLevel2HiiHandle,
299 &Node->Info->ModificationTime,
300 (Node->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"<DIR>":L"",
301 (Node->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L'r':L' ',
302 Node->Info->FileSize
303 );
304 if (Node->Info->Attribute & EFI_FILE_DIRECTORY) {
305 DirCount++;
306 ShellPrintHiiEx (
307 -1,
308 -1,
309 NULL,
310 STRING_TOKEN (STR_LS_LINE_END_DIR),
311 gShellLevel2HiiHandle,
312 Node->FileName
313 );
314 } else {
315 FileCount++;
316 FileSize += Node->Info->FileSize;
317 if ( (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".nsh", (CHAR16*)&(Node->FileName[StrLen (Node->FileName) - 4])) == 0)
318 || (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".efi", (CHAR16*)&(Node->FileName[StrLen (Node->FileName) - 4])) == 0)
319 ){
320 ShellPrintHiiEx (
321 -1,
322 -1,
323 NULL,
324 STRING_TOKEN (STR_LS_LINE_END_EXE),
325 gShellLevel2HiiHandle,
326 Node->FileName
327 );
328 } else {
329 ShellPrintHiiEx (
330 -1,
331 -1,
332 NULL,
333 STRING_TOKEN (STR_LS_LINE_END_FILE),
334 gShellLevel2HiiHandle,
335 Node->FileName
336 );
337 }
338 }
339 }
340 }
341
342 if (!Sfo) {
343 //
344 // print footer
345 //
346 ShellPrintHiiEx (
347 -1,
348 -1,
349 NULL,
350 STRING_TOKEN (STR_LS_FOOTER_LINE),
351 gShellLevel2HiiHandle,
352 FileCount,
353 FileSize,
354 DirCount
355 );
356 }
357
358 if (Rec){
359 DirectoryName = AllocateZeroPool(LongestPath + 2*sizeof(CHAR16));
360 if (DirectoryName == NULL) {
361 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_MEM), gShellLevel2HiiHandle);
362 ShellStatus = SHELL_OUT_OF_RESOURCES;
363 } else {
364 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
365 ; !IsNull(&ListHead->Link, &Node->Link) && ShellStatus == SHELL_SUCCESS
366 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
367 ){
368 if (ShellGetExecutionBreakFlag ()) {
369 ShellStatus = SHELL_ABORTED;
370 break;
371 }
372
373 //
374 // recurse on any directory except the traversing ones...
375 //
376 if (((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY)
377 && StrCmp(Node->FileName, L".") != 0
378 && StrCmp(Node->FileName, L"..") != 0
379 ){
380 StrCpy(DirectoryName, Node->FullName);
381 StrCat(DirectoryName, L"\\*");
382 ShellStatus = PrintLsOutput(
383 Rec,
384 Attribs,
385 Sfo,
386 DirectoryName,
387 FALSE,
388 Count,
389 TimeZone);
390 }
391 }
392 FreePool(DirectoryName);
393 }
394 }
395
396 FreePool(CorrectedPath);
397 ShellCloseFileMetaArg(&ListHead);
398 FreePool(ListHead);
399 return (ShellStatus);
400 }
401
402 STATIC CONST SHELL_PARAM_ITEM LsParamList[] = {
403 {L"-r", TypeFlag},
404 {L"-a", TypeStart},
405 {L"-sfo", TypeFlag},
406 {NULL, TypeMax}
407 };
408
409 /**
410 Function for 'ls' command.
411
412 @param[in] ImageHandle Handle to the Image (NULL if Internal).
413 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
414 **/
415 SHELL_STATUS
416 EFIAPI
417 ShellCommandRunLs (
418 IN EFI_HANDLE ImageHandle,
419 IN EFI_SYSTEM_TABLE *SystemTable
420 )
421 {
422 EFI_STATUS Status;
423 LIST_ENTRY *Package;
424 CHAR16 *ProblemParam;
425 CONST CHAR16 *Attribs;
426 SHELL_STATUS ShellStatus;
427 UINT64 RequiredAttributes;
428 CONST CHAR16 *PathName;
429 CONST CHAR16 *CurDir;
430 UINTN Count;
431 CHAR16 *FullPath;
432 UINTN Size;
433 EFI_TIME TheTime;
434 BOOLEAN SfoMode;
435
436 Size = 0;
437 FullPath = NULL;
438 ProblemParam = NULL;
439 Attribs = NULL;
440 ShellStatus = SHELL_SUCCESS;
441 RequiredAttributes = 0;
442 PathName = NULL;
443 CurDir = NULL;
444 Count = 0;
445
446 //
447 // initialize the shell lib (we must be in non-auto-init...)
448 //
449 Status = ShellInitialize();
450 ASSERT_EFI_ERROR(Status);
451
452 //
453 // Fix local copies of the protocol pointers
454 //
455 Status = CommandInit();
456 ASSERT_EFI_ERROR(Status);
457
458 //
459 // parse the command line
460 //
461 Status = ShellCommandLineParse (LsParamList, &Package, &ProblemParam, TRUE);
462 if (EFI_ERROR(Status)) {
463 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
464 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);
465 FreePool(ProblemParam);
466 ShellStatus = SHELL_INVALID_PARAMETER;
467 } else {
468 ASSERT(FALSE);
469 }
470 } else {
471 //
472 // check for "-?"
473 //
474 if (ShellCommandLineGetFlag(Package, L"-?")) {
475 ASSERT(FALSE);
476 }
477
478 if (ShellCommandLineGetCount(Package) > 2) {
479 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle);
480 ShellStatus = SHELL_INVALID_PARAMETER;
481 } else {
482 //
483 // check for -a
484 //
485 if (ShellCommandLineGetFlag(Package, L"-a")) {
486 for ( Attribs = ShellCommandLineGetValue(Package, L"-a")
487 ; Attribs != NULL && *Attribs != CHAR_NULL && ShellStatus == SHELL_SUCCESS
488 ; Attribs++
489 ){
490 switch (*Attribs) {
491 case L'a':
492 case L'A':
493 RequiredAttributes |= EFI_FILE_ARCHIVE;
494 Count++;
495 continue;
496 case L's':
497 case L'S':
498 RequiredAttributes |= EFI_FILE_SYSTEM;
499 Count++;
500 continue;
501 case L'h':
502 case L'H':
503 RequiredAttributes |= EFI_FILE_HIDDEN;
504 Count++;
505 continue;
506 case L'r':
507 case L'R':
508 RequiredAttributes |= EFI_FILE_READ_ONLY;
509 Count++;
510 continue;
511 case L'd':
512 case L'D':
513 RequiredAttributes |= EFI_FILE_DIRECTORY;
514 Count++;
515 continue;
516 default:
517 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ATTRIBUTE), gShellLevel2HiiHandle, ShellCommandLineGetValue(Package, L"-a"));
518 ShellStatus = SHELL_INVALID_PARAMETER;
519 break;
520 } // switch
521 } // for loop
522 //
523 // if nothing is specified all are specified
524 //
525 if (RequiredAttributes == 0) {
526 RequiredAttributes = EFI_FILE_VALID_ATTR;
527 }
528 } // if -a present
529 if (ShellStatus == SHELL_SUCCESS) {
530 PathName = ShellCommandLineGetRawValue(Package, 1);
531 if (PathName == NULL) {
532 CurDir = gEfiShellProtocol->GetCurDir(NULL);
533 if (CurDir == NULL) {
534 ShellStatus = SHELL_NOT_FOUND;
535 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
536 }
537 }
538 if (PathName != NULL) {
539 if (StrStr(PathName, L":") == NULL && gEfiShellProtocol->GetCurDir(NULL) == NULL) {
540 ShellStatus = SHELL_NOT_FOUND;
541 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
542 } else {
543 ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL));
544 StrnCatGrow(&FullPath, &Size, PathName, 0);
545 if (ShellIsDirectory(PathName) == EFI_SUCCESS) {
546 StrnCatGrow(&FullPath, &Size, L"\\*", 0);
547 }
548 }
549 } else {
550 ASSERT(FullPath == NULL);
551 StrnCatGrow(&FullPath, NULL, L"*", 0);
552 }
553 Status = gRT->GetTime(&TheTime, NULL);
554 if (EFI_ERROR(Status)) {
555 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_UEFI_FUNC_WARN), gShellLevel2HiiHandle, L"gRT->GetTime", Status);
556 TheTime.TimeZone = EFI_UNSPECIFIED_TIMEZONE;
557 }
558
559 SfoMode = ShellCommandLineGetFlag(Package, L"-sfo");
560 if (ShellStatus == SHELL_SUCCESS) {
561 ShellStatus = PrintLsOutput(
562 ShellCommandLineGetFlag(Package, L"-r"),
563 RequiredAttributes,
564 SfoMode,
565 FullPath,
566 TRUE,
567 Count,
568 (INT16)(TheTime.TimeZone==EFI_UNSPECIFIED_TIMEZONE?0:TheTime.TimeZone)
569 );
570 if (ShellStatus == SHELL_NOT_FOUND) {
571 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_FILES), gShellLevel2HiiHandle);
572 } else if (ShellStatus == SHELL_INVALID_PARAMETER) {
573 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle);
574 } else if (ShellStatus == SHELL_ABORTED) {
575 //
576 // Ignore aborting.
577 //
578 } else if (ShellStatus != SHELL_SUCCESS) {
579 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle);
580 }
581 }
582 }
583 }
584 }
585
586 if (FullPath != NULL) {
587 FreePool(FullPath);
588 }
589 //
590 // free the command line package
591 //
592 ShellCommandLineFreeVarList (Package);
593
594 return (ShellStatus);
595 }