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.

4000 lines
112 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. ops.c
  5. Abstract:
  6. Implements the operation interface for the ISM. Operations are used to
  7. track changes to state. An object can have any number of operations
  8. applied to it, as long as the combinations are legal. Each operation
  9. has an optional source and destination property per object.
  10. Author:
  11. Jim Schmidt (jimschm) 01-Mar-2000
  12. Revision History:
  13. <alias> <date> <comments>
  14. --*/
  15. //
  16. // Includes
  17. //
  18. #include "pch.h"
  19. #include "ism.h"
  20. #include "ismp.h"
  21. #define DBG_OPS "Ops"
  22. //
  23. // Strings
  24. //
  25. // None
  26. //
  27. // Constants
  28. //
  29. #define OP_HASH_BUCKETS 503
  30. //
  31. // Macros
  32. //
  33. // None
  34. //
  35. // Types
  36. //
  37. typedef struct {
  38. MIG_OPERATIONID OperationId;
  39. LONGLONG SrcData;
  40. LONGLONG DestData;
  41. } OPERATION_PROPERTY_LINKAGE, *POPERATION_PROPERTY_LINKAGE;
  42. typedef struct {
  43. PUINT LinkageList;
  44. UINT Count;
  45. UINT Index;
  46. POPERATION_PROPERTY_LINKAGE OpPropLinkList;
  47. UINT OpPropCount;
  48. GROWBUFFER SrcPropBuf;
  49. GROWBUFFER DestPropBuf;
  50. MIG_BLOB SrcData;
  51. MIG_BLOB DestData;
  52. BOOL ReturnAllPrivateOps;
  53. } OBJECTOPERATION_HANDLE, *POBJECTOPERATION_HANDLE;
  54. typedef struct {
  55. PUINT LinkageList;
  56. UINT Count;
  57. UINT Index;
  58. PCTSTR ObjectFromMemdb;
  59. } OBJECTWITHOPERATION_HANDLE, *POBJECTWITHOPERATION_HANDLE;
  60. typedef struct {
  61. POPMFILTERCALLBACK FilterCallbackHp;
  62. POPMFILTERCALLBACK FilterCallback;
  63. BOOL TreeFilterHp;
  64. BOOL TreeFilter;
  65. BOOL NoRestoreFilterHp;
  66. BOOL NoRestoreFilter;
  67. POPMAPPLYCALLBACK ApplyCallbackHp;
  68. POPMAPPLYCALLBACK ApplyCallback;
  69. UINT CombinationsCount;
  70. BOOL IgnoreCollision;
  71. MIG_OPERATIONID *Combinations;
  72. } OPERATION_DATA, *POPERATION_DATA;
  73. typedef struct TAG_OPERATION_DATA_ITEM {
  74. struct TAG_OPERATION_DATA_ITEM *NextBucketItem;
  75. MIG_OPERATIONID OperationId;
  76. POPERATION_DATA Data;
  77. } OPERATION_DATA_ITEM, *POPERATION_DATA_ITEM;
  78. typedef struct {
  79. MIG_OBJECTID ObjectId;
  80. PCMIG_BLOB SourceData;
  81. PCMIG_BLOB DestinationData;
  82. LONGLONG SourceDataOffset;
  83. LONGLONG DestinationDataOffset;
  84. } SETOPERATIONARG, *PSETOPERATIONARG;
  85. typedef struct {
  86. MIG_OBJECTID ObjectId;
  87. LONGLONG SourceDataOffset;
  88. LONGLONG DestinationDataOffset;
  89. } SETOPERATIONARG2, *PSETOPERATIONARG2;
  90. typedef struct TAG_GLOBALFILTER {
  91. struct TAG_GLOBALFILTER *Next, *Prev;
  92. UINT Priority;
  93. MIG_PLATFORMTYPEID Platform;
  94. MIG_OPERATIONID OperationId;
  95. POPMFILTERCALLBACK Callback;
  96. BOOL TreeFilter;
  97. BOOL NoRestoreFilter;
  98. } GLOBALFILTER, *PGLOBALFILTER;
  99. typedef struct TAG_GLOBALEDIT {
  100. struct TAG_GLOBALEDIT *Next, *Prev;
  101. UINT Priority;
  102. MIG_PLATFORMTYPEID Platform;
  103. MIG_OPERATIONID OperationId;
  104. POPMAPPLYCALLBACK Callback;
  105. } GLOBALEDIT, *PGLOBALEDIT;
  106. typedef struct TAG_GLOBALFILTERINDEX {
  107. struct TAG_GLOBALFILTERINDEX *Next;
  108. MIG_OBJECTTYPEID ObjectTypeId;
  109. // normal priority
  110. PGLOBALFILTER FilterFirstHead;
  111. PGLOBALFILTER FilterLastHead;
  112. PGLOBALEDIT EditFirstHead;
  113. PGLOBALEDIT EditLastHead;
  114. // high priority
  115. PGLOBALFILTER FilterFirstHeadHp;
  116. PGLOBALFILTER FilterLastHeadHp;
  117. PGLOBALEDIT EditFirstHeadHp;
  118. PGLOBALEDIT EditLastHeadHp;
  119. } GLOBALFILTERINDEX, *PGLOBALFILTERINDEX;
  120. //
  121. // Globals
  122. //
  123. PMHANDLE g_OpPool;
  124. OPERATION_DATA_ITEM g_OpHashTable[OP_HASH_BUCKETS];
  125. PGLOBALFILTERINDEX g_FirstGlobalOperation;
  126. //
  127. // Macro expansion list
  128. //
  129. // None
  130. //
  131. // Private function prototypes
  132. //
  133. MIG_OPERATIONID
  134. pRegisterOperation (
  135. IN PCTSTR OperationName,
  136. IN BOOL Private,
  137. IN PCTSTR CurrentGroup
  138. );
  139. //
  140. // Macro expansion definition
  141. //
  142. // None
  143. //
  144. // Code
  145. //
  146. PCTSTR
  147. pGetOpNameForDebug (
  148. IN MIG_OPERATIONID OperationId
  149. )
  150. {
  151. static TCHAR Name[256];
  152. if (!IsmGetOperationName (OperationId, Name, ARRAYSIZE(Name), NULL, NULL, NULL)) {
  153. StringCopy (Name, TEXT("<invalid operation>"));
  154. }
  155. return Name;
  156. }
  157. PCTSTR
  158. pGetOpNameForDebug2 (
  159. IN MIG_OPERATIONID OperationId
  160. )
  161. {
  162. static TCHAR Name[256];
  163. if (!IsmGetOperationName (OperationId, Name, ARRAYSIZE(Name), NULL, NULL, NULL)) {
  164. StringCopy (Name, TEXT("<invalid operation>"));
  165. }
  166. return Name;
  167. }
  168. UINT
  169. pComputeOperationHash (
  170. IN MIG_OPERATIONID OperationId
  171. )
  172. {
  173. return (UINT) OperationId % OP_HASH_BUCKETS;
  174. }
  175. POPERATION_DATA_ITEM
  176. pFindOperationBucketItem (
  177. IN MIG_OPERATIONID OperationId
  178. )
  179. {
  180. UINT hash;
  181. POPERATION_DATA_ITEM item;
  182. hash = pComputeOperationHash (OperationId);
  183. item = &g_OpHashTable[hash];
  184. do {
  185. if (item->OperationId == OperationId) {
  186. return item;
  187. }
  188. item = item->NextBucketItem;
  189. } while (item);
  190. return NULL;
  191. }
  192. POPERATION_DATA_ITEM
  193. pGetOperationBucketItem (
  194. IN MIG_OPERATIONID OperationId
  195. )
  196. {
  197. POPERATION_DATA_ITEM item;
  198. POPERATION_DATA_ITEM newItem;
  199. UINT hash;
  200. hash = pComputeOperationHash (OperationId);
  201. item = &g_OpHashTable[hash];
  202. if (item->OperationId) {
  203. //
  204. // Find the last bucket item, then allocate a new bucket item
  205. //
  206. while (item->NextBucketItem) {
  207. item = item->NextBucketItem;
  208. }
  209. newItem = (POPERATION_DATA_ITEM) PmGetMemory (g_OpPool, sizeof (OPERATION_DATA_ITEM));
  210. ZeroMemory (newItem, sizeof (OPERATION_DATA_ITEM));
  211. item->NextBucketItem = newItem;
  212. item = newItem;
  213. }
  214. item->OperationId = OperationId;
  215. item->Data = NULL;
  216. return item;
  217. }
  218. VOID
  219. pUpdateOperationData (
  220. IN MIG_OPERATIONID OperationId,
  221. IN POPERATION_DATA Data
  222. )
  223. {
  224. POPERATION_DATA_ITEM item;
  225. item = pFindOperationBucketItem (OperationId);
  226. MYASSERT (item);
  227. MYASSERT (item->Data);
  228. CopyMemory (item->Data, Data, sizeof (OPERATION_DATA));
  229. }
  230. BOOL
  231. pGetOperationData (
  232. IN MIG_OPERATIONID OperationId,
  233. OUT POPERATION_DATA Data
  234. )
  235. {
  236. POPERATION_DATA_ITEM item;
  237. item = pFindOperationBucketItem (OperationId);
  238. if (!item) {
  239. ZeroMemory (Data, sizeof (OPERATION_DATA));
  240. item = pGetOperationBucketItem (OperationId);
  241. MYASSERT (item);
  242. MYASSERT (!item->Data);
  243. item->Data = (POPERATION_DATA) PmDuplicateMemory (
  244. g_OpPool,
  245. (PBYTE) Data,
  246. sizeof (OPERATION_DATA)
  247. );
  248. return TRUE;
  249. }
  250. CopyMemory (Data, item->Data, sizeof (OPERATION_DATA));
  251. return TRUE;
  252. }
  253. VOID
  254. pAddCombinationPair (
  255. IN MIG_OPERATIONID OperationIdToChange,
  256. IN MIG_OPERATIONID OperationIdForTheComboList
  257. )
  258. {
  259. OPERATION_DATA data;
  260. //
  261. // If a data struct does not exist, create one
  262. //
  263. if (!pGetOperationData (OperationIdToChange, &data)) {
  264. return;
  265. }
  266. if (!data.Combinations) {
  267. data.Combinations = (MIG_OPERATIONID *) PmGetMemory (
  268. g_OpPool,
  269. sizeof (MIG_OPERATIONID)
  270. );
  271. data.CombinationsCount = 0;
  272. } else {
  273. data.Combinations = (MIG_OPERATIONID *) PmGetMemory (
  274. g_OpPool,
  275. (data.CombinationsCount + 1) * sizeof (MIG_OPERATIONID)
  276. );
  277. }
  278. MYASSERT (data.Combinations);
  279. data.Combinations[data.CombinationsCount] = OperationIdForTheComboList;
  280. data.CombinationsCount++;
  281. pUpdateOperationData (OperationIdToChange, &data);
  282. }
  283. BOOL
  284. pTestOperationCombination (
  285. IN MIG_OPERATIONID OperationId1,
  286. IN MIG_OPERATIONID OperationId2,
  287. OUT PBOOL IgnoreCollision
  288. )
  289. /*++
  290. Routine Description:
  291. pTestOperationCombination tests if two operations can be combined. The
  292. return result indicates if the combination is prohibited.
  293. Arguments:
  294. OperationId1 - Specifies the first operation to test. The ID must be
  295. valid.
  296. OperationId2 - Specifies the second operation to test. This ID must also be
  297. valid.
  298. IgnoreCollision - Receives that the collision is ignored
  299. Return Value:
  300. TRUE if the combination is prohibited, or FALSE if it is allowed.
  301. --*/
  302. {
  303. POPERATION_DATA_ITEM item;
  304. POPERATION_DATA data;
  305. UINT u;
  306. item = pFindOperationBucketItem (OperationId1);
  307. if (!item) {
  308. return FALSE;
  309. }
  310. data = item->Data;
  311. if (!data) {
  312. return FALSE;
  313. }
  314. for (u = 0 ; u < data->CombinationsCount ; u++) {
  315. if (data->Combinations[u] == OperationId2) {
  316. if (IgnoreCollision) {
  317. *IgnoreCollision = data->IgnoreCollision;
  318. }
  319. return TRUE;
  320. }
  321. }
  322. return FALSE;
  323. }
  324. BOOL
  325. pIsOperationProhibitedOnObject (
  326. IN MIG_OPERATIONID OperationIdToTest,
  327. IN MIG_OBJECTID ObjectId,
  328. IN BOOL NoDebugOutput
  329. )
  330. {
  331. UINT count;
  332. UINT u;
  333. KEYHANDLE *list = NULL;
  334. BOOL result = TRUE;
  335. BOOL ignoreCollision;
  336. POPERATION_DATA_ITEM item;
  337. __try {
  338. //
  339. // First check if this operation is prohibited to be combined with another operation
  340. //
  341. item = pFindOperationBucketItem (OperationIdToTest);
  342. if (!item || !item->Data || !item->Data->CombinationsCount) {
  343. //
  344. // No prohibited pairs exist; return now
  345. //
  346. result = FALSE;
  347. __leave;
  348. }
  349. //
  350. // Now check each operation set on ObjectId against the prohibited ID list
  351. //
  352. list = MemDbGetDoubleLinkageArrayByKeyHandle (ObjectId, OPERATION_INDEX, &count);
  353. if (list) {
  354. count /= sizeof (KEYHANDLE);
  355. for (u = 0 ; u < count ; u++) {
  356. if ((MIG_OPERATIONID) list[u] == OperationIdToTest) {
  357. DEBUGMSG ((
  358. DBG_VERBOSE,
  359. "Operation %s already set on object %s; ignoring subsequent set",
  360. pGetOpNameForDebug (OperationIdToTest),
  361. GetObjectNameForDebugMsg (ObjectId)
  362. ));
  363. __leave;
  364. }
  365. if (pTestOperationCombination (OperationIdToTest, (MIG_OPERATIONID) list[u], &ignoreCollision)) {
  366. if (!ignoreCollision &&
  367. !NoDebugOutput) {
  368. DEBUGMSG ((
  369. DBG_ERROR,
  370. "Can't set operation %s because it conflicts with %s",
  371. pGetOpNameForDebug (OperationIdToTest),
  372. pGetOpNameForDebug2 ((MIG_OPERATIONID) list[u])
  373. ));
  374. }
  375. __leave;
  376. }
  377. }
  378. }
  379. //
  380. // All operations set on ObjectId are allowed to be combined with OperationIdToTest
  381. //
  382. result = FALSE;
  383. }
  384. __finally {
  385. if (list) {
  386. MemDbReleaseMemory (list);
  387. INVALID_POINTER (list);
  388. }
  389. }
  390. return result;
  391. }
  392. PCTSTR
  393. pOperationPathFromId (
  394. IN MIG_OPERATIONID OperationId
  395. )
  396. {
  397. return MemDbGetKeyFromHandle ((UINT) OperationId, 0);
  398. }
  399. VOID
  400. pOperationPathFromName (
  401. IN PCTSTR OperationName,
  402. OUT PTSTR Path
  403. )
  404. {
  405. wsprintf (Path, TEXT("Op\\%s"), OperationName);
  406. }
  407. LONGLONG
  408. pGetOffsetFromDataHandle (
  409. IN MIG_DATAHANDLE DataHandle
  410. )
  411. {
  412. if (!DataHandle) {
  413. return 0;
  414. }
  415. return OffsetFromPropertyDataId ((MIG_PROPERTYDATAID) DataHandle);
  416. }
  417. BOOL
  418. pAddProhibitedCombinations (
  419. IN PCTSTR InfSection
  420. )
  421. {
  422. INFSTRUCT is = INITINFSTRUCT_PMHANDLE;
  423. BOOL b = FALSE;
  424. PCTSTR mainOp;
  425. PCTSTR mainOpModule;
  426. PCTSTR combinationOp;
  427. PCTSTR combinationOpModule;
  428. UINT u;
  429. MIG_OPERATIONID mainOpId;
  430. MIG_OPERATIONID combinationOpId;
  431. PTSTR p;
  432. //
  433. // The INF tells us about prohibited operation combinations. Given a
  434. // specific operation ID, we need to be able to tell if it can be
  435. // combined with another id.
  436. //
  437. __try {
  438. if (InfFindFirstLine (g_IsmInf, InfSection, NULL, &is)) {
  439. do {
  440. mainOp = InfGetStringField (&is, 1);
  441. if (!mainOp) {
  442. continue;
  443. }
  444. p = _tcschr (mainOp, TEXT(':'));
  445. if (p) {
  446. mainOpModule = mainOp;
  447. *p = 0;
  448. mainOp = p + 1;
  449. if (!ValidateModuleName (mainOpModule)) {
  450. LOG ((
  451. LOG_WARNING,
  452. (PCSTR) MSG_INVALID_ID_OPS,
  453. mainOpModule,
  454. InfSection,
  455. is.Context.Line + 1
  456. ));
  457. continue;
  458. }
  459. } else {
  460. mainOpModule = NULL;
  461. }
  462. mainOpId = pRegisterOperation (mainOp, mainOpModule != NULL, mainOpModule);
  463. if (!mainOpId) {
  464. LOG ((
  465. LOG_WARNING,
  466. (PCSTR) MSG_ISM_INF_SYNTAX_ERROR,
  467. InfSection,
  468. is.Context.Line + 1
  469. ));
  470. continue;
  471. }
  472. u = 2;
  473. for (;; u++) {
  474. combinationOp = InfGetStringField (&is, u);
  475. if (!combinationOp) {
  476. break;
  477. }
  478. p = _tcschr (combinationOp, TEXT(':'));
  479. if (p) {
  480. combinationOpModule = combinationOp;
  481. *p = 0;
  482. combinationOp = p + 1;
  483. if (!ValidateModuleName (combinationOpModule)) {
  484. LOG ((
  485. LOG_WARNING,
  486. (PCSTR) MSG_INVALID_ID_OPS,
  487. combinationOpModule,
  488. InfSection,
  489. is.Context.Line + 1
  490. ));
  491. continue;
  492. }
  493. } else {
  494. combinationOpModule = NULL;
  495. }
  496. combinationOpId = pRegisterOperation (
  497. combinationOp,
  498. combinationOpModule != NULL,
  499. combinationOpModule
  500. );
  501. if (!combinationOpId) {
  502. LOG ((
  503. LOG_WARNING,
  504. (PCSTR) MSG_ISM_INF_SYNTAX_ERROR,
  505. InfSection,
  506. is.Context.Line + 1
  507. ));
  508. continue;
  509. }
  510. pAddCombinationPair (mainOpId, combinationOpId);
  511. pAddCombinationPair (combinationOpId, mainOpId);
  512. }
  513. } while (InfFindNextLine (&is));
  514. }
  515. b = TRUE;
  516. }
  517. __finally {
  518. InfCleanUpInfStruct (&is);
  519. }
  520. return b;
  521. }
  522. VOID
  523. pAddIgnoredCollision (
  524. IN MIG_OPERATIONID OperationIdToChange
  525. )
  526. {
  527. OPERATION_DATA data;
  528. //
  529. // If a data struct does not exist, create one
  530. //
  531. if (!pGetOperationData (OperationIdToChange, &data)) {
  532. return;
  533. }
  534. data.IgnoreCollision = TRUE;
  535. pUpdateOperationData (OperationIdToChange, &data);
  536. }
  537. BOOL
  538. pAddIgnoredCollisions (
  539. IN PCTSTR InfSection
  540. )
  541. {
  542. INFSTRUCT is = INITINFSTRUCT_PMHANDLE;
  543. BOOL b = FALSE;
  544. PCTSTR mainOp;
  545. PCTSTR mainOpModule;
  546. MIG_OPERATIONID mainOpId;
  547. PTSTR p;
  548. //
  549. // The INF tells us about ignored operation collisions.
  550. //
  551. __try {
  552. if (InfFindFirstLine (g_IsmInf, InfSection, NULL, &is)) {
  553. do {
  554. mainOp = InfGetStringField (&is, 1);
  555. if (!mainOp) {
  556. continue;
  557. }
  558. p = _tcschr (mainOp, TEXT(':'));
  559. if (p) {
  560. mainOpModule = mainOp;
  561. *p = 0;
  562. mainOp = p + 1;
  563. if (!ValidateModuleName (mainOpModule)) {
  564. LOG ((
  565. LOG_WARNING,
  566. (PCSTR) MSG_INVALID_ID_OPS,
  567. mainOpModule,
  568. InfSection,
  569. is.Context.Line + 1
  570. ));
  571. continue;
  572. }
  573. } else {
  574. mainOpModule = NULL;
  575. }
  576. mainOpId = pRegisterOperation (mainOp, mainOpModule != NULL, mainOpModule);
  577. if (!mainOpId) {
  578. LOG ((
  579. LOG_WARNING,
  580. (PCSTR) MSG_ISM_INF_SYNTAX_ERROR,
  581. InfSection,
  582. is.Context.Line + 1
  583. ));
  584. continue;
  585. }
  586. pAddIgnoredCollision (mainOpId);
  587. } while (InfFindNextLine (&is));
  588. }
  589. b = TRUE;
  590. }
  591. __finally {
  592. InfCleanUpInfStruct (&is);
  593. }
  594. return b;
  595. }
  596. BOOL
  597. InitializeOperations (
  598. VOID
  599. )
  600. {
  601. //
  602. // The INF tells us about prohibited operation combinations. Given a
  603. // specific operation ID, we need to be able to tell if it can be
  604. // combined with another id.
  605. //
  606. g_OpPool = PmCreateNamedPool ("Operation Data");
  607. if (!pAddIgnoredCollisions (S_IGNORED_COLLISIONS)) {
  608. return FALSE;
  609. }
  610. return pAddProhibitedCombinations (S_PROHIBITED_COMBINATIONS);
  611. }
  612. VOID
  613. TerminateOperations (
  614. VOID
  615. )
  616. {
  617. PmEmptyPool (g_OpPool);
  618. PmDestroyPool (g_OpPool);
  619. ZeroMemory (&g_OpHashTable, sizeof (g_OpHashTable));
  620. }
  621. MIG_OPERATIONID
  622. pRegisterOperation (
  623. IN PCTSTR OperationName,
  624. IN BOOL Private,
  625. IN PCTSTR CurrentGroup
  626. )
  627. {
  628. TCHAR operationPath[MEMDB_MAX];
  629. TCHAR decoratedName[MEMDB_MAX];
  630. UINT offset;
  631. if (!IsValidCNameWithDots (OperationName)) {
  632. DEBUGMSG ((DBG_ERROR, "operation name \"%s\" is illegal", OperationName));
  633. return FALSE;
  634. }
  635. #ifdef DEBUG
  636. if (Private && !IsValidCName (CurrentGroup)) {
  637. DEBUGMSG ((DBG_ERROR, "group name \"%s\" is illegal", CurrentGroup));
  638. return FALSE;
  639. }
  640. #endif
  641. if (Private) {
  642. wsprintf (decoratedName, TEXT("%s:%s"), CurrentGroup, OperationName);
  643. } else {
  644. wsprintf (decoratedName, S_COMMON TEXT(":%s"), OperationName);
  645. }
  646. pOperationPathFromName (decoratedName, operationPath);
  647. if (!MarkGroupIds (operationPath)) {
  648. DEBUGMSG ((
  649. DBG_ERROR,
  650. "%s conflicts with previously registered operation",
  651. operationPath
  652. ));
  653. return FALSE;
  654. }
  655. offset = MemDbSetKey (operationPath);
  656. if (!offset) {
  657. EngineError ();
  658. return 0;
  659. }
  660. return (MIG_OPERATIONID) offset;
  661. }
  662. MIG_OPERATIONID
  663. IsmRegisterOperation (
  664. IN PCTSTR OperationName,
  665. IN BOOL Private
  666. )
  667. /*++
  668. Routine Description:
  669. IsmRegisterOperation creates a public or private Operation and returns the
  670. ID to the caller. If the Operation already exists, then the existing ID is
  671. returned to the caller.
  672. Arguments:
  673. OperationName - Specifies the operation name to register.
  674. Private - Specifies TRUE if the operation is owned by the calling module
  675. only, or FALSE if it is shared by all modules. If TRUE is
  676. specified, the caller must be in an ISM callback function.
  677. Return Value:
  678. The ID of the operation, or 0 if the registration failed.
  679. --*/
  680. {
  681. if (!g_CurrentGroup && Private) {
  682. DEBUGMSG ((DBG_ERROR, "IsmRegisterOperation called for private operation outside of ISM-managed context"));
  683. return 0;
  684. }
  685. return pRegisterOperation (OperationName, Private, g_CurrentGroup);
  686. }
  687. MIG_OPERATIONID
  688. IsmGetOperationGroup (
  689. IN MIG_OPERATIONID OperationId
  690. )
  691. {
  692. return (MIG_OPERATIONID) GetGroupOfId ((KEYHANDLE) OperationId);
  693. }
  694. PGLOBALFILTERINDEX
  695. pGetGlobalIndex (
  696. IN MIG_OBJECTTYPEID ObjectTypeId,
  697. IN BOOL Create
  698. )
  699. {
  700. PGLOBALFILTERINDEX index;
  701. ObjectTypeId &= (~PLATFORM_MASK);
  702. index = g_FirstGlobalOperation;
  703. while (index) {
  704. if (index->ObjectTypeId == ObjectTypeId) {
  705. break;
  706. }
  707. index = index->Next;
  708. }
  709. if (!index && Create) {
  710. index = (PGLOBALFILTERINDEX) PmGetMemory (g_IsmUntrackedPool, sizeof (GLOBALFILTERINDEX));
  711. ZeroMemory (index, sizeof (GLOBALFILTERINDEX));
  712. index->Next = g_FirstGlobalOperation;
  713. index->ObjectTypeId = ObjectTypeId;
  714. g_FirstGlobalOperation = index;
  715. }
  716. return index;
  717. }
  718. BOOL
  719. IsmRegisterGlobalFilterCallback (
  720. IN MIG_OBJECTTYPEID ObjectTypeId,
  721. IN PCTSTR FunctionId,
  722. IN POPMFILTERCALLBACK Callback,
  723. IN BOOL TreeFilter,
  724. IN BOOL CanHandleNoRestore
  725. )
  726. /*++
  727. Routine Description:
  728. IsmRegisterGlobalFilterCallback adds a filter to the "global" filter list.
  729. Functions are prioritized by the ism.inf section [Global Filters]. If a
  730. function is not listed, or if no name is given, it has the lowest priority.
  731. In addition, global filters can be prohibited from being processed with
  732. another non-global filter through the [Prohibit Operation Combination]
  733. section of ism.inf.
  734. Arguments:
  735. ObjectTypeId - Specifies the type of the object
  736. FunctionId - Specifies the text name of the callback function, for purposes
  737. of prioritizing and combination management
  738. Callback - Specifies the function address to call
  739. TreeFilter - Specifies TRUE if the callback potentially modifies a portion
  740. of an object's node, or FALSE if it modifies the node completely
  741. or doesn't modify the node at all
  742. Return Value:
  743. TRUE on success, FALSE on failure
  744. --*/
  745. {
  746. PGLOBALFILTERINDEX index;
  747. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  748. PGLOBALFILTER filter;
  749. PGLOBALFILTER *head;
  750. PGLOBALFILTER insertAt;
  751. if (!FunctionId) {
  752. DEBUGMSG ((DBG_ERROR, "All global filters must have a text function ID"));
  753. return FALSE;
  754. }
  755. //
  756. // Locate the index for our type
  757. //
  758. index = pGetGlobalIndex (ObjectTypeId, TRUE);
  759. //
  760. // Allocate a new filter node
  761. //
  762. filter = (PGLOBALFILTER) PmGetMemory (g_IsmUntrackedPool, sizeof (GLOBALFILTER));
  763. filter->Platform = ObjectTypeId & PLATFORM_MASK;
  764. filter->OperationId = IsmRegisterOperation (FunctionId, FALSE);
  765. filter->TreeFilter = TreeFilter;
  766. filter->Callback = Callback;
  767. filter->NoRestoreFilter = CanHandleNoRestore;
  768. //
  769. // Insert the node into the list by priority
  770. //
  771. if (InfFindFirstLine (g_IsmInf, TEXT("Global Operations.Filter First"), FunctionId, &is)) {
  772. filter->Priority = is.Context.Line;
  773. head = &index->FilterFirstHead;
  774. } else if (InfFindFirstLine (g_IsmInf, TEXT("Global Operations.Filter Last"), FunctionId, &is)) {
  775. filter->Priority = is.Context.Line;
  776. head = &index->FilterLastHead;
  777. } else if (InfFindFirstLine (g_IsmInf, TEXT("Global Operations.Filter First.High Priority"), FunctionId, &is)) {
  778. filter->Priority = is.Context.Line;
  779. head = &index->FilterFirstHeadHp;
  780. } else if (InfFindFirstLine (g_IsmInf, TEXT("Global Operations.Filter Last.High Priority"), FunctionId, &is)) {
  781. filter->Priority = is.Context.Line;
  782. head = &index->FilterLastHead;
  783. } else {
  784. filter->Priority = 0xFFFFFFFF;
  785. head = &index->FilterLastHead;
  786. }
  787. insertAt = *head;
  788. while (insertAt) {
  789. if (insertAt->Priority >= filter->Priority) {
  790. insertAt = insertAt->Prev;
  791. break;
  792. }
  793. insertAt = insertAt->Next;
  794. }
  795. if (insertAt) {
  796. filter->Next = insertAt->Next;
  797. insertAt->Next = filter;
  798. if (filter->Next) {
  799. filter->Next->Prev = filter;
  800. }
  801. } else {
  802. *head = filter;
  803. filter->Next = NULL;
  804. }
  805. filter->Prev = insertAt;
  806. InfCleanUpInfStruct (&is);
  807. return TRUE;
  808. }
  809. BOOL
  810. IsmRegisterOperationFilterCallback (
  811. IN MIG_OPERATIONID OperationId,
  812. IN POPMFILTERCALLBACK Callback,
  813. IN BOOL TreeFilter,
  814. IN BOOL HighPriority,
  815. IN BOOL CanHandleNoRestore
  816. )
  817. {
  818. OPERATION_DATA data;
  819. //
  820. // If a data struct does not exist, create one
  821. //
  822. if (!pGetOperationData (OperationId, &data)) {
  823. return FALSE;
  824. }
  825. if (HighPriority) {
  826. if (data.FilterCallbackHp) {
  827. DEBUGMSG ((DBG_ERROR, "High Priority Filter Callback for operation 0x%08X already registered", OperationId));
  828. return FALSE;
  829. }
  830. data.FilterCallbackHp = Callback;
  831. data.TreeFilterHp = TreeFilter;
  832. data.NoRestoreFilterHp = CanHandleNoRestore;
  833. } else {
  834. if (data.FilterCallback) {
  835. DEBUGMSG ((DBG_ERROR, "Filter Callback for operation 0x%08X already registered", OperationId));
  836. return FALSE;
  837. }
  838. data.FilterCallback = Callback;
  839. data.TreeFilter = TreeFilter;
  840. data.NoRestoreFilter = CanHandleNoRestore;
  841. }
  842. pUpdateOperationData (OperationId, &data);
  843. return TRUE;
  844. }
  845. BOOL
  846. WINAPI
  847. IsmRegisterGlobalApplyCallback (
  848. IN MIG_OBJECTTYPEID ObjectTypeId,
  849. IN PCTSTR FunctionId,
  850. IN POPMAPPLYCALLBACK Callback
  851. )
  852. {
  853. PGLOBALFILTERINDEX index;
  854. INFSTRUCT is = INITINFSTRUCT_GROWBUFFER;
  855. PGLOBALEDIT editFn;
  856. PGLOBALEDIT *head;
  857. PGLOBALEDIT insertAt;
  858. if (!FunctionId) {
  859. DEBUGMSG ((DBG_ERROR, "All global content editor callbacks must have a text function ID"));
  860. return FALSE;
  861. }
  862. //
  863. // Locate the index for our type
  864. //
  865. index = pGetGlobalIndex (ObjectTypeId, TRUE);
  866. //
  867. // Allocate a new content edit node
  868. //
  869. editFn = (PGLOBALEDIT) PmGetMemory (g_IsmUntrackedPool, sizeof (GLOBALEDIT));
  870. editFn->Platform = ObjectTypeId & PLATFORM_MASK;
  871. editFn->OperationId = IsmRegisterOperation (FunctionId, FALSE);
  872. editFn->Callback = Callback;
  873. //
  874. // Insert the node into the list by priority
  875. //
  876. if (InfFindFirstLine (g_IsmInf, TEXT("Global Operations.Apply First"), FunctionId, &is)) {
  877. editFn->Priority = is.Context.Line;
  878. head = &index->EditFirstHead;
  879. } else if (InfFindFirstLine (g_IsmInf, TEXT("Global Operations.Apply Last"), FunctionId, &is)) {
  880. editFn->Priority = is.Context.Line;
  881. head = &index->EditLastHead;
  882. } else if (InfFindFirstLine (g_IsmInf, TEXT("Global Operations.Apply First.High Priority"), FunctionId, &is)) {
  883. editFn->Priority = is.Context.Line;
  884. head = &index->EditFirstHeadHp;
  885. } else if (InfFindFirstLine (g_IsmInf, TEXT("Global Operations.Apply Last.High Priority"), FunctionId, &is)) {
  886. editFn->Priority = is.Context.Line;
  887. head = &index->EditLastHead;
  888. } else {
  889. editFn->Priority = 0xFFFFFFFF;
  890. head = &index->EditLastHead;
  891. }
  892. insertAt = *head;
  893. while (insertAt) {
  894. if (insertAt->Priority >= editFn->Priority) {
  895. insertAt = insertAt->Prev;
  896. break;
  897. }
  898. insertAt = insertAt->Next;
  899. }
  900. if (insertAt) {
  901. editFn->Next = insertAt->Next;
  902. insertAt->Next = editFn;
  903. if (editFn->Next) {
  904. editFn->Next->Prev = editFn;
  905. }
  906. } else {
  907. *head = editFn;
  908. editFn->Next = NULL;
  909. }
  910. editFn->Prev = insertAt;
  911. InfCleanUpInfStruct (&is);
  912. return TRUE;
  913. }
  914. BOOL
  915. IsmRegisterOperationApplyCallback (
  916. IN MIG_OPERATIONID OperationId,
  917. IN POPMAPPLYCALLBACK Callback,
  918. IN BOOL HighPriority
  919. )
  920. {
  921. OPERATION_DATA data;
  922. //
  923. // If a data struct does not exist, create one
  924. //
  925. if (!pGetOperationData (OperationId, &data)) {
  926. return FALSE;
  927. }
  928. if (HighPriority) {
  929. if (data.ApplyCallbackHp) {
  930. DEBUGMSG ((
  931. DBG_ERROR,
  932. "High Priority Apply Callback for operation %s already registered",
  933. pGetOpNameForDebug (OperationId)
  934. ));
  935. return FALSE;
  936. }
  937. data.ApplyCallbackHp = Callback;
  938. } else {
  939. if (data.ApplyCallback) {
  940. DEBUGMSG ((
  941. DBG_ERROR,
  942. "Apply Callback for operation %s already registered",
  943. pGetOpNameForDebug (OperationId)
  944. ));
  945. return FALSE;
  946. }
  947. data.ApplyCallback = Callback;
  948. }
  949. pUpdateOperationData (OperationId, &data);
  950. return TRUE;
  951. }
  952. BOOL
  953. pGetOperationName (
  954. IN MIG_OPERATIONID OperationId,
  955. OUT PTSTR OperationName, OPTIONAL
  956. IN UINT OperationNameBufChars,
  957. OUT PBOOL Private, OPTIONAL
  958. OUT PBOOL BelongsToMe, OPTIONAL
  959. OUT PUINT ObjectReferences, OPTIONAL
  960. IN BOOL ReturnAllPrivateOps
  961. )
  962. /*++
  963. Routine Description:
  964. pGetOperationName obtains the operation text name from a numeric ID. It
  965. also identifies private and owned operations.
  966. Arguments:
  967. OperationId - Specifies the operation ID to look up.
  968. OperationName - Receives the operation name. The name is filled for
  969. all valid OperationId values, even when the return
  970. value is FALSE.
  971. OperationNameBufChars - Specifies the number of TCHARs that OperationName
  972. can hold, including the nul terminator.
  973. Private - Receives TRUE if the operation is private, or FALSE
  974. if it is public.
  975. BelongsToMe - Receives TRUE if the operation is private and
  976. belongs to the caller, FALSE otherwise.
  977. ObjectReferences - Receives the number of objects that reference the
  978. operation
  979. Return Value:
  980. TRUE if the operation is public, or if the operation is private and belongs to
  981. the caller.
  982. FALSE if the operation is private and belongs to someone else. OperationName,
  983. Private and BelongsToMe are valid in this case.
  984. FALSE if OperationId is not valid. Operationname, Private and BelongsToMe are
  985. not modified in this case. Do not use this function to test if OperationId
  986. is valid or not.
  987. --*/
  988. {
  989. PCTSTR operationPath = NULL;
  990. PCTSTR start;
  991. PTSTR p, q;
  992. BOOL privateOperation = FALSE;
  993. BOOL groupMatch = FALSE;
  994. BOOL result = FALSE;
  995. UINT references;
  996. PUINT linkageList;
  997. __try {
  998. //
  999. // Did caller specify an item id?
  1000. //
  1001. if (!IsItemId ((KEYHANDLE) OperationId)) {
  1002. DEBUGMSG ((
  1003. DBG_ERROR,
  1004. "IsmGetOperationName: must specify item id, not group id"
  1005. ));
  1006. __leave;
  1007. }
  1008. //
  1009. // Get the operation path from memdb, then parse it for group and name
  1010. //
  1011. operationPath = pOperationPathFromId (OperationId);
  1012. if (!operationPath) {
  1013. __leave;
  1014. }
  1015. p = _tcschr (operationPath, TEXT('\\'));
  1016. if (!p) {
  1017. __leave;
  1018. }
  1019. start = _tcsinc (p);
  1020. p = _tcschr (start, TEXT(':'));
  1021. if (!p) {
  1022. __leave;
  1023. }
  1024. q = _tcsinc (p);
  1025. *p = 0;
  1026. if (StringIMatch (start, S_COMMON)) {
  1027. //
  1028. // This operation is a global operation.
  1029. //
  1030. privateOperation = FALSE;
  1031. groupMatch = TRUE;
  1032. } else if (g_CurrentGroup || ReturnAllPrivateOps) {
  1033. //
  1034. // This operation is private. Check if it is ours.
  1035. //
  1036. privateOperation = TRUE;
  1037. if (g_CurrentGroup && StringIMatch (start, g_CurrentGroup)) {
  1038. groupMatch = TRUE;
  1039. } else {
  1040. groupMatch = ReturnAllPrivateOps;
  1041. }
  1042. } else {
  1043. //
  1044. // This is a private operation, but the caller is not
  1045. // a module that can own operations.
  1046. //
  1047. DEBUGMSG ((DBG_WARNING, "IsmGetOperationName: Caller cannot own private operations"));
  1048. }
  1049. //
  1050. // Copy the name to the buffer, update outbound BOOLs, set result
  1051. //
  1052. if (OperationName && OperationNameBufChars >= sizeof (TCHAR)) {
  1053. StringCopyByteCount (OperationName, q, OperationNameBufChars * sizeof (TCHAR));
  1054. }
  1055. if (Private) {
  1056. *Private = privateOperation;
  1057. }
  1058. if (BelongsToMe) {
  1059. *BelongsToMe = privateOperation && groupMatch;
  1060. }
  1061. if (ObjectReferences) {
  1062. linkageList = MemDbGetDoubleLinkageArrayByKeyHandle (
  1063. OperationId,
  1064. OPERATION_INDEX,
  1065. &references
  1066. );
  1067. references /= SIZEOF(KEYHANDLE);
  1068. if (linkageList) {
  1069. MemDbReleaseMemory (linkageList);
  1070. INVALID_POINTER (linkageList);
  1071. } else {
  1072. references = 0;
  1073. }
  1074. *ObjectReferences = references;
  1075. }
  1076. if (groupMatch) {
  1077. result = TRUE;
  1078. }
  1079. }
  1080. __finally {
  1081. if (operationPath) { //lint !e774
  1082. MemDbReleaseMemory (operationPath);
  1083. operationPath = NULL;
  1084. }
  1085. }
  1086. return result;
  1087. }
  1088. BOOL
  1089. IsmGetOperationName (
  1090. IN MIG_OPERATIONID OperationId,
  1091. OUT PTSTR OperationName, OPTIONAL
  1092. IN UINT OperationNameBufChars,
  1093. OUT PBOOL Private, OPTIONAL
  1094. OUT PBOOL BelongsToMe, OPTIONAL
  1095. OUT PUINT ObjectReferences OPTIONAL
  1096. )
  1097. {
  1098. return pGetOperationName (
  1099. OperationId,
  1100. OperationName,
  1101. OperationNameBufChars,
  1102. Private,
  1103. BelongsToMe,
  1104. ObjectReferences,
  1105. FALSE
  1106. );
  1107. }
  1108. POPERATION_PROPERTY_LINKAGE
  1109. pFindOperationPropertyLinkage (
  1110. IN MIG_OBJECTID ObjectId,
  1111. IN MIG_OPERATIONID OperationIdToFind,
  1112. OUT PBYTE *BlockToFree,
  1113. OUT PUINT BlockSize
  1114. )
  1115. {
  1116. POPERATION_PROPERTY_LINKAGE linkage;
  1117. UINT linkageCount;
  1118. POPERATION_PROPERTY_LINKAGE result = NULL;
  1119. UINT u;
  1120. __try {
  1121. linkage = (POPERATION_PROPERTY_LINKAGE) MemDbGetUnorderedBlobByKeyHandle (
  1122. ObjectId,
  1123. OPERATION_INDEX,
  1124. BlockSize
  1125. );
  1126. linkageCount = *BlockSize / sizeof (OPERATION_PROPERTY_LINKAGE);
  1127. if (!linkage || !linkageCount) {
  1128. __leave;
  1129. }
  1130. for (u = 0 ; u < linkageCount ; u++) {
  1131. if (linkage[u].OperationId == OperationIdToFind) {
  1132. result = linkage + u;
  1133. break;
  1134. }
  1135. }
  1136. }
  1137. __finally {
  1138. if (!result && linkage) {
  1139. MemDbReleaseMemory (linkage);
  1140. INVALID_POINTER (linkage);
  1141. } else {
  1142. *BlockToFree = (PBYTE) linkage;
  1143. }
  1144. }
  1145. return result;
  1146. }
  1147. BOOL
  1148. pSetOperationOnObjectId (
  1149. IN MIG_OBJECTID ObjectId,
  1150. IN MIG_OPERATIONID OperationId,
  1151. IN PCMIG_BLOB SourceData, OPTIONAL
  1152. IN PCMIG_BLOB DestinationData, OPTIONAL
  1153. IN BOOL QueryOnly,
  1154. IN OUT PLONGLONG SourceDataOffset, OPTIONAL
  1155. IN OUT PLONGLONG DestinationDataOffset OPTIONAL
  1156. )
  1157. {
  1158. BOOL result = FALSE;
  1159. OPERATION_PROPERTY_LINKAGE linkage;
  1160. POPERATION_PROPERTY_LINKAGE reuseLinkage;
  1161. PBYTE freeMe;
  1162. UINT linkageSize;
  1163. KEYHANDLE *list = NULL;
  1164. __try {
  1165. //
  1166. // Is the operation or object locked?
  1167. //
  1168. if (TestLock (ObjectId, (KEYHANDLE) OperationId)) {
  1169. SetLastError (ERROR_LOCKED);
  1170. DEBUGMSG ((
  1171. DBG_WARNING,
  1172. "Can't set operation %s on %s because of lock",
  1173. pGetOpNameForDebug (OperationId),
  1174. GetObjectNameForDebugMsg (ObjectId)
  1175. ));
  1176. __leave;
  1177. }
  1178. //
  1179. // Does this operation conflict with itself or another operation?
  1180. //
  1181. if (pIsOperationProhibitedOnObject (OperationId, ObjectId, FALSE)) {
  1182. __leave;
  1183. }
  1184. //
  1185. // If query only, return success
  1186. //
  1187. if (QueryOnly) {
  1188. result = TRUE;
  1189. __leave;
  1190. }
  1191. //
  1192. // Add the operaiton. First, store the properties in property.dat
  1193. //
  1194. ZeroMemory (&linkage, sizeof (linkage));
  1195. if (SourceData || SourceDataOffset) {
  1196. if (SourceDataOffset && *SourceDataOffset) {
  1197. linkage.SrcData = *SourceDataOffset;
  1198. } else {
  1199. linkage.SrcData = AppendProperty (SourceData);
  1200. if (!linkage.SrcData) {
  1201. DEBUGMSG ((DBG_ERROR, "Can't append src property"));
  1202. __leave;
  1203. }
  1204. if (SourceDataOffset) {
  1205. *SourceDataOffset = linkage.SrcData;
  1206. }
  1207. }
  1208. }
  1209. if (DestinationData || DestinationDataOffset) {
  1210. if (DestinationDataOffset && *DestinationDataOffset) {
  1211. linkage.DestData = *DestinationDataOffset;
  1212. } else {
  1213. linkage.DestData = AppendProperty (DestinationData);
  1214. if (!linkage.DestData) {
  1215. DEBUGMSG ((DBG_ERROR, "Can't append dest property"));
  1216. __leave;
  1217. }
  1218. if (DestinationDataOffset) {
  1219. *DestinationDataOffset = linkage.DestData;
  1220. }
  1221. }
  1222. }
  1223. //
  1224. // Establish linkage between the object, operation and properties
  1225. //
  1226. if (SourceData || SourceDataOffset ||
  1227. DestinationData || DestinationDataOffset
  1228. ) {
  1229. linkage.OperationId = OperationId;
  1230. reuseLinkage = pFindOperationPropertyLinkage (
  1231. ObjectId,
  1232. 0,
  1233. &freeMe,
  1234. &linkageSize
  1235. );
  1236. if (reuseLinkage) {
  1237. //
  1238. // Recovery case -- reuse an empty spot in the blob
  1239. //
  1240. CopyMemory (reuseLinkage, &linkage, sizeof (linkage));
  1241. if (!MemDbSetUnorderedBlobByKeyHandle (
  1242. ObjectId,
  1243. OPERATION_INDEX,
  1244. freeMe,
  1245. linkageSize
  1246. )) {
  1247. DEBUGMSG ((DBG_ERROR, "Can't update unordered operation blob"));
  1248. __leave;
  1249. }
  1250. MemDbReleaseMemory (freeMe);
  1251. INVALID_POINTER (freeMe);
  1252. } else {
  1253. //
  1254. // New case -- add the struct to the end of the blob
  1255. //
  1256. if (!MemDbGrowUnorderedBlobByKeyHandle (
  1257. ObjectId,
  1258. OPERATION_INDEX,
  1259. (PBYTE) &linkage,
  1260. sizeof (linkage)
  1261. )) {
  1262. DEBUGMSG ((DBG_ERROR, "Can't grow operation property linkage"));
  1263. __leave;
  1264. }
  1265. }
  1266. }
  1267. if (!MemDbAddDoubleLinkageByKeyHandle (ObjectId, OperationId, OPERATION_INDEX)) {
  1268. DEBUGMSG ((DBG_ERROR, "Can't link object to operation"));
  1269. EngineError ();
  1270. __leave;
  1271. }
  1272. result = TRUE;
  1273. }
  1274. __finally {
  1275. if (list) {
  1276. MemDbReleaseMemory (list);
  1277. INVALID_POINTER (list);
  1278. }
  1279. }
  1280. return result;
  1281. }
  1282. BOOL
  1283. pSetOperationGroup (
  1284. IN KEYHANDLE OperationId,
  1285. IN BOOL FirstPass,
  1286. IN ULONG_PTR Arg
  1287. )
  1288. {
  1289. PSETOPERATIONARG myArg = (PSETOPERATIONARG) Arg;
  1290. return pSetOperationOnObjectId (
  1291. myArg->ObjectId,
  1292. (MIG_OPERATIONID) OperationId,
  1293. myArg->SourceData,
  1294. myArg->DestinationData,
  1295. FirstPass,
  1296. &myArg->SourceDataOffset,
  1297. &myArg->DestinationDataOffset
  1298. );
  1299. }
  1300. BOOL
  1301. pSetOperationGroup2 (
  1302. IN KEYHANDLE OperationId,
  1303. IN BOOL FirstPass,
  1304. IN ULONG_PTR Arg
  1305. )
  1306. {
  1307. PSETOPERATIONARG2 myArg = (PSETOPERATIONARG2) Arg;
  1308. return pSetOperationOnObjectId (
  1309. myArg->ObjectId,
  1310. (MIG_OPERATIONID) OperationId,
  1311. NULL,
  1312. NULL,
  1313. FirstPass,
  1314. myArg->SourceDataOffset ? &myArg->SourceDataOffset : NULL,
  1315. myArg->DestinationDataOffset ? &myArg->DestinationDataOffset : NULL
  1316. );
  1317. }
  1318. BOOL
  1319. IsmSetOperationOnObjectId (
  1320. IN MIG_OBJECTID ObjectId,
  1321. IN MIG_OPERATIONID OperationId,
  1322. IN PCMIG_BLOB SourceData, OPTIONAL
  1323. IN PCMIG_BLOB DestinationData OPTIONAL
  1324. )
  1325. {
  1326. RECURSERETURN rc;
  1327. SETOPERATIONARG myArg;
  1328. myArg.ObjectId = ObjectId;
  1329. myArg.SourceData = SourceData;
  1330. myArg.DestinationData = DestinationData;
  1331. myArg.SourceDataOffset = 0;
  1332. myArg.DestinationDataOffset = 0;
  1333. rc = RecurseForGroupItems (
  1334. OperationId,
  1335. pSetOperationGroup,
  1336. (ULONG_PTR) &myArg,
  1337. FALSE,
  1338. FALSE
  1339. );
  1340. if (rc == RECURSE_FAIL) {
  1341. return FALSE;
  1342. } else if (rc == RECURSE_SUCCESS) {
  1343. return TRUE;
  1344. }
  1345. MYASSERT (rc == RECURSE_NOT_NEEDED);
  1346. return pSetOperationOnObjectId (
  1347. ObjectId,
  1348. OperationId,
  1349. SourceData,
  1350. DestinationData,
  1351. FALSE,
  1352. NULL,
  1353. NULL
  1354. );
  1355. }
  1356. BOOL
  1357. IsmSetOperationOnObject (
  1358. IN MIG_OBJECTTYPEID ObjectTypeId,
  1359. IN MIG_OBJECTSTRINGHANDLE EncodedObjectName,
  1360. IN MIG_OPERATIONID OperationId,
  1361. IN PCMIG_BLOB SourceData, OPTIONAL
  1362. IN PCMIG_BLOB DestinationData OPTIONAL
  1363. )
  1364. {
  1365. MIG_OBJECTID objectId;
  1366. BOOL result = FALSE;
  1367. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  1368. objectId = GetObjectIdForModification (ObjectTypeId, EncodedObjectName);
  1369. if (objectId) {
  1370. result = IsmSetOperationOnObjectId (
  1371. objectId,
  1372. OperationId,
  1373. SourceData,
  1374. DestinationData
  1375. );
  1376. }
  1377. return result;
  1378. }
  1379. MIG_DATAHANDLE
  1380. IsmRegisterOperationData (
  1381. IN PCMIG_BLOB Data
  1382. )
  1383. {
  1384. return (MIG_DATAHANDLE) IsmRegisterPropertyData (Data);
  1385. }
  1386. BOOL
  1387. IsmSetOperationOnObjectId2 (
  1388. IN MIG_OBJECTID ObjectId,
  1389. IN MIG_OPERATIONID OperationId,
  1390. IN MIG_DATAHANDLE SourceData, OPTIONAL
  1391. IN MIG_DATAHANDLE DestinationData OPTIONAL
  1392. )
  1393. {
  1394. RECURSERETURN rc;
  1395. SETOPERATIONARG2 myArg;
  1396. myArg.ObjectId = ObjectId;
  1397. if (SourceData) {
  1398. myArg.SourceDataOffset = pGetOffsetFromDataHandle (SourceData);
  1399. if (!myArg.SourceDataOffset) {
  1400. return FALSE;
  1401. }
  1402. } else {
  1403. myArg.SourceDataOffset = 0;
  1404. }
  1405. if (DestinationData) {
  1406. myArg.DestinationDataOffset = pGetOffsetFromDataHandle (DestinationData);
  1407. if (!myArg.DestinationDataOffset) {
  1408. return FALSE;
  1409. }
  1410. } else {
  1411. myArg.DestinationDataOffset = 0;
  1412. }
  1413. rc = RecurseForGroupItems (
  1414. OperationId,
  1415. pSetOperationGroup2,
  1416. (ULONG_PTR) &myArg,
  1417. FALSE,
  1418. FALSE
  1419. );
  1420. if (rc == RECURSE_FAIL) {
  1421. return FALSE;
  1422. } else if (rc == RECURSE_SUCCESS) {
  1423. return TRUE;
  1424. }
  1425. MYASSERT (rc == RECURSE_NOT_NEEDED);
  1426. return pSetOperationOnObjectId (
  1427. ObjectId,
  1428. OperationId,
  1429. NULL,
  1430. NULL,
  1431. FALSE,
  1432. SourceData ? &myArg.SourceDataOffset : NULL,
  1433. DestinationData ? &myArg.DestinationDataOffset : NULL
  1434. );
  1435. }
  1436. BOOL
  1437. IsmSetOperationOnObject2 (
  1438. IN MIG_OBJECTTYPEID ObjectTypeId,
  1439. IN MIG_OBJECTSTRINGHANDLE EncodedObjectName,
  1440. IN MIG_OPERATIONID OperationId,
  1441. IN MIG_DATAHANDLE SourceData, OPTIONAL
  1442. IN MIG_DATAHANDLE DestinationData OPTIONAL
  1443. )
  1444. {
  1445. MIG_OBJECTID objectId;
  1446. BOOL result = FALSE;
  1447. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  1448. objectId = GetObjectIdForModification (ObjectTypeId, EncodedObjectName);
  1449. if (objectId) {
  1450. result = IsmSetOperationOnObjectId2 (
  1451. objectId,
  1452. OperationId,
  1453. SourceData,
  1454. DestinationData
  1455. );
  1456. }
  1457. return result;
  1458. }
  1459. VOID
  1460. IsmLockOperation (
  1461. IN MIG_OBJECTID ObjectId,
  1462. IN MIG_OPERATIONID OperationId
  1463. )
  1464. {
  1465. LockHandle (ObjectId, (KEYHANDLE) OperationId);
  1466. }
  1467. BOOL
  1468. pClearOperationOnObjectId (
  1469. IN MIG_OBJECTID ObjectId,
  1470. IN MIG_OPERATIONID OperationId,
  1471. IN BOOL QueryOnly
  1472. )
  1473. {
  1474. BOOL result = FALSE;
  1475. POPERATION_PROPERTY_LINKAGE linkage;
  1476. PBYTE freeMe;
  1477. UINT linkageSize;
  1478. __try {
  1479. //
  1480. // Is the operation or object locked?
  1481. //
  1482. if (TestLock (ObjectId, (KEYHANDLE) OperationId)) {
  1483. SetLastError (ERROR_LOCKED);
  1484. DEBUGMSG ((
  1485. DBG_WARNING,
  1486. "Can't remove operation %s on %s because of lock",
  1487. pGetOpNameForDebug (OperationId),
  1488. GetObjectNameForDebugMsg (ObjectId)
  1489. ));
  1490. __leave;
  1491. }
  1492. //
  1493. // If query only, return success
  1494. //
  1495. if (QueryOnly) {
  1496. result = TRUE;
  1497. __leave;
  1498. }
  1499. //
  1500. // Find the reference to this operation within the object's unordered blob
  1501. //
  1502. linkage = pFindOperationPropertyLinkage (
  1503. ObjectId,
  1504. OperationId,
  1505. &freeMe,
  1506. &linkageSize
  1507. );
  1508. if (linkage) {
  1509. ZeroMemory (linkage, sizeof (OPERATION_PROPERTY_LINKAGE));
  1510. if (!MemDbSetUnorderedBlobByKeyHandle (
  1511. ObjectId,
  1512. OPERATION_INDEX,
  1513. freeMe,
  1514. linkageSize
  1515. )) {
  1516. DEBUGMSG ((DBG_ERROR, "Can't reset unordered operation blob"));
  1517. __leave;
  1518. }
  1519. MemDbReleaseMemory (freeMe);
  1520. INVALID_POINTER (freeMe);
  1521. }
  1522. //
  1523. // Remove object-to-operation linkage
  1524. //
  1525. result = MemDbDeleteDoubleLinkageByKeyHandle (
  1526. ObjectId,
  1527. OperationId,
  1528. OPERATION_INDEX
  1529. );
  1530. }
  1531. __finally {
  1532. }
  1533. return result;
  1534. }
  1535. BOOL
  1536. pClearOperationGroup (
  1537. IN KEYHANDLE OperationId,
  1538. IN BOOL FirstPass,
  1539. IN ULONG_PTR Arg
  1540. )
  1541. {
  1542. return pClearOperationOnObjectId (
  1543. (MIG_OBJECTID) Arg,
  1544. (MIG_OPERATIONID) OperationId,
  1545. FirstPass
  1546. );
  1547. }
  1548. BOOL
  1549. IsmClearOperationOnObjectId (
  1550. IN MIG_OBJECTID ObjectId,
  1551. IN MIG_OPERATIONID OperationId
  1552. )
  1553. {
  1554. RECURSERETURN rc;
  1555. //
  1556. // If OperationId is a group, remove all operations in the group
  1557. //
  1558. rc = RecurseForGroupItems (
  1559. OperationId,
  1560. pClearOperationGroup,
  1561. (ULONG_PTR) ObjectId,
  1562. FALSE,
  1563. FALSE
  1564. );
  1565. if (rc == RECURSE_FAIL) {
  1566. return FALSE;
  1567. } else if (rc == RECURSE_SUCCESS) {
  1568. return TRUE;
  1569. }
  1570. MYASSERT (rc == RECURSE_NOT_NEEDED);
  1571. return pClearOperationOnObjectId (ObjectId, OperationId, FALSE);
  1572. }
  1573. BOOL
  1574. IsmClearOperationOnObject (
  1575. IN MIG_OBJECTTYPEID ObjectTypeId,
  1576. IN MIG_OBJECTSTRINGHANDLE EncodedObjectName,
  1577. IN MIG_OPERATIONID OperationId
  1578. )
  1579. {
  1580. MIG_OBJECTID objectId;
  1581. BOOL result = FALSE;
  1582. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  1583. objectId = IsmGetObjectIdFromName (ObjectTypeId, EncodedObjectName, TRUE);
  1584. if (objectId) {
  1585. result = IsmClearOperationOnObjectId (objectId, OperationId);
  1586. }
  1587. return result;
  1588. }
  1589. BOOL
  1590. pIsOperationSetOnObjectId (
  1591. IN MIG_OBJECTID ObjectId,
  1592. IN MIG_OPERATIONID OperationId
  1593. )
  1594. {
  1595. PCTSTR groupKey;
  1596. PCTSTR enumKey = NULL;
  1597. BOOL result = FALSE;
  1598. BOOL done = FALSE;
  1599. MEMDB_ENUM e;
  1600. __try {
  1601. //
  1602. // Did caller specify an item id?
  1603. //
  1604. if (!IsItemId ((KEYHANDLE) OperationId)) {
  1605. if (IsGroupId ((KEYHANDLE) OperationId)) {
  1606. groupKey = MemDbGetKeyFromHandle (OperationId, 0);
  1607. enumKey = JoinText (groupKey, TEXT(".*"));
  1608. MemDbReleaseMemory (groupKey);
  1609. //
  1610. // Enumerate all operations (skip operation subgroups)
  1611. //
  1612. if (MemDbEnumFirst (
  1613. &e,
  1614. enumKey,
  1615. ENUMFLAG_NORMAL,
  1616. ENUMLEVEL_ALLLEVELS,
  1617. ENUMLEVEL_ALLLEVELS
  1618. )) {
  1619. do {
  1620. if (IsItemId (e.KeyHandle)) {
  1621. //
  1622. // Check if at least one operation is set
  1623. //
  1624. if (IsmIsOperationSetOnObjectId (
  1625. ObjectId,
  1626. (MIG_OPERATIONID) e.KeyHandle
  1627. )) {
  1628. MemDbAbortEnum (&e);
  1629. result = TRUE;
  1630. done = TRUE;
  1631. __leave;
  1632. }
  1633. }
  1634. } while (MemDbEnumNext (&e));
  1635. MemDbAbortEnum (&e);
  1636. }
  1637. done = TRUE;
  1638. __leave;
  1639. } else {
  1640. DEBUGMSG ((
  1641. DBG_ERROR,
  1642. "IsmIsOperationSetOnObjectId: operation id is invalid"
  1643. ));
  1644. __leave;
  1645. }
  1646. }
  1647. }
  1648. __finally {
  1649. if (enumKey) {
  1650. FreeText (enumKey);
  1651. INVALID_POINTER (enumKey);
  1652. }
  1653. }
  1654. if (done) {
  1655. return result;
  1656. }
  1657. return MemDbTestDoubleLinkageByKeyHandle (
  1658. ObjectId,
  1659. OperationId,
  1660. OPERATION_INDEX
  1661. );
  1662. }
  1663. BOOL
  1664. pQueryOperationGroup (
  1665. IN KEYHANDLE OperationId,
  1666. IN BOOL FirstPass,
  1667. IN ULONG_PTR Arg
  1668. )
  1669. {
  1670. return pIsOperationSetOnObjectId (
  1671. (MIG_OBJECTID) Arg,
  1672. (MIG_OPERATIONID) OperationId
  1673. );
  1674. }
  1675. BOOL
  1676. IsmIsOperationSetOnObjectId (
  1677. IN MIG_OBJECTID ObjectId,
  1678. IN MIG_OPERATIONID OperationId
  1679. )
  1680. {
  1681. RECURSERETURN rc;
  1682. //
  1683. // If OperationId is a group, query all operations in the group
  1684. //
  1685. rc = RecurseForGroupItems (
  1686. OperationId,
  1687. pQueryOperationGroup,
  1688. (ULONG_PTR) ObjectId,
  1689. TRUE,
  1690. TRUE
  1691. );
  1692. if (rc == RECURSE_FAIL) {
  1693. return FALSE;
  1694. } else if (rc == RECURSE_SUCCESS) {
  1695. return TRUE;
  1696. }
  1697. MYASSERT (rc == RECURSE_NOT_NEEDED);
  1698. return pIsOperationSetOnObjectId (ObjectId, OperationId);
  1699. }
  1700. BOOL
  1701. IsmIsOperationSetOnObject (
  1702. IN MIG_OBJECTTYPEID ObjectTypeId,
  1703. IN MIG_OBJECTSTRINGHANDLE EncodedObjectName,
  1704. IN MIG_OPERATIONID OperationId
  1705. )
  1706. {
  1707. MIG_OBJECTID objectId;
  1708. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  1709. objectId = IsmGetObjectIdFromName (ObjectTypeId, EncodedObjectName, TRUE);
  1710. if (objectId) {
  1711. return IsmIsOperationSetOnObjectId (objectId, OperationId);
  1712. }
  1713. return FALSE;
  1714. }
  1715. BOOL
  1716. IsmGetObjectOperationDataById (
  1717. IN MIG_OBJECTID ObjectId,
  1718. IN MIG_OPERATIONID OperationId,
  1719. OUT PBYTE Buffer, OPTIONAL
  1720. IN UINT BufferSize,
  1721. OUT PUINT BufferSizeNeeded, OPTIONAL
  1722. OUT PMIG_BLOBTYPE Type, OPTIONAL
  1723. IN BOOL DestinationData
  1724. )
  1725. {
  1726. POPERATION_PROPERTY_LINKAGE linkage = NULL;
  1727. UINT dataCount;
  1728. BOOL result = FALSE;
  1729. GROWBUFFER tempBuffer = INIT_GROWBUFFER;
  1730. LONGLONG offset;
  1731. UINT size;
  1732. DWORD error = ERROR_SUCCESS;
  1733. PBYTE freeMe = NULL;
  1734. __try {
  1735. //
  1736. // Obtain the linkage between the operation and its data
  1737. //
  1738. linkage = pFindOperationPropertyLinkage (
  1739. ObjectId,
  1740. OperationId,
  1741. &freeMe,
  1742. &dataCount
  1743. );
  1744. if (!linkage) {
  1745. //
  1746. // No data
  1747. //
  1748. __leave;
  1749. }
  1750. offset = DestinationData ? linkage->DestData : linkage->SrcData;
  1751. if (!offset) {
  1752. //
  1753. // No data
  1754. //
  1755. __leave;
  1756. }
  1757. if (!GetProperty (offset, NULL, NULL, &size, Type)) {
  1758. DEBUGMSG ((DBG_ERROR, "Error getting property instance header from dat file"));
  1759. error = ERROR_INVALID_PARAMETER;
  1760. __leave;
  1761. }
  1762. if (BufferSizeNeeded) {
  1763. *BufferSizeNeeded = size;
  1764. }
  1765. //
  1766. // If a buffer was specified, check its size and fill it if possible
  1767. //
  1768. if (Buffer) {
  1769. if (BufferSize >= size) {
  1770. if (!GetProperty (offset, NULL, Buffer, NULL, NULL)) {
  1771. DEBUGMSG ((DBG_ERROR, "Error reading property data from dat file"));
  1772. //
  1773. // error code is one of the file api error codes
  1774. //
  1775. error = GetLastError();
  1776. __leave;
  1777. }
  1778. } else {
  1779. error = ERROR_MORE_DATA;
  1780. __leave;
  1781. }
  1782. }
  1783. result = TRUE;
  1784. }
  1785. __finally {
  1786. MemDbReleaseMemory (freeMe);
  1787. INVALID_POINTER (freeMe);
  1788. GbFree (&tempBuffer);
  1789. }
  1790. SetLastError (error);
  1791. return result;
  1792. }
  1793. BOOL
  1794. IsmGetObjectOperationData (
  1795. IN MIG_OBJECTTYPEID ObjectTypeId,
  1796. IN MIG_OBJECTSTRINGHANDLE EncodedObjectName,
  1797. IN MIG_OPERATIONID OperationId,
  1798. OUT PBYTE Buffer, OPTIONAL
  1799. IN UINT BufferSize,
  1800. OUT PUINT BufferSizeNeeded, OPTIONAL
  1801. OUT PMIG_BLOBTYPE Type, OPTIONAL
  1802. IN BOOL DestinationData
  1803. )
  1804. {
  1805. MIG_OBJECTID objectId;
  1806. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  1807. objectId = IsmGetObjectIdFromName (ObjectTypeId, EncodedObjectName, TRUE);
  1808. if (objectId) {
  1809. return IsmGetObjectOperationDataById (
  1810. objectId,
  1811. OperationId,
  1812. Buffer,
  1813. BufferSize,
  1814. BufferSizeNeeded,
  1815. Type,
  1816. DestinationData
  1817. );
  1818. }
  1819. return FALSE;
  1820. }
  1821. BOOL
  1822. pEnumFirstObjectOperationById (
  1823. OUT PMIG_OBJECTOPERATION_ENUM EnumPtr,
  1824. IN MIG_OBJECTID ObjectId,
  1825. IN BOOL ReturnAllPrivateOps
  1826. )
  1827. {
  1828. POBJECTOPERATION_HANDLE handle;
  1829. BOOL b = TRUE;
  1830. ZeroMemory (EnumPtr, sizeof (MIG_OBJECTOPERATION_ENUM));
  1831. EnumPtr->Handle = MemAllocZeroed (sizeof (OBJECTOPERATION_HANDLE));
  1832. handle = (POBJECTOPERATION_HANDLE) EnumPtr->Handle;
  1833. handle->ReturnAllPrivateOps = ReturnAllPrivateOps;
  1834. //
  1835. // Obtain the linkage up front
  1836. //
  1837. handle->LinkageList = MemDbGetDoubleLinkageArrayByKeyHandle (
  1838. ObjectId,
  1839. OPERATION_INDEX,
  1840. &handle->Count
  1841. );
  1842. handle->Count /= sizeof(KEYHANDLE);
  1843. if (!handle->LinkageList || !handle->Count) {
  1844. IsmAbortObjectOperationEnum (EnumPtr);
  1845. return FALSE;
  1846. }
  1847. handle->OpPropLinkList = (POPERATION_PROPERTY_LINKAGE) MemDbGetUnorderedBlobByKeyHandle (
  1848. ObjectId,
  1849. OPERATION_INDEX,
  1850. &handle->OpPropCount
  1851. );
  1852. handle->OpPropCount /= sizeof (OPERATION_PROPERTY_LINKAGE);
  1853. if (!handle->OpPropLinkList) {
  1854. handle->OpPropCount = 0;
  1855. }
  1856. //
  1857. // Continue enumeration in "next" function
  1858. //
  1859. return IsmEnumNextObjectOperation (EnumPtr);
  1860. }
  1861. BOOL
  1862. IsmEnumFirstObjectOperationById (
  1863. OUT PMIG_OBJECTOPERATION_ENUM EnumPtr,
  1864. IN MIG_OBJECTID ObjectId
  1865. )
  1866. {
  1867. return pEnumFirstObjectOperationById (EnumPtr, ObjectId, FALSE);
  1868. }
  1869. BOOL
  1870. pEnumFirstObjectOperation (
  1871. OUT PMIG_OBJECTOPERATION_ENUM EnumPtr,
  1872. IN MIG_OBJECTTYPEID ObjectTypeId,
  1873. IN MIG_OBJECTSTRINGHANDLE EncodedObjectName,
  1874. IN BOOL ReturnAllPrivateOps
  1875. )
  1876. {
  1877. MIG_OBJECTID objectId;
  1878. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  1879. objectId = IsmGetObjectIdFromName (ObjectTypeId, EncodedObjectName, TRUE);
  1880. if (objectId) {
  1881. return pEnumFirstObjectOperationById (EnumPtr, objectId, ReturnAllPrivateOps);
  1882. }
  1883. return FALSE;
  1884. }
  1885. BOOL
  1886. IsmEnumFirstObjectOperation (
  1887. OUT PMIG_OBJECTOPERATION_ENUM EnumPtr,
  1888. IN MIG_OBJECTTYPEID ObjectTypeId,
  1889. IN MIG_OBJECTSTRINGHANDLE EncodedObjectName
  1890. )
  1891. {
  1892. return pEnumFirstObjectOperation (EnumPtr, ObjectTypeId, EncodedObjectName, FALSE);
  1893. }
  1894. BOOL
  1895. IsmEnumNextObjectOperation (
  1896. IN OUT PMIG_OBJECTOPERATION_ENUM EnumPtr
  1897. )
  1898. {
  1899. POBJECTOPERATION_HANDLE handle;
  1900. BOOL b = FALSE;
  1901. BOOL mine;
  1902. UINT u;
  1903. POPERATION_PROPERTY_LINKAGE linkage;
  1904. handle = (POBJECTOPERATION_HANDLE) EnumPtr->Handle;
  1905. if (!handle) {
  1906. return FALSE;
  1907. }
  1908. do {
  1909. MYASSERT (!b);
  1910. //
  1911. // Check if we hit the end
  1912. //
  1913. if (handle->Index >= handle->Count) {
  1914. break;
  1915. }
  1916. //
  1917. // Return the next operation
  1918. //
  1919. EnumPtr->OperationId = (MIG_OPERATIONID) handle->LinkageList[handle->Index];
  1920. handle->Index++;
  1921. b = pGetOperationName (
  1922. EnumPtr->OperationId,
  1923. NULL,
  1924. 0,
  1925. &EnumPtr->Private,
  1926. &mine,
  1927. NULL,
  1928. handle->ReturnAllPrivateOps
  1929. );
  1930. //
  1931. // Continue when the operation is not owned by the caller
  1932. //
  1933. if (b && EnumPtr->Private && !mine) {
  1934. b = FALSE;
  1935. }
  1936. } while (!b);
  1937. if (!b) {
  1938. IsmAbortObjectOperationEnum (EnumPtr);
  1939. } else {
  1940. //
  1941. // Before returning match, fill enum structure with property info
  1942. //
  1943. linkage = handle->OpPropLinkList;
  1944. for (u = 0 ; u < handle->OpPropCount ; u++) {
  1945. if (linkage->OperationId == EnumPtr->OperationId) {
  1946. break;
  1947. }
  1948. linkage++;
  1949. }
  1950. if (u < handle->OpPropCount) {
  1951. //
  1952. // This operation has src property, dest property, or both.
  1953. // Get the data from property.dat and put it in the enum
  1954. // struct.
  1955. //
  1956. if (linkage->SrcData) {
  1957. EnumPtr->SourceData = &handle->SrcData;
  1958. CreatePropertyStruct (
  1959. &handle->SrcPropBuf,
  1960. &handle->SrcData,
  1961. linkage->SrcData
  1962. );
  1963. } else {
  1964. EnumPtr->SourceData = NULL;
  1965. }
  1966. if (linkage->DestData) {
  1967. EnumPtr->DestinationData = &handle->DestData;
  1968. CreatePropertyStruct (
  1969. &handle->DestPropBuf,
  1970. &handle->DestData,
  1971. linkage->DestData
  1972. );
  1973. } else {
  1974. EnumPtr->DestinationData = NULL;
  1975. }
  1976. } else {
  1977. //
  1978. // No src or dest properties
  1979. //
  1980. EnumPtr->SourceData = NULL;
  1981. EnumPtr->DestinationData = NULL;
  1982. }
  1983. }
  1984. return b;
  1985. }
  1986. VOID
  1987. IsmAbortObjectOperationEnum (
  1988. IN OUT PMIG_OBJECTOPERATION_ENUM EnumPtr
  1989. )
  1990. {
  1991. POBJECTOPERATION_HANDLE handle;
  1992. if (EnumPtr->Handle) {
  1993. handle = (POBJECTOPERATION_HANDLE) EnumPtr->Handle;
  1994. GbFree (&handle->SrcPropBuf);
  1995. GbFree (&handle->DestPropBuf);
  1996. if (handle->LinkageList) {
  1997. MemDbReleaseMemory (handle->LinkageList);
  1998. INVALID_POINTER (handle->LinkageList);
  1999. }
  2000. if (handle->OpPropLinkList) {
  2001. MemDbReleaseMemory (handle->OpPropLinkList);
  2002. INVALID_POINTER (handle->OpPropLinkList);
  2003. }
  2004. FreeAlloc (EnumPtr->Handle);
  2005. INVALID_POINTER (EnumPtr->Handle);
  2006. }
  2007. ZeroMemory (EnumPtr, sizeof (MIG_OBJECTOPERATION_ENUM));
  2008. }
  2009. BOOL
  2010. IsmEnumFirstObjectWithOperation (
  2011. OUT PMIG_OBJECTWITHOPERATION_ENUM EnumPtr,
  2012. IN MIG_OPERATIONID OperationId
  2013. )
  2014. {
  2015. POBJECTWITHOPERATION_HANDLE handle;
  2016. BOOL b = FALSE;
  2017. __try {
  2018. //
  2019. // Did caller specify an item id?
  2020. //
  2021. if (!IsItemId ((KEYHANDLE) OperationId)) {
  2022. DEBUGMSG ((
  2023. DBG_ERROR,
  2024. "IsmEnumFirstObjectWithOperation: operation id is invalid"
  2025. ));
  2026. __leave;
  2027. }
  2028. ZeroMemory (EnumPtr, sizeof (MIG_OBJECTWITHOPERATION_ENUM));
  2029. EnumPtr->Handle = MemAllocZeroed (sizeof (OBJECTWITHOPERATION_HANDLE));
  2030. handle = (POBJECTWITHOPERATION_HANDLE) EnumPtr->Handle;
  2031. handle->LinkageList = MemDbGetDoubleLinkageArrayByKeyHandle (
  2032. OperationId,
  2033. OPERATION_INDEX,
  2034. &handle->Count
  2035. );
  2036. handle->Count = handle->Count / SIZEOF(KEYHANDLE);
  2037. if (!handle->LinkageList || !handle->Count) {
  2038. IsmAbortObjectWithOperationEnum (EnumPtr);
  2039. __leave;
  2040. } else {
  2041. b = IsmEnumNextObjectWithOperation (EnumPtr);
  2042. }
  2043. }
  2044. __finally {
  2045. }
  2046. return b;
  2047. }
  2048. BOOL
  2049. IsmEnumNextObjectWithOperation (
  2050. IN OUT PMIG_OBJECTWITHOPERATION_ENUM EnumPtr
  2051. )
  2052. {
  2053. POBJECTWITHOPERATION_HANDLE handle;
  2054. PCTSTR objectPath = NULL;
  2055. BOOL b = FALSE;
  2056. PTSTR p;
  2057. __try {
  2058. handle = (POBJECTWITHOPERATION_HANDLE) EnumPtr->Handle;
  2059. if (!handle) {
  2060. __leave;
  2061. }
  2062. while (!b) {
  2063. //
  2064. // Check if enum is done
  2065. //
  2066. if (handle->Index >= handle->Count) {
  2067. break;
  2068. }
  2069. //
  2070. // Get the next object id from the linkage list
  2071. //
  2072. EnumPtr->ObjectId = handle->LinkageList[handle->Index];
  2073. handle->Index++;
  2074. if (handle->ObjectFromMemdb) {
  2075. MemDbReleaseMemory (handle->ObjectFromMemdb);
  2076. INVALID_POINTER (handle->ObjectFromMemdb);
  2077. }
  2078. handle->ObjectFromMemdb = MemDbGetKeyFromHandle ((KEYHANDLE) EnumPtr->ObjectId, 0);
  2079. if (!handle->ObjectFromMemdb) {
  2080. MYASSERT (FALSE); // this error shouldn't happen -- but don't give up
  2081. continue;
  2082. }
  2083. //
  2084. // Turn the object id into a name
  2085. //
  2086. p = _tcschr (handle->ObjectFromMemdb, TEXT('\\'));
  2087. if (p) {
  2088. b = TRUE;
  2089. EnumPtr->ObjectName = _tcsinc (p);
  2090. *p = 0;
  2091. EnumPtr->ObjectTypeId = GetObjectTypeId (handle->ObjectFromMemdb);
  2092. }
  2093. }
  2094. }
  2095. __finally {
  2096. }
  2097. if (!b) {
  2098. IsmAbortObjectWithOperationEnum (EnumPtr);
  2099. }
  2100. return b;
  2101. }
  2102. VOID
  2103. IsmAbortObjectWithOperationEnum (
  2104. IN PMIG_OBJECTWITHOPERATION_ENUM EnumPtr
  2105. )
  2106. {
  2107. POBJECTWITHOPERATION_HANDLE handle;
  2108. if (EnumPtr->Handle) {
  2109. handle = (POBJECTWITHOPERATION_HANDLE) EnumPtr->Handle;
  2110. if (handle->ObjectFromMemdb) {
  2111. MemDbReleaseMemory (handle->ObjectFromMemdb);
  2112. INVALID_POINTER (handle->ObjectFromMemdb);
  2113. }
  2114. if (handle->LinkageList) {
  2115. MemDbReleaseMemory (handle->LinkageList);
  2116. INVALID_POINTER (handle->LinkageList);
  2117. }
  2118. FreeAlloc (EnumPtr->Handle);
  2119. INVALID_POINTER (EnumPtr->Handle);
  2120. }
  2121. ZeroMemory (EnumPtr, sizeof (MIG_OBJECTWITHOPERATION_ENUM));
  2122. }
  2123. MIG_OBJECTSTRINGHANDLE
  2124. TrackedIsmGetLongName (
  2125. IN MIG_OBJECTTYPEID ObjectTypeId,
  2126. IN MIG_OBJECTSTRINGHANDLE ObjectName
  2127. TRACKING_DEF
  2128. )
  2129. {
  2130. GROWBUFFER growBuf = INIT_GROWBUFFER;
  2131. UINT resultType = FILENAME_UNDECIDED;
  2132. BOOL hadLeaf = FALSE;
  2133. PCTSTR node = NULL;
  2134. PCTSTR leaf = NULL;
  2135. PTSTR nativeName = NULL;
  2136. PTSTR nativeNamePtr;
  2137. PTSTR beginSegPtr;
  2138. PTSTR endSegPtr;
  2139. PCTSTR lastSeg;
  2140. UINT savedEnd;
  2141. UINT beginBuffIdx;
  2142. TCHAR savedChar;
  2143. KEYHANDLE kh1, kh2;
  2144. DWORD value;
  2145. MIG_OBJECTSTRINGHANDLE result = NULL;
  2146. TRACK_ENTER();
  2147. if ((ObjectTypeId & (~PLATFORM_MASK)) == MIG_FILE_TYPE) {
  2148. //
  2149. // fire up the short-long algorithm
  2150. //
  2151. if (IsmCreateObjectStringsFromHandle (ObjectName, &node, &leaf)) {
  2152. MYASSERT (node);
  2153. if (leaf) {
  2154. nativeName = DuplicatePathString (S_SHORTLONG_TREE, SizeOfString (node) + SizeOfString (leaf));
  2155. hadLeaf = TRUE;
  2156. } else {
  2157. nativeName = DuplicatePathString (S_SHORTLONG_TREE, SizeOfString (node));
  2158. hadLeaf = FALSE;
  2159. }
  2160. nativeNamePtr = AppendWack (nativeName);
  2161. StringCopy (nativeNamePtr, node);
  2162. if (leaf) {
  2163. StringCopy (AppendWack (nativeNamePtr), leaf);
  2164. }
  2165. GbAppendString (&growBuf, S_SHORTLONG_TREE);
  2166. GbAppendString (&growBuf, TEXT("\\"));
  2167. beginBuffIdx = growBuf.End - (1 * sizeof (TCHAR));
  2168. beginSegPtr = GetFirstSeg (nativeNamePtr);
  2169. if (beginSegPtr) {
  2170. beginSegPtr = _tcsinc (beginSegPtr);
  2171. GbAppendStringAB (&growBuf, nativeNamePtr, beginSegPtr);
  2172. while (beginSegPtr) {
  2173. endSegPtr = _tcschr (beginSegPtr, TEXT('\\'));
  2174. if (!endSegPtr) {
  2175. endSegPtr = GetEndOfString (beginSegPtr);
  2176. MYASSERT (endSegPtr);
  2177. }
  2178. savedChar = *endSegPtr;
  2179. *endSegPtr = 0;
  2180. savedEnd = growBuf.End - (1 * sizeof (TCHAR));
  2181. GbAppendStringAB (&growBuf, beginSegPtr, endSegPtr);
  2182. kh1 = MemDbGetHandleFromKey ((PCTSTR) growBuf.Buf);
  2183. if (kh1) {
  2184. MemDbGetValueByHandle (kh1, &value);
  2185. if (value == FILENAME_LONG) {
  2186. resultType = FILENAME_LONG;
  2187. } else {
  2188. if (resultType != FILENAME_LONG) {
  2189. resultType = FILENAME_SHORT;
  2190. }
  2191. kh2 = MemDbGetDoubleLinkageByKeyHandle (kh1, 0, 0);
  2192. MYASSERT (kh2);
  2193. if (kh2) {
  2194. growBuf.End = savedEnd;
  2195. lastSeg = MemDbGetKeyFromHandle (kh2, MEMDB_LAST_LEVEL);
  2196. GbAppendString (&growBuf, lastSeg);
  2197. MemDbReleaseMemory (lastSeg);
  2198. }
  2199. }
  2200. }
  2201. *endSegPtr = savedChar;
  2202. if (savedChar) {
  2203. beginSegPtr = _tcsinc (endSegPtr);
  2204. GbAppendStringAB (&growBuf, endSegPtr, beginSegPtr);
  2205. } else {
  2206. beginSegPtr = NULL;
  2207. }
  2208. }
  2209. } else {
  2210. GbAppendString (&growBuf, nativeNamePtr);
  2211. }
  2212. FreePathString (nativeName);
  2213. if (node) {
  2214. IsmDestroyObjectString (node);
  2215. }
  2216. if (leaf) {
  2217. IsmDestroyObjectString (leaf);
  2218. }
  2219. if (hadLeaf) {
  2220. beginSegPtr = _tcsrchr ((PTSTR) growBuf.Buf, TEXT('\\'));
  2221. endSegPtr = _tcsinc (beginSegPtr);
  2222. *beginSegPtr = 0;
  2223. } else {
  2224. endSegPtr = NULL;
  2225. }
  2226. result = IsmCreateObjectHandle ((PTSTR) (growBuf.Buf + beginBuffIdx), endSegPtr);
  2227. }
  2228. GbFree (&growBuf);
  2229. }
  2230. TRACK_LEAVE();
  2231. return result;
  2232. }
  2233. MIG_OBJECTSTRINGHANDLE
  2234. IsmFilterObject (
  2235. IN MIG_OBJECTTYPEID ObjectTypeId,
  2236. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  2237. OUT MIG_OBJECTTYPEID *NewObjectTypeId, OPTIONAL
  2238. OUT PBOOL ObjectDeleted, OPTIONAL
  2239. OUT PBOOL ObjectReplaced OPTIONAL
  2240. )
  2241. {
  2242. MIG_OBJECTSTRINGHANDLE objectName = ObjectName;
  2243. ENCODEDSTRHANDLE result = NULL;
  2244. MIG_FILTEROUTPUT filterOutput;
  2245. GROWBUFFER growBuf = INIT_GROWBUFFER;
  2246. UINT resultType = FILENAME_UNDECIDED;
  2247. BOOL hadLeaf = FALSE;
  2248. PCTSTR node = NULL;
  2249. PCTSTR leaf = NULL;
  2250. PTSTR nativeName = NULL;
  2251. PTSTR nativeNamePtr;
  2252. PTSTR beginSegPtr;
  2253. PTSTR endSegPtr;
  2254. PCTSTR lastSeg;
  2255. UINT savedEnd;
  2256. UINT beginBuffIdx;
  2257. TCHAR savedChar;
  2258. KEYHANDLE kh1, kh2;
  2259. DWORD value;
  2260. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  2261. __try {
  2262. if ((ObjectTypeId & (~PLATFORM_MASK)) == MIG_FILE_TYPE) {
  2263. //
  2264. // fire up the short-long algorithm
  2265. //
  2266. if (IsmCreateObjectStringsFromHandle (ObjectName, &node, &leaf)) {
  2267. if (node) {
  2268. if (leaf) {
  2269. nativeName = DuplicatePathString (S_SHORTLONG_TREE, SizeOfString (node) + SizeOfString (leaf));
  2270. hadLeaf = TRUE;
  2271. } else {
  2272. nativeName = DuplicatePathString (S_SHORTLONG_TREE, SizeOfString (node));
  2273. hadLeaf = FALSE;
  2274. }
  2275. nativeNamePtr = AppendWack (nativeName);
  2276. StringCopy (nativeNamePtr, node);
  2277. if (leaf) {
  2278. StringCopy (AppendWack (nativeNamePtr), leaf);
  2279. }
  2280. GbAppendString (&growBuf, S_SHORTLONG_TREE);
  2281. GbAppendString (&growBuf, TEXT("\\"));
  2282. beginBuffIdx = growBuf.End - (1 * sizeof (TCHAR));
  2283. beginSegPtr = GetFirstSeg (nativeNamePtr);
  2284. if (beginSegPtr) {
  2285. beginSegPtr = _tcsinc (beginSegPtr);
  2286. GbAppendStringAB (&growBuf, nativeNamePtr, beginSegPtr);
  2287. while (beginSegPtr) {
  2288. endSegPtr = _tcschr (beginSegPtr, TEXT('\\'));
  2289. if (!endSegPtr) {
  2290. endSegPtr = GetEndOfString (beginSegPtr);
  2291. MYASSERT (endSegPtr);
  2292. }
  2293. savedChar = *endSegPtr;
  2294. *endSegPtr = 0;
  2295. savedEnd = growBuf.End - (1 * sizeof (TCHAR));
  2296. GbAppendStringAB (&growBuf, beginSegPtr, endSegPtr);
  2297. kh1 = MemDbGetHandleFromKey ((PCTSTR) growBuf.Buf);
  2298. if (kh1) {
  2299. MemDbGetValueByHandle (kh1, &value);
  2300. if (value == FILENAME_LONG) {
  2301. resultType = FILENAME_LONG;
  2302. } else {
  2303. if (resultType != FILENAME_LONG) {
  2304. resultType = FILENAME_SHORT;
  2305. }
  2306. kh2 = MemDbGetDoubleLinkageByKeyHandle (kh1, 0, 0);
  2307. MYASSERT (kh2);
  2308. if (kh2) {
  2309. growBuf.End = savedEnd;
  2310. lastSeg = MemDbGetKeyFromHandle (kh2, MEMDB_LAST_LEVEL);
  2311. GbAppendString (&growBuf, lastSeg);
  2312. MemDbReleaseMemory (lastSeg);
  2313. }
  2314. }
  2315. }
  2316. *endSegPtr = savedChar;
  2317. if (savedChar) {
  2318. beginSegPtr = _tcsinc (endSegPtr);
  2319. GbAppendStringAB (&growBuf, endSegPtr, beginSegPtr);
  2320. } else {
  2321. beginSegPtr = NULL;
  2322. }
  2323. }
  2324. } else {
  2325. GbAppendString (&growBuf, nativeNamePtr);
  2326. }
  2327. FreePathString (nativeName);
  2328. if (node) {
  2329. IsmDestroyObjectString (node);
  2330. }
  2331. if (leaf) {
  2332. IsmDestroyObjectString (leaf);
  2333. }
  2334. if (hadLeaf) {
  2335. beginSegPtr = _tcsrchr ((PTSTR) growBuf.Buf, TEXT('\\'));
  2336. endSegPtr = _tcsinc (beginSegPtr);
  2337. *beginSegPtr = 0;
  2338. } else {
  2339. endSegPtr = NULL;
  2340. }
  2341. objectName = IsmCreateObjectHandle ((PTSTR) (growBuf.Buf + beginBuffIdx), endSegPtr);
  2342. }
  2343. }
  2344. }
  2345. if (!ApplyOperationsOnObject (
  2346. ObjectTypeId,
  2347. objectName,
  2348. FALSE,
  2349. !ShouldObjectBeRestored (
  2350. ObjectTypeId,
  2351. IsmGetObjectIdFromName (ObjectTypeId, objectName, TRUE),
  2352. objectName
  2353. ),
  2354. OP_ALL_PRIORITY,
  2355. NULL,
  2356. &filterOutput,
  2357. NULL
  2358. )) {
  2359. __leave;
  2360. }
  2361. if (ObjectDeleted) {
  2362. *ObjectDeleted = filterOutput.Deleted;
  2363. }
  2364. if (ObjectReplaced) {
  2365. *ObjectReplaced = filterOutput.Replaced;
  2366. }
  2367. if (NewObjectTypeId) {
  2368. *NewObjectTypeId = filterOutput.NewObject.ObjectTypeId;
  2369. }
  2370. if (filterOutput.NewObject.ObjectName == objectName) {
  2371. __leave;
  2372. }
  2373. if (resultType == FILENAME_SHORT) {
  2374. // NTRAID#NTBUG9-153258-2000/08/01-jimschm Create dummy file (if does not exist) to reserve and get the short file name
  2375. }
  2376. result = filterOutput.NewObject.ObjectName;
  2377. }
  2378. __finally {
  2379. if (objectName != ObjectName) {
  2380. //
  2381. // free the object name allocated by the short-long algorithm
  2382. //
  2383. IsmDestroyObjectHandle (objectName);
  2384. }
  2385. }
  2386. GbFree (&growBuf);
  2387. return result;
  2388. }
  2389. VOID
  2390. pFreeMigObjectStruct (
  2391. IN PMIG_OBJECT Object,
  2392. IN PMIG_OBJECT OriginalObject, OPTIONAL
  2393. IN PMIG_OBJECT NewObject OPTIONAL
  2394. )
  2395. {
  2396. BOOL free = TRUE;
  2397. if (OriginalObject) {
  2398. if (Object->ObjectName == OriginalObject->ObjectName) {
  2399. free = FALSE;
  2400. }
  2401. }
  2402. if (NewObject) {
  2403. if (Object->ObjectName == NewObject->ObjectName) {
  2404. free = FALSE;
  2405. }
  2406. }
  2407. if (free) {
  2408. IsmDestroyObjectHandle (Object->ObjectName);
  2409. }
  2410. ZeroMemory (Object, sizeof (MIG_OBJECT));
  2411. }
  2412. VOID
  2413. pFreeMigContentStruct (
  2414. IN PMIG_CONTENT Content,
  2415. IN PCMIG_CONTENT OriginalContent, OPTIONAL
  2416. IN PCMIG_CONTENT NewContent OPTIONAL
  2417. )
  2418. {
  2419. BOOL free;
  2420. if (Content->ContentInFile) {
  2421. free = TRUE;
  2422. if (OriginalContent &&
  2423. Content->FileContent.ContentPath == OriginalContent->FileContent.ContentPath
  2424. ) {
  2425. free = FALSE;
  2426. } else if (NewContent &&
  2427. Content->FileContent.ContentPath == NewContent->FileContent.ContentPath
  2428. ) {
  2429. free = FALSE;
  2430. }
  2431. if (free) {
  2432. if (Content->FileContent.ContentPath) {
  2433. IsmReleaseMemory (Content->FileContent.ContentPath);
  2434. Content->FileContent.ContentPath = NULL;
  2435. }
  2436. }
  2437. } else {
  2438. free = TRUE;
  2439. if (OriginalContent &&
  2440. Content->MemoryContent.ContentBytes == OriginalContent->MemoryContent.ContentBytes
  2441. ) {
  2442. free = FALSE;
  2443. } else if (NewContent &&
  2444. Content->MemoryContent.ContentBytes == NewContent->MemoryContent.ContentBytes
  2445. ) {
  2446. free = FALSE;
  2447. }
  2448. if (free) {
  2449. if (Content->MemoryContent.ContentBytes) {
  2450. IsmReleaseMemory (Content->MemoryContent.ContentBytes);
  2451. Content->MemoryContent.ContentBytes = NULL;
  2452. }
  2453. }
  2454. }
  2455. free = TRUE;
  2456. if (OriginalContent &&
  2457. OriginalContent->Details.DetailsData == Content->Details.DetailsData
  2458. ) {
  2459. free = FALSE;
  2460. }
  2461. if (NewContent &&
  2462. NewContent->Details.DetailsData == Content->Details.DetailsData
  2463. ) {
  2464. free = FALSE;
  2465. }
  2466. if (free && Content->Details.DetailsData) {
  2467. IsmReleaseMemory (Content->Details.DetailsData);
  2468. Content->Details.DetailsData = NULL;;
  2469. }
  2470. ZeroMemory (Content, sizeof (MIG_CONTENT));
  2471. }
  2472. BOOL
  2473. ApplyOperationsOnObject (
  2474. IN MIG_OBJECTTYPEID ObjectTypeId,
  2475. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  2476. IN BOOL TreeFiltersOnly,
  2477. IN BOOL NoRestoreObject,
  2478. IN DWORD OperationPriority,
  2479. IN PMIG_CONTENT ApplyInput, OPTIONAL
  2480. OUT PMIG_FILTEROUTPUT FilterOutput,
  2481. OUT PMIG_CONTENT ApplyOutput OPTIONAL
  2482. )
  2483. {
  2484. MIG_FILTERINPUT filterInput;
  2485. MIG_OBJECTOPERATION_ENUM Enum;
  2486. BOOL result = FALSE;
  2487. MIG_CONTENT currentContent;
  2488. OPERATION_DATA operationData;
  2489. POPMFILTERCALLBACK filterCallback;
  2490. POPMAPPLYCALLBACK applyCallback;
  2491. PGLOBALFILTERINDEX globalFilterIndex;
  2492. PGLOBALFILTER globalFilter;
  2493. PGLOBALEDIT globalEdit;
  2494. BOOL needObjectId;
  2495. MIG_OBJECTID objectId = 0;
  2496. if (NoRestoreObject) {
  2497. MYASSERT (!ApplyInput);
  2498. MYASSERT (!ApplyOutput);
  2499. if (ApplyInput || ApplyOutput) {
  2500. return FALSE;
  2501. }
  2502. }
  2503. __try {
  2504. //
  2505. // Save original values
  2506. //
  2507. ZeroMemory (&filterInput, sizeof (filterInput));
  2508. filterInput.OriginalObject.ObjectTypeId = ObjectTypeId;
  2509. filterInput.OriginalObject.ObjectName = ObjectName;
  2510. filterInput.CurrentObject = filterInput.OriginalObject;
  2511. if ((ObjectTypeId & PLATFORM_MASK) == PLATFORM_SOURCE) {
  2512. filterInput.Deleted = NoRestoreObject;
  2513. }
  2514. filterInput.FilterTreeChangesOnly = TreeFiltersOnly;
  2515. ZeroMemory (&currentContent, sizeof (MIG_CONTENT));
  2516. if (ApplyInput) {
  2517. CopyMemory (&currentContent, ApplyInput, sizeof (MIG_CONTENT));
  2518. }
  2519. //
  2520. // Set defaults for output
  2521. //
  2522. FilterOutput->NewObject = filterInput.CurrentObject;
  2523. FilterOutput->Deleted = filterInput.Deleted;
  2524. FilterOutput->Replaced = filterInput.Replaced;
  2525. if (ApplyInput) {
  2526. MYASSERT (ApplyOutput);
  2527. CopyMemory (ApplyOutput, ApplyInput, sizeof (MIG_CONTENT));
  2528. }
  2529. //
  2530. // Find type in filter index and process first pass global filters and editors
  2531. //
  2532. globalFilterIndex = pGetGlobalIndex (ObjectTypeId, FALSE);
  2533. if (globalFilterIndex) {
  2534. //
  2535. // Get object ID
  2536. //
  2537. needObjectId = FALSE;
  2538. if (OperationPriority & OP_HIGH_PRIORITY) {
  2539. if (globalFilterIndex->FilterFirstHeadHp ||
  2540. globalFilterIndex->FilterLastHeadHp ||
  2541. globalFilterIndex->EditFirstHeadHp ||
  2542. globalFilterIndex->EditLastHeadHp
  2543. ) {
  2544. needObjectId = TRUE;
  2545. }
  2546. }
  2547. if (OperationPriority & OP_LOW_PRIORITY) {
  2548. if (globalFilterIndex->FilterFirstHead ||
  2549. globalFilterIndex->FilterLastHead ||
  2550. globalFilterIndex->EditFirstHead ||
  2551. globalFilterIndex->EditLastHead
  2552. ) {
  2553. needObjectId = TRUE;
  2554. }
  2555. }
  2556. if (needObjectId) {
  2557. objectId = IsmGetObjectIdFromName (ObjectTypeId, ObjectName, TRUE);
  2558. }
  2559. //
  2560. // Perform first pass global filter
  2561. //
  2562. if (OperationPriority & OP_HIGH_PRIORITY) {
  2563. globalFilter = globalFilterIndex->FilterFirstHeadHp;
  2564. while (globalFilter) {
  2565. if ((!globalFilter->Platform || (globalFilter->Platform & ObjectTypeId)) &&
  2566. (!TreeFiltersOnly || globalFilter->TreeFilter) &&
  2567. (!NoRestoreObject || globalFilter->NoRestoreFilter)
  2568. ) {
  2569. if (!objectId ||
  2570. !pIsOperationProhibitedOnObject (globalFilter->OperationId, objectId, TRUE)
  2571. ) {
  2572. if (!globalFilter->Callback (
  2573. &filterInput,
  2574. FilterOutput,
  2575. NoRestoreObject,
  2576. NULL,
  2577. NULL
  2578. )) {
  2579. DEBUGMSG ((
  2580. DBG_ERROR,
  2581. "ApplyOperationsOnObject: first pass global filter failed for %s",
  2582. pGetOpNameForDebug (globalFilter->OperationId)
  2583. ));
  2584. __leave;
  2585. }
  2586. //
  2587. // Free input allocations if they are different from
  2588. // both the original and new pointer values
  2589. //
  2590. pFreeMigObjectStruct (
  2591. &filterInput.CurrentObject,
  2592. &filterInput.OriginalObject,
  2593. &FilterOutput->NewObject
  2594. );
  2595. //
  2596. // Filter outputs now become the inputs
  2597. //
  2598. filterInput.CurrentObject = FilterOutput->NewObject;
  2599. filterInput.Deleted = FilterOutput->Deleted;
  2600. filterInput.Replaced = FilterOutput->Replaced;
  2601. }
  2602. }
  2603. globalFilter = globalFilter->Next;
  2604. }
  2605. }
  2606. if (OperationPriority & OP_LOW_PRIORITY) {
  2607. globalFilter = globalFilterIndex->FilterFirstHead;
  2608. while (globalFilter) {
  2609. if ((!globalFilter->Platform || (globalFilter->Platform & ObjectTypeId)) &&
  2610. (!TreeFiltersOnly || globalFilter->TreeFilter) &&
  2611. (!NoRestoreObject || globalFilter->NoRestoreFilter)
  2612. ) {
  2613. if (!objectId ||
  2614. !pIsOperationProhibitedOnObject (globalFilter->OperationId, objectId, TRUE)
  2615. ) {
  2616. if (!globalFilter->Callback (
  2617. &filterInput,
  2618. FilterOutput,
  2619. NoRestoreObject,
  2620. NULL,
  2621. NULL
  2622. )) {
  2623. DEBUGMSG ((
  2624. DBG_ERROR,
  2625. "ApplyOperationsOnObject: first pass global filter failed for %s",
  2626. pGetOpNameForDebug (globalFilter->OperationId)
  2627. ));
  2628. __leave;
  2629. }
  2630. //
  2631. // Free input allocations if they are different from
  2632. // both the original and new pointer values
  2633. //
  2634. pFreeMigObjectStruct (
  2635. &filterInput.CurrentObject,
  2636. &filterInput.OriginalObject,
  2637. &FilterOutput->NewObject
  2638. );
  2639. //
  2640. // Filter outputs now become the inputs
  2641. //
  2642. filterInput.CurrentObject = FilterOutput->NewObject;
  2643. filterInput.Deleted = FilterOutput->Deleted;
  2644. filterInput.Replaced = FilterOutput->Replaced;
  2645. }
  2646. }
  2647. globalFilter = globalFilter->Next;
  2648. }
  2649. }
  2650. //
  2651. // Perform first pass apply
  2652. //
  2653. if (ApplyInput) {
  2654. if (OperationPriority & OP_HIGH_PRIORITY) {
  2655. globalEdit = globalFilterIndex->EditFirstHeadHp;
  2656. while (globalEdit) {
  2657. if (!globalEdit->Platform || (globalEdit->Platform & ObjectTypeId)) {
  2658. if (!objectId ||
  2659. !pIsOperationProhibitedOnObject (globalEdit->OperationId, objectId, TRUE)
  2660. ) {
  2661. //
  2662. // Call the apply function associated with this operation
  2663. //
  2664. if (!globalEdit->Callback (
  2665. ObjectTypeId,
  2666. ObjectName,
  2667. ApplyInput,
  2668. &currentContent,
  2669. ApplyOutput,
  2670. NULL,
  2671. NULL
  2672. )) {
  2673. DEBUGMSG ((
  2674. DBG_ERROR,
  2675. "ApplyOperationsOnObject: first pass global callback failed for %s",
  2676. pGetOpNameForDebug (globalEdit->OperationId)
  2677. ));
  2678. __leave;
  2679. }
  2680. //
  2681. // Free input allocations if they are different from both
  2682. // the original and new pointer values
  2683. //
  2684. pFreeMigContentStruct (&currentContent, ApplyInput, ApplyOutput);
  2685. //
  2686. // Apply outputs now become the current content
  2687. //
  2688. CopyMemory (&currentContent, ApplyOutput, sizeof (MIG_CONTENT));
  2689. }
  2690. }
  2691. globalEdit = globalEdit->Next;
  2692. }
  2693. }
  2694. if (OperationPriority & OP_LOW_PRIORITY) {
  2695. globalEdit = globalFilterIndex->EditFirstHead;
  2696. while (globalEdit) {
  2697. if (!globalEdit->Platform || (globalEdit->Platform & ObjectTypeId)) {
  2698. if (!objectId ||
  2699. !pIsOperationProhibitedOnObject (globalEdit->OperationId, objectId, TRUE)
  2700. ) {
  2701. //
  2702. // Call the apply function associated with this operation
  2703. //
  2704. if (!globalEdit->Callback (
  2705. ObjectTypeId,
  2706. ObjectName,
  2707. ApplyInput,
  2708. &currentContent,
  2709. ApplyOutput,
  2710. NULL,
  2711. NULL
  2712. )) {
  2713. DEBUGMSG ((
  2714. DBG_ERROR,
  2715. "ApplyOperationsOnObject: first pass global callback failed for %s",
  2716. pGetOpNameForDebug (globalEdit->OperationId)
  2717. ));
  2718. __leave;
  2719. }
  2720. //
  2721. // Free input allocations if they are different from both
  2722. // the original and new pointer values
  2723. //
  2724. pFreeMigContentStruct (&currentContent, ApplyInput, ApplyOutput);
  2725. //
  2726. // Apply outputs now become the current content
  2727. //
  2728. CopyMemory (&currentContent, ApplyOutput, sizeof (MIG_CONTENT));
  2729. }
  2730. }
  2731. globalEdit = globalEdit->Next;
  2732. }
  2733. }
  2734. }
  2735. }
  2736. //
  2737. // Enumerate all operations on the object, then call filter and apply
  2738. // callbacks.
  2739. //
  2740. if (pEnumFirstObjectOperation (&Enum, ObjectTypeId, ObjectName, TRUE)) {
  2741. do {
  2742. if (pGetOperationData (Enum.OperationId, &operationData)) {
  2743. if (OperationPriority & OP_HIGH_PRIORITY) {
  2744. //
  2745. // Screen the non-tree filters if necessary
  2746. //
  2747. if ((!TreeFiltersOnly || operationData.TreeFilterHp) &&
  2748. (!NoRestoreObject || operationData.NoRestoreFilterHp)
  2749. ) {
  2750. //
  2751. // NOTE: This loop calls the filter for an operation, then the
  2752. // apply for the operation, then the filter for the next
  2753. // operation, the apply for the next operation, and so on.
  2754. //
  2755. // A content-edit of something that points to itself
  2756. // might not be processed correctly. That is, its
  2757. // own path is not completely filtered, and
  2758. // therefore it might not be correct. To fix this,
  2759. // all filters should run first, and then all apply
  2760. // callbacks should run. But because this would
  2761. // cause double-enumeration of operations (costing
  2762. // operation data retrieval), the loop is left
  2763. // as-is. Also, the theoretical case is rare enough
  2764. // that we aren't concerned, and there is a
  2765. // workaround via the operation priorities.
  2766. //
  2767. //
  2768. // Call the filter associated with this operation
  2769. //
  2770. filterCallback = operationData.FilterCallbackHp;
  2771. if (filterCallback) {
  2772. if (!filterCallback (
  2773. &filterInput,
  2774. FilterOutput,
  2775. NoRestoreObject,
  2776. Enum.SourceData,
  2777. Enum.DestinationData
  2778. )) {
  2779. DEBUGMSG ((
  2780. DBG_ERROR,
  2781. "ApplyOperationsOnObject: filter failed for %s",
  2782. pGetOpNameForDebug (Enum.OperationId)
  2783. ));
  2784. __leave;
  2785. }
  2786. //
  2787. // Free input allocations if they are different from
  2788. // both the original and new pointer values
  2789. //
  2790. pFreeMigObjectStruct (
  2791. &filterInput.CurrentObject,
  2792. &filterInput.OriginalObject,
  2793. &FilterOutput->NewObject
  2794. );
  2795. //
  2796. // Filter outputs now become the inputs
  2797. //
  2798. filterInput.CurrentObject = FilterOutput->NewObject;
  2799. filterInput.Deleted = FilterOutput->Deleted;
  2800. filterInput.Replaced = FilterOutput->Replaced;
  2801. }
  2802. //
  2803. // Call the apply function associated with this operation
  2804. //
  2805. if (ApplyInput) {
  2806. applyCallback = operationData.ApplyCallbackHp;
  2807. } else {
  2808. applyCallback = NULL;
  2809. }
  2810. if (applyCallback) {
  2811. if (!applyCallback (
  2812. ObjectTypeId,
  2813. ObjectName,
  2814. ApplyInput,
  2815. &currentContent,
  2816. ApplyOutput,
  2817. Enum.SourceData,
  2818. Enum.DestinationData
  2819. )) {
  2820. DEBUGMSG ((
  2821. DBG_ERROR,
  2822. "ApplyOperationsOnObject: Operation apply callback failed for %s",
  2823. pGetOpNameForDebug (Enum.OperationId)
  2824. ));
  2825. IsmAbortObjectOperationEnum (&Enum);
  2826. __leave;
  2827. }
  2828. //
  2829. // Free input allocations if they are different from both
  2830. // the original and new pointer values
  2831. //
  2832. pFreeMigContentStruct (&currentContent, ApplyInput, ApplyOutput);
  2833. //
  2834. // Apply outputs now become the current content
  2835. //
  2836. CopyMemory (&currentContent, ApplyOutput, sizeof (MIG_CONTENT));
  2837. }
  2838. }
  2839. }
  2840. if (OperationPriority & OP_LOW_PRIORITY) {
  2841. //
  2842. // Screen the non-tree filters if necessary
  2843. //
  2844. if ((!TreeFiltersOnly || operationData.TreeFilter) &&
  2845. (!NoRestoreObject || operationData.NoRestoreFilter)
  2846. ) {
  2847. //
  2848. // NOTE: This loop calls the filter for an operation, then the
  2849. // apply for the operation, then the filter for the next
  2850. // operation, the apply for the next operation, and so on.
  2851. //
  2852. // A content-edit of something that points to itself
  2853. // might not be processed correctly. That is, its
  2854. // own path is not completely filtered, and
  2855. // therefore it might not be correct. To fix this,
  2856. // all filters should run first, and then all apply
  2857. // callbacks should run. But because this would
  2858. // cause double-enumeration of operations (costing
  2859. // operation data retrieval), the loop is left
  2860. // as-is. Also, the theoretical case is rare enough
  2861. // that we aren't concerned, and there is a
  2862. // workaround via the operation priorities.
  2863. //
  2864. //
  2865. // Call the filter associated with this operation
  2866. //
  2867. filterCallback = operationData.FilterCallback;
  2868. if (filterCallback) {
  2869. if (!filterCallback (
  2870. &filterInput,
  2871. FilterOutput,
  2872. NoRestoreObject,
  2873. Enum.SourceData,
  2874. Enum.DestinationData
  2875. )) {
  2876. DEBUGMSG ((
  2877. DBG_ERROR,
  2878. "ApplyOperationsOnObject: filter failed for %s",
  2879. pGetOpNameForDebug (Enum.OperationId)
  2880. ));
  2881. __leave;
  2882. }
  2883. //
  2884. // Free input allocations if they are different from
  2885. // both the original and new pointer values
  2886. //
  2887. pFreeMigObjectStruct (
  2888. &filterInput.CurrentObject,
  2889. &filterInput.OriginalObject,
  2890. &FilterOutput->NewObject
  2891. );
  2892. //
  2893. // Filter outputs now become the inputs
  2894. //
  2895. filterInput.CurrentObject = FilterOutput->NewObject;
  2896. filterInput.Deleted = FilterOutput->Deleted;
  2897. filterInput.Replaced = FilterOutput->Replaced;
  2898. }
  2899. //
  2900. // Call the apply function associated with this operation
  2901. //
  2902. if (ApplyInput) {
  2903. applyCallback = operationData.ApplyCallback;
  2904. } else {
  2905. applyCallback = NULL;
  2906. }
  2907. if (applyCallback) {
  2908. if (!applyCallback (
  2909. ObjectTypeId,
  2910. ObjectName,
  2911. ApplyInput,
  2912. &currentContent,
  2913. ApplyOutput,
  2914. Enum.SourceData,
  2915. Enum.DestinationData
  2916. )) {
  2917. DEBUGMSG ((
  2918. DBG_ERROR,
  2919. "ApplyOperationsOnObject: Operation apply callback failed for %s",
  2920. pGetOpNameForDebug (Enum.OperationId)
  2921. ));
  2922. IsmAbortObjectOperationEnum (&Enum);
  2923. __leave;
  2924. }
  2925. //
  2926. // Free input allocations if they are different from both
  2927. // the original and new pointer values
  2928. //
  2929. pFreeMigContentStruct (&currentContent, ApplyInput, ApplyOutput);
  2930. //
  2931. // Apply outputs now become the current content
  2932. //
  2933. CopyMemory (&currentContent, ApplyOutput, sizeof (MIG_CONTENT));
  2934. }
  2935. }
  2936. }
  2937. }
  2938. } while (IsmEnumNextObjectOperation (&Enum));
  2939. }
  2940. //
  2941. // Execute last pass global filters and content editors
  2942. //
  2943. if (globalFilterIndex) {
  2944. //
  2945. // Preform last pass global filter
  2946. //
  2947. if (OperationPriority & OP_HIGH_PRIORITY) {
  2948. globalFilter = globalFilterIndex->FilterLastHeadHp;
  2949. while (globalFilter) {
  2950. if ((!globalFilter->Platform || (globalFilter->Platform & ObjectTypeId)) &&
  2951. (!TreeFiltersOnly || globalFilter->TreeFilter) &&
  2952. (!NoRestoreObject || globalFilter->NoRestoreFilter)
  2953. ) {
  2954. if (!objectId ||
  2955. !pIsOperationProhibitedOnObject (globalFilter->OperationId, objectId, TRUE)
  2956. ) {
  2957. if (!globalFilter->Callback (
  2958. &filterInput,
  2959. FilterOutput,
  2960. NoRestoreObject,
  2961. NULL,
  2962. NULL
  2963. )) {
  2964. DEBUGMSG ((
  2965. DBG_ERROR,
  2966. "ApplyOperationsOnObject: last pass global filter failed for %s",
  2967. pGetOpNameForDebug (globalFilter->OperationId)
  2968. ));
  2969. __leave;
  2970. }
  2971. //
  2972. // Free input allocations if they are different from
  2973. // both the original and new pointer values
  2974. //
  2975. pFreeMigObjectStruct (
  2976. &filterInput.CurrentObject,
  2977. &filterInput.OriginalObject,
  2978. &FilterOutput->NewObject
  2979. );
  2980. //
  2981. // Filter outputs now become the inputs
  2982. //
  2983. filterInput.CurrentObject = FilterOutput->NewObject;
  2984. filterInput.Deleted = FilterOutput->Deleted;
  2985. filterInput.Replaced = FilterOutput->Replaced;
  2986. }
  2987. }
  2988. globalFilter = globalFilter->Next;
  2989. }
  2990. }
  2991. if (OperationPriority & OP_LOW_PRIORITY) {
  2992. globalFilter = globalFilterIndex->FilterLastHead;
  2993. while (globalFilter) {
  2994. if ((!globalFilter->Platform || (globalFilter->Platform & ObjectTypeId)) &&
  2995. (!TreeFiltersOnly || globalFilter->TreeFilter) &&
  2996. (!NoRestoreObject || globalFilter->NoRestoreFilter)
  2997. ) {
  2998. if (!objectId ||
  2999. !pIsOperationProhibitedOnObject (globalFilter->OperationId, objectId, TRUE)
  3000. ) {
  3001. if (!globalFilter->Callback (
  3002. &filterInput,
  3003. FilterOutput,
  3004. NoRestoreObject,
  3005. NULL,
  3006. NULL
  3007. )) {
  3008. DEBUGMSG ((
  3009. DBG_ERROR,
  3010. "ApplyOperationsOnObject: last pass global filter failed for %s",
  3011. pGetOpNameForDebug (globalFilter->OperationId)
  3012. ));
  3013. __leave;
  3014. }
  3015. //
  3016. // Free input allocations if they are different from
  3017. // both the original and new pointer values
  3018. //
  3019. pFreeMigObjectStruct (
  3020. &filterInput.CurrentObject,
  3021. &filterInput.OriginalObject,
  3022. &FilterOutput->NewObject
  3023. );
  3024. //
  3025. // Filter outputs now become the inputs
  3026. //
  3027. filterInput.CurrentObject = FilterOutput->NewObject;
  3028. filterInput.Deleted = FilterOutput->Deleted;
  3029. filterInput.Replaced = FilterOutput->Replaced;
  3030. }
  3031. }
  3032. globalFilter = globalFilter->Next;
  3033. }
  3034. }
  3035. if (ApplyInput) {
  3036. if (OperationPriority & OP_HIGH_PRIORITY) {
  3037. globalEdit = globalFilterIndex->EditLastHeadHp;
  3038. while (globalEdit) {
  3039. if (!globalEdit->Platform || (globalEdit->Platform & ObjectTypeId)) {
  3040. if (!objectId ||
  3041. !pIsOperationProhibitedOnObject (globalEdit->OperationId, objectId, TRUE)
  3042. ) {
  3043. //
  3044. // Call the apply function associated with this operation
  3045. //
  3046. if (!globalEdit->Callback (
  3047. ObjectTypeId,
  3048. ObjectName,
  3049. ApplyInput,
  3050. &currentContent,
  3051. ApplyOutput,
  3052. Enum.SourceData,
  3053. Enum.DestinationData
  3054. )) {
  3055. DEBUGMSG ((
  3056. DBG_ERROR,
  3057. "ApplyOperationsOnObject: last pass global callback failed for %s",
  3058. pGetOpNameForDebug (globalEdit->OperationId)
  3059. ));
  3060. __leave;
  3061. }
  3062. //
  3063. // Free input allocations if they are different from both
  3064. // the original and new pointer values
  3065. //
  3066. pFreeMigContentStruct (&currentContent, ApplyInput, ApplyOutput);
  3067. //
  3068. // Apply outputs now become the current content
  3069. //
  3070. CopyMemory (&currentContent, ApplyOutput, sizeof (MIG_CONTENT));
  3071. }
  3072. }
  3073. globalEdit = globalEdit->Next;
  3074. }
  3075. }
  3076. if (OperationPriority & OP_LOW_PRIORITY) {
  3077. globalEdit = globalFilterIndex->EditLastHead;
  3078. while (globalEdit) {
  3079. if (!globalEdit->Platform || (globalEdit->Platform & ObjectTypeId)) {
  3080. if (!objectId ||
  3081. !pIsOperationProhibitedOnObject (globalEdit->OperationId, objectId, TRUE)
  3082. ) {
  3083. //
  3084. // Call the apply function associated with this operation
  3085. //
  3086. if (!globalEdit->Callback (
  3087. ObjectTypeId,
  3088. ObjectName,
  3089. ApplyInput,
  3090. &currentContent,
  3091. ApplyOutput,
  3092. Enum.SourceData,
  3093. Enum.DestinationData
  3094. )) {
  3095. DEBUGMSG ((
  3096. DBG_ERROR,
  3097. "ApplyOperationsOnObject: last pass global callback failed for %s",
  3098. pGetOpNameForDebug (globalEdit->OperationId)
  3099. ));
  3100. __leave;
  3101. }
  3102. //
  3103. // Free input allocations if they are different from both
  3104. // the original and new pointer values
  3105. //
  3106. pFreeMigContentStruct (&currentContent, ApplyInput, ApplyOutput);
  3107. //
  3108. // Apply outputs now become the current content
  3109. //
  3110. CopyMemory (&currentContent, ApplyOutput, sizeof (MIG_CONTENT));
  3111. }
  3112. }
  3113. globalEdit = globalEdit->Next;
  3114. }
  3115. }
  3116. }
  3117. }
  3118. result = TRUE;
  3119. }
  3120. __finally {
  3121. if (!result) {
  3122. //
  3123. // Free all allocations except for the original (made by
  3124. // the caller)
  3125. //
  3126. pFreeMigObjectStruct (
  3127. &filterInput.CurrentObject,
  3128. &filterInput.OriginalObject,
  3129. &FilterOutput->NewObject
  3130. );
  3131. pFreeMigObjectStruct (
  3132. &FilterOutput->NewObject,
  3133. &filterInput.OriginalObject,
  3134. NULL
  3135. );
  3136. if (ApplyInput) {
  3137. pFreeMigContentStruct (&currentContent, ApplyInput, ApplyOutput);
  3138. pFreeMigContentStruct (ApplyOutput, ApplyInput, NULL);
  3139. }
  3140. }
  3141. }
  3142. return result;
  3143. }
  3144. VOID
  3145. FreeFilterOutput (
  3146. IN MIG_OBJECTSTRINGHANDLE OriginalString,
  3147. IN PMIG_FILTEROUTPUT FilterOutput
  3148. )
  3149. {
  3150. MIG_OBJECT object;
  3151. object.ObjectName = OriginalString;
  3152. pFreeMigObjectStruct (&FilterOutput->NewObject, &object, NULL);
  3153. }
  3154. VOID
  3155. FreeApplyOutput (
  3156. IN PCMIG_CONTENT OriginalContent,
  3157. IN PMIG_CONTENT FinalContent
  3158. )
  3159. {
  3160. pFreeMigContentStruct (FinalContent, OriginalContent, NULL);
  3161. }