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 *kEmptyFileAlias = L"[Content]";
27 
28 static const char *kOpenArchiveMessage = "Open archive: ";
29 static const char *kCreatingArchiveMessage = "Creating archive: ";
30 static const char *kUpdatingArchiveMessage = "Updating archive: ";
31 static const char *kScanningMessage = "Scanning the drive:";
32 
33 static const char *kError = "ERROR: ";
34 static const char *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 
FinishScanning(const CDirItemsStat & st)245 HRESULT CUpdateCallbackConsole::FinishScanning(const CDirItemsStat &st)
246 {
247   if (NeedPercents())
248   {
249     _percent.ClosePrint(true);
250     _percent.ClearCurState();
251   }
252 
253   if (_so)
254   {
255     AString s;
256     Print_DirItemsStat(s, st);
257     *_so << s << endl << endl;
258   }
259   return S_OK;
260 }
261 
262 static const char *k_StdOut_ArcName = "StdOut";
263 
StartOpenArchive(const wchar_t * name)264 HRESULT CUpdateCallbackConsole::StartOpenArchive(const wchar_t *name)
265 {
266   if (_so)
267   {
268     *_so << kOpenArchiveMessage;
269     if (name)
270       *_so << name;
271     else
272       *_so << k_StdOut_ArcName;
273     *_so << endl;
274   }
275   return S_OK;
276 }
277 
StartArchive(const wchar_t * name,bool updating)278 HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating)
279 {
280   if (_so)
281   {
282     *_so << (updating ? kUpdatingArchiveMessage : kCreatingArchiveMessage);
283     if (name != 0)
284       *_so << name;
285     else
286       *_so << k_StdOut_ArcName;
287    *_so << endl << endl;
288   }
289   return S_OK;
290 }
291 
FinishArchive(const CFinishArchiveStat & st)292 HRESULT CUpdateCallbackConsole::FinishArchive(const CFinishArchiveStat &st)
293 {
294   ClosePercents2();
295 
296   if (_so)
297   {
298     AString s;
299     // Print_UInt64_and_String(s, _percent.Files == 1 ? "file" : "files", _percent.Files);
300     PrintPropPair(s, "Files read from disk", _percent.Files);
301     s.Add_LF();
302     s += "Archive size: ";
303     PrintSize_bytes_Smart(s, st.OutArcFileSize);
304     s.Add_LF();
305     *_so << endl;
306     *_so << s;
307     // *_so << endl;
308   }
309 
310   return S_OK;
311 }
312 
WriteSfx(const wchar_t * name,UInt64 size)313 HRESULT CUpdateCallbackConsole::WriteSfx(const wchar_t *name, UInt64 size)
314 {
315   if (_so)
316   {
317     *_so << "Write SFX: ";
318     *_so << name;
319     AString s = " : ";
320     PrintSize_bytes_Smart(s, size);
321     *_so << s << endl;
322   }
323   return S_OK;
324 }
325 
326 
DeletingAfterArchiving(const FString & path,bool)327 HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */)
328 {
329   if (LogLevel > 0 && _so)
330   {
331     ClosePercents_for_so();
332 
333     if (!DeleteMessageWasShown)
334     {
335       if (_so)
336         *_so << endl << ": Removing files after including to archive" << endl;
337     }
338 
339     {
340       {
341         _tempA = "Removing";
342         _tempA.Add_Space();
343         *_so << _tempA;
344         _tempU = fs2us(path);
345         _so->PrintUString(_tempU, _tempA);
346         *_so << endl;
347         if (NeedFlush)
348           _so->Flush();
349       }
350     }
351   }
352 
353   if (!DeleteMessageWasShown)
354   {
355     if (NeedPercents())
356     {
357       _percent.ClearCurState();
358     }
359     DeleteMessageWasShown = true;
360   }
361   else
362   {
363     _percent.Files++;
364   }
365 
366   if (NeedPercents())
367   {
368     // if (!FullLog)
369     {
370       _percent.Command = "Removing";
371       _percent.FileName = fs2us(path);
372     }
373     _percent.Print();
374   }
375 
376   return S_OK;
377 }
378 
379 
FinishDeletingAfterArchiving()380 HRESULT CUpdateCallbackConsole::FinishDeletingAfterArchiving()
381 {
382   ClosePercents2();
383   if (_so && DeleteMessageWasShown)
384     *_so << endl;
385   return S_OK;
386 }
387 
CheckBreak()388 HRESULT CUpdateCallbackConsole::CheckBreak()
389 {
390   return CheckBreak2();
391 }
392 
393 /*
394 HRESULT CUpdateCallbackConsole::Finalize()
395 {
396   // MT_LOCK
397   return S_OK;
398 }
399 */
400 
SetNumItems(UInt64 numItems)401 HRESULT CUpdateCallbackConsole::SetNumItems(UInt64 numItems)
402 {
403   if (_so)
404   {
405     ClosePercents_for_so();
406     AString s;
407     PrintPropPair(s, "Items to compress", numItems);
408     *_so << s << endl << endl;
409   }
410   return S_OK;
411 }
412 
SetTotal(UInt64 size)413 HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size)
414 {
415   MT_LOCK
416   if (NeedPercents())
417   {
418     _percent.Total = size;
419     _percent.Print();
420   }
421   return S_OK;
422 }
423 
SetCompleted(const UInt64 * completeValue)424 HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue)
425 {
426   MT_LOCK
427   if (completeValue)
428   {
429     if (NeedPercents())
430     {
431       _percent.Completed = *completeValue;
432       _percent.Print();
433     }
434   }
435   return CheckBreak2();
436 }
437 
SetRatioInfo(const UInt64 *,const UInt64 *)438 HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */)
439 {
440   return CheckBreak2();
441 }
442 
PrintProgress(const wchar_t * name,const char * command,bool showInLog)443 HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, const char *command, bool showInLog)
444 {
445   MT_LOCK
446 
447   bool show2 = (showInLog && _so);
448 
449   if (show2)
450   {
451     ClosePercents_for_so();
452 
453     _tempA = command;
454     if (name)
455       _tempA.Add_Space();
456     *_so << _tempA;
457 
458     _tempU.Empty();
459     if (name)
460       _tempU = name;
461     _so->PrintUString(_tempU, _tempA);
462     *_so << endl;
463     if (NeedFlush)
464       _so->Flush();
465   }
466 
467   if (NeedPercents())
468   {
469     if (PercentsNameLevel >= 1)
470     {
471       _percent.FileName.Empty();
472       _percent.Command.Empty();
473       if (PercentsNameLevel > 1 || !show2)
474       {
475         _percent.Command = command;
476         if (name)
477           _percent.FileName = name;
478       }
479     }
480     _percent.Print();
481   }
482 
483   return CheckBreak2();
484 }
485 
GetStream(const wchar_t * name,bool,bool isAnti,UInt32 mode)486 HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool /* isDir */, bool isAnti, UInt32 mode)
487 {
488   if (StdOutMode)
489     return S_OK;
490 
491   if (!name || name[0] == 0)
492     name = kEmptyFileAlias;
493 
494   unsigned requiredLevel = 1;
495 
496   const char *s;
497   if (mode == NUpdateNotifyOp::kAdd ||
498       mode == NUpdateNotifyOp::kUpdate)
499   {
500     if (isAnti)
501       s = "Anti";
502     else if (mode == NUpdateNotifyOp::kAdd)
503       s = "+";
504     else
505       s = "U";
506   }
507   else
508   {
509     requiredLevel = 3;
510     if (mode == NUpdateNotifyOp::kAnalyze)
511       s = "A";
512     else
513       s = "Reading";
514   }
515 
516   return PrintProgress(name, s, LogLevel >= requiredLevel);
517 }
518 
OpenFileError(const FString & path,DWORD systemError)519 HRESULT CUpdateCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
520 {
521   return OpenFileError_Base(path, systemError);
522 }
523 
ReadingFileError(const FString & path,DWORD systemError)524 HRESULT CUpdateCallbackConsole::ReadingFileError(const FString &path, DWORD systemError)
525 {
526   return ReadingFileError_Base(path, systemError);
527 }
528 
SetOperationResult(Int32)529 HRESULT CUpdateCallbackConsole::SetOperationResult(Int32)
530 {
531   MT_LOCK
532   _percent.Files++;
533   return S_OK;
534 }
535 
536 void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest);
537 
ReportExtractResult(Int32 opRes,Int32 isEncrypted,const wchar_t * name)538 HRESULT CUpdateCallbackConsole::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)
539 {
540   // if (StdOutMode) return S_OK;
541 
542   if (opRes != NArchive::NExtract::NOperationResult::kOK)
543   {
544     ClosePercents2();
545 
546     if (_se)
547     {
548       if (_so)
549         _so->Flush();
550 
551       AString s;
552       SetExtractErrorMessage(opRes, isEncrypted, s);
553       *_se << s << " : " << endl << name << endl << endl;
554       _se->Flush();
555     }
556     return S_OK;
557   }
558   return S_OK;
559 }
560 
561 
ReportUpdateOpeartion(UInt32 op,const wchar_t * name,bool)562 HRESULT CUpdateCallbackConsole::ReportUpdateOpeartion(UInt32 op, const wchar_t *name, bool /* isDir */)
563 {
564   // if (StdOutMode) return S_OK;
565 
566   char temp[16];
567   const char *s;
568 
569   unsigned requiredLevel = 1;
570 
571   switch (op)
572   {
573     case NUpdateNotifyOp::kAdd:       s = "+"; break;
574     case NUpdateNotifyOp::kUpdate:    s = "U"; break;
575     case NUpdateNotifyOp::kAnalyze:   s = "A"; requiredLevel = 3; break;
576     case NUpdateNotifyOp::kReplicate: s = "="; requiredLevel = 3; break;
577     case NUpdateNotifyOp::kRepack:    s = "R"; requiredLevel = 2; break;
578     case NUpdateNotifyOp::kSkip:      s = "."; requiredLevel = 2; break;
579     case NUpdateNotifyOp::kDelete:    s = "D"; requiredLevel = 3; break;
580     case NUpdateNotifyOp::kHeader:    s = "Header creation"; requiredLevel = 100; break;
581     default:
582     {
583       temp[0] = 'o';
584       temp[1] = 'p';
585       ConvertUInt64ToString(op, temp + 2);
586       s = temp;
587     }
588   }
589 
590   return PrintProgress(name, s, LogLevel >= requiredLevel);
591 }
592 
593 /*
594 HRESULT CUpdateCallbackConsole::SetPassword(const UString &
595     #ifndef _NO_CRYPTO
596     password
597     #endif
598     )
599 {
600   #ifndef _NO_CRYPTO
601   PasswordIsDefined = true;
602   Password = password;
603   #endif
604   return S_OK;
605 }
606 */
607 
CryptoGetTextPassword2(Int32 * passwordIsDefined,BSTR * password)608 HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
609 {
610   COM_TRY_BEGIN
611 
612   *password = NULL;
613 
614   #ifdef _NO_CRYPTO
615 
616   *passwordIsDefined = false;
617   return S_OK;
618 
619   #else
620 
621   if (!PasswordIsDefined)
622   {
623     if (AskPassword)
624     {
625       Password = GetPassword(_so);
626       PasswordIsDefined = true;
627     }
628   }
629   *passwordIsDefined = BoolToInt(PasswordIsDefined);
630   return StringToBstr(Password, password);
631 
632   #endif
633 
634   COM_TRY_END
635 }
636 
CryptoGetTextPassword(BSTR * password)637 HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password)
638 {
639   COM_TRY_BEGIN
640 
641   *password = NULL;
642 
643   #ifdef _NO_CRYPTO
644 
645   return E_NOTIMPL;
646 
647   #else
648 
649   if (!PasswordIsDefined)
650   {
651     {
652       Password = GetPassword(_so);
653       PasswordIsDefined = true;
654     }
655   }
656   return StringToBstr(Password, password);
657 
658   #endif
659   COM_TRY_END
660 }
661 
ShowDeleteFile(const wchar_t * name,bool)662 HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool /* isDir */)
663 {
664   if (StdOutMode)
665     return S_OK;
666 
667   if (LogLevel > 7)
668   {
669     if (!name || name[0] == 0)
670       name = kEmptyFileAlias;
671     return PrintProgress(name, "D", true);
672   }
673   return S_OK;
674 }
675