421 lines
8.4 KiB
C++
421 lines
8.4 KiB
C++
#include "rar.hpp"
|
|
|
|
ErrorHandler::ErrorHandler()
|
|
{
|
|
Clean();
|
|
}
|
|
|
|
|
|
void ErrorHandler::Clean()
|
|
{
|
|
ExitCode=RARX_SUCCESS;
|
|
ErrCount=0;
|
|
EnableBreak=true;
|
|
Silent=false;
|
|
UserBreak=false;
|
|
MainExit=false;
|
|
DisableShutdown=false;
|
|
ReadErrIgnoreAll=false;
|
|
}
|
|
|
|
|
|
void ErrorHandler::MemoryError()
|
|
{
|
|
MemoryErrorMsg();
|
|
Exit(RARX_MEMORY);
|
|
}
|
|
|
|
|
|
void ErrorHandler::OpenError(const wchar *FileName)
|
|
{
|
|
#ifndef SILENT
|
|
OpenErrorMsg(FileName);
|
|
Exit(RARX_OPEN);
|
|
#endif
|
|
}
|
|
|
|
|
|
void ErrorHandler::CloseError(const wchar *FileName)
|
|
{
|
|
if (!UserBreak)
|
|
{
|
|
uiMsg(UIERROR_FILECLOSE,FileName);
|
|
SysErrMsg();
|
|
}
|
|
// We must not call Exit and throw an exception here, because this function
|
|
// is called from File object destructor and can be invoked when stack
|
|
// unwinding while handling another exception. Throwing a new exception
|
|
// when stack unwinding is prohibited and terminates a program.
|
|
// If necessary, we can check std::uncaught_exception() before throw.
|
|
SetErrorCode(RARX_FATAL);
|
|
}
|
|
|
|
|
|
void ErrorHandler::ReadError(const wchar *FileName)
|
|
{
|
|
#ifndef SILENT
|
|
ReadErrorMsg(FileName);
|
|
#endif
|
|
#if !defined(SILENT) || defined(RARDLL)
|
|
Exit(RARX_READ);
|
|
#endif
|
|
}
|
|
|
|
|
|
void ErrorHandler::AskRepeatRead(const wchar *FileName,bool &Ignore,bool &Retry,bool &Quit)
|
|
{
|
|
SetErrorCode(RARX_READ);
|
|
#if !defined(SILENT) && !defined(SFX_MODULE)
|
|
if (!Silent)
|
|
{
|
|
uiMsg(UIERROR_FILEREAD,UINULL,FileName);
|
|
SysErrMsg();
|
|
if (ReadErrIgnoreAll)
|
|
Ignore=true;
|
|
else
|
|
{
|
|
bool All=false;
|
|
uiAskRepeatRead(FileName,Ignore,All,Retry,Quit);
|
|
if (All)
|
|
ReadErrIgnoreAll=Ignore=true;
|
|
if (Quit) // Disable shutdown if user select Quit in read error prompt.
|
|
DisableShutdown=true;
|
|
}
|
|
return;
|
|
}
|
|
#endif
|
|
Ignore=true; // Saving the file part for -y or -inul or "Ignore all" choice.
|
|
}
|
|
|
|
|
|
void ErrorHandler::WriteError(const wchar *ArcName,const wchar *FileName)
|
|
{
|
|
#ifndef SILENT
|
|
WriteErrorMsg(ArcName,FileName);
|
|
#endif
|
|
#if !defined(SILENT) || defined(RARDLL)
|
|
Exit(RARX_WRITE);
|
|
#endif
|
|
}
|
|
|
|
|
|
#ifdef _WIN_ALL
|
|
void ErrorHandler::WriteErrorFAT(const wchar *FileName)
|
|
{
|
|
SysErrMsg();
|
|
uiMsg(UIERROR_NTFSREQUIRED,FileName);
|
|
#if !defined(SILENT) && !defined(SFX_MODULE) || defined(RARDLL)
|
|
Exit(RARX_WRITE);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
|
|
bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull)
|
|
{
|
|
#ifndef SILENT
|
|
if (!Silent)
|
|
{
|
|
// We do not display "repeat write" prompt in Android, so we do not
|
|
// need the matching system error message.
|
|
SysErrMsg();
|
|
bool Repeat=uiAskRepeatWrite(FileName,DiskFull);
|
|
if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog.
|
|
DisableShutdown=true;
|
|
return Repeat;
|
|
}
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
|
|
void ErrorHandler::SeekError(const wchar *FileName)
|
|
{
|
|
if (!UserBreak)
|
|
{
|
|
uiMsg(UIERROR_FILESEEK,FileName);
|
|
SysErrMsg();
|
|
}
|
|
#if !defined(SILENT) || defined(RARDLL)
|
|
Exit(RARX_FATAL);
|
|
#endif
|
|
}
|
|
|
|
|
|
void ErrorHandler::GeneralErrMsg(const wchar *fmt,...)
|
|
{
|
|
va_list arglist;
|
|
va_start(arglist,fmt);
|
|
wchar Msg[1024];
|
|
vswprintf(Msg,ASIZE(Msg),fmt,arglist);
|
|
uiMsg(UIERROR_GENERALERRMSG,Msg);
|
|
SysErrMsg();
|
|
va_end(arglist);
|
|
}
|
|
|
|
|
|
void ErrorHandler::MemoryErrorMsg()
|
|
{
|
|
uiMsg(UIERROR_MEMORY);
|
|
SetErrorCode(RARX_MEMORY);
|
|
}
|
|
|
|
|
|
void ErrorHandler::OpenErrorMsg(const wchar *FileName)
|
|
{
|
|
OpenErrorMsg(NULL,FileName);
|
|
}
|
|
|
|
|
|
void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
|
|
{
|
|
Wait(); // Keep GUI responsive if many files cannot be opened when archiving.
|
|
uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
|
|
SysErrMsg();
|
|
SetErrorCode(RARX_OPEN);
|
|
}
|
|
|
|
|
|
void ErrorHandler::CreateErrorMsg(const wchar *FileName)
|
|
{
|
|
CreateErrorMsg(NULL,FileName);
|
|
}
|
|
|
|
|
|
void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName)
|
|
{
|
|
uiMsg(UIERROR_FILECREATE,ArcName,FileName);
|
|
SysErrMsg();
|
|
SetErrorCode(RARX_CREATE);
|
|
}
|
|
|
|
|
|
void ErrorHandler::ReadErrorMsg(const wchar *FileName)
|
|
{
|
|
ReadErrorMsg(NULL,FileName);
|
|
}
|
|
|
|
|
|
void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName)
|
|
{
|
|
uiMsg(UIERROR_FILEREAD,ArcName,FileName);
|
|
SysErrMsg();
|
|
SetErrorCode(RARX_READ);
|
|
}
|
|
|
|
|
|
void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName)
|
|
{
|
|
uiMsg(UIERROR_FILEWRITE,ArcName,FileName);
|
|
SysErrMsg();
|
|
SetErrorCode(RARX_WRITE);
|
|
}
|
|
|
|
|
|
void ErrorHandler::ArcBrokenMsg(const wchar *ArcName)
|
|
{
|
|
uiMsg(UIERROR_ARCBROKEN,ArcName);
|
|
SetErrorCode(RARX_CRC);
|
|
}
|
|
|
|
|
|
void ErrorHandler::ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName)
|
|
{
|
|
uiMsg(UIERROR_CHECKSUM,ArcName,FileName);
|
|
SetErrorCode(RARX_CRC);
|
|
}
|
|
|
|
|
|
void ErrorHandler::UnknownMethodMsg(const wchar *ArcName,const wchar *FileName)
|
|
{
|
|
uiMsg(UIERROR_UNKNOWNMETHOD,ArcName,FileName);
|
|
ErrHandler.SetErrorCode(RARX_FATAL);
|
|
}
|
|
|
|
|
|
void ErrorHandler::Exit(RAR_EXIT ExitCode)
|
|
{
|
|
uiAlarm(UIALARM_ERROR);
|
|
Throw(ExitCode);
|
|
}
|
|
|
|
|
|
void ErrorHandler::SetErrorCode(RAR_EXIT Code)
|
|
{
|
|
switch(Code)
|
|
{
|
|
case RARX_WARNING:
|
|
case RARX_USERBREAK:
|
|
if (ExitCode==RARX_SUCCESS)
|
|
ExitCode=Code;
|
|
break;
|
|
case RARX_CRC:
|
|
if (ExitCode!=RARX_BADPWD)
|
|
ExitCode=Code;
|
|
break;
|
|
case RARX_FATAL:
|
|
if (ExitCode==RARX_SUCCESS || ExitCode==RARX_WARNING)
|
|
ExitCode=RARX_FATAL;
|
|
break;
|
|
default:
|
|
ExitCode=Code;
|
|
break;
|
|
}
|
|
ErrCount++;
|
|
}
|
|
|
|
|
|
#ifdef _WIN_ALL
|
|
BOOL __stdcall ProcessSignal(DWORD SigType)
|
|
#else
|
|
#if defined(__sun)
|
|
extern "C"
|
|
#endif
|
|
void _stdfunction ProcessSignal(int SigType)
|
|
#endif
|
|
{
|
|
#ifdef _WIN_ALL
|
|
// When a console application is run as a service, this allows the service
|
|
// to continue running after the user logs off.
|
|
if (SigType==CTRL_LOGOFF_EVENT)
|
|
return TRUE;
|
|
#endif
|
|
|
|
ErrHandler.UserBreak=true;
|
|
ErrHandler.SetDisableShutdown();
|
|
mprintf(St(MBreak));
|
|
|
|
#ifdef _WIN_ALL
|
|
// Let the main thread to handle 'throw' and destroy file objects.
|
|
for (uint I=0;!ErrHandler.MainExit && I<50;I++)
|
|
Sleep(100);
|
|
#if defined(USE_RC) && !defined(SFX_MODULE) && !defined(RARDLL)
|
|
ExtRes.UnloadDLL();
|
|
#endif
|
|
exit(RARX_USERBREAK);
|
|
#endif
|
|
|
|
#ifdef _UNIX
|
|
static uint BreakCount=0;
|
|
// User continues to press Ctrl+C, exit immediately without cleanup.
|
|
if (++BreakCount>1)
|
|
exit(RARX_USERBREAK);
|
|
// Otherwise return from signal handler and let Wait() function to close
|
|
// files and quit. We cannot use the same approach as in Windows,
|
|
// because Unix signal handler can block execution of our main code.
|
|
#endif
|
|
|
|
#if defined(_WIN_ALL) && !defined(_MSC_VER)
|
|
// Never reached, just to avoid a compiler warning
|
|
return TRUE;
|
|
#endif
|
|
}
|
|
|
|
|
|
void ErrorHandler::SetSignalHandlers(bool Enable)
|
|
{
|
|
EnableBreak=Enable;
|
|
#ifdef _WIN_ALL
|
|
SetConsoleCtrlHandler(Enable ? ProcessSignal:NULL,TRUE);
|
|
#else
|
|
signal(SIGINT,Enable ? ProcessSignal:SIG_IGN);
|
|
signal(SIGTERM,Enable ? ProcessSignal:SIG_IGN);
|
|
#endif
|
|
}
|
|
|
|
|
|
void ErrorHandler::Throw(RAR_EXIT Code)
|
|
{
|
|
if (Code==RARX_USERBREAK && !EnableBreak)
|
|
return;
|
|
#if !defined(SILENT)
|
|
// Do not write "aborted" when just displaying online help.
|
|
if (Code!=RARX_SUCCESS && Code!=RARX_USERERROR)
|
|
mprintf(L"\n%s\n",St(MProgAborted));
|
|
#endif
|
|
SetErrorCode(Code);
|
|
throw Code;
|
|
}
|
|
|
|
|
|
bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
|
|
{
|
|
#ifndef SILENT
|
|
#ifdef _WIN_ALL
|
|
int ErrType=GetLastError();
|
|
if (ErrType!=0)
|
|
return FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,ErrType,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
|
|
Msg,(DWORD)Size,NULL)!=0;
|
|
#endif
|
|
|
|
#if defined(_UNIX) || defined(_EMX)
|
|
if (errno!=0)
|
|
{
|
|
char *err=strerror(errno);
|
|
if (err!=NULL)
|
|
{
|
|
CharToWide(err,Msg,Size);
|
|
return true;
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
return false;
|
|
}
|
|
|
|
|
|
void ErrorHandler::SysErrMsg()
|
|
{
|
|
#ifndef SILENT
|
|
wchar Msg[1024];
|
|
if (!GetSysErrMsg(Msg,ASIZE(Msg)))
|
|
return;
|
|
#ifdef _WIN_ALL
|
|
wchar *CurMsg=Msg;
|
|
while (CurMsg!=NULL) // Print string with \r\n as several strings to multiple lines.
|
|
{
|
|
while (*CurMsg=='\r' || *CurMsg=='\n')
|
|
CurMsg++;
|
|
if (*CurMsg==0)
|
|
break;
|
|
wchar *EndMsg=wcschr(CurMsg,'\r');
|
|
if (EndMsg==NULL)
|
|
EndMsg=wcschr(CurMsg,'\n');
|
|
if (EndMsg!=NULL)
|
|
{
|
|
*EndMsg=0;
|
|
EndMsg++;
|
|
}
|
|
uiMsg(UIERROR_SYSERRMSG,CurMsg);
|
|
CurMsg=EndMsg;
|
|
}
|
|
#endif
|
|
|
|
#if defined(_UNIX) || defined(_EMX)
|
|
uiMsg(UIERROR_SYSERRMSG,Msg);
|
|
#endif
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
int ErrorHandler::GetSystemErrorCode()
|
|
{
|
|
#ifdef _WIN_ALL
|
|
return GetLastError();
|
|
#else
|
|
return errno;
|
|
#endif
|
|
}
|
|
|
|
|
|
void ErrorHandler::SetSystemErrorCode(int Code)
|
|
{
|
|
#ifdef _WIN_ALL
|
|
SetLastError(Code);
|
|
#else
|
|
errno=Code;
|
|
#endif
|
|
}
|