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.

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