// UpdateCallbackConsole.cpp #include "StdAfx.h" #include "../../../Common/IntToString.h" #include "../../../Windows/ErrorMsg.h" #ifndef _7ZIP_ST #include "../../../Windows/Synchronization.h" #endif #include "ConsoleClose.h" #include "UserInputUtils.h" #include "UpdateCallbackConsole.h" using namespace NWindows; #ifndef _7ZIP_ST static NSynchronization::CCriticalSection g_CriticalSection; #define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection); #else #define MT_LOCK #endif static const wchar_t * const kEmptyFileAlias = L"[Content]"; static const char * const kOpenArchiveMessage = "Open archive: "; static const char * const kCreatingArchiveMessage = "Creating archive: "; static const char * const kUpdatingArchiveMessage = "Updating archive: "; static const char * const kScanningMessage = "Scanning the drive:"; static const char * const kError = "ERROR: "; static const char * const kWarning = "WARNING: "; static HRESULT CheckBreak2() { return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK; } HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink); void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags); void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc); HRESULT CUpdateCallbackConsole::OpenResult( const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) { ClosePercents2(); FOR_VECTOR (level, arcLink.Arcs) { const CArc &arc = arcLink.Arcs[level]; const CArcErrorInfo &er = arc.ErrorInfo; UInt32 errorFlags = er.GetErrorFlags(); if (errorFlags != 0 || !er.ErrorMessage.IsEmpty()) { if (_se) { *_se << endl; if (level != 0) *_se << arc.Path << endl; } if (errorFlags != 0) { if (_se) PrintErrorFlags(*_se, "ERRORS:", errorFlags); } if (!er.ErrorMessage.IsEmpty()) { if (_se) *_se << "ERRORS:" << endl << er.ErrorMessage << endl; } if (_se) { *_se << endl; _se->Flush(); } } UInt32 warningFlags = er.GetWarningFlags(); if (warningFlags != 0 || !er.WarningMessage.IsEmpty()) { if (_so) { *_so << endl; if (level != 0) *_so << arc.Path << endl; } if (warningFlags != 0) { if (_so) PrintErrorFlags(*_so, "WARNINGS:", warningFlags); } if (!er.WarningMessage.IsEmpty()) { if (_so) *_so << "WARNINGS:" << endl << er.WarningMessage << endl; } if (_so) { *_so << endl; if (NeedFlush) _so->Flush(); } } if (er.ErrorFormatIndex >= 0) { if (_so) { Print_ErrorFormatIndex_Warning(_so, codecs, arc); if (NeedFlush) _so->Flush(); } } } if (result == S_OK) { if (_so) { RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink)); *_so << endl; } } else { if (_so) _so->Flush(); if (_se) { *_se << kError; _se->NormalizePrint_wstr(name); *_se << endl; HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink); RINOK(res); _se->Flush(); } } return S_OK; } HRESULT CUpdateCallbackConsole::StartScanning() { if (_so) *_so << kScanningMessage << endl; _percent.Command = "Scan "; return S_OK; } HRESULT CUpdateCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */) { if (NeedPercents()) { _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams; _percent.Completed = st.GetTotalBytes(); _percent.FileName = fs2us(path); _percent.Print(); } return CheckBreak(); } void CCallbackConsoleBase::CommonError(const FString &path, DWORD systemError, bool isWarning) { ClosePercents2(); if (_se) { if (_so) _so->Flush(); *_se << endl << (isWarning ? kWarning : kError) << NError::MyFormatMessage(systemError) << endl; _se->NormalizePrint_UString(fs2us(path)); *_se << endl << endl; _se->Flush(); } } HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError) { MT_LOCK ScanErrors.AddError(path, systemError); CommonError(path, systemError, true); return S_OK; } HRESULT CCallbackConsoleBase::OpenFileError_Base(const FString &path, DWORD systemError) { MT_LOCK FailedFiles.AddError(path, systemError); /* if (systemError == ERROR_SHARING_VIOLATION) { */ CommonError(path, systemError, true); return S_FALSE; /* } return systemError; */ } HRESULT CCallbackConsoleBase::ReadingFileError_Base(const FString &path, DWORD systemError) { MT_LOCK CommonError(path, systemError, false); return HRESULT_FROM_WIN32(systemError); } HRESULT CUpdateCallbackConsole::ScanError(const FString &path, DWORD systemError) { return ScanError_Base(path, systemError); } static void PrintPropPair(AString &s, const char *name, UInt64 val) { char temp[32]; ConvertUInt64ToString(val, temp); s += name; s += ": "; s += temp; } void PrintSize_bytes_Smart(AString &s, UInt64 val); void Print_DirItemsStat(AString &s, const CDirItemsStat &st); void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st); HRESULT CUpdateCallbackConsole::FinishScanning(const CDirItemsStat &st) { if (NeedPercents()) { _percent.ClosePrint(true); _percent.ClearCurState(); } if (_so) { AString s; Print_DirItemsStat(s, st); *_so << s << endl << endl; } return S_OK; } static const char * const k_StdOut_ArcName = "StdOut"; HRESULT CUpdateCallbackConsole::StartOpenArchive(const wchar_t *name) { if (_so) { *_so << kOpenArchiveMessage; if (name) *_so << name; else *_so << k_StdOut_ArcName; *_so << endl; } return S_OK; } HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating) { if (_so) { *_so << (updating ? kUpdatingArchiveMessage : kCreatingArchiveMessage); if (name) _so->NormalizePrint_wstr(name); else *_so << k_StdOut_ArcName; *_so << endl << endl; } return S_OK; } HRESULT CUpdateCallbackConsole::FinishArchive(const CFinishArchiveStat &st) { ClosePercents2(); if (_so) { AString s; // Print_UInt64_and_String(s, _percent.Files == 1 ? "file" : "files", _percent.Files); PrintPropPair(s, "Files read from disk", _percent.Files); s.Add_LF(); s += "Archive size: "; PrintSize_bytes_Smart(s, st.OutArcFileSize); s.Add_LF(); *_so << endl; *_so << s; // *_so << endl; } return S_OK; } HRESULT CUpdateCallbackConsole::WriteSfx(const wchar_t *name, UInt64 size) { if (_so) { *_so << "Write SFX: "; *_so << name; AString s (" : "); PrintSize_bytes_Smart(s, size); *_so << s << endl; } return S_OK; } HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */) { if (LogLevel > 0 && _so) { ClosePercents_for_so(); if (!DeleteMessageWasShown) { if (_so) *_so << endl << ": Removing files after including to archive" << endl; } { { _tempA = "Removing"; _tempA.Add_Space(); *_so << _tempA; _tempU = fs2us(path); _so->Normalize_UString(_tempU); _so->PrintUString(_tempU, _tempA); *_so << endl; if (NeedFlush) _so->Flush(); } } } if (!DeleteMessageWasShown) { if (NeedPercents()) { _percent.ClearCurState(); } DeleteMessageWasShown = true; } else { _percent.Files++; } if (NeedPercents()) { // if (!FullLog) { _percent.Command = "Removing"; _percent.FileName = fs2us(path); } _percent.Print(); } return S_OK; } HRESULT CUpdateCallbackConsole::FinishDeletingAfterArchiving() { ClosePercents2(); if (_so && DeleteMessageWasShown) *_so << endl; return S_OK; } HRESULT CUpdateCallbackConsole::CheckBreak() { return CheckBreak2(); } /* HRESULT CUpdateCallbackConsole::Finalize() { // MT_LOCK return S_OK; } */ void static PrintToDoStat(CStdOutStream *_so, const CDirItemsStat2 &stat, const char *name) { AString s; Print_DirItemsStat2(s, stat); *_so << name << ": " << s << endl; } HRESULT CUpdateCallbackConsole::SetNumItems(const CArcToDoStat &stat) { if (_so) { ClosePercents_for_so(); if (!stat.DeleteData.IsEmpty()) { *_so << endl; PrintToDoStat(_so, stat.DeleteData, "Delete data from archive"); } if (!stat.OldData.IsEmpty()) PrintToDoStat(_so, stat.OldData, "Keep old data in archive"); // if (!stat.NewData.IsEmpty()) { PrintToDoStat(_so, stat.NewData, "Add new data to archive"); } *_so << endl; } return S_OK; } HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size) { MT_LOCK if (NeedPercents()) { _percent.Total = size; _percent.Print(); } return S_OK; } HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue) { MT_LOCK if (completeValue) { if (NeedPercents()) { _percent.Completed = *completeValue; _percent.Print(); } } return CheckBreak2(); } HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */) { return CheckBreak2(); } HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, const char *command, bool showInLog) { MT_LOCK bool show2 = (showInLog && _so); if (show2) { ClosePercents_for_so(); _tempA = command; if (name) _tempA.Add_Space(); *_so << _tempA; _tempU.Empty(); if (name) { _tempU = name; _so->Normalize_UString(_tempU); } _so->PrintUString(_tempU, _tempA); *_so << endl; if (NeedFlush) _so->Flush(); } if (NeedPercents()) { if (PercentsNameLevel >= 1) { _percent.FileName.Empty(); _percent.Command.Empty(); if (PercentsNameLevel > 1 || !show2) { _percent.Command = command; if (name) _percent.FileName = name; } } _percent.Print(); } return CheckBreak2(); } HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool /* isDir */, bool isAnti, UInt32 mode) { if (StdOutMode) return S_OK; if (!name || name[0] == 0) name = kEmptyFileAlias; unsigned requiredLevel = 1; const char *s; if (mode == NUpdateNotifyOp::kAdd || mode == NUpdateNotifyOp::kUpdate) { if (isAnti) s = "Anti"; else if (mode == NUpdateNotifyOp::kAdd) s = "+"; else s = "U"; } else { requiredLevel = 3; if (mode == NUpdateNotifyOp::kAnalyze) s = "A"; else s = "Reading"; } return PrintProgress(name, s, LogLevel >= requiredLevel); } HRESULT CUpdateCallbackConsole::OpenFileError(const FString &path, DWORD systemError) { return OpenFileError_Base(path, systemError); } HRESULT CUpdateCallbackConsole::ReadingFileError(const FString &path, DWORD systemError) { return ReadingFileError_Base(path, systemError); } HRESULT CUpdateCallbackConsole::SetOperationResult(Int32) { MT_LOCK _percent.Files++; return S_OK; } void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest); HRESULT CUpdateCallbackConsole::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) { // if (StdOutMode) return S_OK; if (opRes != NArchive::NExtract::NOperationResult::kOK) { ClosePercents2(); if (_se) { if (_so) _so->Flush(); AString s; SetExtractErrorMessage(opRes, isEncrypted, s); *_se << s << " : " << endl; _se->NormalizePrint_wstr(name); *_se << endl << endl; _se->Flush(); } return S_OK; } return S_OK; } HRESULT CUpdateCallbackConsole::ReportUpdateOpeartion(UInt32 op, const wchar_t *name, bool /* isDir */) { // if (StdOutMode) return S_OK; char temp[16]; const char *s; unsigned requiredLevel = 1; switch (op) { case NUpdateNotifyOp::kAdd: s = "+"; break; case NUpdateNotifyOp::kUpdate: s = "U"; break; case NUpdateNotifyOp::kAnalyze: s = "A"; requiredLevel = 3; break; case NUpdateNotifyOp::kReplicate: s = "="; requiredLevel = 3; break; case NUpdateNotifyOp::kRepack: s = "R"; requiredLevel = 2; break; case NUpdateNotifyOp::kSkip: s = "."; requiredLevel = 2; break; case NUpdateNotifyOp::kDelete: s = "D"; requiredLevel = 3; break; case NUpdateNotifyOp::kHeader: s = "Header creation"; requiredLevel = 100; break; default: { temp[0] = 'o'; temp[1] = 'p'; ConvertUInt64ToString(op, temp + 2); s = temp; } } return PrintProgress(name, s, LogLevel >= requiredLevel); } /* HRESULT CUpdateCallbackConsole::SetPassword(const UString & #ifndef _NO_CRYPTO password #endif ) { #ifndef _NO_CRYPTO PasswordIsDefined = true; Password = password; #endif return S_OK; } */ HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) { COM_TRY_BEGIN *password = NULL; #ifdef _NO_CRYPTO *passwordIsDefined = false; return S_OK; #else if (!PasswordIsDefined) { if (AskPassword) { RINOK(GetPassword_HRESULT(_so, Password)); PasswordIsDefined = true; } } *passwordIsDefined = BoolToInt(PasswordIsDefined); return StringToBstr(Password, password); #endif COM_TRY_END } HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password) { COM_TRY_BEGIN *password = NULL; #ifdef _NO_CRYPTO return E_NOTIMPL; #else if (!PasswordIsDefined) { { RINOK(GetPassword_HRESULT(_so, Password)) PasswordIsDefined = true; } } return StringToBstr(Password, password); #endif COM_TRY_END } HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool /* isDir */) { if (StdOutMode) return S_OK; if (LogLevel > 7) { if (!name || name[0] == 0) name = kEmptyFileAlias; return PrintProgress(name, "D", true); } return S_OK; }