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