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.

1493 lines
40 KiB

  1. /*++
  2. Copyright (c) 1997 Microsoft Corporation
  3. Module Name:
  4. migdb.c
  5. Abstract:
  6. This source implements old AppDb functionality
  7. Author:
  8. Calin Negreanu (calinn) 07-Jan-1998
  9. Revision History:
  10. jimschm 23-Sep-1998 Updated for new fileops code
  11. jimschm 25-Feb-1998 Added UninstallSection support
  12. calinn 19-Jan-1998 Added CANCELLED response
  13. --*/
  14. #include "pch.h"
  15. #include "logmsg.h"
  16. #include "osfiles.h"
  17. #define DBG_MIGDB "MigDb"
  18. #define S_STRINGS TEXT("Strings")
  19. //
  20. // Globals
  21. //
  22. PMHANDLE g_MigDbPool = NULL;
  23. PMIGDB_CONTEXT g_ContextList = NULL;
  24. HASHTABLE g_FileTable = NULL;
  25. PMIGDB_TYPE_RULE g_TypeRule = NULL;
  26. GROWBUFFER g_TypeRuleList = INIT_GROWBUFFER;
  27. HINF g_OsFilesInf = INVALID_HANDLE_VALUE;
  28. GROWBUFFER g_AttrGrowBuff = INIT_GROWBUFFER;
  29. GROWBUFFER g_TypeGrowBuff = INIT_GROWBUFFER;
  30. static PINFCONTEXT g_Line;
  31. PMIGDB_HOOK_PROTOTYPE g_MigDbHook = NULL;
  32. #define ArgFunction TEXT("ARG")
  33. #define ArgFunctionLen 3
  34. BOOL
  35. pCallAction (
  36. IN PMIGDB_CONTEXT MigDbContext
  37. );
  38. PMIGDB_ATTRIB
  39. pLoadAttribData (
  40. IN PCTSTR MultiSzStr
  41. );
  42. PMIGDB_HOOK_PROTOTYPE
  43. SetMigDbHook (
  44. PMIGDB_HOOK_PROTOTYPE HookFunction
  45. )
  46. {
  47. PMIGDB_HOOK_PROTOTYPE savedHook;
  48. savedHook = g_MigDbHook;
  49. g_MigDbHook = HookFunction;
  50. return savedHook;
  51. }
  52. INT
  53. pGetAttribIndex (
  54. IN PCTSTR AttribName
  55. )
  56. /*++
  57. Routine Description:
  58. This routine returns the index in attribute functions array for a specified attribute.
  59. Arguments:
  60. AttribName - Attribute name
  61. Return value:
  62. -1 - no such attribute in attribute table
  63. --*/
  64. {
  65. INT attribIndex;
  66. INT rc = 0;
  67. PTSTR attrEnd = NULL;
  68. TCHAR savedChar = 0;
  69. attrEnd = (PTSTR) SkipSpaceR (AttribName, GetEndOfString (AttribName));
  70. if (attrEnd != NULL) {
  71. attrEnd = _tcsinc (attrEnd);
  72. savedChar = attrEnd [0];
  73. attrEnd [0] = 0;
  74. }
  75. __try {
  76. attribIndex = MigDb_GetAttributeIdx (AttribName);
  77. if (attribIndex == -1) {
  78. LOG((LOG_ERROR, (PCSTR) MSG_MIGDB_ATTRIBUTE_NOT_FOUND, AttribName));
  79. }
  80. rc = attribIndex;
  81. }
  82. __finally {
  83. if (attrEnd != NULL) {
  84. attrEnd [0] = savedChar;
  85. }
  86. }
  87. return rc;
  88. }
  89. BOOL
  90. pValidateArg (
  91. IN OUT PMIGDB_ATTRIB AttribStruct
  92. )
  93. {
  94. MYASSERT (AttribStruct);
  95. if (AttribStruct->ArgCount != MigDb_GetReqArgCount (AttribStruct->AttribIndex)) {
  96. #ifdef DEBUG
  97. if (AttribStruct->AttribIndex != -1) {
  98. TCHAR Buffer[16384];
  99. SetupGetLineText (g_Line, NULL, NULL, NULL, Buffer, ARRAYSIZE(Buffer), NULL);
  100. DEBUGMSG ((
  101. DBG_WHOOPS,
  102. "Discarding attribute %s because of too few arguments.\n"
  103. " Line: %s\n",
  104. MigDb_GetAttributeName (AttribStruct->AttribIndex),
  105. Buffer
  106. ));
  107. }
  108. #endif
  109. AttribStruct->AttribIndex = -1;
  110. return FALSE;
  111. }
  112. return TRUE;
  113. }
  114. #define STATE_ATTRNAME 1
  115. #define STATE_ATTRARG 2
  116. PMIGDB_ATTRIB
  117. pLoadAttribData (
  118. IN PCTSTR MultiSzStr
  119. )
  120. /*++
  121. Routine Description:
  122. This routine creates a list of MIGDB_ATTRIBs from a multisz.
  123. Arguments:
  124. MultiSzStr - multisz to be processed
  125. Return value:
  126. MIGDB_ATTRIB nodes
  127. --*/
  128. {
  129. MULTISZ_ENUM multiSzEnum;
  130. PMIGDB_ATTRIB result = NULL;
  131. PMIGDB_ATTRIB tmpAttr = NULL;
  132. INT state = STATE_ATTRNAME;
  133. PTSTR currStrPtr = NULL;
  134. PTSTR currArgPtr = NULL;
  135. PTSTR endArgPtr = NULL;
  136. TCHAR savedChar = 0;
  137. g_AttrGrowBuff.End = 0;
  138. if (EnumFirstMultiSz (&multiSzEnum, MultiSzStr)) {
  139. do {
  140. currStrPtr = (PTSTR) SkipSpace (multiSzEnum.CurrentString);
  141. if (state == STATE_ATTRNAME) {
  142. tmpAttr = (PMIGDB_ATTRIB) PmGetMemory (g_MigDbPool, sizeof (MIGDB_ATTRIB));
  143. ZeroMemory (tmpAttr, sizeof (MIGDB_ATTRIB));
  144. if (_tcsnextc (currStrPtr) == TEXT('!')) {
  145. currStrPtr = _tcsinc (currStrPtr);
  146. currStrPtr = (PTSTR) SkipSpace (currStrPtr);
  147. tmpAttr->NotOperator = TRUE;
  148. }
  149. currArgPtr = _tcschr (currStrPtr, TEXT('('));
  150. if (currArgPtr) {
  151. endArgPtr = _tcsdec (currStrPtr, currArgPtr);
  152. if (endArgPtr) {
  153. endArgPtr = (PTSTR) SkipSpaceR (currStrPtr, endArgPtr);
  154. endArgPtr = _tcsinc (endArgPtr);
  155. }
  156. else {
  157. endArgPtr = currStrPtr;
  158. }
  159. savedChar = *endArgPtr;
  160. *endArgPtr = 0;
  161. tmpAttr->AttribIndex = pGetAttribIndex (currStrPtr);
  162. *endArgPtr = savedChar;
  163. currStrPtr = _tcsinc (currArgPtr);
  164. state = STATE_ATTRARG;
  165. }
  166. else {
  167. // this attribute has no arguments.
  168. tmpAttr->AttribIndex = pGetAttribIndex (currStrPtr);
  169. tmpAttr->Next = result;
  170. result = tmpAttr;
  171. pValidateArg (result);
  172. continue;
  173. }
  174. }
  175. if (state == STATE_ATTRARG) {
  176. currStrPtr = (PTSTR) SkipSpace (currStrPtr);
  177. endArgPtr = _tcsrchr (currStrPtr, TEXT(')'));
  178. if (endArgPtr) {
  179. endArgPtr = _tcsdec (currStrPtr, endArgPtr);
  180. if (endArgPtr) {
  181. endArgPtr = (PTSTR) SkipSpaceR (currStrPtr, endArgPtr);
  182. endArgPtr = _tcsinc (endArgPtr);
  183. }
  184. else {
  185. endArgPtr = currStrPtr;
  186. }
  187. savedChar = *endArgPtr;
  188. *endArgPtr = 0;
  189. }
  190. GbMultiSzAppend (&g_AttrGrowBuff, currStrPtr);
  191. tmpAttr->ArgCount++;
  192. if (endArgPtr) {
  193. *endArgPtr = savedChar;
  194. tmpAttr->Arguments = PmDuplicateMultiSz (g_MigDbPool, (PTSTR)g_AttrGrowBuff.Buf);
  195. g_AttrGrowBuff.End = 0;
  196. state = STATE_ATTRNAME;
  197. tmpAttr->Next = result;
  198. result = tmpAttr;
  199. pValidateArg (result);
  200. }
  201. }
  202. } while (EnumNextMultiSz (&multiSzEnum));
  203. }
  204. return result;
  205. }
  206. BOOL
  207. AddFileToMigDbLinkage (
  208. IN PCTSTR FileName,
  209. IN PINFCONTEXT Context, OPTIONAL
  210. IN DWORD FieldIndex OPTIONAL
  211. )
  212. {
  213. TCHAR tempField [MEMDB_MAX];
  214. DWORD fieldIndex = FieldIndex;
  215. PMIGDB_FILE migDbFile = NULL;
  216. PMIGDB_ATTRIB migDbAttrib = NULL;
  217. HASHITEM stringId;
  218. FILE_LIST_STRUCT fileList;
  219. //creating MIGDB_FILE structure for current file
  220. migDbFile = (PMIGDB_FILE) PmGetMemory (g_MigDbPool, sizeof (MIGDB_FILE));
  221. if (migDbFile != NULL) {
  222. ZeroMemory (migDbFile, sizeof (MIGDB_FILE));
  223. migDbFile->Section = g_ContextList->Sections;
  224. if (Context) {
  225. fieldIndex ++;
  226. if (SetupGetMultiSzField (Context, fieldIndex, tempField, MEMDB_MAX, NULL)) {
  227. g_Line = Context;
  228. migDbFile->Attributes = pLoadAttribData (tempField);
  229. if (g_MigDbHook != NULL) {
  230. migDbAttrib = migDbFile->Attributes;
  231. while (migDbAttrib) {
  232. g_MigDbHook (FileName, g_ContextList, g_ContextList->Sections, migDbFile, migDbAttrib);
  233. migDbAttrib = migDbAttrib->Next;
  234. }
  235. }
  236. }
  237. }
  238. //adding this file into string table and create a MIGDB_FILE node. If file
  239. //already exists in string table then just create another MIGDB_FILE node
  240. //chained with already existing ones.
  241. stringId = HtFindString (g_FileTable, FileName);
  242. if (stringId) {
  243. HtCopyStringData (g_FileTable, stringId, &fileList);
  244. fileList.Last->Next = migDbFile;
  245. fileList.Last = migDbFile;
  246. HtSetStringData (g_FileTable, stringId, &fileList);
  247. } else {
  248. fileList.First = fileList.Last = migDbFile;
  249. HtAddStringAndData (g_FileTable, FileName, &fileList);
  250. }
  251. }
  252. return TRUE;
  253. }
  254. BOOL
  255. pScanForFile (
  256. IN PINFCONTEXT Context,
  257. IN DWORD FieldIndex
  258. )
  259. /*++
  260. Routine Description:
  261. This routine updates migdb data structures loading a specified file info from inf file.
  262. Creates a migdb file node and the file is added in a string table for fast query.
  263. Arguments:
  264. SectionStr - section to process
  265. Return value:
  266. TRUE - the operation was successful
  267. FALSE - otherwise
  268. --*/
  269. {
  270. TCHAR fileName [MEMDB_MAX];
  271. //scanning for file name
  272. if (!SetupGetStringField (Context, FieldIndex, fileName, MEMDB_MAX, NULL)) {
  273. LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_BAD_FILENAME));
  274. return FALSE;
  275. }
  276. return AddFileToMigDbLinkage (fileName, Context, FieldIndex);
  277. }
  278. BOOL
  279. pMigDbAddRuleToTypeRule (
  280. IN PMIGDB_TYPE_RULE TypeRule,
  281. IN PMIGDB_RULE Rule
  282. )
  283. {
  284. PMIGDB_CHAR_NODE node, currNode, prevNode;
  285. PTSTR nodeBase;
  286. PCTSTR p;
  287. WORD w;
  288. BOOL found;
  289. if (Rule->NodeBase) {
  290. currNode = TypeRule->FirstLevel;
  291. prevNode = currNode;
  292. nodeBase = DuplicatePathString (Rule->NodeBase, 0);
  293. CharLower (nodeBase);
  294. p = nodeBase;
  295. while (*p) {
  296. w = (WORD) _tcsnextc (p);
  297. p = _tcsinc (p);
  298. if (currNode) {
  299. if (currNode->Char == w) {
  300. if (!*p) {
  301. Rule->NextRule = currNode->RuleList;
  302. currNode->RuleList = Rule;
  303. }
  304. prevNode = currNode;
  305. currNode = currNode->NextLevel;
  306. } else {
  307. found = FALSE;
  308. while (!found && currNode->NextPeer) {
  309. if (currNode->NextPeer->Char == w) {
  310. if (!*p) {
  311. Rule->NextRule = currNode->NextPeer->RuleList;
  312. currNode->NextPeer->RuleList = Rule;
  313. }
  314. prevNode = currNode->NextPeer;
  315. currNode = prevNode->NextLevel;
  316. found = TRUE;
  317. break;
  318. }
  319. currNode = currNode->NextPeer;
  320. }
  321. if (!found) {
  322. node = PmGetMemory (g_MigDbPool, sizeof (MIGDB_CHAR_NODE));
  323. ZeroMemory (node, sizeof (MIGDB_CHAR_NODE));
  324. if (!*p) {
  325. node->RuleList = Rule;
  326. }
  327. node->Char = w;
  328. node->NextPeer = currNode->NextPeer;
  329. currNode->NextPeer = node;
  330. prevNode = node;
  331. currNode = node->NextLevel;
  332. }
  333. }
  334. } else {
  335. node = PmGetMemory (g_MigDbPool, sizeof (MIGDB_CHAR_NODE));
  336. ZeroMemory (node, sizeof (MIGDB_CHAR_NODE));
  337. if (!*p) {
  338. node->RuleList = Rule;
  339. }
  340. node->Char = w;
  341. if (prevNode) {
  342. prevNode->NextLevel = node;
  343. } else {
  344. TypeRule->FirstLevel = node;
  345. }
  346. prevNode = node;
  347. currNode = prevNode->NextLevel;
  348. }
  349. }
  350. FreePathString (nodeBase);
  351. } else {
  352. Rule->NextRule = TypeRule->RuleList;
  353. TypeRule->RuleList = Rule;
  354. }
  355. return TRUE;
  356. }
  357. BOOL
  358. AddPatternToMigDbLinkage (
  359. IN PCTSTR LeafPattern,
  360. IN PCTSTR NodePattern,
  361. IN PINFCONTEXT Context, OPTIONAL
  362. IN DWORD FieldIndex,
  363. IN INT IncludeNodes
  364. )
  365. {
  366. PMIGDB_RULE rule;
  367. MIG_SEGMENTS nodeSegment;
  368. MIG_SEGMENTS leafSegment;
  369. PCTSTR ourEncodedString;
  370. PCTSTR nodeBase;
  371. TCHAR tempField [MEMDB_MAX];
  372. DWORD fieldIndex = FieldIndex;
  373. nodeSegment.Segment = NodePattern ? NodePattern : TEXT("*");
  374. nodeSegment.IsPattern = TRUE;
  375. leafSegment.Segment = LeafPattern ? LeafPattern : TEXT("*");
  376. leafSegment.IsPattern = TRUE;
  377. ourEncodedString = IsmCreateObjectPattern (
  378. &nodeSegment,
  379. 1,
  380. &leafSegment,
  381. 1
  382. );
  383. //
  384. // build the rule
  385. //
  386. rule = PmGetMemory (g_MigDbPool, sizeof (MIGDB_RULE));
  387. ZeroMemory (rule, sizeof (MIGDB_RULE));
  388. if (NodePattern) {
  389. nodeBase = GetPatternBase (NodePattern);
  390. if (nodeBase) {
  391. rule->NodeBase = PmDuplicateString (g_MigDbPool, nodeBase);
  392. FreePathString (nodeBase);
  393. }
  394. }
  395. rule->ObjectPattern = PmDuplicateString (g_MigDbPool, ourEncodedString);
  396. rule->ParsedPattern = ObsCreateParsedPatternEx (g_MigDbPool, ourEncodedString, FALSE);
  397. MYASSERT (rule->ParsedPattern);
  398. if (rule->ParsedPattern) {
  399. // add aditional information
  400. rule->Section = g_ContextList->Sections;
  401. if (Context) {
  402. fieldIndex ++;
  403. if (SetupGetMultiSzField (Context, fieldIndex, tempField, MEMDB_MAX, NULL)) {
  404. g_Line = Context;
  405. rule->Attributes = pLoadAttribData (tempField);
  406. }
  407. }
  408. rule->IncludeNodes = IncludeNodes;
  409. pMigDbAddRuleToTypeRule (g_TypeRule, rule);
  410. }
  411. IsmDestroyObjectHandle (ourEncodedString);
  412. return TRUE;
  413. }
  414. BOOL
  415. pScanForFilePattern (
  416. IN PINFCONTEXT Context,
  417. IN DWORD FieldIndex
  418. )
  419. /*++
  420. Routine Description:
  421. This routine updates migdb data structures loading a specified file pattern info from inf file.
  422. Creates a migdb file node and the file is added in a string table for fast query.
  423. Arguments:
  424. Context - inf context for the section that we are currently processing
  425. FieldIndex - field index to start with
  426. Return value:
  427. TRUE - the operation was successful
  428. FALSE - otherwise
  429. --*/
  430. {
  431. TCHAR leafPattern [MEMDB_MAX];
  432. PCTSTR leafPatternExp = NULL;
  433. TCHAR nodePattern [MEMDB_MAX];
  434. PCTSTR nodePatternExp = NULL;
  435. PCTSTR sanitizedPath = NULL;
  436. INT includeNodes = 0;
  437. BOOL result = TRUE;
  438. //scanning for leaf pattern
  439. if (!SetupGetStringField (Context, FieldIndex, leafPattern, MEMDB_MAX, NULL)) {
  440. LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_BAD_FILENAME));
  441. return FALSE;
  442. }
  443. leafPatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, leafPattern, NULL);
  444. FieldIndex ++;
  445. //scanning for node pattern
  446. if (!SetupGetStringField (Context, FieldIndex, nodePattern, MEMDB_MAX, NULL)) {
  447. LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_BAD_FILENAME));
  448. return FALSE;
  449. }
  450. nodePatternExp = IsmExpandEnvironmentString (PLATFORM_SOURCE, S_SYSENVVAR_GROUP, nodePattern, NULL);
  451. if (nodePatternExp) {
  452. sanitizedPath = SanitizePath (nodePatternExp);
  453. }
  454. FieldIndex ++;
  455. //scanning for indicator if we should include the nodes as well
  456. if (!SetupGetIntField (Context, FieldIndex, &includeNodes)) {
  457. includeNodes = 0;
  458. }
  459. result = AddPatternToMigDbLinkage (
  460. leafPatternExp?leafPatternExp:leafPattern,
  461. sanitizedPath?sanitizedPath:nodePattern,
  462. Context,
  463. FieldIndex,
  464. includeNodes
  465. );
  466. if (leafPatternExp) {
  467. IsmReleaseMemory (leafPatternExp);
  468. leafPatternExp = NULL;
  469. }
  470. if (nodePatternExp) {
  471. IsmReleaseMemory (nodePatternExp);
  472. nodePatternExp = NULL;
  473. }
  474. if (sanitizedPath) {
  475. FreePathString (sanitizedPath);
  476. }
  477. return result;
  478. }
  479. /*++
  480. Routine Description:
  481. The subsequent two routines enumerate the sections with a particular name and
  482. with .999 extension from an inf file.
  483. Arguments:
  484. SectEnum - enumeration structure
  485. Return value:
  486. TRUE - enumeration continues
  487. FALSE - enumeration ended
  488. --*/
  489. typedef struct _SECT_ENUM {
  490. HINF InfHandle;
  491. INT SectIndex;
  492. PTSTR SectNameEnd;
  493. PTSTR SectName;
  494. } SECT_ENUM, *PSECT_ENUM;
  495. VOID
  496. pAbortSectionEnum (
  497. IN OUT PSECT_ENUM SectEnum
  498. )
  499. {
  500. if (SectEnum && SectEnum->SectName) {
  501. FreePathString (SectEnum->SectName);
  502. SectEnum->SectName = NULL;
  503. SectEnum->SectNameEnd = NULL;
  504. }
  505. }
  506. BOOL
  507. pEnumNextSection (
  508. IN OUT PSECT_ENUM SectEnum
  509. )
  510. {
  511. INFCONTEXT context;
  512. BOOL result = FALSE;
  513. if (SectEnum->SectIndex == -1) {
  514. pAbortSectionEnum (SectEnum);
  515. return FALSE;
  516. }
  517. SectEnum->SectIndex ++;
  518. _stprintf (SectEnum->SectNameEnd, TEXT(".%d"), SectEnum->SectIndex);
  519. result = SetupFindFirstLine (SectEnum->InfHandle, SectEnum->SectName, NULL, &context);
  520. if (!result) {
  521. pAbortSectionEnum (SectEnum);
  522. }
  523. return result;
  524. }
  525. BOOL
  526. pEnumFirstSection (
  527. OUT PSECT_ENUM SectEnum,
  528. IN PCTSTR SectionStr,
  529. IN HINF InfHandle
  530. )
  531. {
  532. INFCONTEXT context;
  533. ZeroMemory (SectEnum, sizeof (SECT_ENUM));
  534. SectEnum->SectIndex = -1;
  535. if (SetupFindFirstLine (InfHandle, SectionStr, NULL, &context)) {
  536. //good, only one section
  537. SectEnum->SectName = DuplicatePathString (SectionStr, 0);
  538. return TRUE;
  539. }
  540. else {
  541. //more than one section
  542. SectEnum->SectIndex = 0;
  543. SectEnum->InfHandle = InfHandle;
  544. SectEnum->SectName = DuplicatePathString (SectionStr, 32);
  545. if (SectEnum->SectName) {
  546. SectEnum->SectNameEnd = GetEndOfString (SectEnum->SectName);
  547. if (SectEnum->SectNameEnd) {
  548. return pEnumNextSection (SectEnum);
  549. }
  550. }
  551. }
  552. // something went wrong, let's get out of here
  553. return FALSE;
  554. }
  555. BOOL
  556. pLoadSectionData (
  557. IN PCTSTR SectionStr,
  558. IN BOOL PatternScan
  559. )
  560. /*++
  561. Routine Description:
  562. This routine updates migdb data structures loading a specified section from inf file. For
  563. every line in the section there is a migdb file node created. Also the file is added in
  564. a string table for fast query.
  565. Arguments:
  566. SectionStr - section to process
  567. Return value:
  568. TRUE - the operation was successful
  569. FALSE - otherwise
  570. --*/
  571. {
  572. INFCONTEXT context;
  573. SECT_ENUM sectEnum;
  574. PMIGDB_SECTION migDbSection;
  575. BOOL result = TRUE;
  576. MYASSERT (g_OsFilesInf != INVALID_HANDLE_VALUE);
  577. if (pEnumFirstSection (&sectEnum, SectionStr, g_OsFilesInf)) {
  578. do {
  579. //initialize the section (this context can have multiple sections)
  580. //and parse the file info
  581. migDbSection = (PMIGDB_SECTION) PmGetMemory (g_MigDbPool, sizeof (MIGDB_SECTION));
  582. if (migDbSection != NULL) {
  583. ZeroMemory (migDbSection, sizeof (MIGDB_SECTION));
  584. migDbSection->Context = g_ContextList;
  585. migDbSection->Next = g_ContextList->Sections;
  586. g_ContextList->Sections = migDbSection;
  587. if (SetupFindFirstLine (g_OsFilesInf, sectEnum.SectName, NULL, &context)) {
  588. do {
  589. if (PatternScan) {
  590. if (!pScanForFilePattern (&context, 1)) {
  591. return FALSE;
  592. }
  593. } else {
  594. if (!pScanForFile (&context, 1)) {
  595. return FALSE;
  596. }
  597. }
  598. }
  599. while (SetupFindNextLine (&context, &context));
  600. }
  601. }
  602. else {
  603. DEBUGMSG ((DBG_ERROR, "Unable to create section for %s", SectionStr));
  604. }
  605. }
  606. while (pEnumNextSection (&sectEnum));
  607. }
  608. return result;
  609. }
  610. BOOL
  611. pLoadTypeData (
  612. IN PCTSTR TypeStr,
  613. IN BOOL PatternScan
  614. )
  615. /*++
  616. Routine Description:
  617. This routine updates migdb data structures loading a specified type data from inf file. For
  618. every line in type section there is a migdb context created. Also for every migdb context
  619. the coresponding section(s) is processed.
  620. Arguments:
  621. TypeStr - file type to process
  622. Return value:
  623. TRUE - the operation was successful
  624. FALSE - otherwise
  625. --*/
  626. {
  627. TCHAR section [MEMDB_MAX];
  628. TCHAR locSection [MEMDB_MAX];
  629. TCHAR message [MEMDB_MAX];
  630. TCHAR tempField [MEMDB_MAX];
  631. PTSTR tempFieldPtr;
  632. PTSTR endOfArg = NULL;
  633. DWORD fieldIndex;
  634. PMIGDB_CONTEXT migDbContext = NULL;
  635. INFCONTEXT context, context1;
  636. BOOL result = TRUE;
  637. INT actionIndex;
  638. MYASSERT (g_OsFilesInf != INVALID_HANDLE_VALUE);
  639. g_TypeGrowBuff.End = 0;
  640. if (SetupFindFirstLine (g_OsFilesInf, TypeStr, NULL, &context)) {
  641. //let's identify the action function index to update MIGDB_CONTEXT structure
  642. actionIndex = MigDb_GetActionIdx (TypeStr);
  643. if (actionIndex == -1) {
  644. LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_BAD_ACTION, TypeStr));
  645. }
  646. do {
  647. if (!SetupGetStringField (&context, 1, section, MEMDB_MAX, NULL)) {
  648. LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_BAD_OR_MISSING_SECTION, TypeStr));
  649. return FALSE;
  650. }
  651. if (!SetupGetStringField (&context, 2, message, MEMDB_MAX, NULL)) {
  652. message [0] = 0;
  653. }
  654. migDbContext = (PMIGDB_CONTEXT) PmGetMemory (g_MigDbPool, sizeof (MIGDB_CONTEXT));
  655. if (migDbContext == NULL) {
  656. DEBUGMSG ((DBG_ERROR, "Unable to create context for %s.", TypeStr));
  657. return FALSE;
  658. }
  659. ZeroMemory (migDbContext, sizeof (MIGDB_CONTEXT));
  660. migDbContext->Next = g_ContextList;
  661. g_ContextList = migDbContext;
  662. // update ActionIndex with known value
  663. migDbContext->ActionIndex = actionIndex;
  664. // update SectName field
  665. migDbContext->SectName = PmDuplicateString (g_MigDbPool, section);
  666. // update SectLocalizedName field
  667. if (SetupFindFirstLine (g_OsFilesInf, S_STRINGS, section, &context1)) {
  668. if (SetupGetStringField (&context1, 1, locSection, MEMDB_MAX, NULL)) {
  669. migDbContext->SectLocalizedName = PmDuplicateString (g_MigDbPool, locSection);
  670. }
  671. }
  672. // set SectNameForDisplay to localized name, or sect name if no localized name
  673. if (migDbContext->SectLocalizedName) {
  674. migDbContext->SectNameForDisplay = migDbContext->SectLocalizedName;
  675. } else {
  676. migDbContext->SectNameForDisplay = migDbContext->SectName;
  677. }
  678. // update Message field
  679. if (message[0] != 0) {
  680. migDbContext->Message = PmDuplicateString (g_MigDbPool, message);
  681. }
  682. // OK, now let's scan all the remaining fields
  683. fieldIndex = 3;
  684. do {
  685. tempField [0] = 0;
  686. if (SetupGetStringField (&context, fieldIndex, tempField, MEMDB_MAX, NULL)) {
  687. if (StringIMatchCharCount (tempField, ArgFunction, ArgFunctionLen)) {
  688. //we have an additional argument for action function
  689. tempFieldPtr = _tcschr (tempField, TEXT('('));
  690. if (tempFieldPtr != NULL) {
  691. tempFieldPtr = (PTSTR) SkipSpace (_tcsinc (tempFieldPtr));
  692. if (tempFieldPtr != NULL) {
  693. endOfArg = _tcschr (tempFieldPtr, TEXT(')'));
  694. if (endOfArg != NULL) {
  695. *endOfArg = 0;
  696. endOfArg = (PTSTR) SkipSpaceR (tempFieldPtr, endOfArg);
  697. }
  698. if (endOfArg != NULL) {
  699. *_tcsinc (endOfArg) = 0;
  700. GbMultiSzAppend (&g_TypeGrowBuff, tempFieldPtr);
  701. }
  702. ELSE_DEBUGMSG ((
  703. DBG_WHOOPS,
  704. "Improperly formatted arg: %s in %s",
  705. tempField,
  706. TypeStr
  707. ));
  708. }
  709. }
  710. }
  711. else {
  712. //we have something else, probably file name and attributes
  713. if (!PatternScan) {
  714. if (_tcschr (tempField, TEXT('.')) == NULL) {
  715. LOG ((LOG_ERROR, (PCSTR) MSG_MIGDB_DOT_SYNTAX_ERROR, TypeStr, section));
  716. }
  717. }
  718. //therefore we initialize the section (this context will have
  719. //only one section) and parse the file info
  720. migDbContext->Sections = (PMIGDB_SECTION) PmGetMemory (
  721. g_MigDbPool,
  722. sizeof (MIGDB_SECTION)
  723. );
  724. if (migDbContext->Sections != NULL) {
  725. ZeroMemory (migDbContext->Sections, sizeof (MIGDB_SECTION));
  726. migDbContext->Sections->Context = migDbContext;
  727. migDbContext->Arguments = PmDuplicateMultiSz (g_MigDbPool, (PTSTR)g_TypeGrowBuff.Buf);
  728. g_TypeGrowBuff.End = 0;
  729. if (PatternScan) {
  730. if (!pScanForFilePattern (&context, fieldIndex)) {
  731. return FALSE;
  732. }
  733. } else {
  734. if (!pScanForFile (&context, fieldIndex)) {
  735. return FALSE;
  736. }
  737. }
  738. tempField [0] = 0;
  739. }
  740. else {
  741. DEBUGMSG ((DBG_ERROR, "Unable to create section for %s/%s", TypeStr, section));
  742. return FALSE;
  743. }
  744. }
  745. }
  746. fieldIndex ++;
  747. } while (tempField [0] != 0);
  748. if (migDbContext->Sections == NULL) {
  749. //now let's add action function arguments in MIGDB_CONTEXT structure
  750. migDbContext->Arguments = PmDuplicateMultiSz (g_MigDbPool, (PTSTR)g_TypeGrowBuff.Buf);
  751. g_TypeGrowBuff.End = 0;
  752. //let's go to the sections and scan all files
  753. if (!pLoadSectionData (section, PatternScan)) {
  754. return FALSE;
  755. }
  756. }
  757. }
  758. while (SetupFindNextLine (&context, &context));
  759. }
  760. return result;
  761. }
  762. BOOL
  763. InitMigDb (
  764. IN PCTSTR MigDbFile
  765. )
  766. /*++
  767. Routine Description:
  768. This routine initialize memory and data structures used by MigDb.
  769. Arguments:
  770. NONE
  771. Return value:
  772. TRUE - the operation was successful
  773. FALSE - otherwise
  774. --*/
  775. {
  776. INT i;
  777. BOOL patternFormat;
  778. PCTSTR typeStr;
  779. MYASSERT (g_OsFilesInf == INVALID_HANDLE_VALUE);
  780. g_OsFilesInf = InfOpenInfFile (MigDbFile);
  781. if (g_OsFilesInf == INVALID_HANDLE_VALUE) {
  782. return FALSE;
  783. }
  784. g_MigDbPool = PmCreateNamedPool ("MigDb Pool");
  785. PmDisableTracking (g_MigDbPool);
  786. g_FileTable = HtAllocWithData (sizeof (FILE_LIST_STRUCT));
  787. if (g_FileTable == NULL) {
  788. DEBUGMSG ((DBG_ERROR, "Cannot initialize memory for migdb operations"));
  789. return FALSE;
  790. }
  791. //load known types from migdb
  792. i = 0;
  793. do {
  794. typeStr = MigDb_GetActionName (i);
  795. if (typeStr != NULL) {
  796. patternFormat = MigDb_IsPatternFormat (i);
  797. if (!pLoadTypeData (typeStr, patternFormat)) {
  798. GbFree (&g_AttrGrowBuff);
  799. GbFree (&g_TypeGrowBuff);
  800. return FALSE;
  801. }
  802. }
  803. i++;
  804. }
  805. while (typeStr != NULL);
  806. GbFree (&g_AttrGrowBuff);
  807. GbFree (&g_TypeGrowBuff);
  808. return TRUE;
  809. }
  810. BOOL
  811. InitMigDbEx (
  812. IN HINF InfHandle
  813. )
  814. {
  815. INT i;
  816. BOOL patternFormat;
  817. PCTSTR typeStr;
  818. MYASSERT (g_OsFilesInf == INVALID_HANDLE_VALUE);
  819. MYASSERT (InfHandle != INVALID_HANDLE_VALUE);
  820. g_OsFilesInf = InfHandle;
  821. if (g_OsFilesInf == INVALID_HANDLE_VALUE) {
  822. return FALSE;
  823. }
  824. g_MigDbPool = PmCreateNamedPool ("MigDb Pool");
  825. PmDisableTracking (g_MigDbPool);
  826. g_FileTable = HtAllocWithData (sizeof (FILE_LIST_STRUCT));
  827. g_TypeRule = PmGetMemory (g_MigDbPool, sizeof (MIGDB_TYPE_RULE));
  828. ZeroMemory (g_TypeRule, sizeof (MIGDB_TYPE_RULE));
  829. if (g_FileTable == NULL) {
  830. DEBUGMSG ((DBG_ERROR, "Cannot initialize memory for migdb operations"));
  831. return FALSE;
  832. }
  833. //load known types from migdb
  834. i = 0;
  835. do {
  836. typeStr = MigDb_GetActionName (i);
  837. if (typeStr != NULL) {
  838. patternFormat = MigDb_IsPatternFormat (i);
  839. if (!pLoadTypeData (typeStr, patternFormat)) {
  840. GbFree (&g_AttrGrowBuff);
  841. GbFree (&g_TypeGrowBuff);
  842. return FALSE;
  843. }
  844. }
  845. i++;
  846. }
  847. while (typeStr != NULL);
  848. GbFree (&g_AttrGrowBuff);
  849. GbFree (&g_TypeGrowBuff);
  850. return TRUE;
  851. }
  852. BOOL
  853. DoneMigDbEx (
  854. VOID
  855. )
  856. /*++
  857. Routine Description:
  858. This routine cleans up all memory used by MigDb.
  859. Arguments:
  860. NONE
  861. Return value:
  862. always TRUE
  863. --*/
  864. {
  865. PMIGDB_CONTEXT migDbContext = NULL;
  866. // first, let's walk through any context and check if it's a required one
  867. migDbContext = g_ContextList;
  868. while (migDbContext) {
  869. if ((!MigDb_CallWhenTriggered (migDbContext->ActionIndex)) &&
  870. (migDbContext->TriggerCount == 0)
  871. ) {
  872. pCallAction (migDbContext);
  873. }
  874. migDbContext = migDbContext->Next;
  875. }
  876. if (g_FileTable != NULL) {
  877. HtFree (g_FileTable);
  878. g_FileTable = NULL;
  879. }
  880. if (g_MigDbPool != NULL) {
  881. PmEmptyPool (g_MigDbPool);
  882. PmDestroyPool (g_MigDbPool);
  883. g_MigDbPool = NULL;
  884. }
  885. g_ContextList = NULL;
  886. return TRUE;
  887. }
  888. BOOL
  889. DoneMigDb (
  890. VOID
  891. )
  892. /*++
  893. Routine Description:
  894. This routine cleans up all memory used by MigDb.
  895. Arguments:
  896. NONE
  897. Return value:
  898. always TRUE
  899. --*/
  900. {
  901. if (!DoneMigDbEx ()) {
  902. return FALSE;
  903. }
  904. if (g_OsFilesInf != INVALID_HANDLE_VALUE) {
  905. InfCloseInfFile (g_OsFilesInf);
  906. g_OsFilesInf = INVALID_HANDLE_VALUE;
  907. }
  908. return TRUE;
  909. }
  910. BOOL
  911. CallAttribute (
  912. IN PMIGDB_ATTRIB MigDbAttrib,
  913. IN PDBATTRIB_PARAMS AttribParams
  914. )
  915. /*++
  916. Routine Description:
  917. This routine calls a specified attribute function for a specified file.
  918. Arguments:
  919. MigDbAttrib - See definition.
  920. AttribParams - See definition
  921. Return value:
  922. TRUE - if attribute function succeded
  923. FALSE - otherwise
  924. --*/
  925. {
  926. PATTRIBUTE_PROTOTYPE p;
  927. BOOL b;
  928. if (MigDbAttrib->AttribIndex == -1) {
  929. //invalid index for attribute function
  930. return FALSE;
  931. }
  932. p = MigDb_GetAttributeAddr (MigDbAttrib->AttribIndex);
  933. MYASSERT (p);
  934. if (MigDbAttrib->NotOperator) {
  935. b = !(p (AttribParams, MigDbAttrib->Arguments));
  936. } else {
  937. b = p (AttribParams, MigDbAttrib->Arguments);
  938. }
  939. return b;
  940. }
  941. BOOL
  942. pCallAction (
  943. IN PMIGDB_CONTEXT MigDbContext
  944. )
  945. /*++
  946. Routine Description:
  947. This routine calls an appropriate action for a specified migdb context.
  948. Arguments:
  949. MigDbContext - See definition.
  950. Return value:
  951. TRUE - if action function succeded
  952. FALSE - otherwise
  953. --*/
  954. {
  955. PACTION_PROTOTYPE p;
  956. BOOL b;
  957. p = MigDb_GetActionAddr (MigDbContext->ActionIndex);
  958. MYASSERT (p);
  959. b = p (MigDbContext);
  960. return b;
  961. }
  962. BOOL
  963. pCheckContext (
  964. IN PMIGDB_CONTEXT MigDbContext,
  965. IN BOOL Handled
  966. )
  967. /*++
  968. Routine Description:
  969. This routine checkes to see if a migdb context is met, that is if all sections
  970. have Satisfied field TRUE.
  971. Arguments:
  972. MigDbContext - See definition.
  973. Return value:
  974. always TRUE
  975. --*/
  976. {
  977. PMIGDB_SECTION migDbSection;
  978. BOOL contextSelected;
  979. BOOL result = FALSE;
  980. migDbSection = MigDbContext->Sections;
  981. contextSelected = TRUE;
  982. while (migDbSection) {
  983. if (!migDbSection->Satisfied) {
  984. contextSelected = FALSE;
  985. break;
  986. }
  987. migDbSection = migDbSection->Next;
  988. }
  989. if (contextSelected) {
  990. MigDbContext->TriggerCount ++;
  991. if (MigDbContext->ActionIndex == -1) {
  992. //
  993. // invalid index for action function
  994. //
  995. DEBUGMSG ((DBG_ERROR, "MigDb: Invalid action index"));
  996. return FALSE;
  997. }
  998. //
  999. // if appropriate call the action
  1000. //
  1001. if (MigDb_CallWhenTriggered (MigDbContext->ActionIndex)) {
  1002. if ((!Handled) ||
  1003. (MigDb_CallAlways (MigDbContext->ActionIndex))
  1004. ) {
  1005. result = pCallAction (MigDbContext);
  1006. }
  1007. }
  1008. //clean up the grow buffer with file list
  1009. GbFree (&MigDbContext->FileList);
  1010. }
  1011. return result;
  1012. }
  1013. BOOL
  1014. pQueryRule (
  1015. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1016. IN PCTSTR ObjectNode
  1017. )
  1018. {
  1019. PTSTR objectBase = NULL;
  1020. PMIGDB_RULE rule;
  1021. PMIGDB_CHAR_NODE charNode;
  1022. PCTSTR p;
  1023. WORD w;
  1024. BOOL result = FALSE;
  1025. if (ObjectNode) {
  1026. objectBase = DuplicatePathString (ObjectNode, 0);
  1027. CharLower (objectBase);
  1028. }
  1029. g_TypeRuleList.End = 0;
  1030. p = objectBase;
  1031. if (p) {
  1032. w = (WORD) _tcsnextc (p);
  1033. charNode = g_TypeRule->FirstLevel;
  1034. while (charNode && *p) {
  1035. if (charNode->Char == w) {
  1036. if (charNode->RuleList) {
  1037. rule = charNode->RuleList;
  1038. while (rule) {
  1039. if (IsmParsedPatternMatch (
  1040. (MIG_PARSEDPATTERN)rule->ParsedPattern,
  1041. MIG_FILE_TYPE,
  1042. ObjectName
  1043. )) {
  1044. CopyMemory (
  1045. GbGrow (&g_TypeRuleList, sizeof (PMIGDB_RULE)),
  1046. &(rule),
  1047. sizeof (PMIGDB_RULE)
  1048. );
  1049. result = TRUE;
  1050. }
  1051. rule = rule->NextRule;
  1052. }
  1053. }
  1054. charNode = charNode->NextLevel;
  1055. p = _tcsinc (p);
  1056. w = (WORD) _tcsnextc (p);
  1057. } else {
  1058. charNode = charNode->NextPeer;
  1059. }
  1060. }
  1061. }
  1062. if (objectBase) {
  1063. FreePathString (objectBase);
  1064. }
  1065. return result;
  1066. }
  1067. BOOL
  1068. MigDbTestFile (
  1069. IN OUT PFILE_HELPER_PARAMS Params
  1070. )
  1071. /*++
  1072. Routine Description:
  1073. This is a callback function called for every file scanned. If the file is not handled we try
  1074. to see if we have this file in database. If so then we check for attributes, update the migdb
  1075. context and if necessarry call the appropriate action.
  1076. Arguments:
  1077. Params - See definition.
  1078. Return value:
  1079. TRUE - if operation was successful
  1080. FALSE - otherwise
  1081. --*/
  1082. {
  1083. HASHITEM stringId;
  1084. PMIGDB_RULE rule;
  1085. PMIGDB_FILE migDbFile;
  1086. PMIGDB_ATTRIB migDbAttrib;
  1087. DBATTRIB_PARAMS attribParams;
  1088. BOOL fileSelected;
  1089. PCTSTR fileName;
  1090. PCTSTR fileExt;
  1091. FILE_LIST_STRUCT fileList;
  1092. UINT index;
  1093. // we don't check the Handled field here because the code will be carefull enough not
  1094. // to call actions that are not gathering informations if the Handled field is not 0.
  1095. fileName = GetFileNameFromPath (Params->NativeObjectName);
  1096. fileExt = GetFileExtensionFromPath (fileName);
  1097. if (g_FileTable) {
  1098. stringId = HtFindString (g_FileTable, fileName);
  1099. if (stringId) {
  1100. //The string table has extra data (a pointer to a MigDbFile node)
  1101. HtCopyStringData (g_FileTable, stringId, &fileList);
  1102. migDbFile = fileList.First;
  1103. while (migDbFile) {
  1104. //check all attributes for this file
  1105. migDbAttrib = migDbFile->Attributes;
  1106. fileSelected = TRUE;
  1107. while (migDbAttrib != NULL) {
  1108. attribParams.FileParams = Params;
  1109. if (!CallAttribute (migDbAttrib, &attribParams)) {
  1110. fileSelected = FALSE;
  1111. break;
  1112. }
  1113. migDbAttrib = migDbAttrib->Next;
  1114. }
  1115. if (fileSelected) {
  1116. MYASSERT (migDbFile->Section);
  1117. //go to section and mark it as satisfied
  1118. migDbFile->Section->Satisfied = TRUE;
  1119. //go to context and add there the file we found in file list
  1120. GbMultiSzAppend (&migDbFile->Section->Context->FileList, Params->ObjectName);
  1121. //check if context is satisfied and if so then call the appropriate action
  1122. if (pCheckContext (migDbFile->Section->Context, Params->Handled)) {
  1123. Params->Handled = TRUE;
  1124. }
  1125. }
  1126. migDbFile = migDbFile->Next;
  1127. }
  1128. }
  1129. }
  1130. if (g_TypeRule) {
  1131. g_TypeRuleList.End = 0;
  1132. if (pQueryRule (Params->ObjectName, Params->ObjectNode)) {
  1133. // let's enumerate all the matching rules to check for attributes
  1134. index = 0;
  1135. while (index < g_TypeRuleList.End) {
  1136. CopyMemory (&rule, &(g_TypeRuleList.Buf[index]), sizeof (PMIGDB_RULE));
  1137. //check all attributes for this file
  1138. migDbAttrib = rule->Attributes;
  1139. fileSelected = TRUE;
  1140. while (migDbAttrib != NULL) {
  1141. attribParams.FileParams = Params;
  1142. if (!CallAttribute (migDbAttrib, &attribParams)) {
  1143. fileSelected = FALSE;
  1144. break;
  1145. }
  1146. migDbAttrib = migDbAttrib->Next;
  1147. }
  1148. if (fileSelected) {
  1149. //One last thing. See if this object is a node and the rule accepts nodes
  1150. if (!rule->IncludeNodes) {
  1151. if (IsmIsObjectHandleNodeOnly (Params->ObjectName)) {
  1152. fileSelected = FALSE;
  1153. }
  1154. }
  1155. if (fileSelected) {
  1156. MYASSERT (rule->Section);
  1157. //go to section and mark it as satisfied
  1158. rule->Section->Satisfied = TRUE;
  1159. //go to context and add there the file we found in file list
  1160. GbMultiSzAppend (&rule->Section->Context->FileList, Params->ObjectName);
  1161. //check if context is satisfied and if so then call the appropriate action
  1162. if (pCheckContext (rule->Section->Context, Params->Handled)) {
  1163. Params->Handled = TRUE;
  1164. }
  1165. }
  1166. }
  1167. index += sizeof (PMIGDB_RULE);
  1168. }
  1169. }
  1170. g_TypeRuleList.End = 0;
  1171. }
  1172. return TRUE;
  1173. }