Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

584 lines
22 KiB

  1. // PathMgr.h -- Declarations for the Path Manager classes and interfaces
  2. #ifndef __PATHMGR_H__
  3. #define __PATHMGR_H__
  4. /*
  5. The path manager interface maintains a database of PathInfo entries. Entries
  6. are keyed by a Unicode path name. They may be enumerated in Unicode lexical order
  7. starting from a given path name. The path manager interfaces support retrieving,
  8. adding, deleting and modifying entries.
  9. Each entry in the database has a unique path name. Name comparisons are case
  10. insensitive according the rules for the U.S. English locale (0x0409). Path strings
  11. are stored in the database exactly as given on whenever a new record is inserted.
  12. Path names may be up to 259 characters long.
  13. */
  14. #if 0
  15. // StreamState defines a collection of bit flags which define the
  16. // access and permission states for a stream or storage.
  17. enum StreamState { Readable = 0x00000001, // Stream may be read
  18. Writeable = 0x00000002, // Stream may be written
  19. ShareRead = 0x00000004, // Multiple readers allowed
  20. ShareWrite = 0x00000008, // Multiple writers allowed
  21. TempStream = 0x00000010, // Stream will be deleted when released
  22. Transacted = 0x00000020 // Stream supports Commit and Revert
  23. };
  24. #endif // 0
  25. //Record stucture for garbage collection
  26. typedef struct _SEntry{
  27. CULINT ullcbOffset;
  28. CULINT ullcbData;
  29. UINT ulEntryID;
  30. }SEntry;
  31. typedef SEntry *PSEntry;
  32. class CPathManager1 : public CITUnknown
  33. {
  34. public:
  35. // Destructor:
  36. ~CPathManager1(void);
  37. // Creation:
  38. static HRESULT NewPathDatabase(IUnknown *punkOuter, ILockBytes *plb,
  39. UINT cbDirectoryBlock, UINT cCacheBlocksMax,
  40. IITPathManager **pplkb
  41. );
  42. static HRESULT LoadPathDatabase(IUnknown *punkOuter, ILockBytes *plb,
  43. IITPathManager **pplkb
  44. );
  45. private:
  46. CPathManager1(IUnknown *pUnkOuter);
  47. class CImpIPathManager : public IITPathManager
  48. {
  49. public:
  50. // Constructor and Destructor:
  51. CImpIPathManager(CPathManager1 *pBackObj, IUnknown *punkOuter);
  52. ~CImpIPathManager(void);
  53. // Initialing routines:
  54. HRESULT InitNewPathDatabase(ILockBytes *plb, UINT cbDirectoryBlock,
  55. UINT cCacheBlocksMax);
  56. HRESULT InitLoadPathDatabase(ILockBytes *plb);
  57. // IPersist Method:
  58. HRESULT STDMETHODCALLTYPE GetClassID(
  59. /* [out] */ CLSID __RPC_FAR *pClassID);
  60. // IITPathManager interfaces:
  61. HRESULT STDMETHODCALLTYPE FlushToLockBytes();
  62. HRESULT STDMETHODCALLTYPE FindEntry (PPathInfo pSI );
  63. HRESULT STDMETHODCALLTYPE CreateEntry(PPathInfo pSINew,
  64. PPathInfo pSIOld,
  65. BOOL fReplace );
  66. HRESULT STDMETHODCALLTYPE DeleteEntry(PPathInfo pSI );
  67. HRESULT STDMETHODCALLTYPE UpdateEntry(PPathInfo pSI );
  68. HRESULT STDMETHODCALLTYPE EnumFromObject
  69. (IUnknown *punkOuter, const WCHAR *pwszPrefix, UINT cwcPrefix,
  70. REFIID riid, PVOID *ppv
  71. );
  72. HRESULT STDMETHODCALLTYPE GetPathDB(IStreamITEx *pTempPDBStrm, BOOL fCompact);
  73. HRESULT STDMETHODCALLTYPE ForceClearDirty();
  74. private:
  75. // The PathInfo data type is used to pass stream information through function
  76. // interfaces within the Path Manager. It is not used as the on-disk layout.
  77. // The on-disk information is kept as follows:
  78. //
  79. // cbPath // Byte length of abPath; Stored as VL32
  80. // abPath // UTF-8 representation of awszStreamPath
  81. // uStateBits // Stored as high order dword of VL64
  82. // iLockedBytesSegment // Stored as low order dword of VL64
  83. // ullcbOffset // Stored as VL64 // Used with ullcbData
  84. // ullcbData // Stored as VL64 // to store storage guids
  85. //
  86. // VL32 and VL64 storage formats, respectively, are 32 and 64 bit variable length
  87. // storage formats. The use the convention that the last byte in the representation
  88. // is less than 0x80. That is, each byte contains seven bits of information.
  89. typedef struct _TaggedPathInfo
  90. {
  91. UINT iDirectoryBlock; // Index of dir block containing this info
  92. UINT cbEntryOffset; // Offset of info within dir block
  93. UINT cbEncoded; // Size of entry within dir block
  94. PathInfo SI;
  95. } TaggedPathInfo, *PTaggedPathInfo;
  96. // The structures below define the on-disk structure of leaf nodes
  97. // and internal nodes. Leaf nodes are the bottom of the B-Tree heirarchy.
  98. // Internal nodes are in the levels above the leaf nodes.
  99. // First we define two type tags for the nodes:
  100. enum { uiMagicLeaf = ('L' << 24 ) | ('G' << 16) | ('M' << 8) | 'P',
  101. uiMagicInternal = ('I' << 24 ) | ('G' << 16) | ('M' << 8) | 'P',
  102. uiMagicUnused = ('U' << 24 ) | ('G' << 16) | ('M' << 8) | 'P'
  103. };
  104. // All nodes begin with a node header:
  105. typedef struct _NodeHeader
  106. {
  107. UINT uiMagic; // A type tag to mark leafs and internal nodes.
  108. UINT cbSlack; // Free space in the trailing portion of the node.
  109. // UINT cEntries; // Now kept at end of node.
  110. } NodeHeader, *PNodeHeader;
  111. // Leaf nodes have additional header information to maintain a chain
  112. // through all the leaf nodes:
  113. typedef struct _LeafChainLinks
  114. {
  115. UINT iLeafSerial; // Serial number for this leaf. Changed when an
  116. // enumeration offset might become invalid.
  117. UINT iLeafPrevious; // Leaf nodes are placed in a lexically ordered chain.
  118. UINT iLeafNext; // These are the links for that double linked chain.
  119. } LeafChainLinks, *PLeafChainLinks;
  120. // Now we can define the structures for leaf nodes and internal nodes.
  121. // Note the use of ab[0]. That's because our nodes size is defined when
  122. // the B-Tree is created. That size includes both the ab space for key
  123. // entries and the header for the node. Since all nodes must be the same
  124. // size than means the ab space for internal nodes is eight-bytes bigger
  125. // than the ab space in leaf nodes. We keep all nodes the same size
  126. // to make the free list mechanism work cleanly. That is, when a leaf
  127. // node is discarded and added to the free list, it may be resurrected
  128. // later and taken out of the free list to become either an internal node
  129. // or a leaf node.
  130. typedef struct _LeafNode
  131. {
  132. NodeHeader nh;
  133. LeafChainLinks lcl;
  134. BYTE ab[0];
  135. } LeafNode, *PLeafNode;
  136. typedef struct _InternalNode
  137. {
  138. NodeHeader nh;
  139. BYTE ab[0];
  140. } InternalNode, *PInternalNode;
  141. // When we read nodes into memory, we embed them in a cache block
  142. // structure so we can add extra state information.
  143. typedef struct _CacheBlock
  144. {
  145. UINT fFlags; // Type and state bits (Defined below).
  146. struct _CacheBlock *pCBPrev; // Previous block in LRU chain.
  147. struct _CacheBlock *pCBNext; // Next block in LRU chain or
  148. // Next block in free chain.
  149. UINT iBlock; // Index of the disk slot corresponding to this node.
  150. UINT cbKeyOffset; // Set by the key scanning routines to mark where
  151. // a key was found or where a new key may be inserted.
  152. UINT cbEntry; // Size in bytes of key plus record.
  153. union
  154. {
  155. LeafNode ldb;
  156. InternalNode idb;
  157. };
  158. } CacheBlock, *PCacheBlock;
  159. enum { FreeBlock = 0x00000001, // Cache block is not in use
  160. InternalBlock = 0x00000002, // Block holds an internal directory
  161. LeafBlock = 0x00000004, // Block holds a leaf directory
  162. BlockTypeMask = 0x00000007, // Bits which define block type
  163. DirtyBlock = 0x00000008, // Block does not match on-disk data.
  164. LockedBlock = 0x00000010, // Block is locked in memory
  165. ReadingIn = 0x00000020, // Block is being read from disk
  166. WritingOut = 0x00000040 // Block is being written to disk
  167. };
  168. typedef struct _SInternalNodeLev{
  169. PInternalNode pINode;
  170. ULONG cbFirstKey;
  171. ULONG cEntries;
  172. }SInternalNodeLev;
  173. HRESULT STDMETHODCALLTYPE CompactPathDB(IStreamITEx *pTempPDBStrm);
  174. HRESULT UpdateHigherLev(IStreamITEx *pTempPDBStrm,
  175. UINT iCurILev,
  176. UINT *piNodeNext,
  177. SInternalNodeLev *rgINode,
  178. PBYTE pbFirstKey,
  179. ULONG cbFirstKey);
  180. UINT PredictNodeID(UINT iCurILev,
  181. UINT iNodeNext,
  182. SInternalNodeLev *rgINode,
  183. PBYTE pbFirstKey,
  184. ULONG cbFirstKey);
  185. HRESULT BinarySearch(UINT uiStart,
  186. UINT uiEnd,
  187. PBYTE pauAccess,
  188. UINT cbAccess,
  189. PTaggedPathInfo ptsi,
  190. PBYTE ab,
  191. PBYTE *ppbOut,
  192. BOOL fSmall);
  193. // These routines manage a key count field at the end of a node.
  194. // The count may be absent if cbSlack is too small. It may be zero
  195. // when the access vector doesn't exist.
  196. void KillKeyCount(LeafNode *pln);
  197. // These routines manage cache block allocation and deallocation.
  198. // When there are no unused blocks, the GetCacheBlocks routine will
  199. // free the oldest unlocked block, writing its content to disk if
  200. // necessary.
  201. HRESULT GetCacheBlock (PCacheBlock *ppCB, UINT fTypeMask);
  202. HRESULT FreeCacheBlock(PCacheBlock pCB);
  203. HRESULT GetFreeBlock(PCacheBlock &pCB);
  204. HRESULT GetActiveBlock(PCacheBlock &pCB, BOOL fIgnoreLocks = FALSE);
  205. void MarkAsMostRecent(PCacheBlock pCB);
  206. void RemoveFromUse (PCacheBlock pCB);
  207. // These routines handle disk I/O for cache blocks.
  208. HRESULT ReadCacheBlock(PCacheBlock pCB, UINT iBlock);
  209. HRESULT WriteCacheBlock(PCacheBlock pCB);
  210. HRESULT FlushToDisk();
  211. // The FindCacheBlock routine finds a cache block which contains
  212. // the image of a particular node block. If that data doesn't
  213. // exist in the cache, it will read it from disk.
  214. HRESULT FindCacheBlock(PCacheBlock *ppCB, UINT iBlock);
  215. // This routine allocate a new node on disk and in the cache blocks.
  216. HRESULT AllocateNode(PCacheBlock *ppCB, UINT fTypeMask);
  217. // This routine adds a node to the free list.
  218. HRESULT DiscardNode(PCacheBlock pCB);
  219. // These routines search through the B-Tree nodes looking for a key
  220. // or a place to insert a new key.
  221. HRESULT FindKeyAndLockBlockSet
  222. (PTaggedPathInfo ptsi, PCacheBlock *papCBSet,
  223. UINT iLevel, UINT cLevels = UINT(~0)
  224. );
  225. HRESULT ScanInternalForKey(PCacheBlock pCacheBlock, PTaggedPathInfo ptsi,
  226. PUINT piChild
  227. );
  228. HRESULT ScanLeafForKey(PCacheBlock pCacheBlock, PTaggedPathInfo ptsi);
  229. // ClearLockFlags turns off lock flags for all cache entries.
  230. void ClearLockFlags(PCacheBlock *papCBSet);
  231. // ClearLockFlagsAbove turns off lock flags for levels above iLevel.
  232. void ClearLockFlagsAbove(PCacheBlock *papCBSet, UINT iLevel);
  233. // These routines insert, delete, and modify entries in a leaf node.
  234. HRESULT InsertEntryIntoLeaf(PTaggedPathInfo ptsi, PCacheBlock *papCBSet);
  235. HRESULT UpdateEntryInLeaf (PTaggedPathInfo ptsi, PCacheBlock *papCBSet);
  236. // These routines insert, delete, and modify entries in any node
  237. HRESULT InsertEntryIntoNode(PTaggedPathInfo ptsi, PBYTE pb, UINT cb, PCacheBlock *papCBSet, UINT iLevel, BOOL fAfter);
  238. HRESULT RemoveEntryFromNode(PTaggedPathInfo ptsi, PCacheBlock *papCBSet, UINT iLevel);
  239. HRESULT ModifyEntryInNode (PTaggedPathInfo ptsi, PBYTE pb, UINT cb, PCacheBlock *papCBSet, UINT iLevel);
  240. // These routines insert a key, remove a key, or modify the information for
  241. // an existing key. The iLevel parameter indicates the level of the tree
  242. // being modified. Level numbers start at the leaves and go upward.
  243. HRESULT InsertAKey (UINT iLevel, PCacheBlock pCacheBlock, PTaggedPathInfo ptsi);
  244. HRESULT RemoveAKey (UINT iLevel, PPathInfo pSI);
  245. HRESULT ModifyKeyData(UINT iLevel, PCacheBlock pCacheBlock, PTaggedPathInfo ptsi);
  246. // This routine splits a node to create more slack space.
  247. HRESULT SplitANode(PCacheBlock *papCBSet, UINT iLevel);
  248. // Routines for encoding and decoding on-disk representations of stream information:
  249. HRESULT DecodePathKey(const BYTE **ppb, PWCHAR pwszPath, PUINT pcwcPath);
  250. PBYTE EncodePathKey( PBYTE pb, const WCHAR *pwszPath, UINT cwcPath);
  251. HRESULT DecodeKeyInfo(const BYTE **ppb, PPathInfo pSI);
  252. PBYTE EncodeKeyInfo( PBYTE pb, const PathInfo *pSI);
  253. PBYTE SkipKeyInfo(PBYTE pb);
  254. HRESULT DecodePathInfo(const BYTE **ppb, PPathInfo pSI);
  255. PBYTE EncodePathInfo( PBYTE pb, const PathInfo *pSI);
  256. BOOL ValidBlockIndex(UINT iBlock);
  257. HRESULT SaveHeader();
  258. enum
  259. {
  260. INVALID_INDEX = UINT(~0),
  261. CB_STREAM_INFO_MAX = MAX_UTF8_PATH + 2 * 10 + 2 * 5 + 2,
  262. PathMagicID = ('P' << 24) | ('S' << 16) | ('T' << 8) | 'I',
  263. PathVersion = 1
  264. };
  265. class CEnumPathMgr1 : public CITUnknown
  266. {
  267. public:
  268. ~CEnumPathMgr1();
  269. static HRESULT NewPathEnumeratorObject
  270. (IUnknown *punkOuter, CImpIPathManager *pPM,
  271. const WCHAR *pwszPathPrefix,
  272. UINT cwcPathPrefix,
  273. REFIID riid,
  274. PVOID *ppv
  275. );
  276. static HRESULT NewPathEnumerator(IUnknown *punkOuter, CImpIPathManager *pPM,
  277. const WCHAR *pwszPathPrefix,
  278. UINT cwcPathPrefix,
  279. IEnumSTATSTG **ppEnumSTATSTG
  280. );
  281. private:
  282. CEnumPathMgr1(IUnknown *pUnkOuter);
  283. class CImpIEnumSTATSTG : public IITEnumSTATSTG
  284. {
  285. public:
  286. CImpIEnumSTATSTG(CITUnknown *pBackObj, IUnknown *punkOuter);
  287. ~CImpIEnumSTATSTG();
  288. HRESULT STDMETHODCALLTYPE InitPathEnumerator(CImpIPathManager *pPM,
  289. const WCHAR *pwszPathPrefix,
  290. UINT cwcPathPrefix
  291. );
  292. //IITEnumSTATSTG interface methods
  293. HRESULT STDMETHODCALLTYPE GetNextEntryInSeq(ULONG celt, PathInfo *rgelt, ULONG *pceltFetched);
  294. HRESULT STDMETHODCALLTYPE GetFirstEntryInSeq(PathInfo *rgelt);
  295. HRESULT STDMETHODCALLTYPE Next(
  296. /* [in] */ ULONG celt,
  297. /* [in] */ STATSTG __RPC_FAR *rgelt,
  298. /* [out] */ ULONG __RPC_FAR *pceltFetched);
  299. HRESULT STDMETHODCALLTYPE Skip(
  300. /* [in] */ ULONG celt);
  301. HRESULT STDMETHODCALLTYPE Reset( void);
  302. HRESULT STDMETHODCALLTYPE Clone(
  303. /* [out] */ IEnumSTATSTG __RPC_FAR *__RPC_FAR *ppenum);
  304. private:
  305. HRESULT STDMETHODCALLTYPE FindEntry();
  306. HRESULT STDMETHODCALLTYPE NextEntry();
  307. CImpIPathManager *m_pPM; // Context of this enumeration
  308. PathInfo m_SI; // Last entry returned
  309. UINT m_iLeafBlock; // Index for leaf containing last entry
  310. UINT m_cbOffsetLastEntry;// Position of prev entry in that leaf
  311. UINT m_cbLastEntry; // Size of prev entry.
  312. UINT m_iSerialNode; // Leaf Serial number
  313. UINT m_iSerialDatabase; // Database serial number
  314. UINT m_cwcPathPrefix; // Length of starting prefix
  315. WCHAR m_pwszPathPrefix[MAX_PATH]; // Starting prefix
  316. // We use leaf and database serial numbers to determine whether our position
  317. // information is still valid. The serial number for a leaf changes whenever
  318. // a change would invalidate our offset into the leaf. This includes cases
  319. // where the node is split and also cases where an entry changes shape. That
  320. // is, we increment the leaf serial number when we delete an entry or modify
  321. // it so that its content is larger or smaller. Inserting an entry also
  322. // increments the leaf's serial number. However appending an entry to the
  323. // end of the leaf won't change its serial number because that change would
  324. // not invalidate any enumeration offset.
  325. //
  326. // The serial number for the database is incremented whenever we delete a
  327. // leaf node. This may indicate that our recorded m_iLeafBlock is no longer
  328. // valid.
  329. //
  330. // Whenever we have a mismatch with either the leaf serial or the database
  331. // serial, we search for a match rather than relying on our position
  332. // information.
  333. //
  334. // Note also the initial condition where m_iSerialNode and m_iSerialDatabase
  335. // are zero. By convention the serial number sequence skips the value zero.
  336. };
  337. CImpIEnumSTATSTG m_ImpEnumSTATSTG;
  338. };
  339. friend CEnumPathMgr1;
  340. friend CEnumPathMgr1::CImpIEnumSTATSTG;
  341. // We set the minimum directory block size so that we'll always be able
  342. // to handle the longest possible path together with the worst case
  343. // encoding for path information. In the worst case a leaf node can just
  344. // barely accomodate a single item.
  345. // The MIN_CACHE_ENTRIES constant controls the number of directory blocks
  346. // which we will cache in memory. We may actually cache more blocks for
  347. // a deep B-Tree.
  348. enum { MIN_DIRECTORY_BLOCK_SIZE = MAX_UTF8_PATH + 30 + sizeof(LeafNode),
  349. MIN_CACHE_ENTRIES = 2
  350. };
  351. // The database header is a meta directory for the node blocks.
  352. // It is the first thing in the on-disk data stream.
  353. typedef struct _DatabaseHeader
  354. {
  355. ULONG uiMagic; // ID value "ITSP"
  356. ULONG uiVersion; // Revision # for this structure
  357. ULONG cbHeader; // sizeof(DatabaseHeader);
  358. ULONG cCacheBlocksMax; // Number of cache blocks allowed
  359. ULONG cbDirectoryBlock; // Size of a directory block
  360. ULONG cEntryAccessShift; // Base 2 log of Gap in entry access vector
  361. ULONG cDirectoryLevels; // Nesting depth from root to leaf
  362. ULONG iRootDirectory; // The top most internal directory
  363. ULONG iLeafFirst; // Lexically first leaf block
  364. ULONG iLeafLast; // Lexically last leaf block
  365. ULONG iBlockFirstFree; // First block in unused block chain
  366. ULONG cBlocks; // Number of directory blocks in use
  367. LCID lcid; // Locale (sorting conventions, comparision rules)
  368. CLSID clsidEntryHandler; // Interface which understands node entries
  369. UINT cbPrefix; // Size of fixed portion of data base
  370. ULONG iOrdinalMapRoot; // Ordinal map root for when they don't fit in a block
  371. ULONG iOrdinalMapFirst; // First and last Ordinal map for leaf blocks.
  372. ULONG iOrdinalMapLast; // These are linked like the leaf blocks.
  373. // Note instance data for the Entry handler immediately follows the
  374. // database header. That data is counted by cbPrefix.
  375. } DatabaseHeader, PDatabaseHeader;
  376. CITCriticalSection m_cs;
  377. ILockBytes *m_plbPathDatabase; // Disk image of the path database header.
  378. DatabaseHeader m_dbh; // Header info for the path database.
  379. BOOL m_fHeaderIsDirty; // Header doesn't match disk version.
  380. UINT m_cCacheBlocks; // Number of active cache blocks
  381. PCacheBlock m_pCBLeastRecent; // LRU end of the in-use chain
  382. PCacheBlock m_pCBMostRecent; // MRU end of the in-use chain
  383. PCacheBlock m_pCBFreeList; // Chain of unused cache blocks
  384. UINT m_PathSetSerial; // Serial number for the path set data base.
  385. // Incremented whenever we delete a leaf node.
  386. };
  387. CImpIPathManager m_PathManager;
  388. };
  389. typedef CPathManager1 *PCPathManager1;
  390. extern GUID aIID_CPathManager[];
  391. extern UINT cInterfaces_CPathManager;
  392. #pragma warning( disable : 4355 )
  393. inline CPathManager1::CPathManager1(IUnknown *pUnkOuter)
  394. : m_PathManager(this, pUnkOuter),
  395. CITUnknown(aIID_CPathManager, cInterfaces_CPathManager, &m_PathManager)
  396. {
  397. }
  398. inline CPathManager1::~CPathManager1(void)
  399. {
  400. }
  401. inline BOOL CPathManager1::CImpIPathManager::ValidBlockIndex(UINT iBlock)
  402. {
  403. // We use all-ones as an invalid index value.
  404. return ~iBlock;
  405. }
  406. inline CPathManager1::CImpIPathManager::CEnumPathMgr1::CEnumPathMgr1(IUnknown *pUnkOuter)
  407. : m_ImpEnumSTATSTG(this, pUnkOuter),
  408. CITUnknown(&IID_IEnumSTATSTG, 1, &m_ImpEnumSTATSTG)
  409. {
  410. }
  411. inline CPathManager1::CImpIPathManager::CEnumPathMgr1::~CEnumPathMgr1(void)
  412. {
  413. }
  414. // Routines for encoding and decoding variable length
  415. // representations for 32 and 64 bit values:
  416. ULONG DecodeVL32(const BYTE **ppb);
  417. CULINT DecodeVL64(const BYTE **ppb);
  418. ULONG CodeSizeVL32(ULONG ul);
  419. PBYTE EncodeVL32(PBYTE pb, ULONG ul);
  420. PBYTE EncodeVL64(PBYTE pb, CULINT *ull);
  421. PBYTE SkipVL(PBYTE pb);
  422. #endif // __PATHMGR_H__