Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

636 lines
15 KiB

  1. //+----------------------------------------------------------------------------
  2. //
  3. // File: PbkCache.cpp
  4. //
  5. // Module: Common pbk parser
  6. //
  7. // Synopsis: Caches parsed pbk files to improve performance. Through
  8. // XP, we would re-load and re-parse the phonebook file
  9. // every time a RAS API is called. Really, we need to
  10. // reload the file only when the file on disk changes or when
  11. // a new device is introduced to the system.
  12. //
  13. // Copyright (c) 2000-2001 Microsoft Corporation
  14. //
  15. // Author: 11/03/01 Paul Mayfield
  16. //
  17. //+----------------------------------------------------------------------------
  18. #ifdef _PBK_CACHE_
  19. extern "C"
  20. {
  21. #include <windows.h> // Win32 core
  22. #include <pbkp.h>
  23. #include <nouiutil.h>
  24. #include <dtl.h>
  25. }
  26. #define PBK_CACHE_MAX_RASFILES 500 // Should match MAX_RASFILES
  27. #define PBK_CACHE_INVALID_SLOT (PBK_CACHE_MAX_RASFILES + 1)
  28. //+----------------------------------------------------------------------------
  29. //
  30. // Synopsis: A node in the pbk cache
  31. //
  32. // Created: pmay
  33. //
  34. //-----------------------------------------------------------------------------
  35. class PbkCacheNode
  36. {
  37. public:
  38. PbkCacheNode();
  39. ~PbkCacheNode();
  40. VOID Close();
  41. DWORD SetFileName(IN WCHAR* pszFileName);
  42. WCHAR* GetPath() {return m_pbFile.pszPath;}
  43. FILETIME GetReadTime() {return m_ftRead;}
  44. DWORD GetLastWriteTime(FILETIME* pTime);
  45. DWORD Reload();
  46. DTLLIST* GetEntryList() {return m_pbFile.pdtllistEntries;}
  47. private:
  48. PBFILE m_pbFile;
  49. FILETIME m_ftRead;
  50. PWCHAR m_pszFileName;
  51. };
  52. //+----------------------------------------------------------------------------
  53. //
  54. // Synopsis: The phonebook cache
  55. //
  56. // Created: pmay
  57. //
  58. //-----------------------------------------------------------------------------
  59. class PbkCache
  60. {
  61. public:
  62. PbkCache();
  63. ~PbkCache();
  64. DWORD Initialize();
  65. DWORD
  66. GetEntry(
  67. IN WCHAR* pszPhonebook,
  68. IN WCHAR* pszEntry,
  69. OUT DTLNODE** ppEntryNode);
  70. VOID
  71. Lock() {EnterCriticalSection(&m_csLock);}
  72. VOID
  73. Unlock() {LeaveCriticalSection(&m_csLock);}
  74. private:
  75. PbkCacheNode* m_Files[PBK_CACHE_MAX_RASFILES];
  76. CRITICAL_SECTION m_csLock;
  77. DWORD
  78. InsertNewNode(
  79. IN PWCHAR pszPhonebook,
  80. IN DWORD dwSlot,
  81. OUT PbkCacheNode** ppNode);
  82. VOID
  83. FindFile(
  84. IN WCHAR* pszFileName,
  85. OUT PbkCacheNode** ppNode,
  86. OUT DWORD* pdwIndex);
  87. };
  88. static PbkCache* g_pPbkCache = NULL;
  89. //+----------------------------------------------------------------------------
  90. //
  91. // Synopsis: Instantiates the phonebook cache
  92. //
  93. // Created: pmay
  94. //
  95. //-----------------------------------------------------------------------------
  96. PbkCacheNode::PbkCacheNode() : m_pszFileName(NULL)
  97. {
  98. ZeroMemory(&m_pbFile, sizeof(m_pbFile));
  99. ZeroMemory(&m_ftRead, sizeof(m_ftRead));
  100. m_pbFile.hrasfile = -1;
  101. }
  102. //+----------------------------------------------------------------------------
  103. //
  104. // Synopsis: Instantiates the phonebook cache
  105. //
  106. // Created: pmay
  107. //
  108. //-----------------------------------------------------------------------------
  109. PbkCacheNode::~PbkCacheNode()
  110. {
  111. Close();
  112. SetFileName(NULL);
  113. }
  114. //+----------------------------------------------------------------------------
  115. //
  116. // Synopsis: Closes the file referred to by this cache node
  117. //
  118. // Created: pmay
  119. //
  120. //-----------------------------------------------------------------------------
  121. VOID
  122. PbkCacheNode::Close()
  123. {
  124. if (m_pbFile.hrasfile != -1)
  125. {
  126. ClosePhonebookFile(&m_pbFile);
  127. }
  128. ZeroMemory(&m_pbFile, sizeof(m_pbFile));
  129. m_pbFile.hrasfile = -1;
  130. ZeroMemory(&m_ftRead, sizeof(m_ftRead));
  131. }
  132. //+----------------------------------------------------------------------------
  133. //
  134. // Synopsis: Sets the file name for this node
  135. //
  136. // Created: pmay
  137. //
  138. //-----------------------------------------------------------------------------
  139. DWORD
  140. PbkCacheNode::SetFileName(
  141. IN WCHAR* pszFileName)
  142. {
  143. Free0(m_pszFileName);
  144. m_pszFileName = NULL;
  145. // Copy the file name
  146. //
  147. if (pszFileName)
  148. {
  149. m_pszFileName = StrDup( pszFileName );
  150. if (m_pszFileName == NULL)
  151. {
  152. return ERROR_NOT_ENOUGH_MEMORY;
  153. }
  154. }
  155. return NO_ERROR;
  156. }
  157. //+----------------------------------------------------------------------------
  158. //
  159. // Synopsis: Instantiates the phonebook cache
  160. //
  161. // Created: pmay
  162. //
  163. //-----------------------------------------------------------------------------
  164. DWORD
  165. PbkCacheNode::GetLastWriteTime(
  166. OUT FILETIME* pTime)
  167. {
  168. BOOL fOk;
  169. HANDLE hFile = INVALID_HANDLE_VALUE;
  170. DWORD dwErr = NO_ERROR;
  171. //For whistler bug 537369 gangz
  172. //We cannot leave the handle open for ever, have to close it after using it.
  173. // so delete the m_hFile data member
  174. // Rather, re-open it and get its information by handle
  175. if (m_pszFileName == NULL || TEXT('\0') == m_pszFileName[0] )
  176. {
  177. return ERROR_CAN_NOT_COMPLETE;
  178. }
  179. if( NULL == pTime )
  180. {
  181. return ERROR_INVALID_PARAMETER;
  182. }
  183. dwErr = GetFileLastWriteTime( m_pszFileName, pTime );
  184. return dwErr;
  185. }
  186. //+----------------------------------------------------------------------------
  187. //
  188. // Synopsis: Instantiates the phonebook cache
  189. //
  190. // Created: pmay
  191. //
  192. //-----------------------------------------------------------------------------
  193. DWORD
  194. PbkCacheNode::Reload()
  195. {
  196. DWORD dwErr = NO_ERROR;
  197. if (m_pszFileName == NULL)
  198. {
  199. return ERROR_CAN_NOT_COMPLETE;
  200. }
  201. do
  202. {
  203. Close();
  204. // Load the RasFile
  205. //
  206. dwErr = ReadPhonebookFileEx(
  207. m_pszFileName,
  208. NULL,
  209. NULL,
  210. RPBF_NoCreate,
  211. &m_pbFile,
  212. &m_ftRead);
  213. if (dwErr != NO_ERROR)
  214. {
  215. break;
  216. }
  217. } while (FALSE);
  218. // Cleanup
  219. //
  220. {
  221. if (dwErr != NO_ERROR)
  222. {
  223. Close();
  224. }
  225. }
  226. return dwErr;
  227. }
  228. //+----------------------------------------------------------------------------
  229. //
  230. // Synopsis: Instantiates the phonebook cache
  231. //
  232. // Created: pmay
  233. //
  234. //-----------------------------------------------------------------------------
  235. PbkCache::PbkCache()
  236. {
  237. ZeroMemory(m_Files, sizeof(m_Files));
  238. }
  239. //+----------------------------------------------------------------------------
  240. //
  241. // Synopsis: Destroys the phonebook cache
  242. //
  243. // Created: pmay
  244. //
  245. //-----------------------------------------------------------------------------
  246. PbkCache::~PbkCache()
  247. {
  248. UINT i;
  249. DeleteCriticalSection(&m_csLock);
  250. for (i = 0; i < PBK_CACHE_MAX_RASFILES; i++)
  251. {
  252. if (m_Files[i])
  253. {
  254. delete m_Files[i];
  255. m_Files[i] = NULL;
  256. }
  257. }
  258. }
  259. //+----------------------------------------------------------------------------
  260. //
  261. // Synopsis: Initializes the phonebook cache
  262. //
  263. // Created: pmay
  264. //
  265. //-----------------------------------------------------------------------------
  266. DWORD
  267. PbkCache::Initialize()
  268. {
  269. DWORD dwErr = NO_ERROR;
  270. __try
  271. {
  272. InitializeCriticalSection(&m_csLock);
  273. }
  274. __except (EXCEPTION_EXECUTE_HANDLER)
  275. {
  276. dwErr = HRESULT_FROM_WIN32(GetExceptionCode());
  277. }
  278. return dwErr;
  279. }
  280. //+----------------------------------------------------------------------------
  281. //
  282. // Synopsis: Initializes the phonebook cache
  283. //
  284. // Created: pmay
  285. //
  286. //-----------------------------------------------------------------------------
  287. DWORD
  288. PbkCache::GetEntry(
  289. IN WCHAR* pszPhonebook,
  290. IN WCHAR* pszEntry,
  291. OUT DTLNODE** ppEntryNode)
  292. {
  293. DWORD dwErr, dwRet, dwSlot = PBK_CACHE_INVALID_SLOT;
  294. PbkCacheNode* pCacheNode = NULL;
  295. DTLNODE* pEntryNode, *pCopyNode = NULL;
  296. PBENTRY* pEntry;
  297. FILETIME ftWrite, ftRead;
  298. BOOL fFound = FALSE;
  299. TRACE2("PbkCache::GetEntry %S %S", pszPhonebook, pszEntry);
  300. Lock();
  301. do
  302. {
  303. FindFile(pszPhonebook, &pCacheNode, &dwSlot);
  304. // The file is not in the cache. Insert it.
  305. //
  306. if (pCacheNode == NULL)
  307. {
  308. TRACE1("Inserting new pbk cache node %d", dwSlot);
  309. dwErr = InsertNewNode(pszPhonebook, dwSlot, &pCacheNode);
  310. if (dwErr != NO_ERROR)
  311. {
  312. break;
  313. }
  314. }
  315. // The file is in the cache. Reload it if needed
  316. //
  317. else
  318. {
  319. ftRead = pCacheNode->GetReadTime();
  320. dwErr = pCacheNode->GetLastWriteTime(&ftWrite);
  321. if (dwErr != NO_ERROR)
  322. {
  323. break;
  324. }
  325. if (CompareFileTime(&ftRead, &ftWrite) < 0)
  326. {
  327. TRACE2("Reloading pbk cache %d (%S)", dwSlot, pszPhonebook);
  328. dwErr = pCacheNode->Reload();
  329. if (dwErr != NO_ERROR)
  330. {
  331. break;
  332. }
  333. }
  334. }
  335. // Find the entry in question
  336. //
  337. dwErr = ERROR_CANNOT_FIND_PHONEBOOK_ENTRY;
  338. for (pEntryNode = DtlGetFirstNode( pCacheNode->GetEntryList() );
  339. pEntryNode;
  340. pEntryNode = DtlGetNextNode( pEntryNode ))
  341. {
  342. pEntry = (PBENTRY*) DtlGetData(pEntryNode);
  343. if (lstrcmpi(pEntry->pszEntryName, pszEntry) == 0)
  344. {
  345. fFound = TRUE;
  346. dwErr = NO_ERROR;
  347. pCopyNode = DuplicateEntryNode(pEntryNode);
  348. if (pCopyNode == NULL)
  349. {
  350. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  351. }
  352. break;
  353. }
  354. }
  355. } while (FALSE);
  356. Unlock();
  357. // Prepare the return value
  358. //
  359. if (pCopyNode)
  360. {
  361. *ppEntryNode = pCopyNode;
  362. dwRet = NO_ERROR;
  363. }
  364. else if (dwErr == ERROR_CANNOT_FIND_PHONEBOOK_ENTRY)
  365. {
  366. dwRet = dwErr;
  367. }
  368. else
  369. {
  370. dwRet = ERROR_CANNOT_OPEN_PHONEBOOK;
  371. }
  372. TRACE3(
  373. "PbkCache::GetEntry returning 0x%x 0x%x fFound=%d",
  374. dwErr,
  375. dwRet,
  376. fFound);
  377. return dwRet;
  378. }
  379. //+----------------------------------------------------------------------------
  380. //
  381. // Synopsis: Searches for a phonebook file in the cache. If the file is not
  382. // in the cache, then the index in which to insert that file is
  383. // returned.
  384. //
  385. // Return values:
  386. // If file is found, *ppNode has node and *pdwIndex has the index
  387. // If file not found, *ppNode == NULL. *pdwIndex has insert point
  388. // If cache is full and file not found:
  389. // *ppNode == NULL,
  390. // *pdwIndex == PBK_CACHE_INVALID_SLOT
  391. // Created: pmay
  392. //
  393. //-----------------------------------------------------------------------------
  394. VOID
  395. PbkCache::FindFile(
  396. IN WCHAR* pszFileName,
  397. OUT PbkCacheNode** ppNode,
  398. OUT DWORD* pdwIndex)
  399. {
  400. DWORD i;
  401. *pdwIndex = PBK_CACHE_INVALID_SLOT;
  402. for (i = 0; i < PBK_CACHE_MAX_RASFILES; i++)
  403. {
  404. if (m_Files[i])
  405. {
  406. if (lstrcmpi(pszFileName, m_Files[i]->GetPath()) == 0)
  407. {
  408. *ppNode = m_Files[i];
  409. *pdwIndex = i;
  410. break;
  411. }
  412. }
  413. else
  414. {
  415. if (*pdwIndex == PBK_CACHE_INVALID_SLOT)
  416. {
  417. *pdwIndex = i;
  418. }
  419. }
  420. }
  421. }
  422. //+----------------------------------------------------------------------------
  423. //
  424. // Synopsis: Inserts a node in the give slot in the cache
  425. //
  426. // Created: pmay
  427. //
  428. //-----------------------------------------------------------------------------
  429. DWORD
  430. PbkCache::InsertNewNode(
  431. IN PWCHAR pszPhonebook,
  432. IN DWORD dwSlot,
  433. OUT PbkCacheNode** ppNode)
  434. {
  435. PbkCacheNode* pCacheNode = NULL;
  436. DWORD dwErr = NO_ERROR;
  437. do
  438. {
  439. if (dwSlot == PBK_CACHE_INVALID_SLOT)
  440. {
  441. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  442. break;
  443. }
  444. pCacheNode = new PbkCacheNode();
  445. if (pCacheNode == NULL)
  446. {
  447. dwErr = ERROR_NOT_ENOUGH_MEMORY;
  448. break;
  449. }
  450. dwErr = pCacheNode->SetFileName(pszPhonebook);
  451. if (dwErr != NO_ERROR)
  452. {
  453. break;
  454. }
  455. dwErr = pCacheNode->Reload();
  456. if (dwErr != NO_ERROR)
  457. {
  458. break;
  459. }
  460. m_Files[dwSlot] = pCacheNode;
  461. *ppNode = pCacheNode;
  462. } while (FALSE);
  463. // Cleanup
  464. //
  465. {
  466. if (dwErr != NO_ERROR)
  467. {
  468. if (pCacheNode)
  469. {
  470. delete pCacheNode;
  471. }
  472. }
  473. }
  474. return dwErr;
  475. }
  476. //+----------------------------------------------------------------------------
  477. //
  478. // Synopsis: check if the phonebook cache is initialized
  479. //
  480. // Created: gangz
  481. //
  482. //-----------------------------------------------------------------------------
  483. BOOL
  484. IsPbkCacheInit()
  485. {
  486. return g_pPbkCache ? TRUE : FALSE;
  487. }
  488. //+----------------------------------------------------------------------------
  489. //
  490. // Synopsis: Initializes the phonebook cache
  491. //
  492. // Created: pmay
  493. //
  494. //-----------------------------------------------------------------------------
  495. DWORD
  496. PbkCacheInit()
  497. {
  498. DWORD dwErr;
  499. ASSERT(g_pPbkCache == NULL);
  500. g_pPbkCache = new PbkCache;
  501. if (g_pPbkCache == NULL)
  502. {
  503. return ERROR_NOT_ENOUGH_MEMORY;
  504. }
  505. dwErr = g_pPbkCache->Initialize();
  506. if (dwErr != NO_ERROR)
  507. {
  508. delete g_pPbkCache;
  509. g_pPbkCache = NULL;
  510. }
  511. return dwErr;
  512. }
  513. //+----------------------------------------------------------------------------
  514. //
  515. // Synopsis: Cleans up the phonebook cache
  516. //
  517. // Created: pmay
  518. //
  519. //-----------------------------------------------------------------------------
  520. VOID
  521. PbkCacheCleanup()
  522. {
  523. PbkCache* pCache = g_pPbkCache;
  524. g_pPbkCache = NULL;
  525. if (pCache)
  526. {
  527. delete pCache;
  528. }
  529. }
  530. //+----------------------------------------------------------------------------
  531. //
  532. // Synopsis: Gets an entry from the cache
  533. //
  534. // Created: pmay
  535. //
  536. //-----------------------------------------------------------------------------
  537. DWORD
  538. PbkCacheGetEntry(
  539. IN WCHAR* pszPhonebook,
  540. IN WCHAR* pszEntry,
  541. OUT DTLNODE** ppEntryNode)
  542. {
  543. if (g_pPbkCache)
  544. {
  545. return g_pPbkCache->GetEntry(pszPhonebook, pszEntry, ppEntryNode);
  546. }
  547. return ERROR_CAN_NOT_COMPLETE;
  548. }
  549. #endif //endof #ifdef _PBK_CACHE_