Leaked source code of windows server 2003
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.

2909 lines
85 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. inifiles.c
  5. Abstract:
  6. There are two major actions that are performed in this module.
  7. 1. Migration of settings from the INI files to the registry according to
  8. subkeys from HKLM\Software\Microsoft\Windows NT\CurrentVersion\IniFileMapping.
  9. Entry point : ProcessIniFileMapping
  10. 2. Processing of INI files not listed in the above key, changing paths to
  11. files that we moved during upgrade.
  12. Entry point : ConvertIniFiles
  13. Author:
  14. Jim Schmidt (jimschm) 11-Sept-1997
  15. Revision History:
  16. jimschm 23-Sep-1998 Changed to use new fileops
  17. calinn 29-Jan-1998 Added lookup for Win95 registry
  18. calinn 19-Jan-1998 added support for Shell settings processing
  19. calinn 06-Oct-1997 rewrote the whole source
  20. calinn 11-May-1998 Added MergeIniSettings, various fixes
  21. --*/
  22. #include "pch.h"
  23. #include "migmainp.h"
  24. #include "..\merge\mergep.h"
  25. #define DBG_INIFILES "IniFiles"
  26. #define DBG_MOVEINISETTINGS "IniFileMove"
  27. #define BufferIncrement 1024
  28. BOOL
  29. pLoadIniFileBuffer (
  30. IN PCTSTR FileName,
  31. IN PCTSTR SectName,
  32. IN PCTSTR KeyName,
  33. OUT PTSTR *OutBuff
  34. );
  35. BOOL
  36. pCopyIniFileToRegistry (
  37. IN HKEY KeyHandle,
  38. IN PCTSTR FileName,
  39. IN BOOL UserMode
  40. );
  41. BOOL
  42. pTransferSectionByKey (
  43. IN PCTSTR OrigFileName,
  44. IN PCTSTR FileName,
  45. IN PCTSTR Section,
  46. IN HKEY SectionKey,
  47. IN OUT BOOL *IniFileChanged,
  48. IN BOOL UserMode
  49. );
  50. BOOL
  51. pTransferSectionByValue (
  52. IN PCTSTR OrigFileName,
  53. IN PCTSTR FileName,
  54. IN PCTSTR Section,
  55. IN PCTSTR SectionValue,
  56. IN OUT BOOL *IniFileChanged,
  57. IN BOOL UserMode
  58. );
  59. BOOL
  60. pSaveMappedValue (
  61. IN PCTSTR OrigFileName,
  62. IN PCTSTR Section,
  63. IN PCTSTR ValueName,
  64. IN PCTSTR RegPath,
  65. IN PCTSTR Value,
  66. IN OUT BOOL *ReverseMapping,
  67. OUT PTSTR *ReverseMapValue,
  68. IN BOOL UserMode
  69. );
  70. BOOL
  71. pBuildSuppressionTable (
  72. IN BOOL UserMode
  73. );
  74. VOID
  75. pFreeSuppressionTable (
  76. VOID
  77. );
  78. BOOL
  79. pIncompatibleShell (
  80. VOID
  81. );
  82. BOOL
  83. pIncompatibleSCR (
  84. VOID
  85. );
  86. BOOL
  87. ProcessIniFileMapping (
  88. IN BOOL UserMode
  89. )
  90. /*++
  91. Routine Description:
  92. ProcessIniFileMapping reads in the INI files, copying data to specific
  93. locations in the registry. This copy is based on the IniFileMapping key in
  94. Software\Microsoft\Windows NT\CurrentVersion.
  95. These mappings can be overridden based upon the content of the [Suppress Ini File Mappings] section.
  96. Arguments:
  97. UserMode - Specifies TRUE if per-user sections are to be processed, or
  98. FALSE if local machine sections are to be processed.
  99. Return Value:
  100. Always returns TRUE. If some error occured while processing, then there will be a log entry
  101. specifying that.
  102. --*/
  103. {
  104. REGKEY_ENUM e;
  105. HKEY IniMappingKey;
  106. HKEY OldRegRoot=NULL;
  107. BOOL Result = TRUE;
  108. DEBUGMSG ((DBG_INIFILES, "Processing INI file mapping - START"));
  109. if (UserMode) {
  110. OldRegRoot = GetRegRoot();
  111. SetRegRoot (g_hKeyRootNT);
  112. }
  113. __try {
  114. if (!EnumFirstRegKeyStr (&e, S_INIFILEMAPPING_KEY)) {
  115. //
  116. // nothing to do here
  117. //
  118. __leave;
  119. }
  120. //
  121. // There is at least one file mapping to process.
  122. // Fill the table of ini file suppression table.
  123. //
  124. __try {
  125. //
  126. // Trying to load the suppression table, recording the eventual error
  127. // but going on with the stuff
  128. //
  129. if (!pBuildSuppressionTable(UserMode)) {
  130. Result = FALSE;
  131. }
  132. // Special case : SHELL= line from SYSTEM.INI
  133. // We try to see if the current shell is supported on NT.
  134. // If not then we will add SHELL to this suppression table
  135. // ensuring that the NT registry setting will get mapped into
  136. // the INI file
  137. if ((!UserMode) &&
  138. (pIncompatibleShell())
  139. ) {
  140. MemDbSetValueEx (
  141. MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW,
  142. TEXT("SYSTEM.INI"),
  143. TEXT("BOOT"),
  144. TEXT("SHELL"),
  145. 0,
  146. NULL
  147. );
  148. }
  149. if ((UserMode) &&
  150. (pIncompatibleSCR())) {
  151. MemDbSetValueEx (
  152. MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW,
  153. TEXT("SYSTEM.INI"),
  154. TEXT("BOOT"),
  155. TEXT("SCRNSAVE.EXE"),
  156. 0,
  157. NULL
  158. );
  159. }
  160. //
  161. // Now processing keys
  162. //
  163. do {
  164. IniMappingKey = OpenRegKey (e.KeyHandle, e.SubKeyName);
  165. if (IniMappingKey) {
  166. //
  167. // Process the file mapping
  168. //
  169. if (!pCopyIniFileToRegistry (
  170. IniMappingKey,
  171. e.SubKeyName,
  172. UserMode
  173. )) {
  174. Result = FALSE;
  175. }
  176. CloseRegKey(IniMappingKey);
  177. }
  178. else {
  179. DEBUGMSG ((DBG_INIFILES, "IniFileMapping : Could not open %s", e.SubKeyName));
  180. Result = FALSE;
  181. }
  182. } while (EnumNextRegKey (&e));
  183. pFreeSuppressionTable();
  184. }
  185. __finally {
  186. AbortRegKeyEnum (&e);
  187. }
  188. }
  189. __finally {
  190. if (UserMode) {
  191. SetRegRoot (OldRegRoot);
  192. }
  193. }
  194. DEBUGMSG ((DBG_INIFILES, "Processing INI file mapping - STOP"));
  195. if (!Result) {
  196. //
  197. // we are going to log that at least one error occured while processing IniFileMapping
  198. //
  199. DEBUGMSG ((DBG_ERROR, (PCSTR)MSG_INI_FILE_MAPPING_LOG));
  200. }
  201. return TRUE;
  202. }
  203. BOOL
  204. pIncompatibleShell (
  205. VOID
  206. )
  207. {
  208. TCHAR key [MEMDB_MAX];
  209. TCHAR shellVal[MEMDB_MAX] = TEXT("");
  210. PCTSTR fileName;
  211. PCTSTR newName;
  212. DWORD result;
  213. fileName = JoinPaths (g_WinDir, TEXT("SYSTEM.INI"));
  214. newName = GetTemporaryLocationForFile (fileName);
  215. if (newName) {
  216. DEBUGMSG ((DBG_INIFILES, "pIncompatibleShell: Using %s for %s", newName, fileName));
  217. FreePathString (fileName);
  218. fileName = newName;
  219. }
  220. if (!DoesFileExist (fileName)) {
  221. DEBUGMSG ((DBG_INIFILES, "pIncompatibleShell: %s not found", fileName));
  222. }
  223. result = GetPrivateProfileString (
  224. TEXT("boot"),
  225. TEXT("shell"),
  226. TEXT("explorer.exe"),
  227. shellVal,
  228. MEMDB_MAX,
  229. fileName);
  230. FreePathString (fileName);
  231. if ((result == 0) ||
  232. (result + 1 == MEMDB_MAX)
  233. ) {
  234. return FALSE;
  235. }
  236. MemDbBuildKey (key, MEMDB_CATEGORY_COMPATIBLE_SHELL_NT, shellVal, NULL, NULL);
  237. return (!MemDbGetValue (key, NULL));
  238. }
  239. BOOL
  240. pIncompatibleSCR (
  241. VOID
  242. )
  243. {
  244. TCHAR scrVal [MEMDB_MAX] = TEXT("");
  245. PCTSTR fileName;
  246. PCTSTR newName;
  247. DWORD result;
  248. fileName = JoinPaths (g_WinDir, TEXT("SYSTEM.INI"));
  249. newName = GetTemporaryLocationForFile (fileName);
  250. if (newName) {
  251. DEBUGMSG ((DBG_INIFILES, "pIncompatibleSCR: Using %s for %s", newName, fileName));
  252. FreePathString (fileName);
  253. fileName = newName;
  254. }
  255. if (!DoesFileExist (fileName)) {
  256. DEBUGMSG ((DBG_INIFILES, "pIncompatibleSCR: %s not found", fileName));
  257. }
  258. result = GetPrivateProfileString (
  259. TEXT("boot"),
  260. TEXT("SCRNSAVE.EXE"),
  261. TEXT(""),
  262. scrVal,
  263. MEMDB_MAX,
  264. fileName);
  265. FreePathString (fileName);
  266. if ((result == 0) ||
  267. (result + 1 == MEMDB_MAX)
  268. ) {
  269. return FALSE;
  270. }
  271. return IsFileMarkedForDelete (scrVal);
  272. }
  273. BOOL
  274. pLoadIniFileBuffer (
  275. IN PCTSTR FileName,
  276. IN PCTSTR SectName,
  277. IN PCTSTR KeyName,
  278. OUT PTSTR *OutBuff
  279. )
  280. /*++
  281. Routine Description:
  282. This routine uses GetPrivateProfileString routine trying to load a section buffer, a key buffer or
  283. a key value (depends on the arguments). The reason why there is such a routine is to be sure that
  284. we are able to load stuff from INI file while not allocating a lot of memory. This routine incrementaly
  285. allocates memory, returning when there is enough memory to load stuff from INI file.
  286. Arguments:
  287. FileName - Specifies INI file to be processed
  288. SectName - Specifies section to be processed. If NULL the whole section buffer will be loaded
  289. KeyName - Specifies the key to be processed. If NULL the whole key buffer will be loaded.
  290. OutBuff - Output buffer holding the result.
  291. Return Value:
  292. TRUE if successful, FALSE otherwise
  293. --*/
  294. {
  295. DWORD OutBuffSize;
  296. DWORD ReadSize;
  297. BOOL Done;
  298. OutBuffSize = 0;
  299. *OutBuff = NULL;
  300. do {
  301. if (*OutBuff) {
  302. MemFree (g_hHeap, 0, *OutBuff);
  303. }
  304. OutBuffSize += BufferIncrement;
  305. *OutBuff = MemAlloc (g_hHeap, 0, OutBuffSize * sizeof (TCHAR));
  306. if (!(*OutBuff)) {
  307. return FALSE;
  308. }
  309. ReadSize = GetPrivateProfileString (
  310. SectName,
  311. KeyName,
  312. TEXT(""),
  313. *OutBuff,
  314. OutBuffSize,
  315. FileName
  316. );
  317. if (SectName && KeyName) {
  318. Done = (ReadSize < OutBuffSize - 1);
  319. } else {
  320. Done = (ReadSize < OutBuffSize - 2);
  321. }
  322. } while (!Done);
  323. return TRUE;
  324. }
  325. BOOL
  326. pCopyIniFileToRegistry (
  327. IN HKEY KeyHandle,
  328. IN PCTSTR FileName,
  329. IN BOOL UserMode
  330. )
  331. /*++
  332. Routine Description:
  333. This routine transports settings from the INI file into registry or from the registry to
  334. the INI file.
  335. Arguments:
  336. KeyHandle - IniFileMapping key associated with this INI file.
  337. FileName - Specifies INI file to be processed
  338. UserMode - Specifies TRUE if per-user sections are to be processed, or
  339. FALSE if local machine sections are to be processed.
  340. Return Value:
  341. TRUE if successful, FALSE if at least one error occured
  342. --*/
  343. {
  344. PCTSTR NewName = NULL;
  345. PCTSTR FullPath = NULL;
  346. TCHAR TempPath[MEMDB_MAX];
  347. PTSTR Section, SectionBuf;
  348. HKEY SectionKey;
  349. PCTSTR SectionValue;
  350. DWORD Attribs = -1;
  351. BOOL IniFileChanged = FALSE;
  352. BOOL mapToIniFile = FALSE;
  353. BOOL Result = TRUE;
  354. DEBUGMSG ((DBG_INIFILES, "Processing %s - START", FileName));
  355. //
  356. // now we have the full path for the INI file
  357. // Since we are going to use Ini file API we have to copy every file to some other name
  358. // to avoid mapping requests into registry
  359. //
  360. if (!GetTempFileName (g_WinDir, TEXT("INI"), 0, TempPath)) {
  361. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot create a temporary file"));
  362. return FALSE;
  363. }
  364. __try {
  365. FullPath = JoinPaths (g_WinDir, FileName);
  366. NewName = GetTemporaryLocationForFile (FullPath);
  367. if (NewName) {
  368. DEBUGMSG ((DBG_INIFILES, "Using %s for %s", NewName, FullPath));
  369. FreePathString (FullPath);
  370. FullPath = NewName;
  371. }
  372. Attribs = GetFileAttributes (FullPath);
  373. if (Attribs == (DWORD)-1) {
  374. DEBUGMSG ((DBG_INIFILES, "pCopyIniFileToRegistry: %s not found", FullPath));
  375. __leave;
  376. }
  377. //
  378. // now trying to copy file
  379. //
  380. if (!CopyFile (FullPath, TempPath, FALSE)) {
  381. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot copy %s to %s", FullPath, TempPath));
  382. Result = FALSE;
  383. __leave;
  384. }
  385. SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
  386. __try {
  387. //
  388. // Next thing we are going to do is to load the sections in a buffer
  389. //
  390. if (!pLoadIniFileBuffer (TempPath, NULL, NULL, &SectionBuf)) {
  391. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot load section buffer for %s", TempPath));
  392. Result = FALSE;
  393. __leave;
  394. }
  395. __try {
  396. //
  397. // now we have all sections of the INI file and proceeding
  398. //
  399. Section = SectionBuf;
  400. //
  401. // there is a loop here for every section in the buffer
  402. //
  403. while (*Section) {
  404. //
  405. // now trying to see if there is a subkey matching section name.
  406. //
  407. SectionKey = OpenRegKey (KeyHandle, Section);
  408. if (SectionKey) {
  409. if (!pTransferSectionByKey (
  410. FileName,
  411. TempPath,
  412. Section,
  413. SectionKey,
  414. &IniFileChanged,
  415. UserMode
  416. )) {
  417. Result = FALSE;
  418. }
  419. CloseRegKey (SectionKey);
  420. }
  421. else {
  422. SectionValue = GetRegValueString (KeyHandle, Section);
  423. if (!SectionValue) {
  424. SectionValue = GetRegValueString (KeyHandle, S_EMPTY);
  425. }
  426. if (SectionValue && (*SectionValue)) {
  427. if (!pTransferSectionByValue (
  428. FileName,
  429. TempPath,
  430. Section,
  431. SectionValue,
  432. &IniFileChanged,
  433. UserMode
  434. )) {
  435. Result = FALSE;
  436. }
  437. }
  438. if (SectionValue) {
  439. MemFree (g_hHeap, 0, SectionValue);
  440. }
  441. }
  442. Section = GetEndOfString (Section) + 1;
  443. }
  444. }
  445. __finally {
  446. if (SectionBuf) {
  447. MemFree (g_hHeap, 0 , SectionBuf);
  448. }
  449. }
  450. //
  451. // finally, if we made any changes then we will copy the INI file back
  452. //
  453. if (IniFileChanged) {
  454. // flushing the INI file
  455. WritePrivateProfileString (
  456. NULL,
  457. NULL,
  458. NULL,
  459. TempPath
  460. );
  461. if (!CopyFile (TempPath, FullPath, FALSE)) {
  462. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot copy %s to %s", TempPath, FullPath));
  463. #pragma prefast(suppress:242, "Don't care about perf of try/finally here")
  464. return FALSE;
  465. }
  466. }
  467. }
  468. __finally {
  469. SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
  470. DeleteFile (TempPath);
  471. }
  472. }
  473. __finally {
  474. if (Attribs != (DWORD)-1) {
  475. SetFileAttributes (FullPath, Attribs);
  476. }
  477. if (FullPath) {
  478. FreePathString (FullPath);
  479. }
  480. SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
  481. DeleteFile (TempPath);
  482. DEBUGMSG ((DBG_INIFILES, "Processing %s - STOP", FileName));
  483. }
  484. return Result;
  485. }
  486. BOOL
  487. pTransferSectionByKey (
  488. IN PCTSTR OrigFileName,
  489. IN PCTSTR FileName,
  490. IN PCTSTR Section,
  491. IN HKEY SectionKey,
  492. IN OUT BOOL *IniFileChanged,
  493. IN BOOL UserMode
  494. )
  495. /*++
  496. Routine Description:
  497. This routine transports settings from a specified section of an INI file
  498. into registry or from the registry to the INI file. If there is a case when
  499. the settings go from registry to INI file then IniFileChanged is set to TRUE
  500. Arguments:
  501. FileName - Specifies INI file to be processed
  502. Section - Specifies section to be processed
  503. SectionKey - key associated with this section
  504. IniFileChanged - Tells the caller that at least one setting was from registry to the INI file
  505. UserMode - Specifies TRUE if per-user sections are to be processed, or
  506. FALSE if local machine sections are to be processed.
  507. Return Value:
  508. TRUE if successful, FALSE if at least one error occured
  509. --*/
  510. {
  511. PTSTR Key, KeyBuf;
  512. PTSTR KeyValue;
  513. PCTSTR SectionValue;
  514. BOOL ReverseMapping;
  515. PTSTR ReverseMapValue;
  516. BOOL Result = TRUE;
  517. if (!pLoadIniFileBuffer (FileName, Section, NULL, &KeyBuf)) {
  518. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot load key buffer for %s in %s", Section, FileName));
  519. return FALSE;
  520. }
  521. __try {
  522. //
  523. // now we have all keys of the section and proceeding
  524. //
  525. Key = KeyBuf;
  526. //
  527. // there is a loop here for every key in the buffer
  528. //
  529. while (*Key) {
  530. //
  531. // trying to read the value for the key
  532. //
  533. if (!pLoadIniFileBuffer (FileName, Section, Key, &KeyValue)) {
  534. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot load key %s in %s in %s", Key, Section, FileName));
  535. Result = FALSE;
  536. continue;
  537. }
  538. __try {
  539. SectionValue = GetRegValueString (SectionKey, Key);
  540. if (!SectionValue) {
  541. SectionValue = GetRegValueString (SectionKey, S_EMPTY);
  542. }
  543. if (SectionValue && (*SectionValue)) {
  544. if (!pSaveMappedValue (
  545. OrigFileName,
  546. Section,
  547. Key,
  548. SectionValue,
  549. KeyValue,
  550. &ReverseMapping,
  551. &ReverseMapValue,
  552. UserMode
  553. )) {
  554. Result = FALSE;
  555. }
  556. if (UserMode && ReverseMapping) {
  557. if (!WritePrivateProfileString (
  558. Section,
  559. Key,
  560. NULL,
  561. FileName
  562. )) {
  563. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot erase key %s from %s from %s", Key, Section, OrigFileName));
  564. Result = FALSE;
  565. }
  566. else {
  567. *IniFileChanged = TRUE;
  568. }
  569. }
  570. else {
  571. if ((ReverseMapping) && (ReverseMapValue)) {
  572. // writing the new value
  573. if (!WritePrivateProfileString (
  574. Section,
  575. Key,
  576. ReverseMapValue,
  577. FileName
  578. )) {
  579. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot write line %s=%s in %s in %s", Key, ReverseMapValue, Section, FileName));
  580. Result = FALSE;
  581. }
  582. else {
  583. *IniFileChanged = TRUE;
  584. }
  585. }
  586. }
  587. if (ReverseMapValue) {
  588. MemFree (g_hHeap, 0, ReverseMapValue);
  589. }
  590. }
  591. if (SectionValue) {
  592. MemFree (g_hHeap, 0, SectionValue);
  593. }
  594. }
  595. __finally {
  596. if (KeyValue) {
  597. MemFree (g_hHeap, 0, KeyValue);
  598. }
  599. }
  600. Key = GetEndOfString (Key) + 1;
  601. }
  602. }
  603. __finally {
  604. if (KeyBuf) {
  605. MemFree (g_hHeap, 0, KeyBuf);
  606. }
  607. }
  608. return Result;
  609. }
  610. BOOL
  611. pTransferSectionByValue (
  612. IN PCTSTR OrigFileName,
  613. IN PCTSTR FileName,
  614. IN PCTSTR Section,
  615. IN PCTSTR SectionValue,
  616. IN OUT BOOL *IniFileChanged,
  617. IN BOOL UserMode
  618. )
  619. /*++
  620. Routine Description:
  621. This routine transports settings from a specified section of an INI file
  622. into registry or from the registry to the INI file. If there is a case when
  623. the settings go from registry to INI file then IniFileChanged is set to TRUE
  624. Arguments:
  625. FileName - Specifies INI file to be processed
  626. Section - Specifies section to be processed
  627. SectionValue - ValueName associated with this section
  628. IniFileChanged - Tells the caller that at least one setting was from registry to the INI file
  629. UserMode - Specifies TRUE if per-user sections are to be processed, or
  630. FALSE if local machine sections are to be processed.
  631. Return Value:
  632. TRUE if successful, FALSE if at least one error occured
  633. --*/
  634. {
  635. PTSTR Key, KeyBuf;
  636. PTSTR KeyValue;
  637. BOOL ReverseMapping;
  638. PTSTR ReverseMapValue;
  639. BOOL Result = TRUE;
  640. if (!pLoadIniFileBuffer (FileName, Section, NULL, &KeyBuf)) {
  641. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot load key buffer for %s in %s", Section, FileName));
  642. return FALSE;
  643. }
  644. __try {
  645. //
  646. // now we have all keys of the section and proceeding
  647. //
  648. Key = KeyBuf;
  649. //
  650. // there is a loop here for every key in the buffer
  651. //
  652. while (*Key) {
  653. //
  654. // trying to read the value for the key
  655. //
  656. if (!pLoadIniFileBuffer (FileName, Section, Key, &KeyValue)) {
  657. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot load key %s in %s in %s", Key, Section, FileName));
  658. Result = FALSE;
  659. continue;
  660. }
  661. __try {
  662. if (!pSaveMappedValue (
  663. OrigFileName,
  664. Section,
  665. Key,
  666. SectionValue,
  667. KeyValue,
  668. &ReverseMapping,
  669. &ReverseMapValue,
  670. UserMode
  671. )) {
  672. Result = FALSE;
  673. }
  674. if (UserMode && ReverseMapping) {
  675. if (!WritePrivateProfileString (
  676. Section,
  677. Key,
  678. NULL,
  679. FileName
  680. )) {
  681. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot erase key %s from %s from %s", Key, Section, OrigFileName));
  682. Result = FALSE;
  683. }
  684. else {
  685. *IniFileChanged = TRUE;
  686. }
  687. }
  688. else {
  689. if ((ReverseMapping) &&(ReverseMapValue)) {
  690. // writing the new value
  691. if (!WritePrivateProfileString (
  692. Section,
  693. Key,
  694. ReverseMapValue,
  695. FileName
  696. )) {
  697. DEBUGMSG ((DBG_ERROR,"Ini File Mapping : Cannot write line %s=%s in %s in %s", Key, ReverseMapValue, Section, FileName));
  698. Result = FALSE;
  699. }
  700. else {
  701. *IniFileChanged = TRUE;
  702. }
  703. }
  704. }
  705. if (ReverseMapValue) {
  706. MemFree (g_hHeap, 0, ReverseMapValue);
  707. }
  708. }
  709. __finally {
  710. if (KeyValue) {
  711. MemFree (g_hHeap, 0, KeyValue);
  712. }
  713. }
  714. Key = GetEndOfString (Key) + 1;
  715. }
  716. }
  717. __finally {
  718. MemFree (g_hHeap, 0, KeyBuf);
  719. }
  720. return Result;
  721. }
  722. BOOL
  723. pDoesStrHavePrefix (
  724. IN OUT PCTSTR *String,
  725. IN PCTSTR Prefix
  726. )
  727. /*++
  728. Routine Description:
  729. Simple routine that checks if a specified string has a specified prefix and if so
  730. advances the string pointer to point exactly after the prefix.
  731. Arguments:
  732. String - String to be processed
  733. Prefix - Prefix to be processed
  734. Return Value:
  735. TRUE if String has Prefix, FALSE otherwise
  736. --*/
  737. {
  738. UINT Len;
  739. Len = TcharCount (Prefix);
  740. if (StringIMatchTcharCount (*String, Prefix, Len)) {
  741. *String += Len;
  742. return TRUE;
  743. }
  744. return FALSE;
  745. }
  746. BOOL
  747. pShouldSaveKey (
  748. IN PCTSTR OrigFileName,
  749. IN PCTSTR Section,
  750. IN PCTSTR ValueName,
  751. IN PCTSTR RegKey, OPTIONAL
  752. IN OUT BOOL *ReverseMapping,
  753. IN BOOL UserMode,
  754. IN BOOL ExclusionsOnly
  755. )
  756. /*++
  757. Routine Description:
  758. Simple routine that checks if a setting should go from INI file to registry.
  759. If the setting is globally suppressed or it's in suppression table returns FALSE
  760. Arguments:
  761. OrigFileName - Specifies the original Win9x INI file name (not the current one)
  762. Section - Specifies the section within the INI file
  763. ValueName - Specifies the key within the INI file section
  764. RegKey - Specifies the registry key destination, from the IniFileMapping key;
  765. optional only if ExclusionsOnly is TRUE
  766. ReverseMapping - Receives TRUE if the direction of data copy is to go from the
  767. NT registry to the INI file; receives FALSE if the direction
  768. is from the INI file to the registry
  769. UserMode - Specifies TRUE to do per-user processing
  770. ExclusionsOnly - Specifies TRUE if only exclusions should be tested
  771. Return Value:
  772. TRUE if direction is from INI file to registry, FALSE otherwise
  773. --*/
  774. {
  775. HKEY key;
  776. HKEY OldRegRoot = NULL;
  777. BOOL b = TRUE;
  778. TCHAR ekey[MEMDB_MAX];
  779. LONG rc;
  780. *ReverseMapping = FALSE;
  781. if (RegKey && IsNtRegObjectSuppressed (RegKey, NULL)) {
  782. DEBUGMSG ((DBG_NAUSEA, "INI destination is suppressed: %s", RegKey));
  783. return FALSE;
  784. }
  785. //
  786. // Let's see if this mapping is suppressed
  787. //
  788. MemDbBuildKey (
  789. ekey,
  790. MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW,
  791. OrigFileName,
  792. Section,
  793. ValueName
  794. );
  795. if (MemDbGetStoredEndPatternValue (ekey, NULL)) {
  796. DEBUGMSG ((
  797. DBG_NAUSEA,
  798. "INI destination is suppressed: %s\\%s\\%s",
  799. OrigFileName,
  800. Section,
  801. ValueName
  802. ));
  803. *ReverseMapping = TRUE;
  804. return FALSE;
  805. }
  806. //
  807. // If the NT key exists and we don't want to overwrite NT values, reverse
  808. // the mapping.
  809. //
  810. MemDbBuildKey (
  811. ekey,
  812. MEMDB_CATEGORY_NO_OVERWRITE_INI_MAPPINGSW,
  813. OrigFileName,
  814. Section,
  815. ValueName
  816. );
  817. if (MemDbGetStoredEndPatternValue (ekey, NULL)) {
  818. if (ExclusionsOnly) {
  819. return FALSE;
  820. }
  821. if (UserMode) {
  822. OldRegRoot = GetRegRoot();
  823. SetRegRoot (g_hKeyRootNT);
  824. }
  825. key = OpenRegKeyStr (RegKey);
  826. if (key) {
  827. rc = RegQueryValueEx (key, ValueName, NULL, NULL, NULL, NULL);
  828. if (rc == ERROR_SUCCESS) {
  829. //
  830. // The NT registry value exists, do not overwrite it.
  831. // Instead, reverse the mapping so that the INI file
  832. // gets the NT value.
  833. //
  834. DEBUGMSG ((
  835. DBG_NAUSEA,
  836. "NT value exists; reversing mapping: %s [%s]",
  837. RegKey,
  838. ValueName
  839. ));
  840. *ReverseMapping = TRUE;
  841. //
  842. // don't write the key on return, instead write in INI file
  843. //
  844. b = FALSE;
  845. }
  846. CloseRegKey (key);
  847. }
  848. if (UserMode) {
  849. SetRegRoot (OldRegRoot);
  850. }
  851. return b;
  852. }
  853. if (ExclusionsOnly) {
  854. return TRUE;
  855. }
  856. //
  857. // If Win9x key exists, reverse the mapping (so the Win9x registry setting
  858. // is used instead of the potentially stale INI file setting)
  859. //
  860. if (UserMode) {
  861. OldRegRoot = GetRegRoot();
  862. SetRegRoot (g_hKeyRoot95);
  863. }
  864. key = OpenRegKeyStr95 (RegKey);
  865. if (UserMode) {
  866. SetRegRoot (OldRegRoot);
  867. }
  868. if (key != NULL) {
  869. if (Win95RegQueryValueEx (key, ValueName, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) {
  870. *ReverseMapping = TRUE;
  871. DEBUGMSG ((DBG_NAUSEA, "INI destination is suppressed: %s", RegKey));
  872. b = FALSE;
  873. }
  874. CloseRegKey95 (key);
  875. }
  876. DEBUGMSG_IF ((b, DBG_NAUSEA, "INI destination is not suppressed: %s", RegKey));
  877. return b;
  878. }
  879. BOOL
  880. pSaveMappedValue (
  881. IN PCTSTR OrigFileName,
  882. IN PCTSTR Section,
  883. IN PCTSTR ValueName,
  884. IN PCTSTR RegPath,
  885. IN PCTSTR Value,
  886. IN OUT BOOL *ReverseMapping,
  887. OUT PTSTR *ReverseMapValue,
  888. IN BOOL UserMode
  889. )
  890. /*++
  891. Routine Description:
  892. This routine has a valuename and a value that should be saved in a key indicated by RegPath.
  893. Arguments:
  894. RegPath - Key where setting should be saved
  895. ValueName - ValueName for the key
  896. Value - Value for the key
  897. ReverseMapping - tells the caller that the setting should be saved from registry to INI file
  898. ReverseMapValue - if ReverseMapping is TRUE that we have the value of the key here
  899. UserMode - Specifies TRUE if per-user sections are to be processed, or
  900. FALSE if local machine sections are to be processed.
  901. Return Value:
  902. TRUE if success, FALSE otherwise
  903. --*/
  904. {
  905. CHARTYPE ch;
  906. TCHAR RegKey[MAX_REGISTRY_KEY];
  907. DWORD rc;
  908. HKEY SaveKey;
  909. PCTSTR newValue;
  910. PTSTR p;
  911. BOOL Result = TRUE;
  912. *ReverseMapping = FALSE;
  913. *ReverseMapValue = NULL;
  914. //
  915. // Parse the string
  916. //
  917. //
  918. // Skip past special chars
  919. //
  920. while (TRUE) {
  921. ch = (CHARTYPE)_tcsnextc (RegPath);
  922. if (ch == TEXT('!') ||
  923. ch == TEXT('#') ||
  924. ch == TEXT('@')
  925. ) {
  926. RegPath = _tcsinc (RegPath);
  927. } else {
  928. break;
  929. }
  930. }
  931. //
  932. // If SYS:, USR: or \Registry\Machine\ then replace appropriately
  933. //
  934. RegKey[0] = 0;
  935. if (pDoesStrHavePrefix (&RegPath, TEXT("SYS:"))) {
  936. if (UserMode) {
  937. return TRUE;
  938. }
  939. p = TEXT("HKLM\\SOFTWARE");
  940. } else if (pDoesStrHavePrefix (&RegPath, TEXT("USR:"))) {
  941. if (!UserMode) {
  942. return TRUE;
  943. }
  944. p = TEXT("HKR");
  945. } else if (pDoesStrHavePrefix (&RegPath, TEXT("\\Registry\\Machine\\"))) {
  946. if (UserMode) {
  947. return TRUE;
  948. }
  949. p = TEXT("HKLM");
  950. }
  951. StringCchPrintf (RegKey, MAX_REGISTRY_KEY, TEXT("%s\\%s"), p, RegPath);
  952. if (pShouldSaveKey(OrigFileName, Section, ValueName, RegKey, ReverseMapping, UserMode, FALSE)) {
  953. SaveKey = CreateRegKeyStr (RegKey);
  954. if (SaveKey) {
  955. newValue = GetPathStringOnNt (Value);
  956. rc = RegSetValueEx (
  957. SaveKey,
  958. ValueName,
  959. 0,
  960. REG_SZ,
  961. (PBYTE) newValue,
  962. SizeOfString (newValue)
  963. );
  964. CloseRegKey (SaveKey);
  965. if (rc != ERROR_SUCCESS) {
  966. SetLastError (rc);
  967. Result = FALSE;
  968. DEBUGMSG ((
  969. DBG_ERROR,
  970. "Process Ini File Mapping: Could not save %s=%s to %s",
  971. ValueName,
  972. newValue,
  973. RegKey
  974. ));
  975. }
  976. FreePathString (newValue);
  977. }
  978. else {
  979. DEBUGMSG ((DBG_ERROR, "Process Ini File Mapping: Could not create %s", RegKey));
  980. }
  981. }
  982. else {
  983. if (*ReverseMapping) {
  984. // trying to open key
  985. SaveKey = OpenRegKeyStr (RegKey);
  986. if (SaveKey) {
  987. *ReverseMapValue = (PTSTR)GetRegValueString (SaveKey, ValueName);
  988. CloseRegKey (SaveKey);
  989. }
  990. }
  991. }
  992. return Result;
  993. }
  994. BOOL
  995. pBuildSuppressionTable (
  996. IN BOOL UserMode
  997. )
  998. /*++
  999. Routine Description:
  1000. Loads the "Suppress INI File Mappings" section from "wkstamig.inf" or from "usermig.inf"
  1001. into a stringtable.
  1002. Arguments:
  1003. UserMode - Specifies TRUE if section is loaded from usermig.inf
  1004. FALSE if section is loaded from wkstamig.inf
  1005. UserMode
  1006. Return Value:
  1007. Always returns TRUE. In case of an error, we are going to log it but returning TRUE
  1008. trying to go on.
  1009. --*/
  1010. {
  1011. HINF InfHandle;
  1012. TCHAR field[MEMDB_MAX];
  1013. INFCONTEXT context;
  1014. if (UserMode) {
  1015. InfHandle = g_UserMigInf;
  1016. }
  1017. else {
  1018. InfHandle = g_WkstaMigInf;
  1019. }
  1020. if (InfHandle == INVALID_HANDLE_VALUE) {
  1021. DEBUGMSG((DBG_ERROR,"Ini File Mapping : wkstamig.inf or usermig.inf is not loaded"));
  1022. return FALSE;
  1023. }
  1024. if (SetupFindFirstLine (InfHandle, S_SUPPRESS_INI_FILE_MAPPINGS, NULL, &context)) {
  1025. do {
  1026. if (SetupGetStringField (&context, 0, field, MEMDB_MAX, NULL)) {
  1027. MemDbSetValueEx (
  1028. MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW,
  1029. field,
  1030. NULL,
  1031. NULL,
  1032. 0,
  1033. NULL
  1034. );
  1035. }
  1036. } while (SetupFindNextLine (&context, &context));
  1037. }
  1038. if (SetupFindFirstLine (InfHandle, S_NO_OVERWRITE_INI_FILE_MAPPINGS, NULL, &context)) {
  1039. do {
  1040. if (SetupGetStringField (&context, 0, field, MEMDB_MAX, NULL)) {
  1041. MemDbSetValueEx (
  1042. MEMDB_CATEGORY_NO_OVERWRITE_INI_MAPPINGSW,
  1043. field,
  1044. NULL,
  1045. NULL,
  1046. 0,
  1047. NULL
  1048. );
  1049. }
  1050. } while (SetupFindNextLine (&context, &context));
  1051. }
  1052. return TRUE;
  1053. }
  1054. VOID
  1055. pFreeSuppressionTable (
  1056. VOID
  1057. )
  1058. /*++
  1059. Routine Description:
  1060. Simple routine that free the string table if it exists
  1061. Arguments:
  1062. none
  1063. Return Value:
  1064. none
  1065. --*/
  1066. {
  1067. MemDbDeleteTree (MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW);
  1068. MemDbDeleteTree (MEMDB_CATEGORY_NO_OVERWRITE_INI_MAPPINGSW);
  1069. }
  1070. enum Separators {
  1071. tab = TEXT('\t'),
  1072. space = TEXT(' '),
  1073. comma = TEXT(','),
  1074. quote = TEXT('\"')
  1075. };
  1076. BOOL
  1077. pAddValue(
  1078. IN OUT TCHAR **Buffer,
  1079. IN OUT TCHAR *Value,
  1080. IN UINT BufChars
  1081. );
  1082. BOOL
  1083. pProcessStrValue (
  1084. IN TCHAR *InBuf,
  1085. OUT TCHAR *OutBuf,
  1086. IN UINT BufChars
  1087. );
  1088. BOOL
  1089. ConvertIniFile (
  1090. IN PCTSTR IniFilePath
  1091. );
  1092. BOOL
  1093. pIsDosFullPathPattern (
  1094. IN PCTSTR String
  1095. )
  1096. /*++
  1097. Routine Description:
  1098. pIsDosFullPathPattern checks if a string may be a valid DOS full path, i.e.
  1099. a drive letter folowed by a colon and a backslash.
  1100. Arguments:
  1101. String - Specifies the string to be tested
  1102. Return Value:
  1103. TRUE if the string may represent a valid full DOS path, FALSE if not.
  1104. --*/
  1105. {
  1106. return String && *String && String[1] == TEXT(':') && String[2] == TEXT('\\');
  1107. }
  1108. BOOL
  1109. ConvertIniFiles (
  1110. VOID
  1111. )
  1112. /*++
  1113. Routine Description:
  1114. ConvertIniFiles reads in the INI files not listed in IniFileMapping key, and converts every
  1115. full path file name to it's new value if it has been moved during instalation. Calls ConvertIniFile
  1116. for each INI file from Windows directory not listed in IniFileMapping.
  1117. This function is mainly for compatibility with older programs using INI files instead of registry
  1118. Arguments:
  1119. none
  1120. Return Value:
  1121. TRUE if successful, FALSE if at least one error occured while processing.
  1122. The function will continue even if an error occures while processing a particular ini file
  1123. trying to get the job done as much as possible.
  1124. --*/
  1125. {
  1126. FILEOP_ENUM fe;
  1127. FILEOP_PROP_ENUM eOpProp;
  1128. MEMDB_ENUM e;
  1129. PCTSTR NtPath;
  1130. PCTSTR filePtr = NULL;
  1131. PCTSTR extPtr = NULL;
  1132. PCTSTR winDirWack = NULL;
  1133. BOOL result = TRUE;
  1134. winDirWack = JoinPaths (g_WinDir, TEXT(""));
  1135. if (EnumFirstPathInOperation (&fe, OPERATION_TEMP_PATH)) {
  1136. do {
  1137. filePtr = GetFileNameFromPath (fe.Path);
  1138. if (!filePtr) {
  1139. continue;
  1140. }
  1141. extPtr = GetFileExtensionFromPath (fe.Path);
  1142. if (!extPtr) {
  1143. continue;
  1144. }
  1145. if (StringIMatch (extPtr, TEXT("INI"))) {
  1146. // this is an INI file that was relocated. Let's process it.
  1147. if (EnumFirstFileOpProperty (&eOpProp, fe.Sequencer, OPERATION_TEMP_PATH)) {
  1148. // even if Result is false we keep trying to update the file
  1149. DEBUGMSG ((DBG_INIFILES, "ConvertIniFile: %s (temp=%s)", fe.Path, eOpProp.Property));
  1150. //
  1151. // see comments at the beginning of MergeIniFile
  1152. //
  1153. if (DoesFileExist (eOpProp.Property)) {
  1154. if (!ConvertIniFile(eOpProp.Property)) {
  1155. result = FALSE;
  1156. }
  1157. } else {
  1158. if (EnumNextFileOpProperty (&eOpProp)) {
  1159. if (!ConvertIniFile(eOpProp.Property)) {
  1160. result = FALSE;
  1161. }
  1162. }
  1163. ELSE_DEBUGMSG ((
  1164. DBG_WHOOPS,
  1165. "ConvertIniFiles: Couldn't get final destination for %s",
  1166. fe.Path
  1167. ));
  1168. }
  1169. }
  1170. }
  1171. } while (EnumNextPathInOperation (&fe));
  1172. }
  1173. FreePathString (winDirWack);
  1174. //
  1175. // also convert all INI files listed in MEMDB_CATEGORY_INIFILES_CONVERT
  1176. //
  1177. if (MemDbGetValueEx (&e, MEMDB_CATEGORY_INIFILES_CONVERT, NULL, NULL)) {
  1178. do {
  1179. NtPath = GetPathStringOnNt (e.szName);
  1180. DEBUGMSG ((DBG_INIFILES, "ConvertIniFile: Nt=%s (Win9x=%s)", NtPath, e.szName));
  1181. if (!ConvertIniFile (NtPath)) {
  1182. result = FALSE;
  1183. }
  1184. FreePathString (NtPath);
  1185. } while (MemDbEnumNextValue (&e));
  1186. }
  1187. if (!result) {
  1188. //
  1189. // we are going to log that at least one error occured while processing IniFileConversion
  1190. //
  1191. DEBUGMSG ((DBG_ERROR, (PCSTR)MSG_INI_FILE_CONVERSION_LOG));
  1192. }
  1193. return TRUE;
  1194. }
  1195. BOOL
  1196. ConvertIniFile (
  1197. IN PCTSTR IniFilePath
  1198. )
  1199. /*++
  1200. Routine Description:
  1201. ConvertIniFile reads in the INI file received and converts every full path file name
  1202. to it's new value if it has been moved during instalation.
  1203. It also applies all string substitutions specified in [String Map] section of wkstamig.inf
  1204. This function is called from ConvertIniFiles.
  1205. Arguments:
  1206. IniFilePath - Specifies INI file that is to be processed
  1207. Return Value:
  1208. TRUE if successful, FALSE if at least one error occured while processing.
  1209. The function will continue even if an error occures while processing a particular ini file
  1210. trying to get the job done as much as possible.
  1211. --*/
  1212. {
  1213. PTSTR Section = NULL;
  1214. PTSTR SectionBuf = NULL;
  1215. PTSTR SectionDest = NULL;
  1216. PTSTR Key = NULL;
  1217. PTSTR KeyBuf = NULL;
  1218. PTSTR KeyDest = NULL;
  1219. BOOL IniFileChanged = FALSE;
  1220. BOOL Result = TRUE;
  1221. DWORD status;
  1222. TCHAR InValueBuf[MEMDB_MAX];
  1223. TCHAR OutValueBuf[MEMDB_MAX];
  1224. TCHAR TempPath[MEMDB_MAX];
  1225. DWORD Attribs;
  1226. //
  1227. // we want to have ready two full paths:
  1228. // 1. full path to ini file that we are processing (Ex: c:\windows\setup\tmp00001)
  1229. // 2. full path to ini file temporary name while processing (system generated)
  1230. //
  1231. if (!DoesFileExist (IniFilePath)) {
  1232. DEBUGMSG ((DBG_INIFILES, "ConvertIniFile: %s not found", IniFilePath));
  1233. return TRUE;
  1234. }
  1235. if (!GetTempFileName (g_WinDir, TEXT("INI"), 0, TempPath)) {
  1236. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot create a temporary file"));
  1237. return FALSE;
  1238. }
  1239. __try {
  1240. //
  1241. // first of all we copy this INI file to be sure that GetPrivateProfileString function
  1242. // does not map our requests into registry
  1243. //
  1244. if (!CopyFile (IniFilePath, TempPath, FALSE)) {
  1245. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot copy %s to %s", IniFilePath, TempPath));
  1246. Result = FALSE;
  1247. __leave;
  1248. }
  1249. Attribs = GetFileAttributes (TempPath);
  1250. MYASSERT (Attribs != (DWORD)-1);
  1251. SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
  1252. //
  1253. // now trying to get section buffer from the INI file
  1254. // We will try to get section buffer in a 1024 bytes buffer. If this is not enough then
  1255. // we will increase buffer size with 1024 and so on.
  1256. //
  1257. if (!pLoadIniFileBuffer (IniFilePath, NULL, NULL, &SectionBuf)) {
  1258. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot load section buffer for %s", IniFilePath));
  1259. Result = FALSE;
  1260. __leave;
  1261. }
  1262. //
  1263. // now we have all sections of the INI file and proceeding
  1264. //
  1265. Section = SectionBuf;
  1266. //
  1267. // there is a loop here for every section in the buffer
  1268. //
  1269. while (*Section) {
  1270. //
  1271. // section name can also contain paths
  1272. //
  1273. if (pIsDosFullPathPattern (Section)) {
  1274. status = GetFileStatusOnNt (Section);
  1275. } else {
  1276. status = FILESTATUS_UNCHANGED;
  1277. }
  1278. if (status & FILESTATUS_DELETED) {
  1279. //
  1280. // delete the whole section
  1281. //
  1282. if (!WritePrivateProfileString (Section, NULL, NULL, TempPath)) {
  1283. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot delete section %s in %s", Section, IniFilePath));
  1284. Result = FALSE;
  1285. }
  1286. IniFileChanged = TRUE;
  1287. } else {
  1288. //
  1289. // now trying to get key buffer for this section
  1290. //
  1291. KeyBuf = NULL;
  1292. if (!pLoadIniFileBuffer (IniFilePath, Section, NULL, &KeyBuf)) {
  1293. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot load key buffer for %s in %s", Section, IniFilePath));
  1294. Result = FALSE;
  1295. __leave;
  1296. }
  1297. //
  1298. // section name may contain paths
  1299. //
  1300. SectionDest = Section;
  1301. if (pProcessStrValue (Section, OutValueBuf, MEMDB_MAX)) {
  1302. //
  1303. // use this new section name
  1304. //
  1305. SectionDest = DuplicateText (OutValueBuf);
  1306. MYASSERT (SectionDest);
  1307. IniFileChanged = TRUE;
  1308. //
  1309. // delete the whole old section before continuing
  1310. //
  1311. if (!WritePrivateProfileString (Section, NULL, NULL, TempPath)) {
  1312. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot delete section %s in %s", Section, IniFilePath));
  1313. Result = FALSE;
  1314. }
  1315. IniFileChanged = TRUE;
  1316. }
  1317. //
  1318. // now we have all keys from this section and proceeding
  1319. //
  1320. Key = KeyBuf;
  1321. //
  1322. // there is a loop here for every key in the section
  1323. //
  1324. while (*Key) {
  1325. //
  1326. // key name can also contain paths
  1327. //
  1328. if (pIsDosFullPathPattern (Key)) {
  1329. status = GetFileStatusOnNt (Key);
  1330. } else {
  1331. status = FILESTATUS_UNCHANGED;
  1332. }
  1333. if (status & FILESTATUS_DELETED) {
  1334. //
  1335. // delete the key
  1336. //
  1337. if (!WritePrivateProfileString (SectionDest, Key, NULL, TempPath)) {
  1338. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot delete key %s in section %s in %s", Key, SectionDest, IniFilePath));
  1339. Result = FALSE;
  1340. }
  1341. IniFileChanged = TRUE;
  1342. } else {
  1343. KeyDest = Key;
  1344. if (pProcessStrValue (Key, OutValueBuf, MEMDB_MAX)) {
  1345. //
  1346. // use this new key name
  1347. //
  1348. KeyDest = DuplicateText (OutValueBuf);
  1349. MYASSERT (KeyDest);
  1350. IniFileChanged = TRUE;
  1351. //
  1352. // deleting the previous key
  1353. //
  1354. if (!WritePrivateProfileString (
  1355. SectionDest,
  1356. Key,
  1357. NULL,
  1358. TempPath
  1359. )) {
  1360. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot delete line %s in %s in %s", Key, SectionDest, IniFilePath));
  1361. Result = FALSE;
  1362. }
  1363. }
  1364. GetPrivateProfileString(
  1365. Section,
  1366. Key,
  1367. TEXT(""),
  1368. InValueBuf,
  1369. MEMDB_MAX,
  1370. IniFilePath
  1371. );
  1372. //
  1373. // let's see if the key value is a deleted file.
  1374. // If so, we will simply delete the key.
  1375. //
  1376. if (pIsDosFullPathPattern (InValueBuf)) {
  1377. status = GetFileStatusOnNt (InValueBuf);
  1378. } else {
  1379. status = FILESTATUS_UNCHANGED;
  1380. }
  1381. if (status & FILESTATUS_DELETED) {
  1382. //
  1383. // deleting the old key
  1384. //
  1385. if (!WritePrivateProfileString (
  1386. SectionDest,
  1387. KeyDest,
  1388. NULL,
  1389. TempPath
  1390. )) {
  1391. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot delete line %s in %s in %s", KeyDest, SectionDest, IniFilePath));
  1392. Result = FALSE;
  1393. }
  1394. IniFileChanged = TRUE;
  1395. } else {
  1396. //
  1397. // now we are going to make a lexical analysis of this value string
  1398. // to see if there are some candidates (e.g. full path file names)
  1399. // To find out if there is a full file name we will just see if the second
  1400. // and the third characters are : respectively \
  1401. //
  1402. if (pProcessStrValue (InValueBuf, OutValueBuf, MEMDB_MAX) ||
  1403. KeyDest != Key ||
  1404. SectionDest != Section
  1405. ) {
  1406. //
  1407. // writing the new value
  1408. //
  1409. if (!WritePrivateProfileString (
  1410. SectionDest,
  1411. KeyDest,
  1412. OutValueBuf,
  1413. TempPath
  1414. )) {
  1415. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot write line %s=%s in %s in %s", KeyDest, OutValueBuf, SectionDest, IniFilePath));
  1416. Result = FALSE;
  1417. }
  1418. IniFileChanged = TRUE;
  1419. }
  1420. }
  1421. if (KeyDest != Key) {
  1422. FreeText (KeyDest);
  1423. KeyDest = NULL;
  1424. }
  1425. }
  1426. Key = GetEndOfString (Key) + 1;
  1427. KeyDest = NULL;
  1428. }
  1429. if (SectionDest != Section) {
  1430. FreeText (SectionDest);
  1431. SectionDest = NULL;
  1432. }
  1433. if (KeyBuf) {
  1434. MemFree (g_hHeap, 0, KeyBuf);
  1435. KeyBuf = NULL;
  1436. }
  1437. }
  1438. Section = GetEndOfString (Section) + 1;
  1439. SectionDest = NULL;
  1440. }
  1441. if (SectionBuf) {
  1442. MemFree (g_hHeap, 0, SectionBuf);
  1443. SectionBuf = NULL;
  1444. }
  1445. //
  1446. // finally, if we made any changes then we will copy the INI file back
  1447. //
  1448. if (IniFileChanged) {
  1449. //
  1450. // flushing the INI file
  1451. //
  1452. WritePrivateProfileString (NULL, NULL, NULL, TempPath);
  1453. SetFileAttributes (TempPath, Attribs);
  1454. SetFileAttributes (IniFilePath, FILE_ATTRIBUTE_NORMAL);
  1455. if (!CopyFile (TempPath, IniFilePath, FALSE)) {
  1456. DEBUGMSG ((DBG_ERROR,"Convert Ini File : Cannot copy %s to %s", TempPath, IniFilePath));
  1457. Result = FALSE;
  1458. __leave;
  1459. }
  1460. }
  1461. }
  1462. __finally {
  1463. SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
  1464. DeleteFile (TempPath);
  1465. if (KeyDest && KeyDest != Key) {
  1466. FreeText (KeyDest);
  1467. KeyDest = NULL;
  1468. }
  1469. if (SectionDest && SectionDest != Section) {
  1470. FreeText (SectionDest);
  1471. SectionDest = NULL;
  1472. }
  1473. if (KeyBuf) {
  1474. MemFree (g_hHeap, 0, KeyBuf);
  1475. KeyBuf = NULL;
  1476. }
  1477. if (SectionBuf) {
  1478. MemFree (g_hHeap, 0, SectionBuf);
  1479. SectionBuf = NULL;
  1480. }
  1481. }
  1482. return Result;
  1483. }
  1484. BOOL
  1485. pLookupStrValue (
  1486. IN PCTSTR Value,
  1487. OUT PTSTR OutBuffer,
  1488. OUT PINT OutBytes,
  1489. IN UINT OutBufferSize
  1490. )
  1491. {
  1492. if (MappingSearchAndReplaceEx (
  1493. g_CompleteMatchMap,
  1494. Value,
  1495. OutBuffer,
  1496. 0,
  1497. OutBytes,
  1498. OutBufferSize,
  1499. STRMAP_COMPLETE_MATCH_ONLY,
  1500. NULL,
  1501. NULL
  1502. )) {
  1503. return TRUE;
  1504. }
  1505. return MappingSearchAndReplaceEx (
  1506. g_SubStringMap,
  1507. Value,
  1508. OutBuffer,
  1509. 0,
  1510. OutBytes,
  1511. OutBufferSize,
  1512. STRMAP_ANY_MATCH,
  1513. NULL,
  1514. NULL
  1515. );
  1516. }
  1517. BOOL
  1518. pProcessStrValue (
  1519. IN TCHAR *InBuf,
  1520. OUT TCHAR *OutBuf,
  1521. IN UINT BufChars
  1522. )
  1523. /*++
  1524. Routine Description:
  1525. Simple lex that identifies lexems separated by comma, space, tab and quote.
  1526. For each lexem calls a function that can change the value of the lexem.
  1527. OBS: When between quote's comma,space and tab are not considered separators
  1528. This function is called from ConvertIniFile.
  1529. Arguments:
  1530. InBuf - Specifies buffer to be processed
  1531. OutBuf - Specifies buffer to hold the result
  1532. BufChars - Specifies the size of OutBuf in chars
  1533. Return Value:
  1534. TRUE if there was any change.
  1535. --*/
  1536. {
  1537. TCHAR OrgLexem[MEMDB_MAX];
  1538. TCHAR *Lexem;
  1539. // Status = 0 - initial state
  1540. // Status = 1 - processing a string between quotes
  1541. // Status = 2 - processing a normal string
  1542. INT Status;
  1543. BOOL Result = FALSE;
  1544. //
  1545. // first check to see if the whole string should be replaced;
  1546. // some paths contain spaces, even if they are not between quotes
  1547. //
  1548. Lexem = OutBuf;
  1549. if (pAddValue (&Lexem, InBuf, BufChars)) {
  1550. *Lexem = 0;
  1551. return TRUE;
  1552. }
  1553. Lexem = OrgLexem;
  1554. Status = 0;
  1555. for (;;) {
  1556. *Lexem = 0;
  1557. *OutBuf = 0;
  1558. switch (*InBuf) {
  1559. case 0:
  1560. Result |= pAddValue(&OutBuf, OrgLexem, MEMDB_MAX);
  1561. *OutBuf = 0;
  1562. return Result;
  1563. case quote:
  1564. if (Status == 0) {
  1565. Status = 1;
  1566. *OutBuf = *InBuf;
  1567. InBuf++;
  1568. OutBuf++;
  1569. break;
  1570. }
  1571. Result |= pAddValue(&OutBuf, OrgLexem, MEMDB_MAX);
  1572. Lexem = OrgLexem;
  1573. if (Status == 1) {
  1574. *OutBuf = *InBuf;
  1575. InBuf++;
  1576. OutBuf++;
  1577. }
  1578. Status = 0;
  1579. break;
  1580. case space:
  1581. case comma:
  1582. case tab:
  1583. if (Status == 1) {
  1584. *Lexem = *InBuf;
  1585. Lexem++;
  1586. InBuf++;
  1587. break;
  1588. };
  1589. if (Status == 0) {
  1590. *OutBuf = *InBuf;
  1591. InBuf++;
  1592. OutBuf++;
  1593. break;
  1594. };
  1595. Result |= pAddValue(&OutBuf, OrgLexem, MEMDB_MAX);
  1596. Lexem = OrgLexem;
  1597. *OutBuf = *InBuf;
  1598. InBuf++;
  1599. OutBuf++;
  1600. Status = 0;
  1601. break;
  1602. default:
  1603. if (Status ==0) {
  1604. Status = 2;
  1605. };
  1606. *Lexem = *InBuf;
  1607. Lexem++;
  1608. InBuf++;
  1609. }
  1610. }
  1611. }
  1612. BOOL
  1613. pAddValue(
  1614. IN OUT TCHAR **Buffer,
  1615. IN OUT TCHAR *Value,
  1616. IN UINT BufChars
  1617. )
  1618. /*++
  1619. Routine Description:
  1620. Simple routine that takes a string value, modifies it (or not) and that adds it
  1621. to a buffer.
  1622. This function is called from pProcessStrValue
  1623. Arguments:
  1624. Buffer - Specifies buffer to hold the value
  1625. Value - Specifies the string value to be processed
  1626. Return Value:
  1627. TRUE if there was any change.
  1628. --*/
  1629. {
  1630. DWORD fileStatus;
  1631. PTSTR newValue, Source;
  1632. INT OutBytes;
  1633. BOOL Result = FALSE;
  1634. //
  1635. // replaced (Value[0]) && (!_tcsncmp (Value + 1, TEXT(":\\"), 2)) with the call below
  1636. // for consistency
  1637. //
  1638. if (pIsDosFullPathPattern (Value)) {
  1639. fileStatus = GetFileStatusOnNt (Value);
  1640. if ((fileStatus & FILESTATUS_MOVED) == FILESTATUS_MOVED) {
  1641. Result = TRUE;
  1642. newValue = GetPathStringOnNt (Value);
  1643. //
  1644. // advance outbound pointer
  1645. //
  1646. Source = newValue;
  1647. while (*Source) {
  1648. **Buffer = *Source;
  1649. (*Buffer)++;
  1650. Source++;
  1651. }
  1652. FreePathString (newValue);
  1653. }
  1654. }
  1655. if (!Result) {
  1656. //
  1657. // try to map this sub-string
  1658. //
  1659. if (pLookupStrValue (
  1660. Value,
  1661. *Buffer,
  1662. &OutBytes,
  1663. BufChars * sizeof (TCHAR)
  1664. )) {
  1665. Result = TRUE;
  1666. MYASSERT (OutBytes % sizeof (TCHAR) == 0);
  1667. *Buffer += OutBytes / sizeof (TCHAR);
  1668. }
  1669. }
  1670. if (!Result) {
  1671. while (*Value) {
  1672. **Buffer = *Value;
  1673. (*Buffer)++;
  1674. Value++;
  1675. }
  1676. }
  1677. return Result;
  1678. }
  1679. BOOL
  1680. pMoveIniSettingsBySection (
  1681. IN PCWSTR Section
  1682. )
  1683. {
  1684. INFCONTEXT context;
  1685. WCHAR srcData [MEMDB_MAX];
  1686. WCHAR destData [MEMDB_MAX];
  1687. WCHAR destValue[MEMDB_MAX];
  1688. WCHAR tempPathS[MEMDB_MAX];
  1689. WCHAR tempPathD[MEMDB_MAX];
  1690. INT adnlData = 0;
  1691. LONG value;
  1692. PWSTR valuePtr;
  1693. PCWSTR srcFile;
  1694. PCWSTR srcSect;
  1695. PCWSTR srcKey;
  1696. PCWSTR destFile;
  1697. PCWSTR destSect;
  1698. PCWSTR destKey;
  1699. PWSTR tempPtr;
  1700. PCWSTR srcFullPath = NULL;
  1701. PCWSTR destFullPath = NULL;
  1702. PCWSTR newPath = NULL;
  1703. PTSTR sect, sectionBuf;
  1704. PTSTR key, keyBuf;
  1705. PCWSTR destSectFull;
  1706. PCWSTR destKeyFull;
  1707. BOOL iniFileChanged;
  1708. DWORD result;
  1709. if (SetupFindFirstLine (g_WkstaMigInf, Section, NULL, &context)) {
  1710. do {
  1711. if ((SetupGetStringField (&context, 0, srcData, MEMDB_MAX, NULL)) &&
  1712. (SetupGetStringField (&context, 1, destData, MEMDB_MAX, NULL))
  1713. ) {
  1714. //
  1715. // We now have a line like : <src INI file>\<src section>\<src key> = <dest INI file>\<dest section>\<dest key>
  1716. //
  1717. __try {
  1718. *tempPathS = 0;
  1719. *tempPathD = 0;
  1720. iniFileChanged = FALSE;
  1721. srcFile = srcData;
  1722. tempPtr = wcschr (srcData, L'\\');
  1723. if (!tempPtr) {
  1724. __leave;
  1725. }
  1726. srcSect = tempPtr + 1;
  1727. *tempPtr = 0;
  1728. tempPtr = wcschr (srcSect, L'\\');
  1729. if (!tempPtr) {
  1730. __leave;
  1731. }
  1732. srcKey = tempPtr + 1;
  1733. *tempPtr = 0;
  1734. destFile = destData;
  1735. tempPtr = wcschr (destData, L'\\');
  1736. if (!tempPtr) {
  1737. __leave;
  1738. }
  1739. destSect = tempPtr + 1;
  1740. *tempPtr = 0;
  1741. tempPtr = wcschr (destSect, L'\\');
  1742. if (!tempPtr) {
  1743. __leave;
  1744. }
  1745. destKey = tempPtr + 1;
  1746. *tempPtr = 0;
  1747. srcFullPath = JoinPaths (g_WinDir, srcFile);
  1748. newPath = GetTemporaryLocationForFile (srcFullPath);
  1749. if (newPath) {
  1750. DEBUGMSG ((DBG_MOVEINISETTINGS, "Using %s for %s", newPath, srcFullPath));
  1751. FreePathString (srcFullPath);
  1752. srcFullPath = newPath;
  1753. }
  1754. if (!DoesFileExist (srcFullPath)) {
  1755. DEBUGMSG ((DBG_INIFILES, "pMoveIniSettingsBySection: %s not found", srcFullPath));
  1756. __leave;
  1757. }
  1758. destFullPath = JoinPaths (g_WinDir, destFile);
  1759. newPath = GetTemporaryLocationForFile (destFullPath);
  1760. if (newPath) {
  1761. DEBUGMSG ((DBG_MOVEINISETTINGS, "pMoveIniSettingsBySection: Using %s for %s", newPath, destFullPath));
  1762. FreePathString (destFullPath);
  1763. destFullPath = newPath;
  1764. }
  1765. // Copy Source File to a temporary location to avoid registry mapping
  1766. if (!GetTempFileName (g_WinDir, TEXT("INI"), 0, tempPathS)) {
  1767. DEBUGMSG ((DBG_ERROR,"pMoveIniSettingsBySection: Cannot create a temporary file"));
  1768. __leave;
  1769. }
  1770. if (!CopyFile (srcFullPath, tempPathS, FALSE)) {
  1771. DEBUGMSG ((DBG_ERROR,"pMoveIniSettingsBySection: Cannot copy %s to %s", srcFullPath, tempPathS));
  1772. __leave;
  1773. }
  1774. // Copy Destination File to a temporary location to avoid registry mapping
  1775. if (!GetTempFileName (g_WinDir, TEXT("INI"), 0, tempPathD)) {
  1776. DEBUGMSG ((DBG_ERROR,"pMoveIniSettingsBySection: Cannot create a temporary file"));
  1777. __leave;
  1778. }
  1779. if (!CopyFile (destFullPath, tempPathD, FALSE)) {
  1780. DEBUGMSG ((DBG_INIFILES,"pMoveIniSettingsBySection: Cannot copy %s to %s", destFullPath, tempPathD));
  1781. }
  1782. // if we have an additional field we use it for dividing the key values (if they are numbers)
  1783. if (!SetupGetIntField (&context, 3, &adnlData)) {
  1784. adnlData = 0;
  1785. }
  1786. //
  1787. // Next thing we are going to do is to load the sections in a buffer
  1788. //
  1789. if (!pLoadIniFileBuffer (tempPathS, NULL, NULL, &sectionBuf)) {
  1790. DEBUGMSG ((DBG_ERROR,"pMoveIniSettingsBySection: Cannot load section buffer for %s (%s)", tempPathS, srcFullPath));
  1791. __leave;
  1792. }
  1793. //
  1794. // now walk through each section
  1795. //
  1796. __try {
  1797. sect = sectionBuf;
  1798. //
  1799. // there is a loop here for every section in the buffer
  1800. //
  1801. while (*sect) {
  1802. if (IsPatternMatch (srcSect, sect)) {
  1803. //
  1804. // Next thing we are going to do is to load the keys in a buffer
  1805. //
  1806. if (!pLoadIniFileBuffer (tempPathS, sect, NULL, &keyBuf)) {
  1807. DEBUGMSG ((DBG_ERROR,"pMoveIniSettingsBySection: Cannot load key buffer for %s in %s (%s)", sect, tempPathS, srcFullPath));
  1808. __leave;
  1809. }
  1810. __try {
  1811. //
  1812. // now we have all keys of the section and proceeding
  1813. //
  1814. key = keyBuf;
  1815. //
  1816. // there is a loop here for every key in the buffer
  1817. //
  1818. while (*key) {
  1819. if (IsPatternMatch (srcKey, key)) {
  1820. result = GetPrivateProfileString (
  1821. sect,
  1822. key,
  1823. TEXT(""),
  1824. destValue,
  1825. MEMDB_MAX,
  1826. tempPathS);
  1827. if ((result == 0) ||
  1828. (result + 1 == MEMDB_MAX)
  1829. ) {
  1830. DEBUGMSG ((
  1831. DBG_MOVEINISETTINGS,
  1832. "pMoveIniSettingsBySection: Cannot read value for %s in %s in %s (%s)",
  1833. key,
  1834. sect,
  1835. tempPathS,
  1836. srcFullPath
  1837. ));
  1838. } else {
  1839. if (adnlData) {
  1840. value = wcstol (destValue, &valuePtr, 10);
  1841. if (*valuePtr == 0) {
  1842. value = value / adnlData;
  1843. wsprintf (destValue, L"%d", value);
  1844. }
  1845. }
  1846. destSectFull = StringSearchAndReplace (destSect, L"*", sect);
  1847. if (!destSectFull) {
  1848. destSectFull = DuplicatePathString (destSect,0);
  1849. }
  1850. destKeyFull = StringSearchAndReplace (destKey, L"*", key);
  1851. if (!destKeyFull) {
  1852. destKeyFull = DuplicatePathString (destKey,0);
  1853. }
  1854. iniFileChanged = TRUE;
  1855. // writing the new value
  1856. if (!WritePrivateProfileString (
  1857. destSectFull,
  1858. destKeyFull,
  1859. destValue,
  1860. tempPathD
  1861. )) {
  1862. DEBUGMSG ((
  1863. DBG_ERROR,
  1864. "Ini File Move : Cannot write line %s=%s in %s in %s (%s)",
  1865. destKeyFull,
  1866. destValue,
  1867. destSectFull,
  1868. tempPathD,
  1869. destFullPath
  1870. ));
  1871. FreePathString (destSectFull);
  1872. FreePathString (destKeyFull);
  1873. __leave;
  1874. }
  1875. FreePathString (destSectFull);
  1876. FreePathString (destKeyFull);
  1877. }
  1878. }
  1879. key = GetEndOfString (key) + 1;
  1880. }
  1881. }
  1882. __finally {
  1883. if (keyBuf) {
  1884. MemFree (g_hHeap, 0 , keyBuf);
  1885. }
  1886. }
  1887. }
  1888. sect = GetEndOfString (sect) + 1;
  1889. }
  1890. }
  1891. __finally {
  1892. if (sectionBuf) {
  1893. MemFree (g_hHeap, 0 , sectionBuf);
  1894. }
  1895. }
  1896. if (iniFileChanged) {
  1897. // flushing the INI file
  1898. WritePrivateProfileString (
  1899. NULL,
  1900. NULL,
  1901. NULL,
  1902. tempPathD
  1903. );
  1904. if (!CopyFile (tempPathD, destFullPath, FALSE)) {
  1905. DEBUGMSG ((DBG_ERROR,"Ini File Move : Cannot copy %s to %s", tempPathD, destFullPath));
  1906. __leave;
  1907. }
  1908. }
  1909. }
  1910. __finally {
  1911. if (srcFullPath) {
  1912. FreePathString (srcFullPath);
  1913. srcFullPath = NULL;
  1914. }
  1915. if (destFullPath) {
  1916. FreePathString (destFullPath);
  1917. destFullPath = NULL;
  1918. }
  1919. if (*tempPathS) {
  1920. SetFileAttributes (tempPathS, FILE_ATTRIBUTE_NORMAL);
  1921. DeleteFile (tempPathS);
  1922. }
  1923. if (*tempPathD) {
  1924. SetFileAttributes (tempPathD, FILE_ATTRIBUTE_NORMAL);
  1925. DeleteFile (tempPathD);
  1926. }
  1927. }
  1928. }
  1929. } while (SetupFindNextLine (&context, &context));
  1930. }
  1931. return TRUE;
  1932. }
  1933. BOOL
  1934. MoveIniSettings (
  1935. VOID
  1936. )
  1937. /*++
  1938. Routine Description:
  1939. There are a number of settings that needs to be moved from one INI file to another during setup.
  1940. There is a section called "MoveIniSettings" in wkstamig.inf that lists those settings.
  1941. The format is <INI file (in %WinDir%)>\section\key = <INI file (in %winDir%)>\section\key
  1942. You can use pattern matching is section and key (INI file must be specified in full).
  1943. The only wild character supported in right term is * and is going to be replaced by the equivalent
  1944. left term. For example if you specify:
  1945. foo.ini\FooSect\FooKey = bar.ini\*\*
  1946. then the FooKey key from FooSect section from foo.ini is going to be moved to bar.ini. This is useful
  1947. to move a whole section :
  1948. foo.ini\FooSect\* = bar.ini\*\*
  1949. We are going to use Get/WritePrivateProfileString because we want that all the settings to be mapped
  1950. into the registry is it's the case (this routine is called after IniFileMapping routine).
  1951. This routine is called before IniFileConversion routine so the moved settings are Win95 ones.
  1952. Arguments:
  1953. None
  1954. Return Value:
  1955. FALSE if any error occured.
  1956. --*/
  1957. {
  1958. WCHAR codePageStr [20] = L"";
  1959. PWSTR codePageSection = NULL;
  1960. MYASSERT (g_WkstaMigInf != INVALID_HANDLE_VALUE);
  1961. pMoveIniSettingsBySection (S_MOVEINISETTINGS);
  1962. _itow (OurGetACP (), codePageStr, 10);
  1963. codePageSection = JoinTextEx (NULL, S_MOVEINISETTINGS, codePageStr, L".", 0, NULL);
  1964. pMoveIniSettingsBySection (codePageSection);
  1965. FreeText (codePageSection);
  1966. return TRUE;
  1967. }
  1968. BOOL
  1969. MergeIniSettings (
  1970. VOID
  1971. )
  1972. {
  1973. FILEOP_ENUM fe;
  1974. FILEOP_PROP_ENUM eOpProp;
  1975. PCTSTR filePtr;
  1976. PCTSTR extPtr;
  1977. PCTSTR winDirWack;
  1978. PCTSTR NtPath;
  1979. BOOL Win9xPriority;
  1980. BOOL result = TRUE;
  1981. //
  1982. // Process INI files that were moved to temporary dir
  1983. //
  1984. winDirWack = JoinPaths (g_WinDir, TEXT(""));
  1985. if (EnumFirstPathInOperation (&fe, OPERATION_TEMP_PATH)) {
  1986. do {
  1987. if (!pBuildSuppressionTable(FALSE)) {
  1988. result = FALSE;
  1989. }
  1990. // Special case : SHELL= line from SYSTEM.INI
  1991. // We try to see if the current shell is supported on NT.
  1992. // If not then we will add SHELL to this suppression table
  1993. // ensuring that the NT registry setting will get mapped into
  1994. // the INI file
  1995. if (pIncompatibleShell()) {
  1996. MemDbSetValueEx (
  1997. MEMDB_CATEGORY_SUPPRESS_INI_MAPPINGSW,
  1998. TEXT("SYSTEM.INI"),
  1999. TEXT("BOOT"),
  2000. TEXT("SHELL"),
  2001. 0,
  2002. NULL
  2003. );
  2004. }
  2005. filePtr = GetFileNameFromPath (fe.Path);
  2006. if (!filePtr) {
  2007. continue;
  2008. }
  2009. extPtr = GetFileExtensionFromPath (fe.Path);
  2010. if (!extPtr) {
  2011. continue;
  2012. }
  2013. if (StringIMatch (extPtr, TEXT("INI"))) {
  2014. // this is an INI file that was relocated. Let's process it.
  2015. if (EnumFirstFileOpProperty (&eOpProp, fe.Sequencer, OPERATION_TEMP_PATH)) {
  2016. if (StringIMatch (filePtr, TEXT("desktop.ini"))) {
  2017. Win9xPriority = FALSE;
  2018. } else {
  2019. Win9xPriority = !StringIMatchAB (winDirWack, fe.Path, filePtr);
  2020. }
  2021. NtPath = GetPathStringOnNt (fe.Path);
  2022. if (!MergeIniFile(NtPath, eOpProp.Property, Win9xPriority)) {
  2023. result = FALSE;
  2024. }
  2025. FreePathString (NtPath);
  2026. }
  2027. }
  2028. } while (EnumNextPathInOperation (&fe));
  2029. pFreeSuppressionTable();
  2030. }
  2031. FreePathString (winDirWack);
  2032. return TRUE;
  2033. }
  2034. PTSTR
  2035. pMapIniSectionKeyToRegistryKey (
  2036. IN PCTSTR FileName,
  2037. IN PCTSTR Section,
  2038. IN PCTSTR Key
  2039. )
  2040. {
  2041. CHARTYPE ch;
  2042. TCHAR RegKey[MAX_REGISTRY_KEY] = S_EMPTY;
  2043. DWORD rc;
  2044. HKEY key, sectKey;
  2045. PTSTR keyStr;
  2046. PTSTR regPath;
  2047. PTSTR data = NULL;
  2048. PTSTR p;
  2049. keyStr = JoinPaths (S_INIFILEMAPPING_KEY, FileName);
  2050. __try {
  2051. key = OpenRegKeyStr (keyStr);
  2052. if (!key) {
  2053. __leave;
  2054. }
  2055. sectKey = OpenRegKey (key, Section);
  2056. if (sectKey) {
  2057. data = GetRegValueString (sectKey, Key);
  2058. if (!data) {
  2059. data = GetRegValueString (sectKey, S_EMPTY);
  2060. }
  2061. CloseRegKey (sectKey);
  2062. } else {
  2063. data = GetRegValueString (key, Section);
  2064. if (!data) {
  2065. data = GetRegValueString (key, S_EMPTY);
  2066. }
  2067. }
  2068. if (data) {
  2069. //
  2070. // convert it to a reg key string
  2071. //
  2072. regPath = data;
  2073. //
  2074. // Skip past special chars
  2075. //
  2076. while (TRUE) {
  2077. ch = (CHARTYPE)_tcsnextc (regPath);
  2078. if (ch == TEXT('!') ||
  2079. ch == TEXT('#') ||
  2080. ch == TEXT('@')
  2081. ) {
  2082. regPath = _tcsinc (regPath);
  2083. } else {
  2084. break;
  2085. }
  2086. }
  2087. //
  2088. // If SYS:, USR: or \Registry\Machine\ then replace appropriately
  2089. //
  2090. if (pDoesStrHavePrefix (&regPath, TEXT("SYS:"))) {
  2091. p = TEXT("HKLM\\SOFTWARE");
  2092. } else if (pDoesStrHavePrefix (&regPath, TEXT("USR:"))) {
  2093. p = TEXT("HKR");
  2094. } else if (pDoesStrHavePrefix (&regPath, TEXT("\\Registry\\Machine\\"))) {
  2095. p = TEXT("HKLM");
  2096. } else {
  2097. LOG ((LOG_WARNING, "Ignoring bad INI mapping string %s", regPath));
  2098. __leave;
  2099. }
  2100. StringCchPrintf (RegKey, MAX_REGISTRY_KEY, TEXT("%s\\%s"), p, regPath);
  2101. }
  2102. }
  2103. __finally {
  2104. if (key) {
  2105. CloseRegKey (key);
  2106. }
  2107. if (data) {
  2108. MemFree (g_hHeap, 0, data);
  2109. }
  2110. FreePathString (keyStr);
  2111. keyStr = NULL;
  2112. }
  2113. if (RegKey[0]) {
  2114. keyStr = DuplicateText (RegKey);
  2115. }
  2116. return keyStr;
  2117. }
  2118. BOOL
  2119. MergeIniFile (
  2120. IN PCTSTR FileNtLocation,
  2121. IN PCTSTR FileTempLocation,
  2122. IN BOOL TempHasPriority
  2123. )
  2124. {
  2125. TCHAR TempPath[MEMDB_MAX];
  2126. TCHAR srcValue[MEMDB_MAX];
  2127. TCHAR destValue[MEMDB_MAX];
  2128. DWORD Attribs = -1;
  2129. PTSTR Section, SectionBuf;
  2130. PTSTR Key, KeyBuf;
  2131. BOOL Result = TRUE;
  2132. BOOL IniFileChanged = FALSE;
  2133. PTSTR regKey;
  2134. PTSTR p;
  2135. PCTSTR fileName;
  2136. //
  2137. // sometimes, textmode setup doesn't move files from other drives to Windows drive,
  2138. // probably because textmode setup drive mapping doesn't match Win9x drive mappings.
  2139. // It's possible that the INI file hasn't actually been moved, so in this case there
  2140. // is nothing to do
  2141. // There is no data loss, since the file is actually not moved and it's converted
  2142. // in place in ConvertIniFiles
  2143. //
  2144. if (*g_WinDir != *FileNtLocation &&
  2145. !DoesFileExist (FileTempLocation) &&
  2146. DoesFileExist (FileNtLocation)
  2147. ) {
  2148. //
  2149. // done, file is already in place
  2150. //
  2151. return TRUE;
  2152. }
  2153. //
  2154. // some desktop.ini are located in temp internet dirs that were removed
  2155. // when Win9x was shutting down; ignore these files
  2156. //
  2157. if (!DoesFileExist (FileTempLocation)) {
  2158. if (!StringIMatch (GetFileNameFromPath (FileNtLocation), TEXT("desktop.ini"))) {
  2159. DEBUGMSG ((DBG_ERROR, "MergeIniFile: File does not exist: %s (Nt=%s)", FileTempLocation, FileNtLocation));
  2160. return FALSE;
  2161. }
  2162. return TRUE;
  2163. }
  2164. if (!DoesFileExist (FileNtLocation)) {
  2165. //
  2166. // just copy back to the original file
  2167. // if the file belongs to a directory that NT doesn't install,
  2168. // create it now
  2169. //
  2170. StackStringCopy (TempPath, FileNtLocation);
  2171. p = _tcsrchr (TempPath, TEXT('\\'));
  2172. if (p) {
  2173. *p = 0;
  2174. if (GetFileAttributes (TempPath) == (DWORD)-1) {
  2175. MakeSurePathExists (TempPath, TRUE);
  2176. }
  2177. }
  2178. if (!CopyFile (FileTempLocation, FileNtLocation, FALSE)) {
  2179. DEBUGMSG ((DBG_ERROR,"MergeIniFile: Cannot copy %s to %s", FileTempLocation, FileNtLocation));
  2180. return FALSE;
  2181. }
  2182. return TRUE;
  2183. }
  2184. if (!GetTempFileName (g_WinDir, TEXT("INI"), 0, TempPath)) {
  2185. DEBUGMSG ((DBG_ERROR,"Merge Ini File : Cannot create a temporary file"));
  2186. return FALSE;
  2187. }
  2188. __try {
  2189. //
  2190. // first of all we copy this INI file to be sure that GetPrivateProfileString function
  2191. // does not map our requests into registry
  2192. //
  2193. if (!CopyFile (FileTempLocation, TempPath, FALSE)) {
  2194. DEBUGMSG ((DBG_ERROR,"Merge Ini File : Cannot copy %s to %s", FileTempLocation, TempPath));
  2195. Result = FALSE;
  2196. __leave;
  2197. }
  2198. Attribs = GetFileAttributes (FileNtLocation);
  2199. SetFileAttributes (FileNtLocation, FILE_ATTRIBUTE_NORMAL);
  2200. MYASSERT (Attribs != (DWORD)-1);
  2201. //
  2202. // now trying to get section buffer from the INI file
  2203. // We will try to get section buffer in a 1024 bytes buffer. If this is not enough then
  2204. // we will increase buffer size with 1024 and so on.
  2205. //
  2206. if (!pLoadIniFileBuffer (TempPath, NULL, NULL, &SectionBuf)) {
  2207. DEBUGMSG ((DBG_ERROR,"Merge Ini File : Cannot load section buffer for %s",TempPath));
  2208. Result = FALSE;
  2209. __leave;
  2210. }
  2211. fileName = GetFileNameFromPath (FileNtLocation);
  2212. if (!fileName) {
  2213. Result = FALSE;
  2214. __leave;
  2215. }
  2216. __try {
  2217. //
  2218. // now we have all sections of the INI file and proceeding
  2219. //
  2220. Section = SectionBuf;
  2221. //
  2222. // there is a loop here for every section in the buffer
  2223. //
  2224. while (*Section) {
  2225. //
  2226. // now trying to get key buffer for this section
  2227. //
  2228. if (!pLoadIniFileBuffer (TempPath, Section, NULL, &KeyBuf)) {
  2229. DEBUGMSG ((DBG_ERROR,"Merge Ini File : Cannot load key buffer for %s in %s", Section, TempPath));
  2230. Result = FALSE;
  2231. continue;
  2232. }
  2233. __try {
  2234. //
  2235. // now we have all keys from this section and proceeding
  2236. //
  2237. Key = KeyBuf;
  2238. //
  2239. // there is a loop here for every key in the section
  2240. //
  2241. while (*Key) {
  2242. BOOL unused;
  2243. //
  2244. // build the corresponding registry key
  2245. //
  2246. regKey = pMapIniSectionKeyToRegistryKey (fileName, Section, Key);
  2247. if (pShouldSaveKey (fileName, Section, Key, regKey, &unused, FALSE, TRUE)) {
  2248. GetPrivateProfileString(
  2249. Section,
  2250. Key,
  2251. TEXT(""),
  2252. srcValue,
  2253. MEMDB_MAX,
  2254. TempPath
  2255. );
  2256. GetPrivateProfileString(
  2257. Section,
  2258. Key,
  2259. TEXT(""),
  2260. destValue,
  2261. MEMDB_MAX,
  2262. FileNtLocation
  2263. );
  2264. if (*srcValue && !*destValue ||
  2265. TempHasPriority && !StringMatch (srcValue, destValue)) {
  2266. IniFileChanged = TRUE;
  2267. // writing the new value
  2268. if (!WritePrivateProfileString (
  2269. Section,
  2270. Key,
  2271. srcValue,
  2272. FileNtLocation
  2273. )) {
  2274. DEBUGMSG ((DBG_ERROR,"Merge Ini File : Cannot write line %s=%s in %s in %s", Key, srcValue, Section, FileNtLocation));
  2275. Result = FALSE;
  2276. }
  2277. }
  2278. }
  2279. ELSE_DEBUGMSG ((
  2280. DBG_VERBOSE,
  2281. "Merge Ini File : Suppressing key %s in section %s of %s",
  2282. Key,
  2283. Section,
  2284. FileNtLocation
  2285. ));
  2286. FreeText (regKey);
  2287. Key = GetEndOfString (Key) + 1;
  2288. }
  2289. }
  2290. __finally {
  2291. if (KeyBuf) {
  2292. MemFree (g_hHeap, 0, KeyBuf);
  2293. }
  2294. }
  2295. Section = GetEndOfString (Section) + 1;
  2296. }
  2297. }
  2298. __finally {
  2299. if (SectionBuf) {
  2300. MemFree (g_hHeap, 0, SectionBuf);
  2301. }
  2302. }
  2303. //
  2304. // finally, if we made any changes then we will copy the INI file back
  2305. //
  2306. if (IniFileChanged) {
  2307. // flushing the INI file
  2308. WritePrivateProfileString (
  2309. NULL,
  2310. NULL,
  2311. NULL,
  2312. FileNtLocation
  2313. );
  2314. }
  2315. }
  2316. __finally {
  2317. if (Attribs != (DWORD)-1) {
  2318. SetFileAttributes (FileNtLocation, Attribs);
  2319. }
  2320. SetFileAttributes (TempPath, FILE_ATTRIBUTE_NORMAL);
  2321. DeleteFile (TempPath);
  2322. }
  2323. return Result;
  2324. }