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.

485 lines
12 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. expandit.c
  5. Abstract:
  6. Expandit provides routines to expand a given file as much as possible.
  7. It is useful for expanding cabinet files and executable files that may
  8. themselves contain cabinet files.
  9. Author:
  10. Marc R. Whitten (marcw) 30-Jul-1998
  11. Revision History:
  12. --*/
  13. #include "pch.h"
  14. #include "migutilp.h"
  15. UINT g_DirSequencer = 0;
  16. BOOL
  17. ExpandAllFilesW (
  18. IN PCWSTR FileDir,
  19. IN PCWSTR TempDir
  20. );
  21. BOOL
  22. ExpandFileW (
  23. IN PCWSTR FullPath,
  24. IN PCWSTR TempDir
  25. );
  26. PWSTR
  27. pGetExpandName (
  28. VOID
  29. )
  30. {
  31. static WCHAR rName[MAX_WCHAR_PATH];
  32. g_DirSequencer++;
  33. swprintf (rName, L"EXP%04x", g_DirSequencer);
  34. return rName;
  35. }
  36. BOOL
  37. pIsFileType (
  38. IN PCWSTR FullPath,
  39. IN PCWSTR TypePattern
  40. )
  41. {
  42. PCWSTR p;
  43. p = GetFileExtensionFromPathW (FullPath);
  44. return p && IsPatternMatchW (TypePattern, p);
  45. }
  46. BOOL CALLBACK
  47. pResNameCallback (
  48. IN HANDLE hModule, // module handle
  49. IN LPCWSTR lpszType, // pointer to resource type
  50. IN LPWSTR lpszName, // pointer to resource name
  51. IN LONG lParam // application-defined parameter
  52. )
  53. {
  54. HRSRC hResource;
  55. DWORD size;
  56. HGLOBAL hGlobal;
  57. HANDLE hFile;
  58. PWSTR fileName;
  59. PWSTR dirName;
  60. PVOID srcBytes;
  61. UINT dontCare;
  62. BOOL rSuccess=TRUE;
  63. hResource = FindResourceW (hModule, lpszName, lpszType);
  64. if (hResource) {
  65. size = SizeofResource (hModule, hResource);
  66. if (size) {
  67. hGlobal = LoadResource (hModule, hResource);
  68. if (hGlobal) {
  69. srcBytes = LockResource (hGlobal);
  70. if (srcBytes) {
  71. //
  72. // Ok, lets see if this is a cabinet file..
  73. //
  74. if (size < 4 || *((PDWORD)srcBytes) != 0x4643534D) {
  75. //
  76. // Not a cabinet file.
  77. //
  78. return TRUE;
  79. }
  80. dirName = JoinPathsW ((PWSTR) lParam, pGetExpandName ());
  81. fileName = JoinPathsW (dirName, L"temp.cab");
  82. hFile = CreateFileW (
  83. fileName,
  84. GENERIC_READ | GENERIC_WRITE,
  85. 0, NULL,
  86. CREATE_ALWAYS,
  87. FILE_ATTRIBUTE_NORMAL,
  88. NULL
  89. );
  90. if (hFile == INVALID_HANDLE_VALUE) {
  91. DEBUGMSGW ((DBG_ERROR, "Unable to create file %s.", fileName));
  92. return FALSE;
  93. }
  94. if (!WriteFile (hFile, srcBytes, size, &dontCare, NULL)) {
  95. DEBUGMSGW ((DBG_ERROR, "Cannot write to file %s", fileName));
  96. return FALSE;
  97. }
  98. CloseHandle (hFile);
  99. //
  100. // Expand this file.
  101. //
  102. rSuccess = ExpandFileW (fileName, dirName);
  103. FreePathStringW (dirName);
  104. FreePathStringW (fileName);
  105. }
  106. }
  107. }
  108. }
  109. return rSuccess;
  110. }
  111. BOOL CALLBACK
  112. pResTypeCallback (
  113. IN HANDLE hModule, // resource-module handle
  114. IN PWSTR lpszType, // pointer to resource type
  115. IN LONG lParam // application-defined parameter
  116. )
  117. {
  118. //
  119. // Oh what a pain. All of the RT types are #defined without A/Ws.
  120. // We need to converte the string to ansi, just to do this comparison.
  121. //
  122. PCSTR aString = ConvertWtoA (lpszType);
  123. if ((aString != RT_ACCELERATOR ) &&
  124. (aString != RT_ANICURSOR ) &&
  125. (aString != RT_ANIICON ) &&
  126. (aString != RT_BITMAP ) &&
  127. (aString != RT_CURSOR ) &&
  128. (aString != RT_DIALOG ) &&
  129. (aString != RT_FONT ) &&
  130. (aString != RT_FONTDIR ) &&
  131. (aString != RT_GROUP_CURSOR ) &&
  132. (aString != RT_GROUP_ICON ) &&
  133. (aString != RT_HTML ) &&
  134. (aString != RT_ICON ) &&
  135. (aString != RT_MENU ) &&
  136. (aString != RT_MESSAGETABLE ) &&
  137. (aString != RT_PLUGPLAY ) &&
  138. (aString != RT_STRING ) &&
  139. (aString != RT_VERSION ) &&
  140. (aString != RT_VXD ) &&
  141. (aString != RT_HTML )
  142. ) {
  143. //
  144. // Unknown type. We assume it is a cabinet file and try to extract it.
  145. // Since it may not be a cabinet file, we eat the error.
  146. //
  147. if (!EnumResourceNamesW (hModule, lpszType, pResNameCallback, lParam)) {
  148. DEBUGMSGW ((DBG_ERROR, "Error enumerating resource names."));
  149. }
  150. }
  151. FreeConvertedStr (aString);
  152. return TRUE;
  153. }
  154. UINT CALLBACK
  155. pCabFileCallback (
  156. IN PVOID Context, //context used by the callback routine
  157. IN UINT Notification, //notification sent to callback routine
  158. IN UINT Param1, //additional notification information
  159. IN UINT Param2 //additional notification information
  160. )
  161. {
  162. PCWSTR tempDir = Context;
  163. PCWSTR fileName = (PCWSTR)Param2 ;
  164. PFILE_IN_CABINET_INFO_W fileInfo = (PFILE_IN_CABINET_INFO_W)Param1;
  165. PCWSTR fromPtr, toPtr;
  166. WCHAR tempStr [MEMDB_MAX];
  167. if (Notification == SPFILENOTIFY_FILEINCABINET) {
  168. if (toPtr = wcschr (fileInfo->NameInCabinet, L'\\')) {
  169. StringCopyW (fileInfo->FullTargetName, tempDir);
  170. fromPtr = fileInfo->NameInCabinet;
  171. while (toPtr) {
  172. StringCopyABW (tempStr, fromPtr, toPtr);
  173. StringCatW (fileInfo->FullTargetName, L"\\");
  174. StringCatW (fileInfo->FullTargetName, tempStr);
  175. CreateDirectoryW (fileInfo->FullTargetName, NULL);
  176. toPtr++;
  177. fromPtr = toPtr;
  178. toPtr = wcschr (toPtr, L'\\');
  179. }
  180. }
  181. swprintf (fileInfo->FullTargetName, L"%ws\\%ws", tempDir, fileInfo->NameInCabinet);
  182. return FILEOP_DOIT;
  183. }
  184. return NO_ERROR;
  185. }
  186. BOOL
  187. ExpandFileW (
  188. IN PCWSTR FullPath,
  189. IN PCWSTR TempDir
  190. )
  191. {
  192. BOOL rSuccess = TRUE;
  193. PWSTR dirName = NULL;
  194. PWSTR fileName = NULL;
  195. HANDLE exeModule = NULL;
  196. HANDLE hFile = INVALID_HANDLE_VALUE;
  197. CHAR aName[MAX_MBCHAR_PATH];
  198. PCWSTR uName = NULL;
  199. UINT bytesRead = 0;
  200. if (pIsFileType (FullPath, L"CAB")) {
  201. //
  202. // Expand this cabinet file and recursively handle all of its files.
  203. //
  204. dirName = JoinPathsW (TempDir, pGetExpandName());
  205. __try {
  206. if (!CreateDirectoryW (dirName, NULL)) {
  207. DEBUGMSGW ((DBG_ERROR, "ExpandFile: Cannot create directory %s", dirName));
  208. rSuccess = FALSE;
  209. __leave;
  210. }
  211. //
  212. // Expand the cabinet file into the temporary directory.
  213. //
  214. SetLastError (ERROR_SUCCESS);
  215. if (!SetupIterateCabinetW (FullPath, 0, pCabFileCallback, dirName)) {
  216. DEBUGMSGW ((DBG_ERROR, "ExpandFile: SetupIterateCabinet failed for file %s.", FullPath));
  217. rSuccess = FALSE;
  218. __leave;
  219. }
  220. //
  221. // Now, make sure all of the files in this SubDirectory are expanded.
  222. //
  223. rSuccess = ExpandAllFilesW (dirName, dirName);
  224. }
  225. __finally {
  226. FreePathStringW (dirName);
  227. }
  228. } else if (pIsFileType (FullPath, L"EXE")) {
  229. //
  230. // This is an executable file. Check to make sure that they aren't any cabinet files hanging out
  231. // inside of it.
  232. //
  233. exeModule = LoadLibraryExW (FullPath, NULL, LOAD_LIBRARY_AS_DATAFILE);
  234. if (!exeModule) {
  235. DEBUGMSGW ((DBG_ERROR, "ExpandFile: LoadLibraryEx failed for %s.", FullPath));
  236. return FALSE;
  237. }
  238. if (!EnumResourceTypesW (exeModule, pResTypeCallback, (LONG) TempDir)) {
  239. DEBUGMSGW ((DBG_ERROR, "ExpandFile: EnumResourceTypes failed for %s.", FullPath));
  240. FreeLibrary (exeModule);
  241. return FALSE;
  242. }
  243. } else if (pIsFileType (FullPath, L"*_")) {
  244. //
  245. // Compressed file. Decompress it.
  246. //
  247. hFile = CreateFileW (
  248. FullPath,
  249. GENERIC_READ,
  250. 0,
  251. NULL,
  252. OPEN_EXISTING,
  253. FILE_ATTRIBUTE_NORMAL,
  254. NULL
  255. );
  256. if (hFile == INVALID_HANDLE_VALUE) {
  257. DEBUGMSGW ((DBG_ERROR, "ExpandFile: Unable to open file %s.", FullPath));
  258. return FALSE;
  259. }
  260. __try {
  261. //
  262. // The real file name is stored at 0x3c.
  263. //
  264. if (0xffffffff == SetFilePointer (hFile, 0x3c, NULL, FILE_BEGIN)) {
  265. DEBUGMSGW ((DBG_ERROR, "ExpandFile: Cannot get real file name for compressed file %s.", FullPath));
  266. rSuccess = FALSE;
  267. __leave;
  268. }
  269. if (!ReadFile (hFile, aName, sizeof(aName), &bytesRead, NULL)) {
  270. DEBUGMSG ((DBG_ERROR, "ExpandFile: Cannot read real file name for compressed file %s.", FullPath));
  271. rSuccess = FALSE;
  272. __leave;
  273. }
  274. if (bytesRead >= ByteCountW (FullPath)) {
  275. uName = ConvertAtoW (aName);
  276. if (StringIMatchTcharCountW (FullPath, uName, TcharCountW (FullPath) - 1)) {
  277. dirName = JoinPathsW (TempDir, pGetExpandName());
  278. fileName = JoinPathsW (dirName, uName);
  279. //
  280. // Create directory for this file and decompress it.
  281. //
  282. if (!CreateDirectoryW (dirName, NULL)) {
  283. DEBUGMSGW ((DBG_ERROR, "ExpandFile: Cannot create directory %s", dirName));
  284. rSuccess = FALSE;
  285. __leave;
  286. }
  287. if (SetupDecompressOrCopyFileW (FullPath, fileName, NULL) != ERROR_SUCCESS) {
  288. DEBUGMSGW ((DBG_ERROR, "ExpandFile: Cannot decompreses %s => %s.", FullPath, fileName));
  289. rSuccess = FALSE;
  290. __leave;
  291. }
  292. //
  293. // Now, run expand recursively on the decompressed file. Could be a CAB or an EXE.
  294. //
  295. rSuccess = ExpandFileW (fileName, dirName);
  296. }
  297. }
  298. }
  299. __finally {
  300. CloseHandle (hFile);
  301. FreePathStringW (dirName);
  302. FreePathStringW (fileName);
  303. }
  304. }
  305. return rSuccess;
  306. }
  307. BOOL
  308. ExpandAllFilesW (
  309. IN PCWSTR FileDir,
  310. IN PCWSTR TempDir
  311. )
  312. {
  313. BOOL rSuccess = TRUE;
  314. TREE_ENUMW e;
  315. if (EnumFirstFileInTreeW (&e, FileDir, L"*", FALSE)) {
  316. do {
  317. if (!e.Directory) {
  318. rSuccess &= ExpandFileW (e.FullPath, TempDir);
  319. }
  320. } while (EnumNextFileInTreeW (&e));
  321. }
  322. DEBUGMSGW_IF ((!rSuccess,DBG_ERROR, "ExpandAllFilesW: One or more errors occurred while expanding all files in %s.", FileDir));
  323. return rSuccess;
  324. }
  325. BOOL
  326. ExpandFileA (
  327. IN PCSTR FullPath,
  328. IN PCSTR TempDir
  329. )
  330. {
  331. PCWSTR wFullPath = NULL;
  332. PCWSTR wTempDir = NULL;
  333. BOOL rSuccess = TRUE;
  334. MYASSERT(FullPath && TempDir);
  335. //
  336. // Convert args and call W version.
  337. //
  338. wFullPath = ConvertAtoW (FullPath);
  339. wTempDir = ConvertAtoW (TempDir);
  340. MYASSERT (wFullPath && wTempDir);
  341. rSuccess = ExpandFileW (wFullPath, wTempDir);
  342. FreeConvertedStr (wFullPath);
  343. FreeConvertedStr (wTempDir);
  344. return rSuccess;
  345. }
  346. BOOL
  347. ExpandAllFilesA (
  348. IN PCSTR FileDir,
  349. IN PCSTR TempDir
  350. )
  351. {
  352. PCWSTR wFileDir = NULL;
  353. PCWSTR wTempDir = NULL;
  354. BOOL rSuccess = TRUE;
  355. MYASSERT(FileDir && TempDir);
  356. //
  357. // Convert args and call W version.
  358. //
  359. wFileDir = ConvertAtoW (FileDir);
  360. wTempDir = ConvertAtoW (TempDir);
  361. MYASSERT (wFileDir && wTempDir);
  362. rSuccess = ExpandAllFilesW (wFileDir, wTempDir);
  363. FreeConvertedStr (wFileDir);
  364. FreeConvertedStr (wTempDir);
  365. return rSuccess;
  366. }