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