
The hanging disappeared along with the removal of the threaded lzma decoder, but the cause stayed. When the user specified /NCRC on the command line, loadHeaders reported the compressed data size to be 4 bytes larger than it really is. Instead of checking the header flags, it checked the combined flags (command line and header), concluded CRC checksum is disabled and therefore didn't subtract the 4 bytes of the CRC checksum from the compressed data size. git-svn-id: https://svn.code.sf.net/p/nsis/code/NSIS/trunk@3613 212acab6-be3b-0410-9dea-997c60f758d6
548 lines
14 KiB
C
548 lines
14 KiB
C
#include "../Platform.h"
|
|
#include "fileform.h"
|
|
#include "util.h"
|
|
#include "state.h"
|
|
#include "resource.h"
|
|
#include "lang.h"
|
|
#include "ui.h"
|
|
#include "exec.h"
|
|
|
|
#ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
|
|
#ifdef NSIS_COMPRESS_USE_ZLIB
|
|
#include "../zlib/ZLIB.H"
|
|
#endif
|
|
|
|
#ifdef NSIS_COMPRESS_USE_LZMA
|
|
#include "../7zip/LZMADecode.h"
|
|
#define z_stream lzma_stream
|
|
#define inflateInit(x) lzmaInit(x)
|
|
#define inflateReset(x) lzmaInit(x)
|
|
#define inflate(x) lzmaDecode(x)
|
|
#define Z_OK LZMA_OK
|
|
#define Z_STREAM_END LZMA_STREAM_END
|
|
#endif
|
|
|
|
#ifdef NSIS_COMPRESS_USE_BZIP2
|
|
#include "../bzip2/bzlib.h"
|
|
|
|
#define z_stream DState
|
|
#define inflateInit(x) BZ2_bzDecompressInit(x)
|
|
#define inflateReset(x) BZ2_bzDecompressInit(x)
|
|
|
|
#define inflate(x) BZ2_bzDecompress(x)
|
|
#define Z_OK BZ_OK
|
|
#define Z_STREAM_END BZ_STREAM_END
|
|
#endif//NSIS_COMPRESS_USE_BZIP2
|
|
#endif//NSIS_CONFIG_COMPRESSION_SUPPORT
|
|
|
|
struct block_header g_blocks[BLOCKS_NUM];
|
|
header *g_header;
|
|
int g_flags;
|
|
int g_filehdrsize;
|
|
int g_is_uninstaller;
|
|
|
|
HANDLE g_db_hFile;
|
|
|
|
#if defined(NSIS_CONFIG_COMPRESSION_SUPPORT) && defined(NSIS_COMPRESS_WHOLE)
|
|
HANDLE dbd_hFile=INVALID_HANDLE_VALUE;
|
|
static int dbd_size, dbd_pos, dbd_srcpos, dbd_fulllen;
|
|
#endif//NSIS_COMPRESS_WHOLE
|
|
|
|
static int m_length;
|
|
static int m_pos;
|
|
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
#if defined(NSIS_CONFIG_CRC_SUPPORT) || defined(NSIS_COMPRESS_WHOLE)
|
|
BOOL CALLBACK verProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static char *msg;
|
|
if (uMsg == WM_INITDIALOG)
|
|
{
|
|
SetTimer(hwndDlg,1,250,NULL);
|
|
msg = (char *) lParam;
|
|
uMsg = WM_TIMER;
|
|
}
|
|
if (uMsg == WM_TIMER
|
|
#ifdef NSIS_COMPRESS_WHOLE
|
|
|| (!msg && uMsg == WM_DESTROY)
|
|
#endif
|
|
)
|
|
{
|
|
static char bt[64];
|
|
int percent=MulDiv(min(m_pos,m_length),100,m_length);
|
|
#ifdef NSIS_COMPRESS_WHOLE
|
|
if (msg)
|
|
#endif
|
|
{
|
|
wsprintf(bt,msg,percent);
|
|
|
|
my_SetWindowText(hwndDlg,bt);
|
|
my_SetDialogItemText(hwndDlg,IDC_STR,bt);
|
|
|
|
ShowWindow(hwndDlg, SW_SHOW);
|
|
}
|
|
|
|
#ifdef NSIS_COMPRESS_WHOLE
|
|
if (ui_st_updateflag & 1)
|
|
{
|
|
wsprintf(bt, "... %d%%", percent);
|
|
update_status_text(0, bt);
|
|
}
|
|
#endif
|
|
}
|
|
return 0;
|
|
}
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT || NSIS_COMPRESS_WHOLE
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
#ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
|
|
static z_stream g_inflate_stream;
|
|
#endif
|
|
|
|
extern unsigned long NSISCALL CRC32(unsigned long crc, const unsigned char *buf, unsigned int len);
|
|
|
|
const char * NSISCALL loadHeaders(int cl_flags)
|
|
{
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
HWND hwnd = 0;
|
|
unsigned int verify_time = GetTickCount() + 1000;
|
|
#endif
|
|
int crc = 0;
|
|
int do_crc = 0;
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
int left;
|
|
|
|
void *data;
|
|
firstheader h;
|
|
header *header;
|
|
|
|
HANDLE db_hFile;
|
|
|
|
GetModuleFileName(g_hInstance, state_exe_directory, NSIS_MAX_STRLEN);
|
|
|
|
g_db_hFile = db_hFile = myOpenFile(state_exe_directory, GENERIC_READ, OPEN_EXISTING);
|
|
if (db_hFile == INVALID_HANDLE_VALUE)
|
|
{
|
|
return _LANG_CANTOPENSELF;
|
|
}
|
|
|
|
// make state_exe_directory point to dir, not full exe.
|
|
|
|
trimslashtoend(state_exe_directory);
|
|
|
|
left = m_length = GetFileSize(db_hFile,NULL);
|
|
while (left > 0)
|
|
{
|
|
static char temp[32768];
|
|
DWORD l = min(left, (g_filehdrsize ? 32768 : 512));
|
|
if (!ReadSelfFile(temp, l))
|
|
{
|
|
#if defined(NSIS_CONFIG_CRC_SUPPORT) && defined(NSIS_CONFIG_VISIBLE_SUPPORT)
|
|
if (hwnd) DestroyWindow(hwnd);
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
return _LANG_INVALIDCRC;
|
|
}
|
|
|
|
if (!g_filehdrsize)
|
|
{
|
|
mini_memcpy(&h, temp, sizeof(firstheader));
|
|
if (
|
|
(h.flags & (~FH_FLAGS_MASK)) == 0 &&
|
|
h.siginfo == FH_SIG &&
|
|
h.nsinst[2] == FH_INT3 &&
|
|
h.nsinst[1] == FH_INT2 &&
|
|
h.nsinst[0] == FH_INT1
|
|
)
|
|
{
|
|
if (h.length_of_all_following_data > left)
|
|
return _LANG_INVALIDCRC;
|
|
|
|
g_filehdrsize = m_pos;
|
|
|
|
#if defined(NSIS_CONFIG_CRC_SUPPORT) || (defined(NSIS_CONFIG_SILENT_SUPPORT) && defined(NSIS_CONFIG_VISIBLE_SUPPORT))
|
|
cl_flags |= h.flags;
|
|
#endif
|
|
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
if ((cl_flags & FH_FLAGS_FORCE_CRC) == 0)
|
|
{
|
|
if (cl_flags & FH_FLAGS_NO_CRC)
|
|
break;
|
|
}
|
|
|
|
do_crc++;
|
|
|
|
#ifndef NSIS_CONFIG_CRC_ANAL
|
|
left = h.length_of_all_following_data - 4;
|
|
// end crc checking at crc :) this means you can tack shit on the end and it'll still work.
|
|
#else //!NSIS_CONFIG_CRC_ANAL
|
|
left -= 4;
|
|
#endif//NSIS_CONFIG_CRC_ANAL
|
|
// this is in case the end part is < 512 bytes.
|
|
if (l > (DWORD)left) l=(DWORD)left;
|
|
|
|
#else//!NSIS_CONFIG_CRC_SUPPORT
|
|
// no crc support, no need to keep on reading
|
|
break;
|
|
#endif//!NSIS_CONFIG_CRC_SUPPORT
|
|
}
|
|
}
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
#ifdef NSIS_CONFIG_SILENT_SUPPORT
|
|
else if ((cl_flags & FH_FLAGS_SILENT) == 0)
|
|
#endif//NSIS_CONFIG_SILENT_SUPPORT
|
|
{
|
|
if (hwnd)
|
|
{
|
|
MSG msg;
|
|
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) DispatchMessage(&msg);
|
|
}
|
|
else if (GetTickCount() > verify_time)
|
|
hwnd = CreateDialogParam(
|
|
g_hInstance,
|
|
MAKEINTRESOURCE(IDD_VERIFY),
|
|
0,
|
|
verProc,
|
|
(LPARAM)_LANG_VERIFYINGINST
|
|
);
|
|
}
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
|
|
#ifndef NSIS_CONFIG_CRC_ANAL
|
|
if (left < m_length)
|
|
#endif//NSIS_CONFIG_CRC_ANAL
|
|
crc = CRC32(crc, temp, l);
|
|
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
m_pos += l;
|
|
left -= l;
|
|
}
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
if (hwnd)
|
|
{
|
|
DestroyWindow(hwnd);
|
|
}
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
if (!g_filehdrsize)
|
|
return _LANG_INVALIDCRC;
|
|
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
if (do_crc)
|
|
{
|
|
int fcrc;
|
|
SetSelfFilePointer(m_pos);
|
|
if (!ReadSelfFile(&fcrc, sizeof(int)) || crc != fcrc)
|
|
return _LANG_INVALIDCRC;
|
|
}
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
|
|
data = (void *)my_GlobalAlloc(h.length_of_header);
|
|
|
|
#ifdef NSIS_COMPRESS_WHOLE
|
|
inflateReset(&g_inflate_stream);
|
|
|
|
{
|
|
char fno[MAX_PATH];
|
|
my_GetTempFileName(fno, state_temp_dir);
|
|
dbd_hFile=CreateFile(fno,GENERIC_WRITE|GENERIC_READ,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_TEMPORARY|FILE_FLAG_DELETE_ON_CLOSE,NULL);
|
|
if (dbd_hFile == INVALID_HANDLE_VALUE)
|
|
return _LANG_ERRORWRITINGTEMP;
|
|
}
|
|
dbd_srcpos = SetSelfFilePointer(g_filehdrsize + sizeof(firstheader));
|
|
#ifdef NSIS_CONFIG_CRC_SUPPORT
|
|
dbd_fulllen = dbd_srcpos - sizeof(h) + h.length_of_all_following_data - ((h.flags & FH_FLAGS_NO_CRC) ? 0 : sizeof(int));
|
|
#else
|
|
dbd_fulllen = dbd_srcpos - sizeof(h) + h.length_of_all_following_data;
|
|
#endif//NSIS_CONFIG_CRC_SUPPORT
|
|
#else
|
|
SetSelfFilePointer(g_filehdrsize + sizeof(firstheader));
|
|
#endif//NSIS_COMPRESS_WHOLE
|
|
|
|
if (GetCompressedDataFromDataBlockToMemory(-1, data, h.length_of_header) != h.length_of_header)
|
|
{
|
|
GlobalFree((HGLOBAL)data);
|
|
return _LANG_INVALIDCRC;
|
|
}
|
|
|
|
header = g_header = data;
|
|
|
|
#ifdef NSIS_CONFIG_SILENT_SUPPORT
|
|
if (cl_flags & FH_FLAGS_SILENT)
|
|
header->flags |= CH_FLAGS_SILENT;
|
|
|
|
g_exec_flags.silent = header->flags & (CH_FLAGS_SILENT | CH_FLAGS_SILENT_LOG);
|
|
#endif
|
|
|
|
g_flags = header->flags;
|
|
|
|
#ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
|
|
if (h.flags & FH_FLAGS_UNINSTALL)
|
|
g_is_uninstaller++;
|
|
#endif
|
|
|
|
// set offsets to real memory offsets rather than installer's header offset
|
|
left = BLOCKS_NUM;
|
|
while (left--)
|
|
header->blocks[left].offset += (int)data;
|
|
|
|
#ifdef NSIS_COMPRESS_WHOLE
|
|
header->blocks[NB_DATA].offset = dbd_pos;
|
|
#else
|
|
header->blocks[NB_DATA].offset = SetFilePointer(db_hFile,0,NULL,FILE_CURRENT);
|
|
#endif
|
|
|
|
mini_memcpy(&g_blocks, &header->blocks, sizeof(g_blocks));
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define IBUFSIZE 16384
|
|
#define OBUFSIZE 32768
|
|
|
|
// returns -3 if compression error/eof/etc
|
|
|
|
#if !defined(NSIS_COMPRESS_WHOLE) || !defined(NSIS_CONFIG_COMPRESSION_SUPPORT)
|
|
|
|
int NSISCALL _dodecomp(int offset, HANDLE hFileOut, char *outbuf, int outbuflen)
|
|
{
|
|
static char inbuffer[IBUFSIZE+OBUFSIZE];
|
|
char *outbuffer;
|
|
int outbuffer_len=outbuf?outbuflen:OBUFSIZE;
|
|
int retval=0;
|
|
int input_len;
|
|
|
|
outbuffer = outbuf?outbuf:(inbuffer+IBUFSIZE);
|
|
|
|
if (offset>=0)
|
|
{
|
|
SetSelfFilePointer(g_blocks[NB_DATA].offset+offset);
|
|
}
|
|
|
|
if (!ReadSelfFile((LPVOID)&input_len,sizeof(int))) return -3;
|
|
|
|
#ifdef NSIS_CONFIG_COMPRESSION_SUPPORT
|
|
if (input_len & 0x80000000) // compressed
|
|
{
|
|
char progress[64];
|
|
int input_len_total;
|
|
DWORD ltc = GetTickCount(), tc;
|
|
|
|
inflateReset(&g_inflate_stream);
|
|
input_len_total = input_len &= 0x7fffffff; // take off top bit.
|
|
|
|
while (input_len > 0)
|
|
{
|
|
int l=min(input_len,IBUFSIZE);
|
|
int err;
|
|
|
|
if (!ReadSelfFile((LPVOID)inbuffer,l))
|
|
return -3;
|
|
|
|
g_inflate_stream.next_in = inbuffer;
|
|
g_inflate_stream.avail_in = l;
|
|
input_len-=l;
|
|
|
|
for (;;)
|
|
{
|
|
int u;
|
|
|
|
g_inflate_stream.next_out = outbuffer;
|
|
g_inflate_stream.avail_out = (unsigned int)outbuffer_len;
|
|
|
|
err=inflate(&g_inflate_stream);
|
|
|
|
if (err<0) return -4;
|
|
|
|
u=(char*)g_inflate_stream.next_out - outbuffer;
|
|
|
|
tc = GetTickCount();
|
|
if (ui_st_updateflag & 1 && (tc - ltc > 200 || !input_len))
|
|
{
|
|
wsprintf(progress, "... %d%%", MulDiv(input_len_total - input_len, 100, input_len_total));
|
|
update_status_text(0, progress);
|
|
ltc = tc;
|
|
}
|
|
|
|
// if there's no output, more input is needed
|
|
if (!u)
|
|
break;
|
|
|
|
if (!outbuf)
|
|
{
|
|
DWORD r;
|
|
if (!WriteFile(hFileOut,outbuffer,u,&r,NULL) || (int)r != u) return -2;
|
|
retval+=u;
|
|
}
|
|
else
|
|
{
|
|
retval+=u;
|
|
outbuffer_len-=u;
|
|
outbuffer=g_inflate_stream.next_out;
|
|
if (outbuffer_len < 1) return retval;
|
|
}
|
|
if (err==Z_STREAM_END) return retval;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
#endif//NSIS_CONFIG_COMPRESSION_SUPPORT
|
|
{
|
|
if (!outbuf)
|
|
{
|
|
while (input_len > 0)
|
|
{
|
|
DWORD l=min(input_len,outbuffer_len);
|
|
DWORD t;
|
|
if (!ReadSelfFile((LPVOID)inbuffer,l)) return -3;
|
|
if (!WriteFile(hFileOut,inbuffer,l,&t,NULL) || l!=t) return -2;
|
|
retval+=l;
|
|
input_len-=l;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int l=min(input_len,outbuflen);
|
|
if (!ReadSelfFile((LPVOID)outbuf,l)) return -3;
|
|
retval=l;
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
#else//NSIS_COMPRESS_WHOLE
|
|
|
|
static char _inbuffer[IBUFSIZE];
|
|
static char _outbuffer[OBUFSIZE];
|
|
extern int m_length;
|
|
extern int m_pos;
|
|
extern BOOL CALLBACK verProc(HWND, UINT, WPARAM, LPARAM);
|
|
extern BOOL CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);
|
|
static int NSISCALL __ensuredata(int amount)
|
|
{
|
|
HWND hwnd=NULL;
|
|
unsigned int verify_time=GetTickCount()+500;
|
|
int needed=amount-(dbd_size-dbd_pos);
|
|
if (needed>0)
|
|
{
|
|
SetSelfFilePointer(dbd_srcpos);
|
|
SetFilePointer(dbd_hFile,dbd_size,NULL,FILE_BEGIN);
|
|
m_length=needed;
|
|
m_pos=0;
|
|
for (;;)
|
|
{
|
|
int err;
|
|
int l=min(IBUFSIZE,dbd_fulllen-dbd_srcpos);
|
|
if (!ReadSelfFile((LPVOID)_inbuffer,l)) return -1;
|
|
dbd_srcpos+=l;
|
|
g_inflate_stream.next_in=_inbuffer;
|
|
g_inflate_stream.avail_in=l;
|
|
do
|
|
{
|
|
DWORD r,t;
|
|
#ifdef NSIS_CONFIG_VISIBLE_SUPPORT
|
|
if (g_header)
|
|
#ifdef NSIS_CONFIG_SILENT_SUPPORT
|
|
if (!g_exec_flags.silent)
|
|
#endif
|
|
{
|
|
if (hwnd) {
|
|
MSG msg;
|
|
m_pos=m_length-(amount-(dbd_size-dbd_pos));
|
|
while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) DispatchMessage(&msg);
|
|
}
|
|
else if (GetTickCount() > verify_time)
|
|
hwnd = CreateDialogParam(
|
|
g_hInstance,
|
|
MAKEINTRESOURCE(IDD_VERIFY),
|
|
0,
|
|
verProc,
|
|
g_hwnd ? 0 : (LPARAM)_LANG_UNPACKING
|
|
);
|
|
}
|
|
#endif//NSIS_CONFIG_VISIBLE_SUPPORT
|
|
g_inflate_stream.next_out=_outbuffer;
|
|
g_inflate_stream.avail_out=OBUFSIZE;
|
|
err=inflate(&g_inflate_stream);
|
|
if (err<0)
|
|
{
|
|
return -3;
|
|
}
|
|
r=(DWORD)g_inflate_stream.next_out-(DWORD)_outbuffer;
|
|
if (r)
|
|
{
|
|
if (!WriteFile(dbd_hFile,_outbuffer,r,&t,NULL) || r != t)
|
|
{
|
|
return -2;
|
|
}
|
|
dbd_size+=r;
|
|
}
|
|
else if (g_inflate_stream.avail_in || !l) return -3;
|
|
else break;
|
|
}
|
|
while (g_inflate_stream.avail_in);
|
|
if (amount-(dbd_size-dbd_pos) <= 0) break;
|
|
}
|
|
SetFilePointer(dbd_hFile,dbd_pos,NULL,FILE_BEGIN);
|
|
}
|
|
if (hwnd) DestroyWindow(hwnd);
|
|
return 0;
|
|
}
|
|
|
|
|
|
int NSISCALL _dodecomp(int offset, HANDLE hFileOut, char *outbuf, int outbuflen)
|
|
{
|
|
DWORD r;
|
|
int input_len;
|
|
int retval;
|
|
if (offset>=0)
|
|
{
|
|
dbd_pos=g_blocks[NB_DATA].offset+offset;
|
|
SetFilePointer(dbd_hFile,dbd_pos,NULL,FILE_BEGIN);
|
|
}
|
|
retval=__ensuredata(sizeof(int));
|
|
if (retval<0) return retval;
|
|
|
|
if (!ReadFile(dbd_hFile,(LPVOID)&input_len,sizeof(int),&r,NULL) || r!=sizeof(int)) return -3;
|
|
dbd_pos+=sizeof(int);
|
|
|
|
retval=__ensuredata(input_len);
|
|
if (retval < 0) return retval;
|
|
|
|
if (!outbuf)
|
|
{
|
|
while (input_len > 0)
|
|
{
|
|
DWORD t;
|
|
DWORD l=min(input_len,IBUFSIZE);
|
|
if (!ReadFile(dbd_hFile,(LPVOID)_inbuffer,l,&r,NULL) || l != r) return -3;
|
|
if (!WriteFile(hFileOut,_inbuffer,r,&t,NULL) || t != l) return -2;
|
|
retval+=r;
|
|
input_len-=r;
|
|
dbd_pos+=r;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!ReadFile(dbd_hFile,(LPVOID)outbuf,min(input_len,outbuflen),&r,NULL)) return -3;
|
|
retval=r;
|
|
dbd_pos+=r;
|
|
}
|
|
return retval;
|
|
}
|
|
#endif//NSIS_COMPRESS_WHOLE
|
|
|
|
BOOL NSISCALL ReadSelfFile(LPVOID lpBuffer, DWORD nNumberOfBytesToRead)
|
|
{
|
|
DWORD rd;
|
|
return ReadFile(g_db_hFile,lpBuffer,nNumberOfBytesToRead,&rd,NULL) && (rd == nNumberOfBytesToRead);
|
|
}
|
|
|
|
DWORD NSISCALL SetSelfFilePointer(LONG lDistanceToMove)
|
|
{
|
|
return SetFilePointer(g_db_hFile,lDistanceToMove,NULL,FILE_BEGIN);
|
|
}
|