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.

443 lines
12 KiB

  1. #include "pch.h"
  2. #include <fdi.h>
  3. #include <crtdbg.h>
  4. #include <fcntl.h>
  5. #include <stdio.h>
  6. #include "loader.h"
  7. // Types
  8. typedef struct _UNPACKEDFILE
  9. {
  10. PTSTR lpszFileName;
  11. PVOID nextFile;
  12. } UNPACKEDFILESTRUCT, *LPUNPACKEDFILE;
  13. // Globals
  14. static ERF g_ERF;
  15. static HFDI g_hFDI = NULL;
  16. static LPUNPACKEDFILE g_lpFileList = NULL;
  17. extern HINSTANCE g_hInstParent;
  18. extern HWND g_hWndParent;
  19. // Prototypes
  20. VOID AddFileToList( PTSTR );
  21. PVOID
  22. DIAMONDAPI
  23. CabAlloc (
  24. IN ULONG Size
  25. )
  26. {
  27. return ALLOC( Size );
  28. }
  29. VOID
  30. DIAMONDAPI
  31. CabFree (
  32. IN PVOID Memory
  33. )
  34. {
  35. FREE( Memory );
  36. }
  37. INT_PTR
  38. DIAMONDAPI
  39. CabOpen (
  40. IN PSTR FileName,
  41. IN INT oFlag,
  42. IN INT pMode
  43. )
  44. {
  45. HANDLE fileHandle;
  46. // oFlag and pMode are prepared for using _open. We won't do that
  47. // and it's a terrible waste of time to check each individual flags
  48. // We'll just assert these values.
  49. _ASSERT (oFlag == _O_BINARY);
  50. fileHandle = CreateFile (FileName,
  51. GENERIC_READ,
  52. FILE_SHARE_READ,
  53. NULL,
  54. OPEN_EXISTING,
  55. FILE_ATTRIBUTE_ARCHIVE,
  56. NULL
  57. );
  58. if (fileHandle == INVALID_HANDLE_VALUE)
  59. {
  60. return -1;
  61. }
  62. return (INT_PTR)fileHandle;
  63. }
  64. UINT
  65. DIAMONDAPI
  66. CabRead (
  67. IN INT_PTR FileHandle,
  68. IN PVOID Buffer,
  69. IN UINT Size
  70. )
  71. {
  72. BOOL result;
  73. ULONG bytesRead;
  74. result = ReadFile ((HANDLE)FileHandle, Buffer, Size, &bytesRead, NULL);
  75. if (!result) {
  76. return ((UINT)(-1));
  77. }
  78. return bytesRead;
  79. }
  80. UINT
  81. DIAMONDAPI
  82. CabWrite (
  83. IN INT_PTR FileHandle,
  84. IN PVOID Buffer,
  85. IN UINT Size
  86. )
  87. {
  88. BOOL result;
  89. DWORD bytesWritten;
  90. result = WriteFile ((HANDLE)FileHandle, Buffer, Size, &bytesWritten, NULL);
  91. if (!result) {
  92. return ((UINT)(-1));
  93. }
  94. return Size;
  95. }
  96. INT
  97. DIAMONDAPI
  98. CabClose (
  99. IN INT_PTR FileHandle
  100. )
  101. {
  102. CloseHandle ((HANDLE)FileHandle);
  103. return 0;
  104. }
  105. LONG
  106. DIAMONDAPI
  107. CabSeek (
  108. IN INT_PTR FileHandle,
  109. IN LONG Distance,
  110. IN INT SeekType
  111. )
  112. {
  113. DWORD result;
  114. DWORD seekType = FILE_BEGIN;
  115. switch (SeekType) {
  116. case SEEK_SET:
  117. seekType = FILE_BEGIN;
  118. break;
  119. case SEEK_CUR:
  120. seekType = FILE_CURRENT;
  121. break;
  122. case SEEK_END:
  123. seekType = FILE_END;
  124. break;
  125. }
  126. result = SetFilePointer ((HANDLE)FileHandle, Distance, NULL, seekType);
  127. if (result == INVALID_SET_FILE_POINTER) {
  128. return -1;
  129. }
  130. return ((LONG)(result));
  131. }
  132. INT_PTR
  133. DIAMONDAPI
  134. CabUnpackStatus
  135. (
  136. IN FDINOTIFICATIONTYPE fdiType,
  137. IN FDINOTIFICATION *pfdiNotification
  138. )
  139. {
  140. HANDLE destHandle = NULL;
  141. PTSTR destFileName = NULL;
  142. FILETIME localFileTime;
  143. FILETIME fileTime;
  144. BOOL fSkip = FALSE;
  145. PTSTR lpszDestPath = NULL;
  146. TCHAR destName [MAX_PATH];
  147. PTSTR destPtr = NULL;
  148. switch (fdiType)
  149. {
  150. case fdintCOPY_FILE: // File to be copied
  151. // pfdin->psz1 = file name in cabinet
  152. // pfdin->cb = uncompressed size of file
  153. // pfdin->date = file date
  154. // pfdin->time = file time
  155. // pfdin->attribs = file attributes
  156. // pfdin->iFolder = file's folder index
  157. if (_tcsicmp (pfdiNotification->psz1, TEXT("migwiz.exe.manifest")) == 0)
  158. {
  159. // Only copy the manifest if this OS is later than Whistler beta 1
  160. fSkip = TRUE;
  161. if (g_VersionInfo.dwMajorVersion >= 5 &&
  162. (g_VersionInfo.dwMinorVersion > 1 ||
  163. (g_VersionInfo.dwMinorVersion == 1 &&
  164. g_VersionInfo.dwBuildNumber >= 2424)))
  165. {
  166. fSkip = FALSE;
  167. }
  168. }
  169. if (!fSkip)
  170. {
  171. // let's look at the system and decide the destination name for the file
  172. ZeroMemory (destName, sizeof (destName));
  173. _tcsncpy (destName, pfdiNotification->psz1, MAX_PATH - 1);
  174. destPtr = _tcsrchr (pfdiNotification->psz1, TEXT('_'));
  175. if (destPtr) {
  176. if (_tcsncmp (destPtr, TEXT("_a."), 3) == 0) {
  177. if (g_VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
  178. // this is an ANSI file, don't copy it on NT
  179. fSkip = TRUE;
  180. } else {
  181. // this is an ANSI file, rename it on Win9x
  182. ZeroMemory (destName, sizeof (destName));
  183. CopyMemory (destName, pfdiNotification->psz1, (UINT) (destPtr - pfdiNotification->psz1) * sizeof (TCHAR));
  184. destPtr += 2;
  185. _tcscat (destName, destPtr);
  186. }
  187. }
  188. if (_tcsncmp (destPtr, TEXT("_u."), 3) == 0) {
  189. if (g_VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
  190. // this is an UNICODE file, don't copy it on NT
  191. fSkip = TRUE;
  192. } else {
  193. // this is an UNICODE file, rename it on Win9x
  194. ZeroMemory (destName, sizeof (destName));
  195. CopyMemory (destName, pfdiNotification->psz1, (UINT) (destPtr - pfdiNotification->psz1) * sizeof (TCHAR));
  196. destPtr += 2;
  197. _tcscat (destName, destPtr);
  198. }
  199. }
  200. }
  201. if (!fSkip) {
  202. SendMessage( g_hWndParent, WM_USER_UNPACKING_FILE, (WPARAM)NULL, (LPARAM)destName);
  203. lpszDestPath = GetDestPath();
  204. // Do not free lpszDestPath, because it is a pointer to a global
  205. if (lpszDestPath)
  206. {
  207. destFileName = JoinPaths( lpszDestPath, destName);
  208. }
  209. if (destFileName)
  210. {
  211. destHandle = CreateFile( destFileName,
  212. GENERIC_WRITE,
  213. 0,
  214. NULL,
  215. CREATE_ALWAYS,
  216. FILE_ATTRIBUTE_TEMPORARY,
  217. NULL );
  218. AddFileToList( destFileName );
  219. FREE( destFileName );
  220. }
  221. }
  222. }
  223. return (INT_PTR)destHandle;
  224. case fdintCLOSE_FILE_INFO: // close the file, set relevant info
  225. // Called after all of the data has been written to a target file.
  226. // This function must close the file and set the file date, time,
  227. // and attributes.
  228. // Entry:
  229. // pfdin->psz1 = file name in cabinet
  230. // pfdin->hf = file handle
  231. // pfdin->date = file date
  232. // pfdin->time = file time
  233. // pfdin->attribs = file attributes
  234. // pfdin->iFolder = file's folder index
  235. // pfdin->cb = Run After Extract (0 - don't run, 1 Run)
  236. // Exit-Success:
  237. // Returns TRUE
  238. // Exit-Failure:
  239. // Returns FALSE, or -1 to abort;
  240. //
  241. // IMPORTANT NOTE IMPORTANT:
  242. // pfdin->cb is overloaded to no longer be the size of
  243. // the file but to be a binary indicated run or not
  244. //
  245. // IMPORTANT NOTE:
  246. // FDI assumes that the target file was closed, even if this
  247. // callback returns failure. FDI will NOT attempt to use
  248. // the PFNCLOSE function supplied on FDICreate() to close
  249. // the file!
  250. if (DosDateTimeToFileTime (pfdiNotification->date, pfdiNotification->time, &localFileTime)) {
  251. if (LocalFileTimeToFileTime (&localFileTime, &fileTime)) {
  252. SetFileTime ((HANDLE)pfdiNotification->hf, &fileTime, &fileTime, &fileTime);
  253. }
  254. }
  255. CloseHandle ((HANDLE)pfdiNotification->hf);
  256. // attributes = (pfdiNotification->attribs & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE)) | FILE_ATTRIBUTE_TEMPORARY;
  257. // SetFileAttributes (destFile, attributes);
  258. // FreePathString (destFile);
  259. return TRUE;
  260. case fdintCABINET_INFO:
  261. // return success
  262. return 0;
  263. case fdintENUMERATE:
  264. // return success
  265. return 0;
  266. case fdintPARTIAL_FILE:
  267. // return failure
  268. return -1;
  269. case fdintNEXT_CABINET:
  270. // return failure
  271. return -1;
  272. default:
  273. break;
  274. }
  275. return 0;
  276. }
  277. VOID
  278. AddFileToList( PTSTR lpszFilename )
  279. {
  280. LPUNPACKEDFILE lpNewFile;
  281. lpNewFile = (LPUNPACKEDFILE)ALLOC( sizeof(UNPACKEDFILESTRUCT) );
  282. if (lpNewFile)
  283. {
  284. lpNewFile->lpszFileName = (PTSTR)ALLOC( (lstrlen(lpszFilename) + 1) * sizeof(TCHAR) );
  285. if (lpNewFile->lpszFileName)
  286. {
  287. lstrcpy( lpNewFile->lpszFileName, lpszFilename );
  288. lpNewFile->nextFile = g_lpFileList;
  289. g_lpFileList = lpNewFile;
  290. }
  291. }
  292. }
  293. VOID
  294. CleanupTempFiles( VOID )
  295. {
  296. LPUNPACKEDFILE lpFile = g_lpFileList;
  297. PTSTR lpszDestPath;
  298. while (lpFile)
  299. {
  300. g_lpFileList = (LPUNPACKEDFILE)lpFile->nextFile;
  301. if (lpFile->lpszFileName)
  302. {
  303. DeleteFile( lpFile->lpszFileName );
  304. FREE( lpFile->lpszFileName );
  305. }
  306. lpFile = g_lpFileList;
  307. }
  308. lpszDestPath = GetDestPath();
  309. if (lpszDestPath)
  310. {
  311. RemoveDirectory( lpszDestPath );
  312. // Do not free lpszDestPath, because it is a pointer to a global value
  313. }
  314. }
  315. ERRORCODE
  316. Unpack( VOID )
  317. {
  318. ERRORCODE ecResult = E_OK;
  319. PTSTR lpszCabFilename;
  320. PTSTR lpszDestPath;
  321. TCHAR szModulePath[MAX_PATH];
  322. TCHAR szDestFile[MAX_PATH];
  323. // Create the File Decompression Interface context
  324. g_hFDI = FDICreate( CabAlloc,
  325. CabFree,
  326. CabOpen,
  327. CabRead,
  328. CabWrite,
  329. CabClose,
  330. CabSeek,
  331. cpuUNKNOWN, // WARNING: Don't use auto-detect from a 16-bit Windows
  332. // application! Use GetWinFlags()!
  333. &g_ERF );
  334. if (g_hFDI == NULL)
  335. {
  336. ecResult = E_UNPACK_FAILED;
  337. goto END;
  338. }
  339. // Create Dest Directory
  340. lpszDestPath = GetDestPath();
  341. // Do not free lpszDestPath, because it is a pointer to a global value
  342. if (!lpszDestPath)
  343. {
  344. ecResult = E_INVALID_PATH;
  345. goto END;
  346. }
  347. lpszCabFilename = GetResourceString( g_hInstParent, IDS_CABFILENAME );
  348. if (lpszCabFilename == NULL)
  349. {
  350. ecResult = E_INVALID_FILENAME;
  351. }
  352. else
  353. {
  354. // Unpack the CAB
  355. if (!FDICopy( g_hFDI,
  356. lpszCabFilename, // Only filename
  357. GetModulePath(), // Only path
  358. 0,
  359. CabUnpackStatus,
  360. NULL,
  361. NULL ))
  362. {
  363. switch (g_ERF.erfOper)
  364. {
  365. case FDIERROR_CABINET_NOT_FOUND:
  366. ecResult = E_CAB_NOT_FOUND;
  367. break;
  368. case FDIERROR_NOT_A_CABINET:
  369. case FDIERROR_UNKNOWN_CABINET_VERSION:
  370. case FDIERROR_CORRUPT_CABINET:
  371. ecResult = E_CAB_CORRUPT;
  372. break;
  373. default:
  374. ecResult = E_UNPACK_FAILED;
  375. break;
  376. }
  377. goto END;
  378. }
  379. FREE( lpszCabFilename );
  380. }
  381. // Now copy migload.exe to the dest. This is needed for creating wizard disks.
  382. if (GetModuleFileName( NULL, szModulePath, MAX_PATH )) {
  383. _tcscpy( szDestFile, lpszDestPath );
  384. _tcscat( szDestFile, TEXT("migload.exe"));
  385. CopyFile( szModulePath, szDestFile, FALSE );
  386. }
  387. END:
  388. if (g_hFDI)
  389. {
  390. FDIDestroy( g_hFDI );
  391. }
  392. return ecResult;
  393. }