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.

439 lines
12 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. GrabMatchingInformation.cpp
  5. Abstract:
  6. Upon ProcessAttach the shim gathers matching information from the current
  7. directory.
  8. Notes:
  9. This is a general purpose shim.
  10. History:
  11. 20-Oct-2000 jdoherty Created
  12. --*/
  13. #include "precomp.h"
  14. #include <stdio.h>
  15. // This module is *not* DBCS safe, but should only be used by our testers
  16. // We should, eventually, correct this file.
  17. // This module has been given an official blessing to use the str routines.
  18. #include "LegalStr.h"
  19. IMPLEMENT_SHIM_BEGIN(GrabMatchingInformation)
  20. #include "ShimHookMacro.h"
  21. APIHOOK_ENUM_BEGIN
  22. APIHOOK_ENUM_ENTRY(GetCommandLineA)
  23. APIHOOK_ENUM_ENTRY(GetCommandLineW)
  24. APIHOOK_ENUM_END
  25. BOOL gbCalledHook;
  26. LPSTR glpOriginalRootDir;
  27. VOID GrabMatchingInformationMain();
  28. BOOL GrabMatchingInfo(LPSTR lpRootDirectory, HANDLE hStorageFile, int nLevel);
  29. BOOL GetRelativePath(LPSTR lpPathFromRoot, LPCSTR lpSubDir, LPCSTR lpFileName);
  30. VOID AddMatchingFile( LPSTR lpData, LPCSTR pszFullPath, LPCSTR pszRelativePath );
  31. LPSTR
  32. APIHOOK(GetCommandLineA)()
  33. {
  34. if (!gbCalledHook)
  35. {
  36. int nLength = 0;
  37. LPSTR lpCursorEnd;
  38. glpOriginalRootDir = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR));
  39. GetModuleFileNameA( NULL, glpOriginalRootDir, MAX_PATH );
  40. nLength = strlen( glpOriginalRootDir );
  41. lpCursorEnd = &glpOriginalRootDir[nLength-1];
  42. while( --nLength )
  43. {
  44. if ( *(lpCursorEnd) == '\\' )
  45. {
  46. *(lpCursorEnd) = '\0';
  47. break;
  48. }
  49. lpCursorEnd--;
  50. if (nLength==0)
  51. {
  52. GetCurrentDirectoryA( MAX_PATH, glpOriginalRootDir );
  53. }
  54. }
  55. GrabMatchingInformationMain();
  56. ShimFree(glpOriginalRootDir);
  57. gbCalledHook = TRUE;
  58. }
  59. return ORIGINAL_API(GetCommandLineA)();
  60. }
  61. LPWSTR
  62. APIHOOK(GetCommandLineW)()
  63. {
  64. if (!gbCalledHook)
  65. {
  66. int nLength = 0;
  67. LPSTR lpCursorEnd;
  68. glpOriginalRootDir = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR));
  69. GetModuleFileNameA( NULL, glpOriginalRootDir, MAX_PATH );
  70. nLength = strlen( glpOriginalRootDir );
  71. lpCursorEnd = &glpOriginalRootDir[nLength-1];
  72. while( --nLength )
  73. {
  74. if ( *(lpCursorEnd) == '\\' )
  75. {
  76. *(lpCursorEnd) = '\0';
  77. break;
  78. }
  79. lpCursorEnd--;
  80. if (nLength==0)
  81. {
  82. GetCurrentDirectoryA( MAX_PATH, glpOriginalRootDir );
  83. }
  84. }
  85. GrabMatchingInformationMain();
  86. ShimFree(glpOriginalRootDir);
  87. gbCalledHook = TRUE;
  88. }
  89. return ORIGINAL_API(GetCommandLineW)();
  90. }
  91. VOID GrabMatchingInformationMain()
  92. {
  93. HANDLE hMutexHandle;
  94. LPSTR lpStorageFilePath;
  95. LPSTR lpDirInfo;
  96. LPSTR lpRootDir;
  97. HANDLE hStorageFile;
  98. DWORD dwBytesWritten = 0;
  99. lpStorageFilePath = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR));
  100. lpDirInfo = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR));
  101. lpRootDir = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR));
  102. // Setup a mutex so only one process at a time can write to the matchinginfo.txt file.
  103. hMutexHandle = CreateMutexA( NULL, FALSE, "MyGrabMIFileMutex" );
  104. WaitForSingleObject( hMutexHandle, INFINITE );
  105. // Build path to where the matching information will be stored.
  106. SHGetSpecialFolderPathA(NULL, lpStorageFilePath, CSIDL_DESKTOPDIRECTORY, TRUE );
  107. strcat( lpStorageFilePath, "\\matchinginfo.txt" );
  108. /*
  109. if ( (strcmp(glpOriginalRootDir ,".") == 0) || (strcmp(glpOriginalRootDir ,"") == 0) )
  110. {
  111. GetCurrentDirectoryA( MAX_PATH, glpOriginalRootDir );
  112. }
  113. */
  114. // Open matchinginfo.txt on the desktop for write if it exists and set the file pointer to the end
  115. // of the file, create a new file otherwise.
  116. hStorageFile = CreateFileA( lpStorageFilePath,
  117. GENERIC_WRITE,
  118. 0,
  119. NULL,
  120. OPEN_ALWAYS,
  121. FILE_ATTRIBUTE_NORMAL,
  122. NULL);
  123. SetFilePointer( hStorageFile, NULL, NULL, FILE_END );
  124. if (hStorageFile == INVALID_HANDLE_VALUE)
  125. {
  126. return;
  127. }
  128. sprintf(lpDirInfo, "<!-- Generating matching information for files in: [ %s ]For Process: [ %s ]-->\r\n",
  129. glpOriginalRootDir,
  130. GetCommandLineA()
  131. );
  132. WriteFile( hStorageFile, lpDirInfo, strlen(lpDirInfo), &dwBytesWritten, NULL );
  133. strcpy(lpRootDir, glpOriginalRootDir);
  134. if (!GrabMatchingInfo(lpRootDir, hStorageFile, 0))
  135. {
  136. CloseHandle(hStorageFile);
  137. return;
  138. }
  139. CloseHandle(hStorageFile);
  140. ShimFree(lpStorageFilePath);
  141. ShimFree(lpDirInfo);
  142. ShimFree(lpRootDir);
  143. ReleaseMutex( hMutexHandle );
  144. return;
  145. }
  146. /*++
  147. This function traverses lpRootDirectory and it's subdirectories while storing the
  148. size and checksum for the files in those directories.
  149. --*/
  150. BOOL GrabMatchingInfo(LPSTR lpRootDirectory, HANDLE hStorageFile, int nLevel)
  151. {
  152. WIN32_FIND_DATAA FindFileData;
  153. HANDLE hSearch; // Search handle returned by FindFirstFile
  154. LPSTR lpSubDir;
  155. LPSTR lpFilePath;
  156. LPSTR lpData;
  157. LPSTR lpPathFromRoot;
  158. DWORD dwBytesWritten = 0;
  159. int cbFileCounter = 0;
  160. lpSubDir = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR));
  161. lpFilePath = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR));
  162. lpData = (LPSTR) ShimMalloc((MAX_PATH*2)*sizeof(LPSTR));
  163. lpPathFromRoot = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR));
  164. // Just repeat displaying a dot so the user knows something is happening.
  165. // USED IN GRABMI
  166. // printf(".");
  167. strcpy (lpSubDir, lpRootDirectory);
  168. strcat(lpRootDirectory, "\\*");
  169. if ( (hSearch=FindFirstFileA( lpRootDirectory, &FindFileData )) == INVALID_HANDLE_VALUE )
  170. {
  171. return FALSE;
  172. }
  173. BOOL bRepeat = FALSE;
  174. while ( (strcmp( FindFileData.cFileName, "." ) == 0) || (strcmp( FindFileData.cFileName, ".." ) == 0) && !bRepeat )
  175. {
  176. FindNextFileA(hSearch, &FindFileData);
  177. if ( strcmp( FindFileData.cFileName, ".." ) == 0 )
  178. bRepeat = TRUE;
  179. }
  180. if (!FindNextFileA(hSearch, &FindFileData))
  181. {
  182. return TRUE;
  183. }
  184. do
  185. {
  186. if (!(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  187. {
  188. // Build path for matching file
  189. strcpy(lpFilePath, lpSubDir);
  190. strcat(lpFilePath, "\\");
  191. strcat(lpFilePath, FindFileData.cFileName);
  192. ZeroMemory( lpData, (MAX_PATH*2)*sizeof(LPSTR) );
  193. // Determine the relative path for the file from the original root directory.
  194. if (!GetRelativePath(lpPathFromRoot, lpSubDir, FindFileData.cFileName))
  195. strcpy(lpPathFromRoot, FindFileData.cFileName);
  196. // Check to see if there is version information for the specified file and whether it is
  197. // an .exe, .icd, ._MP, or .dll. If so add the information to the file.
  198. if ( stristr(lpFilePath, ".exe") ||
  199. stristr(lpFilePath, ".icd") ||
  200. stristr(lpFilePath, "._MP") ||
  201. stristr(lpFilePath, ".dll") )
  202. {
  203. AddMatchingFile( lpData, lpFilePath, lpPathFromRoot );
  204. } else
  205. {
  206. // Limit the amount of info gathered to 10 files per directory excluding the above file types.
  207. if (cbFileCounter < 10)
  208. {
  209. cbFileCounter++;
  210. AddMatchingFile( lpData, lpFilePath, lpPathFromRoot );
  211. }
  212. }
  213. // Write the information stored in lpData to the file
  214. WriteFile( hStorageFile, lpData, strlen(lpData), &dwBytesWritten, NULL );
  215. }
  216. } while ( FindNextFileA( hSearch, &FindFileData ) );
  217. /////////////////////////////////////////////////////////////////////////////////
  218. //
  219. // Now go through the directory again and go into the subdirectories
  220. //
  221. /////////////////////////////////////////////////////////////////////////////////
  222. if (strlen(lpRootDirectory) < 4)
  223. {
  224. if ( (hSearch=FindFirstFileA(lpRootDirectory, &FindFileData)) == INVALID_HANDLE_VALUE)
  225. {
  226. return FALSE;
  227. }
  228. } else
  229. {
  230. if ( (hSearch=FindFirstFileA(lpRootDirectory, &FindFileData)) == INVALID_HANDLE_VALUE)
  231. {
  232. return FALSE;
  233. }
  234. FindNextFileA(hSearch, &FindFileData);
  235. if (!FindNextFileA(hSearch, &FindFileData))
  236. {
  237. FindClose( hSearch );
  238. return TRUE;
  239. }
  240. }
  241. do
  242. {
  243. if ((FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && nLevel < 3)
  244. {
  245. strcat(lpSubDir, "\\");
  246. strcat(lpSubDir, FindFileData.cFileName);
  247. GrabMatchingInfo (lpSubDir, hStorageFile, nLevel+1);
  248. lpSubDir[strlen(lpSubDir)-2]='\0';
  249. strcpy(lpSubDir, lpRootDirectory);
  250. lpSubDir[strlen(lpSubDir)-2]='\0';
  251. }
  252. }while ( FindNextFileA( hSearch, &FindFileData ) );
  253. FindClose(hSearch);
  254. ShimFree(lpSubDir);
  255. ShimFree(lpFilePath);
  256. ShimFree(lpData);
  257. ShimFree(lpPathFromRoot);
  258. return TRUE;
  259. }
  260. BOOL GetRelativePath(LPSTR lpPathFromRoot, LPCSTR lpSubDir, LPCSTR lpFileName)
  261. {
  262. int difference=(strlen(lpSubDir)-strlen(glpOriginalRootDir));
  263. if (difference)
  264. {
  265. for (int i=0; i < difference; i++)
  266. {
  267. lpPathFromRoot[i] = lpSubDir[strlen(glpOriginalRootDir)+i+1];
  268. }
  269. strcat(lpPathFromRoot, "\\");
  270. strcat(lpPathFromRoot, lpFileName);
  271. difference=0;
  272. return TRUE;
  273. }
  274. return FALSE;
  275. }
  276. /*++
  277. AddMatchingFile
  278. Description: Adds a matching file and it's attributes to the tree.
  279. --*/
  280. VOID AddMatchingFile(
  281. OUT LPSTR lpData,
  282. IN LPCSTR pszFullPath,
  283. IN LPCSTR pszRelativePath )
  284. {
  285. PATTRINFO pAttrInfo;
  286. DWORD dwAttrCount;
  287. LPWSTR pwszFullPath;
  288. pwszFullPath = (LPWSTR) ShimMalloc(MAX_PATH*sizeof(LPWSTR));
  289. mbstowcs( pwszFullPath, pszFullPath, MAX_PATH );
  290. //
  291. // Call the attribute manager to get all the attributes for this file.
  292. //
  293. if (SdbGetFileAttributes(pwszFullPath, &pAttrInfo, &dwAttrCount))
  294. {
  295. LPSTR lpBuffer;
  296. LPWSTR lpwBuffer;
  297. lpBuffer = (LPSTR) ShimMalloc(MAX_PATH*sizeof(LPSTR));
  298. lpwBuffer = (LPWSTR) ShimMalloc(MAX_PATH*sizeof(LPWSTR));
  299. //
  300. // Loop through all the attributes and show the ones that are available.
  301. //
  302. // ZeroMemory( lpData, (MAX_PATH*2)*sizeof(LPSTR) );
  303. sprintf(lpData, "<MATCHING_FILE NAME=\"%s\" ", pszRelativePath);
  304. for (DWORD i = 0; i < dwAttrCount; ++i)
  305. {
  306. if ( SdbFormatAttribute(&pAttrInfo[i], lpwBuffer, MAX_PATH) )//CHARCOUNT(lpwBuffer)))
  307. {
  308. ZeroMemory( lpBuffer, MAX_PATH*sizeof(LPSTR) );
  309. wcstombs( lpBuffer, lpwBuffer, wcslen (lpwBuffer) );
  310. //
  311. // wszBuffer has XML for this attribute
  312. //
  313. strcat( lpData, lpBuffer );
  314. strcat( lpData, " " );
  315. }
  316. }
  317. strcat( lpData, "/>\r\n" );
  318. ShimFree( lpBuffer );
  319. ShimFree( lpwBuffer );
  320. SdbFreeFileAttributes(pAttrInfo);
  321. }
  322. ShimFree( pwszFullPath );
  323. }
  324. /*++
  325. Handle DLL_PROCESS_ATTACH and DLL_PROCESS_DETACH in your notify function
  326. to do initialization and uninitialization.
  327. IMPORTANT: Make sure you ONLY call NTDLL, KERNEL32 and MSVCRT APIs during
  328. DLL_PROCESS_ATTACH notification. No other DLLs are initialized at that
  329. point.
  330. If your shim cannot initialize properly, return FALSE and none of the
  331. APIs specified will be hooked.
  332. --*/
  333. BOOL
  334. NOTIFY_FUNCTION(
  335. DWORD fdwReason)
  336. {
  337. if (fdwReason == DLL_PROCESS_ATTACH) {
  338. gbCalledHook = FALSE;
  339. DPFN( eDbgLevelInfo, "Beginng to Grab Information.");
  340. }
  341. return TRUE;
  342. }
  343. /*++
  344. Register hooked functions
  345. --*/
  346. HOOK_BEGIN
  347. APIHOOK_ENTRY(KERNEL32.DLL, GetCommandLineA)
  348. APIHOOK_ENTRY(KERNEL32.DLL, GetCommandLineW)
  349. CALL_NOTIFY_FUNCTION
  350. HOOK_END
  351. IMPLEMENT_SHIM_END