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.

4280 lines
134 KiB

  1. ///////////////////////////////////////////////////////////////////////////////
  2. /* File: sidcache.cpp
  3. Description: This module provides the functionality for a cache of user
  4. SID/Name pairs. See the file header in sidcache.h for details.
  5. Revision History:
  6. Date Description Programmer
  7. -------- --------------------------------------------------- ----------
  8. 07/12/96 Initial creation. BrianAu
  9. 08/14/96 Added SidCacheQueueIterator. BrianAu
  10. 09/20/96 Total redesign. Old design loaded data from file BrianAu
  11. into an in-memory hash table. New design leaves
  12. everything on disk and merely maps the file into
  13. memory. Much more efficient with respect to
  14. speed and size.
  15. 07/02/97 Added SidNameCache::GetFileNames. Brianau
  16. Changed logic for identifying cache file path.
  17. Removed index bucket count param from registry.
  18. 03/18/98 Replaced "domain", "name" and "full name" with BrianAu
  19. "container", "logon name" and "display name" to
  20. better match the actual contents. This was in
  21. reponse to making the quota UI DS-aware. The
  22. "logon name" is now a unique key as it contains
  23. both account name and domain-like information.
  24. i.e. "REDMOND\brianau" or "[email protected]".
  25. */
  26. ///////////////////////////////////////////////////////////////////////////////
  27. #include "pch.h" // PCH
  28. #pragma hdrstop
  29. #include "dskquota.h"
  30. #include "sidcache.h"
  31. #include "registry.h"
  32. //
  33. // Verify that build is UNICODE.
  34. //
  35. #if !defined(UNICODE)
  36. # error This module must be compiled UNICODE.
  37. #endif
  38. //
  39. // How long (milliseconds) we'll wait to get a lock on the cache.
  40. //
  41. const DWORD MUTEX_WAIT_TIMEOUT = 5000;
  42. //
  43. // Byte value used to fill in unused blocks in the data file.
  44. //
  45. const BYTE RECORD_UNUSED_BYTE = 0xCC;
  46. //
  47. // A value to signify the start of a record in the data file.
  48. // The bit pattern is 1010101010101010 0101010101010101
  49. // Highly unlikely that any data file data will produce this
  50. // pattern.
  51. //
  52. const DWORD RECORD_SIGNATURE = 0xAAAA5555;
  53. //
  54. // Signatures written into the header of the index and data files.
  55. // For validating a file just in case someone's put another file
  56. // in their place. The numbers are arbitrary.
  57. // 2600 means "MS building 26N (where I'm working now).
  58. // 3209 is my office number.
  59. // 3210 is BobDay's office number (across the hall).
  60. // Hey, I had to pick something.
  61. //
  62. const DWORD INDEX_FILE_SIGNATURE = 0x26003209;
  63. const DWORD DATA_FILE_SIGNATURE = 0x26003210;
  64. //
  65. // A version number so a future build of the software won't be confused
  66. // by a change in file formats. Bump this if the file format changes.
  67. //
  68. const DWORD FILE_VERSION = 0x00000003;
  69. //
  70. // Average number of 32-byte blocks per cache entry.
  71. // Entries are variable length (SID, Name etc). This average is used
  72. // in initially sizing the data file. I've found that most entries (by far)
  73. // require 4 blocks. Both the data file and index file grow independently
  74. // as needed so it isn't a problem if this isn't always accurate.
  75. //
  76. const DWORD AVG_BLOCKS_PER_ENTRY = 4;
  77. //
  78. // Create space for this many records in a new data file.
  79. // Since the data and index files grow automatically as needed,
  80. // this can change as you see fit.
  81. //
  82. #if DBG
  83. const DWORD NEW_CACHE_ENTRY_COUNT = 4; // Force frequent file growth.
  84. #else
  85. const DWORD NEW_CACHE_ENTRY_COUNT = 128;
  86. #endif
  87. //
  88. // The index and data files automatically grow when needed. These
  89. // values control how much they grow by.
  90. //
  91. #if DBG
  92. const DWORD DATA_FILE_GROW_BLOCKS = 4; // Force frequent file growth.
  93. #else
  94. const DWORD DATA_FILE_GROW_BLOCKS = 512;
  95. #endif
  96. const DWORD INDEX_FILE_GROW_ENTRIES = (DATA_FILE_GROW_BLOCKS / AVG_BLOCKS_PER_ENTRY);
  97. //
  98. // The number of buckets in the cache index hash table.
  99. // Number should be prime. Remember, this index is on disk so we can afford to
  100. // have a reasonably large hash table. While it would be nice to fit the
  101. // buckets within a single page of memory, that would be too small to be effective
  102. // 512 / 4 == 64 buckets. There's also no guarantee that all buckets would be
  103. // mapped to a single physical page.
  104. //
  105. const DWORD INDEX_BUCKET_COUNT = 503;
  106. //
  107. // Convert between blocks and bytes.
  108. // BLOCK_SIZE is a power of 2 so the multiply and division
  109. // can be optimized to shifts.
  110. //
  111. #define BYTE_TO_BLOCK(b) ((b) / BLOCK_SIZE)
  112. #define BLOCK_TO_BYTE(b) ((b) * BLOCK_SIZE)
  113. //
  114. // Base pointers for mapped data and index files.
  115. // When the files are mapped into memory, these globals contain
  116. // the address of the mapped memory.
  117. //
  118. LPBYTE g_pbMappedDataFile;
  119. LPBYTE g_pbMappedIndexFile;
  120. //
  121. // Macros for working with based pointers.
  122. // Pointer members in the file structures contain offsets relative
  123. // to the start of the file. When dereferencing these pointers,
  124. // they must be converted to "based" pointers which add the file's
  125. // base address to the pointer value. This results in a true
  126. // virtual address that can be accessed.
  127. //
  128. #if defined(_X86_)
  129. # define NDX_BASED(t) t __based(g_pbMappedIndexFile)
  130. # define DAT_BASED(t) t __based(g_pbMappedDataFile)
  131. # define NDX_BASED_CAST(t,e) (NDX_BASED(t) *)((DWORD)(e))
  132. # define DAT_BASED_CAST(t,e) (DAT_BASED(t) *)((DWORD)(e))
  133. #else
  134. //
  135. // APPCOMPAT:
  136. // I think there's a bug in the ALPHA compiler that is preventing __based pointers
  137. // from working as I have used them.
  138. // This is a workaround until the bug is fixed or I find out what I'm doing wrong.
  139. //
  140. # define NDX_BASED(t) t
  141. # define DAT_BASED(t) t
  142. # define NDX_BASED_CAST(t,e) ((NDX_BASED(t) *)(((BYTE *)g_pbMappedIndexFile) + ((DWORD_PTR)(e))))
  143. # define DAT_BASED_CAST(t,e) ((DAT_BASED(t) *)(((BYTE *)g_pbMappedDataFile) + ((DWORD_PTR)(e))))
  144. #endif
  145. //
  146. // Macros to verify that the files have been mapped.
  147. // These are primarily used in assertions.
  148. //
  149. #define INDEX_FILE_MAPPED (NULL != g_pbMappedIndexFile)
  150. #define DATA_FILE_MAPPED (NULL != g_pbMappedDataFile)
  151. //
  152. // Names for system objects. Mutex and maps are named so they can
  153. // be shared between processes.
  154. //
  155. const LPCTSTR g_szSidCacheMutex = TEXT("DSKQUOTA_SIDCACHE_MUTEX");
  156. const LPCTSTR g_pszIndexFileMapping = TEXT("DSKQUOTA_SIDCACHE_INDEX");
  157. const LPCTSTR g_pszDataFileMapping = TEXT("DSKQUOTA_SIDCACHE_DATA");
  158. //
  159. // Use to clear a file's GUID and to test for a NULL guid.
  160. //
  161. static const GUID GUID_Null =
  162. { 0x00000000, 0x0000, 0x0000, { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } };
  163. //
  164. // Registry parameter value names.
  165. //
  166. const TCHAR g_szSidCacheRecLifeMin[] = TEXT("SidCacheRecLifeMin");
  167. const TCHAR g_szSidCacheRecLifeMax[] = TEXT("SidCacheRecLifeMax");
  168. //***********************************************************************************
  169. //***********************************************************************************
  170. // C A C H E M A N A G E R
  171. //***********************************************************************************
  172. //***********************************************************************************
  173. //
  174. // Called by both SidNameCache_Get and SidNameCache_Destroy to either retrieve
  175. // the address (and create if necessary) of the singleton cache object or to
  176. // destroy that object. The reason to have this single function is so that
  177. // the singleton pointer is a local variable, inaccessible outside of this
  178. // function. This way the only access to the cache object is through
  179. // the SidNameCache_Get function.
  180. //
  181. HRESULT
  182. SidNameCache_GetOrDestroy(
  183. SidNameCache **ppCache,
  184. bool bGet
  185. )
  186. {
  187. DBGASSERT((NULL != ppCache));
  188. HRESULT hr = E_FAIL;
  189. //
  190. // This is the one-and-only pointer to the SID-Name cache object.
  191. // All code obtains this address through this function.
  192. //
  193. static SidNameCache *pTheCache;
  194. *ppCache = NULL;
  195. HANDLE hMutex = CreateMutex(NULL, FALSE, g_szSidCacheMutex);
  196. if (NULL != hMutex)
  197. {
  198. if (WAIT_OBJECT_0 == WaitForSingleObject(hMutex, INFINITE))
  199. {
  200. if (!bGet)
  201. {
  202. //
  203. // Destroy the existing cache object. NULL the static
  204. // ptr so next request will recreate the cache object.
  205. //
  206. delete pTheCache;
  207. pTheCache = NULL;
  208. hr = S_OK;
  209. }
  210. else
  211. {
  212. //
  213. // Retrieve existing or create new cache object.
  214. //
  215. SidNameCache *pCache = pTheCache;
  216. if (NULL != pCache)
  217. {
  218. //
  219. // Use the existing object.
  220. //
  221. hr = S_OK;
  222. }
  223. else
  224. {
  225. try
  226. {
  227. //
  228. // Doesn't yet exist. Create new one.
  229. //
  230. autoptr<SidNameCache> ptrCache(new SidNameCache);
  231. //
  232. // Open/Create new cache data and index files.
  233. // Will first try to open existing. If either the index or
  234. // data file doesn't exist or is invalid, new files are created.
  235. //
  236. hr = ptrCache->Initialize(TRUE);
  237. if (SUCCEEDED(hr))
  238. {
  239. pCache = ptrCache.get();
  240. ptrCache.disown();
  241. //
  242. // Save in our static variable for future use.
  243. //
  244. pTheCache = pCache;
  245. }
  246. else
  247. {
  248. DBGERROR((TEXT("SID cache initialization failed with error 0x%08X"), hr));
  249. }
  250. }
  251. catch(CAllocException& e)
  252. {
  253. hr = E_OUTOFMEMORY;
  254. }
  255. catch(CSyncException& e)
  256. {
  257. hr = E_FAIL;
  258. }
  259. }
  260. if (SUCCEEDED(hr))
  261. {
  262. //
  263. // Return the pointer to the caller.
  264. //
  265. *ppCache = pCache;
  266. }
  267. }
  268. ReleaseMutex(hMutex);
  269. }
  270. CloseHandle(hMutex);
  271. }
  272. return hr;
  273. }
  274. //
  275. // Retrieves the address of the singleton SidNameCache object.
  276. // If the object doesn't exist it is created.
  277. // Callers do not release or delete this pointer.
  278. // On Process-Detach, the SidNameCache_Destroy() function is
  279. // called to delete the singleton object.
  280. //
  281. HRESULT SidNameCache_Get(SidNameCache **ppCache)
  282. {
  283. const bool bGet = true;
  284. return SidNameCache_GetOrDestroy(ppCache, bGet);
  285. }
  286. //
  287. // Called on Process-Detach to destroy the singleton cache
  288. // object.
  289. //
  290. HRESULT SidNameCache_Destroy(void)
  291. {
  292. const bool bGet = false;
  293. SidNameCache *pUnused;
  294. return SidNameCache_GetOrDestroy(&pUnused, bGet);
  295. }
  296. ///////////////////////////////////////////////////////////////////////////////
  297. /* Function: SidNameCache::SidNameCache
  298. Description: Constructor. Creates an empty SID/Name cache object.
  299. Call one of the Initialize() methods to either create a new index and
  300. data file or to open existing ones.
  301. Arguments: None.
  302. Returns: Nothing.
  303. Exceptions: SyncObjErrorCreate.
  304. Revision History:
  305. Date Description Programmer
  306. -------- --------------------------------------------------- ----------
  307. 09/21/96 Initial creation. BrianAu
  308. */
  309. ///////////////////////////////////////////////////////////////////////////////
  310. SidNameCache::SidNameCache(
  311. VOID
  312. ) : m_hMutex(NULL),
  313. m_pIndexMgr(NULL),
  314. m_pRecordMgr(NULL)
  315. {
  316. DBGTRACE((DM_SIDCACHE, DL_MID, TEXT("SidNameCache::SidNameCache")));
  317. if (NULL == (m_hMutex = CreateMutex(NULL, // No security
  318. FALSE, // Non-owned
  319. g_szSidCacheMutex)))
  320. {
  321. throw CSyncException(CSyncException::mutex, CSyncException::create);
  322. }
  323. SetCacheFilePath();
  324. }
  325. ///////////////////////////////////////////////////////////////////////////////
  326. /* Function: SidNameCache::~SidNameCache
  327. Description: Destructor. Destroys the cache object by deleting the
  328. Index Manager and Record Manager objects. The respective destructor's
  329. for each of the managers will handle closing their files and mapping
  330. objects.
  331. Arguments: None.
  332. Returns: Nothing.
  333. Revision History:
  334. Date Description Programmer
  335. -------- --------------------------------------------------- ----------
  336. 09/21/96 Initial creation. BrianAu
  337. */
  338. ///////////////////////////////////////////////////////////////////////////////
  339. SidNameCache::~SidNameCache(
  340. VOID
  341. )
  342. {
  343. DBGTRACE((DM_SIDCACHE, DL_MID, TEXT("SidNameCache::~SidNameCache")));
  344. if (NULL != m_hMutex)
  345. Lock();
  346. delete m_pIndexMgr;
  347. delete m_pRecordMgr;
  348. if (NULL != m_hMutex)
  349. {
  350. ReleaseLock();
  351. CloseHandle(m_hMutex);
  352. }
  353. }
  354. ///////////////////////////////////////////////////////////////////////////////
  355. /* Function: SidNameCache::Initialize
  356. Description: Initializes a new cache object by creating the Index and
  357. Record manager objects then initializing each. Initialization first
  358. tries to open existing index and data files. If one (or both) of the
  359. files does not exist OR one (or both) of the files is considered
  360. "invalid", new files are created. Need to take a "fail safe" approach
  361. to this.
  362. Arguments:
  363. bOpenExisting - TRUE = Try to open an existing cache index and data file.
  364. If it can't, it creates a new one. FALSE = Just create a new one.
  365. Returns:
  366. NO_ERROR - Success.
  367. E_FAIL - Could not open nor create required files.
  368. Exceptions: OutOfMemory.
  369. Revision History:
  370. Date Description Programmer
  371. -------- --------------------------------------------------- ----------
  372. 09/21/96 Initial creation. BrianAu
  373. */
  374. ///////////////////////////////////////////////////////////////////////////////
  375. HRESULT
  376. SidNameCache::Initialize(
  377. BOOL bOpenExisting
  378. )
  379. {
  380. DBGTRACE((DM_CONTROL, DL_MID, TEXT("SidNameCache::Initialize")));
  381. DBGASSERT((NULL == m_pIndexMgr));
  382. DBGASSERT((NULL == m_pRecordMgr));
  383. HRESULT hResult = E_FAIL;
  384. CacheAutoLock lock(*this);
  385. if (lock.Lock())
  386. {
  387. try
  388. {
  389. if (m_strFilePath.IsEmpty())
  390. {
  391. //
  392. // If file path is empty, it means we couldn't get the
  393. // user's profile directory from the registry.
  394. //
  395. DBGERROR((TEXT("Error creating SID cache files. No path.")));
  396. }
  397. else
  398. {
  399. //
  400. // Name for our cache data and index files.
  401. // Will append .DAT and .NDX respectively.
  402. // This is where you change the file name or extension(s)
  403. // if you want to do that.
  404. //
  405. const TCHAR szSidCacheFile[] = TEXT("NTDiskQuotaSidCache");
  406. //
  407. // Create a fully-qualified path for the cache data and index
  408. // files. m_strFilePath was set in the cache object ctor.
  409. //
  410. CString strDataFile(m_strFilePath);
  411. CString strIndexFile(m_strFilePath);
  412. strDataFile.Format(TEXT("%1\\%2.dat"), (LPCTSTR)m_strFilePath, szSidCacheFile);
  413. strIndexFile.Format(TEXT("%1\\%2.ndx"),(LPCTSTR)m_strFilePath, szSidCacheFile);
  414. //
  415. // Create the record and index manager objects.
  416. //
  417. m_pRecordMgr = new RecordMgr(*this);
  418. m_pIndexMgr = new IndexMgr(*this);
  419. DBGPRINT((DM_CONTROL, DL_MID, TEXT("Create SID cache DataFile = %s IndexFile = %s"),
  420. (LPCTSTR)strDataFile, (LPCTSTR)strIndexFile));
  421. if (bOpenExisting)
  422. {
  423. //
  424. // First try opening existing data and index files.
  425. //
  426. if (NULL != m_pRecordMgr->Initialize(strDataFile))
  427. {
  428. if (NULL != m_pIndexMgr->Initialize(strIndexFile))
  429. hResult = NO_ERROR;
  430. }
  431. }
  432. if (FAILED(hResult) || !FilesAreValid())
  433. {
  434. hResult = E_FAIL;
  435. //
  436. // Couldn't open existing files, try creating new ones.
  437. // Any open files/mappings will be closed.
  438. //
  439. if (NULL != m_pRecordMgr->Initialize(strDataFile,
  440. NEW_CACHE_ENTRY_COUNT * AVG_BLOCKS_PER_ENTRY))
  441. {
  442. if (NULL != m_pIndexMgr->Initialize(strIndexFile,
  443. INDEX_BUCKET_COUNT,
  444. NEW_CACHE_ENTRY_COUNT))
  445. {
  446. hResult = NO_ERROR;
  447. }
  448. }
  449. }
  450. }
  451. }
  452. catch(CAllocException& e)
  453. {
  454. delete m_pRecordMgr;
  455. m_pRecordMgr = NULL;
  456. delete m_pIndexMgr;
  457. m_pIndexMgr = NULL;
  458. hResult = E_OUTOFMEMORY;
  459. }
  460. //
  461. // Mark files as "valid".
  462. //
  463. if (SUCCEEDED(hResult))
  464. ValidateFiles();
  465. }
  466. return hResult;
  467. }
  468. ///////////////////////////////////////////////////////////////////////////////
  469. /* Function: SidNameCache::OpenMappedFile
  470. Description: Opens or creates a file, maps the file into memory and
  471. returns the address of the mapping.
  472. Arguments:
  473. pszFile - Address of name of file to create/open.
  474. pszMapping - Name to give the mapping object. This object is
  475. named so that if multiple processes map the same file (using
  476. the same mapping name), the file is only mapped once.
  477. dwCreation - Creation flag (CREATE_ALWAYS, OPEN_EXISTING);
  478. cbFileHigh/Low - If creating a new file or extending an existing
  479. these two arguments contain the desired size in bytes.
  480. phFile - Address of handle variable to receive the open file's
  481. handle value. Call CloseHandle on this to close the file.
  482. phFileMapping - Address of handle variable to receive the open
  483. file mapping's handle value. Call CloseFileMapping on this
  484. to close the mapping.
  485. Returns:
  486. Address of the mapped file in memory. NULL on failure.
  487. Revision History:
  488. Date Description Programmer
  489. -------- --------------------------------------------------- ----------
  490. 09/21/96 Initial creation. BrianAu
  491. 07/21/97 Files are now created in user's profile under a BrianAu
  492. "DiskQuota" subdirectory.
  493. */
  494. ///////////////////////////////////////////////////////////////////////////////
  495. LPBYTE
  496. SidNameCache::OpenMappedFile(
  497. LPCTSTR pszFile,
  498. LPCTSTR pszMapping,
  499. DWORD dwCreation,
  500. DWORD cbFileHigh,
  501. DWORD cbFileLow,
  502. PHANDLE phFile,
  503. PHANDLE phFileMapping
  504. )
  505. {
  506. DBGTRACE((DM_SIDCACHE, DL_MID, TEXT("SidNameCache::OpenMappedFile")));
  507. LPBYTE pbBase = NULL;
  508. DBGASSERT((NULL != pszFile));
  509. DBGASSERT((NULL != pszMapping));
  510. DBGASSERT((NULL != phFile));
  511. DBGASSERT((NULL != phFileMapping));
  512. *phFile = CreateFile(pszFile,
  513. GENERIC_READ | GENERIC_WRITE,
  514. FILE_SHARE_READ | FILE_SHARE_WRITE,
  515. NULL,
  516. dwCreation,
  517. FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN,
  518. NULL);
  519. if (INVALID_HANDLE_VALUE != *phFile)
  520. {
  521. if ((*phFileMapping = CreateFileMapping(*phFile,
  522. NULL,
  523. PAGE_READWRITE,
  524. cbFileHigh,
  525. cbFileLow,
  526. pszMapping)) != NULL)
  527. {
  528. pbBase = (LPBYTE)MapViewOfFile(*phFileMapping,
  529. FILE_MAP_WRITE,
  530. 0,
  531. 0,
  532. 0);
  533. if (NULL == pbBase)
  534. DBGERROR((TEXT("SIDCACHE - Failed to map view of file %s"),
  535. pszFile));
  536. }
  537. else
  538. {
  539. DBGERROR((TEXT("SIDCACHE - Failed to create mapping %s for file %s"),
  540. pszMapping, pszFile));
  541. }
  542. if (NULL == pbBase)
  543. {
  544. CloseHandle(*phFile);
  545. *phFile = NULL;
  546. }
  547. }
  548. else
  549. DBGERROR((TEXT("SIDCACHE - Failed to open file %s"), pszFile));
  550. return pbBase;
  551. }
  552. ///////////////////////////////////////////////////////////////////////////////
  553. /* Function: SidNameCache::SetCacheFilePath
  554. Description: Obtains the fully-qualified path for the cache's data
  555. and index files and stores the value in m_strFilePath. The files
  556. are to be created under in the user's profile under the directory
  557. \AppData\Microsoft\Windows NT\DiskQuota. We have to read the registry
  558. to find exactly where this subtree lives for this user.
  559. Arguments: None.
  560. Returns: Nothing.
  561. On return, m_strFilePath contains the path to the files.
  562. Revision History:
  563. Date Description Programmer
  564. -------- --------------------------------------------------- ----------
  565. 07/02/97 Initial creation. BrianAu
  566. 07/21/97 Removed default file path. BrianAu
  567. Files can only be stored in user's profile.
  568. Can't allow unsecure access to SID/Name pairs.
  569. */
  570. ///////////////////////////////////////////////////////////////////////////////
  571. VOID
  572. SidNameCache::SetCacheFilePath(
  573. VOID
  574. )
  575. {
  576. DBGTRACE((DM_SIDCACHE, DL_HIGH, TEXT("SidNameCache::SetCacheFilePath")));
  577. //
  578. // Get the user's %UserProfile%\Application Data directory.
  579. // Normally, an app gets this through SHGetSpecialFolderLocation or
  580. // SHGetSpecialFolderPath. However, I don't want to load shell32.dll
  581. // just for that purpose (I've tried to keep shell32 out of this dll).
  582. // Therefore, we read the registry values just like the shell does.
  583. // EricFlo suggested this so it's OK ZAW-wise.
  584. //
  585. LONG lResult = ERROR_SUCCESS;
  586. HKEY hKey = NULL;
  587. DWORD dwDisposition = 0;
  588. const TCHAR szKeyNameRoot[] = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer");
  589. const TCHAR szMSWinNTDiskQuota[] = TEXT("Microsoft\\Windows NT\\DiskQuota");
  590. LPCTSTR rgpszKeys[] = {
  591. TEXT("\\User Shell Folders"),
  592. TEXT("\\Shell Folders"),
  593. };
  594. //
  595. // Start with an empty path buffer.
  596. //
  597. m_strFilePath.Empty();
  598. for (INT i = 0; i < ARRAYSIZE(rgpszKeys) && m_strFilePath.IsEmpty(); i++)
  599. {
  600. //
  601. // Create the key name.
  602. //
  603. CString strKeyName(szKeyNameRoot);
  604. strKeyName += CString(rgpszKeys[i]);
  605. //
  606. // Open the reg key.
  607. //
  608. lResult = RegCreateKeyEx(HKEY_CURRENT_USER,
  609. strKeyName,
  610. 0,
  611. NULL,
  612. 0,
  613. KEY_READ,
  614. NULL,
  615. &hKey,
  616. &dwDisposition);
  617. if (ERROR_SUCCESS == lResult)
  618. {
  619. try
  620. {
  621. //
  622. // Get the path to the user's "Application Data" directory.
  623. //
  624. DBGASSERT((NULL != hKey));
  625. DWORD dwValueType = 0;
  626. DWORD cbValue = MAX_PATH * sizeof(TCHAR);
  627. lResult = RegQueryValueEx(hKey,
  628. TEXT("AppData"),
  629. 0,
  630. &dwValueType,
  631. (LPBYTE)m_strFilePath.GetBuffer(MAX_PATH),
  632. &cbValue);
  633. m_strFilePath.ReleaseBuffer();
  634. if (ERROR_SUCCESS == lResult)
  635. {
  636. //
  637. // Ensure the path has a trailing backslash.
  638. //
  639. INT cchPath = m_strFilePath.Length();
  640. if (0 < cchPath && TEXT('\\') != m_strFilePath[cchPath-1])
  641. {
  642. m_strFilePath += CString(TEXT("\\"));
  643. }
  644. //
  645. // Append "Microsoft\Windows NT\DiskQuota" to the path.
  646. //
  647. m_strFilePath += CString(szMSWinNTDiskQuota);
  648. }
  649. else
  650. {
  651. //
  652. // Something failed. Ensure m_strFilePath is empty.
  653. //
  654. m_strFilePath.Empty();
  655. if (ERROR_FILE_NOT_FOUND != lResult)
  656. {
  657. DBGERROR((TEXT("SIDCACHE - Error %d getting \"AppData\" reg value."), lResult));
  658. }
  659. }
  660. }
  661. catch(CAllocException& e)
  662. {
  663. lResult = ERROR_OUTOFMEMORY;
  664. }
  665. RegCloseKey(hKey);
  666. }
  667. else if (ERROR_FILE_NOT_FOUND != lResult)
  668. {
  669. DBGERROR((TEXT("SIDCACHE - Error %d opening \"\\User Shell Folders\" or \"Shell Folders\" reg key"), lResult));
  670. }
  671. }
  672. if (!m_strFilePath.IsEmpty())
  673. {
  674. //
  675. // Expand any embedded environment strings.
  676. //
  677. m_strFilePath.ExpandEnvironmentStrings();
  678. //
  679. // Ensure the path DOES NOT have a trailing backslash.
  680. //
  681. INT cchPath = m_strFilePath.Length();
  682. if (0 < cchPath && TEXT('\\') == m_strFilePath[cchPath-1])
  683. {
  684. m_strFilePath[cchPath-1] = TEXT('\0');
  685. }
  686. if ((DWORD)-1 == ::GetFileAttributes(m_strFilePath))
  687. {
  688. //
  689. // If the directory doesn't exist, try to create it.
  690. //
  691. if (0 == CreateCacheFileDirectory(m_strFilePath))
  692. {
  693. //
  694. // Couldn't create the directory, make sure the path
  695. // is empty so we don't try to write to a non-existent
  696. // directory.
  697. //
  698. DBGERROR((TEXT("SIDCACHE - Error %d creating directory \"%s\""),
  699. GetLastError(), (LPCTSTR)m_strFilePath));
  700. m_strFilePath.Empty();
  701. }
  702. }
  703. }
  704. }
  705. ///////////////////////////////////////////////////////////////////////////////
  706. /* Function: SidNameCache::CreateCacheFileDirectory
  707. Description: Creates the directory for the SID/Name cache files. Since
  708. the directory lives several levels below "Application Data", we
  709. may need to create several directories before we get to DiskQuota.
  710. Arguments: pszPath - This is a fully-qualified directory path.
  711. Returns: TRUE = Directory created.
  712. FALSE = Directory not created.
  713. Revision History:
  714. Date Description Programmer
  715. -------- --------------------------------------------------- ----------
  716. 07/21/97 Initial creation. BrianAu
  717. */
  718. ///////////////////////////////////////////////////////////////////////////////
  719. BOOL
  720. SidNameCache::CreateCacheFileDirectory(
  721. LPCTSTR pszPath
  722. )
  723. {
  724. DBGTRACE((DM_SIDCACHE, DL_HIGH, TEXT("SidNameCache::CreateCacheFileDirectory")));
  725. BOOL bResult = TRUE;
  726. CString s(pszPath); // Local copy we can play with.
  727. LPTSTR psz = (LPTSTR)s; // Ptr to C string.
  728. while(TEXT('\0') != *psz && bResult)
  729. {
  730. //
  731. // Find the next backslash (or end-of-string).
  732. //
  733. while(TEXT('\0') != *psz && TEXT('\\') != *psz)
  734. {
  735. psz++;
  736. }
  737. //
  738. // Replace backslash with a temporary NUL.
  739. //
  740. TCHAR chSaved = *psz;
  741. *psz = TEXT('\0');
  742. //
  743. // See if the directory already exists.
  744. //
  745. if ((DWORD)-1 == ::GetFileAttributes(s))
  746. {
  747. //
  748. // It doesn't. Try to create it.
  749. //
  750. if (0 == ::CreateDirectory(s, NULL))
  751. {
  752. DBGERROR((TEXT("SIDCACHE - Error %d creating directory \"%s\""),
  753. GetLastError(), (LPCTSTR)s));
  754. bResult = FALSE;
  755. }
  756. }
  757. //
  758. // Replace temp NUL with original backslash and advance ptr
  759. // to next character in path (if we're not at the end of the string).
  760. //
  761. *psz = chSaved;
  762. if (TEXT('\0') != *psz)
  763. {
  764. psz++;
  765. }
  766. }
  767. if (bResult)
  768. {
  769. //
  770. // Created directory. Set SYSTEM & HIDDEN attribute bits on the final
  771. // subdirectory ("\DiskQuota").
  772. //
  773. SetFileAttributes(pszPath,
  774. GetFileAttributes(pszPath) | (FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN));
  775. }
  776. return bResult;
  777. }
  778. ///////////////////////////////////////////////////////////////////////////////
  779. /* Function: SidNameCache::Lock
  780. Description: Obtains an exclusive lock on the cache. This lock is
  781. system-wide so that multiple processes can access the cache files.
  782. Arguments: None.
  783. Returns:
  784. TRUE - Exclusive lock obtained or the lock was abandoned.
  785. No matter how the lock was obtained, the caller should always
  786. check the validity of the index and data files before trusting
  787. their contents.
  788. FALSE - Lock could not be obtained in the required timeout period.
  789. Revision History:
  790. Date Description Programmer
  791. -------- --------------------------------------------------- ----------
  792. 09/21/96 Initial creation. BrianAu
  793. */
  794. ///////////////////////////////////////////////////////////////////////////////
  795. BOOL
  796. SidNameCache::Lock(
  797. VOID
  798. )
  799. {
  800. BOOL bResult = FALSE;
  801. DBGASSERT((NULL != m_hMutex));
  802. //
  803. // IMPORTANT: Don't try handling thread messages with MsgWaitForMultipleObjects.
  804. // This lock function can be called on the resolver's background
  805. // thread. If you pull up that thread's messages, it won't receive
  806. // the WM_QUIT message commanding it to shutdown.
  807. //
  808. switch(WaitForSingleObject(m_hMutex, MUTEX_WAIT_TIMEOUT))
  809. {
  810. case WAIT_OBJECT_0:
  811. case WAIT_ABANDONED:
  812. bResult = TRUE;
  813. break;
  814. case WAIT_FAILED:
  815. case WAIT_TIMEOUT:
  816. default:
  817. break;
  818. }
  819. return bResult;
  820. }
  821. ///////////////////////////////////////////////////////////////////////////////
  822. /* Function: SidNameCache::ReleaseLock
  823. Description: Releases the exclusive lock on the cache. This function must
  824. always be paired with a call to Lock(). Be careful of conditions
  825. which may throw an exception and bypass releasing the lock.
  826. Arguments: None.
  827. Returns: Nothing.
  828. Revision History:
  829. Date Description Programmer
  830. -------- --------------------------------------------------- ----------
  831. 09/21/96 Initial creation. BrianAu
  832. */
  833. ///////////////////////////////////////////////////////////////////////////////
  834. VOID
  835. SidNameCache::ReleaseLock(
  836. VOID
  837. )
  838. {
  839. DBGASSERT((NULL != m_hMutex));
  840. ReleaseMutex(m_hMutex);
  841. }
  842. ///////////////////////////////////////////////////////////////////////////////
  843. /* Function: SidNameCache::BeginTransaction
  844. Description: Called at the beginning of any "transaction" to obtain
  845. exclusive access to the cache and verify the cache files are valid.
  846. Although this is of course not true transaction processing, it provides
  847. a simple approximation that is sufficient for this cache implementation.
  848. Note that before returning, the files are "invalidated". After the
  849. transaction is completed, the caller must call EndTransaction to
  850. release the exclusive lock and mark the files as "valid".
  851. Arguments: None.
  852. Returns:
  853. NO_ERROR - Success. Transaction can be carried out.
  854. ERROR_INVALID_DATA (hr) - Index or data file is invalid. Caller should
  855. re-initialize both index and data files.
  856. ERROR_LOCK_FAILED (hr) - Could not obtain exclusive access to the
  857. index and data files. Caller can either repeat the call or
  858. simply fail the cache access.
  859. Revision History:
  860. Date Description Programmer
  861. -------- --------------------------------------------------- ----------
  862. 09/21/96 Initial creation. BrianAu
  863. */
  864. ///////////////////////////////////////////////////////////////////////////////
  865. HRESULT
  866. SidNameCache::BeginTransaction(
  867. VOID
  868. )
  869. {
  870. HRESULT hResult = NO_ERROR;
  871. if (Lock())
  872. {
  873. if (FilesAreValid())
  874. {
  875. InvalidateFiles();
  876. }
  877. else
  878. {
  879. ReleaseLock();
  880. hResult = HRESULT_FROM_WIN32(ERROR_INVALID_DATA);
  881. }
  882. }
  883. else
  884. hResult = HRESULT_FROM_WIN32(ERROR_LOCK_FAILED);
  885. return hResult;
  886. }
  887. ///////////////////////////////////////////////////////////////////////////////
  888. /* Function: SidNameCache::EndTransaction
  889. Description: Called at the end of any "transaction" to release
  890. exclusive access to the cache and validate the cache files.
  891. Arguments: None.
  892. Returns: Nothing.
  893. Revision History:
  894. Date Description Programmer
  895. -------- --------------------------------------------------- ----------
  896. 09/21/96 Initial creation. BrianAu
  897. */
  898. ///////////////////////////////////////////////////////////////////////////////
  899. VOID
  900. SidNameCache::EndTransaction(
  901. VOID
  902. )
  903. {
  904. //
  905. // If you hit this assertion, probably didn't call BeginTransaction
  906. // first.
  907. //
  908. DBGASSERT((!FilesAreValid()));
  909. ValidateFiles();
  910. ReleaseLock();
  911. }
  912. ///////////////////////////////////////////////////////////////////////////////
  913. /* Function: SidNameCache::Clear
  914. Description: Resets both the index and data files to an empty state.
  915. Arguments: None.
  916. Returns:
  917. TRUE - Files reset.
  918. FALSE - Couldn't obtain lock to reset files or another process
  919. is also using the cache.
  920. Revision History:
  921. Date Description Programmer
  922. -------- --------------------------------------------------- ----------
  923. 09/21/96 Initial creation. BrianAu
  924. 08/07/00 Clear cache by clearing index and data files. Not BrianAu
  925. destroying and recreating.
  926. */
  927. ///////////////////////////////////////////////////////////////////////////////
  928. BOOL
  929. SidNameCache::Clear(
  930. VOID
  931. )
  932. {
  933. DBGTRACE((DM_SIDCACHE, DL_HIGH, TEXT("SidNameCache::Clear")));
  934. BOOL bResult = FALSE;
  935. CacheAutoLock lock(*this);
  936. if (lock.Lock())
  937. {
  938. if (NULL != m_pIndexMgr && NULL != m_pRecordMgr)
  939. {
  940. m_pIndexMgr->Clear();
  941. m_pRecordMgr->Clear();
  942. ValidateFiles();
  943. bResult = TRUE;
  944. }
  945. }
  946. return bResult;
  947. }
  948. ///////////////////////////////////////////////////////////////////////////////
  949. /* Function: SidNameCache::FilesAreValid
  950. Description: Examines the guid field in the index and data files.
  951. If the guids are non-zero and are equal, the files are considered
  952. "valid". BeginTransaction sets each guid to all 0's while
  953. EndTransaction fills them with a new GUID.
  954. Arguments: None.
  955. Returns:
  956. TRUE/FALSE indicating file validity.
  957. Revision History:
  958. Date Description Programmer
  959. -------- --------------------------------------------------- ----------
  960. 09/21/96 Initial creation. BrianAu
  961. */
  962. ///////////////////////////////////////////////////////////////////////////////
  963. BOOL
  964. SidNameCache::FilesAreValid(
  965. VOID
  966. )
  967. {
  968. DBGASSERT((DATA_FILE_MAPPED));
  969. DBGASSERT((INDEX_FILE_MAPPED));
  970. GUID guidIndexFile;
  971. GUID guidDataFile;
  972. m_pIndexMgr->GetFileGUID(&guidIndexFile);
  973. if (GUID_Null != guidIndexFile)
  974. {
  975. m_pRecordMgr->GetFileGUID(&guidDataFile);
  976. return guidDataFile == guidIndexFile;
  977. }
  978. return FALSE; // At least one GUID was all 0's
  979. }
  980. ///////////////////////////////////////////////////////////////////////////////
  981. /* Function: SidNameCache::ValidateFiles
  982. Description: Generates a new GUID and writes it to the header of the
  983. index and data files. This should only be called when a transaction
  984. has been successfully completed. EndTransaction calls this method
  985. to mark the files as "valid".
  986. Arguments: None.
  987. Returns: Nothing.
  988. Revision History:
  989. Date Description Programmer
  990. -------- --------------------------------------------------- ----------
  991. 09/21/96 Initial creation. BrianAu
  992. 05/18/00 Check return value from CoCreateGuid. BrianAu
  993. */
  994. ///////////////////////////////////////////////////////////////////////////////
  995. VOID
  996. SidNameCache::ValidateFiles(
  997. VOID
  998. )
  999. {
  1000. DBGASSERT((DATA_FILE_MAPPED));
  1001. DBGASSERT((INDEX_FILE_MAPPED));
  1002. //
  1003. // If GUID creation fails, the cache will be considered invalid.
  1004. // That's a reasonable system response. Failure of GUID creation
  1005. // is highly unlikely.
  1006. //
  1007. GUID guid;
  1008. if (SUCCEEDED(CoCreateGuid(&guid)))
  1009. {
  1010. m_pRecordMgr->SetFileGUID(&guid);
  1011. m_pIndexMgr->SetFileGUID(&guid);
  1012. }
  1013. }
  1014. ///////////////////////////////////////////////////////////////////////////////
  1015. /* Function: SidNameCache::InvalidateFiles
  1016. Description: Sets the guid field in each file to all 0's. This marks
  1017. a file as "invalid". BeginTransaction calls this.
  1018. Arguments: None.
  1019. Returns: Nothing.
  1020. Revision History:
  1021. Date Description Programmer
  1022. -------- --------------------------------------------------- ----------
  1023. 09/21/96 Initial creation. BrianAu
  1024. */
  1025. ///////////////////////////////////////////////////////////////////////////////
  1026. VOID
  1027. SidNameCache::InvalidateFiles(
  1028. VOID
  1029. )
  1030. {
  1031. DBGASSERT((DATA_FILE_MAPPED));
  1032. DBGASSERT((INDEX_FILE_MAPPED));
  1033. m_pRecordMgr->SetFileGUID(&GUID_Null);
  1034. m_pIndexMgr->SetFileGUID(&GUID_Null);
  1035. }
  1036. ///////////////////////////////////////////////////////////////////////////////
  1037. /* Function: SidNameCache::Lookup
  1038. Description: Given a user SID, this method locates the corresponding
  1039. data record in the cache and returns the requested information.
  1040. (i.e. container, name, full name). Several conditions will cause
  1041. the lookup to fail.
  1042. 1. SID not found in cache.
  1043. 2. Can't get exclusive lock on cache.
  1044. 3. Index or data file (or both) are invalid.
  1045. 4. Record found but expired.
  1046. Arguments:
  1047. pKeySid - Address of SID to use as lookup key.
  1048. ppszContainer [optional] - Address of pointer variable to receive the
  1049. address of buffer containing the "container" name string. Caller is
  1050. responsible for freeing the buffer with delete[].
  1051. May be NULL if the container is not desired.
  1052. ppszLogonName [optional] - Address of pointer variable to receive the
  1053. address of buffer containing logon name string. Caller is
  1054. responsible for freeing the buffer with delete[].
  1055. May be NULL if logon name is not desired.
  1056. ppszDisplayName [optional] - Address of pointer variable to receive the
  1057. address of buffer containing account display string. Caller is
  1058. responsible for freeing the buffer with delete[].
  1059. May be NULL if display name is not desired.
  1060. Returns:
  1061. NO_ERROR - Success.
  1062. ERROR_FILE_NOT_FOUND (hr) - Sid not found in cache.
  1063. ERROR_LOCK_FAILED (hr) - Couldn't get exclusive lock on cache.
  1064. ERROR_INVALID_DATA (hr) - Index or data file is invalid.
  1065. Exceptions: OutOfMemory
  1066. Revision History:
  1067. Date Description Programmer
  1068. -------- --------------------------------------------------- ----------
  1069. 09/21/96 Initial creation. BrianAu
  1070. */
  1071. ///////////////////////////////////////////////////////////////////////////////
  1072. HRESULT
  1073. SidNameCache::Lookup(
  1074. PSID pKeySid,
  1075. LPTSTR *ppszContainer,
  1076. LPTSTR *ppszLogonName,
  1077. LPTSTR *ppszDisplayName
  1078. )
  1079. {
  1080. DBGTRACE((DM_SIDCACHE, DL_MID, TEXT("SidNameCache::Lookup [SID]")));
  1081. DBGASSERT((NULL != pKeySid));
  1082. HRESULT hResult = BeginTransaction();
  1083. if (SUCCEEDED(hResult))
  1084. {
  1085. try
  1086. {
  1087. DWORD iBlock = m_pIndexMgr->Lookup(pKeySid);
  1088. if ((DWORD)-1 != iBlock)
  1089. {
  1090. if (!m_pRecordMgr->RecordExpired(iBlock))
  1091. {
  1092. PSID pSid = NULL;
  1093. //
  1094. // This can throw OutOfMemory.
  1095. //
  1096. hResult = m_pRecordMgr->Retrieve(iBlock,
  1097. &pSid,
  1098. ppszContainer,
  1099. ppszLogonName,
  1100. ppszDisplayName);
  1101. if (SUCCEEDED(hResult))
  1102. DBGASSERT((EqualSid(pSid, pKeySid)));
  1103. if (NULL != pSid)
  1104. delete[] pSid;
  1105. }
  1106. else
  1107. {
  1108. //
  1109. // Record is outdated. Delete it from the cache.
  1110. // Returning "not found" will cause the caller to get
  1111. // a fresh one from the domain controller - which will
  1112. // then again be added to the cache.
  1113. //
  1114. DBGPRINT((DM_SIDCACHE, DL_HIGH,
  1115. TEXT("SIDCACHE - Record at block %d has expired."),
  1116. iBlock));
  1117. m_pIndexMgr->FreeEntry(pKeySid);
  1118. m_pRecordMgr->FreeRecord(iBlock);
  1119. hResult = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1120. }
  1121. }
  1122. else
  1123. {
  1124. hResult = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); // SID not in cache.
  1125. }
  1126. }
  1127. catch(CAllocException &e)
  1128. {
  1129. hResult = E_OUTOFMEMORY;
  1130. }
  1131. EndTransaction();
  1132. }
  1133. return hResult;
  1134. }
  1135. ///////////////////////////////////////////////////////////////////////////////
  1136. /* Function: SidNameCache::Lookup
  1137. Description: Given a user's logon name name, this method locates
  1138. the corresponding SID in the cache. All comments in the previous
  1139. (above) version of this method apply.
  1140. Arguments:
  1141. pszLogonName - Address of account logon name string.
  1142. ppSid - Address of pointer variable to receive the address of buffer
  1143. containing the SID. Caller is responsible for freeing the buffer
  1144. with delete[].
  1145. Returns:
  1146. See list in previous method.
  1147. Exception: OutOfMemory.
  1148. Revision History:
  1149. Date Description Programmer
  1150. -------- --------------------------------------------------- ----------
  1151. 09/21/96 Initial creation. BrianAu
  1152. 03/18/98 Replaced domain\name key arguments with single BrianAu
  1153. logon name key.
  1154. */
  1155. ///////////////////////////////////////////////////////////////////////////////
  1156. HRESULT
  1157. SidNameCache::Lookup(
  1158. LPCTSTR pszLogonName,
  1159. PSID *ppSid
  1160. )
  1161. {
  1162. DBGTRACE((DM_SIDCACHE, DL_MID, TEXT("SidNameCache::Lookup [name]")));
  1163. DBGASSERT((NULL != pszLogonName));
  1164. DBGASSERT((NULL != ppSid));
  1165. HRESULT hResult = BeginTransaction();
  1166. if (SUCCEEDED(hResult))
  1167. {
  1168. try
  1169. {
  1170. //
  1171. // Can throw OutOfMemory.
  1172. //
  1173. DWORD iBlock = m_pIndexMgr->Lookup(pszLogonName);
  1174. if ((DWORD)-1 != iBlock)
  1175. {
  1176. //
  1177. // Can throw OutOfMemory.
  1178. //
  1179. hResult = m_pRecordMgr->Retrieve(iBlock,
  1180. ppSid,
  1181. NULL,
  1182. NULL,
  1183. NULL);
  1184. if (m_pRecordMgr->RecordExpired(iBlock))
  1185. {
  1186. //
  1187. // Record is outdated. Delete it from the cache.
  1188. // Returning "not found" will cause the caller to get
  1189. // a fresh one from the domain controller - which will
  1190. // then again be added to the cache.
  1191. //
  1192. DBGASSERT((NULL != *ppSid));
  1193. m_pIndexMgr->FreeEntry(*ppSid);
  1194. m_pRecordMgr->FreeRecord(iBlock);
  1195. delete[] *ppSid;
  1196. *ppSid = NULL;
  1197. hResult = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1198. }
  1199. }
  1200. else
  1201. {
  1202. hResult = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); // SID not in cache.
  1203. }
  1204. }
  1205. catch(CAllocException& e)
  1206. {
  1207. hResult = E_OUTOFMEMORY;
  1208. }
  1209. EndTransaction();
  1210. }
  1211. return hResult;
  1212. }
  1213. ///////////////////////////////////////////////////////////////////////////////
  1214. /* Function: SidNameCache::Add
  1215. Description: Add user's information to the cache. Information consists
  1216. of the SID (key), container name, account logon name and
  1217. account display name.
  1218. Arguments:
  1219. pSid - Address of user's SID.
  1220. pszContainer - Address of account container name string.
  1221. i.e. "REDMOND" or "ntdev.microsoft.com\US-SOS ....."
  1222. pszLogonName - Address of account logon name string.
  1223. i.e. "REDMOND\brianau" or "[email protected]"
  1224. pszDisplayName - Address of display name string.
  1225. i.e. "Brian Aust"
  1226. Returns:
  1227. NO_ERROR - Success.
  1228. S_FALSE - Already exists in cache. Not added.
  1229. ERROR_LOCK_FAILED (hr) - Couldn't get exclusive lock on cache.
  1230. ERROR_INVALID_DATA (hr) - Index or data file is invalid.
  1231. Exceptions: OutOfMemory.
  1232. Revision History:
  1233. Date Description Programmer
  1234. -------- --------------------------------------------------- ----------
  1235. 09/21/96 Initial creation. BrianAu
  1236. */
  1237. ///////////////////////////////////////////////////////////////////////////////
  1238. HRESULT
  1239. SidNameCache::Add(
  1240. PSID pSid,
  1241. LPCTSTR pszContainer,
  1242. LPCTSTR pszLogonName,
  1243. LPCTSTR pszDisplayName
  1244. )
  1245. {
  1246. DBGTRACE((DM_SIDCACHE, DL_MID, TEXT("SidNameCache::Add")));
  1247. DBGASSERT((NULL != pSid));
  1248. DBGASSERT((NULL != pszContainer));
  1249. DBGASSERT((NULL != pszLogonName));
  1250. DBGASSERT((NULL != pszDisplayName));
  1251. HRESULT hResult = BeginTransaction();
  1252. if (SUCCEEDED(hResult))
  1253. {
  1254. try
  1255. {
  1256. //
  1257. // Can throw OutOfMemory.
  1258. //
  1259. if ((DWORD)-1 == m_pIndexMgr->Lookup(pSid))
  1260. {
  1261. DWORD iBlock = m_pRecordMgr->Store(pSid,
  1262. pszContainer,
  1263. pszLogonName,
  1264. pszDisplayName);
  1265. if ((DWORD)-1 != iBlock)
  1266. {
  1267. m_pIndexMgr->Add(pSid, iBlock);
  1268. hResult = NO_ERROR;
  1269. }
  1270. }
  1271. else
  1272. {
  1273. hResult = S_FALSE; // Already exists. Not a failure.
  1274. }
  1275. }
  1276. catch(CAllocException& e)
  1277. {
  1278. hResult = E_OUTOFMEMORY;
  1279. }
  1280. EndTransaction();
  1281. }
  1282. return hResult;
  1283. }
  1284. //***********************************************************************************
  1285. //***********************************************************************************
  1286. // I N D E X F I L E M A N A G E R
  1287. //***********************************************************************************
  1288. //***********************************************************************************
  1289. ///////////////////////////////////////////////////////////////////////////////
  1290. /* Function: SidNameCache::IndexMgr::IndexMgr
  1291. Description: Index manager constructor.
  1292. Arguments:
  1293. refCache - Reference to containing cache object. Used to call
  1294. record manager and cache manager public methods.
  1295. Returns: Nothing.
  1296. Revision History:
  1297. Date Description Programmer
  1298. -------- --------------------------------------------------- ----------
  1299. 09/21/96 Initial creation. BrianAu
  1300. */
  1301. ///////////////////////////////////////////////////////////////////////////////
  1302. SidNameCache::IndexMgr::IndexMgr(
  1303. SidNameCache& refCache
  1304. ) : m_refCache(refCache),
  1305. m_pFileHdr(NULL),
  1306. m_hFile(NULL),
  1307. m_hFileMapping(NULL)
  1308. {
  1309. DBGTRACE((DM_SIDCACHE, DL_MID, TEXT("SidNameCache::SidNameCache::IndexMgr")));
  1310. //
  1311. // Nothing to do.
  1312. //
  1313. }
  1314. ///////////////////////////////////////////////////////////////////////////////
  1315. /* Function: SidNameCache::IndexMgr::~IndexMgr
  1316. Description: Index manager destructor.
  1317. Arguments: None.
  1318. Returns: Nothing.
  1319. Revision History:
  1320. Date Description Programmer
  1321. -------- --------------------------------------------------- ----------
  1322. 09/21/96 Initial creation. BrianAu
  1323. */
  1324. ///////////////////////////////////////////////////////////////////////////////
  1325. SidNameCache::IndexMgr::~IndexMgr(
  1326. VOID
  1327. )
  1328. {
  1329. DBGTRACE((DM_SIDCACHE, DL_MID, TEXT("SidNameCache::SidNameCache::~IndexMgr")));
  1330. CloseIndexFile();
  1331. }
  1332. ///////////////////////////////////////////////////////////////////////////////
  1333. /* Function: SidNameCache::IndexMgr::Initialize
  1334. Description: Initializes a new index manager object. If both cBuckets
  1335. and cMaxEntries are 0 (default), existing cache files are opened.
  1336. Otherwise, new cache files are created.
  1337. Arguments:
  1338. pszFile - Address of full path for new file.
  1339. cBuckets - Number of hash table buckets in index file. Should be
  1340. prime.
  1341. cMaxEntries - Initial max number of entries for the index. Note
  1342. that the index file grows automatically as required.
  1343. Returns: Address of mapped file or NULL on failure.
  1344. Revision History:
  1345. Date Description Programmer
  1346. -------- --------------------------------------------------- ----------
  1347. 09/21/96 Initial creation. BrianAu
  1348. */
  1349. ///////////////////////////////////////////////////////////////////////////////
  1350. LPBYTE
  1351. SidNameCache::IndexMgr::Initialize(
  1352. LPCTSTR pszFile,
  1353. DWORD cBuckets,
  1354. DWORD cMaxEntries
  1355. )
  1356. {
  1357. DBGTRACE((DM_SIDCACHE, DL_HIGH, TEXT("SidNameCache::IndexMgr::Initialize")));
  1358. DBGASSERT((NULL != pszFile));
  1359. //
  1360. // Store the file name in our CString object.
  1361. //
  1362. m_strFileName = pszFile;
  1363. if (0 == cBuckets && 0 == cMaxEntries)
  1364. {
  1365. //
  1366. // Initialize manager using existing cache files.
  1367. //
  1368. m_pFileHdr = (PINDEX_FILE_HDR)OpenIndexFile(pszFile);
  1369. if (NULL != m_pFileHdr)
  1370. {
  1371. if (FILE_VERSION != m_pFileHdr->dwVersion ||
  1372. INDEX_FILE_SIGNATURE != m_pFileHdr->dwSignature)
  1373. {
  1374. //
  1375. // This version of the software doesn't understand this
  1376. // version of the file or file has an invalid signature.
  1377. // Don't take any chances. We'll just create a new one.
  1378. //
  1379. DBGERROR((TEXT("SIDCACHE - Index file is invalid or incorrect version. A new index file will be created.")));
  1380. CloseIndexFile();
  1381. m_pFileHdr = NULL;
  1382. }
  1383. }
  1384. }
  1385. else
  1386. {
  1387. //
  1388. // Initialize manager by creating new cache files.
  1389. //
  1390. ULARGE_INTEGER uliFileSize;
  1391. uliFileSize.QuadPart = FileSize(cMaxEntries, cBuckets);
  1392. m_pFileHdr = (PINDEX_FILE_HDR)CreateIndexFile(pszFile,
  1393. uliFileSize.HighPart,
  1394. uliFileSize.LowPart);
  1395. if (NULL != m_pFileHdr)
  1396. {
  1397. InitNewIndexFile(cBuckets, cMaxEntries);
  1398. }
  1399. }
  1400. return (LPBYTE)m_pFileHdr;
  1401. }
  1402. ///////////////////////////////////////////////////////////////////////////////
  1403. /* Function: SidNameCache::IndexMgr::CreateIndexFile
  1404. Description: Creates and initializes a new index file.
  1405. Arguments:
  1406. pszFile - Address of full path for new file.
  1407. cbFileHigh/Low - Size of file in bytes.
  1408. Returns: Address of mapped file or NULL on failure.
  1409. Revision History:
  1410. Date Description Programmer
  1411. -------- --------------------------------------------------- ----------
  1412. 09/21/96 Initial creation. BrianAu
  1413. */
  1414. ///////////////////////////////////////////////////////////////////////////////
  1415. LPBYTE
  1416. SidNameCache::IndexMgr::CreateIndexFile(
  1417. LPCTSTR pszFile,
  1418. DWORD cbFileHigh,
  1419. DWORD cbFileLow
  1420. )
  1421. {
  1422. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::IndexMgr::CreateIndexFile")));
  1423. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT("\tFile: \"%s\""), pszFile ? pszFile : TEXT("<null>")));
  1424. DBGASSERT((NULL != pszFile));
  1425. CloseIndexFile(); // Make sure any existing index file is closed.
  1426. g_pbMappedIndexFile = SidNameCache::OpenMappedFile(
  1427. pszFile,
  1428. g_pszIndexFileMapping,
  1429. CREATE_ALWAYS,
  1430. cbFileHigh,
  1431. cbFileLow,
  1432. &m_hFile,
  1433. &m_hFileMapping);
  1434. return g_pbMappedIndexFile;
  1435. }
  1436. ///////////////////////////////////////////////////////////////////////////////
  1437. /* Function: SidNameCache::IndexMgr::OpenIndexFile
  1438. Description: Opens an existing index file.
  1439. Arguments:
  1440. pszFile - Address of full path for new file.
  1441. Returns: Address of mapped file or NULL on failure.
  1442. Revision History:
  1443. Date Description Programmer
  1444. -------- --------------------------------------------------- ----------
  1445. 09/21/96 Initial creation. BrianAu
  1446. */
  1447. ///////////////////////////////////////////////////////////////////////////////
  1448. LPBYTE
  1449. SidNameCache::IndexMgr::OpenIndexFile(
  1450. LPCTSTR pszFile
  1451. )
  1452. {
  1453. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::IndexMgr::OpenIndexFile")));
  1454. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT("\tFile: \"%s\""), pszFile ? pszFile : TEXT("<null>")));
  1455. DBGASSERT((NULL != pszFile));
  1456. CloseIndexFile(); // Make sure any existing index file is closed.
  1457. g_pbMappedIndexFile = SidNameCache::OpenMappedFile(
  1458. pszFile,
  1459. g_pszIndexFileMapping,
  1460. OPEN_EXISTING,
  1461. 0,
  1462. 0,
  1463. &m_hFile,
  1464. &m_hFileMapping);
  1465. return g_pbMappedIndexFile;
  1466. }
  1467. ///////////////////////////////////////////////////////////////////////////////
  1468. /* Function: SidNameCache::IndexMgr::CloseIndexFile
  1469. Description: Closes the current index mapping and file.
  1470. Arguments: None.
  1471. Returns: Nothing.
  1472. Revision History:
  1473. Date Description Programmer
  1474. -------- --------------------------------------------------- ----------
  1475. 09/21/96 Initial creation. BrianAu
  1476. */
  1477. ///////////////////////////////////////////////////////////////////////////////
  1478. VOID
  1479. SidNameCache::IndexMgr::CloseIndexFile(
  1480. VOID
  1481. )
  1482. {
  1483. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::IndexMgr::CloseIndexFile")));
  1484. if (NULL != g_pbMappedIndexFile)
  1485. {
  1486. UnmapViewOfFile(g_pbMappedIndexFile);
  1487. g_pbMappedIndexFile = NULL;
  1488. m_pFileHdr = NULL;
  1489. }
  1490. if (NULL != m_hFileMapping)
  1491. {
  1492. CloseHandle(m_hFileMapping);
  1493. m_hFileMapping = NULL;
  1494. }
  1495. if (NULL != m_hFile && INVALID_HANDLE_VALUE != m_hFile)
  1496. {
  1497. CloseHandle(m_hFile);
  1498. m_hFile = NULL;
  1499. }
  1500. }
  1501. ///////////////////////////////////////////////////////////////////////////////
  1502. /* Function: SidNameCache::IndexMgr::GrowIndexFile
  1503. Description: Increases the size of the current index file.
  1504. Arguments:
  1505. cGrowEntries - Make room for this many more entries. Note that the
  1506. size of the hash table is fixed. If we were to allow this to
  1507. change, it would invalidate any existing hash values in the
  1508. table (hash code is a function of the SID and table size).
  1509. Returns: Address of mapped file or NULL on failure.
  1510. Revision History:
  1511. Date Description Programmer
  1512. -------- --------------------------------------------------- ----------
  1513. 09/21/96 Initial creation. BrianAu
  1514. */
  1515. ///////////////////////////////////////////////////////////////////////////////
  1516. LPBYTE
  1517. SidNameCache::IndexMgr::GrowIndexFile(
  1518. DWORD cGrowEntries
  1519. )
  1520. {
  1521. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::IndexMgr::GrowIndexFile")));
  1522. DBGASSERT((INDEX_FILE_MAPPED));
  1523. DWORD cOldMaxEntries = m_pFileHdr->cMaxEntries;
  1524. DWORD cNewMaxEntries = cOldMaxEntries + cGrowEntries;
  1525. DBGPRINT((DM_SIDCACHE, DL_MID,
  1526. TEXT("Growing SID cache index %d -> %d entries."),
  1527. cOldMaxEntries, cNewMaxEntries));
  1528. //
  1529. // Open the existing file and map with a new larger size.
  1530. // Must calc new size BEFORE closing current index file so that m_pFileHdr
  1531. // is still valid.
  1532. //
  1533. ULARGE_INTEGER uliFileSize;
  1534. uliFileSize.QuadPart = FileSize(cNewMaxEntries, m_pFileHdr->cBuckets);
  1535. CloseIndexFile();
  1536. g_pbMappedIndexFile = SidNameCache::OpenMappedFile(
  1537. m_strFileName,
  1538. g_pszIndexFileMapping,
  1539. OPEN_EXISTING,
  1540. uliFileSize.HighPart,
  1541. uliFileSize.LowPart,
  1542. &m_hFile,
  1543. &m_hFileMapping);
  1544. m_pFileHdr = (PINDEX_FILE_HDR)g_pbMappedIndexFile;
  1545. if (NULL != g_pbMappedIndexFile)
  1546. {
  1547. m_pFileHdr->cMaxEntries = cNewMaxEntries;
  1548. //
  1549. // Growing the index only expands the number of index
  1550. // pool entries. The index hash table is left alone.
  1551. // Good reason to make it large to start with. If we changed
  1552. // the hash table size, existing hash codes would be
  1553. // invalid.
  1554. //
  1555. PINDEX_ENTRY pEntry = m_pFileHdr->pEntries + cOldMaxEntries;
  1556. for (UINT i = 0; i < cGrowEntries; i++)
  1557. {
  1558. AddEntryToFreeList(pEntry++);
  1559. }
  1560. DBGPRINT((DM_SIDCACHE, DL_HIGH, TEXT("SIDCACHE - Index growth complete.")));
  1561. }
  1562. return g_pbMappedIndexFile;
  1563. }
  1564. ///////////////////////////////////////////////////////////////////////////////
  1565. /* Function: SidNameCache::IndexMgr::InitNewIndexFile
  1566. Description: Initializes a new index file filling in the header information
  1567. and clearing the index entries.
  1568. Arguments:
  1569. cBuckets - Number of hash table buckets in index file. Should be
  1570. prime.
  1571. cMaxEntries - Initial max number of entries for the index. Note
  1572. that the index file grows automatically as required.
  1573. Returns: Nothing.
  1574. Revision History:
  1575. Date Description Programmer
  1576. -------- --------------------------------------------------- ----------
  1577. 09/21/96 Initial creation. BrianAu
  1578. */
  1579. ///////////////////////////////////////////////////////////////////////////////
  1580. VOID
  1581. SidNameCache::IndexMgr::InitNewIndexFile(
  1582. DWORD cBuckets,
  1583. DWORD cMaxEntries
  1584. )
  1585. {
  1586. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::IndexMgr::InitNewIndexFile")));
  1587. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT("\tcBuckets = %d, cMaxEntries = %d"),
  1588. cBuckets, cMaxEntries));
  1589. DBGASSERT((INDEX_FILE_MAPPED));
  1590. m_pFileHdr->dwSignature = INDEX_FILE_SIGNATURE;
  1591. m_pFileHdr->dwVersion = FILE_VERSION;
  1592. m_pFileHdr->cBuckets = cBuckets;
  1593. m_pFileHdr->cMaxEntries = cMaxEntries;
  1594. m_pFileHdr->pBuckets = (PINDEX_ENTRY *)(sizeof(INDEX_FILE_HDR));
  1595. m_pFileHdr->pEntries = (PINDEX_ENTRY)(m_pFileHdr->pBuckets + cBuckets);
  1596. //
  1597. // Initialize the hash table and return all entries to the free list.
  1598. //
  1599. Clear();
  1600. }
  1601. ///////////////////////////////////////////////////////////////////////////////
  1602. /* Function: SidNameCache::IndexMgr::Clear
  1603. Description: Fills the hash table with NULL pointers and returns all
  1604. entry nodes to the free list.
  1605. Arguments: None.
  1606. Returns: Nothing.
  1607. Revision History:
  1608. Date Description Programmer
  1609. -------- --------------------------------------------------- ----------
  1610. 09/21/96 Initial creation. BrianAu
  1611. */
  1612. ///////////////////////////////////////////////////////////////////////////////
  1613. VOID
  1614. SidNameCache::IndexMgr::Clear(
  1615. VOID
  1616. )
  1617. {
  1618. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::IndexMgr::Clear")));
  1619. DBGASSERT((INDEX_FILE_MAPPED));
  1620. m_pFileHdr->cEntries = 0;
  1621. SetFileGUID(&GUID_Null);
  1622. //
  1623. // Initialize all hash buckets to NULL.
  1624. //
  1625. DBGASSERT((0 < m_pFileHdr->cBuckets));
  1626. ZeroMemory(NDX_BASED_CAST(BYTE, m_pFileHdr->pBuckets),
  1627. m_pFileHdr->cBuckets * sizeof(PINDEX_ENTRY *));
  1628. //
  1629. // Return all index entry nodes to the free list.
  1630. //
  1631. PINDEX_ENTRY pEntry = m_pFileHdr->pEntries;
  1632. DBGASSERT((0 < m_pFileHdr->cMaxEntries));
  1633. for (UINT i = 0; i < m_pFileHdr->cMaxEntries; i++)
  1634. {
  1635. //
  1636. // We're iterating through all entries. No need to detach first.
  1637. //
  1638. AddEntryToFreeList(pEntry++);
  1639. }
  1640. }
  1641. ///////////////////////////////////////////////////////////////////////////////
  1642. /* Function: SidNameCache::IndexMgr::SetFileGUID
  1643. Function: SidNameCache::IndexMgr::GetFileGUID
  1644. Description: These functions manipulate the guid field in the index file's
  1645. header.
  1646. The GUID is used to ensure integrity between
  1647. the data and index files. Before any change to either file, the
  1648. GUID's are both set to 0. When the change operation is complete,
  1649. a new GUID is generated and written to both files. Therefore, before
  1650. any transaction, we can validate the data and index files by reading
  1651. and comparing GUIDs. If the GUIDs are not 0 and are equal, the
  1652. file can be assumed to be valid.
  1653. Arguments:
  1654. pguid - Address of source or destination GUID.
  1655. Returns: Nothing.
  1656. Revision History:
  1657. Date Description Programmer
  1658. -------- --------------------------------------------------- ----------
  1659. 09/21/96 Initial creation. BrianAu
  1660. */
  1661. ///////////////////////////////////////////////////////////////////////////////
  1662. VOID
  1663. SidNameCache::IndexMgr::SetFileGUID(
  1664. const GUID *pguid
  1665. )
  1666. {
  1667. DBGASSERT((INDEX_FILE_MAPPED));
  1668. DBGASSERT((NULL != pguid));
  1669. CopyMemory(&m_pFileHdr->guid, pguid, sizeof(GUID));
  1670. }
  1671. VOID
  1672. SidNameCache::IndexMgr::GetFileGUID(
  1673. LPGUID pguid
  1674. )
  1675. {
  1676. DBGASSERT((INDEX_FILE_MAPPED));
  1677. DBGASSERT((NULL != pguid));
  1678. CopyMemory(pguid, &m_pFileHdr->guid, sizeof(GUID));
  1679. }
  1680. ///////////////////////////////////////////////////////////////////////////////
  1681. /* Function: SidNameCache::IndexMgr::AllocEntry
  1682. Description: Allocates an entry from the free list.
  1683. Arguments: None.
  1684. Returns:
  1685. Address of new entry node or NULL if free list is empty.
  1686. Revision History:
  1687. Date Description Programmer
  1688. -------- --------------------------------------------------- ----------
  1689. 09/21/96 Initial creation. BrianAu
  1690. */
  1691. ///////////////////////////////////////////////////////////////////////////////
  1692. PINDEX_ENTRY
  1693. SidNameCache::IndexMgr::AllocEntry(
  1694. VOID
  1695. )
  1696. {
  1697. DBGASSERT((INDEX_FILE_MAPPED));
  1698. PINDEX_ENTRY pEntry = m_pFileHdr->pFirstFree;
  1699. if (NULL != pEntry)
  1700. {
  1701. NDX_BASED(INDEX_ENTRY) *pBasedEntry = NDX_BASED_CAST(INDEX_ENTRY, pEntry);
  1702. //
  1703. // Unlink the entry from the free list.
  1704. //
  1705. m_pFileHdr->pFirstFree = pBasedEntry->pNext;
  1706. //
  1707. // Clear it's "prev" and "next" pointers.
  1708. //
  1709. pBasedEntry->pNext = pBasedEntry->pPrev = NULL;
  1710. if (NULL != m_pFileHdr->pFirstFree)
  1711. {
  1712. //
  1713. // If there is at least one entry in the free list, set the "prev"
  1714. // pointer of the new "first" entry to NULL.
  1715. //
  1716. pBasedEntry = NDX_BASED_CAST(INDEX_ENTRY, m_pFileHdr->pFirstFree);
  1717. pBasedEntry->pPrev = NULL;
  1718. }
  1719. m_pFileHdr->cEntries++;
  1720. }
  1721. return pEntry;
  1722. }
  1723. ///////////////////////////////////////////////////////////////////////////////
  1724. /* Function: SidNameCache::IndexMgr::FreeEntry
  1725. Description: Removes an entry from it's current list and returns it to the
  1726. free list. Two versions are provided. One accepts a SID as an entry
  1727. identifier, the other accepts the address of the index entry.
  1728. Arguments:
  1729. pSid - Address of SID associated with entry to be free'd.
  1730. pEntry - Address of index entry to be free'd
  1731. Returns: Nothing.
  1732. Revision History:
  1733. Date Description Programmer
  1734. -------- --------------------------------------------------- ----------
  1735. 09/21/96 Initial creation. BrianAu
  1736. */
  1737. ///////////////////////////////////////////////////////////////////////////////
  1738. VOID
  1739. SidNameCache::IndexMgr::FreeEntry(
  1740. PSID pSid
  1741. )
  1742. {
  1743. DBGASSERT((NULL != pSid));
  1744. PINDEX_ENTRY pEntry = Find(pSid);
  1745. if (NULL != pEntry)
  1746. {
  1747. FreeEntry(pEntry);
  1748. }
  1749. }
  1750. VOID
  1751. SidNameCache::IndexMgr::FreeEntry(
  1752. PINDEX_ENTRY pEntry
  1753. )
  1754. {
  1755. DBGASSERT((NULL != pEntry));
  1756. DetachEntry(pEntry);
  1757. AddEntryToFreeList(pEntry);
  1758. m_pFileHdr->cEntries--;
  1759. }
  1760. ///////////////////////////////////////////////////////////////////////////////
  1761. /* Function: SidNameCache::IndexMgr::AddEntryToFreeList
  1762. Description: Returns a detached index entry to the free list.
  1763. Arguments:
  1764. pEntry - Address of index entry to be added to free list.
  1765. Returns: Nothing.
  1766. Revision History:
  1767. Date Description Programmer
  1768. -------- --------------------------------------------------- ----------
  1769. 09/21/96 Initial creation. BrianAu
  1770. */
  1771. ///////////////////////////////////////////////////////////////////////////////
  1772. VOID
  1773. SidNameCache::IndexMgr::AddEntryToFreeList(
  1774. PINDEX_ENTRY pEntry
  1775. )
  1776. {
  1777. DBGASSERT((INDEX_FILE_MAPPED));
  1778. DBGASSERT((NULL != pEntry));
  1779. NDX_BASED(INDEX_ENTRY) *pBased = NDX_BASED_CAST(INDEX_ENTRY, pEntry);
  1780. //
  1781. // Insert the node at the head of the free list.
  1782. // Note that double-linking isn't necessary in the free list
  1783. // (we always add and remove free list entries at the head)
  1784. // therefore we don't need to set the next node's "prev" pointer.
  1785. //
  1786. pBased->iBucket = (DWORD)-1;
  1787. pBased->iBlock = (DWORD)-1;
  1788. pBased->pPrev = NULL;
  1789. pBased->pNext = m_pFileHdr->pFirstFree;
  1790. m_pFileHdr->pFirstFree = pEntry;
  1791. }
  1792. ///////////////////////////////////////////////////////////////////////////////
  1793. /* Function: SidNameCache::IndexMgr::DetachEntry
  1794. Description: Detaches an index entry from its current list.
  1795. Note that this function assumes that the node exists in a valid
  1796. linked list of nodes. Do not call this function on an uninitialized
  1797. index entry.
  1798. Arguments:
  1799. pEntry - Address of index entry to be detached.
  1800. Returns: Nothing.
  1801. Revision History:
  1802. Date Description Programmer
  1803. -------- --------------------------------------------------- ----------
  1804. 09/21/96 Initial creation. BrianAu
  1805. */
  1806. ///////////////////////////////////////////////////////////////////////////////
  1807. PINDEX_ENTRY
  1808. SidNameCache::IndexMgr::DetachEntry(
  1809. PINDEX_ENTRY pEntry
  1810. )
  1811. {
  1812. DBGASSERT((INDEX_FILE_MAPPED));
  1813. DBGASSERT((NULL != pEntry));
  1814. NDX_BASED(INDEX_ENTRY) *pBased = NDX_BASED_CAST(INDEX_ENTRY, pEntry);
  1815. NDX_BASED(INDEX_ENTRY) *pBasedNext;
  1816. NDX_BASED(INDEX_ENTRY) *pBasedPrev;
  1817. //
  1818. // Unlink the entry from it's list.
  1819. //
  1820. if (NULL != pBased->pPrev)
  1821. {
  1822. pBasedPrev = NDX_BASED_CAST(INDEX_ENTRY, pBased->pPrev);
  1823. pBasedPrev->pNext = pBased->pNext;
  1824. }
  1825. if (NULL != pBased->pNext)
  1826. {
  1827. pBasedNext = NDX_BASED_CAST(INDEX_ENTRY, pBased->pNext);
  1828. pBasedNext->pPrev = pBased->pPrev;
  1829. }
  1830. //
  1831. // If we're detaching the entry that's attached to the hash array element,
  1832. // adjust the element's value.
  1833. //
  1834. if (GetHashBucketValue(pBased->iBucket) == pEntry)
  1835. SetHashBucketValue(pBased->iBucket, pBased->pNext);
  1836. pBased->pNext = pBased->pPrev = NULL;
  1837. return pEntry;
  1838. }
  1839. ///////////////////////////////////////////////////////////////////////////////
  1840. /* Function: SidNameCache::IndexMgr::GetHashBucketValue
  1841. Description: Returns the address of the first index entry in a hash bucket.
  1842. Arguments:
  1843. iBucket - Array index of bucket in hash table array.
  1844. Returns:
  1845. Address of first entry in bucket's entry list.
  1846. Revision History:
  1847. Date Description Programmer
  1848. -------- --------------------------------------------------- ----------
  1849. 09/21/96 Initial creation. BrianAu
  1850. */
  1851. ///////////////////////////////////////////////////////////////////////////////
  1852. PINDEX_ENTRY
  1853. SidNameCache::IndexMgr::GetHashBucketValue(
  1854. DWORD iBucket
  1855. )
  1856. {
  1857. DBGASSERT((INDEX_FILE_MAPPED));
  1858. DBGASSERT((iBucket < m_pFileHdr->cBuckets));
  1859. NDX_BASED(PINDEX_ENTRY) *pBased = NDX_BASED_CAST(PINDEX_ENTRY, m_pFileHdr->pBuckets + iBucket);
  1860. return *pBased;
  1861. }
  1862. ///////////////////////////////////////////////////////////////////////////////
  1863. /* Function: SidNameCache::IndexMgr::SetHashBucketValue
  1864. Description: Sets the address of the first index entry in a hash bucket.
  1865. OK to set it as NULL.
  1866. Arguments:
  1867. iBucket - Array index of bucket in hash table array.
  1868. pEntry - Address of entry node.
  1869. Returns:
  1870. Address of first entry in bucket's entry list.
  1871. Revision History:
  1872. Date Description Programmer
  1873. -------- --------------------------------------------------- ----------
  1874. 09/21/96 Initial creation. BrianAu
  1875. */
  1876. ///////////////////////////////////////////////////////////////////////////////
  1877. VOID
  1878. SidNameCache::IndexMgr::SetHashBucketValue(
  1879. DWORD iBucket,
  1880. PINDEX_ENTRY pEntry
  1881. )
  1882. {
  1883. DBGASSERT((INDEX_FILE_MAPPED));
  1884. DBGASSERT((iBucket < m_pFileHdr->cBuckets));
  1885. //
  1886. // pEntry == NULL is OK.
  1887. //
  1888. NDX_BASED(PINDEX_ENTRY) *pBased = NDX_BASED_CAST(PINDEX_ENTRY,
  1889. m_pFileHdr->pBuckets + iBucket);
  1890. *pBased = pEntry;
  1891. }
  1892. ///////////////////////////////////////////////////////////////////////////////
  1893. /* Function: SidNameCache::IndexMgr::Find (3 overloaded methods)
  1894. Description: Given either a SID, a SID and hash value, or a user logon name,
  1895. this method returns the address of the index entry
  1896. representing that cache entry.
  1897. Arguments:
  1898. pKeySid - Address of SID to use as a lookup key.
  1899. dwHashCode - Result of calling Hash(pKeySid).
  1900. pszKeyLogonName - Address of account logon name string.
  1901. Returns:
  1902. Address of index entry representing the user.
  1903. NULL if not found.
  1904. Exceptions: OutOfMemory.
  1905. Revision History:
  1906. Date Description Programmer
  1907. -------- --------------------------------------------------- ----------
  1908. 09/21/96 Initial creation. BrianAu
  1909. */
  1910. ///////////////////////////////////////////////////////////////////////////////
  1911. PINDEX_ENTRY
  1912. SidNameCache::IndexMgr::Find(
  1913. PSID pKeySid
  1914. )
  1915. {
  1916. DBGASSERT((INDEX_FILE_MAPPED));
  1917. DBGASSERT((NULL != pKeySid));
  1918. return Find(pKeySid, Hash(pKeySid)); // Can throw OutOfMemory.
  1919. }
  1920. PINDEX_ENTRY
  1921. SidNameCache::IndexMgr::Find(
  1922. PSID pKeySid,
  1923. DWORD dwHashCode
  1924. )
  1925. {
  1926. DBGASSERT((INDEX_FILE_MAPPED));
  1927. DBGASSERT((NULL != pKeySid));
  1928. BOOL bFound = FALSE;
  1929. PINDEX_ENTRY pEntry = GetHashBucketValue(dwHashCode);
  1930. while(NULL != pEntry && !bFound)
  1931. {
  1932. PSID pSid = NULL;
  1933. NDX_BASED(INDEX_ENTRY) *pBased = NDX_BASED_CAST(INDEX_ENTRY, pEntry);
  1934. //
  1935. // This can throw OutOfMemory.
  1936. //
  1937. if (SUCCEEDED(m_refCache.m_pRecordMgr->Retrieve(pBased->iBlock,
  1938. &pSid,
  1939. NULL,
  1940. NULL,
  1941. NULL)))
  1942. {
  1943. if (EqualSid(pKeySid, pSid))
  1944. {
  1945. bFound = TRUE;
  1946. }
  1947. }
  1948. if (!bFound)
  1949. {
  1950. pEntry = pBased->pNext;
  1951. }
  1952. delete[] pSid;
  1953. }
  1954. return pEntry;
  1955. }
  1956. //
  1957. // This version of Find() performs a linear search of the index to locate
  1958. // the specified logon name. The cache is currently indexed only
  1959. // on user SID because this is the only key used for very rapid lookups.
  1960. // The cache implementation could be easily extended to include a
  1961. // logon name index. All that's needed is a second hash bucket array,
  1962. // a hash-on-name function and some adjustments to the placement of
  1963. // file data. I just don't think the benefit is worth the cost.
  1964. //
  1965. PINDEX_ENTRY
  1966. SidNameCache::IndexMgr::Find(
  1967. LPCTSTR pszKeyLogonName
  1968. )
  1969. {
  1970. DBGASSERT((INDEX_FILE_MAPPED));
  1971. DBGASSERT((NULL != pszKeyLogonName));
  1972. BOOL bFound = FALSE;
  1973. PINDEX_ENTRY pEntry = NULL;
  1974. for (UINT i = 0; !bFound && (i < m_pFileHdr->cBuckets); i++)
  1975. {
  1976. pEntry = GetHashBucketValue(i);
  1977. while(NULL != pEntry && !bFound)
  1978. {
  1979. array_autoptr<TCHAR> ptrLogonName;
  1980. NDX_BASED(INDEX_ENTRY) *pBased = NDX_BASED_CAST(INDEX_ENTRY, pEntry);
  1981. //
  1982. // This can throw OutOfMemory.
  1983. //
  1984. if (SUCCEEDED(m_refCache.m_pRecordMgr->Retrieve(pBased->iBlock,
  1985. NULL,
  1986. NULL, // no container.
  1987. ptrLogonName.getaddr(),
  1988. NULL))) // no display name
  1989. {
  1990. DBGASSERT((NULL != ptrLogonName.get()));
  1991. if (0 == lstrcmpi(ptrLogonName.get(), pszKeyLogonName))
  1992. {
  1993. bFound = TRUE;
  1994. }
  1995. }
  1996. if (!bFound)
  1997. {
  1998. pEntry = pBased->pNext;
  1999. }
  2000. }
  2001. }
  2002. return pEntry;
  2003. }
  2004. ///////////////////////////////////////////////////////////////////////////////
  2005. /* Function: SidNameCache::IndexMgr::Lookup (2 overloaded methods)
  2006. Description: Given either a SID or an account logon name,
  2007. this method returns the starting block index of the corresponding
  2008. record in the data file.
  2009. Arguments:
  2010. pSid - Address of SID to use as a lookup key.
  2011. pszLogonName - Address of account logon name string.
  2012. Returns:
  2013. Index of the starting block for the record in the data file.
  2014. (DWORD)-1 if the record is not found.
  2015. Exceptions: OutOfMemory.
  2016. Revision History:
  2017. Date Description Programmer
  2018. -------- --------------------------------------------------- ----------
  2019. 09/21/96 Initial creation. BrianAu
  2020. */
  2021. ///////////////////////////////////////////////////////////////////////////////
  2022. DWORD
  2023. SidNameCache::IndexMgr::Lookup(
  2024. PSID pSid
  2025. )
  2026. {
  2027. DBGASSERT((NULL != pSid));
  2028. //
  2029. // This can throw OutOfMemory.
  2030. //
  2031. PINDEX_ENTRY pEntry = Find(pSid, Hash(pSid));
  2032. if (NULL != pEntry)
  2033. {
  2034. NDX_BASED(INDEX_ENTRY) *pBased = NDX_BASED_CAST(INDEX_ENTRY, pEntry);
  2035. return pBased->iBlock;
  2036. }
  2037. return (DWORD)-1;
  2038. }
  2039. DWORD
  2040. SidNameCache::IndexMgr::Lookup(
  2041. LPCTSTR pszLogonName
  2042. )
  2043. {
  2044. DBGASSERT((NULL != pszLogonName));
  2045. //
  2046. // This can throw OutOfMemory.
  2047. //
  2048. PINDEX_ENTRY pEntry = Find(pszLogonName);
  2049. if (NULL != pEntry)
  2050. {
  2051. NDX_BASED(INDEX_ENTRY) *pBased = NDX_BASED_CAST(INDEX_ENTRY, pEntry);
  2052. return pBased->iBlock;
  2053. }
  2054. return (DWORD)-1;
  2055. }
  2056. ///////////////////////////////////////////////////////////////////////////////
  2057. /* Function: SidNameCache::IndexMgr::Add
  2058. Description: Adds a SID/data-file-index pair to the index file. This
  2059. entry can later be used to locate the SID's record in the data file.
  2060. Arguments:
  2061. pSid - Address of SID to use as a lookup key.
  2062. iBlock - Index of the starting block for the SID's record in the
  2063. data file.
  2064. Returns: Address of the item's new index entry.
  2065. Exceptions: OutOfMemory.
  2066. Revision History:
  2067. Date Description Programmer
  2068. -------- --------------------------------------------------- ----------
  2069. 09/21/96 Initial creation. BrianAu
  2070. */
  2071. ///////////////////////////////////////////////////////////////////////////////
  2072. PINDEX_ENTRY
  2073. SidNameCache::IndexMgr::Add(
  2074. PSID pSid,
  2075. DWORD iBlock
  2076. )
  2077. {
  2078. DWORD dwHashCode = Hash(pSid);
  2079. PINDEX_ENTRY pEntry = Find(pSid, dwHashCode); // Can throw OutOfMemory.
  2080. //
  2081. // Don't create duplicate entries.
  2082. //
  2083. if (NULL == pEntry)
  2084. {
  2085. //
  2086. // Try to allocate an index entry from the free list.
  2087. //
  2088. pEntry = AllocEntry();
  2089. if (NULL == pEntry)
  2090. {
  2091. //
  2092. // Grow the index file and try again.
  2093. //
  2094. GrowIndexFile(INDEX_FILE_GROW_ENTRIES);
  2095. pEntry = AllocEntry();
  2096. }
  2097. if (NULL != pEntry)
  2098. {
  2099. NDX_BASED(INDEX_ENTRY) *pBasedEntry = NDX_BASED_CAST(INDEX_ENTRY, pEntry);
  2100. NDX_BASED(INDEX_ENTRY) *pBasedNext;
  2101. //
  2102. // Fill in the members of the new entry.
  2103. //
  2104. pBasedEntry->iBucket = dwHashCode;
  2105. pBasedEntry->iBlock = iBlock;
  2106. pBasedEntry->pNext = GetHashBucketValue(dwHashCode);
  2107. pBasedEntry->pPrev = NULL;
  2108. //
  2109. // Now insert it at the head of the hash bucket's entry list.
  2110. //
  2111. if (NULL != pBasedEntry->pNext)
  2112. {
  2113. pBasedNext = NDX_BASED_CAST(INDEX_ENTRY, pBasedEntry->pNext);
  2114. pBasedNext->pPrev = pEntry;
  2115. }
  2116. SetHashBucketValue(dwHashCode, pEntry);
  2117. }
  2118. }
  2119. return pEntry;
  2120. }
  2121. ///////////////////////////////////////////////////////////////////////////////
  2122. /* Function: SidNameCache::IndexMgr::Hash
  2123. Description: Given a SID, this method calculates a hash value to be used
  2124. as an offset into the index's hash table bucket array. The
  2125. algorithm simply sums the value of the SID's bytes. The resulting
  2126. hash code is this sum modulo the size of the hash table. For this
  2127. simple algorithm to be effective, it is important that the hash
  2128. table size be a prime number.
  2129. Here's some representative primes: 101, 503, 1009, 5003, 10007
  2130. Arguments:
  2131. pSid - Address of SID to use as an index lookup key.
  2132. Returns: Hashed SID. The value will be between 0 and m_pFileHdr->cBuckets.
  2133. Revision History:
  2134. Date Description Programmer
  2135. -------- --------------------------------------------------- ----------
  2136. 09/21/96 Initial creation. BrianAu
  2137. */
  2138. ///////////////////////////////////////////////////////////////////////////////
  2139. DWORD
  2140. SidNameCache::IndexMgr::Hash(
  2141. PSID pSid
  2142. )
  2143. {
  2144. DBGASSERT((INDEX_FILE_MAPPED));
  2145. DWORD dwCode = 0;
  2146. PBYTE pbSid = (PBYTE)pSid;
  2147. PBYTE pbEndSid = pbSid + GetLengthSid(pSid);
  2148. for ( ;pbSid < pbEndSid; pbSid++)
  2149. dwCode += *pbSid;
  2150. return dwCode % m_pFileHdr->cBuckets;
  2151. }
  2152. ///////////////////////////////////////////////////////////////////////////////
  2153. /* Function: SidNameCache::IndexMgr::Dump [DEBUG only]
  2154. Description: Dumps the contents of the index file to the debugger output.
  2155. Arguments: None.
  2156. Returns: Nothing.
  2157. Revision History:
  2158. Date Description Programmer
  2159. -------- --------------------------------------------------- ----------
  2160. 09/21/96 Initial creation. BrianAu
  2161. */
  2162. ///////////////////////////////////////////////////////////////////////////////
  2163. #if DBG
  2164. VOID
  2165. SidNameCache::IndexMgr::Dump(
  2166. VOID
  2167. )
  2168. {
  2169. UINT i, j;
  2170. DBGASSERT((INDEX_FILE_MAPPED));
  2171. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT("Dumping SidNameCache IndexMgr at 0x%p"), this));
  2172. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" Base...............: 0x%p"), g_pbMappedIndexFile));
  2173. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" m_pFileHdr.........: 0x%p"), m_pFileHdr));
  2174. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" dwSignature......: 0x%08X"), (DWORD)m_pFileHdr->dwSignature));
  2175. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" dwVersion........: 0x%08X"), (DWORD)m_pFileHdr->dwVersion));
  2176. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" cBuckets.........: %d"), (DWORD)m_pFileHdr->cBuckets));
  2177. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" cMaxEntries......: %d"), (DWORD)m_pFileHdr->cMaxEntries));
  2178. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" cEntries.........: %d"), (DWORD)m_pFileHdr->cEntries));
  2179. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" pBuckets.........: 0x%p"), m_pFileHdr->pBuckets));
  2180. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" pEntries.........: 0x%p"), m_pFileHdr->pEntries));
  2181. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" pFirstFree.......: 0x%p"), m_pFileHdr->pFirstFree));
  2182. for (i = 0; i < m_pFileHdr->cBuckets; i++)
  2183. {
  2184. PINDEX_ENTRY pEntry = GetHashBucketValue(i);
  2185. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" Bucket[%03d] = 0x%p"), i, pEntry));
  2186. while(NULL != pEntry)
  2187. {
  2188. NDX_BASED(INDEX_ENTRY) *pBased = NDX_BASED_CAST(INDEX_ENTRY, pEntry);
  2189. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" Bkt = %3d P = 0x%08X N = 0x%08X Blk = %d"),
  2190. pBased->iBucket,
  2191. pBased->pPrev,
  2192. pBased->pNext,
  2193. pBased->iBlock));
  2194. pEntry = pBased->pNext;
  2195. }
  2196. }
  2197. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" FreeList")));
  2198. PINDEX_ENTRY pEntry = m_pFileHdr->pFirstFree;
  2199. while(NULL != pEntry)
  2200. {
  2201. NDX_BASED(INDEX_ENTRY) *pBased = NDX_BASED_CAST(INDEX_ENTRY, pEntry);
  2202. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" Bkt = %3d P = 0x%08X N = 0x%08X Blk = %d"),
  2203. pBased->iBucket,
  2204. pBased->pPrev,
  2205. pBased->pNext,
  2206. pBased->iBlock));
  2207. pEntry = pBased->pNext;
  2208. }
  2209. }
  2210. #endif
  2211. //***********************************************************************************
  2212. //***********************************************************************************
  2213. // D A T A F I L E M A N A G E R
  2214. //***********************************************************************************
  2215. //***********************************************************************************
  2216. //
  2217. // Default cache record life values in days.
  2218. //
  2219. const DWORD DEF_REC_LIFE_MIN = 30;
  2220. const DWORD DEF_REC_LIFE_MAX = 60;
  2221. ///////////////////////////////////////////////////////////////////////////////
  2222. /* Function: SidNameCache::RecordMgr::RecordMgr
  2223. Description: Record manager constructor.
  2224. Arguments:
  2225. refCache - Reference to containing cache object. Used to call
  2226. index manager and cache manager public methods.
  2227. Returns: Nothing.
  2228. Exceptions: OutOfMemory.
  2229. Revision History:
  2230. Date Description Programmer
  2231. -------- --------------------------------------------------- ----------
  2232. 09/21/96 Initial creation. BrianAu
  2233. */
  2234. ///////////////////////////////////////////////////////////////////////////////
  2235. SidNameCache::RecordMgr::RecordMgr(
  2236. SidNameCache& refCache
  2237. ) : m_refCache(refCache),
  2238. m_pFileHdr(NULL),
  2239. m_hFile(NULL),
  2240. m_hFileMapping(NULL),
  2241. m_cDaysRecLifeMin(DEF_REC_LIFE_MIN),
  2242. m_cDaysRecLifeRange(DEF_REC_LIFE_MAX - DEF_REC_LIFE_MIN)
  2243. {
  2244. DWORD cDaysRecLifeMax = DEF_REC_LIFE_MAX;
  2245. DBGTRACE((DM_SIDCACHE, DL_MID, TEXT("SidNameCache::SidNameCache::RecordMgr")));
  2246. //
  2247. // Retrieve the min/max record life (days) from the registry.
  2248. // Note that we store record life min and range since those are
  2249. // what's used in the record life calculation. Seems more
  2250. // self-explanatory to store min/max in the registry rather than
  2251. // min/range.
  2252. //
  2253. RegKey key(HKEY_CURRENT_USER, REGSTR_KEY_DISKQUOTA);
  2254. if (key.Open(KEY_WRITE, true))
  2255. {
  2256. if (FAILED(key.GetValue(g_szSidCacheRecLifeMin, &m_cDaysRecLifeMin)) ||
  2257. 65536 <= m_cDaysRecLifeMin)
  2258. {
  2259. m_cDaysRecLifeMin = DEF_REC_LIFE_MIN; // Default;
  2260. key.SetValue(g_szSidCacheRecLifeMin, m_cDaysRecLifeMin);
  2261. }
  2262. if (FAILED(key.GetValue(g_szSidCacheRecLifeMax, &cDaysRecLifeMax)) ||
  2263. 65536 <= cDaysRecLifeMax)
  2264. {
  2265. cDaysRecLifeMax = DEF_REC_LIFE_MAX; // Default;
  2266. key.SetValue(g_szSidCacheRecLifeMax, cDaysRecLifeMax);
  2267. }
  2268. }
  2269. if (cDaysRecLifeMax < m_cDaysRecLifeMin)
  2270. cDaysRecLifeMax = m_cDaysRecLifeMin;
  2271. m_cDaysRecLifeRange = cDaysRecLifeMax - m_cDaysRecLifeMin;
  2272. }
  2273. ///////////////////////////////////////////////////////////////////////////////
  2274. /* Function: SidNameCache::RecordMgr::~RecordMgr
  2275. Description: Record manager destructor. Closes the data file.
  2276. Arguments: None.
  2277. Returns: Nothing.
  2278. Revision History:
  2279. Date Description Programmer
  2280. -------- --------------------------------------------------- ----------
  2281. 09/21/96 Initial creation. BrianAu
  2282. */
  2283. ///////////////////////////////////////////////////////////////////////////////
  2284. SidNameCache::RecordMgr::~RecordMgr(
  2285. VOID
  2286. )
  2287. {
  2288. DBGTRACE((DM_SIDCACHE, DL_MID, TEXT("SidNameCache::SidNameCache::~RecordMgr")));
  2289. CloseDataFile();
  2290. }
  2291. ///////////////////////////////////////////////////////////////////////////////
  2292. /* Function: SidNameCache::RecordMgr::Initialize
  2293. Description: Initializes a new record manager object.
  2294. Arguments:
  2295. pszFile - Address of full path for new file.
  2296. cBlocks - Number of storage blocks in data file. Each is 32 bytes.
  2297. If this argument is 0, the function tries to open an existing
  2298. cache data file.
  2299. Returns: Address of mapped file or NULL on failure.
  2300. Revision History:
  2301. Date Description Programmer
  2302. -------- --------------------------------------------------- ----------
  2303. 09/21/96 Initial creation. BrianAu
  2304. */
  2305. ///////////////////////////////////////////////////////////////////////////////
  2306. LPBYTE
  2307. SidNameCache::RecordMgr::Initialize(
  2308. LPCTSTR pszFile,
  2309. DWORD cBlocks
  2310. )
  2311. {
  2312. DBGTRACE((DM_SIDCACHE, DL_HIGH, TEXT("SidNameCache::RecordMgr::Initialize")));
  2313. DBGPRINT((DM_SIDCACHE, DL_HIGH, TEXT("\tpszFile = \"%s\", cBlocks = %d"),
  2314. pszFile ? pszFile : TEXT("<null>"), cBlocks));
  2315. //
  2316. // Store the file name in our CString object.
  2317. //
  2318. m_strFileName = pszFile;
  2319. if (0 != cBlocks)
  2320. {
  2321. //
  2322. // Create a new data file.
  2323. //
  2324. // cBlocks must be a multiple of 32.
  2325. // This satisfies the quadword alignment and makes sizing the
  2326. // allocation bitmap much easier. We let the caller pass in any value
  2327. // they want and we just adjust it upward as needed.
  2328. //
  2329. if (cBlocks & 0x0000001F)
  2330. cBlocks = (cBlocks & 0xFFFFFFE0) + 32;
  2331. ULARGE_INTEGER uliFileSize;
  2332. uliFileSize.QuadPart = FileSize(cBlocks);
  2333. m_pFileHdr = (PDATA_FILE_HDR)CreateDataFile(pszFile,
  2334. uliFileSize.HighPart,
  2335. uliFileSize.LowPart);
  2336. if (NULL != m_pFileHdr)
  2337. {
  2338. InitNewDataFile(cBlocks);
  2339. }
  2340. }
  2341. else
  2342. {
  2343. //
  2344. // Open an existing data file.
  2345. //
  2346. m_pFileHdr = (PDATA_FILE_HDR)OpenDataFile(pszFile);
  2347. if (NULL != m_pFileHdr)
  2348. {
  2349. if (FILE_VERSION != m_pFileHdr->dwVersion ||
  2350. DATA_FILE_SIGNATURE != m_pFileHdr->dwSignature)
  2351. {
  2352. //
  2353. // This version of the software doesn't understand this
  2354. // version of the file or the signature is invalid.
  2355. // Don't take any chances. We'll just create a new one.
  2356. //
  2357. DBGERROR((TEXT("SIDCACHE - Data file is invalid or incorrect version. A new data file will be created.")));
  2358. CloseDataFile();
  2359. m_pFileHdr = NULL;
  2360. }
  2361. }
  2362. }
  2363. return (LPBYTE)m_pFileHdr;
  2364. }
  2365. ///////////////////////////////////////////////////////////////////////////////
  2366. /* Function: SidNameCache::RecordMgr::CreateDataFile
  2367. Description: Creates and initializes a new data file.
  2368. Arguments:
  2369. pszFile - Address of full path for new file.
  2370. cbFileHigh/Low - Size of file in bytes.
  2371. Returns: Address of mapped file or NULL on failure.
  2372. Revision History:
  2373. Date Description Programmer
  2374. -------- --------------------------------------------------- ----------
  2375. 09/21/96 Initial creation. BrianAu
  2376. */
  2377. ///////////////////////////////////////////////////////////////////////////////
  2378. LPBYTE
  2379. SidNameCache::RecordMgr::CreateDataFile(
  2380. LPCTSTR pszFile,
  2381. DWORD cbFileHigh,
  2382. DWORD cbFileLow
  2383. )
  2384. {
  2385. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::RecordMgr::CreateDataFile")));
  2386. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT("\tpszFile = \"%s\""),
  2387. pszFile ? pszFile : TEXT("<null>")));
  2388. CloseDataFile(); // Make sure any existing data file is closed.
  2389. g_pbMappedDataFile = SidNameCache::OpenMappedFile(
  2390. pszFile,
  2391. g_pszDataFileMapping,
  2392. CREATE_ALWAYS,
  2393. cbFileHigh,
  2394. cbFileLow,
  2395. &m_hFile,
  2396. &m_hFileMapping);
  2397. return g_pbMappedDataFile;
  2398. }
  2399. ///////////////////////////////////////////////////////////////////////////////
  2400. /* Function: SidNameCache::RecordMgr::OpenDataFile
  2401. Description: Opens an existing data file.
  2402. Arguments:
  2403. pszFile - Address of full path of existing file.
  2404. Returns: Address of mapped file or NULL on failure.
  2405. Revision History:
  2406. Date Description Programmer
  2407. -------- --------------------------------------------------- ----------
  2408. 09/21/96 Initial creation. BrianAu
  2409. */
  2410. ///////////////////////////////////////////////////////////////////////////////
  2411. LPBYTE
  2412. SidNameCache::RecordMgr::OpenDataFile(
  2413. LPCTSTR pszFile
  2414. )
  2415. {
  2416. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::RecordMgr::OpenDataFile")));
  2417. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT("\tpszFile = \"%s\""),
  2418. pszFile ? pszFile : TEXT("<null>")));
  2419. CloseDataFile(); // Make sure any existing data file is closed.
  2420. g_pbMappedDataFile = SidNameCache::OpenMappedFile(
  2421. pszFile,
  2422. g_pszDataFileMapping,
  2423. OPEN_EXISTING,
  2424. 0,
  2425. 0,
  2426. &m_hFile,
  2427. &m_hFileMapping);
  2428. return g_pbMappedDataFile;
  2429. }
  2430. ///////////////////////////////////////////////////////////////////////////////
  2431. /* Function: SidNameCache::RecordMgr::CloseDataFile
  2432. Description: Closes the current data mapping and file.
  2433. Arguments: None.
  2434. Returns: Nothing.
  2435. Revision History:
  2436. Date Description Programmer
  2437. -------- --------------------------------------------------- ----------
  2438. 09/21/96 Initial creation. BrianAu
  2439. */
  2440. ///////////////////////////////////////////////////////////////////////////////
  2441. VOID
  2442. SidNameCache::RecordMgr::CloseDataFile(
  2443. VOID
  2444. )
  2445. {
  2446. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::RecordMgr::CloseDataFile")));
  2447. if (NULL != g_pbMappedDataFile)
  2448. {
  2449. UnmapViewOfFile(g_pbMappedDataFile);
  2450. g_pbMappedDataFile = NULL;
  2451. m_pFileHdr = NULL;
  2452. }
  2453. if (NULL != m_hFileMapping)
  2454. {
  2455. CloseHandle(m_hFileMapping);
  2456. m_hFileMapping = NULL;
  2457. }
  2458. if (NULL != m_hFile && INVALID_HANDLE_VALUE != m_hFile)
  2459. {
  2460. CloseHandle(m_hFile);
  2461. m_hFile = NULL;
  2462. }
  2463. }
  2464. ///////////////////////////////////////////////////////////////////////////////
  2465. /* Function: SidNameCache::RecordMgr::GrowDataFile
  2466. Description: Increases the size of the current data file.
  2467. Arguments:
  2468. cGrowBlocks - Add this many more blocks to the data file. The
  2469. block allocation bitmap is also extended to accomdate the new
  2470. block count.
  2471. Returns: Address of mapped file or NULL on failure.
  2472. Revision History:
  2473. Date Description Programmer
  2474. -------- --------------------------------------------------- ----------
  2475. 09/21/96 Initial creation. BrianAu
  2476. */
  2477. ///////////////////////////////////////////////////////////////////////////////
  2478. LPBYTE
  2479. SidNameCache::RecordMgr::GrowDataFile(
  2480. DWORD cGrowBlocks
  2481. )
  2482. {
  2483. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::RecordMgr::GrowDataFile")));
  2484. DBGASSERT((DATA_FILE_MAPPED));
  2485. DWORD cOldBlocks = m_pFileHdr->cBlocks;
  2486. DWORD cNewBlocks = cOldBlocks + cGrowBlocks;
  2487. DWORD cOldMapEle = m_pFileHdr->cMapElements;
  2488. DWORD cNewMapEle = 0; // Will calc later.
  2489. //
  2490. // cBlocks must be a multiple of 32.
  2491. // This satisfies the quadword alignment and makes sizing the
  2492. // allocation bitmap much easier.
  2493. //
  2494. if (cNewBlocks & 0x0000001F)
  2495. cNewBlocks = (cNewBlocks & 0xFFFFFFE0) + 32;
  2496. DBGASSERT((cNewBlocks >= cOldBlocks));
  2497. //
  2498. // Adjust cGrowBlocks for any adjustments in cNewBlocks.
  2499. //
  2500. cGrowBlocks = cNewBlocks - cOldBlocks;
  2501. //
  2502. // How many alloc map elements (DWORDs) do we need now?
  2503. //
  2504. cNewMapEle = cNewBlocks / BITS_IN_DWORD;
  2505. DBGPRINT((DM_SIDCACHE, DL_MID,
  2506. TEXT("Growing SID cache data file\nMap Ele %d -> %d\nBlocks %d -> %d"),
  2507. cOldMapEle, cNewMapEle, cOldBlocks, cNewBlocks));
  2508. //
  2509. // Open the mapped file with a new larger size.
  2510. //
  2511. ULARGE_INTEGER uliFileSize;
  2512. uliFileSize.QuadPart = FileSize(cNewBlocks);
  2513. CloseDataFile();
  2514. g_pbMappedDataFile = SidNameCache::OpenMappedFile(
  2515. m_strFileName,
  2516. g_pszDataFileMapping,
  2517. OPEN_EXISTING,
  2518. uliFileSize.HighPart,
  2519. uliFileSize.LowPart,
  2520. &m_hFile,
  2521. &m_hFileMapping);
  2522. m_pFileHdr = (PDATA_FILE_HDR)g_pbMappedDataFile;
  2523. if (NULL != g_pbMappedDataFile)
  2524. {
  2525. UINT i = 0;
  2526. //
  2527. // Block count and map size both increase.
  2528. // Since map size increases, blocks must be moved to accomodate new
  2529. // map elements. Since the index file tracks records by block index,
  2530. // this movement doesn't affect existing index file entries.
  2531. //
  2532. m_pFileHdr->cBlocks = cNewBlocks;
  2533. m_pFileHdr->cMapElements = cNewMapEle;
  2534. //
  2535. // Save current block base for when we move the blocks to make room for
  2536. // the growth of the allocation bitmap.
  2537. //
  2538. PBLOCK pBlocksOld = m_pFileHdr->pBlocks;
  2539. //
  2540. // Calculate the new address of block 0.
  2541. // We want all of the data blocks quadword aligned because they contain
  2542. // a FILETIME structure (64-bits).
  2543. //
  2544. m_pFileHdr->pBlocks = (PBLOCK)(m_pFileHdr->pdwMap + m_pFileHdr->cMapElements);
  2545. QuadAlign((LPDWORD)(&m_pFileHdr->pBlocks));
  2546. //
  2547. // Move all of the existing blocks to their new locations.
  2548. //
  2549. MoveMemory(DAT_BASED_CAST(BLOCK, m_pFileHdr->pBlocks),
  2550. DAT_BASED_CAST(BLOCK, pBlocksOld),
  2551. cOldBlocks * sizeof(BLOCK));
  2552. //
  2553. // Initialize the new map elements to 0 (un-allocated).
  2554. //
  2555. ZeroMemory(DAT_BASED_CAST(BYTE, m_pFileHdr->pdwMap + cOldMapEle),
  2556. (cNewMapEle - cOldMapEle) * sizeof(DWORD));
  2557. //
  2558. // Initialize the new data blocks to 0xCC pattern.
  2559. //
  2560. FillBlocks(cOldBlocks, cGrowBlocks, RECORD_UNUSED_BYTE);
  2561. DBGPRINT((DM_SIDCACHE, DL_MID, TEXT("SIDCACHE - Data file growth complete.")));
  2562. }
  2563. return g_pbMappedDataFile;
  2564. }
  2565. ///////////////////////////////////////////////////////////////////////////////
  2566. /* Function: SidNameCache::RecordMgr::SetFileGUID
  2567. Function: SidNameCache::RecordMgr::GetFileGUID
  2568. Description: These functions manipulate the guid field in the data file's
  2569. header.
  2570. The GUID is used to ensure integrity between
  2571. the data and index files. Before any change to either file, the
  2572. GUID's are both set to 0. When the change operation is complete,
  2573. a new GUID is generated and written to both files. Therefore, before
  2574. any transaction, we can validate the data and index files by reading
  2575. and comparing GUIDs. If the GUIDs are not 0 and are equal, the
  2576. file can be assumed to be valid.
  2577. Arguments:
  2578. pguid - Address of source or destination GUID.
  2579. Returns: Nothing.
  2580. Revision History:
  2581. Date Description Programmer
  2582. -------- --------------------------------------------------- ----------
  2583. 09/21/96 Initial creation. BrianAu
  2584. */
  2585. ///////////////////////////////////////////////////////////////////////////////
  2586. VOID
  2587. SidNameCache::RecordMgr::SetFileGUID(
  2588. const GUID *pguid
  2589. )
  2590. {
  2591. DBGASSERT((DATA_FILE_MAPPED));
  2592. DBGASSERT((NULL != pguid));
  2593. CopyMemory(&m_pFileHdr->guid, pguid, sizeof(GUID));
  2594. }
  2595. VOID
  2596. SidNameCache::RecordMgr::GetFileGUID(
  2597. LPGUID pguid
  2598. )
  2599. {
  2600. DBGASSERT((DATA_FILE_MAPPED));
  2601. DBGASSERT((NULL != pguid));
  2602. CopyMemory(pguid, &m_pFileHdr->guid, sizeof(GUID));
  2603. }
  2604. ///////////////////////////////////////////////////////////////////////////////
  2605. /* Function: SidNameCache::RecordMgr::InitNewDataFile
  2606. Description: Initializes a new data file filling in the header information
  2607. and writing 0xCC in all the data block bytes.
  2608. Arguments:
  2609. cBlocks - Number of data blocks (32 bytes each) in data file.
  2610. Returns: Nothing.
  2611. Revision History:
  2612. Date Description Programmer
  2613. -------- --------------------------------------------------- ----------
  2614. 09/21/96 Initial creation. BrianAu
  2615. */
  2616. ///////////////////////////////////////////////////////////////////////////////
  2617. VOID
  2618. SidNameCache::RecordMgr::InitNewDataFile(
  2619. DWORD cBlocks
  2620. )
  2621. {
  2622. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::RecordMgr::InitNewDataFile")));
  2623. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT("\tcBlocks = %d"), cBlocks));
  2624. UINT i = 0;
  2625. DBGASSERT((DATA_FILE_MAPPED));
  2626. //
  2627. // Initialize file header.
  2628. //
  2629. m_pFileHdr->dwSignature = DATA_FILE_SIGNATURE;
  2630. m_pFileHdr->dwVersion = FILE_VERSION;
  2631. m_pFileHdr->cBlocks = cBlocks;
  2632. m_pFileHdr->cMapElements = cBlocks / BITS_IN_DWORD;
  2633. m_pFileHdr->pdwMap = (LPDWORD)(sizeof(DATA_FILE_HDR));
  2634. m_pFileHdr->pBlocks = (PBLOCK)(m_pFileHdr->pdwMap + m_pFileHdr->cMapElements);
  2635. //
  2636. // We want all of the data blocks quadword aligned because they contain
  2637. // a FILETIME structure (64-bits).
  2638. //
  2639. QuadAlign((LPDWORD)(&m_pFileHdr->pBlocks));
  2640. //
  2641. // Write 0xCC to all data block bytes.
  2642. //
  2643. Clear();
  2644. }
  2645. ///////////////////////////////////////////////////////////////////////////////
  2646. /* Function: SidNameCache::RecordMgr::Clear
  2647. Description: Zero's the file header guid, clears all bits in the
  2648. block allocation bitmap and fills the data blocks with 0xCC.
  2649. Arguments: None.
  2650. Returns: Nothing.
  2651. Revision History:
  2652. Date Description Programmer
  2653. -------- --------------------------------------------------- ----------
  2654. 09/21/96 Initial creation. BrianAu
  2655. */
  2656. ///////////////////////////////////////////////////////////////////////////////
  2657. VOID
  2658. SidNameCache::RecordMgr::Clear(
  2659. VOID
  2660. )
  2661. {
  2662. DBGTRACE((DM_SIDCACHE, DL_LOW, TEXT("SidNameCache::RecordMgr::Clear")));
  2663. DBGASSERT((DATA_FILE_MAPPED));
  2664. m_pFileHdr->cBlocksUsed = 0;
  2665. m_pFileHdr->iFirstFree = 0;
  2666. SetFileGUID(&GUID_Null);
  2667. //
  2668. // Initialize all block allocation map bits to 0 (un-allocated).
  2669. //
  2670. ZeroMemory(DAT_BASED_CAST(BYTE, m_pFileHdr->pdwMap),
  2671. m_pFileHdr->cMapElements * sizeof(DWORD));
  2672. //
  2673. // Initialize all data blocks to 0xCC pattern.
  2674. //
  2675. FillBlocks(0, m_pFileHdr->cBlocks, RECORD_UNUSED_BYTE);
  2676. }
  2677. ///////////////////////////////////////////////////////////////////////////////
  2678. /* Function: SidNameCache::RecordMgr::FillBlocks
  2679. Description: Fills a range of blocks with a specified byte.
  2680. Arguments:
  2681. iBlock - Index of first block in range.
  2682. cBlocks - Number of blocks to fill.
  2683. b - Byte to write to blocks.
  2684. Returns: Nothing.
  2685. Revision History:
  2686. Date Description Programmer
  2687. -------- --------------------------------------------------- ----------
  2688. 09/21/96 Initial creation. BrianAu
  2689. */
  2690. ///////////////////////////////////////////////////////////////////////////////
  2691. VOID
  2692. SidNameCache::RecordMgr::FillBlocks(
  2693. DWORD iBlock,
  2694. DWORD cBlocks,
  2695. BYTE b
  2696. )
  2697. {
  2698. DBGASSERT((DATA_FILE_MAPPED));
  2699. DBGASSERT((ValidBlockNumber(iBlock)));
  2700. DAT_BASED(BYTE) *pb = DAT_BASED_CAST(BYTE, BlockAddress(iBlock));
  2701. DBGASSERT((SidNameCache::IsQuadAligned(pb)));
  2702. //
  2703. // Just in case the fill request would extend over the
  2704. // end of the file, truncate the requested block count. The assertion
  2705. // will catch it during development.
  2706. //
  2707. DWORD iLastBlock = iBlock + cBlocks - 1;
  2708. DBGASSERT((ValidBlockNumber(iLastBlock)));
  2709. if (iLastBlock >= m_pFileHdr->cBlocks)
  2710. cBlocks = m_pFileHdr->cBlocks - iBlock;
  2711. FillMemory(pb, sizeof(BLOCK) * cBlocks, b);
  2712. }
  2713. ///////////////////////////////////////////////////////////////////////////////
  2714. /* Function: SidNameCache::RecordMgr::IsBitSet
  2715. Function: SidNameCache::RecordMgr::SetBit
  2716. Function: SidNameCache::RecordMgr::ClrBit
  2717. Description: Tests and sets bits in the block allocation bitmap.
  2718. Arguments:
  2719. pdwBase - Address of 1st DWORD in bitmap.
  2720. iBit - 0-based index of bit in bitmap.
  2721. Returns: IsBitSet returns TRUE/FALSE indicating the state of the bit.
  2722. Revision History:
  2723. Date Description Programmer
  2724. -------- --------------------------------------------------- ----------
  2725. 09/21/96 Initial creation. BrianAu
  2726. */
  2727. ///////////////////////////////////////////////////////////////////////////////
  2728. BOOL
  2729. SidNameCache::RecordMgr::IsBitSet(
  2730. LPDWORD pdwBase,
  2731. DWORD iBit
  2732. )
  2733. {
  2734. DBGASSERT((NULL != pdwBase));
  2735. DWORD b = iBit & 0x0000001F;
  2736. DWORD i = iBit >> 5;
  2737. return (*(pdwBase + i)) & (1 << b);
  2738. }
  2739. VOID
  2740. SidNameCache::RecordMgr::SetBit(
  2741. LPDWORD pdwBase,
  2742. DWORD iBit
  2743. )
  2744. {
  2745. DBGASSERT((NULL != pdwBase));
  2746. DWORD b = iBit & 0x0000001F;
  2747. DWORD i = iBit >> 5;
  2748. (*(pdwBase + i)) |= (1 << b);
  2749. }
  2750. VOID
  2751. SidNameCache::RecordMgr::ClrBit(
  2752. LPDWORD pdwBase,
  2753. DWORD iBit
  2754. )
  2755. {
  2756. DBGASSERT((NULL != pdwBase));
  2757. DWORD b = iBit & 0x0000001F;
  2758. DWORD i = iBit >> 5;
  2759. (*(pdwBase + i)) &= ~(1 << b);
  2760. }
  2761. ///////////////////////////////////////////////////////////////////////////////
  2762. /* Function: SidNameCache::RecordMgr::ValidBlockNumber
  2763. Description: Determine if a given block number is valid for the
  2764. current data file. Primarily meant for use in assertions.
  2765. Arguments:
  2766. iBlock - 0-based index of block in data file.
  2767. Returns: TRUE/FALSE indicating validity of block number.
  2768. Revision History:
  2769. Date Description Programmer
  2770. -------- --------------------------------------------------- ----------
  2771. 09/21/96 Initial creation. BrianAu
  2772. */
  2773. ///////////////////////////////////////////////////////////////////////////////
  2774. BOOL
  2775. SidNameCache::RecordMgr::ValidBlockNumber(
  2776. DWORD iBlock
  2777. )
  2778. {
  2779. DBGASSERT((DATA_FILE_MAPPED));
  2780. return (iBlock < m_pFileHdr->cBlocks);
  2781. }
  2782. ///////////////////////////////////////////////////////////////////////////////
  2783. /* Function: SidNameCache::RecordMgr::IsBlockUsed
  2784. Function: SidNameCache::RecordMgr::MarkBlockUsed
  2785. Function: SidNameCache::RecordMgr::MarkBlockUnused
  2786. Description: Examines and changes the allocation state of a block in the
  2787. data file.
  2788. Arguments:
  2789. iBlock - 0-based index of block in data file.
  2790. Returns: IsBlockUsed returns TRUE/FALSE indicating the allocation state.
  2791. Revision History:
  2792. Date Description Programmer
  2793. -------- --------------------------------------------------- ----------
  2794. 09/21/96 Initial creation. BrianAu
  2795. */
  2796. ///////////////////////////////////////////////////////////////////////////////
  2797. BOOL
  2798. SidNameCache::RecordMgr::IsBlockUsed(
  2799. DWORD iBlock
  2800. )
  2801. {
  2802. DBGASSERT((DATA_FILE_MAPPED));
  2803. DBGASSERT((ValidBlockNumber(iBlock)));
  2804. DAT_BASED(DWORD) *pdwBased = DAT_BASED_CAST(DWORD, m_pFileHdr->pdwMap);
  2805. return IsBitSet((LPDWORD)pdwBased, iBlock);
  2806. }
  2807. VOID
  2808. SidNameCache::RecordMgr::MarkBlockUsed(
  2809. DWORD iBlock
  2810. )
  2811. {
  2812. DBGASSERT((DATA_FILE_MAPPED));
  2813. DBGASSERT((ValidBlockNumber(iBlock)));
  2814. DAT_BASED(DWORD) *pdwBased = DAT_BASED_CAST(DWORD, m_pFileHdr->pdwMap);
  2815. DBGASSERT((!IsBitSet((LPDWORD)pdwBased, iBlock)));
  2816. SetBit((LPDWORD)pdwBased, iBlock);
  2817. }
  2818. VOID
  2819. SidNameCache::RecordMgr::MarkBlockUnused(
  2820. DWORD iBlock
  2821. )
  2822. {
  2823. DBGASSERT((DATA_FILE_MAPPED));
  2824. DBGASSERT((ValidBlockNumber(iBlock)));
  2825. DAT_BASED(DWORD) *pdwBased = DAT_BASED_CAST(DWORD, m_pFileHdr->pdwMap);
  2826. DBGASSERT((IsBitSet((LPDWORD)pdwBased, iBlock)));
  2827. ClrBit((LPDWORD)pdwBased, iBlock);
  2828. }
  2829. ///////////////////////////////////////////////////////////////////////////////
  2830. /* Function: SidNameCache::RecordMgr::BlocksRequired
  2831. Description: Calculate the number of blocks required to store a given
  2832. number of bytes.
  2833. Arguments:
  2834. cb - Number of bytes requested.
  2835. Returns: Number of 32-byte blocks required to store the bytes.
  2836. Revision History:
  2837. Date Description Programmer
  2838. -------- --------------------------------------------------- ----------
  2839. 09/21/96 Initial creation. BrianAu
  2840. */
  2841. ///////////////////////////////////////////////////////////////////////////////
  2842. DWORD
  2843. SidNameCache::RecordMgr::BlocksRequired(
  2844. DWORD cb
  2845. )
  2846. {
  2847. //
  2848. // Round byte request up to nearest 32-byte block.
  2849. //
  2850. if (cb & 0x0000001F)
  2851. cb = (cb & 0xFFFFFFE0) + 32;
  2852. //
  2853. // How many "blocks" are required?
  2854. //
  2855. return BYTE_TO_BLOCK(cb);
  2856. }
  2857. ///////////////////////////////////////////////////////////////////////////////
  2858. /* Function: SidNameCache::IsQuadAligned
  2859. Function: SidNameCache::QuadAlign
  2860. Function: SidNameCache::WordAlign
  2861. Description: Methods that determine if a value is quad aligned and for
  2862. updating a value so that it is quad or word aligned.
  2863. Arguments:
  2864. See the individual methods. It's pretty self-explanatory.
  2865. Returns:
  2866. See the individual methods. It's pretty self-explanatory.
  2867. Revision History:
  2868. Date Description Programmer
  2869. -------- --------------------------------------------------- ----------
  2870. 09/21/96 Initial creation. BrianAu
  2871. */
  2872. ///////////////////////////////////////////////////////////////////////////////
  2873. BOOL
  2874. SidNameCache::IsQuadAligned(
  2875. LPVOID pv
  2876. )
  2877. {
  2878. return (IsQuadAligned((DWORD_PTR)pv));
  2879. }
  2880. BOOL
  2881. SidNameCache::IsQuadAligned(
  2882. DWORD_PTR dw
  2883. )
  2884. {
  2885. return (0 == (dw & 0x00000007));
  2886. }
  2887. VOID
  2888. SidNameCache::QuadAlign(
  2889. LPDWORD pdwValue
  2890. )
  2891. {
  2892. DBGASSERT((NULL != pdwValue));
  2893. if (*pdwValue & 0x00000007)
  2894. {
  2895. //
  2896. // Round up to next whole multiple of 8.
  2897. //
  2898. *pdwValue = (*pdwValue & 0xFFFFFFF8) + 8;
  2899. }
  2900. }
  2901. VOID
  2902. SidNameCache::WordAlign(
  2903. LPDWORD pdwValue
  2904. )
  2905. {
  2906. DBGASSERT((NULL != pdwValue));
  2907. if (*pdwValue & 0x00000001)
  2908. {
  2909. //
  2910. // Round up to next whole multiple of 2.
  2911. //
  2912. *pdwValue = (*pdwValue & 0xFFFFFFFE) + 2;
  2913. }
  2914. }
  2915. ///////////////////////////////////////////////////////////////////////////////
  2916. /* Function: SidNameCache::RecordMgr::BytesRequiredForRecord
  2917. Description: Calculates the number of bytes required to store a given
  2918. data file record. Optionally returns the required size for each
  2919. field in the record (SID, name, domain etc). The function makes
  2920. allowances for any required data type alignments in the file.
  2921. Arguments:
  2922. pSid - Address of user's SID.
  2923. pcbSid [optional] - Address of variable to receive required SID length.
  2924. pszContainer - Address of user's account container name string.
  2925. pcbContainer [optional] - Address of variable to receive required length
  2926. of container name string.
  2927. pszLogonName - Address of user's logon name string.
  2928. pcbLogonName [optional] - Address of variable to receive required length
  2929. of logon name string.
  2930. pszDisplayName - Address of user's display name string.
  2931. pcbDisplayName [optional] - Address of variable to receive required
  2932. length of display name string.
  2933. Returns: Number of bytes required to store the record.
  2934. Revision History:
  2935. Date Description Programmer
  2936. -------- --------------------------------------------------- ----------
  2937. 09/21/96 Initial creation. BrianAu
  2938. */
  2939. ///////////////////////////////////////////////////////////////////////////////
  2940. DWORD
  2941. SidNameCache::RecordMgr::BytesRequiredForRecord(
  2942. PSID pSid,
  2943. LPDWORD pcbSid,
  2944. LPCTSTR pszContainer,
  2945. LPDWORD pcbContainer,
  2946. LPCTSTR pszLogonName,
  2947. LPDWORD pcbLogonName,
  2948. LPCTSTR pszDisplayName,
  2949. LPDWORD pcbDisplayName
  2950. )
  2951. {
  2952. DWORD cb = 0;
  2953. DWORD cbTotal = sizeof(RECORD_HDR);
  2954. //
  2955. // SID follows the header so it IS quadword aligned.
  2956. // It's a byte structure so it doesn't have to be; but it is anyway.
  2957. //
  2958. cb = GetLengthSid(pSid);
  2959. cbTotal += cb;
  2960. if (NULL != pcbSid)
  2961. *pcbSid = cb;
  2962. //
  2963. // Strings are UNICODE and must be word-aligned. Just align the first.
  2964. // All subsequent are guaranteed to be properly aligned.
  2965. //
  2966. SidNameCache::WordAlign(&cbTotal);
  2967. cb = (lstrlen(pszContainer) + 1) * sizeof(TCHAR);
  2968. cbTotal += cb;
  2969. if (NULL != pcbContainer)
  2970. *pcbContainer = cb;
  2971. cb = (lstrlen(pszLogonName) + 1) * sizeof(TCHAR);
  2972. cbTotal += cb;
  2973. if (NULL != pcbLogonName)
  2974. *pcbLogonName = cb;
  2975. cb = (lstrlen(pszDisplayName) + 1) * sizeof(TCHAR);
  2976. cbTotal += cb;
  2977. if (NULL != pcbDisplayName)
  2978. *pcbDisplayName = cb;
  2979. return cbTotal;
  2980. }
  2981. ///////////////////////////////////////////////////////////////////////////////
  2982. /* Function: SidNameCache::RecordMgr::FreeBlock
  2983. Description: Frees a single block in the data file.
  2984. Arguments:
  2985. iBlock - 0-based index of the block.
  2986. Returns: Nothing.
  2987. Revision History:
  2988. Date Description Programmer
  2989. -------- --------------------------------------------------- ----------
  2990. 09/21/96 Initial creation. BrianAu
  2991. */
  2992. ///////////////////////////////////////////////////////////////////////////////
  2993. VOID
  2994. SidNameCache::RecordMgr::FreeBlock(
  2995. DWORD iBlock
  2996. )
  2997. {
  2998. DBGASSERT((DATA_FILE_MAPPED));
  2999. DBGASSERT((ValidBlockNumber(iBlock)));
  3000. DBGASSERT((IsBlockUsed(iBlock)));
  3001. MarkBlockUnused(iBlock);
  3002. DBGASSERT((!IsBlockUsed(iBlock)));
  3003. FillBlocks(iBlock, 1, RECORD_UNUSED_BYTE);
  3004. //
  3005. // Update the "first free" index if needed.
  3006. //
  3007. if (iBlock < m_pFileHdr->iFirstFree)
  3008. m_pFileHdr->iFirstFree = iBlock;
  3009. }
  3010. ///////////////////////////////////////////////////////////////////////////////
  3011. /* Function: SidNameCache::RecordMgr::FreeBlocks
  3012. Description: Frees a series of contiguous blocks in the data file.
  3013. Arguments:
  3014. iBlock - 0-based index of the first block in the series.
  3015. cBlocks - Number of blocks in the series.
  3016. Returns: Nothing.
  3017. Revision History:
  3018. Date Description Programmer
  3019. -------- --------------------------------------------------- ----------
  3020. 09/21/96 Initial creation. BrianAu
  3021. */
  3022. ///////////////////////////////////////////////////////////////////////////////
  3023. VOID
  3024. SidNameCache::RecordMgr::FreeBlocks(
  3025. DWORD iFirstBlock,
  3026. DWORD cBlocks
  3027. )
  3028. {
  3029. for (UINT i = 0; i < cBlocks; i++)
  3030. FreeBlock(iFirstBlock + i);
  3031. }
  3032. ///////////////////////////////////////////////////////////////////////////////
  3033. /* Function: SidNameCache::RecordMgr::FreeRecord
  3034. Description: Frees all blocks in a data file record.
  3035. Arguments:
  3036. iFirstBlock - 0-based index of the first block in the record.
  3037. Returns: Nothing.
  3038. Revision History:
  3039. Date Description Programmer
  3040. -------- --------------------------------------------------- ----------
  3041. 09/21/96 Initial creation. BrianAu
  3042. */
  3043. ///////////////////////////////////////////////////////////////////////////////
  3044. VOID
  3045. SidNameCache::RecordMgr::FreeRecord(
  3046. DWORD iFirstBlock
  3047. )
  3048. {
  3049. DBGASSERT((DATA_FILE_MAPPED));
  3050. DBGASSERT((ValidBlockNumber(iFirstBlock)));
  3051. DAT_BASED(RECORD_HDR) *pRecHdr = DAT_BASED_CAST(RECORD_HDR, BlockAddress(iFirstBlock));
  3052. DBGASSERT((RECORD_SIGNATURE == pRecHdr->dwSignature));
  3053. FreeBlocks(iFirstBlock, pRecHdr->cBlocks);
  3054. }
  3055. ///////////////////////////////////////////////////////////////////////////////
  3056. /* Function: SidNameCache::RecordMgr::BlockAddress
  3057. Description: Calculates the non-based address of a given block in the
  3058. data file.
  3059. Arguments:
  3060. iBlock - 0-based index of the block.
  3061. Returns: Address of the block in the data file.
  3062. Revision History:
  3063. Date Description Programmer
  3064. -------- --------------------------------------------------- ----------
  3065. 09/21/96 Initial creation. BrianAu
  3066. */
  3067. ///////////////////////////////////////////////////////////////////////////////
  3068. PBLOCK
  3069. SidNameCache::RecordMgr::BlockAddress(
  3070. DWORD iBlock
  3071. )
  3072. {
  3073. DBGASSERT((DATA_FILE_MAPPED));
  3074. DBGASSERT((ValidBlockNumber(iBlock)));
  3075. return m_pFileHdr->pBlocks + iBlock;
  3076. }
  3077. ///////////////////////////////////////////////////////////////////////////////
  3078. /* Function: SidNameCache::RecordMgr::FileSize
  3079. Description: Calculate the data file size required for a given number of
  3080. data blocks. Accounts for data type alignment.
  3081. Arguments:
  3082. cBlocks - Number of blocks required in the data file.
  3083. Returns: Bytes required.
  3084. Revision History:
  3085. Date Description Programmer
  3086. -------- --------------------------------------------------- ----------
  3087. 09/24/96 Initial creation. BrianAu
  3088. */
  3089. ///////////////////////////////////////////////////////////////////////////////
  3090. UINT64
  3091. SidNameCache::RecordMgr::FileSize(
  3092. DWORD cBlocks
  3093. )
  3094. {
  3095. DWORD dwTemp = sizeof(DATA_FILE_HDR) +
  3096. ((cBlocks / BITS_IN_DWORD) * sizeof(DWORD));
  3097. //
  3098. // Start of blocks must be quad-aligned.
  3099. //
  3100. SidNameCache::QuadAlign(&dwTemp);
  3101. return (UINT64)(dwTemp) +
  3102. (UINT64)(sizeof(BLOCK) * cBlocks);
  3103. }
  3104. ///////////////////////////////////////////////////////////////////////////////
  3105. /* Function: SidNameCache::RecordMgr::AllocBlocks
  3106. Description: Allocates a specified number of contiguous blocks in the
  3107. data file.
  3108. Arguments:
  3109. cBlocksReqd - Number of blocks required in the allocation.
  3110. Returns: If successful, returns the index of the first block in the
  3111. allocation. Returns (DWORD)-1 if the block's can't be allocated.
  3112. Revision History:
  3113. Date Description Programmer
  3114. -------- --------------------------------------------------- ----------
  3115. 09/21/96 Initial creation. BrianAu
  3116. */
  3117. ///////////////////////////////////////////////////////////////////////////////
  3118. DWORD
  3119. SidNameCache::RecordMgr::AllocBlocks(
  3120. DWORD cBlocksReqd
  3121. )
  3122. {
  3123. DBGASSERT((DATA_FILE_MAPPED));
  3124. DWORD iBlock = m_pFileHdr->iFirstFree;
  3125. DBGPRINT((DM_SIDCACHE, DL_MID,
  3126. TEXT("SIDCACHE - AllocBlocks: Allocate %d blocks"),
  3127. cBlocksReqd));
  3128. while(iBlock < m_pFileHdr->cBlocks)
  3129. {
  3130. DBGPRINT((DM_SIDCACHE, DL_MID,
  3131. TEXT(" Start scan at block %d"), iBlock));
  3132. //
  3133. // Look for cBlocksReqd consecutive free blocks.
  3134. //
  3135. for (UINT j = 0; j < cBlocksReqd && (iBlock + j) < m_pFileHdr->cBlocks ; j++)
  3136. {
  3137. DBGPRINT((DM_SIDCACHE, DL_MID, TEXT(" Checking %d"), iBlock + j));
  3138. if (IsBlockUsed(iBlock + j))
  3139. {
  3140. //
  3141. // This one's used. Start searching again.
  3142. //
  3143. DBGPRINT((DM_SIDCACHE, DL_MID, TEXT(" %d is used"), iBlock + j));
  3144. break;
  3145. }
  3146. #if DBG
  3147. //
  3148. // If a block is marked "unused", it should contain all 0xCC.
  3149. //
  3150. DAT_BASED(BYTE) *pb = DAT_BASED_CAST(BYTE, BlockAddress(iBlock + j));
  3151. for (UINT k = 0; k < sizeof(BLOCK); k++)
  3152. {
  3153. DBGASSERT((RECORD_UNUSED_BYTE == *(pb + k)));
  3154. }
  3155. #endif
  3156. }
  3157. DBGPRINT((DM_SIDCACHE, DL_MID, TEXT(" Scan complete. %d blocks checked"), j));
  3158. if (j == cBlocksReqd)
  3159. {
  3160. //
  3161. // Found a sufficient range of free blocks.
  3162. // Mark the blocks as allocated in the allocation bitmap.
  3163. //
  3164. for (UINT i = 0; i < cBlocksReqd; i++)
  3165. MarkBlockUsed(iBlock + i);
  3166. if (iBlock == m_pFileHdr->iFirstFree)
  3167. {
  3168. //
  3169. // Now scan to find the next free block.
  3170. // We'll save it's location to help with future free-block searches.
  3171. //
  3172. for (m_pFileHdr->iFirstFree = iBlock + cBlocksReqd;
  3173. m_pFileHdr->iFirstFree < m_pFileHdr->cBlocks && IsBlockUsed(m_pFileHdr->iFirstFree);
  3174. m_pFileHdr->iFirstFree++)
  3175. {
  3176. DBGPRINT((DM_SIDCACHE, DL_MID,
  3177. TEXT("SIDCACHE - Advancing first free %d"),
  3178. m_pFileHdr->iFirstFree));
  3179. NULL;
  3180. }
  3181. }
  3182. DBGPRINT((DM_SIDCACHE, DL_MID, TEXT("SIDCACHE - Found free block range at %d"), iBlock));
  3183. return iBlock;
  3184. }
  3185. iBlock += (j + 1); // Continue search.
  3186. }
  3187. DBGPRINT((DM_SIDCACHE, DL_MID, TEXT("SIDCACHE - No blocks available")));
  3188. return (DWORD)-1; // No blocks available of sufficient size.
  3189. }
  3190. ///////////////////////////////////////////////////////////////////////////////
  3191. /* Function: SidNameCache::RecordMgr::RecordExpired
  3192. Description: Determine if a given record has expired. A record has
  3193. "expired" if it's expiration date is prior to "today".
  3194. Arguments:
  3195. iBlock - 0-based index of first block in record.
  3196. Returns: Nothing.
  3197. Revision History:
  3198. Date Description Programmer
  3199. -------- --------------------------------------------------- ----------
  3200. 09/21/96 Initial creation. BrianAu
  3201. */
  3202. ///////////////////////////////////////////////////////////////////////////////
  3203. BOOL
  3204. SidNameCache::RecordMgr::RecordExpired(
  3205. DWORD iBlock
  3206. )
  3207. {
  3208. DBGASSERT((ValidBlockNumber(iBlock)));
  3209. DAT_BASED(RECORD_HDR) *pRec = DAT_BASED_CAST(RECORD_HDR, BlockAddress(iBlock));
  3210. DBGASSERT((SidNameCache::IsQuadAligned(pRec)));
  3211. DBGASSERT((RECORD_SIGNATURE == pRec->dwSignature));
  3212. SYSTEMTIME SysNow;
  3213. FILETIME FileNow;
  3214. ULARGE_INTEGER uliFileNow;
  3215. ULARGE_INTEGER uliBirthday;
  3216. uliBirthday.LowPart = pRec->Birthday.dwLowDateTime;
  3217. uliBirthday.HighPart = pRec->Birthday.dwHighDateTime;
  3218. GetSystemTime(&SysNow);
  3219. SystemTimeToFileTime(&SysNow, &FileNow);
  3220. uliFileNow.LowPart = FileNow.dwLowDateTime;
  3221. uliFileNow.HighPart = FileNow.dwHighDateTime;
  3222. DWORD cDaysVariation = 0;
  3223. //
  3224. // Avoid div-by-zero.
  3225. //
  3226. if (0 < m_cDaysRecLifeRange)
  3227. cDaysVariation = SysNow.wMilliseconds % m_cDaysRecLifeRange;
  3228. //
  3229. // Add time specified in registry to the record's birthday.
  3230. // 864,000,000,000L is the number of 100 nanosecond periods in a day
  3231. // which is the unit the FILETIME structure is based on.
  3232. //
  3233. uliBirthday.QuadPart += ((UINT64)864000000000L *
  3234. (UINT64)(m_cDaysRecLifeMin + cDaysVariation));
  3235. //
  3236. // If it's still less than "now", the record is considered good.
  3237. //
  3238. return uliFileNow.QuadPart > uliBirthday.QuadPart;
  3239. }
  3240. ///////////////////////////////////////////////////////////////////////////////
  3241. /* Function: SidNameCache::RecordMgr::Store
  3242. Description: Stores a record in the data file.
  3243. Arguments:
  3244. pSid - Address of user's SID.
  3245. pszContainer - Address of user's account container name string.
  3246. pszLogonName - Address of user's logon name string.
  3247. pszDisplayName - Address of user's display name string.
  3248. Returns: Index of the first block used for the record.
  3249. (DWORD)-1 if the block couldn't be stored. Could mean out-of-disk
  3250. space.
  3251. Revision History:
  3252. Date Description Programmer
  3253. -------- --------------------------------------------------- ----------
  3254. 09/21/96 Initial creation. BrianAu
  3255. */
  3256. ///////////////////////////////////////////////////////////////////////////////
  3257. DWORD
  3258. SidNameCache::RecordMgr::Store(
  3259. PSID pSid,
  3260. LPCTSTR pszContainer,
  3261. LPCTSTR pszLogonName,
  3262. LPCTSTR pszDisplayName
  3263. )
  3264. {
  3265. DWORD cbSid = 0;
  3266. DWORD cbContainer = 0;
  3267. DWORD cbLogonName = 0;
  3268. DWORD cbDisplayName = 0;
  3269. DWORD cbRequired = BytesRequiredForRecord(
  3270. pSid,
  3271. &cbSid,
  3272. pszContainer,
  3273. &cbContainer,
  3274. pszLogonName,
  3275. &cbLogonName,
  3276. pszDisplayName,
  3277. &cbDisplayName);
  3278. DWORD cBlocksRequired = BlocksRequired(cbRequired);
  3279. DBGPRINT((DM_SIDCACHE, DL_MID,
  3280. TEXT("SIDCACHE - Store: %s (%s) in \"%s\" %d bytes, %d blocks"),
  3281. pszDisplayName, pszLogonName, pszContainer, cbRequired, cBlocksRequired));
  3282. //
  3283. // Try to allocate the required blocks.
  3284. //
  3285. DWORD iBlock = AllocBlocks(cBlocksRequired);
  3286. if ((DWORD)-1 == iBlock)
  3287. {
  3288. //
  3289. // Couldn't allocate blocks. Extend the data file.
  3290. //
  3291. GrowDataFile(DATA_FILE_GROW_BLOCKS);
  3292. iBlock = AllocBlocks(cBlocksRequired);
  3293. }
  3294. if ((DWORD)-1 != iBlock)
  3295. {
  3296. //
  3297. // Got the required number of blocks.
  3298. //
  3299. DBGASSERT((ValidBlockNumber(iBlock)));
  3300. PBLOCK pBlock = BlockAddress(iBlock);
  3301. DAT_BASED(RECORD_HDR) *pRec = DAT_BASED_CAST(RECORD_HDR, pBlock);
  3302. DAT_BASED(BYTE) *pbRec = DAT_BASED_CAST(BYTE, pBlock);
  3303. //
  3304. // Fill in the record header.
  3305. // Includes storing the item offset values from the start of the record.
  3306. // Storing these values in the record hdr will help with data retrieval.
  3307. //
  3308. pRec->dwSignature = RECORD_SIGNATURE;
  3309. pRec->cBlocks = cBlocksRequired;
  3310. pRec->cbOfsSid = sizeof(RECORD_HDR);
  3311. pRec->cbOfsContainer = pRec->cbOfsSid + cbSid;
  3312. WordAlign(&pRec->cbOfsContainer);
  3313. pRec->cbOfsLogonName = pRec->cbOfsContainer + cbContainer;
  3314. pRec->cbOfsDisplayName = pRec->cbOfsLogonName + cbLogonName;;
  3315. //
  3316. // Record the "birthday" so we can age the record.
  3317. //
  3318. SYSTEMTIME SysNow;
  3319. GetSystemTime(&SysNow);
  3320. SystemTimeToFileTime(&SysNow, &pRec->Birthday);
  3321. //
  3322. // Store the record's data.
  3323. // Use ACTUAL length values for memory transfers.
  3324. //
  3325. CopySid(cbSid, (PSID)(pbRec + pRec->cbOfsSid), pSid);
  3326. lstrcpy((LPTSTR)(pbRec + pRec->cbOfsContainer), pszContainer);
  3327. lstrcpy((LPTSTR)(pbRec + pRec->cbOfsLogonName), pszLogonName);
  3328. lstrcpy((LPTSTR)(pbRec + pRec->cbOfsDisplayName), pszDisplayName);
  3329. //
  3330. // Update the file's "blocks used" count.
  3331. //
  3332. m_pFileHdr->cBlocksUsed += pRec->cBlocks;
  3333. }
  3334. return iBlock;
  3335. }
  3336. ///////////////////////////////////////////////////////////////////////////////
  3337. /* Function: SidNameCache::RecordMgr::Retrieve
  3338. Description: Retrieves a record in the data file.
  3339. Arguments:
  3340. iBlock - 0-based index of the starting block in the record.
  3341. ppSid [optional] - Address of SID pointer variable to receive the
  3342. address of the SID buffer. The caller is responsible for freeing
  3343. the buffer. May be NULL.
  3344. ppszContainer [optional] - Address of pointer variable to receive the
  3345. address of the container name string buffer. The caller is
  3346. responsible for freeing the buffer. May be NULL.
  3347. ppszLogonName [optional] - Address of pointer variable to receive the
  3348. address of the logon name string buffer. The caller is
  3349. responsible for freeing the buffer. May be NULL.
  3350. ppszDisplayName [optional] - Address of pointer variable to receive the
  3351. address of the display name string buffer. The caller is
  3352. responsible for freeing the buffer. May be NULL.
  3353. Returns:
  3354. NO_ERROR - Success.
  3355. ERROR_INVALID_SID (hr) - The record contains an invalid SID. Probably
  3356. a corrupt record.
  3357. Exceptions: OutOfMemory.
  3358. Revision History:
  3359. Date Description Programmer
  3360. -------- --------------------------------------------------- ----------
  3361. 09/21/96 Initial creation. BrianAu
  3362. */
  3363. ///////////////////////////////////////////////////////////////////////////////
  3364. HRESULT
  3365. SidNameCache::RecordMgr::Retrieve(
  3366. DWORD iBlock,
  3367. PSID *ppSid,
  3368. LPTSTR *ppszContainer,
  3369. LPTSTR *ppszLogonName,
  3370. LPTSTR *ppszDisplayName
  3371. )
  3372. {
  3373. PBLOCK pBlock = BlockAddress(iBlock);
  3374. DAT_BASED(RECORD_HDR) *pRec = DAT_BASED_CAST(RECORD_HDR, pBlock);
  3375. DAT_BASED(BYTE) *pbRec = DAT_BASED_CAST(BYTE, pBlock);
  3376. DBGASSERT((SidNameCache::IsQuadAligned(pRec)));
  3377. DBGASSERT((RECORD_SIGNATURE == pRec->dwSignature));
  3378. if (NULL != ppSid)
  3379. {
  3380. PSID pSid = (PSID)(pbRec + pRec->cbOfsSid);
  3381. if (IsValidSid(pSid))
  3382. {
  3383. *ppSid = SidDup(pSid);
  3384. }
  3385. else
  3386. return HRESULT_FROM_WIN32(ERROR_INVALID_SID);
  3387. }
  3388. if (NULL != ppszContainer)
  3389. {
  3390. *ppszContainer = StringDup((LPTSTR)(pbRec + pRec->cbOfsContainer));
  3391. }
  3392. if (NULL != ppszLogonName)
  3393. {
  3394. *ppszLogonName = StringDup((LPTSTR)(pbRec + pRec->cbOfsLogonName));
  3395. }
  3396. if (NULL != ppszDisplayName)
  3397. {
  3398. *ppszDisplayName = StringDup((LPTSTR)(pbRec + pRec->cbOfsDisplayName));
  3399. }
  3400. return NO_ERROR;
  3401. }
  3402. ///////////////////////////////////////////////////////////////////////////////
  3403. /* Function: SidNameCache::RecordMgr::Dump
  3404. Description: Dumps the contents of the data file to the debugger output.
  3405. Arguments: None.
  3406. Returns: Nothing.
  3407. Revision History:
  3408. Date Description Programmer
  3409. -------- --------------------------------------------------- ----------
  3410. 09/21/96 Initial creation. BrianAu
  3411. */
  3412. ///////////////////////////////////////////////////////////////////////////////
  3413. #if DBG
  3414. VOID
  3415. SidNameCache::RecordMgr::Dump(
  3416. VOID
  3417. )
  3418. {
  3419. UINT i, j;
  3420. DBGASSERT((DATA_FILE_MAPPED));
  3421. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT("Dumping SidNameCache RecordMgr at 0x%p"), this));
  3422. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" Base...............: 0x%p"), g_pbMappedDataFile));
  3423. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" m_pFileHdr.........: 0x%p"), m_pFileHdr));
  3424. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" dwSignature......: 0x%08X"), (DWORD)m_pFileHdr->dwSignature));
  3425. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" dwVersion........: 0x%08X"), (DWORD)m_pFileHdr->dwVersion));
  3426. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" cBlocks..........: %d"), (DWORD)m_pFileHdr->cBlocks));
  3427. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" cBlocksUsed......: %d"), (DWORD)m_pFileHdr->cBlocksUsed));
  3428. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" cMapElements.....: %d"), (DWORD)m_pFileHdr->cMapElements));
  3429. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" iFirstFree.......: %d"), (DWORD)m_pFileHdr->iFirstFree));
  3430. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" pdwMap...........: 0x%p"), m_pFileHdr->pdwMap));
  3431. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT(" pBlocks..........: 0x%p"), m_pFileHdr->pBlocks));
  3432. PBLOCK pBlock = m_pFileHdr->pBlocks;
  3433. for (i = 0; i < m_pFileHdr->cBlocks; i++)
  3434. {
  3435. DAT_BASED(BYTE) *pb = DAT_BASED_CAST(BYTE, pBlock);
  3436. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT("BLOCK %d --------------------"), i));
  3437. for (UINT row = 0; row < 2; row++)
  3438. {
  3439. TCHAR szHex[MAX_PATH];
  3440. TCHAR szAscii[MAX_PATH];
  3441. LPTSTR pszHex = szHex;
  3442. pb = DAT_BASED_CAST(BYTE, pBlock) + (row * (sizeof(BLOCK)/2));
  3443. for (j = 0; j < 16; j++)
  3444. {
  3445. wsprintf(pszHex, TEXT("%02X "), *pb);
  3446. pb++;
  3447. pszHex += 2;
  3448. }
  3449. LPTSTR pszAscii = szAscii;
  3450. pb = DAT_BASED_CAST(BYTE, pBlock) + (row * (sizeof(BLOCK)/2));
  3451. for (j = 0; j < 16; j++)
  3452. {
  3453. wsprintf(pszAscii, TEXT("%c"), *pb > 31 ? *pb : TEXT('.'));
  3454. pb++;
  3455. pszAscii++;
  3456. }
  3457. DBGPRINT((DM_SIDCACHE, DL_LOW, TEXT("%s %s"), szHex, szAscii));
  3458. }
  3459. pBlock++;
  3460. }
  3461. }
  3462. #endif // DEBUG