Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

899 lines
25 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1992 Microsoft Corporation
  3. Module Name:
  4. showinst.c
  5. Abstract:
  6. This program compares the actions described by two Installation Modification Log file
  7. created by the INSTALER program
  8. Author:
  9. Steve Wood (stevewo) 15-Jan-1996
  10. Revision History:
  11. --*/
  12. #include "instutil.h"
  13. #include "iml.h"
  14. BOOLEAN VerboseOutput;
  15. BOOLEAN
  16. CompareIml(
  17. PINSTALLATION_MODIFICATION_LOGFILE pIml1,
  18. PINSTALLATION_MODIFICATION_LOGFILE pIml2
  19. );
  20. int
  21. _CRTAPI1
  22. main(
  23. int argc,
  24. char *argv[]
  25. )
  26. {
  27. char *s;
  28. PWSTR ImlPathAlt = NULL;
  29. PINSTALLATION_MODIFICATION_LOGFILE pIml1 = NULL;
  30. PINSTALLATION_MODIFICATION_LOGFILE pIml2 = NULL;
  31. InitCommonCode( "COMPINST",
  32. "InstallationName2 [-v]",
  33. "-v verbose output\n"
  34. );
  35. VerboseOutput = FALSE;
  36. while (--argc) {
  37. s = *++argv;
  38. if (*s == '-' || *s == '/') {
  39. while (*++s) {
  40. switch( tolower( *s ) ) {
  41. case 'v':
  42. VerboseOutput = TRUE;
  43. break;
  44. default:
  45. CommonSwitchProcessing( &argc, &argv, *s );
  46. break;
  47. }
  48. }
  49. }
  50. else
  51. if (!CommonArgProcessing( &argc, &argv )) {
  52. if (ImlPathAlt != NULL) {
  53. Usage( "Too many installation names specified - '%s'", (ULONG)s );
  54. }
  55. ImlPathAlt = FormatImlPath( InstalerDirectory, GetArgAsUnicode( s ) );
  56. }
  57. }
  58. if (ImlPath == NULL || ImlPathAlt == NULL) {
  59. Usage( "Must specify two installation names to compare", 0 );
  60. }
  61. if (!SetCurrentDirectory( InstalerDirectory )) {
  62. FatalError( "Unable to change to '%ws' directory (%u)",
  63. (ULONG)InstalerDirectory,
  64. GetLastError()
  65. );
  66. }
  67. pIml1 = LoadIml( ImlPath );
  68. if (pIml1 == NULL) {
  69. FatalError( "Unable to load '%ws' (%u)",
  70. (ULONG)ImlPath,
  71. GetLastError()
  72. );
  73. }
  74. pIml2 = LoadIml( ImlPathAlt );
  75. if (pIml2 == NULL) {
  76. FatalError( "Unable to load '%ws' (%u)",
  77. (ULONG)ImlPathAlt,
  78. GetLastError()
  79. );
  80. }
  81. printf( "Displaying differences between:\n" );
  82. printf( " Installation 1: %ws\n", ImlPath );
  83. printf( " Installation 2: %ws\n", ImlPathAlt );
  84. exit( CompareIml( pIml1, pIml2 ) == FALSE );
  85. return 0;
  86. }
  87. typedef struct _IML_GENERIC_RECORD {
  88. POFFSET Next; // IML_GENERIC_RECORD
  89. ULONG Action;
  90. POFFSET Name; // WCHAR
  91. POFFSET Records; // IML_GENERIC_RECORD
  92. } IML_GENERIC_RECORD, *PIML_GENERIC_RECORD;
  93. typedef
  94. VOID
  95. (*PIML_PRINT_RECORD_ROUTINE)(
  96. PINSTALLATION_MODIFICATION_LOGFILE pIml,
  97. PIML_GENERIC_RECORD pGeneric,
  98. PWSTR Parents[],
  99. ULONG Depth,
  100. ULONG i
  101. );
  102. typedef
  103. BOOLEAN
  104. (*PIML_COMPARE_CONTENTS_ROUTINE)(
  105. PINSTALLATION_MODIFICATION_LOGFILE pIml1,
  106. PIML_GENERIC_RECORD pGeneric1,
  107. PINSTALLATION_MODIFICATION_LOGFILE pIml2,
  108. PIML_GENERIC_RECORD pGeneric2,
  109. PWSTR Parents[]
  110. );
  111. PINSTALLATION_MODIFICATION_LOGFILE pSortIml;
  112. int
  113. _CRTAPI1
  114. CompareGeneric(
  115. const void *Reference1,
  116. const void *Reference2
  117. )
  118. {
  119. PIML_GENERIC_RECORD p1 = *(PIML_GENERIC_RECORD *)Reference1;
  120. PIML_GENERIC_RECORD p2 = *(PIML_GENERIC_RECORD *)Reference2;
  121. if (p1->Name == 0) {
  122. if (p2->Name == 0) {
  123. return 0;
  124. }
  125. else {
  126. return -1;
  127. }
  128. }
  129. else
  130. if (p2->Name == 0) {
  131. return 1;
  132. }
  133. return _wcsicmp( MP( PWSTR, pSortIml, p1->Name ),
  134. MP( PWSTR, pSortIml, p2->Name )
  135. );
  136. }
  137. PIML_GENERIC_RECORD *
  138. GetSortedGenericListAsArray(
  139. PINSTALLATION_MODIFICATION_LOGFILE pIml,
  140. PIML_GENERIC_RECORD pGeneric
  141. )
  142. {
  143. PIML_GENERIC_RECORD p, *pp;
  144. ULONG n;
  145. p = pGeneric;
  146. n = 1;
  147. while (p != NULL) {
  148. n += 1;
  149. p = MP( PIML_GENERIC_RECORD, pIml, p->Next );
  150. }
  151. pp = HeapAlloc( GetProcessHeap(), 0, n * sizeof( *pp ) );
  152. p = pGeneric;
  153. n = 0;
  154. while (p != NULL) {
  155. pp[ n++ ] = p;
  156. p = MP( PIML_GENERIC_RECORD, pIml, p->Next );
  157. }
  158. pp[ n ] = NULL;
  159. pSortIml = pIml;
  160. qsort( (void *)pp, n, sizeof( *pp ), CompareGeneric );
  161. pSortIml = NULL;
  162. return pp;
  163. }
  164. BOOLEAN
  165. CompareGenericIml(
  166. PINSTALLATION_MODIFICATION_LOGFILE pIml1,
  167. PIML_GENERIC_RECORD pGeneric1,
  168. PINSTALLATION_MODIFICATION_LOGFILE pIml2,
  169. PIML_GENERIC_RECORD pGeneric2,
  170. PWSTR Parents[],
  171. ULONG Depth,
  172. PIML_PRINT_RECORD_ROUTINE PrintRecordRoutine,
  173. PIML_COMPARE_CONTENTS_ROUTINE CompareContentsRoutine
  174. )
  175. {
  176. PVOID pBufferToFree1;
  177. PVOID pBufferToFree2;
  178. PIML_GENERIC_RECORD *ppGeneric1;
  179. PIML_GENERIC_RECORD *ppGeneric2;
  180. PIML_GENERIC_RECORD pShow1;
  181. PIML_GENERIC_RECORD pShow2;
  182. BOOLEAN Result = FALSE;
  183. PWSTR s1, s2;
  184. int cmpResult;
  185. ppGeneric1 = GetSortedGenericListAsArray( pIml1, pGeneric1 );
  186. if (ppGeneric1 == NULL) {
  187. return FALSE;
  188. }
  189. pBufferToFree1 = ppGeneric1;
  190. ppGeneric2 = GetSortedGenericListAsArray( pIml2, pGeneric2 );
  191. if (ppGeneric2 == NULL) {
  192. HeapFree( GetProcessHeap(), 0, pBufferToFree1 );
  193. return FALSE;
  194. }
  195. pBufferToFree2 = ppGeneric2;
  196. pGeneric1 = *ppGeneric1++;
  197. pGeneric2 = *ppGeneric2++;
  198. while (TRUE) {
  199. pShow1 = NULL;
  200. pShow2 = NULL;
  201. if (pGeneric1 == NULL) {
  202. if (pGeneric2 == NULL) {
  203. break;
  204. }
  205. //
  206. // pGeneric2 is new
  207. //
  208. pShow2 = pGeneric2;
  209. pGeneric2 = *ppGeneric2++;
  210. Result = FALSE;
  211. }
  212. else
  213. if (pGeneric2 == NULL) {
  214. //
  215. // pGeneric1 is new
  216. //
  217. pShow1 = pGeneric1;
  218. pGeneric1 = *ppGeneric1++;
  219. Result = FALSE;
  220. }
  221. else {
  222. s1 = MP( PWSTR, pIml1, pGeneric1->Name );
  223. s2 = MP( PWSTR, pIml2, pGeneric2->Name );
  224. if (s1 == NULL) {
  225. if (s2 == NULL) {
  226. cmpResult = 0;
  227. }
  228. else {
  229. cmpResult = -1;
  230. }
  231. }
  232. else
  233. if (s2 == NULL) {
  234. cmpResult = 1;
  235. }
  236. else {
  237. cmpResult = _wcsicmp( s1, s2 );
  238. }
  239. if (cmpResult == 0) {
  240. if (Depth > 1) {
  241. Parents[ Depth - 1 ] = MP( PWSTR, pIml1, pGeneric1->Name );
  242. Result = CompareGenericIml( pIml1,
  243. MP( PIML_GENERIC_RECORD, pIml1, pGeneric1->Records ),
  244. pIml2,
  245. MP( PIML_GENERIC_RECORD, pIml2, pGeneric2->Records ),
  246. Parents,
  247. Depth - 1,
  248. PrintRecordRoutine,
  249. CompareContentsRoutine
  250. );
  251. }
  252. else {
  253. Result = (*CompareContentsRoutine)( pIml1, pGeneric1,
  254. pIml2, pGeneric2,
  255. Parents
  256. );
  257. }
  258. pGeneric1 = *ppGeneric1++;
  259. pGeneric2 = *ppGeneric2++;
  260. }
  261. else
  262. if (cmpResult > 0) {
  263. pShow2 = pGeneric2;
  264. pGeneric2 = *ppGeneric2++;
  265. }
  266. else {
  267. pShow1 = pGeneric1;
  268. pGeneric1 = *ppGeneric1++;
  269. }
  270. }
  271. if (pShow1) {
  272. (*PrintRecordRoutine)( pIml1, pShow1, Parents, Depth, 1 );
  273. }
  274. if (pShow2) {
  275. (*PrintRecordRoutine)( pIml2, pShow2, Parents, Depth, 2 );
  276. }
  277. }
  278. HeapFree( GetProcessHeap(), 0, pBufferToFree1 );
  279. HeapFree( GetProcessHeap(), 0, pBufferToFree2 );
  280. return Result;
  281. }
  282. char *FileActionStrings[] = {
  283. "CreateNewFile",
  284. "ModifyOldFile",
  285. "DeleteOldFile",
  286. "RenameOldFile",
  287. "ModifyFileDateTime",
  288. "ModifyFileAttributes"
  289. };
  290. PWSTR
  291. FormatFileTime(
  292. LPFILETIME LastWriteTime
  293. )
  294. {
  295. FILETIME LocalFileTime;
  296. SYSTEMTIME DateTime;
  297. static WCHAR DateTimeBuffer[ 128 ];
  298. FileTimeToLocalFileTime( LastWriteTime, &LocalFileTime );
  299. FileTimeToSystemTime( &LocalFileTime, &DateTime );
  300. _snwprintf( DateTimeBuffer,
  301. 128,
  302. L"%02u/%02u/%04u %02u:%02u:%02u",
  303. (ULONG)DateTime.wMonth,
  304. (ULONG)DateTime.wDay,
  305. (ULONG)DateTime.wYear,
  306. (ULONG)DateTime.wHour,
  307. (ULONG)DateTime.wMinute,
  308. (ULONG)DateTime.wSecond
  309. );
  310. return DateTimeBuffer;
  311. }
  312. VOID
  313. PrintFileRecordIml(
  314. PINSTALLATION_MODIFICATION_LOGFILE pIml,
  315. PIML_GENERIC_RECORD pGeneric,
  316. PWSTR Parents[],
  317. ULONG Depth,
  318. ULONG i
  319. )
  320. {
  321. PIML_FILE_RECORD pFile = (PIML_FILE_RECORD)pGeneric;
  322. printf( "File: %ws\n %u: %s\n",
  323. MP( PWSTR, pIml, pFile->Name ),
  324. i, FileActionStrings[ pFile->Action ]
  325. );
  326. }
  327. BOOLEAN
  328. CompareFileContentsIml(
  329. PINSTALLATION_MODIFICATION_LOGFILE pIml1,
  330. PIML_GENERIC_RECORD pGeneric1,
  331. PINSTALLATION_MODIFICATION_LOGFILE pIml2,
  332. PIML_GENERIC_RECORD pGeneric2,
  333. PWSTR Parents[]
  334. )
  335. {
  336. PIML_FILE_RECORD pFile1 = (PIML_FILE_RECORD)pGeneric1;
  337. PIML_FILE_RECORD pFile2 = (PIML_FILE_RECORD)pGeneric2;
  338. PIML_FILE_RECORD_CONTENTS pFileContents1;
  339. PIML_FILE_RECORD_CONTENTS pFileContents2;
  340. BOOLEAN ActionsDiffer = FALSE;
  341. BOOLEAN DatesDiffer = FALSE;
  342. BOOLEAN AttributesDiffer = FALSE;
  343. BOOLEAN SizesDiffer = FALSE;
  344. BOOLEAN ContentsDiffer = FALSE;
  345. BOOLEAN Result = TRUE;
  346. PCHAR s1, s2;
  347. ULONG n;
  348. pFileContents1 = MP( PIML_FILE_RECORD_CONTENTS, pIml1, pFile1->NewFile );
  349. pFileContents2 = MP( PIML_FILE_RECORD_CONTENTS, pIml2, pFile2->NewFile );
  350. if (pFile1->Action != pFile2->Action) {
  351. ActionsDiffer = TRUE;
  352. Result = FALSE;
  353. }
  354. else
  355. if (pFileContents1 != NULL && pFileContents2 != NULL) {
  356. if (pFile1->Action != CreateNewFile &&
  357. ((pFileContents1->LastWriteTime.dwHighDateTime !=
  358. pFileContents2->LastWriteTime.dwHighDateTime
  359. ) ||
  360. (pFileContents1->LastWriteTime.dwLowDateTime !=
  361. pFileContents2->LastWriteTime.dwLowDateTime
  362. )
  363. )
  364. ) {
  365. DatesDiffer = TRUE;
  366. Result = FALSE;
  367. }
  368. if (pFileContents1->FileAttributes != pFileContents2->FileAttributes) {
  369. AttributesDiffer = TRUE;
  370. Result = FALSE;
  371. }
  372. if (pFileContents1->FileSize != pFileContents2->FileSize) {
  373. SizesDiffer = TRUE;
  374. Result = FALSE;
  375. }
  376. else
  377. if (pFileContents1->Contents == 0 ||
  378. pFileContents2->Contents == 0 ||
  379. memcmp( MP( PVOID, pIml1, pFileContents1->Contents ),
  380. MP( PVOID, pIml2, pFileContents2->Contents ),
  381. pFileContents1->FileSize
  382. ) != 0
  383. ) {
  384. s1 = MP( PVOID, pIml1, pFileContents1->Contents );
  385. s2 = MP( PVOID, pIml2, pFileContents2->Contents );
  386. if (s1 == NULL || s2 == NULL) {
  387. n = 0;
  388. }
  389. else {
  390. n = pFileContents1->FileSize;
  391. }
  392. while (n) {
  393. if (*s1 != *s2) {
  394. n = pFileContents1->FileSize - n;
  395. break;
  396. }
  397. n -= 1;
  398. s1 += 1;
  399. s2 += 1;
  400. }
  401. ContentsDiffer = TRUE;
  402. Result = FALSE;
  403. }
  404. }
  405. if (!Result) {
  406. printf( "File: %ws\n", MP( PWSTR, pIml1, pFile1->Name ) );
  407. if (ActionsDiffer) {
  408. printf( " 1: Action - %s\n", FileActionStrings[ pFile1->Action ] );
  409. printf( " 2: Action - %s\n", FileActionStrings[ pFile2->Action ] );
  410. }
  411. if (DatesDiffer) {
  412. printf( " 1: LastWriteTime - %ws\n",
  413. FormatFileTime( &pFileContents1->LastWriteTime )
  414. );
  415. printf( " 2: LastWriteTime - %ws\n",
  416. FormatFileTime( &pFileContents2->LastWriteTime )
  417. );
  418. }
  419. if (AttributesDiffer) {
  420. printf( " 1: Attributes - 0x%08x\n", pFileContents1->FileAttributes );
  421. printf( " 2: Attributes - 0x%08x\n", pFileContents2->FileAttributes );
  422. }
  423. if (SizesDiffer) {
  424. printf( " 1: File Size - 0x%08x\n", pFileContents1->FileSize );
  425. printf( " 2: File Size - 0x%08x\n", pFileContents2->FileSize );
  426. }
  427. if (ContentsDiffer) {
  428. printf( " 1: Contents Differs\n" );
  429. printf( " 2: from each other at offset %08x\n", n );
  430. }
  431. }
  432. return Result;
  433. }
  434. char *KeyActionStrings[] = {
  435. "CreateNewKey",
  436. "DeleteOldKey",
  437. "ModifyKeyValues"
  438. };
  439. char *ValueActionStrings[] = {
  440. "CreateNewValue",
  441. "DeleteOldValue",
  442. "ModifyOldValue"
  443. };
  444. char *ValueTypeStrings[] = {
  445. "REG_NONE",
  446. "REG_SZ",
  447. "REG_EXPAND_SZ",
  448. "REG_BINARY",
  449. "REG_DWORD",
  450. "REG_DWORD_BIG_ENDIAN",
  451. "REG_LINK",
  452. "REG_MULTI_SZ",
  453. "REG_RESOURCE_LIST",
  454. "REG_FULL_RESOURCE_DESCRIPTOR",
  455. "REG_RESOURCE_REQUIREMENTS_LIST"
  456. };
  457. VOID
  458. PrintKeyValueRecordIml(
  459. PINSTALLATION_MODIFICATION_LOGFILE pIml,
  460. PIML_GENERIC_RECORD pGeneric,
  461. PWSTR Parents[],
  462. ULONG Depth,
  463. ULONG i
  464. )
  465. {
  466. PIML_KEY_RECORD pKey = (PIML_KEY_RECORD)pGeneric;
  467. PIML_VALUE_RECORD pValue = (PIML_VALUE_RECORD)pGeneric;
  468. if (Depth == 2) {
  469. printf( "Key: %ws\n %u: %s\n",
  470. MP( PWSTR, pIml, pKey->Name ),
  471. i, KeyActionStrings[ pKey->Action ]
  472. );
  473. }
  474. else {
  475. if (Parents[ 1 ] != NULL) {
  476. printf( "Key: %ws\n", Parents[ 1 ] );
  477. Parents[ 1 ] = NULL;
  478. }
  479. printf( " Value: %ws\n %u: %s\n",
  480. MP( PWSTR, pIml, pValue->Name ),
  481. i, ValueActionStrings[ pValue->Action ]
  482. );
  483. }
  484. }
  485. UCHAR BlanksForPadding[] =
  486. " ";
  487. VOID
  488. PrintValueContents(
  489. PCHAR PrefixString,
  490. PINSTALLATION_MODIFICATION_LOGFILE pIml,
  491. PIML_VALUE_RECORD_CONTENTS pValueContents
  492. )
  493. {
  494. ULONG ValueType;
  495. ULONG ValueLength;
  496. PVOID ValueData;
  497. ULONG cbPrefix, cb, i, j;
  498. PWSTR pw;
  499. PULONG p;
  500. ValueType = pValueContents->Type;
  501. ValueLength = pValueContents->Length;
  502. ValueData = MP( PVOID, pIml, pValueContents->Data );
  503. cbPrefix = printf( "%s", PrefixString );
  504. cb = cbPrefix + printf( "%s", ValueTypeStrings[ ValueType ] );
  505. switch( ValueType ) {
  506. case REG_SZ:
  507. case REG_LINK:
  508. case REG_EXPAND_SZ:
  509. pw = (PWSTR)ValueData;
  510. printf( " (%u) \"%.*ws\"\n", ValueLength, ValueLength/sizeof(WCHAR), pw );
  511. break;
  512. case REG_MULTI_SZ:
  513. pw = (PWSTR)ValueData;
  514. i = 0;
  515. if (*pw)
  516. while (i < (ValueLength - 1) / sizeof( WCHAR )) {
  517. if (i > 0) {
  518. printf( " \\\n%.*s", cbPrefix, BlanksForPadding );
  519. }
  520. printf( "\"%ws\" ", pw+i );
  521. do {
  522. ++i;
  523. }
  524. while (pw[i] != UNICODE_NULL);
  525. ++i;
  526. }
  527. printf( "\n" );
  528. break;
  529. case REG_DWORD:
  530. case REG_DWORD_BIG_ENDIAN:
  531. printf( " 0x%08x\n", *(PULONG)ValueData );
  532. break;
  533. case REG_RESOURCE_LIST:
  534. case REG_FULL_RESOURCE_DESCRIPTOR:
  535. case REG_RESOURCE_REQUIREMENTS_LIST:
  536. case REG_BINARY:
  537. case REG_NONE:
  538. cb = printf( " [0x%08lx]", ValueLength );
  539. if (ValueLength != 0) {
  540. p = (PULONG)ValueData;
  541. i = (ValueLength + 3) / sizeof( ULONG );
  542. for (j=0; j<i; j++) {
  543. if ((cbPrefix + cb + 11) > 78) {
  544. printf( " \\\n%.*s", cbPrefix, BlanksForPadding );
  545. cb = 0;
  546. }
  547. else {
  548. cb += printf( " " );
  549. }
  550. cb += printf( "0x%08lx", *p++ );
  551. }
  552. }
  553. printf( "\n" );
  554. break;
  555. }
  556. }
  557. BOOLEAN
  558. CompareKeyValueContentsIml(
  559. PINSTALLATION_MODIFICATION_LOGFILE pIml1,
  560. PIML_GENERIC_RECORD pGeneric1,
  561. PINSTALLATION_MODIFICATION_LOGFILE pIml2,
  562. PIML_GENERIC_RECORD pGeneric2,
  563. PWSTR Parents[]
  564. )
  565. {
  566. PIML_VALUE_RECORD pValue1 = (PIML_VALUE_RECORD)pGeneric1;
  567. PIML_VALUE_RECORD pValue2 = (PIML_VALUE_RECORD)pGeneric2;
  568. PIML_VALUE_RECORD_CONTENTS pValueContents1;
  569. PIML_VALUE_RECORD_CONTENTS pValueContents2;
  570. BOOLEAN ActionsDiffer = FALSE;
  571. BOOLEAN TypesDiffer = FALSE;
  572. BOOLEAN LengthsDiffer = FALSE;
  573. BOOLEAN ContentsDiffer = FALSE;
  574. BOOLEAN Result = TRUE;
  575. PCHAR s1, s2;
  576. ULONG n;
  577. pValueContents1 = MP( PIML_VALUE_RECORD_CONTENTS, pIml1, pValue1->NewValue );
  578. pValueContents2 = MP( PIML_VALUE_RECORD_CONTENTS, pIml2, pValue2->NewValue );
  579. if (pValue1->Action != pValue2->Action) {
  580. ActionsDiffer = TRUE;
  581. Result = FALSE;
  582. }
  583. else
  584. if (pValueContents1 != NULL && pValueContents2 != NULL) {
  585. if (pValue1->Action != CreateNewValue &&
  586. (pValueContents1->Type != pValueContents2->Type)
  587. ) {
  588. TypesDiffer = TRUE;
  589. Result = FALSE;
  590. }
  591. if (pValueContents1->Length != pValueContents2->Length) {
  592. LengthsDiffer = TRUE;
  593. Result = FALSE;
  594. }
  595. else
  596. if (pValueContents1->Data == 0 ||
  597. pValueContents2->Data == 0 ||
  598. memcmp( MP( PVOID, pIml1, pValueContents1->Data ),
  599. MP( PVOID, pIml2, pValueContents2->Data ),
  600. pValueContents1->Length
  601. ) != 0
  602. ) {
  603. s1 = MP( PVOID, pIml1, pValueContents1->Data );
  604. s2 = MP( PVOID, pIml2, pValueContents2->Data );
  605. if (s1 == NULL || s2 == NULL) {
  606. n = 0;
  607. }
  608. else {
  609. n = pValueContents1->Length;
  610. }
  611. while (n) {
  612. if (*s1 != *s2) {
  613. n = pValueContents1->Length - n;
  614. break;
  615. }
  616. n -= 1;
  617. s1 += 1;
  618. s2 += 1;
  619. }
  620. ContentsDiffer = TRUE;
  621. Result = FALSE;
  622. }
  623. }
  624. if (!Result) {
  625. if (Parents[ 2 ] != NULL) {
  626. printf( "Key: %ws\n", Parents[ 2 ] );
  627. Parents[ 2 ] = NULL;
  628. }
  629. printf( " Value: %ws\n", MP( PWSTR, pIml1, pValue1->Name ) );
  630. if (ActionsDiffer) {
  631. printf( " 1: Action - %s\n", ValueActionStrings[ pValue1->Action ] );
  632. printf( " 2: Action - %s\n", ValueActionStrings[ pValue2->Action ] );
  633. }
  634. if (TypesDiffer || LengthsDiffer || ContentsDiffer ) {
  635. PrintValueContents( " 1: ", pIml1, pValueContents1 );
  636. PrintValueContents( " 2: ", pIml2, pValueContents2 );
  637. }
  638. }
  639. return Result;
  640. }
  641. char *IniActionStrings[] = {
  642. "CreateNewIniFile",
  643. "ModifyOldIniFile"
  644. };
  645. char *SectionActionStrings[] = {
  646. "CreateNewSection",
  647. "DeleteOldSection",
  648. "ModifySectionVariables"
  649. };
  650. char *VariableActionStrings[] = {
  651. "CreateNewVariable",
  652. "DeleteOldVariable",
  653. "ModifyOldVariable"
  654. };
  655. VOID
  656. PrintIniSectionVariableRecordIml(
  657. PINSTALLATION_MODIFICATION_LOGFILE pIml,
  658. PIML_GENERIC_RECORD pGeneric,
  659. PWSTR Parents[],
  660. ULONG Depth,
  661. ULONG i
  662. )
  663. {
  664. PIML_INI_RECORD pIni = (PIML_INI_RECORD)pGeneric;
  665. PIML_INISECTION_RECORD pSection = (PIML_INISECTION_RECORD)pGeneric;
  666. PIML_INIVARIABLE_RECORD pVariable = (PIML_INIVARIABLE_RECORD)pGeneric;
  667. if (Depth == 3) {
  668. printf( "Ini File: %ws\n %u: %s\n",
  669. MP( PWSTR, pIml, pIni->Name ),
  670. i, IniActionStrings[ pIni->Action ]
  671. );
  672. }
  673. else
  674. if (Depth == 2) {
  675. if (Parents[ 2 ] != NULL) {
  676. printf( "Ini File: %ws\n", Parents[ 2 ] );
  677. Parents[ 2 ] = NULL;
  678. }
  679. printf( " Section: %ws\n %u: %s\n",
  680. MP( PWSTR, pIml, pSection->Name ),
  681. i, SectionActionStrings[ pSection->Action ]
  682. );
  683. }
  684. else {
  685. if (Parents[ 2 ] != NULL) {
  686. printf( "Ini File: %ws\n", Parents[ 2 ] );
  687. Parents[ 2 ] = NULL;
  688. }
  689. if (Parents[ 1 ] != NULL) {
  690. printf( " Section: %ws\n", Parents[ 1 ] );
  691. Parents[ 1 ] = NULL;
  692. }
  693. printf( " Variable: %ws\n %u: %s\n",
  694. MP( PWSTR, pIml, pVariable->Name ),
  695. i, VariableActionStrings[ pVariable->Action ]
  696. );
  697. }
  698. }
  699. BOOLEAN
  700. CompareIniSectionVariableContentsIml(
  701. PINSTALLATION_MODIFICATION_LOGFILE pIml1,
  702. PIML_GENERIC_RECORD pGeneric1,
  703. PINSTALLATION_MODIFICATION_LOGFILE pIml2,
  704. PIML_GENERIC_RECORD pGeneric2,
  705. PWSTR Parents[]
  706. )
  707. {
  708. PIML_INIVARIABLE_RECORD pVariable1 = (PIML_INIVARIABLE_RECORD)pGeneric1;
  709. PIML_INIVARIABLE_RECORD pVariable2 = (PIML_INIVARIABLE_RECORD)pGeneric2;
  710. PWSTR pVariableContents1;
  711. PWSTR pVariableContents2;
  712. BOOLEAN ActionsDiffer = FALSE;
  713. BOOLEAN ContentsDiffer = FALSE;
  714. BOOLEAN Result = TRUE;
  715. pVariableContents1 = MP( PWSTR, pIml1, pVariable1->NewValue );
  716. pVariableContents2 = MP( PWSTR, pIml2, pVariable2->NewValue );
  717. if (pVariable1->Action != pVariable2->Action) {
  718. ActionsDiffer = TRUE;
  719. Result = FALSE;
  720. }
  721. else
  722. if (pVariableContents1 != NULL && pVariableContents2 != NULL) {
  723. if (wcscmp( pVariableContents1, pVariableContents2 ) != 0) {
  724. ContentsDiffer = TRUE;
  725. Result = FALSE;
  726. }
  727. }
  728. if (!Result) {
  729. if (Parents[ 2 ] != NULL) {
  730. printf( "Ini File: %ws\n", Parents[ 2 ] );
  731. Parents[ 2 ] = NULL;
  732. }
  733. if (Parents[ 1 ] != NULL) {
  734. printf( " Section: %ws\n", Parents[ 1 ] );
  735. Parents[ 1 ] = NULL;
  736. }
  737. printf( " Variable: %ws\n", MP( PWSTR, pIml1, pVariable1->Name ) );
  738. if (ActionsDiffer) {
  739. printf( " 1: Action - %s\n", VariableActionStrings[ pVariable1->Action ] );
  740. printf( " 2: Action - %s\n", VariableActionStrings[ pVariable2->Action ] );
  741. }
  742. if (ContentsDiffer) {
  743. printf( " 1: '%ws'\n", pVariableContents1 );
  744. printf( " 2: '%ws'\n", pVariableContents2 );
  745. }
  746. }
  747. return Result;
  748. }
  749. BOOLEAN
  750. CompareIml(
  751. PINSTALLATION_MODIFICATION_LOGFILE pIml1,
  752. PINSTALLATION_MODIFICATION_LOGFILE pIml2
  753. )
  754. {
  755. BOOLEAN Result = TRUE;
  756. PWSTR Parents[ 3 ];
  757. Result &= CompareGenericIml( pIml1, MP( PIML_GENERIC_RECORD, pIml1, pIml1->FileRecords ),
  758. pIml2, MP( PIML_GENERIC_RECORD, pIml2, pIml2->FileRecords ),
  759. NULL,
  760. 1,
  761. PrintFileRecordIml,
  762. CompareFileContentsIml
  763. );
  764. memset( Parents, 0, sizeof( Parents ) );
  765. Result &= CompareGenericIml( pIml1, MP( PIML_GENERIC_RECORD, pIml1, pIml1->KeyRecords ),
  766. pIml2, MP( PIML_GENERIC_RECORD, pIml2, pIml2->KeyRecords ),
  767. Parents,
  768. 2,
  769. PrintKeyValueRecordIml,
  770. CompareKeyValueContentsIml
  771. );
  772. memset( Parents, 0, sizeof( Parents ) );
  773. Result &= CompareGenericIml( pIml1, MP( PIML_GENERIC_RECORD, pIml1, pIml1->IniRecords ),
  774. pIml2, MP( PIML_GENERIC_RECORD, pIml2, pIml2->IniRecords ),
  775. Parents,
  776. 3,
  777. PrintIniSectionVariableRecordIml,
  778. CompareIniSectionVariableContentsIml
  779. );
  780. return Result;
  781. }