1 #include "rar.hpp"
2 
ErrorHandler()3 ErrorHandler::ErrorHandler()
4 {
5   Clean();
6 }
7 
8 
Clean()9 void ErrorHandler::Clean()
10 {
11   ExitCode=RARX_SUCCESS;
12   ErrCount=0;
13   EnableBreak=true;
14   Silent=false;
15   UserBreak=false;
16   MainExit=false;
17   DisableShutdown=false;
18   ReadErrIgnoreAll=false;
19 }
20 
21 
MemoryError()22 void ErrorHandler::MemoryError()
23 {
24   MemoryErrorMsg();
25   Exit(RARX_MEMORY);
26 }
27 
28 
OpenError(const wchar * FileName)29 void ErrorHandler::OpenError(const wchar *FileName)
30 {
31 #ifndef SILENT
32   OpenErrorMsg(FileName);
33   Exit(RARX_OPEN);
34 #endif
35 }
36 
37 
CloseError(const wchar * FileName)38 void ErrorHandler::CloseError(const wchar *FileName)
39 {
40   if (!UserBreak)
41   {
42     uiMsg(UIERROR_FILECLOSE,FileName);
43     SysErrMsg();
44   }
45   // We must not call Exit and throw an exception here, because this function
46   // is called from File object destructor and can be invoked when stack
47   // unwinding while handling another exception. Throwing a new exception
48   // when stack unwinding is prohibited and terminates a program.
49   // If necessary, we can check std::uncaught_exception() before throw.
50   SetErrorCode(RARX_FATAL);
51 }
52 
53 
ReadError(const wchar * FileName)54 void ErrorHandler::ReadError(const wchar *FileName)
55 {
56 #ifndef SILENT
57   ReadErrorMsg(FileName);
58 #endif
59 #if !defined(SILENT) || defined(RARDLL)
60   Exit(RARX_READ);
61 #endif
62 }
63 
64 
AskRepeatRead(const wchar * FileName,bool & Ignore,bool & Retry,bool & Quit)65 void ErrorHandler::AskRepeatRead(const wchar *FileName,bool &Ignore,bool &Retry,bool &Quit)
66 {
67   SetErrorCode(RARX_READ);
68 #if !defined(SILENT) && !defined(SFX_MODULE)
69   if (!Silent)
70   {
71     uiMsg(UIERROR_FILEREAD,UINULL,FileName);
72     SysErrMsg();
73     if (ReadErrIgnoreAll)
74       Ignore=true;
75     else
76     {
77       bool All=false;
78       uiAskRepeatRead(FileName,Ignore,All,Retry,Quit);
79       if (All)
80         ReadErrIgnoreAll=Ignore=true;
81       if (Quit) // Disable shutdown if user select Quit in read error prompt.
82         DisableShutdown=true;
83     }
84     return;
85   }
86 #endif
87   Ignore=true; // Saving the file part for -y or -inul or "Ignore all" choice.
88 }
89 
90 
WriteError(const wchar * ArcName,const wchar * FileName)91 void ErrorHandler::WriteError(const wchar *ArcName,const wchar *FileName)
92 {
93 #ifndef SILENT
94   WriteErrorMsg(ArcName,FileName);
95 #endif
96 #if !defined(SILENT) || defined(RARDLL)
97   Exit(RARX_WRITE);
98 #endif
99 }
100 
101 
102 #ifdef _WIN_ALL
WriteErrorFAT(const wchar * FileName)103 void ErrorHandler::WriteErrorFAT(const wchar *FileName)
104 {
105   SysErrMsg();
106   uiMsg(UIERROR_NTFSREQUIRED,FileName);
107 #if !defined(SILENT) && !defined(SFX_MODULE) || defined(RARDLL)
108   Exit(RARX_WRITE);
109 #endif
110 }
111 #endif
112 
113 
AskRepeatWrite(const wchar * FileName,bool DiskFull)114 bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull)
115 {
116 #ifndef SILENT
117   if (!Silent)
118   {
119     // We do not display "repeat write" prompt in Android, so we do not
120     // need the matching system error message.
121     SysErrMsg();
122     bool Repeat=uiAskRepeatWrite(FileName,DiskFull);
123     if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog.
124       DisableShutdown=true;
125     return Repeat;
126   }
127 #endif
128   return false;
129 }
130 
131 
SeekError(const wchar * FileName)132 void ErrorHandler::SeekError(const wchar *FileName)
133 {
134   if (!UserBreak)
135   {
136     uiMsg(UIERROR_FILESEEK,FileName);
137     SysErrMsg();
138   }
139 #if !defined(SILENT) || defined(RARDLL)
140   Exit(RARX_FATAL);
141 #endif
142 }
143 
144 
GeneralErrMsg(const wchar * fmt,...)145 void ErrorHandler::GeneralErrMsg(const wchar *fmt,...)
146 {
147   va_list arglist;
148   va_start(arglist,fmt);
149   wchar Msg[1024];
150   vswprintf(Msg,ASIZE(Msg),fmt,arglist);
151   uiMsg(UIERROR_GENERALERRMSG,Msg);
152   SysErrMsg();
153   va_end(arglist);
154 }
155 
156 
MemoryErrorMsg()157 void ErrorHandler::MemoryErrorMsg()
158 {
159   uiMsg(UIERROR_MEMORY);
160   SetErrorCode(RARX_MEMORY);
161 }
162 
163 
OpenErrorMsg(const wchar * FileName)164 void ErrorHandler::OpenErrorMsg(const wchar *FileName)
165 {
166   OpenErrorMsg(NULL,FileName);
167 }
168 
169 
OpenErrorMsg(const wchar * ArcName,const wchar * FileName)170 void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
171 {
172   Wait(); // Keep GUI responsive if many files cannot be opened when archiving.
173   uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
174   SysErrMsg();
175   SetErrorCode(RARX_OPEN);
176 }
177 
178 
CreateErrorMsg(const wchar * FileName)179 void ErrorHandler::CreateErrorMsg(const wchar *FileName)
180 {
181   CreateErrorMsg(NULL,FileName);
182 }
183 
184 
CreateErrorMsg(const wchar * ArcName,const wchar * FileName)185 void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName)
186 {
187   uiMsg(UIERROR_FILECREATE,ArcName,FileName);
188   SysErrMsg();
189   SetErrorCode(RARX_CREATE);
190 }
191 
192 
ReadErrorMsg(const wchar * FileName)193 void ErrorHandler::ReadErrorMsg(const wchar *FileName)
194 {
195   ReadErrorMsg(NULL,FileName);
196 }
197 
198 
ReadErrorMsg(const wchar * ArcName,const wchar * FileName)199 void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName)
200 {
201   uiMsg(UIERROR_FILEREAD,ArcName,FileName);
202   SysErrMsg();
203   SetErrorCode(RARX_READ);
204 }
205 
206 
WriteErrorMsg(const wchar * ArcName,const wchar * FileName)207 void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName)
208 {
209   uiMsg(UIERROR_FILEWRITE,ArcName,FileName);
210   SysErrMsg();
211   SetErrorCode(RARX_WRITE);
212 }
213 
214 
ArcBrokenMsg(const wchar * ArcName)215 void ErrorHandler::ArcBrokenMsg(const wchar *ArcName)
216 {
217   uiMsg(UIERROR_ARCBROKEN,ArcName);
218   SetErrorCode(RARX_CRC);
219 }
220 
221 
ChecksumFailedMsg(const wchar * ArcName,const wchar * FileName)222 void ErrorHandler::ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName)
223 {
224   uiMsg(UIERROR_CHECKSUM,ArcName,FileName);
225   SetErrorCode(RARX_CRC);
226 }
227 
228 
UnknownMethodMsg(const wchar * ArcName,const wchar * FileName)229 void ErrorHandler::UnknownMethodMsg(const wchar *ArcName,const wchar *FileName)
230 {
231   uiMsg(UIERROR_UNKNOWNMETHOD,ArcName,FileName);
232   ErrHandler.SetErrorCode(RARX_FATAL);
233 }
234 
235 
Exit(RAR_EXIT ExitCode)236 void ErrorHandler::Exit(RAR_EXIT ExitCode)
237 {
238   uiAlarm(UIALARM_ERROR);
239   Throw(ExitCode);
240 }
241 
242 
SetErrorCode(RAR_EXIT Code)243 void ErrorHandler::SetErrorCode(RAR_EXIT Code)
244 {
245   switch(Code)
246   {
247     case RARX_WARNING:
248     case RARX_USERBREAK:
249       if (ExitCode==RARX_SUCCESS)
250         ExitCode=Code;
251       break;
252     case RARX_CRC:
253       if (ExitCode!=RARX_BADPWD)
254         ExitCode=Code;
255       break;
256     case RARX_FATAL:
257       if (ExitCode==RARX_SUCCESS || ExitCode==RARX_WARNING)
258         ExitCode=RARX_FATAL;
259       break;
260     default:
261       ExitCode=Code;
262       break;
263   }
264   ErrCount++;
265 }
266 
267 
268 #ifdef _WIN_ALL
ProcessSignal(DWORD SigType)269 BOOL __stdcall ProcessSignal(DWORD SigType)
270 #else
271 #if defined(__sun)
272 extern "C"
273 #endif
274 void _stdfunction ProcessSignal(int SigType)
275 #endif
276 {
277 #ifdef _WIN_ALL
278   // When a console application is run as a service, this allows the service
279   // to continue running after the user logs off.
280   if (SigType==CTRL_LOGOFF_EVENT)
281     return TRUE;
282 #endif
283 
284   ErrHandler.UserBreak=true;
285   ErrHandler.SetDisableShutdown();
286   mprintf(St(MBreak));
287 
288 #ifdef _WIN_ALL
289   // Let the main thread to handle 'throw' and destroy file objects.
290   for (uint I=0;!ErrHandler.MainExit && I<50;I++)
291     Sleep(100);
292 #if defined(USE_RC) && !defined(SFX_MODULE) && !defined(RARDLL)
293   ExtRes.UnloadDLL();
294 #endif
295   exit(RARX_USERBREAK);
296 #endif
297 
298 #ifdef _UNIX
299   static uint BreakCount=0;
300   // User continues to press Ctrl+C, exit immediately without cleanup.
301   if (++BreakCount>1)
302     exit(RARX_USERBREAK);
303   // Otherwise return from signal handler and let Wait() function to close
304   // files and quit. We cannot use the same approach as in Windows,
305   // because Unix signal handler can block execution of our main code.
306 #endif
307 
308 #if defined(_WIN_ALL) && !defined(_MSC_VER)
309   // Never reached, just to avoid a compiler warning
310   return TRUE;
311 #endif
312 }
313 
314 
SetSignalHandlers(bool Enable)315 void ErrorHandler::SetSignalHandlers(bool Enable)
316 {
317   EnableBreak=Enable;
318 #ifdef _WIN_ALL
319   SetConsoleCtrlHandler(Enable ? ProcessSignal:NULL,TRUE);
320 #else
321   signal(SIGINT,Enable ? ProcessSignal:SIG_IGN);
322   signal(SIGTERM,Enable ? ProcessSignal:SIG_IGN);
323 #endif
324 }
325 
326 
Throw(RAR_EXIT Code)327 void ErrorHandler::Throw(RAR_EXIT Code)
328 {
329   if (Code==RARX_USERBREAK && !EnableBreak)
330     return;
331 #if !defined(SILENT)
332   // Do not write "aborted" when just displaying online help.
333   if (Code!=RARX_SUCCESS && Code!=RARX_USERERROR)
334     mprintf(L"\n%s\n",St(MProgAborted));
335 #endif
336   SetErrorCode(Code);
337   throw Code;
338 }
339 
340 
GetSysErrMsg(wchar * Msg,size_t Size)341 bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
342 {
343 #ifndef SILENT
344 #ifdef _WIN_ALL
345   int ErrType=GetLastError();
346   if (ErrType!=0)
347     return FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
348                          NULL,ErrType,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
349                          Msg,(DWORD)Size,NULL)!=0;
350 #endif
351 
352 #if defined(_UNIX) || defined(_EMX)
353   if (errno!=0)
354   {
355     char *err=strerror(errno);
356     if (err!=NULL)
357     {
358       CharToWide(err,Msg,Size);
359       return true;
360     }
361   }
362 #endif
363 #endif
364   return false;
365 }
366 
367 
SysErrMsg()368 void ErrorHandler::SysErrMsg()
369 {
370 #ifndef SILENT
371   wchar Msg[1024];
372   if (!GetSysErrMsg(Msg,ASIZE(Msg)))
373     return;
374 #ifdef _WIN_ALL
375   wchar *CurMsg=Msg;
376   while (CurMsg!=NULL) // Print string with \r\n as several strings to multiple lines.
377   {
378     while (*CurMsg=='\r' || *CurMsg=='\n')
379       CurMsg++;
380     if (*CurMsg==0)
381       break;
382     wchar *EndMsg=wcschr(CurMsg,'\r');
383     if (EndMsg==NULL)
384       EndMsg=wcschr(CurMsg,'\n');
385     if (EndMsg!=NULL)
386     {
387       *EndMsg=0;
388       EndMsg++;
389     }
390     uiMsg(UIERROR_SYSERRMSG,CurMsg);
391     CurMsg=EndMsg;
392   }
393 #endif
394 
395 #if defined(_UNIX) || defined(_EMX)
396   uiMsg(UIERROR_SYSERRMSG,Msg);
397 #endif
398 
399 #endif
400 }
401 
402 
GetSystemErrorCode()403 int ErrorHandler::GetSystemErrorCode()
404 {
405 #ifdef _WIN_ALL
406   return GetLastError();
407 #else
408   return errno;
409 #endif
410 }
411 
412 
SetSystemErrorCode(int Code)413 void ErrorHandler::SetSystemErrorCode(int Code)
414 {
415 #ifdef _WIN_ALL
416   SetLastError(Code);
417 #else
418   errno=Code;
419 #endif
420 }
421