#include "pch.h" #include #include #include #include #include "loader.h" // Types typedef struct _UNPACKEDFILE { PTSTR lpszFileName; PVOID nextFile; } UNPACKEDFILESTRUCT, *LPUNPACKEDFILE; // Globals static ERF g_ERF; static HFDI g_hFDI = NULL; static LPUNPACKEDFILE g_lpFileList = NULL; extern HINSTANCE g_hInstParent; extern HWND g_hWndParent; // Prototypes VOID AddFileToList( PTSTR ); PVOID DIAMONDAPI CabAlloc ( IN ULONG Size ) { return ALLOC( Size ); } VOID DIAMONDAPI CabFree ( IN PVOID Memory ) { FREE( Memory ); } INT_PTR DIAMONDAPI CabOpen ( IN PSTR FileName, IN INT oFlag, IN INT pMode ) { HANDLE fileHandle; // oFlag and pMode are prepared for using _open. We won't do that // and it's a terrible waste of time to check each individual flags // We'll just assert these values. _ASSERT (oFlag == _O_BINARY); fileHandle = CreateFile (FileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ARCHIVE, NULL ); if (fileHandle == INVALID_HANDLE_VALUE) { return -1; } return (INT_PTR)fileHandle; } UINT DIAMONDAPI CabRead ( IN INT_PTR FileHandle, IN PVOID Buffer, IN UINT Size ) { BOOL result; ULONG bytesRead; result = ReadFile ((HANDLE)FileHandle, Buffer, Size, &bytesRead, NULL); if (!result) { return ((UINT)(-1)); } return bytesRead; } UINT DIAMONDAPI CabWrite ( IN INT_PTR FileHandle, IN PVOID Buffer, IN UINT Size ) { BOOL result; DWORD bytesWritten; result = WriteFile ((HANDLE)FileHandle, Buffer, Size, &bytesWritten, NULL); if (!result) { return ((UINT)(-1)); } return Size; } INT DIAMONDAPI CabClose ( IN INT_PTR FileHandle ) { CloseHandle ((HANDLE)FileHandle); return 0; } LONG DIAMONDAPI CabSeek ( IN INT_PTR FileHandle, IN LONG Distance, IN INT SeekType ) { DWORD result; DWORD seekType = FILE_BEGIN; switch (SeekType) { case SEEK_SET: seekType = FILE_BEGIN; break; case SEEK_CUR: seekType = FILE_CURRENT; break; case SEEK_END: seekType = FILE_END; break; } result = SetFilePointer ((HANDLE)FileHandle, Distance, NULL, seekType); if (result == INVALID_SET_FILE_POINTER) { return -1; } return ((LONG)(result)); } INT_PTR DIAMONDAPI CabUnpackStatus ( IN FDINOTIFICATIONTYPE fdiType, IN FDINOTIFICATION *pfdiNotification ) { HANDLE destHandle = NULL; PTSTR destFileName = NULL; FILETIME localFileTime; FILETIME fileTime; BOOL fSkip = FALSE; PTSTR lpszDestPath = NULL; TCHAR destName [MAX_PATH]; PTSTR destPtr = NULL; switch (fdiType) { case fdintCOPY_FILE: // File to be copied // pfdin->psz1 = file name in cabinet // pfdin->cb = uncompressed size of file // pfdin->date = file date // pfdin->time = file time // pfdin->attribs = file attributes // pfdin->iFolder = file's folder index if (_tcsicmp (pfdiNotification->psz1, TEXT("migwiz.exe.manifest")) == 0) { // Only copy the manifest if this OS is later than Whistler beta 1 fSkip = TRUE; if (g_VersionInfo.dwMajorVersion >= 5 && (g_VersionInfo.dwMinorVersion > 1 || (g_VersionInfo.dwMinorVersion == 1 && g_VersionInfo.dwBuildNumber >= 2424))) { fSkip = FALSE; } } if (!fSkip) { // let's look at the system and decide the destination name for the file ZeroMemory (destName, sizeof (destName)); _tcsncpy (destName, pfdiNotification->psz1, MAX_PATH - 1); destPtr = _tcsrchr (pfdiNotification->psz1, TEXT('_')); if (destPtr) { if (_tcsncmp (destPtr, TEXT("_a."), 3) == 0) { if (g_VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) { // this is an ANSI file, don't copy it on NT fSkip = TRUE; } else { // this is an ANSI file, rename it on Win9x ZeroMemory (destName, sizeof (destName)); CopyMemory (destName, pfdiNotification->psz1, (UINT) (destPtr - pfdiNotification->psz1) * sizeof (TCHAR)); destPtr += 2; _tcscat (destName, destPtr); } } if (_tcsncmp (destPtr, TEXT("_u."), 3) == 0) { if (g_VersionInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { // this is an UNICODE file, don't copy it on NT fSkip = TRUE; } else { // this is an UNICODE file, rename it on Win9x ZeroMemory (destName, sizeof (destName)); CopyMemory (destName, pfdiNotification->psz1, (UINT) (destPtr - pfdiNotification->psz1) * sizeof (TCHAR)); destPtr += 2; _tcscat (destName, destPtr); } } } if (!fSkip) { SendMessage( g_hWndParent, WM_USER_UNPACKING_FILE, (WPARAM)NULL, (LPARAM)destName); lpszDestPath = GetDestPath(); // Do not free lpszDestPath, because it is a pointer to a global if (lpszDestPath) { destFileName = JoinPaths( lpszDestPath, destName); } if (destFileName) { destHandle = CreateFile( destFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, NULL ); AddFileToList( destFileName ); FREE( destFileName ); } } } return (INT_PTR)destHandle; case fdintCLOSE_FILE_INFO: // close the file, set relevant info // Called after all of the data has been written to a target file. // This function must close the file and set the file date, time, // and attributes. // Entry: // pfdin->psz1 = file name in cabinet // pfdin->hf = file handle // pfdin->date = file date // pfdin->time = file time // pfdin->attribs = file attributes // pfdin->iFolder = file's folder index // pfdin->cb = Run After Extract (0 - don't run, 1 Run) // Exit-Success: // Returns TRUE // Exit-Failure: // Returns FALSE, or -1 to abort; // // IMPORTANT NOTE IMPORTANT: // pfdin->cb is overloaded to no longer be the size of // the file but to be a binary indicated run or not // // IMPORTANT NOTE: // FDI assumes that the target file was closed, even if this // callback returns failure. FDI will NOT attempt to use // the PFNCLOSE function supplied on FDICreate() to close // the file! if (DosDateTimeToFileTime (pfdiNotification->date, pfdiNotification->time, &localFileTime)) { if (LocalFileTimeToFileTime (&localFileTime, &fileTime)) { SetFileTime ((HANDLE)pfdiNotification->hf, &fileTime, &fileTime, &fileTime); } } CloseHandle ((HANDLE)pfdiNotification->hf); // attributes = (pfdiNotification->attribs & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_ARCHIVE)) | FILE_ATTRIBUTE_TEMPORARY; // SetFileAttributes (destFile, attributes); // FreePathString (destFile); return TRUE; case fdintCABINET_INFO: // return success return 0; case fdintENUMERATE: // return success return 0; case fdintPARTIAL_FILE: // return failure return -1; case fdintNEXT_CABINET: // return failure return -1; default: break; } return 0; } VOID AddFileToList( PTSTR lpszFilename ) { LPUNPACKEDFILE lpNewFile; lpNewFile = (LPUNPACKEDFILE)ALLOC( sizeof(UNPACKEDFILESTRUCT) ); if (lpNewFile) { lpNewFile->lpszFileName = (PTSTR)ALLOC( (lstrlen(lpszFilename) + 1) * sizeof(TCHAR) ); if (lpNewFile->lpszFileName) { lstrcpy( lpNewFile->lpszFileName, lpszFilename ); lpNewFile->nextFile = g_lpFileList; g_lpFileList = lpNewFile; } } } VOID CleanupTempFiles( VOID ) { LPUNPACKEDFILE lpFile = g_lpFileList; PTSTR lpszDestPath; while (lpFile) { g_lpFileList = (LPUNPACKEDFILE)lpFile->nextFile; if (lpFile->lpszFileName) { DeleteFile( lpFile->lpszFileName ); FREE( lpFile->lpszFileName ); } lpFile = g_lpFileList; } lpszDestPath = GetDestPath(); if (lpszDestPath) { RemoveDirectory( lpszDestPath ); // Do not free lpszDestPath, because it is a pointer to a global value } } ERRORCODE Unpack( VOID ) { ERRORCODE ecResult = E_OK; PTSTR lpszCabFilename; PTSTR lpszDestPath; TCHAR szModulePath[MAX_PATH]; TCHAR szDestFile[MAX_PATH]; // Create the File Decompression Interface context g_hFDI = FDICreate( CabAlloc, CabFree, CabOpen, CabRead, CabWrite, CabClose, CabSeek, cpuUNKNOWN, // WARNING: Don't use auto-detect from a 16-bit Windows // application! Use GetWinFlags()! &g_ERF ); if (g_hFDI == NULL) { ecResult = E_UNPACK_FAILED; goto END; } // Create Dest Directory lpszDestPath = GetDestPath(); // Do not free lpszDestPath, because it is a pointer to a global value if (!lpszDestPath) { ecResult = E_INVALID_PATH; goto END; } lpszCabFilename = GetResourceString( g_hInstParent, IDS_CABFILENAME ); if (lpszCabFilename == NULL) { ecResult = E_INVALID_FILENAME; } else { // Unpack the CAB if (!FDICopy( g_hFDI, lpszCabFilename, // Only filename GetModulePath(), // Only path 0, CabUnpackStatus, NULL, NULL )) { switch (g_ERF.erfOper) { case FDIERROR_CABINET_NOT_FOUND: ecResult = E_CAB_NOT_FOUND; break; case FDIERROR_NOT_A_CABINET: case FDIERROR_UNKNOWN_CABINET_VERSION: case FDIERROR_CORRUPT_CABINET: ecResult = E_CAB_CORRUPT; break; default: ecResult = E_UNPACK_FAILED; break; } goto END; } FREE( lpszCabFilename ); } // Now copy migload.exe to the dest. This is needed for creating wizard disks. if (GetModuleFileName( NULL, szModulePath, MAX_PATH )) { _tcscpy( szDestFile, lpszDestPath ); _tcscat( szDestFile, TEXT("migload.exe")); CopyFile( szModulePath, szDestFile, FALSE ); } END: if (g_hFDI) { FDIDestroy( g_hFDI ); } return ecResult; }