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.

714 lines
20 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. // NTRAID#NTBUG9-585661-2002/03/19 JonN redundant call to Delete()
  208. Delete();
  209. }
  210. else
  211. {
  212. // NTRAID#NTBUG9-585715-2002/03/19 JonN It is entirely possible to not read
  213. // read all of the shares if there are many of them. Ideally we should
  214. // keep reading (is resume handle supported?), but for now the assertion
  215. // can simply be removed.
  216. appAssert(entriesRead == totalEntries);
  217. m_cShares = entriesRead;
  218. }
  219. // ISSUE-2002/03/19-JonN We consider "no shares" to be the same as
  220. // "sharing disabled". Creating/deleting the first share will
  221. // generate SHCNE_ASSOCCHANGED. The problem is unlikely since
  222. // there is usually a $ share.
  223. if (m_cShares > 0)
  224. {
  225. //
  226. // Now, create a hash table and put all the shares into it (strings are
  227. // cached; don't copy any data)
  228. //
  229. m_pHash = new CStrHashTable(m_cShares * 2 - 1);
  230. if ((NULL == m_pHash) || FAILED(m_pHash->QueryError()))
  231. {
  232. // out of memory; delete everything
  233. Delete();
  234. }
  235. else
  236. {
  237. SHARE_INFO_502* pShareBase = (SHARE_INFO_502 *)m_pBufShares;
  238. for (UINT iShare = 0; iShare < m_cShares; iShare++)
  239. {
  240. SHARE_INFO_502* pShare = &pShareBase[iShare];
  241. if (ShouldSkipShare(pShare, FALSE)) // don't include hidden
  242. continue;
  243. HRESULT hr = m_pHash->Insert(pShare->shi502_path);
  244. if (FAILED(hr))
  245. {
  246. // out of memory; delete everything
  247. Delete();
  248. break;
  249. }
  250. }
  251. }
  252. #if DBG == 1
  253. if (NULL != m_pHash)
  254. {
  255. // if everything hasn't been deleted because of a memory problem...
  256. m_pHash->Print();
  257. }
  258. #endif // DBG == 1
  259. }
  260. g_fSharingEnabled = CacheOK();
  261. }
  262. //+-------------------------------------------------------------------------
  263. //
  264. // Member: CShareCache::IsShareNameUsed
  265. //
  266. // Synopsis: Returns TRUE if the share name in question is already used
  267. //
  268. // History: 4-Apr-95 BruceFo Created
  269. //
  270. //--------------------------------------------------------------------------
  271. BOOL
  272. CShareCache::IsShareNameUsed(
  273. IN PWSTR pszShareName
  274. )
  275. {
  276. CTakeCriticalSection t(&m_csBuf);
  277. if (!CacheOK())
  278. {
  279. return FALSE;
  280. }
  281. SHARE_INFO_502* pShareBase = (SHARE_INFO_502 *)m_pBufShares;
  282. for (UINT iShare = 0; iShare < m_cShares; iShare++)
  283. {
  284. SHARE_INFO_502* pShare = &pShareBase[iShare];
  285. // 585678-2002/03/19 JonN check for NULL
  286. if ( NULL != pShare->shi502_netname
  287. && 0 == _wcsicmp(pszShareName, pShare->shi502_netname))
  288. {
  289. return TRUE;
  290. }
  291. }
  292. return FALSE;
  293. }
  294. //+-------------------------------------------------------------------------
  295. //
  296. // Member: CShareCache::IsExistingShare
  297. //
  298. // Synopsis: Finds out if a share name is already in use with a different
  299. // path.
  300. //
  301. // Arguments: [pszShareName] - name of share being replaced
  302. // [pszPath] - path to compare against
  303. // [pszOldPath] - If not null, filled with path of the share,
  304. // if found
  305. //
  306. // Returns: Returns TRUE if found and the paths are different,
  307. // FALSE otherwise
  308. //
  309. // History: 4-May-95 BruceFo Stolen
  310. //
  311. // ISSUE-2002/04/12-JonN should combine this function with previous function
  312. //
  313. //--------------------------------------------------------------------------
  314. BOOL
  315. CShareCache::IsExistingShare(
  316. IN PCWSTR pszShareName,
  317. IN PCWSTR pszPath,
  318. OUT PWSTR pszOldPath,
  319. IN INT cchOldPathBuf // 585682-2002/04/12-JonN
  320. )
  321. {
  322. appAssert(NULL != pszShareName);
  323. CTakeCriticalSection t(&m_csBuf);
  324. if (!CacheOK())
  325. {
  326. return FALSE;
  327. }
  328. SHARE_INFO_502* pShareBase = (SHARE_INFO_502 *)m_pBufShares;
  329. for (UINT iShare = 0; iShare < m_cShares; iShare++)
  330. {
  331. SHARE_INFO_502* pShare = &pShareBase[iShare];
  332. if ( NULL != pShare->shi502_netname
  333. && 0 == _wcsicmp(pszShareName, pShare->shi502_netname))
  334. {
  335. if (pszOldPath != NULL)
  336. {
  337. // 585682-2002/03/19 JonN
  338. wcsncpy(pszOldPath, pShare->shi502_path, cchOldPathBuf);
  339. pszOldPath[cchOldPathBuf-1] = L'\0';
  340. }
  341. return TRUE;
  342. }
  343. }
  344. return FALSE;
  345. }
  346. //+-------------------------------------------------------------------------
  347. //
  348. // Member: CShareCache::ConstructList
  349. //
  350. // Synopsis: Construct a list of shares for a particular path
  351. //
  352. // Arguments:
  353. //
  354. // Returns: hresult
  355. //
  356. // History: 21-Aug-95 BruceFo Created
  357. //
  358. //--------------------------------------------------------------------------
  359. HRESULT
  360. CShareCache::ConstructList(
  361. IN PCWSTR pszPath,
  362. IN OUT CShareInfo* pShareList,
  363. OUT ULONG* pcShares
  364. )
  365. {
  366. CTakeCriticalSection t(&m_csBuf);
  367. SHARE_INFO_502* pShareBase = (SHARE_INFO_502 *)m_pBufShares;
  368. HRESULT hr;
  369. ULONG cShares = 0;
  370. for (UINT iShare = 0; iShare < m_cShares; iShare++)
  371. {
  372. SHARE_INFO_502* pShare = &pShareBase[iShare];
  373. // NTRAID#NTBUG9-585678-2002/03/19 JonN check for NULL
  374. if (0 == _wcsicmp(pszPath, pShare->shi502_path))
  375. {
  376. if (ShouldSkipShare(pShare, TRUE)) // include hidden
  377. continue;
  378. //
  379. // We found one!
  380. //
  381. appDebugOut((DEB_ITRACE,
  382. "ConstructList: adding %ws\n",
  383. pShare->shi502_netname));
  384. CShareInfo* pNewInfo = new CShareInfo();
  385. if (NULL == pNewInfo)
  386. {
  387. // ISSUE-2002/04/17-JonN We should delete the partial list
  388. return E_OUTOFMEMORY;
  389. }
  390. hr = pNewInfo->InitInstance();
  391. if (FAILED(hr))
  392. {
  393. // ISSUE-2002/04/17-JonN We should delete the partial list
  394. delete pNewInfo;
  395. return hr;
  396. }
  397. // We can't point into the data protected by a critical section,
  398. // so we must copy it.
  399. hr = pNewInfo->Copy(pShare);
  400. if (FAILED(hr))
  401. {
  402. // ISSUE-2002/04/17-JonN We should delete the partial list
  403. delete pNewInfo;
  404. return hr;
  405. }
  406. // 585723-2002/03/19 JonN
  407. // This could happen due to API failure. This used to cause us
  408. // to fail out of the loop. Instead, we now just fail through
  409. // and let the caching display be wrong.
  410. NET_API_STATUS ret = pNewInfo->ReadCacheFlags ();
  411. appAssert( NERR_Success == ret );
  412. /*
  413. if ( NERR_Success != ret )
  414. {
  415. // ISSUE-2002/04/17-JonN We should delete the partial list
  416. delete pNewInfo;
  417. return HRESULT_FROM_WIN32 (ret);
  418. }
  419. */
  420. pNewInfo->InsertBefore(pShareList); // add to end of list
  421. ++cShares;
  422. }
  423. }
  424. *pcShares = cShares;
  425. return S_OK;
  426. }
  427. //+-------------------------------------------------------------------------
  428. //
  429. // Member: CShareCache::ConstructParentWarnList
  430. //
  431. // Synopsis: Construct a new list of shares that are children or descendants
  432. // of the path passed in.
  433. //
  434. // Arguments: [pszPath] - the prefix path to check for
  435. // [ppShareList] - new share list, if success. Caller must delete
  436. // it using 'delete' on each element. This list is
  437. // doubly-linked with a dummy head node. NOTE: As an
  438. // optimization, this is set to NULL if there is no share.
  439. // This avoids allocating and deleting memory unless there
  440. // is something to warn the user about.
  441. //
  442. // Returns: hresult
  443. //
  444. // History: 21-Aug-95 BruceFo Created
  445. //
  446. //--------------------------------------------------------------------------
  447. HRESULT
  448. CShareCache::ConstructParentWarnList(
  449. IN PCWSTR pszPath,
  450. OUT CShareInfo** ppShareList
  451. )
  452. {
  453. CTakeCriticalSection t(&m_csBuf);
  454. HRESULT hr = S_OK;
  455. CShareInfo* pShareList = NULL;
  456. SHARE_INFO_502* pShareBase = (SHARE_INFO_502 *)m_pBufShares;
  457. INT cchPath = wcslen(pszPath);
  458. for (UINT iShare = 0; iShare < m_cShares; iShare++)
  459. {
  460. SHARE_INFO_502* pShare = &pShareBase[iShare];
  461. PWSTR pszSharePath = pShare->shi502_path;
  462. INT cchSharePath = wcslen(pszSharePath);
  463. if (cchSharePath >= cchPath)
  464. {
  465. // WARNING - the following won't work with LFN/shortname differences
  466. // PERF: we're doing a prefix match of the current directory
  467. // name on the set of share names. This could be expensive with
  468. // a linear search!
  469. if (0 == _wcsnicmp(pszSharePath, pszPath, cchPath)
  470. && ( *(pszSharePath + cchPath) == TEXT('\\')
  471. || *(pszSharePath + cchPath) == TEXT('\0')
  472. )
  473. )
  474. {
  475. appDebugOut((DEB_TRACE,
  476. "ConstructParentWarnList, share %ws, file %ws. Found a prefix!\n",
  477. pszSharePath, pszPath));
  478. if (NULL == pShareList)
  479. {
  480. // do the lazy dummy head node creation if this is the
  481. // first prefix match
  482. pShareList = new CShareInfo(); // dummy head node
  483. if (NULL == pShareList)
  484. {
  485. return E_OUTOFMEMORY;
  486. }
  487. }
  488. CShareInfo* pNewInfo = new CShareInfo();
  489. if (NULL == pNewInfo)
  490. {
  491. hr = E_OUTOFMEMORY;
  492. }
  493. else
  494. {
  495. hr = pNewInfo->InitInstance();
  496. if (SUCCEEDED(hr))
  497. {
  498. // We can't point into the data protected by a
  499. // critical section, so we must copy it.
  500. hr = pNewInfo->Copy(pShare);
  501. if ( SUCCEEDED (hr) )
  502. {
  503. // NTRAID#NTBUG9-603727-2002/04/15 JonN
  504. // There is no point in calling ReadCacheFlags,
  505. // since the caller won't use that field.
  506. // It matters because the API could fail
  507. // and cause ConstructParentWarnList to fail.
  508. // NTRAID#NTBUG9-589996-2002/04/15 JonN
  509. // fixed memory leak.
  510. NET_API_STATUS ret = pNewInfo->ReadCacheFlags ();
  511. appAssert( NERR_Success == ret );
  512. /*
  513. if ( NERR_Success != ret )
  514. {
  515. delete pNewInfo;
  516. return HRESULT_FROM_WIN32 (ret);
  517. }
  518. */
  519. }
  520. }
  521. }
  522. if (FAILED(hr))
  523. {
  524. delete pNewInfo;
  525. DeleteShareInfoList(pShareList, TRUE);
  526. return hr;
  527. }
  528. pNewInfo->InsertBefore(pShareList); // add to end of list
  529. }
  530. }
  531. }
  532. *ppShareList = pShareList;
  533. return S_OK;
  534. }
  535. //+-------------------------------------------------------------------------
  536. //
  537. // Member: CShareCache::CacheOK
  538. //
  539. // Synopsis: Returns TRUE if the cache contains valid data.
  540. //
  541. // History: 24-Sep-95 BruceFo Created
  542. //
  543. // Note: The critical section must be held when calling this function
  544. //
  545. //--------------------------------------------------------------------------
  546. BOOL
  547. CShareCache::CacheOK(
  548. VOID
  549. )
  550. {
  551. // either both are valid or both are invalid
  552. appAssert(
  553. ((NULL != m_pHash) && (NULL != m_pBufShares)) ||
  554. ((NULL == m_pHash) && (NULL == m_pBufShares))
  555. );
  556. return (NULL != m_pHash);
  557. }
  558. #if DBG == 1
  559. //+-------------------------------------------------------------------------
  560. //
  561. // Function: DumpNetEnum
  562. //
  563. // Synopsis: Dumps an array of SHARE_INFO_502 structures.
  564. //
  565. // History: 4-Apr-95 BruceFo Created
  566. //
  567. //--------------------------------------------------------------------------
  568. VOID
  569. DumpNetEnum(
  570. IN LPVOID pBufShares,
  571. IN ULONG entriesRead
  572. )
  573. {
  574. SHARE_INFO_502* pBase = (SHARE_INFO_502*) pBufShares;
  575. appDebugOut((DEB_TRACE,
  576. "DumpNetEnum: %d entries\n",
  577. entriesRead));
  578. for (ULONG i = 0; i < entriesRead; i++)
  579. {
  580. SHARE_INFO_502* p = &(pBase[i]);
  581. appDebugOut((DEB_TRACE | DEB_NOCOMPNAME,
  582. "\t Share name: %ws\n"
  583. "\t Type: %d (0x%08lx)\n"
  584. "\t Comment: %ws\n"
  585. "\tPermissions: %d (0x%08lx)\n"
  586. "\t Max uses: %d\n"
  587. "\t Path: %ws\n"
  588. "\t Password: %ws\n"
  589. "\t Reserved: %d\n"
  590. "\t Security? %ws\n"
  591. "\n"
  592. ,
  593. p->shi502_netname,
  594. p->shi502_type, p->shi502_type,
  595. p->shi502_remark,
  596. p->shi502_permissions, p->shi502_permissions,
  597. p->shi502_max_uses,
  598. p->shi502_path,
  599. (NULL == p->shi502_passwd) ? L"none" : p->shi502_passwd,
  600. p->shi502_reserved,
  601. (NULL == p->shi502_security_descriptor) ? L"No" : L"Yes"
  602. ));
  603. }
  604. }
  605. #endif // DBG == 1