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.

2223 lines
57 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. property.c
  5. Abstract:
  6. Implements the property interface of the ISM. Properties are used to
  7. associate data with objects. They are identified by name, and a single
  8. object can have multiple instances of the same property.
  9. Author:
  10. Jim Schmidt (jimschm) 01-Mar-2000
  11. Revision History:
  12. <alias> <date> <comments>
  13. --*/
  14. //
  15. // Includes
  16. //
  17. #include "pch.h"
  18. #include "ism.h"
  19. #include "ismp.h"
  20. #define DBG_PROPERTY "Property"
  21. //
  22. // Strings
  23. //
  24. #define S_PROPINST TEXT("PropInst")
  25. #define S_PROPINST_FORMAT S_PROPINST TEXT("\\%u")
  26. #define S_PROPERTYFILE TEXT("|PropertyFile") // pipe is to decorate for uniqueness
  27. //
  28. // Constants
  29. //
  30. #define PROPERTY_FILE_SIGNATURE 0xF062298F
  31. #define PROPERTY_FILE_VERSION 0x00010000
  32. //
  33. // Macros
  34. //
  35. // None
  36. //
  37. // Types
  38. //
  39. typedef enum {
  40. PROPENUM_GET_NEXT_LINKAGE,
  41. PROPENUM_GET_NEXT_INSTANCE,
  42. PROPENUM_RETURN_VALUE,
  43. PROPENUM_DONE
  44. } PROPENUM_STATE;
  45. typedef struct {
  46. MIG_PROPERTYID PropertyId;
  47. LONGLONG DatFileOffset;
  48. } PROPERTY_DATA_REFERENCE, *PPROPERTY_DATA_REFERENCE;
  49. #pragma pack(push,1)
  50. typedef struct {
  51. DWORD Size;
  52. WORD PropertyDataType;
  53. // data follows in the file
  54. } PROPERTY_ITEM_HEADER, *PPROPERTY_ITEM_HEADER;
  55. typedef struct {
  56. DWORD Signature;
  57. DWORD Version;
  58. } PROPERTY_FILE_HEADER, *PPROPERTY_FILE_HEADER;
  59. #pragma pack(pop)
  60. typedef struct {
  61. MIG_PROPERTYID FilterPropertyId;
  62. MIG_OBJECTID ObjectId;
  63. PUINT LinkageList;
  64. UINT LinkageCount;
  65. UINT LinkageEnumPosition;
  66. PPROPERTY_DATA_REFERENCE InstanceArray;
  67. UINT InstanceCount;
  68. UINT InstancePosition;
  69. PROPENUM_STATE State;
  70. } OBJECTPROPERTY_HANDLE, *POBJECTPROPERTY_HANDLE;
  71. typedef struct {
  72. MIG_PROPERTYID PropertyId;
  73. PUINT LinkageList;
  74. UINT LinkageCount;
  75. UINT LinkagePos;
  76. ENCODEDSTRHANDLE ObjectPath;
  77. } OBJECTWITHPROPERTY_HANDLE, *POBJECTWITHPROPERTY_HANDLE;
  78. typedef struct {
  79. MIG_OBJECTID ObjectId;
  80. PCMIG_BLOB Property;
  81. LONGLONG PreExistingProperty;
  82. } ADDPROPERTYARG, *PADDPROPERTYARG;
  83. //
  84. // Globals
  85. //
  86. PCTSTR g_PropertyDatName;
  87. HANDLE g_PropertyDatHandle;
  88. //
  89. // Macro expansion list
  90. //
  91. // None
  92. //
  93. // Private function prototypes
  94. //
  95. // None
  96. //
  97. // Macro expansion definition
  98. //
  99. // None
  100. //
  101. // Code
  102. //
  103. BOOL
  104. InitializeProperties (
  105. MIG_PLATFORMTYPEID Platform,
  106. BOOL VcmMode
  107. )
  108. {
  109. PROPERTY_FILE_HEADER header;
  110. TCHAR tempFile [MAX_PATH];
  111. MIG_OBJECTSTRINGHANDLE propertyObjectName;
  112. MIG_CONTENT propertyContent;
  113. //
  114. // In gather mode, create property.dat in a temp dir.
  115. // In restore mode, get property.dat from the transport, then
  116. // open it.
  117. //
  118. if (Platform == PLATFORM_SOURCE) {
  119. IsmGetTempFile (tempFile, ARRAYSIZE (tempFile));
  120. g_PropertyDatName = DuplicatePathString (tempFile, 0);
  121. g_PropertyDatHandle = BfCreateFile (g_PropertyDatName);
  122. if (g_PropertyDatHandle) {
  123. header.Signature = PROPERTY_FILE_SIGNATURE;
  124. header.Version = PROPERTY_FILE_VERSION;
  125. if (!BfWriteFile (g_PropertyDatHandle, (PBYTE) &header, sizeof (header))) {
  126. return FALSE;
  127. }
  128. propertyObjectName = IsmCreateObjectHandle (S_PROPERTYFILE, NULL);
  129. DataTypeAddObject (propertyObjectName, g_PropertyDatName, !VcmMode);
  130. IsmDestroyObjectHandle (propertyObjectName);
  131. }
  132. } else {
  133. propertyObjectName = IsmCreateObjectHandle (S_PROPERTYFILE, NULL);
  134. if (IsmAcquireObjectEx (MIG_DATA_TYPE | PLATFORM_SOURCE, propertyObjectName, &propertyContent, CONTENTTYPE_FILE, 0)) {
  135. BfGetTempFileName (tempFile, ARRAYSIZE (tempFile));
  136. g_PropertyDatName = DuplicatePathString (tempFile, 0);
  137. if (CopyFile (propertyContent.FileContent.ContentPath, g_PropertyDatName, FALSE)) {
  138. g_PropertyDatHandle = BfOpenFile (g_PropertyDatName);
  139. }
  140. IsmReleaseObject (&propertyContent);
  141. } else if (IsmAcquireObjectEx (MIG_DATA_TYPE | PLATFORM_DESTINATION, propertyObjectName, &propertyContent, CONTENTTYPE_FILE, 0)) {
  142. g_PropertyDatName = DuplicatePathString (propertyContent.FileContent.ContentPath, 0);
  143. g_PropertyDatHandle = BfOpenFile (g_PropertyDatName);
  144. IsmReleaseObject (&propertyContent);
  145. }
  146. IsmDestroyObjectHandle (propertyObjectName);
  147. }
  148. return g_PropertyDatHandle != NULL;
  149. }
  150. VOID
  151. TerminateProperties (
  152. MIG_PLATFORMTYPEID Platform
  153. )
  154. {
  155. if (g_PropertyDatHandle) {
  156. CloseHandle (g_PropertyDatHandle);
  157. g_PropertyDatHandle = NULL;
  158. }
  159. if (g_PropertyDatName) {
  160. if (Platform == PLATFORM_DESTINATION) {
  161. DeleteFile (g_PropertyDatName);
  162. }
  163. FreePathString (g_PropertyDatName);
  164. g_PropertyDatName = NULL;
  165. }
  166. }
  167. PCTSTR
  168. pGetPropertyNameForDebugMsg (
  169. IN MIG_PROPERTYID PropertyId
  170. )
  171. {
  172. static TCHAR name[256];
  173. if (!IsmGetPropertyName (PropertyId, name, ARRAYSIZE(name), NULL, NULL, NULL)) {
  174. StringCopy (name, TEXT("<invalid property>"));
  175. }
  176. return name;
  177. }
  178. PCTSTR
  179. pPropertyPathFromId (
  180. IN MIG_PROPERTYID PropertyId
  181. )
  182. {
  183. return MemDbGetKeyFromHandle ((UINT) PropertyId, 0);
  184. }
  185. VOID
  186. pPropertyPathFromName (
  187. IN PCTSTR PropertyName,
  188. OUT PTSTR Path
  189. )
  190. {
  191. wsprintf (Path, TEXT("Property\\%s"), PropertyName);
  192. }
  193. LONGLONG
  194. OffsetFromPropertyDataId (
  195. IN MIG_PROPERTYDATAID PropertyDataId
  196. )
  197. {
  198. PCTSTR p;
  199. LONGLONG offset;
  200. p = MemDbGetKeyFromHandle (
  201. (KEYHANDLE) PropertyDataId,
  202. MEMDB_LAST_LEVEL
  203. );
  204. if (!p) {
  205. DEBUGMSG ((DBG_ERROR, "Can't get offset from invalid property instance"));
  206. return 0;
  207. }
  208. offset = (LONGLONG) TToU64 (p);
  209. MemDbReleaseMemory (p);
  210. return offset;
  211. }
  212. MIG_PROPERTYDATAID
  213. pPropertyDataIdFromOffset (
  214. IN LONGLONG DataOffset
  215. )
  216. {
  217. TCHAR instanceKey[256];
  218. KEYHANDLE handle;
  219. wsprintf (instanceKey, S_PROPINST_FORMAT, DataOffset);
  220. handle = MemDbGetHandleFromKey (instanceKey);
  221. if (!handle) {
  222. return 0;
  223. }
  224. return (MIG_PROPERTYDATAID) handle;
  225. }
  226. #if 0
  227. //
  228. // This function is not valid because the assumption it was initially
  229. // implemented with has changed. It used to be that a property instance
  230. // was associated with a specific property id. Now the instance is
  231. // just the data, which can be associated with any property!
  232. //
  233. MIG_PROPERTYID
  234. pPropertyIdFromInstance (
  235. IN MIG_PROPERTYDATAID PropertyDataId
  236. )
  237. {
  238. MIG_PROPERTYID result = 0;
  239. KEYHANDLE *linkage;
  240. UINT count;
  241. PPROPERTY_DATA_REFERENCE dataRef = NULL;
  242. UINT dataRefSize;
  243. UINT u;
  244. LONGLONG offset;
  245. linkage = (KEYHANDLE *) MemDbGetSingleLinkageArrayByKeyHandle (
  246. PropertyDataId,
  247. PROPERTY_INDEX,
  248. &count
  249. );
  250. count /= sizeof (KEYHANDLE);
  251. __try {
  252. if (!linkage || !count) {
  253. __leave;
  254. }
  255. offset = OffsetFromPropertyDataId (PropertyData);
  256. if (!offset) {
  257. __leave;
  258. }
  259. dataRef = (PPROPERTY_DATA_REFERENCE) MemDbGetUnorderedBlobByKeyHandle (
  260. (MIG_OBJECTID) linkage[0],
  261. PROPERTY_INDEX,
  262. &dataRefSize
  263. );
  264. dataRefSize /= sizeof (PROPERTY_DATA_REFERENCE);
  265. if (!dataRef || !dataRefSize) {
  266. __leave;
  267. }
  268. for (u = 0 ; u < dataRefSize ; u++) {
  269. if (dataRef[u].DatFileOffset == offset) {
  270. result = dataRef[u].PropertyId;
  271. break;
  272. }
  273. }
  274. }
  275. __finally {
  276. MemDbReleaseMemory (linkage);
  277. INVALID_POINTER (linkage);
  278. MemDbReleaseMemory (dataRef);
  279. INVALID_POINTER (dataRef);
  280. }
  281. return result;
  282. }
  283. #endif
  284. MIG_PROPERTYID
  285. IsmRegisterProperty (
  286. IN PCTSTR Name,
  287. IN BOOL Private
  288. )
  289. /*++
  290. Routine Description:
  291. IsmRegisterProperty creates a public or private property and returns the
  292. ID to the caller. If the property already exists, then the existing ID is
  293. returned to the caller.
  294. Arguments:
  295. Name - Specifies the property name to register.
  296. Private - Specifies TRUE if the property is owned by the calling module
  297. only, or FALSE if it is shared by all modules. If TRUE is
  298. specified, the caller must be in an ISM callback function.
  299. Return Value:
  300. The ID of the property, or 0 if the registration failed.
  301. --*/
  302. {
  303. TCHAR propertyPath[MEMDB_MAX];
  304. TCHAR decoratedName[MEMDB_MAX];
  305. UINT offset;
  306. if (!g_CurrentGroup && Private) {
  307. DEBUGMSG ((DBG_ERROR, "IsmRegisterProperty called for private property outside of ISM-managed context"));
  308. return 0;
  309. }
  310. if (!IsValidCNameWithDots (Name)) {
  311. DEBUGMSG ((DBG_ERROR, "property name \"%s\" is illegal", Name));
  312. return FALSE;
  313. }
  314. #ifdef DEBUG
  315. if (Private && !IsValidCName (g_CurrentGroup)) {
  316. DEBUGMSG ((DBG_ERROR, "group name \"%s\" is illegal", g_CurrentGroup));
  317. return FALSE;
  318. }
  319. #endif
  320. if (Private) {
  321. wsprintf (decoratedName, TEXT("%s:%s"), g_CurrentGroup, Name);
  322. } else {
  323. wsprintf (decoratedName, S_COMMON TEXT(":%s"), Name);
  324. }
  325. pPropertyPathFromName (decoratedName, propertyPath);
  326. if (!MarkGroupIds (propertyPath)) {
  327. DEBUGMSG ((
  328. DBG_ERROR,
  329. "%s conflicts with previously registered property",
  330. propertyPath
  331. ));
  332. return FALSE;
  333. }
  334. offset = MemDbSetKey (propertyPath);
  335. if (!offset) {
  336. EngineError ();
  337. return 0;
  338. }
  339. MYASSERT (offset);
  340. return (MIG_PROPERTYID) offset;
  341. }
  342. BOOL
  343. IsmGetPropertyName (
  344. IN MIG_PROPERTYID PropertyId,
  345. OUT PTSTR PropertyName, OPTIONAL
  346. IN UINT PropertyNameBufChars,
  347. OUT PBOOL Private, OPTIONAL
  348. OUT PBOOL BelongsToMe, OPTIONAL
  349. OUT PUINT ObjectReferences OPTIONAL
  350. )
  351. /*++
  352. Routine Description:
  353. IsmGetPropertyName obtains the property text name from a numeric ID. It
  354. also identifies private and owned properties.
  355. Arguments:
  356. PropertyId - Specifies the property ID to look up.
  357. PropertyName - Receives the property name. The name is filled for
  358. all valid PropertyId values, even when the return
  359. value is FALSE.
  360. PropertyNameBufChars - Specifies the number of TCHARs that PropertyName
  361. can hold, including the nul terminator.
  362. Private - Receives TRUE if the property is private, or FALSE
  363. if it is public.
  364. BelongsToMe - Receives TRUE if the property is private and
  365. belongs to the caller, FALSE otherwise.
  366. ObjectReferences - Receives the number of objects that reference the
  367. property
  368. Return Value:
  369. TRUE if the property is public, or if the property is private and belongs to
  370. the caller.
  371. FALSE if the property is private and belongs to someone else. PropertyName,
  372. Private and BelongsToMe are valid in this case.
  373. FALSE if PropertyId is not valid. Propertyname, Private and BelongsToMe are
  374. not modified in this case. Do not use this function to test if PropertyId
  375. is valid or not.
  376. --*/
  377. {
  378. PCTSTR propertyPath = NULL;
  379. PCTSTR start;
  380. PTSTR p, q;
  381. BOOL privateProperty = FALSE;
  382. BOOL groupMatch = FALSE;
  383. BOOL result = FALSE;
  384. UINT references;
  385. PUINT linkageList;
  386. __try {
  387. //
  388. // Get the property path from memdb, then parse it for group and name
  389. //
  390. propertyPath = pPropertyPathFromId (PropertyId);
  391. if (!propertyPath) {
  392. __leave;
  393. }
  394. p = _tcschr (propertyPath, TEXT('\\'));
  395. if (!p) {
  396. __leave;
  397. }
  398. start = _tcsinc (p);
  399. p = _tcschr (start, TEXT(':'));
  400. if (!p) {
  401. __leave;
  402. }
  403. q = _tcsinc (p);
  404. *p = 0;
  405. if (StringIMatch (start, S_COMMON)) {
  406. //
  407. // This property is a global property.
  408. //
  409. groupMatch = TRUE;
  410. } else if (g_CurrentGroup) {
  411. //
  412. // This property is private. Check if it is ours.
  413. //
  414. privateProperty = TRUE;
  415. groupMatch = StringIMatch (start, g_CurrentGroup);
  416. } else {
  417. //
  418. // This is a private property, but the caller is not
  419. // a module that can own properties.
  420. //
  421. DEBUGMSG ((DBG_WARNING, "IsmGetPropertyName: Caller cannot own private properties"));
  422. }
  423. //
  424. // Copy the name to the buffer, update outbound BOOLs, set result
  425. //
  426. if (PropertyName && PropertyNameBufChars >= sizeof (TCHAR)) {
  427. StringCopyByteCount (PropertyName, q, PropertyNameBufChars * sizeof (TCHAR));
  428. }
  429. if (Private) {
  430. *Private = privateProperty;
  431. }
  432. if (ObjectReferences) {
  433. linkageList = MemDbGetDoubleLinkageArrayByKeyHandle (
  434. PropertyId,
  435. PROPERTY_INDEX,
  436. &references
  437. );
  438. references /= SIZEOF(KEYHANDLE);
  439. if (linkageList) {
  440. MemDbReleaseMemory (linkageList);
  441. INVALID_POINTER (linkageList);
  442. } else {
  443. references = 0;
  444. }
  445. *ObjectReferences = references;
  446. }
  447. if (BelongsToMe) {
  448. *BelongsToMe = privateProperty && groupMatch;
  449. }
  450. result = groupMatch;
  451. }
  452. __finally {
  453. if (propertyPath) { //lint !e774
  454. MemDbReleaseMemory (propertyPath);
  455. INVALID_POINTER (propertyPath);
  456. }
  457. }
  458. return result;
  459. }
  460. MIG_PROPERTYID
  461. IsmGetPropertyGroup (
  462. IN MIG_PROPERTYID PropertyId
  463. )
  464. {
  465. return (MIG_PROPERTYID) GetGroupOfId ((KEYHANDLE) PropertyId);
  466. }
  467. LONGLONG
  468. AppendProperty (
  469. PCMIG_BLOB Property
  470. )
  471. {
  472. LONGLONG offset;
  473. PROPERTY_ITEM_HEADER item;
  474. #ifndef UNICODE
  475. PCWSTR convStr = NULL;
  476. #endif
  477. PCBYTE data = NULL;
  478. if (!g_PropertyDatHandle) {
  479. MYASSERT (FALSE);
  480. return 0;
  481. }
  482. if (!BfGoToEndOfFile (g_PropertyDatHandle, &offset)) {
  483. DEBUGMSG ((DBG_ERROR, "Can't seek to end of property.dat"));
  484. return 0;
  485. }
  486. __try {
  487. switch (Property->Type) {
  488. case BLOBTYPE_STRING:
  489. #ifndef UNICODE
  490. convStr = ConvertAtoW (Property->String);
  491. if (convStr) {
  492. item.Size = (DWORD) SizeOfStringW (convStr);
  493. data = (PCBYTE) convStr;
  494. } else {
  495. DEBUGMSG ((DBG_ERROR, "Error writing to property.dat"));
  496. offset = 0;
  497. __leave;
  498. }
  499. #else
  500. item.Size = (DWORD) SizeOfString (Property->String);
  501. data = (PCBYTE) Property->String;
  502. #endif
  503. break;
  504. case BLOBTYPE_BINARY:
  505. item.Size = (DWORD) Property->BinarySize;
  506. data = Property->BinaryData;
  507. break;
  508. default:
  509. MYASSERT(FALSE);
  510. offset = 0;
  511. __leave;
  512. }
  513. item.PropertyDataType = (WORD) Property->Type;
  514. if (!BfWriteFile (g_PropertyDatHandle, (PCBYTE) &item, sizeof (item)) ||
  515. !BfWriteFile (g_PropertyDatHandle, data, item.Size)
  516. ) {
  517. DEBUGMSG ((DBG_ERROR, "Can't write to property.dat"));
  518. offset = 0;
  519. __leave;
  520. }
  521. }
  522. __finally {
  523. }
  524. #ifndef UNICODE
  525. if (convStr) {
  526. FreeConvertedStr (convStr);
  527. convStr = NULL;
  528. }
  529. #endif
  530. return offset;
  531. }
  532. MIG_PROPERTYDATAID
  533. IsmRegisterPropertyData (
  534. IN PCMIG_BLOB Property
  535. )
  536. {
  537. LONGLONG offset;
  538. TCHAR offsetString[256];
  539. KEYHANDLE offsetHandle;
  540. offset = AppendProperty (Property);
  541. if (!offset) {
  542. return 0;
  543. }
  544. wsprintf (offsetString, S_PROPINST_FORMAT, offset);
  545. offsetHandle = MemDbSetKey (offsetString);
  546. if (!offsetHandle) {
  547. EngineError ();
  548. }
  549. return (MIG_PROPERTYDATAID) offsetHandle;
  550. }
  551. BOOL
  552. GetProperty (
  553. IN LONGLONG Offset,
  554. IN OUT PGROWBUFFER Buffer, OPTIONAL
  555. OUT PBYTE PreAllocatedBuffer, OPTIONAL
  556. OUT PUINT Size, OPTIONAL
  557. OUT PMIG_BLOBTYPE PropertyDataType OPTIONAL
  558. )
  559. {
  560. PBYTE data;
  561. PROPERTY_ITEM_HEADER item;
  562. #ifndef UNICODE
  563. PCSTR ansiStr = NULL;
  564. DWORD ansiSize = 0;
  565. PBYTE ansiData = NULL;
  566. #endif
  567. if (!g_PropertyDatHandle) {
  568. MYASSERT (FALSE);
  569. return FALSE;
  570. }
  571. if (!BfSetFilePointer (g_PropertyDatHandle, Offset)) {
  572. DEBUGMSG ((DBG_ERROR, "Can't seek to %I64Xh in property.dat", Offset));
  573. return FALSE;
  574. }
  575. if (!BfReadFile (g_PropertyDatHandle, (PBYTE) &item, sizeof (item))) {
  576. DEBUGMSG ((DBG_ERROR, "Can't read property item header"));
  577. return FALSE;
  578. }
  579. #ifndef UNICODE
  580. if (item.PropertyDataType == BLOBTYPE_STRING) {
  581. // we have some work to do
  582. if (PropertyDataType) {
  583. *PropertyDataType = (MIG_BLOBTYPE) item.PropertyDataType;
  584. }
  585. data = IsmGetMemory (item.Size);
  586. if (!data) {
  587. return FALSE;
  588. }
  589. ZeroMemory (data, item.Size);
  590. if (!BfReadFile (g_PropertyDatHandle, data, item.Size)) {
  591. DEBUGMSG ((DBG_ERROR, "Can't read property item"));
  592. IsmReleaseMemory (data);
  593. return FALSE;
  594. }
  595. ansiStr = ConvertWtoA ((PCWSTR) data);
  596. if (!ansiStr) {
  597. DEBUGMSG ((DBG_ERROR, "Can't read property item"));
  598. IsmReleaseMemory (data);
  599. return FALSE;
  600. }
  601. ansiSize = SizeOfStringA (ansiStr);
  602. if (Size) {
  603. *Size = ansiSize;
  604. }
  605. if (Buffer || PreAllocatedBuffer) {
  606. if (PreAllocatedBuffer) {
  607. CopyMemory (PreAllocatedBuffer, ansiStr, ansiSize);
  608. } else {
  609. ansiData = GbGrow (Buffer, ansiSize);
  610. if (!ansiData) {
  611. DEBUGMSG ((DBG_ERROR, "Can't allocate %u bytes", ansiSize));
  612. FreeConvertedStr (ansiStr);
  613. IsmReleaseMemory (data);
  614. return FALSE;
  615. }
  616. CopyMemory (ansiData, ansiStr, ansiSize);
  617. }
  618. }
  619. FreeConvertedStr (ansiStr);
  620. IsmReleaseMemory (data);
  621. } else {
  622. #endif
  623. if (Size) {
  624. *Size = item.Size;
  625. }
  626. if (PropertyDataType) {
  627. *PropertyDataType = (MIG_BLOBTYPE) item.PropertyDataType;
  628. }
  629. if (Buffer || PreAllocatedBuffer) {
  630. if (PreAllocatedBuffer) {
  631. data = PreAllocatedBuffer;
  632. } else {
  633. data = GbGrow (Buffer, item.Size);
  634. if (!data) {
  635. DEBUGMSG ((DBG_ERROR, "Can't allocate %u bytes", item.Size));
  636. return FALSE;
  637. }
  638. }
  639. if (!BfReadFile (g_PropertyDatHandle, data, item.Size)) {
  640. DEBUGMSG ((DBG_ERROR, "Can't read property item"));
  641. return FALSE;
  642. }
  643. }
  644. #ifndef UNICODE
  645. }
  646. #endif
  647. return TRUE;
  648. }
  649. BOOL
  650. CreatePropertyStruct (
  651. IN OUT PGROWBUFFER Buffer,
  652. OUT PMIG_BLOB PropertyStruct,
  653. IN LONGLONG Offset
  654. )
  655. {
  656. UINT size;
  657. MIG_BLOBTYPE type;
  658. //
  659. // Obtain property size, data and type
  660. //
  661. Buffer->End = 0;
  662. if (!GetProperty (Offset, Buffer, NULL, &size, &type)) {
  663. DEBUGMSG ((DBG_ERROR, "Error getting op property instance header from dat file"));
  664. return FALSE;
  665. }
  666. //
  667. // Fill in the property struct
  668. //
  669. PropertyStruct->Type = type;
  670. switch (type) {
  671. case BLOBTYPE_STRING:
  672. PropertyStruct->String = (PCTSTR) Buffer->Buf;
  673. break;
  674. case BLOBTYPE_BINARY:
  675. PropertyStruct->BinaryData = Buffer->Buf;
  676. PropertyStruct->BinarySize = size;
  677. break;
  678. default:
  679. ZeroMemory (PropertyStruct, sizeof (MIG_BLOB));
  680. break;
  681. }
  682. return TRUE;
  683. }
  684. MIG_PROPERTYDATAID
  685. pAddPropertyToObjectId (
  686. IN MIG_OBJECTID ObjectId,
  687. IN MIG_PROPERTYID PropertyId,
  688. IN PCMIG_BLOB Property,
  689. IN BOOL QueryOnly,
  690. IN PLONGLONG PreExistingProperty OPTIONAL
  691. )
  692. {
  693. PROPERTY_DATA_REFERENCE propertyRef;
  694. MIG_PROPERTYDATAID result = 0;
  695. GROWBUFFER buffer = INIT_GROWBUFFER;
  696. TCHAR offsetString[256];
  697. KEYHANDLE offsetHandle;
  698. UINT u;
  699. PPROPERTY_DATA_REFERENCE dataRef;
  700. UINT dataRefSize;
  701. __try {
  702. //
  703. // Is the property id locked?
  704. //
  705. if (TestLock (ObjectId, (KEYHANDLE) PropertyId)) {
  706. SetLastError (ERROR_LOCKED);
  707. DEBUGMSG ((
  708. DBG_WARNING,
  709. "Can't set property %s on %s because of lock",
  710. pGetPropertyNameForDebugMsg (PropertyId),
  711. GetObjectNameForDebugMsg (ObjectId)
  712. ));
  713. __leave;
  714. }
  715. if (QueryOnly) {
  716. result = TRUE;
  717. __leave;
  718. }
  719. //
  720. // Store the property in the dat file
  721. //
  722. propertyRef.PropertyId = PropertyId;
  723. if (PreExistingProperty) {
  724. propertyRef.DatFileOffset = *PreExistingProperty;
  725. } else {
  726. propertyRef.DatFileOffset = AppendProperty (Property);
  727. if (!propertyRef.DatFileOffset) {
  728. __leave;
  729. }
  730. if (PreExistingProperty) {
  731. *PreExistingProperty = propertyRef.DatFileOffset;
  732. }
  733. }
  734. //
  735. // Link the object to the property, and the object to the property
  736. // instance and data
  737. //
  738. if (!MemDbAddDoubleLinkageByKeyHandle (PropertyId, ObjectId, PROPERTY_INDEX)) {
  739. DEBUGMSG ((DBG_ERROR, "Can't link object to property"));
  740. EngineError ();
  741. __leave;
  742. }
  743. dataRef = (PPROPERTY_DATA_REFERENCE) MemDbGetUnorderedBlobByKeyHandle (
  744. ObjectId,
  745. PROPERTY_INDEX,
  746. &dataRefSize
  747. );
  748. dataRefSize /= sizeof (PROPERTY_DATA_REFERENCE);
  749. if (dataRef && dataRefSize) {
  750. //
  751. // Scan the unorderd blob for a zero property id (means "deleted")
  752. //
  753. for (u = 0 ; u < dataRefSize ; u++) {
  754. if (!dataRef[u].PropertyId) {
  755. break;
  756. }
  757. }
  758. //
  759. // If a zero property id was found, use it and update the array
  760. //
  761. if (u < dataRefSize) {
  762. CopyMemory (&dataRef[u], &propertyRef, sizeof (PROPERTY_DATA_REFERENCE));
  763. } else {
  764. MemDbReleaseMemory (dataRef);
  765. dataRef = NULL;
  766. }
  767. }
  768. if (!dataRef) {
  769. //
  770. // If the array was initially empty, or if no deleted space was found,
  771. // then grow the blob by putting the new property reference at the end
  772. //
  773. if (!MemDbGrowUnorderedBlobByKeyHandle (
  774. ObjectId,
  775. PROPERTY_INDEX,
  776. (PBYTE) &propertyRef,
  777. sizeof (propertyRef)
  778. )) {
  779. DEBUGMSG ((DBG_ERROR, "Can't link property data to property"));
  780. __leave;
  781. }
  782. } else {
  783. //
  784. // If the array was not freed, then it has been updated, and it needs
  785. // to be saved back to memdb. Do that, then release the memory.
  786. //
  787. if (!MemDbSetUnorderedBlobByKeyHandle (
  788. ObjectId,
  789. PROPERTY_INDEX,
  790. (PBYTE) dataRef,
  791. dataRefSize * sizeof (PROPERTY_DATA_REFERENCE)
  792. )) {
  793. DEBUGMSG ((DBG_ERROR, "Can't link property data to property (2)"));
  794. __leave;
  795. }
  796. MemDbReleaseMemory (dataRef);
  797. INVALID_POINTER (dataRef);
  798. }
  799. //
  800. // Link the offset to the object
  801. //
  802. wsprintf (offsetString, S_PROPINST_FORMAT, propertyRef.DatFileOffset);
  803. offsetHandle = MemDbSetKey (offsetString);
  804. if (!offsetHandle) {
  805. EngineError ();
  806. __leave;
  807. }
  808. if (!MemDbAddSingleLinkageByKeyHandle (offsetHandle, ObjectId, PROPERTY_INDEX)) {
  809. DEBUGMSG ((DBG_ERROR, "Can't link dat file offset to object"));
  810. EngineError ();
  811. __leave;
  812. }
  813. result = (MIG_PROPERTYDATAID) offsetHandle;
  814. }
  815. __finally {
  816. GbFree (&buffer);
  817. }
  818. return result;
  819. }
  820. BOOL
  821. pAddPropertyGroup (
  822. IN KEYHANDLE PropertyId,
  823. IN BOOL FirstPass,
  824. IN ULONG_PTR Arg
  825. )
  826. {
  827. PADDPROPERTYARG myArg = (PADDPROPERTYARG) Arg;
  828. MYASSERT (IsItemId (PropertyId));
  829. return pAddPropertyToObjectId (
  830. myArg->ObjectId,
  831. (MIG_PROPERTYID) PropertyId,
  832. myArg->Property,
  833. FirstPass,
  834. &myArg->PreExistingProperty
  835. );
  836. }
  837. MIG_PROPERTYDATAID
  838. IsmAddPropertyToObjectId (
  839. IN MIG_OBJECTID ObjectId,
  840. IN MIG_PROPERTYID PropertyId,
  841. IN PCMIG_BLOB Property
  842. )
  843. {
  844. RECURSERETURN rc;
  845. ADDPROPERTYARG myArg;
  846. //
  847. // If PropertyId is a group, set all properties in the group
  848. //
  849. myArg.ObjectId = ObjectId;
  850. myArg.Property = Property;
  851. myArg.PreExistingProperty = 0;
  852. rc = RecurseForGroupItems (
  853. PropertyId,
  854. pAddPropertyGroup,
  855. (ULONG_PTR) &myArg,
  856. FALSE,
  857. FALSE
  858. );
  859. if (rc == RECURSE_FAIL) {
  860. return FALSE;
  861. } else if (rc == RECURSE_SUCCESS) {
  862. return TRUE;
  863. }
  864. MYASSERT (rc == RECURSE_NOT_NEEDED);
  865. return pAddPropertyToObjectId (ObjectId, PropertyId, Property, FALSE, NULL);
  866. }
  867. MIG_PROPERTYDATAID
  868. IsmAddPropertyToObject (
  869. IN MIG_OBJECTTYPEID ObjectTypeId,
  870. IN ENCODEDSTRHANDLE EncodedObjectName,
  871. IN MIG_PROPERTYID PropertyId,
  872. IN PCMIG_BLOB Property
  873. )
  874. {
  875. MIG_OBJECTID objectId;
  876. BOOL result = FALSE;
  877. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  878. objectId = GetObjectIdForModification (ObjectTypeId, EncodedObjectName);
  879. if (objectId) {
  880. result = IsmAddPropertyToObjectId (objectId, PropertyId, Property);
  881. }
  882. return result;
  883. }
  884. BOOL
  885. IsmAddPropertyDataToObjectId (
  886. IN MIG_OBJECTID ObjectId,
  887. IN MIG_PROPERTYID PropertyId,
  888. IN MIG_PROPERTYDATAID PropertyDataId
  889. )
  890. {
  891. LONGLONG offset;
  892. MIG_PROPERTYDATAID instance;
  893. offset = OffsetFromPropertyDataId (PropertyDataId);
  894. if (!offset) {
  895. DEBUGMSG ((DBG_ERROR, "Invalid property instance passed to IsmAddPropertyDataToObjectId (2)"));
  896. SetLastError (ERROR_INVALID_PARAMETER);
  897. return FALSE;
  898. }
  899. instance = pAddPropertyToObjectId (
  900. ObjectId,
  901. PropertyId,
  902. NULL,
  903. FALSE,
  904. &offset
  905. );
  906. return instance != 0;
  907. }
  908. BOOL
  909. IsmAddPropertyDataToObject (
  910. IN MIG_OBJECTTYPEID ObjectTypeId,
  911. IN ENCODEDSTRHANDLE EncodedObjectName,
  912. IN MIG_PROPERTYID PropertyId,
  913. IN MIG_PROPERTYDATAID PropertyDataId
  914. )
  915. {
  916. MIG_OBJECTID objectId;
  917. BOOL result = FALSE;
  918. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  919. objectId = GetObjectIdForModification (ObjectTypeId, EncodedObjectName);
  920. if (objectId) {
  921. result = IsmAddPropertyDataToObjectId (objectId, PropertyId, PropertyDataId);
  922. }
  923. return result;
  924. }
  925. VOID
  926. IsmLockProperty (
  927. IN MIG_OBJECTID ObjectId,
  928. IN MIG_PROPERTYID PropertyId
  929. )
  930. {
  931. LockHandle (ObjectId, (KEYHANDLE) PropertyId);
  932. }
  933. BOOL
  934. IsmGetPropertyData (
  935. IN MIG_PROPERTYDATAID PropertyDataId,
  936. OUT PBYTE Buffer, OPTIONAL
  937. IN UINT BufferSize,
  938. OUT PUINT PropertyDataSize, OPTIONAL
  939. OUT PMIG_BLOBTYPE PropertyDataType OPTIONAL
  940. )
  941. {
  942. LONGLONG offset;
  943. UINT size;
  944. //
  945. // Convert the property instance to the property.dat offset
  946. //
  947. offset = OffsetFromPropertyDataId (PropertyDataId);
  948. if (!offset) {
  949. DEBUGMSG ((DBG_ERROR, "Invalid property instance passed to IsmGetPropertyData"));
  950. SetLastError (ERROR_INVALID_PARAMETER);
  951. return FALSE;
  952. }
  953. //
  954. // Obtain the property data size
  955. //
  956. if (!GetProperty (offset, NULL, NULL, &size, PropertyDataType)) {
  957. DEBUGMSG ((DBG_ERROR, "Error getting property instance header from dat file"));
  958. SetLastError (ERROR_INVALID_PARAMETER);
  959. return FALSE;
  960. }
  961. if (PropertyDataSize) {
  962. *PropertyDataSize = size;
  963. }
  964. //
  965. // If a buffer was specified, check its size and fill it if possible
  966. //
  967. if (Buffer) {
  968. if (BufferSize >= size) {
  969. if (!GetProperty (offset, NULL, Buffer, NULL, NULL)) {
  970. DEBUGMSG ((DBG_ERROR, "Error reading property data from dat file"));
  971. // error code is one of the file api error codes
  972. return FALSE;
  973. }
  974. } else {
  975. SetLastError (ERROR_MORE_DATA);
  976. return FALSE;
  977. }
  978. }
  979. return TRUE;
  980. }
  981. BOOL
  982. IsmRemovePropertyData (
  983. IN MIG_PROPERTYDATAID PropertyDataId
  984. )
  985. {
  986. BOOL result = FALSE;
  987. KEYHANDLE *linkageArray;
  988. UINT linkageCount;
  989. UINT u;
  990. UINT v;
  991. UINT propertySearch;
  992. PPROPERTY_DATA_REFERENCE dataRef;
  993. UINT dataRefSize;
  994. LONGLONG offset;
  995. TCHAR instanceKey[256];
  996. KEYHANDLE lockId = 0;
  997. BOOL noMoreLeft;
  998. BOOL b;
  999. __try {
  1000. //
  1001. // Determine the offset for the property instance
  1002. //
  1003. offset = OffsetFromPropertyDataId (PropertyDataId);
  1004. if (!offset) {
  1005. __leave;
  1006. }
  1007. //
  1008. // Get single linkage list from property instance. The links point
  1009. // to objects.
  1010. //
  1011. linkageArray = (KEYHANDLE *) MemDbGetSingleLinkageArrayByKeyHandle (
  1012. PropertyDataId, // handle
  1013. PROPERTY_INDEX,
  1014. &linkageCount
  1015. );
  1016. if (!linkageArray) {
  1017. //
  1018. // Doesn't exist!
  1019. //
  1020. DEBUGMSG ((DBG_ERROR, "Tried to remove invalid property instance"));
  1021. __leave;
  1022. }
  1023. linkageCount /= sizeof (KEYHANDLE);
  1024. if (!linkageCount) {
  1025. DEBUGMSG ((DBG_WHOOPS, "Empty linkage list for property instances"));
  1026. __leave;
  1027. }
  1028. //
  1029. // For all entries in the linkage list, remove the blob entry
  1030. //
  1031. for (u = 0 ; u < linkageCount ; u++) {
  1032. //
  1033. // Check if the object is locked
  1034. //
  1035. if (IsObjectLocked (linkageArray[u])) {
  1036. DEBUGMSG ((
  1037. DBG_WARNING,
  1038. "Can't remove property from %s because of object lock",
  1039. GetObjectNameForDebugMsg (linkageArray[u])
  1040. ));
  1041. continue;
  1042. }
  1043. if (lockId) {
  1044. //
  1045. // For the first pass, the lockId is unknown. On additional
  1046. // passes, the per-object property lock is checked here.
  1047. //
  1048. if (IsHandleLocked ((MIG_OBJECTID) linkageArray[u], lockId)) {
  1049. DEBUGMSG ((
  1050. DBG_WARNING,
  1051. "Can't remove property from %s because of object lock",
  1052. GetObjectNameForDebugMsg (linkageArray[u])
  1053. ));
  1054. continue;
  1055. }
  1056. }
  1057. //
  1058. // Get the unordered blob for the object
  1059. //
  1060. dataRef = (PPROPERTY_DATA_REFERENCE) MemDbGetUnorderedBlobByKeyHandle (
  1061. linkageArray[u],
  1062. PROPERTY_INDEX,
  1063. &dataRefSize
  1064. );
  1065. dataRefSize /= sizeof (PROPERTY_DATA_REFERENCE);
  1066. if (!dataRef || !dataRefSize) {
  1067. DEBUGMSG ((DBG_WHOOPS, "Empty propid/offset blob for property instance"));
  1068. continue;
  1069. }
  1070. #ifdef DEBUG
  1071. //
  1072. // Assert that the blob has a reference to the offset we are removing
  1073. //
  1074. for (v = 0 ; v < dataRefSize ; v++) {
  1075. if (dataRef[v].DatFileOffset == offset) {
  1076. break;
  1077. }
  1078. }
  1079. MYASSERT (v < dataRefSize);
  1080. #endif
  1081. //
  1082. // Scan the blob for all references to this property instance, then
  1083. // reset the PropertyId member. If removing the property instance
  1084. // causes the property not to be referenced by the object, then
  1085. // also remove the property name linkage.
  1086. //
  1087. noMoreLeft = FALSE;
  1088. for (v = 0 ; v < dataRefSize && !noMoreLeft ; v++) {
  1089. if (dataRef[v].DatFileOffset == offset) {
  1090. MYASSERT (!lockId || dataRef[v].PropertyId == lockId);
  1091. //
  1092. // Check if the per-object property is locked (on the first pass only)
  1093. //
  1094. if (!lockId) {
  1095. lockId = (KEYHANDLE) dataRef[v].PropertyId;
  1096. if (IsHandleLocked ((MIG_OBJECTID) linkageArray[u], lockId)) {
  1097. DEBUGMSG ((
  1098. DBG_WARNING,
  1099. "Can't remove property from %s because of object lock (2)",
  1100. GetObjectNameForDebugMsg (linkageArray[u])
  1101. ));
  1102. //
  1103. // noMoreLeft is used to detect this case outside the loop
  1104. //
  1105. MYASSERT (!noMoreLeft);
  1106. break;
  1107. }
  1108. }
  1109. //
  1110. // Are there more references in this blob to the current property ID?
  1111. //
  1112. for (propertySearch = 0 ; propertySearch < dataRefSize ; propertySearch++) {
  1113. if (propertySearch == v) {
  1114. continue;
  1115. }
  1116. if (dataRef[propertySearch].PropertyId == dataRef[v].PropertyId) {
  1117. break;
  1118. }
  1119. }
  1120. //
  1121. // If no other references to property, remove the property name linkage
  1122. //
  1123. if (propertySearch >= dataRefSize) {
  1124. MemDbDeleteDoubleLinkageByKeyHandle (
  1125. linkageArray[u],
  1126. dataRef[v].PropertyId,
  1127. PROPERTY_INDEX
  1128. );
  1129. noMoreLeft = TRUE;
  1130. }
  1131. //
  1132. // Reset the current property id (to "deleted" status)
  1133. //
  1134. dataRef[v].PropertyId = 0;
  1135. }
  1136. }
  1137. if (v >= dataRefSize || noMoreLeft) {
  1138. //
  1139. // The loop did not terminated early because of a lock,
  1140. // so reapply the change
  1141. //
  1142. b = MemDbSetUnorderedBlobByKeyHandle (
  1143. linkageArray[u],
  1144. PROPERTY_INDEX,
  1145. (PBYTE) dataRef,
  1146. dataRefSize * sizeof (PROPERTY_DATA_REFERENCE)
  1147. );
  1148. } else {
  1149. b = TRUE;
  1150. }
  1151. MemDbReleaseMemory (dataRef);
  1152. if (!b) {
  1153. DEBUGMSG ((DBG_ERROR, "Can't re-apply property linkage blob during instance remove"));
  1154. EngineError ();
  1155. __leave;
  1156. }
  1157. }
  1158. //
  1159. // Remove the property instance
  1160. //
  1161. wsprintf (instanceKey, S_PROPINST_FORMAT, offset);
  1162. MemDbDeleteKey (instanceKey);
  1163. result = TRUE;
  1164. }
  1165. __finally {
  1166. }
  1167. return result;
  1168. }
  1169. BOOL
  1170. pRemovePropertyFromObjectId (
  1171. IN MIG_OBJECTID ObjectId,
  1172. IN MIG_PROPERTYID PropertyId,
  1173. IN BOOL QueryOnly
  1174. )
  1175. {
  1176. BOOL result = FALSE;
  1177. UINT u;
  1178. PPROPERTY_DATA_REFERENCE dataRef = NULL;
  1179. UINT dataRefSize;
  1180. TCHAR instanceKey[256];
  1181. KEYHANDLE propertyData;
  1182. BOOL b;
  1183. __try {
  1184. //
  1185. // Test for locks
  1186. //
  1187. if (TestLock (ObjectId, (KEYHANDLE) PropertyId)) {
  1188. SetLastError (ERROR_LOCKED);
  1189. DEBUGMSG ((
  1190. DBG_WARNING,
  1191. "Can't remove property %s on %s because of lock",
  1192. pGetPropertyNameForDebugMsg (PropertyId),
  1193. GetObjectNameForDebugMsg (ObjectId)
  1194. ));
  1195. __leave;
  1196. }
  1197. if (QueryOnly) {
  1198. result = TRUE;
  1199. __leave;
  1200. }
  1201. //
  1202. // Get the unordered blob
  1203. //
  1204. dataRef = (PPROPERTY_DATA_REFERENCE) MemDbGetUnorderedBlobByKeyHandle (
  1205. ObjectId,
  1206. PROPERTY_INDEX,
  1207. &dataRefSize
  1208. );
  1209. dataRefSize /= sizeof (PROPERTY_DATA_REFERENCE);
  1210. if (!dataRef || !dataRefSize) {
  1211. DEBUGMSG ((DBG_WHOOPS, "Empty propid/offset blob for property removal"));
  1212. __leave;
  1213. }
  1214. //
  1215. // Scan the blob for references to this property
  1216. //
  1217. b = FALSE;
  1218. for (u = 0 ; u < dataRefSize ; u++) {
  1219. if (dataRef[u].PropertyId == PropertyId) {
  1220. //
  1221. // Remove the single linkage from offset to object
  1222. //
  1223. wsprintf (instanceKey, S_PROPINST_FORMAT, dataRef[u].DatFileOffset);
  1224. propertyData = MemDbGetHandleFromKey (instanceKey);
  1225. if (!propertyData) {
  1226. DEBUGMSG ((DBG_WHOOPS, "Property references non-existent offset"));
  1227. continue;
  1228. }
  1229. MemDbDeleteSingleLinkageByKeyHandle (propertyData, ObjectId, PROPERTY_INDEX);
  1230. //
  1231. // IMPORTANT: The operation above might have made the property instance
  1232. // key point to nothing (because the last remaining linkage was removed).
  1233. // However, it is critical not to remove the abandoned propertyData key,
  1234. // becase the caller might still have handle to the property instance, and
  1235. // this handle can be applied to a new object later.
  1236. //
  1237. //
  1238. // Now reset the property id ("deleted" state)
  1239. //
  1240. dataRef[u].PropertyId = 0;
  1241. b = TRUE;
  1242. }
  1243. }
  1244. //
  1245. // Reapply the changed blob
  1246. //
  1247. if (b) {
  1248. if (!MemDbSetUnorderedBlobByKeyHandle (
  1249. ObjectId,
  1250. PROPERTY_INDEX,
  1251. (PBYTE) dataRef,
  1252. dataRefSize * sizeof (PROPERTY_DATA_REFERENCE)
  1253. )) {
  1254. __leave;
  1255. }
  1256. }
  1257. //
  1258. // Remove the object-to-property name linkage. If this fails and b is FALSE,
  1259. // then the object doesn't have a reference to the property.
  1260. //
  1261. if (!MemDbDeleteDoubleLinkageByKeyHandle (ObjectId, PropertyId, PROPERTY_INDEX)) {
  1262. DEBUGMSG_IF ((b, DBG_WHOOPS, "Can't delete object<->property linkage"));
  1263. __leave;
  1264. }
  1265. result = TRUE;
  1266. }
  1267. __finally {
  1268. if (dataRef) {
  1269. MemDbReleaseMemory (dataRef);
  1270. INVALID_POINTER (dataRef);
  1271. }
  1272. }
  1273. return result;
  1274. }
  1275. BOOL
  1276. pRemovePropertyGroup (
  1277. IN KEYHANDLE PropertyId,
  1278. IN BOOL FirstPass,
  1279. IN ULONG_PTR Arg
  1280. )
  1281. {
  1282. return pRemovePropertyFromObjectId (
  1283. (MIG_OBJECTID) Arg,
  1284. (MIG_PROPERTYID) PropertyId,
  1285. FirstPass
  1286. );
  1287. }
  1288. BOOL
  1289. IsmRemovePropertyFromObjectId (
  1290. IN MIG_OBJECTID ObjectId,
  1291. IN MIG_PROPERTYID PropertyId
  1292. )
  1293. {
  1294. RECURSERETURN rc;
  1295. //
  1296. // If PropertyId is a group, set all attribs in the group
  1297. //
  1298. rc = RecurseForGroupItems (
  1299. PropertyId,
  1300. pRemovePropertyGroup,
  1301. (ULONG_PTR) ObjectId,
  1302. FALSE,
  1303. FALSE
  1304. );
  1305. if (rc == RECURSE_FAIL) {
  1306. return FALSE;
  1307. } else if (rc == RECURSE_SUCCESS) {
  1308. return TRUE;
  1309. }
  1310. MYASSERT (rc == RECURSE_NOT_NEEDED);
  1311. return pRemovePropertyFromObjectId (ObjectId, PropertyId, FALSE);
  1312. }
  1313. BOOL
  1314. IsmRemovePropertyFromObject (
  1315. IN MIG_OBJECTTYPEID ObjectTypeId,
  1316. IN ENCODEDSTRHANDLE EncodedObjectName,
  1317. IN MIG_PROPERTYID PropertyId
  1318. )
  1319. {
  1320. MIG_OBJECTID objectId;
  1321. BOOL result = FALSE;
  1322. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  1323. objectId = IsmGetObjectIdFromName (ObjectTypeId, EncodedObjectName, TRUE);
  1324. if (objectId) {
  1325. result = IsmRemovePropertyFromObjectId (objectId, PropertyId);
  1326. }
  1327. return result;
  1328. }
  1329. BOOL
  1330. pIsPropertySetOnObjectId (
  1331. IN MIG_OBJECTID ObjectId,
  1332. IN MIG_PROPERTYID PropertyId
  1333. )
  1334. {
  1335. return MemDbTestDoubleLinkageByKeyHandle (
  1336. ObjectId,
  1337. PropertyId,
  1338. PROPERTY_INDEX
  1339. );
  1340. }
  1341. BOOL
  1342. pQueryPropertyGroup (
  1343. IN KEYHANDLE PropertyId,
  1344. IN BOOL FirstPass,
  1345. IN ULONG_PTR Arg
  1346. )
  1347. {
  1348. return pIsPropertySetOnObjectId (
  1349. (MIG_OBJECTID) Arg,
  1350. (MIG_PROPERTYID) PropertyId
  1351. );
  1352. }
  1353. BOOL
  1354. IsmIsPropertySetOnObjectId (
  1355. IN MIG_OBJECTID ObjectId,
  1356. IN MIG_PROPERTYID PropertyId
  1357. )
  1358. {
  1359. RECURSERETURN rc;
  1360. //
  1361. // If PropertyId is a group, query all properties in the group
  1362. //
  1363. rc = RecurseForGroupItems (
  1364. PropertyId,
  1365. pQueryPropertyGroup,
  1366. (ULONG_PTR) ObjectId,
  1367. TRUE,
  1368. TRUE
  1369. );
  1370. if (rc == RECURSE_FAIL) {
  1371. return FALSE;
  1372. } else if (rc == RECURSE_SUCCESS) {
  1373. return TRUE;
  1374. }
  1375. MYASSERT (rc == RECURSE_NOT_NEEDED);
  1376. return pIsPropertySetOnObjectId (ObjectId, PropertyId);
  1377. }
  1378. BOOL
  1379. IsmIsPropertySetOnObject (
  1380. IN MIG_OBJECTTYPEID ObjectTypeId,
  1381. IN ENCODEDSTRHANDLE EncodedObjectName,
  1382. IN MIG_PROPERTYID PropertyId
  1383. )
  1384. {
  1385. MIG_OBJECTID objectId;
  1386. BOOL result = FALSE;
  1387. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  1388. objectId = IsmGetObjectIdFromName (ObjectTypeId, EncodedObjectName, TRUE);
  1389. if (objectId) {
  1390. result = IsmIsPropertySetOnObjectId (objectId, PropertyId);
  1391. }
  1392. return result;
  1393. }
  1394. BOOL
  1395. IsmEnumFirstObjectPropertyById (
  1396. OUT PMIG_OBJECTPROPERTY_ENUM EnumPtr,
  1397. IN MIG_OBJECTID ObjectId,
  1398. IN MIG_PROPERTYID FilterProperty OPTIONAL
  1399. )
  1400. {
  1401. POBJECTPROPERTY_HANDLE handle;
  1402. BOOL b = TRUE;
  1403. UINT size;
  1404. //
  1405. // Initialize the enum structure and alloc an internal data struct
  1406. //
  1407. ZeroMemory (EnumPtr, sizeof (MIG_OBJECTPROPERTY_ENUM));
  1408. EnumPtr->Handle = MemAllocZeroed (sizeof (OBJECTPROPERTY_HANDLE));
  1409. handle = (POBJECTPROPERTY_HANDLE) EnumPtr->Handle;
  1410. handle->ObjectId = ObjectId;
  1411. handle->FilterPropertyId = FilterProperty;
  1412. if (!handle->ObjectId) {
  1413. IsmAbortObjectPropertyEnum (EnumPtr);
  1414. return FALSE;
  1415. }
  1416. //
  1417. // Property enumeration occurs in the following states
  1418. //
  1419. // 1. Get linkage list of all properties
  1420. // 2. Take first linkage from the list
  1421. // 3. Find the property name
  1422. // 4. Find the first instance of the property in the unordered blob
  1423. // 5. Return the property name and property data to the caller
  1424. // 6. Find the next instance of the property in the undorderd blob
  1425. // - go back to state 5 if another instance is found
  1426. // - go to state 7 if no more instances are found
  1427. // 7. Take the next linkage from the list
  1428. // - go back to state 3 if another linkage exists
  1429. // - terminate otherwise
  1430. //
  1431. //
  1432. // Get linkage list of all properties
  1433. //
  1434. handle->LinkageList = MemDbGetDoubleLinkageArrayByKeyHandle (
  1435. handle->ObjectId,
  1436. PROPERTY_INDEX,
  1437. &handle->LinkageCount
  1438. );
  1439. handle->LinkageCount /= sizeof (KEYHANDLE);
  1440. if (!handle->LinkageList || !handle->LinkageCount) {
  1441. IsmAbortObjectPropertyEnum (EnumPtr);
  1442. return FALSE;
  1443. }
  1444. handle->LinkageEnumPosition = 0;
  1445. //
  1446. // Get unordered blob that points us into property.dat
  1447. //
  1448. handle->InstanceArray = (PPROPERTY_DATA_REFERENCE) MemDbGetUnorderedBlobByKeyHandle (
  1449. handle->ObjectId,
  1450. PROPERTY_INDEX,
  1451. &size
  1452. );
  1453. if (!handle->InstanceArray || !size) {
  1454. DEBUGMSG ((DBG_WHOOPS, "Object<->Property Instance linkage is broken in enum"));
  1455. IsmAbortObjectPropertyEnum (EnumPtr);
  1456. }
  1457. handle->InstanceCount = size / sizeof (PROPERTY_DATA_REFERENCE);
  1458. //
  1459. // Call next enum routine to continue with state machine
  1460. //
  1461. handle->State = PROPENUM_GET_NEXT_LINKAGE;
  1462. return IsmEnumNextObjectProperty (EnumPtr);
  1463. }
  1464. BOOL
  1465. IsmEnumFirstObjectProperty (
  1466. OUT PMIG_OBJECTPROPERTY_ENUM EnumPtr,
  1467. IN MIG_OBJECTTYPEID ObjectTypeId,
  1468. IN ENCODEDSTRHANDLE EncodedObjectName,
  1469. IN MIG_PROPERTYID FilterProperty OPTIONAL
  1470. )
  1471. {
  1472. MIG_OBJECTID objectId;
  1473. BOOL result = FALSE;
  1474. ObjectTypeId = FixEnumerationObjectTypeId (ObjectTypeId);
  1475. objectId = IsmGetObjectIdFromName (ObjectTypeId, EncodedObjectName, TRUE);
  1476. if (objectId) {
  1477. result = IsmEnumFirstObjectPropertyById (EnumPtr, objectId, FilterProperty);
  1478. }
  1479. return result;
  1480. }
  1481. BOOL
  1482. IsmEnumNextObjectProperty (
  1483. IN OUT PMIG_OBJECTPROPERTY_ENUM EnumPtr
  1484. )
  1485. {
  1486. POBJECTPROPERTY_HANDLE handle;
  1487. PPROPERTY_DATA_REFERENCE propData;
  1488. handle = (POBJECTPROPERTY_HANDLE) EnumPtr->Handle;
  1489. if (!handle) {
  1490. return FALSE;
  1491. }
  1492. while (handle->State != PROPENUM_RETURN_VALUE &&
  1493. handle->State != PROPENUM_DONE
  1494. ) {
  1495. switch (handle->State) {
  1496. case PROPENUM_GET_NEXT_LINKAGE:
  1497. if (handle->LinkageEnumPosition >= handle->LinkageCount) {
  1498. handle->State = PROPENUM_DONE;
  1499. break;
  1500. }
  1501. EnumPtr->PropertyId = (MIG_PROPERTYID) handle->LinkageList[handle->LinkageEnumPosition];
  1502. handle->LinkageEnumPosition++;
  1503. //
  1504. // If there is a property id filter, make sure we ignore all properties
  1505. // except for the one specified
  1506. //
  1507. if (handle->FilterPropertyId) {
  1508. if (handle->FilterPropertyId != EnumPtr->PropertyId) {
  1509. //
  1510. // This property is not interesting -- skip it
  1511. //
  1512. handle->State = PROPENUM_GET_NEXT_LINKAGE;
  1513. break;
  1514. }
  1515. }
  1516. //
  1517. // Now make sure the property is not owned by someone else
  1518. //
  1519. if (!IsmGetPropertyName (
  1520. EnumPtr->PropertyId,
  1521. NULL,
  1522. 0,
  1523. &EnumPtr->Private,
  1524. NULL,
  1525. NULL
  1526. )) {
  1527. //
  1528. // This property is not owned by the caller -- skip it
  1529. //
  1530. handle->State = PROPENUM_GET_NEXT_LINKAGE;
  1531. break;
  1532. }
  1533. //
  1534. // The current property is either common or is owned by the caller;
  1535. // now enumerate the property instances.
  1536. //
  1537. handle->InstancePosition = 0;
  1538. #ifdef DEBUG
  1539. //
  1540. // Assert that there is at least one instance of the property
  1541. // in the current unordered blob
  1542. //
  1543. {
  1544. UINT u;
  1545. for (u = 0 ; u < handle->InstanceCount ; u++) {
  1546. propData = &handle->InstanceArray[u];
  1547. if (propData->PropertyId == EnumPtr->PropertyId) {
  1548. break;
  1549. }
  1550. }
  1551. MYASSERT (u < handle->InstanceCount);
  1552. }
  1553. #endif
  1554. handle->State = PROPENUM_GET_NEXT_INSTANCE;
  1555. break;
  1556. case PROPENUM_GET_NEXT_INSTANCE:
  1557. //
  1558. // Sequentially search the unordered blob for the current property,
  1559. // continuing from the last match (if any)
  1560. //
  1561. handle->State = PROPENUM_GET_NEXT_LINKAGE;
  1562. while (handle->InstancePosition < handle->InstanceCount) {
  1563. propData = &handle->InstanceArray[handle->InstancePosition];
  1564. handle->InstancePosition++;
  1565. if (propData->PropertyId == EnumPtr->PropertyId) {
  1566. EnumPtr->PropertyDataId = pPropertyDataIdFromOffset (propData->DatFileOffset);
  1567. handle->State = PROPENUM_RETURN_VALUE;
  1568. break;
  1569. }
  1570. }
  1571. break;
  1572. }
  1573. }
  1574. if (handle->State == PROPENUM_DONE) {
  1575. IsmAbortObjectPropertyEnum (EnumPtr);
  1576. return FALSE;
  1577. }
  1578. MYASSERT (handle->State == PROPENUM_RETURN_VALUE);
  1579. handle->State = PROPENUM_GET_NEXT_INSTANCE;
  1580. return TRUE;
  1581. }
  1582. VOID
  1583. IsmAbortObjectPropertyEnum (
  1584. IN OUT PMIG_OBJECTPROPERTY_ENUM EnumPtr
  1585. )
  1586. {
  1587. POBJECTPROPERTY_HANDLE handle;
  1588. if (EnumPtr->Handle) {
  1589. handle = (POBJECTPROPERTY_HANDLE) EnumPtr->Handle;
  1590. if (handle->LinkageList) {
  1591. MemDbReleaseMemory (handle->LinkageList);
  1592. INVALID_POINTER (handle->LinkageList);
  1593. }
  1594. FreeAlloc (EnumPtr->Handle);
  1595. INVALID_POINTER (EnumPtr->Handle);
  1596. }
  1597. ZeroMemory (EnumPtr, sizeof (MIG_OBJECTPROPERTY_ENUM));
  1598. }
  1599. MIG_PROPERTYDATAID
  1600. IsmGetPropertyFromObject (
  1601. IN MIG_OBJECTTYPEID ObjectTypeId,
  1602. IN MIG_OBJECTSTRINGHANDLE ObjectName,
  1603. IN MIG_PROPERTYID ObjectProperty
  1604. )
  1605. {
  1606. MIG_OBJECTPROPERTY_ENUM propEnum;
  1607. MIG_PROPERTYDATAID result = 0;
  1608. if (IsmEnumFirstObjectProperty (&propEnum, ObjectTypeId, ObjectName, ObjectProperty)) {
  1609. result = propEnum.PropertyDataId;
  1610. IsmAbortObjectPropertyEnum (&propEnum);
  1611. }
  1612. return result;
  1613. }
  1614. MIG_PROPERTYDATAID
  1615. IsmGetPropertyFromObjectId (
  1616. IN MIG_OBJECTID ObjectId,
  1617. IN MIG_PROPERTYID ObjectProperty
  1618. )
  1619. {
  1620. MIG_OBJECTPROPERTY_ENUM propEnum;
  1621. MIG_PROPERTYDATAID result = 0;
  1622. if (IsmEnumFirstObjectPropertyById (&propEnum, ObjectId, ObjectProperty)) {
  1623. result = propEnum.PropertyDataId;
  1624. IsmAbortObjectPropertyEnum (&propEnum);
  1625. }
  1626. return result;
  1627. }
  1628. BOOL
  1629. IsmEnumFirstObjectWithProperty (
  1630. OUT PMIG_OBJECTWITHPROPERTY_ENUM EnumPtr,
  1631. IN MIG_PROPERTYID PropertyId
  1632. )
  1633. {
  1634. POBJECTWITHPROPERTY_HANDLE handle;
  1635. BOOL result = FALSE;
  1636. __try {
  1637. if (!IsItemId ((KEYHANDLE) PropertyId)) {
  1638. DEBUGMSG ((DBG_ERROR, "IsmEnumFirstObjectWithProperty: invalid property id"));
  1639. __leave;
  1640. }
  1641. //
  1642. // Initialize the enum struct and alloc a data struct
  1643. //
  1644. ZeroMemory (EnumPtr, sizeof (MIG_OBJECTWITHPROPERTY_ENUM));
  1645. EnumPtr->Handle = MemAllocZeroed (sizeof (OBJECTWITHPROPERTY_HANDLE));
  1646. handle = (POBJECTWITHPROPERTY_HANDLE) EnumPtr->Handle;
  1647. //
  1648. // Obtain the object<->property linkage list from the property ID
  1649. //
  1650. handle->LinkageList = MemDbGetDoubleLinkageArrayByKeyHandle (
  1651. PropertyId,
  1652. PROPERTY_INDEX,
  1653. &handle->LinkageCount
  1654. );
  1655. handle->LinkageCount /= SIZEOF(KEYHANDLE);
  1656. if (!handle->LinkageList || !handle->LinkageCount) {
  1657. IsmAbortObjectWithPropertyEnum (EnumPtr);
  1658. __leave;
  1659. }
  1660. handle->LinkagePos = 0;
  1661. handle->PropertyId = PropertyId;
  1662. //
  1663. // Call the enum next routine to continue
  1664. //
  1665. result = IsmEnumNextObjectWithProperty (EnumPtr);
  1666. }
  1667. __finally {
  1668. }
  1669. return result;
  1670. }
  1671. BOOL
  1672. IsmEnumNextObjectWithProperty (
  1673. IN OUT PMIG_OBJECTWITHPROPERTY_ENUM EnumPtr
  1674. )
  1675. {
  1676. POBJECTWITHPROPERTY_HANDLE handle;
  1677. BOOL result = FALSE;
  1678. PTSTR p;
  1679. __try {
  1680. handle = (POBJECTWITHPROPERTY_HANDLE) EnumPtr->Handle;
  1681. if (!handle) {
  1682. __leave;
  1683. }
  1684. if (handle->LinkagePos >= handle->LinkageCount) {
  1685. IsmAbortObjectWithPropertyEnum (EnumPtr);
  1686. __leave;
  1687. }
  1688. EnumPtr->ObjectId = handle->LinkageList[handle->LinkagePos];
  1689. handle->LinkagePos++;
  1690. if (handle->ObjectPath) {
  1691. MemDbReleaseMemory (handle->ObjectPath);
  1692. INVALID_POINTER (handle->ObjectPath);
  1693. }
  1694. handle->ObjectPath = MemDbGetKeyFromHandle ((UINT) EnumPtr->ObjectId, 0);
  1695. if (!handle->ObjectPath) {
  1696. __leave;
  1697. }
  1698. p = _tcschr (handle->ObjectPath, TEXT('\\'));
  1699. if (!p) {
  1700. __leave;
  1701. }
  1702. EnumPtr->ObjectName = _tcsinc (p);
  1703. *p = 0;
  1704. EnumPtr->ObjectTypeId = GetObjectTypeId (handle->ObjectPath);
  1705. result = TRUE;
  1706. }
  1707. __finally {
  1708. }
  1709. return result;
  1710. }
  1711. VOID
  1712. IsmAbortObjectWithPropertyEnum (
  1713. IN OUT PMIG_OBJECTWITHPROPERTY_ENUM EnumPtr
  1714. )
  1715. {
  1716. POBJECTWITHPROPERTY_HANDLE handle;
  1717. if (EnumPtr->Handle) {
  1718. handle = (POBJECTWITHPROPERTY_HANDLE) EnumPtr->Handle;
  1719. if (handle->ObjectPath) {
  1720. MemDbReleaseMemory (handle->ObjectPath);
  1721. INVALID_POINTER (handle->ObjectPath);
  1722. }
  1723. if (handle->LinkageList) {
  1724. MemDbReleaseMemory (handle->LinkageList);
  1725. INVALID_POINTER (handle->LinkageList);
  1726. }
  1727. FreeAlloc (EnumPtr->Handle);
  1728. INVALID_POINTER (EnumPtr->Handle);
  1729. }
  1730. ZeroMemory (EnumPtr, sizeof (MIG_OBJECTWITHPROPERTY_ENUM));
  1731. }