Comp.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. /** @file
  2. Main file for Comp shell Debug1 function.
  3. (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
  4. Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
  5. SPDX-License-Identifier: BSD-2-Clause-Patent
  6. **/
  7. #include "UefiShellDebug1CommandsLib.h"
  8. STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
  9. { L"-n", TypeValue },
  10. { L"-s", TypeValue },
  11. { NULL, TypeMax }
  12. };
  13. typedef enum {
  14. OutOfDiffPoint,
  15. InDiffPoint,
  16. InPrevDiffPoint
  17. } READ_STATUS;
  18. //
  19. // Buffer type, for reading both file operands in chunks.
  20. //
  21. typedef struct {
  22. UINT8 *Data; // dynamically allocated buffer
  23. UINTN Allocated; // the allocated size of Data
  24. UINTN Next; // next position in Data to fetch a byte at
  25. UINTN Left; // number of bytes left in Data for fetching at Next
  26. } FILE_BUFFER;
  27. /**
  28. Function to print differnt point data.
  29. @param[in] FileName File name.
  30. @param[in] FileTag File tag name.
  31. @param[in] Buffer Data buffer to be printed.
  32. @param[in] BufferSize Size of the data to be printed.
  33. @param[in] Address Address of the differnt point.
  34. @param[in] DifferentBytes Total size of the buffer.
  35. **/
  36. VOID
  37. PrintDifferentPoint (
  38. CONST CHAR16 *FileName,
  39. CHAR16 *FileTag,
  40. UINT8 *Buffer,
  41. UINT64 BufferSize,
  42. UINTN Address,
  43. UINT64 DifferentBytes
  44. )
  45. {
  46. UINTN Index;
  47. ShellPrintEx (-1, -1, L"%s: %s\r\n %08x:", FileTag, FileName, Address);
  48. //
  49. // Print data in hex-format.
  50. //
  51. for (Index = 0; Index < BufferSize; Index++) {
  52. ShellPrintEx (-1, -1, L" %02x", Buffer[Index]);
  53. }
  54. if (BufferSize < DifferentBytes) {
  55. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_END_OF_FILE), gShellDebug1HiiHandle);
  56. }
  57. ShellPrintEx (-1, -1, L" *");
  58. //
  59. // Print data in char-format.
  60. //
  61. for (Index = 0; Index < BufferSize; Index++) {
  62. if ((Buffer[Index] >= 0x20) && (Buffer[Index] <= 0x7E)) {
  63. ShellPrintEx (-1, -1, L"%c", Buffer[Index]);
  64. } else {
  65. //
  66. // Print dots for control characters
  67. //
  68. ShellPrintEx (-1, -1, L".");
  69. }
  70. }
  71. ShellPrintEx (-1, -1, L"*\r\n");
  72. }
  73. /**
  74. Initialize a FILE_BUFFER.
  75. @param[out] FileBuffer The FILE_BUFFER to initialize. On return, the caller
  76. is responsible for checking FileBuffer->Data: if
  77. FileBuffer->Data is NULL on output, then memory
  78. allocation failed.
  79. **/
  80. STATIC
  81. VOID
  82. FileBufferInit (
  83. OUT FILE_BUFFER *FileBuffer
  84. )
  85. {
  86. FileBuffer->Allocated = PcdGet32 (PcdShellFileOperationSize);
  87. FileBuffer->Data = AllocatePool (FileBuffer->Allocated);
  88. FileBuffer->Left = 0;
  89. }
  90. /**
  91. Uninitialize a FILE_BUFFER.
  92. @param[in,out] FileBuffer The FILE_BUFFER to uninitialize. The caller is
  93. responsible for making sure FileBuffer was first
  94. initialized with FileBufferInit(), successfully or
  95. unsuccessfully.
  96. **/
  97. STATIC
  98. VOID
  99. FileBufferUninit (
  100. IN OUT FILE_BUFFER *FileBuffer
  101. )
  102. {
  103. SHELL_FREE_NON_NULL (FileBuffer->Data);
  104. }
  105. /**
  106. Read a byte from a SHELL_FILE_HANDLE, buffered with a FILE_BUFFER.
  107. @param[in] FileHandle The SHELL_FILE_HANDLE to replenish FileBuffer
  108. from, if needed.
  109. @param[in,out] FileBuffer The FILE_BUFFER to read a byte from. If FileBuffer
  110. is empty on entry, then FileBuffer is refilled
  111. from FileHandle, before outputting a byte from
  112. FileBuffer to Byte. The caller is responsible for
  113. ensuring that FileBuffer was successfully
  114. initialized with FileBufferInit().
  115. @param[out] BytesRead On successful return, BytesRead is set to 1 if the
  116. next byte from FileBuffer has been stored to Byte.
  117. On successful return, BytesRead is set to 0 if
  118. FileBuffer is empty, and FileHandle is at EOF.
  119. When an error is returned, BytesRead is not set.
  120. @param[out] Byte On output, the next byte from FileBuffer. Only set
  121. if (a) EFI_SUCCESS is returned and (b) BytesRead
  122. is set to 1 on output.
  123. @retval EFI_SUCCESS BytesRead has been set to 0 or 1. In the latter case,
  124. Byte has been set as well.
  125. @return Error codes propagated from
  126. gEfiShellProtocol->ReadFile().
  127. **/
  128. STATIC
  129. EFI_STATUS
  130. FileBufferReadByte (
  131. IN SHELL_FILE_HANDLE FileHandle,
  132. IN OUT FILE_BUFFER *FileBuffer,
  133. OUT UINTN *BytesRead,
  134. OUT UINT8 *Byte
  135. )
  136. {
  137. UINTN ReadSize;
  138. EFI_STATUS Status;
  139. if (FileBuffer->Left == 0) {
  140. ReadSize = FileBuffer->Allocated;
  141. Status = gEfiShellProtocol->ReadFile (
  142. FileHandle,
  143. &ReadSize,
  144. FileBuffer->Data
  145. );
  146. if (EFI_ERROR (Status)) {
  147. return Status;
  148. }
  149. if (ReadSize == 0) {
  150. *BytesRead = 0;
  151. return EFI_SUCCESS;
  152. }
  153. FileBuffer->Next = 0;
  154. FileBuffer->Left = ReadSize;
  155. }
  156. *BytesRead = 1;
  157. *Byte = FileBuffer->Data[FileBuffer->Next];
  158. FileBuffer->Next++;
  159. FileBuffer->Left--;
  160. return EFI_SUCCESS;
  161. }
  162. /**
  163. Function for 'comp' command.
  164. @param[in] ImageHandle Handle to the Image (NULL if Internal).
  165. @param[in] SystemTable Pointer to the System Table (NULL if Internal).
  166. **/
  167. SHELL_STATUS
  168. EFIAPI
  169. ShellCommandRunComp (
  170. IN EFI_HANDLE ImageHandle,
  171. IN EFI_SYSTEM_TABLE *SystemTable
  172. )
  173. {
  174. EFI_STATUS Status;
  175. LIST_ENTRY *Package;
  176. CHAR16 *ProblemParam;
  177. CHAR16 *FileName1;
  178. CHAR16 *FileName2;
  179. CONST CHAR16 *TempParam;
  180. SHELL_STATUS ShellStatus;
  181. SHELL_FILE_HANDLE FileHandle1;
  182. SHELL_FILE_HANDLE FileHandle2;
  183. UINT64 Size1;
  184. UINT64 Size2;
  185. UINT64 DifferentBytes;
  186. UINT64 DifferentCount;
  187. UINT8 DiffPointNumber;
  188. UINT8 OneByteFromFile1;
  189. UINT8 OneByteFromFile2;
  190. UINT8 *DataFromFile1;
  191. UINT8 *DataFromFile2;
  192. FILE_BUFFER FileBuffer1;
  193. FILE_BUFFER FileBuffer2;
  194. UINTN InsertPosition1;
  195. UINTN InsertPosition2;
  196. UINTN DataSizeFromFile1;
  197. UINTN DataSizeFromFile2;
  198. UINTN TempAddress;
  199. UINTN Index;
  200. UINTN DiffPointAddress;
  201. READ_STATUS ReadStatus;
  202. ShellStatus = SHELL_SUCCESS;
  203. Status = EFI_SUCCESS;
  204. FileName1 = NULL;
  205. FileName2 = NULL;
  206. FileHandle1 = NULL;
  207. FileHandle2 = NULL;
  208. DataFromFile1 = NULL;
  209. DataFromFile2 = NULL;
  210. ReadStatus = OutOfDiffPoint;
  211. DifferentCount = 10;
  212. DifferentBytes = 4;
  213. DiffPointNumber = 0;
  214. InsertPosition1 = 0;
  215. InsertPosition2 = 0;
  216. TempAddress = 0;
  217. DiffPointAddress = 0;
  218. //
  219. // initialize the shell lib (we must be in non-auto-init...)
  220. //
  221. Status = ShellInitialize ();
  222. ASSERT_EFI_ERROR (Status);
  223. Status = CommandInit ();
  224. ASSERT_EFI_ERROR (Status);
  225. //
  226. // parse the command line
  227. //
  228. Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
  229. if (EFI_ERROR (Status)) {
  230. if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
  231. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDebug1HiiHandle, L"comp", ProblemParam);
  232. FreePool (ProblemParam);
  233. ShellStatus = SHELL_INVALID_PARAMETER;
  234. } else {
  235. ASSERT (FALSE);
  236. }
  237. } else {
  238. if (ShellCommandLineGetCount (Package) > 3) {
  239. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDebug1HiiHandle, L"comp");
  240. ShellStatus = SHELL_INVALID_PARAMETER;
  241. } else if (ShellCommandLineGetCount (Package) < 3) {
  242. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_FEW), gShellDebug1HiiHandle, L"comp");
  243. ShellStatus = SHELL_INVALID_PARAMETER;
  244. } else {
  245. TempParam = ShellCommandLineGetRawValue (Package, 1);
  246. ASSERT (TempParam != NULL);
  247. FileName1 = ShellFindFilePath (TempParam);
  248. if (FileName1 == NULL) {
  249. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
  250. ShellStatus = SHELL_NOT_FOUND;
  251. } else {
  252. Status = ShellOpenFileByName (FileName1, &FileHandle1, EFI_FILE_MODE_READ, 0);
  253. if (EFI_ERROR (Status)) {
  254. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
  255. ShellStatus = SHELL_NOT_FOUND;
  256. }
  257. }
  258. TempParam = ShellCommandLineGetRawValue (Package, 2);
  259. ASSERT (TempParam != NULL);
  260. FileName2 = ShellFindFilePath (TempParam);
  261. if (FileName2 == NULL) {
  262. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_FILE_FIND_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
  263. ShellStatus = SHELL_NOT_FOUND;
  264. } else {
  265. Status = ShellOpenFileByName (FileName2, &FileHandle2, EFI_FILE_MODE_READ, 0);
  266. if (EFI_ERROR (Status)) {
  267. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_FILE_OPEN_FAIL), gShellDebug1HiiHandle, L"comp", TempParam);
  268. ShellStatus = SHELL_NOT_FOUND;
  269. }
  270. }
  271. if (ShellStatus == SHELL_SUCCESS) {
  272. Status = gEfiShellProtocol->GetFileSize (FileHandle1, &Size1);
  273. ASSERT_EFI_ERROR (Status);
  274. Status = gEfiShellProtocol->GetFileSize (FileHandle2, &Size2);
  275. ASSERT_EFI_ERROR (Status);
  276. if (ShellCommandLineGetFlag (Package, L"-n")) {
  277. TempParam = ShellCommandLineGetValue (Package, L"-n");
  278. if (TempParam == NULL) {
  279. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"comp", L"-n");
  280. ShellStatus = SHELL_INVALID_PARAMETER;
  281. } else {
  282. if (gUnicodeCollation->StriColl (gUnicodeCollation, (CHAR16 *)TempParam, L"all") == 0) {
  283. DifferentCount = MAX_UINTN;
  284. } else {
  285. Status = ShellConvertStringToUint64 (TempParam, &DifferentCount, FALSE, TRUE);
  286. if (EFI_ERROR (Status) || (DifferentCount == 0)) {
  287. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"comp", TempParam, L"-n");
  288. ShellStatus = SHELL_INVALID_PARAMETER;
  289. }
  290. }
  291. }
  292. }
  293. if (ShellCommandLineGetFlag (Package, L"-s")) {
  294. TempParam = ShellCommandLineGetValue (Package, L"-s");
  295. if (TempParam == NULL) {
  296. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDebug1HiiHandle, L"comp", L"-s");
  297. ShellStatus = SHELL_INVALID_PARAMETER;
  298. } else {
  299. Status = ShellConvertStringToUint64 (TempParam, &DifferentBytes, FALSE, TRUE);
  300. if (EFI_ERROR (Status) || (DifferentBytes == 0)) {
  301. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM_VAL), gShellDebug1HiiHandle, L"comp", TempParam, L"-s");
  302. ShellStatus = SHELL_INVALID_PARAMETER;
  303. } else {
  304. if (DifferentBytes > MAX (Size1, Size2)) {
  305. DifferentBytes = MAX (Size1, Size2);
  306. }
  307. }
  308. }
  309. }
  310. }
  311. if (ShellStatus == SHELL_SUCCESS) {
  312. DataFromFile1 = AllocateZeroPool ((UINTN)DifferentBytes);
  313. DataFromFile2 = AllocateZeroPool ((UINTN)DifferentBytes);
  314. FileBufferInit (&FileBuffer1);
  315. FileBufferInit (&FileBuffer2);
  316. if ((DataFromFile1 == NULL) || (DataFromFile2 == NULL) ||
  317. (FileBuffer1.Data == NULL) || (FileBuffer2.Data == NULL))
  318. {
  319. ShellStatus = SHELL_OUT_OF_RESOURCES;
  320. SHELL_FREE_NON_NULL (DataFromFile1);
  321. SHELL_FREE_NON_NULL (DataFromFile2);
  322. FileBufferUninit (&FileBuffer1);
  323. FileBufferUninit (&FileBuffer2);
  324. }
  325. }
  326. if (ShellStatus == SHELL_SUCCESS) {
  327. while (DiffPointNumber < DifferentCount) {
  328. DataSizeFromFile1 = 1;
  329. DataSizeFromFile2 = 1;
  330. OneByteFromFile1 = 0;
  331. OneByteFromFile2 = 0;
  332. Status = FileBufferReadByte (
  333. FileHandle1,
  334. &FileBuffer1,
  335. &DataSizeFromFile1,
  336. &OneByteFromFile1
  337. );
  338. ASSERT_EFI_ERROR (Status);
  339. Status = FileBufferReadByte (
  340. FileHandle2,
  341. &FileBuffer2,
  342. &DataSizeFromFile2,
  343. &OneByteFromFile2
  344. );
  345. ASSERT_EFI_ERROR (Status);
  346. TempAddress++;
  347. //
  348. // 1.When end of file and no chars in DataFromFile buffer, then break while.
  349. // 2.If no more char in File1 or File2, The ReadStatus is InPrevDiffPoint forever.
  350. // So the previous different point is the last one, then break the while block.
  351. //
  352. if (((DataSizeFromFile1 == 0) && (InsertPosition1 == 0) && (DataSizeFromFile2 == 0) && (InsertPosition2 == 0)) ||
  353. ((ReadStatus == InPrevDiffPoint) && ((DataSizeFromFile1 == 0) || (DataSizeFromFile2 == 0)))
  354. )
  355. {
  356. break;
  357. }
  358. if (ReadStatus == OutOfDiffPoint) {
  359. if (OneByteFromFile1 != OneByteFromFile2) {
  360. ReadStatus = InDiffPoint;
  361. DiffPointAddress = TempAddress;
  362. if (DataSizeFromFile1 == 1) {
  363. DataFromFile1[InsertPosition1++] = OneByteFromFile1;
  364. }
  365. if (DataSizeFromFile2 == 1) {
  366. DataFromFile2[InsertPosition2++] = OneByteFromFile2;
  367. }
  368. }
  369. } else if (ReadStatus == InDiffPoint) {
  370. if (DataSizeFromFile1 == 1) {
  371. DataFromFile1[InsertPosition1++] = OneByteFromFile1;
  372. }
  373. if (DataSizeFromFile2 == 1) {
  374. DataFromFile2[InsertPosition2++] = OneByteFromFile2;
  375. }
  376. } else if (ReadStatus == InPrevDiffPoint) {
  377. if (OneByteFromFile1 == OneByteFromFile2) {
  378. ReadStatus = OutOfDiffPoint;
  379. }
  380. }
  381. //
  382. // ReadStatus should be always equal InDiffPoint.
  383. //
  384. if ((InsertPosition1 == DifferentBytes) ||
  385. (InsertPosition2 == DifferentBytes) ||
  386. ((DataSizeFromFile1 == 0) && (DataSizeFromFile2 == 0))
  387. )
  388. {
  389. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_DIFFERENCE_POINT), gShellDebug1HiiHandle, ++DiffPointNumber);
  390. PrintDifferentPoint (FileName1, L"File1", DataFromFile1, InsertPosition1, DiffPointAddress, DifferentBytes);
  391. PrintDifferentPoint (FileName2, L"File2", DataFromFile2, InsertPosition2, DiffPointAddress, DifferentBytes);
  392. //
  393. // One of two buffuers is empty, it means this is the last different point.
  394. //
  395. if ((InsertPosition1 == 0) || (InsertPosition2 == 0)) {
  396. break;
  397. }
  398. for (Index = 1; Index < InsertPosition1 && Index < InsertPosition2; Index++) {
  399. if (DataFromFile1[Index] == DataFromFile2[Index]) {
  400. ReadStatus = OutOfDiffPoint;
  401. break;
  402. }
  403. }
  404. if (ReadStatus == OutOfDiffPoint) {
  405. //
  406. // Try to find a new different point in the rest of DataFromFile.
  407. //
  408. for ( ; Index < MAX (InsertPosition1, InsertPosition2); Index++) {
  409. if (DataFromFile1[Index] != DataFromFile2[Index]) {
  410. ReadStatus = InDiffPoint;
  411. DiffPointAddress += Index;
  412. break;
  413. }
  414. }
  415. } else {
  416. //
  417. // Doesn't find a new different point, still in the same different point.
  418. //
  419. ReadStatus = InPrevDiffPoint;
  420. }
  421. CopyMem (DataFromFile1, DataFromFile1 + Index, InsertPosition1 - Index);
  422. CopyMem (DataFromFile2, DataFromFile2 + Index, InsertPosition2 - Index);
  423. SetMem (DataFromFile1 + InsertPosition1 - Index, (UINTN)DifferentBytes - InsertPosition1 + Index, 0);
  424. SetMem (DataFromFile2 + InsertPosition2 - Index, (UINTN)DifferentBytes - InsertPosition2 + Index, 0);
  425. InsertPosition1 -= Index;
  426. InsertPosition2 -= Index;
  427. }
  428. }
  429. SHELL_FREE_NON_NULL (DataFromFile1);
  430. SHELL_FREE_NON_NULL (DataFromFile2);
  431. FileBufferUninit (&FileBuffer1);
  432. FileBufferUninit (&FileBuffer2);
  433. if (DiffPointNumber == 0) {
  434. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_PASS), gShellDebug1HiiHandle);
  435. } else {
  436. ShellStatus = SHELL_NOT_EQUAL;
  437. ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_COMP_FOOTER_FAIL), gShellDebug1HiiHandle);
  438. }
  439. }
  440. }
  441. ShellCommandLineFreeVarList (Package);
  442. }
  443. SHELL_FREE_NON_NULL (FileName1);
  444. SHELL_FREE_NON_NULL (FileName2);
  445. if (FileHandle1 != NULL) {
  446. gEfiShellProtocol->CloseFile (FileHandle1);
  447. }
  448. if (FileHandle2 != NULL) {
  449. gEfiShellProtocol->CloseFile (FileHandle2);
  450. }
  451. return (ShellStatus);
  452. }