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.

755 lines
17 KiB

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