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.

412 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. DeleteSpecifiedFiles.cpp
  5. Abstract:
  6. This SHIM renames the MFC42loc.dll that is installed by the APP in the
  7. %windir%\system32 directory and sets up the temporary file for destruction.
  8. Notes:
  9. This app. places the MFC42loc.dll into the %windir%\system32 directory even on a English language
  10. locale thereby forcing some APPS to use it and thereby some 'Dialogs' and 'Message boxes' are messed up.
  11. History:
  12. 08/21/2000 prashkud Created
  13. --*/
  14. #include "precomp.h"
  15. #include "CharVector.h"
  16. #include "strsafe.h"
  17. #include <new> // for inplace new
  18. IMPLEMENT_SHIM_BEGIN(DeleteSpecifiedFiles)
  19. #include "ShimHookMacro.h"
  20. APIHOOK_ENUM_BEGIN
  21. APIHOOK_ENUM_END
  22. class FILENAME_PATH
  23. {
  24. public:
  25. CString FileName;
  26. CString FileVersion;
  27. BOOL bPresent;
  28. FILENAME_PATH()
  29. {
  30. bPresent = FALSE;
  31. }
  32. };
  33. class FileNamePathList : public VectorT<FILENAME_PATH>
  34. {
  35. };
  36. VectorT<FILENAME_PATH> *g_StFileNamePath = NULL;
  37. /*++
  38. This function checks the 'FileVersion' of the first variable 'szFileName'
  39. matches that of the 2nd parameter 'szFileVersion' and if it matches returns
  40. TRUE else returns FALSE.
  41. --*/
  42. BOOL
  43. FileCheckVersion(
  44. const CString & csFileName,
  45. const CString & csFileVersion
  46. )
  47. {
  48. DWORD dwDummy;
  49. PVOID pVersionInfo;
  50. UINT cbTranslate, i;
  51. WCHAR SubBlock[100];
  52. LPWSTR lpBuffer;
  53. DWORD dwBytes;
  54. WORD wLangID;
  55. struct LANGANDCODEPAGE
  56. {
  57. WORD wLanguage;
  58. WORD wCodePage;
  59. } *lpTranslate;
  60. DWORD dwVersionInfoSize;
  61. //
  62. // There is no File Version specified. So, no point in going ahead. Return TRUE.
  63. //
  64. if (csFileVersion.IsEmpty())
  65. {
  66. return TRUE;
  67. }
  68. dwVersionInfoSize = GetFileVersionInfoSizeW((LPWSTR)csFileName.Get(), &dwDummy);
  69. if (dwVersionInfoSize > 0)
  70. {
  71. pVersionInfo = malloc(dwVersionInfoSize);
  72. if (pVersionInfo)
  73. {
  74. if (0 != GetFileVersionInfoW(
  75. (LPWSTR)csFileName.Get(),
  76. 0,
  77. dwVersionInfoSize,
  78. pVersionInfo
  79. ))
  80. {
  81. // Now, pVersionInfo contains the required version block.
  82. // Use it with VerQueryValue to get the
  83. // the language info that is needed
  84. // Get System locale before and note down the language for the system
  85. // Read the list of languages and code pages.
  86. if (VerQueryValueW(
  87. pVersionInfo,
  88. L"\\VarFileInfo\\Translation",
  89. (LPVOID*)&lpTranslate,
  90. &cbTranslate
  91. ))
  92. {
  93. //
  94. // Read the language string each language and code page.
  95. //
  96. for (i=0; i < (cbTranslate/sizeof(struct LANGANDCODEPAGE)); i++)
  97. {
  98. if (StringCbPrintfW(
  99. SubBlock,
  100. (sizeof(SubBlock) - 1),
  101. L"\\StringFileInfo\\%04x%04x\\FileVersion",
  102. lpTranslate[i].wLanguage,
  103. lpTranslate[i].wCodePage
  104. ) < 0)
  105. {
  106. DPFN(
  107. eDbgLevelError,
  108. "Long string - Cannot handle");
  109. break;
  110. }
  111. else
  112. {
  113. SubBlock[ARRAYSIZE(SubBlock) - 1] = '\0';
  114. }
  115. //
  116. // Retrieve FileVersion for language and code page "i" from the pVersionInfo.
  117. //
  118. if (VerQueryValueW(
  119. pVersionInfo,
  120. SubBlock,
  121. (LPVOID*)&lpBuffer,
  122. (UINT*)&dwBytes))
  123. {
  124. if (!(csFileVersion.Compare(lpBuffer)))
  125. {
  126. DPFN(
  127. eDbgLevelInfo,
  128. "Version string for current file is %S,%S",
  129. lpBuffer, csFileVersion.Get());
  130. free(pVersionInfo);
  131. return TRUE;
  132. }
  133. }
  134. } // for loop
  135. }
  136. }
  137. free(pVersionInfo);
  138. }
  139. }
  140. return FALSE;
  141. }
  142. /*++
  143. This function as the name suggests deletes the file or if it is in use moves
  144. it to the 'Temp' folder.
  145. --*/
  146. VOID
  147. DeleteFiles()
  148. {
  149. for (int i = 0; i < g_StFileNamePath->Size(); ++i)
  150. {
  151. const FILENAME_PATH & fnp = g_StFileNamePath->Get(i);
  152. DPFN( eDbgLevelSpew, "DeleteFiles file(%S) version(%S)", fnp.FileName.Get(), fnp.FileVersion.Get());
  153. if (!fnp.bPresent)
  154. {
  155. //
  156. // CheckFileVersion
  157. //
  158. if (FileCheckVersion(fnp.FileName, fnp.FileVersion))
  159. {
  160. LOGN(eDbgLevelError,"Deleting file %S.", fnp.FileName.Get());
  161. // Delete the file..
  162. if (!DeleteFileW(fnp.FileName))
  163. {
  164. CString csTempDir;
  165. CString csTempPath;
  166. LOGN(eDbgLevelError,"Moving file %S.", fnp.FileName.Get());
  167. //
  168. // Could not delete.Retry by renaming it and then deleting it.
  169. // New file is %windir%\Temp
  170. //
  171. csTempDir.GetTempPathW();
  172. csTempPath.GetTempFileNameW(csTempDir, L"XXXX", 0);
  173. if (MoveFileExW( fnp.FileName, csTempPath, MOVEFILE_REPLACE_EXISTING ))
  174. {
  175. SetFileAttributesW(
  176. csTempPath,
  177. FILE_ATTRIBUTE_ARCHIVE |
  178. FILE_ATTRIBUTE_TEMPORARY);
  179. DeleteFileW(csTempPath);
  180. }
  181. }
  182. }
  183. }
  184. }
  185. }
  186. /*++
  187. This function checks for the existence of the file specified on the commandline .
  188. This is called during the DLL_PROCESS_ATTACH notification
  189. --*/
  190. BOOL
  191. CheckFileExistence()
  192. {
  193. // If any among the list is not present, mark it as 'Not Present' and only those marked as
  194. // 'Not present' will be deleted.
  195. BOOL bFileDoesNotExist = FALSE;
  196. WIN32_FIND_DATAW StWin32FileData;
  197. for (int i = 0; i < g_StFileNamePath->Size(); ++i)
  198. {
  199. FILENAME_PATH & fnp = g_StFileNamePath->Get(i);
  200. DPFN( eDbgLevelSpew, "CheckFileExistence file(%S) version(%S)", fnp.FileName.Get(), fnp.FileVersion.Get());
  201. HANDLE hTempFile = FindFirstFileW(fnp.FileName, &StWin32FileData);
  202. if (INVALID_HANDLE_VALUE != hTempFile)
  203. {
  204. FindClose(hTempFile);
  205. //
  206. // File is present. Check its version if given.
  207. //
  208. if (FileCheckVersion(fnp.FileName, fnp.FileVersion))
  209. {
  210. fnp.bPresent = TRUE;
  211. }
  212. else
  213. {
  214. bFileDoesNotExist = TRUE;
  215. fnp.bPresent = FALSE;
  216. }
  217. }
  218. else
  219. {
  220. bFileDoesNotExist = TRUE;
  221. fnp.bPresent = FALSE;
  222. }
  223. }
  224. return bFileDoesNotExist;
  225. }
  226. /*++
  227. The command line can contain FileName:Path:VersionString,FileName1:Path1:VersionString1 etc....
  228. Eg. Ole2.dll:system:604.5768.94567,MFC42.dll:0:,Foo.dll:d:\program Files\DisneyInteractive etc..
  229. 'system' implies the %windir%. '0' implies that the filename itself is a fully qualified path
  230. OR one has the option of giving the path seperately OR it can be left blank.
  231. --*/
  232. BOOL
  233. ParseCommandLine(LPCSTR lpszCommandLine)
  234. {
  235. CSTRING_TRY
  236. {
  237. g_StFileNamePath = new VectorT<FILENAME_PATH>;
  238. if (!g_StFileNamePath)
  239. {
  240. return FALSE;
  241. }
  242. CStringToken csCommandLine(COMMAND_LINE, ":,;");
  243. CString csTok;
  244. CString csFilePart;
  245. DWORD dwState = 0;
  246. while (csCommandLine.GetToken(csTok))
  247. {
  248. FILENAME_PATH fnp;
  249. switch(dwState)
  250. {
  251. case 0:
  252. dwState++;
  253. fnp.FileName = csTok;
  254. break;
  255. case 1:
  256. // The file part needs to be stored.
  257. csFilePart = fnp.FileName;
  258. if (csTok.CompareNoCase(L"system") == 0)
  259. {
  260. fnp.FileName.GetSystemDirectoryW();
  261. fnp.FileName.AppendPath(csFilePart);
  262. }
  263. else
  264. {
  265. fnp.FileName = csTok;
  266. fnp.FileName.AppendPath(csFilePart);
  267. }
  268. dwState++;
  269. break;
  270. case 2:
  271. dwState = 0;
  272. fnp.FileVersion = csTok;
  273. DPFN( eDbgLevelInfo, "ParseCommandLine file(%S) version(%S)", fnp.FileName.Get(), fnp.FileVersion.Get());
  274. // Found all three states, add it to the list
  275. if (!g_StFileNamePath->AppendConstruct(fnp))
  276. {
  277. // Append failed, stop parsing
  278. return FALSE;
  279. }
  280. break;
  281. }
  282. }
  283. }
  284. CSTRING_CATCH
  285. {
  286. return FALSE;
  287. }
  288. return TRUE;
  289. }
  290. /*++
  291. Register hooked functions
  292. --*/
  293. BOOL
  294. NOTIFY_FUNCTION(
  295. DWORD fdwReason
  296. )
  297. {
  298. static BOOL fDidNotExist = FALSE;
  299. switch (fdwReason)
  300. {
  301. case SHIM_STATIC_DLLS_INITIALIZED:
  302. {
  303. if (ParseCommandLine(COMMAND_LINE))
  304. {
  305. //
  306. // Ok...CommandLine is in place...Now Check for those Files...
  307. // If any one file exists, then we are not responsible. We bail out..
  308. //
  309. fDidNotExist = CheckFileExistence();
  310. }
  311. break;
  312. }
  313. case DLL_PROCESS_DETACH:
  314. {
  315. //
  316. // Check for the specified file at the specified location. If it existed prior to
  317. // to this in PROCESS_DLL_ATTACH, it is not installed us...Just bail out !
  318. // If the file did not exist before, it is our problem and we should remove them.
  319. //
  320. if (fDidNotExist)
  321. {
  322. DeleteFiles();
  323. }
  324. break;
  325. }
  326. }
  327. return TRUE;
  328. }
  329. HOOK_BEGIN
  330. CALL_NOTIFY_FUNCTION
  331. HOOK_END
  332. IMPLEMENT_SHIM_END