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.

675 lines
17 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1995 - 1995.
  5. //
  6. // File: cache.cxx
  7. //
  8. // Contents: Functions to manage a cache of shares
  9. //
  10. // History: 11-Apr-95 BruceFo Created
  11. // 21-Aug-95 BruceFo Created CShareCache class to clean up
  12. // resource usage of resources protected
  13. // by critical section.
  14. //
  15. //----------------------------------------------------------------------------
  16. #include "headers.hxx"
  17. #pragma hdrstop
  18. #include "critsec.hxx"
  19. #include "cache.hxx"
  20. #include "dllmain.hxx"
  21. #include "shrinfo.hxx"
  22. #include "strhash.hxx"
  23. #include "util.hxx"
  24. //////////////////////////////////////////////////////////////////////////////
  25. #if DBG == 1
  26. VOID
  27. DumpNetEnum(
  28. IN LPVOID pBufShares,
  29. IN ULONG entriesRead
  30. );
  31. #endif // DBG == 1
  32. //////////////////////////////////////////////////////////////////////////////
  33. CShareCache g_ShareCache; // the main share cache
  34. //////////////////////////////////////////////////////////////////////////////
  35. //+-------------------------------------------------------------------------
  36. //
  37. // Member: CShareCache::CShareCache
  38. //
  39. // Synopsis: Constructor.
  40. //
  41. // History: 21-Aug-95 BruceFo Created
  42. //
  43. //--------------------------------------------------------------------------
  44. CShareCache::CShareCache(
  45. VOID
  46. )
  47. :
  48. m_cShares(0),
  49. m_pBufShares(NULL),
  50. m_pHash(NULL)
  51. {
  52. InitializeCriticalSection(&m_csBuf);
  53. }
  54. //+-------------------------------------------------------------------------
  55. //
  56. // Member: CShareCache::~CShareCache
  57. //
  58. // Synopsis: Destructor
  59. //
  60. // History: 21-Aug-95 BruceFo Created
  61. //
  62. //--------------------------------------------------------------------------
  63. CShareCache::~CShareCache()
  64. {
  65. Delete();
  66. DeleteCriticalSection(&m_csBuf);
  67. }
  68. //+-------------------------------------------------------------------------
  69. //
  70. // Member: CShareCache::Delete
  71. //
  72. // Synopsis: Gets rid of cached memory.
  73. //
  74. // History: 21-Aug-95 BruceFo Created
  75. //
  76. //--------------------------------------------------------------------------
  77. VOID
  78. CShareCache::Delete(
  79. VOID
  80. )
  81. {
  82. CTakeCriticalSection t(&m_csBuf);
  83. if (NULL != m_pBufShares)
  84. {
  85. NetApiBufferFree(m_pBufShares);
  86. }
  87. m_pBufShares = NULL;
  88. delete m_pHash;
  89. m_pHash = NULL;
  90. m_cShares = 0;
  91. }
  92. //+-------------------------------------------------------------------------
  93. //
  94. // Member: CShareCache::IsPathShared
  95. //
  96. // Synopsis: See ::IsPathShared.
  97. //
  98. // History: 21-Aug-95 BruceFo Created
  99. //
  100. //--------------------------------------------------------------------------
  101. BOOL
  102. CShareCache::IsPathShared(
  103. LPCTSTR lpPath,
  104. BOOL fRefresh
  105. )
  106. {
  107. BOOL bOldSharingEnabled = g_fSharingEnabled;
  108. BOOL bRet = FALSE;
  109. {
  110. // scope the critical section taking
  111. CTakeCriticalSection t(&m_csBuf);
  112. // For plug and play: if the server service starts
  113. // or stops, we get a refresh call. If sharing is not currently
  114. // enabled but a refresh is request, see if sharing has just become
  115. // available.
  116. if (fRefresh)
  117. {
  118. appDebugOut((DEB_TRACE, "Forced cache refresh!\n"));
  119. RefreshNoCritSec();
  120. }
  121. if (CacheOK())
  122. {
  123. appAssert(NULL != m_pHash);
  124. bRet = m_pHash->IsMember(lpPath);
  125. }
  126. else
  127. {
  128. // the server doesn't seem to be running...
  129. bRet = FALSE;
  130. }
  131. }
  132. if (bOldSharingEnabled != g_fSharingEnabled)
  133. {
  134. // The server either came up or went down, and we refreshed based on
  135. // that fact. Force the shell/explorer to redraw *all* views.
  136. appDebugOut((DEB_TRACE, "Forcing the shell to redraw *all* views!\n"));
  137. SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
  138. }
  139. return bRet;
  140. }
  141. //+-------------------------------------------------------------------------
  142. //
  143. // Member: CShareCache::Refresh
  144. //
  145. // Synopsis: Refreshes the cache of shares
  146. //
  147. // History: 21-Aug-95 BruceFo Created
  148. //
  149. // Note: Sets g_fSharingEnabled
  150. //
  151. //--------------------------------------------------------------------------
  152. VOID
  153. CShareCache::Refresh(
  154. VOID
  155. )
  156. {
  157. CTakeCriticalSection t(&m_csBuf);
  158. RefreshNoCritSec();
  159. }
  160. // in:
  161. // pShare share to inspect
  162. // bIncludeHidden -> admin shares (X$, ADMIN$) will not be skipped
  163. // otherwise they are included
  164. BOOL ShouldSkipShare(SHARE_INFO_502* pShare, BOOL bIncludeHidden)
  165. {
  166. // needs to have an associated path
  167. // needs to be STYPE_DISK (to skip IPC$)
  168. // STYPE_SPECIAL indicates hidden admin share
  169. return (pShare->shi502_path == NULL) ||
  170. (pShare->shi502_path[0] == 0) ||
  171. ((pShare->shi502_type & ~STYPE_SPECIAL) != STYPE_DISKTREE) ||
  172. (bIncludeHidden ? FALSE : (pShare->shi502_type & STYPE_SPECIAL));
  173. }
  174. //+-------------------------------------------------------------------------
  175. //
  176. // Member: CShareCache::RefreshNoCritSec
  177. //
  178. // Synopsis: Refreshes the cache of shares: the critical section must
  179. // already taken!
  180. //
  181. // History: 18-Aug-95 BruceFo Created
  182. //
  183. // Note: Sets g_fSharingEnabled
  184. //
  185. //--------------------------------------------------------------------------
  186. VOID
  187. CShareCache::RefreshNoCritSec(
  188. VOID
  189. )
  190. {
  191. Delete();
  192. DWORD entriesRead, totalEntries;
  193. DWORD err = ::NetShareEnum(
  194. NULL, // local computer
  195. 502,
  196. &m_pBufShares,
  197. 0xffffffff, // no buffer limit; get them all!
  198. &entriesRead,
  199. &totalEntries,
  200. NULL); // no resume handle 'cause we're getting all
  201. if (err != NERR_Success)
  202. {
  203. appDebugOut((DEB_ERROR,
  204. "Error enumerating shares: 0x%08lx\n",
  205. err));
  206. m_pBufShares = NULL; // just in case NetShareEnum munged it
  207. Delete();
  208. }
  209. else
  210. {
  211. appAssert(entriesRead == totalEntries);
  212. m_cShares = entriesRead;
  213. }
  214. if (m_cShares > 0)
  215. {
  216. //
  217. // Now, create a hash table and put all the shares into it (strings are
  218. // cached; don't copy any data)
  219. //
  220. m_pHash = new CStrHashTable(m_cShares * 2 - 1);
  221. if ((NULL == m_pHash) || FAILED(m_pHash->QueryError()))
  222. {
  223. // out of memory; delete everything
  224. Delete();
  225. }
  226. else
  227. {
  228. SHARE_INFO_502* pShareBase = (SHARE_INFO_502 *)m_pBufShares;
  229. for (UINT iShare = 0; iShare < m_cShares; iShare++)
  230. {
  231. SHARE_INFO_502* pShare = &pShareBase[iShare];
  232. if (ShouldSkipShare(pShare, FALSE)) // don't include hidden
  233. continue;
  234. HRESULT hr = m_pHash->Insert(pShare->shi502_path);
  235. if (FAILED(hr))
  236. {
  237. // out of memory; delete everything
  238. Delete();
  239. break;
  240. }
  241. }
  242. }
  243. #if DBG == 1
  244. if (NULL != m_pHash)
  245. {
  246. // if everything hasn't been deleted because of a memory problem...
  247. m_pHash->Print();
  248. }
  249. #endif // DBG == 1
  250. }
  251. g_fSharingEnabled = CacheOK();
  252. }
  253. //+-------------------------------------------------------------------------
  254. //
  255. // Member: CShareCache::IsShareNameUsed
  256. //
  257. // Synopsis: Returns TRUE if the share name in question is already used
  258. //
  259. // History: 4-Apr-95 BruceFo Created
  260. //
  261. //--------------------------------------------------------------------------
  262. BOOL
  263. CShareCache::IsShareNameUsed(
  264. IN PWSTR pszShareName
  265. )
  266. {
  267. CTakeCriticalSection t(&m_csBuf);
  268. if (!CacheOK())
  269. {
  270. return FALSE;
  271. }
  272. SHARE_INFO_502* pShareBase = (SHARE_INFO_502 *)m_pBufShares;
  273. for (UINT iShare = 0; iShare < m_cShares; iShare++)
  274. {
  275. SHARE_INFO_502* pShare = &pShareBase[iShare];
  276. if (0 == _wcsicmp(pszShareName, pShare->shi502_netname))
  277. {
  278. return TRUE;
  279. }
  280. }
  281. return FALSE;
  282. }
  283. //+-------------------------------------------------------------------------
  284. //
  285. // Member: CShareCache::IsExistingShare
  286. //
  287. // Synopsis: Finds out if a share name is already in use with a different
  288. // path.
  289. //
  290. // Arguments: [pszShareName] - name of share being replaced
  291. // [pszPath] - path to compare against
  292. // [pszOldPath] - If not null, filled with path of the share,
  293. // if found
  294. //
  295. // Returns: Returns TRUE if found and the paths are different,
  296. // FALSE otherwise
  297. //
  298. // History: 4-May-95 BruceFo Stolen
  299. //
  300. //--------------------------------------------------------------------------
  301. BOOL
  302. CShareCache::IsExistingShare(
  303. IN PCWSTR pszShareName,
  304. IN PCWSTR pszPath,
  305. OUT PWSTR pszOldPath
  306. )
  307. {
  308. appAssert(NULL != pszShareName);
  309. CTakeCriticalSection t(&m_csBuf);
  310. if (!CacheOK())
  311. {
  312. return FALSE;
  313. }
  314. SHARE_INFO_502* pShareBase = (SHARE_INFO_502 *)m_pBufShares;
  315. for (UINT iShare = 0; iShare < m_cShares; iShare++)
  316. {
  317. SHARE_INFO_502* pShare = &pShareBase[iShare];
  318. if (0 == _wcsicmp(pszShareName, pShare->shi502_netname))
  319. {
  320. if (pszOldPath != NULL)
  321. {
  322. wcscpy(pszOldPath, pShare->shi502_path);
  323. }
  324. return TRUE;
  325. }
  326. }
  327. return FALSE;
  328. }
  329. //+-------------------------------------------------------------------------
  330. //
  331. // Member: CShareCache::ConstructList
  332. //
  333. // Synopsis: Construct a list of shares for a particular path
  334. //
  335. // Arguments:
  336. //
  337. // Returns: hresult
  338. //
  339. // History: 21-Aug-95 BruceFo Created
  340. //
  341. //--------------------------------------------------------------------------
  342. HRESULT
  343. CShareCache::ConstructList(
  344. IN PCWSTR pszPath,
  345. IN OUT CShareInfo* pShareList,
  346. OUT ULONG* pcShares
  347. )
  348. {
  349. CTakeCriticalSection t(&m_csBuf);
  350. SHARE_INFO_502* pShareBase = (SHARE_INFO_502 *)m_pBufShares;
  351. HRESULT hr;
  352. ULONG cShares = 0;
  353. for (UINT iShare = 0; iShare < m_cShares; iShare++)
  354. {
  355. SHARE_INFO_502* pShare = &pShareBase[iShare];
  356. if (0 == _wcsicmp(pszPath, pShare->shi502_path))
  357. {
  358. if (ShouldSkipShare(pShare, TRUE)) // include hidden
  359. continue;
  360. //
  361. // We found one!
  362. //
  363. appDebugOut((DEB_ITRACE,
  364. "ConstructList: adding %ws\n",
  365. pShare->shi502_netname));
  366. CShareInfo* pNewInfo = new CShareInfo();
  367. if (NULL == pNewInfo)
  368. {
  369. return E_OUTOFMEMORY;
  370. }
  371. hr = pNewInfo->InitInstance();
  372. if (FAILED(hr))
  373. {
  374. delete pNewInfo;
  375. return hr;
  376. }
  377. // We can't point into the data protected by a critical section,
  378. // so we must copy it.
  379. hr = pNewInfo->Copy(pShare);
  380. if (FAILED(hr))
  381. {
  382. delete pNewInfo;
  383. return hr;
  384. }
  385. NET_API_STATUS ret = pNewInfo->ReadCacheFlags ();
  386. if ( NERR_Success != ret )
  387. {
  388. delete pNewInfo;
  389. return HRESULT_FROM_WIN32 (ret);
  390. }
  391. pNewInfo->InsertBefore(pShareList); // add to end of list
  392. ++cShares;
  393. }
  394. }
  395. *pcShares = cShares;
  396. return S_OK;
  397. }
  398. //+-------------------------------------------------------------------------
  399. //
  400. // Member: CShareCache::ConstructParentWarnList
  401. //
  402. // Synopsis: Construct a new list of shares that are children or descendants
  403. // of the path passed in.
  404. //
  405. // Arguments: [pszPath] - the prefix path to check for
  406. // [ppShareList] - new share list, if success. Caller must delete
  407. // it using 'delete' on each element. This list is
  408. // doubly-linked with a dummy head node. NOTE: As an
  409. // optimization, this is set to NULL if there is no share.
  410. // This avoids allocating and deleting memory unless there
  411. // is something to warn the user about.
  412. //
  413. // Returns: hresult
  414. //
  415. // History: 21-Aug-95 BruceFo Created
  416. //
  417. //--------------------------------------------------------------------------
  418. HRESULT
  419. CShareCache::ConstructParentWarnList(
  420. IN PCWSTR pszPath,
  421. OUT CShareInfo** ppShareList
  422. )
  423. {
  424. CTakeCriticalSection t(&m_csBuf);
  425. HRESULT hr;
  426. CShareInfo* pShareList = NULL;
  427. SHARE_INFO_502* pShareBase = (SHARE_INFO_502 *)m_pBufShares;
  428. INT cchPath = wcslen(pszPath);
  429. for (UINT iShare = 0; iShare < m_cShares; iShare++)
  430. {
  431. SHARE_INFO_502* pShare = &pShareBase[iShare];
  432. PWSTR pszSharePath = pShare->shi502_path;
  433. INT cchSharePath = wcslen(pszSharePath);
  434. if (cchSharePath >= cchPath)
  435. {
  436. // WARNING - the following won't work with LFN/shortname differences
  437. // PERF: we're doing a prefix match of the current directory
  438. // name on the set of share names. This could be expensive with
  439. // a linear search!
  440. if (0 == _wcsnicmp(pszSharePath, pszPath, cchPath)
  441. && ( *(pszSharePath + cchPath) == TEXT('\\')
  442. || *(pszSharePath + cchPath) == TEXT('\0')
  443. )
  444. )
  445. {
  446. appDebugOut((DEB_TRACE,
  447. "ConstructParentWarnList, share %ws, file %ws. Found a prefix!\n",
  448. pszSharePath, pszPath));
  449. if (NULL == pShareList)
  450. {
  451. // do the lazy dummy head node creation if this is the
  452. // first prefix match
  453. pShareList = new CShareInfo(); // dummy head node
  454. if (NULL == pShareList)
  455. {
  456. return E_OUTOFMEMORY;
  457. }
  458. }
  459. CShareInfo* pNewInfo = new CShareInfo();
  460. if (NULL == pNewInfo)
  461. {
  462. hr = E_OUTOFMEMORY;
  463. }
  464. else
  465. {
  466. hr = pNewInfo->InitInstance();
  467. if (SUCCEEDED(hr))
  468. {
  469. // We can't point into the data protected by a
  470. // critical section, so we must copy it.
  471. hr = pNewInfo->Copy(pShare);
  472. if ( SUCCEEDED (hr) )
  473. {
  474. NET_API_STATUS ret = pNewInfo->ReadCacheFlags ();
  475. if ( NERR_Success != ret )
  476. {
  477. delete pNewInfo;
  478. return HRESULT_FROM_WIN32 (ret);
  479. }
  480. }
  481. }
  482. }
  483. if (FAILED(hr))
  484. {
  485. delete pNewInfo;
  486. DeleteShareInfoList(pShareList, TRUE);
  487. return hr;
  488. }
  489. pNewInfo->InsertBefore(pShareList); // add to end of list
  490. }
  491. }
  492. }
  493. *ppShareList = pShareList;
  494. return S_OK;
  495. }
  496. //+-------------------------------------------------------------------------
  497. //
  498. // Member: CShareCache::CacheOK
  499. //
  500. // Synopsis: Returns TRUE if the cache contains valid data.
  501. //
  502. // History: 24-Sep-95 BruceFo Created
  503. //
  504. // Note: The critical section must be held when calling this function
  505. //
  506. //--------------------------------------------------------------------------
  507. BOOL
  508. CShareCache::CacheOK(
  509. VOID
  510. )
  511. {
  512. // either both are valid or both are invalid
  513. appAssert(
  514. ((NULL != m_pHash) && (NULL != m_pBufShares)) ||
  515. ((NULL == m_pHash) && (NULL == m_pBufShares))
  516. );
  517. return (NULL != m_pHash);
  518. }
  519. #if DBG == 1
  520. //+-------------------------------------------------------------------------
  521. //
  522. // Function: DumpNetEnum
  523. //
  524. // Synopsis: Dumps an array of SHARE_INFO_502 structures.
  525. //
  526. // History: 4-Apr-95 BruceFo Created
  527. //
  528. //--------------------------------------------------------------------------
  529. VOID
  530. DumpNetEnum(
  531. IN LPVOID pBufShares,
  532. IN ULONG entriesRead
  533. )
  534. {
  535. SHARE_INFO_502* pBase = (SHARE_INFO_502*) pBufShares;
  536. appDebugOut((DEB_TRACE,
  537. "DumpNetEnum: %d entries\n",
  538. entriesRead));
  539. for (ULONG i = 0; i < entriesRead; i++)
  540. {
  541. SHARE_INFO_502* p = &(pBase[i]);
  542. appDebugOut((DEB_TRACE | DEB_NOCOMPNAME,
  543. "\t Share name: %ws\n"
  544. "\t Type: %d (0x%08lx)\n"
  545. "\t Comment: %ws\n"
  546. "\tPermissions: %d (0x%08lx)\n"
  547. "\t Max uses: %d\n"
  548. "\t Path: %ws\n"
  549. "\t Password: %ws\n"
  550. "\t Reserved: %d\n"
  551. "\t Security? %ws\n"
  552. "\n"
  553. ,
  554. p->shi502_netname,
  555. p->shi502_type, p->shi502_type,
  556. p->shi502_remark,
  557. p->shi502_permissions, p->shi502_permissions,
  558. p->shi502_max_uses,
  559. p->shi502_path,
  560. (NULL == p->shi502_passwd) ? L"none" : p->shi502_passwd,
  561. p->shi502_reserved,
  562. (NULL == p->shi502_security_descriptor) ? L"No" : L"Yes"
  563. ));
  564. }
  565. }
  566. #endif // DBG == 1