Coverage Report

Created: 2025-04-11 06:56

/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 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
}