Coverage Report

Created: 2023-06-07 06:02

/src/unrar/errhnd.cpp
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
}