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.

680 lines
18 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. rules.c
  5. Abstract:
  6. Implements the "rule" algorithm that scores script patterns and keeps them
  7. in reverse-sorted order.
  8. Author:
  9. Jim Schmidt (jimschm) 12-May-2000
  10. Revision History:
  11. <alias> <date> <comments>
  12. --*/
  13. //
  14. // Includes
  15. //
  16. #include "pch.h"
  17. #include "v1p.h"
  18. #define DBG_V1 "v1"
  19. //
  20. // Strings
  21. //
  22. // None
  23. //
  24. // Constants
  25. //
  26. // None
  27. //
  28. // Macros
  29. //
  30. // None
  31. //
  32. // Types
  33. //
  34. typedef struct _TAG_RULE {
  35. PCTSTR ObjectBase;
  36. MIG_OBJECTSTRINGHANDLE ObjectPattern;
  37. POBSPARSEDPATTERN ParsedPattern;
  38. UINT Score;
  39. ACTIONGROUP ActionGroup;
  40. DWORD ActionFlags;
  41. ACTION_STRUCT ActionStruct;
  42. struct _TAG_RULE *NextRule;
  43. } RULE, *PRULE;
  44. typedef struct _TAG_CHAR_NODE {
  45. PRULE RuleList;
  46. WORD Char;
  47. WORD Flags;
  48. struct _TAG_CHAR_NODE *NextLevel;
  49. struct _TAG_CHAR_NODE *NextPeer;
  50. } CHAR_NODE, *PCHAR_NODE;
  51. typedef struct {
  52. MIG_OBJECTTYPEID ObjectTypeId;
  53. PRULE RuleList;
  54. PCHAR_NODE FirstLevel;
  55. } TYPE_RULE, *PTYPE_RULE;
  56. typedef struct {
  57. MIG_OBJECTTYPEID ObjectTypeId;
  58. TYPE_RULE TypeRule;
  59. } TYPETORULE, *PTYPETORULE;
  60. //
  61. // Globals
  62. //
  63. GROWBUFFER g_TypeToIncRule = INIT_GROWBUFFER;
  64. GROWBUFFER g_TypeToPriRule = INIT_GROWBUFFER;
  65. GROWBUFFER g_TypeToCollRule = INIT_GROWBUFFER;
  66. GROWBUFFER g_TypeRuleList = INIT_GROWBUFFER;
  67. PMHANDLE g_RulePool;
  68. //
  69. // Macro expansion list
  70. //
  71. // None
  72. //
  73. // Private function prototypes
  74. //
  75. // None
  76. //
  77. // Macro expansion definition
  78. //
  79. // None
  80. //
  81. // Code
  82. //
  83. BOOL
  84. pAddRuleToTypeRule (
  85. IN PTYPE_RULE TypeRule,
  86. IN PRULE Rule
  87. )
  88. {
  89. PCHAR_NODE node, currNode, prevNode;
  90. PTSTR objectBase;
  91. PCTSTR p;
  92. WORD w;
  93. BOOL found;
  94. if (Rule->ObjectBase) {
  95. currNode = TypeRule->FirstLevel;
  96. prevNode = currNode;
  97. objectBase = DuplicatePathString (Rule->ObjectBase, 0);
  98. CharLower (objectBase);
  99. p = objectBase;
  100. while (*p) {
  101. w = (WORD) _tcsnextc (p);
  102. p = _tcsinc (p);
  103. if (currNode) {
  104. if (currNode->Char == w) {
  105. if (!*p) {
  106. Rule->NextRule = currNode->RuleList;
  107. currNode->RuleList = Rule;
  108. }
  109. prevNode = currNode;
  110. currNode = currNode->NextLevel;
  111. } else {
  112. found = FALSE;
  113. while (!found && currNode->NextPeer) {
  114. if (currNode->NextPeer->Char == w) {
  115. if (!*p) {
  116. Rule->NextRule = currNode->NextPeer->RuleList;
  117. currNode->NextPeer->RuleList = Rule;
  118. }
  119. prevNode = currNode->NextPeer;
  120. currNode = prevNode->NextLevel;
  121. found = TRUE;
  122. break;
  123. }
  124. currNode = currNode->NextPeer;
  125. }
  126. if (!found) {
  127. node = PmGetMemory (g_RulePool, sizeof (CHAR_NODE));
  128. ZeroMemory (node, sizeof (CHAR_NODE));
  129. if (!*p) {
  130. node->RuleList = Rule;
  131. }
  132. node->Char = w;
  133. node->NextPeer = currNode->NextPeer;
  134. currNode->NextPeer = node;
  135. prevNode = node;
  136. currNode = node->NextLevel;
  137. }
  138. }
  139. } else {
  140. node = PmGetMemory (g_RulePool, sizeof (CHAR_NODE));
  141. ZeroMemory (node, sizeof (CHAR_NODE));
  142. if (!*p) {
  143. node->RuleList = Rule;
  144. }
  145. node->Char = w;
  146. if (prevNode) {
  147. prevNode->NextLevel = node;
  148. } else {
  149. TypeRule->FirstLevel = node;
  150. }
  151. prevNode = node;
  152. currNode = prevNode->NextLevel;
  153. }
  154. }
  155. FreePathString (objectBase);
  156. } else {
  157. Rule->NextRule = TypeRule->RuleList;
  158. TypeRule->RuleList = Rule;
  159. }
  160. return TRUE;
  161. }
  162. UINT
  163. pComputeSubScore (
  164. IN BOOL ExcludeLastPatSeg,
  165. IN PCTSTR String,
  166. IN UINT WildcardScore,
  167. IN UINT FixedCharScore,
  168. IN UINT WackScoreBeforeWildcard,
  169. IN UINT WackScoreAfterWildcard
  170. )
  171. {
  172. PCTSTR p;
  173. BOOL skipExtendedPattern;
  174. UINT score = 0;
  175. BOOL patternEncountered = FALSE;
  176. CHARTYPE ch;
  177. UINT state = 0;
  178. UINT delScore = 0;
  179. for (p = String ; *p ; p = _tcsinc (p)) {
  180. skipExtendedPattern = FALSE;
  181. switch (_tcsnextc (p)) {
  182. case TEXT('*'):
  183. if (state == 1) {
  184. state = 2;
  185. }
  186. if (state == 2) {
  187. delScore += WildcardScore;
  188. }
  189. score += WildcardScore;
  190. skipExtendedPattern = TRUE;
  191. patternEncountered = TRUE;
  192. break;
  193. case TEXT('?'):
  194. if (state == 1) {
  195. state = 2;
  196. }
  197. if (state == 2) {
  198. delScore += WildcardScore;
  199. }
  200. score += WildcardScore;
  201. skipExtendedPattern = TRUE;
  202. patternEncountered = TRUE;
  203. break;
  204. case TEXT('\\'):
  205. state = 1;
  206. if (patternEncountered) {
  207. score += WackScoreAfterWildcard;
  208. delScore = WackScoreAfterWildcard;
  209. } else {
  210. score += WackScoreBeforeWildcard;
  211. delScore = WackScoreBeforeWildcard;
  212. }
  213. break;
  214. case TEXT(':'):
  215. //
  216. // Special case: if just a drive spec with no wacks,
  217. // add the wack score
  218. //
  219. if (p[1] == 0) {
  220. score += WackScoreBeforeWildcard;
  221. break;
  222. }
  223. // fall through
  224. default:
  225. state = 0;
  226. delScore = 0;
  227. score += FixedCharScore;
  228. break;
  229. }
  230. if (skipExtendedPattern) {
  231. if (_tcsnextc (_tcsinc (p)) == TEXT('[')) {
  232. do {
  233. p = _tcsinc (p);
  234. ch = (CHARTYPE) _tcsnextc (p);
  235. if (ch == TEXT('^')) {
  236. p++;
  237. }
  238. } while (ch != TEXT(']'));
  239. }
  240. }
  241. }
  242. if (ExcludeLastPatSeg) {
  243. if (score > delScore) {
  244. score -= delScore;
  245. if (delScore && score > 0) {
  246. score -= 1;
  247. }
  248. } else {
  249. score = 0;
  250. }
  251. }
  252. return score;
  253. }
  254. UINT
  255. pComputeScore (
  256. IN MIG_OBJECTSTRINGHANDLE EncodedString
  257. )
  258. {
  259. PCTSTR node;
  260. PCTSTR leaf;
  261. UINT score = 0;
  262. IsmCreateObjectStringsFromHandle (EncodedString, &node, &leaf);
  263. if (node) {
  264. score += 1000 * pComputeSubScore (TRUE, node, 0, 10, 1000, 500);
  265. }
  266. if (leaf) {
  267. score += pComputeSubScore (FALSE, leaf, 0, 10, 0, 0);
  268. }
  269. IsmDestroyObjectString (node);
  270. IsmDestroyObjectString (leaf);
  271. return score;
  272. }
  273. PTYPE_RULE
  274. pGetListForType (
  275. IN PGROWBUFFER TypeToRule,
  276. IN MIG_OBJECTTYPEID ObjectTypeId
  277. )
  278. {
  279. PTYPE_RULE pos;
  280. PTYPE_RULE end;
  281. ObjectTypeId &= ~(PLATFORM_MASK);
  282. pos = (PTYPE_RULE) TypeToRule->Buf;
  283. end = (PTYPE_RULE) (TypeToRule->Buf + TypeToRule->End);
  284. while (pos < end) {
  285. if (pos->ObjectTypeId == ObjectTypeId) {
  286. return pos;
  287. }
  288. pos++;
  289. }
  290. pos = (PTYPE_RULE) GbGrow (TypeToRule, sizeof (TYPE_RULE));
  291. ZeroMemory (pos, sizeof (TYPE_RULE));
  292. pos->ObjectTypeId = ObjectTypeId;
  293. return pos;
  294. }
  295. VOID
  296. InitRules (
  297. VOID
  298. )
  299. {
  300. g_RulePool = PmCreateNamedPoolEx ("Rule Data", 32768);
  301. PmDisableTracking (g_RulePool);
  302. }
  303. VOID
  304. TerminateRules (
  305. VOID
  306. )
  307. {
  308. GbFree (&g_TypeToIncRule);
  309. GbFree (&g_TypeToPriRule);
  310. GbFree (&g_TypeToCollRule);
  311. GbFree (&g_TypeRuleList);
  312. PmEmptyPool (g_RulePool);
  313. PmDestroyPool (g_RulePool);
  314. INVALID_POINTER (g_RulePool);
  315. }
  316. UINT
  317. pGetActionWeight (
  318. IN ACTIONGROUP ActionGroup
  319. )
  320. {
  321. switch (ActionGroup) {
  322. case ACTIONGROUP_DEFAULTPRIORITY:
  323. return ACTIONWEIGHT_DEFAULTPRIORITY;
  324. case ACTIONGROUP_SPECIFICPRIORITY:
  325. return ACTIONWEIGHT_SPECIFICPRIORITY;
  326. case ACTIONGROUP_EXCLUDE:
  327. return ACTIONWEIGHT_EXCLUDE;
  328. case ACTIONGROUP_EXCLUDEEX:
  329. return ACTIONWEIGHT_EXCLUDEEX;
  330. case ACTIONGROUP_INCLUDE:
  331. return ACTIONWEIGHT_INCLUDE;
  332. case ACTIONGROUP_INCLUDEEX:
  333. return ACTIONWEIGHT_INCLUDEEX;
  334. case ACTIONGROUP_RENAME:
  335. return ACTIONWEIGHT_RENAME;
  336. case ACTIONGROUP_RENAMEEX:
  337. return ACTIONWEIGHT_RENAMEEX;
  338. case ACTIONGROUP_INCLUDERELEVANT:
  339. return ACTIONWEIGHT_INCLUDERELEVANT;
  340. case ACTIONGROUP_INCLUDERELEVANTEX:
  341. return ACTIONWEIGHT_INCLUDERELEVANTEX;
  342. case ACTIONGROUP_RENAMERELEVANT:
  343. return ACTIONWEIGHT_RENAMERELEVANT;
  344. case ACTIONGROUP_RENAMERELEVANTEX:
  345. return ACTIONWEIGHT_RENAMERELEVANTEX;
  346. case ACTIONGROUP_REGFILE:
  347. return ACTIONWEIGHT_REGFILE;
  348. case ACTIONGROUP_REGFILEEX:
  349. return ACTIONWEIGHT_REGFILEEX;
  350. case ACTIONGROUP_REGFOLDER:
  351. return ACTIONWEIGHT_REGFOLDER;
  352. case ACTIONGROUP_REGFOLDEREX:
  353. return ACTIONWEIGHT_REGFOLDEREX;
  354. case ACTIONGROUP_REGICON:
  355. return ACTIONWEIGHT_REGICON;
  356. case ACTIONGROUP_REGICONEX:
  357. return ACTIONWEIGHT_REGICONEX;
  358. case ACTIONGROUP_DELREGKEY:
  359. return ACTIONWEIGHT_DELREGKEY;
  360. default:
  361. return 0;
  362. }
  363. }
  364. BOOL
  365. AddRuleEx (
  366. IN MIG_OBJECTTYPEID Type,
  367. IN MIG_OBJECTSTRINGHANDLE ObjectBase,
  368. IN MIG_OBJECTSTRINGHANDLE ObjectPattern,
  369. IN ACTIONGROUP ActionGroup,
  370. IN DWORD ActionFlags,
  371. IN PACTION_STRUCT ActionStruct, OPTIONAL
  372. IN RULEGROUP RuleGroup
  373. )
  374. {
  375. PTYPE_RULE typeRule;
  376. MIG_SEGMENTS nodeSegment;
  377. MIG_SEGMENTS leafSegment;
  378. PCTSTR ourEncodedString;
  379. PCTSTR node;
  380. PCTSTR leaf;
  381. PRULE rule;
  382. PGROWBUFFER ruleStruct;
  383. switch (RuleGroup) {
  384. case RULEGROUP_NORMAL:
  385. ruleStruct = &g_TypeToIncRule;
  386. break;
  387. case RULEGROUP_PRIORITY:
  388. ruleStruct = &g_TypeToPriRule;
  389. break;
  390. case RULEGROUP_COLLPATTERN:
  391. ruleStruct = &g_TypeToCollRule;
  392. break;
  393. }
  394. typeRule = pGetListForType (ruleStruct, Type);
  395. if (!typeRule) {
  396. return FALSE;
  397. }
  398. //
  399. // Make sure both node an leaf are specified
  400. //
  401. IsmCreateObjectStringsFromHandleEx (ObjectPattern, &node, &leaf, TRUE);
  402. nodeSegment.Segment = node ? node : TEXT("*");
  403. nodeSegment.IsPattern = TRUE;
  404. leafSegment.Segment = leaf ? leaf : TEXT("*");
  405. leafSegment.IsPattern = TRUE;
  406. ourEncodedString = IsmCreateObjectPattern (
  407. &nodeSegment,
  408. 1,
  409. &leafSegment,
  410. 1
  411. );
  412. IsmDestroyObjectString (node);
  413. IsmDestroyObjectString (leaf);
  414. //
  415. // Insert the rule based on score
  416. //
  417. rule = PmGetMemory (g_RulePool, sizeof (RULE));
  418. ZeroMemory (rule, sizeof (RULE));
  419. if (ObjectBase) {
  420. IsmCreateObjectStringsFromHandle (ObjectBase, &node, &leaf);
  421. if (node) {
  422. rule->ObjectBase = PmDuplicateString (g_RulePool, node);
  423. }
  424. IsmDestroyObjectString (node);
  425. IsmDestroyObjectString (leaf);
  426. }
  427. rule->ObjectPattern = PmDuplicateString (g_RulePool, ourEncodedString);
  428. rule->ParsedPattern = ObsCreateParsedPatternEx (g_RulePool, ourEncodedString, FALSE);
  429. MYASSERT (rule->ParsedPattern);
  430. if (rule->ParsedPattern) {
  431. rule->Score = pComputeScore (ourEncodedString);
  432. rule->Score = rule->Score * 10 + pGetActionWeight (ActionGroup);
  433. rule->ActionGroup = ActionGroup;
  434. rule->ActionFlags = ActionFlags;
  435. if (ActionStruct) {
  436. if (ActionStruct->ObjectBase) {
  437. rule->ActionStruct.ObjectBase = PmDuplicateString (g_RulePool, ActionStruct->ObjectBase);
  438. }
  439. if (ActionStruct->ObjectDest) {
  440. rule->ActionStruct.ObjectDest = PmDuplicateString (g_RulePool, ActionStruct->ObjectDest);
  441. }
  442. if (ActionStruct->AddnlDest) {
  443. rule->ActionStruct.AddnlDest = PmDuplicateString (g_RulePool, ActionStruct->AddnlDest);
  444. }
  445. if (ActionStruct->ObjectHint) {
  446. rule->ActionStruct.ObjectHint = PmDuplicateString (g_RulePool, ActionStruct->ObjectHint);
  447. }
  448. }
  449. pAddRuleToTypeRule (typeRule, rule);
  450. } else {
  451. IsmCreateObjectStringsFromHandleEx (ourEncodedString, &node, &leaf, TRUE);
  452. LOG ((LOG_ERROR, (PCSTR) MSG_OBJECT_SPEC_ERROR, node, leaf));
  453. IsmDestroyObjectString (node);
  454. IsmDestroyObjectString (leaf);
  455. }
  456. IsmDestroyObjectHandle (ourEncodedString);
  457. return TRUE;
  458. }
  459. BOOL
  460. QueryRuleEx (
  461. IN MIG_OBJECTTYPEID Type,
  462. IN MIG_OBJECTSTRINGHANDLE EncodedString,
  463. IN PCTSTR ObjectNode,
  464. OUT PACTIONGROUP ActionGroup,
  465. OUT PDWORD ActionFlags,
  466. OUT PACTION_STRUCT ActionStruct, OPTIONAL
  467. IN RULEGROUP RuleGroup
  468. )
  469. {
  470. PTYPE_RULE typeRule;
  471. PCHAR_NODE charNode;
  472. PTSTR objectBase;
  473. PCTSTR p;
  474. WORD w;
  475. PRULE rule;
  476. PRULE foundRule;
  477. UINT maxScore;
  478. ACTIONGROUP initialAction = ACTIONGROUP_NONE;
  479. DWORD matchingFlags = 0;
  480. PGROWBUFFER ruleStruct;
  481. switch (RuleGroup) {
  482. case RULEGROUP_NORMAL:
  483. ruleStruct = &g_TypeToIncRule;
  484. break;
  485. case RULEGROUP_PRIORITY:
  486. ruleStruct = &g_TypeToPriRule;
  487. break;
  488. case RULEGROUP_COLLPATTERN:
  489. ruleStruct = &g_TypeToCollRule;
  490. break;
  491. }
  492. if (ActionStruct) {
  493. ZeroMemory (ActionStruct, sizeof (ACTION_STRUCT));
  494. }
  495. typeRule = pGetListForType (ruleStruct, Type);
  496. if (!typeRule) {
  497. return FALSE;
  498. }
  499. //
  500. // Let's walk the structure finding all possible rules and put them in a grow buffer
  501. // Later we'll examine the rules one by one. Note that the root rules always qualify
  502. //
  503. if (ObjectNode) {
  504. objectBase = DuplicatePathString (ObjectNode, 0);
  505. CharLower (objectBase);
  506. }
  507. g_TypeRuleList.End = 0;
  508. p = objectBase;
  509. if (p) {
  510. w = (WORD) _tcsnextc (p);
  511. charNode = typeRule->FirstLevel;
  512. while (charNode && *p) {
  513. if (charNode->Char == w) {
  514. if (charNode->RuleList) {
  515. CopyMemory (GbGrow (&g_TypeRuleList, sizeof (PRULE)), &(charNode->RuleList), sizeof (PRULE));
  516. }
  517. charNode = charNode->NextLevel;
  518. p = _tcsinc (p);
  519. w = (WORD) _tcsnextc (p);
  520. } else {
  521. charNode = charNode->NextPeer;
  522. }
  523. }
  524. }
  525. maxScore = 0;
  526. foundRule = NULL;
  527. while (g_TypeRuleList.End) {
  528. CopyMemory (&rule, &(g_TypeRuleList.Buf[g_TypeRuleList.End - sizeof (PRULE)]), sizeof (PRULE));
  529. while (rule) {
  530. if (maxScore <= rule->Score) {
  531. if (IsmParsedPatternMatch ((MIG_PARSEDPATTERN)rule->ParsedPattern, Type, EncodedString)) {
  532. if (foundRule && (maxScore == rule->Score)) {
  533. if (initialAction == rule->ActionGroup) {
  534. matchingFlags |= rule->ActionFlags;
  535. }
  536. } else {
  537. foundRule = rule;
  538. initialAction = foundRule->ActionGroup;
  539. matchingFlags = foundRule->ActionFlags;
  540. maxScore = rule->Score;
  541. }
  542. }
  543. }
  544. rule = rule->NextRule;
  545. }
  546. g_TypeRuleList.End -= sizeof (PRULE);
  547. }
  548. rule = typeRule->RuleList;
  549. while (rule) {
  550. if (maxScore <= rule->Score) {
  551. if (IsmParsedPatternMatch ((MIG_PARSEDPATTERN)rule->ParsedPattern, Type, EncodedString)) {
  552. if (foundRule && (maxScore == rule->Score)) {
  553. if (initialAction == rule->ActionGroup) {
  554. matchingFlags |= rule->ActionFlags;
  555. }
  556. } else {
  557. foundRule = rule;
  558. initialAction = foundRule->ActionGroup;
  559. matchingFlags = foundRule->ActionFlags;
  560. maxScore = rule->Score;
  561. }
  562. }
  563. }
  564. rule = rule->NextRule;
  565. }
  566. if (foundRule) {
  567. *ActionGroup = initialAction;
  568. *ActionFlags = matchingFlags;
  569. if (ActionStruct && (!ActionStruct->ObjectBase) && (foundRule->ActionStruct.ObjectBase)) {
  570. ActionStruct->ObjectBase = foundRule->ActionStruct.ObjectBase;
  571. }
  572. if (ActionStruct && (!ActionStruct->ObjectDest) && (foundRule->ActionStruct.ObjectDest)) {
  573. ActionStruct->ObjectDest = foundRule->ActionStruct.ObjectDest;
  574. }
  575. if (ActionStruct && (!ActionStruct->AddnlDest) && (foundRule->ActionStruct.AddnlDest)) {
  576. ActionStruct->AddnlDest = foundRule->ActionStruct.AddnlDest;
  577. }
  578. if (ActionStruct && (!ActionStruct->ObjectHint) && (foundRule->ActionStruct.ObjectHint)) {
  579. ActionStruct->ObjectHint = foundRule->ActionStruct.ObjectHint;
  580. }
  581. }
  582. FreePathString (objectBase);
  583. return (foundRule != NULL);
  584. }