Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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