1 // UpdateCallbackConsole.cpp
2 
3 #include "StdAfx.h"
4 
5 #include "../../../Common/IntToString.h"
6 
7 #include "../../../Windows/ErrorMsg.h"
8 
9 #ifndef _7ZIP_ST
10 #include "../../../Windows/Synchronization.h"
11 #endif
12 
13 #include "ConsoleClose.h"
14 #include "UserInputUtils.h"
15 #include "UpdateCallbackConsole.h"
16 
17 using namespace NWindows;
18 
19 #ifndef _7ZIP_ST
20 static NSynchronization::CCriticalSection g_CriticalSection;
21 #define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
22 #else
23 #define MT_LOCK
24 #endif
25 
26 static const wchar_t * const kEmptyFileAlias = L"[Content]";
27 
28 static const char * const kOpenArchiveMessage = "Open archive: ";
29 static const char * const kCreatingArchiveMessage = "Creating archive: ";
30 static const char * const kUpdatingArchiveMessage = "Updating archive: ";
31 static const char * const kScanningMessage = "Scanning the drive:";
32 
33 static const char * const kError = "ERROR: ";
34 static const char * const kWarning = "WARNING: ";
35 
CheckBreak2()36 static HRESULT CheckBreak2()
37 {
38   return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
39 }
40 
41 HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
42 HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
43 
44 void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
45 
46 void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc);
47 
OpenResult(const CCodecs * codecs,const CArchiveLink & arcLink,const wchar_t * name,HRESULT result)48 HRESULT CUpdateCallbackConsole::OpenResult(
49     const CCodecs *codecs, const CArchiveLink &arcLink,
50     const wchar_t *name, HRESULT result)
51 {
52   ClosePercents2();
53 
54   FOR_VECTOR (level, arcLink.Arcs)
55   {
56     const CArc &arc = arcLink.Arcs[level];
57     const CArcErrorInfo &er = arc.ErrorInfo;
58 
59     UInt32 errorFlags = er.GetErrorFlags();
60 
61     if (errorFlags != 0 || !er.ErrorMessage.IsEmpty())
62     {
63       if (_se)
64       {
65         *_se << endl;
66         if (level != 0)
67           *_se << arc.Path << endl;
68       }
69 
70       if (errorFlags != 0)
71       {
72         if (_se)
73           PrintErrorFlags(*_se, "ERRORS:", errorFlags);
74       }
75 
76       if (!er.ErrorMessage.IsEmpty())
77       {
78         if (_se)
79           *_se << "ERRORS:" << endl << er.ErrorMessage << endl;
80       }
81 
82       if (_se)
83       {
84         *_se << endl;
85         _se->Flush();
86       }
87     }
88 
89     UInt32 warningFlags = er.GetWarningFlags();
90 
91     if (warningFlags != 0 || !er.WarningMessage.IsEmpty())
92     {
93       if (_so)
94       {
95         *_so << endl;
96         if (level != 0)
97           *_so << arc.Path << endl;
98       }
99 
100       if (warningFlags != 0)
101       {
102         if (_so)
103           PrintErrorFlags(*_so, "WARNINGS:", warningFlags);
104       }
105 
106       if (!er.WarningMessage.IsEmpty())
107       {
108         if (_so)
109           *_so << "WARNINGS:" << endl << er.WarningMessage << endl;
110       }
111 
112       if (_so)
113       {
114         *_so << endl;
115         if (NeedFlush)
116           _so->Flush();
117       }
118     }
119 
120 
121     if (er.ErrorFormatIndex >= 0)
122     {
123       if (_so)
124       {
125         Print_ErrorFormatIndex_Warning(_so, codecs, arc);
126         if (NeedFlush)
127           _so->Flush();
128       }
129     }
130   }
131 
132   if (result == S_OK)
133   {
134     if (_so)
135     {
136       RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink));
137       *_so << endl;
138     }
139   }
140   else
141   {
142     if (_so)
143       _so->Flush();
144     if (_se)
145     {
146       *_se << kError << name << endl;
147       HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink);
148       RINOK(res);
149       _se->Flush();
150     }
151   }
152 
153   return S_OK;
154 }
155 
StartScanning()156 HRESULT CUpdateCallbackConsole::StartScanning()
157 {
158   if (_so)
159     *_so << kScanningMessage << endl;
160   _percent.Command = "Scan ";
161   return S_OK;
162 }
163 
ScanProgress(const CDirItemsStat & st,const FString & path,bool)164 HRESULT CUpdateCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */)
165 {
166   if (NeedPercents())
167   {
168     _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams;
169     _percent.Completed = st.GetTotalBytes();
170     _percent.FileName = fs2us(path);
171     _percent.Print();
172   }
173 
174   return CheckBreak();
175 }
176 
CommonError(const FString & path,DWORD systemError,bool isWarning)177 void CCallbackConsoleBase::CommonError(const FString &path, DWORD systemError, bool isWarning)
178 {
179   ClosePercents2();
180 
181   if (_se)
182   {
183     if (_so)
184       _so->Flush();
185 
186     *_se << endl << (isWarning ? kWarning : kError)
187         << NError::MyFormatMessage(systemError)
188         << endl << fs2us(path) << endl << endl;
189     _se->Flush();
190   }
191 }
192 
193 
ScanError_Base(const FString & path,DWORD systemError)194 HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError)
195 {
196   MT_LOCK
197 
198   ScanErrors.AddError(path, systemError);
199   CommonError(path, systemError, true);
200 
201   return S_OK;
202 }
203 
OpenFileError_Base(const FString & path,DWORD systemError)204 HRESULT CCallbackConsoleBase::OpenFileError_Base(const FString &path, DWORD systemError)
205 {
206   MT_LOCK
207   FailedFiles.AddError(path, systemError);
208   /*
209   if (systemError == ERROR_SHARING_VIOLATION)
210   {
211   */
212     CommonError(path, systemError, true);
213     return S_FALSE;
214   /*
215   }
216   return systemError;
217   */
218 }
219 
ReadingFileError_Base(const FString & path,DWORD systemError)220 HRESULT CCallbackConsoleBase::ReadingFileError_Base(const FString &path, DWORD systemError)
221 {
222   MT_LOCK
223   CommonError(path, systemError, false);
224   return HRESULT_FROM_WIN32(systemError);
225 }
226 
ScanError(const FString & path,DWORD systemError)227 HRESULT CUpdateCallbackConsole::ScanError(const FString &path, DWORD systemError)
228 {
229   return ScanError_Base(path, systemError);
230 }
231 
232 
PrintPropPair(AString & s,const char * name,UInt64 val)233 static void PrintPropPair(AString &s, const char *name, UInt64 val)
234 {
235   char temp[32];
236   ConvertUInt64ToString(val, temp);
237   s += name;
238   s += ": ";
239   s += temp;
240 }
241 
242 void PrintSize_bytes_Smart(AString &s, UInt64 val);
243 void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
244 void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st);
245 
FinishScanning(const CDirItemsStat & st)246 HRESULT CUpdateCallbackConsole::FinishScanning(const CDirItemsStat &st)
247 {
248   if (NeedPercents())
249   {
250     _percent.ClosePrint(true);
251     _percent.ClearCurState();
252   }
253 
254   if (_so)
255   {
256     AString s;
257     Print_DirItemsStat(s, st);
258     *_so << s << endl << endl;
259   }
260   return S_OK;
261 }
262 
263 static const char * const k_StdOut_ArcName = "StdOut";
264 
StartOpenArchive(const wchar_t * name)265 HRESULT CUpdateCallbackConsole::StartOpenArchive(const wchar_t *name)
266 {
267   if (_so)
268   {
269     *_so << kOpenArchiveMessage;
270     if (name)
271       *_so << name;
272     else
273       *_so << k_StdOut_ArcName;
274     *_so << endl;
275   }
276   return S_OK;
277 }
278 
StartArchive(const wchar_t * name,bool updating)279 HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating)
280 {
281   if (_so)
282   {
283     *_so << (updating ? kUpdatingArchiveMessage : kCreatingArchiveMessage);
284     if (name != 0)
285       *_so << name;
286     else
287       *_so << k_StdOut_ArcName;
288    *_so << endl << endl;
289   }
290   return S_OK;
291 }
292 
FinishArchive(const CFinishArchiveStat & st)293 HRESULT CUpdateCallbackConsole::FinishArchive(const CFinishArchiveStat &st)
294 {
295   ClosePercents2();
296 
297   if (_so)
298   {
299     AString s;
300     // Print_UInt64_and_String(s, _percent.Files == 1 ? "file" : "files", _percent.Files);
301     PrintPropPair(s, "Files read from disk", _percent.Files);
302     s.Add_LF();
303     s += "Archive size: ";
304     PrintSize_bytes_Smart(s, st.OutArcFileSize);
305     s.Add_LF();
306     *_so << endl;
307     *_so << s;
308     // *_so << endl;
309   }
310 
311   return S_OK;
312 }
313 
WriteSfx(const wchar_t * name,UInt64 size)314 HRESULT CUpdateCallbackConsole::WriteSfx(const wchar_t *name, UInt64 size)
315 {
316   if (_so)
317   {
318     *_so << "Write SFX: ";
319     *_so << name;
320     AString s (" : ");
321     PrintSize_bytes_Smart(s, size);
322     *_so << s << endl;
323   }
324   return S_OK;
325 }
326 
327 
DeletingAfterArchiving(const FString & path,bool)328 HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */)
329 {
330   if (LogLevel > 0 && _so)
331   {
332     ClosePercents_for_so();
333 
334     if (!DeleteMessageWasShown)
335     {
336       if (_so)
337         *_so << endl << ": Removing files after including to archive" << endl;
338     }
339 
340     {
341       {
342         _tempA = "Removing";
343         _tempA.Add_Space();
344         *_so << _tempA;
345         _tempU = fs2us(path);
346         _so->PrintUString(_tempU, _tempA);
347         *_so << endl;
348         if (NeedFlush)
349           _so->Flush();
350       }
351     }
352   }
353 
354   if (!DeleteMessageWasShown)
355   {
356     if (NeedPercents())
357     {
358       _percent.ClearCurState();
359     }
360     DeleteMessageWasShown = true;
361   }
362   else
363   {
364     _percent.Files++;
365   }
366 
367   if (NeedPercents())
368   {
369     // if (!FullLog)
370     {
371       _percent.Command = "Removing";
372       _percent.FileName = fs2us(path);
373     }
374     _percent.Print();
375   }
376 
377   return S_OK;
378 }
379 
380 
FinishDeletingAfterArchiving()381 HRESULT CUpdateCallbackConsole::FinishDeletingAfterArchiving()
382 {
383   ClosePercents2();
384   if (_so && DeleteMessageWasShown)
385     *_so << endl;
386   return S_OK;
387 }
388 
CheckBreak()389 HRESULT CUpdateCallbackConsole::CheckBreak()
390 {
391   return CheckBreak2();
392 }
393 
394 /*
395 HRESULT CUpdateCallbackConsole::Finalize()
396 {
397   // MT_LOCK
398   return S_OK;
399 }
400 */
401 
402 
PrintToDoStat(CStdOutStream * _so,const CDirItemsStat2 & stat,const char * name)403 void static PrintToDoStat(CStdOutStream *_so, const CDirItemsStat2 &stat, const char *name)
404 {
405   AString s;
406   Print_DirItemsStat2(s, stat);
407   *_so << name << ": " << s << endl;
408 }
409 
SetNumItems(const CArcToDoStat & stat)410 HRESULT CUpdateCallbackConsole::SetNumItems(const CArcToDoStat &stat)
411 {
412   if (_so)
413   {
414     ClosePercents_for_so();
415     if (!stat.DeleteData.IsEmpty())
416     {
417       *_so << endl;
418       PrintToDoStat(_so, stat.DeleteData, "Delete data from archive");
419     }
420     if (!stat.OldData.IsEmpty())
421       PrintToDoStat(_so, stat.OldData, "Keep old data in archive");
422     // if (!stat.NewData.IsEmpty())
423     {
424       PrintToDoStat(_so, stat.NewData, "Add new data to archive");
425     }
426     *_so << endl;
427   }
428   return S_OK;
429 }
430 
SetTotal(UInt64 size)431 HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size)
432 {
433   MT_LOCK
434   if (NeedPercents())
435   {
436     _percent.Total = size;
437     _percent.Print();
438   }
439   return S_OK;
440 }
441 
SetCompleted(const UInt64 * completeValue)442 HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue)
443 {
444   MT_LOCK
445   if (completeValue)
446   {
447     if (NeedPercents())
448     {
449       _percent.Completed = *completeValue;
450       _percent.Print();
451     }
452   }
453   return CheckBreak2();
454 }
455 
SetRatioInfo(const UInt64 *,const UInt64 *)456 HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */)
457 {
458   return CheckBreak2();
459 }
460 
PrintProgress(const wchar_t * name,const char * command,bool showInLog)461 HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, const char *command, bool showInLog)
462 {
463   MT_LOCK
464 
465   bool show2 = (showInLog && _so);
466 
467   if (show2)
468   {
469     ClosePercents_for_so();
470 
471     _tempA = command;
472     if (name)
473       _tempA.Add_Space();
474     *_so << _tempA;
475 
476     _tempU.Empty();
477     if (name)
478       _tempU = name;
479     _so->PrintUString(_tempU, _tempA);
480     *_so << endl;
481     if (NeedFlush)
482       _so->Flush();
483   }
484 
485   if (NeedPercents())
486   {
487     if (PercentsNameLevel >= 1)
488     {
489       _percent.FileName.Empty();
490       _percent.Command.Empty();
491       if (PercentsNameLevel > 1 || !show2)
492       {
493         _percent.Command = command;
494         if (name)
495           _percent.FileName = name;
496       }
497     }
498     _percent.Print();
499   }
500 
501   return CheckBreak2();
502 }
503 
GetStream(const wchar_t * name,bool,bool isAnti,UInt32 mode)504 HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool /* isDir */, bool isAnti, UInt32 mode)
505 {
506   if (StdOutMode)
507     return S_OK;
508 
509   if (!name || name[0] == 0)
510     name = kEmptyFileAlias;
511 
512   unsigned requiredLevel = 1;
513 
514   const char *s;
515   if (mode == NUpdateNotifyOp::kAdd ||
516       mode == NUpdateNotifyOp::kUpdate)
517   {
518     if (isAnti)
519       s = "Anti";
520     else if (mode == NUpdateNotifyOp::kAdd)
521       s = "+";
522     else
523       s = "U";
524   }
525   else
526   {
527     requiredLevel = 3;
528     if (mode == NUpdateNotifyOp::kAnalyze)
529       s = "A";
530     else
531       s = "Reading";
532   }
533 
534   return PrintProgress(name, s, LogLevel >= requiredLevel);
535 }
536 
OpenFileError(const FString & path,DWORD systemError)537 HRESULT CUpdateCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
538 {
539   return OpenFileError_Base(path, systemError);
540 }
541 
ReadingFileError(const FString & path,DWORD systemError)542 HRESULT CUpdateCallbackConsole::ReadingFileError(const FString &path, DWORD systemError)
543 {
544   return ReadingFileError_Base(path, systemError);
545 }
546 
SetOperationResult(Int32)547 HRESULT CUpdateCallbackConsole::SetOperationResult(Int32)
548 {
549   MT_LOCK
550   _percent.Files++;
551   return S_OK;
552 }
553 
554 void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest);
555 
ReportExtractResult(Int32 opRes,Int32 isEncrypted,const wchar_t * name)556 HRESULT CUpdateCallbackConsole::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)
557 {
558   // if (StdOutMode) return S_OK;
559 
560   if (opRes != NArchive::NExtract::NOperationResult::kOK)
561   {
562     ClosePercents2();
563 
564     if (_se)
565     {
566       if (_so)
567         _so->Flush();
568 
569       AString s;
570       SetExtractErrorMessage(opRes, isEncrypted, s);
571       *_se << s << " : " << endl << name << endl << endl;
572       _se->Flush();
573     }
574     return S_OK;
575   }
576   return S_OK;
577 }
578 
579 
ReportUpdateOpeartion(UInt32 op,const wchar_t * name,bool)580 HRESULT CUpdateCallbackConsole::ReportUpdateOpeartion(UInt32 op, const wchar_t *name, bool /* isDir */)
581 {
582   // if (StdOutMode) return S_OK;
583 
584   char temp[16];
585   const char *s;
586 
587   unsigned requiredLevel = 1;
588 
589   switch (op)
590   {
591     case NUpdateNotifyOp::kAdd:       s = "+"; break;
592     case NUpdateNotifyOp::kUpdate:    s = "U"; break;
593     case NUpdateNotifyOp::kAnalyze:   s = "A"; requiredLevel = 3; break;
594     case NUpdateNotifyOp::kReplicate: s = "="; requiredLevel = 3; break;
595     case NUpdateNotifyOp::kRepack:    s = "R"; requiredLevel = 2; break;
596     case NUpdateNotifyOp::kSkip:      s = "."; requiredLevel = 2; break;
597     case NUpdateNotifyOp::kDelete:    s = "D"; requiredLevel = 3; break;
598     case NUpdateNotifyOp::kHeader:    s = "Header creation"; requiredLevel = 100; break;
599     default:
600     {
601       temp[0] = 'o';
602       temp[1] = 'p';
603       ConvertUInt64ToString(op, temp + 2);
604       s = temp;
605     }
606   }
607 
608   return PrintProgress(name, s, LogLevel >= requiredLevel);
609 }
610 
611 /*
612 HRESULT CUpdateCallbackConsole::SetPassword(const UString &
613     #ifndef _NO_CRYPTO
614     password
615     #endif
616     )
617 {
618   #ifndef _NO_CRYPTO
619   PasswordIsDefined = true;
620   Password = password;
621   #endif
622   return S_OK;
623 }
624 */
625 
CryptoGetTextPassword2(Int32 * passwordIsDefined,BSTR * password)626 HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
627 {
628   COM_TRY_BEGIN
629 
630   *password = NULL;
631 
632   #ifdef _NO_CRYPTO
633 
634   *passwordIsDefined = false;
635   return S_OK;
636 
637   #else
638 
639   if (!PasswordIsDefined)
640   {
641     if (AskPassword)
642     {
643       RINOK(GetPassword_HRESULT(_so, Password));
644       PasswordIsDefined = true;
645     }
646   }
647   *passwordIsDefined = BoolToInt(PasswordIsDefined);
648   return StringToBstr(Password, password);
649 
650   #endif
651 
652   COM_TRY_END
653 }
654 
CryptoGetTextPassword(BSTR * password)655 HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password)
656 {
657   COM_TRY_BEGIN
658 
659   *password = NULL;
660 
661   #ifdef _NO_CRYPTO
662 
663   return E_NOTIMPL;
664 
665   #else
666 
667   if (!PasswordIsDefined)
668   {
669     {
670       RINOK(GetPassword_HRESULT(_so, Password))
671       PasswordIsDefined = true;
672     }
673   }
674   return StringToBstr(Password, password);
675 
676   #endif
677   COM_TRY_END
678 }
679 
ShowDeleteFile(const wchar_t * name,bool)680 HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool /* isDir */)
681 {
682   if (StdOutMode)
683     return S_OK;
684 
685   if (LogLevel > 7)
686   {
687     if (!name || name[0] == 0)
688       name = kEmptyFileAlias;
689     return PrintProgress(name, "D", true);
690   }
691   return S_OK;
692 }
693