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.

376 lines
8.9 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: sharecnx.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pch.h"
  11. #pragma hdrstop
  12. #include "sharecnx.h"
  13. //
  14. // This class is a simple cache of net share names and some status flags.
  15. // Initially, the only status maintained is to remember if there's an
  16. // an open net connection for the share.
  17. // The motivation for the cache is to avoid expensive net calls while
  18. // we're cruising through lists of files (i.e. deleting files from the
  19. // cache). After we delete a file from the cache, it is effectively
  20. // unpinned. Therefore, we like to notify the shell so it can remove
  21. // the "pinned" icon overlay from the affected file(s). However,
  22. // we don't want to hit the net with a change notify if there
  23. // isn't an open connection to a file's parent share. Before we issue
  24. // a change notify, we just query this cache for a file using
  25. // IsOpenConnectionPathUNC(). If there's no entry for the file's share,
  26. // one is added and the connection status is obtained. If there's
  27. // already an entry, then we just return the status. The public APIs
  28. // support a "refresh" flag if refresh is desired.
  29. // Additional status information could easily be added for each entry
  30. // if it's needed later.
  31. // [brianau - 12/12/98]
  32. //
  33. //-----------------------------------------------------------------------------
  34. // CShareCnxStatusCache member functions.
  35. //-----------------------------------------------------------------------------
  36. CShareCnxStatusCache::CShareCnxStatusCache(
  37. void
  38. ) : m_hdpa(NULL)
  39. {
  40. }
  41. CShareCnxStatusCache::~CShareCnxStatusCache(
  42. void
  43. )
  44. {
  45. if (NULL != m_hdpa)
  46. {
  47. //
  48. // Delete all the entries then destroy the DPA.
  49. //
  50. int cEntries = Count();
  51. for (int i = 0; i < cEntries; i++)
  52. {
  53. delete GetEntry(i);
  54. }
  55. DPA_Destroy(m_hdpa);
  56. }
  57. }
  58. //
  59. // Returns address of entry or NULL if not found.
  60. //
  61. CShareCnxStatusCache::Entry *
  62. CShareCnxStatusCache::FindEntry(
  63. LPCTSTR pszShare
  64. ) const
  65. {
  66. if (NULL != m_hdpa)
  67. {
  68. int cEntries = Count();
  69. for (int i = 0; i < cEntries; i++)
  70. {
  71. Entry *pEntry = GetEntry(i);
  72. if (NULL != pEntry && NULL != pEntry->Share())
  73. {
  74. if (0 == lstrcmpi(pszShare, pEntry->Share()))
  75. {
  76. //
  77. // Aha, we found a match.
  78. //
  79. return pEntry;
  80. }
  81. }
  82. }
  83. }
  84. return NULL;
  85. }
  86. //
  87. // Creates a new entry and adds it to the DPA of entries.
  88. // If successful, returns address of new entry.
  89. // Does not check for duplicate entry before adding new one.
  90. //
  91. CShareCnxStatusCache::Entry *
  92. CShareCnxStatusCache::AddEntry(
  93. LPCTSTR pszShare,
  94. DWORD dwStatus
  95. )
  96. {
  97. Entry *pEntry = NULL;
  98. if (NULL == m_hdpa)
  99. {
  100. //
  101. // Must be first addition. Create the DPA.
  102. //
  103. m_hdpa = DPA_Create(8);
  104. }
  105. if (NULL != m_hdpa)
  106. {
  107. int iEntry = -1;
  108. pEntry = new Entry(pszShare, dwStatus);
  109. if (NULL != pEntry && pEntry->IsValid())
  110. {
  111. //
  112. // We have a valid entry. Add it to the DPA.
  113. //
  114. iEntry = DPA_AppendPtr(m_hdpa, pEntry);
  115. }
  116. if (-1 == iEntry)
  117. {
  118. //
  119. // One of the following bad things happened:
  120. //
  121. // 1. Entry creation failed. Most likely couldn't alloc string.
  122. // 2. Failed to add entry to DPA (out of memory).
  123. //
  124. // Either way, destroy the entry and set the entry ptr so we
  125. // return NULL.
  126. //
  127. delete pEntry;
  128. pEntry = NULL;
  129. }
  130. }
  131. return pEntry;
  132. }
  133. //
  134. // Determine if the net share associated with a UNC path (file or folder)
  135. // has an open connection on this machine.
  136. //
  137. // Returns:
  138. // S_OK = Open connection.
  139. // S_FALSE = No open connection.
  140. // E_OUTOFMEMORY
  141. //
  142. HRESULT
  143. CShareCnxStatusCache::IsOpenConnectionPathUNC(
  144. LPCTSTR pszPathUNC,
  145. bool bRefresh // [optional]. Default = false.
  146. )
  147. {
  148. //
  149. // Trim the path back to just the UNC share name.
  150. // Call IsOpenConnectionShare() to do the actual work.
  151. //
  152. TCHAR szShare[MAX_PATH * 2];
  153. lstrcpyn(szShare, pszPathUNC, ARRAYSIZE(szShare));
  154. PathStripToRoot(szShare);
  155. return IsOpenConnectionShare(szShare);
  156. }
  157. //
  158. // Determine if the net share has an open connection on this machine.
  159. //
  160. // Returns:
  161. // S_OK = Open connection.
  162. // S_FALSE = No open connection.
  163. //
  164. HRESULT
  165. CShareCnxStatusCache::IsOpenConnectionShare(
  166. LPCTSTR pszShare,
  167. bool bRefresh // [optional]. Default = false.
  168. )
  169. {
  170. DWORD dwStatus = 0;
  171. HRESULT hr = GetShareStatus(pszShare, &dwStatus, bRefresh);
  172. if (SUCCEEDED(hr))
  173. {
  174. if (0 != (dwStatus & Entry::StatusOpenCnx))
  175. hr = S_OK;
  176. else
  177. hr = S_FALSE;
  178. }
  179. return hr;
  180. }
  181. //
  182. // Returns:
  183. //
  184. // E_INVALIDARG = Path was not a UNC share.
  185. // S_OK = Status is valid.
  186. //
  187. HRESULT
  188. CShareCnxStatusCache::GetShareStatus(
  189. LPCTSTR pszShare,
  190. DWORD *pdwStatus,
  191. bool bRefresh // [optional]. Default = false.
  192. )
  193. {
  194. HRESULT hr = E_INVALIDARG; // Assume share name isn't UNC.
  195. *pdwStatus = 0;
  196. if (PathIsUNCServerShare(pszShare))
  197. {
  198. //
  199. // We have a valid UNC "\\server\share" name string.
  200. //
  201. Entry *pEntry = FindEntry(pszShare);
  202. if (NULL == pEntry)
  203. {
  204. //
  205. // Cache miss. Get the system status for the share and try to
  206. // cache it.
  207. //
  208. hr = Entry::QueryShareStatus(pszShare, pdwStatus);
  209. if (SUCCEEDED(hr))
  210. {
  211. //
  212. // Note that we don't return any errors from the cache attempt.
  213. // The only problem of not caching the entry is that the next
  214. // call to this function will need to re-query the system for
  215. // the information. This makes the cache meaningless but it's
  216. // not worth failing the information request. Just slows things
  217. // down a bit.
  218. //
  219. AddEntry(pszShare, *pdwStatus);
  220. }
  221. }
  222. else
  223. {
  224. //
  225. // Cache hit.
  226. //
  227. hr = S_OK;
  228. if (bRefresh)
  229. {
  230. //
  231. // Caller want's fresh info.
  232. //
  233. hr = pEntry->Refresh();
  234. }
  235. *pdwStatus = pEntry->Status();
  236. if (SUCCEEDED(hr))
  237. hr = pEntry->LastResult();
  238. }
  239. }
  240. return hr;
  241. }
  242. //
  243. // Returns number of entries in the cache.
  244. //
  245. int
  246. CShareCnxStatusCache::Count(
  247. void
  248. ) const
  249. {
  250. return (NULL != m_hdpa) ? DPA_GetPtrCount(m_hdpa) : 0;
  251. }
  252. //-----------------------------------------------------------------------------
  253. // CShareCnxStatusCache::Entry member functions.
  254. //-----------------------------------------------------------------------------
  255. CShareCnxStatusCache::Entry::Entry(
  256. LPCTSTR pszShare,
  257. DWORD dwStatus
  258. ) : m_pszShare(StrDup(pszShare)),
  259. m_dwStatus(dwStatus),
  260. m_hrLastResult(NOERROR)
  261. {
  262. if (NULL == m_pszShare)
  263. {
  264. m_hrLastResult = E_OUTOFMEMORY;
  265. }
  266. }
  267. CShareCnxStatusCache::Entry::~Entry(
  268. void
  269. )
  270. {
  271. if (NULL != m_pszShare)
  272. {
  273. LocalFree(m_pszShare);
  274. }
  275. }
  276. //
  277. // Obtain new status info for the entry.
  278. // Returns true if no errors obtaining info, false if there were errors.
  279. //
  280. HRESULT
  281. CShareCnxStatusCache::Entry::Refresh(
  282. void
  283. )
  284. {
  285. m_dwStatus = 0;
  286. m_hrLastResult = E_OUTOFMEMORY;
  287. if (NULL != m_pszShare)
  288. m_hrLastResult = QueryShareStatus(m_pszShare, &m_dwStatus);
  289. return m_hrLastResult;
  290. }
  291. //
  292. // Static function for obtaining entry status info from the
  293. // system. Made this a static function so the cache object
  294. // can obtain information before creating the entry. In case
  295. // entry creation fails, we still want to be able to return
  296. // valid status info.
  297. //
  298. HRESULT
  299. CShareCnxStatusCache::Entry::QueryShareStatus(
  300. LPCTSTR pszShare,
  301. DWORD *pdwStatus
  302. )
  303. {
  304. HRESULT hr = NOERROR;
  305. *pdwStatus = 0;
  306. //
  307. // Check the open connection status for this share.
  308. //
  309. hr = ::IsOpenConnectionShare(pszShare);
  310. switch(hr)
  311. {
  312. case S_OK:
  313. //
  314. // Open connection found.
  315. //
  316. *pdwStatus |= StatusOpenCnx;
  317. break;
  318. case S_FALSE:
  319. hr = S_OK;
  320. break;
  321. default:
  322. break;
  323. }
  324. //
  325. // If any other status information is required in the future,
  326. // here's where you collect it from the system.
  327. //
  328. return hr;
  329. }