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.

752 lines
17 KiB

  1. #include "pch.h"
  2. #define MIGRATEINF ".\\migrate.inf"
  3. #define INITIALBUFFERSIZE 1024
  4. #define MIGINF_NOCREATE FALSE
  5. #define MIGINF_CREATE TRUE
  6. typedef struct tagMIGOBJECT MIGOBJECT, *PMIGOBJECT;
  7. struct tagMIGOBJECT {
  8. PSTR Key;
  9. PSTR Value;
  10. PMIGOBJECT Next;
  11. };
  12. typedef struct tagMIGSECTION MIGSECTION, * PMIGSECTION;
  13. struct tagMIGSECTION {
  14. PSTR Name;
  15. PMIGOBJECT Items;
  16. PMIGSECTION Next;
  17. };
  18. PMIGSECTION g_MigrationInf;
  19. POOLHANDLE g_Pool = NULL;
  20. static
  21. PCSTR
  22. pGetTypeAsString (
  23. IN MIGTYPE Type
  24. )
  25. {
  26. //
  27. // Note: Strings must be in the same order as the
  28. // corresponding types in the MIGTYPE enumeration above.
  29. //
  30. static PCHAR typeStrings[] = {
  31. "FIRST - Invalid",
  32. "File",
  33. "Path",
  34. "Registry",
  35. "Message - Invalid",
  36. "LAST - Invalid"
  37. };
  38. assert(Type > MIG_FIRSTTYPE && Type < MIG_LASTTYPE);
  39. return typeStrings[Type];
  40. }
  41. static
  42. PMIGSECTION
  43. pFindSection (
  44. IN PCSTR SectionString,
  45. IN BOOL CreateIfNotExist
  46. )
  47. {
  48. PMIGSECTION rSection;
  49. //
  50. // We assume that SectionString is not null.
  51. //
  52. assert(SectionString);
  53. rSection = g_MigrationInf;
  54. while (rSection && (_mbsicmp(rSection -> Name,SectionString) != 0)) {
  55. //
  56. // Continue looking.
  57. //
  58. rSection = rSection -> Next;
  59. }
  60. if (!rSection && CreateIfNotExist) {
  61. //
  62. // No section was found matching this name. Make a new section and add it
  63. // to the list.
  64. //
  65. rSection = PoolMemGetMemory(g_Pool,sizeof(MIGSECTION));
  66. if (rSection) {
  67. ZeroMemory(rSection,sizeof(MIGSECTION));
  68. rSection -> Name = PoolMemDuplicateStringA(g_Pool,SectionString);
  69. rSection -> Next = g_MigrationInf;
  70. g_MigrationInf = rSection;
  71. if (!rSection -> Name) {
  72. //
  73. // Something went wrong when we tried to duplicate the SectionString.
  74. // NULL out the rSection so that the caller doesn't get back a
  75. // malformed section object.
  76. //
  77. rSection = NULL;
  78. }
  79. }
  80. }
  81. return rSection;
  82. }
  83. static
  84. BOOL
  85. pPathIsInPath(
  86. IN PCSTR SubPath,
  87. IN PCSTR ParentPath
  88. )
  89. {
  90. DWORD parentLength;
  91. BOOL rInPath;
  92. //
  93. // This function assumes both parameters are non-NULL.
  94. //
  95. assert(SubPath);
  96. assert(ParentPath);
  97. parentLength = _mbslen(ParentPath);
  98. //
  99. // A path is considered "in" another path if the path is in the ParentPath
  100. // or a subdirectory of it.
  101. //
  102. rInPath = !_mbsnicmp(SubPath,ParentPath,parentLength);
  103. if (rInPath) {
  104. rInPath = SubPath[parentLength] == 0 || SubPath[parentLength] == '\\';
  105. }
  106. return rInPath;
  107. }
  108. static
  109. DWORD
  110. pGetMbsSize (
  111. IN LPCSTR String
  112. )
  113. {
  114. DWORD rLength;
  115. rLength = (DWORD) _mbschr(String,0) - (DWORD) String + 1;
  116. return rLength;
  117. }
  118. static
  119. LPSTR
  120. pEscapeString (
  121. IN MIGTYPE Type,
  122. OUT LPSTR EscapedString,
  123. IN LPCSTR String
  124. )
  125. {
  126. LPSTR stringStart;
  127. static CHAR exclusions[] = "[]~,;%\"";
  128. INT currentChar;
  129. //
  130. // We assume that all parameters are valid.
  131. //
  132. assert(EscapedString && String);
  133. stringStart = EscapedString;
  134. while (*String) {
  135. currentChar = _mbsnextc (String);
  136. if (Type == MIG_REGKEY) {
  137. //
  138. // Registry keys require more complex escaping than do normal INF strings.
  139. //
  140. if (!_ismbcprint (currentChar) || _mbschr (exclusions, currentChar)) {
  141. //
  142. // Escape unprintable or excluded character
  143. //
  144. wsprintfA (EscapedString, "~%X~", currentChar);
  145. EscapedString = _mbschr (EscapedString, 0);
  146. String = _mbsinc (String);
  147. }
  148. else {
  149. //
  150. // Copy multibyte character
  151. //
  152. if (IsDBCSLeadByte (*String)) {
  153. *EscapedString = *String;
  154. EscapedString++;
  155. String++;
  156. }
  157. *EscapedString = *String;
  158. EscapedString++;
  159. String++;
  160. }
  161. }
  162. else {
  163. //
  164. // Escaping is pretty simple for non-registry keys. All we do is double up
  165. // quotes and percents.
  166. //
  167. if (*String == '\"' || *String == '%') {
  168. *EscapedString = *String;
  169. EscapedString++;
  170. }
  171. //
  172. // Copy multibyte character
  173. //
  174. if (IsDBCSLeadByte (*String)) {
  175. *EscapedString = *String;
  176. EscapedString++;
  177. String++;
  178. }
  179. *EscapedString = *String;
  180. EscapedString++;
  181. String++;
  182. }
  183. }
  184. //
  185. // Ensure that returned string is NULL terminated.
  186. //
  187. *EscapedString = 0;
  188. return stringStart;
  189. }
  190. static
  191. PSTR
  192. pGetValueString (
  193. IN MIGTYPE ObjectType,
  194. IN LPCSTR StringOne,
  195. IN LPCSTR StringTwo
  196. )
  197. {
  198. static PSTR buffer;
  199. static DWORD bufferSize;
  200. DWORD maxLength;
  201. PSTR bufferEnd;
  202. //
  203. // This function assumes that StringOne exists.
  204. //
  205. assert(StringOne);
  206. if (ObjectType == MIG_REGKEY) {
  207. //
  208. // Size: size of both strings, plus the size of the quotes, plus the size of the brackets
  209. // for the value, * 6. This is the maximum size one of these could grow to, if every
  210. // character had to be escaped out.
  211. //
  212. maxLength = (pGetMbsSize(StringOne) + (StringTwo ? pGetMbsSize(StringTwo) + 2 : 0)) * 6 + 2;
  213. }
  214. else {
  215. //
  216. // Size: size of the string * 2 (The max size if every char was a '%' or '"' plus the quotes.
  217. //
  218. maxLength = pGetMbsSize(StringOne) * 2 + 2;
  219. }
  220. if (maxLength > bufferSize) {
  221. //
  222. // Initialize our buffer, or create a larger one.
  223. //
  224. bufferSize = (maxLength > INITIALBUFFERSIZE) ? maxLength : INITIALBUFFERSIZE;
  225. buffer = PoolMemCreateStringA(g_Pool,bufferSize);
  226. }
  227. if (buffer != NULL) {
  228. //
  229. // Insert initial quote.
  230. //
  231. *buffer = '"';
  232. //
  233. // Massage the string to ensure it is a valid INF file string.
  234. //
  235. pEscapeString(ObjectType,_mbsinc(buffer),StringOne);
  236. //
  237. // If this is a REGISTRY entry, then we also need to add the value part of the string,
  238. // if one was specified (In StringTwo)
  239. //
  240. if (ObjectType == MIG_REGKEY && StringTwo) {
  241. //
  242. // Add the opening bracket.
  243. //
  244. bufferEnd = _mbschr(buffer,0);
  245. *bufferEnd = '[';
  246. //
  247. // Add the value string in, again making sure the string is valid for an INF file.
  248. //
  249. pEscapeString(ObjectType,_mbsinc(bufferEnd),StringTwo);
  250. //
  251. // Now, add the closing braket.
  252. //
  253. bufferEnd = _mbschr(buffer,0);
  254. *bufferEnd = ']';
  255. //
  256. // Terminate the string.
  257. //
  258. bufferEnd = _mbsinc(bufferEnd);
  259. *bufferEnd = 0;
  260. }
  261. //
  262. // Add the final quote.
  263. //
  264. bufferEnd = _mbschr(buffer,0);
  265. *bufferEnd = '"';
  266. bufferEnd = _mbsinc(bufferEnd);
  267. *bufferEnd = 0;
  268. }
  269. return buffer;
  270. }
  271. static
  272. BOOL
  273. pCreateMigObject (
  274. IN MIGTYPE ObjectType,
  275. IN PCSTR ParamOne,
  276. IN PCSTR ParamTwo,
  277. IN PMIGSECTION Section
  278. )
  279. {
  280. BOOL rSuccess;
  281. PMIGOBJECT newObject = NULL;
  282. //
  283. // pCreateMigObject uses a set of hueristics to correctly assemble an object.
  284. // These hueristics are based on the ObjectType and the contents of ParamTwo.
  285. //
  286. // ObjectType ParamTwo Key Value
  287. // -------------------------------------------------------------------------
  288. // MIG_REGKEY <any> ParamOne[ParamTwo] Registry
  289. // <other> NULL ParamOne <ObjectType As String>
  290. // <other> non-NULL ParamOne ParamTwo
  291. //
  292. //
  293. if (Section) {
  294. //
  295. // First, create an object...
  296. //
  297. newObject = PoolMemGetMemory(g_Pool,sizeof(MIGOBJECT));
  298. if (newObject) {
  299. if (ObjectType == MIG_REGKEY) {
  300. newObject -> Key =
  301. PoolMemDuplicateStringA(g_Pool,pGetValueString(ObjectType,ParamOne,ParamTwo));
  302. newObject -> Value = PoolMemDuplicateStringA(g_Pool,pGetTypeAsString(ObjectType));
  303. }
  304. else {
  305. newObject -> Key =
  306. PoolMemDuplicateStringA(g_Pool,pGetValueString(ObjectType,ParamOne,NULL));
  307. if (ParamTwo) {
  308. newObject -> Value =
  309. PoolMemDuplicateStringA(g_Pool,pGetValueString(ObjectType,ParamTwo,NULL));
  310. }
  311. else {
  312. newObject -> Value =
  313. PoolMemDuplicateStringA(g_Pool,pGetTypeAsString(ObjectType));
  314. }
  315. }
  316. }
  317. }
  318. if (newObject && newObject -> Key && newObject -> Value) {
  319. //
  320. // The object has been successfully created. Link it into the section.
  321. //
  322. newObject -> Next = Section -> Items;
  323. Section -> Items = newObject;
  324. rSuccess = TRUE;
  325. }
  326. else {
  327. rSuccess = FALSE;
  328. }
  329. return newObject && newObject -> Key && newObject -> Value;
  330. }
  331. static
  332. BOOL
  333. pWriteInfSectionToDisk (
  334. IN PMIGSECTION Section
  335. )
  336. {
  337. PMIGOBJECT curObject;
  338. BOOL rSuccess = TRUE;
  339. if (Section) {
  340. curObject = Section -> Items;
  341. while (curObject && rSuccess) {
  342. if (Section -> Name && curObject -> Key && curObject -> Value) {
  343. rSuccess = WritePrivateProfileString(
  344. Section -> Name,
  345. curObject -> Key,
  346. curObject -> Value,
  347. MIGRATEINF
  348. );
  349. }
  350. curObject = curObject -> Next;
  351. }
  352. }
  353. else {
  354. rSuccess = FALSE;
  355. }
  356. return rSuccess;
  357. }
  358. static
  359. BOOL
  360. pBuildListFromSection (
  361. IN PCSTR SectionString
  362. )
  363. {
  364. HINF infHandle;
  365. PMIGSECTION section;
  366. PMIGOBJECT currentObject;
  367. INFCONTEXT ic;
  368. DWORD size;
  369. BOOL rSuccess = TRUE;
  370. //
  371. // This function assumes that Section is non-NULL.
  372. //
  373. assert(SectionString);
  374. currentObject = NULL;
  375. //
  376. // First find the section specified.
  377. //
  378. section = pFindSection(SectionString,MIGINF_CREATE);
  379. if (section) {
  380. infHandle = SetupOpenInfFileA(MIGRATEINF,NULL,INF_STYLE_WIN4,NULL);
  381. if (infHandle != INVALID_HANDLE_VALUE) {
  382. if (SetupFindFirstLine(infHandle,SectionString,NULL,&ic)) {
  383. do {
  384. //
  385. // Create the object.
  386. //
  387. currentObject = (PMIGOBJECT) PoolMemGetMemory(g_Pool,sizeof(MIGOBJECT));
  388. if (!currentObject) {
  389. rSuccess = FALSE;
  390. break;
  391. }
  392. //
  393. // Get the size of the string.
  394. //
  395. if (!SetupGetLineTextA(&ic,NULL,NULL,NULL,NULL,0,&size)) {
  396. rSuccess = FALSE;
  397. break;
  398. }
  399. //
  400. // Create a string large enough.
  401. //
  402. currentObject -> Key = PoolMemCreateStringA(g_Pool,size);
  403. if (!currentObject -> Key) {
  404. rSuccess = FALSE;
  405. break;
  406. }
  407. //
  408. // Get the string.
  409. //
  410. if (!SetupGetLineTextA(&ic,NULL,NULL,NULL,currentObject -> Key,size,NULL)) {
  411. rSuccess = FALSE;
  412. break;
  413. }
  414. //
  415. // Successfully retrieved the line.
  416. //
  417. currentObject -> Value = (PSTR) pGetTypeAsString(MIG_FILE);
  418. currentObject -> Next = section -> Items;
  419. section -> Items = currentObject;
  420. } while(SetupFindNextLine(&ic,&ic));
  421. }
  422. SetupCloseInfFile(infHandle);
  423. }
  424. }
  425. else {
  426. rSuccess = FALSE;
  427. }
  428. return rSuccess;
  429. }
  430. BOOL
  431. WINAPI
  432. MigInf_Initialize(
  433. VOID
  434. )
  435. {
  436. //
  437. // First, initialize our pool and Zero out the structure.
  438. //
  439. g_Pool = PoolMemInitPool();
  440. if (g_Pool) {
  441. //
  442. // Now, read in the migration paths and excluded paths sections.
  443. //
  444. if (!pBuildListFromSection(SECTION_MIGRATIONPATHS) ||
  445. !pBuildListFromSection(SECTION_EXCLUDEDPATHS)) {
  446. //
  447. // Something went wrong (i.e. out of memory. Destroy and NULL our pool.
  448. //
  449. PoolMemDestroyPool(g_Pool);
  450. g_Pool = NULL;
  451. }
  452. }
  453. //
  454. // If our memory pool initialized successfully, return TRUE.
  455. //
  456. return (g_Pool != NULL);
  457. }
  458. VOID
  459. WINAPI
  460. MigInf_CleanUp (
  461. VOID
  462. )
  463. {
  464. //
  465. // Only thing we need to do is clean out pool mem. We'll NULL out the list header to make
  466. // sure it isn't usable.
  467. //
  468. if (g_Pool) {
  469. PoolMemDestroyPool(g_Pool);
  470. g_Pool = NULL;
  471. }
  472. g_MigrationInf = NULL;
  473. }
  474. BOOL
  475. WINAPI
  476. MigInf_AddObject (
  477. IN MIGTYPE ObjectType,
  478. IN PCSTR SectionString,
  479. IN PCSTR ParamOne,
  480. IN PCSTR ParamTwo
  481. )
  482. {
  483. return pCreateMigObject(
  484. ObjectType,
  485. ParamOne,
  486. ParamTwo,
  487. pFindSection(SectionString,MIGINF_CREATE)
  488. );
  489. }
  490. BOOL
  491. WINAPI
  492. MigInf_FirstInSection(
  493. IN PCSTR SectionName,
  494. OUT PMIGINFSECTIONENUM Enum
  495. )
  496. {
  497. PMIGSECTION section;
  498. //
  499. // We assume that Enum is valid.
  500. //
  501. assert(Enum);
  502. section = pFindSection(SectionName,MIGINF_NOCREATE);
  503. if (section) {
  504. Enum -> EnumKey = (PVOID) section -> Items;
  505. }
  506. return MigInf_NextInSection(Enum);
  507. }
  508. BOOL
  509. WINAPI
  510. MigInf_NextInSection(
  511. IN OUT PMIGINFSECTIONENUM Enum
  512. )
  513. {
  514. BOOL rSuccess = FALSE;
  515. //
  516. // We assume that the Enum is valid.
  517. //
  518. assert(Enum);
  519. if (Enum -> EnumKey) {
  520. Enum -> Key = ((PMIGOBJECT) (Enum -> EnumKey)) -> Key;
  521. Enum -> Value = ((PMIGOBJECT) (Enum -> EnumKey)) -> Value;
  522. Enum -> EnumKey = ((PVOID) ((PMIGOBJECT) (Enum -> EnumKey)) -> Next);
  523. rSuccess = TRUE;
  524. }
  525. return rSuccess;
  526. }
  527. BOOL
  528. WINAPI
  529. MigInf_WriteInfToDisk (
  530. VOID
  531. )
  532. {
  533. BOOL rSuccess = TRUE;
  534. PMIGSECTION curSection;
  535. //
  536. // Simply loop through all of the sections, writing each of them to disk.
  537. // As long as WriteSectionToDisk works, we work.
  538. //
  539. curSection = g_MigrationInf;
  540. while (curSection && rSuccess) {
  541. //
  542. // We skip the [Excluded Paths] and [Migration Paths] sections.
  543. //
  544. if (_mbsicmp(curSection -> Name,SECTION_EXCLUDEDPATHS) &&
  545. _mbsicmp(curSection -> Name,SECTION_MIGRATIONPATHS)) {
  546. rSuccess = pWriteInfSectionToDisk(curSection);
  547. }
  548. curSection = curSection -> Next;
  549. }
  550. return rSuccess;
  551. }
  552. BOOL
  553. WINAPI
  554. MigInf_PathIsExcluded (
  555. IN PCSTR Path
  556. )
  557. {
  558. PMIGOBJECT curExcluded;
  559. PMIGSECTION section;
  560. BOOL rIsExcluded = FALSE;
  561. //
  562. // We assume Path is valid.
  563. //
  564. assert(Path);
  565. section = pFindSection(SECTION_EXCLUDEDPATHS,MIGINF_NOCREATE);
  566. if (section) {
  567. curExcluded = section -> Items;
  568. while (curExcluded && !rIsExcluded) {
  569. rIsExcluded = pPathIsInPath(Path,curExcluded -> Key);
  570. curExcluded = curExcluded -> Next;
  571. }
  572. }
  573. return rIsExcluded;
  574. }
  575. PCSTR
  576. WINAPI
  577. MigInf_GetNewSectionName (
  578. VOID
  579. )
  580. {
  581. static CHAR sectionName[20];
  582. static DWORD seedNum=0;
  583. sprintf(sectionName,"msg%0.7u",seedNum++);
  584. return sectionName;
  585. }