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.

474 lines
18 KiB

  1. #ifndef _INC_DSKQUOTA_SIDCACHE_H
  2. #define _INC_DSKQUOTA_SIDCACHE_H
  3. ///////////////////////////////////////////////////////////////////////////////
  4. /* File: sidcache.h
  5. Description: Header for classes associated with the SID/Name cache.
  6. Here's a ER-style diagram of the SID cache. The cache consists
  7. of a data file and index file. The index is a hash table consisting
  8. of an array of hash buckets, each containing 0 or more hash bucket entries.
  9. Each hash bucket entry contains the index of it's corresponding user record
  10. in the data file. The index hash code is based on the user SID.
  11. The index is designed for fast lookup of queue entries. Hash values are
  12. calculated by simply summing the value of the bytes in a SID and
  13. performing modulo division with the number of hash buckets. Each hash
  14. bucket contains a doubly-linked list to handle hash value collisions
  15. and removal of expired entries. Each hash bucket entry contains the index
  16. of the starting block for the user's record in the data file.
  17. +-----------+ +--------+<---> User SID
  18. +-->| data file |<--->>| record |<---> User Domain
  19. | +-----------+ +--------+<---> User Name
  20. | ^ <---> User Full User Name
  21. +-----------+<---+ |
  22. | cache | |
  23. +-----------+<---+ +--- points to ----+
  24. | |
  25. | |
  26. | +----------+ +-------------+ +--------------+
  27. +-->| ndx file |<--->>| hash bucket |<-->>| bucket entry |
  28. +----------+ +-------------+ +--------------+
  29. <---> = One-to-one
  30. <-->> = One-to-many
  31. Notes:
  32. 1. Because SID->Name resolution over the network is very slow
  33. (0-10 seconds), I anticipate that this cache will be used heavily
  34. and may contain 100's or 1000's of entries depending upon the
  35. volume's usage.
  36. Index file structure ------------------------------------------------------
  37. +------------------------+
  38. | Header | <--- Type INDEX_FILE_HDR
  39. +------------------------+
  40. | |
  41. | | <--- Array of DWORDs. Count should be prime.
  42. | Hash bucket array | Each element represents a hash bucket.
  43. | | Unused elements contain NULL.
  44. | | Used elements contain address of first
  45. | | entry in hash bucket's entry list.
  46. +------------------------+
  47. | |
  48. | |
  49. | | <--- Array of INDEX_ENTRY.
  50. | Index entries | Each entry is a node in a linked list.
  51. | | Initially, all are on the "free list".
  52. | | As entries are allocated, they are
  53. | | transfered to the appropriate hash bucket's
  54. | | list. Each used entry contains the
  55. | | starting block number of the corresponding
  56. | | record in the data file.
  57. +------------------------+
  58. Data file structure -------------------------------------------------------
  59. +------------------------+
  60. | Header | <--- Type DATA_FILE_HDR
  61. +------------------------+
  62. | |
  63. | Block alloc map | <--- Array of DWORDs. Each bit represents the
  64. | | allocation state of a record block.
  65. | | 0 = free, 1 = allocated.
  66. +------------------------+
  67. | |
  68. | |
  69. | | <--- Array of BLOCKs. (32-bytes each)
  70. | Record blocks | Each data record consists of one or more
  71. | | blocks. The first block in each record
  72. | | is of type RECORD_HDR. The remaining
  73. | | blocks contain the variable-length SID,
  74. | | Domain name, User name and Full User
  75. | | name. Blocks are aligned on quadword
  76. | | boundaries for the FILETIME structure
  77. | | in RECORD_HDR. The 3 name string fields
  78. | | are UNICODE and are WORD-aligned.
  79. | | Unused blocks are filled with 0xCC.
  80. | | A BLOCK is the smallest allocation unit.
  81. +------------------------+
  82. Revision History:
  83. Date Description Programmer
  84. -------- --------------------------------------------------- ----------
  85. 07/12/96 Initial creation. BrianAu
  86. 08/14/96 Added SidCacheQueueIterator. BrianAu
  87. 09/05/96 Added domain name string. BrianAu
  88. 09/20/96 Total redesign. Old design loaded data from file BrianAu
  89. into an in-memory hash table. New design leaves
  90. everything on disk and merely maps the file into
  91. memory. Much more efficient with respect to
  92. speed and size.
  93. 03/18/98 Replaced "domain", "name" and "full name" with BrianAu
  94. "container", "logon name" and "display name" to
  95. better match the actual contents. This was in
  96. reponse to making the quota UI DS-aware. The
  97. "logon name" is now a unique key as it contains
  98. both account name and domain-like information.
  99. i.e. "REDMOND\brianau" or "[email protected]".
  100. */
  101. ///////////////////////////////////////////////////////////////////////////////
  102. const DWORD BITS_IN_BYTE = 8;
  103. const DWORD BITS_IN_DWORD = BITS_IN_BYTE * sizeof(DWORD);
  104. //
  105. // On-disk structure of a single index entry.
  106. // There's an entry for each record in the cache.
  107. // Length = 16 bytes.
  108. //
  109. typedef struct index_entry
  110. {
  111. index_entry *pPrev;
  112. index_entry *pNext;
  113. DWORD iBlock;
  114. DWORD iBucket;
  115. } INDEX_ENTRY, *PINDEX_ENTRY;
  116. //
  117. // On-disk structure of index file header.
  118. // Length = 48 bytes
  119. // Must be even multiple of 8 bytes (quadword-align).
  120. //
  121. typedef struct index_file_hdr
  122. {
  123. DWORD dwSignature; // ID's file as a quota cache index.
  124. DWORD dwVersion; // SW version that created file.
  125. GUID guid; // Verifies validity of data.
  126. DWORD cBuckets; // Number of hash buckets.
  127. DWORD cMaxEntries; // Max number of entries.
  128. DWORD cEntries; // Number of used entries.
  129. PINDEX_ENTRY *pBuckets; // Address of first hash bucket.
  130. PINDEX_ENTRY pEntries; // Offset to first entry.
  131. PINDEX_ENTRY pFirstFree; // Offset to first entry in free list.
  132. } INDEX_FILE_HDR, *PINDEX_FILE_HDR;
  133. //
  134. // Define what a data file "block" is.
  135. // Keep the block size a power of 2.
  136. //
  137. const DWORD BLOCK_SIZE = 32; // Size is in bytes.
  138. typedef BYTE BLOCK[BLOCK_SIZE];
  139. typedef BLOCK *PBLOCK;
  140. //
  141. // On-disk structure of data file header.
  142. // Length = 48 bytes.
  143. //
  144. typedef struct data_file_hdr
  145. {
  146. DWORD dwSignature; // ID's file as quota cache data.
  147. DWORD dwVersion; // SW version that created file.
  148. GUID guid; // Verifies validity of data.
  149. DWORD cBlocks; // Total number of allocation blocks.
  150. DWORD cBlocksUsed; // Number of used allocation blocks.
  151. DWORD cMapElements; // Number of alloc map elements.
  152. DWORD iFirstFree; // Index of first free block.
  153. LPDWORD pdwMap; // Address of alloc map.
  154. PBLOCK pBlocks; // Address of block pool.
  155. } DATA_FILE_HDR, *PDATA_FILE_HDR;
  156. //
  157. // On-disk structure of the header info for each record.
  158. // This fixed length structure precedes the variable-length part.
  159. // Quad-word aligned.
  160. // Length = 32 bytes (1 block).
  161. // Strings are UNICODE, WORD-aligned.
  162. //
  163. typedef struct record_hdr
  164. {
  165. DWORD dwSignature; // Rec hdr signature. (0xAAAA5555)
  166. DWORD cBlocks; // Blks in record.
  167. FILETIME Birthday; // When was record added to cache?
  168. DWORD cbOfsSid; // Ofs from start of record.
  169. DWORD cbOfsContainer; // Ofs from start of record.
  170. DWORD cbOfsLogonName; // Ofs from start of record.
  171. DWORD cbOfsDisplayName; // Ofs from start of record.
  172. } RECORD_HDR, *PRECORD_HDR;
  173. class SidNameCache
  174. {
  175. private:
  176. //
  177. // Private class encapsulating the functions of the cache index.
  178. //
  179. class IndexMgr
  180. {
  181. private:
  182. SidNameCache& m_refCache; // Ref to outer cache object.
  183. PINDEX_FILE_HDR m_pFileHdr; // Same as g_pbMappedIndexFile.
  184. HANDLE m_hFile; // Handle to index file.
  185. HANDLE m_hFileMapping; // Mapped file.
  186. CString m_strFileName; // Full path\name of index file.
  187. LPBYTE CreateIndexFile(LPCTSTR pszFile,
  188. DWORD cbFileHigh,
  189. DWORD cbFileLow);
  190. LPBYTE OpenIndexFile(LPCTSTR pszFile);
  191. LPBYTE GrowIndexFile(DWORD cGrowEntries);
  192. VOID CloseIndexFile(VOID);
  193. VOID InitNewIndexFile(DWORD cBuckets, DWORD cMaxEntries);
  194. PINDEX_ENTRY AllocEntry(VOID);
  195. VOID FreeEntry(PINDEX_ENTRY pEntry);
  196. VOID AddEntryToFreeList(PINDEX_ENTRY pEntry);
  197. PINDEX_ENTRY DetachEntry(PINDEX_ENTRY pEntry);
  198. PINDEX_ENTRY Find(PSID pSid);
  199. PINDEX_ENTRY Find(PSID pSid, DWORD dwHashCode);
  200. PINDEX_ENTRY Find(LPCTSTR pszLogonName);
  201. DWORD Hash(PSID pSid);
  202. PINDEX_ENTRY GetHashBucketValue(DWORD iBucket);
  203. VOID SetHashBucketValue(DWORD iBucket, PINDEX_ENTRY pEntry);
  204. //
  205. // Prevent copy.
  206. //
  207. IndexMgr(const IndexMgr& rhs);
  208. IndexMgr& operator = (const IndexMgr& rhs);
  209. public:
  210. IndexMgr(SidNameCache& refCache);
  211. ~IndexMgr(VOID);
  212. LPBYTE Initialize(LPCTSTR pszFile,
  213. DWORD cBuckets = 0,
  214. DWORD cMaxEntries = 0);
  215. DWORD Lookup(PSID pSid);
  216. DWORD Lookup(LPCTSTR pszLogonName);
  217. PINDEX_ENTRY Add(PSID pSid, DWORD iBlock);
  218. static UINT64 FileSize(DWORD cMaxEntries, DWORD cBuckets)
  219. {
  220. return (UINT64)(sizeof(INDEX_FILE_HDR)) +
  221. (UINT64)(sizeof(PINDEX_ENTRY) * cBuckets) +
  222. (UINT64)(sizeof(INDEX_ENTRY) * cMaxEntries);
  223. }
  224. VOID SetFileGUID(const GUID *pguid);
  225. VOID GetFileGUID(LPGUID pguid);
  226. VOID FreeEntry(PSID pSid);
  227. VOID Clear(VOID);
  228. #ifdef DBG
  229. VOID Dump(VOID);
  230. #endif
  231. };
  232. //
  233. // Private class that manages the cache's stored data records.
  234. //
  235. class RecordMgr
  236. {
  237. private:
  238. SidNameCache& m_refCache; // Ref to outer cache object.
  239. PDATA_FILE_HDR m_pFileHdr; // Same as g_pbMappedDataFile
  240. HANDLE m_hFile; // Handle to data file.
  241. HANDLE m_hFileMapping; // Mapped data file.
  242. DWORD m_cDaysRecLifeMin; // Min and range are used to
  243. DWORD m_cDaysRecLifeRange; // calc lifetime of records.
  244. CString m_strFileName; // Full path\name of data file.
  245. BOOL ValidBlockNumber(DWORD iBlock);
  246. VOID FillBlocks(DWORD iBlock, DWORD cBlocks, BYTE b);
  247. BOOL IsBitSet(LPDWORD pdwBase, DWORD iBit);
  248. VOID SetBit(LPDWORD pdwBase, DWORD iBit);
  249. VOID ClrBit(LPDWORD pdwBase, DWORD iBit);
  250. BOOL IsBlockUsed(DWORD iBlock);
  251. VOID MarkBlockUsed(DWORD iBlock);
  252. VOID MarkBlockUnused(DWORD iBlock);
  253. DWORD BlocksRequired(DWORD cb);
  254. DWORD BytesRequiredForRecord(
  255. PSID pSid,
  256. LPDWORD pcbSid,
  257. LPCTSTR pszContainer,
  258. LPDWORD pcbContainer,
  259. LPCTSTR pszLogonName,
  260. LPDWORD pcbLogonName,
  261. LPCTSTR pszDisplayName,
  262. LPDWORD pcbDisplayName);
  263. VOID FreeBlock(DWORD iBlock);
  264. VOID FreeBlocks(DWORD iFirstBlock, DWORD cBlocks);
  265. BLOCK *BlockAddress(DWORD iBlock);
  266. DWORD AllocBlocks(DWORD cbRecord);
  267. LPBYTE CreateDataFile(LPCTSTR pszFile, DWORD cbFileHigh, DWORD cbFileLow);
  268. LPBYTE OpenDataFile(LPCTSTR pszFile);
  269. LPBYTE GrowDataFile(DWORD cGrowBlocks);
  270. VOID InitNewDataFile(DWORD cBlocks);
  271. VOID CloseDataFile(VOID);
  272. //
  273. // Prevent copy.
  274. //
  275. RecordMgr(const RecordMgr& rhs);
  276. RecordMgr& operator = (const RecordMgr& rhs);
  277. public:
  278. RecordMgr(SidNameCache& refCache);
  279. ~RecordMgr(VOID);
  280. LPBYTE Initialize(
  281. LPCTSTR pszFile,
  282. DWORD cBlocks = 0);
  283. static UINT64 FileSize(DWORD cBlocks);
  284. DWORD Store(
  285. PSID pSid,
  286. LPCTSTR pszContainer,
  287. LPCTSTR pszLogonName,
  288. LPCTSTR pszDisplayName);
  289. BOOL RecordExpired(DWORD iBlock);
  290. HRESULT Retrieve(
  291. DWORD iBlock,
  292. PSID *ppSid,
  293. LPTSTR *ppszContainer,
  294. LPTSTR *ppszLogonName,
  295. LPTSTR *ppszDisplayName);
  296. VOID SetFileGUID(const GUID *pguid);
  297. VOID GetFileGUID(LPGUID pguid);
  298. VOID FreeRecord(DWORD iFirstBlock);
  299. VOID Clear(VOID);
  300. #ifdef DBG
  301. VOID Dump(VOID);
  302. #endif
  303. };
  304. //
  305. // Private class for handling locks on cache files that must
  306. // be automatically released when an exception is thrown.
  307. //
  308. class CacheAutoLock
  309. {
  310. public:
  311. explicit CacheAutoLock(SidNameCache& Cache)
  312. : m_Cache(Cache) { };
  313. BOOL Lock(VOID)
  314. { return m_Cache.Lock(); }
  315. ~CacheAutoLock(VOID)
  316. {m_Cache.ReleaseLock(); }
  317. private:
  318. SidNameCache& m_Cache;
  319. //
  320. // Prevent copy.
  321. //
  322. CacheAutoLock(const CacheAutoLock& rhs);
  323. CacheAutoLock& operator = (const CacheAutoLock& rhs);
  324. };
  325. friend class CacheAutoLock;
  326. HANDLE m_hMutex; // For locking during updates.
  327. IndexMgr *m_pIndexMgr; // Manages index file.
  328. RecordMgr *m_pRecordMgr; // Manages data file.
  329. CString m_strFilePath; // Path to cache files.
  330. BOOL Lock(VOID);
  331. VOID ReleaseLock(VOID);
  332. BOOL FilesAreValid(VOID);
  333. VOID ValidateFiles(VOID);
  334. VOID InvalidateFiles(VOID);
  335. VOID SetCacheFilePath(VOID);
  336. BOOL CreateCacheFileDirectory(LPCTSTR pszPath);
  337. //
  338. // Private ctor prevents creation outside of singleton access
  339. // function.
  340. //
  341. SidNameCache(VOID);
  342. //
  343. // The singleton instance access function.
  344. //
  345. friend HRESULT SidNameCache_GetOrDestroy(SidNameCache **ppCache, bool bGet);
  346. public:
  347. ~SidNameCache(VOID);
  348. HRESULT Initialize(
  349. BOOL bOpenExisting);
  350. HRESULT Lookup(
  351. PSID pSid,
  352. LPTSTR *ppszContainer,
  353. LPTSTR *ppszLogonName,
  354. LPTSTR *ppszDisplayName);
  355. HRESULT Lookup(
  356. LPCTSTR pszLogonName,
  357. PSID *ppSid);
  358. HRESULT Add(
  359. PSID pSid,
  360. LPCTSTR pszContainer,
  361. LPCTSTR pszLogonName,
  362. LPCTSTR pszDisplayName);
  363. // HRESULT CheckConsistency(VOID);
  364. BOOL Clear(VOID);
  365. HRESULT BeginTransaction(VOID);
  366. VOID EndTransaction(VOID);
  367. static LPBYTE OpenMappedFile(
  368. LPCTSTR pszDataFile,
  369. LPCTSTR pszMapping,
  370. DWORD dwCreation,
  371. DWORD cbFileHigh,
  372. DWORD cbFileLow,
  373. PHANDLE phFile,
  374. PHANDLE phFileMapping);
  375. static BOOL IsQuadAligned(LPVOID pv);
  376. static BOOL IsQuadAligned(DWORD_PTR dw);
  377. static VOID QuadAlign(LPDWORD lpdwValue);
  378. static VOID WordAlign(LPDWORD lpdwValue);
  379. #if DBG
  380. VOID Dump(VOID)
  381. { m_pIndexMgr->Dump(); m_pRecordMgr->Dump(); }
  382. #endif
  383. friend class IndexMgr;
  384. friend class RecordMgr;
  385. };
  386. HRESULT SidNameCache_Get(SidNameCache **ppCache);
  387. HRESULT SidNameCache_Destroy(void);
  388. #endif // _INC_DSKQUOTA_SIDCACHE_H