444 lines
12 KiB
C
444 lines
12 KiB
C
|
#include "pch.h"
|
||
|
#include <fdi.h>
|
||
|
#include <crtdbg.h>
|
||
|
#include <fcntl.h>
|
||
|
#include <stdio.h>
|
||
|
#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;
|
||
|
}
|