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.

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