errhnd.cpp 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. #include "rar.hpp"
  2. ErrorHandler::ErrorHandler()
  3. {
  4. Clean();
  5. }
  6. void ErrorHandler::Clean()
  7. {
  8. ExitCode=RARX_SUCCESS;
  9. ErrCount=0;
  10. EnableBreak=true;
  11. Silent=false;
  12. UserBreak=false;
  13. MainExit=false;
  14. DisableShutdown=false;
  15. ReadErrIgnoreAll=false;
  16. }
  17. void ErrorHandler::MemoryError()
  18. {
  19. MemoryErrorMsg();
  20. Exit(RARX_MEMORY);
  21. }
  22. void ErrorHandler::OpenError(const wchar *FileName)
  23. {
  24. #ifndef SILENT
  25. OpenErrorMsg(FileName);
  26. Exit(RARX_OPEN);
  27. #endif
  28. }
  29. void ErrorHandler::CloseError(const wchar *FileName)
  30. {
  31. if (!UserBreak)
  32. {
  33. uiMsg(UIERROR_FILECLOSE,FileName);
  34. SysErrMsg();
  35. }
  36. // We must not call Exit and throw an exception here, because this function
  37. // is called from File object destructor and can be invoked when stack
  38. // unwinding while handling another exception. Throwing a new exception
  39. // when stack unwinding is prohibited and terminates a program.
  40. // If necessary, we can check std::uncaught_exception() before throw.
  41. SetErrorCode(RARX_FATAL);
  42. }
  43. void ErrorHandler::ReadError(const wchar *FileName)
  44. {
  45. #ifndef SILENT
  46. ReadErrorMsg(FileName);
  47. #endif
  48. #if !defined(SILENT) || defined(RARDLL)
  49. Exit(RARX_READ);
  50. #endif
  51. }
  52. void ErrorHandler::AskRepeatRead(const wchar *FileName,bool &Ignore,bool &Retry,bool &Quit)
  53. {
  54. SetErrorCode(RARX_READ);
  55. #if !defined(SILENT) && !defined(SFX_MODULE)
  56. if (!Silent)
  57. {
  58. uiMsg(UIERROR_FILEREAD,UINULL,FileName);
  59. SysErrMsg();
  60. if (ReadErrIgnoreAll)
  61. Ignore=true;
  62. else
  63. {
  64. bool All=false;
  65. uiAskRepeatRead(FileName,Ignore,All,Retry,Quit);
  66. if (All)
  67. ReadErrIgnoreAll=Ignore=true;
  68. if (Quit) // Disable shutdown if user select Quit in read error prompt.
  69. DisableShutdown=true;
  70. }
  71. return;
  72. }
  73. #endif
  74. Ignore=true; // Saving the file part for -y or -inul or "Ignore all" choice.
  75. }
  76. void ErrorHandler::WriteError(const wchar *ArcName,const wchar *FileName)
  77. {
  78. #ifndef SILENT
  79. WriteErrorMsg(ArcName,FileName);
  80. #endif
  81. #if !defined(SILENT) || defined(RARDLL)
  82. Exit(RARX_WRITE);
  83. #endif
  84. }
  85. #ifdef _WIN_ALL
  86. void ErrorHandler::WriteErrorFAT(const wchar *FileName)
  87. {
  88. SysErrMsg();
  89. uiMsg(UIERROR_NTFSREQUIRED,FileName);
  90. #if !defined(SILENT) && !defined(SFX_MODULE) || defined(RARDLL)
  91. Exit(RARX_WRITE);
  92. #endif
  93. }
  94. #endif
  95. bool ErrorHandler::AskRepeatWrite(const wchar *FileName,bool DiskFull)
  96. {
  97. #ifndef SILENT
  98. if (!Silent)
  99. {
  100. // We do not display "repeat write" prompt in Android, so we do not
  101. // need the matching system error message.
  102. SysErrMsg();
  103. bool Repeat=uiAskRepeatWrite(FileName,DiskFull);
  104. if (!Repeat) // Disable shutdown if user pressed Cancel in error dialog.
  105. DisableShutdown=true;
  106. return Repeat;
  107. }
  108. #endif
  109. return false;
  110. }
  111. void ErrorHandler::SeekError(const wchar *FileName)
  112. {
  113. if (!UserBreak)
  114. {
  115. uiMsg(UIERROR_FILESEEK,FileName);
  116. SysErrMsg();
  117. }
  118. #if !defined(SILENT) || defined(RARDLL)
  119. Exit(RARX_FATAL);
  120. #endif
  121. }
  122. void ErrorHandler::GeneralErrMsg(const wchar *fmt,...)
  123. {
  124. va_list arglist;
  125. va_start(arglist,fmt);
  126. wchar Msg[1024];
  127. vswprintf(Msg,ASIZE(Msg),fmt,arglist);
  128. uiMsg(UIERROR_GENERALERRMSG,Msg);
  129. SysErrMsg();
  130. va_end(arglist);
  131. }
  132. void ErrorHandler::MemoryErrorMsg()
  133. {
  134. uiMsg(UIERROR_MEMORY);
  135. SetErrorCode(RARX_MEMORY);
  136. }
  137. void ErrorHandler::OpenErrorMsg(const wchar *FileName)
  138. {
  139. OpenErrorMsg(NULL,FileName);
  140. }
  141. void ErrorHandler::OpenErrorMsg(const wchar *ArcName,const wchar *FileName)
  142. {
  143. Wait(); // Keep GUI responsive if many files cannot be opened when archiving.
  144. uiMsg(UIERROR_FILEOPEN,ArcName,FileName);
  145. SysErrMsg();
  146. SetErrorCode(RARX_OPEN);
  147. }
  148. void ErrorHandler::CreateErrorMsg(const wchar *FileName)
  149. {
  150. CreateErrorMsg(NULL,FileName);
  151. }
  152. void ErrorHandler::CreateErrorMsg(const wchar *ArcName,const wchar *FileName)
  153. {
  154. uiMsg(UIERROR_FILECREATE,ArcName,FileName);
  155. SysErrMsg();
  156. SetErrorCode(RARX_CREATE);
  157. }
  158. void ErrorHandler::ReadErrorMsg(const wchar *FileName)
  159. {
  160. ReadErrorMsg(NULL,FileName);
  161. }
  162. void ErrorHandler::ReadErrorMsg(const wchar *ArcName,const wchar *FileName)
  163. {
  164. uiMsg(UIERROR_FILEREAD,ArcName,FileName);
  165. SysErrMsg();
  166. SetErrorCode(RARX_READ);
  167. }
  168. void ErrorHandler::WriteErrorMsg(const wchar *ArcName,const wchar *FileName)
  169. {
  170. uiMsg(UIERROR_FILEWRITE,ArcName,FileName);
  171. SysErrMsg();
  172. SetErrorCode(RARX_WRITE);
  173. }
  174. void ErrorHandler::ArcBrokenMsg(const wchar *ArcName)
  175. {
  176. uiMsg(UIERROR_ARCBROKEN,ArcName);
  177. SetErrorCode(RARX_CRC);
  178. }
  179. void ErrorHandler::ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName)
  180. {
  181. uiMsg(UIERROR_CHECKSUM,ArcName,FileName);
  182. SetErrorCode(RARX_CRC);
  183. }
  184. void ErrorHandler::UnknownMethodMsg(const wchar *ArcName,const wchar *FileName)
  185. {
  186. uiMsg(UIERROR_UNKNOWNMETHOD,ArcName,FileName);
  187. ErrHandler.SetErrorCode(RARX_FATAL);
  188. }
  189. void ErrorHandler::Exit(RAR_EXIT ExitCode)
  190. {
  191. uiAlarm(UIALARM_ERROR);
  192. Throw(ExitCode);
  193. }
  194. void ErrorHandler::SetErrorCode(RAR_EXIT Code)
  195. {
  196. switch(Code)
  197. {
  198. case RARX_WARNING:
  199. case RARX_USERBREAK:
  200. if (ExitCode==RARX_SUCCESS)
  201. ExitCode=Code;
  202. break;
  203. case RARX_CRC:
  204. if (ExitCode!=RARX_BADPWD)
  205. ExitCode=Code;
  206. break;
  207. case RARX_FATAL:
  208. if (ExitCode==RARX_SUCCESS || ExitCode==RARX_WARNING)
  209. ExitCode=RARX_FATAL;
  210. break;
  211. default:
  212. ExitCode=Code;
  213. break;
  214. }
  215. ErrCount++;
  216. }
  217. #ifdef _WIN_ALL
  218. BOOL __stdcall ProcessSignal(DWORD SigType)
  219. #else
  220. #if defined(__sun)
  221. extern "C"
  222. #endif
  223. void _stdfunction ProcessSignal(int SigType)
  224. #endif
  225. {
  226. #ifdef _WIN_ALL
  227. // When a console application is run as a service, this allows the service
  228. // to continue running after the user logs off.
  229. if (SigType==CTRL_LOGOFF_EVENT)
  230. return TRUE;
  231. #endif
  232. ErrHandler.UserBreak=true;
  233. ErrHandler.SetDisableShutdown();
  234. mprintf(St(MBreak));
  235. #ifdef _WIN_ALL
  236. // Let the main thread to handle 'throw' and destroy file objects.
  237. for (uint I=0;!ErrHandler.MainExit && I<50;I++)
  238. Sleep(100);
  239. #if defined(USE_RC) && !defined(SFX_MODULE) && !defined(RARDLL)
  240. ExtRes.UnloadDLL();
  241. #endif
  242. exit(RARX_USERBREAK);
  243. #endif
  244. #ifdef _UNIX
  245. static uint BreakCount=0;
  246. // User continues to press Ctrl+C, exit immediately without cleanup.
  247. if (++BreakCount>1)
  248. exit(RARX_USERBREAK);
  249. // Otherwise return from signal handler and let Wait() function to close
  250. // files and quit. We cannot use the same approach as in Windows,
  251. // because Unix signal handler can block execution of our main code.
  252. #endif
  253. #if defined(_WIN_ALL) && !defined(_MSC_VER)
  254. // Never reached, just to avoid a compiler warning
  255. return TRUE;
  256. #endif
  257. }
  258. void ErrorHandler::SetSignalHandlers(bool Enable)
  259. {
  260. EnableBreak=Enable;
  261. #ifdef _WIN_ALL
  262. SetConsoleCtrlHandler(Enable ? ProcessSignal:NULL,TRUE);
  263. #else
  264. signal(SIGINT,Enable ? ProcessSignal:SIG_IGN);
  265. signal(SIGTERM,Enable ? ProcessSignal:SIG_IGN);
  266. #endif
  267. }
  268. void ErrorHandler::Throw(RAR_EXIT Code)
  269. {
  270. if (Code==RARX_USERBREAK && !EnableBreak)
  271. return;
  272. #if !defined(SILENT)
  273. // Do not write "aborted" when just displaying online help.
  274. if (Code!=RARX_SUCCESS && Code!=RARX_USERERROR)
  275. mprintf(L"\n%s\n",St(MProgAborted));
  276. #endif
  277. SetErrorCode(Code);
  278. throw Code;
  279. }
  280. bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size)
  281. {
  282. #ifndef SILENT
  283. #ifdef _WIN_ALL
  284. int ErrType=GetLastError();
  285. if (ErrType!=0)
  286. return FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
  287. NULL,ErrType,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT),
  288. Msg,(DWORD)Size,NULL)!=0;
  289. #endif
  290. #if defined(_UNIX) || defined(_EMX)
  291. if (errno!=0)
  292. {
  293. char *err=strerror(errno);
  294. if (err!=NULL)
  295. {
  296. CharToWide(err,Msg,Size);
  297. return true;
  298. }
  299. }
  300. #endif
  301. #endif
  302. return false;
  303. }
  304. void ErrorHandler::SysErrMsg()
  305. {
  306. #ifndef SILENT
  307. wchar Msg[1024];
  308. if (!GetSysErrMsg(Msg,ASIZE(Msg)))
  309. return;
  310. #ifdef _WIN_ALL
  311. wchar *CurMsg=Msg;
  312. while (CurMsg!=NULL) // Print string with \r\n as several strings to multiple lines.
  313. {
  314. while (*CurMsg=='\r' || *CurMsg=='\n')
  315. CurMsg++;
  316. if (*CurMsg==0)
  317. break;
  318. wchar *EndMsg=wcschr(CurMsg,'\r');
  319. if (EndMsg==NULL)
  320. EndMsg=wcschr(CurMsg,'\n');
  321. if (EndMsg!=NULL)
  322. {
  323. *EndMsg=0;
  324. EndMsg++;
  325. }
  326. uiMsg(UIERROR_SYSERRMSG,CurMsg);
  327. CurMsg=EndMsg;
  328. }
  329. #endif
  330. #if defined(_UNIX) || defined(_EMX)
  331. uiMsg(UIERROR_SYSERRMSG,Msg);
  332. #endif
  333. #endif
  334. }
  335. int ErrorHandler::GetSystemErrorCode()
  336. {
  337. #ifdef _WIN_ALL
  338. return GetLastError();
  339. #else
  340. return errno;
  341. #endif
  342. }
  343. void ErrorHandler::SetSystemErrorCode(int Code)
  344. {
  345. #ifdef _WIN_ALL
  346. SetLastError(Code);
  347. #else
  348. errno=Code;
  349. #endif
  350. }