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 wchar *FileName) |
30 | 0 | { |
31 | | #ifndef SILENT |
32 | | OpenErrorMsg(FileName); |
33 | | Exit(RARX_OPEN); |
34 | | #endif |
35 | 0 | } |
36 | | |
37 | | |
38 | | void ErrorHandler::CloseError(const wchar *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 wchar *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 wchar *FileName,bool &Ignore,bool &Retry,bool &Quit) |
66 | 0 | { |
67 | 0 | 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 | 0 | Ignore=true; // Saving the file part for -y or -inul or "Ignore all" choice. |
88 | 0 | } |
89 | | |
90 | | |
91 | | void ErrorHandler::WriteError(const wchar *ArcName,const wchar *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 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 | | |
114 | | bool ErrorHandler::AskRepeatWrite(const wchar *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 wchar *FileName) |
133 | 0 | { |
134 | 0 | if (!UserBreak) |
135 | 0 | { |
136 | 0 | uiMsg(UIERROR_FILESEEK,FileName); |
137 | 0 | SysErrMsg(); |
138 | 0 | } |
139 | 0 | #if !defined(SILENT) || defined(RARDLL) |
140 | 0 | Exit(RARX_FATAL); |
141 | 0 | #endif |
142 | 0 | } |
143 | | |
144 | | |
145 | | void ErrorHandler::GeneralErrMsg(const wchar *fmt,...) |
146 | 0 | { |
147 | 0 | va_list arglist; |
148 | 0 | va_start(arglist,fmt); |
149 | 0 | wchar Msg[1024]; |
150 | 0 | vswprintf(Msg,ASIZE(Msg),fmt,arglist); |
151 | 0 | uiMsg(UIERROR_GENERALERRMSG,Msg); |
152 | 0 | SysErrMsg(); |
153 | 0 | va_end(arglist); |
154 | 0 | } |
155 | | |
156 | | |
157 | | void ErrorHandler::MemoryErrorMsg() |
158 | 0 | { |
159 | 0 | uiMsg(UIERROR_MEMORY); |
160 | 0 | SetErrorCode(RARX_MEMORY); |
161 | 0 | } |
162 | | |
163 | | |
164 | | void ErrorHandler::OpenErrorMsg(const wchar *FileName) |
165 | 0 | { |
166 | 0 | OpenErrorMsg(NULL,FileName); |
167 | 0 | } |
168 | | |
169 | | |
170 | | void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName) |
171 | 0 | { |
172 | 0 | Wait(); // Keep GUI responsive if many files cannot be opened when archiving. |
173 | 0 | uiMsg(UIERROR_FILEOPEN,ArcName,FileName); |
174 | 0 | SysErrMsg(); |
175 | 0 | SetErrorCode(RARX_OPEN); |
176 | 0 | } |
177 | | |
178 | | |
179 | | void ErrorHandler::CreateErrorMsg(const wchar *FileName) |
180 | 0 | { |
181 | 0 | CreateErrorMsg(NULL,FileName); |
182 | 0 | } |
183 | | |
184 | | |
185 | | void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName) |
186 | 0 | { |
187 | 0 | uiMsg(UIERROR_FILECREATE,ArcName,FileName); |
188 | 0 | SysErrMsg(); |
189 | 0 | SetErrorCode(RARX_CREATE); |
190 | 0 | } |
191 | | |
192 | | |
193 | | void ErrorHandler::ReadErrorMsg(const wchar *FileName) |
194 | 0 | { |
195 | 0 | ReadErrorMsg(NULL,FileName); |
196 | 0 | } |
197 | | |
198 | | |
199 | | void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName) |
200 | 0 | { |
201 | 0 | uiMsg(UIERROR_FILEREAD,ArcName,FileName); |
202 | 0 | SysErrMsg(); |
203 | 0 | SetErrorCode(RARX_READ); |
204 | 0 | } |
205 | | |
206 | | |
207 | | void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName) |
208 | 0 | { |
209 | 0 | uiMsg(UIERROR_FILEWRITE,ArcName,FileName); |
210 | 0 | SysErrMsg(); |
211 | 0 | SetErrorCode(RARX_WRITE); |
212 | 0 | } |
213 | | |
214 | | |
215 | | void ErrorHandler::ArcBrokenMsg(const wchar *ArcName) |
216 | 0 | { |
217 | 0 | uiMsg(UIERROR_ARCBROKEN,ArcName); |
218 | 0 | SetErrorCode(RARX_CRC); |
219 | 0 | } |
220 | | |
221 | | |
222 | | void ErrorHandler::ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName) |
223 | 0 | { |
224 | 0 | uiMsg(UIERROR_CHECKSUM,ArcName,FileName); |
225 | 0 | SetErrorCode(RARX_CRC); |
226 | 0 | } |
227 | | |
228 | | |
229 | | void ErrorHandler::UnknownMethodMsg(const wchar *ArcName,const wchar *FileName) |
230 | 0 | { |
231 | 0 | uiMsg(UIERROR_UNKNOWNMETHOD,ArcName,FileName); |
232 | 0 | ErrHandler.SetErrorCode(RARX_FATAL); |
233 | 0 | } |
234 | | |
235 | | |
236 | | void ErrorHandler::Exit(RAR_EXIT ExitCode) |
237 | 0 | { |
238 | 0 | uiAlarm(UIALARM_ERROR); |
239 | 0 | Throw(ExitCode); |
240 | 0 | } |
241 | | |
242 | | |
243 | | void ErrorHandler::SetErrorCode(RAR_EXIT Code) |
244 | 5 | { |
245 | 5 | switch(Code) |
246 | 5 | { |
247 | 2 | case RARX_WARNING: |
248 | 2 | case RARX_USERBREAK: |
249 | 2 | if (ExitCode==RARX_SUCCESS) |
250 | 1 | ExitCode=Code; |
251 | 2 | break; |
252 | 3 | case RARX_CRC: |
253 | 3 | if (ExitCode!=RARX_BADPWD) |
254 | 3 | ExitCode=Code; |
255 | 3 | break; |
256 | 0 | case RARX_FATAL: |
257 | 0 | if (ExitCode==RARX_SUCCESS || ExitCode==RARX_WARNING) |
258 | 0 | ExitCode=RARX_FATAL; |
259 | 0 | break; |
260 | 0 | default: |
261 | 0 | ExitCode=Code; |
262 | 0 | break; |
263 | 5 | } |
264 | 5 | ErrCount++; |
265 | 5 | } |
266 | | |
267 | | |
268 | | #ifdef _WIN_ALL |
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 | 0 | { |
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 | 0 | ErrHandler.UserBreak=true; |
285 | 0 | ErrHandler.SetDisableShutdown(); |
286 | 0 | 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 | 0 | #ifdef _UNIX |
299 | 0 | static uint BreakCount=0; |
300 | | // User continues to press Ctrl+C, exit immediately without cleanup. |
301 | 0 | if (++BreakCount>1) |
302 | 0 | 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 | 0 | #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 | 0 | } |
313 | | |
314 | | |
315 | | void ErrorHandler::SetSignalHandlers(bool Enable) |
316 | 0 | { |
317 | 0 | EnableBreak=Enable; |
318 | | #ifdef _WIN_ALL |
319 | | SetConsoleCtrlHandler(Enable ? ProcessSignal:NULL,TRUE); |
320 | | #else |
321 | 0 | signal(SIGINT,Enable ? ProcessSignal:SIG_IGN); |
322 | 0 | signal(SIGTERM,Enable ? ProcessSignal:SIG_IGN); |
323 | 0 | #endif |
324 | 0 | } |
325 | | |
326 | | |
327 | | void ErrorHandler::Throw(RAR_EXIT Code) |
328 | 0 | { |
329 | 0 | if (Code==RARX_USERBREAK && !EnableBreak) |
330 | 0 | 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 | 0 | SetErrorCode(Code); |
337 | 0 | throw Code; |
338 | 0 | } |
339 | | |
340 | | |
341 | | bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size) |
342 | 0 | { |
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 | 0 | return false; |
365 | 0 | } |
366 | | |
367 | | |
368 | | void ErrorHandler::SysErrMsg() |
369 | 0 | { |
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 | 0 | } |
401 | | |
402 | | |
403 | | int ErrorHandler::GetSystemErrorCode() |
404 | 0 | { |
405 | | #ifdef _WIN_ALL |
406 | | return GetLastError(); |
407 | | #else |
408 | 0 | return errno; |
409 | 0 | #endif |
410 | 0 | } |
411 | | |
412 | | |
413 | | void ErrorHandler::SetSystemErrorCode(int Code) |
414 | 0 | { |
415 | | #ifdef _WIN_ALL |
416 | | SetLastError(Code); |
417 | | #else |
418 | 0 | errno=Code; |
419 | 0 | #endif |
420 | 0 | } |