Ls.c revision a405b86d274d32b92f69842bfb9a1ab143128f57
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**/ 33SHELL_STATUS 34EFIAPI 35PrintLsOutput( 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 384STATIC 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**/ 397SHELL_STATUS 398EFIAPI 399ShellCommandRunLs ( 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} 565