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.

316 lines
11 KiB

  1. /*****************************************************************************
  2. *
  3. * ftp.cpp - FTP folder bookkeeping
  4. *
  5. *****************************************************************************/
  6. #include "priv.h"
  7. #include "ftpinet.h"
  8. #include "ftpsite.h"
  9. #include "ftplist.h"
  10. #include "msieftp.h"
  11. #include "cookie.h"
  12. extern CFtpList * g_FtpSiteCache;
  13. extern DWORD g_dwOpenConnections;
  14. /*****************************************************************************
  15. *
  16. * Dynamic Globals. There should be as few of these as possible.
  17. *
  18. * All access to dynamic globals must be thread-safe.
  19. *
  20. *****************************************************************************/
  21. ULONG g_cRef = 0; /* Global reference count */
  22. CRITICAL_SECTION g_csDll; /* The shared critical section */
  23. extern HANDLE g_hthWorker; // Background worker thread
  24. #ifdef DEBUG
  25. DWORD g_TlsMem = 0xffffffff;
  26. extern DWORD g_TLSliStopWatchStartHi;
  27. extern DWORD g_TLSliStopWatchStartLo;
  28. LEAKSTRUCT g_LeakList[] =
  29. {
  30. {0, "CFtpFolder"},
  31. {0, "CFtpDir"},
  32. {0, "CFtpSite"},
  33. {0, "CFtpObj"},
  34. {0, "CFtpEidl"},
  35. {0, "CFtpDrop"},
  36. {0, "CFtpList"},
  37. {0, "CFtpStm"},
  38. {0, "CAccount"},
  39. {0, "CFtpFactory"},
  40. {0, "CFtpContextMenu"},
  41. {0, "CFtpEfe"},
  42. {0, "CFtpGlob"},
  43. {0, "CFtpIcon"},
  44. {0, "CMallocItem"},
  45. {0, "CFtpPidlList"},
  46. {0, "CFtpProp"},
  47. {0, "CStatusBar"},
  48. {0, "CFtpView"},
  49. {0, "CFtpWebView"},
  50. {0, "CCookieList"},
  51. {0, "CDropOperation"}
  52. };
  53. #endif // DEBUG
  54. ULONG g_cRef_CFtpView = 0; // Needed to determine when to purge cache.
  55. /*****************************************************************************
  56. *
  57. * DllAddRef / DllRelease
  58. *
  59. * Maintain the DLL reference count.
  60. *
  61. *****************************************************************************/
  62. void DllAddRef(void)
  63. {
  64. CREATE_CALLERS_ADDRESS; // For debug spew.
  65. InterlockedIncrement((LPLONG)&g_cRef);
  66. TraceMsg(TF_FTPREF, "DllAddRef() g_cRef=%d, called from=%#08lx.", g_cRef, GET_CALLERS_ADDRESS);
  67. }
  68. void DllRelease(void)
  69. {
  70. CREATE_CALLERS_ADDRESS; // For debug spew.
  71. TraceMsg(TF_FTPREF, "DllRelease() g_cRef=%d, called from=%#08lx.", g_cRef-1, GET_CALLERS_ADDRESS);
  72. InterlockedDecrement((LPLONG)&g_cRef);
  73. }
  74. /*****************************************************************************
  75. *
  76. * DllGetClassObject
  77. *
  78. * OLE entry point. Produces an IClassFactory for the indicated GUID.
  79. *
  80. * The artificial refcount inside DllGetClassObject helps to
  81. * avoid the race condition described in DllCanUnloadNow. It's
  82. * not perfect, but it makes the race window much smaller.
  83. *
  84. *****************************************************************************/
  85. STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID * ppvObj)
  86. {
  87. HRESULT hres;
  88. DllAddRef();
  89. if (IsEqualIID(rclsid, CLSID_FtpFolder) ||
  90. IsEqualIID(rclsid, CLSID_FtpWebView) ||
  91. IsEqualIID(rclsid, CLSID_FtpDataObject) ||
  92. IsEqualIID(rclsid, CLSID_FtpInstaller))
  93. {
  94. hres = CFtpFactory_Create(rclsid, riid, ppvObj);
  95. }
  96. else
  97. {
  98. *ppvObj = NULL;
  99. hres = CLASS_E_CLASSNOTAVAILABLE;
  100. }
  101. DllRelease();
  102. return hres;
  103. }
  104. /*****************************************************************************
  105. *
  106. * DllCanUnloadNow
  107. *
  108. * OLE entry point. Fail iff there are outstanding refs.
  109. *
  110. * There is an unavoidable race condition between DllCanUnloadNow
  111. * and the creation of a new IClassFactory: Between the time we
  112. * return from DllCanUnloadNow() and the caller inspects the value,
  113. * another thread in the same process may decide to call
  114. * DllGetClassObject, thus suddenly creating an object in this DLL
  115. * when there previously was none.
  116. *
  117. * It is the caller's responsibility to prepare for this possibility;
  118. * there is nothing we can do about it.
  119. *
  120. *****************************************************************************/
  121. STDMETHODIMP DllCanUnloadNow(void)
  122. {
  123. HRESULT hres;
  124. ENTERCRITICALNOASSERT;
  125. // Purge Cache if there aren't any FtpViews open.
  126. if ((0 == g_cRef_CFtpView))
  127. {
  128. // Since no views are open, we want to try to purge
  129. // the Delayed Actions so we can closed down the background
  130. // thread. Is it running?
  131. if (AreOutstandingDelayedActions())
  132. {
  133. LEAVECRITICALNOASSERT;
  134. PurgeDelayedActions(); // Try to close it down.
  135. ENTERCRITICALNOASSERT;
  136. }
  137. if (!AreOutstandingDelayedActions()) // Did it close down?
  138. {
  139. // We need to purge the session key because we lost the password
  140. // redirects in the CFtpSites. So we would login but later fail
  141. // when we try to fish out the password when falling back to
  142. // URLMON/shdocfl for file downloads. (NT #362108)
  143. PurgeSessionKey();
  144. CFtpPunkList_Purge(&g_FtpSiteCache); // Yes so purge the cache...
  145. }
  146. }
  147. hres = g_cRef ? S_FALSE : S_OK;
  148. TraceMsg(TF_FTP_DLLLOADING, "DllCanUnloadNow() DllRefs=%d, returning hres=%#08lx. (S_OK means yes)", g_cRef, hres);
  149. LEAVECRITICALNOASSERT;
  150. return hres;
  151. }
  152. void CheckForLeaks(BOOL fForce)
  153. {
  154. #ifdef DEBUG
  155. DWORD dwLeakCount = 0;
  156. if (fForce)
  157. {
  158. // Let's free our stuff so we can make sure not to leak it.
  159. // This is done more to force our selves to be w/o leaks
  160. // than anything else.
  161. DllCanUnloadNow();
  162. }
  163. for (int nIndex = 0; nIndex < ARRAYSIZE(g_LeakList); nIndex++)
  164. dwLeakCount += g_LeakList[nIndex].dwRef;
  165. if ((!g_FtpSiteCache || fForce) && (dwLeakCount || g_dwOpenConnections || g_cRef))
  166. {
  167. TraceMsg(TF_ALWAYS, "***********************************************");
  168. TraceMsg(TF_ALWAYS, "* LEAK - LEAK - LEAK - LEAK - LEAK *");
  169. TraceMsg(TF_ALWAYS, "* *");
  170. TraceMsg(TF_ALWAYS, "* WARNING: The FTP Shell Extension Leaked *");
  171. TraceMsg(TF_ALWAYS, "* one or more objects *");
  172. TraceMsg(TF_ALWAYS, "***********************************************");
  173. TraceMsg(TF_ALWAYS, "* *");
  174. for (int nIndex = 0; nIndex < ARRAYSIZE(g_LeakList); nIndex++)
  175. {
  176. if (g_LeakList[nIndex].dwRef)
  177. TraceMsg(TF_ALWAYS, "* %hs, Leaked=%d *", g_LeakList[nIndex].szObject, g_LeakList[nIndex].dwRef);
  178. }
  179. TraceMsg(TF_ALWAYS, "* *");
  180. TraceMsg(TF_ALWAYS, "* Open Wininet Connections=%d *", g_dwOpenConnections);
  181. TraceMsg(TF_ALWAYS, "* DLL Refs=%d *", g_cRef);
  182. TraceMsg(TF_ALWAYS, "* *");
  183. TraceMsg(TF_ALWAYS, "***********************************************");
  184. ASSERT(0);
  185. }
  186. #endif // DEBUG
  187. }
  188. // Globals to free.
  189. extern CCookieList * g_pCookieList;
  190. /*****************************************************************************\
  191. DESCRIPTION:
  192. DLL entry point.
  193. \*****************************************************************************/
  194. STDAPI_(BOOL) DllEntry(HINSTANCE hinst, DWORD dwReason, LPVOID lpReserved)
  195. {
  196. // This is called in two situations, FreeLibrary() is called and lpReserved is
  197. // NULL, or the process is shutting down and lpReserved is not NULL.
  198. BOOL fIsProcessShuttingDown = (lpReserved ? TRUE : FALSE);
  199. switch (dwReason)
  200. {
  201. case DLL_PROCESS_ATTACH:
  202. SHFusionInitializeFromModule(hinst);
  203. InitializeCriticalSection(&g_csDll);
  204. #ifdef DEBUG
  205. g_TlsMem = TlsAlloc();
  206. g_TLSliStopWatchStartHi = TlsAlloc();
  207. g_TLSliStopWatchStartLo = TlsAlloc();
  208. #endif
  209. // Don't put it under #ifdef DEBUG
  210. CcshellGetDebugFlags();
  211. DisableThreadLibraryCalls(hinst);
  212. g_hthWorker = NULL;
  213. g_hinst = hinst;
  214. g_formatEtcOffsets.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_SHELLIDLISTOFFSET);
  215. g_formatPasteSucceeded.cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_PASTESUCCEEDED);
  216. g_cfTargetCLSID = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_TARGETCLSID);
  217. g_dropTypes[DROP_FCont].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILECONTENTS);
  218. g_dropTypes[DROP_FGDW].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILEDESCRIPTORW);
  219. g_dropTypes[DROP_FGDA].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILEDESCRIPTORA);
  220. g_dropTypes[DROP_IDList].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_SHELLIDLIST);
  221. g_dropTypes[DROP_FNMA].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILENAMEMAPA);
  222. g_dropTypes[DROP_FNMW].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_FILENAMEMAPW);
  223. g_dropTypes[DROP_PrefDe].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT);
  224. g_dropTypes[DROP_PerfDe].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT);
  225. g_dropTypes[DROP_FTP_PRIVATE].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(TEXT("FtpPrivateData"));
  226. g_dropTypes[DROP_URL].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(TEXT("UniformResourceLocator"));
  227. g_dropTypes[DROP_OLEPERSIST].cfFormat = (CLIPFORMAT)RegisterClipboardFormat(TEXT("OleClipboardPersistOnFlush"));
  228. GetModuleFileNameA(GetModuleHandle(TEXT("SHELL32")), g_szShell32, ARRAYSIZE(g_szShell32));
  229. if (FAILED(CFtpSite_Init()))
  230. return 0;
  231. break;
  232. case DLL_PROCESS_DETACH:
  233. {
  234. CCookieList * pCookieList = (CCookieList *) InterlockedExchangePointer((void **) &g_pCookieList, NULL);
  235. if (pCookieList)
  236. delete pCookieList;
  237. // Yes, so we need to make sure all of the CFtpView's have closed down
  238. // or it's really bad to purge the FTP cache of FTP Servers (CFtpSite) and
  239. // their directories (CFtpDir).
  240. ASSERT(0 == g_cRef_CFtpView);
  241. // Now force the Delayed Actions to happen now instead of waiting.
  242. PurgeDelayedActions();
  243. // OndrejS turned this on. It's firing but I think they are false positives. Since FTP
  244. // Folders does so much caching, this is non-trivial to track down. I will turn this off
  245. // until Ondrej has time to verify.
  246. // CheckForLeaks(fIsProcessShuttingDown);
  247. UnloadWininet();
  248. DeleteCriticalSection(&g_csDll);
  249. #ifdef DEBUG
  250. if (g_TLSliStopWatchStartHi)
  251. {
  252. TlsFree(g_TLSliStopWatchStartHi);
  253. g_TLSliStopWatchStartHi = NULL;
  254. }
  255. if (g_TLSliStopWatchStartLo)
  256. {
  257. TlsFree(g_TLSliStopWatchStartLo);
  258. g_TLSliStopWatchStartLo = NULL;
  259. }
  260. #endif
  261. SHFusionUninitialize();
  262. }
  263. break;
  264. }
  265. return 1;
  266. }