123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 |
- #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
- }
|