]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellLevel2CommandsLib/Ls.c
udk2010.up2.shell initial release.
[mirror_edk2.git] / ShellPkg / Library / UefiShellLevel2CommandsLib / Ls.c
1 /** @file
2 Main file for ls shell level 2 function.
3
4 Copyright (c) 2009 - 2010, 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 ASSERT(CorrectedPath != NULL);
70 ShellCommandCleanPath(CorrectedPath);
71
72 Status = ShellOpenFileMetaArg((CHAR16*)CorrectedPath, EFI_FILE_MODE_READ, &ListHead);
73 if (EFI_ERROR(Status)) {
74 return (SHELL_DEVICE_ERROR);
75 }
76 if (ListHead == NULL || IsListEmpty(&ListHead->Link)) {
77 //
78 // On the first one only we expect to find something...
79 // do we find the . and .. directories otherwise?
80 //
81 if (First) {
82 return (SHELL_NOT_FOUND);
83 }
84 return (SHELL_SUCCESS);
85 }
86
87 if (Sfo && First) {
88 //
89 // Get the first valid handle (directories)
90 //
91 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
92 ; !IsNull(&ListHead->Link, &Node->Link) && Node->Handle == NULL
93 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
94 );
95
96 if (Node->Handle == NULL) {
97 DirectoryName = GetFullyQualifiedPath(((EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link))->FullName);
98
99 //
100 // We need to open something up to get system information
101 //
102 Status = gEfiShellProtocol->OpenFileByName(
103 DirectoryName,
104 &ShellFileHandle,
105 EFI_FILE_MODE_READ);
106
107 ASSERT_EFI_ERROR(Status);
108 FreePool(DirectoryName);
109
110 //
111 // Get the Volume Info from ShellFileHandle
112 //
113 SysInfo = NULL;
114 SysInfoSize = 0;
115 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(ShellFileHandle);
116 Status = EfiFpHandle->GetInfo(
117 EfiFpHandle,
118 &gEfiFileSystemInfoGuid,
119 &SysInfoSize,
120 SysInfo);
121
122 if (Status == EFI_BUFFER_TOO_SMALL) {
123 SysInfo = AllocateZeroPool(SysInfoSize);
124 Status = EfiFpHandle->GetInfo(
125 EfiFpHandle,
126 &gEfiFileSystemInfoGuid,
127 &SysInfoSize,
128 SysInfo);
129 }
130
131 ASSERT_EFI_ERROR(Status);
132
133 gEfiShellProtocol->CloseFile(ShellFileHandle);
134 } else {
135 //
136 // Get the Volume Info from Node->Handle
137 //
138 SysInfo = NULL;
139 SysInfoSize = 0;
140 EfiFpHandle = ConvertShellHandleToEfiFileProtocol(Node->Handle);
141 Status = EfiFpHandle->GetInfo(
142 EfiFpHandle,
143 &gEfiFileSystemInfoGuid,
144 &SysInfoSize,
145 SysInfo);
146
147 if (Status == EFI_BUFFER_TOO_SMALL) {
148 SysInfo = AllocateZeroPool(SysInfoSize);
149 Status = EfiFpHandle->GetInfo(
150 EfiFpHandle,
151 &gEfiFileSystemInfoGuid,
152 &SysInfoSize,
153 SysInfo);
154 }
155
156 ASSERT_EFI_ERROR(Status);
157 }
158
159 ShellPrintHiiEx (
160 -1,
161 -1,
162 NULL,
163 STRING_TOKEN (STR_GEN_SFO_HEADER),
164 gShellLevel2HiiHandle,
165 L"ls");
166 //
167 // print VolumeInfo table
168 //
169 ASSERT(SysInfo != NULL);
170 ShellPrintHiiEx (
171 0,
172 gST->ConOut->Mode->CursorRow,
173 NULL,
174 STRING_TOKEN (STR_LS_SFO_VOLINFO),
175 gShellLevel2HiiHandle,
176 SysInfo->VolumeLabel,
177 SysInfo->VolumeSize,
178 SysInfo->ReadOnly?L"TRUE":L"FALSE",
179 SysInfo->FreeSpace,
180 SysInfo->BlockSize
181 );
182 if (SysInfo != NULL) {
183 FreePool(SysInfo);
184 }
185 }
186
187 if (!Sfo) {
188 //
189 // get directory name from path...
190 //
191 DirectoryName = GetFullyQualifiedPath(CorrectedPath);
192
193 //
194 // print header
195 //
196 ShellPrintHiiEx (
197 0,
198 gST->ConOut->Mode->CursorRow,
199 NULL,
200 STRING_TOKEN (STR_LS_HEADER_LINE1),
201 gShellLevel2HiiHandle,
202 DirectoryName
203 );
204 FreePool(DirectoryName);
205 }
206 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
207 ; !IsNull(&ListHead->Link, &Node->Link)
208 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
209 ){
210 ASSERT(Node != NULL);
211 if (LongestPath < StrSize(Node->FullName)) {
212 LongestPath = StrSize(Node->FullName);
213 }
214 ASSERT(Node->Info != NULL);
215 ASSERT((Node->Info->Attribute & EFI_FILE_VALID_ATTR) == Node->Info->Attribute);
216 if (Attribs == 0) {
217 //
218 // NOT system & NOT hidden
219 //
220 if ( (Node->Info->Attribute & EFI_FILE_SYSTEM)
221 || (Node->Info->Attribute & EFI_FILE_HIDDEN)
222 ){
223 continue;
224 }
225 } else if (Attribs != EFI_FILE_VALID_ATTR) {
226 if (Count == 1) {
227 //
228 // the bit must match
229 //
230 if ( (Node->Info->Attribute & Attribs) != Attribs) {
231 continue;
232 }
233 } else {
234 //
235 // exact match on all bits
236 //
237 if ( Node->Info->Attribute != Attribs) {
238 continue;
239 }
240 }
241 }
242
243 if (Sfo) {
244 //
245 // Print the FileInfo Table
246 //
247 ShellPrintHiiEx (
248 0,
249 gST->ConOut->Mode->CursorRow,
250 NULL,
251 STRING_TOKEN (STR_LS_SFO_FILEINFO),
252 gShellLevel2HiiHandle,
253 Node->FullName,
254 Node->Info->FileSize,
255 Node->Info->PhysicalSize,
256 (Node->Info->Attribute & EFI_FILE_ARCHIVE) != 0?L"a":L"",
257 (Node->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"d":L"",
258 (Node->Info->Attribute & EFI_FILE_HIDDEN) != 0?L"h":L"",
259 (Node->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L"r":L"",
260 (Node->Info->Attribute & EFI_FILE_SYSTEM) != 0?L"s":L"",
261 Node->Info->CreateTime.Hour,
262 Node->Info->CreateTime.Minute,
263 Node->Info->CreateTime.Second,
264 Node->Info->CreateTime.Day,
265 Node->Info->CreateTime.Month,
266 Node->Info->CreateTime.Year,
267 Node->Info->LastAccessTime.Hour,
268 Node->Info->LastAccessTime.Minute,
269 Node->Info->LastAccessTime.Second,
270 Node->Info->LastAccessTime.Day,
271 Node->Info->LastAccessTime.Month,
272 Node->Info->LastAccessTime.Year,
273 Node->Info->ModificationTime.Hour,
274 Node->Info->ModificationTime.Minute,
275 Node->Info->ModificationTime.Second,
276 Node->Info->ModificationTime.Day,
277 Node->Info->ModificationTime.Month,
278 Node->Info->ModificationTime.Year
279 );
280 } else {
281 //
282 // print this one out...
283 // first print the universal start, next print the type specific name format, last print the CRLF
284 //
285 ShellPrintHiiEx (
286 -1,
287 -1,
288 NULL,
289 STRING_TOKEN (STR_LS_LINE_START_ALL),
290 gShellLevel2HiiHandle,
291 &Node->Info->ModificationTime,
292 (Node->Info->Attribute & EFI_FILE_DIRECTORY) != 0?L"<DIR>":L"",
293 (Node->Info->Attribute & EFI_FILE_READ_ONLY) != 0?L'r':L' ',
294 Node->Info->FileSize
295 );
296 if (Node->Info->Attribute & EFI_FILE_DIRECTORY) {
297 DirCount++;
298 ShellPrintHiiEx (
299 -1,
300 -1,
301 NULL,
302 STRING_TOKEN (STR_LS_LINE_END_DIR),
303 gShellLevel2HiiHandle,
304 Node->FileName
305 );
306 } else {
307 FileCount++;
308 FileSize += Node->Info->FileSize;
309 if ( (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".nsh", (CHAR16*)&(Node->FileName[StrLen (Node->FileName) - 4])) == 0)
310 || (gUnicodeCollation->StriColl(gUnicodeCollation, (CHAR16*)L".efi", (CHAR16*)&(Node->FileName[StrLen (Node->FileName) - 4])) == 0)
311 ){
312 ShellPrintHiiEx (
313 -1,
314 -1,
315 NULL,
316 STRING_TOKEN (STR_LS_LINE_END_EXE),
317 gShellLevel2HiiHandle,
318 Node->FileName
319 );
320 } else {
321 ShellPrintHiiEx (
322 -1,
323 -1,
324 NULL,
325 STRING_TOKEN (STR_LS_LINE_END_FILE),
326 gShellLevel2HiiHandle,
327 Node->FileName
328 );
329 }
330 }
331 }
332 }
333
334 if (!Sfo) {
335 //
336 // print footer
337 //
338 ShellPrintHiiEx (
339 -1,
340 -1,
341 NULL,
342 STRING_TOKEN (STR_LS_FOOTER_LINE),
343 gShellLevel2HiiHandle,
344 FileCount,
345 FileSize,
346 DirCount
347 );
348 }
349
350 if (Rec){
351 DirectoryName = AllocatePool(LongestPath + 2*sizeof(CHAR16));
352 for ( Node = (EFI_SHELL_FILE_INFO *)GetFirstNode(&ListHead->Link)
353 ; !IsNull(&ListHead->Link, &Node->Link)
354 ; Node = (EFI_SHELL_FILE_INFO *)GetNextNode(&ListHead->Link, &Node->Link)
355 ){
356 //
357 // recurse on any directory except the traversing ones...
358 //
359 if (((Node->Info->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY)
360 && StrCmp(Node->FileName, L".") != 0
361 && StrCmp(Node->FileName, L"..") != 0
362 ){
363 StrCpy(DirectoryName, Node->FullName);
364 StrCat(DirectoryName, L"\\*");
365 PrintLsOutput(
366 Rec,
367 Attribs,
368 Sfo,
369 DirectoryName,
370 FALSE,
371 Count,
372 TimeZone);
373 }
374 }
375 FreePool(DirectoryName);
376 }
377
378 FreePool(CorrectedPath);
379 ShellCloseFileMetaArg(&ListHead);
380 FreePool(ListHead);
381 return (ShellStatus);
382 }
383
384 STATIC CONST SHELL_PARAM_ITEM LsParamList[] = {
385 {L"-r", TypeFlag},
386 {L"-a", TypeStart},
387 {L"-sfo", TypeFlag},
388 {NULL, TypeMax}
389 };
390
391 /**
392 Function for 'ls' command.
393
394 @param[in] ImageHandle Handle to the Image (NULL if Internal).
395 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
396 **/
397 SHELL_STATUS
398 EFIAPI
399 ShellCommandRunLs (
400 IN EFI_HANDLE ImageHandle,
401 IN EFI_SYSTEM_TABLE *SystemTable
402 )
403 {
404 EFI_STATUS Status;
405 LIST_ENTRY *Package;
406 CHAR16 *ProblemParam;
407 CONST CHAR16 *Attribs;
408 SHELL_STATUS ShellStatus;
409 UINT64 RequiredAttributes;
410 CONST CHAR16 *PathName;
411 CONST CHAR16 *CurDir;
412 UINTN Count;
413 CHAR16 *FullPath;
414 UINTN Size;
415 EFI_TIME theTime;
416 BOOLEAN SfoMode;
417
418 Size = 0;
419 FullPath = NULL;
420 ProblemParam = NULL;
421 Attribs = NULL;
422 ShellStatus = SHELL_SUCCESS;
423 RequiredAttributes = 0;
424 PathName = NULL;
425 CurDir = NULL;
426 Count = 0;
427
428 //
429 // initialize the shell lib (we must be in non-auto-init...)
430 //
431 Status = ShellInitialize();
432 ASSERT_EFI_ERROR(Status);
433
434 //
435 // Fix local copies of the protocol pointers
436 //
437 Status = CommandInit();
438 ASSERT_EFI_ERROR(Status);
439
440 //
441 // parse the command line
442 //
443 Status = ShellCommandLineParse (LsParamList, &Package, &ProblemParam, TRUE);
444 if (EFI_ERROR(Status)) {
445 if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
446 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellLevel2HiiHandle, ProblemParam);
447 FreePool(ProblemParam);
448 ShellStatus = SHELL_INVALID_PARAMETER;
449 } else {
450 ASSERT(FALSE);
451 }
452 } else {
453 //
454 // check for "-?"
455 //
456 if (ShellCommandLineGetFlag(Package, L"-?")) {
457 ASSERT(FALSE);
458 }
459
460 if (ShellCommandLineGetCount(Package) > 2) {
461 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellLevel2HiiHandle);
462 ShellStatus = SHELL_INVALID_PARAMETER;
463 } else {
464 //
465 // check for -a
466 //
467 if (ShellCommandLineGetFlag(Package, L"-a")) {
468 for ( Attribs = ShellCommandLineGetValue(Package, L"-a")
469 ; Attribs != NULL && *Attribs != CHAR_NULL && ShellStatus == SHELL_SUCCESS
470 ; Attribs++
471 ){
472 switch (*Attribs) {
473 case L'a':
474 case L'A':
475 RequiredAttributes |= EFI_FILE_ARCHIVE;
476 Count++;
477 continue;
478 case L's':
479 case L'S':
480 RequiredAttributes |= EFI_FILE_SYSTEM;
481 Count++;
482 continue;
483 case L'h':
484 case L'H':
485 RequiredAttributes |= EFI_FILE_HIDDEN;
486 Count++;
487 continue;
488 case L'r':
489 case L'R':
490 RequiredAttributes |= EFI_FILE_READ_ONLY;
491 Count++;
492 continue;
493 case L'd':
494 case L'D':
495 RequiredAttributes |= EFI_FILE_DIRECTORY;
496 Count++;
497 continue;
498 default:
499 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_ATTRIBUTE), gShellLevel2HiiHandle, ShellCommandLineGetValue(Package, L"-a"));
500 ShellStatus = SHELL_INVALID_PARAMETER;
501 break;
502 } // switch
503 } // for loop
504 //
505 // if nothing is specified all are specified
506 //
507 if (RequiredAttributes == 0) {
508 RequiredAttributes = EFI_FILE_VALID_ATTR;
509 }
510 } // if -a present
511 if (ShellStatus == SHELL_SUCCESS) {
512 PathName = ShellCommandLineGetRawValue(Package, 1);
513 if (PathName == NULL) {
514 CurDir = gEfiShellProtocol->GetCurDir(NULL);
515 if (CurDir == NULL) {
516 ShellStatus = SHELL_NOT_FOUND;
517 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_CWD), gShellLevel2HiiHandle);
518 }
519 }
520 if (PathName != NULL) {
521 ASSERT((FullPath == NULL && Size == 0) || (FullPath != NULL));
522 StrnCatGrow(&FullPath, &Size, PathName, 0);
523 if (ShellIsDirectory(PathName) == EFI_SUCCESS) {
524 StrnCatGrow(&FullPath, &Size, L"\\*", 0);
525 }
526 } else {
527 ASSERT(FullPath == NULL);
528 StrnCatGrow(&FullPath, NULL, L"*", 0);
529 }
530 Status = gRT->GetTime(&theTime, NULL);
531 ASSERT_EFI_ERROR(Status);
532 SfoMode = ShellCommandLineGetFlag(Package, L"-sfo");
533 if (ShellStatus == SHELL_SUCCESS) {
534 ShellStatus = PrintLsOutput(
535 ShellCommandLineGetFlag(Package, L"-r"),
536 RequiredAttributes,
537 SfoMode,
538 FullPath,
539 TRUE,
540 Count,
541 (INT16)(theTime.TimeZone==2047?0:theTime.TimeZone)
542 );
543 if (ShellStatus == SHELL_NOT_FOUND) {
544 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_FILES), gShellLevel2HiiHandle);
545 } else if (ShellStatus == SHELL_INVALID_PARAMETER) {
546 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle);
547 } else if (ShellStatus != SHELL_SUCCESS) {
548 ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PARAM_INV), gShellLevel2HiiHandle);
549 }
550 }
551 }
552 }
553 }
554
555 if (FullPath != NULL) {
556 FreePool(FullPath);
557 }
558 //
559 // free the command line package
560 //
561 ShellCommandLineFreeVarList (Package);
562
563 return (ShellStatus);
564 }