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.

1680 lines
55 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995-2000.
  5. //
  6. // File: PropRec.hxx
  7. //
  8. // Contents: Record format for persistent property store
  9. //
  10. // Classes: CPropertyRecord
  11. //
  12. // History: 28-Dec-19 KyleP Created
  13. //
  14. //----------------------------------------------------------------------------
  15. #pragma once
  16. #include <propset.h>
  17. #include <cidebug.hxx>
  18. #include <pstore.hxx>
  19. class CStorageVariant;
  20. const PREV = 0;
  21. const NEXT = 1;
  22. const FREEBLOCKSIZE = 2;
  23. const cFreeListSlots = 3;
  24. //+-------------------------------------------------------------------------
  25. //
  26. // Class: COnDiskPropertyRecord
  27. //
  28. // Purpose: Manipulates property values for single object/record
  29. //
  30. // History: 28-Dec-95 KyleP Created
  31. // 29-May-97 KrishnaN Made records self describing
  32. // 16-Dec-97 KrishnaN Added support for "lean" records
  33. //
  34. // Notes: This class is like a template, that applies structure to a
  35. // single record of a memory-mapped file. Layout of data
  36. // members corresponds exactly to the on-disk version of the
  37. // property store.
  38. //
  39. // There are two types of records "normal" and "lean". Normal
  40. // records have all the support they need to handle overflows,
  41. // variable length records, and variable length properties. The
  42. // "lean" records, on the other hand, can only store fixed
  43. // properties. Since the size of a lean record is always known
  44. // and fixed (until changes to the metadata are made), we don't
  45. // need the ability for overflows and for variable length records.
  46. // That gives us an opportunity to eliminate a significant portion
  47. // of the COnDiskPropertyRecord overhead for a lean record.
  48. //
  49. // Layout of a normal record is as follows:
  50. // 1) Per-record state.
  51. // Count of additional records appended physically
  52. // to this one. Low bit used to indicate record
  53. // is in use.
  54. // Used space in variable property area (in dwords)
  55. // Link to overflow record.
  56. // 2) Existence bitmap. One dword / 16 properties, rounded up
  57. // to nearest dword. First bit (of two) indicates existence.
  58. // Second indicates existence is on overflow.
  59. // 3) Fixed length property storage.
  60. // 4) Variable length property storage. For each property:
  61. // Dword for size.
  62. // High word is size (in dwords) used by current property.
  63. // Low word is allocated size (in dwords).
  64. // Allocated space.
  65. //
  66. //
  67. // Layout of a lean record is as follows:
  68. //
  69. // 1) Existence bitmap. One dword / 16 properties, rounded up
  70. // to nearest dword. First bit (of two) indicates existence.
  71. // Second is unused but left in for compatibility with normal record.
  72. // 3) Fixed length property storage.
  73. //
  74. // Freelist Maintenance:
  75. //
  76. // When a record is not in use, it goes into the free list. This list
  77. // is a doubly linked list sorted by size. The next and prev pointers
  78. // used to be stored in the toplevel and overflow fields of the normal
  79. // record. With the introduction of the lean version of the record,
  80. // which doesn't have the toplevel and overflow fields, we need to
  81. // have two fields to be always present that can be used for link
  82. // tracking. The first and second fields of the data portion, pointed
  83. // to by _aul, will be used to store these ptrs. A third field is needed
  84. // to track the size of the next free block. Therefore the minimum
  85. // size of a record is being modified to include space for _aul[PREV], _aul[NEXT],
  86. // and _aul[FREEBLOCKSIZE]. When we start adding records, we will account for the
  87. // preallocation of these three ULONG fields.
  88. //
  89. //--------------------------------------------------------------------------
  90. #include <pshpack4.h>
  91. class COnDiskPropertyRecord
  92. {
  93. enum ERecType { eVirgin = 0x0000,
  94. eTopLevel = 0xAAAA,
  95. eOverflow = 0x5555,
  96. eFree = 0xBBBB,
  97. eTopLevelLean = 0xCCCC,
  98. eFreeLean = 0xDDDD};
  99. public:
  100. inline void * operator new( size_t size, ULONG record, BYTE * pBase, ULONG culRec );
  101. inline void operator delete( void * p );
  102. inline static ULONG MinStreamSize( ULONG record, ULONG culRec );
  103. //
  104. // Block linking
  105. //
  106. inline WORKID OverflowBlock() const;
  107. inline void SetOverflowBlock( WORKID wid );
  108. inline WORKID ToplevelBlock() const;
  109. inline void SetToplevelBlock( WORKID wid );
  110. inline void ClearToplevelField();
  111. //
  112. // Simple reads / writes.
  113. //
  114. void ReadFixed( ULONG Ordinal,
  115. ULONG Mask,
  116. ULONG oStart,
  117. ULONG cTotal,
  118. ULONG Type,
  119. PROPVARIANT & var,
  120. BYTE * pbExtra,
  121. unsigned * pcbExtra,
  122. PStorage & storage );
  123. BOOL ReadVariable( ULONG Ordinal,
  124. ULONG Mask,
  125. ULONG oStart,
  126. ULONG cTotal,
  127. ULONG cFixed,
  128. PROPVARIANT & var,
  129. BYTE * pbExtra,
  130. unsigned * pcbExtra );
  131. void WriteFixed( ULONG Ordinal,
  132. ULONG Mask,
  133. ULONG oStart,
  134. ULONG Type,
  135. ULONG cTotal,
  136. CStorageVariant const & var );
  137. BOOL WriteVariable( ULONG Ordinal,
  138. ULONG Mask,
  139. ULONG oStart,
  140. ULONG cTotal,
  141. ULONG cFixed,
  142. ULONG culRec,
  143. CStorageVariant const & var,
  144. PStorage & storage );
  145. //
  146. // Multi-record properties.
  147. //
  148. inline BOOL IsLongRecord();
  149. inline ULONG CountRecords() const;
  150. inline void MakeLongRecord( ULONG cRecords );
  151. inline BOOL IsValidType() const;
  152. inline BOOL IsValidInUseRecord( WORKID wid, ULONG cRecPerPage ) const;
  153. inline BOOL IsValidLength( WORKID wid, ULONG cRecPerPage ) const;
  154. inline BOOL AreLinksValid( WORKID widMax ) const;
  155. static ULONG CountNormalRecordsToStore( ULONG cTotal, ULONG culRec,
  156. CStorageVariant const & var );
  157. //
  158. // Free list management
  159. //
  160. inline void MakeNormalFreeRecord( ULONG cRecords, WORKID widNextFree,
  161. ULONG cNextFree, ULONG culRec );
  162. inline void MakeNormalFreeRecord( WORKID widNextFree,
  163. ULONG cNextFree, ULONG culRec );
  164. inline void MakeLeanFreeRecord( ULONG cRecords, WORKID widNextFree,
  165. ULONG cNextFree, ULONG culRec );
  166. inline void MakeLeanFreeRecord( WORKID widNextFree,
  167. ULONG cNextFree, ULONG culRec );
  168. inline ULONG GetNextFreeRecord() const;
  169. inline ULONG GetPreviousFreeRecord() const;
  170. inline ULONG GetNextFreeSize() const;
  171. inline void SetNextFree( WORKID widNextFree, ULONG cNextFree );
  172. inline void SetPreviousFreeRecord( WORKID widPreviousFree );
  173. //
  174. // Overflow records chaining.
  175. //
  176. inline ULONG GetOverflowChainLength() const;
  177. inline void IncrementOverflowChainLength();
  178. inline void SetOverflowChainLength( ULONG cOvfl );
  179. //
  180. // Existence / Use
  181. //
  182. inline BOOL IsInUse() const;
  183. inline BOOL IsTopLevel() const;
  184. inline BOOL IsNormalTopLevel() const;
  185. inline BOOL IsOverflow() const;
  186. inline BOOL IsLeanFreeRecord() const;
  187. inline BOOL IsFreeRecord() const;
  188. inline BOOL IsFreeOrVirginRecord() const;
  189. inline void MakeNewNormalTopLevel();
  190. inline void MakeNewLeanTopLevel();
  191. inline void MakeNewOverflow();
  192. inline void ForceOverflow();
  193. inline void ClearNormal( ULONG culRec );
  194. inline void ClearLean( ULONG culRec );
  195. inline void ClearAll( ULONG culRec );
  196. inline BOOL HasProperties( ULONG cTotal );
  197. inline USHORT Type() const;
  198. inline void SetType(USHORT type);
  199. //
  200. // Reader / Writer
  201. //
  202. inline BOOL IsBeingWritten();
  203. inline BOOL IsBeingRead();
  204. inline void AddReader();
  205. inline void RemoveReader();
  206. inline void AddWriter();
  207. inline void RemoveWriter();
  208. # if CIDBG == 1
  209. inline BOOL LokIsBeingWrittenTwice();
  210. inline BOOL IsNormalEmpty( ULONG culRec );
  211. inline BOOL IsLeanEmpty( ULONG culRec );
  212. # endif
  213. inline static ULONG FixedOverheadLean();
  214. inline static ULONG FixedOverheadNormal();
  215. inline static ULONG MinimalOverheadNormal();
  216. inline BOOL IsStored( ULONG Ordinal, ULONG mask );
  217. inline BOOL IsStoredOnOverflow( ULONG Ordinal, ULONG mask );
  218. //
  219. // Backup support
  220. //
  221. inline void * GetTopLevelFieldAddress() const
  222. {
  223. Win4Assert(!IsLeanRecord());
  224. return (void *) &((SNormalRecord *)&Data)->_ulToplevel;
  225. };
  226. // Lean record support
  227. inline BOOL IsLeanRecord() const
  228. {
  229. return (Type() == eTopLevelLean ||
  230. Type() == eFreeLean);
  231. }
  232. private:
  233. inline void SetStored( ULONG Ordinal, ULONG mask );
  234. inline void ClearStored( ULONG Ordinal, ULONG mask );
  235. inline void SetStoredOnOverflow( ULONG Ordinal, ULONG mask );
  236. inline void ClearStoredOnOverflow( ULONG Ordinal, ULONG mask );
  237. inline static ULONG UsedSize( ULONG ul );
  238. inline static ULONG AllocatedSize( ULONG ul ) { return (ul & 0xFFFF); }
  239. inline static void SetUsedSize( ULONG * pul, ULONG ul );
  240. inline static void SetAllocatedSize( ULONG * pul, ULONG ul );
  241. inline static void MarkOverflow( ULONG * pul );
  242. inline static BOOL IsOverflow( ULONG ul );
  243. inline ULONG FreeVariableSpace( ULONG cTotal, ULONG cFixed, ULONG oStart, ULONG cbRec );
  244. inline ULONG * FindVariableProp( ULONG Ordinal, ULONG cFixed, ULONG cTotal, ULONG oStart );
  245. static void RightCompress( ULONG * pul, ULONG cul, ULONG cRemaining );
  246. static ULONG * LeftCompress( ULONG * pul, ULONG cul, ULONG * pulEnd );
  247. //
  248. // Special optimized Unicode writes.
  249. //
  250. static BOOL IsUnicodeSpecial( CStorageVariant const & var, ULONG & cul );
  251. static BOOL IsUnicodeSpecial( SERIALIZEDPROPERTYVALUE const * pProp,
  252. ULONG & cb );
  253. static void WriteUnicodeSpecial( CStorageVariant const & var,
  254. SERIALIZEDPROPERTYVALUE * pProp );
  255. static void ReadUnicodeSpecial( SERIALIZEDPROPERTYVALUE const * pProp,
  256. PROPVARIANT & var,
  257. BYTE * pbExtra );
  258. static void ReadUnicodeSpecialCTMA( SERIALIZEDPROPERTYVALUE const * pProp,
  259. PROPVARIANT & var );
  260. struct SNormalRecord
  261. {
  262. USHORT _type; // Type of the record
  263. USHORT _cAdditionalRecords; // For long records, size (in records) of long record.
  264. ULONG _culVariableUsed; // Bytes of record that are in use. Variable section only.
  265. WORKID _ulOverflow; // Pointer to overflow block.
  266. WORKID _ulToplevel; // Pointer to the toplevel record. For toplevel
  267. // records, this will be the length of the
  268. // chain.
  269. ULONG _aul[1]; // Rest of block is variable:
  270. // a) Existence bits
  271. // b) Fixed size properties
  272. // c) Variable size properties
  273. };
  274. struct SLeanRecord
  275. {
  276. USHORT _type; // Type of the record
  277. USHORT _cAdditionalRecords; // For long records, size (in records) of long record.
  278. // We only use this field for free list maintenance.
  279. // "In use" lean records are always one record long.
  280. ULONG _aul[1]; // Rest of block is variable:
  281. // a) Existence bits
  282. // b) Fixed size properties
  283. };
  284. // Convenient inline functions
  285. // _cAdditionalRecords is at the same position in both
  286. // structures. Cast to either structure is fine.
  287. inline USHORT AdditionalRecords() const
  288. {
  289. Win4Assert(offsetof(SNormalRecord, _cAdditionalRecords) ==
  290. offsetof(SLeanRecord, _cAdditionalRecords));
  291. return ((SNormalRecord *)&Data)->_cAdditionalRecords;
  292. }
  293. inline void SetAdditionalRecords(USHORT cRecs)
  294. {
  295. Win4Assert(offsetof(SNormalRecord, _cAdditionalRecords) ==
  296. offsetof(SLeanRecord, _cAdditionalRecords));
  297. ((SNormalRecord *)&Data)->_cAdditionalRecords = cRecs;
  298. }
  299. inline ULONG VariableUsed() const
  300. {
  301. Win4Assert(!IsLeanRecord());
  302. return ((SNormalRecord *)&Data)->_culVariableUsed;
  303. }
  304. inline void SetVariableUsed(ULONG ulVarUsed)
  305. {
  306. Win4Assert(!IsLeanRecord());
  307. ((SNormalRecord *)&Data)->_culVariableUsed = ulVarUsed;
  308. }
  309. // All we have is a buffer containing the on-disk bits of the record. Depending
  310. // on the type of the record, we will cast that buffer into SNormalRecord or
  311. // SLeanRecord.
  312. ULONG Data;
  313. };
  314. #include <poppack.h>
  315. //+---------------------------------------------------------------------------
  316. //
  317. // Member: COnDiskPropertyRecord::operator new, public
  318. //
  319. // Synopsis: Special operator new (computes offset of record in file)
  320. //
  321. // Arguments: [size] -- Required (and unused) parameter
  322. // [record] -- Record number
  323. // [pBase] -- Address of record 0
  324. // [culRec] -- Size in dwords of single record
  325. //
  326. // History: 27-Dec-95 KyleP Created.
  327. //
  328. //----------------------------------------------------------------------------
  329. inline void * COnDiskPropertyRecord::operator new( size_t size,
  330. ULONG record,
  331. BYTE * pBase,
  332. ULONG culRec )
  333. {
  334. ciDebugOut(( DEB_PROPSTORE,
  335. "PROPSTORE: Opening record at offset 0x%x (%d)\n",
  336. record * culRec * 4,
  337. record * culRec * 4 ));
  338. return pBase + record * culRec * 4;
  339. }
  340. //+---------------------------------------------------------------------------
  341. //
  342. // Member: COnDiskPropertyRecord::operator delete, public
  343. //
  344. // Synopsis: Just to make sure it isn't called...
  345. //
  346. // History: 27-Dec-95 KyleP Created.
  347. //
  348. //----------------------------------------------------------------------------
  349. inline void COnDiskPropertyRecord::operator delete( void * p )
  350. {
  351. // No action. This is mapped onto a file.
  352. }
  353. // _type is the first field of both SNormalRecord
  354. // and SLeanRecord, so we access it through either
  355. inline USHORT COnDiskPropertyRecord::Type() const
  356. {
  357. return ((SNormalRecord *)&Data)->_type;
  358. }
  359. inline void COnDiskPropertyRecord::SetType(USHORT type)
  360. {
  361. ((SNormalRecord *)&Data)->_type = type;
  362. }
  363. //+---------------------------------------------------------------------------
  364. //
  365. // Member: COnDiskPropertyRecord::IsLongRecord, public
  366. //
  367. // Returns: TRUE if record is long (consists of more than one
  368. // physically contiguous record).
  369. //
  370. // History: 27-Dec-95 KyleP Created.
  371. //
  372. //----------------------------------------------------------------------------
  373. inline BOOL COnDiskPropertyRecord::IsLongRecord()
  374. {
  375. // Lean records can only be long when they are in the free list
  376. #if CIDBG == 1
  377. if (eTopLevelLean == Type())
  378. Win4Assert(0 == AdditionalRecords());
  379. #endif // CIDBG
  380. return ( AdditionalRecords() != 0);
  381. }
  382. //+---------------------------------------------------------------------------
  383. //
  384. // Member: COnDiskPropertyRecord::CountRecords, public
  385. //
  386. // Returns: Size of record (in one-records)
  387. //
  388. // History: 27-Dec-95 KyleP Created.
  389. //
  390. //----------------------------------------------------------------------------
  391. inline ULONG COnDiskPropertyRecord::CountRecords() const
  392. {
  393. // Lean records can only be long when they are in the free list
  394. #if CIDBG == 1
  395. if (eTopLevelLean == Type())
  396. Win4Assert(0 == AdditionalRecords());
  397. #endif // CIDBG
  398. return AdditionalRecords() + 1;
  399. }
  400. //+---------------------------------------------------------------------------
  401. //
  402. // Member: COnDiskPropertyRecord::MakeLongRecord, public
  403. //
  404. // Synopsis: Indicates record is long.
  405. //
  406. // Arguments: [cRecords] -- Number of physically contiguous records.
  407. //
  408. // History: 27-Dec-95 KyleP Created.
  409. //
  410. //----------------------------------------------------------------------------
  411. inline void COnDiskPropertyRecord::MakeLongRecord( ULONG cRecords )
  412. {
  413. Win4Assert( cRecords >= 1 );
  414. // Win4Assert( !HasProperties( 1 ) );
  415. // Lean records can only be long when they are in the free list
  416. #if CIDBG == 1
  417. if (eTopLevelLean == Type())
  418. Win4Assert(1 == cRecords);
  419. #endif // CIDBG
  420. SetAdditionalRecords((USHORT) (cRecords - 1));
  421. }
  422. //+---------------------------------------------------------------------------
  423. //
  424. // Member: COnDiskProperyRecord::IsFreeRecord
  425. //
  426. // Synopsis: Tests if the current record is a Free record.
  427. //
  428. // History: 2-23-96 srikants Created
  429. //
  430. //----------------------------------------------------------------------------
  431. inline BOOL COnDiskPropertyRecord::IsFreeRecord() const
  432. {
  433. return (eFreeLean == Type() || eFree == Type());
  434. }
  435. //+---------------------------------------------------------------------------
  436. //
  437. // Member: COnDiskProperyRecord::IsLeanFreeRecord
  438. //
  439. // Synopsis: Tests if the current record is a Lean Free record.
  440. //
  441. // History: Dec-31-97 KrishnaN Created
  442. //
  443. //----------------------------------------------------------------------------
  444. inline BOOL COnDiskPropertyRecord::IsLeanFreeRecord() const
  445. {
  446. return (eFreeLean == Type());
  447. }
  448. //+---------------------------------------------------------------------------
  449. //
  450. // Member: COnDiskProperyRecord::IsFreeOrVirginRecord
  451. //
  452. // Synopsis: Tests if the current record is a Free or a virgin record.
  453. //
  454. // History: 12-03-97 krishnaN Created
  455. //
  456. //----------------------------------------------------------------------------
  457. inline BOOL COnDiskPropertyRecord::IsFreeOrVirginRecord() const
  458. {
  459. return (eFree == Type() || eFreeLean == Type() ||
  460. eVirgin == Type());
  461. }
  462. //+---------------------------------------------------------------------------
  463. //
  464. // Member: COnDiskPropertyRecord::MakeNormalFreeRecord
  465. //
  466. // Synopsis: Makes the current normal record a free record.
  467. //
  468. // Arguments: [ulNextFree] - The workid of the next free record
  469. // [cFree] - Size of next free record
  470. // [culRec] - Count of ULONGs per record.
  471. //
  472. // History: 4-11-96 srikants Created
  473. //
  474. // Notes: It is assumed that the "_cAdditionalRecords" is correctly set
  475. //
  476. //----------------------------------------------------------------------------
  477. inline void COnDiskPropertyRecord::MakeNormalFreeRecord( WORKID ulNextFree,
  478. ULONG cFree,
  479. ULONG culRec )
  480. {
  481. ClearNormal( culRec );
  482. SetNextFree( ulNextFree, cFree );
  483. }
  484. //+---------------------------------------------------------------------------
  485. //
  486. // Member: COnDiskPropertyRecord::MakeLeanFreeRecord
  487. //
  488. // Synopsis: Makes the current lean record a free record.
  489. //
  490. // Arguments: [ulNextFree] - The workid of the next free record
  491. // [cFree] - Size of next free record
  492. // [culRec] - Count of ULONGs per record.
  493. //
  494. // History: 17-12-97 KrishnaN Created
  495. //
  496. // Notes: It is assumed that the "_cAdditionalRecords" is correctly set
  497. //
  498. //----------------------------------------------------------------------------
  499. inline void COnDiskPropertyRecord::MakeLeanFreeRecord( WORKID ulNextFree,
  500. ULONG cFree,
  501. ULONG culRec )
  502. {
  503. ClearLean( culRec );
  504. SetNextFree( ulNextFree, cFree );
  505. }
  506. //+---------------------------------------------------------------------------
  507. //
  508. // Member: COnDiskPropertyRecord::MakeNormalFreeRecord
  509. //
  510. // Synopsis: Makes the current record a free record of length "cRecords"
  511. //
  512. // Arguments: [cRecords] - Length of this block in "records"
  513. // [ulNextFree] - The next free record wid
  514. // [cFree] - Size of next free record
  515. // [culRec] - Count of ULONGs per record
  516. //
  517. // History: 4-11-96 srikants Created
  518. //
  519. //----------------------------------------------------------------------------
  520. inline void COnDiskPropertyRecord::MakeNormalFreeRecord(
  521. ULONG cRecords,
  522. WORKID ulNextFree,
  523. ULONG cFree,
  524. ULONG culRec )
  525. {
  526. MakeLongRecord( cRecords );
  527. MakeNormalFreeRecord( ulNextFree, cFree, culRec );
  528. }
  529. //+---------------------------------------------------------------------------
  530. //
  531. // Member: COnDiskPropertyRecord::MakeNormalFreeRecord
  532. //
  533. // Synopsis: Makes the current record a free record of length "cRecords"
  534. //
  535. // Arguments: [cRecords] - Length of this block in "records"
  536. // [ulNextFree] - The next free record wid
  537. // [cFree] - Size of next free record
  538. // [culRec] - Count of ULONGs per record
  539. //
  540. // History: 12-17-97 KrishnaN Created
  541. //
  542. //----------------------------------------------------------------------------
  543. inline void COnDiskPropertyRecord::MakeLeanFreeRecord(
  544. ULONG cRecords,
  545. WORKID ulNextFree,
  546. ULONG cFree,
  547. ULONG culRec )
  548. {
  549. // Mark it to be a free record before attempting to make it a long
  550. // record.
  551. MakeLeanFreeRecord( ulNextFree, cFree, culRec );
  552. MakeLongRecord( cRecords );
  553. }
  554. //+---------------------------------------------------------------------------
  555. //
  556. // Member: COnDiskPropertyRecord::SetNextFreeRecord
  557. //
  558. // Synopsis: Sets the next free record.
  559. //
  560. // History: 4-10-96 srikants Created
  561. //
  562. //----------------------------------------------------------------------------
  563. inline void COnDiskPropertyRecord::SetNextFree( WORKID widNextFree,
  564. ULONG cNextFree )
  565. {
  566. Win4Assert( IsFreeRecord() );
  567. ULONG *aul;
  568. if (eFree == Type())
  569. aul = ((SNormalRecord *)&Data)->_aul;
  570. else
  571. aul = ((SLeanRecord *)&Data)->_aul;
  572. aul[NEXT] = widNextFree;
  573. aul[FREEBLOCKSIZE] = cNextFree;
  574. }
  575. //+---------------------------------------------------------------------------
  576. //
  577. // Member: COnDiskPropertyRecord::SetPreviousFreeRecord
  578. //
  579. // Synopsis: Sets the previous free record.
  580. //
  581. // History: 4-10-96 srikants Created
  582. //
  583. //----------------------------------------------------------------------------
  584. inline void COnDiskPropertyRecord::SetPreviousFreeRecord( WORKID widPrevFree )
  585. {
  586. Win4Assert( IsFreeRecord() );
  587. if (eFree == Type())
  588. ((SNormalRecord *)&Data)->_aul[PREV] = widPrevFree;
  589. else
  590. ((SLeanRecord *)&Data)->_aul[PREV] = widPrevFree;
  591. }
  592. //+---------------------------------------------------------------------------
  593. //
  594. // Member: COnDiskPropertyRecord::GetNextFreeRecord
  595. //
  596. // Synopsis: Gets the next free record.
  597. //
  598. // History: 4-10-96 srikants Created
  599. //
  600. //----------------------------------------------------------------------------
  601. inline ULONG COnDiskPropertyRecord::GetNextFreeRecord() const
  602. {
  603. Win4Assert( IsFreeRecord() );
  604. if (eFree == Type())
  605. return ((SNormalRecord *)&Data)->_aul[NEXT];
  606. else
  607. return ((SLeanRecord *)&Data)->_aul[NEXT];
  608. }
  609. //+---------------------------------------------------------------------------
  610. //
  611. // Member: COnDiskPropertyRecord::GetPreviousFreeRecord
  612. //
  613. // Synopsis: Gets the previous free record.
  614. //
  615. // History: 4-10-96 srikants Created
  616. //
  617. //----------------------------------------------------------------------------
  618. inline ULONG COnDiskPropertyRecord::GetPreviousFreeRecord() const
  619. {
  620. Win4Assert( IsFreeRecord() );
  621. if (eFree == Type())
  622. return ((SNormalRecord *)&Data)->_aul[PREV];
  623. else
  624. return ((SLeanRecord *)&Data)->_aul[PREV];
  625. }
  626. //+---------------------------------------------------------------------------
  627. //
  628. // Member: COnDiskPropertyRecord::GetNextFreeSize
  629. //
  630. // Synopsis: Gets the next free blocks size.
  631. //
  632. // History: 4-10-96 srikants Created
  633. //
  634. //----------------------------------------------------------------------------
  635. inline ULONG COnDiskPropertyRecord::GetNextFreeSize() const
  636. {
  637. Win4Assert( IsFreeRecord() );
  638. if (eFree == Type())
  639. return ((SNormalRecord *)&Data)->_aul[FREEBLOCKSIZE];
  640. else
  641. return ((SLeanRecord *)&Data)->_aul[FREEBLOCKSIZE];
  642. }
  643. //+---------------------------------------------------------------------------
  644. //
  645. // Member: COnDiskPropertyRecord::MinStreamSize, public
  646. //
  647. // Synopsis: Computes position of record in stream
  648. //
  649. // Arguments: [record] -- Record number
  650. // [culRec] -- Size in dwords of single record
  651. //
  652. // Returns: Minimum size stream that can hold this record.
  653. //
  654. // History: 27-Dec-95 KyleP Created.
  655. //
  656. //----------------------------------------------------------------------------
  657. inline ULONG COnDiskPropertyRecord::MinStreamSize( ULONG record, ULONG culRec )
  658. {
  659. return (record + 1) * culRec * 4;
  660. }
  661. //+---------------------------------------------------------------------------
  662. //
  663. // Member: COnDiskPropertyRecord::OverflowBlock, public
  664. //
  665. // Returns: Overflow block id (zero if no overflow block)
  666. //
  667. // History: 27-Dec-95 KyleP Created.
  668. //
  669. //
  670. //----------------------------------------------------------------------------
  671. inline WORKID COnDiskPropertyRecord::OverflowBlock() const
  672. {
  673. Win4Assert(!IsLeanRecord());
  674. return ((SNormalRecord *)&Data)->_ulOverflow;
  675. }
  676. //+---------------------------------------------------------------------------
  677. //
  678. // Member: COnDiskPropertyRecord::SetOverflowBlock, public
  679. //
  680. // Synopsis: Sets overflow block id (zero if no overflow block)
  681. //
  682. // Arguments: [wid] -- Workid (record number) of link
  683. //
  684. // History: 27-Dec-95 KyleP Created.
  685. //
  686. //----------------------------------------------------------------------------
  687. inline void COnDiskPropertyRecord::SetOverflowBlock( WORKID wid )
  688. {
  689. Win4Assert(!IsLeanRecord());
  690. ((SNormalRecord *)&Data)->_ulOverflow = wid;
  691. }
  692. //+---------------------------------------------------------------------------
  693. //
  694. // Member: COnDiskPropertyRecord::ToplevelBlock
  695. //
  696. // Synopsis: Returns the previous block value.
  697. //
  698. // History: 4-10-96 srikants Created
  699. //
  700. // Notes: For a top-level record, this will be the length of the
  701. // overflow chain records.
  702. // For a free list record, this will be the size of the next
  703. // free block in the list.
  704. //
  705. //----------------------------------------------------------------------------
  706. inline WORKID COnDiskPropertyRecord::ToplevelBlock() const
  707. {
  708. Win4Assert(!IsLeanRecord());
  709. return ((SNormalRecord *)&Data)->_ulToplevel;
  710. }
  711. //+---------------------------------------------------------------------------
  712. //
  713. // Member: COnDiskPropertyRecord::SetToplevelBlock
  714. //
  715. // Synopsis: Updates the previous block value.
  716. //
  717. // Arguments: [widPrev] - Value of the previous block
  718. //
  719. // History: 4-10-96 srikants Created
  720. //
  721. //----------------------------------------------------------------------------
  722. inline void COnDiskPropertyRecord::SetToplevelBlock( WORKID widToplevel )
  723. {
  724. Win4Assert( eOverflow == Type() );
  725. ((SNormalRecord *)&Data)->_ulToplevel = widToplevel;
  726. }
  727. //+---------------------------------------------------------------------------
  728. //
  729. // Member: COnDiskPropertyRecord::ClearToplevelField, public
  730. //
  731. // Arguments:
  732. //
  733. // History: 4-10-96 srikants Created
  734. //
  735. //----------------------------------------------------------------------------
  736. inline void COnDiskPropertyRecord::ClearToplevelField()
  737. {
  738. Win4Assert( eFree == Type() || eVirgin == Type() );
  739. // can't use SetToplevelBlock because that is to be used
  740. // only with overflow records.
  741. ((SNormalRecord *)&Data)->_ulToplevel = 0;
  742. }
  743. //+---------------------------------------------------------------------------
  744. //
  745. // Member: COnDiskPropertyRecord::GetOverflowChainLength, public
  746. //
  747. // Arguments:
  748. //
  749. // History: 4-10-96 srikants Created
  750. //
  751. //----------------------------------------------------------------------------
  752. inline ULONG COnDiskPropertyRecord::GetOverflowChainLength() const
  753. {
  754. Win4Assert( eTopLevel == Type() );
  755. return ToplevelBlock();
  756. }
  757. //+---------------------------------------------------------------------------
  758. //
  759. // Member: COnDiskPropertyRecord::IncrementOverflowChainLength, public
  760. //
  761. // Arguments:
  762. //
  763. // History: 4-10-96 srikants Created
  764. //
  765. //----------------------------------------------------------------------------
  766. inline void COnDiskPropertyRecord::IncrementOverflowChainLength()
  767. {
  768. Win4Assert( eTopLevel == Type() );
  769. (((SNormalRecord *)&Data)->_ulToplevel)++;
  770. }
  771. //+---------------------------------------------------------------------------
  772. //
  773. // Member: COnDiskPropertyRecord::SetOverflowChainLength, public
  774. //
  775. // Arguments: [cCount] -- Size of overflow chain
  776. //
  777. // History: 4-10-96 srikants Created
  778. //
  779. //----------------------------------------------------------------------------
  780. inline void COnDiskPropertyRecord::SetOverflowChainLength( ULONG cCount )
  781. {
  782. Win4Assert( !IsLeanRecord() );
  783. // can't use SetToplevelBlock because that is to be used
  784. // only with overflow records.
  785. ((SNormalRecord *)&Data)->_ulToplevel = cCount;
  786. }
  787. //+---------------------------------------------------------------------------
  788. //
  789. // Member: COnDiskPropertyRecord::IsInUse, public
  790. //
  791. // Returns: TRUE if record is in use.
  792. //
  793. // History: 27-Dec-95 KyleP Created.
  794. //
  795. //----------------------------------------------------------------------------
  796. inline BOOL COnDiskPropertyRecord::IsInUse() const
  797. {
  798. return (eTopLevel == Type() || eOverflow == Type() ||
  799. eTopLevelLean == Type());
  800. }
  801. //+---------------------------------------------------------------------------
  802. //
  803. // Member: COnDiskPropertyRecord::HasProperties, public
  804. //
  805. // Arguments: [cTotal] -- Total number of properties in record.
  806. //
  807. // Returns: TRUE if record has properties stored on it. May be
  808. // in use. Used for debugging.
  809. //
  810. // History: 22-Feb-96 KyleP Created.
  811. //
  812. //----------------------------------------------------------------------------
  813. inline BOOL COnDiskPropertyRecord::HasProperties( ULONG cTotal )
  814. {
  815. ULONG *aul;
  816. // This won't work if we have a "lean virgin" record. In that case,
  817. // we need to have separate functions for lean and normal records.
  818. Win4Assert(eVirgin != Type());
  819. if (IsLeanRecord())
  820. aul = ((SLeanRecord *)&Data)->_aul;
  821. else
  822. aul = ((SNormalRecord *)&Data)->_aul;
  823. for ( ULONG cBitWords = ((cTotal-1) / 16) + 1; cBitWords > 0; cBitWords-- )
  824. {
  825. if ( aul[cBitWords-1] != 0 )
  826. return TRUE;
  827. }
  828. return FALSE;
  829. }
  830. //+---------------------------------------------------------------------------
  831. //
  832. // Member: COnDiskPropertyRecord::MakeNewNormalTopLevel
  833. //
  834. // Synopsis: Marks the current record as a normal top level record.
  835. //
  836. // History: 2-23-96 srikants Created
  837. //
  838. //----------------------------------------------------------------------------
  839. inline void COnDiskPropertyRecord::MakeNewNormalTopLevel()
  840. {
  841. Win4Assert(!IsLeanRecord());
  842. SetType(eTopLevel);
  843. ((SNormalRecord *)&Data)->_ulToplevel =
  844. ((SNormalRecord *)&Data)->_ulOverflow = 0; // Setting the length of overflow chain
  845. SetVariableUsed(0);
  846. // reset the ULONGs of _aul used for free list mgmt.
  847. RtlZeroMemory(((SNormalRecord *)&Data)->_aul, cFreeListSlots*sizeof(ULONG));
  848. }
  849. //+---------------------------------------------------------------------------
  850. //
  851. // Member: COnDiskPropertyRecord::MakeNewLeanTopLevel
  852. //
  853. // Synopsis: Marks the current record as a lean top level record.
  854. //
  855. // History: 17-Dec-97 KrishnaN Created
  856. //
  857. //----------------------------------------------------------------------------
  858. inline void COnDiskPropertyRecord::MakeNewLeanTopLevel()
  859. {
  860. SetType(eTopLevelLean);
  861. // reset the ULONGs of _aul used for free list mgmt.
  862. RtlZeroMemory(((SLeanRecord *)&Data)->_aul, cFreeListSlots*sizeof(ULONG));
  863. }
  864. //+---------------------------------------------------------------------------
  865. //
  866. // Member: COnDiskProperyRecord::IsTopLevel
  867. //
  868. // Synopsis: Tests if the current record is a TopLevel record.
  869. //
  870. // History: 2-23-96 srikants Created
  871. //
  872. //----------------------------------------------------------------------------
  873. inline BOOL COnDiskPropertyRecord::IsTopLevel() const
  874. {
  875. return (eTopLevel == Type() || eTopLevelLean == Type());
  876. }
  877. //+---------------------------------------------------------------------------
  878. //
  879. // Member: COnDiskProperyRecord::IsNormalTopLevel
  880. //
  881. // Synopsis: Tests if the current record is a TopLevel record.
  882. //
  883. // History: 2-23-96 srikants Created
  884. //
  885. //----------------------------------------------------------------------------
  886. inline BOOL COnDiskPropertyRecord::IsNormalTopLevel() const
  887. {
  888. return (eTopLevel == Type());
  889. }
  890. //+---------------------------------------------------------------------------
  891. //
  892. // Member: COnDiskPropertyRecord::MakeNewOverflow
  893. //
  894. // Synopsis: Marks the record as an overflow record
  895. //
  896. // History: 4-10-96 srikants Created
  897. //
  898. //----------------------------------------------------------------------------
  899. inline void COnDiskPropertyRecord::MakeNewOverflow()
  900. {
  901. Win4Assert(!IsLeanRecord());
  902. SetType(eOverflow);
  903. ((SNormalRecord *)&Data)->_ulToplevel =
  904. ((SNormalRecord *)&Data)->_ulOverflow = 0; // Setting the length of overflow chain
  905. SetVariableUsed(0);
  906. // reset the ULONGs of _aul used for free list mgmt.
  907. RtlZeroMemory(((SNormalRecord *)&Data)->_aul, cFreeListSlots*sizeof(ULONG));
  908. }
  909. inline void COnDiskPropertyRecord::ForceOverflow()
  910. {
  911. Win4Assert(!IsLeanRecord());
  912. SetType(eOverflow);
  913. }
  914. //+---------------------------------------------------------------------------
  915. //
  916. // Member: COnDiskPropertyRecord::IsOverflow
  917. //
  918. // Synopsis: Tests if this is an overflow record.
  919. //
  920. // History: 4-10-96 srikants Created
  921. //
  922. //----------------------------------------------------------------------------
  923. inline BOOL COnDiskPropertyRecord::IsOverflow() const
  924. {
  925. return eOverflow == Type();
  926. }
  927. //+---------------------------------------------------------------------------
  928. //
  929. // Member: COnDiskPropertyRecord::IsValidLength
  930. //
  931. // Synopsis: Tests if the length is valid for this record for the given
  932. // WORKID and records per page. A record can never span page and
  933. // so the WORKID will help us determine if the length is valid
  934. // or not.
  935. //
  936. // Arguments: [wid] - WORKID of this record
  937. // [cRecPerPage] - Number of records per page.
  938. //
  939. // History: 4-10-96 srikants Created
  940. //
  941. //----------------------------------------------------------------------------
  942. inline BOOL COnDiskPropertyRecord::IsValidLength( WORKID wid, ULONG cRecPerPage ) const
  943. {
  944. WORKID offset = wid % cRecPerPage;
  945. // Lean records can only be long when they are in the free list
  946. #if CIDBG == 1
  947. if (eTopLevelLean == Type())
  948. Win4Assert(0 == AdditionalRecords());
  949. #endif // CIDBG
  950. return offset+AdditionalRecords() < cRecPerPage;
  951. }
  952. inline BOOL COnDiskPropertyRecord::IsValidInUseRecord( WORKID wid, ULONG cRecPerPage ) const
  953. {
  954. if ( eTopLevel == Type() || eOverflow == Type() || eTopLevelLean == Type() )
  955. {
  956. return IsValidLength( wid, cRecPerPage );
  957. }
  958. else
  959. return FALSE;
  960. }
  961. inline BOOL COnDiskPropertyRecord::IsValidType() const
  962. {
  963. return eTopLevel == Type() ||
  964. eOverflow == Type() ||
  965. eFree == Type() ||
  966. eVirgin == Type() ||
  967. eFreeLean == Type() ||
  968. eTopLevelLean== Type();
  969. }
  970. //+---------------------------------------------------------------------------
  971. //
  972. // Member: COnDiskPropertyRecord::AreLinksValid
  973. //
  974. // Synopsis: Tests if the forward and backward links are valid given the
  975. // widMax.
  976. //
  977. // Arguments: [widMax] - The maximum workid that is in use for the entire
  978. // property store.
  979. //
  980. // History: 4-10-96 srikants Created
  981. //
  982. //----------------------------------------------------------------------------
  983. inline BOOL COnDiskPropertyRecord::AreLinksValid( WORKID widMax ) const
  984. {
  985. // If this method is used for free or virgin records, we will need a
  986. // conditional return. The links for free records are in _aul[PREV] and _aul[NEXT].
  987. Win4Assert(!IsFreeOrVirginRecord());
  988. if (IsLeanRecord())
  989. return TRUE; // no links to worry about.
  990. else
  991. return OverflowBlock() <= widMax && ToplevelBlock() <= widMax;
  992. }
  993. //+---------------------------------------------------------------------------
  994. //
  995. // Member: COnDiskPropertyRecord::ClearNormal, public
  996. //
  997. // Synopsis: Zero complete normal record.
  998. //
  999. // Arguments: [culRec] -- Size in dwords of record
  1000. //
  1001. // History: 27-Dec-95 KyleP Created.
  1002. //
  1003. //----------------------------------------------------------------------------
  1004. inline void COnDiskPropertyRecord::ClearNormal( ULONG culRec )
  1005. {
  1006. Win4Assert( 2 == offsetof( SNormalRecord, _cAdditionalRecords ) );
  1007. Win4Assert( 4 == offsetof( SNormalRecord, _culVariableUsed ) );
  1008. RtlZeroMemory( &((SNormalRecord *)&Data)->_culVariableUsed,
  1009. culRec * CountRecords() * sizeof (ULONG) -
  1010. offsetof( SNormalRecord, _culVariableUsed ) );
  1011. SetType(eFree);
  1012. }
  1013. //+---------------------------------------------------------------------------
  1014. //
  1015. // Member: COnDiskPropertyRecord::ClearLean, public
  1016. //
  1017. // Synopsis: Zero complete lean record.
  1018. //
  1019. // Arguments: [culRec] -- Size in dwords of record
  1020. //
  1021. // History: 17-Dec-97 KrishnaN Created.
  1022. //
  1023. //----------------------------------------------------------------------------
  1024. inline void COnDiskPropertyRecord::ClearLean( ULONG culRec )
  1025. {
  1026. RtlZeroMemory( ((SLeanRecord *)&Data)->_aul,
  1027. culRec * CountRecords() * sizeof (ULONG) -
  1028. offsetof( SLeanRecord, _aul ) );
  1029. SetType(eFreeLean);
  1030. }
  1031. //+---------------------------------------------------------------------------
  1032. //
  1033. // Member: COnDiskPropertyRecord::ClearAll
  1034. //
  1035. // Synopsis: Clears the entire record to be 0 filled.
  1036. //
  1037. // Arguments: [culRec] -
  1038. //
  1039. // History: 3-25-96 srikants Created
  1040. //
  1041. //----------------------------------------------------------------------------
  1042. inline void COnDiskPropertyRecord::ClearAll( ULONG culRec )
  1043. {
  1044. RtlZeroMemory(&Data, culRec*sizeof(ULONG));
  1045. }
  1046. //+---------------------------------------------------------------------------
  1047. //
  1048. // Member: COnDiskPropertyRecord::FixedOverheadNormal, public
  1049. //
  1050. // Returns: Size of normal record including 3 dwords for free list mgmt.
  1051. //
  1052. // History: 27-Dec-95 KyleP Created.
  1053. //
  1054. //----------------------------------------------------------------------------
  1055. inline ULONG COnDiskPropertyRecord::FixedOverheadNormal()
  1056. {
  1057. // We need to preallocate the first three ULONGs of the variable
  1058. // section of the record for free list mgmt.
  1059. return ((ULONG) (ULONG_PTR)&((SNormalRecord *)0)->_aul[3]) / sizeof(ULONG);
  1060. }
  1061. //+---------------------------------------------------------------------------
  1062. //
  1063. // Member: COnDiskPropertyRecord::MinimalOverheadNormal, public
  1064. //
  1065. // Returns: Size of normal record, sans uninterpreted variable area.
  1066. //
  1067. // History: 27-Dec-95 KyleP Created.
  1068. //
  1069. //----------------------------------------------------------------------------
  1070. inline ULONG COnDiskPropertyRecord::MinimalOverheadNormal()
  1071. {
  1072. // Just the minimal overhead of a normal record
  1073. return ((ULONG) (ULONG_PTR)&((SNormalRecord *)0)->_aul[0]) / sizeof(ULONG);
  1074. }
  1075. //+---------------------------------------------------------------------------
  1076. //
  1077. // Member: COnDiskPropertyRecord::FixedOverheadLean, public
  1078. //
  1079. // Returns: Size of lean record, sans uninterpreted variable area.
  1080. //
  1081. // History: 17-Dec-97 KrishnaN Created.
  1082. //
  1083. //----------------------------------------------------------------------------
  1084. inline ULONG COnDiskPropertyRecord::FixedOverheadLean()
  1085. {
  1086. // We need to preallocate the first three ULONGs of the variable
  1087. // section of the record for free list mgmt.
  1088. return ((ULONG) (ULONG_PTR)&((SLeanRecord *)0)->_aul[3]) / sizeof(ULONG);
  1089. }
  1090. //+---------------------------------------------------------------------------
  1091. //
  1092. // Member: COnDiskPropertyRecord::IsStored, public
  1093. //
  1094. // Synopsis: Test property existence.
  1095. //
  1096. // Arguments: [Ordinal] -- Position of property in list.
  1097. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1098. //
  1099. // Returns: TRUE if property at [Ordinal] is stored.
  1100. //
  1101. // History: 27-Dec-95 KyleP Created.
  1102. //
  1103. //----------------------------------------------------------------------------
  1104. inline BOOL COnDiskPropertyRecord::IsStored( ULONG Ordinal, ULONG mask )
  1105. {
  1106. Win4Assert(eVirgin != Type());
  1107. ULONG *aul;
  1108. if (IsLeanRecord())
  1109. aul = ((SLeanRecord *)&Data)->_aul;
  1110. else
  1111. aul = ((SNormalRecord *)&Data)->_aul;
  1112. return ( (aul[Ordinal / 16] & mask) != 0 );
  1113. }
  1114. //+---------------------------------------------------------------------------
  1115. //
  1116. // Member: COnDiskPropertyRecord::SetStored, public
  1117. //
  1118. // Synopsis: Marks property as stored.
  1119. //
  1120. // Arguments: [Ordinal] -- Position of property in list.
  1121. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1122. //
  1123. // History: 27-Dec-95 KyleP Created.
  1124. //
  1125. //----------------------------------------------------------------------------
  1126. inline void COnDiskPropertyRecord::SetStored( ULONG Ordinal, ULONG mask )
  1127. {
  1128. Win4Assert(eVirgin != Type());
  1129. ULONG *aul;
  1130. if (IsLeanRecord())
  1131. aul = ((SLeanRecord *)&Data)->_aul;
  1132. else
  1133. aul = ((SNormalRecord *)&Data)->_aul;
  1134. aul[Ordinal / 16] |= mask;
  1135. }
  1136. //+---------------------------------------------------------------------------
  1137. //
  1138. // Member: COnDiskPropertyRecord::ClearStored, public
  1139. //
  1140. // Synopsis: Marks property as not stored.
  1141. //
  1142. // Arguments: [Ordinal] -- Position of property in list.
  1143. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1144. //
  1145. // History: 27-Dec-95 KyleP Created.
  1146. //
  1147. //----------------------------------------------------------------------------
  1148. inline void COnDiskPropertyRecord::ClearStored( ULONG Ordinal, ULONG mask )
  1149. {
  1150. Win4Assert(eVirgin != Type());
  1151. ULONG *aul;
  1152. if (IsLeanRecord())
  1153. aul = ((SLeanRecord *)&Data)->_aul;
  1154. else
  1155. aul = ((SNormalRecord *)&Data)->_aul;
  1156. aul[Ordinal / 16] &= ~mask;
  1157. }
  1158. //+---------------------------------------------------------------------------
  1159. //
  1160. // Member: COnDiskPropertyRecord::IsStoredOnOverflow, public
  1161. //
  1162. // Synopsis: Test property overflow.
  1163. //
  1164. // Arguments: [Ordinal] -- Position of property in list.
  1165. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1166. //
  1167. // Returns: TRUE if property at [Ordinal] is stored on overflow record.
  1168. //
  1169. // History: 27-Dec-95 KyleP Created.
  1170. //
  1171. //----------------------------------------------------------------------------
  1172. inline BOOL COnDiskPropertyRecord::IsStoredOnOverflow( ULONG Ordinal, ULONG mask )
  1173. {
  1174. Win4Assert( !IsLeanRecord() );
  1175. Win4Assert( ( mask & (mask - 1) ) == 0 );
  1176. return ( ( ((SNormalRecord *)&Data)->_aul[Ordinal / 16] & (mask << 1)) != 0 );
  1177. }
  1178. //+---------------------------------------------------------------------------
  1179. //
  1180. // Member: COnDiskPropertyRecord::SetStoredOnOverflow, public
  1181. //
  1182. // Synopsis: Marks property as stored on overflow record.
  1183. //
  1184. // Arguments: [Ordinal] -- Position of property in list.
  1185. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1186. //
  1187. // History: 27-Dec-95 KyleP Created.
  1188. //
  1189. //----------------------------------------------------------------------------
  1190. inline void COnDiskPropertyRecord::SetStoredOnOverflow( ULONG Ordinal, ULONG mask )
  1191. {
  1192. Win4Assert( !IsLeanRecord() );
  1193. Win4Assert( ( mask & (mask - 1) ) == 0 );
  1194. ((SNormalRecord *)&Data)->_aul[Ordinal / 16] |= (mask << 1);
  1195. }
  1196. //+---------------------------------------------------------------------------
  1197. //
  1198. // Member: COnDiskPropertyRecord::ClearStoredOnOverflow, public
  1199. //
  1200. // Synopsis: Marks property as not stored on overflow record.
  1201. //
  1202. // Arguments: [Ordinal] -- Position of property in list.
  1203. // [mask] -- Bitmask of ordinal. Pre-computed for efficiency.
  1204. //
  1205. // History: 27-Dec-95 KyleP Created.
  1206. //
  1207. //----------------------------------------------------------------------------
  1208. inline void COnDiskPropertyRecord::ClearStoredOnOverflow( ULONG Ordinal, ULONG mask )
  1209. {
  1210. Win4Assert( !IsLeanRecord() );
  1211. Win4Assert( ( mask & (mask - 1) ) == 0 );
  1212. ((SNormalRecord *)&Data)->_aul[Ordinal / 16] &= ~(mask << 1);
  1213. }
  1214. //+---------------------------------------------------------------------------
  1215. //
  1216. // Member: COnDiskPropertyRecord::UsedSize, public
  1217. //
  1218. // Arguments: [ul] -- Dword containing used/alloced size fields.
  1219. //
  1220. // Returns: Used size.
  1221. //
  1222. // History: 27-Dec-95 KyleP Created.
  1223. //
  1224. //----------------------------------------------------------------------------
  1225. inline ULONG COnDiskPropertyRecord::UsedSize( ULONG ul )
  1226. {
  1227. ULONG size = ul >> 16;
  1228. if ( size == 0xFFFF)
  1229. size = 0;
  1230. return size;
  1231. }
  1232. //+---------------------------------------------------------------------------
  1233. //
  1234. // Member: COnDiskPropertyRecord::SetUsedSize, public
  1235. //
  1236. // Synopsis: Sets used size.
  1237. //
  1238. // Arguments: [pul] -- Pointer to dword containing used/alloced size fields.
  1239. // [ul] -- New used size
  1240. //
  1241. // History: 27-Dec-95 KyleP Created.
  1242. //
  1243. //----------------------------------------------------------------------------
  1244. inline void COnDiskPropertyRecord::SetUsedSize( ULONG * pul, ULONG ul )
  1245. {
  1246. Win4Assert( AllocatedSize(*pul) >= ul || ul == 0xFFFF );
  1247. *pul = (*pul & 0xFFFF) | (ul << 16);
  1248. }
  1249. //+---------------------------------------------------------------------------
  1250. //
  1251. // Member: COnDiskPropertyRecord::SetAllocatedSize, public
  1252. //
  1253. // Synopsis: Sets allocated size.
  1254. //
  1255. // Arguments: [pul] -- Pointer to dword containing used/alloced size fields.
  1256. // [ul] -- New allocated size
  1257. //
  1258. // History: 27-Dec-95 KyleP Created.
  1259. //
  1260. //----------------------------------------------------------------------------
  1261. inline void COnDiskPropertyRecord::SetAllocatedSize( ULONG * pul, ULONG ul )
  1262. {
  1263. Win4Assert( (ul >> 16) == 0 );
  1264. *pul = (*pul & 0xFFFF0000) | ul;
  1265. }
  1266. //+---------------------------------------------------------------------------
  1267. //
  1268. // Member: COnDiskPropertyRecord::MarkOverflow, public
  1269. //
  1270. // Synopsis: Indicates variable stored in overflow record.
  1271. //
  1272. // Arguments: [pul] -- Pointer to dword containing used/alloced size fields.
  1273. //
  1274. // History: 27-Dec-95 KyleP Created.
  1275. //
  1276. //----------------------------------------------------------------------------
  1277. inline void COnDiskPropertyRecord::MarkOverflow( ULONG * pul )
  1278. {
  1279. SetUsedSize( pul, 0xFFFF );
  1280. }
  1281. //+---------------------------------------------------------------------------
  1282. //
  1283. // Member: COnDiskPropertyRecord::IsOverflow, public
  1284. //
  1285. // Arguments: [ul] -- dword containing used/alloced size fields.
  1286. //
  1287. // Returns: TRUE if variable is in overflow record.
  1288. //
  1289. // History: 27-Dec-95 KyleP Created.
  1290. //
  1291. //----------------------------------------------------------------------------
  1292. inline BOOL COnDiskPropertyRecord::IsOverflow( ULONG ul )
  1293. {
  1294. return ((ul & 0xFFFF0000) == 0xFFFF0000);
  1295. }
  1296. //+---------------------------------------------------------------------------
  1297. //
  1298. // Member: COnDiskPropertyRecord::FreeVariableSpace, public
  1299. //
  1300. // Synopsis: Compute free space.
  1301. //
  1302. // Arguments: [cTotal] -- Total number of properties in record.
  1303. // [cFixed] -- Count of fixed properties in record.
  1304. // [oStart] -- Offset to start of variable storage area
  1305. // [culRec] -- Size in dwords of record.
  1306. //
  1307. // Returns: Unused variable space in record.
  1308. //
  1309. // History: 27-Dec-95 KyleP Created.
  1310. //
  1311. //----------------------------------------------------------------------------
  1312. inline ULONG COnDiskPropertyRecord::FreeVariableSpace( ULONG cTotal,
  1313. ULONG cFixed,
  1314. ULONG oStart,
  1315. ULONG culRec )
  1316. {
  1317. Win4Assert( !IsLeanRecord() );
  1318. LONG lFree = (culRec * CountRecords()) - // Record size
  1319. MinimalOverheadNormal() - // Minimal fixed overhead
  1320. ((cTotal - 1) / 16 + 1) - // Existence bitmap
  1321. oStart - // Fixed property storage
  1322. (cTotal - cFixed) - // Used/Alloc sizes
  1323. VariableUsed(); // Variable properties
  1324. Win4Assert(lFree >= 0);
  1325. return (ULONG) lFree;
  1326. }
  1327. //+---------------------------------------------------------------------------
  1328. //
  1329. // Member: COnDiskPropertyRecord::FindVariableProp, public
  1330. //
  1331. // Synopsis: Locate start of property.
  1332. //
  1333. // Arguments: [Ordinal] -- Ordinal of property to locate.
  1334. // [cFixed] -- Count of fixed properties in record.
  1335. // [cTotal] -- Total number of properties in record.
  1336. // [oStart] -- Offset to start of variable storage area.
  1337. //
  1338. // Returns: Pointer to start of property
  1339. //
  1340. // History: 27-Dec-95 KyleP Created.
  1341. //
  1342. //----------------------------------------------------------------------------
  1343. inline ULONG * COnDiskPropertyRecord::FindVariableProp( ULONG Ordinal,
  1344. ULONG cFixed,
  1345. ULONG cTotal,
  1346. ULONG oStart )
  1347. {
  1348. Win4Assert( !IsLeanRecord() );
  1349. ciDebugOut(( DEB_PROPSTORE,
  1350. "Ordinal = %d, %d fixed, %d total, offset = 0x%x\n",
  1351. Ordinal, cFixed, cTotal, oStart ));
  1352. //
  1353. // Start is after existance bitmap and fixed properties.
  1354. //
  1355. ULONG * pulVarRecord = &((SNormalRecord *)&Data)->_aul[(cTotal-1) / 16 + 1 + oStart];
  1356. #if CIDBG
  1357. ULONG culUsed = 0;
  1358. #endif // CIDBG
  1359. //
  1360. // Skip over variable props. The "+1" is for the allocation dword.
  1361. //
  1362. for ( ULONG i = cFixed; i < Ordinal; i++ )
  1363. {
  1364. ciDebugOut(( DEB_PROPSTORE, "Ordinal %d starts at offset 0x%x (%d)\n",
  1365. i,
  1366. (ULONG)((ULONG_PTR)pulVarRecord - (ULONG_PTR)this),
  1367. (ULONG)((ULONG_PTR)pulVarRecord - (ULONG_PTR)this) ));
  1368. #if CIDBG
  1369. culUsed += UsedSize(*pulVarRecord);
  1370. #endif
  1371. pulVarRecord += AllocatedSize(*pulVarRecord) + 1;
  1372. }
  1373. ciDebugOut(( DEB_PROPSTORE, "Ordinal %d starts at offset 0x%x (%d)\n",
  1374. i,
  1375. (ULONG)((ULONG_PTR)pulVarRecord - (ULONG_PTR)this),
  1376. (ULONG)((ULONG_PTR)pulVarRecord - (ULONG_PTR)this) ));
  1377. Win4Assert( culUsed + UsedSize(*pulVarRecord) <= VariableUsed() );
  1378. return pulVarRecord;
  1379. }
  1380. #if CIDBG == 1
  1381. //+---------------------------------------------------------------------------
  1382. //
  1383. // Member: COnDiskPropertyRecord::IsNormalEmpty, public
  1384. //
  1385. // Arguments: [culRec] -- Size of record.
  1386. //
  1387. // Returns: TRUE if the normal record is empty.
  1388. //
  1389. // History: 19-Dec-97 KrishnaN Created.
  1390. //
  1391. //----------------------------------------------------------------------------
  1392. inline BOOL COnDiskPropertyRecord::IsNormalEmpty( ULONG culRec )
  1393. {
  1394. BOOL fEmpty = ( 0 == VariableUsed() &&
  1395. 0 == OverflowBlock() &&
  1396. 0 == ToplevelBlock() );
  1397. for ( ULONG i = 0; i < (culRec-5); i++ )
  1398. {
  1399. if ( 0 != ((SNormalRecord *)&Data)->_aul[i] )
  1400. {
  1401. fEmpty = FALSE;
  1402. break;
  1403. }
  1404. }
  1405. return fEmpty;
  1406. }
  1407. //+---------------------------------------------------------------------------
  1408. //
  1409. // Member: COnDiskPropertyRecord::IsLeanEmpty, public
  1410. //
  1411. // Arguments: [culRec] -- Size of record.
  1412. //
  1413. // Returns: TRUE if the lean record is empty.
  1414. //
  1415. // History: 19-Dec-97 KrishnaN Created.
  1416. //
  1417. //----------------------------------------------------------------------------
  1418. inline BOOL COnDiskPropertyRecord::IsLeanEmpty( ULONG culRec )
  1419. {
  1420. BOOL fEmpty = TRUE;
  1421. for ( ULONG i = 0; i < (culRec-1); i++ )
  1422. {
  1423. if ( 0 != ((SLeanRecord *)&Data)->_aul[i] )
  1424. {
  1425. fEmpty = FALSE;
  1426. break;
  1427. }
  1428. }
  1429. return fEmpty;
  1430. }
  1431. #endif // CIDBG