Source code of Windows XP (NT5)
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.

1294 lines
39 KiB

  1. //--------------------------------------------------------------
  2. //
  3. // File: bothchar
  4. //
  5. // Contents: Functions that need to be compiled as ascii for
  6. // scanstate and unicode for loadstate.
  7. //
  8. //---------------------------------------------------------------
  9. #include "bothchar.hxx"
  10. //---------------------------------------------------------------
  11. // Constants
  12. UCHAR EMPTY_STRING[] = "";
  13. const UCHAR NEWLINE_SET[256] =
  14. {
  15. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0,
  16. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  17. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  18. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  19. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  20. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  21. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  22. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  23. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  24. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  25. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  26. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  27. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  28. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  29. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
  30. 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
  31. };
  32. const DWORD VERBOSE_BIT = 0x01; // used with -v flag
  33. const DWORD DEBUGOUTPUT_BIT = 0x02; // used with -v flag
  34. const DWORD VERBOSEREG_BIT = 0x04; // used with -v flag
  35. #define LOADSTATE_KEY TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Loadstate")
  36. //---------------------------------------------------------------
  37. // Globals.
  38. TCHAR *DomainName = NULL;
  39. TCHAR *UserName = NULL;
  40. TCHAR *UserPath = NULL;
  41. //---------------------------------------------------------------
  42. void CStringList::Add( CStringList *pslMore )
  43. {
  44. CStringList *b;
  45. CStringList *c;
  46. CStringList *d;
  47. // Do nothing if there is no list.
  48. if (pslMore == NULL)
  49. return;
  50. // Determine some nodes to work with.
  51. b = pslMore->_pslNext;
  52. c = pslMore;
  53. d = _pslNext;
  54. // Relink the list so head points to b is a list to c points to d is
  55. // a list back to head.
  56. _pslNext = b;
  57. c->_pslNext = d;
  58. }
  59. //---------------------------------------------------------------
  60. CStringList::CStringList( DWORD dwLen )
  61. {
  62. _pslNext = this;
  63. if (dwLen == 0)
  64. {
  65. _ptsString = NULL;
  66. _fHead = TRUE;
  67. }
  68. else
  69. {
  70. _fHead = FALSE;
  71. _ptsString = (TCHAR *) malloc( dwLen*sizeof(TCHAR) );
  72. }
  73. }
  74. //---------------------------------------------------------------
  75. CStringList::~CStringList()
  76. {
  77. CStringList *pslCurrent = _pslNext;
  78. CStringList *pslEnd;
  79. // Non header nodes just free their string.
  80. if (_ptsString != NULL)
  81. free( _ptsString );
  82. // Header nodes free the list.
  83. if (_fHead)
  84. {
  85. while (pslCurrent != this)
  86. {
  87. pslEnd = pslCurrent->_pslNext;
  88. delete pslCurrent;
  89. pslCurrent = pslEnd;
  90. }
  91. }
  92. }
  93. //---------------------------------------------------------------
  94. DWORD ParseSectionList( INFCONTEXT *pic,
  95. TCHAR **pptsLabel,
  96. CStringList **pslList )
  97. {
  98. DWORD len;
  99. BOOL fSuccess;
  100. DWORD dwFields;
  101. DWORD i;
  102. DWORD dwResult = ERROR_SUCCESS;
  103. CStringList *pslCurrent;
  104. // Initialize output
  105. *pslList = NULL;
  106. // Query the length of the label name
  107. fSuccess = SetupGetStringField( pic, 0, NULL, 0, &len );
  108. LOG_ASSERT_GLE( fSuccess, dwResult );
  109. // Allocate space
  110. *pptsLabel = (TCHAR *) malloc( len * sizeof(TCHAR) );
  111. LOG_ASSERT_EXPR( *pptsLabel != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
  112. ERROR_NOT_ENOUGH_MEMORY );
  113. // Read the label name
  114. fSuccess = SetupGetStringField( pic, 0, *pptsLabel, len, NULL );
  115. LOG_ASSERT_GLE( fSuccess, dwResult );
  116. // Find out how many fields are on the line.
  117. dwFields = SetupGetFieldCount( pic );
  118. LOG_ASSERT_GLE( dwFields != 0, dwResult );
  119. // Read each field.
  120. for (i = 1; i <= dwFields; i++)
  121. {
  122. // Query the length of the field
  123. fSuccess = SetupGetStringField( pic, i, NULL, 0, &len );
  124. LOG_ASSERT_GLE( fSuccess, dwResult );
  125. // Allocate a new node.
  126. pslCurrent = new CStringList( len );
  127. LOG_ASSERT_EXPR( pslCurrent != NULL,
  128. IDS_NOT_ENOUGH_MEMORY,
  129. dwResult,
  130. ERROR_NOT_ENOUGH_MEMORY);
  131. LOG_ASSERT_EXPR( pslCurrent->String() != NULL,
  132. IDS_NOT_ENOUGH_MEMORY,
  133. dwResult,
  134. ERROR_NOT_ENOUGH_MEMORY );
  135. // Copy the field into the node.
  136. fSuccess = SetupGetStringField( pic, i, pslCurrent->String(), len, NULL );
  137. LOG_ASSERT_GLE( fSuccess, dwResult );
  138. // Link the node in the list.
  139. if (*pslList == NULL)
  140. *pslList = pslCurrent;
  141. else
  142. (*pslList)->Add( pslCurrent );
  143. }
  144. cleanup:
  145. return dwResult;
  146. }
  147. /***************************************************************************
  148. ParseRegPath
  149. Read a string field from a line in the rules inf file and parse it
  150. into a root, key, and value. All components of the reg path are optional.
  151. root\key [value]
  152. ***************************************************************************/
  153. DWORD ParseRegPath( INFCONTEXT *pic,
  154. DWORD dwField,
  155. TCHAR **pptsRoot,
  156. TCHAR **pptsKey,
  157. TCHAR **pptsValue )
  158. {
  159. TCHAR *ptsBuffer = NULL;
  160. TCHAR *ptsStop;
  161. TCHAR *ptsStart;
  162. TCHAR *bracket;
  163. BOOL fSuccess;
  164. DWORD dwLen = 0;
  165. DWORD dwResult = ERROR_SUCCESS;
  166. //Null out return values in case of later error.
  167. *pptsRoot = NULL;
  168. *pptsKey = NULL;
  169. *pptsValue = NULL;
  170. // Compute the length of the reg path field.
  171. SetupGetStringField( pic, dwField, NULL, 0, &dwLen );
  172. // Allocate a buffer.
  173. ptsBuffer = (TCHAR *) malloc( dwLen*sizeof(TCHAR) );
  174. LOG_ASSERT_EXPR( ptsBuffer != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
  175. ERROR_NOT_ENOUGH_MEMORY );
  176. // Get the whole reg path. The function fails if the field is empty.
  177. fSuccess = SetupGetStringField( pic, dwField, ptsBuffer, dwLen, &dwLen );
  178. if (!fSuccess)
  179. {
  180. free( ptsBuffer );
  181. return ERROR_SUCCESS;
  182. }
  183. // Look for a backslash.
  184. ptsStop = _tcschr( ptsBuffer, TEXT('\\') );
  185. // If there wasn't one, there is no root.
  186. if (ptsStop == NULL)
  187. {
  188. *pptsRoot = NULL;
  189. ptsStart = ptsBuffer;
  190. }
  191. // If there was one, copy the root name.
  192. else
  193. {
  194. *pptsRoot = (TCHAR *) malloc( ((ptsStop - ptsBuffer) + 1) *
  195. sizeof(TCHAR) );
  196. LOG_ASSERT_EXPR( *pptsRoot != NULL,
  197. IDS_NOT_ENOUGH_MEMORY,
  198. dwResult,
  199. ERROR_NOT_ENOUGH_MEMORY );
  200. _tcsncpy( *pptsRoot, ptsBuffer, ptsStop - ptsBuffer );
  201. (*pptsRoot)[ptsStop - ptsBuffer] = 0;
  202. ptsStart = ptsStop + 1;
  203. }
  204. // Look for an opening square bracket.
  205. ptsStop = _tcschr( ptsStart, TEXT('[') );
  206. // If there wasn't one, copy the rest of the string to the key name.
  207. if (ptsStop == NULL)
  208. {
  209. if (ptsStart[0] == 0)
  210. *pptsKey = NULL;
  211. else
  212. {
  213. *pptsKey = (TCHAR *) malloc( (dwLen - (ptsStart - ptsBuffer)) *
  214. sizeof(TCHAR) );
  215. *pptsValue = NULL;
  216. LOG_ASSERT_EXPR( *pptsKey != NULL,
  217. IDS_NOT_ENOUGH_MEMORY,
  218. dwResult,
  219. ERROR_NOT_ENOUGH_MEMORY );
  220. _tcscpy( *pptsKey, ptsStart );
  221. }
  222. }
  223. // Handle an optional key and a value.
  224. else
  225. {
  226. // Back up past any intervening white space.
  227. bracket = ptsStop + 1;
  228. while (ptsStop != ptsStart &&
  229. (ptsStop[0] == TEXT(' ') || ptsStop[0] == TEXT('[')))
  230. ptsStop -= 1;
  231. // If there are any characters left, copy them to the key.
  232. if (ptsStop != ptsStart)
  233. {
  234. ptsStop += 1;
  235. *pptsKey = (TCHAR *) malloc( ((ptsStop - ptsStart) + 1) *
  236. sizeof(TCHAR) );
  237. LOG_ASSERT_EXPR( *pptsKey != NULL,
  238. IDS_NOT_ENOUGH_MEMORY,
  239. dwResult,
  240. ERROR_NOT_ENOUGH_MEMORY );
  241. _tcsncpy( *pptsKey, ptsStart, ptsStop - ptsStart );
  242. (*pptsKey)[ptsStop - ptsStart] = 0;
  243. }
  244. else
  245. *pptsKey = NULL;
  246. // Find the closing square bracket.
  247. ptsStart = bracket;
  248. bracket = _tcschr( ptsStart, TEXT(']') );
  249. LOG_ASSERT_EXPR( bracket != NULL,
  250. IDS_INF_ERROR,
  251. dwResult,
  252. SPAPI_E_GENERAL_SYNTAX );
  253. // Copy the value name.
  254. *pptsValue = (TCHAR *) malloc( ((bracket - ptsStart) + 1) *
  255. sizeof(TCHAR) );
  256. LOG_ASSERT_EXPR( *pptsValue != NULL,
  257. IDS_NOT_ENOUGH_MEMORY,
  258. dwResult,
  259. ERROR_NOT_ENOUGH_MEMORY );
  260. _tcsncpy( *pptsValue, ptsStart, bracket - ptsStart );
  261. (*pptsValue)[bracket - ptsStart] = 0;
  262. }
  263. cleanup:
  264. if (ptsBuffer != NULL)
  265. free( ptsBuffer );
  266. return dwResult;
  267. }
  268. /***************************************************************************
  269. ParseRule
  270. Read a line from the rules inf file in one of the following formats.
  271. When partial paths are specified, compute the full path. Create a rule
  272. record from the line.
  273. reg_path2 is optional and reg_path is parsed by the function
  274. ParseRegPath into a root, key, and value.
  275. reg-path1 = reg_path2
  276. If reg_path2 contains just a leaf name, generate a full path using
  277. the path from reg_path1 and replacing its leaf with the leaf from reg_path2.
  278. ***************************************************************************/
  279. DWORD ParseRule( INFCONTEXT *pic, HASH_NODE **pphnRule )
  280. {
  281. TCHAR *ptsBuffer;
  282. DWORD dwReqLen;
  283. DWORD dwResult = ERROR_SUCCESS;
  284. BOOL fSuccess;
  285. TCHAR *ptsLast;
  286. TCHAR *ptsTemp;
  287. // Allocate a new rule.
  288. *pphnRule = (HASH_NODE *) malloc( sizeof(HASH_NODE) );
  289. LOG_ASSERT_EXPR( *pphnRule != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
  290. ERROR_NOT_ENOUGH_MEMORY );
  291. (*pphnRule)->dwAction = 0;
  292. (*pphnRule)->phnNext = 0;
  293. (*pphnRule)->ptsNewValue = NULL;
  294. (*pphnRule)->ptsNewKey = NULL;
  295. (*pphnRule)->ptsFunction = NULL;
  296. (*pphnRule)->ptsFileDest = NULL;
  297. // Get the first reg path.
  298. dwResult = ParseRegPath( pic,
  299. 0,
  300. &(*pphnRule)->ptsRoot,
  301. &(*pphnRule)->ptsKey,
  302. &(*pphnRule)->ptsValue );
  303. FAIL_ON_ERROR( dwResult );
  304. // Get the second reg path.
  305. dwResult = ParseRegPath( pic,
  306. 1,
  307. &ptsBuffer,
  308. &(*pphnRule)->ptsNewKey,
  309. &(*pphnRule)->ptsNewValue );
  310. FAIL_ON_ERROR( dwResult );
  311. // Get the optional regfile destination
  312. fSuccess = SetupGetStringField( pic, 2, NULL, 0, &dwReqLen );
  313. if ((TRUE == fSuccess) && (dwReqLen > 0))
  314. {
  315. (*pphnRule)->ptsFileDest = (TCHAR *)malloc(dwReqLen * sizeof(TCHAR));
  316. LOG_ASSERT_EXPR( (*pphnRule)->ptsFileDest != NULL, IDS_NOT_ENOUGH_MEMORY, dwResult,
  317. ERROR_NOT_ENOUGH_MEMORY );
  318. fSuccess = SetupGetStringField(pic, 2, (*pphnRule)->ptsFileDest, dwReqLen, NULL);
  319. LOG_ASSERT_GLE(fSuccess, dwResult);
  320. }
  321. // If the original key ends with a star, remove it and set the recursive
  322. // flag.
  323. if ((*pphnRule)->ptsKey != NULL)
  324. {
  325. dwReqLen = _tcslen( (*pphnRule)->ptsKey );
  326. if (dwReqLen > 2 &&
  327. (*pphnRule)->ptsKey[dwReqLen-1] == TEXT('*') &&
  328. (*pphnRule)->ptsKey[dwReqLen-2] == TEXT('\\'))
  329. {
  330. (*pphnRule)->dwAction |= recursive_fa;
  331. (*pphnRule)->ptsKey[dwReqLen-2] = 0;
  332. }
  333. // If there is a new key, set the rename_leaf or rename_path flag.
  334. if ((*pphnRule)->ptsNewKey != NULL)
  335. if ((*pphnRule)->dwAction & recursive_fa)
  336. (*pphnRule)->dwAction |= rename_path_fa;
  337. else
  338. (*pphnRule)->dwAction |= rename_leaf_fa;
  339. }
  340. // If there is a new value, set the rename_value flag.
  341. if ((*pphnRule)->ptsNewValue != NULL)
  342. (*pphnRule)->dwAction |= rename_value_fa;
  343. // If the new key did not contain a root, compute a full path for it.
  344. if (ptsBuffer == NULL &&
  345. (*pphnRule)->ptsKey != NULL &&
  346. (*pphnRule)->ptsNewKey != NULL)
  347. {
  348. // Find the last backslash in the key.
  349. ptsLast = (*pphnRule)->ptsKey;
  350. do
  351. {
  352. ptsTemp = _tcschr( ptsLast, TEXT('\\') );
  353. if (ptsTemp != NULL)
  354. ptsLast = ptsTemp+1;
  355. } while (ptsTemp != NULL);
  356. // Don't do anything if the original key contains just a leaf.
  357. if (ptsLast != (*pphnRule)->ptsKey)
  358. {
  359. // Allocate a ptsBuffer to hold the old path and the new leaf.
  360. free( ptsBuffer );
  361. dwReqLen = _tcslen( (*pphnRule)->ptsNewKey ) +
  362. (ptsLast - (*pphnRule)->ptsKey) + 2;
  363. ptsBuffer = (TCHAR *) malloc( dwReqLen*sizeof(TCHAR) );
  364. LOG_ASSERT_EXPR( ptsBuffer != NULL,
  365. IDS_NOT_ENOUGH_MEMORY,
  366. dwResult,
  367. ERROR_NOT_ENOUGH_MEMORY );
  368. // Copy in the old path and the new leaf.
  369. _tcsncpy( ptsBuffer,
  370. (*pphnRule)->ptsKey,
  371. (ptsLast - (*pphnRule)->ptsKey) );
  372. _tcscpy( &ptsBuffer[ptsLast-(*pphnRule)->ptsKey],
  373. (*pphnRule)->ptsNewKey );
  374. free( (*pphnRule)->ptsNewKey );
  375. (*pphnRule)->ptsNewKey = ptsBuffer;
  376. }
  377. }
  378. else
  379. free(ptsBuffer);
  380. // Consider freeing strings on error.
  381. cleanup:
  382. if (dwResult != ERROR_SUCCESS)
  383. {
  384. if (*pphnRule != NULL)
  385. {
  386. free((*pphnRule)->ptsRoot);
  387. free((*pphnRule)->ptsKey);
  388. free((*pphnRule)->ptsValue);
  389. free((*pphnRule)->ptsNewKey);
  390. free((*pphnRule)->ptsNewValue);
  391. free((*pphnRule)->ptsFunction);
  392. free((*pphnRule)->ptsFileDest);
  393. free(*pphnRule);
  394. *pphnRule = NULL;
  395. }
  396. }
  397. return dwResult;
  398. }
  399. //---------------------------------------------------------------
  400. // This function prints from an ascii format string to a unicode
  401. // win32 file handle. It is not thread safe.
  402. DWORD Win32Printf( HANDLE file, char *format, ... )
  403. {
  404. va_list va;
  405. DWORD dwWritten;
  406. DWORD dwLen;
  407. DWORD dwWideLength;
  408. WCHAR *pwsBuffer = NULL;
  409. const ULONG LINEBUFSIZE = 4096;
  410. #ifdef UNICODE
  411. char *pszBuffer;
  412. int iCharLen;
  413. char szOutputBuffer[LINEBUFSIZE];
  414. #endif
  415. BOOL fSuccess;
  416. TCHAR tcsPrintBuffer[LINEBUFSIZE];
  417. TCHAR *ptsFormat;
  418. #ifdef UNICODE
  419. WCHAR wcsFormat[LINEBUFSIZE];
  420. dwWideLength = MultiByteToWideChar(CP_ACP, 0, format, -1, NULL, 0);
  421. if (dwWideLength >= LINEBUFSIZE)
  422. {
  423. pwsBuffer = (WCHAR *)_alloca( dwWideLength * sizeof(WCHAR));
  424. if (pwsBuffer == NULL)
  425. return ERROR_NOT_ENOUGH_MEMORY;
  426. ptsFormat = pwsBuffer;
  427. if (!MultiByteToWideChar( CP_ACP,
  428. 0,
  429. format,
  430. -1,
  431. pwsBuffer,
  432. dwWideLength ))
  433. return GetLastError();
  434. }
  435. else
  436. {
  437. if (!MultiByteToWideChar(CP_ACP,
  438. 0,
  439. format,
  440. -1,
  441. wcsFormat,
  442. LINEBUFSIZE))
  443. {
  444. return GetLastError();
  445. }
  446. ptsFormat = wcsFormat;
  447. }
  448. #else
  449. ptsFormat = format;
  450. #endif
  451. va_start( va, format );
  452. // The doc says if wvsprintf fails, return value is less than
  453. // the length of the expected output. Since its hard to know the
  454. // correct output length, always clear the last error and always
  455. // check it.
  456. SetLastError(ERROR_SUCCESS);
  457. wvsprintf( tcsPrintBuffer, ptsFormat, va );
  458. va_end(va);
  459. if (GetLastError() != ERROR_SUCCESS)
  460. return GetLastError();
  461. // When printing to the console or logfile use ascii.
  462. // When printing to the migration file use Unicode.
  463. dwLen = _tcslen(tcsPrintBuffer);
  464. if ((file != OutputFile) || OutputAnsi)
  465. {
  466. #ifdef UNICODE
  467. //Convert to ANSI for output
  468. iCharLen = WideCharToMultiByte(CP_ACP,
  469. 0,
  470. tcsPrintBuffer,
  471. -1,
  472. NULL,
  473. 0,
  474. NULL,
  475. NULL);
  476. if (iCharLen >= LINEBUFSIZE)
  477. {
  478. pszBuffer = (char *)_alloca( iCharLen * sizeof(char));
  479. if (pszBuffer == NULL)
  480. return ERROR_OUTOFMEMORY;
  481. if (!WideCharToMultiByte(CP_ACP,
  482. 0,
  483. tcsPrintBuffer,
  484. -1,
  485. pszBuffer,
  486. iCharLen,
  487. NULL,
  488. NULL))
  489. return GetLastError();
  490. pwsBuffer = (WCHAR *)pszBuffer;
  491. }
  492. else
  493. {
  494. if (!WideCharToMultiByte(CP_ACP,
  495. 0,
  496. tcsPrintBuffer,
  497. -1,
  498. szOutputBuffer,
  499. LINEBUFSIZE,
  500. NULL,
  501. NULL))
  502. return GetLastError();
  503. pwsBuffer = (WCHAR *)szOutputBuffer;
  504. }
  505. dwWideLength = dwLen;
  506. #else
  507. pwsBuffer = (WCHAR *) tcsPrintBuffer;
  508. dwWideLength = dwLen;
  509. #endif
  510. }
  511. else
  512. {
  513. #ifdef UNICODE
  514. pwsBuffer = tcsPrintBuffer;
  515. dwWideLength = dwLen * sizeof(WCHAR);
  516. #else
  517. // Allocate a buffer to hold the unicode string.
  518. DEBUG_ASSERT( dwLen < LINEBUFSIZE );
  519. dwWideLength = MultiByteToWideChar( CP_ACP,
  520. 0,
  521. tcsPrintBuffer,
  522. dwLen,
  523. NULL,
  524. 0 );
  525. pwsBuffer = (WCHAR *) _alloca( dwWideLength*sizeof(WCHAR) );
  526. if (pwsBuffer == NULL)
  527. return ERROR_NOT_ENOUGH_MEMORY;
  528. // Convert the buffer to unicode.
  529. dwWideLength = MultiByteToWideChar( CP_ACP,
  530. 0,
  531. tcsPrintBuffer,
  532. dwLen,
  533. pwsBuffer,
  534. dwWideLength );
  535. if (dwWideLength == 0)
  536. return GetLastError();
  537. dwWideLength *= sizeof(WCHAR);
  538. #endif
  539. }
  540. // Write the unicode string.
  541. fSuccess = WriteFile( file, pwsBuffer, dwWideLength, &dwWritten, NULL );
  542. if (!fSuccess || dwWideLength != dwWritten)
  543. return GetLastError();
  544. if (file == STDERR)
  545. {
  546. //Also write to the log file for these
  547. fSuccess = WriteFile( LogFile,
  548. pwsBuffer,
  549. dwWideLength,
  550. &dwWritten,
  551. NULL );
  552. if (!fSuccess || dwWideLength != dwWritten)
  553. {
  554. return GetLastError();
  555. }
  556. }
  557. return ERROR_SUCCESS;
  558. }
  559. //*****************************************************************
  560. //
  561. // Synopsis: Recursive function to make the command line. We have to do
  562. // this because CStringList stores the parameter in reverse
  563. // order.
  564. //
  565. // Parameters: h
  566. // We need to know when we reach the end of the
  567. // CStringList, which is denoted by pointing back to the
  568. // head of the chain. But in a recursive function we lose
  569. // the head of the chain so it is passed in.
  570. //
  571. // History: 11/8/1999 Created by WeiruC.
  572. //
  573. // Return Value: Win32 error code.
  574. //
  575. //*****************************************************************
  576. void MakeCommandLine(CStringList* h, CStringList* command, TCHAR* commandLine)
  577. {
  578. if (h==NULL || command == NULL || commandLine == NULL)
  579. {
  580. if (DebugOutput)
  581. {
  582. Win32Printf(LogFile, "Error: NULL pointer passed to MakeCommandLine\r\n");
  583. }
  584. _tcscpy(commandLine, TEXT(""));
  585. return;
  586. }
  587. if(command->Next() != h)
  588. {
  589. MakeCommandLine(h, command->Next(), commandLine);
  590. }
  591. // No sizes of these buffers are passed in, so we must assume that there is enough space
  592. _tcscat(commandLine, TEXT("\""));
  593. _tcscat(commandLine, command->String());
  594. _tcscat(commandLine, TEXT("\""));
  595. _tcscat(commandLine, TEXT(" "));
  596. }
  597. //---------------------------------------------------------------
  598. // This is a variation of strpbrk. It searchs a string that may
  599. // contain nulls for any character in the set. It returns a pointer
  600. // to the first character in the set or null if the string does
  601. // not contain any characters in the set. Since the function
  602. // searchs past nulls in the str parameter, the len parameter
  603. // indicates the actual length of str. The set is an array of
  604. // booleans.
  605. UCHAR *mempbrk( UCHAR *str, DWORD len, const UCHAR set[256] )
  606. {
  607. DWORD i;
  608. for (i = 0; i < len; i++)
  609. if (set[str[i]] != 0)
  610. return &str[i];
  611. return NULL;
  612. }
  613. //---------------------------------------------------------------
  614. DWORD WriteKey( HANDLE outfile, DWORD type, TCHAR *rootname, TCHAR *key, TCHAR *value_name,
  615. UCHAR *data, DWORD data_len )
  616. {
  617. DWORD result = ERROR_SUCCESS;
  618. DWORD j;
  619. UCHAR *curr;
  620. DWORD orig = 0;
  621. // If a string contains an embedded carriage return or linefeed, save
  622. // it as binary and convert it back to a string on read.
  623. if (type == REG_SZ || type == REG_MULTI_SZ || type == REG_EXPAND_SZ)
  624. {
  625. curr = mempbrk( data, data_len, NEWLINE_SET );
  626. if (curr != NULL)
  627. {
  628. if (type == REG_SZ)
  629. orig = 0x400000;
  630. else if (type == REG_MULTI_SZ)
  631. orig = 0x100000;
  632. else
  633. orig = 0x200000;
  634. type = REG_BINARY;
  635. }
  636. }
  637. if (NULL == rootname)
  638. rootname = TEXT("");
  639. if (NULL == key)
  640. key = TEXT("");
  641. if (NULL == value_name)
  642. value_name = TEXT("");
  643. switch (type)
  644. {
  645. case REG_DWORD:
  646. if (data == NULL)
  647. *data = 0;
  648. result = Win32Printf( outfile, "%s, \"%s\", \"%s\", 0x10001, 0x%x\r\n", rootname, key,
  649. value_name, *((DWORD *) data) );
  650. FAIL_ON_ERROR( result );
  651. break;
  652. case REG_EXPAND_SZ:
  653. case REG_SZ:
  654. if (data == NULL)
  655. data = EMPTY_STRING;
  656. result = Win32Printf( outfile, "%s, \"%s\", \"%s\", 0x%x, \"%s\"\r\n", rootname,
  657. key, value_name,
  658. type == REG_SZ ? FLG_ADDREG_TYPE_SZ : FLG_ADDREG_TYPE_EXPAND_SZ,
  659. data );
  660. FAIL_ON_ERROR( result );
  661. break;
  662. case REG_MULTI_SZ:
  663. // Print the start of the line and the first string.
  664. if (data == NULL)
  665. data = EMPTY_STRING;
  666. result = Win32Printf( outfile, "%s, \"%s\", \"%s\", 0x10000, \"%s\"", rootname,
  667. key, value_name, data );
  668. FAIL_ON_ERROR( result );
  669. // Print each remaining string.
  670. curr = data+strlen((char *) data)+1;
  671. do
  672. {
  673. // Print a comma and the current string.
  674. Win32Printf( outfile, ", \"%s\"", curr );
  675. // Skip passed the current string and its null.
  676. curr += strlen((char *) curr)+1;
  677. } while ((DWORD) (curr - data) < data_len);
  678. // Print the trailing newline.
  679. result = Win32Printf( outfile, "\r\n" );
  680. FAIL_ON_ERROR( result );
  681. break;
  682. case REG_BINARY:
  683. case REG_NONE:
  684. default: // Unknown types, just copy the type and treat the data as binary
  685. // Print the start of the line.
  686. result = Win32Printf( outfile, "%s, \"%s\", \"%s\", 0x%x",
  687. rootname, key, value_name,
  688. ((type == REG_NONE ? 0x800000 : type ) | orig) );
  689. FAIL_ON_ERROR( result );
  690. // Print each byte in hex without the 0x prefix.
  691. for (j = 0; j < data_len; j++)
  692. {
  693. result = Win32Printf( outfile, ",%x", data[j] );
  694. FAIL_ON_ERROR( result );
  695. if ( (j+1) % 20 == 0)
  696. {
  697. result = Win32Printf( outfile, "\\\r\n" );
  698. FAIL_ON_ERROR( result );
  699. }
  700. }
  701. result = Win32Printf( outfile, "\r\n" );
  702. FAIL_ON_ERROR( result );
  703. break;
  704. }
  705. cleanup:
  706. return result;
  707. }
  708. //---------------------------------------------------------------
  709. //
  710. DWORD LogReadRule( HASH_NODE *phnNode )
  711. {
  712. DWORD dwRetval = ERROR_SUCCESS;
  713. BOOL fRuleFound = FALSE;
  714. dwRetval = Win32Printf(LogFile, "Read rule: ");
  715. FAIL_ON_ERROR( dwRetval );
  716. if (phnNode->dwAction & function_fa )
  717. {
  718. dwRetval = Win32Printf(LogFile, "function");
  719. FAIL_ON_ERROR( dwRetval );
  720. fRuleFound = TRUE;
  721. }
  722. if (phnNode->dwAction & (rename_leaf_fa | rename_path_fa | rename_value_fa))
  723. {
  724. dwRetval = Win32Printf(LogFile, "rename" );
  725. FAIL_ON_ERROR( dwRetval );
  726. fRuleFound = TRUE;
  727. }
  728. if (phnNode->dwAction & file_fa)
  729. {
  730. dwRetval = Win32Printf(LogFile, "copy file");
  731. FAIL_ON_ERROR( dwRetval );
  732. fRuleFound = TRUE;
  733. }
  734. if (phnNode->dwAction & delete_fa ||
  735. phnNode->dwAction & suppress_fa)
  736. {
  737. dwRetval = Win32Printf(LogFile, "delete" );
  738. FAIL_ON_ERROR( dwRetval );
  739. fRuleFound = TRUE;
  740. }
  741. // If none of the above, then it must be an addreg
  742. if ( fRuleFound == FALSE )
  743. {
  744. dwRetval = Win32Printf(LogFile, "addreg" );
  745. FAIL_ON_ERROR( dwRetval );
  746. }
  747. dwRetval = Win32Printf(LogFile,
  748. " %s\\%s ",
  749. phnNode->ptsRoot,
  750. phnNode->ptsKey);
  751. FAIL_ON_ERROR( dwRetval );
  752. if ( phnNode->ptsValue != NULL )
  753. {
  754. dwRetval = Win32Printf(LogFile,
  755. "[%s] ",
  756. phnNode->ptsValue );
  757. FAIL_ON_ERROR( dwRetval );
  758. }
  759. if ( phnNode->ptsNewKey != NULL || phnNode->ptsNewValue != NULL )
  760. {
  761. dwRetval = Win32Printf(LogFile, "to ");
  762. FAIL_ON_ERROR( dwRetval );
  763. if (phnNode->ptsNewKey != NULL)
  764. {
  765. dwRetval = Win32Printf(LogFile,
  766. "%s ",
  767. phnNode->ptsNewKey);
  768. FAIL_ON_ERROR( dwRetval );
  769. }
  770. if (phnNode->ptsNewValue != NULL)
  771. {
  772. dwRetval = Win32Printf(LogFile,
  773. "[%s]",
  774. phnNode->ptsNewValue);
  775. FAIL_ON_ERROR( dwRetval );
  776. }
  777. }
  778. dwRetval = Win32Printf(LogFile, "\r\n");
  779. FAIL_ON_ERROR( dwRetval );
  780. cleanup:
  781. return (dwRetval);
  782. }
  783. //---------------------------------------------------------------
  784. char *GetValueFromRegistry(const char *lpValue)
  785. {
  786. HKEY hKey;
  787. char *buffer = NULL;
  788. DWORD dwDataSize = 0;
  789. DWORD result;
  790. result = RegOpenKeyEx( HKEY_CURRENT_USER, LOADSTATE_KEY, 0, KEY_READ, &hKey );
  791. FAIL_ON_ERROR( result );
  792. // Determine size needed
  793. dwDataSize = 0;
  794. result = RegQueryValueExA( hKey, lpValue, NULL, NULL, NULL, &dwDataSize);
  795. FAIL_ON_ERROR( result );
  796. buffer = (char *)malloc((dwDataSize + 1) * sizeof(char));
  797. if (NULL == buffer)
  798. {
  799. Win32PrintfResource(Console, IDS_NOT_ENOUGH_MEMORY);
  800. goto cleanup;
  801. }
  802. result = RegQueryValueExA( hKey, lpValue, NULL, NULL,
  803. (LPBYTE)buffer, &dwDataSize);
  804. cleanup:
  805. if ((ERROR_SUCCESS != result) && (NULL != buffer))
  806. {
  807. free(buffer);
  808. buffer = NULL;
  809. }
  810. RegCloseKey(hKey);
  811. return buffer;
  812. }
  813. #define MAX_VALUE_LENGTH 255
  814. //---------------------------------------------------------------
  815. DWORD OpenInfsFromRegistry()
  816. {
  817. HKEY hKey;
  818. DWORD dwIndex = 0;
  819. char szData[MAX_PATH + 1];
  820. char szValueName[MAX_VALUE_LENGTH];
  821. DWORD dwValueSize;
  822. DWORD dwDataSize;
  823. DWORD result = ERROR_SUCCESS;
  824. result = RegOpenKeyEx( HKEY_CURRENT_USER, LOADSTATE_KEY, 0, KEY_READ, &hKey );
  825. FAIL_ON_ERROR( result );
  826. do
  827. {
  828. dwDataSize = MAX_PATH;
  829. dwValueSize = MAX_VALUE_LENGTH;
  830. result = RegEnumValueA(hKey, dwIndex,
  831. szValueName, &dwValueSize,
  832. NULL, NULL,
  833. (UCHAR *)szData, &dwDataSize);
  834. if (ERROR_NO_MORE_ITEMS != result)
  835. {
  836. FAIL_ON_ERROR( result );
  837. // If this is an Inf* key, then open the Inf file
  838. if (0 == strncmp(szValueName, "Inf", 3))
  839. {
  840. result = OpenInf( szData );
  841. FAIL_ON_ERROR( result );
  842. }
  843. dwIndex++;
  844. }
  845. } while (ERROR_SUCCESS == result);
  846. cleanup:
  847. RegCloseKey(hKey);
  848. return result;
  849. }
  850. //---------------------------------------------------------------
  851. DWORD ParseParams( int argc, char *argv[], BOOL scan, TCHAR *pszFullLogFilename )
  852. {
  853. int i;
  854. BOOL cleared_flags = FALSE;
  855. DWORD result;
  856. char *error;
  857. int iarg;
  858. BOOL fAppendLog = FALSE;
  859. BOOL fLogFile = FALSE;
  860. TCHAR *logfile = NULL;
  861. TCHAR szArgv[MAX_PATH + 1];
  862. char *lpData;
  863. // Save the OS version.
  864. Win9x = (GetVersion() & 0x80000000);
  865. // Check all the parameters.
  866. for (i = 1; i < argc; i++)
  867. {
  868. if (argv[i][0] == '/' ||
  869. argv[i][0] == '-')
  870. {
  871. switch (tolower(argv[i][1]))
  872. {
  873. case 'a':
  874. OutputAnsi = TRUE;
  875. break;
  876. case 'f':
  877. CopyFiles = TRUE;
  878. if (!cleared_flags)
  879. {
  880. CopyUser = FALSE;
  881. CopySystem = FALSE;
  882. SchedSystem = FALSE;
  883. cleared_flags = TRUE;
  884. }
  885. break;
  886. case 'i':
  887. // Verify that there is a file name.
  888. if (i == argc-1)
  889. {
  890. Win32PrintfResourceA( Console, IDS_INF_REQUIRED );
  891. PrintHelp( scan );
  892. return ERROR_INVALID_PARAMETER;
  893. }
  894. // Open the inf file.
  895. i += 1;
  896. result = OpenInf( argv[i] );
  897. if (result != ERROR_SUCCESS)
  898. return result;
  899. break;
  900. case 'l':
  901. // Verify that there is a file name.
  902. if (i == argc-1)
  903. {
  904. Win32PrintfResourceA( Console, IDS_LOG_REQUIRED );
  905. PrintHelp( scan );
  906. return ERROR_INVALID_PARAMETER;
  907. }
  908. // Fail if the log file was already specified.
  909. if (fLogFile == TRUE)
  910. {
  911. Win32PrintfResourceA( Console, IDS_LOG_ONCE );
  912. PrintHelp( scan );
  913. return ERROR_INVALID_PARAMETER;
  914. }
  915. i += 1;
  916. #ifdef _UNICODE
  917. if (0 == MultiByteToWideChar (GetACP(), 0, argv[i], -1, szArgv, MAX_PATH))
  918. {
  919. result = GetLastError();
  920. Win32PrintfResourceA( Console, IDS_INVALID_PARAMETER, argv[i] );
  921. return result;
  922. }
  923. logfile = szArgv;
  924. #else
  925. logfile = argv[i];
  926. #endif
  927. fLogFile = TRUE;
  928. break;
  929. case 'm':
  930. ReallyCopyFiles = FALSE;
  931. break;
  932. case 'p':
  933. UserPortion = TRUE;
  934. fAppendLog = TRUE;
  935. if (!scan)
  936. {
  937. if (fLogFile == TRUE)
  938. {
  939. Win32PrintfResourceA( Console, IDS_LOG_ONCE );
  940. PrintHelp( scan );
  941. return ERROR_INVALID_PARAMETER;
  942. }
  943. lpData = GetValueFromRegistry("Logfile");
  944. #ifdef _UNICODE
  945. if (0 == MultiByteToWideChar (GetACP(), 0, lpData, -1, szArgv, MAX_PATH))
  946. {
  947. result = GetLastError();
  948. Win32PrintfResourceA( Console, IDS_INVALID_PARAMETER, lpData);
  949. return result;
  950. }
  951. logfile = szArgv;
  952. #else
  953. logfile = lpData;
  954. #endif
  955. fLogFile = TRUE;
  956. MigrationPath = GetValueFromRegistry("Store");
  957. if (MigrationPath != NULL)
  958. {
  959. MultiByteToWideChar(CP_ACP, 0, MigrationPath, -1,
  960. wcsMigrationPath, MAX_PATH + 1);
  961. }
  962. OpenInfsFromRegistry();
  963. }
  964. break;
  965. case 'q':
  966. // TestMode will:
  967. // - skip version checking the OS
  968. // - not create a user hive with /f (still will with /u)
  969. TestMode = TRUE;
  970. break;
  971. case 'r': // run once
  972. SchedSystem = TRUE;
  973. if (!cleared_flags)
  974. {
  975. CopyFiles = FALSE;
  976. CopySystem = FALSE;
  977. CopyUser = FALSE;
  978. cleared_flags = TRUE;
  979. }
  980. break;
  981. case 's':
  982. CopySystem = TRUE;
  983. if (!cleared_flags)
  984. {
  985. CopyFiles = FALSE;
  986. CopyUser = FALSE;
  987. SchedSystem = FALSE;
  988. cleared_flags = TRUE;
  989. }
  990. break;
  991. case 'u':
  992. CopyUser = TRUE;
  993. if (!cleared_flags)
  994. {
  995. CopyFiles = FALSE;
  996. CopySystem = FALSE;
  997. SchedSystem = FALSE;
  998. cleared_flags = TRUE;
  999. }
  1000. break;
  1001. case 'v':
  1002. // Verify that there is a verbosity argument
  1003. i += 1;
  1004. if ((i == argc) || (1 != sscanf(argv[i], "%d", &iarg)))
  1005. {
  1006. Win32PrintfResourceA( Console, IDS_VERBOSE_FLAG_REQUIRED );
  1007. PrintHelp( scan );
  1008. return ERROR_INVALID_PARAMETER;
  1009. }
  1010. if ( ( iarg & VERBOSE_BIT ) == VERBOSE_BIT )
  1011. {
  1012. Verbose = TRUE;
  1013. }
  1014. if ( ( iarg & DEBUGOUTPUT_BIT ) == DEBUGOUTPUT_BIT )
  1015. {
  1016. DebugOutput = TRUE;
  1017. }
  1018. if ( ( iarg & VERBOSEREG_BIT ) == VERBOSEREG_BIT )
  1019. {
  1020. VerboseReg = TRUE;
  1021. }
  1022. break;
  1023. case 'x':
  1024. if (!cleared_flags)
  1025. {
  1026. CopyFiles = FALSE;
  1027. CopySystem = FALSE;
  1028. CopyUser = FALSE;
  1029. SchedSystem = FALSE;
  1030. cleared_flags = TRUE;
  1031. }
  1032. break;
  1033. case '9':
  1034. Win9x = TRUE;
  1035. break;
  1036. default:
  1037. // There should be no other switches defined.
  1038. Win32PrintfResourceA( Console, IDS_INVALID_PARAMETER, argv[i] );
  1039. PrintHelp( scan );
  1040. return ERROR_INVALID_PARAMETER;
  1041. }
  1042. }
  1043. else if (MigrationPath != NULL)
  1044. {
  1045. // The path to the server should be specified exactly once.
  1046. Win32PrintfResourceA( Console, IDS_INVALID_PARAMETER, argv[i] );
  1047. PrintHelp( scan );
  1048. return ERROR_INVALID_PARAMETER;
  1049. }
  1050. else
  1051. {
  1052. // Save the migration path.
  1053. MigrationPath = argv[i];
  1054. DWORD ccMigPath;
  1055. if (!(ccMigPath = MultiByteToWideChar(CP_ACP,
  1056. 0,
  1057. MigrationPath,
  1058. -1,
  1059. wcsMigrationPath,
  1060. MAX_PATH + 1)))
  1061. {
  1062. Win32PrintfResourceA( Console,
  1063. IDS_INVALID_PARAMETER,
  1064. MigrationPath );
  1065. PrintHelp( scan );
  1066. return ERROR_INVALID_PARAMETER;
  1067. }
  1068. }
  1069. }
  1070. // Verify that a path was specified.
  1071. if (MigrationPath == NULL)
  1072. {
  1073. Win32PrintfResourceA( Console, IDS_MISSING_MIGRATION );
  1074. PrintHelp( scan );
  1075. return ERROR_INVALID_PARAMETER;
  1076. }
  1077. // Open LogFile
  1078. if ( fLogFile == FALSE )
  1079. {
  1080. if (scan)
  1081. logfile = TEXT("scanstate.log");
  1082. else
  1083. logfile = TEXT("loadstate.log");
  1084. }
  1085. if (fAppendLog == FALSE)
  1086. {
  1087. // Delete any previous log
  1088. DeleteFile( logfile );
  1089. }
  1090. LogFile = CreateFile( logfile,
  1091. GENERIC_WRITE, 0, NULL,
  1092. fAppendLog ? OPEN_ALWAYS : CREATE_NEW,
  1093. FILE_ATTRIBUTE_NORMAL, NULL );
  1094. if (LogFile == INVALID_HANDLE_VALUE)
  1095. {
  1096. result = GetLastError();
  1097. Win32PrintfResourceA( Console, IDS_OPEN_LOG_ERROR, logfile );
  1098. error = NULL;
  1099. FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1100. FORMAT_MESSAGE_FROM_SYSTEM,
  1101. 0,
  1102. result,
  1103. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1104. (char *) &error,
  1105. 0,
  1106. NULL );
  1107. if (error != NULL)
  1108. {
  1109. Win32Printf( Console, error );
  1110. LocalFree( error );
  1111. }
  1112. return result;
  1113. }
  1114. else if (fAppendLog == TRUE)
  1115. {
  1116. // Move file pointer to the end of the file,
  1117. // so we won't overwrite previous entries
  1118. result = SetFilePointer( LogFile, 0, NULL, FILE_END);
  1119. if ( result == INVALID_SET_FILE_POINTER )
  1120. {
  1121. result = GetLastError();
  1122. Win32PrintfResourceA( Console, IDS_OPEN_LOG_ERROR, logfile );
  1123. error = NULL;
  1124. FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER |
  1125. FORMAT_MESSAGE_FROM_SYSTEM,
  1126. 0,
  1127. result,
  1128. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  1129. (char *) &error,
  1130. 0,
  1131. NULL );
  1132. if (error != NULL)
  1133. {
  1134. Win32Printf( Console, error );
  1135. LocalFree( error );
  1136. }
  1137. return result;
  1138. }
  1139. }
  1140. TCHAR *ptsFileNamePart;
  1141. result = GetFullPathName( logfile, MAX_PATH, pszFullLogFilename, &ptsFileNamePart);
  1142. if (0 == result)
  1143. {
  1144. return GetLastError();
  1145. }
  1146. return ERROR_SUCCESS;
  1147. }