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