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.

1683 lines
38 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. iniact.c
  5. Abstract:
  6. This module contains the implementation of the engine and actions on INI files.
  7. To add a new INI action, just add it to wkstamig.inf or usermig.inf, add it to
  8. INI_ACTIONS macro list and implement a function with the same name having
  9. FNINIACT prototype.
  10. Author:
  11. Ovidiu Temereanca (ovidiut) 07-May-1999
  12. Environment:
  13. GUI mode Setup.
  14. Revision History:
  15. 07-May-1999 ovidiut Creation and initial implementation.
  16. --*/
  17. //
  18. // includes
  19. //
  20. #include "pch.h"
  21. #include "migmainp.h"
  22. #ifdef DEBUG
  23. #define DBG_INIACT "IniAct"
  24. #endif
  25. //
  26. // GUID Format: {%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}
  27. // we care about the exact length of this string
  28. //
  29. #define GUIDSTR_LEN (1 + 8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1)
  30. #define DASH_INDEXES 1+8, 1+8+1+4, 1+8+1+4+1+4, 1+8+1+4+1+4+1+4
  31. //
  32. // Add a macro here with an INI Action function name and implement it.
  33. // Make sure wkstamig.inf or usermig.inf use the same function name in [INI Files Actions].
  34. // See FNINIACT definition for the function prototype
  35. //
  36. #define INI_ACTIONS \
  37. DEFMAC (MigrateDesktopIniSCI) \
  38. DEFMAC (MigrateDesktopIniESFV) \
  39. //
  40. // Private prototypes
  41. //
  42. //
  43. // description of rule's settings
  44. //
  45. typedef struct {
  46. //
  47. // INI file specification, as appears in INF files (Field 1)
  48. //
  49. PCTSTR IniSpec;
  50. //
  51. // Section specified in INF (Field 2)
  52. //
  53. PCTSTR Section;
  54. //
  55. // Key specified in INF (Field 3)
  56. //
  57. PCTSTR Key;
  58. //
  59. // Data specified in INF (Field 4)
  60. //
  61. PCTSTR Data;
  62. //
  63. // Function-dependent strings defined in INF;
  64. // all strings from section named in Field 5
  65. // the strings are double-zero terminated
  66. //
  67. GROWBUFFER Settings;
  68. } RULEATTRIBS, *PRULEATTRIBS;
  69. //
  70. // description of an INI file (original, actual, NT location)
  71. //
  72. typedef struct {
  73. //
  74. // original (Win9x) INI file location
  75. //
  76. PCTSTR OrigIniPath;
  77. //
  78. // actual INI file location (it was copied to a temp location)
  79. //
  80. PCTSTR ActualLocation;
  81. //
  82. // NT file location; it may be different than Win9x location
  83. //
  84. PCTSTR NtIniPath;
  85. } INIFILE, *PINIFILE;
  86. //
  87. // the prototype of an INI file processing function
  88. //
  89. typedef BOOL (FNINIACT) (
  90. IN PRULEATTRIBS RuleAttribs,
  91. IN PINIFILE IniFile
  92. );
  93. typedef FNINIACT* PFNINIACT;
  94. //
  95. // description of an INI action (there is a list of actions)
  96. //
  97. typedef struct _INIACT {
  98. //
  99. // it's a list of actions
  100. //
  101. struct _INIACT* Next;
  102. //
  103. // processing function name (Key field in INF)
  104. //
  105. PCTSTR FnName;
  106. //
  107. // a pointer to the processing function
  108. //
  109. PFNINIACT FnIniAct;
  110. //
  111. // the attributes of this rule as defined in INF + context
  112. //
  113. RULEATTRIBS RuleAttribs;
  114. } INIACT, *PINIACT;
  115. //
  116. // this serves as a map from function name to function pointer
  117. //
  118. typedef struct {
  119. PCTSTR FnName;
  120. PFNINIACT Fn;
  121. } INIACTMAP, *PINIACTMAP;
  122. //
  123. // global data
  124. //
  125. //
  126. // memory pool used by IniActions
  127. //
  128. static POOLHANDLE g_IniActPool = NULL;
  129. //
  130. // the list of rules
  131. //
  132. static PINIACT g_IniActHead = NULL, g_IniActTail = NULL;
  133. //
  134. // function declarations
  135. //
  136. #define DEFMAC(Name) FNINIACT Name;
  137. INI_ACTIONS
  138. #undef DEFMAC
  139. //
  140. // map function name -> function pointer
  141. //
  142. #define DEFMAC(Name) TEXT(#Name), Name,
  143. static INIACTMAP g_IniActionsMapping[] = {
  144. INI_ACTIONS
  145. NULL, NULL
  146. };
  147. #undef DEFMAC
  148. BOOL
  149. pLookupRuleFn (
  150. IN OUT PINIACT IniAct
  151. )
  152. /*++
  153. Routine Description:
  154. pLookupRuleFn tries to find the function specified in IniAct->FnName and put the pointer
  155. in IniAct->FnIniAct. It will look in the global map g_IniActionsMapping.
  156. Arguments:
  157. IniAct - Specifies the function name and receives the function pointer.
  158. Return Value:
  159. TRUE if the function was found, FALSE otherwise
  160. --*/
  161. {
  162. INT i;
  163. for (i = 0; g_IniActionsMapping[i].FnName; i++) {
  164. if (StringMatch (g_IniActionsMapping[i].FnName, IniAct->FnName)) {
  165. IniAct->FnIniAct = g_IniActionsMapping[i].Fn;
  166. return TRUE;
  167. }
  168. }
  169. return FALSE;
  170. }
  171. PCTSTR
  172. pGetNextMultiSzString (
  173. IN PCTSTR Str
  174. )
  175. /*++
  176. Routine Description:
  177. pGetNextMultiSzString skips over the string specified to get to the next string,
  178. assumed to be in contiguous memory.
  179. Arguments:
  180. Str - Specifies the string to skip over
  181. Return Value:
  182. A pointer to the caracter following the string (starting of the next one).
  183. --*/
  184. {
  185. return (PCTSTR) (((PBYTE)Str) + SizeOfString (Str));
  186. }
  187. VOID
  188. pGetRuleSectionSettings (
  189. IN OUT PINIACT IniAct,
  190. IN HINF Inf,
  191. IN PCTSTR Section
  192. )
  193. /*++
  194. Routine Description:
  195. pGetRuleSectionSettings reads all settings from specified Inf file and
  196. specified section and appends them to IniAct->RuleAttribs.Settings
  197. Arguments:
  198. IniAct - Receives the strings read
  199. Inf - Specifies the source INF file
  200. Section - Specifies the section containing the strings
  201. Return Value:
  202. none
  203. --*/
  204. {
  205. INFCONTEXT ctx;
  206. TCHAR field[MEMDB_MAX];
  207. if (SetupFindFirstLine (Inf, Section, NULL, &ctx)) {
  208. do {
  209. if (SetupGetStringField (&ctx, 0, field, MEMDB_MAX, NULL)) {
  210. MultiSzAppend (&IniAct->RuleAttribs.Settings, field);
  211. }
  212. } while (SetupFindNextLine (&ctx, &ctx));
  213. }
  214. }
  215. BOOL
  216. pGetIniActData (
  217. IN OUT PINFCONTEXT ctx,
  218. OUT PINIACT IniAct
  219. )
  220. /*++
  221. Routine Description:
  222. pGetIniActData reads all rule settings from the specified INF context
  223. and puts them in IniAct
  224. Arguments:
  225. ctx - Specifies the INF context containing the attributes of this rule;
  226. receives new context data
  227. IniAct - Receives the data read
  228. Return Value:
  229. TRUE if attributes read are valid and they make up a valid rule
  230. --*/
  231. {
  232. TCHAR field[MEMDB_MAX];
  233. TCHAR FileSpec[MAX_PATH];
  234. if (!(SetupGetStringField (ctx, 0, field, MEMDB_MAX, NULL) && field[0])) {
  235. DEBUGMSG ((
  236. DBG_ASSERT,
  237. "pGetIniActData: couldn't get function name in Wkstamig.inf"
  238. ));
  239. MYASSERT (FALSE);
  240. return FALSE;
  241. }
  242. IniAct->FnName = DuplicateText (field);
  243. //
  244. // lookup handling function
  245. //
  246. if (!pLookupRuleFn (IniAct)) {
  247. DEBUGMSG ((
  248. DBG_ASSERT,
  249. "pGetIniActData: couldn't find implementation of function [%s] in Wkstamig.inf",
  250. IniAct->FnName
  251. ));
  252. MYASSERT (FALSE);
  253. return FALSE;
  254. }
  255. if (!(SetupGetStringField (ctx, 1, field, MEMDB_MAX, NULL) && field[0])) {
  256. DEBUGMSG ((
  257. DBG_ASSERT,
  258. "pGetIniActData: couldn't get INI file spec in Wkstamig.inf"
  259. ));
  260. MYASSERT (FALSE);
  261. return FALSE;
  262. }
  263. //
  264. // expand env vars first
  265. //
  266. if (ExpandEnvironmentStrings (field, FileSpec, MAX_PATH) <= MAX_PATH) {
  267. //
  268. // there shouldn't be any % left
  269. //
  270. if (_tcschr (FileSpec, TEXT('%'))) {
  271. DEBUGMSG ((
  272. DBG_ASSERT,
  273. "pGetIniActData: invalid INI file spec in Wkstamig.inf"
  274. ));
  275. MYASSERT (FALSE);
  276. return FALSE;
  277. }
  278. } else {
  279. DEBUGMSG ((
  280. DBG_ASSERT,
  281. "pGetIniActData: INI file spec too long in Wkstamig.inf"
  282. ));
  283. MYASSERT (FALSE);
  284. return FALSE;
  285. }
  286. IniAct->RuleAttribs.IniSpec = DuplicateText (FileSpec);
  287. //
  288. // rest of fields are optional
  289. //
  290. if (SetupGetStringField (ctx, 2, field, MEMDB_MAX, NULL) && field[0]) {
  291. IniAct->RuleAttribs.Section = DuplicateText (field);
  292. }
  293. if (SetupGetStringField (ctx, 3, field, MEMDB_MAX, NULL) && field[0]) {
  294. IniAct->RuleAttribs.Key = DuplicateText (field);
  295. }
  296. if (SetupGetStringField (ctx, 4, field, MEMDB_MAX, NULL) && field[0]) {
  297. IniAct->RuleAttribs.Data = DuplicateText (field);
  298. }
  299. if (SetupGetStringField (ctx, 5, field, MEMDB_MAX, NULL) && field[0]) {
  300. //
  301. // this is actually a section name in the same INF file
  302. // read its contents and make a multisz string with them
  303. //
  304. pGetRuleSectionSettings (IniAct, ctx->Inf, field);
  305. }
  306. return TRUE;
  307. }
  308. VOID
  309. pCleanUpIniAction (
  310. IN OUT PINIACT IniAct
  311. )
  312. /*++
  313. Routine Description:
  314. pCleanUpIniAction frees all resources associated with the given IniAct
  315. Arguments:
  316. IniAct - Specifies the action to be "emptied"; all resources are freed
  317. Return Value:
  318. none
  319. --*/
  320. {
  321. FreeText (IniAct->FnName);
  322. IniAct->FnName = NULL;
  323. FreeText (IniAct->RuleAttribs.IniSpec);
  324. FreeText (IniAct->RuleAttribs.Section);
  325. FreeText (IniAct->RuleAttribs.Key);
  326. FreeText (IniAct->RuleAttribs.Data);
  327. FreeGrowBuffer (&IniAct->RuleAttribs.Settings);
  328. ZeroMemory (&IniAct->RuleAttribs, sizeof (IniAct->RuleAttribs));
  329. }
  330. BOOL
  331. pCreateIniActions (
  332. IN INIACT_CONTEXT Context
  333. )
  334. /*++
  335. Routine Description:
  336. pCreateIniActions will create a list of rules read from an INF depending on the Context
  337. Arguments:
  338. Context - Specifies the context in which the function is called
  339. Return Value:
  340. TRUE if the list (defined by the globals g_IniActHead and g_IniActTail) is not empty
  341. --*/
  342. {
  343. INFCONTEXT InfContext;
  344. PINIACT IniAct;
  345. PCTSTR Section;
  346. if (g_WkstaMigInf == INVALID_HANDLE_VALUE) {
  347. DEBUGMSG ((DBG_ERROR, "Ini Actions: wkstamig.inf is not loaded"));
  348. return FALSE;
  349. }
  350. if (Context == INIACT_WKS_FIRST) {
  351. Section = S_INIFILES_ACTIONS_FIRST;
  352. } else {
  353. Section = S_INIFILES_ACTIONS_LAST;
  354. }
  355. if (SetupFindFirstLine (g_WkstaMigInf, Section, NULL, &InfContext)) {
  356. do {
  357. IniAct = PoolMemGetMemory (g_IniActPool, sizeof (*IniAct));
  358. ZeroMemory (IniAct, sizeof (*IniAct));
  359. if (pGetIniActData (&InfContext, IniAct)) {
  360. //
  361. // add it to the list
  362. //
  363. if (g_IniActTail) {
  364. g_IniActTail->Next = IniAct;
  365. g_IniActTail = IniAct;
  366. } else {
  367. g_IniActHead = g_IniActTail = IniAct;
  368. }
  369. } else {
  370. pCleanUpIniAction (IniAct);
  371. PoolMemReleaseMemory (g_IniActPool, IniAct);
  372. }
  373. } while (SetupFindNextLine (&InfContext, &InfContext));
  374. }
  375. return g_IniActHead != NULL;
  376. }
  377. VOID
  378. pFreeIniActions (
  379. VOID
  380. )
  381. /*++
  382. Routine Description:
  383. pFreeIniActions destroys all rules in the global list (see g_IniActHead and g_IniActTail)
  384. Arguments:
  385. none
  386. Return Value:
  387. none
  388. --*/
  389. {
  390. PINIACT NextRule;
  391. while (g_IniActHead) {
  392. NextRule = g_IniActHead->Next;
  393. pCleanUpIniAction (g_IniActHead);
  394. PoolMemReleaseMemory (g_IniActPool, g_IniActHead);
  395. g_IniActHead = NextRule;
  396. }
  397. g_IniActTail = NULL;
  398. }
  399. BOOL
  400. pEnumFirstIniAction (
  401. OUT PINIACT* IniAct
  402. )
  403. /*++
  404. Routine Description:
  405. pEnumFirstIniAction enumerates the first rule in the global list and puts a pointer to it
  406. in IniAct
  407. Arguments:
  408. IniAct - Receives the first INI rule; NULL if none
  409. Return Value:
  410. TRUE if there is at least a rule, FALSE if list is empty
  411. --*/
  412. {
  413. *IniAct = g_IniActHead;
  414. return *IniAct != NULL;
  415. }
  416. BOOL
  417. pEnumNextIniAction (
  418. IN OUT PINIACT* IniAct
  419. )
  420. /*++
  421. Routine Description:
  422. pEnumNextIniAction enumerates the next action after IniAct in the global list and puts
  423. a pointer to it in the same IniAct
  424. Arguments:
  425. IniAct - Specifies a pointer to an INI rule; will receive a pointer to the next rule;
  426. receives NULL if last rule
  427. Return Value:
  428. TRUE if there is a rule following (*IniAct is a valid pointer), FALSE if not
  429. --*/
  430. {
  431. if (*IniAct) {
  432. *IniAct = (*IniAct)->Next;
  433. }
  434. return *IniAct != NULL;
  435. }
  436. PTSTR
  437. pGetAllKeys (
  438. IN PCTSTR IniFilePath,
  439. IN PCTSTR Section
  440. )
  441. /*++
  442. Routine Description:
  443. pGetAllKeys reads all keys or sections from the specified INI file and returns
  444. a pointer to allocated memory that contains all keys in the specified section.
  445. If section is NULL, a list of all sections is retrived instead.
  446. Arguments:
  447. IniFilePath - Specifies the INI file
  448. Section - Specifies the section containg the keys; if NULL, sections are retrieved
  449. instead of keys
  450. Return Value:
  451. A pointer to a multisz containing all keys or sections; caller must free the memory
  452. --*/
  453. {
  454. PTSTR Keys = NULL;
  455. DWORD Size = 64 * sizeof (TCHAR);
  456. DWORD chars;
  457. MYASSERT (IniFilePath);
  458. do {
  459. if (Keys) {
  460. PoolMemReleaseMemory (g_IniActPool, Keys);
  461. }
  462. Size *= 2;
  463. Keys = PoolMemGetMemory (g_IniActPool, Size);
  464. chars = GetPrivateProfileString (
  465. Section,
  466. NULL,
  467. TEXT(""),
  468. Keys,
  469. Size,
  470. IniFilePath
  471. );
  472. } while (chars == Size - 2);
  473. return Keys;
  474. }
  475. PTSTR
  476. pGetKeyValue (
  477. IN PCTSTR IniFilePath,
  478. IN PCTSTR Section,
  479. IN PCTSTR Key
  480. )
  481. /*++
  482. Routine Description:
  483. pGetKeyValue reads the value associated with the given key, section, INI file and returns
  484. a pointer to allocated memory that contains this value as a string.
  485. Both section and Key must not be NULL.
  486. Arguments:
  487. IniFilePath - Specifies the INI file
  488. Section - Specifies the section
  489. Key - Specifies the key
  490. Return Value:
  491. A pointer to a string containing the value; caller must free the memory
  492. --*/
  493. {
  494. PTSTR Value = NULL;
  495. DWORD Size = 64 * sizeof (TCHAR);
  496. DWORD chars;
  497. MYASSERT (IniFilePath);
  498. MYASSERT (Section);
  499. MYASSERT (Key);
  500. do {
  501. if (Value) {
  502. PoolMemReleaseMemory (g_IniActPool, Value);
  503. }
  504. Size *= 2;
  505. Value = PoolMemGetMemory (g_IniActPool, Size);
  506. chars = GetPrivateProfileString (
  507. Section,
  508. Key,
  509. TEXT(""),
  510. Value,
  511. Size,
  512. IniFilePath
  513. );
  514. } while (chars == Size - 1);
  515. return Value;
  516. }
  517. BOOL
  518. pIsFileActionRule (
  519. IN PINIACT IniAct,
  520. IN PINIFILE IniFile
  521. )
  522. /*++
  523. Routine Description:
  524. pIsFileActionRule determines if the specified rule applies to the whole INI file
  525. Arguments:
  526. IniAct - Specifies the INI action
  527. IniFile - Specifies the INI file
  528. Return Value:
  529. TRUE if the rule applies to the whole INI file, FALSE if not
  530. --*/
  531. {
  532. MYASSERT (IniAct);
  533. return !IniAct->RuleAttribs.Section && !IniAct->RuleAttribs.Key;
  534. }
  535. BOOL
  536. pDoFileAction (
  537. IN PINIACT IniAct,
  538. IN PINIFILE IniFile
  539. )
  540. /*++
  541. Routine Description:
  542. pDoFileAction applies the specified rule to the whole INI file
  543. Arguments:
  544. IniAct - Specifies the INI action
  545. IniFile - Specifies the INI file
  546. Return Value:
  547. the result returned by the INI action processing function on this INI file
  548. --*/
  549. {
  550. GROWBUFFER GbKeys = GROWBUF_INIT;
  551. PTSTR Sections, Keys;
  552. PCTSTR Section, Key;
  553. BOOL Result;
  554. MYASSERT (IniAct && IniAct->FnIniAct && !IniAct->RuleAttribs.Section && !IniAct->RuleAttribs.Key);
  555. Sections = pGetAllKeys (IniFile->ActualLocation, NULL);
  556. IniAct->RuleAttribs.Section = Sections;
  557. for (Section = Sections; *Section; Section = pGetNextMultiSzString (Section)) {
  558. Keys = pGetAllKeys (IniFile->ActualLocation, Section);
  559. for (Key = Keys; *Key; Key = pGetNextMultiSzString (Key)) {
  560. MultiSzAppend (&GbKeys, Key);
  561. }
  562. PoolMemReleaseMemory (g_IniActPool, Keys);
  563. }
  564. //
  565. // end with another zero (here are 2 TCHAR zeroes...)
  566. //
  567. GrowBufAppendDword (&GbKeys, 0);
  568. IniAct->RuleAttribs.Key = (PCTSTR)GbKeys.Buf;
  569. Result = (*IniAct->FnIniAct)(&IniAct->RuleAttribs, IniFile);
  570. IniAct->RuleAttribs.Key = NULL;
  571. IniAct->RuleAttribs.Section = NULL;
  572. FreeGrowBuffer (&GbKeys);
  573. PoolMemReleaseMemory (g_IniActPool, Sections);
  574. return Result;
  575. }
  576. BOOL
  577. pIsSectionActionRule(
  578. IN PINIACT IniAct,
  579. IN PINIFILE IniFile
  580. )
  581. /*++
  582. Routine Description:
  583. pIsSectionActionRule determines if the specified rule applies to a section
  584. of the INI file
  585. Arguments:
  586. IniAct - Specifies the INI action
  587. IniFile - Specifies the INI file
  588. Return Value:
  589. TRUE if the rule applies to a section of the INI file, FALSE if not
  590. --*/
  591. {
  592. MYASSERT (IniAct);
  593. return IniAct->RuleAttribs.Section && !IniAct->RuleAttribs.Key;
  594. }
  595. BOOL
  596. pDoSectionAction (
  597. IN PINIACT IniAct,
  598. IN PINIFILE IniFile
  599. )
  600. /*++
  601. Routine Description:
  602. pDoSectionAction applies the specified rule to a section of the INI file
  603. Arguments:
  604. IniAct - Specifies the INI action
  605. IniFile - Specifies the INI file
  606. Return Value:
  607. the result returned by the INI action processing function
  608. --*/
  609. {
  610. PTSTR Keys;
  611. BOOL Result;
  612. MYASSERT (IniAct && IniAct->FnIniAct && IniAct->RuleAttribs.Section && !IniAct->RuleAttribs.Key);
  613. Keys = pGetAllKeys (IniFile->ActualLocation, IniAct->RuleAttribs.Section);
  614. IniAct->RuleAttribs.Key = Keys;
  615. Result = (*IniAct->FnIniAct)(&IniAct->RuleAttribs, IniFile);
  616. IniAct->RuleAttribs.Key = NULL;
  617. PoolMemReleaseMemory (g_IniActPool, Keys);
  618. return Result;
  619. }
  620. BOOL
  621. pDoKeyAction (
  622. IN PINIACT IniAct,
  623. IN PINIFILE IniFile
  624. )
  625. /*++
  626. Routine Description:
  627. pDoKeyAction applies the specified rule to a key of the INI file
  628. Arguments:
  629. IniAct - Specifies the INI action
  630. IniFile - Specifies the INI file
  631. Return Value:
  632. the result returned by the INI action processing function
  633. --*/
  634. {
  635. MYASSERT (IniAct && IniAct->FnIniAct && IniAct->RuleAttribs.Key);
  636. return (*IniAct->FnIniAct)(&IniAct->RuleAttribs, IniFile);
  637. }
  638. BOOL
  639. pDoIniAction (
  640. IN PINIFILE IniFile
  641. )
  642. /*++
  643. Routine Description:
  644. This is the actual worker routine called by pDoIniActions for each INI file to
  645. be migrated.
  646. Arguments:
  647. IniFile - Specifies the INI file
  648. Return Value:
  649. TRUE if INI migration was successful for this file, FALSE otherwise
  650. --*/
  651. {
  652. PINIACT IniAct;
  653. BOOL Result = TRUE;
  654. BOOL b;
  655. //
  656. // check INI file against all rules; if a rule applies, do it
  657. //
  658. if (pEnumFirstIniAction (&IniAct)) {
  659. do {
  660. if (!IsPatternMatch (IniAct->RuleAttribs.IniSpec, IniFile->OrigIniPath)) {
  661. continue;
  662. }
  663. //
  664. // do the action; check for file actions first
  665. //
  666. if (pIsFileActionRule (IniAct, IniFile)) {
  667. b = pDoFileAction (IniAct, IniFile);
  668. } else {
  669. //
  670. // check section actions next
  671. //
  672. if (pIsSectionActionRule (IniAct, IniFile)) {
  673. //
  674. // do it for each section in the current file
  675. //
  676. b = pDoSectionAction (IniAct, IniFile);
  677. } else {
  678. //
  679. // do key actions last
  680. //
  681. b = pDoKeyAction (IniAct, IniFile);
  682. }
  683. }
  684. DEBUGMSG_IF ((
  685. !b,
  686. DBG_INIACT,
  687. "pDoIniActions: function [%s] failed on file [%s]",
  688. IniAct->FnName,
  689. IniFile->OrigIniPath
  690. ));
  691. Result &= b;
  692. } while (pEnumNextIniAction (&IniAct));
  693. }
  694. return Result;
  695. }
  696. BOOL
  697. pDoIniActions (
  698. IN INIACT_CONTEXT Context
  699. )
  700. /*++
  701. Routine Description:
  702. This is the actual worker routine called by DoIniActions. It may be called
  703. in different contexts.
  704. Arguments:
  705. Context - Specifies the context in which the function is called
  706. Return Value:
  707. TRUE if INI files migration was successful, FALSE otherwise
  708. --*/
  709. {
  710. MEMDB_ENUM e;
  711. INIFILE IniFile;
  712. PCTSTR OrigIniPath;
  713. PCTSTR ActualLocation;
  714. PCTSTR NtIniPath;
  715. PCTSTR MemDbCategory;
  716. //
  717. // get all rules first
  718. //
  719. if (pCreateIniActions (Context)) {
  720. //
  721. // enum all candidates files from corresponding memdb category
  722. //
  723. if (Context == INIACT_WKS_FIRST) {
  724. MemDbCategory = MEMDB_CATEGORY_INIACT_FIRST;
  725. } else {
  726. MemDbCategory = MEMDB_CATEGORY_INIACT_LAST;
  727. }
  728. if (MemDbGetValueEx (&e, MemDbCategory, NULL, NULL)) {
  729. do {
  730. OrigIniPath = e.szName;
  731. ActualLocation = GetTemporaryLocationForFile (OrigIniPath);
  732. if (!ActualLocation) {
  733. DEBUGMSG ((
  734. DBG_ERROR,
  735. "Couldn't find temp location for INIACT key: %s\\%s",
  736. MemDbCategory,
  737. e.szName
  738. ));
  739. continue;
  740. }
  741. NtIniPath = GetPathStringOnNt (OrigIniPath);
  742. //
  743. // fill in the members of IniFile
  744. //
  745. IniFile.OrigIniPath = OrigIniPath;
  746. IniFile.ActualLocation = ActualLocation;
  747. IniFile.NtIniPath = NtIniPath;
  748. if (!pDoIniAction (&IniFile)) {
  749. DEBUGMSG ((
  750. DBG_INIACT,
  751. "Some errors occured during migration of INI file [%s] -> [%s]",
  752. OrigIniPath,
  753. NtIniPath
  754. ));
  755. }
  756. //
  757. // now convert the INI file (fix paths etc)
  758. //
  759. // ConvertIniFile (NtIniPath);
  760. FreePathString (NtIniPath);
  761. FreePathString (ActualLocation);
  762. ZeroMemory (&IniFile, sizeof (IniFile));
  763. } while (MemDbEnumNextValue (&e));
  764. }
  765. pFreeIniActions ();
  766. }
  767. return TRUE;
  768. }
  769. BOOL
  770. DoIniActions (
  771. IN INIACT_CONTEXT Context
  772. )
  773. /*++
  774. Routine Description:
  775. This is the main routine called to perform INI files migration. It may be called
  776. several times, specifying the context.
  777. Arguments:
  778. Context - Specifies the context in which the function is called
  779. Return Value:
  780. TRUE if INI files migration was successful in that context, FALSE otherwise
  781. --*/
  782. {
  783. BOOL b;
  784. g_IniActPool = PoolMemInitNamedPool ("IniAct");
  785. if (!g_IniActPool) {
  786. return FALSE;
  787. }
  788. b = FALSE;
  789. __try {
  790. b = pDoIniActions (Context);
  791. }
  792. __finally {
  793. PoolMemDestroyPool (g_IniActPool);
  794. g_IniActPool = NULL;
  795. }
  796. return b;
  797. }
  798. BOOL
  799. pIsValidGuidStr (
  800. IN PCTSTR GuidStr
  801. )
  802. /*++
  803. Routine Description:
  804. Determines if a GUID represented as a string has a valid representation (braces included).
  805. Arguments:
  806. GuidStr - Specifies the GUID to check; it must contain the surrounding braces
  807. Return Value:
  808. TRUE if the specified GUID is valid, or FALSE if it is not.
  809. --*/
  810. {
  811. DWORD GuidIdx, DashIdx;
  812. BYTE DashIndexes[4] = { DASH_INDEXES };
  813. TCHAR ch;
  814. MYASSERT (GuidStr);
  815. if (_tcslen (GuidStr) != GUIDSTR_LEN ||
  816. GuidStr[0] != TEXT('{') ||
  817. GuidStr[GUIDSTR_LEN - 1] != TEXT('}')) {
  818. return FALSE;
  819. }
  820. for (GuidIdx = 1, DashIdx = 0; GuidIdx < GUIDSTR_LEN - 1; GuidIdx++) {
  821. //
  822. // check all digits and dashes positions
  823. //
  824. ch = GuidStr[GuidIdx];
  825. if (DashIdx < 4 && (BYTE)GuidIdx == DashIndexes[DashIdx]) {
  826. if (ch != TEXT('-')) {
  827. return FALSE;
  828. }
  829. DashIdx++;
  830. } else {
  831. if (ch < TEXT('0') || ch > TEXT('9')) {
  832. if (!(ch >= TEXT('A') && ch <= TEXT('F') || ch >= TEXT('a') && ch <= TEXT('f'))) {
  833. return FALSE;
  834. }
  835. }
  836. }
  837. }
  838. return TRUE;
  839. }
  840. BOOL
  841. pIsGuidSuppressed (
  842. PCTSTR GuidStr
  843. )
  844. /*++
  845. Routine Description:
  846. Determines if a GUID is suppressed or not.
  847. Arguments:
  848. GuidStr - Specifies the GUID to look up, which must be valid and
  849. must contain the surrounding braces
  850. Return Value:
  851. TRUE if the specified GUID is suppressed, or FALSE if it is not.
  852. --*/
  853. {
  854. TCHAR Node[MEMDB_MAX];
  855. MemDbBuildKey (
  856. Node,
  857. MEMDB_CATEGORY_GUIDS,
  858. NULL,
  859. NULL,
  860. GuidStr
  861. );
  862. return MemDbGetValue (Node, NULL);
  863. }
  864. BOOL
  865. pIsValidShellExtClsid (
  866. IN PCTSTR GuidStr
  867. )
  868. /*++
  869. Routine Description:
  870. pIsValidShellExtClsid determines if a GUID is a valid shell extension
  871. Arguments:
  872. GuidStr - Specifies the GUID to look up, which must be valid and
  873. must contain the surrounding braces
  874. Return Value:
  875. TRUE if the specified GUID is a valid shell ext, or FALSE if it is not.
  876. --*/
  877. {
  878. #if 0
  879. HKEY Key;
  880. LONG rc;
  881. #endif
  882. //
  883. // check if the GUID is a known bad guid
  884. //
  885. if (pIsGuidSuppressed (GuidStr)) {
  886. return FALSE;
  887. }
  888. return TRUE;
  889. //
  890. // I removed the registry check because it is not always accurate;
  891. // some GUIDS may work without being listed in S_SHELLEXT_APPROVED keys
  892. // as it's the case with the default GUID {5984FFE0-28D4-11CF-AE66-08002B2E1262}
  893. //
  894. #if 0
  895. rc = TrackedRegOpenKeyEx (
  896. HKEY_LOCAL_MACHINE,
  897. S_SHELLEXT_APPROVED,
  898. 0,
  899. KEY_QUERY_VALUE,
  900. &Key
  901. );
  902. if (rc == ERROR_SUCCESS) {
  903. rc = RegQueryValueEx (Key, GuidStr, NULL, NULL, NULL, NULL);
  904. CloseRegKey (Key);
  905. }
  906. if (rc == ERROR_SUCCESS) {
  907. return TRUE;
  908. }
  909. return FALSE;
  910. #endif
  911. }
  912. BOOL
  913. pFindStrInMultiSzStrI (
  914. IN PCTSTR Str,
  915. IN PCTSTR MultiSz
  916. )
  917. /*++
  918. Routine Description:
  919. pFindStrInMultiSzStrI looks for Str in a list of multi-sz; the search is case-insensitive
  920. Arguments:
  921. Str - Specifies the string to look for
  922. MultiSz - Specifies the list to be searched
  923. Return Value:
  924. TRUE if the string was found in the list, or FALSE if not.
  925. --*/
  926. {
  927. PCTSTR p;
  928. for (p = MultiSz; *p; p = pGetNextMultiSzString (p)) {
  929. if (StringIMatch (p, Str)) {
  930. return TRUE;
  931. }
  932. }
  933. return FALSE;
  934. }
  935. BOOL
  936. pMigrateSection (
  937. IN PCTSTR Section,
  938. IN PRULEATTRIBS RuleAttribs,
  939. IN PINIFILE IniFile
  940. )
  941. /*++
  942. Routine Description:
  943. pMigrateSection migrates a whole section of the INI file.
  944. Arguments:
  945. Section - Specifies section name
  946. RuleAttribs - Specifies the rule attributes which govern the migration
  947. IniFile - Specifies the INI file
  948. Return Value:
  949. TRUE if the section was transferred successfully, or FALSE if not.
  950. --*/
  951. {
  952. PTSTR Keys;
  953. PTSTR Value;
  954. PCTSTR Key;
  955. BOOL b = TRUE;
  956. Keys = pGetAllKeys (IniFile->ActualLocation, Section);
  957. if (*Keys) {
  958. //
  959. // there are keys to transfer; first remove the entire section that will be replaced
  960. //
  961. WritePrivateProfileString (
  962. Section,
  963. NULL,
  964. NULL,
  965. IniFile->NtIniPath
  966. );
  967. }
  968. for (Key = Keys; *Key; Key = pGetNextMultiSzString (Key)) {
  969. Value = pGetKeyValue (IniFile->ActualLocation, Section, Key);
  970. b &= WritePrivateProfileString (
  971. Section,
  972. Key,
  973. Value,
  974. IniFile->NtIniPath
  975. );
  976. PoolMemReleaseMemory (g_IniActPool, Value);
  977. }
  978. PoolMemReleaseMemory (g_IniActPool, Keys);
  979. return b;
  980. }
  981. BOOL
  982. MigrateDesktopIniSCI (
  983. IN PRULEATTRIBS RuleAttribs,
  984. IN PINIFILE IniFile
  985. )
  986. /*++
  987. Routine Description:
  988. MigrateDesktopIniSCI migrates desktop.ini settings in section [.ShellClassInfo].
  989. It reads all keys and associated values within the section and writes them back
  990. to the NT version of this file. The "settings" multisz in this case represents
  991. a list of keys that must be synchronized; if no Win9x key exists, the corresponding
  992. NT key must be deleted; if the Win9x key exists, its value is copied
  993. Arguments:
  994. RuleAttribs - Specifies the rule attributes which govern the migration
  995. IniFile - Specifies the INI file
  996. Return Value:
  997. TRUE if the section was transferred successfully, or FALSE if an error occured.
  998. --*/
  999. {
  1000. PCTSTR Key, SKey, NewValue;
  1001. BOOL Found;
  1002. BOOL Result, b;
  1003. PTSTR Win9xValue, NtValue;
  1004. TCHAR Dummy[2];
  1005. DEBUGMSG ((
  1006. DBG_INIACT,
  1007. "Processing: %s -> %s [%s]",
  1008. IniFile->OrigIniPath,
  1009. IniFile->NtIniPath,
  1010. RuleAttribs->Section
  1011. ));
  1012. Result = TRUE;
  1013. //
  1014. // RuleAttribs->Settings points in this case to a list of keys that
  1015. // must be synchronized; if no Win9x key exists, the corresponding
  1016. // NT key must be deleted; if Win9x key exists, its value is copied
  1017. //
  1018. for (SKey = (PCTSTR)RuleAttribs->Settings.Buf;
  1019. *SKey;
  1020. SKey = pGetNextMultiSzString (SKey)
  1021. ) {
  1022. Found = FALSE;
  1023. for (Key = RuleAttribs->Key; *Key; Key = pGetNextMultiSzString (Key)) {
  1024. if (StringIMatch (SKey, Key)) {
  1025. Found = TRUE;
  1026. break;
  1027. }
  1028. }
  1029. if (!Found) {
  1030. //
  1031. // remove NT key if there is one
  1032. //
  1033. if (GetPrivateProfileString (
  1034. RuleAttribs->Section,
  1035. SKey,
  1036. TEXT(""),
  1037. Dummy,
  1038. 2,
  1039. IniFile->NtIniPath
  1040. )) {
  1041. if (!WritePrivateProfileString (
  1042. RuleAttribs->Section,
  1043. SKey,
  1044. NULL,
  1045. IniFile->NtIniPath
  1046. )) {
  1047. Result = FALSE;
  1048. DEBUGMSG ((DBG_INIACT, "Couldn't remove NT key [%s]", SKey));
  1049. }
  1050. ELSE_DEBUGMSG ((DBG_INIACT, "Removed NT key [%s]", SKey));
  1051. }
  1052. }
  1053. }
  1054. for (Key = RuleAttribs->Key; *Key; Key = pGetNextMultiSzString (Key)) {
  1055. //
  1056. // for each key on Win9x, update NT value;
  1057. // check for suppressed GUIDs
  1058. //
  1059. Win9xValue = pGetKeyValue (IniFile->ActualLocation, RuleAttribs->Section, Key);
  1060. NewValue = Win9xValue;
  1061. if (pIsValidGuidStr (NewValue) && pIsGuidSuppressed (NewValue)) {
  1062. //
  1063. // remove the key
  1064. //
  1065. NewValue = NULL;
  1066. }
  1067. NtValue = pGetKeyValue (IniFile->NtIniPath, RuleAttribs->Section, Key);
  1068. if (!NewValue && *NtValue || !StringMatch (NewValue, NtValue)) {
  1069. b = WritePrivateProfileString (
  1070. RuleAttribs->Section,
  1071. Key,
  1072. NewValue,
  1073. IniFile->NtIniPath
  1074. );
  1075. if (b) {
  1076. DEBUGMSG ((
  1077. DBG_INIACT,
  1078. "Replaced key [%s] NT value [%s] with 9x value [%s]",
  1079. Key,
  1080. NtValue,
  1081. Win9xValue));
  1082. } else {
  1083. Result = FALSE;
  1084. DEBUGMSG ((
  1085. DBG_INIACT,
  1086. "Failed to replace key [%s] NT value [%s] with 9x value [%s]",
  1087. Key,
  1088. NtValue,
  1089. Win9xValue));
  1090. }
  1091. }
  1092. PoolMemReleaseMemory (g_IniActPool, Win9xValue);
  1093. PoolMemReleaseMemory (g_IniActPool, NtValue);
  1094. }
  1095. return Result;
  1096. }
  1097. BOOL
  1098. MigrateDesktopIniESFV (
  1099. IN PRULEATTRIBS RuleAttribs,
  1100. IN PINIFILE IniFile
  1101. )
  1102. /*++
  1103. Routine Description:
  1104. MigrateDesktopIniESFV migrates desktop.ini settings in section [ExtShellFolderViews].
  1105. It reads all keys and associated values within the section and writes them back
  1106. to the NT version of this file. The "settings" multisz is not interpreted in this case.
  1107. Arguments:
  1108. RuleAttribs - Specifies the rule attributes which govern the migration
  1109. IniFile - Specifies the INI file
  1110. Return Value:
  1111. TRUE if the section was transferred successfully, or FALSE if an error occured.
  1112. --*/
  1113. {
  1114. PCTSTR ViewID;
  1115. BOOL b, Result;
  1116. DWORD chars;
  1117. PTSTR Win9xValue;
  1118. TCHAR DefaultViewID[GUIDSTR_LEN + 2];
  1119. BOOL ReplaceDefViewID = FALSE;
  1120. PTSTR NtValue;
  1121. #ifdef DEBUG
  1122. TCHAR NtViewID[GUIDSTR_LEN + 2];
  1123. #endif
  1124. Result = TRUE;
  1125. DEBUGMSG ((
  1126. DBG_INIACT,
  1127. "Processing: %s -> %s [%s]",
  1128. IniFile->OrigIniPath,
  1129. IniFile->NtIniPath,
  1130. RuleAttribs->Section
  1131. ));
  1132. //
  1133. // get the default view id
  1134. //
  1135. chars = GetPrivateProfileString (
  1136. RuleAttribs->Section,
  1137. S_DEFAULT,
  1138. TEXT(""),
  1139. DefaultViewID,
  1140. GUIDSTR_LEN + 2,
  1141. IniFile->ActualLocation
  1142. );
  1143. if (*DefaultViewID && chars != GUIDSTR_LEN || !pIsValidShellExtClsid (DefaultViewID)) {
  1144. //
  1145. // invalid view id
  1146. //
  1147. DEBUGMSG ((
  1148. DBG_INIACT,
  1149. "Invalid Default ViewID [%s]; will not be processed",
  1150. DefaultViewID
  1151. ));
  1152. *DefaultViewID = 0;
  1153. }
  1154. for (ViewID = RuleAttribs->Key; *ViewID; ViewID = pGetNextMultiSzString (ViewID)) {
  1155. //
  1156. // except for Default={ViewID},
  1157. // all the other lines in this section should have the format {ViewID}=value
  1158. // for each {ViewID} there is a section with the same name
  1159. // keeping other keys (attributes of that shell view)
  1160. //
  1161. if (StringIMatch (ViewID, S_DEFAULT)) {
  1162. continue;
  1163. }
  1164. if (pIsValidGuidStr (ViewID) && pIsValidShellExtClsid (ViewID)) {
  1165. //
  1166. // transfer the whole GUID section, if it's not one that shouldn't be migrated
  1167. // a list of GUIDS that shouldn't be migrated is in RuleAttribs->Settings
  1168. //
  1169. if (!pFindStrInMultiSzStrI (ViewID, (PCTSTR)RuleAttribs->Settings.Buf)) {
  1170. b = pMigrateSection (ViewID, RuleAttribs, IniFile);
  1171. if (b) {
  1172. DEBUGMSG ((DBG_INIACT, "Successfully migrated section [%s]", ViewID));
  1173. if (*DefaultViewID && !StringIMatch (ViewID, DefaultViewID)) {
  1174. ReplaceDefViewID = TRUE;
  1175. }
  1176. //
  1177. // set {ViewID}=value in NT desktop.ini
  1178. //
  1179. NtValue = pGetKeyValue (IniFile->NtIniPath, RuleAttribs->Section, ViewID);
  1180. Win9xValue = pGetKeyValue (
  1181. IniFile->ActualLocation,
  1182. RuleAttribs->Section,
  1183. ViewID
  1184. );
  1185. if (!StringIMatch (NtValue, Win9xValue)) {
  1186. b = WritePrivateProfileString (
  1187. RuleAttribs->Section,
  1188. ViewID,
  1189. Win9xValue,
  1190. IniFile->NtIniPath
  1191. );
  1192. DEBUGMSG_IF ((
  1193. b,
  1194. DBG_INIACT,
  1195. "Replaced key [%s] NT value [%s] with 9x value [%s]",
  1196. ViewID,
  1197. NtValue,
  1198. Win9xValue));
  1199. } else {
  1200. b = TRUE;
  1201. }
  1202. PoolMemReleaseMemory (g_IniActPool, Win9xValue);
  1203. PoolMemReleaseMemory (g_IniActPool, NtValue);
  1204. }
  1205. ELSE_DEBUGMSG ((DBG_INIACT, "Section [%s] was not migrated successfully", ViewID));
  1206. //
  1207. // update global result
  1208. //
  1209. Result &= b;
  1210. }
  1211. }
  1212. ELSE_DEBUGMSG ((DBG_INIACT, "Invalid ShellExtViewID: [%s]; will not be processed", ViewID));
  1213. }
  1214. if (ReplaceDefViewID) {
  1215. //
  1216. // replace NT default view with Win9x default view
  1217. //
  1218. #ifdef DEBUG
  1219. GetPrivateProfileString (
  1220. RuleAttribs->Section,
  1221. S_DEFAULT,
  1222. TEXT(""),
  1223. NtViewID,
  1224. GUIDSTR_LEN + 2,
  1225. IniFile->NtIniPath
  1226. );
  1227. #endif
  1228. b = WritePrivateProfileString (
  1229. RuleAttribs->Section,
  1230. S_DEFAULT,
  1231. DefaultViewID,
  1232. IniFile->NtIniPath
  1233. );
  1234. DEBUGMSG_IF ((
  1235. b,
  1236. DBG_INIACT,
  1237. "Replaced default NT ViewID [%s] with Default Win9x ViewID [%s]",
  1238. NtViewID,
  1239. DefaultViewID));
  1240. Result &= b;
  1241. }
  1242. return Result;
  1243. }